```console
-// Create an env var MY_NAME
+// 환경 변수 MY_NAME 생성
$ $Env:MY_NAME = "Wade Wilson"
-// Use it with other programs, like
+// 다른 프로그램과 함께 사용하기. 예:
$ echo "Hello $Env:MY_NAME"
Hello Wade Wilson
@@ -78,20 +78,20 @@ print(f"Hello {name} from Python")
-/// tip
+/// tip | 팁
`pwdlib`를 사용하면 **Django**, **Flask** 보안 플러그인 또는 다른 여러 도구로 생성한 패스워드를 읽을 수 있도록 설정할 수도 있습니다.
@@ -100,7 +100,7 @@ $ pip install "pwdlib[argon2]"
권장 설정으로 PasswordHash 인스턴스를 생성합니다. 이는 패스워드를 해싱하고 검증하는 데 사용됩니다.
-/// tip
+/// tip | 팁
pwdlib는 bcrypt 해싱 알고리즘도 지원하지만 레거시 알고리즘은 포함하지 않습니다. 오래된 해시로 작업해야 한다면 passlib 라이브러리를 사용하는 것을 권장합니다.
@@ -116,9 +116,13 @@ pwdlib는 bcrypt 해싱 알고리즘도 지원하지만 레거시 알고리즘
그리고 사용자를 인증하고 반환하는 또 다른 함수도 생성합니다.
-{* ../../docs_src/security/tutorial004_an_py310.py hl[8,49,56:57,60:61,70:76] *}
+{* ../../docs_src/security/tutorial004_an_py310.py hl[8,49,51,58:59,62:63,72:79] *}
-/// note
+`authenticate_user`가 데이터베이스에 존재하지 않는 사용자이름으로 호출되더라도, 여전히 `verify_password`를 더미 해시에 대해 실행합니다.
+
+이렇게 하면 사용자이름이 유효하든 아니든 엔드포인트가 응답하는 데 걸리는 시간이 대략 동일해져, 기존 사용자이름을 열거하는 데 악용될 수 있는 **타이밍 공격**을 방지합니다.
+
+/// note | 참고
새로운 (가짜) 데이터베이스 `fake_users_db`를 확인하면, 이제 해시 처리된 패스워드가 어떻게 생겼는지 볼 수 있습니다: `"$argon2id$v=19$m=65536,t=3,p=4$wagCPXjifgvUFBzq4hqe3w$CYaIb8sB+wtD+Vu/P4uod1+Qof8h+1g7bbDlBID48Rc"`.
@@ -152,7 +156,7 @@ JWT 토큰을 서명하는 데 사용될 알고리즘을 위한 변수 `ALGORITH
새 액세스 토큰을 생성하기 위한 유틸리티 함수를 생성합니다.
-{* ../../docs_src/security/tutorial004_an_py310.py hl[4,7,13:15,29:31,79:87] *}
+{* ../../docs_src/security/tutorial004_an_py310.py hl[4,7,13:15,29:31,82:90] *}
## 의존성 업데이트 { #update-the-dependencies }
@@ -162,7 +166,7 @@ JWT 토큰을 서명하는 데 사용될 알고리즘을 위한 변수 `ALGORITH
토큰이 유효하지 않다면 즉시 HTTP 오류를 반환합니다.
-{* ../../docs_src/security/tutorial004_an_py310.py hl[90:107] *}
+{* ../../docs_src/security/tutorial004_an_py310.py hl[93:110] *}
## `/token` *경로 처리* 업데이트 { #update-the-token-path-operation }
@@ -170,7 +174,7 @@ JWT 토큰을 서명하는 데 사용될 알고리즘을 위한 변수 `ALGORITH
실제 JWT 액세스 토큰을 생성하여 반환합니다.
-{* ../../docs_src/security/tutorial004_an_py310.py hl[118:133] *}
+{* ../../docs_src/security/tutorial004_an_py310.py hl[121:136] *}
### JWT "주체(subject)" `sub`에 대한 기술 세부사항 { #technical-details-about-the-jwt-subject-sub }
@@ -209,7 +213,7 @@ JWT는 사용자를 식별하고 사용자가 API에서 직접 작업을 수행
Username: `johndoe`
Password: `secret`
-/// check
+/// check | 확인
코드 어디에도 평문 패스워드 "`secret`"은 없고, 해시된 버전만 있다는 점에 유의하십시오.
@@ -234,7 +238,7 @@ Password: `secret`
-/// note
+/// note | 참고
`Bearer `로 시작하는 값을 가진 `Authorization` 헤더에 주목하십시오.
diff --git a/docs/ko/docs/tutorial/security/simple-oauth2.md b/docs/ko/docs/tutorial/security/simple-oauth2.md
index 189dd89f2a..918c94b25f 100644
--- a/docs/ko/docs/tutorial/security/simple-oauth2.md
+++ b/docs/ko/docs/tutorial/security/simple-oauth2.md
@@ -162,7 +162,7 @@ UserInDB(
/// tip | 팁
-다음 장에서는 패스워드 해싱 및
토큰을 사용하여 실제 보안 구현을 볼 수 있습니다.
하지만 지금은 필요한 세부 정보에 집중하겠습니다.
@@ -286,4 +286,4 @@ UserInDB(
유일한 오점은 아직 실제로 "안전"하지 않다는 것입니다.
-다음 장에서는 안전한 패스워드 해싱 라이브러리와
토큰을 사용하는 방법을 살펴보겠습니다.
diff --git a/docs/ko/docs/tutorial/sql-databases.md b/docs/ko/docs/tutorial/sql-databases.md
index 3d64cf627a..20c1367164 100644
--- a/docs/ko/docs/tutorial/sql-databases.md
+++ b/docs/ko/docs/tutorial/sql-databases.md
@@ -8,7 +8,7 @@
/// tip | 팁
-다른 SQL 또는 NoSQL 데이터베이스 라이브러리를 사용할 수도 있습니다 (일부는
이라고도 불립니다), FastAPI는 특정 라이브러리의 사용을 강요하지 않습니다. 😎
+다른 SQL 또는 NoSQL 데이터베이스 라이브러리를 사용할 수도 있습니다 (일부는
이라고도 불립니다), FastAPI는 특정 라이브러리의 사용을 강요하지 않습니다. 😎
///
diff --git a/docs/ko/docs/tutorial/static-files.md b/docs/ko/docs/tutorial/static-files.md
index aa4c571793..0235d83c7f 100644
--- a/docs/ko/docs/tutorial/static-files.md
+++ b/docs/ko/docs/tutorial/static-files.md
@@ -7,7 +7,7 @@
* `StaticFiles`를 임포트합니다.
* 특정 경로에 `StaticFiles()` 인스턴스를 "마운트"합니다.
-{* ../../docs_src/static_files/tutorial001_py39.py hl[2,6] *}
+{* ../../docs_src/static_files/tutorial001_py310.py hl[2,6] *}
/// note | 기술 세부사항
diff --git a/docs/ko/docs/tutorial/testing.md b/docs/ko/docs/tutorial/testing.md
index db7fb17ead..57ab811515 100644
--- a/docs/ko/docs/tutorial/testing.md
+++ b/docs/ko/docs/tutorial/testing.md
@@ -2,7 +2,7 @@
를 직접 사용할 수 있습니다.
@@ -30,7 +30,7 @@ $ pip install httpx
표준적인 파이썬 표현식으로 확인이 필요한 곳에 간단한 `assert` 문장을 작성하세요(역시 표준적인 `pytest` 관례입니다).
-{* ../../docs_src/app_testing/tutorial001_py39.py hl[2,12,15:18] *}
+{* ../../docs_src/app_testing/tutorial001_py310.py hl[2,12,15:18] *}
/// tip | 팁
@@ -42,7 +42,7 @@ $ pip install httpx
///
-/// note Technical Details | 기술 세부사항
+/// note | 기술 세부사항
`from starlette.testclient import TestClient` 역시 사용할 수 있습니다.
@@ -76,7 +76,7 @@ FastAPI 애플리케이션에 요청을 보내는 것 외에도 테스트에서
`main.py` 파일 안에 **FastAPI** app 을 만들었습니다:
-{* ../../docs_src/app_testing/app_a_py39/main.py *}
+{* ../../docs_src/app_testing/app_a_py310/main.py *}
### 테스트 파일 { #testing-file }
@@ -92,7 +92,7 @@ FastAPI 애플리케이션에 요청을 보내는 것 외에도 테스트에서
파일들이 동일한 패키지에 위치해 있으므로, 상대 임포트를 사용하여 `main` 모듈(`main.py`)에서 `app` 객체를 임포트 해올 수 있습니다.
-{* ../../docs_src/app_testing/app_a_py39/test_main.py hl[3] *}
+{* ../../docs_src/app_testing/app_a_py310/test_main.py hl[3] *}
...그리고 이전에 작성했던 것과 같은 테스트 코드를 작성할 수 있습니다.
@@ -115,7 +115,7 @@ FastAPI 애플리케이션에 요청을 보내는 것 외에도 테스트에서
이제 **FastAPI** 앱이 있는 `main.py` 파일에 몇 가지 다른 **경로 처리**가 추가된 경우를 생각해봅시다.
-단일 오류를 반환할 수 있는 `GET` 작업이 있습니다.
+오류를 반환할 수 있는 `GET` 작업이 있습니다.
여러 다른 오류를 반환할 수 있는 `POST` 작업이 있습니다.
diff --git a/docs/ko/docs/virtual-environments.md b/docs/ko/docs/virtual-environments.md
index b639f8a3e4..e6baef73b4 100644
--- a/docs/ko/docs/virtual-environments.md
+++ b/docs/ko/docs/virtual-environments.md
@@ -37,15 +37,15 @@ Python 설치까지 포함해 **모든 것을 관리해주는 도구**를 도입
```console
-// Go to the home directory
+// 홈 디렉터리로 이동
$ cd
-// Create a directory for all your code projects
+// 모든 코드 프로젝트를 위한 디렉터리 생성
$ mkdir code
-// Enter into that code directory
+// 그 code 디렉터리로 이동
$ cd code
-// Create a directory for this project
+// 이 프로젝트를 위한 디렉터리 생성
$ mkdir awesome-project
-// Enter into that project directory
+// 그 프로젝트 디렉터리로 이동
$ cd awesome-project
```
@@ -53,7 +53,7 @@ $ cd awesome-project
## 가상 환경 생성 { #create-a-virtual-environment }
-Python 프로젝트를 **처음 시작할 때**, **
프로젝트 내부**에 가상 환경을 생성하세요.
+Python 프로젝트를 **처음 시작할 때**, 가상 환경을 **
프로젝트 내부**에 생성하세요.
/// tip
@@ -166,7 +166,7 @@ $ source .venv/Scripts/activate
해당 환경에 **새 패키지**를 설치할 때마다, 환경을 다시 **활성화**하세요.
-이렇게 하면 해당 패키지가 설치한 **터미널(
CLI) 프로그램**을 사용할 때, 전역으로 설치되어 있을 수도 있는(아마 필요한 버전과는 다른 버전인) 다른 프로그램이 아니라 가상 환경에 있는 것을 사용하게 됩니다.
+이렇게 하면 해당 패키지가 설치한 **터미널(
CLI) 프로그램**을 사용할 때, 전역으로 설치되어 있을 수도 있는(아마 필요한 버전과는 다른 버전인) 다른 프로그램이 아니라 가상 환경에 있는 것을 사용하게 됩니다.
///
@@ -557,7 +557,7 @@ Python을 설치하면 컴퓨터에 몇몇 파일이 들어 있는 디렉터리
```console
-// Don't run this now, it's just an example 🤓
+// 지금은 실행하지 마세요, 예시일 뿐입니다 🤓
$ pip install "fastapi[standard]"
---> 100%
```
@@ -811,7 +811,7 @@ $ cd ~/code/prisoner-of-azkaban
$ python main.py
-// Error importing sirius, it's not installed 😱
+// sirius 임포트 오류, 설치되어 있지 않습니다 😱
Traceback (most recent call last):
File "main.py", line 1, in
import sirius
@@ -826,13 +826,13 @@ Traceback (most recent call last):
```console
$ cd ~/code/prisoner-of-azkaban
-// You don't need to be in the old directory to deactivate, you can do it wherever you are, even after going to the other project 😎
+// 비활성화를 위해 이전 디렉터리에 있을 필요는 없습니다. 어디서든, 다른 프로젝트로 이동한 뒤에도 할 수 있습니다 😎
$ deactivate
-// Activate the virtual environment in prisoner-of-azkaban/.venv 🚀
+// prisoner-of-azkaban/.venv의 가상 환경을 활성화하세요 🚀
$ source .venv/bin/activate
-// Now when you run python, it will find the package sirius installed in this virtual environment ✨
+// 이제 python을 실행하면, 이 가상 환경에 설치된 sirius 패키지를 찾습니다 ✨
$ python main.py
I solemnly swear 🐺
diff --git a/docs/pt/docs/_llm-test.md b/docs/pt/docs/_llm-test.md
index b59292f47c..9f03c4b886 100644
--- a/docs/pt/docs/_llm-test.md
+++ b/docs/pt/docs/_llm-test.md
@@ -104,8 +104,8 @@ $ cd code
...e um exemplo de código Python...
```Python
-wont_work() # This won't work 😱
-works(foo="bar") # This works 🎉
+wont_work() # Isto não vai funcionar 😱
+works(foo="bar") # Isto funciona 🎉
```
...e é isso.
@@ -197,20 +197,15 @@ Aqui estão algumas coisas envolvidas em elementos HTML "abbr" (algumas são inv
### O abbr fornece uma frase completa { #the-abbr-gives-a-full-phrase }
-* GTD
-* lt
-* XWT
-* PSGI
-
-### O abbr fornece uma explicação { #the-abbr-gives-an-explanation }
-
-* cluster
-* Deep Learning
+* GTD
+* lt
+* XWT
+* PSGI
### O abbr fornece uma frase completa e uma explicação { #the-abbr-gives-a-full-phrase-and-an-explanation }
-* MDN
-* I/O.
+* MDN
+* I/O.
////
@@ -224,6 +219,11 @@ Veja a seção `### HTML abbr elements` no prompt geral em `scripts/translate.py
////
+## Elementos HTML "dfn" { #html-dfn-elements }
+
+* cluster
+* Deep Learning
+
## Títulos { #headings }
//// tab | Teste
diff --git a/docs/pt/docs/advanced/additional-responses.md b/docs/pt/docs/advanced/additional-responses.md
index 688bc16967..2e277ac104 100644
--- a/docs/pt/docs/advanced/additional-responses.md
+++ b/docs/pt/docs/advanced/additional-responses.md
@@ -26,7 +26,7 @@ O **FastAPI** pegará este modelo, gerará o esquema JSON dele e incluirá no lo
Por exemplo, para declarar um outro retorno com o status code `404` e um modelo do Pydantic chamado `Message`, você pode escrever:
-{* ../../docs_src/additional_responses/tutorial001_py39.py hl[18,22] *}
+{* ../../docs_src/additional_responses/tutorial001_py310.py hl[18,22] *}
/// note | Nota
@@ -203,7 +203,7 @@ Por exemplo, você pode declarar um retorno com o código de status `404` que ut
E um retorno com o código de status `200` que utiliza o seu `response_model`, porém inclui um `example` customizado:
-{* ../../docs_src/additional_responses/tutorial003_py39.py hl[20:31] *}
+{* ../../docs_src/additional_responses/tutorial003_py310.py hl[20:31] *}
Isso será combinado e incluído em seu OpenAPI, e disponibilizado na documentação da sua API:
@@ -243,5 +243,5 @@ Por exemplo:
Para verificar exatamente o que você pode incluir nos retornos, você pode conferir estas seções na especificação do OpenAPI:
-* Objeto de Retorno OpenAPI, inclui o `Response Object`.
-* Objeto de Retorno OpenAPI, você pode incluir qualquer coisa dele diretamente em cada retorno dentro do seu parâmetro `responses`. Incluindo `description`, `headers`, `content` (dentro dele que você declara diferentes media types e esquemas JSON), e `links`.
+* Objeto de Retornos do OpenAPI, inclui o `Response Object`.
+* Objeto de Retorno do OpenAPI, você pode incluir qualquer coisa dele diretamente em cada retorno dentro do seu parâmetro `responses`. Incluindo `description`, `headers`, `content` (dentro dele que você declara diferentes media types e esquemas JSON), e `links`.
diff --git a/docs/pt/docs/advanced/advanced-dependencies.md b/docs/pt/docs/advanced/advanced-dependencies.md
index 959a7f3c2b..419a092c80 100644
--- a/docs/pt/docs/advanced/advanced-dependencies.md
+++ b/docs/pt/docs/advanced/advanced-dependencies.md
@@ -18,7 +18,7 @@ Não propriamente a classe (que já é um chamável), mas a instância desta cla
Para fazer isso, nós declaramos o método `__call__`:
-{* ../../docs_src/dependencies/tutorial011_an_py39.py hl[12] *}
+{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[12] *}
Neste caso, o `__call__` é o que o **FastAPI** utilizará para verificar parâmetros adicionais e sub dependências, e isso é o que será chamado para passar o valor ao parâmetro na sua *função de operação de rota* posteriormente.
@@ -26,7 +26,7 @@ Neste caso, o `__call__` é o que o **FastAPI** utilizará para verificar parâm
E agora, nós podemos utilizar o `__init__` para declarar os parâmetros da instância que podemos utilizar para "parametrizar" a dependência:
-{* ../../docs_src/dependencies/tutorial011_an_py39.py hl[9] *}
+{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[9] *}
Neste caso, o **FastAPI** nunca tocará ou se importará com o `__init__`, nós vamos utilizar diretamente em nosso código.
@@ -34,7 +34,7 @@ Neste caso, o **FastAPI** nunca tocará ou se importará com o `__init__`, nós
Nós poderíamos criar uma instância desta classe com:
-{* ../../docs_src/dependencies/tutorial011_an_py39.py hl[18] *}
+{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[18] *}
E deste modo nós podemos "parametrizar" a nossa dependência, que agora possui `"bar"` dentro dele, como o atributo `checker.fixed_content`.
@@ -50,7 +50,7 @@ checker(q="somequery")
...e passar o que quer que isso retorne como valor da dependência em nossa *função de operação de rota* como o parâmetro `fixed_content_included`:
-{* ../../docs_src/dependencies/tutorial011_an_py39.py hl[22] *}
+{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[22] *}
/// tip | Dica
diff --git a/docs/pt/docs/advanced/advanced-python-types.md b/docs/pt/docs/advanced/advanced-python-types.md
new file mode 100644
index 0000000000..f92a20bd46
--- /dev/null
+++ b/docs/pt/docs/advanced/advanced-python-types.md
@@ -0,0 +1,61 @@
+# Tipos Avançados de Python { #advanced-python-types }
+
+Aqui estão algumas ideias adicionais que podem ser úteis ao trabalhar com tipos em Python.
+
+## Usando `Union` ou `Optional` { #using-union-or-optional }
+
+Se, por algum motivo, seu código não puder usar `|`, por exemplo, se não for em uma anotação de tipo, mas em algo como `response_model=`, em vez de usar a barra vertical (`|`) você pode usar `Union` do `typing`.
+
+Por exemplo, você poderia declarar que algo pode ser `str` ou `None`:
+
+```python
+from typing import Union
+
+
+def say_hi(name: Union[str, None]):
+ print(f"Hi {name}!")
+```
+
+O `typing` também tem um atalho para declarar que algo pode ser `None`, com `Optional`.
+
+Aqui vai uma dica do meu ponto de vista bem subjetivo:
+
+* 🚨 Evite usar `Optional[SomeType]`
+* Em vez disso ✨ use **`Union[SomeType, None]`** ✨.
+
+Ambos são equivalentes e, por baixo, são a mesma coisa, mas eu recomendaria `Union` em vez de `Optional` porque a palavra "opcional" sugere que o valor é opcional; na verdade, significa "pode ser `None`", mesmo quando não é opcional e continua sendo obrigatório.
+
+Acho que `Union[SomeType, None]` é mais explícito quanto ao significado.
+
+É apenas uma questão de palavras e nomes. Mas essas palavras podem influenciar como você e sua equipe pensam sobre o código.
+
+Como exemplo, veja esta função:
+
+```python
+from typing import Optional
+
+
+def say_hi(name: Optional[str]):
+ print(f"Hey {name}!")
+```
+
+O parâmetro `name` é definido como `Optional[str]`, mas não é opcional; não é possível chamar a função sem o parâmetro:
+
+```Python
+say_hi() # Ah, não, isso gera um erro! 😱
+```
+
+O parâmetro `name` continua obrigatório (não é opcional) porque não tem valor padrão. Ainda assim, `name` aceita `None` como valor:
+
+```Python
+say_hi(name=None) # Isso funciona, None é válido 🎉
+```
+
+A boa notícia é que, na maioria dos casos, você poderá simplesmente usar `|` para definir uniões de tipos:
+
+```python
+def say_hi(name: str | None):
+ print(f"Hey {name}!")
+```
+
+Então, normalmente você não precisa se preocupar com nomes como `Optional` e `Union`. 😎
diff --git a/docs/pt/docs/advanced/async-tests.md b/docs/pt/docs/advanced/async-tests.md
index 953ebedd9c..2fe678adb9 100644
--- a/docs/pt/docs/advanced/async-tests.md
+++ b/docs/pt/docs/advanced/async-tests.md
@@ -32,11 +32,11 @@ Para um exemplos simples, vamos considerar uma estrutura de arquivos semelhante
O arquivo `main.py` teria:
-{* ../../docs_src/async_tests/app_a_py39/main.py *}
+{* ../../docs_src/async_tests/app_a_py310/main.py *}
O arquivo `test_main.py` teria os testes para para o arquivo `main.py`, ele poderia ficar assim:
-{* ../../docs_src/async_tests/app_a_py39/test_main.py *}
+{* ../../docs_src/async_tests/app_a_py310/test_main.py *}
## Executá-lo { #run-it }
@@ -56,7 +56,7 @@ $ pytest
O marcador `@pytest.mark.anyio` informa ao pytest que esta função de teste deve ser invocada de maneira assíncrona:
-{* ../../docs_src/async_tests/app_a_py39/test_main.py hl[7] *}
+{* ../../docs_src/async_tests/app_a_py310/test_main.py hl[7] *}
/// tip | Dica
@@ -66,7 +66,7 @@ Note que a função de teste é `async def` agora, no lugar de apenas `def` como
Então podemos criar um `AsyncClient` com a aplicação, e enviar requisições assíncronas para ela utilizando `await`.
-{* ../../docs_src/async_tests/app_a_py39/test_main.py hl[9:12] *}
+{* ../../docs_src/async_tests/app_a_py310/test_main.py hl[9:12] *}
Isso é equivalente a:
diff --git a/docs/pt/docs/advanced/behind-a-proxy.md b/docs/pt/docs/advanced/behind-a-proxy.md
index bf0d124289..1581415156 100644
--- a/docs/pt/docs/advanced/behind-a-proxy.md
+++ b/docs/pt/docs/advanced/behind-a-proxy.md
@@ -44,7 +44,7 @@ $ fastapi run --forwarded-allow-ips="*"
Por exemplo, suponha que você defina uma *operação de rota* `/items/`:
-{* ../../docs_src/behind_a_proxy/tutorial001_01_py39.py hl[6] *}
+{* ../../docs_src/behind_a_proxy/tutorial001_01_py310.py hl[6] *}
Se o cliente tentar ir para `/items`, por padrão, ele seria redirecionado para `/items/`.
@@ -91,9 +91,9 @@ O **proxy** intercepta a requisição original do cliente e adiciona os headers
Esses headers preservam informações sobre a requisição original que, de outra forma, seriam perdidas:
-* X-Forwarded-For: o endereço IP original do cliente
-* X-Forwarded-Proto: o protocolo original (`https`)
-* X-Forwarded-Host: o host original (`mysuperapp.com`)
+* **X-Forwarded-For**: o endereço IP original do cliente
+* **X-Forwarded-Proto**: o protocolo original (`https`)
+* **X-Forwarded-Host**: o host original (`mysuperapp.com`)
Quando a **CLI do FastAPI** é configurada com `--forwarded-allow-ips`, ela confia nesses headers e os utiliza, por exemplo, para gerar as URLs corretas em redirecionamentos.
@@ -115,7 +115,7 @@ Nesse caso, o path original `/app` seria servido em `/api/v1/app`.
Embora todo o seu código esteja escrito assumindo que existe apenas `/app`.
-{* ../../docs_src/behind_a_proxy/tutorial001_py39.py hl[6] *}
+{* ../../docs_src/behind_a_proxy/tutorial001_py310.py hl[6] *}
E o proxy estaria **"removendo"** o **prefixo de path** dinamicamente antes de transmitir a solicitação para o servidor da aplicação (provavelmente Uvicorn via CLI do FastAPI), mantendo sua aplicação convencida de que está sendo servida em `/app`, para que você não precise atualizar todo o seu código para incluir o prefixo `/api/v1`.
@@ -193,7 +193,7 @@ Você pode obter o `root_path` atual usado pela sua aplicação para cada solici
Aqui estamos incluindo-o na mensagem apenas para fins de demonstração.
-{* ../../docs_src/behind_a_proxy/tutorial001_py39.py hl[8] *}
+{* ../../docs_src/behind_a_proxy/tutorial001_py310.py hl[8] *}
Então, se você iniciar o Uvicorn com:
@@ -220,7 +220,7 @@ A resposta seria algo como:
Alternativamente, se você não tiver uma maneira de fornecer uma opção de linha de comando como `--root-path` ou equivalente, você pode definir o parâmetro `root_path` ao criar sua aplicação FastAPI:
-{* ../../docs_src/behind_a_proxy/tutorial002_py39.py hl[3] *}
+{* ../../docs_src/behind_a_proxy/tutorial002_py310.py hl[3] *}
Passar o `root_path` para `FastAPI` seria o equivalente a passar a opção de linha de comando `--root-path` para Uvicorn ou Hypercorn.
@@ -400,7 +400,7 @@ Se você passar uma lista personalizada de `servers` e houver um `root_path` (po
Por exemplo:
-{* ../../docs_src/behind_a_proxy/tutorial003_py39.py hl[4:7] *}
+{* ../../docs_src/behind_a_proxy/tutorial003_py310.py hl[4:7] *}
Gerará um OpenAPI schema como:
@@ -455,7 +455,7 @@ Se você não especificar o parâmetro `servers` e `root_path` for igual a `/`,
Se você não quiser que o **FastAPI** inclua um servidor automático usando o `root_path`, você pode usar o parâmetro `root_path_in_servers=False`:
-{* ../../docs_src/behind_a_proxy/tutorial004_py39.py hl[9] *}
+{* ../../docs_src/behind_a_proxy/tutorial004_py310.py hl[9] *}
e então ele não será incluído no OpenAPI schema.
diff --git a/docs/pt/docs/advanced/custom-response.md b/docs/pt/docs/advanced/custom-response.md
index 5f26390c28..a409f1dc85 100644
--- a/docs/pt/docs/advanced/custom-response.md
+++ b/docs/pt/docs/advanced/custom-response.md
@@ -30,7 +30,7 @@ Isso ocorre por que, por padrão, o FastAPI irá verificar cada item dentro do d
Mas se você tem certeza que o conteúdo que você está retornando é **serializável com JSON**, você pode passá-lo diretamente para a classe de resposta e evitar o trabalho extra que o FastAPI teria ao passar o conteúdo pelo `jsonable_encoder` antes de passar para a classe de resposta.
-{* ../../docs_src/custom_response/tutorial001b_py39.py hl[2,7] *}
+{* ../../docs_src/custom_response/tutorial001b_py310.py hl[2,7] *}
/// info | Informação
@@ -55,7 +55,7 @@ Para retornar uma resposta com HTML diretamente do **FastAPI**, utilize `HTMLRes
* Importe `HTMLResponse`
* Passe `HTMLResponse` como o parâmetro de `response_class` do seu *decorador de operação de rota*.
-{* ../../docs_src/custom_response/tutorial002_py39.py hl[2,7] *}
+{* ../../docs_src/custom_response/tutorial002_py310.py hl[2,7] *}
/// info | Informação
@@ -73,7 +73,7 @@ Como visto em [Retornando uma Resposta Diretamente](response-directly.md){.inter
O mesmo exemplo de antes, retornando uma `HTMLResponse`, poderia parecer com:
-{* ../../docs_src/custom_response/tutorial003_py39.py hl[2,7,19] *}
+{* ../../docs_src/custom_response/tutorial003_py310.py hl[2,7,19] *}
/// warning | Atenção
@@ -97,7 +97,7 @@ A `response_class` será usada apenas para documentar o OpenAPI da *operação d
Por exemplo, poderia ser algo como:
-{* ../../docs_src/custom_response/tutorial004_py39.py hl[7,21,23] *}
+{* ../../docs_src/custom_response/tutorial004_py310.py hl[7,21,23] *}
Neste exemplo, a função `generate_html_response()` já cria e retorna uma `Response` em vez de retornar o HTML em uma `str`.
@@ -136,7 +136,7 @@ Ela aceita os seguintes parâmetros:
O FastAPI (Starlette, na verdade) irá incluir o cabeçalho Content-Length automaticamente. Ele também irá incluir o cabeçalho Content-Type, baseado no `media_type` e acrescentando uma codificação para tipos textuais.
-{* ../../docs_src/response_directly/tutorial002_py39.py hl[1,18] *}
+{* ../../docs_src/response_directly/tutorial002_py310.py hl[1,18] *}
### `HTMLResponse` { #htmlresponse }
@@ -146,7 +146,7 @@ Usa algum texto ou sequência de bytes e retorna uma resposta HTML. Como você l
Usa algum texto ou sequência de bytes para retornar uma resposta de texto não formatado.
-{* ../../docs_src/custom_response/tutorial005_py39.py hl[2,7,9] *}
+{* ../../docs_src/custom_response/tutorial005_py310.py hl[2,7,9] *}
### `JSONResponse` { #jsonresponse }
@@ -180,7 +180,7 @@ Essa resposta requer a instalação do pacote `ujson`, com o comando `pip instal
///
-{* ../../docs_src/custom_response/tutorial001_py39.py hl[2,7] *}
+{* ../../docs_src/custom_response/tutorial001_py310.py hl[2,7] *}
/// tip | Dica
@@ -194,13 +194,13 @@ Retorna um redirecionamento HTTP. Utiliza o código de status 307 (Redirecioname
Você pode retornar uma `RedirectResponse` diretamente:
-{* ../../docs_src/custom_response/tutorial006_py39.py hl[2,9] *}
+{* ../../docs_src/custom_response/tutorial006_py310.py hl[2,9] *}
---
Ou você pode utilizá-la no parâmetro `response_class`:
-{* ../../docs_src/custom_response/tutorial006b_py39.py hl[2,7,9] *}
+{* ../../docs_src/custom_response/tutorial006b_py310.py hl[2,7,9] *}
Se você fizer isso, então você pode retornar a URL diretamente da sua *função de operação de rota*
@@ -210,13 +210,13 @@ Neste caso, o `status_code` utilizada será o padrão de `RedirectResponse`, que
Você também pode utilizar o parâmetro `status_code` combinado com o parâmetro `response_class`:
-{* ../../docs_src/custom_response/tutorial006c_py39.py hl[2,7,9] *}
+{* ../../docs_src/custom_response/tutorial006c_py310.py hl[2,7,9] *}
### `StreamingResponse` { #streamingresponse }
Recebe um gerador assíncrono ou um gerador/iterador comum e retorna o corpo da resposta de forma contínua (stream).
-{* ../../docs_src/custom_response/tutorial007_py39.py hl[2,14] *}
+{* ../../docs_src/custom_response/tutorial007_py310.py hl[2,14] *}
#### Utilizando `StreamingResponse` com objetos semelhantes a arquivos { #using-streamingresponse-with-file-like-objects }
@@ -226,7 +226,7 @@ Dessa forma, você não precisa ler todo o arquivo na memória primeiro, e você
Isso inclui muitas bibliotecas que interagem com armazenamento em nuvem, processamento de vídeos, entre outras.
-{* ../../docs_src/custom_response/tutorial008_py39.py hl[2,10:12,14] *}
+{* ../../docs_src/custom_response/tutorial008_py310.py hl[2,10:12,14] *}
1. Essa é a função geradora. É definida como "função geradora" porque contém declarações `yield` nela.
2. Ao utilizar o bloco `with`, nós garantimos que o objeto semelhante a um arquivo é fechado após a função geradora ser finalizada. Isto é, após a resposta terminar de ser enviada.
@@ -255,11 +255,11 @@ Recebe um conjunto de argumentos do construtor diferente dos outros tipos de res
Respostas de Arquivos incluem o tamanho do arquivo, data da última modificação e ETags apropriados, nos cabeçalhos `Content-Length`, `Last-Modified` e `ETag`, respectivamente.
-{* ../../docs_src/custom_response/tutorial009_py39.py hl[2,10] *}
+{* ../../docs_src/custom_response/tutorial009_py310.py hl[2,10] *}
Você também pode usar o parâmetro `response_class`:
-{* ../../docs_src/custom_response/tutorial009b_py39.py hl[2,8,10] *}
+{* ../../docs_src/custom_response/tutorial009b_py310.py hl[2,8,10] *}
Nesse caso, você pode retornar o caminho do arquivo diretamente da sua *função de operação de rota*.
@@ -273,7 +273,7 @@ Vamos supor também que você queira retornar um JSON indentado e formatado, ent
Você poderia criar uma classe `CustomORJSONResponse`. A principal coisa a ser feita é sobrecarregar o método render da classe Response, `Response.render(content)`, que retorna o conteúdo em bytes:
-{* ../../docs_src/custom_response/tutorial009c_py39.py hl[9:14,17] *}
+{* ../../docs_src/custom_response/tutorial009c_py310.py hl[9:14,17] *}
Agora em vez de retornar:
@@ -299,7 +299,7 @@ O padrão que define isso é o `default_response_class`.
No exemplo abaixo, o **FastAPI** irá utilizar `ORJSONResponse` por padrão, em todas as *operações de rota*, em vez de `JSONResponse`.
-{* ../../docs_src/custom_response/tutorial010_py39.py hl[2,4] *}
+{* ../../docs_src/custom_response/tutorial010_py310.py hl[2,4] *}
/// tip | Dica
diff --git a/docs/pt/docs/advanced/dataclasses.md b/docs/pt/docs/advanced/dataclasses.md
index 6dc9feb299..c2af6fac6d 100644
--- a/docs/pt/docs/advanced/dataclasses.md
+++ b/docs/pt/docs/advanced/dataclasses.md
@@ -64,7 +64,7 @@ Nesse caso, você pode simplesmente trocar as `dataclasses` padrão por `pydanti
6. Aqui estamos retornando um dicionário que contém `items`, que é uma lista de dataclasses.
- O FastAPI ainda é capaz de serializar os dados para JSON.
+ O FastAPI ainda é capaz de serializar os dados para JSON.
7. Aqui o `response_model` está usando uma anotação de tipo de uma lista de dataclasses `Author`.
diff --git a/docs/pt/docs/advanced/events.md b/docs/pt/docs/advanced/events.md
index 8cdc358289..551053508d 100644
--- a/docs/pt/docs/advanced/events.md
+++ b/docs/pt/docs/advanced/events.md
@@ -6,13 +6,13 @@ Da mesma forma, você pode definir a lógica (código) que deve ser executada qu
Como esse código é executado antes de a aplicação **começar** a receber requisições e logo depois que ela **termina** de lidar com as requisições, ele cobre todo o **lifespan** da aplicação (a palavra "lifespan" será importante em um segundo 😉).
-Isso pode ser muito útil para configurar **recursos** que você precisa usar por toda a aplicação, e que são **compartilhados** entre as requisições e/ou que você precisa **limpar** depois. Por exemplo, um pool de conexões com o banco de dados ou o carregamento de um modelo de machine learning compartilhado.
+Isso pode ser muito útil para configurar **recursos** que você precisa usar por toda a aplicação, e que são **compartilhados** entre as requisições e/ou que você precisa **limpar** depois. Por exemplo, um pool de conexões com o banco de dados ou o carregamento de um modelo de Aprendizado de Máquina compartilhado.
## Caso de uso { #use-case }
Vamos começar com um exemplo de **caso de uso** e então ver como resolvê-lo com isso.
-Vamos imaginar que você tem alguns **modelos de machine learning** que deseja usar para lidar com as requisições. 🤖
+Vamos imaginar que você tem alguns **modelos de Aprendizado de Máquina** que deseja usar para lidar com as requisições. 🤖
Os mesmos modelos são compartilhados entre as requisições, então não é um modelo por requisição, ou um por usuário, ou algo parecido.
@@ -30,9 +30,9 @@ Vamos começar com um exemplo e depois ver em detalhes.
Nós criamos uma função assíncrona `lifespan()` com `yield` assim:
-{* ../../docs_src/events/tutorial003_py39.py hl[16,19] *}
+{* ../../docs_src/events/tutorial003_py310.py hl[16,19] *}
-Aqui estamos simulando a operação de *inicialização* custosa de carregar o modelo, colocando a (falsa) função do modelo no dicionário com modelos de machine learning antes do `yield`. Esse código será executado **antes** de a aplicação **começar a receber requisições**, durante a *inicialização*.
+Aqui estamos simulando a operação de *inicialização* custosa de carregar o modelo, colocando a (falsa) função do modelo no dicionário com modelos de Aprendizado de Máquina antes do `yield`. Esse código será executado **antes** de a aplicação **começar a receber requisições**, durante a *inicialização*.
E então, logo após o `yield`, descarregamos o modelo. Esse código será executado **depois** de a aplicação **terminar de lidar com as requisições**, pouco antes do *encerramento*. Isso poderia, por exemplo, liberar recursos como memória ou uma GPU.
@@ -48,7 +48,7 @@ Talvez você precise iniciar uma nova versão, ou apenas cansou de executá-la.
A primeira coisa a notar é que estamos definindo uma função assíncrona com `yield`. Isso é muito semelhante a Dependências com `yield`.
-{* ../../docs_src/events/tutorial003_py39.py hl[14:19] *}
+{* ../../docs_src/events/tutorial003_py310.py hl[14:19] *}
A primeira parte da função, antes do `yield`, será executada **antes** de a aplicação iniciar.
@@ -60,7 +60,7 @@ Se você verificar, a função está decorada com um `@asynccontextmanager`.
Isso converte a função em algo chamado "**gerenciador de contexto assíncrono**".
-{* ../../docs_src/events/tutorial003_py39.py hl[1,13] *}
+{* ../../docs_src/events/tutorial003_py310.py hl[1,13] *}
Um **gerenciador de contexto** em Python é algo que você pode usar em uma declaração `with`, por exemplo, `open()` pode ser usado como um gerenciador de contexto:
@@ -82,7 +82,7 @@ No nosso exemplo de código acima, não o usamos diretamente, mas passamos para
O parâmetro `lifespan` da aplicação `FastAPI` aceita um **gerenciador de contexto assíncrono**, então podemos passar para ele nosso novo gerenciador de contexto assíncrono `lifespan`.
-{* ../../docs_src/events/tutorial003_py39.py hl[22] *}
+{* ../../docs_src/events/tutorial003_py310.py hl[22] *}
## Eventos alternativos (descontinuados) { #alternative-events-deprecated }
@@ -104,7 +104,7 @@ Essas funções podem ser declaradas com `async def` ou `def` normal.
Para adicionar uma função que deve rodar antes de a aplicação iniciar, declare-a com o evento `"startup"`:
-{* ../../docs_src/events/tutorial001_py39.py hl[8] *}
+{* ../../docs_src/events/tutorial001_py310.py hl[8] *}
Nesse caso, a função de manipulador do evento `startup` inicializará os itens do "banco de dados" (apenas um `dict`) com alguns valores.
@@ -116,7 +116,7 @@ E sua aplicação não começará a receber requisições até que todos os mani
Para adicionar uma função que deve ser executada quando a aplicação estiver encerrando, declare-a com o evento `"shutdown"`:
-{* ../../docs_src/events/tutorial002_py39.py hl[6] *}
+{* ../../docs_src/events/tutorial002_py310.py hl[6] *}
Aqui, a função de manipulador do evento `shutdown` escreverá uma linha de texto `"Application shutdown"` no arquivo `log.txt`.
diff --git a/docs/pt/docs/advanced/generate-clients.md b/docs/pt/docs/advanced/generate-clients.md
index 5134bc7cb5..c6c7785a01 100644
--- a/docs/pt/docs/advanced/generate-clients.md
+++ b/docs/pt/docs/advanced/generate-clients.md
@@ -40,7 +40,7 @@ Algumas dessas soluções também podem ser open source ou oferecer planos gratu
Vamos começar com uma aplicação FastAPI simples:
-{* ../../docs_src/generate_clients/tutorial001_py39.py hl[7:9,12:13,16:17,21] *}
+{* ../../docs_src/generate_clients/tutorial001_py310.py hl[7:9,12:13,16:17,21] *}
Note que as *operações de rota* definem os modelos que usam para o corpo da requisição e o corpo da resposta, usando os modelos `Item` e `ResponseMessage`.
@@ -98,7 +98,7 @@ Em muitos casos, sua aplicação FastAPI será maior, e você provavelmente usar
Por exemplo, você poderia ter uma seção para **items** e outra seção para **users**, e elas poderiam ser separadas por tags:
-{* ../../docs_src/generate_clients/tutorial002_py39.py hl[21,26,34] *}
+{* ../../docs_src/generate_clients/tutorial002_py310.py hl[21,26,34] *}
### Gere um cliente TypeScript com Tags { #generate-a-typescript-client-with-tags }
@@ -141,11 +141,11 @@ O FastAPI usa um **ID exclusivo** para cada *operação de rota*, ele é usado p
Você pode personalizar essa função. Ela recebe uma `APIRoute` e retorna uma string.
-Por exemplo, aqui está usando a primeira tag (você provavelmente terá apenas uma tag) e o nome da *operação de rota* (o nome da função).
+Por exemplo, aqui está usando a primeira tag (Você provavelmente terá apenas uma tag) e o nome da *operação de rota* (o nome da função).
Você pode então passar essa função personalizada para o **FastAPI** como o parâmetro `generate_unique_id_function`:
-{* ../../docs_src/generate_clients/tutorial003_py39.py hl[6:7,10] *}
+{* ../../docs_src/generate_clients/tutorial003_py310.py hl[6:7,10] *}
### Gere um cliente TypeScript com IDs de operação personalizados { #generate-a-typescript-client-with-custom-operation-ids }
@@ -167,7 +167,7 @@ Mas para o cliente gerado, poderíamos **modificar** os IDs de operação do Ope
Poderíamos baixar o JSON do OpenAPI para um arquivo `openapi.json` e então poderíamos **remover essa tag prefixada** com um script como este:
-{* ../../docs_src/generate_clients/tutorial004_py39.py *}
+{* ../../docs_src/generate_clients/tutorial004_py310.py *}
//// tab | Node.js
diff --git a/docs/pt/docs/advanced/index.md b/docs/pt/docs/advanced/index.md
index 23e5510743..d2727be43f 100644
--- a/docs/pt/docs/advanced/index.md
+++ b/docs/pt/docs/advanced/index.md
@@ -8,7 +8,7 @@ Nas próximas seções você verá outras opções, configurações, e recursos
/// tip | Dica
-As próximas seções **não são necessáriamente "avançadas"**
+As próximas seções **não são necessariamente "avançadas"**.
E é possível que para seu caso de uso, a solução esteja em uma delas.
diff --git a/docs/pt/docs/advanced/middleware.md b/docs/pt/docs/advanced/middleware.md
index 30c1834790..6bc4bfd2f0 100644
--- a/docs/pt/docs/advanced/middleware.md
+++ b/docs/pt/docs/advanced/middleware.md
@@ -57,13 +57,13 @@ Garante que todas as requisições devem ser `https` ou `wss`.
Qualquer requisição para `http` ou `ws` será redirecionada para o esquema seguro.
-{* ../../docs_src/advanced_middleware/tutorial001_py39.py hl[2,6] *}
+{* ../../docs_src/advanced_middleware/tutorial001_py310.py hl[2,6] *}
## `TrustedHostMiddleware` { #trustedhostmiddleware }
Garante que todas as requisições recebidas tenham um cabeçalho `Host` corretamente configurado, a fim de proteger contra ataques de cabeçalho de host HTTP.
-{* ../../docs_src/advanced_middleware/tutorial002_py39.py hl[2,6:8] *}
+{* ../../docs_src/advanced_middleware/tutorial002_py310.py hl[2,6:8] *}
Os seguintes argumentos são suportados:
@@ -78,7 +78,7 @@ Gerencia respostas GZip para qualquer requisição que inclua `"gzip"` no cabeç
O middleware lidará com respostas padrão e de streaming.
-{* ../../docs_src/advanced_middleware/tutorial003_py39.py hl[2,6] *}
+{* ../../docs_src/advanced_middleware/tutorial003_py310.py hl[2,6] *}
Os seguintes argumentos são suportados:
@@ -91,7 +91,7 @@ Há muitos outros middlewares ASGI.
Por exemplo:
-* Uvicorn's `ProxyHeadersMiddleware`
+* `ProxyHeadersMiddleware` do Uvicorn
* MessagePack
Para checar outros middlewares disponíveis, confira Documentação de Middlewares do Starlette e a Lista Incrível do ASGI.
diff --git a/docs/pt/docs/advanced/openapi-callbacks.md b/docs/pt/docs/advanced/openapi-callbacks.md
index 57c8c5e81d..653c26d99c 100644
--- a/docs/pt/docs/advanced/openapi-callbacks.md
+++ b/docs/pt/docs/advanced/openapi-callbacks.md
@@ -106,11 +106,11 @@ Ela deve parecer exatamente como uma *operação de rota* normal do FastAPI:
Há 2 diferenças principais de uma *operação de rota* normal:
* Ela não necessita ter nenhum código real, porque seu aplicativo nunca chamará esse código. Ele é usado apenas para documentar a *API externa*. Então, a função poderia ter apenas `pass`.
-* O *path* pode conter uma expressão OpenAPI 3 (veja mais abaixo) em que pode usar variáveis com parâmetros e partes da solicitação original enviada para *sua API*.
+* O *path* pode conter uma expressão OpenAPI 3 (veja mais abaixo) em que pode usar variáveis com parâmetros e partes do request original enviado para *sua API*.
### A expressão do path do callback { #the-callback-path-expression }
-O *path* do callback pode ter uma expressão OpenAPI 3 que pode conter partes da solicitação original enviada para *sua API*.
+O *path* do callback pode ter uma expressão OpenAPI 3 que pode conter partes do request original enviado para *sua API*.
Nesse caso, é a `str`:
diff --git a/docs/pt/docs/advanced/openapi-webhooks.md b/docs/pt/docs/advanced/openapi-webhooks.md
index 011898e8cd..ed0d702b2b 100644
--- a/docs/pt/docs/advanced/openapi-webhooks.md
+++ b/docs/pt/docs/advanced/openapi-webhooks.md
@@ -32,7 +32,7 @@ Webhooks estão disponíveis a partir do OpenAPI 3.1.0, e possui suporte do Fast
Quando você cria uma aplicação com o **FastAPI**, existe um atributo chamado `webhooks`, que você utilizar para defini-los da mesma maneira que você definiria as suas **operações de rotas**, utilizando por exemplo `@app.webhooks.post()`.
-{* ../../docs_src/openapi_webhooks/tutorial001_py39.py hl[9:13,36:53] *}
+{* ../../docs_src/openapi_webhooks/tutorial001_py310.py hl[9:12,15:20] *}
Os webhooks que você define aparecerão no esquema do **OpenAPI** e na **página de documentação** gerada automaticamente.
diff --git a/docs/pt/docs/advanced/path-operation-advanced-configuration.md b/docs/pt/docs/advanced/path-operation-advanced-configuration.md
index b3af116a28..c4dd3cbe78 100644
--- a/docs/pt/docs/advanced/path-operation-advanced-configuration.md
+++ b/docs/pt/docs/advanced/path-operation-advanced-configuration.md
@@ -12,7 +12,7 @@ Você pode definir o `operationId` do OpenAPI que será utilizado na sua *opera
Você deveria ter certeza que ele é único para cada operação.
-{* ../../docs_src/path_operation_advanced_configuration/tutorial001_py39.py hl[6] *}
+{* ../../docs_src/path_operation_advanced_configuration/tutorial001_py310.py hl[6] *}
### Utilizando o nome da *função de operação de rota* como o operationId { #using-the-path-operation-function-name-as-the-operationid }
@@ -20,7 +20,7 @@ Se você quiser utilizar o nome das funções da sua API como `operationId`s, vo
Você deveria fazer isso depois de adicionar todas as suas *operações de rota*.
-{* ../../docs_src/path_operation_advanced_configuration/tutorial002_py39.py hl[2, 12:21, 24] *}
+{* ../../docs_src/path_operation_advanced_configuration/tutorial002_py310.py hl[2, 12:21, 24] *}
/// tip | Dica
@@ -40,7 +40,7 @@ Mesmo que elas estejam em módulos (arquivos Python) diferentes.
Para excluir uma *operação de rota* do esquema OpenAPI gerado (e por consequência, dos sistemas de documentação automáticos), utilize o parâmetro `include_in_schema` e defina ele como `False`:
-{* ../../docs_src/path_operation_advanced_configuration/tutorial003_py39.py hl[6] *}
+{* ../../docs_src/path_operation_advanced_configuration/tutorial003_py310.py hl[6] *}
## Descrição avançada a partir de docstring { #advanced-description-from-docstring }
@@ -92,7 +92,7 @@ Você pode estender o esquema do OpenAPI para uma *operação de rota* utilizand
Esse parâmetro `openapi_extra` pode ser útil, por exemplo, para declarar [Extensões do OpenAPI](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#specificationExtensions):
-{* ../../docs_src/path_operation_advanced_configuration/tutorial005_py39.py hl[6] *}
+{* ../../docs_src/path_operation_advanced_configuration/tutorial005_py310.py hl[6] *}
Se você abrir os documentos criados automaticamente para a API, sua extensão aparecerá no final da *operação de rota* específica.
@@ -139,9 +139,9 @@ Por exemplo, você poderia decidir ler e validar a requisição com seu próprio
Você pode fazer isso com `openapi_extra`:
-{* ../../docs_src/path_operation_advanced_configuration/tutorial006_py39.py hl[19:36, 39:40] *}
+{* ../../docs_src/path_operation_advanced_configuration/tutorial006_py310.py hl[19:36, 39:40] *}
-Nesse exemplo, nós não declaramos nenhum modelo do Pydantic. Na verdade, o corpo da requisição não está nem mesmo analisado como JSON, ele é lido diretamente como `bytes`, e a função `magic_data_reader()` seria a responsável por analisar ele de alguma forma.
+Nesse exemplo, nós não declaramos nenhum modelo do Pydantic. Na verdade, o corpo da requisição não está nem mesmo analisado como JSON, ele é lido diretamente como `bytes`, e a função `magic_data_reader()` seria a responsável por analisá-lo de alguma forma.
De toda forma, nós podemos declarar o esquema esperado para o corpo da requisição.
@@ -153,7 +153,7 @@ E você pode fazer isso até mesmo quando o tipo de dados na requisição não
Por exemplo, nesta aplicação nós não usamos a funcionalidade integrada ao FastAPI de extrair o JSON Schema dos modelos Pydantic nem a validação automática para JSON. Na verdade, estamos declarando o tipo de conteúdo da requisição como YAML, em vez de JSON:
-{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py39.py hl[15:20, 22] *}
+{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py310.py hl[15:20, 22] *}
Entretanto, mesmo que não utilizemos a funcionalidade integrada por padrão, ainda estamos usando um modelo Pydantic para gerar um JSON Schema manualmente para os dados que queremos receber em YAML.
@@ -161,7 +161,7 @@ Então utilizamos a requisição diretamente e extraímos o corpo como `bytes`.
E então no nosso código, nós analisamos o conteúdo YAML diretamente e, em seguida, estamos usando novamente o mesmo modelo Pydantic para validar o conteúdo YAML:
-{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py39.py hl[24:31] *}
+{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py310.py hl[24:31] *}
/// tip | Dica
diff --git a/docs/pt/docs/advanced/response-change-status-code.md b/docs/pt/docs/advanced/response-change-status-code.md
index ee81f0bfc8..76d9462a87 100644
--- a/docs/pt/docs/advanced/response-change-status-code.md
+++ b/docs/pt/docs/advanced/response-change-status-code.md
@@ -18,9 +18,9 @@ Para estes casos, você pode utilizar um parâmetro `Response`.
Você pode declarar um parâmetro do tipo `Response` em sua *função de operação de rota* (assim como você pode fazer para cookies e headers).
-E então você pode definir o `status_code` neste objeto de retorno temporal.
+E então você pode definir o `status_code` neste objeto de retorno *temporal*.
-{* ../../docs_src/response_change_status_code/tutorial001_py39.py hl[1,9,12] *}
+{* ../../docs_src/response_change_status_code/tutorial001_py310.py hl[1,9,12] *}
E então você pode retornar qualquer objeto que você precise, como você faria normalmente (um `dict`, um modelo de banco de dados, etc.).
diff --git a/docs/pt/docs/advanced/response-cookies.md b/docs/pt/docs/advanced/response-cookies.md
index 67820b433b..ae9660743a 100644
--- a/docs/pt/docs/advanced/response-cookies.md
+++ b/docs/pt/docs/advanced/response-cookies.md
@@ -6,7 +6,7 @@ Você pode declarar um parâmetro do tipo `Response` na sua *função de operaç
E então você pode definir cookies nesse objeto de resposta *temporário*.
-{* ../../docs_src/response_cookies/tutorial002_py39.py hl[1, 8:9] *}
+{* ../../docs_src/response_cookies/tutorial002_py310.py hl[1, 8:9] *}
Em seguida, você pode retornar qualquer objeto que precise, como normalmente faria (um `dict`, um modelo de banco de dados, etc).
@@ -24,7 +24,7 @@ Para fazer isso, você pode criar uma resposta como descrito em [Retorne uma Res
Então, defina os cookies nela e a retorne:
-{* ../../docs_src/response_cookies/tutorial001_py39.py hl[10:12] *}
+{* ../../docs_src/response_cookies/tutorial001_py310.py hl[10:12] *}
/// tip | Dica
diff --git a/docs/pt/docs/advanced/response-directly.md b/docs/pt/docs/advanced/response-directly.md
index bbbef2f913..311aba56ce 100644
--- a/docs/pt/docs/advanced/response-directly.md
+++ b/docs/pt/docs/advanced/response-directly.md
@@ -2,7 +2,7 @@
Quando você cria uma *operação de rota* no **FastAPI** você pode retornar qualquer dado nela: um dicionário (`dict`), uma lista (`list`), um modelo do Pydantic ou do seu banco de dados, etc.
-Por padrão, o **FastAPI** irá converter automaticamente o valor do retorno para JSON utilizando o `jsonable_encoder` explicado em [JSON Compatible Encoder](../tutorial/encoder.md){.internal-link target=_blank}.
+Por padrão, o **FastAPI** irá converter automaticamente o valor do retorno para JSON utilizando o `jsonable_encoder` explicado em [Codificador Compatível com JSON](../tutorial/encoder.md){.internal-link target=_blank}.
Então, por baixo dos panos, ele incluiria esses dados compatíveis com JSON (e.g. um `dict`) dentro de uma `JSONResponse` que é utilizada para enviar uma resposta para o cliente.
@@ -54,7 +54,7 @@ Vamos dizer que você quer retornar uma resposta usando o prefixo `X-`.
-Porém, se voce tiver cabeçalhos personalizados que deseja que um cliente no navegador possa ver, você precisa adicioná-los às suas configurações de CORS (saiba mais em [CORS (Cross-Origin Resource Sharing)](../tutorial/cors.md){.internal-link target=_blank}), usando o parâmetro `expose_headers` descrito na documentação de CORS do Starlette.
+Porém, se você tiver cabeçalhos personalizados que deseja que um cliente no navegador possa ver, você precisa adicioná-los às suas configurações de CORS (saiba mais em [CORS (Cross-Origin Resource Sharing)](../tutorial/cors.md){.internal-link target=_blank}), usando o parâmetro `expose_headers` descrito na documentação de CORS do Starlette.
diff --git a/docs/pt/docs/advanced/security/http-basic-auth.md b/docs/pt/docs/advanced/security/http-basic-auth.md
index bd572217b2..0ebdb1eb93 100644
--- a/docs/pt/docs/advanced/security/http-basic-auth.md
+++ b/docs/pt/docs/advanced/security/http-basic-auth.md
@@ -20,7 +20,7 @@ Então, quando você digitar o usuário e senha, o navegador os envia automatica
* Isso retorna um objeto do tipo `HTTPBasicCredentials`:
* Isto contém o `username` e o `password` enviado.
-{* ../../docs_src/security/tutorial006_an_py39.py hl[4,8,12] *}
+{* ../../docs_src/security/tutorial006_an_py310.py hl[4,8,12] *}
Quando você tentar abrir a URL pela primeira vez (ou clicar no botão "Executar" na documentação) o navegador vai pedir pelo seu usuário e senha:
@@ -40,7 +40,7 @@ Para lidar com isso, primeiramente nós convertemos o `username` e o `password`
Então nós podemos utilizar o `secrets.compare_digest()` para garantir que o `credentials.username` é `"stanleyjobson"`, e que o `credentials.password` é `"swordfish"`.
-{* ../../docs_src/security/tutorial007_an_py39.py hl[1,12:24] *}
+{* ../../docs_src/security/tutorial007_an_py310.py hl[1,12:24] *}
Isso seria parecido com:
@@ -104,4 +104,4 @@ Deste modo, ao utilizar `secrets.compare_digest()` no código de sua aplicação
Após detectar que as credenciais estão incorretas, retorne um `HTTPException` com o status 401 (o mesmo retornado quando nenhuma credencial foi informada) e adicione o cabeçalho `WWW-Authenticate` para fazer com que o navegador mostre o prompt de login novamente:
-{* ../../docs_src/security/tutorial007_an_py39.py hl[26:30] *}
+{* ../../docs_src/security/tutorial007_an_py310.py hl[26:30] *}
diff --git a/docs/pt/docs/advanced/security/oauth2-scopes.md b/docs/pt/docs/advanced/security/oauth2-scopes.md
index 591ac9b4aa..0a0c785a01 100644
--- a/docs/pt/docs/advanced/security/oauth2-scopes.md
+++ b/docs/pt/docs/advanced/security/oauth2-scopes.md
@@ -94,7 +94,7 @@ E nós retornamos os escopos como parte do token JWT.
Para manter as coisas simples, aqui nós estamos apenas adicionando os escopos recebidos diretamente ao token.
-Porém em sua aplicação, por segurança, você deve garantir que você apenas adiciona os escopos que o usuário possui permissão de fato, ou aqueles que você predefiniu.
+Porém em sua aplicação, por segurança, você deveria garantir que você apenas adiciona os escopos que o usuário possui permissão de fato, ou aqueles que você predefiniu.
///
diff --git a/docs/pt/docs/advanced/settings.md b/docs/pt/docs/advanced/settings.md
index 28411269bb..88e7f591c3 100644
--- a/docs/pt/docs/advanced/settings.md
+++ b/docs/pt/docs/advanced/settings.md
@@ -54,7 +54,7 @@ Da mesma forma que com modelos do Pydantic, você declara atributos de classe co
Você pode usar as mesmas funcionalidades e ferramentas de validação que usa em modelos do Pydantic, como diferentes tipos de dados e validações adicionais com `Field()`.
-{* ../../docs_src/settings/tutorial001_py39.py hl[2,5:8,11] *}
+{* ../../docs_src/settings/tutorial001_py310.py hl[2,5:8,11] *}
/// tip | Dica
@@ -70,7 +70,7 @@ Em seguida, ele converterá e validará os dados. Assim, quando você usar esse
Depois você pode usar o novo objeto `settings` na sua aplicação:
-{* ../../docs_src/settings/tutorial001_py39.py hl[18:20] *}
+{* ../../docs_src/settings/tutorial001_py310.py hl[18:20] *}
### Executar o servidor { #run-the-server }
@@ -104,11 +104,11 @@ Você pode colocar essas configurações em outro arquivo de módulo como visto
Por exemplo, você poderia ter um arquivo `config.py` com:
-{* ../../docs_src/settings/app01_py39/config.py *}
+{* ../../docs_src/settings/app01_py310/config.py *}
E então usá-lo em um arquivo `main.py`:
-{* ../../docs_src/settings/app01_py39/main.py hl[3,11:13] *}
+{* ../../docs_src/settings/app01_py310/main.py hl[3,11:13] *}
/// tip | Dica
@@ -126,7 +126,7 @@ Isso pode ser especialmente útil durante os testes, pois é muito fácil sobres
Vindo do exemplo anterior, seu arquivo `config.py` poderia ser assim:
-{* ../../docs_src/settings/app02_an_py39/config.py hl[10] *}
+{* ../../docs_src/settings/app02_an_py310/config.py hl[10] *}
Perceba que agora não criamos uma instância padrão `settings = Settings()`.
@@ -134,7 +134,7 @@ Perceba que agora não criamos uma instância padrão `settings = Settings()`.
Agora criamos uma dependência que retorna um novo `config.Settings()`.
-{* ../../docs_src/settings/app02_an_py39/main.py hl[6,12:13] *}
+{* ../../docs_src/settings/app02_an_py310/main.py hl[6,12:13] *}
/// tip | Dica
@@ -146,13 +146,13 @@ Por enquanto, você pode assumir que `get_settings()` é uma função normal.
E então podemos exigi-la na *função de operação de rota* como dependência e usá-la onde for necessário.
-{* ../../docs_src/settings/app02_an_py39/main.py hl[17,19:21] *}
+{* ../../docs_src/settings/app02_an_py310/main.py hl[17,19:21] *}
### Configurações e testes { #settings-and-testing }
Então seria muito fácil fornecer um objeto de configurações diferente durante os testes criando uma sobrescrita de dependência para `get_settings`:
-{* ../../docs_src/settings/app02_an_py39/test_main.py hl[9:10,13,21] *}
+{* ../../docs_src/settings/app02_an_py310/test_main.py hl[9:10,13,21] *}
Na sobrescrita da dependência definimos um novo valor para `admin_email` ao criar o novo objeto `Settings`, e então retornamos esse novo objeto.
@@ -193,7 +193,7 @@ APP_NAME="ChimichangApp"
E então atualizar seu `config.py` com:
-{* ../../docs_src/settings/app03_an_py39/config.py hl[9] *}
+{* ../../docs_src/settings/app03_an_py310/config.py hl[9] *}
/// tip | Dica
@@ -226,7 +226,7 @@ criaríamos esse objeto para cada requisição e leríamos o arquivo `.env` para
Mas como estamos usando o decorador `@lru_cache` por cima, o objeto `Settings` será criado apenas uma vez, na primeira vez em que for chamado. ✔️
-{* ../../docs_src/settings/app03_an_py39/main.py hl[1,11] *}
+{* ../../docs_src/settings/app03_an_py310/main.py hl[1,11] *}
Em qualquer chamada subsequente de `get_settings()` nas dependências das próximas requisições, em vez de executar o código interno de `get_settings()` e criar um novo objeto `Settings`, ele retornará o mesmo objeto que foi retornado na primeira chamada, repetidamente.
diff --git a/docs/pt/docs/advanced/sub-applications.md b/docs/pt/docs/advanced/sub-applications.md
index c61d1e92a0..7f176e98d9 100644
--- a/docs/pt/docs/advanced/sub-applications.md
+++ b/docs/pt/docs/advanced/sub-applications.md
@@ -10,7 +10,7 @@ Se você precisar ter duas aplicações FastAPI independentes, cada uma com seu
Primeiro, crie a aplicação principal, de nível superior, **FastAPI**, e suas *operações de rota*:
-{* ../../docs_src/sub_applications/tutorial001_py39.py hl[3, 6:8] *}
+{* ../../docs_src/sub_applications/tutorial001_py310.py hl[3, 6:8] *}
### Sub-aplicação { #sub-application }
@@ -18,7 +18,7 @@ Em seguida, crie sua sub-aplicação e suas *operações de rota*.
Essa sub-aplicação é apenas outra aplicação FastAPI padrão, mas esta é a que será "montada":
-{* ../../docs_src/sub_applications/tutorial001_py39.py hl[11, 14:16] *}
+{* ../../docs_src/sub_applications/tutorial001_py310.py hl[11, 14:16] *}
### Monte a sub-aplicação { #mount-the-sub-application }
@@ -26,7 +26,7 @@ Na sua aplicação de nível superior, `app`, monte a sub-aplicação, `subapi`.
Neste caso, ela será montada no path `/subapi`:
-{* ../../docs_src/sub_applications/tutorial001_py39.py hl[11, 19] *}
+{* ../../docs_src/sub_applications/tutorial001_py310.py hl[11, 19] *}
### Verifique a documentação automática da API { #check-the-automatic-api-docs }
diff --git a/docs/pt/docs/advanced/templates.md b/docs/pt/docs/advanced/templates.md
index eb64e72bb8..843727f4f8 100644
--- a/docs/pt/docs/advanced/templates.md
+++ b/docs/pt/docs/advanced/templates.md
@@ -27,7 +27,7 @@ $ pip install jinja2
* Declare um parâmetro `Request` no *path operation* que retornará um template.
* Use o `templates` que você criou para renderizar e retornar uma `TemplateResponse`, passe o nome do template, o objeto `request` e um dicionário "context" com pares chave-valor a serem usados dentro do template do Jinja2.
-{* ../../docs_src/templates/tutorial001_py39.py hl[4,11,15:18] *}
+{* ../../docs_src/templates/tutorial001_py310.py hl[4,11,15:18] *}
/// note | Nota
diff --git a/docs/pt/docs/advanced/testing-dependencies.md b/docs/pt/docs/advanced/testing-dependencies.md
index 52b12dddbc..f68cdc3a41 100644
--- a/docs/pt/docs/advanced/testing-dependencies.md
+++ b/docs/pt/docs/advanced/testing-dependencies.md
@@ -36,7 +36,7 @@ Você pode definir uma sobreposição de dependência para uma dependência que
A dependência original pode estar sendo utilizada em uma *função de operação de rota*, um *decorador de operação de rota* (quando você não utiliza o valor retornado), uma chamada ao `.include_router()`, etc.
-O FastAPI ainda poderá sobrescrevê-lo.
+O FastAPI ainda poderá sobrescrevê-la.
///
@@ -46,6 +46,7 @@ E então você pode redefinir as suas sobreposições (removê-las) definindo o
app.dependency_overrides = {}
```
+
/// tip | Dica
Se você quer sobrepor uma dependência apenas para alguns testes, você pode definir a sobreposição no início do teste (dentro da função de teste) e reiniciá-la ao final (no final da função de teste).
diff --git a/docs/pt/docs/advanced/testing-events.md b/docs/pt/docs/advanced/testing-events.md
index 971b437630..56c5d45c83 100644
--- a/docs/pt/docs/advanced/testing-events.md
+++ b/docs/pt/docs/advanced/testing-events.md
@@ -2,10 +2,10 @@
Quando você precisa que o `lifespan` seja executado em seus testes, você pode utilizar o `TestClient` com a instrução `with`:
-{* ../../docs_src/app_testing/tutorial004_py39.py hl[9:15,18,27:28,30:32,41:43] *}
+{* ../../docs_src/app_testing/tutorial004_py310.py hl[9:15,18,27:28,30:32,41:43] *}
Você pode ler mais detalhes sobre o ["Executando lifespan em testes no site oficial da documentação do Starlette."](https://www.starlette.dev/lifespan/#running-lifespan-in-tests)
Para os eventos `startup` e `shutdown` descontinuados, você pode usar o `TestClient` da seguinte forma:
-{* ../../docs_src/app_testing/tutorial003_py39.py hl[9:12,20:24] *}
+{* ../../docs_src/app_testing/tutorial003_py310.py hl[9:12,20:24] *}
diff --git a/docs/pt/docs/advanced/testing-websockets.md b/docs/pt/docs/advanced/testing-websockets.md
index d9d1723a64..ffb0ba3383 100644
--- a/docs/pt/docs/advanced/testing-websockets.md
+++ b/docs/pt/docs/advanced/testing-websockets.md
@@ -4,7 +4,7 @@ Você pode usar o mesmo `TestClient` para testar WebSockets.
Para isso, você utiliza o `TestClient` dentro de uma instrução `with`, conectando com o WebSocket:
-{* ../../docs_src/app_testing/tutorial002_py39.py hl[27:31] *}
+{* ../../docs_src/app_testing/tutorial002_py310.py hl[27:31] *}
/// note | Nota
diff --git a/docs/pt/docs/advanced/using-request-directly.md b/docs/pt/docs/advanced/using-request-directly.md
index ab1ef9ff4d..283a831d9a 100644
--- a/docs/pt/docs/advanced/using-request-directly.md
+++ b/docs/pt/docs/advanced/using-request-directly.md
@@ -5,7 +5,7 @@ Até agora você declarou as partes da requisição que você precisa utilizando
Obtendo dados de:
* O path como parâmetros.
-* Cabeçalhos (*Headers*).
+* Cabeçalhos.
* Cookies.
* etc.
@@ -29,7 +29,7 @@ Vamos imaginar que você deseja obter o endereço de IP/host do cliente dentro d
Para isso você precisa acessar a requisição diretamente.
-{* ../../docs_src/using_request_directly/tutorial001_py39.py hl[1,7:8] *}
+{* ../../docs_src/using_request_directly/tutorial001_py310.py hl[1,7:8] *}
Ao declarar o parâmetro com o tipo sendo um `Request` em sua *função de operação de rota*, o **FastAPI** saberá como passar o `Request` neste parâmetro.
diff --git a/docs/pt/docs/advanced/websockets.md b/docs/pt/docs/advanced/websockets.md
index 021a73bed3..c294b7603e 100644
--- a/docs/pt/docs/advanced/websockets.md
+++ b/docs/pt/docs/advanced/websockets.md
@@ -38,13 +38,13 @@ Na produção, você teria uma das opções acima.
Mas é a maneira mais simples de focar no lado do servidor de WebSockets e ter um exemplo funcional:
-{* ../../docs_src/websockets/tutorial001_py39.py hl[2,6:38,41:43] *}
+{* ../../docs_src/websockets/tutorial001_py310.py hl[2,6:38,41:43] *}
## Crie um `websocket` { #create-a-websocket }
Em sua aplicação **FastAPI**, crie um `websocket`:
-{* ../../docs_src/websockets/tutorial001_py39.py hl[1,46:47] *}
+{* ../../docs_src/websockets/tutorial001_py310.py hl[1,46:47] *}
/// note | Detalhes Técnicos
@@ -58,7 +58,7 @@ A **FastAPI** fornece o mesmo `WebSocket` diretamente apenas como uma conveniên
Em sua rota WebSocket você pode esperar (`await`) por mensagens e enviar mensagens.
-{* ../../docs_src/websockets/tutorial001_py39.py hl[48:52] *}
+{* ../../docs_src/websockets/tutorial001_py310.py hl[48:52] *}
Você pode receber e enviar dados binários, de texto e JSON.
@@ -154,7 +154,7 @@ Com isso você pode conectar o WebSocket e então enviar e receber mensagens:
Quando uma conexão WebSocket é fechada, o `await websocket.receive_text()` levantará uma exceção `WebSocketDisconnect`, que você pode então capturar e lidar como neste exemplo.
-{* ../../docs_src/websockets/tutorial003_py39.py hl[79:81] *}
+{* ../../docs_src/websockets/tutorial003_py310.py hl[79:81] *}
Para testar:
diff --git a/docs/pt/docs/advanced/wsgi.md b/docs/pt/docs/advanced/wsgi.md
index 99b783cdbe..3178b85eb0 100644
--- a/docs/pt/docs/advanced/wsgi.md
+++ b/docs/pt/docs/advanced/wsgi.md
@@ -18,7 +18,7 @@ Em seguida, encapsule a aplicação WSGI (e.g. Flask) com o middleware.
E então monte isso sob um path.
-{* ../../docs_src/wsgi/tutorial001_py39.py hl[1,3,23] *}
+{* ../../docs_src/wsgi/tutorial001_py310.py hl[1,3,23] *}
/// note | Nota
diff --git a/docs/pt/docs/alternatives.md b/docs/pt/docs/alternatives.md
index fd992ec951..17ef260dd4 100644
--- a/docs/pt/docs/alternatives.md
+++ b/docs/pt/docs/alternatives.md
@@ -20,7 +20,7 @@ Mas em algum momento, não havia outra opção senão criar algo que fornecesse
É relativamente bem acoplado com bancos de dados relacionais (como MySQL ou PostgreSQL), então, ter um banco de dados NoSQL (como Couchbase, MongoDB, Cassandra, etc.) como mecanismo principal de armazenamento não é muito fácil.
-Foi criado para gerar o HTML no backend, não para criar APIs usadas por um frontend moderno (como React, Vue.js e Angular) ou por outros sistemas (como dispositivos IoT) comunicando com ele.
+Foi criado para gerar o HTML no backend, não para criar APIs usadas por um frontend moderno (como React, Vue.js e Angular) ou por outros sistemas (como dispositivos IoT) comunicando com ele.
### Django REST Framework { #django-rest-framework }
@@ -137,7 +137,7 @@ Existem vários Flask REST frameworks, mas depois de investir tempo e trabalho i
### Marshmallow { #marshmallow }
-Uma das principais funcionalidades necessárias em sistemas de API é a "serialização" de dados, que é pegar dados do código (Python) e convertê-los em algo que possa ser enviado pela rede. Por exemplo, converter um objeto contendo dados de um banco de dados em um objeto JSON. Converter objetos `datetime` em strings, etc.
+Uma das principais funcionalidades necessárias em sistemas de API é a "serialização" de dados, que é pegar dados do código (Python) e convertê-los em algo que possa ser enviado pela rede. Por exemplo, converter um objeto contendo dados de um banco de dados em um objeto JSON. Converter objetos `datetime` em strings, etc.
Outra grande funcionalidade necessária pelas APIs é a validação de dados, garantindo que os dados são válidos, dados certos parâmetros. Por exemplo, que algum campo seja `int`, e não alguma string aleatória. Isso é especialmente útil para dados de entrada.
@@ -145,7 +145,7 @@ Sem um sistema de validação de dados, você teria que realizar todas as verifi
Essas funcionalidades são o que o Marshmallow foi construído para fornecer. É uma ótima biblioteca, e eu a utilizei bastante antes.
-Mas ele foi criado antes de existirem as anotações de tipo do Python. Então, para definir cada schema você precisa utilizar utilitários e classes específicos fornecidos pelo Marshmallow.
+Mas ele foi criado antes de existirem as anotações de tipo do Python. Então, para definir cada schema você precisa utilizar utilitários e classes específicos fornecidos pelo Marshmallow.
/// check | **FastAPI** inspirado para
@@ -155,7 +155,7 @@ Usar código para definir "schemas" que forneçam, automaticamente, tipos de dad
### Webargs { #webargs }
-Outra grande funcionalidade requerida pelas APIs é o parsing de dados vindos de requisições de entrada.
+Outra grande funcionalidade requerida pelas APIs é o parsing de dados vindos de requisições de entrada.
Webargs é uma ferramenta feita para fornecer isso no topo de vários frameworks, inclusive Flask.
@@ -419,7 +419,7 @@ Controlar toda a validação de dados, serialização de dados e documentação
### Starlette { #starlette }
-Starlette é um framework/caixa de ferramentas ASGI leve, o que é ideal para construir serviços asyncio de alta performance.
+Starlette é um framework/caixa de ferramentas ASGI leve, o que é ideal para construir serviços asyncio de alta performance.
Ele é muito simples e intuitivo. É projetado para ser facilmente extensível, e ter componentes modulares.
diff --git a/docs/pt/docs/benchmarks.md b/docs/pt/docs/benchmarks.md
index c0b0c4c466..a54df3d9d5 100644
--- a/docs/pt/docs/benchmarks.md
+++ b/docs/pt/docs/benchmarks.md
@@ -29,6 +29,6 @@ A hierarquia segue assim:
* **FastAPI**:
* Do mesmo modo que Starlette utiliza Uvicorn e não pode ser mais rápido que ele, **FastAPI** utiliza o Starlette, então não tem como ser mais rápido do que o Starlette.
* FastAPI fornece mais recursos acima do Starlette. Recursos que você quase sempre precisará quando construir APIs, como validação de dados e serialização. E utilizando eles, você terá uma documentação automática de graça (a documentação automática nem sequer adiciona peso para rodar as aplicações, ela é gerada na inicialização).
- * Se você nunca utilizou FastAPI mas utilizou diretamente o Starlette (ou outra ferramenta, como Sanic, Flask, Responder, etc) você teria que implementar toda validação de dados e serialização por conta. Então, sua aplicação final poderia ainda ter a mesma sobrecarga como se fosse desenvolvida com FastAPI. Em muitos casos, a validação de dados e serialização é o maior pedaço de código escrito em aplicações.
+ * Se você não utilizasse o FastAPI e utilizasse diretamente o Starlette (ou outra ferramenta, como Sanic, Flask, Responder, etc), você teria que implementar toda a validação de dados e serialização por conta. Então, sua aplicação final poderia ainda ter a mesma sobrecarga como se fosse desenvolvida com FastAPI. Em muitos casos, a validação de dados e serialização é o maior pedaço de código escrito em aplicações.
* Então, ao utilizar o FastAPI você estará economizando tempo de desenvolvimento, evitará _bugs_, linhas de código, e você provavelmente terá a mesma performance (ou melhor) do que não utilizá-lo (já que você teria que implementar tudo isso em seu código).
* Se você quer fazer comparações com o FastAPI, compare com um _framework_ (ou conjunto de ferramentas) para aplicações _web_ que forneça validação de dados, serialização e documentação, como Flask-apispec, NestJS, Molten, etc. _Frameworks_ com validação de dados automática, serialização e documentação integradas.
diff --git a/docs/pt/docs/deployment/cloud.md b/docs/pt/docs/deployment/cloud.md
index 419fd76265..2e181146ba 100644
--- a/docs/pt/docs/deployment/cloud.md
+++ b/docs/pt/docs/deployment/cloud.md
@@ -1,6 +1,6 @@
# Implantar FastAPI em provedores de nuvem { #deploy-fastapi-on-cloud-providers }
-Você pode usar praticamente **qualquer provedor de nuvem** para implantar seu aplicativo FastAPI.
+Você pode usar praticamente **qualquer provedor de nuvem** para implantar sua aplicação FastAPI.
Na maioria dos casos, os principais provedores de nuvem têm tutoriais para implantar o FastAPI com eles.
diff --git a/docs/pt/docs/deployment/docker.md b/docs/pt/docs/deployment/docker.md
index d47a153946..4663e96a11 100644
--- a/docs/pt/docs/deployment/docker.md
+++ b/docs/pt/docs/deployment/docker.md
@@ -14,7 +14,7 @@ Está com pressa e já sabe dessas coisas? Pode ir direto para o [`Dockerfile` a
Visualização do Dockerfile 👀
```Dockerfile
-FROM python:3.9
+FROM python:3.14
WORKDIR /code
@@ -166,7 +166,7 @@ Agora, no mesmo diretório do projeto, crie um arquivo `Dockerfile` com:
```{ .dockerfile .annotate }
# (1)!
-FROM python:3.9
+FROM python:3.14
# (2)!
WORKDIR /code
@@ -390,7 +390,7 @@ Se seu FastAPI for um único arquivo, por exemplo, `main.py` sem um diretório `
Então você só teria que alterar os caminhos correspondentes para copiar o arquivo dentro do `Dockerfile`:
```{ .dockerfile .annotate hl_lines="10 13" }
-FROM python:3.9
+FROM python:3.14
WORKDIR /code
@@ -454,7 +454,7 @@ Sem usar contêineres, fazer aplicativos executarem na inicialização e com rei
## Replicação - Número de Processos { #replication-number-of-processes }
-Se você tiver um cluster de máquinas com **Kubernetes**, Docker Swarm Mode, Nomad ou outro sistema complexo semelhante para gerenciar contêineres distribuídos em várias máquinas, então provavelmente desejará **lidar com a replicação** no **nível do cluster** em vez de usar um **gerenciador de processos** (como Uvicorn com workers) em cada contêiner.
+Se você tiver um cluster de máquinas com **Kubernetes**, Docker Swarm Mode, Nomad ou outro sistema complexo semelhante para gerenciar contêineres distribuídos em várias máquinas, então provavelmente desejará **lidar com a replicação** no **nível do cluster** em vez de usar um **gerenciador de processos** (como Uvicorn com workers) em cada contêiner.
Um desses sistemas de gerenciamento de contêineres distribuídos como o Kubernetes normalmente tem alguma maneira integrada de lidar com a **replicação de contêineres** enquanto ainda oferece **balanceamento de carga** para as solicitações recebidas. Tudo no **nível do cluster**.
@@ -499,7 +499,7 @@ Claro, existem **casos especiais** em que você pode querer ter **um contêiner*
Nesses casos, você pode usar a opção de linha de comando `--workers` para definir o número de workers que deseja executar:
```{ .dockerfile .annotate }
-FROM python:3.9
+FROM python:3.14
WORKDIR /code
@@ -570,7 +570,7 @@ Se você tiver uma configuração simples, com um **único contêiner** que ent
### Imagem Docker base { #base-docker-image }
-Antes havia uma imagem oficial do FastAPI para Docker: tiangolo/uvicorn-gunicorn-fastapi-docker. Mas agora ela está descontinuada. ⛔️
+Antes havia uma imagem oficial do FastAPI para Docker: tiangolo/uvicorn-gunicorn-fastapi. Mas agora ela está descontinuada. ⛔️
Você provavelmente **não** deve usar essa imagem base do Docker (ou qualquer outra semelhante).
diff --git a/docs/pt/docs/deployment/https.md b/docs/pt/docs/deployment/https.md
index 6195cefab2..ccd842adbc 100644
--- a/docs/pt/docs/deployment/https.md
+++ b/docs/pt/docs/deployment/https.md
@@ -28,7 +28,7 @@ Agora, a partir de uma perspectiva do desenvolvedor, aqui estão algumas coisas
* Por padrão, isso significa que você só pode ter um certificado HTTPS por endereço IP.
* Não importa o tamanho do seu servidor ou quão pequeno cada aplicativo que você tem nele possa ser.
* No entanto, existe uma solução para isso.
-* Há uma extensão para o protocolo TLS (aquele que lida com a criptografia no nível TCP, antes do HTTP) chamada SNI.
+* Há uma extensão para o protocolo TLS (aquele que lida com a criptografia no nível TCP, antes do HTTP) chamada SNI.
* Esta extensão SNI permite que um único servidor (com um único endereço IP) tenha vários certificados HTTPS e atenda a vários domínios / aplicativos HTTPS.
* Para que isso funcione, um único componente (programa) em execução no servidor, ouvindo no endereço IP público, deve ter todos os certificados HTTPS no servidor.
* Depois de obter uma conexão segura, o protocolo de comunicação ainda é HTTP.
@@ -65,7 +65,7 @@ Aqui está um exemplo de como uma API HTTPS poderia ser estruturada, passo a pas
A etapa inicial provavelmente seria adquirir algum nome de domínio. Então, você iria configurá-lo em um servidor DNS (possivelmente no mesmo provedor em nuvem).
-Você provavelmente usaria um servidor em nuvem (máquina virtual) ou algo parecido, e ele teria um fixo Endereço IP público.
+Você provavelmente usaria um servidor em nuvem (máquina virtual) ou algo parecido, e ele teria um fixo Endereço IP público.
No(s) servidor(es) DNS, você configuraria um registro (um `A record`) para apontar seu domínio para o endereço IP público do seu servidor.
@@ -135,7 +135,7 @@ Então, o cliente envia uma solicitação HTTPS. Que é apenas uma solicitação
-### Desencriptando a Solicitação { #decrypt-the-request }
+### Desencripte a Solicitação { #decrypt-the-request }
O Proxy de Terminação TLS então usaria a encriptação combinada para desencriptar a solicitação, e transmitiria a solicitação básica (desencriptada) para o processo executando a aplicação (por exemplo, um processo com Uvicorn executando a aplicação FastAPI).
@@ -186,7 +186,7 @@ Para fazer isso, e acomodar as necessidades de diferentes aplicações, existem
* Executar como um servidor (ao menos durante o processo de aquisição do certificado) no endereço IP público associado com o domínio.
* Como dito anteriormente, apenas um processo pode estar ligado a uma porta e IP específicos.
* Essa é uma dos motivos que fazem utilizar o mesmo Proxy de Terminação TLS para gerenciar a renovação de certificados ser tão útil.
- * Caso contrário, você pode ter que parar a execução do Proxy de Terminação TLS momentaneamente, inicializar o programa de renovação para renovar os certificados, e então reiniciar o Proxy de Terminação TLS. Isso não é o ideal, já que sua(s) aplicação(ões) não vão estar disponíveis enquanto o Proxy de Terminação TLS estiver desligado.
+ * Caso contrário, você pode ter que parar a execução do Proxy de Terminação TLS momentaneamente, inicializar o programa de renovação para adquirir os certificados, depois configurá-los com o Proxy de Terminação TLS, e então reiniciar o Proxy de Terminação TLS. Isso não é o ideal, já que sua(s) aplicação(ões) não vão estar disponíveis enquanto o Proxy de Terminação TLS estiver desligado.
Todo esse processo de renovação, enquanto o aplicativo ainda funciona, é uma das principais razões para preferir um sistema separado para gerenciar HTTPS com um Proxy de Terminação TLS em vez de usar os certificados TLS no servidor da aplicação diretamente (e.g. com o Uvicorn).
diff --git a/docs/pt/docs/deployment/index.md b/docs/pt/docs/deployment/index.md
index 6a6c21804d..d9755d0a2b 100644
--- a/docs/pt/docs/deployment/index.md
+++ b/docs/pt/docs/deployment/index.md
@@ -4,7 +4,7 @@ Implantar uma aplicação **FastAPI** é relativamente fácil.
## O que significa Implantação { #what-does-deployment-mean }
-Implantar uma aplicação significa executar as etapas necessárias para torná-la disponível para os usuários.
+**Implantar** uma aplicação significa executar as etapas necessárias para torná-la **disponível para os usuários**.
Para uma **web API**, isso normalmente envolve colocá-la em uma **máquina remota**, com um **programa de servidor** que ofereça bom desempenho, estabilidade, etc., de modo que seus **usuários** possam **acessar** a aplicação com eficiência e sem interrupções ou problemas.
diff --git a/docs/pt/docs/deployment/manually.md b/docs/pt/docs/deployment/manually.md
index 21d0f44cdf..da3a52cf3a 100644
--- a/docs/pt/docs/deployment/manually.md
+++ b/docs/pt/docs/deployment/manually.md
@@ -46,7 +46,7 @@ Você pode utilizar esse comando, por exemplo, para iniciar sua aplicação **Fa
Vamos nos aprofundar um pouco mais em detalhes.
-FastAPI utiliza um padrão para construir frameworks e servidores web em Python chamado ASGI. FastAPI é um framework web ASGI.
+FastAPI utiliza um padrão para construir frameworks e servidores web em Python chamado ASGI. FastAPI é um framework web ASGI.
A principal coisa que você precisa para executar uma aplicação **FastAPI** (ou qualquer outra aplicação ASGI) em uma máquina de servidor remoto é um programa de servidor ASGI como o **Uvicorn**, que é o que vem por padrão no comando `fastapi`.
diff --git a/docs/pt/docs/deployment/versions.md b/docs/pt/docs/deployment/versions.md
index a2aca5a17e..32676da236 100644
--- a/docs/pt/docs/deployment/versions.md
+++ b/docs/pt/docs/deployment/versions.md
@@ -64,9 +64,9 @@ O "MINOR" é o número do meio, por exemplo, em `0.2.3`, a versão MINOR é `2`.
## Atualizando as versões do FastAPI { #upgrading-the-fastapi-versions }
-Você deve adicionar testes para a sua aplicação.
+Você deveria adicionar testes para a sua aplicação.
-Com **FastAPI** isso é muito fácil (graças ao Starlette), veja a documentação: [Testing](../tutorial/testing.md){.internal-link target=_blank}
+Com **FastAPI** isso é muito fácil (graças ao Starlette), veja a documentação: [Testes](../tutorial/testing.md){.internal-link target=_blank}
Depois que você tiver testes, você pode atualizar a sua versão do **FastAPI** para uma mais recente e se certificar de que todo o seu código está funcionando corretamente executando seus testes.
diff --git a/docs/pt/docs/fastapi-cli.md b/docs/pt/docs/fastapi-cli.md
index 0bd7bcd21e..f1e633a236 100644
--- a/docs/pt/docs/fastapi-cli.md
+++ b/docs/pt/docs/fastapi-cli.md
@@ -58,7 +58,7 @@ Internamente, o **FastAPI CLI** usa o OpenAPI para criação de APIs, incluindo declarações de caminho operações, parâmetros, requisições de corpo, segurança etc.
+* OpenAPI para criação de APIs, incluindo declarações de caminho operações, parâmetros, requisições de corpo, segurança etc.
* Modelo de documentação automática com JSON Schema (já que o OpenAPI em si é baseado no JSON Schema).
* Projetado em cima desses padrões após um estudo meticuloso, em vez de uma reflexão breve.
* Isso também permite o uso de **geração de código do cliente** automaticamente em muitas linguagens.
@@ -136,7 +136,7 @@ Tudo construído como ferramentas e componentes reutilizáveis que são fáceis
### Injeção de dependência { #dependency-injection }
-FastAPI inclui um sistema de injeção de dependência extremamente fácil de usar, mas extremamente poderoso.
+FastAPI inclui um sistema de injeção de dependência extremamente fácil de usar, mas extremamente poderoso.
* Mesmo dependências podem ter dependências, criando uma hierarquia ou **"grafo" de dependências**.
* Tudo **automaticamente controlado** pelo framework.
@@ -153,8 +153,8 @@ Qualquer integração é projetada para ser tão simples de usar (com dependênc
### Testado { #tested }
-* 100% de cobertura de testes.
-* 100% do código com anotações de tipo.
+* 100% de cobertura de testes.
+* 100% do código com anotações de tipo.
* Usado para aplicações em produção.
## Recursos do Starlette { #starlette-features }
@@ -179,7 +179,7 @@ Com **FastAPI**, você terá todos os recursos do **Starlette** (já que FastAPI
**FastAPI** é totalmente compatível com (e baseado no) Pydantic. Então, qualquer código Pydantic adicional que você tiver, também funcionará.
-Incluindo bibliotecas externas também baseadas no Pydantic, como ORMs e ODMs para bancos de dados.
+Incluindo bibliotecas externas também baseadas no Pydantic, como ORMs e ODMs para bancos de dados.
Isso também significa que em muitos casos você poderá passar o mesmo objeto que você receber de uma requisição **diretamente para o banco de dados**, já que tudo é validado automaticamente.
@@ -190,7 +190,7 @@ Com **FastAPI** você terá todos os recursos do **Pydantic** (já que FastAPI u
* **Sem pegadinhas**:
* Sem novas definições de esquema de micro-linguagem para aprender.
* Se você conhece os tipos do Python, você sabe como usar o Pydantic.
-* Vai bem com o/a seu/sua **IDE/linter/cérebro**:
+* Vai bem com o/a seu/sua **IDE/linter/cérebro**:
* Como as estruturas de dados do Pydantic são apenas instâncias de classes que você define, o preenchimento automático, linting, mypy e a sua intuição devem funcionar corretamente com seus dados validados.
* Valida **estruturas complexas**:
* Use modelos hierárquicos do Pydantic, `List` e `Dict` do `typing` do Python, etc.
diff --git a/docs/pt/docs/history-design-future.md b/docs/pt/docs/history-design-future.md
index 6995287391..fb90d1e1c3 100644
--- a/docs/pt/docs/history-design-future.md
+++ b/docs/pt/docs/history-design-future.md
@@ -24,7 +24,7 @@ Há muitas ferramentas criadas antes que ajudaram a inspirar sua criação.
Eu estive evitando a criação de um novo _framework_ por vários anos. Primeiro tentei resolver todas as funcionalidades cobertas por **FastAPI** usando muitos _frameworks_, _plug-ins_ e ferramentas diferentes.
-Mas em algum ponto, não havia outra opção senão criar algo que oferecia todas as funcionalidades, aproveitando as melhores ideias de ferramentas anteriores, e combinando-as da melhor maneira possível, usando funcionalidades da linguagem que nem estavam disponíveis antes (_type hints_ do Python 3.6+).
+Mas em algum ponto, não havia outra opção senão criar algo que oferecia todas as funcionalidades, aproveitando as melhores ideias de ferramentas anteriores, e combinando-as da melhor maneira possível, usando funcionalidades da linguagem que nem estavam disponíveis antes (anotações de tipo do Python 3.6+).
@@ -32,7 +32,7 @@ Mas em algum ponto, não havia outra opção senão criar algo que oferecia toda
Ao usar todas as alternativas anteriores, eu tive a chance de aprender com todas elas, aproveitar ideias e combiná-las da melhor maneira que encontrei para mim e para os times de desenvolvedores com os quais trabalhava.
-Por exemplo, estava claro que idealmente ele deveria ser baseado nos _type hints_ padrões do Python.
+Por exemplo, estava claro que idealmente ele deveria ser baseado nas anotações de tipo padrão do Python.
Também, a melhor abordagem era usar padrões já existentes.
diff --git a/docs/pt/docs/how-to/authentication-error-status-code.md b/docs/pt/docs/how-to/authentication-error-status-code.md
index 878a1ca1ac..40790f180d 100644
--- a/docs/pt/docs/how-to/authentication-error-status-code.md
+++ b/docs/pt/docs/how-to/authentication-error-status-code.md
@@ -8,7 +8,7 @@ Mas, se por algum motivo seus clientes dependem do comportamento antigo, você p
Por exemplo, você pode criar uma subclasse de `HTTPBearer` que retorne um erro `403 Forbidden` em vez do erro padrão `401 Unauthorized`:
-{* ../../docs_src/authentication_error_status_code/tutorial001_an_py39.py hl[9:13] *}
+{* ../../docs_src/authentication_error_status_code/tutorial001_an_py310.py hl[9:13] *}
/// tip | Dica
diff --git a/docs/pt/docs/how-to/conditional-openapi.md b/docs/pt/docs/how-to/conditional-openapi.md
index b475dae6d6..b77600a7bc 100644
--- a/docs/pt/docs/how-to/conditional-openapi.md
+++ b/docs/pt/docs/how-to/conditional-openapi.md
@@ -29,13 +29,13 @@ Você pode usar facilmente as mesmas configurações do Pydantic para configurar
Por exemplo:
-{* ../../docs_src/conditional_openapi/tutorial001_py39.py hl[6,11] *}
+{* ../../docs_src/conditional_openapi/tutorial001_py310.py hl[6,11] *}
Aqui declaramos a configuração `openapi_url` com o mesmo padrão de `"/openapi.json"`.
E então a usamos ao criar a aplicação `FastAPI`.
-Então você pode desabilitar o OpenAPI (incluindo a documentação da interface do usuário) definindo a variável de ambiente `OPENAPI_URL` como uma string vazia, como:
+Então você pode desabilitar o OpenAPI (incluindo a documentação da interface do usuário) definindo a variável de ambiente `OPENAPI_URL` como a string vazia, como:
diff --git a/docs/pt/docs/how-to/configure-swagger-ui.md b/docs/pt/docs/how-to/configure-swagger-ui.md
index 2d1863c64c..a8f9bed476 100644
--- a/docs/pt/docs/how-to/configure-swagger-ui.md
+++ b/docs/pt/docs/how-to/configure-swagger-ui.md
@@ -18,7 +18,7 @@ Sem alterar as configurações, o destaque de sintaxe é habilitado por padrão:
Mas você pode desabilitá-lo definindo `syntaxHighlight` como `False`:
-{* ../../docs_src/configure_swagger_ui/tutorial001_py39.py hl[3] *}
+{* ../../docs_src/configure_swagger_ui/tutorial001_py310.py hl[3] *}
...e então o Swagger UI não mostrará mais o destaque de sintaxe:
@@ -28,7 +28,7 @@ Mas você pode desabilitá-lo definindo `syntaxHighlight` como `False`:
Da mesma forma que você pode definir o tema de destaque de sintaxe com a chave `"syntaxHighlight.theme"` (observe que há um ponto no meio):
-{* ../../docs_src/configure_swagger_ui/tutorial002_py39.py hl[3] *}
+{* ../../docs_src/configure_swagger_ui/tutorial002_py310.py hl[3] *}
Essa configuração alteraria o tema de cores de destaque de sintaxe:
@@ -46,7 +46,7 @@ Você pode substituir qualquer um deles definindo um valor diferente no argument
Por exemplo, para desabilitar `deepLinking` você pode passar essas configurações para `swagger_ui_parameters`:
-{* ../../docs_src/configure_swagger_ui/tutorial003_py39.py hl[3] *}
+{* ../../docs_src/configure_swagger_ui/tutorial003_py310.py hl[3] *}
## Outros parâmetros da UI do Swagger { #other-swagger-ui-parameters }
diff --git a/docs/pt/docs/how-to/custom-docs-ui-assets.md b/docs/pt/docs/how-to/custom-docs-ui-assets.md
index adda9eca50..c7a62aefdf 100644
--- a/docs/pt/docs/how-to/custom-docs-ui-assets.md
+++ b/docs/pt/docs/how-to/custom-docs-ui-assets.md
@@ -2,13 +2,13 @@
A documentação da API usa **Swagger UI** e **ReDoc**, e cada um deles precisa de alguns arquivos JavaScript e CSS.
-Por padrão, esses arquivos são fornecidos por um
CDN.
+Por padrão, esses arquivos são fornecidos por um
CDN.
Mas é possível personalizá-los, você pode definir um CDN específico ou providenciar os arquivos você mesmo.
## CDN Personalizado para JavaScript e CSS { #custom-cdn-for-javascript-and-css }
-Vamos supor que você deseja usar um
CDN diferente, por exemplo, você deseja usar `https://unpkg.com/`.
+Vamos supor que você deseja usar um
CDN diferente, por exemplo, você deseja usar `https://unpkg.com/`.
Isso pode ser útil se, por exemplo, você mora em um país que restringe algumas URLs.
@@ -18,7 +18,7 @@ O primeiro passo é desativar a documentação automática, pois por padrão, el
Para desativá-los, defina suas URLs como `None` ao criar sua aplicação FastAPI:
-{* ../../docs_src/custom_docs_ui/tutorial001_py39.py hl[8] *}
+{* ../../docs_src/custom_docs_ui/tutorial001_py310.py hl[8] *}
### Incluir a documentação personalizada { #include-the-custom-docs }
@@ -34,7 +34,7 @@ Você pode reutilizar as funções internas do FastAPI para criar as páginas HT
E de forma semelhante para o ReDoc...
-{* ../../docs_src/custom_docs_ui/tutorial001_py39.py hl[2:6,11:19,22:24,27:33] *}
+{* ../../docs_src/custom_docs_ui/tutorial001_py310.py hl[2:6,11:19,22:24,27:33] *}
/// tip | Dica
@@ -50,7 +50,7 @@ Swagger UI lidará com isso nos bastidores para você, mas ele precisa desse aux
Agora, para poder testar se tudo funciona, crie uma *operação de rota*:
-{* ../../docs_src/custom_docs_ui/tutorial001_py39.py hl[36:38] *}
+{* ../../docs_src/custom_docs_ui/tutorial001_py310.py hl[36:38] *}
### Teste { #test-it }
@@ -118,7 +118,7 @@ Depois disso, sua estrutura de arquivos deve se parecer com:
* Importe `StaticFiles`.
* "Monte" a instância `StaticFiles()` em um caminho específico.
-{* ../../docs_src/custom_docs_ui/tutorial002_py39.py hl[7,11] *}
+{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[7,11] *}
### Teste os arquivos estáticos { #test-the-static-files }
@@ -144,7 +144,7 @@ Da mesma forma que ao usar um CDN personalizado, o primeiro passo é desativar a
Para desativá-los, defina suas URLs como `None` ao criar sua aplicação FastAPI:
-{* ../../docs_src/custom_docs_ui/tutorial002_py39.py hl[9] *}
+{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[9] *}
### Incluir a documentação personalizada para arquivos estáticos { #include-the-custom-docs-for-static-files }
@@ -160,7 +160,7 @@ Novamente, você pode reutilizar as funções internas do FastAPI para criar as
E de forma semelhante para o ReDoc...
-{* ../../docs_src/custom_docs_ui/tutorial002_py39.py hl[2:6,14:22,25:27,30:36] *}
+{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[2:6,14:22,25:27,30:36] *}
/// tip | Dica
@@ -176,7 +176,7 @@ Swagger UI lidará com isso nos bastidores para você, mas ele precisa desse aux
Agora, para poder testar se tudo funciona, crie uma *operação de rota*:
-{* ../../docs_src/custom_docs_ui/tutorial002_py39.py hl[39:41] *}
+{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[39:41] *}
### Teste a UI de Arquivos Estáticos { #test-static-files-ui }
diff --git a/docs/pt/docs/how-to/extending-openapi.md b/docs/pt/docs/how-to/extending-openapi.md
index b1b50ce654..b8277c1c4b 100644
--- a/docs/pt/docs/how-to/extending-openapi.md
+++ b/docs/pt/docs/how-to/extending-openapi.md
@@ -43,19 +43,19 @@ Por exemplo, vamos adicionar
documentação do Strawberry.
diff --git a/docs/pt/docs/how-to/index.md b/docs/pt/docs/how-to/index.md
index a3d16380fe..91df638d7a 100644
--- a/docs/pt/docs/how-to/index.md
+++ b/docs/pt/docs/how-to/index.md
@@ -2,9 +2,9 @@
Aqui você encontrará diferentes exemplos práticos ou tutoriais de "como fazer" para **vários tópicos**.
-A maioria dessas ideias será mais ou menos **independente**, e na maioria dos casos você só precisará estudá-las se elas se aplicarem diretamente ao **seu projeto**.
+A maioria dessas ideias será mais ou menos **independente**, e na maioria dos casos você deveria estudá-las apenas se elas se aplicarem diretamente ao **seu projeto**.
-Se algo parecer interessante e útil para o seu projeto, vá em frente e dê uma olhada. Caso contrário, você pode simplesmente ignorá-lo.
+Se algo parecer interessante e útil para o seu projeto, vá em frente e dê uma olhada. Caso contrário, você pode simplesmente ignorá-las.
/// tip | Dica
diff --git a/docs/pt/docs/index.md b/docs/pt/docs/index.md
index e61cc2e2f4..c337f6d3ac 100644
--- a/docs/pt/docs/index.md
+++ b/docs/pt/docs/index.md
@@ -40,7 +40,7 @@ Os recursos chave são:
* **Rápido**: alta performance, equivalente a **NodeJS** e **Go** (graças ao Starlette e Pydantic). [Um dos frameworks mais rápidos disponíveis](#performance).
* **Rápido para codar**: Aumenta a velocidade para desenvolver recursos entre 200% a 300%. *
* **Poucos bugs**: Reduz cerca de 40% de erros induzidos por humanos (desenvolvedores). *
-* **Intuitivo**: Grande suporte a editores.
Completação em todos os lugares. Menos tempo debugando.
+* **Intuitivo**: Grande suporte a editores.
Completação em todos os lugares. Menos tempo debugando.
* **Fácil**: Projetado para ser fácil de aprender e usar. Menos tempo lendo docs.
* **Enxuto**: Minimize duplicação de código. Múltiplas funcionalidades para cada declaração de parâmetro. Menos bugs.
* **Robusto**: Tenha código pronto para produção. E com documentação interativa automática.
@@ -368,7 +368,7 @@ item: Item
* Validação de dados:
* Erros automáticos e claros quando o dado é inválido.
* Validação até para objetos JSON profundamente aninhados.
-*
Conversão de dados de entrada: vindo da rede para dados e tipos Python. Consegue ler:
+*
Conversão de dados de entrada: vindo da rede para dados e tipos Python. Consegue ler:
* JSON.
* Parâmetros de path.
* Parâmetros query.
@@ -376,7 +376,7 @@ item: Item
* Cabeçalhos.
* Formulários.
* Arquivos.
-*
Conversão de dados de saída: convertendo de tipos e dados Python para dados de rede (como JSON):
+*
Conversão de dados de saída: convertendo de tipos e dados Python para dados de rede (como JSON):
* Converte tipos Python (`str`, `int`, `float`, `bool`, `list` etc).
* Objetos `datetime`.
* Objetos `UUID`.
@@ -439,7 +439,7 @@ Para um exemplo mais completo incluindo mais recursos, veja
Injeção de Dependência**.
+* Um poderoso e fácil de usar sistema de **Injeção de Dependência**.
* Segurança e autenticação, incluindo suporte para **OAuth2** com autenticação com **JWT tokens** e **HTTP Basic**.
* Técnicas mais avançadas (mas igualmente fáceis) para declaração de **modelos JSON profundamente aninhados** (graças ao Pydantic).
* Integrações **GraphQL** com o Strawberry e outras bibliotecas.
@@ -524,7 +524,7 @@ Utilizado pelo Starlette:
*
httpx - Obrigatório caso você queira utilizar o `TestClient`.
*
jinja2 - Obrigatório se você quer utilizar a configuração padrão de templates.
-*
python-multipart - Obrigatório se você deseja suporte a
"parsing" de formulário, com `request.form()`.
+*
python-multipart - Obrigatório se você deseja suporte a
"parsing" de formulário, com `request.form()`.
Utilizado pelo FastAPI:
diff --git a/docs/pt/docs/python-types.md b/docs/pt/docs/python-types.md
index fc983d1df1..bc3f47858c 100644
--- a/docs/pt/docs/python-types.md
+++ b/docs/pt/docs/python-types.md
@@ -1,14 +1,14 @@
# Introdução aos tipos Python { #python-types-intro }
-O Python possui suporte para "dicas de tipo" ou "type hints" (também chamado de "anotações de tipo" ou "type annotations")
+O Python possui suporte para "type hints" opcionais (também chamados de "type annotations").
-Esses **"type hints"** são uma sintaxe especial que permite declarar o
tipo de uma variável.
+Esses **"type hints"** ou anotações são uma sintaxe especial que permite declarar o
tipo de uma variável.
Ao declarar tipos para suas variáveis, editores e ferramentas podem oferecer um melhor suporte.
Este é apenas um **tutorial rápido / atualização** sobre type hints do Python. Ele cobre apenas o mínimo necessário para usá-los com o **FastAPI**... que é realmente muito pouco.
-O **FastAPI** é baseado nesses type hints, eles oferecem muitas vantagens e benefícios.
+O **FastAPI** é todo baseado nesses type hints, eles oferecem muitas vantagens e benefícios.
Mas mesmo que você nunca use o **FastAPI**, você se beneficiaria de aprender um pouco sobre eles.
@@ -22,7 +22,7 @@ Se você é um especialista em Python e já sabe tudo sobre type hints, pule par
Vamos começar com um exemplo simples:
-{* ../../docs_src/python_types/tutorial001_py39.py *}
+{* ../../docs_src/python_types/tutorial001_py310.py *}
A chamada deste programa gera:
@@ -34,9 +34,9 @@ A função faz o seguinte:
* Pega um `first_name` e `last_name`.
* Converte a primeira letra de cada uma em maiúsculas com `title()`.
-*
Concatena com um espaço no meio.
+*
Concatena com um espaço no meio.
-{* ../../docs_src/python_types/tutorial001_py39.py hl[2] *}
+{* ../../docs_src/python_types/tutorial001_py310.py hl[2] *}
### Edite-o { #edit-it }
@@ -52,7 +52,7 @@ Era `upper`? Era `uppercase`? `first_uppercase`? `capitalize`?
Em seguida, tente com o velho amigo do programador, o preenchimento automático do editor.
-Você digita o primeiro parâmetro da função, `first_name`, depois um ponto (`.`) e, em seguida, pressiona `Ctrl + Space` para acionar a conclusão.
+Você digita o primeiro parâmetro da função, `first_name`, depois um ponto (`.`) e, em seguida, pressiona `Ctrl+Space` para acionar o preenchimento automático.
Mas, infelizmente, você não obtém nada útil:
@@ -78,7 +78,7 @@ para:
Esses são os "type hints":
-{* ../../docs_src/python_types/tutorial002_py39.py hl[1] *}
+{* ../../docs_src/python_types/tutorial002_py310.py hl[1] *}
Isso não é o mesmo que declarar valores padrão como seria com:
@@ -88,7 +88,7 @@ Isso não é o mesmo que declarar valores padrão como seria com:
É uma coisa diferente.
-Estamos usando dois pontos (`:`), não é igual a (`=`).
+Estamos usando dois pontos (`:`), não sinal de igual (`=`).
E adicionar type hints normalmente não muda o que acontece do que aconteceria sem eles.
@@ -106,17 +106,17 @@ Com isso, você pode rolar, vendo as opções, até encontrar o que "soa familia
Verifique esta função, ela já possui type hints:
-{* ../../docs_src/python_types/tutorial003_py39.py hl[1] *}
+{* ../../docs_src/python_types/tutorial003_py310.py hl[1] *}
-Como o editor conhece os tipos de variáveis, você não obtém apenas o preenchimento automático, mas também as verificações de erro:
+Como o editor conhece os tipos das variáveis, você não obtém apenas o preenchimento automático, mas também as verificações de erro:

-Agora você sabe que precisa corrigí-lo, converta `age` em uma string com `str(age)`:
+Agora você sabe que precisa corrigi-la, convertendo `age` em uma string com `str(age)`:
-{* ../../docs_src/python_types/tutorial004_py39.py hl[2] *}
+{* ../../docs_src/python_types/tutorial004_py310.py hl[2] *}
-## Declarando Tipos { #declaring-types }
+## Declarando tipos { #declaring-types }
Você acabou de ver o local principal para declarar type hints. Como parâmetros de função.
@@ -133,29 +133,32 @@ Você pode usar, por exemplo:
* `bool`
* `bytes`
-{* ../../docs_src/python_types/tutorial005_py39.py hl[1] *}
+{* ../../docs_src/python_types/tutorial005_py310.py hl[1] *}
-### Tipos genéricos com parâmetros de tipo { #generic-types-with-type-parameters }
+### Módulo `typing` { #typing-module }
-Existem algumas estruturas de dados que podem conter outros valores, como `dict`, `list`, `set` e `tuple`. E os valores internos também podem ter seu próprio tipo.
+Para alguns casos adicionais, você pode precisar importar alguns itens do módulo padrão `typing`, por exemplo, quando quiser declarar que algo pode ter "qualquer tipo", você pode usar `Any` de `typing`:
-Estes tipos que possuem tipos internos são chamados de tipos "**genéricos**". E é possível declará-los mesmo com os seus tipos internos.
+```python
+from typing import Any
-Para declarar esses tipos e os tipos internos, você pode usar o módulo Python padrão `typing`. Ele existe especificamente para suportar esses type hints.
-#### Versões mais recentes do Python { #newer-versions-of-python }
-
-A sintaxe utilizando `typing` é **compatível** com todas as versões, desde o Python 3.6 até as últimas, incluindo o Python 3.9, 3.10, etc.
+def some_function(data: Any):
+ print(data)
+```
-Conforme o Python evolui, **novas versões** chegam com suporte melhorado para esses type annotations, e em muitos casos, você não precisará nem importar e utilizar o módulo `typing` para declarar os type annotations.
+### Tipos genéricos { #generic-types }
-Se você pode escolher uma versão mais recente do Python para o seu projeto, você poderá aproveitar isso ao seu favor.
+Alguns tipos podem receber "parâmetros de tipo" entre colchetes, para definir seus tipos internos, por exemplo, uma "lista de strings" seria declarada como `list[str]`.
-Em todos os documentos existem exemplos compatíveis com cada versão do Python (quando existem diferenças).
+Esses tipos que podem receber parâmetros de tipo são chamados **tipos genéricos** ou **genéricos**.
-Por exemplo, "**Python 3.6+**" significa que é compatível com o Python 3.6 ou superior (incluindo o 3.7, 3.8, 3.9, 3.10, etc). E "**Python 3.9+**" significa que é compatível com o Python 3.9 ou mais recente (incluindo o 3.10, etc).
+Você pode usar os mesmos tipos internos como genéricos (com colchetes e tipos dentro):
-Se você pode utilizar a **versão mais recente do Python**, utilize os exemplos para as últimas versões. Eles terão as **melhores e mais simples sintaxes**, como por exemplo, "**Python 3.10+**".
+* `list`
+* `tuple`
+* `set`
+* `dict`
#### List { #list }
@@ -167,11 +170,11 @@ Como o tipo, coloque `list`.
Como a lista é um tipo que contém tipos internos, você os coloca entre colchetes:
-{* ../../docs_src/python_types/tutorial006_py39.py hl[1] *}
+{* ../../docs_src/python_types/tutorial006_py310.py hl[1] *}
/// info | Informação
-Estes tipos internos dentro dos colchetes são chamados "parâmetros de tipo" (type parameters).
+Esses tipos internos dentro dos colchetes são chamados de "parâmetros de tipo".
Neste caso, `str` é o parâmetro de tipo passado para `list`.
@@ -193,9 +196,9 @@ E, ainda assim, o editor sabe que é um `str` e fornece suporte para isso.
Você faria o mesmo para declarar `tuple`s e `set`s:
-{* ../../docs_src/python_types/tutorial007_py39.py hl[1] *}
+{* ../../docs_src/python_types/tutorial007_py310.py hl[1] *}
-Isso significa que:
+Isso significa:
* A variável `items_t` é uma `tuple` com 3 itens, um `int`, outro `int` e uma `str`.
* A variável `items_s` é um `set`, e cada um de seus itens é do tipo `bytes`.
@@ -208,7 +211,7 @@ O primeiro parâmetro de tipo é para as chaves do `dict`.
O segundo parâmetro de tipo é para os valores do `dict`:
-{* ../../docs_src/python_types/tutorial008_py39.py hl[1] *}
+{* ../../docs_src/python_types/tutorial008_py310.py hl[1] *}
Isso significa que:
@@ -218,46 +221,22 @@ Isso significa que:
#### Union { #union }
-Você pode declarar que uma variável pode ser de qualquer um dentre **diversos tipos**. Por exemplo, um `int` ou um `str`.
-
-No Python 3.6 e superior (incluindo o Python 3.10), você pode utilizar o tipo `Union` de `typing`, e colocar dentro dos colchetes os possíveis tipos aceitáveis.
+Você pode declarar que uma variável pode ser de qualquer um dentre **vários tipos**, por exemplo, um `int` ou um `str`.
-No Python 3.10 também existe uma **nova sintaxe** onde você pode colocar os possíveis tipos separados por uma
barra vertical (`|`).
+Para defini-la, você usa a
barra vertical (`|`) para separar ambos os tipos.
-//// tab | Python 3.10+
+Isso é chamado de "união", porque a variável pode ser qualquer coisa na união desses dois conjuntos de tipos.
```Python hl_lines="1"
{!> ../../docs_src/python_types/tutorial008b_py310.py!}
```
-////
-
-//// tab | Python 3.9+
-
-```Python hl_lines="1 4"
-{!> ../../docs_src/python_types/tutorial008b_py39.py!}
-```
-
-////
-
-Em ambos os casos, isso significa que `item` poderia ser um `int` ou um `str`.
+Isso significa que `item` pode ser um `int` ou um `str`.
#### Possivelmente `None` { #possibly-none }
Você pode declarar que um valor pode ter um tipo, como `str`, mas que ele também pode ser `None`.
-No Python 3.6 e superior (incluindo o Python 3.10) você pode declará-lo importando e utilizando `Optional` do módulo `typing`.
-
-```Python hl_lines="1 4"
-{!../../docs_src/python_types/tutorial009_py39.py!}
-```
-
-O uso de `Optional[str]` em vez de apenas `str` permitirá que o editor o ajude a detectar erros, onde você pode estar assumindo que um valor é sempre um `str`, quando na verdade também pode ser `None`.
-
-`Optional[Something]` é na verdade um atalho para `Union[Something, None]`, eles são equivalentes.
-
-Isso também significa que no Python 3.10, você pode utilizar `Something | None`:
-
//// tab | Python 3.10+
```Python hl_lines="1"
@@ -266,96 +245,7 @@ Isso também significa que no Python 3.10, você pode utilizar `Something | None
////
-//// tab | Python 3.9+
-
-```Python hl_lines="1 4"
-{!> ../../docs_src/python_types/tutorial009_py39.py!}
-```
-
-////
-
-//// tab | Python 3.9+ alternativa
-
-```Python hl_lines="1 4"
-{!> ../../docs_src/python_types/tutorial009b_py39.py!}
-```
-
-////
-
-#### Utilizando `Union` ou `Optional` { #using-union-or-optional }
-
-Se você está utilizando uma versão do Python abaixo da 3.10, aqui vai uma dica do meu ponto de vista bem **subjetivo**:
-
-* 🚨 Evite utilizar `Optional[SomeType]`
-* No lugar, ✨ **use `Union[SomeType, None]`** ✨.
-
-Ambos são equivalentes, e no final das contas, eles são o mesmo. Mas eu recomendaria o `Union` ao invés de `Optional` porque a palavra **Optional** parece implicar que o valor é opcional, quando na verdade significa "isso pode ser `None`", mesmo que ele não seja opcional e ainda seja obrigatório.
-
-Eu penso que `Union[SomeType, None]` é mais explícito sobre o que ele significa.
-
-Isso é apenas sobre palavras e nomes. Mas estas palavras podem afetar como os seus colegas de trabalho pensam sobre o código.
-
-Por exemplo, vamos pegar esta função:
-
-{* ../../docs_src/python_types/tutorial009c_py39.py hl[1,4] *}
-
-O parâmetro `name` é definido como `Optional[str]`, mas ele **não é opcional**, você não pode chamar a função sem o parâmetro:
-
-```Python
-say_hi() # Oh, no, this throws an error! 😱
-```
-
-O parâmetro `name` **ainda é obrigatório** (não *opcional*) porque ele não possui um valor padrão. Mesmo assim, `name` aceita `None` como valor:
-
-```Python
-say_hi(name=None) # This works, None is valid 🎉
-```
-
-A boa notícia é, quando você estiver no Python 3.10 você não precisará se preocupar mais com isso, pois você poderá simplesmente utilizar o `|` para definir uniões de tipos:
-
-{* ../../docs_src/python_types/tutorial009c_py310.py hl[1,4] *}
-
-E então você não precisará mais se preocupar com nomes como `Optional` e `Union`. 😎
-
-#### Tipos genéricos { #generic-types }
-
-Esses tipos que usam parâmetros de tipo entre colchetes são chamados **tipos genéricos** ou **genéricos**. Por exemplo:
-
-//// tab | Python 3.10+
-
-Você pode utilizar os mesmos tipos internos como genéricos (com colchetes e tipos dentro):
-
-* `list`
-* `tuple`
-* `set`
-* `dict`
-
-E o mesmo que com versões anteriores do Python, do módulo `typing`:
-
-* `Union`
-* `Optional`
-* ...entre outros.
-
-No Python 3.10, como uma alternativa para a utilização dos genéricos `Union` e `Optional`, você pode usar a
barra vertical (`|`) para declarar uniões de tipos. Isso é muito melhor e mais simples.
-
-////
-
-//// tab | Python 3.9+
-
-Você pode utilizar os mesmos tipos internos como genéricos (com colchetes e tipos dentro):
-
-* `list`
-* `tuple`
-* `set`
-* `dict`
-
-E genéricos do módulo `typing`:
-
-* `Union`
-* `Optional`
-* ...entre outros.
-
-////
+Usar `str | None` em vez de apenas `str` permitirá que o editor o ajude a detectar erros em que você poderia estar assumindo que um valor é sempre um `str`, quando na verdade ele também pode ser `None`.
### Classes como tipos { #classes-as-types }
@@ -363,13 +253,13 @@ Você também pode declarar uma classe como o tipo de uma variável.
Digamos que você tenha uma classe `Person`, com um nome:
-{* ../../docs_src/python_types/tutorial010_py39.py hl[1:3] *}
+{* ../../docs_src/python_types/tutorial010_py310.py hl[1:3] *}
Então você pode declarar que uma variável é do tipo `Person`:
-{* ../../docs_src/python_types/tutorial010_py39.py hl[6] *}
+{* ../../docs_src/python_types/tutorial010_py310.py hl[6] *}
-E então, novamente, você recebe todo o apoio do editor:
+E então, novamente, você recebe todo o suporte do editor:

@@ -379,7 +269,7 @@ Isso não significa que "`one_person` é a **classe** chamada `Person`".
## Modelos Pydantic { #pydantic-models }
-O
Pydantic é uma biblioteca Python para executar a validação de dados.
+
Pydantic é uma biblioteca Python para executar a validação de dados.
Você declara a "forma" dos dados como classes com atributos.
@@ -403,23 +293,17 @@ O **FastAPI** é todo baseado em Pydantic.
Você verá muito mais disso na prática no [Tutorial - Guia do usuário](tutorial/index.md){.internal-link target=_blank}.
-/// tip | Dica
-
-O Pydantic tem um comportamento especial quando você usa `Optional` ou `Union[Something, None]` sem um valor padrão. Você pode ler mais sobre isso na documentação do Pydantic sobre
campos Opcionais Obrigatórios.
-
-///
-
## Type Hints com Metadados de Anotações { #type-hints-with-metadata-annotations }
-O Python possui uma funcionalidade que nos permite incluir **
metadados adicionais** nos type hints utilizando `Annotated`.
+O Python também possui uma funcionalidade que permite incluir **
metadados adicionais** nesses type hints utilizando `Annotated`.
-Desde o Python 3.9, `Annotated` faz parte da biblioteca padrão, então você pode importá-lo de `typing`.
+Você pode importar `Annotated` de `typing`.
-{* ../../docs_src/python_types/tutorial013_py39.py hl[1,4] *}
+{* ../../docs_src/python_types/tutorial013_py310.py hl[1,4] *}
O Python em si não faz nada com este `Annotated`. E para editores e outras ferramentas, o tipo ainda é `str`.
-Mas você pode utilizar este espaço dentro do `Annotated` para fornecer ao **FastAPI** metadata adicional sobre como você deseja que a sua aplicação se comporte.
+Mas você pode utilizar este espaço dentro do `Annotated` para fornecer ao **FastAPI** metadados adicionais sobre como você deseja que a sua aplicação se comporte.
O importante aqui de se lembrar é que **o primeiro *type parameter*** que você informar ao `Annotated` é o **tipo de fato**. O resto é apenas metadado para outras ferramentas.
@@ -446,12 +330,12 @@ Com o **FastAPI**, você declara parâmetros com type hints e obtém:
... e o **FastAPI** usa as mesmas declarações para:
-* **Definir requisitos**: dos parâmetros de rota, parâmetros da consulta, cabeçalhos, corpos, dependências, etc.
-* **Converter dados**: da solicitação para o tipo necessário.
-* **Validar dados**: provenientes de cada solicitação:
+* **Definir requisitos**: dos parâmetros de path da request, parâmetros da query, cabeçalhos, corpos, dependências, etc.
+* **Converter dados**: da request para o tipo necessário.
+* **Validar dados**: provenientes de cada request:
* Gerando **erros automáticos** retornados ao cliente quando os dados são inválidos.
* **Documentar** a API usando OpenAPI:
- * que é usado pelas interfaces de usuário da documentação interativa automática.
+ * que é usada pelas interfaces de usuário da documentação interativa automática.
Tudo isso pode parecer abstrato. Não se preocupe. Você verá tudo isso em ação no [Tutorial - Guia do usuário](tutorial/index.md){.internal-link target=_blank}.
@@ -459,6 +343,6 @@ O importante é que, usando tipos padrão de Python, em um único local (em vez
/// info | Informação
-Se você já passou por todo o tutorial e voltou para ver mais sobre os tipos, um bom recurso é
a "cheat sheet" do `mypy` .
+Se você já passou por todo o tutorial e voltou para ver mais sobre os tipos, um bom recurso é
a "cheat sheet" do `mypy`.
///
diff --git a/docs/pt/docs/translation-banner.md b/docs/pt/docs/translation-banner.md
new file mode 100644
index 0000000000..f3069ddd77
--- /dev/null
+++ b/docs/pt/docs/translation-banner.md
@@ -0,0 +1,11 @@
+/// details | 🌐 Tradução por IA e humanos
+
+Esta tradução foi feita por IA orientada por humanos. 🤝
+
+Ela pode conter erros de interpretação do significado original ou soar pouco natural, etc. 🤖
+
+Você pode melhorar esta tradução [ajudando-nos a orientar melhor o LLM de IA](https://fastapi.tiangolo.com/pt/contributing/#translations).
+
+[Versão em inglês](ENGLISH_VERSION_URL)
+
+///
diff --git a/docs/pt/docs/tutorial/background-tasks.md b/docs/pt/docs/tutorial/background-tasks.md
index 34805364b4..462fb00dcb 100644
--- a/docs/pt/docs/tutorial/background-tasks.md
+++ b/docs/pt/docs/tutorial/background-tasks.md
@@ -15,7 +15,7 @@ Isso inclui, por exemplo:
Primeiro, importe `BackgroundTasks` e defina um parâmetro na sua *função de operação de rota* com uma declaração de tipo `BackgroundTasks`:
-{* ../../docs_src/background_tasks/tutorial001_py39.py hl[1,13] *}
+{* ../../docs_src/background_tasks/tutorial001_py310.py hl[1,13] *}
O **FastAPI** criará o objeto do tipo `BackgroundTasks` para você e o passará como esse parâmetro.
@@ -31,13 +31,13 @@ Neste caso, a função da tarefa escreverá em um arquivo (simulando o envio de
E como a operação de escrita não usa `async` e `await`, definimos a função com um `def` normal:
-{* ../../docs_src/background_tasks/tutorial001_py39.py hl[6:9] *}
+{* ../../docs_src/background_tasks/tutorial001_py310.py hl[6:9] *}
## Adicione a tarefa em segundo plano { #add-the-background-task }
Dentro da sua *função de operação de rota*, passe sua função de tarefa para o objeto de *tarefas em segundo plano* com o método `.add_task()`:
-{* ../../docs_src/background_tasks/tutorial001_py39.py hl[14] *}
+{* ../../docs_src/background_tasks/tutorial001_py310.py hl[14] *}
O `.add_task()` recebe como argumentos:
diff --git a/docs/pt/docs/tutorial/bigger-applications.md b/docs/pt/docs/tutorial/bigger-applications.md
index 87bd13375a..ad758988f7 100644
--- a/docs/pt/docs/tutorial/bigger-applications.md
+++ b/docs/pt/docs/tutorial/bigger-applications.md
@@ -58,17 +58,17 @@ A mesma estrutura de arquivos com comentários:
```bash
.
-├── app # "app" is a Python package
-│ ├── __init__.py # this file makes "app" a "Python package"
-│ ├── main.py # "main" module, e.g. import app.main
-│ ├── dependencies.py # "dependencies" module, e.g. import app.dependencies
-│ └── routers # "routers" is a "Python subpackage"
-│ │ ├── __init__.py # makes "routers" a "Python subpackage"
-│ │ ├── items.py # "items" submodule, e.g. import app.routers.items
-│ │ └── users.py # "users" submodule, e.g. import app.routers.users
-│ └── internal # "internal" is a "Python subpackage"
-│ ├── __init__.py # makes "internal" a "Python subpackage"
-│ └── admin.py # "admin" submodule, e.g. import app.internal.admin
+├── app # "app" é um pacote Python
+│ ├── __init__.py # este arquivo torna "app" um "pacote Python"
+│ ├── main.py # módulo "main", p.ex., import app.main
+│ ├── dependencies.py # módulo "dependencies", p.ex., import app.dependencies
+│ └── routers # "routers" é um "subpacote Python"
+│ │ ├── __init__.py # torna "routers" um "subpacote Python"
+│ │ ├── items.py # submódulo "items", p.ex., import app.routers.items
+│ │ └── users.py # submódulo "users", p.ex., import app.routers.users
+│ └── internal # "internal" é um "subpacote Python"
+│ ├── __init__.py # torna "internal" um "subpacote Python"
+│ └── admin.py # submódulo "admin", p.ex., import app.internal.admin
```
## `APIRouter` { #apirouter }
@@ -85,7 +85,7 @@ Você pode criar as *operações de rota* para esse módulo usando o `APIRouter`
Você o importa e cria uma "instância" da mesma maneira que faria com a classe `FastAPI`:
-{* ../../docs_src/bigger_applications/app_an_py39/routers/users.py hl[1,3] title["app/routers/users.py"] *}
+{* ../../docs_src/bigger_applications/app_an_py310/routers/users.py hl[1,3] title["app/routers/users.py"] *}
### *Operações de Rota* com `APIRouter` { #path-operations-with-apirouter }
@@ -93,7 +93,7 @@ E então você o utiliza para declarar suas *operações de rota*.
Utilize-o da mesma maneira que utilizaria a classe `FastAPI`:
-{* ../../docs_src/bigger_applications/app_an_py39/routers/users.py hl[6,11,16] title["app/routers/users.py"] *}
+{* ../../docs_src/bigger_applications/app_an_py310/routers/users.py hl[6,11,16] title["app/routers/users.py"] *}
Você pode pensar em `APIRouter` como uma classe "mini `FastAPI`".
@@ -117,7 +117,7 @@ Então, as colocamos em seu próprio módulo de `dependencies` (`app/dependencie
Agora usaremos uma dependência simples para ler um cabeçalho `X-Token` personalizado:
-{* ../../docs_src/bigger_applications/app_an_py39/dependencies.py hl[3,6:8] title["app/dependencies.py"] *}
+{* ../../docs_src/bigger_applications/app_an_py310/dependencies.py hl[3,6:8] title["app/dependencies.py"] *}
/// tip | Dica
@@ -149,7 +149,7 @@ Sabemos que todas as *operações de rota* neste módulo têm o mesmo:
Então, em vez de adicionar tudo isso a cada *operação de rota*, podemos adicioná-lo ao `APIRouter`.
-{* ../../docs_src/bigger_applications/app_an_py39/routers/items.py hl[5:10,16,21] title["app/routers/items.py"] *}
+{* ../../docs_src/bigger_applications/app_an_py310/routers/items.py hl[5:10,16,21] title["app/routers/items.py"] *}
Como o path de cada *operação de rota* tem que começar com `/`, como em:
@@ -208,7 +208,7 @@ E precisamos obter a função de dependência do módulo `app.dependencies`, o a
Então usamos uma importação relativa com `..` para as dependências:
-{* ../../docs_src/bigger_applications/app_an_py39/routers/items.py hl[3] title["app/routers/items.py"] *}
+{* ../../docs_src/bigger_applications/app_an_py310/routers/items.py hl[3] title["app/routers/items.py"] *}
#### Como funcionam as importações relativas { #how-relative-imports-work }
@@ -279,7 +279,7 @@ Não estamos adicionando o prefixo `/items` nem `tags=["items"]` a cada *operaç
Mas ainda podemos adicionar _mais_ `tags` que serão aplicadas a uma *operação de rota* específica, e também algumas `responses` extras específicas para essa *operação de rota*:
-{* ../../docs_src/bigger_applications/app_an_py39/routers/items.py hl[30:31] title["app/routers/items.py"] *}
+{* ../../docs_src/bigger_applications/app_an_py310/routers/items.py hl[30:31] title["app/routers/items.py"] *}
/// tip | Dica
@@ -305,13 +305,13 @@ Você importa e cria uma classe `FastAPI` normalmente.
E podemos até declarar [dependências globais](dependencies/global-dependencies.md){.internal-link target=_blank} que serão combinadas com as dependências para cada `APIRouter`:
-{* ../../docs_src/bigger_applications/app_an_py39/main.py hl[1,3,7] title["app/main.py"] *}
+{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[1,3,7] title["app/main.py"] *}
### Importe o `APIRouter` { #import-the-apirouter }
Agora importamos os outros submódulos que possuem `APIRouter`s:
-{* ../../docs_src/bigger_applications/app_an_py39/main.py hl[4:5] title["app/main.py"] *}
+{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[4:5] title["app/main.py"] *}
Como os arquivos `app/routers/users.py` e `app/routers/items.py` são submódulos que fazem parte do mesmo pacote Python `app`, podemos usar um único ponto `.` para importá-los usando "importações relativas".
@@ -374,13 +374,13 @@ o `router` de `users` sobrescreveria o de `items` e não poderíamos usá-los ao
Então, para poder usar ambos no mesmo arquivo, importamos os submódulos diretamente:
-{* ../../docs_src/bigger_applications/app_an_py39/main.py hl[5] title["app/main.py"] *}
+{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[5] title["app/main.py"] *}
### Inclua os `APIRouter`s para `users` e `items` { #include-the-apirouters-for-users-and-items }
Agora, vamos incluir os `router`s dos submódulos `users` e `items`:
-{* ../../docs_src/bigger_applications/app_an_py39/main.py hl[10:11] title["app/main.py"] *}
+{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[10:11] title["app/main.py"] *}
/// info | Informação
@@ -420,13 +420,13 @@ Ele contém um `APIRouter` com algumas *operações de rota* de administração
Para este exemplo, será super simples. Mas digamos que, como ele é compartilhado com outros projetos na organização, não podemos modificá-lo e adicionar um `prefix`, `dependencies`, `tags`, etc. diretamente ao `APIRouter`:
-{* ../../docs_src/bigger_applications/app_an_py39/internal/admin.py hl[3] title["app/internal/admin.py"] *}
+{* ../../docs_src/bigger_applications/app_an_py310/internal/admin.py hl[3] title["app/internal/admin.py"] *}
Mas ainda queremos definir um `prefix` personalizado ao incluir o `APIRouter` para que todas as suas *operações de rota* comecem com `/admin`, queremos protegê-lo com as `dependencies` que já temos para este projeto e queremos incluir `tags` e `responses`.
Podemos declarar tudo isso sem precisar modificar o `APIRouter` original passando esses parâmetros para `app.include_router()`:
-{* ../../docs_src/bigger_applications/app_an_py39/main.py hl[14:17] title["app/main.py"] *}
+{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[14:17] title["app/main.py"] *}
Dessa forma, o `APIRouter` original permanecerá inalterado, para que possamos compartilhar o mesmo arquivo `app/internal/admin.py` com outros projetos na organização.
@@ -447,7 +447,7 @@ Também podemos adicionar *operações de rota* diretamente ao aplicativo `FastA
Aqui fazemos isso... só para mostrar que podemos 🤷:
-{* ../../docs_src/bigger_applications/app_an_py39/main.py hl[21:23] title["app/main.py"] *}
+{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[21:23] title["app/main.py"] *}
e funcionará corretamente, junto com todas as outras *operações de rota* adicionadas com `app.include_router()`.
diff --git a/docs/pt/docs/tutorial/body-multiple-params.md b/docs/pt/docs/tutorial/body-multiple-params.md
index 24f35b2105..828cde633a 100644
--- a/docs/pt/docs/tutorial/body-multiple-params.md
+++ b/docs/pt/docs/tutorial/body-multiple-params.md
@@ -104,12 +104,6 @@ Dado que, por padrão, valores singulares são interpretados como parâmetros de
q: str | None = None
```
-Ou em Python 3.9:
-
-```Python
-q: Union[str, None] = None
-```
-
Por exemplo:
{* ../../docs_src/body_multiple_params/tutorial004_an_py310.py hl[28] *}
diff --git a/docs/pt/docs/tutorial/body-nested-models.md b/docs/pt/docs/tutorial/body-nested-models.md
index f2bec19a2f..d53d3f649a 100644
--- a/docs/pt/docs/tutorial/body-nested-models.md
+++ b/docs/pt/docs/tutorial/body-nested-models.md
@@ -164,7 +164,7 @@ images: list[Image]
como em:
-{* ../../docs_src/body_nested_models/tutorial008_py39.py hl[13] *}
+{* ../../docs_src/body_nested_models/tutorial008_py310.py hl[13] *}
## Suporte de editor em todo canto { #editor-support-everywhere }
@@ -194,7 +194,7 @@ Outro caso útil é quando você deseja ter chaves de outro tipo, por exemplo, `
Neste caso, você aceitaria qualquer `dict`, desde que tenha chaves` int` com valores `float`:
-{* ../../docs_src/body_nested_models/tutorial009_py39.py hl[7] *}
+{* ../../docs_src/body_nested_models/tutorial009_py310.py hl[7] *}
/// tip | Dica
diff --git a/docs/pt/docs/tutorial/body.md b/docs/pt/docs/tutorial/body.md
index 669334439a..bec553e215 100644
--- a/docs/pt/docs/tutorial/body.md
+++ b/docs/pt/docs/tutorial/body.md
@@ -72,9 +72,9 @@ Apenas com essa declaração de tipos do Python, o **FastAPI** irá:
* Validar os dados.
* Se algum dado for inválido, irá retornar um erro bem claro, indicando exatamente onde e o que estava incorreto.
* Entregar a você a informação recebida no parâmetro `item`.
- * Como você o declarou na função como do tipo `Item`, você também terá o suporte do editor (completação, etc) para todos os atributos e seus tipos.
+ * Como você o declarou na função como do tipo `Item`, você também terá o suporte do editor (preenchimento automático, etc) para todos os atributos e seus tipos.
* Gerar definições de
JSON Schema para o seu modelo; você também pode usá-las em qualquer outro lugar se fizer sentido para o seu projeto.
-* Esses schemas farão parte do esquema OpenAPI gerado, e serão usados pelas
UIs de documentação automática.
+* Esses schemas farão parte do esquema OpenAPI gerado, e serão usados pelas
UIs de documentação automática.
## Documentação automática { #automatic-docs }
@@ -88,7 +88,7 @@ E também serão utilizados na documentação da API dentro de cada *operação
## Suporte do editor { #editor-support }
-No seu editor, dentro da função você receberá dicas de tipos e completação em todo lugar (isso não aconteceria se você recebesse um `dict` em vez de um modelo Pydantic):
+No seu editor, dentro da função você receberá dicas de tipos e preenchimento automático em todo lugar (isso não aconteceria se você recebesse um `dict` em vez de um modelo Pydantic):

@@ -155,7 +155,7 @@ Os parâmetros da função serão reconhecidos conforme abaixo:
O FastAPI saberá que o valor de `q` não é obrigatório por causa do valor padrão `= None`.
-O `str | None` (Python 3.10+) ou o `Union` em `Union[str, None]` (Python 3.9+) não é utilizado pelo FastAPI para determinar que o valor não é obrigatório, ele saberá que não é obrigatório porque tem um valor padrão `= None`.
+O `str | None` não é utilizado pelo FastAPI para determinar que o valor não é obrigatório, ele saberá que não é obrigatório porque tem um valor padrão `= None`.
Mas adicionar as anotações de tipo permitirá ao seu editor oferecer um suporte melhor e detectar erros.
diff --git a/docs/pt/docs/tutorial/cookie-param-models.md b/docs/pt/docs/tutorial/cookie-param-models.md
index 73c94050fb..f125314c8b 100644
--- a/docs/pt/docs/tutorial/cookie-param-models.md
+++ b/docs/pt/docs/tutorial/cookie-param-models.md
@@ -18,7 +18,7 @@ Essa mesma técnica se aplica para `Query`, `Cookie`, e `Header`. 😎
## Cookies com Modelos Pydantic { #cookies-with-a-pydantic-model }
-Declare o parâmetro de **cookie** que você precisa em um **modelo Pydantic**, e depois declare o parâmetro como um `Cookie`:
+Declare os parâmetros de **cookie** de que você precisa em um **modelo Pydantic**, e depois declare o parâmetro como `Cookie`:
{* ../../docs_src/cookie_param_models/tutorial001_an_py310.py hl[9:12,16] *}
@@ -46,7 +46,7 @@ Mas mesmo que você **adicionar os dados** e clicar em "Executar", pelo motivo d
Em alguns casos especiais (provavelmente não muito comuns), você pode querer **restringir** os cookies que você deseja receber.
-Agora a sua API possui o poder de controlar o seu próprio
consentimento de cookie. 🤪🍪
+Agora a sua API possui o poder de controlar o seu próprio
consentimento de cookie. 🤪🍪
Você pode utilizar a configuração do modelo Pydantic para `proibir` qualquer campo `extra`:
@@ -54,9 +54,9 @@ Você pode utilizar a configuração do modelo Pydantic para `proibir` qualquer
Se o cliente tentar enviar alguns **cookies extras**, eles receberão um retorno de **erro**.
-Coitados dos banners de cookies com todo o seu esforço para obter o seu consentimento para a
API rejeitá-lo. 🍪
+Coitados dos banners de cookies com todo o seu esforço para obter o seu consentimento para a
API rejeitá-lo. 🍪
-Por exemplo, se o cliente tentar enviar um cookie `santa_tracker` com o valor de `good-list-please`, o cliente receberá uma resposta de **erro** informando que o `santa_tracker`
cookie não é permitido:
+Por exemplo, se o cliente tentar enviar um cookie `santa_tracker` com o valor de `good-list-please`, o cliente receberá uma resposta de **erro** informando que o `santa_tracker`
cookie não é permitido:
```json
{
@@ -73,4 +73,4 @@ Por exemplo, se o cliente tentar enviar um cookie `santa_tracker` com o valor de
## Resumo { #summary }
-Você consegue utilizar **modelos Pydantic** para declarar
**cookies** no **FastAPI**. 😎
+Você consegue utilizar **modelos Pydantic** para declarar
**cookies** no **FastAPI**. 😎
diff --git a/docs/pt/docs/tutorial/cors.md b/docs/pt/docs/tutorial/cors.md
index 0f99db888e..055cfeacad 100644
--- a/docs/pt/docs/tutorial/cors.md
+++ b/docs/pt/docs/tutorial/cors.md
@@ -46,7 +46,8 @@ Você também pode especificar se o seu backend permite:
* Métodos HTTP específicos (`POST`, `PUT`) ou todos eles com o curinga `"*"`.
* Cabeçalhos HTTP específicos ou todos eles com o curinga `"*"`.
-{* ../../docs_src/cors/tutorial001_py39.py hl[2,6:11,13:19] *}
+{* ../../docs_src/cors/tutorial001_py310.py hl[2,6:11,13:19] *}
+
Os parâmetros padrão usados pela implementação `CORSMiddleware` são restritivos por padrão, então você precisará habilitar explicitamente as origens, métodos ou cabeçalhos específicos para que os navegadores tenham permissão para usá-los em um contexto cross domain.
diff --git a/docs/pt/docs/tutorial/debugging.md b/docs/pt/docs/tutorial/debugging.md
index e39c7d1280..773921bb3c 100644
--- a/docs/pt/docs/tutorial/debugging.md
+++ b/docs/pt/docs/tutorial/debugging.md
@@ -6,7 +6,7 @@ Você pode conectar o depurador no seu editor, por exemplo, com o Visual Studio
Em sua aplicação FastAPI, importe e execute `uvicorn` diretamente:
-{* ../../docs_src/debugging/tutorial001_py39.py hl[1,15] *}
+{* ../../docs_src/debugging/tutorial001_py310.py hl[1,15] *}
### Sobre `__name__ == "__main__"` { #about-name-main }
@@ -62,7 +62,7 @@ from myapp import app
# Mais um pouco de código
```
-nesse caso, a variável criada automaticamente dentro de `myapp.py` não terá a variável `__name__` com o valor `"__main__"`.
+nesse caso, a variável `__name__` criada automaticamente dentro de `myapp.py` não terá o valor `"__main__"`.
Então, a linha:
diff --git a/docs/pt/docs/tutorial/dependencies/classes-as-dependencies.md b/docs/pt/docs/tutorial/dependencies/classes-as-dependencies.md
index c30d0b5f08..7231373a72 100644
--- a/docs/pt/docs/tutorial/dependencies/classes-as-dependencies.md
+++ b/docs/pt/docs/tutorial/dependencies/classes-as-dependencies.md
@@ -101,7 +101,7 @@ O **FastAPI** chama a classe `CommonQueryParams`. Isso cria uma "instância" des
Perceba como escrevemos `CommonQueryParams` duas vezes no código abaixo:
-//// tab | Python 3.9+
+//// tab | Python 3.10+
```Python
commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]
@@ -109,7 +109,7 @@ commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]
////
-//// tab | Python 3.9+ non-Annotated
+//// tab | Python 3.10+ non-Annotated
/// tip | Dica
@@ -137,7 +137,7 @@ O último `CommonQueryParams`, em:
Nesse caso, o primeiro `CommonQueryParams`, em:
-//// tab | Python 3.9+
+//// tab | Python 3.10+
```Python
commons: Annotated[CommonQueryParams, ...
@@ -145,7 +145,7 @@ commons: Annotated[CommonQueryParams, ...
////
-//// tab | Python 3.9+ non-Annotated
+//// tab | Python 3.10+ non-Annotated
/// tip | Dica
@@ -163,7 +163,7 @@ commons: CommonQueryParams ...
Na verdade você poderia escrever apenas:
-//// tab | Python 3.9+
+//// tab | Python 3.10+
```Python
commons: Annotated[Any, Depends(CommonQueryParams)]
@@ -171,7 +171,7 @@ commons: Annotated[Any, Depends(CommonQueryParams)]
////
-//// tab | Python 3.9+ non-Annotated
+//// tab | Python 3.10+ non-Annotated
/// tip | Dica
@@ -197,7 +197,7 @@ Mas declarar o tipo é encorajado por que é a forma que o seu editor de texto s
Mas você pode ver que temos uma repetição do código neste exemplo, escrevendo `CommonQueryParams` duas vezes:
-//// tab | Python 3.9+
+//// tab | Python 3.10+
```Python
commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]
@@ -205,7 +205,7 @@ commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]
////
-//// tab | Python 3.9+ non-Annotated
+//// tab | Python 3.10+ non-Annotated
/// tip | Dica
@@ -225,7 +225,7 @@ Para esses casos específicos, você pode fazer o seguinte:
Em vez de escrever:
-//// tab | Python 3.9+
+//// tab | Python 3.10+
```Python
commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]
@@ -233,7 +233,7 @@ commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]
////
-//// tab | Python 3.9+ non-Annotated
+//// tab | Python 3.10+ non-Annotated
/// tip | Dica
@@ -249,7 +249,7 @@ commons: CommonQueryParams = Depends(CommonQueryParams)
...escreva:
-//// tab | Python 3.9+
+//// tab | Python 3.10+
```Python
commons: Annotated[CommonQueryParams, Depends()]
@@ -257,7 +257,7 @@ commons: Annotated[CommonQueryParams, Depends()]
////
-//// tab | Python 3.9+ non-Annotated
+//// tab | Python 3.10+ non-Annotated
/// tip | Dica
diff --git a/docs/pt/docs/tutorial/dependencies/dependencies-in-path-operation-decorators.md b/docs/pt/docs/tutorial/dependencies/dependencies-in-path-operation-decorators.md
index ee8a58dc24..4a99091d11 100644
--- a/docs/pt/docs/tutorial/dependencies/dependencies-in-path-operation-decorators.md
+++ b/docs/pt/docs/tutorial/dependencies/dependencies-in-path-operation-decorators.md
@@ -1,6 +1,6 @@
# Dependências em decoradores de operações de rota { #dependencies-in-path-operation-decorators }
-Em alguns casos você não precisa necessariamente retornar o valor de uma dependência dentro de uma *função de operação de rota*.
+Em alguns casos você não precisa necessariamente do valor de retorno de uma dependência dentro de uma *função de operação de rota*.
Ou a dependência não retorna nenhum valor.
@@ -14,7 +14,7 @@ O *decorador da operação de rota* recebe um argumento opcional `dependencies`.
Ele deve ser uma lista de `Depends()`:
-{* ../../docs_src/dependencies/tutorial006_an_py39.py hl[19] *}
+{* ../../docs_src/dependencies/tutorial006_an_py310.py hl[19] *}
Essas dependências serão executadas/resolvidas da mesma forma que dependências comuns. Mas o valor delas (se existir algum) não será passado para a sua *função de operação de rota*.
@@ -44,13 +44,13 @@ Você pode utilizar as mesmas *funções* de dependências que você usaria norm
Dependências podem declarar requisitos de requisições (como cabeçalhos) ou outras subdependências:
-{* ../../docs_src/dependencies/tutorial006_an_py39.py hl[8,13] *}
+{* ../../docs_src/dependencies/tutorial006_an_py310.py hl[8,13] *}
### Levantar exceções { #raise-exceptions }
Essas dependências podem `raise` exceções, da mesma forma que dependências comuns:
-{* ../../docs_src/dependencies/tutorial006_an_py39.py hl[10,15] *}
+{* ../../docs_src/dependencies/tutorial006_an_py310.py hl[10,15] *}
### Valores de retorno { #return-values }
@@ -58,7 +58,7 @@ E elas também podem ou não retornar valores, eles não serão utilizados.
Então, você pode reutilizar uma dependência comum (que retorna um valor) que já seja utilizada em outro lugar, e mesmo que o valor não seja utilizado, a dependência será executada:
-{* ../../docs_src/dependencies/tutorial006_an_py39.py hl[11,16] *}
+{* ../../docs_src/dependencies/tutorial006_an_py310.py hl[11,16] *}
## Dependências para um grupo de *operações de rota* { #dependencies-for-a-group-of-path-operations }
diff --git a/docs/pt/docs/tutorial/dependencies/dependencies-with-yield.md b/docs/pt/docs/tutorial/dependencies/dependencies-with-yield.md
index 3678730139..dd9d9fbe6d 100644
--- a/docs/pt/docs/tutorial/dependencies/dependencies-with-yield.md
+++ b/docs/pt/docs/tutorial/dependencies/dependencies-with-yield.md
@@ -1,6 +1,6 @@
# Dependências com yield { #dependencies-with-yield }
-O **FastAPI** possui suporte para dependências que realizam
alguns passos extras ao finalizar.
+O **FastAPI** possui suporte para dependências que realizam
alguns passos extras ao finalizar.
Para fazer isso, utilize `yield` em vez de `return`, e escreva os passos extras (código) depois.
@@ -29,15 +29,15 @@ Por exemplo, você poderia utilizar isso para criar uma sessão do banco de dado
Apenas o código anterior à declaração com `yield` e o código contendo essa declaração são executados antes de criar uma resposta:
-{* ../../docs_src/dependencies/tutorial007_py39.py hl[2:4] *}
+{* ../../docs_src/dependencies/tutorial007_py310.py hl[2:4] *}
O valor gerado (yielded) é o que é injetado nas *operações de rota* e outras dependências:
-{* ../../docs_src/dependencies/tutorial007_py39.py hl[4] *}
+{* ../../docs_src/dependencies/tutorial007_py310.py hl[4] *}
O código após o `yield` é executado após a resposta:
-{* ../../docs_src/dependencies/tutorial007_py39.py hl[5:6] *}
+{* ../../docs_src/dependencies/tutorial007_py310.py hl[5:6] *}
/// tip | Dica
@@ -57,7 +57,7 @@ Então, você pode procurar por essa exceção específica dentro da dependênci
Da mesma forma, você pode utilizar `finally` para garantir que os passos de saída são executados, com ou sem exceções.
-{* ../../docs_src/dependencies/tutorial007_py39.py hl[3,5] *}
+{* ../../docs_src/dependencies/tutorial007_py310.py hl[3,5] *}
## Subdependências com `yield` { #sub-dependencies-with-yield }
@@ -67,7 +67,7 @@ O **FastAPI** garantirá que o "código de saída" em cada dependência com `yie
Por exemplo, `dependency_c` pode depender de `dependency_b`, e `dependency_b` depender de `dependency_a`:
-{* ../../docs_src/dependencies/tutorial008_an_py39.py hl[6,14,22] *}
+{* ../../docs_src/dependencies/tutorial008_an_py310.py hl[6,14,22] *}
E todas elas podem utilizar `yield`.
@@ -75,7 +75,7 @@ Neste caso, `dependency_c`, para executar seu código de saída, precisa que o v
E, por outro lado, `dependency_b` precisa que o valor de `dependency_a` (nomeado de `dep_a`) esteja disponível para executar seu código de saída.
-{* ../../docs_src/dependencies/tutorial008_an_py39.py hl[18:19,26:27] *}
+{* ../../docs_src/dependencies/tutorial008_an_py310.py hl[18:19,26:27] *}
Da mesma forma, você pode ter algumas dependências com `yield` e outras com `return` e ter uma relação de dependência entre algumas das duas.
@@ -109,7 +109,7 @@ Mas ela existe para ser utilizada caso você precise. 🤓
///
-{* ../../docs_src/dependencies/tutorial008b_an_py39.py hl[18:22,31] *}
+{* ../../docs_src/dependencies/tutorial008b_an_py310.py hl[18:22,31] *}
Se você quiser capturar exceções e criar uma resposta personalizada com base nisso, crie um [Manipulador de Exceções Customizado](../handling-errors.md#install-custom-exception-handlers){.internal-link target=_blank}.
@@ -117,7 +117,7 @@ Se você quiser capturar exceções e criar uma resposta personalizada com base
Se você capturar uma exceção com `except` em uma dependência que utilize `yield` e ela não for levantada novamente (ou uma nova exceção for levantada), o FastAPI não será capaz de identificar que houve uma exceção, da mesma forma que aconteceria com Python puro:
-{* ../../docs_src/dependencies/tutorial008c_an_py39.py hl[15:16] *}
+{* ../../docs_src/dependencies/tutorial008c_an_py310.py hl[15:16] *}
Neste caso, o cliente irá ver uma resposta *HTTP 500 Internal Server Error* como deveria acontecer, já que não estamos levantando nenhuma `HTTPException` ou coisa parecida, mas o servidor **não terá nenhum log** ou qualquer outra indicação de qual foi o erro. 😱
@@ -127,7 +127,7 @@ Se você capturar uma exceção em uma dependência com `yield`, a menos que voc
Você pode relançar a mesma exceção utilizando `raise`:
-{* ../../docs_src/dependencies/tutorial008d_an_py39.py hl[17] *}
+{* ../../docs_src/dependencies/tutorial008d_an_py310.py hl[17] *}
Agora o cliente irá receber a mesma resposta *HTTP 500 Internal Server Error*, mas o servidor terá nosso `InternalError` personalizado nos logs. 😎
@@ -190,7 +190,7 @@ Normalmente, o código de saída das dependências com `yield` é executado **ap
Mas se você sabe que não precisará usar a dependência depois de retornar da *função de operação de rota*, você pode usar `Depends(scope="function")` para dizer ao FastAPI que deve fechar a dependência depois que a *função de operação de rota* retornar, mas **antes** de a **resposta ser enviada**.
-{* ../../docs_src/dependencies/tutorial008e_an_py39.py hl[12,16] *}
+{* ../../docs_src/dependencies/tutorial008e_an_py310.py hl[12,16] *}
`Depends()` recebe um parâmetro `scope` que pode ser:
@@ -269,7 +269,7 @@ Em Python, você pode criar Gerenciadores de Contexto ao
Injeção de Dependência**.
+O **FastAPI** possui um poderoso, mas intuitivo sistema de **Injeção de Dependência**.
Esse sistema foi pensado para ser fácil de usar, e permitir que qualquer desenvolvedor possa integrar facilmente outros componentes ao **FastAPI**.
@@ -25,7 +25,7 @@ Vamos ver um exemplo simples. Tão simples que não será muito útil, por enqua
Mas dessa forma podemos focar em como o sistema de **Injeção de Dependência** funciona.
-### Criando uma dependência, ou "injetável" { #create-a-dependency-or-dependable }
+### Criando uma dependência, ou "dependable" { #create-a-dependency-or-dependable }
Primeiro vamos focar na dependência.
@@ -89,7 +89,7 @@ Você verá quais outras "coisas", além de funções, podem ser usadas como dep
Sempre que uma nova requisição for realizada, o **FastAPI** se encarrega de:
-* Chamar sua dependência ("injetável") com os parâmetros corretos.
+* Chamar sua dependência ("dependable") com os parâmetros corretos.
* Obter o resultado da função.
* Atribuir esse resultado para o parâmetro em sua *função de operação de rota*.
@@ -186,7 +186,7 @@ Outros termos comuns para essa mesma ideia de "injeção de dependência" são:
Integrações e "plug-ins" podem ser construídos com o sistema de **Injeção de Dependência**. Mas na verdade, **não há necessidade de criar "plug-ins"**, já que utilizando dependências é possível declarar um número infinito de integrações e interações que se tornam disponíveis para as suas *funções de operação de rota*.
-E as dependências pode ser criadas de uma forma bastante simples e intuitiva que permite que você importe apenas os pacotes Python que forem necessários, e integrá-los com as funções de sua API em algumas linhas de código, *literalmente*.
+E as dependências podem ser criadas de uma forma bastante simples e intuitiva que permite que você importe apenas os pacotes Python que forem necessários, e integrá-los com as funções de sua API em algumas linhas de código, *literalmente*.
Você verá exemplos disso nos próximos capítulos, acerca de bancos de dados relacionais e NoSQL, segurança, etc.
@@ -199,7 +199,7 @@ A simplicidade do sistema de injeção de dependência do **FastAPI** faz ele co
* pacotes externos
* APIs externas
* sistemas de autenticação e autorização
-* istemas de monitoramento de uso para APIs
+* sistemas de monitoramento de uso para APIs
* sistemas de injeção de dados de resposta
* etc.
@@ -209,7 +209,7 @@ Mesmo que o sistema hierárquico de injeção de dependência seja simples de de
Você pode definir dependências que por sua vez definem suas próprias dependências.
-No fim, uma árvore hierárquica de dependências é criadas, e o sistema de **Injeção de Dependência** toma conta de resolver todas essas dependências (e as sub-dependências delas) para você, e provê (injeta) os resultados em cada passo.
+Por fim, uma árvore hierárquica de dependências é criada, e o sistema de **Injeção de Dependência** toma conta de resolver todas essas dependências (e as sub-dependências delas) para você, e provê (injeta) os resultados em cada passo.
Por exemplo, vamos supor que você possua 4 endpoints na sua API (*operações de rota*):
diff --git a/docs/pt/docs/tutorial/dependencies/sub-dependencies.md b/docs/pt/docs/tutorial/dependencies/sub-dependencies.md
index e2dc9bbf9a..63ed0e48ad 100644
--- a/docs/pt/docs/tutorial/dependencies/sub-dependencies.md
+++ b/docs/pt/docs/tutorial/dependencies/sub-dependencies.md
@@ -58,11 +58,11 @@ query_extractor --> query_or_cookie_extractor --> read_query
Se uma de suas dependências é declarada várias vezes para a mesma *operação de rota*, por exemplo, múltiplas dependências com uma mesma subdependência, o **FastAPI** irá chamar essa subdependência uma única vez para cada requisição.
-E o valor retornado é salvo em um "cache" e repassado para todos os "dependentes" que precisam dele em uma requisição específica, em vez de chamar a dependência múltiplas vezes para uma mesma requisição.
+E o valor retornado é salvo em um "cache" e repassado para todos os "dependentes" que precisam dele em uma requisição específica, em vez de chamar a dependência múltiplas vezes para uma mesma requisição.
Em um cenário avançado onde você precise que a dependência seja calculada em cada passo (possivelmente várias vezes) de uma requisição em vez de utilizar o valor em "cache", você pode definir o parâmetro `use_cache=False` em `Depends`:
-//// tab | Python 3.9+
+//// tab | Python 3.10+
```Python hl_lines="1"
async def needy_dependency(fresh_value: Annotated[str, Depends(get_value, use_cache=False)]):
@@ -71,7 +71,7 @@ async def needy_dependency(fresh_value: Annotated[str, Depends(get_value, use_ca
////
-//// tab | Python 3.9+ non-Annotated
+//// tab | Python 3.10+ non-Annotated
/// tip | Dica
diff --git a/docs/pt/docs/tutorial/extra-models.md b/docs/pt/docs/tutorial/extra-models.md
index 24eafce015..3136597417 100644
--- a/docs/pt/docs/tutorial/extra-models.md
+++ b/docs/pt/docs/tutorial/extra-models.md
@@ -190,9 +190,9 @@ Mas se colocarmos isso na atribuição `response_model=PlaneItem | CarItem`, ter
Da mesma forma, você pode declarar respostas de listas de objetos.
-Para isso, use o padrão Python `typing.List` (ou simplesmente `list` no Python 3.9 e superior):
+Para isso, use o padrão Python `list`:
-{* ../../docs_src/extra_models/tutorial004_py39.py hl[18] *}
+{* ../../docs_src/extra_models/tutorial004_py310.py hl[18] *}
## Resposta com `dict` arbitrário { #response-with-arbitrary-dict }
@@ -200,9 +200,9 @@ Você também pode declarar uma resposta usando um simples `dict` arbitrário, d
Isso é útil se você não souber os nomes de campo / atributo válidos (que seriam necessários para um modelo Pydantic) antecipadamente.
-Neste caso, você pode usar `typing.Dict` (ou simplesmente `dict` no Python 3.9 e superior):
+Neste caso, você pode usar `dict`:
-{* ../../docs_src/extra_models/tutorial005_py39.py hl[6] *}
+{* ../../docs_src/extra_models/tutorial005_py310.py hl[6] *}
## Recapitulação { #recap }
diff --git a/docs/pt/docs/tutorial/first-steps.md b/docs/pt/docs/tutorial/first-steps.md
index 86cddde5da..4ccc7cf040 100644
--- a/docs/pt/docs/tutorial/first-steps.md
+++ b/docs/pt/docs/tutorial/first-steps.md
@@ -2,7 +2,7 @@
O arquivo FastAPI mais simples pode se parecer com:
-{* ../../docs_src/first_steps/tutorial001_py39.py *}
+{* ../../docs_src/first_steps/tutorial001_py310.py *}
Copie o conteúdo para um arquivo `main.py`.
@@ -183,7 +183,7 @@ Deploying to FastAPI Cloud...
### Passo 1: importe `FastAPI` { #step-1-import-fastapi }
-{* ../../docs_src/first_steps/tutorial001_py39.py hl[1] *}
+{* ../../docs_src/first_steps/tutorial001_py310.py hl[1] *}
`FastAPI` é uma classe Python que fornece todas as funcionalidades para sua API.
@@ -197,7 +197,7 @@ Você pode usar todas as funcionalidades do operação get
+* usando uma get operação
/// info | Informações sobre `@decorator`
@@ -320,7 +320,7 @@ Esta é a nossa "**função de operação de rota**":
* **operação**: é `get`.
* **função**: é a função abaixo do "decorador" (abaixo do `@app.get("/")`).
-{* ../../docs_src/first_steps/tutorial001_py39.py hl[7] *}
+{* ../../docs_src/first_steps/tutorial001_py310.py hl[7] *}
Esta é uma função Python.
@@ -332,7 +332,7 @@ Neste caso, é uma função `async`.
Você também pode defini-la como uma função normal em vez de `async def`:
-{* ../../docs_src/first_steps/tutorial003_py39.py hl[7] *}
+{* ../../docs_src/first_steps/tutorial003_py310.py hl[7] *}
/// note | Nota
@@ -342,7 +342,7 @@ Se você não sabe a diferença, verifique o [Async: *"Com pressa?"*](../async.m
### Passo 5: retorne o conteúdo { #step-5-return-the-content }
-{* ../../docs_src/first_steps/tutorial001_py39.py hl[8] *}
+{* ../../docs_src/first_steps/tutorial001_py310.py hl[8] *}
Você pode retornar um `dict`, `list` e valores singulares como `str`, `int`, etc.
diff --git a/docs/pt/docs/tutorial/handling-errors.md b/docs/pt/docs/tutorial/handling-errors.md
index 1c162c205f..252dbb06fb 100644
--- a/docs/pt/docs/tutorial/handling-errors.md
+++ b/docs/pt/docs/tutorial/handling-errors.md
@@ -25,7 +25,7 @@ Para retornar ao cliente *responses* HTTP com erros, use o `HTTPException`.
### Import `HTTPException` { #import-httpexception }
-{* ../../docs_src/handling_errors/tutorial001_py39.py hl[1] *}
+{* ../../docs_src/handling_errors/tutorial001_py310.py hl[1] *}
### Lance o `HTTPException` no seu código { #raise-an-httpexception-in-your-code }
@@ -33,13 +33,13 @@ Para retornar ao cliente *responses* HTTP com erros, use o `HTTPException`.
E porque é uma exceção do Python, você não **retorna** (return) o `HTTPException`, você lança o (raise) no seu código.
-Isso também significa que, se você está escrevendo uma função de utilidade, a qual você está chamando dentro da sua função de operações de caminhos, e você lança o `HTTPException` dentro da função de utilidade, o resto do seu código não será executado dentro da função de operações de caminhos. Ao contrário, o `HTTPException` irá finalizar a requisição no mesmo instante e enviará o erro HTTP oriundo do `HTTPException` para o cliente.
+Isso também significa que, se você está escrevendo uma função de utilidade, a qual você está chamando dentro da sua função de operação de rota, e você lança o `HTTPException` dentro da função de utilidade, o resto do seu código não será executado dentro da função de operação de rota. Ao contrário, o `HTTPException` irá finalizar a requisição no mesmo instante e enviará o erro HTTP oriundo do `HTTPException` para o cliente.
O benefício de lançar uma exceção em vez de retornar um valor ficará mais evidente na seção sobre Dependências e Segurança.
Neste exemplo, quando o cliente pede, na requisição, por um item cujo ID não existe, a exceção com o status code `404` é lançada:
-{* ../../docs_src/handling_errors/tutorial001_py39.py hl[11] *}
+{* ../../docs_src/handling_errors/tutorial001_py310.py hl[11] *}
### A response resultante { #the-resulting-response }
@@ -77,7 +77,7 @@ Você provavelmente não precisará utilizar esses headers diretamente no seu c
Mas caso você precise, para um cenário mais complexo, você pode adicionar headers customizados:
-{* ../../docs_src/handling_errors/tutorial002_py39.py hl[14] *}
+{* ../../docs_src/handling_errors/tutorial002_py310.py hl[14] *}
## Instale manipuladores de exceções customizados { #install-custom-exception-handlers }
@@ -87,9 +87,9 @@ Digamos que você tenha uma exceção customizada `UnicornException` que você (
Nesse cenário, se você precisa manipular essa exceção de modo global com o FastAPI, você pode adicionar um manipulador de exceção customizada com `@app.exception_handler()`.
-{* ../../docs_src/handling_errors/tutorial003_py39.py hl[5:7,13:18,24] *}
+{* ../../docs_src/handling_errors/tutorial003_py310.py hl[5:7,13:18,24] *}
-Nesse cenário, se você fizer uma requisição para `/unicorns/yolo`, a *operação de caminho* vai lançar (`raise`) o `UnicornException`.
+Nesse cenário, se você fizer uma requisição para `/unicorns/yolo`, a *operação de rota* vai lançar (`raise`) o `UnicornException`.
Essa exceção será manipulada, contudo, pelo `unicorn_exception_handler`.
@@ -125,7 +125,7 @@ Para sobrescrevê-lo, importe o `RequestValidationError` e use-o com o `@app.exc
O manipulador de exceções receberá um `Request` e a exceção.
-{* ../../docs_src/handling_errors/tutorial004_py39.py hl[2,14:19] *}
+{* ../../docs_src/handling_errors/tutorial004_py310.py hl[2,14:19] *}
Se você for ao `/items/foo`, em vez de receber o JSON padrão com o erro:
@@ -157,7 +157,7 @@ Do mesmo modo, você pode sobrescrever o `HTTPException`.
Por exemplo, você pode querer retornar uma *response* em *plain text* ao invés de um JSON para os seguintes erros:
-{* ../../docs_src/handling_errors/tutorial004_py39.py hl[3:4,9:11,25] *}
+{* ../../docs_src/handling_errors/tutorial004_py310.py hl[3:4,9:11,25] *}
/// note | Detalhes Técnicos
@@ -181,7 +181,7 @@ O `RequestValidationError` contém o `body` que ele recebeu de dados inválidos.
Você pode utilizá-lo enquanto desenvolve seu app para registrar o *body* e debugá-lo, e assim retorná-lo ao usuário, etc.
-{* ../../docs_src/handling_errors/tutorial005_py39.py hl[14] *}
+{* ../../docs_src/handling_errors/tutorial005_py310.py hl[14] *}
Tente enviar um item inválido como este:
@@ -237,6 +237,6 @@ from starlette.exceptions import HTTPException as StarletteHTTPException
Se você quer usar a exceção em conjunto com o mesmo manipulador de exceção *default* do **FastAPI**, você pode importar e re-usar esses manipuladores de exceção do `fastapi.exception_handlers`:
-{* ../../docs_src/handling_errors/tutorial006_py39.py hl[2:5,15,21] *}
+{* ../../docs_src/handling_errors/tutorial006_py310.py hl[2:5,15,21] *}
Nesse exemplo você apenas imprime (`print`) o erro com uma mensagem expressiva. Mesmo assim, dá para pegar a ideia. Você pode usar a exceção e então apenas re-usar o manipulador de exceção *default*.
diff --git a/docs/pt/docs/tutorial/header-params.md b/docs/pt/docs/tutorial/header-params.md
index a0deb98bee..a56f5805e0 100644
--- a/docs/pt/docs/tutorial/header-params.md
+++ b/docs/pt/docs/tutorial/header-params.md
@@ -12,7 +12,7 @@ Primeiro importe `Header`:
Então declare os paramêtros de cabeçalho usando a mesma estrutura que em `Path`, `Query` e `Cookie`.
-O primeiro valor é o valor padrão, você pode passar todas as validações adicionais ou parâmetros de anotação:
+Você pode definir o valor padrão, assim como todas as validações extras ou parâmetros de anotação:
{* ../../docs_src/header_params/tutorial001_an_py310.py hl[9] *}
diff --git a/docs/pt/docs/tutorial/metadata.md b/docs/pt/docs/tutorial/metadata.md
index df77e56484..476b5c806e 100644
--- a/docs/pt/docs/tutorial/metadata.md
+++ b/docs/pt/docs/tutorial/metadata.md
@@ -1,4 +1,4 @@
-# Metadados e Urls de Documentos { #metadata-and-docs-urls }
+# Metadados e URLs da Documentação { #metadata-and-docs-urls }
Você pode personalizar várias configurações de metadados na sua aplicação **FastAPI**.
@@ -18,7 +18,7 @@ Você pode definir os seguintes campos que são usados na especificação OpenAP
Você pode defini-los da seguinte maneira:
-{* ../../docs_src/metadata/tutorial001_py39.py hl[3:16, 19:32] *}
+{* ../../docs_src/metadata/tutorial001_py310.py hl[3:16, 19:32] *}
/// tip | Dica
@@ -32,11 +32,11 @@ Com essa configuração, a documentação automática da API se pareceria com:
## Identificador de Licença { #license-identifier }
-Desde o OpenAPI 3.1.0 e FastAPI 0.99.0, você também pode definir o license_info com um identifier em vez de uma url.
+Desde o OpenAPI 3.1.0 e FastAPI 0.99.0, você também pode definir o `license_info` com um `identifier` em vez de uma `url`.
Por exemplo:
-{* ../../docs_src/metadata/tutorial001_1_py39.py hl[31] *}
+{* ../../docs_src/metadata/tutorial001_1_py310.py hl[31] *}
## Metadados para tags { #metadata-for-tags }
@@ -58,7 +58,7 @@ Vamos tentar isso em um exemplo com tags para `users` e `items`.
Crie metadados para suas tags e passe-os para o parâmetro `openapi_tags`:
-{* ../../docs_src/metadata/tutorial004_py39.py hl[3:16,18] *}
+{* ../../docs_src/metadata/tutorial004_py310.py hl[3:16,18] *}
Observe que você pode usar Markdown dentro das descrições. Por exemplo, "login" será exibido em negrito (**login**) e "fancy" será exibido em itálico (_fancy_).
@@ -72,7 +72,7 @@ Você não precisa adicionar metadados para todas as tags que você usa.
Use o parâmetro `tags` com suas *operações de rota* (e `APIRouter`s) para atribuí-los a diferentes tags:
-{* ../../docs_src/metadata/tutorial004_py39.py hl[21,26] *}
+{* ../../docs_src/metadata/tutorial004_py310.py hl[21,26] *}
/// info | Informação
@@ -100,7 +100,7 @@ Mas você pode configurá-lo com o parâmetro `openapi_url`.
Por exemplo, para defini-lo para ser servido em `/api/v1/openapi.json`:
-{* ../../docs_src/metadata/tutorial002_py39.py hl[3] *}
+{* ../../docs_src/metadata/tutorial002_py310.py hl[3] *}
Se você quiser desativar completamente o esquema OpenAPI, pode definir `openapi_url=None`, o que também desativará as interfaces de documentação que o utilizam.
@@ -117,4 +117,4 @@ Você pode configurar as duas interfaces de documentação incluídas:
Por exemplo, para definir o Swagger UI para ser servido em `/documentation` e desativar o ReDoc:
-{* ../../docs_src/metadata/tutorial003_py39.py hl[3] *}
+{* ../../docs_src/metadata/tutorial003_py310.py hl[3] *}
diff --git a/docs/pt/docs/tutorial/middleware.md b/docs/pt/docs/tutorial/middleware.md
index b49c1eaa11..7cccfcb6ac 100644
--- a/docs/pt/docs/tutorial/middleware.md
+++ b/docs/pt/docs/tutorial/middleware.md
@@ -31,13 +31,13 @@ A função middleware recebe:
* Então ela retorna a `response` gerada pela *operação de rota* correspondente.
* Você pode então modificar ainda mais o `response` antes de retorná-lo.
-{* ../../docs_src/middleware/tutorial001_py39.py hl[8:9,11,14] *}
+{* ../../docs_src/middleware/tutorial001_py310.py hl[8:9,11,14] *}
/// tip | Dica
Tenha em mente que cabeçalhos proprietários personalizados podem ser adicionados usando o prefixo `X-`.
-Mas se você tiver cabeçalhos personalizados desejando que um cliente em um navegador esteja apto a ver, você precisa adicioná-los às suas configurações CORS ([CORS (Cross-Origin Resource Sharing)](cors.md){.internal-link target=_blank}) usando o parâmetro `expose_headers` documentado em
Documentos CORS da Starlette.
+Mas se você tiver cabeçalhos personalizados desejando que um cliente em um navegador esteja apto a ver, você precisa adicioná-los às suas configurações CORS ([CORS (Cross-Origin Resource Sharing)](cors.md){.internal-link target=_blank}) usando o parâmetro `expose_headers` documentado em
Documentação CORS da Starlette.
///
@@ -57,7 +57,7 @@ E também depois que a `response` é gerada, antes de retorná-la.
Por exemplo, você pode adicionar um cabeçalho personalizado `X-Process-Time` contendo o tempo em segundos que levou para processar a solicitação e gerar uma resposta:
-{* ../../docs_src/middleware/tutorial001_py39.py hl[10,12:13] *}
+{* ../../docs_src/middleware/tutorial001_py310.py hl[10,12:13] *}
/// tip | Dica
diff --git a/docs/pt/docs/tutorial/path-operation-configuration.md b/docs/pt/docs/tutorial/path-operation-configuration.md
index 2527c28922..c17b12e2bd 100644
--- a/docs/pt/docs/tutorial/path-operation-configuration.md
+++ b/docs/pt/docs/tutorial/path-operation-configuration.md
@@ -46,7 +46,7 @@ Nestes casos, pode fazer sentido armazenar as tags em um `Enum`.
**FastAPI** suporta isso da mesma maneira que com strings simples:
-{* ../../docs_src/path_operation_configuration/tutorial002b_py39.py hl[1,8:10,13,18] *}
+{* ../../docs_src/path_operation_configuration/tutorial002b_py310.py hl[1,8:10,13,18] *}
## Resumo e descrição { #summary-and-description }
@@ -56,7 +56,7 @@ Você pode adicionar um `summary` e uma `description`:
## Descrição do docstring { #description-from-docstring }
-Como as descrições tendem a ser longas e cobrir várias linhas, você pode declarar a descrição da *operação de rota* na
docstring da função e o **FastAPI** irá lê-la de lá.
+Como as descrições tendem a ser longas e cobrir várias linhas, você pode declarar a descrição da *operação de rota* na
docstring da função e o **FastAPI** irá lê-la de lá.
Você pode escrever
Markdown na docstring, ele será interpretado e exibido corretamente (levando em conta a indentação da docstring).
@@ -90,9 +90,9 @@ Então, se você não fornecer uma, o **FastAPI** irá gerar automaticamente uma
## Descontinuar uma *operação de rota* { #deprecate-a-path-operation }
-Se você precisar marcar uma *operação de rota* como
descontinuada, mas sem removê-la, passe o parâmetro `deprecated`:
+Se você precisar marcar uma *operação de rota* como
descontinuada, mas sem removê-la, passe o parâmetro `deprecated`:
-{* ../../docs_src/path_operation_configuration/tutorial006_py39.py hl[16] *}
+{* ../../docs_src/path_operation_configuration/tutorial006_py310.py hl[16] *}
Ela será claramente marcada como descontinuada nas documentações interativas:
diff --git a/docs/pt/docs/tutorial/path-params-numeric-validations.md b/docs/pt/docs/tutorial/path-params-numeric-validations.md
index 9f12ba38fe..bb2e154f43 100644
--- a/docs/pt/docs/tutorial/path-params-numeric-validations.md
+++ b/docs/pt/docs/tutorial/path-params-numeric-validations.md
@@ -54,11 +54,11 @@ Isso não faz diferença para o **FastAPI**. Ele vai detectar os parâmetros pel
Então, você pode declarar sua função assim:
-{* ../../docs_src/path_params_numeric_validations/tutorial002_py39.py hl[7] *}
+{* ../../docs_src/path_params_numeric_validations/tutorial002_py310.py hl[7] *}
Mas tenha em mente que, se você usar `Annotated`, você não terá esse problema, não fará diferença, pois você não está usando valores padrão de parâmetros de função para `Query()` ou `Path()`.
-{* ../../docs_src/path_params_numeric_validations/tutorial002_an_py39.py *}
+{* ../../docs_src/path_params_numeric_validations/tutorial002_an_py310.py *}
## Ordene os parâmetros de acordo com sua necessidade, truques { #order-the-parameters-as-you-need-tricks }
@@ -81,15 +81,15 @@ Se você quiser:
Passe `*`, como o primeiro parâmetro da função.
-O Python não fará nada com esse `*`, mas saberá que todos os parâmetros seguintes devem ser chamados como argumentos nomeados (pares chave-valor), também conhecidos como
kwargs. Mesmo que eles não tenham um valor padrão.
+O Python não fará nada com esse `*`, mas saberá que todos os parâmetros seguintes devem ser chamados como argumentos nomeados (pares chave-valor), também conhecidos como
kwargs. Mesmo que eles não tenham um valor padrão.
-{* ../../docs_src/path_params_numeric_validations/tutorial003_py39.py hl[7] *}
+{* ../../docs_src/path_params_numeric_validations/tutorial003_py310.py hl[7] *}
### Melhor com `Annotated` { #better-with-annotated }
Tenha em mente que, se você usar `Annotated`, como você não está usando valores padrão de parâmetros de função, você não terá esse problema e provavelmente não precisará usar `*`.
-{* ../../docs_src/path_params_numeric_validations/tutorial003_an_py39.py hl[10] *}
+{* ../../docs_src/path_params_numeric_validations/tutorial003_an_py310.py hl[10] *}
## Validações numéricas: maior que ou igual { #number-validations-greater-than-or-equal }
@@ -97,7 +97,7 @@ Com `Query` e `Path` (e outras que você verá depois) você pode declarar restr
Aqui, com `ge=1`, `item_id` precisará ser um número inteiro “`g`reater than or `e`qual” a `1`.
-{* ../../docs_src/path_params_numeric_validations/tutorial004_an_py39.py hl[10] *}
+{* ../../docs_src/path_params_numeric_validations/tutorial004_an_py310.py hl[10] *}
## Validações numéricas: maior que e menor que ou igual { #number-validations-greater-than-and-less-than-or-equal }
@@ -106,7 +106,7 @@ O mesmo se aplica a:
* `gt`: maior que (`g`reater `t`han)
* `le`: menor que ou igual (`l`ess than or `e`qual)
-{* ../../docs_src/path_params_numeric_validations/tutorial005_an_py39.py hl[10] *}
+{* ../../docs_src/path_params_numeric_validations/tutorial005_an_py310.py hl[10] *}
## Validações numéricas: floats, maior que e menor que { #number-validations-floats-greater-than-and-less-than }
@@ -118,7 +118,7 @@ Assim, `0.5` seria um valor válido. Mas `0.0` ou `0` não seriam.
E o mesmo para
lt.
-{* ../../docs_src/path_params_numeric_validations/tutorial006_an_py39.py hl[13] *}
+{* ../../docs_src/path_params_numeric_validations/tutorial006_an_py310.py hl[13] *}
## Recapitulando { #recap }
diff --git a/docs/pt/docs/tutorial/path-params.md b/docs/pt/docs/tutorial/path-params.md
index 1f47ca6e59..e8e420ad0d 100644
--- a/docs/pt/docs/tutorial/path-params.md
+++ b/docs/pt/docs/tutorial/path-params.md
@@ -2,7 +2,7 @@
Você pode declarar "parâmetros" ou "variáveis" de path com a mesma sintaxe usada por strings de formatação do Python:
-{* ../../docs_src/path_params/tutorial001_py39.py hl[6:7] *}
+{* ../../docs_src/path_params/tutorial001_py310.py hl[6:7] *}
O valor do parâmetro de path `item_id` será passado para a sua função como o argumento `item_id`.
@@ -16,7 +16,7 @@ Então, se você executar este exemplo e acessar
conversão { #data-conversion }
+## Dados conversão { #data-conversion }
Se você executar este exemplo e abrir seu navegador em http://127.0.0.1:8000/items/3, você verá uma resposta:
@@ -35,7 +35,7 @@ Se você executar este exemplo e abrir seu navegador em
"parsing" automático do request.
+Então, com essa declaração de tipo, o **FastAPI** fornece "parsing" automático do request.
///
## Validação de dados { #data-validation }
@@ -110,19 +110,19 @@ E então você também pode ter um path `/users/{user_id}` para obter dados sobr
Como as *operações de rota* são avaliadas em ordem, você precisa garantir que o path para `/users/me` seja declarado antes do de `/users/{user_id}`:
-{* ../../docs_src/path_params/tutorial003_py39.py hl[6,11] *}
+{* ../../docs_src/path_params/tutorial003_py310.py hl[6,11] *}
Caso contrário, o path para `/users/{user_id}` também corresponderia a `/users/me`, "achando" que está recebendo um parâmetro `user_id` com o valor `"me"`.
Da mesma forma, você não pode redefinir uma operação de rota:
-{* ../../docs_src/path_params/tutorial003b_py39.py hl[6,11] *}
+{* ../../docs_src/path_params/tutorial003b_py310.py hl[6,11] *}
A primeira sempre será usada, já que o path corresponde primeiro.
## Valores predefinidos { #predefined-values }
-Se você tem uma *operação de rota* que recebe um *parâmetro de path*, mas quer que os valores válidos possíveis do *parâmetro de path* sejam predefinidos, você pode usar um `Enum` padrão do Python.
+Se você tem uma *operação de rota* que recebe um *parâmetro de path*, mas quer que os valores válidos possíveis do *parâmetro de path* sejam predefinidos, você pode usar um `Enum` padrão do Python.
### Crie uma classe `Enum` { #create-an-enum-class }
@@ -132,17 +132,17 @@ Ao herdar de `str`, a documentação da API saberá que os valores devem ser do
Em seguida, crie atributos de classe com valores fixos, que serão os valores válidos disponíveis:
-{* ../../docs_src/path_params/tutorial005_py39.py hl[1,6:9] *}
+{* ../../docs_src/path_params/tutorial005_py310.py hl[1,6:9] *}
/// tip | Dica
-Se você está se perguntando, "AlexNet", "ResNet" e "LeNet" são apenas nomes de modelos de Aprendizado de Máquina.
+Se você está se perguntando, "AlexNet", "ResNet" e "LeNet" são apenas nomes de modelos de Aprendizado de Máquina modelos.
///
### Declare um parâmetro de path { #declare-a-path-parameter }
Em seguida, crie um *parâmetro de path* com anotação de tipo usando a classe enum que você criou (`ModelName`):
-{* ../../docs_src/path_params/tutorial005_py39.py hl[16] *}
+{* ../../docs_src/path_params/tutorial005_py310.py hl[16] *}
### Verifique a documentação { #check-the-docs }
@@ -158,13 +158,13 @@ O valor do *parâmetro de path* será um *membro de enumeração*.
Você pode compará-lo com o *membro de enumeração* no seu enum `ModelName` criado:
-{* ../../docs_src/path_params/tutorial005_py39.py hl[17] *}
+{* ../../docs_src/path_params/tutorial005_py310.py hl[17] *}
#### Obtenha o valor da enumeração { #get-the-enumeration-value }
Você pode obter o valor real (um `str` neste caso) usando `model_name.value`, ou, em geral, `your_enum_member.value`:
-{* ../../docs_src/path_params/tutorial005_py39.py hl[20] *}
+{* ../../docs_src/path_params/tutorial005_py310.py hl[20] *}
/// tip | Dica
Você também pode acessar o valor `"lenet"` com `ModelName.lenet.value`.
@@ -176,7 +176,7 @@ Você pode retornar *membros de enum* da sua *operação de rota*, até mesmo an
Eles serão convertidos para seus valores correspondentes (strings neste caso) antes de serem retornados ao cliente:
-{* ../../docs_src/path_params/tutorial005_py39.py hl[18,21,23] *}
+{* ../../docs_src/path_params/tutorial005_py310.py hl[18,21,23] *}
No seu cliente, você receberá uma resposta JSON como:
@@ -215,7 +215,7 @@ Nesse caso, o nome do parâmetro é `file_path`, e a última parte, `:path`, diz
Então, você pode usá-lo com:
-{* ../../docs_src/path_params/tutorial004_py39.py hl[6] *}
+{* ../../docs_src/path_params/tutorial004_py310.py hl[6] *}
/// tip | Dica
Você pode precisar que o parâmetro contenha `/home/johndoe/myfile.txt`, com uma barra inicial (`/`).
@@ -227,8 +227,8 @@ Nesse caso, a URL seria: `/files//home/johndoe/myfile.txt`, com uma barra dupla
Com o **FastAPI**, ao usar declarações de tipo do Python curtas, intuitivas e padrão, você obtém:
-- Suporte no editor: verificações de erro, autocompletar, etc.
-- "Parsing" de dados
+- Suporte no editor: verificações de erro, preenchimento automático, etc.
+- "parsing" de dados
- Validação de dados
- Anotação da API e documentação automática
diff --git a/docs/pt/docs/tutorial/query-param-models.md b/docs/pt/docs/tutorial/query-param-models.md
index 42d2604cd4..7fc59c0335 100644
--- a/docs/pt/docs/tutorial/query-param-models.md
+++ b/docs/pt/docs/tutorial/query-param-models.md
@@ -18,10 +18,9 @@ Declare os **parâmetros de consulta** que você precisa em um **modelo Pydantic
O **FastAPI** **extrairá** os dados para **cada campo** dos **parâmetros de consulta** presentes na requisição, e fornecerá o modelo Pydantic que você definiu.
+## Verifique a Documentação { #check-the-docs }
-## Verifique os Documentos { #check-the-docs }
-
-Você pode ver os parâmetros de consulta nos documentos de IU em `/docs`:
+Você pode ver os parâmetros de consulta na IU da documentação em `/docs`:

@@ -29,9 +28,9 @@ Você pode ver os parâmetros de consulta nos documentos de IU em `/docs`:
## Restrinja Parâmetros de Consulta Extras { #forbid-extra-query-parameters }
-Em alguns casos especiais (provavelmente não muito comuns), você queira **restrinjir** os parâmetros de consulta que deseja receber.
+Em alguns casos especiais (provavelmente não muito comuns), você queira **restringir** os parâmetros de consulta que deseja receber.
-Você pode usar a configuração do modelo Pydantic para `forbid` (proibir) qualquer campo `extra`:
+Você pode usar a configuração do modelo Pydantic para `forbid` qualquer campo `extra`:
{* ../../docs_src/query_param_models/tutorial002_an_py310.py hl[10] *}
@@ -43,7 +42,7 @@ Por exemplo, se o cliente tentar enviar um parâmetro de consulta `tool` com o v
https://example.com/items/?limit=10&tool=plumbus
```
-Eles receberão um retorno de **erro** informando-os que o parâmentro de consulta `tool` não é permitido:
+Eles receberão um retorno de **erro** informando-os que o parâmetro de consulta `tool` não é permitido:
```json
{
diff --git a/docs/pt/docs/tutorial/query-params-str-validations.md b/docs/pt/docs/tutorial/query-params-str-validations.md
index c93a941e52..b76b76a268 100644
--- a/docs/pt/docs/tutorial/query-params-str-validations.md
+++ b/docs/pt/docs/tutorial/query-params-str-validations.md
@@ -18,7 +18,7 @@ Ter `str | None` permitirá que seu editor lhe ofereça melhor suporte e detecte
## Validação adicional { #additional-validation }
-Vamos impor que, embora `q` seja opcional, sempre que for fornecido, **seu comprimento não exceda 50 caracteres**.
+Vamos impor que, embora `q` seja opcional, sempre que for fornecido, seu comprimento não exceda 50 caracteres.
### Importe `Query` e `Annotated` { #import-query-and-annotated }
@@ -47,40 +47,16 @@ Agora é a hora de usá-lo com FastAPI. 🚀
Tínhamos esta anotação de tipo:
-//// tab | Python 3.10+
-
```Python
q: str | None = None
```
-////
-
-//// tab | Python 3.9+
-
-```Python
-q: Union[str, None] = None
-```
-
-////
-
O que faremos é envolver isso com `Annotated`, para que fique assim:
-//// tab | Python 3.10+
-
```Python
q: Annotated[str | None] = None
```
-////
-
-//// tab | Python 3.9+
-
-```Python
-q: Annotated[Union[str, None]] = None
-```
-
-////
-
Ambas as versões significam a mesma coisa, `q` é um parâmetro que pode ser `str` ou `None`, e por padrão é `None`.
Agora vamos pular para a parte divertida. 🎉
@@ -93,23 +69,23 @@ Agora que temos esse `Annotated` onde podemos colocar mais informações (neste
Perceba que o valor padrão continua sendo `None`, então o parâmetro ainda é opcional.
-Mas agora, com `Query(max_length=50)` dentro de `Annotated`, estamos dizendo ao FastAPI que queremos **validação adicional** para este valor, queremos que tenha no máximo 50 caracteres. 😎
+Mas agora, com `Query(max_length=50)` dentro de `Annotated`, estamos dizendo ao FastAPI que queremos validação adicional para este valor, queremos que tenha no máximo 50 caracteres. 😎
/// tip | Dica
-Aqui estamos usando `Query()` porque este é um **parâmetro de consulta**. Mais adiante veremos outros como `Path()`, `Body()`, `Header()` e `Cookie()`, que também aceitam os mesmos argumentos que `Query()`.
+Aqui estamos usando `Query()` porque este é um parâmetro de consulta. Mais adiante veremos outros como `Path()`, `Body()`, `Header()` e `Cookie()`, que também aceitam os mesmos argumentos que `Query()`.
///
Agora o FastAPI vai:
-* **Validar** os dados garantindo que o comprimento máximo seja de 50 caracteres
-* Mostrar um **erro claro** para o cliente quando os dados não forem válidos
-* **Documentar** o parâmetro na *operação de rota* do esquema OpenAPI (então ele aparecerá na **UI de docs automática**)
+* Validar os dados garantindo que o comprimento máximo seja de 50 caracteres
+* Mostrar um erro claro para o cliente quando os dados não forem válidos
+* Documentar o parâmetro na operação de rota do esquema OpenAPI (então ele aparecerá na UI de docs automática)
## Alternativa (antiga): `Query` como valor padrão { #alternative-old-query-as-the-default-value }
-Versões anteriores do FastAPI (antes de
0.95.0) exigiam que você usasse `Query` como valor padrão do seu parâmetro, em vez de colocá-lo em `Annotated`, há uma grande chance de você ver código usando isso por aí, então vou explicar.
+Versões anteriores do FastAPI (antes de
0.95.0) exigiam que você usasse `Query` como valor padrão do seu parâmetro, em vez de colocá-lo em `Annotated`, há uma grande chance de você ver código usando isso por aí, então vou explicar.
/// tip | Dica
@@ -144,7 +120,7 @@ Então, podemos passar mais parâmetros para `Query`. Neste caso, o parâmetro `
q: str | None = Query(default=None, max_length=50)
```
-Isso validará os dados, mostrará um erro claro quando os dados não forem válidos e documentará o parâmetro na *operação de rota* do esquema OpenAPI.
+Isso validará os dados, mostrará um erro claro quando os dados não forem válidos e documentará o parâmetro na operação de rota do esquema OpenAPI.
### `Query` como valor padrão ou em `Annotated` { #query-as-the-default-value-or-in-annotated }
@@ -174,13 +150,13 @@ q: str = Query(default="rick")
### Vantagens de `Annotated` { #advantages-of-annotated }
-**Usar `Annotated` é recomendado** em vez do valor padrão nos parâmetros da função, é **melhor** por vários motivos. 🤓
+Usar `Annotated` é recomendado em vez do valor padrão nos parâmetros da função, é melhor por vários motivos. 🤓
-O valor **padrão** do **parâmetro da função** é o **valor padrão real**, isso é mais intuitivo com Python em geral. 😌
+O valor padrão do parâmetro da função é o valor padrão real, isso é mais intuitivo com Python em geral. 😌
-Você poderia **chamar** essa mesma função em **outros lugares** sem FastAPI, e ela **funcionaria como esperado**. Se houver um parâmetro **obrigatório** (sem valor padrão), seu **editor** vai avisar com um erro, e o **Python** também reclamará se você executá-la sem passar o parâmetro obrigatório.
+Você poderia chamar essa mesma função em outros lugares sem FastAPI, e ela funcionaria como esperado. Se houver um parâmetro obrigatório (sem valor padrão), seu editor vai avisar com um erro, e o Python também reclamará se você executá-la sem passar o parâmetro obrigatório.
-Quando você não usa `Annotated` e em vez disso usa o estilo de **valor padrão (antigo)**, se você chamar essa função sem FastAPI em **outros lugares**, terá que **lembrar** de passar os argumentos para a função para que funcione corretamente, caso contrário os valores serão diferentes do esperado (por exemplo, `QueryInfo` ou algo parecido em vez de `str`). E seu editor não vai avisar, e o Python também não vai reclamar ao executar a função, apenas quando as operações internas falharem.
+Quando você não usa `Annotated` e em vez disso usa o estilo de valor padrão (antigo), se você chamar essa função sem FastAPI em outros lugares, terá que lembrar de passar os argumentos para a função para que funcione corretamente, caso contrário os valores serão diferentes do esperado (por exemplo, `QueryInfo` ou algo parecido em vez de `str`). E seu editor não vai avisar, e o Python também não vai reclamar ao executar a função, apenas quando as operações internas falharem.
Como `Annotated` pode ter mais de uma anotação de metadados, você agora pode até usar a mesma função com outras ferramentas, como o
Typer. 🚀
@@ -192,7 +168,7 @@ Você também pode adicionar um parâmetro `min_length`:
## Adicione expressões regulares { #add-regular-expressions }
-Você pode definir um `pattern` de
expressão regular que o parâmetro deve corresponder:
+Você pode definir um `pattern` de
expressão regular que o parâmetro deve corresponder:
{* ../../docs_src/query_params_str_validations/tutorial004_an_py310.py hl[11] *}
@@ -202,9 +178,9 @@ Esse padrão específico de expressão regular verifica se o valor recebido no p
* `fixedquery`: tem exatamente o valor `fixedquery`.
* `$`: termina ali, não tem mais caracteres depois de `fixedquery`.
-Se você se sentir perdido com essas ideias de **"expressão regular"**, não se preocupe. Esse é um assunto difícil para muitas pessoas. Você ainda pode fazer muitas coisas sem precisar de expressões regulares por enquanto.
+Se você se sentir perdido com essas ideias de "expressão regular", não se preocupe. Esse é um assunto difícil para muitas pessoas. Você ainda pode fazer muitas coisas sem precisar de expressões regulares por enquanto.
-Agora você sabe que, sempre que precisar delas, pode usá-las no **FastAPI**.
+Agora você sabe que, sempre que precisar delas, pode usá-las no FastAPI.
## Valores padrão { #default-values }
@@ -212,7 +188,7 @@ Você pode, claro, usar valores padrão diferentes de `None`.
Digamos que você queira declarar o parâmetro de consulta `q` com `min_length` de `3` e ter um valor padrão de `"fixedquery"`:
-{* ../../docs_src/query_params_str_validations/tutorial005_an_py39.py hl[9] *}
+{* ../../docs_src/query_params_str_validations/tutorial005_an_py310.py hl[9] *}
/// note | Nota
@@ -242,7 +218,7 @@ q: Annotated[str | None, Query(min_length=3)] = None
Então, quando você precisa declarar um valor como obrigatório usando `Query`, você pode simplesmente não declarar um valor padrão:
-{* ../../docs_src/query_params_str_validations/tutorial006_an_py39.py hl[9] *}
+{* ../../docs_src/query_params_str_validations/tutorial006_an_py310.py hl[9] *}
### Obrigatório, pode ser `None` { #required-can-be-none }
@@ -266,7 +242,7 @@ Então, com uma URL como:
http://localhost:8000/items/?q=foo&q=bar
```
-você receberia os múltiplos valores dos *parâmetros de consulta* `q` (`foo` e `bar`) em uma `list` Python dentro da sua *função de operação de rota*, no *parâmetro da função* `q`.
+você receberia os múltiplos valores dos parâmetros de consulta `q` (`foo` e `bar`) em uma `list` Python dentro da sua função de operação de rota, no parâmetro da função `q`.
Assim, a resposta para essa URL seria:
@@ -293,7 +269,7 @@ A documentação interativa da API será atualizada de acordo, permitindo múlti
Você também pode definir uma `list` de valores padrão caso nenhum seja fornecido:
-{* ../../docs_src/query_params_str_validations/tutorial012_an_py39.py hl[9] *}
+{* ../../docs_src/query_params_str_validations/tutorial012_an_py310.py hl[9] *}
Se você for até:
@@ -316,13 +292,13 @@ o valor padrão de `q` será: `["foo", "bar"]` e sua resposta será:
Você também pode usar `list` diretamente em vez de `list[str]`:
-{* ../../docs_src/query_params_str_validations/tutorial013_an_py39.py hl[9] *}
+{* ../../docs_src/query_params_str_validations/tutorial013_an_py310.py hl[9] *}
/// note | Nota
Tenha em mente que, neste caso, o FastAPI não verificará o conteúdo da lista.
-Por exemplo, `list[int]` verificaria (e documentaria) que os conteúdos da lista são inteiros. Mas `list` sozinho não.
+Por exemplo, `list[int]` verificaria (and documentaria) que os conteúdos da lista são inteiros. Mas `list` sozinho não.
///
@@ -372,7 +348,7 @@ Então você pode declarar um `alias`, e esse alias será usado para encontrar o
Agora digamos que você não gosta mais desse parâmetro.
-Você tem que deixá-lo por um tempo, pois há clientes usando-o, mas quer que a documentação mostre claramente que ele está
deprecated.
+Você tem que deixá-lo por um tempo, pois há clientes usando-o, mas quer que a documentação mostre claramente que ele está
descontinuado.
Então passe o parâmetro `deprecated=True` para `Query`:
@@ -390,9 +366,9 @@ Para excluir um parâmetro de consulta do OpenAPI gerado (e portanto, dos sistem
## Validação personalizada { #custom-validation }
-Podem existir casos em que você precise fazer alguma **validação personalizada** que não pode ser feita com os parâmetros mostrados acima.
+Podem existir casos em que você precise fazer alguma validação personalizada que não pode ser feita com os parâmetros mostrados acima.
-Nesses casos, você pode usar uma **função validadora personalizada** que é aplicada após a validação normal (por exemplo, depois de validar que o valor é uma `str`).
+Nesses casos, você pode usar uma função validadora personalizada que é aplicada após a validação normal (por exemplo, depois de validar que o valor é uma `str`).
Você pode fazer isso usando o
`AfterValidator` do Pydantic dentro de `Annotated`.
@@ -402,7 +378,7 @@ O Pydantic também tem
ISBN ou com `imdb-` para um ID de URL de filme IMDB:
+Por exemplo, este validador personalizado verifica se o ID do item começa com `isbn-` para um número de livro ISBN ou com `imdb-` para um ID de URL de filme IMDB:
{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py hl[5,16:19,24] *}
@@ -414,15 +390,15 @@ Isso está disponível com a versão 2 do Pydantic ou superior. 😎
/// tip | Dica
-Se você precisar fazer qualquer tipo de validação que exija comunicação com algum **componente externo**, como um banco de dados ou outra API, você deveria usar **Dependências do FastAPI** em vez disso; você aprenderá sobre elas mais adiante.
+Se você precisar fazer qualquer tipo de validação que exija comunicação com algum componente externo, como um banco de dados ou outra API, você deveria usar Dependências do FastAPI em vez disso; você aprenderá sobre elas mais adiante.
-Esses validadores personalizados são para coisas que podem ser verificadas **apenas** com os **mesmos dados** fornecidos na requisição.
+Esses validadores personalizados são para coisas que podem ser verificadas apenas com os mesmos dados fornecidos na requisição.
///
### Entenda esse código { #understand-that-code }
-O ponto importante é apenas usar **`AfterValidator` com uma função dentro de `Annotated`**. Sinta-se à vontade para pular esta parte. 🤸
+O ponto importante é apenas usar `AfterValidator` com uma função dentro de `Annotated`. Sinta-se à vontade para pular esta parte. 🤸
---
@@ -436,17 +412,17 @@ Percebeu? Uma string usando `value.startswith()` pode receber uma tupla, e verif
#### Um item aleatório { #a-random-item }
-Com `data.items()` obtemos um objeto iterável com tuplas contendo a chave e o valor de cada item do dicionário.
+Com `data.items()` obtemos um objeto iterável com tuplas contendo a chave e o valor de cada item do dicionário.
Convertimos esse objeto iterável em uma `list` adequada com `list(data.items())`.
-Em seguida, com `random.choice()` podemos obter um **valor aleatório** da lista, então obtemos uma tupla com `(id, name)`. Será algo como `("imdb-tt0371724", "The Hitchhiker's Guide to the Galaxy")`.
+Em seguida, com `random.choice()` podemos obter um valor aleatório da lista, então obtemos uma tupla com `(id, name)`. Será algo como `("imdb-tt0371724", "The Hitchhiker's Guide to the Galaxy")`.
-Depois **atribuímos esses dois valores** da tupla às variáveis `id` e `name`.
+Depois atribuímos esses dois valores da tupla às variáveis `id` e `name`.
Assim, se o usuário não fornecer um ID de item, ele ainda receberá uma sugestão aleatória.
-...fazemos tudo isso em **uma única linha simples**. 🤯 Você não ama Python? 🐍
+...fazemos tudo isso em uma única linha simples. 🤯 Você não ama Python? 🐍
{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py ln[22:30] hl[29] *}
diff --git a/docs/pt/docs/tutorial/query-params.md b/docs/pt/docs/tutorial/query-params.md
index 8826602a25..f429885660 100644
--- a/docs/pt/docs/tutorial/query-params.md
+++ b/docs/pt/docs/tutorial/query-params.md
@@ -2,7 +2,7 @@
Quando você declara outros parâmetros na função que não fazem parte dos parâmetros da rota, esses parâmetros são automaticamente interpretados como parâmetros de "consulta".
-{* ../../docs_src/query_params/tutorial001_py39.py hl[9] *}
+{* ../../docs_src/query_params/tutorial001_py310.py hl[9] *}
A consulta é o conjunto de pares chave-valor que vai depois de `?` na URL, separado pelo caractere `&`.
@@ -24,7 +24,7 @@ Mas quando você declara eles com os tipos do Python (no exemplo acima, como `in
Todo o processo que era aplicado para parâmetros de rota também é aplicado para parâmetros de consulta:
* Suporte do editor (obviamente)
-* "Parsing" de dados
+* "análise" de dados
* Validação de dados
* Documentação automática
@@ -127,7 +127,7 @@ Caso você não queira adicionar um valor específico mas queira apenas torná-l
Porém, quando você quiser fazer com que o parâmetro de consulta seja obrigatório, você pode simplesmente não declarar nenhum valor como padrão.
-{* ../../docs_src/query_params/tutorial005_py39.py hl[6:7] *}
+{* ../../docs_src/query_params/tutorial005_py310.py hl[6:7] *}
Aqui o parâmetro de consulta `needy` é um valor obrigatório, do tipo `str`.
diff --git a/docs/pt/docs/tutorial/request-files.md b/docs/pt/docs/tutorial/request-files.md
index 5d0891163a..1364a1dd46 100644
--- a/docs/pt/docs/tutorial/request-files.md
+++ b/docs/pt/docs/tutorial/request-files.md
@@ -20,13 +20,13 @@ Isso é necessário, visto que os arquivos enviados são enviados como "dados de
Importe `File` e `UploadFile` de `fastapi`:
-{* ../../docs_src/request_files/tutorial001_an_py39.py hl[3] *}
+{* ../../docs_src/request_files/tutorial001_an_py310.py hl[3] *}
## Definir Parâmetros `File` { #define-file-parameters }
Crie parâmetros de arquivo da mesma forma que você faria para `Body` ou `Form`:
-{* ../../docs_src/request_files/tutorial001_an_py39.py hl[9] *}
+{* ../../docs_src/request_files/tutorial001_an_py310.py hl[9] *}
/// info | Informação
@@ -54,7 +54,7 @@ Mas há muitos casos em que você pode se beneficiar do uso de `UploadFile`.
Defina um parâmetro de arquivo com um tipo de `UploadFile`:
-{* ../../docs_src/request_files/tutorial001_an_py39.py hl[14] *}
+{* ../../docs_src/request_files/tutorial001_an_py310.py hl[14] *}
Utilizar `UploadFile` tem várias vantagens sobre `bytes`:
@@ -121,7 +121,7 @@ Dados de formulários normalmente são codificados usando o "media type" `applic
Mas quando o formulário inclui arquivos, ele é codificado como `multipart/form-data`. Se você usar `File`, o **FastAPI** saberá que tem que pegar os arquivos da parte correta do corpo da requisição.
-Se você quiser ler mais sobre essas codificações e campos de formulário, vá para a MDN web docs para POST.
+Se você quiser ler mais sobre essas codificações e campos de formulário, vá para a
MDN web docs para POST.
///
@@ -143,7 +143,7 @@ Você pode tornar um arquivo opcional usando anotações de tipo padrão e defin
Você também pode usar `File()` com `UploadFile`, por exemplo, para definir metadados adicionais:
-{* ../../docs_src/request_files/tutorial001_03_an_py39.py hl[9,15] *}
+{* ../../docs_src/request_files/tutorial001_03_an_py310.py hl[9,15] *}
## Uploads de Múltiplos Arquivos { #multiple-file-uploads }
@@ -153,13 +153,13 @@ Eles serão associados ao mesmo "campo de formulário" enviado usando "dados de
Para usar isso, declare uma lista de `bytes` ou `UploadFile`:
-{* ../../docs_src/request_files/tutorial002_an_py39.py hl[10,15] *}
+{* ../../docs_src/request_files/tutorial002_an_py310.py hl[10,15] *}
Você receberá, tal como declarado, uma `list` de `bytes` ou `UploadFile`.
/// note | Detalhes Técnicos
-Você pode também pode usar `from starlette.responses import HTMLResponse`.
+Você também pode usar `from starlette.responses import HTMLResponse`.
**FastAPI** providencia o mesmo `starlette.responses` que `fastapi.responses` apenas como uma conveniência para você, o desenvolvedor. Mas a maioria das respostas disponíveis vem diretamente do Starlette.
@@ -169,7 +169,7 @@ Você pode também pode usar `from starlette.responses import HTMLResponse`.
Da mesma forma de antes, você pode usar `File()` para definir parâmetros adicionais, mesmo para `UploadFile`:
-{* ../../docs_src/request_files/tutorial003_an_py39.py hl[11,18:20] *}
+{* ../../docs_src/request_files/tutorial003_an_py310.py hl[11,18:20] *}
## Recapitulando { #recap }
diff --git a/docs/pt/docs/tutorial/request-form-models.md b/docs/pt/docs/tutorial/request-form-models.md
index 8eeffac2ad..38f160aa83 100644
--- a/docs/pt/docs/tutorial/request-form-models.md
+++ b/docs/pt/docs/tutorial/request-form-models.md
@@ -24,7 +24,7 @@ Isto é suportado desde a versão `0.113.0` do FastAPI. 🤓
Você precisa apenas declarar um **modelo Pydantic** com os campos que deseja receber como **campos de formulários**, e então declarar o parâmetro como um `Form`:
-{* ../../docs_src/request_form_models/tutorial001_an_py39.py hl[9:11,15] *}
+{* ../../docs_src/request_form_models/tutorial001_an_py310.py hl[9:11,15] *}
O **FastAPI** irá **extrair** as informações para **cada campo** dos **dados do formulário** na requisição e dar para você o modelo Pydantic que você definiu.
@@ -42,13 +42,13 @@ Em alguns casos de uso especiais (provavelmente não muito comum), você pode de
/// note | Nota
-Isso é suportado deste a versão `0.114.0` do FastAPI. 🤓
+Isso é suportado desde a versão `0.114.0` do FastAPI. 🤓
///
Você pode utilizar a configuração de modelo do Pydantic para `proibir` qualquer campo `extra`:
-{* ../../docs_src/request_form_models/tutorial002_an_py39.py hl[12] *}
+{* ../../docs_src/request_form_models/tutorial002_an_py310.py hl[12] *}
Caso um cliente tente enviar informações adicionais, ele receberá um retorno de **erro**.
diff --git a/docs/pt/docs/tutorial/request-forms-and-files.md b/docs/pt/docs/tutorial/request-forms-and-files.md
index 277fc2f600..8b5f034e9e 100644
--- a/docs/pt/docs/tutorial/request-forms-and-files.md
+++ b/docs/pt/docs/tutorial/request-forms-and-files.md
@@ -16,13 +16,13 @@ $ pip install python-multipart
## Importe `File` e `Form` { #import-file-and-form }
-{* ../../docs_src/request_forms_and_files/tutorial001_an_py39.py hl[3] *}
+{* ../../docs_src/request_forms_and_files/tutorial001_an_py310.py hl[3] *}
## Defina parâmetros de `File` e `Form` { #define-file-and-form-parameters }
Crie parâmetros de arquivo e formulário da mesma forma que você faria para `Body` ou `Query`:
-{* ../../docs_src/request_forms_and_files/tutorial001_an_py39.py hl[10:12] *}
+{* ../../docs_src/request_forms_and_files/tutorial001_an_py310.py hl[10:12] *}
Os arquivos e campos de formulário serão carregados como dados de formulário e você receberá os arquivos e campos de formulário.
@@ -30,7 +30,7 @@ E você pode declarar alguns dos arquivos como `bytes` e alguns como `UploadFile
/// warning | Atenção
-Você pode declarar vários parâmetros `File` e `Form` em uma *operação de caminho*, mas não é possível declarar campos `Body` para receber como JSON, pois a requisição terá o corpo codificado usando `multipart/form-data` ao invés de `application/json`.
+Você pode declarar vários parâmetros `File` e `Form` em uma *operação de rota*, mas não é possível declarar campos `Body` para receber como JSON, pois a requisição terá o corpo codificado usando `multipart/form-data` ao invés de `application/json`.
Isso não é uma limitação do **FastAPI**, é parte do protocolo HTTP.
@@ -38,4 +38,4 @@ Isso não é uma limitação do **FastAPI**, é parte do protocolo HTTP.
## Recapitulando { #recap }
-Usar `File` e `Form` juntos quando precisar receber dados e arquivos na mesma requisição.
+Use `File` e `Form` juntos quando precisar receber dados e arquivos na mesma requisição.
diff --git a/docs/pt/docs/tutorial/request-forms.md b/docs/pt/docs/tutorial/request-forms.md
index faa50bcbfe..d255d0f9be 100644
--- a/docs/pt/docs/tutorial/request-forms.md
+++ b/docs/pt/docs/tutorial/request-forms.md
@@ -18,17 +18,17 @@ $ pip install python-multipart
Importe `Form` de `fastapi`:
-{* ../../docs_src/request_forms/tutorial001_an_py39.py hl[3] *}
+{* ../../docs_src/request_forms/tutorial001_an_py310.py hl[3] *}
## Defina parâmetros de `Form` { #define-form-parameters }
Crie parâmetros de formulário da mesma forma que você faria para `Body` ou `Query`:
-{* ../../docs_src/request_forms/tutorial001_an_py39.py hl[9] *}
+{* ../../docs_src/request_forms/tutorial001_an_py310.py hl[9] *}
Por exemplo, em uma das maneiras que a especificação OAuth2 pode ser usada (chamada "fluxo de senha"), é necessário enviar um `username` e uma `password` como campos do formulário.
-A
spec exige que os campos sejam exatamente nomeados como `username` e `password` e sejam enviados como campos de formulário, não JSON.
+A
especificação exige que os campos sejam exatamente nomeados como `username` e `password` e sejam enviados como campos de formulário, não JSON.
Com `Form` você pode declarar as mesmas configurações que com `Body` (e `Query`, `Path`, `Cookie`), incluindo validação, exemplos, um alias (por exemplo, `user-name` em vez de `username`), etc.
diff --git a/docs/pt/docs/tutorial/response-model.md b/docs/pt/docs/tutorial/response-model.md
index 8a7a712488..e3b97b630f 100644
--- a/docs/pt/docs/tutorial/response-model.md
+++ b/docs/pt/docs/tutorial/response-model.md
@@ -183,7 +183,7 @@ Pode haver casos em que você retorna algo que não é um campo Pydantic válido
O caso mais comum seria [retornar uma Response diretamente, conforme explicado posteriormente na documentação avançada](../advanced/response-directly.md){.internal-link target=_blank}.
-{* ../../docs_src/response_model/tutorial003_02_py39.py hl[8,10:11] *}
+{* ../../docs_src/response_model/tutorial003_02_py310.py hl[8,10:11] *}
Este caso simples é tratado automaticamente pelo FastAPI porque a anotação do tipo de retorno é a classe (ou uma subclasse de) `Response`.
@@ -193,7 +193,7 @@ E as ferramentas também ficarão felizes porque `RedirectResponse` e `JSO
Você também pode usar uma subclasse de `Response` na anotação de tipo:
-{* ../../docs_src/response_model/tutorial003_03_py39.py hl[8:9] *}
+{* ../../docs_src/response_model/tutorial003_03_py310.py hl[8:9] *}
Isso também funcionará porque `RedirectResponse` é uma subclasse de `Response`, e o FastAPI tratará automaticamente este caso simples.
@@ -201,7 +201,7 @@ Isso também funcionará porque `RedirectResponse` é uma subclasse de `Response
Mas quando você retorna algum outro objeto arbitrário que não é um tipo Pydantic válido (por exemplo, um objeto de banco de dados) e você o anota dessa forma na função, o FastAPI tentará criar um modelo de resposta Pydantic a partir dessa anotação de tipo e falhará.
-O mesmo aconteceria se você tivesse algo como uma
união entre tipos diferentes onde um ou mais deles não são tipos Pydantic válidos, por exemplo, isso falharia 💥:
+O mesmo aconteceria se você tivesse algo como uma
união entre tipos diferentes onde um ou mais deles não são tipos Pydantic válidos, por exemplo, isso falharia 💥:
{* ../../docs_src/response_model/tutorial003_04_py310.py hl[8] *}
@@ -290,7 +290,7 @@ Se os dados tiverem os mesmos valores que os padrões, como o item com ID `baz`:
}
```
-O FastAPI é inteligente o suficiente (na verdade, o Pydantic é inteligente o suficiente) para perceber que, embora `description`, `tax` e `tags` tenham os mesmos valores que os padrões, eles foram definidos explicitamente (em vez de retirados dos padrões).
+O FastAPI é inteligente o suficiente (na verdade, o Pydantic é inteligente o suficiente) para perceber que, embora `description`, `tax` e `tags` tenham os mesmos valores que os padrões, eles foram definidos explícita e diretamente (em vez de retirados dos padrões).
Portanto, eles serão incluídos na resposta JSON.
diff --git a/docs/pt/docs/tutorial/response-status-code.md b/docs/pt/docs/tutorial/response-status-code.md
index 756c86dada..a3f8d8a568 100644
--- a/docs/pt/docs/tutorial/response-status-code.md
+++ b/docs/pt/docs/tutorial/response-status-code.md
@@ -8,7 +8,7 @@ Da mesma forma que você pode especificar um modelo de resposta, você também p
* `@app.delete()`
* etc.
-{* ../../docs_src/response_status_code/tutorial001_py39.py hl[6] *}
+{* ../../docs_src/response_status_code/tutorial001_py310.py hl[6] *}
/// note | Nota
@@ -66,7 +66,7 @@ Resumidamente:
/// tip | Dica
-Para saber mais sobre cada código de status e qual código serve para quê, verifique a
documentação do MDN sobre códigos de status HTTP.
+Para saber mais sobre cada código de status e qual código serve para quê, verifique a
documentação do MDN sobre códigos de status HTTP.
///
@@ -74,7 +74,7 @@ Para saber mais sobre cada código de status e qual código serve para quê, ver
Vamos ver o exemplo anterior novamente:
-{* ../../docs_src/response_status_code/tutorial001_py39.py hl[6] *}
+{* ../../docs_src/response_status_code/tutorial001_py310.py hl[6] *}
`201` é o código de status para "Criado".
@@ -82,7 +82,7 @@ Mas você não precisa memorizar o que cada um desses códigos significa.
Você pode usar as variáveis de conveniência de `fastapi.status`.
-{* ../../docs_src/response_status_code/tutorial002_py39.py hl[1,6] *}
+{* ../../docs_src/response_status_code/tutorial002_py310.py hl[1,6] *}
Eles são apenas uma conveniência, eles possuem o mesmo número, mas dessa forma você pode usar o preenchimento automático do editor para encontrá-los:
diff --git a/docs/pt/docs/tutorial/schema-extra-example.md b/docs/pt/docs/tutorial/schema-extra-example.md
index 2d62ffd851..560fda908e 100644
--- a/docs/pt/docs/tutorial/schema-extra-example.md
+++ b/docs/pt/docs/tutorial/schema-extra-example.md
@@ -74,7 +74,7 @@ Você também pode, é claro, passar vários `examples`:
Quando fizer isso, os exemplos farão parte do **JSON Schema** interno para esses dados do body.
-No entanto,
no momento em que isto foi escrito, o Swagger UI, a ferramenta responsável por exibir a UI da documentação, não suporta mostrar vários exemplos para os dados no **JSON Schema**. Mas leia abaixo para uma solução alternativa.
+No entanto,
no momento em que isto foi escrito, o Swagger UI, a ferramenta responsável por exibir a UI da documentação, não suporta mostrar vários exemplos para os dados no **JSON Schema**. Mas leia abaixo para uma solução alternativa.
### `examples` específicos do OpenAPI { #openapi-specific-examples }
diff --git a/docs/pt/docs/tutorial/security/first-steps.md b/docs/pt/docs/tutorial/security/first-steps.md
index 715a21b6ef..f0edd57533 100644
--- a/docs/pt/docs/tutorial/security/first-steps.md
+++ b/docs/pt/docs/tutorial/security/first-steps.md
@@ -20,7 +20,7 @@ Vamos primeiro usar o código e ver como funciona, e depois voltaremos para ente
Copie o exemplo em um arquivo `main.py`:
-{* ../../docs_src/security/tutorial001_an_py39.py *}
+{* ../../docs_src/security/tutorial001_an_py310.py *}
## Execute-o { #run-it }
@@ -132,7 +132,7 @@ Nesse caso, o **FastAPI** também fornece as ferramentas para construí-la.
Quando criamos uma instância da classe `OAuth2PasswordBearer`, passamos o parâmetro `tokenUrl`. Esse parâmetro contém a URL que o client (o frontend rodando no navegador do usuário) usará para enviar o `username` e o `password` para obter um token.
-{* ../../docs_src/security/tutorial001_an_py39.py hl[8] *}
+{* ../../docs_src/security/tutorial001_an_py310.py hl[8] *}
/// tip | Dica
@@ -156,7 +156,7 @@ Isso ocorre porque ele usa o mesmo nome da especificação do OpenAPI. Assim, se
///
-A variável `oauth2_scheme` é uma instância de `OAuth2PasswordBearer`, mas também é "chamável" (callable).
+A variável `oauth2_scheme` é uma instância de `OAuth2PasswordBearer`, mas também é um "callable".
Ela pode ser chamada como:
@@ -170,7 +170,7 @@ Então, pode ser usada com `Depends`.
Agora você pode passar esse `oauth2_scheme` em uma dependência com `Depends`.
-{* ../../docs_src/security/tutorial001_an_py39.py hl[12] *}
+{* ../../docs_src/security/tutorial001_an_py310.py hl[12] *}
Essa dependência fornecerá uma `str` que é atribuída ao parâmetro `token` da função de operação de rota.
diff --git a/docs/pt/docs/tutorial/security/get-current-user.md b/docs/pt/docs/tutorial/security/get-current-user.md
index 2135ae236d..4c6397c31f 100644
--- a/docs/pt/docs/tutorial/security/get-current-user.md
+++ b/docs/pt/docs/tutorial/security/get-current-user.md
@@ -2,7 +2,7 @@
No capítulo anterior, o sistema de segurança (que é baseado no sistema de injeção de dependências) estava fornecendo à *função de operação de rota* um `token` como uma `str`:
-{* ../../docs_src/security/tutorial001_an_py39.py hl[12] *}
+{* ../../docs_src/security/tutorial001_an_py310.py hl[12] *}
Mas isso ainda não é tão útil.
diff --git a/docs/pt/docs/tutorial/security/index.md b/docs/pt/docs/tutorial/security/index.md
index d3de3e0509..f4c92ea567 100644
--- a/docs/pt/docs/tutorial/security/index.md
+++ b/docs/pt/docs/tutorial/security/index.md
@@ -88,7 +88,6 @@ OpenAPI define os seguintes esquemas de segurança:
* `openIdConnect`: tem uma forma para definir como descobrir automaticamente o dado da autenticação OAuth2.
* Essa descoberta automática é o que é definido na especificação OpenID Connect.
-
/// tip | Dica
Integração com outros provedores de autenticação/autorização como Google, Facebook, X (Twitter), GitHub, etc. é bem possível e relativamente fácil.
@@ -99,7 +98,7 @@ O problema mais complexo é criar um provedor de autenticação/autorização co
## **FastAPI** utilitários { #fastapi-utilities }
-**FastAPI** fornece várias ferramentas para cada um desses esquemas de segurança no módulo `fastapi.security` que simplesmente usa esses mecanismos de segurança.
+**FastAPI** fornece várias ferramentas para cada um desses esquemas de segurança no módulo `fastapi.security` que simplificam o uso desses mecanismos de segurança.
Nos próximos capítulos você irá ver como adicionar segurança à sua API usando essas ferramentas disponibilizadas pelo **FastAPI**.
diff --git a/docs/pt/docs/tutorial/security/oauth2-jwt.md b/docs/pt/docs/tutorial/security/oauth2-jwt.md
index f68b8c39ea..4ba38b9f04 100644
--- a/docs/pt/docs/tutorial/security/oauth2-jwt.md
+++ b/docs/pt/docs/tutorial/security/oauth2-jwt.md
@@ -116,7 +116,11 @@ E outra função utilitária para verificar se uma senha recebida corresponde ao
E outra para autenticar e retornar um usuário.
-{* ../../docs_src/security/tutorial004_an_py310.py hl[8,49,56:57,60:61,70:76] *}
+{* ../../docs_src/security/tutorial004_an_py310.py hl[8,49,51,58:59,62:63,72:79] *}
+
+Quando `authenticate_user` é chamado com um nome de usuário que não existe no banco de dados, ainda executamos `verify_password` contra um hash fictício.
+
+Isso garante que o endpoint leve aproximadamente o mesmo tempo para responder, seja o nome de usuário válido ou não, prevenindo **timing attacks** que poderiam ser usados para enumerar nomes de usuário existentes.
/// note | Nota
@@ -152,7 +156,7 @@ Defina um modelo Pydantic que será usado no endpoint de token para a resposta.
Crie uma função utilitária para gerar um novo token de acesso.
-{* ../../docs_src/security/tutorial004_an_py310.py hl[4,7,13:15,29:31,79:87] *}
+{* ../../docs_src/security/tutorial004_an_py310.py hl[4,7,13:15,29:31,82:90] *}
## Atualize as dependências { #update-the-dependencies }
@@ -162,7 +166,7 @@ Decodifique o token recebido, verifique-o e retorne o usuário atual.
Se o token for inválido, retorne um erro HTTP imediatamente.
-{* ../../docs_src/security/tutorial004_an_py310.py hl[90:107] *}
+{* ../../docs_src/security/tutorial004_an_py310.py hl[93:110] *}
## Atualize a *operação de rota* `/token` { #update-the-token-path-operation }
@@ -170,7 +174,7 @@ Crie um `timedelta` com o tempo de expiração do token.
Crie um token de acesso JWT real e o retorne.
-{* ../../docs_src/security/tutorial004_an_py310.py hl[118:133] *}
+{* ../../docs_src/security/tutorial004_an_py310.py hl[121:136] *}
### Detalhes técnicos sobre o "sujeito" `sub` do JWT { #technical-details-about-the-jwt-subject-sub }
diff --git a/docs/pt/docs/tutorial/static-files.md b/docs/pt/docs/tutorial/static-files.md
index 04a02c7f96..0b2d0718f2 100644
--- a/docs/pt/docs/tutorial/static-files.md
+++ b/docs/pt/docs/tutorial/static-files.md
@@ -7,7 +7,7 @@ Você pode servir arquivos estáticos automaticamente a partir de um diretório
* Importe `StaticFiles`.
* "Monte" uma instância de `StaticFiles()` em um path específico.
-{* ../../docs_src/static_files/tutorial001_py39.py hl[2,6] *}
+{* ../../docs_src/static_files/tutorial001_py310.py hl[2,6] *}
/// note | Detalhes Técnicos
diff --git a/docs/pt/docs/tutorial/testing.md b/docs/pt/docs/tutorial/testing.md
index e56edcb8c2..44dc2d2257 100644
--- a/docs/pt/docs/tutorial/testing.md
+++ b/docs/pt/docs/tutorial/testing.md
@@ -30,7 +30,7 @@ Use o objeto `TestClient` da mesma forma que você faz com `httpx`.
Escreva instruções `assert` simples com as expressões Python padrão que você precisa verificar (novamente, `pytest` padrão).
-{* ../../docs_src/app_testing/tutorial001_py39.py hl[2,12,15:18] *}
+{* ../../docs_src/app_testing/tutorial001_py310.py hl[2,12,15:18] *}
/// tip | Dica
@@ -76,7 +76,7 @@ Digamos que você tenha uma estrutura de arquivo conforme descrito em [Aplicaç
No arquivo `main.py` você tem sua aplicação **FastAPI**:
-{* ../../docs_src/app_testing/app_a_py39/main.py *}
+{* ../../docs_src/app_testing/app_a_py310/main.py *}
### Arquivo de teste { #testing-file }
@@ -92,7 +92,7 @@ Então você poderia ter um arquivo `test_main.py` com seus testes. Ele poderia
Como esse arquivo está no mesmo pacote, você pode usar importações relativas para importar o objeto `app` do módulo `main` (`main.py`):
-{* ../../docs_src/app_testing/app_a_py39/test_main.py hl[3] *}
+{* ../../docs_src/app_testing/app_a_py310/test_main.py hl[3] *}
...e ter o código para os testes como antes.
diff --git a/docs/pt/docs/virtual-environments.md b/docs/pt/docs/virtual-environments.md
index 5736f71095..e222c61ad6 100644
--- a/docs/pt/docs/virtual-environments.md
+++ b/docs/pt/docs/virtual-environments.md
@@ -1,6 +1,6 @@
# Ambientes Virtuais { #virtual-environments }
-Ao trabalhar em projetos Python, você provavelmente deve usar um **ambiente virtual** (ou um mecanismo similar) para isolar os pacotes que você instala para cada projeto.
+Ao trabalhar em projetos Python, você provavelmente deveria usar um **ambiente virtual** (ou um mecanismo similar) para isolar os pacotes que você instala para cada projeto.
/// info | Informação
@@ -53,7 +53,7 @@ $ cd awesome-project
## Crie um ambiente virtual { #create-a-virtual-environment }
-Ao começar a trabalhar em um projeto Python **pela primeira vez**, crie um ambiente virtual **
dentro do seu projeto**.
+Ao começar a trabalhar em um projeto Python **pela primeira vez**, crie um ambiente virtual **
dentro do seu projeto**.
/// tip | Dica
@@ -166,7 +166,7 @@ $ source .venv/Scripts/activate
Toda vez que você instalar um **novo pacote** naquele ambiente, **ative** o ambiente novamente.
-Isso garante que, se você usar um **programa de terminal (
CLI)** instalado por esse pacote, você usará aquele do seu ambiente virtual e não qualquer outro que possa ser instalado globalmente, provavelmente com uma versão diferente do que você precisa.
+Isso garante que, se você usar um **programa de terminal (
CLI)** instalado por esse pacote, você usará aquele do seu ambiente virtual e não qualquer outro que possa ser instalado globalmente, provavelmente com uma versão diferente do que você precisa.
///
@@ -176,7 +176,7 @@ Verifique se o ambiente virtual está ativo (o comando anterior funcionou).
/// tip | Dica
-Isso é **opcional**, mas é uma boa maneira de **verificar** se tudo está funcionando conforme o esperado e se você está usando o ambiente virtual intendido.
+Isso é **opcional**, mas é uma boa maneira de **verificar** se tudo está funcionando conforme o esperado e se você está usando o ambiente virtual pretendido.
///
@@ -220,7 +220,7 @@ Se você usar
diff --git a/docs/ru/docs/_llm-test.md b/docs/ru/docs/_llm-test.md
index 6a0272f3a5..247d3a964f 100644
--- a/docs/ru/docs/_llm-test.md
+++ b/docs/ru/docs/_llm-test.md
@@ -202,11 +202,6 @@ works(foo="bar") # Это работает 🎉
* XWT
* PSGI
-### abbr даёт объяснение { #the-abbr-gives-an-explanation }
-
-* кластер
-* Глубокое обучение
-
### abbr даёт полную расшифровку и объяснение { #the-abbr-gives-a-full-phrase-and-an-explanation }
* MDN
@@ -224,6 +219,11 @@ works(foo="bar") # Это работает 🎉
////
+## HTML-элементы "dfn" { #html-dfn-elements }
+
+* кластер
+* Глубокое обучение
+
## Заголовки { #headings }
//// tab | Тест
diff --git a/docs/ru/docs/advanced/additional-responses.md b/docs/ru/docs/advanced/additional-responses.md
index fca4f072da..ca36ba20e3 100644
--- a/docs/ru/docs/advanced/additional-responses.md
+++ b/docs/ru/docs/advanced/additional-responses.md
@@ -26,7 +26,7 @@
Например, чтобы объявить ещё один ответ со статус-кодом `404` и Pydantic-моделью `Message`, можно написать:
-{* ../../docs_src/additional_responses/tutorial001_py39.py hl[18,22] *}
+{* ../../docs_src/additional_responses/tutorial001_py310.py hl[18,22] *}
/// note | Примечание
@@ -203,7 +203,7 @@
А также ответ со статус-кодом `200`, который использует ваш `response_model`, но включает пользовательский `example`:
-{* ../../docs_src/additional_responses/tutorial003_py39.py hl[20:31] *}
+{* ../../docs_src/additional_responses/tutorial003_py310.py hl[20:31] *}
Всё это будет объединено и включено в ваш OpenAPI и отображено в документации API:
diff --git a/docs/ru/docs/advanced/advanced-dependencies.md b/docs/ru/docs/advanced/advanced-dependencies.md
index fb2643cd5c..686a0cf91e 100644
--- a/docs/ru/docs/advanced/advanced-dependencies.md
+++ b/docs/ru/docs/advanced/advanced-dependencies.md
@@ -18,7 +18,7 @@
Для этого объявляем метод `__call__`:
-{* ../../docs_src/dependencies/tutorial011_an_py39.py hl[12] *}
+{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[12] *}
В этом случае именно `__call__` **FastAPI** использует для проверки дополнительных параметров и подзависимостей, и именно он будет вызван, чтобы позже передать значение параметру в вашей *функции-обработчике пути*.
@@ -26,7 +26,7 @@
Теперь мы можем использовать `__init__`, чтобы объявить параметры экземпляра, с помощью которых будем «параметризовать» зависимость:
-{* ../../docs_src/dependencies/tutorial011_an_py39.py hl[9] *}
+{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[9] *}
В этом случае **FastAPI** вовсе не трогает `__init__` и не зависит от него — мы используем его напрямую в нашем коде.
@@ -34,7 +34,7 @@
Мы можем создать экземпляр этого класса так:
-{* ../../docs_src/dependencies/tutorial011_an_py39.py hl[18] *}
+{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[18] *}
Так мы «параметризуем» нашу зависимость: теперь внутри неё хранится "bar" в атрибуте `checker.fixed_content`.
@@ -50,7 +50,7 @@ checker(q="somequery")
…и передаст возвращённое значение как значение зависимости в параметр `fixed_content_included` нашей *функции-обработчика пути*:
-{* ../../docs_src/dependencies/tutorial011_an_py39.py hl[22] *}
+{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[22] *}
/// tip | Совет
diff --git a/docs/ru/docs/advanced/advanced-python-types.md b/docs/ru/docs/advanced/advanced-python-types.md
new file mode 100644
index 0000000000..62dcf8c4f1
--- /dev/null
+++ b/docs/ru/docs/advanced/advanced-python-types.md
@@ -0,0 +1,61 @@
+# Продвинутые типы Python { #advanced-python-types }
+
+Ниже несколько дополнительных идей, которые могут быть полезны при работе с типами Python.
+
+## Использование `Union` или `Optional` { #using-union-or-optional }
+
+Если по какой-то причине ваш код не может использовать `|`, например, если это не аннотация типов, а что-то вроде `response_model=`, вместо вертикальной черты (`|`) можно использовать `Union` из `typing`.
+
+Например, вы можете объявить, что значение может быть `str` или `None`:
+
+```python
+from typing import Union
+
+
+def say_hi(name: Union[str, None]):
+ print(f"Hi {name}!")
+```
+
+В `typing` также есть сокращение, чтобы объявить, что значение может быть `None`, — `Optional`.
+
+Вот совет с моей очень субъективной точки зрения:
+
+- 🚨 Избегайте использования `Optional[SomeType]`
+- Вместо этого ✨ используйте **`Union[SomeType, None]`** ✨.
+
+Оба варианта эквивалентны и под капотом это одно и то же, но я бы рекомендовал `Union` вместо `Optional`, потому что слово «optional» может наводить на мысль, что значение необязательное, тогда как на самом деле это означает «значение может быть `None`», даже если оно не является необязательным и по-прежнему требуется.
+
+По-моему, `Union[SomeType, None]` более явно передаёт смысл.
+
+Речь только о словах и названиях. Но эти слова могут влиять на то, как вы и ваша команда думаете о коде.
+
+В качестве примера возьмём такую функцию:
+
+```python
+from typing import Optional
+
+
+def say_hi(name: Optional[str]):
+ print(f"Hey {name}!")
+```
+
+Параметр `name` объявлен как `Optional[str]`, но он не является необязательным: вы не можете вызвать функцию без этого параметра:
+
+```Python
+say_hi() # О нет, это вызывает ошибку! 😱
+```
+
+Параметр `name` по-прежнему обязателен (не «optional»), так как у него нет значения по умолчанию. При этом `name` принимает `None` в качестве значения:
+
+```Python
+say_hi(name=None) # Это работает, None допустим 🎉
+```
+
+Хорошая новость: в большинстве случаев вы сможете просто использовать `|` для объявления объединений типов:
+
+```python
+def say_hi(name: str | None):
+ print(f"Hey {name}!")
+```
+
+Так что обычно вам не о чем переживать из‑за названий вроде `Optional` и `Union`. 😎
diff --git a/docs/ru/docs/advanced/async-tests.md b/docs/ru/docs/advanced/async-tests.md
index e689704066..52939c2559 100644
--- a/docs/ru/docs/advanced/async-tests.md
+++ b/docs/ru/docs/advanced/async-tests.md
@@ -32,11 +32,11 @@
Файл `main.py`:
-{* ../../docs_src/async_tests/app_a_py39/main.py *}
+{* ../../docs_src/async_tests/app_a_py310/main.py *}
Файл `test_main.py` содержит тесты для `main.py`, теперь он может выглядеть так:
-{* ../../docs_src/async_tests/app_a_py39/test_main.py *}
+{* ../../docs_src/async_tests/app_a_py310/test_main.py *}
## Запуск тестов { #run-it }
@@ -56,7 +56,7 @@ $ pytest
Маркер `@pytest.mark.anyio` говорит pytest, что тестовая функция должна быть вызвана асинхронно:
-{* ../../docs_src/async_tests/app_a_py39/test_main.py hl[7] *}
+{* ../../docs_src/async_tests/app_a_py310/test_main.py hl[7] *}
/// tip | Подсказка
@@ -66,7 +66,7 @@ $ pytest
Затем мы можем создать `AsyncClient` со ссылкой на приложение и посылать асинхронные запросы, используя `await`.
-{* ../../docs_src/async_tests/app_a_py39/test_main.py hl[9:12] *}
+{* ../../docs_src/async_tests/app_a_py310/test_main.py hl[9:12] *}
Это эквивалентно следующему:
@@ -94,6 +94,6 @@ response = client.get('/')
/// tip | Подсказка
-Если вы столкнулись с `RuntimeError: Task attached to a different loop` при вызове асинхронных функций в ваших тестах (например, при использовании MongoDB's MotorClient), то не забывайте инициализировать объекты, которым нужен цикл событий (event loop), только внутри асинхронных функций, например, в `'@app.on_event("startup")` callback.
+Если вы столкнулись с `RuntimeError: Task attached to a different loop` при вызове асинхронных функций в ваших тестах (например, при использовании
MongoDB's MotorClient), то не забывайте инициализировать объекты, которым нужен цикл событий (event loop), только внутри асинхронных функций, например, в `@app.on_event("startup")` callback.
///
diff --git a/docs/ru/docs/advanced/behind-a-proxy.md b/docs/ru/docs/advanced/behind-a-proxy.md
index f78da01a09..ec75ed3698 100644
--- a/docs/ru/docs/advanced/behind-a-proxy.md
+++ b/docs/ru/docs/advanced/behind-a-proxy.md
@@ -44,7 +44,7 @@ $ fastapi run --forwarded-allow-ips="*"
Например, вы объявили операцию пути `/items/`:
-{* ../../docs_src/behind_a_proxy/tutorial001_01_py39.py hl[6] *}
+{* ../../docs_src/behind_a_proxy/tutorial001_01_py310.py hl[6] *}
Если клиент обратится к `/items`, по умолчанию произойдёт редирект на `/items/`.
@@ -115,7 +115,7 @@ sequenceDiagram
Хотя весь ваш код написан с расчётом, что путь один — `/app`.
-{* ../../docs_src/behind_a_proxy/tutorial001_py39.py hl[6] *}
+{* ../../docs_src/behind_a_proxy/tutorial001_py310.py hl[6] *}
Прокси будет «обрезать» префикс пути на лету перед передачей запроса на сервер приложения (скорее всего Uvicorn, запущенный через FastAPI CLI), поддерживая у вашего приложения иллюзию, что его обслуживают по `/app`, чтобы вам не пришлось менять весь код и добавлять префикс `/api/v1`.
@@ -193,7 +193,7 @@ $ fastapi run main.py --forwarded-allow-ips="*" --root-path /api/v1
Здесь мы добавляем его в сообщение лишь для демонстрации.
-{* ../../docs_src/behind_a_proxy/tutorial001_py39.py hl[8] *}
+{* ../../docs_src/behind_a_proxy/tutorial001_py310.py hl[8] *}
Затем, если вы запустите Uvicorn так:
@@ -220,7 +220,7 @@ $ fastapi run main.py --forwarded-allow-ips="*" --root-path /api/v1
Если нет возможности передать опцию командной строки `--root-path` (или аналог), вы можете указать параметр `root_path` при создании приложения FastAPI:
-{* ../../docs_src/behind_a_proxy/tutorial002_py39.py hl[3] *}
+{* ../../docs_src/behind_a_proxy/tutorial002_py310.py hl[3] *}
Передача `root_path` в `FastAPI` эквивалентна опции командной строки `--root-path` для Uvicorn или Hypercorn.
@@ -241,17 +241,17 @@ $ fastapi run main.py --forwarded-allow-ips="*" --root-path /api/v1
Uvicorn ожидает, что прокси обратится к нему по `http://127.0.0.1:8000/app`, а уже задача прокси — добавить сверху префикс `/api/v1`.
-## О прокси с урезанным префиксом пути { #about-proxies-with-a-stripped-path-prefix }
+## О прокси с функцией удаления префикса пути { #about-proxies-with-a-stripped-path-prefix }
-Помните, что прокси с урезанным префиксом пути — лишь один из вариантов настройки.
+Помните, что прокси с функцией удаления префикса пути — лишь один из вариантов настройки.
-Во многих случаях по умолчанию прокси будет без урезанного префикса пути.
+Во многих случаях по умолчанию прокси будет без функции удаления префикса пути.
-В таком случае (без урезанного префикса) прокси слушает, например, по адресу `https://myawesomeapp.com`, и если браузер идёт на `https://myawesomeapp.com/api/v1/app`, а ваш сервер (например, Uvicorn) слушает на `http://127.0.0.1:8000`, то прокси (без урезанного префикса) обратится к Uvicorn по тому же пути: `http://127.0.0.1:8000/api/v1/app`.
+В таком случае (без функции удаления префикса пути) прокси слушает, например, по адресу `https://myawesomeapp.com`, и если браузер идёт на `https://myawesomeapp.com/api/v1/app`, а ваш сервер (например, Uvicorn) слушает на `http://127.0.0.1:8000`, то прокси (без урезанного префикса) обратится к Uvicorn по тому же пути: `http://127.0.0.1:8000/api/v1/app`.
## Локальное тестирование с Traefik { #testing-locally-with-traefik }
-Вы можете легко поэкспериментировать локально с урезанным префиксом пути, используя
Traefik.
+Вы можете легко поэкспериментировать локально с функцией удаления префикса пути, используя
Traefik.
Скачайте Traefik — это один бинарный файл; распакуйте архив и запустите его прямо из терминала.
@@ -400,7 +400,7 @@ $ fastapi run main.py --forwarded-allow-ips="*" --root-path /api/v1
Например:
-{* ../../docs_src/behind_a_proxy/tutorial003_py39.py hl[4:7] *}
+{* ../../docs_src/behind_a_proxy/tutorial003_py310.py hl[4:7] *}
Будет сгенерирована схема OpenAPI примерно такая:
@@ -455,7 +455,7 @@ $ fastapi run main.py --forwarded-allow-ips="*" --root-path /api/v1
Если вы не хотите, чтобы FastAPI добавлял автоматический сервер, используя `root_path`, укажите параметр `root_path_in_servers=False`:
-{* ../../docs_src/behind_a_proxy/tutorial004_py39.py hl[9] *}
+{* ../../docs_src/behind_a_proxy/tutorial004_py310.py hl[9] *}
и тогда этот сервер не будет добавлен в схему OpenAPI.
diff --git a/docs/ru/docs/advanced/custom-response.md b/docs/ru/docs/advanced/custom-response.md
index 49550b49ff..b9f91373da 100644
--- a/docs/ru/docs/advanced/custom-response.md
+++ b/docs/ru/docs/advanced/custom-response.md
@@ -30,7 +30,7 @@
Но если вы уверены, что содержимое, которое вы возвращаете, **сериализуемо в JSON**, вы можете передать его напрямую в класс ответа и избежать дополнительных накладных расходов, которые FastAPI понёс бы, пропуская возвращаемое содержимое через `jsonable_encoder` перед передачей в класс ответа.
-{* ../../docs_src/custom_response/tutorial001b_py39.py hl[2,7] *}
+{* ../../docs_src/custom_response/tutorial001b_py310.py hl[2,7] *}
/// info | Информация
@@ -55,7 +55,7 @@
- Импортируйте `HTMLResponse`.
- Передайте `HTMLResponse` в параметр `response_class` вашего декоратора операции пути.
-{* ../../docs_src/custom_response/tutorial002_py39.py hl[2,7] *}
+{* ../../docs_src/custom_response/tutorial002_py310.py hl[2,7] *}
/// info | Информация
@@ -73,17 +73,17 @@
Тот же пример сверху, возвращающий `HTMLResponse`, может выглядеть так:
-{* ../../docs_src/custom_response/tutorial003_py39.py hl[2,7,19] *}
+{* ../../docs_src/custom_response/tutorial003_py310.py hl[2,7,19] *}
/// warning | Предупреждение
-`Response`, возвращённый напрямую вашей функцией-обработчиком пути, не будет задокументирован в OpenAPI (например, `Content-Type` нне будет задокументирова) и не будет виден в автоматически сгенерированной интерактивной документации.
+`Response`, возвращённый напрямую вашей функцией-обработчиком пути, не будет задокументирован в OpenAPI (например, `Content-Type` не будет задокументирован) и не будет виден в автоматически сгенерированной интерактивной документации.
///
/// info | Информация
-Разумеется, фактические заголовок `Content-Type`, статус-код и т.д. возьмутся из объекта `Response`, который вы вернули.
+Разумеется, фактический заголовок `Content-Type`, статус-код и т.д. возьмутся из объекта `Response`, который вы вернули.
///
@@ -97,7 +97,7 @@
Например, это может быть что-то вроде:
-{* ../../docs_src/custom_response/tutorial004_py39.py hl[7,21,23] *}
+{* ../../docs_src/custom_response/tutorial004_py310.py hl[7,21,23] *}
В этом примере функция `generate_html_response()` уже генерирует и возвращает `Response` вместо возврата HTML в `str`.
@@ -136,7 +136,7 @@
FastAPI (фактически Starlette) автоматически добавит заголовок Content-Length. Также будет добавлен заголовок Content-Type, основанный на `media_type` и с добавлением charset для текстовых типов.
-{* ../../docs_src/response_directly/tutorial002_py39.py hl[1,18] *}
+{* ../../docs_src/response_directly/tutorial002_py310.py hl[1,18] *}
### `HTMLResponse` { #htmlresponse }
@@ -146,7 +146,7 @@ FastAPI (фактически Starlette) автоматически добави
Принимает текст или байты и возвращает ответ в виде простого текста.
-{* ../../docs_src/custom_response/tutorial005_py39.py hl[2,7,9] *}
+{* ../../docs_src/custom_response/tutorial005_py310.py hl[2,7,9] *}
### `JSONResponse` { #jsonresponse }
@@ -180,7 +180,7 @@ FastAPI (фактически Starlette) автоматически добави
///
-{* ../../docs_src/custom_response/tutorial001_py39.py hl[2,7] *}
+{* ../../docs_src/custom_response/tutorial001_py310.py hl[2,7] *}
/// tip | Совет
@@ -194,13 +194,13 @@ FastAPI (фактически Starlette) автоматически добави
Вы можете вернуть `RedirectResponse` напрямую:
-{* ../../docs_src/custom_response/tutorial006_py39.py hl[2,9] *}
+{* ../../docs_src/custom_response/tutorial006_py310.py hl[2,9] *}
---
Или можно использовать его в параметре `response_class`:
-{* ../../docs_src/custom_response/tutorial006b_py39.py hl[2,7,9] *}
+{* ../../docs_src/custom_response/tutorial006b_py310.py hl[2,7,9] *}
Если вы сделаете так, то сможете возвращать URL напрямую из своей функции-обработчика пути.
@@ -210,13 +210,13 @@ FastAPI (фактически Starlette) автоматически добави
Также вы можете использовать параметр `status_code` в сочетании с параметром `response_class`:
-{* ../../docs_src/custom_response/tutorial006c_py39.py hl[2,7,9] *}
+{* ../../docs_src/custom_response/tutorial006c_py310.py hl[2,7,9] *}
### `StreamingResponse` { #streamingresponse }
Принимает асинхронный генератор или обычный генератор/итератор и отправляет тело ответа потоково.
-{* ../../docs_src/custom_response/tutorial007_py39.py hl[2,14] *}
+{* ../../docs_src/custom_response/tutorial007_py310.py hl[2,14] *}
#### Использование `StreamingResponse` с файлоподобными объектами { #using-streamingresponse-with-file-like-objects }
@@ -226,7 +226,7 @@ FastAPI (фактически Starlette) автоматически добави
Это включает многие библиотеки для работы с облачным хранилищем, обработки видео и т.д.
-{* ../../docs_src/custom_response/tutorial008_py39.py hl[2,10:12,14] *}
+{* ../../docs_src/custom_response/tutorial008_py310.py hl[2,10:12,14] *}
1. Это функция-генератор. Она является «функцией-генератором», потому что содержит оператор(ы) `yield` внутри.
2. Используя блок `with`, мы гарантируем, что файлоподобный объект будет закрыт после завершения работы функции-генератора. То есть после того, как она закончит отправку ответа.
@@ -255,11 +255,11 @@ FastAPI (фактически Starlette) автоматически добави
Файловые ответы будут содержать соответствующие заголовки `Content-Length`, `Last-Modified` и `ETag`.
-{* ../../docs_src/custom_response/tutorial009_py39.py hl[2,10] *}
+{* ../../docs_src/custom_response/tutorial009_py310.py hl[2,10] *}
Вы также можете использовать параметр `response_class`:
-{* ../../docs_src/custom_response/tutorial009b_py39.py hl[2,8,10] *}
+{* ../../docs_src/custom_response/tutorial009b_py310.py hl[2,8,10] *}
В этом случае вы можете возвращать путь к файлу напрямую из своей функции-обработчика пути.
@@ -273,7 +273,7 @@ FastAPI (фактически Starlette) автоматически добави
Вы могли бы создать `CustomORJSONResponse`. Главное, что вам нужно сделать — реализовать метод `Response.render(content)`, который возвращает содержимое как `bytes`:
-{* ../../docs_src/custom_response/tutorial009c_py39.py hl[9:14,17] *}
+{* ../../docs_src/custom_response/tutorial009c_py310.py hl[9:14,17] *}
Теперь вместо того, чтобы возвращать:
@@ -299,7 +299,7 @@ FastAPI (фактически Starlette) автоматически добави
В примере ниже **FastAPI** будет использовать `ORJSONResponse` по умолчанию во всех операциях пути вместо `JSONResponse`.
-{* ../../docs_src/custom_response/tutorial010_py39.py hl[2,4] *}
+{* ../../docs_src/custom_response/tutorial010_py310.py hl[2,4] *}
/// tip | Совет
diff --git a/docs/ru/docs/advanced/dataclasses.md b/docs/ru/docs/advanced/dataclasses.md
index b3ced37c1e..87a5763c10 100644
--- a/docs/ru/docs/advanced/dataclasses.md
+++ b/docs/ru/docs/advanced/dataclasses.md
@@ -64,7 +64,7 @@ FastAPI построен поверх **Pydantic**, и я показывал в
6. Здесь мы возвращаем словарь, содержащий `items`, который является списком dataclass.
- FastAPI по-прежнему способен
сериализовать данные в JSON.
+ FastAPI по-прежнему способен
сериализовать данные в JSON.
7. Здесь `response_model` использует аннотацию типа — список dataclass `Author`.
diff --git a/docs/ru/docs/advanced/events.md b/docs/ru/docs/advanced/events.md
index db73d9094e..bcb5b000a4 100644
--- a/docs/ru/docs/advanced/events.md
+++ b/docs/ru/docs/advanced/events.md
@@ -30,7 +30,7 @@
Мы создаём асинхронную функцию `lifespan()` с `yield` примерно так:
-{* ../../docs_src/events/tutorial003_py39.py hl[16,19] *}
+{* ../../docs_src/events/tutorial003_py310.py hl[16,19] *}
Здесь мы симулируем дорогую операцию startup по загрузке модели, помещая (фиктивную) функцию модели в словарь с моделями Машинного обучения до `yield`. Этот код будет выполнен до того, как приложение начнет принимать запросы, во время startup.
@@ -48,7 +48,7 @@
Первое, на что стоит обратить внимание, — мы определяем асинхронную функцию с `yield`. Это очень похоже на Зависимости с `yield`.
-{* ../../docs_src/events/tutorial003_py39.py hl[14:19] *}
+{* ../../docs_src/events/tutorial003_py310.py hl[14:19] *}
Первая часть функции, до `yield`, будет выполнена до запуска приложения.
@@ -60,7 +60,7 @@
Это превращает функцию в «асинхронный менеджер контекста».
-{* ../../docs_src/events/tutorial003_py39.py hl[1,13] *}
+{* ../../docs_src/events/tutorial003_py310.py hl[1,13] *}
Менеджер контекста в Python — это то, что можно использовать в операторе `with`. Например, `open()` можно использовать как менеджер контекста:
@@ -82,7 +82,7 @@ async with lifespan(app):
Параметр `lifespan` приложения `FastAPI` принимает асинхронный менеджер контекста, поэтому мы можем передать ему наш новый асинхронный менеджер контекста `lifespan`.
-{* ../../docs_src/events/tutorial003_py39.py hl[22] *}
+{* ../../docs_src/events/tutorial003_py310.py hl[22] *}
## Альтернативные события (устаревшие) { #alternative-events-deprecated }
@@ -104,7 +104,7 @@ async with lifespan(app):
Чтобы добавить функцию, которую нужно запустить до старта приложения, объявите её как обработчик события `"startup"`:
-{* ../../docs_src/events/tutorial001_py39.py hl[8] *}
+{* ../../docs_src/events/tutorial001_py310.py hl[8] *}
В этом случае функция-обработчик события `startup` инициализирует «базу данных» items (это просто `dict`) некоторыми значениями.
@@ -116,7 +116,7 @@ async with lifespan(app):
Чтобы добавить функцию, которую нужно запустить при завершении работы приложения, объявите её как обработчик события `"shutdown"`:
-{* ../../docs_src/events/tutorial002_py39.py hl[6] *}
+{* ../../docs_src/events/tutorial002_py310.py hl[6] *}
Здесь функция-обработчик события `shutdown` запишет строку текста `"Application shutdown"` в файл `log.txt`.
diff --git a/docs/ru/docs/advanced/generate-clients.md b/docs/ru/docs/advanced/generate-clients.md
index 00bdd31fe8..4eb098a88f 100644
--- a/docs/ru/docs/advanced/generate-clients.md
+++ b/docs/ru/docs/advanced/generate-clients.md
@@ -2,7 +2,7 @@
Поскольку **FastAPI** основан на спецификации **OpenAPI**, его API можно описать в стандартном формате, понятном множеству инструментов.
-Это упрощает генерацию актуальной **документации**, клиентских библиотек (
**SDKs**) на разных языках, а также **тестирования** или **воркфлоу автоматизации**, которые остаются синхронизированными с вашим кодом.
+Это упрощает генерацию актуальной **документации**, клиентских библиотек (
**SDKs**) на разных языках, а также **тестирования** или **воркфлоу автоматизации**, которые остаются синхронизированными с вашим кодом.
В этом руководстве вы узнаете, как сгенерировать **TypeScript SDK** для вашего бэкенда на FastAPI.
@@ -40,7 +40,7 @@ FastAPI автоматически генерирует спецификации
Начнём с простого приложения FastAPI:
-{* ../../docs_src/generate_clients/tutorial001_py39.py hl[7:9,12:13,16:17,21] *}
+{* ../../docs_src/generate_clients/tutorial001_py310.py hl[7:9,12:13,16:17,21] *}
Обратите внимание, что *операции пути (обработчики пути)* определяют модели, которые они используют для полезной нагрузки запроса и полезной нагрузки ответа, с помощью моделей `Item` и `ResponseMessage`.
@@ -98,7 +98,7 @@ npx @hey-api/openapi-ts -i http://localhost:8000/openapi.json -o src/client
Например, у вас может быть раздел для **items** и другой раздел для **users**, и они могут быть разделены тегами:
-{* ../../docs_src/generate_clients/tutorial002_py39.py hl[21,26,34] *}
+{* ../../docs_src/generate_clients/tutorial002_py310.py hl[21,26,34] *}
### Генерация TypeScript‑клиента с тегами { #generate-a-typescript-client-with-tags }
@@ -145,7 +145,7 @@ FastAPI использует **уникальный ID** для каждой *о
Затем вы можете передать эту пользовательскую функцию в **FastAPI** через параметр `generate_unique_id_function`:
-{* ../../docs_src/generate_clients/tutorial003_py39.py hl[6:7,10] *}
+{* ../../docs_src/generate_clients/tutorial003_py310.py hl[6:7,10] *}
### Генерация TypeScript‑клиента с пользовательскими ID операций { #generate-a-typescript-client-with-custom-operation-ids }
@@ -157,7 +157,7 @@ FastAPI использует **уникальный ID** для каждой *о
### Предобработка спецификации OpenAPI для генератора клиента { #preprocess-the-openapi-specification-for-the-client-generator }
-Сгенерированном коде всё ещё есть **дублирующаяся информация**.
+В сгенерированном коде всё ещё есть **дублирующаяся информация**.
Мы уже знаем, что этот метод относится к **items**, потому что это слово есть в `ItemsService` (взято из тега), но при этом имя тега всё ещё добавлено префиксом к имени метода. 😕
@@ -167,7 +167,7 @@ FastAPI использует **уникальный ID** для каждой *о
Мы можем скачать OpenAPI JSON в файл `openapi.json`, а затем **убрать этот префикс‑тег** таким скриптом:
-{* ../../docs_src/generate_clients/tutorial004_py39.py *}
+{* ../../docs_src/generate_clients/tutorial004_py310.py *}
//// tab | Node.js
diff --git a/docs/ru/docs/advanced/middleware.md b/docs/ru/docs/advanced/middleware.md
index 5ebe010782..1f1a160604 100644
--- a/docs/ru/docs/advanced/middleware.md
+++ b/docs/ru/docs/advanced/middleware.md
@@ -57,13 +57,13 @@ app.add_middleware(UnicornMiddleware, some_config="rainbow")
Любой входящий запрос по `http` или `ws` будет перенаправлен на безопасную схему.
-{* ../../docs_src/advanced_middleware/tutorial001_py39.py hl[2,6] *}
+{* ../../docs_src/advanced_middleware/tutorial001_py310.py hl[2,6] *}
## `TrustedHostMiddleware` { #trustedhostmiddleware }
Гарантирует, что во всех входящих запросах корректно установлен `Host`‑заголовок, чтобы защититься от атак на HTTP‑заголовок Host.
-{* ../../docs_src/advanced_middleware/tutorial002_py39.py hl[2,6:8] *}
+{* ../../docs_src/advanced_middleware/tutorial002_py310.py hl[2,6:8] *}
Поддерживаются следующие аргументы:
@@ -78,12 +78,12 @@ app.add_middleware(UnicornMiddleware, some_config="rainbow")
Это middleware обрабатывает как обычные, так и потоковые ответы.
-{* ../../docs_src/advanced_middleware/tutorial003_py39.py hl[2,6] *}
+{* ../../docs_src/advanced_middleware/tutorial003_py310.py hl[2,6] *}
Поддерживаются следующие аргументы:
- `minimum_size` — не сжимать GZip‑ом ответы, размер которых меньше этого минимального значения в байтах. По умолчанию — `500`.
-- `compresslevel` — уровень GZip‑сжатия. Целое число от 1 до 9. По умолчанию — `9`. Более низкое значение — быстреее сжатие, но больший размер файла; более высокое значение — более медленное сжатие, но меньший размер файла.
+- `compresslevel` — уровень GZip‑сжатия. Целое число от 1 до 9. По умолчанию — `9`. Более низкое значение — быстрее сжатие, но больший размер файла; более высокое значение — более медленное сжатие, но меньший размер файла.
## Другие middleware { #other-middlewares }
diff --git a/docs/ru/docs/advanced/openapi-webhooks.md b/docs/ru/docs/advanced/openapi-webhooks.md
index 3a2b9fff74..b477075c11 100644
--- a/docs/ru/docs/advanced/openapi-webhooks.md
+++ b/docs/ru/docs/advanced/openapi-webhooks.md
@@ -16,9 +16,9 @@
Вся логика регистрации URL-адресов для вебхуков и код, который реально отправляет эти запросы, целиком на вашей стороне. Вы пишете это так, как вам нужно, в своем собственном коде.
-## Документирование вебхуков с помощью FastAPI и OpenAPI { #documenting-webhooks-with-fastapi-and-openapi }
+## Документирование вебхуков с помощью **FastAPI** и OpenAPI { #documenting-webhooks-with-fastapi-and-openapi }
-С FastAPI, используя OpenAPI, вы можете определить имена этих вебхуков, типы HTTP-операций, которые ваше приложение может отправлять (например, `POST`, `PUT` и т.д.), а также тела запросов, которые ваше приложение будет отправлять.
+С **FastAPI**, используя OpenAPI, вы можете определить имена этих вебхуков, типы HTTP-операций, которые ваше приложение может отправлять (например, `POST`, `PUT` и т.д.), а также тела запросов, которые ваше приложение будет отправлять.
Это значительно упростит вашим пользователям реализацию их API для приема ваших вебхук-запросов; возможно, они даже смогут автоматически сгенерировать часть кода своего API.
@@ -32,7 +32,7 @@
При создании приложения на **FastAPI** есть атрибут `webhooks`, с помощью которого можно объявлять вебхуки так же, как вы объявляете операции пути (обработчики пути), например с `@app.webhooks.post()`.
-{* ../../docs_src/openapi_webhooks/tutorial001_py39.py hl[9:13,36:53] *}
+{* ../../docs_src/openapi_webhooks/tutorial001_py310.py hl[9:12,15:20] *}
Определенные вами вебхуки попадут в схему **OpenAPI** и в автоматический **интерфейс документации**.
diff --git a/docs/ru/docs/advanced/path-operation-advanced-configuration.md b/docs/ru/docs/advanced/path-operation-advanced-configuration.md
index 86d3a5b630..b8c879bf6f 100644
--- a/docs/ru/docs/advanced/path-operation-advanced-configuration.md
+++ b/docs/ru/docs/advanced/path-operation-advanced-configuration.md
@@ -12,7 +12,7 @@
Нужно убедиться, что он уникален для каждой операции.
-{* ../../docs_src/path_operation_advanced_configuration/tutorial001_py39.py hl[6] *}
+{* ../../docs_src/path_operation_advanced_configuration/tutorial001_py310.py hl[6] *}
### Использование имени *функции-обработчика пути* как operationId { #using-the-path-operation-function-name-as-the-operationid }
@@ -20,7 +20,7 @@
Делать это следует после добавления всех *операций пути*.
-{* ../../docs_src/path_operation_advanced_configuration/tutorial002_py39.py hl[2, 12:21, 24] *}
+{* ../../docs_src/path_operation_advanced_configuration/tutorial002_py310.py hl[2, 12:21, 24] *}
/// tip | Совет
@@ -40,7 +40,7 @@
Чтобы исключить *операцию пути* из генерируемой схемы OpenAPI (а значит, и из автоматических систем документации), используйте параметр `include_in_schema` и установите его в `False`:
-{* ../../docs_src/path_operation_advanced_configuration/tutorial003_py39.py hl[6] *}
+{* ../../docs_src/path_operation_advanced_configuration/tutorial003_py310.py hl[6] *}
## Расширенное описание из docstring { #advanced-description-from-docstring }
@@ -92,7 +92,7 @@
`openapi_extra` может пригодиться, например, чтобы объявить [Расширения OpenAPI](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#specificationExtensions):
-{* ../../docs_src/path_operation_advanced_configuration/tutorial005_py39.py hl[6] *}
+{* ../../docs_src/path_operation_advanced_configuration/tutorial005_py310.py hl[6] *}
Если вы откроете автоматическую документацию API, ваше расширение появится внизу страницы конкретной *операции пути*.
@@ -139,9 +139,9 @@
Это можно сделать с помощью `openapi_extra`:
-{* ../../docs_src/path_operation_advanced_configuration/tutorial006_py39.py hl[19:36, 39:40] *}
+{* ../../docs_src/path_operation_advanced_configuration/tutorial006_py310.py hl[19:36, 39:40] *}
-В этом примере мы не объявляли никакую Pydantic-модель. Фактически тело запроса даже не
распарсено как JSON, оно читается напрямую как `bytes`, а функция `magic_data_reader()` будет отвечать за его парсинг каким-то способом.
+В этом примере мы не объявляли никакую Pydantic-модель. Фактически тело запроса даже не
распарсено как JSON, оно читается напрямую как `bytes`, а функция `magic_data_reader()` будет отвечать за его парсинг каким-то способом.
Тем не менее, мы можем объявить ожидаемую схему для тела запроса.
@@ -153,7 +153,7 @@
Например, в этом приложении мы не используем встроенную функциональность FastAPI для извлечения JSON Schema из моделей Pydantic, равно как и автоматическую валидацию JSON. Мы объявляем тип содержимого HTTP-запроса как YAML, а не JSON:
-{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py39.py hl[15:20, 22] *}
+{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py310.py hl[15:20, 22] *}
Тем не менее, хотя мы не используем встроенную функциональность по умолчанию, мы всё равно используем Pydantic-модель, чтобы вручную сгенерировать JSON Schema для данных, которые мы хотим получить в YAML.
@@ -161,7 +161,7 @@
А затем в нашем коде мы напрямую парсим это содержимое YAML и снова используем ту же Pydantic-модель, чтобы валидировать YAML-содержимое:
-{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py39.py hl[24:31] *}
+{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py310.py hl[24:31] *}
/// tip | Совет
diff --git a/docs/ru/docs/advanced/response-change-status-code.md b/docs/ru/docs/advanced/response-change-status-code.md
index 85d9050ffc..273862bae9 100644
--- a/docs/ru/docs/advanced/response-change-status-code.md
+++ b/docs/ru/docs/advanced/response-change-status-code.md
@@ -20,7 +20,7 @@
И затем вы можете установить `status_code` в этом *временном* объекте ответа.
-{* ../../docs_src/response_change_status_code/tutorial001_py39.py hl[1,9,12] *}
+{* ../../docs_src/response_change_status_code/tutorial001_py310.py hl[1,9,12] *}
После этого вы можете вернуть любой объект, который вам нужен, как обычно (`dict`, модель базы данных и т.д.).
diff --git a/docs/ru/docs/advanced/response-cookies.md b/docs/ru/docs/advanced/response-cookies.md
index 2872d6c0ad..d3662ef8ed 100644
--- a/docs/ru/docs/advanced/response-cookies.md
+++ b/docs/ru/docs/advanced/response-cookies.md
@@ -6,7 +6,7 @@
Затем установить cookies в этом временном объекте ответа.
-{* ../../docs_src/response_cookies/tutorial002_py39.py hl[1, 8:9] *}
+{* ../../docs_src/response_cookies/tutorial002_py310.py hl[1, 8:9] *}
После этого можно вернуть любой объект, как и раньше (например, `dict`, объект модели базы данных и так далее).
@@ -24,7 +24,7 @@
Затем установите cookies и верните этот объект:
-{* ../../docs_src/response_cookies/tutorial001_py39.py hl[10:12] *}
+{* ../../docs_src/response_cookies/tutorial001_py310.py hl[10:12] *}
/// tip | Совет
diff --git a/docs/ru/docs/advanced/response-directly.md b/docs/ru/docs/advanced/response-directly.md
index b452810714..60facdd857 100644
--- a/docs/ru/docs/advanced/response-directly.md
+++ b/docs/ru/docs/advanced/response-directly.md
@@ -54,7 +54,7 @@
Вы можете поместить ваш XML-контент в строку, поместить её в `Response` и вернуть:
-{* ../../docs_src/response_directly/tutorial002_py39.py hl[1,18] *}
+{* ../../docs_src/response_directly/tutorial002_py310.py hl[1,18] *}
## Примечания { #notes }
diff --git a/docs/ru/docs/advanced/response-headers.md b/docs/ru/docs/advanced/response-headers.md
index 8f24f05b07..dc821983bc 100644
--- a/docs/ru/docs/advanced/response-headers.md
+++ b/docs/ru/docs/advanced/response-headers.md
@@ -6,7 +6,7 @@
А затем вы можете устанавливать HTTP-заголовки в этом *временном* объекте ответа.
-{* ../../docs_src/response_headers/tutorial002_py39.py hl[1, 7:8] *}
+{* ../../docs_src/response_headers/tutorial002_py310.py hl[1, 7:8] *}
После этого вы можете вернуть любой нужный объект, как обычно (например, `dict`, модель из базы данных и т.д.).
@@ -22,7 +22,7 @@
Создайте ответ, как описано в [Вернуть Response напрямую](response-directly.md){.internal-link target=_blank}, и передайте заголовки как дополнительный параметр:
-{* ../../docs_src/response_headers/tutorial001_py39.py hl[10:12] *}
+{* ../../docs_src/response_headers/tutorial001_py310.py hl[10:12] *}
/// note | Технические детали
diff --git a/docs/ru/docs/advanced/security/http-basic-auth.md b/docs/ru/docs/advanced/security/http-basic-auth.md
index 41e62d4bf3..a6bfb7c546 100644
--- a/docs/ru/docs/advanced/security/http-basic-auth.md
+++ b/docs/ru/docs/advanced/security/http-basic-auth.md
@@ -20,7 +20,7 @@
* Она возвращает объект типа `HTTPBasicCredentials`:
* Он содержит отправленные `username` и `password`.
-{* ../../docs_src/security/tutorial006_an_py39.py hl[4,8,12] *}
+{* ../../docs_src/security/tutorial006_an_py310.py hl[4,8,12] *}
Когда вы впервые откроете URL (или нажмёте кнопку «Execute» в документации), браузер попросит ввести имя пользователя и пароль:
@@ -40,7 +40,7 @@
Затем можно использовать `secrets.compare_digest()`, чтобы убедиться, что `credentials.username` равен `"stanleyjobson"`, а `credentials.password` — `"swordfish"`.
-{* ../../docs_src/security/tutorial007_an_py39.py hl[1,12:24] *}
+{* ../../docs_src/security/tutorial007_an_py310.py hl[1,12:24] *}
Это было бы похоже на:
@@ -104,4 +104,4 @@ Pythonу придётся сравнить весь общий префикс `s
После того как обнаружено, что учётные данные некорректны, верните `HTTPException` со статус-кодом ответа 401 (тем же, что и при отсутствии учётных данных) и добавьте HTTP-заголовок `WWW-Authenticate`, чтобы браузер снова показал окно входа:
-{* ../../docs_src/security/tutorial007_an_py39.py hl[26:30] *}
+{* ../../docs_src/security/tutorial007_an_py310.py hl[26:30] *}
diff --git a/docs/ru/docs/advanced/settings.md b/docs/ru/docs/advanced/settings.md
index 8408faebff..15537e2b40 100644
--- a/docs/ru/docs/advanced/settings.md
+++ b/docs/ru/docs/advanced/settings.md
@@ -54,7 +54,7 @@ $ pip install "fastapi[all]"
Вы можете использовать все те же возможности валидации и инструменты, что и для Pydantic‑моделей, например разные типы данных и дополнительную валидацию через `Field()`.
-{* ../../docs_src/settings/tutorial001_py39.py hl[2,5:8,11] *}
+{* ../../docs_src/settings/tutorial001_py310.py hl[2,5:8,11] *}
/// tip | Совет
@@ -70,7 +70,7 @@ $ pip install "fastapi[all]"
Затем вы можете использовать новый объект `settings` в вашем приложении:
-{* ../../docs_src/settings/tutorial001_py39.py hl[18:20] *}
+{* ../../docs_src/settings/tutorial001_py310.py hl[18:20] *}
### Запуск сервера { #run-the-server }
@@ -104,11 +104,11 @@ $ ADMIN_EMAIL="deadpool@example.com" APP_NAME="ChimichangApp" fastapi run main.p
Например, у вас может быть файл `config.py` со следующим содержимым:
-{* ../../docs_src/settings/app01_py39/config.py *}
+{* ../../docs_src/settings/app01_py310/config.py *}
А затем использовать его в файле `main.py`:
-{* ../../docs_src/settings/app01_py39/main.py hl[3,11:13] *}
+{* ../../docs_src/settings/app01_py310/main.py hl[3,11:13] *}
/// tip | Совет
@@ -126,7 +126,7 @@ $ ADMIN_EMAIL="deadpool@example.com" APP_NAME="ChimichangApp" fastapi run main.p
Продолжая предыдущий пример, ваш файл `config.py` может выглядеть так:
-{* ../../docs_src/settings/app02_an_py39/config.py hl[10] *}
+{* ../../docs_src/settings/app02_an_py310/config.py hl[10] *}
Обратите внимание, что теперь мы не создаем экземпляр по умолчанию `settings = Settings()`.
@@ -134,7 +134,7 @@ $ ADMIN_EMAIL="deadpool@example.com" APP_NAME="ChimichangApp" fastapi run main.p
Теперь мы создаем зависимость, которая возвращает новый `config.Settings()`.
-{* ../../docs_src/settings/app02_an_py39/main.py hl[6,12:13] *}
+{* ../../docs_src/settings/app02_an_py310/main.py hl[6,12:13] *}
/// tip | Совет
@@ -146,13 +146,13 @@ $ ADMIN_EMAIL="deadpool@example.com" APP_NAME="ChimichangApp" fastapi run main.p
Затем мы можем запросить ее в *функции-обработчике пути* как зависимость и использовать там, где нужно.
-{* ../../docs_src/settings/app02_an_py39/main.py hl[17,19:21] *}
+{* ../../docs_src/settings/app02_an_py310/main.py hl[17,19:21] *}
### Настройки и тестирование { #settings-and-testing }
Далее будет очень просто предоставить другой объект настроек во время тестирования, создав переопределение зависимости для `get_settings`:
-{* ../../docs_src/settings/app02_an_py39/test_main.py hl[9:10,13,21] *}
+{* ../../docs_src/settings/app02_an_py310/test_main.py hl[9:10,13,21] *}
В переопределении зависимости мы задаем новое значение `admin_email` при создании нового объекта `Settings`, а затем возвращаем этот новый объект.
@@ -193,7 +193,7 @@ APP_NAME="ChimichangApp"
Затем обновите ваш `config.py` так:
-{* ../../docs_src/settings/app03_an_py39/config.py hl[9] *}
+{* ../../docs_src/settings/app03_an_py310/config.py hl[9] *}
/// tip | Совет
@@ -226,7 +226,7 @@ def get_settings():
Но так как мы используем декоратор `@lru_cache` сверху, объект `Settings` будет создан только один раз — при первом вызове. ✔️
-{* ../../docs_src/settings/app03_an_py39/main.py hl[1,11] *}
+{* ../../docs_src/settings/app03_an_py310/main.py hl[1,11] *}
Затем при любых последующих вызовах `get_settings()` в зависимостях для следующих запросов, вместо выполнения внутреннего кода `get_settings()` и создания нового объекта `Settings`, будет возвращаться тот же объект, что был возвращен при первом вызове, снова и снова.
diff --git a/docs/ru/docs/advanced/sub-applications.md b/docs/ru/docs/advanced/sub-applications.md
index fa5a683f45..4fd5649ce3 100644
--- a/docs/ru/docs/advanced/sub-applications.md
+++ b/docs/ru/docs/advanced/sub-applications.md
@@ -10,7 +10,7 @@
Сначала создайте основное, верхнего уровня, приложение **FastAPI** и его *операции пути*:
-{* ../../docs_src/sub_applications/tutorial001_py39.py hl[3, 6:8] *}
+{* ../../docs_src/sub_applications/tutorial001_py310.py hl[3, 6:8] *}
### Подприложение { #sub-application }
@@ -18,7 +18,7 @@
Это подприложение — обычное стандартное приложение FastAPI, но именно оно будет «смонтировано»:
-{* ../../docs_src/sub_applications/tutorial001_py39.py hl[11, 14:16] *}
+{* ../../docs_src/sub_applications/tutorial001_py310.py hl[11, 14:16] *}
### Смонтируйте подприложение { #mount-the-sub-application }
@@ -26,7 +26,7 @@
В этом случае оно будет смонтировано по пути `/subapi`:
-{* ../../docs_src/sub_applications/tutorial001_py39.py hl[11, 19] *}
+{* ../../docs_src/sub_applications/tutorial001_py310.py hl[11, 19] *}
### Проверьте автоматическую документацию API { #check-the-automatic-api-docs }
diff --git a/docs/ru/docs/advanced/templates.md b/docs/ru/docs/advanced/templates.md
index 460e2e4660..68adcb5151 100644
--- a/docs/ru/docs/advanced/templates.md
+++ b/docs/ru/docs/advanced/templates.md
@@ -27,7 +27,7 @@ $ pip install jinja2
- Объявите параметр `Request` в *операции пути*, которая будет возвращать шаблон.
- Используйте созданный `templates`, чтобы отрендерить и вернуть `TemplateResponse`; передайте имя шаблона, объект `request` и словарь «context» с парами ключ-значение для использования внутри шаблона Jinja2.
-{* ../../docs_src/templates/tutorial001_py39.py hl[4,11,15:18] *}
+{* ../../docs_src/templates/tutorial001_py310.py hl[4,11,15:18] *}
/// note | Примечание
diff --git a/docs/ru/docs/advanced/testing-events.md b/docs/ru/docs/advanced/testing-events.md
index 82caea845b..452342cdd2 100644
--- a/docs/ru/docs/advanced/testing-events.md
+++ b/docs/ru/docs/advanced/testing-events.md
@@ -2,11 +2,11 @@
Если вам нужно, чтобы `lifespan` выполнялся в ваших тестах, вы можете использовать `TestClient` вместе с оператором `with`:
-{* ../../docs_src/app_testing/tutorial004_py39.py hl[9:15,18,27:28,30:32,41:43] *}
+{* ../../docs_src/app_testing/tutorial004_py310.py hl[9:15,18,27:28,30:32,41:43] *}
Вы можете узнать больше подробностей в статье [Запуск lifespan в тестах на официальном сайте документации Starlette.](https://www.starlette.dev/lifespan/#running-lifespan-in-tests)
Для устаревших событий `startup` и `shutdown` вы можете использовать `TestClient` следующим образом:
-{* ../../docs_src/app_testing/tutorial003_py39.py hl[9:12,20:24] *}
+{* ../../docs_src/app_testing/tutorial003_py310.py hl[9:12,20:24] *}
diff --git a/docs/ru/docs/advanced/testing-websockets.md b/docs/ru/docs/advanced/testing-websockets.md
index b6626679e4..f6fa6a04be 100644
--- a/docs/ru/docs/advanced/testing-websockets.md
+++ b/docs/ru/docs/advanced/testing-websockets.md
@@ -4,7 +4,7 @@
Для этого используйте `TestClient` с менеджером контекста `with`, подключаясь к WebSocket:
-{* ../../docs_src/app_testing/tutorial002_py39.py hl[27:31] *}
+{* ../../docs_src/app_testing/tutorial002_py310.py hl[27:31] *}
/// note | Примечание
diff --git a/docs/ru/docs/advanced/using-request-directly.md b/docs/ru/docs/advanced/using-request-directly.md
index cdf500c0e2..0c091cdeda 100644
--- a/docs/ru/docs/advanced/using-request-directly.md
+++ b/docs/ru/docs/advanced/using-request-directly.md
@@ -29,7 +29,7 @@
Для этого нужно обратиться к запросу напрямую.
-{* ../../docs_src/using_request_directly/tutorial001_py39.py hl[1,7:8] *}
+{* ../../docs_src/using_request_directly/tutorial001_py310.py hl[1,7:8] *}
Если объявить параметр *функции-обработчика пути* с типом `Request`, **FastAPI** поймёт, что нужно передать объект `Request` в этот параметр.
diff --git a/docs/ru/docs/advanced/websockets.md b/docs/ru/docs/advanced/websockets.md
index fa5e4738eb..446cc2505e 100644
--- a/docs/ru/docs/advanced/websockets.md
+++ b/docs/ru/docs/advanced/websockets.md
@@ -38,13 +38,13 @@ $ pip install websockets
Для примера нам нужен наиболее простой способ, который позволит сосредоточиться на серверной части веб‑сокетов и получить рабочий код:
-{* ../../docs_src/websockets/tutorial001_py39.py hl[2,6:38,41:43] *}
+{* ../../docs_src/websockets/tutorial001_py310.py hl[2,6:38,41:43] *}
## Создание `websocket` { #create-a-websocket }
Создайте `websocket` в своем **FastAPI** приложении:
-{* ../../docs_src/websockets/tutorial001_py39.py hl[1,46:47] *}
+{* ../../docs_src/websockets/tutorial001_py310.py hl[1,46:47] *}
/// note | Технические детали
@@ -58,7 +58,7 @@ $ pip install websockets
Через эндпоинт веб-сокета вы можете получать и отправлять сообщения.
-{* ../../docs_src/websockets/tutorial001_py39.py hl[48:52] *}
+{* ../../docs_src/websockets/tutorial001_py310.py hl[48:52] *}
Вы можете получать и отправлять двоичные, текстовые и JSON данные.
@@ -154,7 +154,7 @@ $ fastapi dev main.py
Если веб-сокет соединение закрыто, то `await websocket.receive_text()` вызовет исключение `WebSocketDisconnect`, которое можно поймать и обработать как в этом примере:
-{* ../../docs_src/websockets/tutorial003_py39.py hl[79:81] *}
+{* ../../docs_src/websockets/tutorial003_py310.py hl[79:81] *}
Чтобы воспроизвести пример:
diff --git a/docs/ru/docs/advanced/wsgi.md b/docs/ru/docs/advanced/wsgi.md
index 41d3a169c7..aa630c228e 100644
--- a/docs/ru/docs/advanced/wsgi.md
+++ b/docs/ru/docs/advanced/wsgi.md
@@ -18,7 +18,7 @@
После этого смонтируйте его на путь.
-{* ../../docs_src/wsgi/tutorial001_py39.py hl[1,3,23] *}
+{* ../../docs_src/wsgi/tutorial001_py310.py hl[1,3,23] *}
/// note | Примечание
diff --git a/docs/ru/docs/alternatives.md b/docs/ru/docs/alternatives.md
index 17b54aad2f..1f713c3f39 100644
--- a/docs/ru/docs/alternatives.md
+++ b/docs/ru/docs/alternatives.md
@@ -137,7 +137,7 @@ def read_url():
###
Marshmallow { #marshmallow }
-Одна из основных возможностей, нужных системам API, — «
сериализация» данных, то есть преобразование данных из кода (Python) во что-то, что можно отправить по сети. Например, преобразование объекта с данными из базы в JSON-объект. Преобразование объектов `datetime` в строки и т. п.
+Одна из основных возможностей, нужных системам API, — «
сериализация» данных, то есть преобразование данных из кода (Python) во что-то, что можно отправить по сети. Например, преобразование объекта с данными из базы в JSON-объект. Преобразование объектов `datetime` в строки и т. п.
Ещё одна важная возможность, востребованная API, — валидация данных: убеждаться, что данные валидны с учётом заданных параметров. Например, что какое-то поле — `int`, а не произвольная строка. Это особенно полезно для входящих данных.
@@ -145,7 +145,7 @@ def read_url():
Именно для этих возможностей и был создан Marshmallow. Это отличная библиотека, я много ей пользовался раньше.
-Но она появилась до того, как в Python появились аннотации типов. Поэтому для определения каждой
схемы нужно использовать специальные утилиты и классы, предоставляемые Marshmallow.
+Но она появилась до того, как в Python появились аннотации типов. Поэтому для определения каждой
схемы нужно использовать специальные утилиты и классы, предоставляемые Marshmallow.
/// check | Вдохновило **FastAPI** на
@@ -155,7 +155,7 @@ def read_url():
###
Webargs { #webargs }
-Ещё одна важная возможность для API —
парсинг данных из входящих HTTP-запросов.
+Ещё одна важная возможность для API —
парсинг данных из входящих HTTP-запросов.
Webargs — это инструмент, созданный для этого поверх нескольких фреймворков, включая Flask.
@@ -245,7 +245,7 @@ Flask-apispec был создан теми же разработчиками, ч
В нём встроена система внедрения зависимостей, вдохновлённая Angular 2. Требуется предварительная регистрация «инжектируемых» компонентов (как и во всех известных мне системах внедрения зависимостей), что добавляет многословности и повторяемости кода.
-Поскольку параметры описываются с помощью типов TypeScript (аналог аннотаций типов в Python), поддержка редактора весьма хороша.
+Поскольку параметры описываются с помощью типов TypeScript (аналог аннотаций типов в Python), поддержка редактора кода весьма хороша.
Но так как данные о типах TypeScript не сохраняются после компиляции в JavaScript, он не может полагаться на типы для одновременного определения валидации, сериализации и документации. Из‑за этого и некоторых проектных решений для получения валидации, сериализации и автоматической генерации схем приходится добавлять декораторы во многих местах. В итоге это становится довольно многословным.
@@ -359,7 +359,7 @@ Hug вдохновил **FastAPI** объявлять параметр `response
В нём были автоматические валидация данных, сериализация данных и генерация схемы OpenAPI на основе тех же аннотаций типов в нескольких местах.
-Определение схемы тела запроса не использовало те же аннотации типов Python, как в Pydantic, — это было ближе к Marshmallow, поэтому поддержка редактора была бы хуже, но всё равно APIStar оставался лучшим доступным вариантом.
+Определение схемы тела запроса не использовало те же аннотации типов Python, как в Pydantic, — это было ближе к Marshmallow, поэтому поддержка редактора кода была бы хуже, но всё равно APIStar оставался лучшим доступным вариантом.
На тот момент у него были лучшие показатели в бенчмарках (его превосходил только Starlette).
@@ -419,7 +419,7 @@ Pydantic — это библиотека для определения вали
###
Starlette { #starlette }
-Starlette — это лёгкий
ASGI фреймворк/набор инструментов, идеально подходящий для создания высокопроизводительных asyncio‑сервисов.
+Starlette — это лёгкий
ASGI фреймворк/набор инструментов, идеально подходящий для создания высокопроизводительных asyncio‑сервисов.
Он очень простой и интуитивный. Спроектирован так, чтобы его было легко расширять, и чтобы компоненты были модульными.
diff --git a/docs/ru/docs/async.md b/docs/ru/docs/async.md
index 15d4e108ab..bff32aaf49 100644
--- a/docs/ru/docs/async.md
+++ b/docs/ru/docs/async.md
@@ -4,7 +4,7 @@
## Нет времени? { #in-a-hurry }
-
TL;DR:
+
TL;DR:
Если вы используете сторонние библиотеки, которые нужно вызывать с `await`, например:
@@ -68,13 +68,13 @@ def results():
Асинхронный код значит, что в языке 💬 есть способ сказать компьютеру/программе 🤖, что в некоторый момент кода ему 🤖 придётся подождать, пока *что-то ещё* где-то в другом месте завершится. Назовём это *что-то ещё* «медленный файл» 📝.
-И пока мы ждём завершения работы с «медленныи файлом» 📝, компьютер может заняться другой работой.
+И пока мы ждём завершения работы с «медленным файлом» 📝, компьютер может заняться другой работой.
Затем компьютер/программа 🤖 будет возвращаться каждый раз, когда появится возможность (пока снова где-то идёт ожидание), или когда 🤖 завершит всю текущую работу. И он 🤖 проверит, не завершилась ли какая-либо из задач, которых он ждал, и сделает то, что нужно.
Далее он 🤖 возьмёт первую завершившуюся задачу (скажем, наш «медленный файл» 📝) и продолжит делать с ней то, что требуется.
-Это «ожидание чего-то ещё» обычно относится к операциям
I/O, которые относительно «медленные» (по сравнению со скоростью процессора и оперативной памяти), например ожидание:
+Это «ожидание чего-то ещё» обычно относится к операциям
I/O, которые относительно «медленные» (по сравнению со скоростью процессора и оперативной памяти), например ожидание:
* отправки данных клиентом по сети
* получения клиентом данных, отправленных вашей программой по сети
@@ -85,7 +85,7 @@ def results():
* возврата результатов запроса к базе данных
* и т.д.
-Поскольку основное время выполнения уходит на ожидание операций
I/O, их называют операциями, «ограниченными вводом-выводом» (I/O bound).
+Поскольку основное время выполнения уходит на ожидание операций
I/O, их называют операциями, «ограниченными вводом-выводом» (I/O bound).
Это называется «асинхронным», потому что компьютеру/программе не нужно «синхронизироваться» с медленной задачей, простаивая и выжидая точный момент её завершения, чтобы забрать результат и продолжить работу.
@@ -277,7 +277,7 @@ def results():
В этом сценарии каждый уборщик (включая вас) был бы процессором, выполняющим свою часть работы.
-И так как основное время выполнения уходит на реальную работу (а не ожидание), а работу в компьютере выполняет
CPU, такие задачи называют «ограниченными процессором» (CPU bound).
+И так как основное время выполнения уходит на реальную работу (а не ожидание), а работу в компьютере выполняет
CPU, такие задачи называют «ограниченными процессором» (CPU bound).
---
@@ -417,7 +417,7 @@ Starlette (и **FastAPI**) основаны на
I/O.
+Если вы пришли из другого async-фреймворка, который работает иначе, и привыкли объявлять тривиальные *функции-обработчики пути*, выполняющие только вычисления, через простой `def` ради крошечной выгоды в производительности (около 100 наносекунд), обратите внимание: в **FastAPI** эффект будет противоположным. В таких случаях лучше использовать `async def`, если только ваши *функции-обработчики пути* не используют код, выполняющий блокирующий I/O.
Тем не менее, в обоих случаях велика вероятность, что **FastAPI** [всё равно будет быстрее](index.md#performance){.internal-link target=_blank} (или как минимум сопоставим) с вашим предыдущим фреймворком.
diff --git a/docs/ru/docs/benchmarks.md b/docs/ru/docs/benchmarks.md
index 612b39f708..c8cacae5f3 100644
--- a/docs/ru/docs/benchmarks.md
+++ b/docs/ru/docs/benchmarks.md
@@ -16,19 +16,19 @@
* **Uvicorn**: ASGI-сервер
* **Starlette**: (использует Uvicorn) веб-микрофреймворк
- * **FastAPI**: (использует Starlette) API-микрофреймворк с рядом дополнительных возможностей для создания API, включая валидацию данных и т. п.
+ * **FastAPI**: (использует Starlette) API-микрофреймворк с рядом дополнительных возможностей для создания API, включая валидацию данных и т.п.
* **Uvicorn**:
* Будет иметь наилучшую производительность, так как помимо самого сервера у него немного дополнительного кода.
* Вы не будете писать приложение непосредственно на Uvicorn. Это означало бы, что Ваш код должен включать как минимум весь код, предоставляемый Starlette (или **FastAPI**). И если Вы так сделаете, то в конечном итоге Ваше приложение будет иметь те же накладные расходы, что и при использовании фреймворка, минимизирующего код Вашего приложения и Ваши ошибки.
- * Если Вы сравниваете Uvicorn, сравнивайте его с Daphne, Hypercorn, uWSGI и т. д. — серверами приложений.
+ * Если Вы сравниваете Uvicorn, сравнивайте его с Daphne, Hypercorn, uWSGI и т.д. — серверами приложений.
* **Starlette**:
* Будет на следующем месте по производительности после Uvicorn. Фактически Starlette запускается под управлением Uvicorn, поэтому он может быть только «медленнее» Uvicorn из‑за выполнения большего объёма кода.
- * Зато он предоставляет Вам инструменты для создания простых веб‑приложений с маршрутизацией по путям и т. п.
- * Если Вы сравниваете Starlette, сравнивайте его с Sanic, Flask, Django и т. д. — веб‑фреймворками (или микрофреймворками).
+ * Зато он предоставляет Вам инструменты для создания простых веб‑приложений с маршрутизацией по путям и т.п.
+ * Если Вы сравниваете Starlette, сравнивайте его с Sanic, Flask, Django и т.д. — веб‑фреймворками (или микрофреймворками).
* **FastAPI**:
* Точно так же, как Starlette использует Uvicorn и не может быть быстрее него, **FastAPI** использует Starlette, поэтому не может быть быстрее его.
* FastAPI предоставляет больше возможностей поверх Starlette — те, которые почти всегда нужны при создании API, такие как валидация и сериализация данных. В довесок Вы ещё и получаете автоматическую документацию (автоматическая документация даже не увеличивает накладные расходы при работе приложения, так как она создаётся при запуске).
- * Если бы Вы не использовали FastAPI, а использовали Starlette напрямую (или другой инструмент вроде Sanic, Flask, Responder и т. д.), Вам пришлось бы самостоятельно реализовать валидацию и сериализацию данных. То есть, в итоге, Ваше приложение имело бы такие же накладные расходы, как если бы оно было создано с использованием FastAPI. И во многих случаях валидация и сериализация данных представляют собой самый большой объём кода, написанного в приложениях.
+ * Если бы Вы не использовали FastAPI, а использовали Starlette напрямую (или другой инструмент вроде Sanic, Flask, Responder и т.д.), Вам пришлось бы самостоятельно реализовать валидацию и сериализацию данных. То есть, в итоге, Ваше приложение имело бы такие же накладные расходы, как если бы оно было создано с использованием FastAPI. И во многих случаях валидация и сериализация данных представляют собой самый большой объём кода, написанного в приложениях.
* Таким образом, используя FastAPI, Вы экономите время разработки, уменьшаете количество ошибок, строк кода и, вероятно, получите ту же производительность (или лучше), как и если бы не использовали его (поскольку Вам пришлось бы реализовать все его возможности в своём коде).
* Если Вы сравниваете FastAPI, сравнивайте его с фреймворком веб‑приложений (или набором инструментов), который обеспечивает валидацию данных, сериализацию и документацию, такими как Flask-apispec, NestJS, Molten и им подобные. Фреймворки с интегрированной автоматической валидацией данных, сериализацией и документацией.
diff --git a/docs/ru/docs/deployment/concepts.md b/docs/ru/docs/deployment/concepts.md
index 207d1604d7..173dbb962d 100644
--- a/docs/ru/docs/deployment/concepts.md
+++ b/docs/ru/docs/deployment/concepts.md
@@ -27,13 +27,13 @@
В [предыдущей главе про HTTPS](https.md){.internal-link target=_blank} мы разобрались, как HTTPS обеспечивает шифрование для вашего API.
-Также мы увидели, что HTTPS обычно обеспечивает компонент, **внешний** по отношению к серверу вашего приложения — **TLS Termination Proxy**.
+Также мы увидели, что HTTPS обычно обеспечивает компонент, **внешний** по отношению к серверу вашего приложения — **прокси-сервер TSL-терминации**.
И должен быть компонент, отвечающий за **обновление HTTPS‑сертификатов** — это может быть тот же самый компонент или отдельный.
### Примеры инструментов для HTTPS { #example-tools-for-https }
-Некоторые инструменты, которые можно использовать как TLS Termination Proxy:
+Некоторые инструменты, которые можно использовать как прокси-сервер TSL-терминации:
* Traefik
* Автоматически обновляет сертификаты ✨
@@ -47,7 +47,7 @@
* С внешним компонентом (например, cert-manager) для обновления сертификатов
* Обрабатывается внутри облачного провайдера как часть его услуг (см. ниже 👇)
-Другой вариант — использовать **облачный сервис**, который возьмёт на себя больше задач, включая настройку HTTPS. Там могут быть ограничения или дополнительная стоимость и т.п., но в таком случае вам не придётся самим настраивать TLS Termination Proxy.
+Другой вариант — использовать **облачный сервис**, который возьмёт на себя больше задач, включая настройку HTTPS. Там могут быть ограничения или дополнительная стоимость и т.п., но в таком случае вам не придётся самим настраивать прокси-сервер TSL-терминации.
В следующих главах я покажу конкретные примеры.
@@ -214,7 +214,7 @@
Процесс‑менеджер, вероятно, будет тем, кто слушает **порт** на IP. И он будет передавать всю коммуникацию воркер‑процессам.
-Эти воркеры будут запускать ваше приложение, выполнять основные вычисления для получения **запроса** и возврата **ответа**, и загружать всё, что вы кладёте в переменные, в RAM.
+Эти воркеры будут запускать ваше приложение, выполнять основные вычисления для получения **HTTP‑запроса** и возврата **HTTP‑ответа**, и загружать всё, что вы кладёте в переменные, в RAM.
@@ -289,7 +289,7 @@
Ваш сервер(а) — это **ресурс**, который ваши программы могут потреблять или **использовать**: время вычислений на CPU и доступную оперативную память (RAM).
-Какую долю системных ресурсов вы хотите потреблять/использовать? Можно подумать «немного», но на практике вы, скорее всего, захотите потреблять **максимум без падений**.
+Какую долю системных ресурсов вы хотите потреблять/использовать? Можно подумать «немного», но на практике вы, вероятно, захотите потреблять **максимум без падений**.
Если вы платите за 3 сервера, но используете лишь малую часть их RAM и CPU, вы, вероятно, **тратите деньги впустую** 💸 и **электроэнергию серверов** 🌎 и т.п.
diff --git a/docs/ru/docs/deployment/docker.md b/docs/ru/docs/deployment/docker.md
index 9e8562be70..5dfa211599 100644
--- a/docs/ru/docs/deployment/docker.md
+++ b/docs/ru/docs/deployment/docker.md
@@ -14,7 +14,7 @@
Предпросмотр Dockerfile 👀
```Dockerfile
-FROM python:3.9
+FROM python:3.14
WORKDIR /code
@@ -166,7 +166,7 @@ def read_item(item_id: int, q: str | None = None):
```{ .dockerfile .annotate }
# (1)!
-FROM python:3.9
+FROM python:3.14
# (2)!
WORKDIR /code
@@ -214,7 +214,7 @@ CMD ["fastapi", "run", "app/main.py", "--port", "80"]
5. Копируем директорию `./app` внутрь директории `/code`.
- Так как здесь весь код, который **меняется чаще всего**, кэш Docker **вряд ли** будет использоваться для этого шагa или **последующих шагов**.
+ Так как здесь весь код, который **меняется чаще всего**, кэш Docker **вряд ли** будет использоваться для этого шага или **последующих шагов**.
Поэтому важно разместить этот шаг **ближе к концу** `Dockerfile`, чтобы оптимизировать время сборки образа контейнера.
@@ -273,9 +273,9 @@ CMD fastapi run app/main.py --port 80
└── requirements.txt
```
-#### За прокси-сервером TLS терминации { #behind-a-tls-termination-proxy }
+#### За прокси-сервером TSL-терминации { #behind-a-tls-termination-proxy }
-Если вы запускаете контейнер за прокси-сервером завершения TLS (балансировщиком нагрузки), таким как Nginx или Traefik, добавьте опцию `--proxy-headers`. Это сообщит Uvicorn (через FastAPI CLI), что приложение работает за HTTPS и можно доверять соответствующим заголовкам.
+Если вы запускаете контейнер за прокси-сервером TSL-терминации (балансировщиком нагрузки), таким как Nginx или Traefik, добавьте опцию `--proxy-headers`. Это сообщит Uvicorn (через FastAPI CLI), что приложение работает за HTTPS и можно доверять соответствующим заголовкам.
```Dockerfile
CMD ["fastapi", "run", "app/main.py", "--proxy-headers", "--port", "80"]
@@ -390,7 +390,7 @@ $ docker run -d --name mycontainer -p 80:80 myimage
Тогда в `Dockerfile` нужно изменить пути копирования:
```{ .dockerfile .annotate hl_lines="10 13" }
-FROM python:3.9
+FROM python:3.14
WORKDIR /code
@@ -454,7 +454,7 @@ CMD ["fastapi", "run", "main.py", "--port", "80"]
## Репликация — количество процессов { #replication-number-of-processes }
-Если у вас есть кластер машин с **Kubernetes**, Docker Swarm Mode, Nomad или другой похожей системой для управления распределёнными контейнерами на нескольких машинах, скорее всего вы будете **управлять репликацией** на **уровне кластера**, а не использовать **менеджер процессов** (например, Uvicorn с воркерами) в каждом контейнере.
+Если у вас есть кластер машин с **Kubernetes**, Docker Swarm Mode, Nomad или другой похожей системой для управления распределёнными контейнерами на нескольких машинах, скорее всего вы будете **управлять репликацией** на **уровне кластера**, а не использовать **менеджер процессов** (например, Uvicorn с воркерами) в каждом контейнере.
Одна из таких систем управления распределёнными контейнерами, как Kubernetes, обычно имеет встроенный способ управлять **репликацией контейнеров**, поддерживая **балансировку нагрузки** для входящих запросов — всё это на **уровне кластера**.
@@ -462,17 +462,17 @@ CMD ["fastapi", "run", "main.py", "--port", "80"]
### Балансировщик нагрузки { #load-balancer }
-При использовании контейнеров обычно есть компонент, **слушающий главный порт**. Это может быть другой контейнер — **прокси завершения TLS** для обработки **HTTPS** или похожий инструмент.
+При использовании контейнеров обычно есть компонент, **слушающий главный порт**. Это может быть другой контейнер — **прокси-сервер TSL-терминации** для обработки **HTTPS** или похожий инструмент.
Поскольку этот компонент принимает **нагрузку** запросов и распределяет её между воркерами **сбалансированно**, его часто называют **балансировщиком нагрузки**.
/// tip | Подсказка
-Тот же компонент **прокси завершения TLS**, который обрабатывает HTTPS, скорее всего также будет **балансировщиком нагрузки**.
+Тот же компонент **прокси-сервер TSL-терминации**, который обрабатывает HTTPS, скорее всего также будет **балансировщиком нагрузки**.
///
-При работе с контейнерами система, которую вы используете для запуска и управления ими, уже имеет внутренние средства для передачи **сетевого взаимодействия** (например, HTTP-запросов) от **балансировщика нагрузки** (который также может быть **прокси завершения TLS**) к контейнеру(-ам) с вашим приложением.
+При работе с контейнерами система, которую вы используете для запуска и управления ими, уже имеет внутренние средства для передачи **сетевого взаимодействия** (например, HTTP-запросов) от **балансировщика нагрузки** (который также может быть **прокси-сервером TSL-терминации**) к контейнеру(-ам) с вашим приложением.
### Один балансировщик — несколько контейнеров-воркеров { #one-load-balancer-multiple-worker-containers }
@@ -499,7 +499,7 @@ CMD ["fastapi", "run", "main.py", "--port", "80"]
В таких случаях вы можете использовать опцию командной строки `--workers`, чтобы указать нужное количество воркеров:
```{ .dockerfile .annotate }
-FROM python:3.9
+FROM python:3.14
WORKDIR /code
diff --git a/docs/ru/docs/deployment/https.md b/docs/ru/docs/deployment/https.md
index 05a03255e8..ffeccfd7da 100644
--- a/docs/ru/docs/deployment/https.md
+++ b/docs/ru/docs/deployment/https.md
@@ -65,7 +65,7 @@
Чаще всего всё начинается с **приобретения** **имени домена**. Затем вы настраиваете его на DNS‑сервере (возможно, у того же облачного провайдера).
-Скорее всего, вы получите облачный сервер (виртуальную машину) или что-то подобное, и у него будет постоянный **публичный IP-адрес**.
+Скорее всего, вы получите облачный сервер (виртуальную машину) или что-то подобное, и у него будет постоянный **публичный IP-адрес**.
На DNS‑сервере(ах) вы настроите запись («`A record`» - запись типа A), указывающую, что **ваш домен** должен указывать на публичный **IP‑адрес вашего сервера**.
diff --git a/docs/ru/docs/deployment/index.md b/docs/ru/docs/deployment/index.md
index ffb77641dd..7e735593be 100644
--- a/docs/ru/docs/deployment/index.md
+++ b/docs/ru/docs/deployment/index.md
@@ -18,6 +18,6 @@
Например, мы, команда, стоящая за FastAPI, создали **FastAPI Cloud**, чтобы сделать развёртывание приложений FastAPI в облаке как можно более простым и прямолинейным, с тем же удобством для разработчика, что и при работе с FastAPI.
-В этом блоке я покажу вам некоторые из основных концепций, которые вы, вероятно, должны иметь в виду при развертывании приложения **FastAPI** (хотя большинство из них применимо к любому другому типу веб-приложений).
+Я покажу вам некоторые из основных концепций, которые вы, вероятно, должны иметь в виду при развертывании приложения **FastAPI** (хотя большинство из них применимо к любому другому типу веб-приложений).
В последующих разделах вы узнаете больше деталей и методов, необходимых для этого. ✨
diff --git a/docs/ru/docs/deployment/versions.md b/docs/ru/docs/deployment/versions.md
index 58d5aa110d..4195d689fe 100644
--- a/docs/ru/docs/deployment/versions.md
+++ b/docs/ru/docs/deployment/versions.md
@@ -1,12 +1,12 @@
# О версиях FastAPI { #about-fastapi-versions }
-**FastAPI** уже используется в продакшене во многих приложениях и системах. Покрытие тестами поддерживается на уровне 100%. Но его разработка всё ещё движется быстрыми темпами.
+**FastAPI** уже используется в продакшн во многих приложениях и системах. Покрытие тестами поддерживается на уровне 100%. Но его разработка всё ещё движется быстрыми темпами.
Часто добавляются новые функции, регулярно исправляются баги, код продолжает постоянно совершенствоваться.
По указанным причинам текущие версии до сих пор `0.x.x`. Это говорит о том, что каждая версия может содержать обратно несовместимые изменения, следуя
Семантическому версионированию.
-Уже сейчас вы можете создавать приложения в продакшене, используя **FastAPI** (и скорее всего так и делаете), главное убедиться в том, что вы используете версию, которая корректно работает с вашим кодом.
+Уже сейчас вы можете создавать приложения в продакшн, используя **FastAPI** (и скорее всего так и делаете), главное убедиться в том, что вы используете версию, которая корректно работает с вашим кодом.
## Закрепите вашу версию `fastapi` { #pin-your-fastapi-version }
diff --git a/docs/ru/docs/environment-variables.md b/docs/ru/docs/environment-variables.md
index 6291b79d26..759127420f 100644
--- a/docs/ru/docs/environment-variables.md
+++ b/docs/ru/docs/environment-variables.md
@@ -161,7 +161,7 @@ Hello World from Python
Эти переменные окружения могут работать только с **текстовыми строками**, поскольку они являются внешними по отношению к Python и должны быть совместимы с другими программами и остальной системой (и даже с различными операционными системами, такими как Linux, Windows, macOS).
-Это означает, что **любое значение**, считанное в Python из переменной окружения, **будет `str`**, и любое преобразование к другому типу или любая проверка должны быть выполнены в коде.
+Это означает, что **любое значение**, считанное в Python из переменной окружения, **будет `str`**, и любое преобразование к другому типу или любая валидация должны быть выполнены в коде.
Подробнее об использовании переменных окружения для работы с **настройками приложения** вы узнаете в [Расширенное руководство пользователя - Настройки и переменные среды](./advanced/settings.md){.internal-link target=_blank}.
diff --git a/docs/ru/docs/fastapi-cli.md b/docs/ru/docs/fastapi-cli.md
index 72cf55e7b0..a46e0053ee 100644
--- a/docs/ru/docs/fastapi-cli.md
+++ b/docs/ru/docs/fastapi-cli.md
@@ -52,7 +52,7 @@ FastAPI CLI берет путь к вашей Python-программе (нап
Для работы в режиме продакшн вместо `fastapi dev` нужно использовать `fastapi run`. 🚀
-Внутри **FastAPI CLI** используется
Uvicorn, высокопроизводительный, готовый к работе в продакшне ASGI-сервер. 😎
+Внутри **FastAPI CLI** используется
Uvicorn, высокопроизводительный, готовый к работе в продакшн ASGI-сервер. 😎
## `fastapi dev` { #fastapi-dev }
diff --git a/docs/ru/docs/features.md b/docs/ru/docs/features.md
index 703ff951ef..0bc3dbb2d1 100644
--- a/docs/ru/docs/features.md
+++ b/docs/ru/docs/features.md
@@ -6,7 +6,7 @@
### Основано на открытых стандартах { #based-on-open-standards }
-*
OpenAPI для создания API, включая объявления
операций пути, параметров, тел запросов, безопасности и т. д.
+*
OpenAPI для создания API, включая объявления
операций пути, параметров, тел запросов, безопасности и т.д.
* Автоматическая документация моделей данных с помощью
JSON Schema (так как сама спецификация OpenAPI основана на JSON Schema).
* Разработан вокруг этих стандартов, после тщательного их изучения. Это не дополнительная надстройка поверх.
* Это также позволяет использовать автоматическую **генерацию клиентского кода** на многих языках.
@@ -107,7 +107,7 @@ FastAPI имеет продуманные значения **по умолчан
* Объекты JSON (`dict`).
* Массив JSON (`list`) с определёнными типами элементов.
* Строковые (`str`) поля с ограничением минимальной и максимальной длины.
- * Числа (`int`, `float`) с минимальными и максимальными значениями и т. п.
+ * Числа (`int`, `float`) с минимальными и максимальными значениями и т.п.
* Проверка для более экзотических типов, таких как:
* URL.
@@ -126,24 +126,24 @@ FastAPI имеет продуманные значения **по умолчан
* HTTP Basic.
* **OAuth2** (также с **токенами JWT**). Ознакомьтесь с руководством [OAuth2 с JWT](tutorial/security/oauth2-jwt.md){.internal-link target=_blank}.
* Ключи API в:
- * Заголовках.
+ * HTTP-заголовках.
* Параметрах запросов.
* Cookies и т.п.
Вдобавок все функции безопасности от Starlette (включая **сессионные cookies**).
-Все инструменты и компоненты спроектированы для многократного использования и легко интегрируются с вашими системами, хранилищами данных, реляционными и NoSQL базами данных и т. д.
+Все инструменты и компоненты спроектированы для многократного использования и легко интегрируются с вашими системами, хранилищами данных, реляционными и NoSQL базами данных и т.д.
### Внедрение зависимостей { #dependency-injection }
-FastAPI включает в себя чрезвычайно простую в использовании, но чрезвычайно мощную систему
Внедрения зависимостей.
+FastAPI включает в себя чрезвычайно простую в использовании, но чрезвычайно мощную систему
Внедрения зависимостей.
* Даже зависимости могут иметь зависимости, создавая иерархию или **«граф» зависимостей**.
* Всё **автоматически обрабатывается** фреймворком.
* Все зависимости могут запрашивать данные из запросов и **дополнять операции пути** ограничениями и автоматической документацией.
* **Автоматическая проверка** даже для параметров *операций пути*, определённых в зависимостях.
-* Поддержка сложных систем аутентификации пользователей, **соединений с базами данных** и т. д.
-* **Никаких компромиссов** с базами данных, интерфейсами и т. д. Но при этом — лёгкая интеграция со всеми ними.
+* Поддержка сложных систем аутентификации пользователей, **соединений с базами данных** и т.д.
+* **Никаких компромиссов** с базами данных, интерфейсами и т.д. Но при этом — лёгкая интеграция со всеми ними.
### Нет ограничений на "Плагины" { #unlimited-plug-ins }
@@ -153,8 +153,8 @@ FastAPI включает в себя чрезвычайно простую в и
### Проверен { #tested }
-* 100%
покрытие тестами.
-* 100%
аннотирование типов в кодовой базе.
+* 100%
покрытие тестами.
+* 100%
аннотирование типов в кодовой базе.
* Используется в продакшн‑приложениях.
## Возможности Starlette { #starlette-features }
@@ -179,7 +179,7 @@ FastAPI включает в себя чрезвычайно простую в и
**FastAPI** полностью совместим с (и основан на)
Pydantic. Поэтому любой дополнительный код Pydantic, который у вас есть, также будет работать.
-Включая внешние библиотеки, также основанные на Pydantic, такие как
ORM’ы,
ODM’ы для баз данных.
+Включая внешние библиотеки, также основанные на Pydantic, такие как
ORM’ы,
ODM’ы для баз данных.
Это также означает, что во многих случаях вы можете передавать тот же объект, который получили из запроса, **непосредственно в базу данных**, так как всё проверяется автоматически.
@@ -190,10 +190,10 @@ FastAPI включает в себя чрезвычайно простую в и
* **Никакой нервотрёпки**:
* Не нужно изучать новые схемы в микроязыках.
* Если вы знаете типы в Python, вы знаете, как использовать Pydantic.
-* Прекрасно сочетается с вашим **
IDE/
linter/мозгом**:
+* Прекрасно сочетается с вашим **
IDE/
линтер/мозгом**:
* Потому что структуры данных pydantic — это всего лишь экземпляры классов, определённых вами; автозавершение, проверка кода, mypy и ваша интуиция — всё будет работать с вашими валидированными данными.
* Валидация **сложных структур**:
- * Использование иерархических моделей Pydantic; `List`, `Dict` и т. п. из модуля `typing` (входит в стандартную библиотеку Python).
+ * Использование иерархических моделей Pydantic; `List`, `Dict` и т.п. из модуля `typing` (входит в стандартную библиотеку Python).
* Валидаторы позволяют чётко и легко определять, проверять и документировать сложные схемы данных в виде JSON Schema.
* У вас могут быть глубоко **вложенные объекты JSON**, и все они будут проверены и аннотированы.
* **Расширяемость**:
diff --git a/docs/ru/docs/history-design-future.md b/docs/ru/docs/history-design-future.md
index 9cdd53376d..5019157600 100644
--- a/docs/ru/docs/history-design-future.md
+++ b/docs/ru/docs/history-design-future.md
@@ -30,7 +30,7 @@
## Исследования { #investigation }
-Благодаря опыту использования существующих альтернатив, мы с коллегами изучили их основные идеи и скомбинировали собранные знания наилучшим образом.
+Используя все существовавшие ранее альтернативы, я получил возможность у каждой из них чему-то научиться, позаимствовать идеи и объединить их наилучшим образом для себя и для команд разработчиков, с которыми я работал.
Например, стало ясно, что необходимо брать за основу стандартные аннотации типов Python.
@@ -44,13 +44,13 @@
Я проверил несколько идей на самых популярных редакторах кода: PyCharm, VS Code, редакторы на базе Jedi.
-Данные по редакторам я взял из
опроса Python-разработчиков, который охватывает около 80% пользователей.
+Согласно последнему
опросу Python-разработчиков, который охватывает около 80% пользователей.
Это означает, что **FastAPI** был специально проверен на редакторах, используемых 80% Python-разработчиками. И поскольку большинство других редакторов, как правило, работают аналогичным образом, все его преимущества должны работать практически для всех редакторов.
Таким образом, я смог найти наилучшие способы сократить дублирование кода, обеспечить повсеместное автозавершение, проверку типов и ошибок и т.д.
-И все это, чтобы все пользователи могли получать наилучший опыт разработки.
+И все это, чтобы все разработчики могли получать наилучший опыт разработки.
## Зависимости { #requirements }
@@ -58,7 +58,7 @@
По моим предложениям был изменён код этого фреймворка, чтобы сделать его полностью совместимым с JSON Schema, поддержать различные способы определения ограничений и улучшить поддержку в редакторах кода (проверки типов, автозавершение) на основе тестов в нескольких редакторах.
-В то же время, я принимал участие в разработке
**Starlette**, ещё один из основных компонентов FastAPI.
+Во время разработки я также внес вклад в
**Starlette**, другую ключевую зависимость.
## Разработка { #development }
@@ -76,4 +76,4 @@
У **FastAPI** великое будущее.
-И [ваш вклад в это](help-fastapi.md){.internal-link target=_blank} - очень ценнен.
+И [ваш вклад в это](help-fastapi.md){.internal-link target=_blank} - очень ценен.
diff --git a/docs/ru/docs/how-to/authentication-error-status-code.md b/docs/ru/docs/how-to/authentication-error-status-code.md
index 5675cecc52..596563c541 100644
--- a/docs/ru/docs/how-to/authentication-error-status-code.md
+++ b/docs/ru/docs/how-to/authentication-error-status-code.md
@@ -8,7 +8,7 @@
Например, вы можете создать подкласс `HTTPBearer`, который будет возвращать ошибку `403 Forbidden` вместо стандартной `401 Unauthorized`:
-{* ../../docs_src/authentication_error_status_code/tutorial001_an_py39.py hl[9:13] *}
+{* ../../docs_src/authentication_error_status_code/tutorial001_an_py310.py hl[9:13] *}
/// tip | Совет
diff --git a/docs/ru/docs/how-to/conditional-openapi.md b/docs/ru/docs/how-to/conditional-openapi.md
index d0845b91e2..6efa30608e 100644
--- a/docs/ru/docs/how-to/conditional-openapi.md
+++ b/docs/ru/docs/how-to/conditional-openapi.md
@@ -4,9 +4,9 @@
## О безопасности, API и документации { #about-security-apis-and-docs }
-Скрытие пользовательских интерфейсов документации в продакшн *не должно* быть способом защиты вашего API.
+Скрытие пользовательских интерфейсов документации в продакшн не должно быть способом защиты вашего API.
-Это не добавляет дополнительной безопасности вашему API, *операции пути* (обработчики пути) всё равно будут доступны по своим путям.
+Это не добавляет дополнительной безопасности вашему API, операции пути (обработчики пути) всё равно будут доступны по своим путям.
Если в вашем коде есть уязвимость, она всё равно останется.
@@ -29,7 +29,7 @@
Например:
-{* ../../docs_src/conditional_openapi/tutorial001_py39.py hl[6,11] *}
+{* ../../docs_src/conditional_openapi/tutorial001_py310.py hl[6,11] *}
Здесь мы объявляем настройку `openapi_url` с тем же значением по умолчанию — `"/openapi.json"`.
diff --git a/docs/ru/docs/how-to/configure-swagger-ui.md b/docs/ru/docs/how-to/configure-swagger-ui.md
index b3b1c1ba62..f4f2a0e549 100644
--- a/docs/ru/docs/how-to/configure-swagger-ui.md
+++ b/docs/ru/docs/how-to/configure-swagger-ui.md
@@ -18,7 +18,7 @@ FastAPI преобразует эти настройки в **JSON**, чтобы
Но вы можете отключить её, установив `syntaxHighlight` в `False`:
-{* ../../docs_src/configure_swagger_ui/tutorial001_py39.py hl[3] *}
+{* ../../docs_src/configure_swagger_ui/tutorial001_py310.py hl[3] *}
…и после этого Swagger UI больше не будет показывать подсветку синтаксиса:
@@ -28,7 +28,7 @@ FastAPI преобразует эти настройки в **JSON**, чтобы
Аналогично вы можете задать тему подсветки синтаксиса с ключом "syntaxHighlight.theme" (обратите внимание, что посередине стоит точка):
-{* ../../docs_src/configure_swagger_ui/tutorial002_py39.py hl[3] *}
+{* ../../docs_src/configure_swagger_ui/tutorial002_py310.py hl[3] *}
Эта настройка изменит цветовую тему подсветки синтаксиса:
@@ -46,7 +46,7 @@ FastAPI включает некоторые параметры конфигур
Например, чтобы отключить `deepLinking`, можно передать такие настройки в `swagger_ui_parameters`:
-{* ../../docs_src/configure_swagger_ui/tutorial003_py39.py hl[3] *}
+{* ../../docs_src/configure_swagger_ui/tutorial003_py310.py hl[3] *}
## Другие параметры Swagger UI { #other-swagger-ui-parameters }
diff --git a/docs/ru/docs/how-to/custom-docs-ui-assets.md b/docs/ru/docs/how-to/custom-docs-ui-assets.md
index f524911e65..e3c31b32c5 100644
--- a/docs/ru/docs/how-to/custom-docs-ui-assets.md
+++ b/docs/ru/docs/how-to/custom-docs-ui-assets.md
@@ -18,7 +18,7 @@
Чтобы отключить её, установите их URL в значение `None` при создании вашего приложения `FastAPI`:
-{* ../../docs_src/custom_docs_ui/tutorial001_py39.py hl[8] *}
+{* ../../docs_src/custom_docs_ui/tutorial001_py310.py hl[8] *}
### Подключить пользовательскую документацию { #include-the-custom-docs }
@@ -34,7 +34,7 @@
Аналогично и для ReDoc...
-{* ../../docs_src/custom_docs_ui/tutorial001_py39.py hl[2:6,11:19,22:24,27:33] *}
+{* ../../docs_src/custom_docs_ui/tutorial001_py310.py hl[2:6,11:19,22:24,27:33] *}
/// tip | Совет
@@ -50,7 +50,7 @@ Swagger UI сделает это за вас «за кулисами», но д
Чтобы убедиться, что всё работает, создайте *операцию пути*:
-{* ../../docs_src/custom_docs_ui/tutorial001_py39.py hl[36:38] *}
+{* ../../docs_src/custom_docs_ui/tutorial001_py310.py hl[36:38] *}
### Тестирование { #test-it }
@@ -118,7 +118,7 @@ Swagger UI сделает это за вас «за кулисами», но д
* Импортируйте `StaticFiles`.
* Смонтируйте экземпляр `StaticFiles()` в определённый путь.
-{* ../../docs_src/custom_docs_ui/tutorial002_py39.py hl[7,11] *}
+{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[7,11] *}
### Протестируйте статические файлы { #test-the-static-files }
@@ -144,7 +144,7 @@ Swagger UI сделает это за вас «за кулисами», но д
Чтобы отключить её, установите их URL в значение `None` при создании вашего приложения `FastAPI`:
-{* ../../docs_src/custom_docs_ui/tutorial002_py39.py hl[9] *}
+{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[9] *}
### Подключить пользовательскую документацию со статическими файлами { #include-the-custom-docs-for-static-files }
@@ -160,7 +160,7 @@ Swagger UI сделает это за вас «за кулисами», но д
Аналогично и для ReDoc...
-{* ../../docs_src/custom_docs_ui/tutorial002_py39.py hl[2:6,14:22,25:27,30:36] *}
+{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[2:6,14:22,25:27,30:36] *}
/// tip | Совет
@@ -176,7 +176,7 @@ Swagger UI сделает это за вас «за кулисами», но д
Чтобы убедиться, что всё работает, создайте *операцию пути*:
-{* ../../docs_src/custom_docs_ui/tutorial002_py39.py hl[39:41] *}
+{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[39:41] *}
### Тестирование UI со статическими файлами { #test-static-files-ui }
diff --git a/docs/ru/docs/how-to/extending-openapi.md b/docs/ru/docs/how-to/extending-openapi.md
index 1d69cbdb3a..197a1790a2 100644
--- a/docs/ru/docs/how-to/extending-openapi.md
+++ b/docs/ru/docs/how-to/extending-openapi.md
@@ -24,7 +24,7 @@
* `version`: Версия вашего API, например `2.5.0`.
* `openapi_version`: Версия используемой спецификации OpenAPI. По умолчанию — последняя: `3.1.0`.
* `summary`: Краткое описание API.
-* `description`: Описание вашего API; может включать Markdown и будет отображается в документации.
+* `description`: Описание вашего API; может включать Markdown и будет отображаться в документации.
* `routes`: Список маршрутов — это каждая зарегистрированная *операция пути*. Берутся из `app.routes`.
/// info | Информация
@@ -43,19 +43,19 @@
Сначала напишите приложение **FastAPI** как обычно:
-{* ../../docs_src/extending_openapi/tutorial001_py39.py hl[1,4,7:9] *}
+{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[1,4,7:9] *}
### Сгенерируйте схему OpenAPI { #generate-the-openapi-schema }
Затем используйте ту же вспомогательную функцию для генерации схемы OpenAPI внутри функции `custom_openapi()`:
-{* ../../docs_src/extending_openapi/tutorial001_py39.py hl[2,15:21] *}
+{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[2,15:21] *}
### Измените схему OpenAPI { #modify-the-openapi-schema }
Теперь можно добавить расширение ReDoc, добавив кастомный `x-logo` в «объект» `info` в схеме OpenAPI:
-{* ../../docs_src/extending_openapi/tutorial001_py39.py hl[22:24] *}
+{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[22:24] *}
### Кэшируйте схему OpenAPI { #cache-the-openapi-schema }
@@ -65,13 +65,13 @@
Она будет создана один раз, а затем тот же кэшированный вариант будет использоваться для последующих запросов.
-{* ../../docs_src/extending_openapi/tutorial001_py39.py hl[13:14,25:26] *}
+{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[13:14,25:26] *}
### Переопределите метод { #override-the-method }
Теперь вы можете заменить метод `.openapi()` на вашу новую функцию.
-{* ../../docs_src/extending_openapi/tutorial001_py39.py hl[29] *}
+{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[29] *}
### Проверьте { #check-it }
diff --git a/docs/ru/docs/how-to/graphql.md b/docs/ru/docs/how-to/graphql.md
index 50c321e7dd..9e28d61822 100644
--- a/docs/ru/docs/how-to/graphql.md
+++ b/docs/ru/docs/how-to/graphql.md
@@ -35,7 +35,7 @@
Вот небольшой пример того, как можно интегрировать Strawberry с FastAPI:
-{* ../../docs_src/graphql_/tutorial001_py39.py hl[3,22,25] *}
+{* ../../docs_src/graphql_/tutorial001_py310.py hl[3,22,25] *}
Подробнее о Strawberry можно узнать в
документации Strawberry.
diff --git a/docs/ru/docs/how-to/index.md b/docs/ru/docs/how-to/index.md
index 228c125dde..75e7fff265 100644
--- a/docs/ru/docs/how-to/index.md
+++ b/docs/ru/docs/how-to/index.md
@@ -1,13 +1,13 @@
# Как сделать — Рецепты { #how-to-recipes }
-Здесь вы найдете разные рецепты и руководства «как сделать» по различным темам.
+Здесь вы найдете разные рецепты и руководства «как сделать» по **различным темам**.
-Большинство из этих идей более-менее независимы, и в большинстве случаев вам стоит изучать их только если они напрямую относятся к вашему проекту.
+Большинство из этих идей более-менее **независимы**, и в большинстве случаев вам стоит изучать их только если они напрямую относятся к **вашему проекту**.
Если что-то кажется интересным и полезным для вашего проекта, смело изучайте; в противном случае, вероятно, можно просто пропустить.
/// tip | Совет
-Если вы хотите изучить FastAPI структурированно (рекомендуется), вместо этого читайте [Учебник — Руководство пользователя](../tutorial/index.md){.internal-link target=_blank} по главам.
+Если вы хотите **изучить FastAPI** структурированно (рекомендуется), вместо этого читайте [Учебник — Руководство пользователя](../tutorial/index.md){.internal-link target=_blank} по главам.
///
diff --git a/docs/ru/docs/index.md b/docs/ru/docs/index.md
index b1a0c9a2e9..877014a086 100644
--- a/docs/ru/docs/index.md
+++ b/docs/ru/docs/index.md
@@ -40,7 +40,7 @@ FastAPI — это современный, быстрый (высокопрои
* **Скорость**: Очень высокая производительность, на уровне **NodeJS** и **Go** (благодаря Starlette и Pydantic). [Один из самых быстрых доступных фреймворков Python](#performance).
* **Быстрота разработки**: Увеличьте скорость разработки фич примерно на 200–300%. *
* **Меньше ошибок**: Сократите примерно на 40% количество ошибок, вызванных человеком (разработчиком). *
-* **Интуитивность**: Отличная поддержка редактора кода.
Автозавершение везде. Меньше времени на отладку.
+* **Интуитивность**: Отличная поддержка редактора кода.
Автозавершение везде. Меньше времени на отладку.
* **Простота**: Разработан так, чтобы его было легко использовать и осваивать. Меньше времени на чтение документации.
* **Краткость**: Минимизируйте дублирование кода. Несколько возможностей из каждого объявления параметров. Меньше ошибок.
* **Надежность**: Получите код, готовый к продакшн. С автоматической интерактивной документацией.
@@ -127,7 +127,7 @@ FastAPI — это современный, быстрый (высокопрои

-Если вы создаёте приложение
CLI для использования в терминале вместо веб-API, посмотрите
**Typer**.
+Если вы создаёте приложение
CLI для использования в терминале вместо веб-API, посмотрите
**Typer**.
**Typer** — младший брат FastAPI. И он задуман как **FastAPI для CLI**. ⌨️ 🚀
@@ -368,7 +368,7 @@ item: Item
* Валидацию данных:
* Автоматические и понятные ошибки, когда данные некорректны.
* Валидацию даже для глубоко вложенных объектов JSON.
-*
Преобразование входных данных: из сети в данные и типы Python. Чтение из:
+*
Преобразование входных данных: из сети в данные и типы Python. Чтение из:
* JSON.
* Параметров пути.
* Параметров запроса.
@@ -376,7 +376,7 @@ item: Item
* HTTP-заголовков.
* Форм.
* Файлов.
-*
Преобразование выходных данных: из данных и типов Python в данные сети (например, JSON):
+*
Преобразование выходных данных: из данных и типов Python в данные сети (например, JSON):
* Преобразование типов Python (`str`, `int`, `float`, `bool`, `list` и т.д.).
* Объекты `datetime`.
* Объекты `UUID`.
@@ -439,7 +439,7 @@ item: Item
* Объявление **параметров** из других источников: **HTTP-заголовки**, **cookies**, **поля формы** и **файлы**.
* Как задать **ограничения валидации** вроде `maximum_length` или `regex`.
-* Очень мощную и простую в использовании систему **
внедрения зависимостей**.
+* Очень мощную и простую в использовании систему **
внедрения зависимостей**.
* Безопасность и аутентификацию, включая поддержку **OAuth2** с **JWT токенами** и **HTTP Basic** аутентификацию.
* Более продвинутые (но столь же простые) приёмы объявления **глубоко вложенных JSON-моделей** (спасибо Pydantic).
* Интеграцию **GraphQL** с
Strawberry и другими библиотеками.
@@ -524,7 +524,7 @@ FastAPI зависит от Pydantic и Starlette.
*
httpx — обязателен, если вы хотите использовать `TestClient`.
*
jinja2 — обязателен, если вы хотите использовать конфигурацию шаблонов по умолчанию.
-*
python-multipart - обязателен, если вы хотите поддерживать
«парсинг» форм через `request.form()`.
+*
python-multipart - обязателен, если вы хотите поддерживать
«парсинг» форм через `request.form()`.
Используется FastAPI:
diff --git a/docs/ru/docs/project-generation.md b/docs/ru/docs/project-generation.md
index dbedf76fe3..8155457e38 100644
--- a/docs/ru/docs/project-generation.md
+++ b/docs/ru/docs/project-generation.md
@@ -18,7 +18,7 @@
- 🤖 Автоматически сгенерированный фронтенд‑клиент.
- 🧪 [Playwright](https://playwright.dev) для End‑to‑End тестирования.
- 🦇 Поддержка тёмной темы.
-- 🐋 [Docker Compose](https://www.docker.com) для разработки и продакшна.
+- 🐋 [Docker Compose](https://www.docker.com) для разработки и продакшн.
- 🔒 Безопасное хэширование паролей по умолчанию.
- 🔑 Аутентификация по JWT‑токенам.
- 📫 Восстановление пароля по электронной почте.
diff --git a/docs/ru/docs/python-types.md b/docs/ru/docs/python-types.md
index ae4a1e2b79..95153c3882 100644
--- a/docs/ru/docs/python-types.md
+++ b/docs/ru/docs/python-types.md
@@ -2,7 +2,7 @@
Python поддерживает необязательные «подсказки типов» (их также называют «аннотациями типов»).
-Эти **«подсказки типов»** или аннотации — это специальный синтаксис, позволяющий объявлять
тип переменной.
+Эти **«подсказки типов»** или аннотации — это специальный синтаксис, позволяющий объявлять
тип переменной.
Объявляя типы для ваших переменных, редакторы кода и инструменты смогут лучше вас поддерживать.
@@ -22,7 +22,7 @@ Python поддерживает необязательные «подсказк
Давайте начнем с простого примера:
-{* ../../docs_src/python_types/tutorial001_py39.py *}
+{* ../../docs_src/python_types/tutorial001_py310.py *}
Вызов этой программы выводит:
@@ -34,9 +34,9 @@ John Doe
* Принимает `first_name` и `last_name`.
* Преобразует первую букву каждого значения в верхний регистр с помощью `title()`.
-*
Соединяет их пробелом посередине.
+*
Соединяет их пробелом посередине.
-{* ../../docs_src/python_types/tutorial001_py39.py hl[2] *}
+{* ../../docs_src/python_types/tutorial001_py310.py hl[2] *}
### Отредактируем пример { #edit-it }
@@ -78,7 +78,7 @@ John Doe
Это и есть «подсказки типов»:
-{* ../../docs_src/python_types/tutorial002_py39.py hl[1] *}
+{* ../../docs_src/python_types/tutorial002_py310.py hl[1] *}
Это не то же самое, что объявление значений по умолчанию, как, например:
@@ -106,7 +106,7 @@ John Doe
Посмотрите на эту функцию — у неё уже есть подсказки типов:
-{* ../../docs_src/python_types/tutorial003_py39.py hl[1] *}
+{* ../../docs_src/python_types/tutorial003_py310.py hl[1] *}
Так как редактор кода знает типы переменных, вы получаете не только автозавершение, но и проверки ошибок:
@@ -114,7 +114,7 @@ John Doe
Теперь вы знаете, что нужно исправить — преобразовать `age` в строку с помощью `str(age)`:
-{* ../../docs_src/python_types/tutorial004_py39.py hl[2] *}
+{* ../../docs_src/python_types/tutorial004_py310.py hl[2] *}
## Объявление типов { #declaring-types }
@@ -133,29 +133,32 @@ John Doe
* `bool`
* `bytes`
-{* ../../docs_src/python_types/tutorial005_py39.py hl[1] *}
+{* ../../docs_src/python_types/tutorial005_py310.py hl[1] *}
-### Generic-типы с параметрами типов { #generic-types-with-type-parameters }
+### Модуль `typing` { #typing-module }
-Есть структуры данных, которые могут содержать другие значения, например, `dict`, `list`, `set` и `tuple`. И внутренние значения тоже могут иметь свой тип.
+Для некоторых дополнительных сценариев может понадобиться импортировать что-то из стандартного модуля `typing`. Например, когда вы хотите объявить, что что-то имеет «любой тип», можно использовать `Any` из `typing`:
-Такие типы, которые содержат внутренние типы, называют «**generic**»-типами. И их можно объявлять, в том числе с указанием внутренних типов.
+```python
+from typing import Any
-Чтобы объявлять эти типы и их внутренние типы, вы можете использовать стандартный модуль Python `typing`. Он существует специально для поддержки подсказок типов.
-#### Новые версии Python { #newer-versions-of-python }
-
-Синтаксис с использованием `typing` **совместим** со всеми версиями, от Python 3.6 до самых новых, включая Python 3.9, Python 3.10 и т.д.
+def some_function(data: Any):
+ print(data)
+```
-По мере развития Python **новые версии** получают улучшенную поддержку этих аннотаций типов, и во многих случаях вам даже не нужно импортировать и использовать модуль `typing`, чтобы объявлять аннотации типов.
+### Generic-типы { #generic-types }
-Если вы можете выбрать более свежую версию Python для проекта, вы получите дополнительную простоту.
+Некоторые типы могут принимать «параметры типов» в квадратных скобках, чтобы определить их внутренние типы. Например, «список строк» объявляется как `list[str]`.
-Во всей документации есть примеры, совместимые с каждой версией Python (когда есть различия).
+Такие типы, которые принимают параметры типов, называются **Generic-типами** или **Generics**.
-Например, «**Python 3.6+**» означает совместимость с Python 3.6 и выше (включая 3.7, 3.8, 3.9, 3.10 и т.д.). А «**Python 3.9+**» — совместимость с Python 3.9 и выше (включая 3.10 и т.п.).
+Вы можете использовать те же встроенные типы как generics (с квадратными скобками и типами внутри):
-Если вы можете использовать **последние версии Python**, используйте примеры для самой новой версии — у них будет **самый лучший и простой синтаксис**, например, «**Python 3.10+**».
+* `list`
+* `tuple`
+* `set`
+* `dict`
#### List { #list }
@@ -167,7 +170,7 @@ John Doe
Так как список — это тип, содержащий внутренние типы, укажите их в квадратных скобках:
-{* ../../docs_src/python_types/tutorial006_py39.py hl[1] *}
+{* ../../docs_src/python_types/tutorial006_py310.py hl[1] *}
/// info | Информация
@@ -193,7 +196,7 @@ John Doe
Аналогично вы бы объявили `tuple` и `set`:
-{* ../../docs_src/python_types/tutorial007_py39.py hl[1] *}
+{* ../../docs_src/python_types/tutorial007_py310.py hl[1] *}
Это означает:
@@ -208,7 +211,7 @@ John Doe
Второй параметр типа — для значений `dict`:
-{* ../../docs_src/python_types/tutorial008_py39.py hl[1] *}
+{* ../../docs_src/python_types/tutorial008_py310.py hl[1] *}
Это означает:
@@ -220,44 +223,20 @@ John Doe
Вы можете объявить, что переменная может быть **одним из нескольких типов**, например, `int` или `str`.
-В Python 3.6 и выше (включая Python 3.10) вы можете использовать тип `Union` из `typing` и перечислить в квадратных скобках все допустимые типы.
-
-В Python 3.10 также появился **новый синтаксис**, где допустимые типы можно указать через
вертикальную черту (`|`).
+Чтобы это определить, используйте
вертикальную черту (`|`) для разделения обоих типов.
-//// tab | Python 3.10+
+Это называется «объединение» (union), потому что переменная может быть чем угодно из объединения этих двух множеств типов.
```Python hl_lines="1"
{!> ../../docs_src/python_types/tutorial008b_py310.py!}
```
-////
-
-//// tab | Python 3.9+
-
-```Python hl_lines="1 4"
-{!> ../../docs_src/python_types/tutorial008b_py39.py!}
-```
-
-////
-
-В обоих случаях это означает, что `item` может быть `int` или `str`.
+Это означает, что `item` может быть `int` или `str`.
#### Возможно `None` { #possibly-none }
Вы можете объявить, что значение может иметь определённый тип, например `str`, но также может быть и `None`.
-В Python 3.6 и выше (включая Python 3.10) это можно объявить, импортировав и используя `Optional` из модуля `typing`.
-
-```Python hl_lines="1 4"
-{!../../docs_src/python_types/tutorial009_py39.py!}
-```
-
-Использование `Optional[str]` вместо просто `str` позволит редактору кода помочь вам обнаружить ошибки, когда вы предполагаете, что значение всегда `str`, хотя на самом деле оно может быть и `None`.
-
-`Optional[Something]` — это на самом деле сокращение для `Union[Something, None]`, они эквивалентны.
-
-Это также означает, что в Python 3.10 вы можете использовать `Something | None`:
-
//// tab | Python 3.10+
```Python hl_lines="1"
@@ -266,96 +245,7 @@ John Doe
////
-//// tab | Python 3.9+
-
-```Python hl_lines="1 4"
-{!> ../../docs_src/python_types/tutorial009_py39.py!}
-```
-
-////
-
-//// tab | Python 3.9+ альтернативный вариант
-
-```Python hl_lines="1 4"
-{!> ../../docs_src/python_types/tutorial009b_py39.py!}
-```
-
-////
-
-#### Использовать `Union` или `Optional` { #using-union-or-optional }
-
-Если вы используете версию Python ниже 3.10, вот совет с моей весьма **субъективной** точки зрения:
-
-* 🚨 Избегайте использования `Optional[SomeType]`
-* Вместо этого ✨ **используйте `Union[SomeType, None]`** ✨.
-
-Оба варианта эквивалентны и внутри одинаковы, но я бы рекомендовал `Union` вместо `Optional`, потому что слово «**optional**» («необязательный») может навести на мысль, что значение необязательное, хотя на самом деле оно означает «может быть `None`», даже если параметр не является необязательным и всё ещё обязателен.
-
-Мне кажется, `Union[SomeType, None]` более явно выражает смысл.
-
-Речь только о словах и названиях. Но эти слова могут влиять на то, как вы и ваши коллеги думаете о коде.
-
-В качестве примера возьмём эту функцию:
-
-{* ../../docs_src/python_types/tutorial009c_py39.py hl[1,4] *}
-
-Параметр `name` определён как `Optional[str]`, но он **не необязательный** — вы не можете вызвать функцию без этого параметра:
-
-```Python
-say_hi() # О нет, это вызывает ошибку! 😱
-```
-
-Параметр `name` всё ещё **обязателен** (не *optional*), потому что у него нет значения по умолчанию. При этом `name` принимает `None` как значение:
-
-```Python
-say_hi(name=None) # Это работает, None допустим 🎉
-```
-
-Хорошая новость: как только вы перейдёте на Python 3.10, об этом можно не переживать — вы сможете просто использовать `|` для объединения типов:
-
-{* ../../docs_src/python_types/tutorial009c_py310.py hl[1,4] *}
-
-И тогда вам не придётся задумываться о названиях вроде `Optional` и `Union`. 😎
-
-#### Generic-типы { #generic-types }
-
-Типы, которые принимают параметры типов в квадратных скобках, называются **Generic-типами** или **Generics**, например:
-
-//// tab | Python 3.10+
-
-Вы можете использовать те же встроенные типы как generics (с квадратными скобками и типами внутри):
-
-* `list`
-* `tuple`
-* `set`
-* `dict`
-
-И, как и в предыдущих версиях Python, из модуля `typing`:
-
-* `Union`
-* `Optional`
-* ...и другие.
-
-В Python 3.10, как альтернативу generics `Union` и `Optional`, можно использовать
вертикальную черту (`|`) для объявления объединений типов — это гораздо лучше и проще.
-
-////
-
-//// tab | Python 3.9+
-
-Вы можете использовать те же встроенные типы как generics (с квадратными скобками и типами внутри):
-
-* `list`
-* `tuple`
-* `set`
-* `dict`
-
-И generics из модуля `typing`:
-
-* `Union`
-* `Optional`
-* ...и другие.
-
-////
+Использование `str | None` вместо просто `str` позволит редактору кода помочь вам обнаружить ошибки, когда вы предполагаете, что значение всегда `str`, хотя на самом деле оно может быть и `None`.
### Классы как типы { #classes-as-types }
@@ -363,11 +253,11 @@ say_hi(name=None) # Это работает, None допустим 🎉
Допустим, у вас есть класс `Person` с именем:
-{* ../../docs_src/python_types/tutorial010_py39.py hl[1:3] *}
+{* ../../docs_src/python_types/tutorial010_py310.py hl[1:3] *}
Тогда вы можете объявить переменную типа `Person`:
-{* ../../docs_src/python_types/tutorial010_py39.py hl[6] *}
+{* ../../docs_src/python_types/tutorial010_py310.py hl[6] *}
И снова вы получите полную поддержку редактора кода:
@@ -401,21 +291,15 @@ say_hi(name=None) # Это работает, None допустим 🎉
**FastAPI** целиком основан на Pydantic.
-Вы увидите намного больше всего этого на практике в [Руководстве пользователя](tutorial/index.md){.internal-link target=_blank}.
-
-/// tip | Совет
-
-У Pydantic есть особое поведение, когда вы используете `Optional` или `Union[Something, None]` без значения по умолчанию. Подробнее читайте в документации Pydantic:
Required Optional fields.
-
-///
+Вы увидите намного больше всего этого на практике в [Учебник - Руководство пользователя](tutorial/index.md){.internal-link target=_blank}.
## Подсказки типов с аннотациями метаданных { #type-hints-with-metadata-annotations }
-В Python также есть возможность добавлять **дополнительные
метаданные** к подсказкам типов с помощью `Annotated`.
+В Python также есть возможность добавлять **дополнительные
метаданные** к подсказкам типов с помощью `Annotated`.
-Начиная с Python 3.9, `Annotated` входит в стандартную библиотеку, поэтому вы можете импортировать его из `typing`.
+Вы можете импортировать `Annotated` из `typing`.
-{* ../../docs_src/python_types/tutorial013_py39.py hl[1,4] *}
+{* ../../docs_src/python_types/tutorial013_py310.py hl[1,4] *}
Сам Python ничего не делает с `Annotated`. А для редакторов кода и других инструментов тип по-прежнему `str`.
@@ -453,7 +337,7 @@ say_hi(name=None) # Это работает, None допустим 🎉
* **Документирования** API с использованием OpenAPI:
* что затем используется пользовательскими интерфейсами автоматической интерактивной документации.
-Всё это может звучать абстрактно. Не волнуйтесь. Вы увидите всё это в действии в [Руководстве пользователя](tutorial/index.md){.internal-link target=_blank}.
+Всё это может звучать абстрактно. Не волнуйтесь. Вы увидите всё это в действии в [Учебник - Руководство пользователя](tutorial/index.md){.internal-link target=_blank}.
Важно то, что, используя стандартные типы Python в одном месте (вместо добавления дополнительных классов, декораторов и т.д.), **FastAPI** сделает за вас большую часть работы.
diff --git a/docs/ru/docs/tutorial/background-tasks.md b/docs/ru/docs/tutorial/background-tasks.md
index 8d7b7442f9..9fa7a85029 100644
--- a/docs/ru/docs/tutorial/background-tasks.md
+++ b/docs/ru/docs/tutorial/background-tasks.md
@@ -15,7 +15,7 @@
Сначала импортируйте `BackgroundTasks` и объявите параметр в вашей функции‑обработчике пути с типом `BackgroundTasks`:
-{* ../../docs_src/background_tasks/tutorial001_py39.py hl[1,13] *}
+{* ../../docs_src/background_tasks/tutorial001_py310.py hl[1,13] *}
**FastAPI** создаст объект типа `BackgroundTasks` для вас и передаст его через этот параметр.
@@ -31,13 +31,13 @@
Так как операция записи не использует `async` и `await`, мы определим функцию как обычную `def`:
-{* ../../docs_src/background_tasks/tutorial001_py39.py hl[6:9] *}
+{* ../../docs_src/background_tasks/tutorial001_py310.py hl[6:9] *}
## Добавление фоновой задачи { #add-the-background-task }
Внутри вашей функции‑обработчика пути передайте функцию задачи объекту фоновых задач методом `.add_task()`:
-{* ../../docs_src/background_tasks/tutorial001_py39.py hl[14] *}
+{* ../../docs_src/background_tasks/tutorial001_py310.py hl[14] *}
`.add_task()` принимает следующие аргументы:
@@ -47,7 +47,7 @@
## Встраивание зависимостей { #dependency-injection }
-Использование `BackgroundTasks` также работает с системой встраивания зависимостей, вы можете объявить параметр типа `BackgroundTasks` на нескольких уровнях: в функции‑обработчике пути, в зависимости (dependable), в подзависимости и т. д.
+Использование `BackgroundTasks` также работает с системой встраивания зависимостей, вы можете объявить параметр типа `BackgroundTasks` на нескольких уровнях: в функции‑обработчике пути, в зависимости (dependable), в подзависимости и т.д.
**FastAPI** знает, что делать в каждом случае и как переиспользовать один и тот же объект, так чтобы все фоновые задачи были объединены и затем выполнены в фоне:
@@ -73,7 +73,7 @@
## Предостережение { #caveat }
-Если вам нужно выполнять тяжелые вычисления в фоне, и при этом они не обязательно должны запускаться тем же процессом (например, вам не нужно делиться памятью, переменными и т. п.), вам могут подойти более мощные инструменты, такие как
Celery.
+Если вам нужно выполнять тяжелые вычисления в фоне, и при этом они не обязательно должны запускаться тем же процессом (например, вам не нужно делиться памятью, переменными и т.п.), вам могут подойти более мощные инструменты, такие как
Celery.
Они обычно требуют более сложной конфигурации, менеджера очереди сообщений/заданий (например, RabbitMQ или Redis), но позволяют запускать фоновые задачи в нескольких процессах и, что особенно важно, на нескольких серверах.
diff --git a/docs/ru/docs/tutorial/bigger-applications.md b/docs/ru/docs/tutorial/bigger-applications.md
index 76304523c9..3fb36d5a22 100644
--- a/docs/ru/docs/tutorial/bigger-applications.md
+++ b/docs/ru/docs/tutorial/bigger-applications.md
@@ -85,7 +85,7 @@ from app.routers import items
Точно так же, как и в случае с классом `FastAPI`, вам нужно импортировать и создать его «экземпляр»:
-{* ../../docs_src/bigger_applications/app_an_py39/routers/users.py hl[1,3] title["app/routers/users.py"] *}
+{* ../../docs_src/bigger_applications/app_an_py310/routers/users.py hl[1,3] title["app/routers/users.py"] *}
### *Операции пути* с `APIRouter` { #path-operations-with-apirouter }
@@ -93,7 +93,7 @@ from app.routers import items
Используйте его так же, как вы использовали бы класс `FastAPI`:
-{* ../../docs_src/bigger_applications/app_an_py39/routers/users.py hl[6,11,16] title["app/routers/users.py"] *}
+{* ../../docs_src/bigger_applications/app_an_py310/routers/users.py hl[6,11,16] title["app/routers/users.py"] *}
Вы можете думать об `APIRouter` как об «мини-классе `FastAPI`».
@@ -117,7 +117,7 @@ from app.routers import items
Теперь мы воспользуемся простой зависимостью, чтобы прочитать кастомный HTTP-заголовок `X-Token`:
-{* ../../docs_src/bigger_applications/app_an_py39/dependencies.py hl[3,6:8] title["app/dependencies.py"] *}
+{* ../../docs_src/bigger_applications/app_an_py310/dependencies.py hl[3,6:8] title["app/dependencies.py"] *}
/// tip | Подсказка
@@ -149,7 +149,7 @@ from app.routers import items
Таким образом, вместо того чтобы добавлять всё это в каждую *операцию пути*, мы можем добавить это в `APIRouter`.
-{* ../../docs_src/bigger_applications/app_an_py39/routers/items.py hl[5:10,16,21] title["app/routers/items.py"] *}
+{* ../../docs_src/bigger_applications/app_an_py310/routers/items.py hl[5:10,16,21] title["app/routers/items.py"] *}
Так как путь каждой *операции пути* должен начинаться с `/`, как здесь:
@@ -208,7 +208,7 @@ async def read_item(item_id: str):
Поэтому мы используем относительный импорт с `..` для зависимостей:
-{* ../../docs_src/bigger_applications/app_an_py39/routers/items.py hl[3] title["app/routers/items.py"] *}
+{* ../../docs_src/bigger_applications/app_an_py310/routers/items.py hl[3] title["app/routers/items.py"] *}
#### Как работает относительный импорт { #how-relative-imports-work }
@@ -279,7 +279,7 @@ from ...dependencies import get_token_header
Но мы всё равно можем добавить _ещё_ `tags`, которые будут применяться к конкретной *операции пути*, а также дополнительные `responses`, специфичные для этой *операции пути*:
-{* ../../docs_src/bigger_applications/app_an_py39/routers/items.py hl[30:31] title["app/routers/items.py"] *}
+{* ../../docs_src/bigger_applications/app_an_py310/routers/items.py hl[30:31] title["app/routers/items.py"] *}
/// tip | Подсказка
@@ -305,13 +305,13 @@ from ...dependencies import get_token_header
И мы даже можем объявить [глобальные зависимости](dependencies/global-dependencies.md){.internal-link target=_blank}, которые будут объединены с зависимостями для каждого `APIRouter`:
-{* ../../docs_src/bigger_applications/app_an_py39/main.py hl[1,3,7] title["app/main.py"] *}
+{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[1,3,7] title["app/main.py"] *}
### Импорт `APIRouter` { #import-the-apirouter }
Теперь мы импортируем другие подмодули, содержащие `APIRouter`:
-{* ../../docs_src/bigger_applications/app_an_py39/main.py hl[4:5] title["app/main.py"] *}
+{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[4:5] title["app/main.py"] *}
Так как файлы `app/routers/users.py` и `app/routers/items.py` являются подмодулями, входящими в один и тот же Python-пакет `app`, мы можем использовать одну точку `.` для импорта через «относительные импорты».
@@ -374,13 +374,13 @@ from .routers.users import router
Поэтому, чтобы иметь возможность использовать обе в одном файле, мы импортируем подмодули напрямую:
-{* ../../docs_src/bigger_applications/app_an_py39/main.py hl[5] title["app/main.py"] *}
+{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[5] title["app/main.py"] *}
### Подключение `APIRouter` для `users` и `items` { #include-the-apirouters-for-users-and-items }
Теперь давайте подключим `router` из подмодулей `users` и `items`:
-{* ../../docs_src/bigger_applications/app_an_py39/main.py hl[10:11] title["app/main.py"] *}
+{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[10:11] title["app/main.py"] *}
/// info | Примечание
@@ -420,13 +420,13 @@ from .routers.users import router
Для этого примера всё будет очень просто. Но допустим, что поскольку он используется совместно с другими проектами в организации, мы не можем модифицировать его и добавить `prefix`, `dependencies`, `tags` и т.д. непосредственно в `APIRouter`:
-{* ../../docs_src/bigger_applications/app_an_py39/internal/admin.py hl[3] title["app/internal/admin.py"] *}
+{* ../../docs_src/bigger_applications/app_an_py310/internal/admin.py hl[3] title["app/internal/admin.py"] *}
Но мы всё равно хотим задать пользовательский `prefix` при подключении `APIRouter`, чтобы все его *операции пути* начинались с `/admin`, хотим защитить его с помощью `dependencies`, которые у нас уже есть для этого проекта, и хотим включить `tags` и `responses`.
Мы можем объявить всё это, не изменяя исходный `APIRouter`, передав эти параметры в `app.include_router()`:
-{* ../../docs_src/bigger_applications/app_an_py39/main.py hl[14:17] title["app/main.py"] *}
+{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[14:17] title["app/main.py"] *}
Таким образом исходный `APIRouter` не будет модифицирован, и мы сможем использовать файл `app/internal/admin.py` сразу в нескольких проектах организации.
@@ -447,7 +447,7 @@ from .routers.users import router
Здесь мы делаем это... просто чтобы показать, что можем 🤷:
-{* ../../docs_src/bigger_applications/app_an_py39/main.py hl[21:23] title["app/main.py"] *}
+{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[21:23] title["app/main.py"] *}
и это будет работать корректно вместе со всеми другими *операциями пути*, добавленными через `app.include_router()`.
diff --git a/docs/ru/docs/tutorial/body-multiple-params.md b/docs/ru/docs/tutorial/body-multiple-params.md
index 9d94004947..ddd9c6fdd9 100644
--- a/docs/ru/docs/tutorial/body-multiple-params.md
+++ b/docs/ru/docs/tutorial/body-multiple-params.md
@@ -52,7 +52,7 @@
}
```
-/// note | Внимание
+/// note | Заметка
Обратите внимание, что хотя параметр `item` был объявлен таким же способом, как и раньше, теперь предполагается, что он находится внутри тела с ключом `item`.
@@ -104,12 +104,6 @@
q: str | None = None
```
-Или в Python 3.9:
-
-```Python
-q: Union[str, None] = None
-```
-
Например:
{* ../../docs_src/body_multiple_params/tutorial004_an_py310.py hl[28] *}
diff --git a/docs/ru/docs/tutorial/body-nested-models.md b/docs/ru/docs/tutorial/body-nested-models.md
index 4c914b97f0..6610b209c2 100644
--- a/docs/ru/docs/tutorial/body-nested-models.md
+++ b/docs/ru/docs/tutorial/body-nested-models.md
@@ -163,7 +163,7 @@ images: list[Image]
например так:
-{* ../../docs_src/body_nested_models/tutorial008_py39.py hl[13] *}
+{* ../../docs_src/body_nested_models/tutorial008_py310.py hl[13] *}
## Поддержка редактора кода везде { #editor-support-everywhere }
@@ -193,7 +193,7 @@ images: list[Image]
В этом случае вы принимаете любой `dict`, пока у него есть ключи типа `int` со значениями типа `float`:
-{* ../../docs_src/body_nested_models/tutorial009_py39.py hl[7] *}
+{* ../../docs_src/body_nested_models/tutorial009_py310.py hl[7] *}
/// tip | Совет
diff --git a/docs/ru/docs/tutorial/body.md b/docs/ru/docs/tutorial/body.md
index 537d7ebc96..3e55607da5 100644
--- a/docs/ru/docs/tutorial/body.md
+++ b/docs/ru/docs/tutorial/body.md
@@ -72,7 +72,7 @@
* Проведёт валидацию данных.
* Если данные некорректны, вернёт понятную и наглядную ошибку, указывающую, где именно и что было некорректно.
* Передаст полученные данные в параметр `item`.
- * Поскольку внутри функции вы объявили его с типом `Item`, у вас будет поддержка со стороны редактора кода (автозавершение и т. п.) для всех атрибутов и их типов.
+ * Поскольку внутри функции вы объявили его с типом `Item`, у вас будет поддержка со стороны редактора кода (автозавершение и т.п.) для всех атрибутов и их типов.
* Сгенерирует определения
JSON Schema для вашей модели; вы можете использовать их и в других местах, если это имеет смысл для вашего проекта.
* Эти схемы будут частью сгенерированной схемы OpenAPI и будут использоваться автоматической документацией
UIs.
@@ -148,14 +148,14 @@ JSON Schema ваших моделей будет частью сгенериро
Параметры функции будут распознаны следующим образом:
* Если параметр также объявлен в **пути**, он будет использоваться как path-параметр.
-* Если параметр имеет **скалярный тип** (например, `int`, `float`, `str`, `bool` и т. п.), он будет интерпретирован как параметр **запроса**.
+* Если параметр имеет **скалярный тип** (например, `int`, `float`, `str`, `bool` и т.п.), он будет интерпретирован как параметр **запроса**.
* Если параметр объявлен как тип **модели Pydantic**, он будет интерпретирован как **тело** запроса.
/// note | Заметка
FastAPI понимает, что значение `q` не является обязательным из-за значения по умолчанию `= None`.
-Аннотации типов `str | None` (Python 3.10+) или `Union` в `Union[str, None]` (Python 3.9+) не используются FastAPI для определения обязательности; он узнает, что параметр не обязателен, потому что у него есть значение по умолчанию `= None`.
+Аннотация типов `str | None` не используется FastAPI для определения обязательности; он узнает, что параметр не обязателен, потому что у него есть значение по умолчанию `= None`.
Но добавление аннотаций типов позволит вашему редактору кода лучше вас поддерживать и обнаруживать ошибки.
diff --git a/docs/ru/docs/tutorial/cookie-param-models.md b/docs/ru/docs/tutorial/cookie-param-models.md
index 182813afdf..9b34cf0300 100644
--- a/docs/ru/docs/tutorial/cookie-param-models.md
+++ b/docs/ru/docs/tutorial/cookie-param-models.md
@@ -46,7 +46,7 @@
В некоторых случаях (не особо часто встречающихся) вам может понадобиться **ограничить** cookies, которые вы хотите получать.
-Теперь ваш API сам решает,
принимать ли cookies. 🤪🍪
+Теперь у вашего API есть возможность контролировать своё
согласие на использование cookie. 🤪🍪
Вы можете сконфигурировать Pydantic-модель так, чтобы запретить (`forbid`) любые дополнительные (`extra`) поля:
@@ -54,9 +54,9 @@
Если клиент попробует отправить **дополнительные cookies**, то в ответ он получит **ошибку**.
-Бедные баннеры cookies, они всеми силами пытаются получить ваше согласие — и всё ради того, чтобы
API его отклонил. 🍪
+Бедные баннеры cookies, они всеми силами пытаются получить ваше согласие — и всё ради того, чтобы
API его отклонил. 🍪
-Например, если клиент попытается отправить cookie `santa_tracker` со значением `good-list-please`, то в ответ он получит **ошибку**, сообщающую ему, что cookie `santa_tracker`
не разрешён:
+Например, если клиент попытается отправить cookie `santa_tracker` со значением `good-list-please`, то в ответ он получит **ошибку**, сообщающую ему, что `santa_tracker`
cookie не разрешён:
```json
{
@@ -73,4 +73,4 @@
## Заключение { #summary }
-Вы можете использовать **Pydantic-модели** для объявления
**cookies** в **FastAPI**. 😎
+Вы можете использовать **Pydantic-модели** для объявления
**cookies** в **FastAPI**. 😎
diff --git a/docs/ru/docs/tutorial/cookie-params.md b/docs/ru/docs/tutorial/cookie-params.md
index 2d2eff8d7c..8dad3873e4 100644
--- a/docs/ru/docs/tutorial/cookie-params.md
+++ b/docs/ru/docs/tutorial/cookie-params.md
@@ -32,11 +32,11 @@
/// info | Дополнительная информация
-Имейте в виду, что, поскольку браузеры обрабатывают cookies особым образом и «за кулисами», они не позволяют JavaScript просто так получать к ним доступ.
+Имейте в виду, что, поскольку **браузеры обрабатывают cookies** особым образом и «за кулисами», они **не** позволяют **JavaScript** просто так получать к ним доступ.
-Если вы откроете интерфейс документации API на `/docs`, вы сможете увидеть документацию по cookies для ваших операций пути.
+Если вы откроете **интерфейс документации API** на `/docs`, вы сможете увидеть **документацию** по cookies для ваших *операции пути*.
-Но даже если вы заполните данные и нажмёте «Execute», поскольку UI документации работает с JavaScript, cookies отправлены не будут, и вы увидите сообщение об ошибке, как будто вы не указали никаких значений.
+Но даже если вы **заполните данные** и нажмёте «Execute», поскольку UI документации работает с **JavaScript**, cookies отправлены не будут, и вы увидите сообщение об **ошибке**, как будто вы не указали никаких значений.
///
diff --git a/docs/ru/docs/tutorial/cors.md b/docs/ru/docs/tutorial/cors.md
index d09a31e2c3..feaa159683 100644
--- a/docs/ru/docs/tutorial/cors.md
+++ b/docs/ru/docs/tutorial/cors.md
@@ -46,7 +46,7 @@
* Отдельных HTTP-методов (`POST`, `PUT`) или всех вместе, используя `"*"`.
* Отдельных HTTP-заголовков или всех вместе, используя `"*"`.
-{* ../../docs_src/cors/tutorial001_py39.py hl[2,6:11,13:19] *}
+{* ../../docs_src/cors/tutorial001_py310.py hl[2,6:11,13:19] *}
`CORSMiddleware` использует "запрещающие" значения по умолчанию, поэтому вам нужно явным образом разрешить использование отдельных источников, методов или заголовков, чтобы браузеры могли использовать их в кросс-доменном контексте.
@@ -77,7 +77,7 @@
## Больше информации { #more-info }
-Для получения более подробной информации о
CORS обратитесь к
документации CORS от Mozilla.
+Для получения более подробной информации о
CORS обратитесь к
документации CORS от Mozilla.
/// note | Технические детали
diff --git a/docs/ru/docs/tutorial/debugging.md b/docs/ru/docs/tutorial/debugging.md
index 51955835e6..483fe80869 100644
--- a/docs/ru/docs/tutorial/debugging.md
+++ b/docs/ru/docs/tutorial/debugging.md
@@ -6,7 +6,7 @@
В вашем FastAPI приложении, импортируйте и вызовите `uvicorn` напрямую:
-{* ../../docs_src/debugging/tutorial001_py39.py hl[1,15] *}
+{* ../../docs_src/debugging/tutorial001_py310.py hl[1,15] *}
### Описание `__name__ == "__main__"` { #about-name-main }
@@ -42,7 +42,7 @@ $ python myapp.py
то встроенная переменная `__name__`, автоматически создаваемая Python в вашем файле, будет иметь значение строкового типа `"__main__"`.
-Тогда выполнится условие и эта часть кода:
+Тогда эта часть кода:
```Python
uvicorn.run(app, host="0.0.0.0", port=8000)
@@ -59,7 +59,7 @@ $ python myapp.py
```Python
from myapp import app
-# Some more code
+# Еще немного кода
```
то автоматическая создаваемая внутри файла `myapp.py` переменная `__name__` будет иметь значение отличающееся от `"__main__"`.
@@ -99,7 +99,7 @@ from myapp import app
---
-Если используете Pycharm, вы можете выполнить следующие шаги:
+Если используете PyCharm, вы можете выполнить следующие шаги:
* Открыть "Run" меню.
* Выбрать опцию "Debug...".
diff --git a/docs/ru/docs/tutorial/dependencies/classes-as-dependencies.md b/docs/ru/docs/tutorial/dependencies/classes-as-dependencies.md
index a38e885d43..9a3171e9f1 100644
--- a/docs/ru/docs/tutorial/dependencies/classes-as-dependencies.md
+++ b/docs/ru/docs/tutorial/dependencies/classes-as-dependencies.md
@@ -4,7 +4,7 @@
## `dict` из предыдущего примера { #a-dict-from-the-previous-example }
-В предыдущем примере мы возвращали `dict` из нашей зависимости:
+В предыдущем примере мы возвращали `dict` из нашей зависимости («dependable»):
{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[9] *}
@@ -67,7 +67,7 @@ fluffy = Cat(name="Mr Fluffy")
Это относится и к вызываемым объектам без параметров. Работа с ними происходит точно так же, как и для *функций-обработчиков пути* без параметров.
-Теперь мы можем изменить зависимость `common_parameters`, указанную выше, на класс `CommonQueryParams`:
+Теперь мы можем изменить зависимость («dependable») `common_parameters`, указанную выше, на класс `CommonQueryParams`:
{* ../../docs_src/dependencies/tutorial002_an_py310.py hl[11:15] *}
@@ -101,7 +101,7 @@ fluffy = Cat(name="Mr Fluffy")
Обратите внимание, что в приведенном выше коде мы два раза пишем `CommonQueryParams`:
-//// tab | Python 3.9+
+//// tab | Python 3.10+
```Python
commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]
@@ -109,7 +109,7 @@ commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]
////
-//// tab | Python 3.9+ non-Annotated
+//// tab | Python 3.10+ без Annotated
/// tip | Подсказка
@@ -137,7 +137,7 @@ commons: CommonQueryParams = Depends(CommonQueryParams)
В этом случае первый `CommonQueryParams`, в:
-//// tab | Python 3.9+
+//// tab | Python 3.10+
```Python
commons: Annotated[CommonQueryParams, ...
@@ -145,7 +145,7 @@ commons: Annotated[CommonQueryParams, ...
////
-//// tab | Python 3.9+ non-Annotated
+//// tab | Python 3.10+ без Annotated
/// tip | Подсказка
@@ -163,7 +163,7 @@ commons: CommonQueryParams ...
На самом деле можно написать просто:
-//// tab | Python 3.9+
+//// tab | Python 3.10+
```Python
commons: Annotated[Any, Depends(CommonQueryParams)]
@@ -171,7 +171,7 @@ commons: Annotated[Any, Depends(CommonQueryParams)]
////
-//// tab | Python 3.9+ non-Annotated
+//// tab | Python 3.10+ без Annotated
/// tip | Подсказка
@@ -197,7 +197,7 @@ commons = Depends(CommonQueryParams)
Но вы видите, что здесь мы имеем некоторое повторение кода, дважды написав `CommonQueryParams`:
-//// tab | Python 3.9+
+//// tab | Python 3.10+
```Python
commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]
@@ -205,7 +205,7 @@ commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]
////
-//// tab | Python 3.9+ non-Annotated
+//// tab | Python 3.10+ без Annotated
/// tip | Подсказка
@@ -225,7 +225,7 @@ commons: CommonQueryParams = Depends(CommonQueryParams)
Вместо того чтобы писать:
-//// tab | Python 3.9+
+//// tab | Python 3.10+
```Python
commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]
@@ -233,7 +233,7 @@ commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]
////
-//// tab | Python 3.9+ non-Annotated
+//// tab | Python 3.10+ без Annotated
/// tip | Подсказка
@@ -249,7 +249,7 @@ commons: CommonQueryParams = Depends(CommonQueryParams)
...следует написать:
-//// tab | Python 3.9+
+//// tab | Python 3.10+
```Python
commons: Annotated[CommonQueryParams, Depends()]
@@ -257,7 +257,7 @@ commons: Annotated[CommonQueryParams, Depends()]
////
-//// tab | Python 3.9+ non-Annotated
+//// tab | Python 3.10+ без Annotated
/// tip | Подсказка
diff --git a/docs/ru/docs/tutorial/dependencies/dependencies-in-path-operation-decorators.md b/docs/ru/docs/tutorial/dependencies/dependencies-in-path-operation-decorators.md
index ef56644485..4cfc4e699f 100644
--- a/docs/ru/docs/tutorial/dependencies/dependencies-in-path-operation-decorators.md
+++ b/docs/ru/docs/tutorial/dependencies/dependencies-in-path-operation-decorators.md
@@ -14,7 +14,7 @@
Это должен быть `list` состоящий из `Depends()`:
-{* ../../docs_src/dependencies/tutorial006_an_py39.py hl[19] *}
+{* ../../docs_src/dependencies/tutorial006_an_py310.py hl[19] *}
Зависимости из dependencies выполнятся так же, как и обычные зависимости. Но их значения (если они были) не будут переданы в *функцию операции пути*.
@@ -30,7 +30,7 @@
/// info | Примечание
-В этом примере мы используем выдуманные пользовательские заголовки `X-Key` и `X-Token`.
+В этом примере мы используем выдуманные пользовательские HTTP-заголовки `X-Key` и `X-Token`.
Но в реальных проектах, при внедрении системы безопасности, вы получите больше пользы используя интегрированные [средства защиты (следующая глава)](../security/index.md){.internal-link target=_blank}.
@@ -42,15 +42,15 @@
### Требования к зависимостям { #dependency-requirements }
-Они могут объявлять требования к запросу (например заголовки) или другие подзависимости:
+Они могут объявлять требования к запросу (например HTTP-заголовки) или другие подзависимости:
-{* ../../docs_src/dependencies/tutorial006_an_py39.py hl[8,13] *}
+{* ../../docs_src/dependencies/tutorial006_an_py310.py hl[8,13] *}
### Вызов исключений { #raise-exceptions }
Зависимости из dependencies могут вызывать исключения с помощью `raise`, как и обычные зависимости:
-{* ../../docs_src/dependencies/tutorial006_an_py39.py hl[10,15] *}
+{* ../../docs_src/dependencies/tutorial006_an_py310.py hl[10,15] *}
### Возвращаемые значения { #return-values }
@@ -58,7 +58,7 @@
Таким образом, вы можете переиспользовать обычную зависимость (возвращающую значение), которую вы уже используете где-то в другом месте, и хотя значение не будет использоваться, зависимость будет выполнена:
-{* ../../docs_src/dependencies/tutorial006_an_py39.py hl[11,16] *}
+{* ../../docs_src/dependencies/tutorial006_an_py310.py hl[11,16] *}
## Зависимости для группы *операций путей* { #dependencies-for-a-group-of-path-operations }
diff --git a/docs/ru/docs/tutorial/dependencies/dependencies-with-yield.md b/docs/ru/docs/tutorial/dependencies/dependencies-with-yield.md
index dc202db616..03a7c083c4 100644
--- a/docs/ru/docs/tutorial/dependencies/dependencies-with-yield.md
+++ b/docs/ru/docs/tutorial/dependencies/dependencies-with-yield.md
@@ -1,6 +1,6 @@
# Зависимости с yield { #dependencies-with-yield }
-FastAPI поддерживает зависимости, которые выполняют некоторые
дополнительные шаги после завершения.
+FastAPI поддерживает зависимости, которые выполняют некоторые
дополнительные шаги после завершения.
Для этого используйте `yield` вместо `return`, а дополнительные шаги (код) напишите после него.
@@ -29,15 +29,15 @@ FastAPI поддерживает зависимости, которые выпо
Перед созданием ответа будет выполнен только код до и включая оператор `yield`:
-{* ../../docs_src/dependencies/tutorial007_py39.py hl[2:4] *}
+{* ../../docs_src/dependencies/tutorial007_py310.py hl[2:4] *}
Значение, полученное из `yield`, внедряется в *операции пути* и другие зависимости:
-{* ../../docs_src/dependencies/tutorial007_py39.py hl[4] *}
+{* ../../docs_src/dependencies/tutorial007_py310.py hl[4] *}
Код, следующий за оператором `yield`, выполняется после ответа:
-{* ../../docs_src/dependencies/tutorial007_py39.py hl[5:6] *}
+{* ../../docs_src/dependencies/tutorial007_py310.py hl[5:6] *}
/// tip | Подсказка
@@ -57,7 +57,7 @@ FastAPI поддерживает зависимости, которые выпо
Точно так же можно использовать `finally`, чтобы убедиться, что обязательные шаги при выходе выполнены независимо от того, было ли исключение или нет.
-{* ../../docs_src/dependencies/tutorial007_py39.py hl[3,5] *}
+{* ../../docs_src/dependencies/tutorial007_py310.py hl[3,5] *}
## Подзависимости с `yield` { #sub-dependencies-with-yield }
@@ -67,7 +67,7 @@ FastAPI поддерживает зависимости, которые выпо
Например, `dependency_c` может зависеть от `dependency_b`, а `dependency_b` — от `dependency_a`:
-{* ../../docs_src/dependencies/tutorial008_an_py39.py hl[6,14,22] *}
+{* ../../docs_src/dependencies/tutorial008_an_py310.py hl[6,14,22] *}
И все они могут использовать `yield`.
@@ -75,7 +75,7 @@ FastAPI поддерживает зависимости, которые выпо
И, в свою очередь, `dependency_b` нуждается в том, чтобы значение из `dependency_a` (здесь `dep_a`) было доступно для её кода выхода.
-{* ../../docs_src/dependencies/tutorial008_an_py39.py hl[18:19,26:27] *}
+{* ../../docs_src/dependencies/tutorial008_an_py310.py hl[18:19,26:27] *}
Точно так же можно иметь часть зависимостей с `yield`, часть — с `return`, и какие-то из них могут зависеть друг от друга.
@@ -109,7 +109,7 @@ FastAPI поддерживает зависимости, которые выпо
///
-{* ../../docs_src/dependencies/tutorial008b_an_py39.py hl[18:22,31] *}
+{* ../../docs_src/dependencies/tutorial008b_an_py310.py hl[18:22,31] *}
Если вы хотите перехватывать исключения и формировать на их основе пользовательский ответ, создайте [Пользовательский обработчик исключений](../handling-errors.md#install-custom-exception-handlers){.internal-link target=_blank}.
@@ -117,7 +117,7 @@ FastAPI поддерживает зависимости, которые выпо
Если вы ловите исключение с помощью `except` в зависимости с `yield` и не вызываете его снова (или не вызываете новое исключение), FastAPI не сможет заметить, что было исключение — так же, как это происходит в обычном Python:
-{* ../../docs_src/dependencies/tutorial008c_an_py39.py hl[15:16] *}
+{* ../../docs_src/dependencies/tutorial008c_an_py310.py hl[15:16] *}
В этом случае клиент получит *HTTP 500 Internal Server Error*, как и должно быть, поскольку мы не вызываем `HTTPException` или что-то подобное, но на сервере **не будет никаких логов** или других указаний на то, какая была ошибка. 😱
@@ -127,7 +127,7 @@ FastAPI поддерживает зависимости, которые выпо
Вы можете повторно вызвать то же самое исключение с помощью `raise`:
-{* ../../docs_src/dependencies/tutorial008d_an_py39.py hl[17] *}
+{* ../../docs_src/dependencies/tutorial008d_an_py310.py hl[17] *}
Теперь клиент получит тот же *HTTP 500 Internal Server Error*, но на сервере в логах будет наше пользовательское `InternalError`. 😎
@@ -190,7 +190,7 @@ participant tasks as Background tasks
Но если вы знаете, что не будете использовать зависимость после возврата из *функции-обработчика пути*, вы можете использовать `Depends(scope="function")`, чтобы сообщить FastAPI, что он должен закрыть зависимость после возврата из *функции-обработчика пути*, но **до того**, как **ответ будет отправлен**.
-{* ../../docs_src/dependencies/tutorial008e_an_py39.py hl[12,16] *}
+{* ../../docs_src/dependencies/tutorial008e_an_py310.py hl[12,16] *}
`Depends()` принимает параметр `scope`, который может быть:
@@ -269,7 +269,7 @@ with open("./somefile.txt") as f:
Их также можно использовать внутри зависимостей **FastAPI** с `yield`, применяя операторы
`with` или `async with` внутри функции зависимости:
-{* ../../docs_src/dependencies/tutorial010_py39.py hl[1:9,13] *}
+{* ../../docs_src/dependencies/tutorial010_py310.py hl[1:9,13] *}
/// tip | Подсказка
diff --git a/docs/ru/docs/tutorial/dependencies/global-dependencies.md b/docs/ru/docs/tutorial/dependencies/global-dependencies.md
index 2347c6dd83..f488322a9e 100644
--- a/docs/ru/docs/tutorial/dependencies/global-dependencies.md
+++ b/docs/ru/docs/tutorial/dependencies/global-dependencies.md
@@ -6,10 +6,10 @@
В этом случае они будут применяться ко всем *операциям пути* в приложении:
-{* ../../docs_src/dependencies/tutorial012_an_py39.py hl[17] *}
+{* ../../docs_src/dependencies/tutorial012_an_py310.py hl[17] *}
Все способы [добавления `dependencies` (зависимостей) в *декораторах операций пути*](dependencies-in-path-operation-decorators.md){.internal-link target=_blank} по-прежнему применимы, но в данном случае зависимости применяются ко всем *операциям пути* приложения.
## Зависимости для групп *операций пути* { #dependencies-for-groups-of-path-operations }
-Позднее, читая о том, как структурировать более крупные [приложения, содержащие много файлов](../../tutorial/bigger-applications.md){.internal-link target=_blank}, вы узнаете, как объявить один параметр `dependencies` для целой группы *операций пути*.
+Позднее, читая о том, как структурировать более крупные приложения ([приложения, содержащие много файлов](../../tutorial/bigger-applications.md){.internal-link target=_blank}), возможно, состоящие из нескольких файлов, вы узнаете, как объявить один параметр `dependencies` для целой группы *операций пути*.
diff --git a/docs/ru/docs/tutorial/dependencies/index.md b/docs/ru/docs/tutorial/dependencies/index.md
index 98b0d59c6a..29f735ab61 100644
--- a/docs/ru/docs/tutorial/dependencies/index.md
+++ b/docs/ru/docs/tutorial/dependencies/index.md
@@ -1,6 +1,6 @@
# Зависимости { #dependencies }
-**FastAPI** имеет очень мощную, но интуитивную систему **
Инъекция зависимостей**.
+**FastAPI** имеет очень мощную, но интуитивную систему **
Инъекция зависимостей**.
Она спроектирована так, чтобы быть очень простой в использовании и облегчать любому разработчику интеграцию других компонентов с **FastAPI**.
diff --git a/docs/ru/docs/tutorial/dependencies/sub-dependencies.md b/docs/ru/docs/tutorial/dependencies/sub-dependencies.md
index da31a6682f..3c71defd89 100644
--- a/docs/ru/docs/tutorial/dependencies/sub-dependencies.md
+++ b/docs/ru/docs/tutorial/dependencies/sub-dependencies.md
@@ -58,11 +58,11 @@ query_extractor --> query_or_cookie_extractor --> read_query
Если одна из ваших зависимостей объявлена несколько раз для одной и той же *функции операции пути*, например, несколько зависимостей имеют общую подзависимость, **FastAPI** будет знать, что вызывать эту подзависимость нужно только один раз за запрос.
-При этом возвращаемое значение будет сохранено в
"кэш" и будет передано всем "зависимым" функциям, которые нуждаются в нем внутри этого конкретного запроса, вместо того, чтобы вызывать зависимость несколько раз для одного и того же запроса.
+При этом возвращаемое значение будет сохранено в
«кэш» и будет передано всем "зависимым" функциям, которые нуждаются в нем внутри этого конкретного запроса, вместо того, чтобы вызывать зависимость несколько раз для одного и того же запроса.
В расширенном сценарии, когда вы знаете, что вам нужно, чтобы зависимость вызывалась на каждом шаге (возможно, несколько раз) в одном и том же запросе, вместо использования "кэшированного" значения, вы можете установить параметр `use_cache=False` при использовании `Depends`:
-//// tab | Python 3.9+
+//// tab | Python 3.10+
```Python hl_lines="1"
async def needy_dependency(fresh_value: Annotated[str, Depends(get_value, use_cache=False)]):
@@ -71,7 +71,7 @@ async def needy_dependency(fresh_value: Annotated[str, Depends(get_value, use_ca
////
-//// tab | Python 3.9+ без Annotated
+//// tab | Python 3.10+ без Annotated
/// tip | Подсказка
diff --git a/docs/ru/docs/tutorial/encoder.md b/docs/ru/docs/tutorial/encoder.md
index 16981f79de..28e2a49c0a 100644
--- a/docs/ru/docs/tutorial/encoder.md
+++ b/docs/ru/docs/tutorial/encoder.md
@@ -10,9 +10,9 @@
Представим, что у вас есть база данных `fake_db`, которая принимает только JSON-совместимые данные.
-Например, он не принимает объекты `datetime`, так как они не совместимы с JSON.
+Например, она не принимает объекты `datetime`, так как они не совместимы с JSON.
-В таком случае объект `datetime` следует преобразовать в строку соответствующую
формату ISO.
+В таком случае объект `datetime` следует преобразовать в строку, соответствующую
формату ISO.
Точно так же эта база данных не может принять Pydantic-модель (объект с атрибутами), а только `dict`.
diff --git a/docs/ru/docs/tutorial/extra-models.md b/docs/ru/docs/tutorial/extra-models.md
index 03156f2b4e..f9b63ca70e 100644
--- a/docs/ru/docs/tutorial/extra-models.md
+++ b/docs/ru/docs/tutorial/extra-models.md
@@ -190,9 +190,9 @@ some_variable: PlaneItem | CarItem
Таким же образом вы можете объявлять HTTP-ответы, возвращающие списки объектов.
-Для этого используйте стандартный `typing.List` в Python (или просто `list` в Python 3.9 и выше):
+Для этого используйте стандартный `list` в Python:
-{* ../../docs_src/extra_models/tutorial004_py39.py hl[18] *}
+{* ../../docs_src/extra_models/tutorial004_py310.py hl[18] *}
## Ответ с произвольным `dict` { #response-with-arbitrary-dict }
@@ -200,9 +200,9 @@ some_variable: PlaneItem | CarItem
Это полезно, если вы заранее не знаете корректных названий полей/атрибутов (которые будут нужны при использовании Pydantic-модели).
-В этом случае вы можете использовать `typing.Dict` (или просто `dict` в Python 3.9 и выше):
+В этом случае вы можете использовать `dict`:
-{* ../../docs_src/extra_models/tutorial005_py39.py hl[6] *}
+{* ../../docs_src/extra_models/tutorial005_py310.py hl[6] *}
## Резюме { #recap }
diff --git a/docs/ru/docs/tutorial/first-steps.md b/docs/ru/docs/tutorial/first-steps.md
index 798c03d517..cee264ff46 100644
--- a/docs/ru/docs/tutorial/first-steps.md
+++ b/docs/ru/docs/tutorial/first-steps.md
@@ -2,7 +2,7 @@
Самый простой файл FastAPI может выглядеть так:
-{* ../../docs_src/first_steps/tutorial001_py39.py *}
+{* ../../docs_src/first_steps/tutorial001_py310.py *}
Скопируйте это в файл `main.py`.
@@ -183,7 +183,7 @@ Deploying to FastAPI Cloud...
### Шаг 1: импортируйте `FastAPI` { #step-1-import-fastapi }
-{* ../../docs_src/first_steps/tutorial001_py39.py hl[1] *}
+{* ../../docs_src/first_steps/tutorial001_py310.py hl[1] *}
`FastAPI` — это класс на Python, который предоставляет всю функциональность для вашего API.
@@ -197,7 +197,7 @@ Deploying to FastAPI Cloud...
### Шаг 2: создайте экземпляр `FastAPI` { #step-2-create-a-fastapi-instance }
-{* ../../docs_src/first_steps/tutorial001_py39.py hl[3] *}
+{* ../../docs_src/first_steps/tutorial001_py310.py hl[3] *}
Здесь переменная `app` будет экземпляром класса `FastAPI`.
@@ -266,12 +266,12 @@ https://example.com/items/foo
#### Определите *декоратор операции пути (path operation decorator)* { #define-a-path-operation-decorator }
-{* ../../docs_src/first_steps/tutorial001_py39.py hl[6] *}
+{* ../../docs_src/first_steps/tutorial001_py310.py hl[6] *}
`@app.get("/")` сообщает **FastAPI**, что функция прямо под ним отвечает за обработку запросов, поступающих:
* по пути `/`
-* с использованием
get операции
+* с использованием
get операции
/// info | Информация о `@decorator`
@@ -320,7 +320,7 @@ https://example.com/items/foo
* **операция**: `get`.
* **функция**: функция ниже «декоратора» (ниже `@app.get("/")`).
-{* ../../docs_src/first_steps/tutorial001_py39.py hl[7] *}
+{* ../../docs_src/first_steps/tutorial001_py310.py hl[7] *}
Это функция на Python.
@@ -332,7 +332,7 @@ https://example.com/items/foo
Вы также можете определить её как обычную функцию вместо `async def`:
-{* ../../docs_src/first_steps/tutorial003_py39.py hl[7] *}
+{* ../../docs_src/first_steps/tutorial003_py310.py hl[7] *}
/// note | Примечание
@@ -342,7 +342,7 @@ https://example.com/items/foo
### Шаг 5: верните содержимое { #step-5-return-the-content }
-{* ../../docs_src/first_steps/tutorial001_py39.py hl[8] *}
+{* ../../docs_src/first_steps/tutorial001_py310.py hl[8] *}
Вы можете вернуть `dict`, `list`, отдельные значения `str`, `int` и т.д.
diff --git a/docs/ru/docs/tutorial/handling-errors.md b/docs/ru/docs/tutorial/handling-errors.md
index 2e00d70759..fbd82cf28a 100644
--- a/docs/ru/docs/tutorial/handling-errors.md
+++ b/docs/ru/docs/tutorial/handling-errors.md
@@ -11,7 +11,7 @@
* Элемент, к которому клиент пытался получить доступ, не существует.
* и т.д.
-В таких случаях обычно возвращается **HTTP-код статуса ответа** в диапазоне **400** (от 400 до 499).
+В таких случаях обычно возвращают **HTTP статус-код** в диапазоне **400** (от 400 до 499).
Они похожи на двухсотые HTTP статус-коды (от 200 до 299), которые означают, что запрос обработан успешно.
@@ -25,7 +25,7 @@
### Импортируйте `HTTPException` { #import-httpexception }
-{* ../../docs_src/handling_errors/tutorial001_py39.py hl[1] *}
+{* ../../docs_src/handling_errors/tutorial001_py310.py hl[1] *}
### Вызовите `HTTPException` в своем коде { #raise-an-httpexception-in-your-code }
@@ -39,7 +39,7 @@
В данном примере, когда клиент запрашивает элемент по несуществующему ID, возникает исключение со статус-кодом `404`:
-{* ../../docs_src/handling_errors/tutorial001_py39.py hl[11] *}
+{* ../../docs_src/handling_errors/tutorial001_py310.py hl[11] *}
### Возвращаемый ответ { #the-resulting-response }
@@ -71,13 +71,13 @@
## Добавление пользовательских заголовков { #add-custom-headers }
-В некоторых ситуациях полезно иметь возможность добавлять пользовательские заголовки к ошибке HTTP. Например, для некоторых типов безопасности.
+В некоторых ситуациях полезно иметь возможность добавлять пользовательские HTTP-заголовки к ошибке HTTP. Например, для некоторых типов безопасности.
Скорее всего, вам не потребуется использовать его непосредственно в коде.
Но в случае, если это необходимо для продвинутого сценария, можно добавить пользовательские заголовки:
-{* ../../docs_src/handling_errors/tutorial002_py39.py hl[14] *}
+{* ../../docs_src/handling_errors/tutorial002_py310.py hl[14] *}
## Установка пользовательских обработчиков исключений { #install-custom-exception-handlers }
@@ -89,7 +89,7 @@
Можно добавить собственный обработчик исключений с помощью `@app.exception_handler()`:
-{* ../../docs_src/handling_errors/tutorial003_py39.py hl[5:7,13:18,24] *}
+{* ../../docs_src/handling_errors/tutorial003_py310.py hl[5:7,13:18,24] *}
Здесь, если запросить `/unicorns/yolo`, то *операция пути* вызовет `UnicornException`.
@@ -127,7 +127,7 @@
Обработчик исключения получит объект `Request` и исключение.
-{* ../../docs_src/handling_errors/tutorial004_py39.py hl[2,14:19] *}
+{* ../../docs_src/handling_errors/tutorial004_py310.py hl[2,14:19] *}
Теперь, если перейти к `/items/foo`, то вместо стандартной JSON-ошибки с:
@@ -159,7 +159,7 @@ Field: ('path', 'item_id'), Error: Input should be a valid integer, unable to pa
Например, для этих ошибок можно вернуть обычный текстовый ответ вместо JSON:
-{* ../../docs_src/handling_errors/tutorial004_py39.py hl[3:4,9:11,25] *}
+{* ../../docs_src/handling_errors/tutorial004_py310.py hl[3:4,9:11,25] *}
/// note | Технические детали
@@ -183,7 +183,7 @@ Field: ('path', 'item_id'), Error: Input should be a valid integer, unable to pa
Вы можете использовать его при разработке приложения для регистрации тела и его отладки, возврата пользователю и т.д.
-{* ../../docs_src/handling_errors/tutorial005_py39.py hl[14] *}
+{* ../../docs_src/handling_errors/tutorial005_py310.py hl[14] *}
Теперь попробуйте отправить недействительный элемент, например:
@@ -239,6 +239,6 @@ from starlette.exceptions import HTTPException as StarletteHTTPException
Если вы хотите использовать исключение вместе с теми же обработчиками исключений по умолчанию из **FastAPI**, вы можете импортировать и повторно использовать обработчики исключений по умолчанию из `fastapi.exception_handlers`:
-{* ../../docs_src/handling_errors/tutorial006_py39.py hl[2:5,15,21] *}
+{* ../../docs_src/handling_errors/tutorial006_py310.py hl[2:5,15,21] *}
В этом примере вы просто `выводите в терминал` ошибку с очень выразительным сообщением, но идея вам понятна. Вы можете использовать исключение, а затем просто повторно использовать стандартные обработчики исключений.
diff --git a/docs/ru/docs/tutorial/metadata.md b/docs/ru/docs/tutorial/metadata.md
index e4fe5fb544..221655aa5d 100644
--- a/docs/ru/docs/tutorial/metadata.md
+++ b/docs/ru/docs/tutorial/metadata.md
@@ -18,7 +18,7 @@
Вы можете задать их следующим образом:
-{* ../../docs_src/metadata/tutorial001_py39.py hl[3:16, 19:32] *}
+{* ../../docs_src/metadata/tutorial001_py310.py hl[3:16, 19:32] *}
/// tip | Подсказка
@@ -36,7 +36,7 @@
К примеру:
-{* ../../docs_src/metadata/tutorial001_1_py39.py hl[31] *}
+{* ../../docs_src/metadata/tutorial001_1_py310.py hl[31] *}
## Метаданные для тегов { #metadata-for-tags }
@@ -58,7 +58,7 @@
Создайте метаданные для ваших тегов и передайте их в параметре `openapi_tags`:
-{* ../../docs_src/metadata/tutorial004_py39.py hl[3:16,18] *}
+{* ../../docs_src/metadata/tutorial004_py310.py hl[3:16,18] *}
Помните, что вы можете использовать Markdown внутри описания, к примеру "login" будет отображен жирным шрифтом (**login**) и "fancy" будет отображаться курсивом (_fancy_).
@@ -72,7 +72,7 @@
Используйте параметр `tags` с вашими *операциями пути* (и `APIRouter`ами), чтобы присвоить им различные теги:
-{* ../../docs_src/metadata/tutorial004_py39.py hl[21,26] *}
+{* ../../docs_src/metadata/tutorial004_py310.py hl[21,26] *}
/// info | Дополнительная информация
@@ -100,7 +100,7 @@
К примеру, чтобы задать её отображение по адресу `/api/v1/openapi.json`:
-{* ../../docs_src/metadata/tutorial002_py39.py hl[3] *}
+{* ../../docs_src/metadata/tutorial002_py310.py hl[3] *}
Если вы хотите отключить схему OpenAPI полностью, вы можете задать `openapi_url=None`, это также отключит пользовательские интерфейсы документации, которые её используют.
@@ -117,4 +117,4 @@
К примеру, чтобы задать отображение Swagger UI по адресу `/documentation` и отключить ReDoc:
-{* ../../docs_src/metadata/tutorial003_py39.py hl[3] *}
+{* ../../docs_src/metadata/tutorial003_py310.py hl[3] *}
diff --git a/docs/ru/docs/tutorial/middleware.md b/docs/ru/docs/tutorial/middleware.md
index a83d3c0111..734545cd8b 100644
--- a/docs/ru/docs/tutorial/middleware.md
+++ b/docs/ru/docs/tutorial/middleware.md
@@ -1,10 +1,8 @@
# Middleware (Промежуточный слой) { #middleware }
-Вы можете добавить промежуточный слой (middleware) в **FastAPI** приложение.
-
-"Middleware" это функция, которая выполняется с каждым запросом до его обработки какой-либо конкретной *операцией пути*.
-А также с каждым ответом перед его возвращением.
+Вы можете добавить middleware (промежуточный слой) в **FastAPI** приложение.
+"Middleware" - это функция, которая выполняется с каждым **запросом** до его обработки какой-либо конкретной *операцией пути*. А также с каждым **ответом** перед его возвращением.
* Она принимает каждый поступающий **запрос**.
* Может что-то сделать с этим **запросом** или выполнить любой нужный код.
@@ -23,23 +21,23 @@
## Создание middleware { #create-a-middleware }
-Для создания middleware используйте декоратор `@app.middleware("http")`.
+Для создания middleware используйте декоратор `@app.middleware("http")` поверх функции.
Функция middleware получает:
-* `request` (объект запроса).
+* `request`.
* Функцию `call_next`, которая получает `request` в качестве параметра.
* Эта функция передаёт `request` соответствующей *операции пути*.
- * Затем она возвращает ответ `response`, сгенерированный *операцией пути*.
-* Также имеется возможность видоизменить `response`, перед тем как его вернуть.
+ * Затем она возвращает `response`, сгенерированный соответствующей *операцией пути*.
+* Также имеется возможность видоизменить `response` перед тем как его вернуть.
-{* ../../docs_src/middleware/tutorial001_py39.py hl[8:9,11,14] *}
+{* ../../docs_src/middleware/tutorial001_py310.py hl[8:9,11,14] *}
-/// tip | Примечание
+/// tip | Совет
-Имейте в виду, что можно добавлять свои собственные заголовки
при помощи префикса 'X-'.
+Имейте в виду, что можно добавлять проприетарные HTTP-заголовки
с префиксом `X-`.
-Если же вы хотите добавить собственные заголовки, которые клиент сможет увидеть в браузере, то вам потребуется добавить их в настройки CORS ([CORS (Cross-Origin Resource Sharing)](cors.md){.internal-link target=_blank}), используя параметр `expose_headers`, см. документацию
Starlette's CORS docs.
+Но если вы хотите, чтобы клиент в браузере мог видеть ваши пользовательские заголовки, необходимо добавить их в настройки CORS ([CORS (Cross-Origin Resource Sharing)](cors.md){.internal-link target=_blank}), используя параметр `expose_headers`, описанный в
документации по CORS Starlette.
///
@@ -53,17 +51,17 @@
### До и после `response` { #before-and-after-the-response }
-Вы можете добавить код, использующий `request` до передачи его какой-либо *операции пути*.
+Вы можете добавить код, использующий `request`, до передачи его какой-либо *операции пути*.
А также после формирования `response`, до того, как вы его вернёте.
Например, вы можете добавить собственный заголовок `X-Process-Time`, содержащий время в секундах, необходимое для обработки запроса и генерации ответа:
-{* ../../docs_src/middleware/tutorial001_py39.py hl[10,12:13] *}
+{* ../../docs_src/middleware/tutorial001_py310.py hl[10,12:13] *}
-/// tip | Примечание
+/// tip | Совет
-Мы используем
`time.perf_counter()` вместо `time.time()` для обеспечения большей точности наших примеров. 🤓
+Мы используем
`time.perf_counter()` вместо `time.time()` для обеспечения большей точности в таких случаях. 🤓
///
@@ -94,4 +92,4 @@ app.add_middleware(MiddlewareB)
О других middleware вы можете узнать больше в разделе [Advanced User Guide: Advanced Middleware](../advanced/middleware.md){.internal-link target=_blank}.
-В следующем разделе вы можете прочитать, как настроить
CORS с помощью middleware.
+В следующем разделе вы можете прочитать, как настроить
CORS с помощью middleware.
diff --git a/docs/ru/docs/tutorial/path-operation-configuration.md b/docs/ru/docs/tutorial/path-operation-configuration.md
index 112a1efca5..31531c67f1 100644
--- a/docs/ru/docs/tutorial/path-operation-configuration.md
+++ b/docs/ru/docs/tutorial/path-operation-configuration.md
@@ -4,7 +4,7 @@
/// warning | Внимание
-Помните, что эти параметры передаются непосредственно *декоратору операций пути*, а не вашей *функции-обработчику операций пути*.
+Помните, что эти параметры передаются непосредственно *декоратору операций пути*, а не вашей *функции-обработчику пути*.
///
@@ -46,7 +46,7 @@
**FastAPI** поддерживает это так же, как и в случае с обычными строками:
-{* ../../docs_src/path_operation_configuration/tutorial002b_py39.py hl[1,8:10,13,18] *}
+{* ../../docs_src/path_operation_configuration/tutorial002b_py310.py hl[1,8:10,13,18] *}
## Краткое и развёрнутое содержание { #summary-and-description }
@@ -56,7 +56,7 @@
## Описание из строк документации { #description-from-docstring }
-Так как описания обычно длинные и содержат много строк, вы можете объявить описание *операции пути* в функции
строки документации и **FastAPI** прочитает её отсюда.
+Так как описания обычно длинные и содержат много строк, вы можете объявить описание *операции пути* в
строке документации функции, и **FastAPI** прочитает её оттуда.
Вы можете использовать
Markdown в строке документации, и он будет интерпретирован и отображён корректно (с учетом отступа в строке документации).
@@ -90,9 +90,9 @@ OpenAPI указывает, что каждой *операции пути* не
## Обозначение *операции пути* как устаревшей { #deprecate-a-path-operation }
-Если вам необходимо пометить *операцию пути* как
устаревшую, при этом не удаляя её, передайте параметр `deprecated`:
+Если вам необходимо пометить *операцию пути* как
устаревшую, при этом не удаляя её, передайте параметр `deprecated`:
-{* ../../docs_src/path_operation_configuration/tutorial006_py39.py hl[16] *}
+{* ../../docs_src/path_operation_configuration/tutorial006_py310.py hl[16] *}
Он будет четко помечен как устаревший в интерактивной документации:
diff --git a/docs/ru/docs/tutorial/path-params-numeric-validations.md b/docs/ru/docs/tutorial/path-params-numeric-validations.md
index f0fe788051..6c1148b60c 100644
--- a/docs/ru/docs/tutorial/path-params-numeric-validations.md
+++ b/docs/ru/docs/tutorial/path-params-numeric-validations.md
@@ -44,7 +44,7 @@ Path-параметр всегда является обязательным, п
И если вам больше ничего не нужно указывать для этого параметра, то нет необходимости использовать `Query`.
-Но вам по-прежнему нужно использовать `Path` для path-параметра `item_id`. И если по какой-либо причине вы не хотите использовать `Annotated`, то могут возникнуть небольшие сложности.
+Но вам по-прежнему нужно использовать `Path` для path-параметра `item_id`. И по какой-либо причине вы не хотите использовать `Annotated`.
Если вы поместите параметр со значением по умолчанию перед другим параметром, у которого нет значения по умолчанию, то Python укажет на ошибку.
@@ -54,11 +54,11 @@ Path-параметр всегда является обязательным, п
Поэтому вы можете определить функцию так:
-{* ../../docs_src/path_params_numeric_validations/tutorial002_py39.py hl[7] *}
+{* ../../docs_src/path_params_numeric_validations/tutorial002_py310.py hl[7] *}
Но имейте в виду, что если вы используете `Annotated`, вы не столкнётесь с этой проблемой, так как вы не используете значения по умолчанию параметров функции для `Query()` или `Path()`.
-{* ../../docs_src/path_params_numeric_validations/tutorial002_an_py39.py *}
+{* ../../docs_src/path_params_numeric_validations/tutorial002_an_py310.py *}
## Задайте нужный вам порядок параметров, полезные приёмы { #order-the-parameters-as-you-need-tricks }
@@ -83,13 +83,13 @@ Path-параметр всегда является обязательным, п
Python не будет ничего делать с `*`, но он будет знать, что все следующие параметры являются именованными аргументами (парами ключ-значение), также известными как
kwargs, даже если у них нет значений по умолчанию.
-{* ../../docs_src/path_params_numeric_validations/tutorial003_py39.py hl[7] *}
+{* ../../docs_src/path_params_numeric_validations/tutorial003_py310.py hl[7] *}
### Лучше с `Annotated` { #better-with-annotated }
Имейте в виду, что если вы используете `Annotated`, то, поскольку вы не используете значений по умолчанию для параметров функции, у вас не возникнет подобной проблемы и вам, вероятно, не придётся использовать `*`.
-{* ../../docs_src/path_params_numeric_validations/tutorial003_an_py39.py hl[10] *}
+{* ../../docs_src/path_params_numeric_validations/tutorial003_an_py310.py hl[10] *}
## Валидация числовых данных: больше или равно { #number-validations-greater-than-or-equal }
@@ -97,7 +97,7 @@ Python не будет ничего делать с `*`, но он будет з
В этом примере при указании `ge=1`, параметр `item_id` должен быть целым числом "`g`reater than or `e`qual" — больше или равно `1`.
-{* ../../docs_src/path_params_numeric_validations/tutorial004_an_py39.py hl[10] *}
+{* ../../docs_src/path_params_numeric_validations/tutorial004_an_py310.py hl[10] *}
## Валидация числовых данных: больше и меньше или равно { #number-validations-greater-than-and-less-than-or-equal }
@@ -106,7 +106,7 @@ Python не будет ничего делать с `*`, но он будет з
* `gt`: больше (`g`reater `t`han)
* `le`: меньше или равно (`l`ess than or `e`qual)
-{* ../../docs_src/path_params_numeric_validations/tutorial005_an_py39.py hl[10] *}
+{* ../../docs_src/path_params_numeric_validations/tutorial005_an_py310.py hl[10] *}
## Валидация числовых данных: числа с плавающей точкой, больше и меньше { #number-validations-floats-greater-than-and-less-than }
@@ -118,7 +118,7 @@ Python не будет ничего делать с `*`, но он будет з
То же самое справедливо и для
lt.
-{* ../../docs_src/path_params_numeric_validations/tutorial006_an_py39.py hl[13] *}
+{* ../../docs_src/path_params_numeric_validations/tutorial006_an_py310.py hl[13] *}
## Резюме { #recap }
diff --git a/docs/ru/docs/tutorial/path-params.md b/docs/ru/docs/tutorial/path-params.md
index 83a7ed3ffe..7295697487 100644
--- a/docs/ru/docs/tutorial/path-params.md
+++ b/docs/ru/docs/tutorial/path-params.md
@@ -2,7 +2,7 @@
Вы можете определить "параметры" или "переменные" пути, используя синтаксис форматированных строк Python:
-{* ../../docs_src/path_params/tutorial001_py39.py hl[6:7] *}
+{* ../../docs_src/path_params/tutorial001_py310.py hl[6:7] *}
Значение параметра пути `item_id` будет передано в функцию в качестве аргумента `item_id`.
@@ -16,7 +16,7 @@
Вы можете объявить тип параметра пути в функции, используя стандартные аннотации типов Python:
-{* ../../docs_src/path_params/tutorial002_py39.py hl[7] *}
+{* ../../docs_src/path_params/tutorial002_py310.py hl[7] *}
Здесь, `item_id` объявлен типом `int`.
@@ -26,7 +26,7 @@
///
-##
Преобразование данных { #data-conversion }
+##
Преобразование данных { #data-conversion }
Если запустите этот пример и перейдёте по адресу:
http://127.0.0.1:8000/items/3, то увидите ответ:
@@ -38,7 +38,7 @@
Обратите внимание на значение `3`, которое получила (и вернула) функция. Это целочисленный Python `int`, а не строка `"3"`.
-Используя такое объявление типов, **FastAPI** выполняет автоматический
"парсинг" запросов.
+Используя такое объявление типов, **FastAPI** выполняет автоматический HTTP-запрос
"парсинг".
///
@@ -118,13 +118,13 @@
Поскольку *операции пути* выполняются в порядке их объявления, необходимо, чтобы путь для `/users/me` был объявлен раньше, чем путь для `/users/{user_id}`:
-{* ../../docs_src/path_params/tutorial003_py39.py hl[6,11] *}
+{* ../../docs_src/path_params/tutorial003_py310.py hl[6,11] *}
Иначе путь для `/users/{user_id}` также будет соответствовать `/users/me`, "подразумевая", что он получает параметр `user_id` со значением `"me"`.
Аналогично, вы не можете переопределить операцию с путем:
-{* ../../docs_src/path_params/tutorial003b_py39.py hl[6,11] *}
+{* ../../docs_src/path_params/tutorial003b_py310.py hl[6,11] *}
Первый будет выполняться всегда, так как путь совпадает первым.
@@ -140,11 +140,11 @@
Затем создайте атрибуты класса с фиксированными допустимыми значениями:
-{* ../../docs_src/path_params/tutorial005_py39.py hl[1,6:9] *}
+{* ../../docs_src/path_params/tutorial005_py310.py hl[1,6:9] *}
/// tip | Подсказка
-Если интересно, то "AlexNet", "ResNet" и "LeNet" - это названия
моделей Машинного обучения.
+Если интересно, то "AlexNet", "ResNet" и "LeNet" - это названия
моделей Машинного обучения.
///
@@ -152,7 +152,7 @@
Определите *параметр пути*, используя в аннотации типа класс перечисления (`ModelName`), созданный ранее:
-{* ../../docs_src/path_params/tutorial005_py39.py hl[16] *}
+{* ../../docs_src/path_params/tutorial005_py310.py hl[16] *}
### Проверьте документацию { #check-the-docs }
@@ -168,13 +168,13 @@
Вы можете сравнить это значение с *элементом перечисления* класса `ModelName`:
-{* ../../docs_src/path_params/tutorial005_py39.py hl[17] *}
+{* ../../docs_src/path_params/tutorial005_py310.py hl[17] *}
#### Получение *значения перечисления* { #get-the-enumeration-value }
Можно получить фактическое значение (в данном случае - `str`) с помощью `model_name.value` или в общем случае `your_enum_member.value`:
-{* ../../docs_src/path_params/tutorial005_py39.py hl[20] *}
+{* ../../docs_src/path_params/tutorial005_py310.py hl[20] *}
/// tip | Подсказка
@@ -188,8 +188,8 @@
Они будут преобразованы в соответствующие значения (в данном случае - строки) перед их возвратом клиенту:
-{* ../../docs_src/path_params/tutorial005_py39.py hl[18,21,23] *}
-Вы отправите клиенту такой JSON-ответ:
+{* ../../docs_src/path_params/tutorial005_py310.py hl[18,21,23] *}
+На стороне клиента вы получите такой JSON-ответ:
```JSON
{
@@ -226,7 +226,7 @@ OpenAPI не поддерживает способов объявления *п
Можете использовать так:
-{* ../../docs_src/path_params/tutorial004_py39.py hl[6] *}
+{* ../../docs_src/path_params/tutorial004_py310.py hl[6] *}
/// tip | Подсказка
@@ -241,7 +241,7 @@ OpenAPI не поддерживает способов объявления *п
Используя **FastAPI** вместе со стандартными объявлениями типов Python (короткими и интуитивно понятными), вы получаете:
* Поддержку редактора кода (проверку ошибок, автозавершение и т.п.)
-* "
Парсинг" данных
+* "
Парсинг" данных
* Валидацию данных
* Аннотации API и автоматическую документацию
diff --git a/docs/ru/docs/tutorial/query-param-models.md b/docs/ru/docs/tutorial/query-param-models.md
index 5ad7f1d99d..7f29740acc 100644
--- a/docs/ru/docs/tutorial/query-param-models.md
+++ b/docs/ru/docs/tutorial/query-param-models.md
@@ -6,7 +6,7 @@
/// note | Заметка
-Этот функционал доступен с версии `0.115.0`. 🤓
+Это поддерживается начиная с версии FastAPI `0.115.0`. 🤓
///
diff --git a/docs/ru/docs/tutorial/query-params-str-validations.md b/docs/ru/docs/tutorial/query-params-str-validations.md
index 2bc2fb22c5..43cbcad03c 100644
--- a/docs/ru/docs/tutorial/query-params-str-validations.md
+++ b/docs/ru/docs/tutorial/query-params-str-validations.md
@@ -47,40 +47,16 @@ FastAPI поймёт, что значение `q` не обязательно,
У нас была такая аннотация типа:
-//// tab | Python 3.10+
-
```Python
q: str | None = None
```
-////
-
-//// tab | Python 3.9+
-
-```Python
-q: Union[str, None] = None
-```
-
-////
-
Мы «обернём» это в `Annotated`, и получится:
-//// tab | Python 3.10+
-
```Python
q: Annotated[str | None] = None
```
-////
-
-//// tab | Python 3.9+
-
-```Python
-q: Annotated[Union[str, None]] = None
-```
-
-////
-
Обе версии означают одно и то же: `q` — параметр, который может быть `str` или `None`, и по умолчанию равен `None`.
А теперь к самому интересному. 🎉
@@ -109,7 +85,7 @@ q: Annotated[Union[str, None]] = None
## Альтернатива (устаревшее): `Query` как значение по умолчанию { #alternative-old-query-as-the-default-value }
-В предыдущих версиях FastAPI (до
0.95.0) требовалось использовать `Query` как значение по умолчанию для параметра вместо помещения его в `Annotated`. Скорее всего вы ещё встретите такой код, поэтому поясню.
+В предыдущих версиях FastAPI (до
0.95.0) требовалось использовать `Query` как значение по умолчанию для параметра вместо помещения его в `Annotated`. Скорее всего вы ещё встретите такой код, поэтому поясню.
/// tip | Подсказка
@@ -191,7 +167,7 @@ q: str = Query(default="rick")
## Регулярные выражения { #add-regular-expressions }
-Вы можете определить
регулярное выражение `pattern`, которому должен соответствовать параметр:
+Вы можете определить
регулярное выражение `pattern`, которому должен соответствовать параметр:
{* ../../docs_src/query_params_str_validations/tutorial004_an_py310.py hl[11] *}
@@ -211,7 +187,7 @@ q: str = Query(default="rick")
Допустим, вы хотите объявить, что query-параметр `q` должен иметь `min_length` равный `3` и значение по умолчанию `"fixedquery"`:
-{* ../../docs_src/query_params_str_validations/tutorial005_an_py39.py hl[9] *}
+{* ../../docs_src/query_params_str_validations/tutorial005_an_py310.py hl[9] *}
/// note | Примечание
@@ -241,7 +217,7 @@ q: Annotated[str | None, Query(min_length=3)] = None
Поэтому, когда вам нужно объявить значение как обязательное при использовании `Query`, просто не указывайте значение по умолчанию:
-{* ../../docs_src/query_params_str_validations/tutorial006_an_py39.py hl[9] *}
+{* ../../docs_src/query_params_str_validations/tutorial006_an_py310.py hl[9] *}
### Обязательный, но может быть `None` { #required-can-be-none }
@@ -292,7 +268,7 @@ http://localhost:8000/items/?q=foo&q=bar
Можно также определить значение по умолчанию как `list`, если ничего не передано:
-{* ../../docs_src/query_params_str_validations/tutorial012_an_py39.py hl[9] *}
+{* ../../docs_src/query_params_str_validations/tutorial012_an_py310.py hl[9] *}
Если вы перейдёте по адресу:
@@ -315,7 +291,7 @@ http://localhost:8000/items/
Можно использовать `list` напрямую вместо `list[str]`:
-{* ../../docs_src/query_params_str_validations/tutorial013_an_py39.py hl[9] *}
+{* ../../docs_src/query_params_str_validations/tutorial013_an_py310.py hl[9] *}
/// note | Примечание
@@ -371,7 +347,7 @@ http://127.0.0.1:8000/items/?item-query=foobaritems
Предположим, этот параметр вам больше не нравится.
-Его нужно оставить на какое‑то время, так как клиенты его используют, но вы хотите, чтобы в документации он явно отображался как
устаревший.
+Его нужно оставить на какое‑то время, так как клиенты его используют, но вы хотите, чтобы в документации он явно отображался как
устаревший.
Тогда передайте параметр `deprecated=True` в `Query`:
@@ -401,7 +377,7 @@ http://127.0.0.1:8000/items/?item-query=foobaritems
///
-Например, эта кастомная проверка убеждается, что ID элемента начинается с `isbn-` для номера книги
ISBN или с `imdb-` для ID URL фильма на
IMDB:
+Например, эта кастомная проверка убеждается, что ID элемента начинается с `isbn-` для номера книги
ISBN или с `imdb-` для ID URL фильма на
IMDB:
{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py hl[5,16:19,24] *}
@@ -435,7 +411,7 @@ http://127.0.0.1:8000/items/?item-query=foobaritems
#### Случайный элемент { #a-random-item }
-С помощью `data.items()` мы получаем
итерируемый объект с кортежами, содержащими ключ и значение для каждого элемента словаря.
+С помощью `data.items()` мы получаем
итерируемый объект с кортежами, содержащими ключ и значение для каждого элемента словаря.
Мы превращаем этот итерируемый объект в обычный `list` через `list(data.items())`.
diff --git a/docs/ru/docs/tutorial/query-params.md b/docs/ru/docs/tutorial/query-params.md
index be1c0e46e1..cbacb129c5 100644
--- a/docs/ru/docs/tutorial/query-params.md
+++ b/docs/ru/docs/tutorial/query-params.md
@@ -2,7 +2,7 @@
Когда вы объявляете параметры функции, которые не являются параметрами пути, они автоматически интерпретируются как "query"-параметры.
-{* ../../docs_src/query_params/tutorial001_py39.py hl[9] *}
+{* ../../docs_src/query_params/tutorial001_py310.py hl[9] *}
Query-параметры представляют из себя набор пар ключ-значение, которые идут после знака `?` в URL-адресе, разделенные символами `&`.
@@ -24,7 +24,7 @@ http://127.0.0.1:8000/items/?skip=0&limit=10
Все те же правила, которые применяются к path-параметрам, также применяются и query-параметрам:
* Поддержка от редактора кода (очевидно)
-*
"Парсинг" данных
+*
"Парсинг" данных
* Проверка на соответствие данных (Валидация)
* Автоматическая документация
@@ -121,13 +121,13 @@ http://127.0.0.1:8000/items/foo?short=yes
## Обязательные query-параметры { #required-query-parameters }
-Когда вы объявляете значение по умолчанию для параметра, который не является path-параметром (в этом разделе, мы пока что познакомились только с path-параметрами), то он не является обязательным.
+Когда вы объявляете значение по умолчанию для параметра, который не является path-параметром (в этом разделе мы пока что рассмотрели только query-параметры), то он не является обязательным.
Если вы не хотите задавать конкретное значение, но хотите сделать параметр необязательным, вы можете установить значение по умолчанию равным `None`.
Но если вы хотите сделать query-параметр обязательным, вы можете просто не указывать значение по умолчанию:
-{* ../../docs_src/query_params/tutorial005_py39.py hl[6:7] *}
+{* ../../docs_src/query_params/tutorial005_py310.py hl[6:7] *}
Здесь параметр запроса `needy` является обязательным параметром с типом данных `str`.
diff --git a/docs/ru/docs/tutorial/request-files.md b/docs/ru/docs/tutorial/request-files.md
index 9cfbd53dfe..41922333f8 100644
--- a/docs/ru/docs/tutorial/request-files.md
+++ b/docs/ru/docs/tutorial/request-files.md
@@ -20,13 +20,13 @@ $ pip install python-multipart
Импортируйте `File` и `UploadFile` из модуля `fastapi`:
-{* ../../docs_src/request_files/tutorial001_an_py39.py hl[3] *}
+{* ../../docs_src/request_files/tutorial001_an_py310.py hl[3] *}
## Определите параметры `File` { #define-file-parameters }
Создайте параметры `File` так же, как вы это делаете для `Body` или `Form`:
-{* ../../docs_src/request_files/tutorial001_an_py39.py hl[9] *}
+{* ../../docs_src/request_files/tutorial001_an_py310.py hl[9] *}
/// info | Дополнительная информация
@@ -54,7 +54,7 @@ $ pip install python-multipart
Определите параметр файла с типом `UploadFile`:
-{* ../../docs_src/request_files/tutorial001_an_py39.py hl[14] *}
+{* ../../docs_src/request_files/tutorial001_an_py310.py hl[14] *}
Использование `UploadFile` имеет ряд преимуществ перед `bytes`:
@@ -122,7 +122,7 @@ contents = myfile.file.read()
Но когда форма включает файлы, она кодируется как multipart/form-data. Если вы используете `File`, **FastAPI** будет знать, что ему нужно получить файлы из нужной части тела.
-Если вы хотите узнать больше об этих кодировках и полях форм, перейдите по ссылке
MDN web docs for POST.
+Если вы хотите узнать больше об этих кодировках и полях форм, перейдите по ссылке
MDN web docs for POST.
///
@@ -144,7 +144,7 @@ contents = myfile.file.read()
Вы также можете использовать `File()` вместе с `UploadFile`, например, для установки дополнительных метаданных:
-{* ../../docs_src/request_files/tutorial001_03_an_py39.py hl[9,15] *}
+{* ../../docs_src/request_files/tutorial001_03_an_py310.py hl[9,15] *}
## Загрузка нескольких файлов { #multiple-file-uploads }
@@ -154,7 +154,7 @@ contents = myfile.file.read()
Для этого необходимо объявить список `bytes` или `UploadFile`:
-{* ../../docs_src/request_files/tutorial002_an_py39.py hl[10,15] *}
+{* ../../docs_src/request_files/tutorial002_an_py310.py hl[10,15] *}
Вы получите, как и было объявлено, список `list` из `bytes` или `UploadFile`.
@@ -170,7 +170,7 @@ contents = myfile.file.read()
Так же, как и раньше, вы можете использовать `File()` для задания дополнительных параметров, даже для `UploadFile`:
-{* ../../docs_src/request_files/tutorial003_an_py39.py hl[11,18:20] *}
+{* ../../docs_src/request_files/tutorial003_an_py310.py hl[11,18:20] *}
## Резюме { #recap }
diff --git a/docs/ru/docs/tutorial/request-form-models.md b/docs/ru/docs/tutorial/request-form-models.md
index f8c58356cb..f4411a27bc 100644
--- a/docs/ru/docs/tutorial/request-form-models.md
+++ b/docs/ru/docs/tutorial/request-form-models.md
@@ -24,7 +24,7 @@ $ pip install python-multipart
Вам просто нужно объявить **Pydantic-модель** с полями, которые вы хотите получить как **поля формы**, а затем объявить параметр как `Form`:
-{* ../../docs_src/request_form_models/tutorial001_an_py39.py hl[9:11,15] *}
+{* ../../docs_src/request_form_models/tutorial001_an_py310.py hl[9:11,15] *}
**FastAPI** **извлечёт** данные для **каждого поля** из **данных формы** в запросе и выдаст вам объявленную Pydantic-модель.
@@ -48,7 +48,7 @@ $ pip install python-multipart
Вы можете сконфигурировать Pydantic-модель так, чтобы запретить (`forbid`) все дополнительные (`extra`) поля:
-{* ../../docs_src/request_form_models/tutorial002_an_py39.py hl[12] *}
+{* ../../docs_src/request_form_models/tutorial002_an_py310.py hl[12] *}
Если клиент попробует отправить дополнительные данные, то в ответ он получит **ошибку**.
diff --git a/docs/ru/docs/tutorial/request-forms-and-files.md b/docs/ru/docs/tutorial/request-forms-and-files.md
index 691dc75ba3..10836d74fd 100644
--- a/docs/ru/docs/tutorial/request-forms-and-files.md
+++ b/docs/ru/docs/tutorial/request-forms-and-files.md
@@ -16,13 +16,13 @@ $ pip install python-multipart
## Импортируйте `File` и `Form` { #import-file-and-form }
-{* ../../docs_src/request_forms_and_files/tutorial001_an_py39.py hl[3] *}
+{* ../../docs_src/request_forms_and_files/tutorial001_an_py310.py hl[3] *}
## Определите параметры `File` и `Form` { #define-file-and-form-parameters }
Создайте параметры файла и формы таким же образом, как для `Body` или `Query`:
-{* ../../docs_src/request_forms_and_files/tutorial001_an_py39.py hl[10:12] *}
+{* ../../docs_src/request_forms_and_files/tutorial001_an_py310.py hl[10:12] *}
Файлы и поля формы будут загружены в виде данных формы, и вы получите файлы и поля формы.
diff --git a/docs/ru/docs/tutorial/request-forms.md b/docs/ru/docs/tutorial/request-forms.md
index e257652b61..01f71ac2fc 100644
--- a/docs/ru/docs/tutorial/request-forms.md
+++ b/docs/ru/docs/tutorial/request-forms.md
@@ -18,17 +18,17 @@ $ pip install python-multipart
Импортируйте `Form` из `fastapi`:
-{* ../../docs_src/request_forms/tutorial001_an_py39.py hl[3] *}
+{* ../../docs_src/request_forms/tutorial001_an_py310.py hl[3] *}
## Определение параметров `Form` { #define-form-parameters }
Создайте параметры формы так же, как это делается для `Body` или `Query`:
-{* ../../docs_src/request_forms/tutorial001_an_py39.py hl[9] *}
+{* ../../docs_src/request_forms/tutorial001_an_py310.py hl[9] *}
-Например, в одном из способов использования спецификации OAuth2 (называемом «потоком пароля») требуется отправить `username` и `password` в виде полей формы.
+Например, в одном из способов использования спецификации OAuth2 (называемом «password flow» - аутентификация по паролю) требуется отправить `username` и `password` в виде полей формы.
-
spec требует, чтобы поля были строго названы `username` и `password` и отправлялись как поля формы, а не JSON.
+
спецификация требует, чтобы поля были строго названы `username` и `password` и отправлялись как поля формы, а не JSON.
С помощью `Form` вы можете объявить те же настройки, что и с `Body` (и `Query`, `Path`, `Cookie`), включая валидацию, примеры, псевдоним (например, `user-name` вместо `username`) и т.д.
@@ -56,7 +56,7 @@ $ pip install python-multipart
Но когда форма содержит файлы, она кодируется как `multipart/form-data`. О работе с файлами вы прочтёте в следующей главе.
-Если вы хотите узнать больше про эти кодировки и поля формы, обратитесь к
MDN веб-документации для `POST`.
+Если вы хотите узнать больше про эти кодировки и поля формы, обратитесь к
MDN веб-документации для `POST`.
///
diff --git a/docs/ru/docs/tutorial/response-model.md b/docs/ru/docs/tutorial/response-model.md
index 22a811cd57..cd99ce28c7 100644
--- a/docs/ru/docs/tutorial/response-model.md
+++ b/docs/ru/docs/tutorial/response-model.md
@@ -183,7 +183,7 @@ FastAPI делает несколько вещей внутри вместе с
Самый распространённый случай — [возвращать Response напрямую, как описано далее в разделах документации для продвинутых](../advanced/response-directly.md){.internal-link target=_blank}.
-{* ../../docs_src/response_model/tutorial003_02_py39.py hl[8,10:11] *}
+{* ../../docs_src/response_model/tutorial003_02_py310.py hl[8,10:11] *}
Этот простой случай обрабатывается FastAPI автоматически, потому что аннотация возвращаемого типа — это класс (или подкласс) `Response`.
@@ -193,7 +193,7 @@ FastAPI делает несколько вещей внутри вместе с
Вы также можете использовать подкласс `Response` в аннотации типа:
-{* ../../docs_src/response_model/tutorial003_03_py39.py hl[8:9] *}
+{* ../../docs_src/response_model/tutorial003_03_py310.py hl[8:9] *}
Это тоже сработает, так как `RedirectResponse` — подкласс `Response`, и FastAPI автоматически обработает этот простой случай.
@@ -201,7 +201,7 @@ FastAPI делает несколько вещей внутри вместе с
Но когда вы возвращаете произвольный объект, не являющийся валидным типом Pydantic (например, объект базы данных), и аннотируете его таким образом в функции, FastAPI попытается создать модель ответа Pydantic из этой аннотации типа и потерпит неудачу.
-То же произойдёт, если у вас будет что-то вроде
union разных типов, где один или несколько не являются валидными типами Pydantic, например, это приведёт к ошибке 💥:
+То же произойдёт, если у вас будет что-то вроде
union разных типов, где один или несколько не являются валидными типами Pydantic, например, это приведёт к ошибке 💥:
{* ../../docs_src/response_model/tutorial003_04_py310.py hl[8] *}
diff --git a/docs/ru/docs/tutorial/response-status-code.md b/docs/ru/docs/tutorial/response-status-code.md
index 30f642b643..13d982e803 100644
--- a/docs/ru/docs/tutorial/response-status-code.md
+++ b/docs/ru/docs/tutorial/response-status-code.md
@@ -8,7 +8,7 @@
* `@app.delete()`
* и других.
-{* ../../docs_src/response_status_code/tutorial001_py39.py hl[6] *}
+{* ../../docs_src/response_status_code/tutorial001_py310.py hl[6] *}
/// note | Примечание
@@ -66,7 +66,7 @@ FastAPI знает об этом и создаст документацию Open
/// tip | Подсказка
-Чтобы узнать больше о HTTP кодах статуса и о том, для чего каждый из них предназначен, ознакомьтесь с
MDN документацией об HTTP статус-кодах.
+Чтобы узнать больше о HTTP кодах статуса и о том, для чего каждый из них предназначен, ознакомьтесь с
MDN документацией об HTTP статус-кодах.
///
@@ -74,7 +74,7 @@ FastAPI знает об этом и создаст документацию Open
Рассмотрим предыдущий пример еще раз:
-{* ../../docs_src/response_status_code/tutorial001_py39.py hl[6] *}
+{* ../../docs_src/response_status_code/tutorial001_py310.py hl[6] *}
`201` – это код статуса "Создано".
@@ -82,7 +82,7 @@ FastAPI знает об этом и создаст документацию Open
Для удобства вы можете использовать переменные из `fastapi.status`.
-{* ../../docs_src/response_status_code/tutorial002_py39.py hl[1,6] *}
+{* ../../docs_src/response_status_code/tutorial002_py310.py hl[1,6] *}
Они содержат те же числовые значения, но позволяют использовать автозавершение редактора кода для выбора кода статуса:
@@ -90,7 +90,7 @@ FastAPI знает об этом и создаст документацию Open
/// note | Технические детали
-Вы также можете использовать `from starlette import status` вместо `from fastapi import status`.
+Вы также можете использовать `from starlette import status`.
**FastAPI** позволяет использовать как `starlette.status`, так и `fastapi.status` исключительно для удобства разработчиков. Но поставляется fastapi.status непосредственно из Starlette.
diff --git a/docs/ru/docs/tutorial/schema-extra-example.md b/docs/ru/docs/tutorial/schema-extra-example.md
index e4a97c8801..c7381aae25 100644
--- a/docs/ru/docs/tutorial/schema-extra-example.md
+++ b/docs/ru/docs/tutorial/schema-extra-example.md
@@ -74,7 +74,7 @@ OpenAPI 3.1.0 (используется начиная с FastAPI 0.99.0) доб
Когда вы делаете это, примеры становятся частью внутренней **JSON Schema** для данных тела запроса.
-Тем не менее, на
момент написания этого Swagger UI, инструмент, отвечающий за отображение UI документации, не поддерживает показ нескольких примеров для данных в **JSON Schema**. Но ниже есть обходной путь.
+Тем не менее, на
момент написания этого Swagger UI, инструмент, отвечающий за отображение UI документации, не поддерживает показ нескольких примеров для данных в **JSON Schema**. Но ниже есть обходной путь.
### Специфические для OpenAPI `examples` { #openapi-specific-examples }
diff --git a/docs/ru/docs/tutorial/security/first-steps.md b/docs/ru/docs/tutorial/security/first-steps.md
index 983e85e661..9b9673b842 100644
--- a/docs/ru/docs/tutorial/security/first-steps.md
+++ b/docs/ru/docs/tutorial/security/first-steps.md
@@ -20,7 +20,7 @@
Скопируйте пример в файл `main.py`:
-{* ../../docs_src/security/tutorial001_an_py39.py *}
+{* ../../docs_src/security/tutorial001_an_py310.py *}
## Запуск { #run-it }
@@ -132,7 +132,7 @@ OAuth2 был спроектирован так, чтобы бэкенд или
При создании экземпляра класса `OAuth2PasswordBearer` мы передаем параметр `tokenUrl`. Этот параметр содержит URL, который клиент (фронтенд, работающий в браузере пользователя) будет использовать для отправки `username` и `password`, чтобы получить токен.
-{* ../../docs_src/security/tutorial001_an_py39.py hl[8] *}
+{* ../../docs_src/security/tutorial001_an_py310.py hl[8] *}
/// tip | Подсказка
@@ -170,7 +170,7 @@ oauth2_scheme(some, parameters)
Теперь вы можете передать `oauth2_scheme` как зависимость с `Depends`.
-{* ../../docs_src/security/tutorial001_an_py39.py hl[12] *}
+{* ../../docs_src/security/tutorial001_an_py310.py hl[12] *}
Эта зависимость предоставит `str`, который будет присвоен параметру `token` *функции-обработчика пути*.
diff --git a/docs/ru/docs/tutorial/security/get-current-user.md b/docs/ru/docs/tutorial/security/get-current-user.md
index c6bc07cc16..8388b672c7 100644
--- a/docs/ru/docs/tutorial/security/get-current-user.md
+++ b/docs/ru/docs/tutorial/security/get-current-user.md
@@ -2,7 +2,7 @@
В предыдущей главе система безопасности (основанная на системе внедрения зависимостей) передавала *функции-обработчику пути* `token` типа `str`:
-{* ../../docs_src/security/tutorial001_an_py39.py hl[12] *}
+{* ../../docs_src/security/tutorial001_an_py310.py hl[12] *}
Но это всё ещё не слишком полезно.
diff --git a/docs/ru/docs/tutorial/security/index.md b/docs/ru/docs/tutorial/security/index.md
index ebac013b6c..bd8da824b3 100644
--- a/docs/ru/docs/tutorial/security/index.md
+++ b/docs/ru/docs/tutorial/security/index.md
@@ -1,56 +1,56 @@
-# Настройка авторизации { #security }
+# Безопасность { #security }
Существует множество способов обеспечения безопасности, аутентификации и авторизации.
-Обычно эта тема является достаточно сложной и трудной.
+Обычно эта тема является достаточно сложной и «трудной».
-Во многих фреймворках и системах только работа с определением доступов к приложению и аутентификацией требует значительных затрат усилий и написания множества кода (во многих случаях его объём может составлять более 50% от всего написанного кода).
+Во многих фреймворках и системах только работа с безопасностью и аутентификацией требует значительных затрат усилий и написания множества кода (во многих случаях его объём может составлять 50% или более от всего написанного кода).
-**FastAPI** предоставляет несколько инструментов, которые помогут вам настроить **Авторизацию** легко, быстро, стандартным способом, без необходимости изучать все её тонкости.
+**FastAPI** предоставляет несколько инструментов, которые помогут вам работать с **безопасностью** легко, быстро, стандартным способом, без необходимости изучать и разбираться во всех спецификациях по безопасности.
-Но сначала давайте рассмотрим некоторые небольшие концепции.
+Но сначала давайте рассмотрим несколько небольших концепций.
-## Куда-то торопишься? { #in-a-hurry }
+## Нет времени? { #in-a-hurry }
-Если вам не нужна информация о каких-либо из следующих терминов и вам просто нужно добавить защиту с аутентификацией на основе логина и пароля *прямо сейчас*, переходите к следующим главам.
+Если вам не важны какие-либо из этих терминов и вам просто нужно добавить защиту с аутентификацией на основе имени пользователя и пароля прямо сейчас, переходите к следующим главам.
## OAuth2 { #oauth2 }
-OAuth2 - это протокол, который определяет несколько способов обработки аутентификации и авторизации.
+OAuth2 - это спецификация, которая определяет несколько способов обработки аутентификации и авторизации.
-Он довольно обширен и охватывает несколько сложных вариантов использования.
+Это довольно обширная спецификация, охватывающая несколько сложных вариантов использования.
-OAuth2 включает в себя способы аутентификации с использованием "третьей стороны".
+Она включает способы аутентификации с использованием «третьей стороны».
-Это то, что используют под собой все кнопки "вход с помощью Facebook, Google, X (Twitter), GitHub" на страницах авторизации.
+Именно это используется во всех системах с кнопками «войти с помощью Facebook, Google, X (Twitter), GitHub».
### OAuth 1 { #oauth-1 }
-Ранее использовался протокол OAuth 1, который сильно отличается от OAuth2 и является более сложным, поскольку он включал прямые описания того, как шифровать сообщение.
+Ранее использовался OAuth 1, который сильно отличается от OAuth2 и является более сложным, поскольку он включал прямые спецификации того, как шифровать обмен данными.
В настоящее время он не очень популярен и не используется.
-OAuth2 не указывает, как шифровать сообщение, он ожидает, что ваше приложение будет обслуживаться по протоколу HTTPS.
+OAuth2 не указывает, как шифровать обмен данными, он ожидает, что ваше приложение будет обслуживаться по протоколу HTTPS.
/// tip | Подсказка
-В разделе **Развертывание** вы увидите как настроить протокол HTTPS бесплатно, используя Traefik и Let's Encrypt.
+В разделе о **развертывании** вы увидите, как настроить HTTPS бесплатно, используя Traefik и Let's Encrypt.
///
## OpenID Connect { #openid-connect }
-OpenID Connect - это еще один протокол, основанный на **OAuth2**.
+OpenID Connect — это ещё одна спецификация, основанная на **OAuth2**.
-Он просто расширяет OAuth2, уточняя некоторые вещи, не имеющие однозначного определения в OAuth2, в попытке сделать его более совместимым.
+Она просто расширяет OAuth2, уточняя некоторые вещи, которые относительно неоднозначны в OAuth2, стараясь сделать его более совместимым.
-Например, для входа в Google используется OpenID Connect (который под собой использует OAuth2).
+Например, для входа в Google используется OpenID Connect (который под капотом использует OAuth2).
Но вход в Facebook не поддерживает OpenID Connect. У него есть собственная вариация OAuth2.
-### OpenID (не "OpenID Connect") { #openid-not-openid-connect }
+### OpenID (не «OpenID Connect») { #openid-not-openid-connect }
-Также ранее использовался стандарт "OpenID", который пытался решить ту же проблему, что и **OpenID Connect**, но не был основан на OAuth2.
+Также ранее использовалась спецификация «OpenID», которая пыталась решить ту же задачу, что и **OpenID Connect**, но не была основана на OAuth2.
Таким образом, это была полноценная дополнительная система.
@@ -62,45 +62,45 @@ OpenAPI (ранее известный как Swagger) - это открытая
**FastAPI** основан на **OpenAPI**.
-Это то, что делает возможным наличие множества автоматических интерактивных интерфейсов документирования, сгенерированного кода и т.д.
+Это то, что делает возможными несколько автоматических интерактивных интерфейсов документации, генерацию кода и т.д.
-В OpenAPI есть способ использовать несколько "схем" безопасности.
+В OpenAPI есть способ определить несколько «схем» безопасности.
-Таким образом, вы можете воспользоваться преимуществами Всех этих стандартных инструментов, включая интерактивные системы документирования.
+Используя их, вы можете воспользоваться преимуществами всех этих инструментов, основанных на стандартах, включая интерактивные системы документирования.
-OpenAPI может использовать следующие схемы авторизации:
+OpenAPI определяет следующие схемы безопасности:
-* `apiKey`: уникальный идентификатор для приложения, который может быть получен из:
- * Параметров запроса.
- * Заголовка.
- * Cookies.
-* `http`: стандартные системы аутентификации по протоколу HTTP, включая:
- * `bearer`: заголовок `Authorization` со значением `Bearer {уникальный токен}`. Это унаследовано от OAuth2.
- * Базовая аутентификация по протоколу HTTP.
+* `apiKey`: специфичный для приложения ключ, который может поступать из:
+ * параметра запроса.
+ * HTTP-заголовка.
+ * cookie.
+* `http`: стандартные системы аутентификации по HTTP, включая:
+ * `bearer`: HTTP-заголовок `Authorization` со значением `Bearer ` плюс токен. Это унаследовано от OAuth2.
+ * Базовая аутентификация по HTTP.
* HTTP Digest и т.д.
-* `oauth2`: все способы обеспечения безопасности OAuth2 называемые "потоки" (англ. "flows").
- * Некоторые из этих "потоков" подходят для реализации аутентификации через сторонний сервис использующий OAuth 2.0 (например, Google, Facebook, X (Twitter), GitHub и т.д.):
+* `oauth2`: все способы OAuth2 для обеспечения безопасности (называются «потоками»).
+ * Несколько из этих «потоков» подходят для построения провайдера аутентификации OAuth 2.0 (например, Google, Facebook, X (Twitter), GitHub и т.д.):
* `implicit`
* `clientCredentials`
* `authorizationCode`
- * Но есть один конкретный "поток", который может быть идеально использован для обработки аутентификации непосредственно в том же приложении:
- * `password`: в некоторых следующих главах будут рассмотрены примеры этого.
-* `openIdConnect`: способ определить, как автоматически обнаруживать данные аутентификации OAuth2.
- * Это автоматическое обнаружение определено в спецификации OpenID Connect.
+ * Но есть один конкретный «поток», который можно идеально использовать для обработки аутентификации непосредственно в этом же приложении:
+ * `password`: в некоторых следующих главах будут приведены примеры.
+* `openIdConnect`: имеет способ определить, как автоматически обнаруживать данные аутентификации OAuth2.
+ * Именно это автоматическое обнаружение определено в спецификации OpenID Connect.
/// tip | Подсказка
-Интеграция сторонних сервисов для аутентификации/авторизации таких как Google, Facebook, X (Twitter), GitHub и т.д. осуществляется достаточно легко.
+Интеграция сторонних провайдеров аутентификации/авторизации, таких как Google, Facebook, X (Twitter), GitHub и т.д., также возможна и относительно проста.
-Самой сложной проблемой является создание такого провайдера аутентификации/авторизации, но **FastAPI** предоставляет вам инструменты, позволяющие легко это сделать, выполняя при этом всю тяжелую работу за вас.
+Самой сложной задачей является создание такого провайдера аутентификации/авторизации, но **FastAPI** предоставляет вам инструменты, позволяющие легко это сделать, выполняя при этом всю тяжёлую работу за вас.
///
-## Преимущества **FastAPI** { #fastapi-utilities }
+## Инструменты **FastAPI** { #fastapi-utilities }
-Fast API предоставляет несколько инструментов для каждой из этих схем безопасности в модуле `fastapi.security`, которые упрощают использование этих механизмов безопасности.
+FastAPI предоставляет несколько инструментов для каждой из этих схем безопасности в модуле `fastapi.security`, которые упрощают использование этих механизмов безопасности.
-В следующих главах вы увидите, как обезопасить свой API, используя инструменты, предоставляемые **FastAPI**.
+В следующих главах вы увидите, как добавить безопасность в ваш API, используя инструменты, предоставляемые **FastAPI**.
-И вы также увидите, как он автоматически интегрируется в систему интерактивной документации.
+И вы также увидите, как это автоматически интегрируется в систему интерактивной документации.
diff --git a/docs/ru/docs/tutorial/security/oauth2-jwt.md b/docs/ru/docs/tutorial/security/oauth2-jwt.md
index 803491f539..f7853d48f7 100644
--- a/docs/ru/docs/tutorial/security/oauth2-jwt.md
+++ b/docs/ru/docs/tutorial/security/oauth2-jwt.md
@@ -1,10 +1,10 @@
# OAuth2 с паролем (и хешированием), Bearer с JWT-токенами { #oauth2-with-password-and-hashing-bearer-with-jwt-tokens }
-Теперь, когда у нас определен процесс обеспечения безопасности, давайте сделаем приложение действительно безопасным, используя токены
JWT и безопасное хеширование паролей.
+Теперь, когда у нас определен процесс обеспечения безопасности, давайте сделаем приложение действительно безопасным, используя токены
JWT и безопасное хеширование паролей.
Этот код можно реально использовать в своем приложении, сохранять хэши паролей в базе данных и т.д.
-Мы продолжим разбираться, начиная с того места, на котором остановились в предыдущей главе.
+Мы продолжим разбираться, начиная с того места, на котором остановились в предыдущей главе, и расширим его.
## Про JWT { #about-jwt }
@@ -20,7 +20,7 @@ eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4
Но он подписан. Следовательно, когда вы получаете токен, который вы эмитировали (выдавали), вы можете убедиться, что это именно вы его эмитировали.
-Таким образом, можно создать токен со сроком действия, скажем, 1 неделя. А когда пользователь вернется на следующий день с тем же токеном, вы будете знать, что он все еще авторизирован в вашей системе.
+Таким образом, можно создать токен со сроком действия, скажем, 1 неделя. А когда пользователь вернется на следующий день с тем же токеном, вы будете знать, что он все еще авторизован в вашей системе.
Через неделю срок действия токена истечет, пользователь не будет авторизован и ему придется заново входить в систему, чтобы получить новый токен. А если пользователь (или третье лицо) попытается модифицировать токен, чтобы изменить срок действия, вы сможете это обнаружить, поскольку подписи не будут совпадать.
@@ -43,9 +43,11 @@ $ pip install pyjwt
/// info | Дополнительная информация
+
Если вы планируете использовать алгоритмы цифровой подписи, такие как RSA или ECDSA, вам следует установить зависимость библиотеки криптографии `pyjwt[crypto]`.
Подробнее об этом можно прочитать в документации по установке PyJWT.
+
///
## Хеширование паролей { #password-hashing }
@@ -83,11 +85,13 @@ $ pip install "pwdlib[argon2]"
/// tip | Подсказка
+
С помощью `pwdlib` можно даже настроить его на чтение паролей, созданных **Django**, плагином безопасности **Flask** или многими другими библиотеками.
Таким образом, вы сможете, например, совместно использовать одни и те же данные из приложения Django в базе данных с приложением FastAPI. Или постепенно мигрировать Django-приложение, используя ту же базу данных.
При этом пользователи смогут одновременно входить в систему как из приложения Django, так и из приложения **FastAPI**.
+
///
## Хеширование и проверка паролей { #hash-and-verify-the-passwords }
@@ -97,11 +101,13 @@ $ pip install "pwdlib[argon2]"
Создайте экземпляр PasswordHash с рекомендованными настройками — он будет использоваться для хэширования и проверки паролей.
/// tip | Подсказка
+
pwdlib также поддерживает алгоритм хеширования bcrypt, но не включает устаревшие алгоритмы — для работы с устаревшими хэшами рекомендуется использовать библиотеку passlib.
Например, вы можете использовать ее для чтения и проверки паролей, сгенерированных другой системой (например, Django), но хэшировать все новые пароли другим алгоритмом, например Argon2 или Bcrypt.
И при этом быть совместимым со всеми этими системами.
+
///
Создайте служебную функцию для хэширования пароля, поступающего от пользователя.
@@ -110,10 +116,16 @@ pwdlib также поддерживает алгоритм хешировани
И еще одну — для аутентификации и возврата пользователя.
-{* ../../docs_src/security/tutorial004_an_py310.py hl[8,49,56:57,60:61,70:76] *}
+{* ../../docs_src/security/tutorial004_an_py310.py hl[8,49,51,58:59,62:63,72:79] *}
+
+Когда `authenticate_user` вызывается с именем пользователя, которого нет в базе данных, мы все равно запускаем `verify_password` с использованием фиктивного хэша.
+
+Это гарантирует, что эндпоинт отвечает примерно за одно и то же время вне зависимости от того, существует имя пользователя или нет, предотвращая тайминговые атаки (атака по времени), с помощью которых можно было бы перечислять существующие имена пользователей.
/// note | Технические детали
+
Если проверить новую (фальшивую) базу данных `fake_users_db`, то можно увидеть, как теперь выглядит хэшированный пароль: `"$argon2id$v=19$m=65536,t=3,p=4$wagCPXjifgvUFBzq4hqe3w$CYaIb8sB+wtD+Vu/P4uod1+Qof8h+1g7bbDlBID48Rc"`.
+
///
## Работа с JWT токенами { #handle-jwt-tokens }
@@ -144,7 +156,7 @@ $ openssl rand -hex 32
Создайте служебную функцию для генерации нового токена доступа.
-{* ../../docs_src/security/tutorial004_an_py310.py hl[4,7,13:15,29:31,79:87] *}
+{* ../../docs_src/security/tutorial004_an_py310.py hl[4,7,13:15,29:31,82:90] *}
## Обновление зависимостей { #update-the-dependencies }
@@ -154,7 +166,7 @@ $ openssl rand -hex 32
Если токен недействителен, то сразу же верните HTTP-ошибку.
-{* ../../docs_src/security/tutorial004_an_py310.py hl[90:107] *}
+{* ../../docs_src/security/tutorial004_an_py310.py hl[93:110] *}
## Обновление *операции пути* `/token` { #update-the-token-path-operation }
@@ -162,7 +174,7 @@ $ openssl rand -hex 32
Создайте реальный токен доступа JWT и верните его
-{* ../../docs_src/security/tutorial004_an_py310.py hl[118:133] *}
+{* ../../docs_src/security/tutorial004_an_py310.py hl[121:136] *}
### Технические подробности о JWT ключе `sub` { #technical-details-about-the-jwt-subject-sub }
@@ -202,7 +214,9 @@ Username: `johndoe`
Password: `secret`
/// check | Проверка
+
Обратите внимание, что нигде в коде не используется открытый текст пароля "`secret`", мы используем только его хэшированную версию.
+
///
@@ -225,7 +239,9 @@ Password: `secret`
/// note | Техническая информация
+
Обратите внимание на HTTP-заголовок `Authorization`, значение которого начинается с `Bearer `.
+
///
## Продвинутое использование `scopes` { #advanced-usage-with-scopes }
diff --git a/docs/ru/docs/tutorial/security/simple-oauth2.md b/docs/ru/docs/tutorial/security/simple-oauth2.md
index 36ff32c8ef..4b86a40139 100644
--- a/docs/ru/docs/tutorial/security/simple-oauth2.md
+++ b/docs/ru/docs/tutorial/security/simple-oauth2.md
@@ -236,7 +236,7 @@ UserInDB(
-Если щёлкнуть на значке замка и выйти из системы, а затем попытаться выполнить ту же операцию ещё раз, будет выдана ошибка HTTP 401:
+Если щёлкнуть на значке замка и выйти из системы, а затем попробовать выполнить ту же операцию ещё раз, будет выдана ошибка HTTP 401:
```JSON
{
diff --git a/docs/ru/docs/tutorial/sql-databases.md b/docs/ru/docs/tutorial/sql-databases.md
index 1d03465337..ed67739cc9 100644
--- a/docs/ru/docs/tutorial/sql-databases.md
+++ b/docs/ru/docs/tutorial/sql-databases.md
@@ -8,7 +8,7 @@
/// tip | Подсказка
-Вы можете использовать любую другую библиотеку для работы с SQL или NoSQL базами данных (иногда их называют "ORMs"), FastAPI ничего не навязывает. 😎
+Вы можете использовать любую другую библиотеку для работы с SQL или NoSQL базами данных (иногда их называют "ORMs"), FastAPI ничего не навязывает. 😎
///
@@ -344,7 +344,7 @@ $ fastapi dev main.py
-Если вы перейдёте в UI API `/docs`, вы увидите, что он обновился: теперь при создании героя он не ожидает получить `id` от клиента и т. д.
+Если вы перейдёте в UI API `/docs`, вы увидите, что он обновился: теперь при создании героя он не ожидает получить `id` от клиента и т.д.

@@ -354,4 +354,4 @@ $ fastapi dev main.py
Вы можете использовать
**SQLModel** для взаимодействия с SQL базой данных и упростить код с помощью *моделей данных* и *моделей-таблиц*.
-Гораздо больше вы можете узнать в документации **SQLModel**, там есть более подробный мини-
туториал по использованию SQLModel с **FastAPI**. 🚀
+Гораздо больше вы можете узнать в документации **SQLModel**, там есть более подробное мини-
руководство по использованию SQLModel с **FastAPI**. 🚀
diff --git a/docs/ru/docs/tutorial/static-files.md b/docs/ru/docs/tutorial/static-files.md
index f40cfe9b04..3b0cab8313 100644
--- a/docs/ru/docs/tutorial/static-files.md
+++ b/docs/ru/docs/tutorial/static-files.md
@@ -7,7 +7,7 @@
* Импортируйте `StaticFiles`.
* "Примонтируйте" экземпляр `StaticFiles()` к определённому пути.
-{* ../../docs_src/static_files/tutorial001_py39.py hl[2,6] *}
+{* ../../docs_src/static_files/tutorial001_py310.py hl[2,6] *}
/// note | Технические детали
diff --git a/docs/ru/docs/tutorial/testing.md b/docs/ru/docs/tutorial/testing.md
index ab58429c51..6dd2fe579a 100644
--- a/docs/ru/docs/tutorial/testing.md
+++ b/docs/ru/docs/tutorial/testing.md
@@ -30,7 +30,7 @@ $ pip install httpx
Напишите простое утверждение с `assert` дабы проверить истинность Python-выражения (это тоже стандарт `pytest`).
-{* ../../docs_src/app_testing/tutorial001_py39.py hl[2,12,15:18] *}
+{* ../../docs_src/app_testing/tutorial001_py310.py hl[2,12,15:18] *}
/// tip | Подсказка
@@ -76,7 +76,7 @@ $ pip install httpx
В файле `main.py` находится Ваше приложение **FastAPI**:
-{* ../../docs_src/app_testing/app_a_py39/main.py *}
+{* ../../docs_src/app_testing/app_a_py310/main.py *}
### Файл тестов { #testing-file }
@@ -92,7 +92,7 @@ $ pip install httpx
Так как оба файла находятся в одной директории, для импорта объекта приложения из файла `main` в файл `test_main` Вы можете использовать относительный импорт:
-{* ../../docs_src/app_testing/app_a_py39/test_main.py hl[3] *}
+{* ../../docs_src/app_testing/app_a_py310/test_main.py hl[3] *}
...и писать дальше тесты, как и раньше.
@@ -119,7 +119,7 @@ $ pip install httpx
Ещё есть операция `POST`, и она может вернуть несколько ошибок.
-Обе *операции пути* требуют наличия в запросе заголовка `X-Token`.
+Обе *операции пути* требуют наличия в запросе HTTP-заголовка `X-Token`.
{* ../../docs_src/app_testing/app_b_an_py310/main.py *}
@@ -139,7 +139,7 @@ $ pip install httpx
* Передаёте *path*-параметры или *query*-параметры, вписав их непосредственно в строку URL.
* Передаёте JSON в теле запроса, передав Python-объект (например: `dict`) через именованный параметр `json`.
* Если же Вам необходимо отправить *форму с данными* вместо JSON, то используйте параметр `data` вместо `json`.
-* Для передачи *заголовков*, передайте объект `dict` через параметр `headers`.
+* Для передачи *HTTP-заголовков*, передайте объект `dict` через параметр `headers`.
* Для передачи *cookies* также передайте `dict`, но через параметр `cookies`.
Для получения дополнительной информации о передаче данных на бэкенд с помощью `httpx` или `TestClient` ознакомьтесь с
документацией HTTPX.
diff --git a/docs/ru/docs/virtual-environments.md b/docs/ru/docs/virtual-environments.md
index 43136298a3..f931cc3c82 100644
--- a/docs/ru/docs/virtual-environments.md
+++ b/docs/ru/docs/virtual-environments.md
@@ -53,7 +53,7 @@ $ cd awesome-project
## Создание виртуального окружения { #create-a-virtual-environment }
-Когда вы начинаете работать над Python‑проектом **впервые**, создайте виртуальное окружение **
внутри вашего проекта**.
+Когда вы начинаете работать над Python‑проектом **впервые**, создайте виртуальное окружение **
внутри вашего проекта**.
/// tip | Подсказка
@@ -166,7 +166,7 @@ $ source .venv/Scripts/activate
Каждый раз, когда вы устанавливаете **новый пакет** в это окружение, **активируйте** окружение снова.
-Это гарантирует, что если вы используете **программу терминала (
CLI)**, установленную этим пакетом, вы будете использовать именно ту, что из вашего виртуального окружения, а не какую‑то глобально установленную, возможно другой версии, чем вам нужна.
+Это гарантирует, что если вы используете **программу терминала (
CLI)**, установленную этим пакетом, вы будете использовать именно ту, что из вашего виртуального окружения, а не какую‑то глобально установленную, возможно другой версии, чем вам нужна.
///
diff --git a/docs/tr/docs/_llm-test.md b/docs/tr/docs/_llm-test.md
index 0ca218e6e9..0ba5cca752 100644
--- a/docs/tr/docs/_llm-test.md
+++ b/docs/tr/docs/_llm-test.md
@@ -27,7 +27,7 @@ Bu bir code snippet: `foo`. Bu da başka bir code snippet: `bar`. Bir tane daha:
Code snippet'lerin içeriği olduğu gibi bırakılmalıdır.
-`script/translate.py` içindeki genel prompt'ta `### Content of code snippets` bölümüne bakın.
+`scripts/translate.py` içindeki genel prompt'ta `### Content of code snippets` bölümüne bakın.
////
@@ -116,7 +116,7 @@ works(foo="bar") # This works 🎉
Code block'ların içindeki code değiştirilmemelidir; tek istisna yorumlardır (comments).
-`script/translate.py` içindeki genel prompt'ta `### Content of code blocks` bölümüne bakın.
+`scripts/translate.py` içindeki genel prompt'ta `### Content of code blocks` bölümüne bakın.
////
@@ -125,31 +125,31 @@ Code block'ların içindeki code değiştirilmemelidir; tek istisna yorumlardır
//// tab | Test
/// info | Bilgi
-Some text
+Bazı metin
///
/// note | Not
-Some text
+Bazı metin
///
/// note | Teknik Detaylar
-Some text
+Bazı metin
///
/// check | Ek bilgi
-Some text
+Bazı metin
///
/// tip | İpucu
-Some text
+Bazı metin
///
/// warning | Uyarı
-Some text
+Bazı metin
///
/// danger | Tehlike
-Some text
+Bazı metin
///
////
@@ -158,7 +158,7 @@ Some text
Sekmelerin ve `Info`/`Note`/`Warning`/vb. blokların başlığı, dikey çizgiden (`|`) sonra çeviri olarak eklenmelidir.
-`script/translate.py` içindeki genel prompt'ta `### Special blocks` ve `### Tab blocks` bölümlerine bakın.
+`scripts/translate.py` içindeki genel prompt'ta `### Special blocks` ve `### Tab blocks` bölümlerine bakın.
////
@@ -170,10 +170,10 @@ Link metni çevrilmelidir, link adresi değişmeden kalmalıdır:
* [Yukarıdaki başlığa link](#code-snippets)
* [Internal link](index.md#installation){.internal-link target=_blank}
-*
External link
-*
Link to a style
-*
Link to a script
-*
Link to an image
+*
Harici link
+*
Bir stile bağlantı
+*
Bir betiğe bağlantı
+*
Bir görsele bağlantı
Link metni çevrilmelidir, link adresi çeviriye işaret etmelidir:
@@ -185,7 +185,7 @@ Link metni çevrilmelidir, link adresi çeviriye işaret etmelidir:
Link'ler çevrilmelidir, ancak adresleri değişmeden kalmalıdır. Bir istisna, FastAPI dokümantasyonunun sayfalarına verilen mutlak link'lerdir. Bu durumda link, çeviriye işaret etmelidir.
-`script/translate.py` içindeki genel prompt'ta `### Links` bölümüne bakın.
+`scripts/translate.py` içindeki genel prompt'ta `### Links` bölümüne bakın.
////
@@ -199,14 +199,9 @@ Burada HTML "abbr" öğeleriyle sarılmış bazı şeyler var (bazıları uydurm
*
GTD
*
lt
-*
XWT
+*
XWT
*
PSGI
-### abbr bir açıklama verir { #the-abbr-gives-an-explanation }
-
-*
cluster
-*
Deep Learning
-
### abbr tam bir ifade ve bir açıklama verir { #the-abbr-gives-a-full-phrase-and-an-explanation }
*
MDN
@@ -220,10 +215,15 @@ Burada HTML "abbr" öğeleriyle sarılmış bazı şeyler var (bazıları uydurm
Çeviriler, LLM'nin kaldırmaması gereken kendi "abbr" öğelerini ekleyebilir. Örneğin İngilizce kelimeleri açıklamak için.
-`script/translate.py` içindeki genel prompt'ta `### HTML abbr elements` bölümüne bakın.
+`scripts/translate.py` içindeki genel prompt'ta `### HTML abbr elements` bölümüne bakın.
////
+## HTML "dfn" öğeleri { #html-dfn-elements }
+
+*
küme
+*
Derin Öğrenme
+
## Başlıklar { #headings }
//// tab | Test
@@ -246,7 +246,7 @@ Tekrar merhaba.
Başlıklarla ilgili tek katı kural, LLM'nin süslü parantezler içindeki hash kısmını değiştirmemesidir; böylece link'ler bozulmaz.
-`script/translate.py` içindeki genel prompt'ta `### Headings` bölümüne bakın.
+`scripts/translate.py` içindeki genel prompt'ta `### Headings` bölümüne bakın.
Dile özel bazı talimatlar için örneğin `docs/de/llm-prompt.md` içindeki `### Headings` bölümüne bakın.
diff --git a/docs/tr/docs/advanced/additional-responses.md b/docs/tr/docs/advanced/additional-responses.md
index c8e372775c..3a066af407 100644
--- a/docs/tr/docs/advanced/additional-responses.md
+++ b/docs/tr/docs/advanced/additional-responses.md
@@ -26,7 +26,7 @@ Bu response `dict`'lerinin her birinde, `response_model`'e benzer şekilde bir P
Örneğin, `404` status code'u ve `Message` Pydantic model'i ile başka bir response tanımlamak için şunu yazabilirsiniz:
-{* ../../docs_src/additional_responses/tutorial001_py39.py hl[18,22] *}
+{* ../../docs_src/additional_responses/tutorial001_py310.py hl[18,22] *}
/// note | Not
@@ -203,7 +203,7 @@ Varsayılan `200` status code'unu (ya da gerekiyorsa özel bir tane) kullanarak
Ayrıca `response_model`'inizi kullanan, ancak özel bir `example` içeren `200` status code'lu bir response da tanımlayabilirsiniz:
-{* ../../docs_src/additional_responses/tutorial003_py39.py hl[20:31] *}
+{* ../../docs_src/additional_responses/tutorial003_py310.py hl[20:31] *}
Bunların hepsi OpenAPI'nize birleştirilerek dahil edilir ve API dokümanlarında gösterilir:
diff --git a/docs/tr/docs/advanced/advanced-dependencies.md b/docs/tr/docs/advanced/advanced-dependencies.md
index 8afb544bdd..8be92a6ac7 100644
--- a/docs/tr/docs/advanced/advanced-dependencies.md
+++ b/docs/tr/docs/advanced/advanced-dependencies.md
@@ -18,7 +18,7 @@ Class'ın kendisini değil (zaten callable'dır), o class'ın bir instance'ını
Bunu yapmak için `__call__` adında bir method tanımlarız:
-{* ../../docs_src/dependencies/tutorial011_an_py39.py hl[12] *}
+{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[12] *}
Bu durumda, ek parametreleri ve alt-dependency'leri kontrol etmek için **FastAPI**'nin kullanacağı şey bu `__call__` olacaktır; ayrıca daha sonra *path operation function* içindeki parametreye bir değer geçmek için çağrılacak olan da budur.
@@ -26,7 +26,7 @@ Bu durumda, ek parametreleri ve alt-dependency'leri kontrol etmek için **FastAP
Ve şimdi, dependency'yi "parametreleştirmek" için kullanacağımız instance parametrelerini tanımlamak üzere `__init__` kullanabiliriz:
-{* ../../docs_src/dependencies/tutorial011_an_py39.py hl[9] *}
+{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[9] *}
Bu durumda **FastAPI**, `__init__` ile asla uğraşmaz veya onu önemsemez; onu doğrudan kendi kodumuzda kullanırız.
@@ -34,7 +34,7 @@ Bu durumda **FastAPI**, `__init__` ile asla uğraşmaz veya onu önemsemez; onu
Bu class'tan bir instance'ı şöyle oluşturabiliriz:
-{* ../../docs_src/dependencies/tutorial011_an_py39.py hl[18] *}
+{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[18] *}
Böylece dependency'mizi "parametreleştirmiş" oluruz; artık içinde `"bar"` vardır ve bu değer `checker.fixed_content` attribute'u olarak durur.
@@ -50,7 +50,7 @@ checker(q="somequery")
...ve bunun döndürdüğü her şeyi, *path operation function* içinde `fixed_content_included` parametresine dependency değeri olarak geçirir:
-{* ../../docs_src/dependencies/tutorial011_an_py39.py hl[22] *}
+{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[22] *}
/// tip | İpucu
diff --git a/docs/tr/docs/advanced/advanced-python-types.md b/docs/tr/docs/advanced/advanced-python-types.md
new file mode 100644
index 0000000000..91fe1d5e09
--- /dev/null
+++ b/docs/tr/docs/advanced/advanced-python-types.md
@@ -0,0 +1,61 @@
+# Gelişmiş Python Tipleri { #advanced-python-types }
+
+Python tipleriyle çalışırken işinize yarayabilecek bazı ek fikirler.
+
+## `Union` veya `Optional` Kullanımı { #using-union-or-optional }
+
+Kodunuz herhangi bir nedenle `|` kullanamıyorsa — örneğin bir tip açıklamasında (type annotation) değil de `response_model=` gibi bir yerdeyse — dikey çizgi (`|`) yerine `typing` içindeki `Union`'ı kullanabilirsiniz.
+
+Örneğin, bir şeyin `str` ya da `None` olabileceğini şöyle belirtebilirsiniz:
+
+```python
+from typing import Union
+
+
+def say_hi(name: Union[str, None]):
+ print(f"Hi {name}!")
+```
+
+`typing`, bir şeyin `None` olabileceğini belirtmek için `Optional` ile bir kısayol da sunar.
+
+Benim oldukça öznel bakış açıma göre küçük bir ipucu:
+
+- 🚨 `Optional[SomeType]` kullanmaktan kaçının
+- Bunun yerine ✨ **`Union[SomeType, None]` kullanın** ✨.
+
+İkisi de eşdeğer ve temelde aynıdır; ancak "**optional**" kelimesi değerin isteğe bağlı olduğunu ima eder. Oysa aslında " `None` olabilir" demektir; değer isteğe bağlı olmasa ve hâlâ zorunlu olsa bile.
+
+Bence `Union[SomeType, None]` ne demek istediğini daha açık anlatır.
+
+Burada mesele sadece kelimeler ve isimler. Ancak bu kelimeler sizin ve ekip arkadaşlarınızın koda bakışını etkileyebilir.
+
+Örnek olarak şu fonksiyona bakalım:
+
+```python
+from typing import Optional
+
+
+def say_hi(name: Optional[str]):
+ print(f"Hey {name}!")
+```
+
+`name` parametresi `Optional[str]` olarak tanımlıdır; ancak isteğe bağlı değildir, parametre olmadan fonksiyonu çağıramazsınız:
+
+```Python
+say_hi() # Ah hayır, bu hata fırlatır! 😱
+```
+
+`name` parametresi varsayılan bir değeri olmadığı için hâlâ zorunludur (yani *optional* değildir). Yine de `name`, değer olarak `None` kabul eder:
+
+```Python
+say_hi(name=None) # Bu çalışır, None geçerlidir 🎉
+```
+
+İyi haber şu ki, çoğu durumda tip birliklerini (union) tanımlamak için doğrudan `|` kullanabilirsiniz:
+
+```python
+def say_hi(name: str | None):
+ print(f"Hey {name}!")
+```
+
+Dolayısıyla, normalde `Optional` ve `Union` gibi isimler için endişelenmenize gerek yok. 😎
diff --git a/docs/tr/docs/advanced/async-tests.md b/docs/tr/docs/advanced/async-tests.md
index 82349bbec4..1e5b37a3d6 100644
--- a/docs/tr/docs/advanced/async-tests.md
+++ b/docs/tr/docs/advanced/async-tests.md
@@ -32,11 +32,11 @@ Basit bir örnek için, [Bigger Applications](../tutorial/bigger-applications.md
`main.py` dosyası şöyle olur:
-{* ../../docs_src/async_tests/app_a_py39/main.py *}
+{* ../../docs_src/async_tests/app_a_py310/main.py *}
`test_main.py` dosyasında `main.py` için testler yer alır, artık şöyle görünebilir:
-{* ../../docs_src/async_tests/app_a_py39/test_main.py *}
+{* ../../docs_src/async_tests/app_a_py310/test_main.py *}
## Çalıştırma { #run-it }
@@ -56,7 +56,7 @@ $ pytest
`@pytest.mark.anyio` marker'ı, pytest'e bu test fonksiyonunun asenkron olarak çağrılması gerektiğini söyler:
-{* ../../docs_src/async_tests/app_a_py39/test_main.py hl[7] *}
+{* ../../docs_src/async_tests/app_a_py310/test_main.py hl[7] *}
/// tip | İpucu
@@ -66,7 +66,7 @@ Test fonksiyonu artık `TestClient` kullanırken eskiden olduğu gibi sadece `de
Ardından app ile bir `AsyncClient` oluşturup `await` kullanarak ona async request'ler gönderebiliriz.
-{* ../../docs_src/async_tests/app_a_py39/test_main.py hl[9:12] *}
+{* ../../docs_src/async_tests/app_a_py310/test_main.py hl[9:12] *}
Bu, şu kullanıma denktir:
diff --git a/docs/tr/docs/advanced/behind-a-proxy.md b/docs/tr/docs/advanced/behind-a-proxy.md
index e70b16960f..5cf9a534dd 100644
--- a/docs/tr/docs/advanced/behind-a-proxy.md
+++ b/docs/tr/docs/advanced/behind-a-proxy.md
@@ -44,7 +44,7 @@ $ fastapi run --forwarded-allow-ips="*"
Örneğin `/items/` adında bir *path operation* tanımladığınızı düşünelim:
-{* ../../docs_src/behind_a_proxy/tutorial001_01_py39.py hl[6] *}
+{* ../../docs_src/behind_a_proxy/tutorial001_01_py310.py hl[6] *}
Client `/items`'a gitmeye çalışırsa, varsayılan olarak `/items/`'a redirect edilir.
@@ -115,7 +115,7 @@ Bu durumda, orijinal `/app` path'i aslında `/api/v1/app` altında servis edilir
Kodunuzun tamamı sadece `/app` varmış gibi yazılmış olsa bile.
-{* ../../docs_src/behind_a_proxy/tutorial001_py39.py hl[6] *}
+{* ../../docs_src/behind_a_proxy/tutorial001_py310.py hl[6] *}
Proxy, request'i app server'a (muhtemelen FastAPI CLI üzerinden Uvicorn) iletmeden önce **path prefix**'i anlık olarak **"kırpar"** (strip). Böylece uygulamanız hâlâ `/app` altında servis ediliyormuş gibi davranır ve tüm kodunuzu `/api/v1` prefix'ini içerecek şekilde güncellemeniz gerekmez.
@@ -149,14 +149,14 @@ Docs UI'nin, bu API `server`'ının (proxy arkasında) `/api/v1` altında bulund
```JSON hl_lines="4-8"
{
"openapi": "3.1.0",
- // More stuff here
+ // Burada daha fazla şey var
"servers": [
{
"url": "/api/v1"
}
],
"paths": {
- // More stuff here
+ // Burada daha fazla şey var
}
}
```
@@ -193,7 +193,7 @@ Uygulamanızın her request için kullandığı mevcut `root_path` değerini ala
Burada sadece göstermek için bunu mesaja dahil ediyoruz.
-{* ../../docs_src/behind_a_proxy/tutorial001_py39.py hl[8] *}
+{* ../../docs_src/behind_a_proxy/tutorial001_py310.py hl[8] *}
Ardından Uvicorn'u şu şekilde başlatırsanız:
@@ -220,7 +220,7 @@ Response şöyle bir şey olur:
Alternatif olarak, `--root-path` gibi bir komut satırı seçeneği (veya muadili) sağlayamıyorsanız, FastAPI uygulamanızı oluştururken `root_path` parametresini ayarlayabilirsiniz:
-{* ../../docs_src/behind_a_proxy/tutorial002_py39.py hl[3] *}
+{* ../../docs_src/behind_a_proxy/tutorial002_py310.py hl[3] *}
`FastAPI`'ye `root_path` vermek, Uvicorn veya Hypercorn'a `--root-path` komut satırı seçeneğini vermekle eşdeğerdir.
@@ -400,14 +400,14 @@ Ancak başka alternatif `servers` da sağlayabilirsiniz; örneğin *aynı* docs
Örneğin:
-{* ../../docs_src/behind_a_proxy/tutorial003_py39.py hl[4:7] *}
+{* ../../docs_src/behind_a_proxy/tutorial003_py310.py hl[4:7] *}
Şöyle bir OpenAPI şeması üretir:
```JSON hl_lines="5-7"
{
"openapi": "3.1.0",
- // More stuff here
+ // Burada daha fazla şey var
"servers": [
{
"url": "/api/v1"
@@ -422,7 +422,7 @@ Ancak başka alternatif `servers` da sağlayabilirsiniz; örneğin *aynı* docs
}
],
"paths": {
- // More stuff here
+ // Burada daha fazla şey var
}
}
```
@@ -455,7 +455,7 @@ OpenAPI spesifikasyonunda `servers` özelliği opsiyoneldir.
**FastAPI**'nin `root_path` kullanarak otomatik bir server eklemesini istemiyorsanız, `root_path_in_servers=False` parametresini kullanabilirsiniz:
-{* ../../docs_src/behind_a_proxy/tutorial004_py39.py hl[9] *}
+{* ../../docs_src/behind_a_proxy/tutorial004_py310.py hl[9] *}
Böylece OpenAPI şemasına dahil etmez.
diff --git a/docs/tr/docs/advanced/custom-response.md b/docs/tr/docs/advanced/custom-response.md
index c5148f4287..218a5de5cb 100644
--- a/docs/tr/docs/advanced/custom-response.md
+++ b/docs/tr/docs/advanced/custom-response.md
@@ -30,7 +30,7 @@ Büyük response'larda, doğrudan bir `Response` döndürmek bir dictionary dön
Ancak döndürdüğünüz içeriğin **JSON ile serialize edilebilir** olduğundan eminseniz, onu doğrudan response class’ına verebilir ve FastAPI’nin response class’ına vermeden önce dönüş içeriğinizi `jsonable_encoder` içinden geçirirken oluşturacağı ek yükten kaçınabilirsiniz.
-{* ../../docs_src/custom_response/tutorial001b_py39.py hl[2,7] *}
+{* ../../docs_src/custom_response/tutorial001b_py310.py hl[2,7] *}
/// info | Bilgi
@@ -55,7 +55,7 @@ Ve OpenAPI’de de bu şekilde dokümante edilir.
* `HTMLResponse` import edin.
* *path operation decorator*’ınızın `response_class` parametresi olarak `HTMLResponse` verin.
-{* ../../docs_src/custom_response/tutorial002_py39.py hl[2,7] *}
+{* ../../docs_src/custom_response/tutorial002_py310.py hl[2,7] *}
/// info | Bilgi
@@ -73,7 +73,7 @@ Ve OpenAPI’de de bu şekilde dokümante edilir.
Yukarıdaki örneğin aynısı, bu sefer bir `HTMLResponse` döndürerek, şöyle görünebilir:
-{* ../../docs_src/custom_response/tutorial003_py39.py hl[2,7,19] *}
+{* ../../docs_src/custom_response/tutorial003_py310.py hl[2,7,19] *}
/// warning | Uyarı
@@ -97,7 +97,7 @@ Bu durumda `response_class` sadece OpenAPI *path operation*’ını dokümante e
Örneğin şöyle bir şey olabilir:
-{* ../../docs_src/custom_response/tutorial004_py39.py hl[7,21,23] *}
+{* ../../docs_src/custom_response/tutorial004_py310.py hl[7,21,23] *}
Bu örnekte `generate_html_response()` fonksiyonu, HTML’i bir `str` olarak döndürmek yerine zaten bir `Response` üretip döndürmektedir.
@@ -136,7 +136,7 @@ Bunu doğrudan döndürebilirsiniz.
FastAPI (aslında Starlette) otomatik olarak bir Content-Length header’ı ekler. Ayrıca `media_type`’a göre bir Content-Type header’ı ekler ve text türleri için sona bir charset ekler.
-{* ../../docs_src/response_directly/tutorial002_py39.py hl[1,18] *}
+{* ../../docs_src/response_directly/tutorial002_py310.py hl[1,18] *}
### `HTMLResponse` { #htmlresponse }
@@ -146,7 +146,7 @@ Yukarıda okuduğunuz gibi, bir miktar text veya bytes alır ve HTML response d
Bir miktar text veya bytes alır ve düz metin response döndürür.
-{* ../../docs_src/custom_response/tutorial005_py39.py hl[2,7,9] *}
+{* ../../docs_src/custom_response/tutorial005_py310.py hl[2,7,9] *}
### `JSONResponse` { #jsonresponse }
@@ -180,7 +180,7 @@ Bunun için `ujson` kurulmalıdır; örneğin `pip install ujson`.
///
-{* ../../docs_src/custom_response/tutorial001_py39.py hl[2,7] *}
+{* ../../docs_src/custom_response/tutorial001_py310.py hl[2,7] *}
/// tip | İpucu
@@ -194,13 +194,13 @@ HTTP redirect döndürür. Varsayılan olarak 307 status code (Temporary Redirec
`RedirectResponse`’u doğrudan döndürebilirsiniz:
-{* ../../docs_src/custom_response/tutorial006_py39.py hl[2,9] *}
+{* ../../docs_src/custom_response/tutorial006_py310.py hl[2,9] *}
---
Veya `response_class` parametresi içinde kullanabilirsiniz:
-{* ../../docs_src/custom_response/tutorial006b_py39.py hl[2,7,9] *}
+{* ../../docs_src/custom_response/tutorial006b_py310.py hl[2,7,9] *}
Bunu yaparsanız, *path operation* function’ınızdan doğrudan URL döndürebilirsiniz.
@@ -210,13 +210,13 @@ Bu durumda kullanılan `status_code`, `RedirectResponse` için varsayılan olan
Ayrıca `status_code` parametresini `response_class` parametresiyle birlikte kullanabilirsiniz:
-{* ../../docs_src/custom_response/tutorial006c_py39.py hl[2,7,9] *}
+{* ../../docs_src/custom_response/tutorial006c_py310.py hl[2,7,9] *}
### `StreamingResponse` { #streamingresponse }
Bir async generator veya normal generator/iterator alır ve response body’yi stream eder.
-{* ../../docs_src/custom_response/tutorial007_py39.py hl[2,14] *}
+{* ../../docs_src/custom_response/tutorial007_py310.py hl[2,14] *}
#### `StreamingResponse`’u file-like objelerle kullanma { #using-streamingresponse-with-file-like-objects }
@@ -226,7 +226,7 @@ Böylece önce hepsini memory’ye okumak zorunda kalmazsınız; bu generator fu
Buna cloud storage ile etkileşime giren, video işleyen ve benzeri birçok kütüphane dahildir.
-{* ../../docs_src/custom_response/tutorial008_py39.py hl[2,10:12,14] *}
+{* ../../docs_src/custom_response/tutorial008_py310.py hl[2,10:12,14] *}
1. Bu generator function’dır. İçinde `yield` ifadeleri olduğu için "generator function" denir.
2. Bir `with` bloğu kullanarak, generator function bittiğinde file-like objenin kapandığından emin oluruz. Yani response göndermeyi bitirdikten sonra kapanır.
@@ -255,11 +255,11 @@ Diğer response türlerine göre instantiate ederken farklı argümanlar alır:
File response'ları uygun `Content-Length`, `Last-Modified` ve `ETag` header’larını içerir.
-{* ../../docs_src/custom_response/tutorial009_py39.py hl[2,10] *}
+{* ../../docs_src/custom_response/tutorial009_py310.py hl[2,10] *}
`response_class` parametresini de kullanabilirsiniz:
-{* ../../docs_src/custom_response/tutorial009b_py39.py hl[2,8,10] *}
+{* ../../docs_src/custom_response/tutorial009b_py310.py hl[2,8,10] *}
Bu durumda *path operation* function’ınızdan doğrudan dosya path'ini döndürebilirsiniz.
@@ -273,7 +273,7 @@ Diyelim ki girintili ve biçimlendirilmiş JSON döndürmek istiyorsunuz; bunun
Bir `CustomORJSONResponse` oluşturabilirsiniz. Burada yapmanız gereken temel şey, content’i `bytes` olarak döndüren bir `Response.render(content)` metodu yazmaktır:
-{* ../../docs_src/custom_response/tutorial009c_py39.py hl[9:14,17] *}
+{* ../../docs_src/custom_response/tutorial009c_py310.py hl[9:14,17] *}
Artık şunu döndürmek yerine:
@@ -299,7 +299,7 @@ Bunu tanımlayan parametre `default_response_class`’tır.
Aşağıdaki örnekte **FastAPI**, tüm *path operations* için varsayılan olarak `JSONResponse` yerine `ORJSONResponse` kullanır.
-{* ../../docs_src/custom_response/tutorial010_py39.py hl[2,4] *}
+{* ../../docs_src/custom_response/tutorial010_py310.py hl[2,4] *}
/// tip | İpucu
diff --git a/docs/tr/docs/advanced/dataclasses.md b/docs/tr/docs/advanced/dataclasses.md
index 2639760070..ed70a6a946 100644
--- a/docs/tr/docs/advanced/dataclasses.md
+++ b/docs/tr/docs/advanced/dataclasses.md
@@ -64,7 +64,7 @@ Bu durumda standart `dataclasses` yerine, drop-in replacement olan `pydantic.dat
6. Burada `items` içeren bir dictionary döndürüyoruz; `items` bir dataclass listesi.
- FastAPI, veriyi JSON'a
serializing etmeyi yine başarır.
+ FastAPI, veriyi JSON'a
serileştirmeyi yine başarır.
7. Burada `response_model`, `Author` dataclass'larından oluşan bir listenin type annotation'ını kullanıyor.
diff --git a/docs/tr/docs/advanced/events.md b/docs/tr/docs/advanced/events.md
index 257b952f95..cef8b42a53 100644
--- a/docs/tr/docs/advanced/events.md
+++ b/docs/tr/docs/advanced/events.md
@@ -30,7 +30,7 @@ Bu *startup* ve *shutdown* mantığını, `FastAPI` uygulamasının `lifespan` p
Aşağıdaki gibi `yield` kullanan async bir `lifespan()` fonksiyonu oluşturuyoruz:
-{* ../../docs_src/events/tutorial003_py39.py hl[16,19] *}
+{* ../../docs_src/events/tutorial003_py310.py hl[16,19] *}
Burada, `yield` öncesinde (sahte) model fonksiyonunu machine learning modellerini içeren dictionary’e koyarak, modeli yükleme gibi maliyetli bir *startup* işlemini simüle ediyoruz. Bu kod, *startup* sırasında, uygulama **request almaya başlamadan önce** çalıştırılır.
@@ -48,7 +48,7 @@ Belki yeni bir sürüm başlatmanız gerekiyordur, ya da çalıştırmaktan sık
Dikkat edilmesi gereken ilk şey, `yield` içeren async bir fonksiyon tanımlıyor olmamız. Bu, `yield` kullanan Dependencies’e oldukça benzer.
-{* ../../docs_src/events/tutorial003_py39.py hl[14:19] *}
+{* ../../docs_src/events/tutorial003_py310.py hl[14:19] *}
Fonksiyonun `yield`’den önceki kısmı, uygulama başlamadan **önce** çalışır.
@@ -60,7 +60,7 @@ Bakarsanız, fonksiyon `@asynccontextmanager` ile dekore edilmiş.
Bu da fonksiyonu "**async context manager**" denen şeye dönüştürür.
-{* ../../docs_src/events/tutorial003_py39.py hl[1,13] *}
+{* ../../docs_src/events/tutorial003_py310.py hl[1,13] *}
Python’da **context manager**, `with` ifadesi içinde kullanabildiğiniz bir yapıdır. Örneğin `open()` bir context manager olarak kullanılabilir:
@@ -82,7 +82,7 @@ Yukarıdaki kod örneğimizde bunu doğrudan kullanmıyoruz; bunun yerine FastAP
`FastAPI` uygulamasının `lifespan` parametresi bir **async context manager** alır; dolayısıyla oluşturduğumuz yeni `lifespan` async context manager’ını buraya geçebiliriz.
-{* ../../docs_src/events/tutorial003_py39.py hl[22] *}
+{* ../../docs_src/events/tutorial003_py310.py hl[22] *}
## Alternatif Events (kullanımdan kaldırıldı) { #alternative-events-deprecated }
@@ -104,7 +104,7 @@ Bu fonksiyonlar `async def` ile veya normal `def` ile tanımlanabilir.
Uygulama başlamadan önce çalıştırılacak bir fonksiyon eklemek için, `"startup"` event’i ile tanımlayın:
-{* ../../docs_src/events/tutorial001_py39.py hl[8] *}
+{* ../../docs_src/events/tutorial001_py310.py hl[8] *}
Bu durumda `startup` event handler fonksiyonu, "database" öğesini (sadece bir `dict`) bazı değerlerle başlatır.
@@ -116,7 +116,7 @@ Ve tüm `startup` event handler’ları tamamlanmadan uygulamanız request almay
Uygulama kapanırken çalıştırılacak bir fonksiyon eklemek için, `"shutdown"` event’i ile tanımlayın:
-{* ../../docs_src/events/tutorial002_py39.py hl[6] *}
+{* ../../docs_src/events/tutorial002_py310.py hl[6] *}
Burada `shutdown` event handler fonksiyonu, `log.txt` dosyasına `"Application shutdown"` satırını yazar.
@@ -150,11 +150,11 @@ Bu nedenle artık bunun yerine, yukarıda açıklandığı gibi `lifespan` kulla
Meraklı nerd’ler için küçük bir teknik detay. 🤓
-Altta, ASGI teknik spesifikasyonunda bu,
Lifespan Protocol’ün bir parçasıdır ve `startup` ile `shutdown` adında event’ler tanımlar.
+Altta, ASGI teknik spesifikasyonunda bu,
Lifespan Protokolü’nün bir parçasıdır ve `startup` ile `shutdown` adında event’ler tanımlar.
/// info | Bilgi
-Starlette `lifespan` handler’ları hakkında daha fazlasını
Starlette's Lifespan docs içinde okuyabilirsiniz.
+Starlette `lifespan` handler’ları hakkında daha fazlasını
Starlette Lifespan dokümanları içinde okuyabilirsiniz.
Ayrıca kodunuzun başka bölgelerinde de kullanılabilecek lifespan state’i nasıl yöneteceğinizi de kapsar.
diff --git a/docs/tr/docs/advanced/generate-clients.md b/docs/tr/docs/advanced/generate-clients.md
index af278f2fef..f3d6038a8f 100644
--- a/docs/tr/docs/advanced/generate-clients.md
+++ b/docs/tr/docs/advanced/generate-clients.md
@@ -40,7 +40,7 @@ Bu çözümlerin bazıları açık kaynak olabilir veya ücretsiz katman sunabil
Basit bir FastAPI uygulamasıyla başlayalım:
-{* ../../docs_src/generate_clients/tutorial001_py39.py hl[7:9,12:13,16:17,21] *}
+{* ../../docs_src/generate_clients/tutorial001_py310.py hl[7:9,12:13,16:17,21] *}
*Path operation*'ların, request payload ve response payload için kullandıkları modelleri `Item` ve `ResponseMessage` modelleriyle tanımladıklarına dikkat edin.
@@ -98,7 +98,7 @@ Birçok durumda FastAPI uygulamanız daha büyük olacaktır ve farklı *path op
Örneğin **items** için bir bölüm, **users** için başka bir bölüm olabilir ve bunları tag'lerle ayırabilirsiniz:
-{* ../../docs_src/generate_clients/tutorial002_py39.py hl[21,26,34] *}
+{* ../../docs_src/generate_clients/tutorial002_py310.py hl[21,26,34] *}
### Tag'lerle TypeScript Client Üretme { #generate-a-typescript-client-with-tags }
@@ -145,7 +145,7 @@ Bu fonksiyonu özelleştirebilirsiniz. Bir `APIRoute` alır ve string döndürü
Sonrasında bu özel fonksiyonu `generate_unique_id_function` parametresiyle **FastAPI**'ye geçebilirsiniz:
-{* ../../docs_src/generate_clients/tutorial003_py39.py hl[6:7,10] *}
+{* ../../docs_src/generate_clients/tutorial003_py310.py hl[6:7,10] *}
### Özel Operation ID'lerle TypeScript Client Üretme { #generate-a-typescript-client-with-custom-operation-ids }
@@ -167,7 +167,7 @@ Ancak üretilen client için, client'ları üretmeden hemen önce OpenAPI operat
OpenAPI JSON'u `openapi.json` diye bir dosyaya indirip, şu tarz bir script ile **öndeki tag'i kaldırabiliriz**:
-{* ../../docs_src/generate_clients/tutorial004_py39.py *}
+{* ../../docs_src/generate_clients/tutorial004_py310.py *}
//// tab | Node.js
diff --git a/docs/tr/docs/advanced/index.md b/docs/tr/docs/advanced/index.md
index 3995109e25..ec43da6b3b 100644
--- a/docs/tr/docs/advanced/index.md
+++ b/docs/tr/docs/advanced/index.md
@@ -2,7 +2,7 @@
## Ek Özellikler { #additional-features }
-Ana [Tutorial - User Guide](../tutorial/index.md){.internal-link target=_blank} sayfası, **FastAPI**'ın tüm temel özelliklerini tanımanız için yeterli olmalıdır.
+Ana [Tutorial - User Guide](../tutorial/index.md){.internal-link target=_blank} sayfası, **FastAPI**'nin tüm temel özelliklerini tanımanız için yeterli olmalıdır.
Sonraki bölümlerde diğer seçenekleri, konfigürasyonları ve ek özellikleri göreceksiniz.
@@ -16,6 +16,6 @@ Ve kullanım amacınıza bağlı olarak, çözüm bunlardan birinde olabilir.
## Önce Tutorial'ı Okuyun { #read-the-tutorial-first }
-Ana [Tutorial - User Guide](../tutorial/index.md){.internal-link target=_blank} sayfasındaki bilgilerle **FastAPI**'nın çoğu özelliğini yine de kullanabilirsiniz.
+Ana [Tutorial - User Guide](../tutorial/index.md){.internal-link target=_blank} sayfasındaki bilgilerle **FastAPI**'nin çoğu özelliğini yine de kullanabilirsiniz.
Ve sonraki bölümler, onu zaten okuduğunuzu ve bu temel fikirleri bildiğinizi varsayar.
diff --git a/docs/tr/docs/advanced/middleware.md b/docs/tr/docs/advanced/middleware.md
index a22644a090..7c1fb54f6a 100644
--- a/docs/tr/docs/advanced/middleware.md
+++ b/docs/tr/docs/advanced/middleware.md
@@ -57,13 +57,13 @@ Gelen tüm request'lerin `https` veya `wss` olmasını zorunlu kılar.
`http` veya `ws` olarak gelen herhangi bir request, bunun yerine güvenli şemaya redirect edilir.
-{* ../../docs_src/advanced_middleware/tutorial001_py39.py hl[2,6] *}
+{* ../../docs_src/advanced_middleware/tutorial001_py310.py hl[2,6] *}
## `TrustedHostMiddleware` { #trustedhostmiddleware }
HTTP Host Header saldırılarına karşı korunmak için, gelen tüm request'lerde `Host` header'ının doğru ayarlanmış olmasını zorunlu kılar.
-{* ../../docs_src/advanced_middleware/tutorial002_py39.py hl[2,6:8] *}
+{* ../../docs_src/advanced_middleware/tutorial002_py310.py hl[2,6:8] *}
Aşağıdaki argümanlar desteklenir:
@@ -78,7 +78,7 @@ Gelen bir request doğru şekilde doğrulanmazsa `400` response gönderilir.
Middleware hem standart hem de streaming response'ları ele alır.
-{* ../../docs_src/advanced_middleware/tutorial003_py39.py hl[2,6] *}
+{* ../../docs_src/advanced_middleware/tutorial003_py310.py hl[2,6] *}
Aşağıdaki argümanlar desteklenir:
diff --git a/docs/tr/docs/advanced/openapi-webhooks.md b/docs/tr/docs/advanced/openapi-webhooks.md
index dd9e9bbe73..68b7e6f8d9 100644
--- a/docs/tr/docs/advanced/openapi-webhooks.md
+++ b/docs/tr/docs/advanced/openapi-webhooks.md
@@ -32,7 +32,7 @@ Webhook'lar OpenAPI 3.1.0 ve üzeri sürümlerde mevcuttur; FastAPI `0.99.0` ve
Bir **FastAPI** uygulaması oluşturduğunuzda, *webhook*'ları tanımlamak için kullanabileceğiniz bir `webhooks` attribute'u vardır; *path operation* tanımlar gibi, örneğin `@app.webhooks.post()` ile.
-{* ../../docs_src/openapi_webhooks/tutorial001_py39.py hl[9:13,36:53] *}
+{* ../../docs_src/openapi_webhooks/tutorial001_py310.py hl[9:12,15:20] *}
Tanımladığınız webhook'lar **OpenAPI** şemasında ve otomatik **docs UI**'da yer alır.
diff --git a/docs/tr/docs/advanced/path-operation-advanced-configuration.md b/docs/tr/docs/advanced/path-operation-advanced-configuration.md
index e326842d67..ad2c460955 100644
--- a/docs/tr/docs/advanced/path-operation-advanced-configuration.md
+++ b/docs/tr/docs/advanced/path-operation-advanced-configuration.md
@@ -12,7 +12,7 @@ OpenAPI konusunda "uzman" değilseniz, muhtemelen buna ihtiyacınız yok.
Bunun her operation için benzersiz olduğundan emin olmanız gerekir.
-{* ../../docs_src/path_operation_advanced_configuration/tutorial001_py39.py hl[6] *}
+{* ../../docs_src/path_operation_advanced_configuration/tutorial001_py310.py hl[6] *}
### operationId olarak *path operation function* adını kullanma { #using-the-path-operation-function-name-as-the-operationid }
@@ -20,7 +20,7 @@ API’lerinizin function adlarını `operationId` olarak kullanmak istiyorsanız
Bunu, tüm *path operation*’ları ekledikten sonra yapmalısınız.
-{* ../../docs_src/path_operation_advanced_configuration/tutorial002_py39.py hl[2, 12:21, 24] *}
+{* ../../docs_src/path_operation_advanced_configuration/tutorial002_py310.py hl[2, 12:21, 24] *}
/// tip | İpucu
@@ -40,7 +40,7 @@ Farklı modüllerde (Python dosyalarında) olsalar bile.
Bir *path operation*’ı üretilen OpenAPI şemasından (dolayısıyla otomatik dokümantasyon sistemlerinden) hariç tutmak için `include_in_schema` parametresini kullanın ve `False` yapın:
-{* ../../docs_src/path_operation_advanced_configuration/tutorial003_py39.py hl[6] *}
+{* ../../docs_src/path_operation_advanced_configuration/tutorial003_py310.py hl[6] *}
## Docstring’den İleri Düzey Açıklama { #advanced-description-from-docstring }
@@ -68,7 +68,7 @@ Uygulamanızda bir *path operation* tanımladığınızda, **FastAPI** OpenAPI
/// note | Teknik Detaylar
-OpenAPI spesifikasyonunda buna
Operation Object denir.
+OpenAPI spesifikasyonunda buna
Operation Nesnesi denir.
///
@@ -90,9 +90,9 @@ Bir *path operation* için OpenAPI şemasını `openapi_extra` parametresiyle ge
### OpenAPI Extensions { #openapi-extensions }
-Örneğin bu `openapi_extra`, [OpenAPI Extensions](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#specificationExtensions) tanımlamak için faydalı olabilir:
+Örneğin bu `openapi_extra`, [OpenAPI Uzantıları](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#specificationExtensions) tanımlamak için faydalı olabilir:
-{* ../../docs_src/path_operation_advanced_configuration/tutorial005_py39.py hl[6] *}
+{* ../../docs_src/path_operation_advanced_configuration/tutorial005_py310.py hl[6] *}
Otomatik API dokümanlarını açtığınızda, extension’ınız ilgili *path operation*’ın en altında görünür.
@@ -139,9 +139,9 @@ Böylece otomatik üretilen şemaya ek veri ekleyebilirsiniz.
Bunu `openapi_extra` ile yapabilirsiniz:
-{* ../../docs_src/path_operation_advanced_configuration/tutorial006_py39.py hl[19:36, 39:40] *}
+{* ../../docs_src/path_operation_advanced_configuration/tutorial006_py310.py hl[19:36, 39:40] *}
-Bu örnekte herhangi bir Pydantic model tanımlamadık. Hatta request body JSON olarak
parsed bile edilmiyor; doğrudan `bytes` olarak okunuyor ve `magic_data_reader()` fonksiyonu bunu bir şekilde parse etmekten sorumlu oluyor.
+Bu örnekte herhangi bir Pydantic model tanımlamadık. Hatta request body JSON olarak
ayrıştırılmıyor; doğrudan `bytes` olarak okunuyor ve `magic_data_reader()` fonksiyonu bunu bir şekilde parse etmekten sorumlu oluyor.
Buna rağmen, request body için beklenen şemayı tanımlayabiliriz.
@@ -153,7 +153,7 @@ Ve bunu, request içindeki veri tipi JSON olmasa bile yapabilirsiniz.
Örneğin bu uygulamada, FastAPI’nin Pydantic modellerinden JSON Schema çıkarmaya yönelik entegre işlevselliğini ve JSON için otomatik doğrulamayı kullanmıyoruz. Hatta request content type’ını JSON değil, YAML olarak tanımlıyoruz:
-{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py39.py hl[15:20, 22] *}
+{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py310.py hl[15:20, 22] *}
Buna rağmen, varsayılan entegre işlevselliği kullanmasak da, YAML olarak almak istediğimiz veri için JSON Schema’yı manuel üretmek üzere bir Pydantic model kullanmaya devam ediyoruz.
@@ -161,7 +161,7 @@ Ardından request’i doğrudan kullanıp body’yi `bytes` olarak çıkarıyoru
Sonrasında kodumuzda bu YAML içeriğini doğrudan parse ediyor, ardından YAML içeriğini doğrulamak için yine aynı Pydantic modeli kullanıyoruz:
-{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py39.py hl[24:31] *}
+{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py310.py hl[24:31] *}
/// tip | İpucu
diff --git a/docs/tr/docs/advanced/response-change-status-code.md b/docs/tr/docs/advanced/response-change-status-code.md
index 239c0dddd4..cc86cc0e3a 100644
--- a/docs/tr/docs/advanced/response-change-status-code.md
+++ b/docs/tr/docs/advanced/response-change-status-code.md
@@ -20,7 +20,7 @@ Bu tür durumlarda bir `Response` parametresi kullanabilirsiniz.
Ardından bu *geçici (temporal)* `Response` nesnesi üzerinde `status_code` değerini ayarlayabilirsiniz.
-{* ../../docs_src/response_change_status_code/tutorial001_py39.py hl[1,9,12] *}
+{* ../../docs_src/response_change_status_code/tutorial001_py310.py hl[1,9,12] *}
Sonrasında, normalde yaptığınız gibi ihtiyacınız olan herhangi bir nesneyi döndürebilirsiniz (`dict`, bir veritabanı modeli, vb.).
diff --git a/docs/tr/docs/advanced/response-cookies.md b/docs/tr/docs/advanced/response-cookies.md
index d00bfc4cd0..526d6d3c67 100644
--- a/docs/tr/docs/advanced/response-cookies.md
+++ b/docs/tr/docs/advanced/response-cookies.md
@@ -6,7 +6,7 @@
Ardından bu *geçici* response nesnesi üzerinde cookie'leri set edebilirsiniz.
-{* ../../docs_src/response_cookies/tutorial002_py39.py hl[1, 8:9] *}
+{* ../../docs_src/response_cookies/tutorial002_py310.py hl[1, 8:9] *}
Sonrasında normalde yaptığınız gibi ihtiyaç duyduğunuz herhangi bir nesneyi döndürebilirsiniz (bir `dict`, bir veritabanı modeli vb.).
@@ -24,9 +24,9 @@ Bunu yapmak için, [Doğrudan Response Döndürme](response-directly.md){.intern
Sonra bunun içinde Cookie'leri set edin ve response'u döndürün:
-{* ../../docs_src/response_cookies/tutorial001_py39.py hl[10:12] *}
+{* ../../docs_src/response_cookies/tutorial001_py310.py hl[10:12] *}
-/// tip | İpucu
+/// tip
`Response` parametresini kullanmak yerine doğrudan bir response döndürürseniz, FastAPI onu olduğu gibi (doğrudan) döndürür.
diff --git a/docs/tr/docs/advanced/response-directly.md b/docs/tr/docs/advanced/response-directly.md
index 332f1224fc..cadefbdde0 100644
--- a/docs/tr/docs/advanced/response-directly.md
+++ b/docs/tr/docs/advanced/response-directly.md
@@ -2,7 +2,7 @@
**FastAPI** ile bir *path operation* oluşturduğunuzda, normalde ondan herhangi bir veri döndürebilirsiniz: bir `dict`, bir `list`, bir Pydantic model, bir veritabanı modeli vb.
-Varsayılan olarak **FastAPI**, döndürdüğünüz bu değeri [JSON Compatible Encoder](../tutorial/encoder.md){.internal-link target=_blank} bölümünde anlatılan `jsonable_encoder` ile otomatik olarak JSON'a çevirir.
+Varsayılan olarak **FastAPI**, döndürdüğünüz bu değeri [JSON Uyumlu Encoder](../tutorial/encoder.md){.internal-link target=_blank} bölümünde anlatılan `jsonable_encoder` ile otomatik olarak JSON'a çevirir.
Ardından perde arkasında, JSON-uyumlu bu veriyi (ör. bir `dict`) client'a response göndermek için kullanılacak bir `JSONResponse` içine yerleştirir.
@@ -54,12 +54,12 @@ Diyelim ki
Marshmallow { #marshmallow }
-API sistemlerinin ihtiyaç duyduğu temel özelliklerden biri, koddan (Python) veriyi alıp ağ üzerinden gönderilebilecek bir şeye dönüştürmek, yani veri “
dönüşüm”üdür. Örneğin, bir veritabanından gelen verileri içeren bir objeyi JSON objesine dönüştürmek, `datetime` objelerini string’e çevirmek vb.
+API sistemlerinin ihtiyaç duyduğu temel özelliklerden biri, koddan (Python) veriyi alıp ağ üzerinden gönderilebilecek bir şeye dönüştürmek, yani veri “
dönüşüm”üdür. Örneğin, bir veritabanından gelen verileri içeren bir objeyi JSON objesine dönüştürmek, `datetime` objelerini string’e çevirmek vb.
API’ların ihtiyaç duyduğu bir diğer önemli özellik, veri doğrulamadır; belirli parametreler göz önüne alındığında verinin geçerli olduğundan emin olmak. Örneğin, bir alanın `int` olması ve rastgele bir metin olmaması. Bu özellikle dışarıdan gelen veriler için kullanışlıdır.
@@ -145,7 +145,7 @@ Bir veri doğrulama sistemi olmadan, tüm bu kontrolleri kod içinde el ile yapm
Marshmallow, bu özellikleri sağlamak için inşa edildi. Harika bir kütüphanedir ve geçmişte çok kullandım.
-Ancak Python tip belirteçlerinden önce yazılmıştır. Dolayısıyla her
şemayı tanımlamak için Marshmallow’un sağladığı belirli yardımcılar ve sınıflar kullanılır.
+Ancak Python tip belirteçlerinden önce yazılmıştır. Dolayısıyla her
şemayı tanımlamak için Marshmallow’un sağladığı belirli yardımcılar ve sınıflar kullanılır.
/// check | **FastAPI**'a ilham olan
@@ -155,7 +155,7 @@ Kodla, veri tiplerini ve doğrulamayı otomatik sağlayan “şemalar” tanıml
###
Webargs { #webargs }
-API’ların ihtiyaç duyduğu bir diğer büyük özellik, gelen isteklerden veriyi
ayrıştırmadır.
+API’ların ihtiyaç duyduğu bir diğer büyük özellik, gelen isteklerden veriyi
ayrıştırmadır.
Webargs, Flask dahil birkaç framework’ün üzerinde bunu sağlamak için geliştirilmiş bir araçtır.
@@ -417,7 +417,7 @@ Tüm veri doğrulama, veri dönüşümü ve JSON Schema tabanlı otomatik model
###
Starlette { #starlette }
-Starlette, yüksek performanslı asyncio servisleri oluşturmak için ideal, hafif bir
ASGI framework’ü/araç takımıdır.
+Starlette, yüksek performanslı asyncio servisleri oluşturmak için ideal, hafif bir
ASGI framework’ü/araç takımıdır.
Çok basit ve sezgiseldir. Kolayca genişletilebilir ve modüler bileşenlere sahip olacak şekilde tasarlanmıştır.
diff --git a/docs/tr/docs/async.md b/docs/tr/docs/async.md
index 88fd763fce..c788d60a86 100644
--- a/docs/tr/docs/async.md
+++ b/docs/tr/docs/async.md
@@ -1,18 +1,18 @@
-# Concurrency ve async / await
+# Eşzamanlılık ve async / await { #concurrency-and-async-await }
-*path operasyon fonksiyonu* için `async def `sözdizimi, asenkron kod, eşzamanlılık ve paralellik hakkında bazı ayrıntılar.
+*path operasyon fonksiyonları* için `async def` sözdizimi hakkında detaylar ve asenkron kod, eşzamanlılık (concurrency) ve paralellik üzerine arka plan bilgisi.
-## Aceleniz mi var?
+## Aceleniz mi var? { #in-a-hurry }
-
TL;DR:
+
TL;DR:
-Eğer `await` ile çağrılması gerektiğini belirten üçüncü taraf kütüphaneleri kullanıyorsanız, örneğin:
+Eğer `await` ile çağırmanız gerektiğini söyleyen üçüncü taraf kütüphaneler kullanıyorsanız, örneğin:
```Python
results = await some_library()
```
-O zaman *path operasyon fonksiyonunu* `async def` ile tanımlayın örneğin:
+O zaman *path operasyon fonksiyonlarınızı* aşağıdaki gibi `async def` ile tanımlayın:
```Python hl_lines="2"
@app.get('/')
@@ -23,13 +23,13 @@ async def read_results():
/// note | Not
-Sadece `async def` ile tanımlanan fonksiyonlar içinde `await` kullanabilirsiniz.
+`await` yalnızca `async def` ile oluşturulan fonksiyonların içinde kullanılabilir.
///
---
-Eğer bir veritabanı, bir API, dosya sistemi vb. ile iletişim kuran bir üçüncü taraf bir kütüphane kullanıyorsanız ve `await` kullanımını desteklemiyorsa, (bu şu anda çoğu veritabanı kütüphanesi için geçerli bir durumdur), o zaman *path operasyon fonksiyonunuzu* `def` kullanarak normal bir şekilde tanımlayın, örneğin:
+Eğer bir veritabanı, bir API, dosya sistemi vb. ile iletişim kuran ve `await` desteği olmayan bir üçüncü taraf kütüphane kullanıyorsanız (bu şu anda çoğu veritabanı kütüphanesi için geçerlidir), o zaman *path operasyon fonksiyonlarınızı* normal olarak `def` ile tanımlayın:
```Python hl_lines="2"
@app.get('/')
@@ -40,279 +40,307 @@ def results():
---
-Eğer uygulamanız (bir şekilde) başka bir şeyle iletişim kurmak ve onun cevap vermesini beklemek zorunda değilse, `async def` kullanın.
+Uygulamanız (bir şekilde) başka bir şeyle iletişim kurmak ve onun yanıtını beklemek zorunda değilse, içinde `await` kullanmanız gerekmese bile `async def` kullanın.
---
-Sadece bilmiyorsanız, normal `def` kullanın.
+Emin değilseniz, normal `def` kullanın.
---
-**Not**: *path operasyon fonksiyonlarınızda* `def` ve `async def`'i ihtiyaç duyduğunuz gibi karıştırabilir ve her birini sizin için en iyi seçeneği kullanarak tanımlayabilirsiniz. FastAPI onlarla doğru olanı yapacaktır.
+Not: *path operasyon fonksiyonlarınızda* `def` ve `async def`'i ihtiyacınız kadar karıştırabilirsiniz, her birini sizin için en iyi seçenekle tanımlayın. FastAPI onlar için doğru olanı yapacaktır.
-Her neyse, yukarıdaki durumlardan herhangi birinde, FastAPI yine de asenkron olarak çalışacak ve son derece hızlı olacaktır.
+Yukarıdaki durumların herhangi birinde FastAPI yine de asenkron olarak çalışır ve son derece hızlıdır.
-Ancak yukarıdaki adımları takip ederek, bazı performans optimizasyonları yapılabilecektir.
+Ancak yukarıdaki adımları izleyerek bazı performans optimizasyonları mümkün olur.
-## Teknik Detaylar
+## Teknik Detaylar { #technical-details }
-Python'un modern versiyonlarında **`async` ve `await`** sözdizimi ile **"coroutines"** kullanan **"asenkron kod"** desteğine sahiptir.
+Python’un modern sürümleri, **`async` ve `await`** sözdizimiyle, **"coroutines"** denilen bir yapıyı kullanarak **"asenkron kod"** desteğine sahiptir.
-Bu ifadeyi aşağıdaki bölümlerde daha da ayrıntılı açıklayalım:
+Aşağıdaki bölümlerde bu ifadeyi parça parça ele alalım:
-* **Asenkron kod**
+* **Asenkron Kod**
* **`async` ve `await`**
-* **Coroutines**
+* **Coroutine'ler**
-## Asenkron kod
+## Asenkron Kod { #asynchronous-code }
-Asenkron kod programlama dilinin 💬 bilgisayara / programa 🤖 kodun bir noktasında, *başka bir kodun* bir yerde bitmesini 🤖 beklemesi gerektiğini söylemenin bir yoludur. Bu *başka koda* "slow-file" denir 📝.
+Asenkron kod, dilin 💬 bilgisayara / programa 🤖 kodun bir noktasında, bir yerde *başka bir şeyin* bitmesini beklemesi gerektiğini söylemesinin bir yoludur. Diyelim ki bu *başka şeye* "slow-file" 📝 diyoruz.
-Böylece, bu süreçte bilgisayar "slow-file" 📝 tamamlanırken gidip başka işler yapabilir.
+Bu sırada bilgisayar, "slow-file" 📝 biterken gidip başka işler yapabilir.
-Sonra bilgisayar / program 🤖 her fırsatı olduğunda o noktada yaptığı tüm işleri 🤖 bitirene kadar geri dönücek. Ve 🤖 yapması gerekeni yaparak, beklediği görevlerden herhangi birinin bitip bitmediğini görecek.
+Sonra bilgisayar / program 🤖, ya tekrar beklediği için ya da o anda elindeki tüm işleri bitirdiğinde fırsat buldukça geri gelir. Ve beklediği görevlerden herhangi biri bittiyse, yapılması gerekenleri yapar.
-Ardından, 🤖 bitirmek için ilk görevi alır ("slow-file" 📝) ve onunla ne yapması gerekiyorsa onu devam ettirir.
+Ardından, 🤖 ilk biten görevi alır (örneğin bizim "slow-file" 📝) ve onunla yapması gerekenlere devam eder.
-Bu "başka bir şey için bekle" normalde, aşağıdakileri beklemek gibi (işlemcinin ve RAM belleğinin hızına kıyasla) nispeten "yavaş" olan
I/O işlemlerine atıfta bulunur:
+Bu "başka bir şeyi beklemek" genelde işlemci ve RAM hızına kıyasla nispeten "yavaş" olan
I/O işlemlerine atıfta bulunur, örneğin şunları beklemek gibi:
-* istemci tarafından ağ üzerinden veri göndermek
-* ağ üzerinden istemciye gönderilen veriler
-* sistem tarafından okunacak ve programınıza verilecek bir dosya içeriği
-* programınızın diske yazılmak üzere sisteme verdiği dosya içerikleri
+* istemciden verinin ağ üzerinden gelmesi
+* programınızın gönderdiği verinin ağ üzerinden istemciye ulaşması
+* diskteki bir dosyanın içeriğinin sistem tarafından okunup programınıza verilmesi
+* programınızın sisteme verdiği içeriğin diske yazılması
* uzak bir API işlemi
-* bir veritabanı bitirme işlemi
-* sonuçları döndürmek için bir veritabanı sorgusu
+* bir veritabanı işleminin bitmesi
+* bir veritabanı sorgusunun sonuç döndürmesi
* vb.
-Yürütme süresi çoğunlukla
I/O işlemleri beklenerek tüketildiğinden bunlara "I/O bağlantılı" işlemler denir.
+Çalışma süresi çoğunlukla
I/O işlemlerini beklemekle geçtiğinden, bunlara "I/O bound" işlemler denir.
-Buna "asenkron" denir, çünkü bilgisayar/program yavaş görevle "senkronize" olmak zorunda değildir, görevin tam olarak biteceği anı bekler, hiçbir şey yapmadan, görev sonucunu alabilmek ve çalışmaya devam edebilmek için .
+"Bunun" asenkron" denmesinin sebebi, bilgisayarın / programın yavaş görevle "senkronize" olmak, görev tam bittiği anda orada olup görev sonucunu almak ve işe devam etmek için hiçbir şey yapmadan beklemek zorunda olmamasıdır.
-Bunun yerine, "asenkron" bir sistem olarak, bir kez bittiğinde, bilgisayarın / programın yapması gerekeni bitirmesi için biraz (birkaç mikrosaniye) sırada bekleyebilir ve ardından sonuçları almak için geri gelebilir ve onlarla çalışmaya devam edebilir.
+Bunun yerine "asenkron" bir sistem olarak, görev bittiğinde, bilgisayarın / programın o sırada yaptığı işi bitirmesi için biraz (birkaç mikrosaniye) sırada bekleyebilir ve sonra sonuçları almak üzere geri dönüp onlarla çalışmaya devam edebilir.
-"Senkron" ("asenkron"un aksine) için genellikle "sıralı" terimini de kullanırlar, çünkü bilgisayar/program, bu adımlar beklemeyi içerse bile, farklı bir göreve geçmeden önce tüm adımları sırayla izler.
+"Senkron" (asenkronun tersi) için genelde "sıralı" terimi de kullanılır; çünkü bilgisayar / program, farklı bir göreve geçmeden önce tüm adımları sırayla izler, bu adımlar beklemeyi içerse bile.
+### Eşzamanlılık ve Burgerler { #concurrency-and-burgers }
-### Eşzamanlılık (Concurrency) ve Burgerler
+Yukarıda anlatılan **asenkron** kod fikrine bazen **"eşzamanlılık"** (concurrency) da denir. **"Paralellik"**ten (parallelism) farklıdır.
+**Eşzamanlılık** ve **paralellik**, "aynı anda az çok birden fazla şeyin olması" ile ilgilidir.
-Yukarıda açıklanan bu **asenkron** kod fikrine bazen **"eşzamanlılık"** da denir. **"Paralellikten"** farklıdır.
+Ama *eşzamanlılık* ve *paralellik* arasındaki ayrıntılar oldukça farklıdır.
-**Eşzamanlılık** ve **paralellik**, "aynı anda az ya da çok olan farklı işler" ile ilgilidir.
+Farkı görmek için burgerlerle ilgili şu hikayeyi hayal edin:
-Ancak *eşzamanlılık* ve *paralellik* arasındaki ayrıntılar oldukça farklıdır.
+### Eşzamanlı Burgerler { #concurrent-burgers }
+Aşkınla fast food almaya gidiyorsun, kasiyer senden önceki insanların siparişlerini alırken sıraya giriyorsun. 😍
-Farkı görmek için burgerlerle ilgili aşağıdaki hikayeyi hayal edin:
+

-### Eşzamanlı Burgerler
+Sonra sıra size geliyor, sen ve aşkın için 2 çok havalı burger sipariş ediyorsun. 🍔🍔
-
+

-Aşkınla beraber 😍 dışarı hamburger yemeye çıktınız 🍔, kasiyer 💁 öndeki insanlardan sipariş alırken siz sıraya girdiniz.
+Kasiyer, mutfaktaki aşçıya burgerlerini hazırlamaları gerektiğini söylüyor (o an önceki müşterilerin burgerlerini hazırlıyor olsalar bile).
-Sıra sizde ve sen aşkın 😍 ve kendin için 2 çılgın hamburger 🍔 söylüyorsun.
+

-Ödemeyi yaptın 💸.
+Ödeme yapıyorsun. 💸
-Kasiyer 💁 mutfakdaki aşçıya 👨🍳 hamburgerleri 🍔 hazırlaması gerektiğini söyler ve aşçı bunu bilir (o an önceki müşterilerin siparişlerini hazırlıyor olsa bile).
+Kasiyer sana sıra numaranı veriyor.
-Kasiyer 💁 size bir sıra numarası verir.
+

-Beklerken askınla 😍 bir masaya oturur ve uzun bir süre konuşursunuz(Burgerleriniz çok çılgın olduğundan ve hazırlanması biraz zaman alıyor ✨🍔✨).
+Beklerken aşkınla bir masa seçip oturuyorsunuz, uzun uzun sohbet ediyorsunuz (burgerler baya havalı ve hazırlanması biraz zaman alıyor).
-Hamburgeri beklerkenki zamanı 🍔, aşkının ne kadar zeki ve tatlı olduğuna hayran kalarak harcayabilirsin ✨😍✨.
+Masada aşkınla otururken, burgerleri beklerken, o zamanı aşkının ne kadar harika, tatlı ve zeki olduğuna hayran kalarak geçirebilirsin ✨😍✨.
-Aşkınla 😍 konuşurken arada sıranın size gelip gelmediğini kontrol ediyorsun.
+

-Nihayet sıra size geldi. Tezgaha gidip hamburgerleri 🍔kapıp masaya geri dönüyorsun.
+Bekler ve sohbet ederken, ara ara tezgâhtaki numaraya bakıp sıranın size gelip gelmediğini kontrol ediyorsun.
-Aşkınla hamburgerlerinizi yiyor 🍔 ve iyi vakit geçiriyorsunuz ✨.
+Bir noktada, nihayet sıra size geliyor. Tezgâha gidiyor, burgerleri alıp masaya dönüyorsun.
+
+

+
+Aşkınla burgerleri yiyip güzel vakit geçiriyorsunuz. ✨
+
+

+
+/// info | Bilgi
+
+Harika çizimler:
Ketrina Thompson. 🎨
+
+///
---
-Bu hikayedeki bilgisayar / program 🤖 olduğunuzu hayal edin.
+Bu hikâyede bilgisayar / program 🤖 olduğunu hayal et.
-Sırada beklerken boştasın 😴, sıranı beklerken herhangi bir "üretim" yapmıyorsun. Ama bu sıra hızlı çünkü kasiyer sadece siparişleri alıyor (onları hazırlamıyor), burada bir sıknıtı yok.
+Sıradayken sadece boştasın 😴, sıranı bekliyorsun, çok "üretken" bir şey yapmıyorsun. Ama sorun yok, çünkü kasiyer sadece sipariş alıyor (hazırlamıyor), bu yüzden sıra hızlı ilerliyor.
-Sonra sıra size geldiğinde gerçekten "üretken" işler yapabilirsiniz 🤓, menüyü oku, ne istediğine larar ver, aşkının seçimini al 😍, öde 💸, doğru kartı çıkart, ödemeyi kontrol et, faturayı kontrol et, siparişin doğru olup olmadığını kontrol et, vb.
+Sıra sana geldiğinde gerçekten "üretken" işler yapıyorsun: menüyü işliyorsun, ne istediğine karar veriyorsun, aşkının seçimini alıyorsun, ödüyorsun, doğru para ya da kartı verdiğini kontrol ediyorsun, doğru ücretlendirildiğini kontrol ediyorsun, sipariş kalemlerinin doğru olduğunu kontrol ediyorsun, vb.
-Ama hamburgerler 🍔 hazır olmamasına rağmen Kasiyer 💁 ile işiniz "duraklıyor" ⏸, çünkü hamburgerlerin hazır olmasını bekliyoruz 🕙.
+Ama sonra, burgerlerin hâlâ gelmemiş olsa da, kasiyerle olan işin "duraklatılıyor" ⏸, çünkü burgerlerin hazır olmasını 🕙 beklemen gerekiyor.
-Ama tezgahtan uzaklaşıp sıranız gelene kadarmasanıza dönebilir 🔀 ve dikkatinizi aşkınıza 😍 verebilirsiniz vr bunun üzerine "çalışabilirsiniz" ⏯ 🤓. Artık "üretken" birşey yapıyorsunuz 🤓, sevgilinle 😍 flört eder gibi.
+Fakat tezgâhtan uzaklaşıp masada sıra numaranla oturduğun için, dikkatinizi 🔀 aşkına çevirebilir, onunla "çalışmaya" ⏯ 🤓 odaklanabilirsin. Yani yine çok "üretken" bir şey yapıyorsun, aşkınla flört etmek gibi 😍.
-Kasiyer 💁 "Hamburgerler hazır !" 🍔 dediğinde ve görüntülenen numara sizin numaranız olduğunda hemen koşup hamburgerlerinizi almaya çalışmıyorsunuz. Biliyorsunuzki kimse sizin hamburgerlerinizi 🍔 çalmayacak çünkü sıra sizin.
+Ardından kasiyer 💁, tezgâh ekranına numaranı koyarak "burgerleri bitirdim" diyor; ama numara seninki olduğunda çılgınca sıçramıyorsun. Sıra numaran sende, herkesin kendi numarası var; kimse burgerlerini çalamaz.
-Yani Aşkınızın😍 hikayeyi bitirmesini bekliyorsunuz (çalışmayı bitir ⏯ / görev işleniyor.. 🤓), nazikçe gülümseyin ve hamburger yemeye gittiğinizi söyleyin ⏸.
+Bu yüzden aşkının hikâyeyi bitirmesini (mevcut işi ⏯ / işlenen görevi 🤓 bitirmesini) bekliyor, nazikçe gülümsüyor ve burgerleri almaya gittiğini söylüyorsun ⏸.
-Ardından tezgaha 🔀, şimdi biten ilk göreve ⏯ gidin, Hamburgerleri 🍔 alın, teşekkür edin ve masaya götürün. sayacın bu adımı tamamlanır ⏹. Bu da yeni bir görev olan "hamburgerleri ye" 🔀 ⏯ görevini başlatırken "hamburgerleri al" ⏹ görevini bitirir.
+Sonra tezgâha 🔀 gidip artık bitmiş olan ilk göreve ⏯ dönüyor, burgerleri alıyor, teşekkür ediyor ve masaya getiriyorsun. Tezgâhla etkileşimin bu adımı / görevi böylece bitiyor ⏹. Bu da yeni bir görev olan "burgerleri yemek" 🔀 ⏯ görevini oluşturuyor, ama "burgerleri almak" görevi tamamlandı ⏹.
-### Parallel Hamburgerler
+### Paralel Burgerler { #parallel-burgers }
-Şimdi bunların "Eşzamanlı Hamburger" değil, "Paralel Hamburger" olduğunu düşünelim.
+Şimdi bunların "Eşzamanlı Burgerler" değil, "Paralel Burgerler" olduğunu hayal edelim.
-Hamburger 🍔 almak için 😍 aşkınla Paralel fast food'a gidiyorsun.
+Aşkınla paralel fast food almaya gidiyorsun.
-Birden fazla kasiyer varken (varsayalım 8) sıraya girdiniz👩🍳👨🍳👩🍳👨🍳👩🍳👨🍳👩🍳👨🍳 ve sıranız gelene kadar bekliyorsunuz.
+Aynı anda aşçı da olan birden fazla (8 diyelim) kasiyerin, senden önceki insanların siparişlerini aldığı bir sırada bekliyorsun.
-Sizden önceki herkez ayrılmadan önce hamburgerlerinin 🍔 hazır olmasını bekliyor 🕙. Çünkü kasiyerlerin her biri bir hamburger hazırlanmadan önce bir sonraki siparişe geçmiiyor.
+Senden önceki herkes, tezgâhtan ayrılmadan önce burgerlerinin hazırlanmasını bekliyor; çünkü 8 kasiyerin her biri bir sonraki siparişe geçmeden önce burgeri hemen gidip hazırlıyor.
-Sonunda senin sıran, aşkın 😍 ve kendin için 2 hamburger 🍔 siparişi verdiniz.
+

-Ödemeyi yaptınız 💸.
+Sonunda sıra size geliyor, sen ve aşkın için 2 çok havalı burger siparişi veriyorsun.
-Kasiyer mutfağa gider 👨🍳.
+Ödüyorsun 💸.
-Sırada bekliyorsunuz 🕙, kimse sizin burgerinizi 🍔 almaya çalışmıyor çünkü sıra sizin.
+

-Sen ve aşkın 😍 sıranızı korumak ve hamburgerleri almakla o kadar meşgulsünüz ki birbirinize vakit 🕙 ayıramıyorsunuz 😞.
+Kasiyer mutfağa gidiyor.
-İşte bu "senkron" çalışmadır. Kasiyer/aşçı 👨🍳ile senkron hareket ediyorsunuz. Bu yüzden beklemek 🕙 ve kasiyer/aşçı burgeri 🍔bitirip size getirdiğinde orda olmak zorundasınız yoksa başka biri alabilir.
+Tezgâhın önünde ayakta 🕙 bekliyorsun; sıra numarası olmadığından, burgerlerini senden önce kimsenin almaması için orada durman gerekiyor.
-Sonra kasiyeri/aşçı 👨🍳 nihayet hamburgerlerinizle 🍔, uzun bir süre sonra 🕙 tezgaha geri geliyor.
+

-Burgerlerinizi 🍔 al ve aşkınla masanıza doğru ilerle 😍.
+Sen ve aşkın, kimsenin önünüze geçip burgerler gelince almaması için meşgul olduğunuzdan, aşkına dikkatini veremiyorsun. 😞
-Sadece burgerini yiyorsun 🍔 ve bitti ⏹.
+Bu "senkron" bir iştir; kasiyer/aşçı 👨🍳 ile "senkronize"sin. 🕙 Beklemen ve kasiyer/aşçı 👨🍳 burgerleri bitirip sana verdiği anda tam orada olman gerekir; yoksa bir başkası alabilir.
-Bekleyerek çok fazla zaman geçtiğinden 🕙 konuşmaya çok fazla vakit kalmadı 😞.
+

----
+Sonra kasiyer/aşçı 👨🍳, uzun süre tezgâhın önünde 🕙 bekledikten sonra nihayet burgerlerinle geri geliyor.
+
+

+
+Burgerleri alıyor ve aşkınla masaya gidiyorsun.
+
+Sadece yiyorsunuz ve iş bitiyor. ⏹
-Paralel burger senaryosunda ise, siz iki işlemcili birer robotsunuz 🤖 (sen ve sevgilin 😍), Beklıyorsunuz 🕙 hem konuşarak güzel vakit geçirirken ⏯ hem de sıranızı bekliyorsunuz 🕙.
+

-Mağazada ise 8 işlemci bulunuyor (Kasiyer/aşçı) 👩🍳👨🍳👩🍳👨🍳👩🍳👨🍳👩🍳👨🍳. Eşzamanlı burgerde yalnızca 2 kişi olabiliyordu (bir kasiyer ve bir aşçı) 💁 👨🍳.
+Vaktin çoğu tezgâhın önünde 🕙 beklemekle geçtiğinden, pek konuşma ya da flört olmadı. 😞
-Ama yine de bu en iyisi değil 😞.
+/// info | Bilgi
+
+Harika çizimler:
Ketrina Thompson. 🎨
+
+///
---
-Bu hikaye burgerler 🍔 için paralel.
+Bu paralel burger senaryosunda, ikiniz (sen ve aşkın) iki işlemcili bir bilgisayar / programsınız 🤖; ikiniz de uzun süre tezgâhta "bekleme" işine 🕙 dikkat ⏯ ayırıyorsunuz.
+
+Fast food dükkânında 8 işlemci var (kasiyer/aşçılar). Eşzamanlı burger dükkânında yalnızca 2 kişi olabilir (bir kasiyer ve bir aşçı).
+
+Ama yine de nihai deneyim pek iyi değil. 😞
-Bir gerçek hayat örneği verelim. Bir banka hayal edin.
+---
-Bankaların çoğunda birkaç kasiyer 👨💼👨💼👨💼👨💼 ve uzun bir sıra var 🕙🕙🕙🕙🕙🕙🕙🕙.
+Bu, burgerler için paralel karşılık gelen hikâye olurdu. 🍔
-Tüm işi sırayla bir müşteri ile yapan tüm kasiyerler 👨💼⏯.
+Daha "gerçek hayat" bir örnek için, bir banka hayal edin.
-Ve uzun süre kuyrukta beklemek 🕙 zorundasın yoksa sıranı kaybedersin.
+Yakın zamana kadar, bankaların çoğunda birden çok gişe memuru 👨💼👨💼👨💼👨💼 ve uzun bir sıra 🕙🕙🕙🕙🕙🕙🕙🕙 vardı.
-Muhtemelen ayak işlerı yaparken sevgilini 😍 bankaya 🏦 getirmezsin.
+Tüm gişe memurları bir müşteriyle tüm işi yapar, sonra sıradakiyle 👨💼⏯.
-### Burger Sonucu
+Ve sıranı kaybetmemek için uzun süre 🕙 kuyrukta beklemen gerekir.
-Bu "aşkınla fast food burgerleri" senaryosunda, çok fazla bekleme olduğu için 🕙, eşzamanlı bir sisteme sahip olmak çok daha mantıklı ⏸🔀⏯.
+Muhtemelen, bankada 🏦 işlerini hallederken aşkını 😍 yanında götürmek istemezsin.
-Web uygulamalarının çoğu için durum böyledir.
+### Burger Sonucu { #burger-conclusion }
-Pek çok kullanıcı var, ama sunucunuz pek de iyi olmayan bir bağlantı ile istek atmalarını bekliyor.
+"Fast food burgerleri ve aşkın" senaryosunda, çok fazla bekleme 🕙 olduğundan, eşzamanlı bir sistem ⏸🔀⏯ çok daha mantıklıdır.
-Ve sonra yanıtların geri gelmesi için tekrar 🕙 bekliyor
+Bu, çoğu web uygulaması için de geçerlidir.
-Bu "bekleme" 🕙 mikrosaniye cinsinden ölçülür, yine de, hepsini toplarsak çok fazla bekleme var.
+Çok fazla kullanıcı vardır; ancak sunucunuz, iyi olmayan bağlantılarından gelen istekleri 🕙 bekler.
-Bu nedenle, web API'leri için asenkron ⏸🔀⏯ kod kullanmak çok daha mantıklı.
+Ve sonra yanıtların geri gelmesini yine 🕙 bekler.
-Mevcut popüler Python frameworklerinin çoğu (Flask ve Django gibi), Python'daki yeni asenkron özellikler mevcut olmadan önce yazıldı. Bu nedenle, dağıtılma biçimleri paralel yürütmeyi ve yenisi kadar güçlü olmayan eski bir eşzamansız yürütme biçimini destekler.
+Bu "beklemeler" 🕙 mikrosaniyelerle ölçülür; ama hepsi toplandığında sonuçta oldukça fazla bekleme olur.
-Asenkron web (ASGI) özelliği, WebSockets için destek eklemek için Django'ya eklenmiş olsa da.
+Bu yüzden web API’leri için asenkron ⏸🔀⏯ kod kullanmak çok mantıklıdır.
-Asenkron çalışabilme NodeJS in popüler olmasının sebebi (paralel olamasa bile) ve Go dilini güçlü yapan özelliktir.
+Bu tür asenkronluk, NodeJS’i popüler yapan şeydir (NodeJS paralel olmasa bile) ve Go dilinin gücüdür.
-Ve bu **FastAPI** ile elde ettiğiniz performans düzeyiyle aynıdır.
+Ve **FastAPI** ile elde ettiğiniz performans seviyesi de budur.
-Aynı anda paralellik ve asenkronluğa sahip olabildiğiniz için, test edilen NodeJS çerçevelerinin çoğundan daha yüksek performans elde edersiniz ve C'ye daha yakın derlenmiş bir dil olan Go ile eşit bir performans elde edersiniz
(bütün teşekkürler Starlette'e ).
+Ayrıca, aynı anda hem paralellik hem de asenkronluk kullanabildiğiniz için, test edilen çoğu NodeJS framework’ünden daha yüksek ve C’ye daha yakın derlenen bir dil olan Go ile başa baş performans elde edersiniz
(hepsi Starlette sayesinde).
-### Eşzamanlılık paralellikten daha mı iyi?
+### Eşzamanlılık paralellikten daha mı iyi? { #is-concurrency-better-than-parallelism }
-Hayır! Hikayenin ahlakı bu değil.
+Hayır! Hikâyenin özü bu değil.
-Eşzamanlılık paralellikten farklıdır. Ve çok fazla bekleme içeren **belirli** senaryolarda daha iyidir. Bu nedenle, genellikle web uygulamaları için paralellikten çok daha iyidir. Ama her şey için değil.
+Eşzamanlılık paralellikten farklıdır. Ve çok fazla bekleme içeren **belirli** senaryolarda daha iyidir. Bu nedenle, genellikle web uygulaması geliştirme için paralellikten çok daha iyidir. Ama her şey için değil.
-Yanı, bunu aklınızda oturtmak için aşağıdaki kısa hikayeyi hayal edin:
+Bunu dengelemek için, şu kısa hikâyeyi hayal edin:
-> Büyük, kirli bir evi temizlemelisin.
+> Büyük, kirli bir evi temizlemen gerekiyor.
-*Evet, tüm hikaye bu*.
+*Evet, tüm hikâye bu kadar*.
---
-Beklemek yok 🕙. Hiçbir yerde. Sadece evin birden fazla yerinde yapılacak fazlasıyla iş var.
+Hiçbir yerde 🕙 bekleme yok; sadece evin birden fazla yerinde yapılacak çok iş var.
-You could have turns as in the burgers example, first the living room, then the kitchen, but as you are not waiting 🕙 for anything, just cleaning and cleaning, the turns wouldn't affect anything.
-Hamburger örneğindeki gibi dönüşleriniz olabilir, önce oturma odası, sonra mutfak, ama hiçbir şey için 🕙 beklemediğinizden, sadece temizlik, temizlik ve temizlik, dönüşler hiçbir şeyi etkilemez.
+Hamburger örneğindeki gibi dönüşlerle ilerleyebilirsin, önce salon, sonra mutfak; ama hiçbir şey 🕙 beklemediğin için, sadece temizlik yaptığından, dönüşlerin hiçbir etkisi olmaz.
-Sıralı veya sırasız (eşzamanlılık) bitirmek aynı zaman alır ve aynı miktarda işi yaparsınız.
+Dönüşlerle ya da dönüşsüz (eşzamanlılık) bitirmek aynı zaman alır ve aynı miktarda iş yapmış olursun.
-Ama bu durumda, 8 eski kasiyer/aşçı - yeni temizlikçiyi getirebilseydiniz 👩🍳👨🍳👩🍳👨🍳👩🍳👨🍳👩🍳👨🍳 ve her birini (artı siz) evin bir bölgesini temizlemek için görevlendirseydiniz, ekstra yardımla tüm işleri **paralel** olarak yapabilir ve çok daha erken bitirebilirdiniz.
+Ama bu durumda, 8 eski kasiyer/aşçı—yeni temizlikçiyi getirip her birine (artı sana) evin bir bölümünü versen, fazladan yardımla tüm işleri **paralel** yaparak çok daha çabuk bitirebilirdin.
-Bu senaryoda, temizlikçilerin her biri (siz dahil) birer işlemci olacak ve üzerine düşeni yapacaktır.
+Bu senaryoda, her bir temizlikçi (sen dâhil) birer işlemci olur ve kendi iş payını yapar.
-Yürütme süresinin çoğu (beklemek yerine) iş yapıldığından ve bilgisayardaki iş bir
CPU tarafından yapıldığından, bu sorunlara "CPU bound" diyorlar".
+Ve yürütme süresinin çoğu gerçek işten (bekleme yerine) oluştuğu ve bilgisayardaki işi bir
CPU yaptığı için, bu sorunlara "CPU bound" denir.
---
-CPU'ya bağlı işlemlerin yaygın örnekleri, karmaşık matematik işlemleri gerektiren işlerdir.
+CPU’ya bağlı işlemlerin yaygın örnekleri, karmaşık matematiksel işlem gerektiren iş yükleridir.
Örneğin:
* **Ses** veya **görüntü işleme**.
-* **Bilgisayar görüsü**: bir görüntü milyonlarca pikselden oluşur, her pikselin 3 değeri / rengi vardır, bu pikseller üzerinde aynı anda bir şeyler hesaplamayı gerektiren işleme.
-* **Makine Öğrenimi**: Çok sayıda "matris" ve "vektör" çarpımı gerektirir. Sayıları olan ve hepsini aynı anda çarpan büyük bir elektronik tablo düşünün.
-* **Derin Öğrenme**: Bu, Makine Öğreniminin bir alt alanıdır, dolayısıyla aynısı geçerlidir. Sadece çarpılacak tek bir sayı tablosu değil, büyük bir sayı kümesi vardır ve çoğu durumda bu modelleri oluşturmak ve/veya kullanmak için özel işlemciler kullanırsınız.
+* **Bilgisayar görüsü**: bir görüntü milyonlarca pikselden oluşur, her pikselin 3 değeri / rengi vardır; işleme genellikle bu pikseller üzerinde aynı anda bir şeyler hesaplamayı gerektirir.
+* **Makine Öğrenimi**: genellikle çok sayıda "matris" ve "vektör" çarpımı gerekir. Sayılar içeren devasa bir elektronik tabloyu ve hepsini aynı anda çarpmayı düşünün.
+* **Derin Öğrenme**: Makine Öğreniminin bir alt alanıdır, dolayısıyla aynısı geçerlidir. Sadece çarpılacak tek bir sayı tablosu değil, kocaman bir sayı kümesi vardır ve çoğu durumda bu modelleri kurmak ve/veya kullanmak için özel işlemciler kullanırsınız.
-### Eşzamanlılık + Paralellik: Web + Makine Öğrenimi
+### Eşzamanlılık + Paralellik: Web + Makine Öğrenimi { #concurrency-parallelism-web-machine-learning }
-**FastAPI** ile web geliştirme için çok yaygın olan eşzamanlılıktan yararlanabilirsiniz (NodeJS'in aynı çekiciliği).
+**FastAPI** ile web geliştirmede çok yaygın olan eşzamanlılıktan (NodeJS’in başlıca cazibesiyle aynı) yararlanabilirsiniz.
-Ancak, Makine Öğrenimi sistemlerindekile gibi **CPU'ya bağlı** iş yükleri için paralellik ve çoklu işlemenin (birden çok işlemin paralel olarak çalışması) avantajlarından da yararlanabilirsiniz.
+Ama ayrıca **CPU’ya bağlı** iş yükleri (Makine Öğrenimi sistemlerindeki gibi) için paralellik ve çoklu işlemden (paralel çalışan birden çok işlem) de yararlanabilirsiniz.
-Buna ek olarak Python'un **Veri Bilimi**, Makine Öğrenimi ve özellikle Derin Öğrenme için ana dil olduğu gerçeği, FastAPI'yi Veri Bilimi / Makine Öğrenimi web API'leri ve uygulamaları için çok iyi bir seçenek haline getirir.
+Buna ek olarak Python’un **Veri Bilimi**, Makine Öğrenimi ve özellikle Derin Öğrenme için ana dil olması, FastAPI’yi Veri Bilimi / Makine Öğrenimi web API’leri ve uygulamaları için çok iyi bir seçenek yapar.
-Production'da nasıl oldugunu görmek için şu bölüme bakın [Deployment](deployment/index.md){.internal-link target=_blank}.
+Production’da bu paralelliği nasıl sağlayacağınızı görmek için [Deployment](deployment/index.md){.internal-link target=_blank} bölümüne bakın.
-## `async` ve `await`
+## `async` ve `await` { #async-and-await }
-Python'un modern sürümleri, asenkron kodu tanımlamanın çok sezgisel bir yoluna sahiptir. Bu, normal "sequentıal" (sıralı) kod gibi görünmesini ve doğru anlarda sizin için "awaıt" ile bekleme yapmasını sağlar.
+Python’un modern sürümleri, asenkron kodu tanımlamak için oldukça sezgisel bir yol sunar. Bu sayede kod normal "sıralı" kod gibi görünür ve doğru anlarda sizin yerinize "beklemeyi" yapar.
-Sonuçları vermeden önce beklemeyi gerektirecek ve yeni Python özelliklerini destekleyen bir işlem olduğunda aşağıdaki gibi kodlayabilirsiniz:
+Sonuçları vermeden önce bekleme gerektiren ve bu yeni Python özelliklerini destekleyen bir işlem olduğunda, şöyle kodlayabilirsiniz:
```Python
burgers = await get_burgers(2)
```
-Buradaki `await` anahtari Python'a, sonuçları `burgers` degiskenine atamadan önce `get_burgers(2)` kodunun işini bitirmesini 🕙 beklemesi gerektiğini söyler. Bununla Python, bu ara zamanda başka bir şey 🔀 ⏯ yapabileceğini bilecektir (başka bir istek almak gibi).
+Buradaki kilit nokta `await`. Python’a, sonuçları `burgers` değişkenine koymadan önce `get_burgers(2)` çalışmasının bitmesini 🕙 beklemesi ⏸ gerektiğini söyler. Böylece Python, bu arada başka bir şey 🔀 ⏯ yapabileceğini bilir (ör. başka bir request almak gibi).
- `await`kodunun çalışması için, eşzamansızlığı destekleyen bir fonksiyonun içinde olması gerekir. Bunu da yapmak için fonksiyonu `async def` ile tanımlamamız yeterlidir:
+`await`’in çalışabilmesi için, bu asenkronluğu destekleyen bir fonksiyonun içinde olması gerekir. Bunu yapmak için fonksiyonu `async def` ile tanımlayın:
```Python hl_lines="1"
async def get_burgers(number: int):
- # burgerleri oluşturmak için asenkron birkaç iş
+ # Burgerleri yaratmak için bazı asenkron işler yap
return burgers
```
...`def` yerine:
```Python hl_lines="2"
-# bu kod asenkron değil
+# Bu asenkron değildir
def get_sequential_burgers(number: int):
- # burgerleri oluşturmak için senkron bırkaç iş
+ # Burgerleri yaratmak için bazı sıralı işler yap
return burgers
```
-`async def` ile Python, bu fonksıyonun içinde, `await` ifadelerinin farkında olması gerektiğini ve çalışma zamanı gelmeden önce bu işlevin yürütülmesini "duraklatabileceğini" ve başka bir şey yapabileceğini 🔀 bilir.
+`async def` ile Python, bu fonksiyonun içinde `await` ifadelerinin olabileceğini bilir ve bu fonksiyonun yürütülmesini "duraklatıp" ⏸ başka bir şey yapabileceğini 🔀, sonra geri dönebileceğini anlar.
-`async def` fonksiyonunu çağırmak istediğinizde, onu "awaıt" ıle kullanmanız gerekir. Yani, bu işe yaramaz:
+`async def` fonksiyonunu çağırmak istediğinizde, onu "await" etmeniz gerekir. Yani şu çalışmaz:
```Python
-# Bu işe yaramaz, çünkü get_burgers, şu şekilde tanımlandı: async def
+# Bu çalışmaz, çünkü get_burgers şöyle tanımlandı: async def
burgers = get_burgers(2)
```
---
-Bu nedenle, size onu `await` ile çağırabileceğinizi söyleyen bir kitaplık kullanıyorsanız, onu `async def` ile tanımlanan *path fonksiyonu* içerisinde kullanmanız gerekir, örneğin:
+Dolayısıyla, `await` ile çağrılabileceğini söyleyen bir kütüphane kullanıyorsanız, onu kullanan *path operasyon fonksiyonunu* `async def` ile oluşturmanız gerekir, örneğin:
```Python hl_lines="2-3"
@app.get('/burgers')
@@ -321,87 +349,96 @@ async def read_burgers():
return burgers
```
-### Daha fazla teknik detay
+### Daha teknik detaylar { #more-technical-details }
+
+`await`’in yalnızca `async def` ile tanımlanan fonksiyonların içinde kullanılabildiğini fark etmiş olabilirsiniz.
+
+Aynı zamanda, `async def` ile tanımlanan fonksiyonların da "await" edilmesi gerekir. Yani `async def` ile tanımlanan fonksiyonlar yalnızca `async def` ile tanımlanan fonksiyonların içinde çağrılabilir.
+
+Peki, tavuk-yumurta meselesi: ilk `async` fonksiyon nasıl çağrılır?
+
+**FastAPI** ile çalışıyorsanız bunu dert etmenize gerek yok; çünkü o "ilk" fonksiyon sizin *path operasyon fonksiyonunuz* olacaktır ve FastAPI doğru olanı yapmasını bilir.
-`await` in yalnızca `async def` ile tanımlanan fonksıyonların içinde kullanılabileceğini fark etmişsinizdir.
+Ama FastAPI olmadan da `async` / `await` kullanmak isterseniz, bunu da yapabilirsiniz.
-Ama aynı zamanda, `async def` ile tanımlanan fonksiyonların "await" ile beklenmesi gerekir. Bu nedenle, "`async def` içeren fonksiyonlar yalnızca "`async def` ile tanımlanan fonksiyonların içinde çağrılabilir.
+### Kendi async kodunuzu yazın { #write-your-own-async-code }
+Starlette (ve **FastAPI**)
AnyIO üzerine kuruludur; bu sayede Python standart kütüphanesindeki
asyncio ve
Trio ile uyumludur.
-Yani yumurta mı tavukdan, tavuk mu yumurtadan gibi ilk `async` fonksiyonu nasıl çağırılır?
+Özellikle, kendi kodunuzda daha gelişmiş desenler gerektiren ileri seviye eşzamanlılık kullanım senaryoları için doğrudan
AnyIO kullanabilirsiniz.
-**FastAPI** ile çalışıyorsanız bunun için endişelenmenize gerek yok, çünkü bu "ilk" fonksiyon sizin *path fonksiyonunuz* olacak ve FastAPI doğru olanı nasıl yapacağını bilecek.
+Hatta FastAPI kullanmıyor olsanız bile, yüksek uyumluluk ve avantajları (ör. *structured concurrency*) için
AnyIO ile kendi async uygulamalarınızı yazabilirsiniz.
-Ancak FastAPI olmadan `async` / `await` kullanmak istiyorsanız,
resmi Python belgelerini kontrol edin.
+AnyIO’nun üzerine, tür açıklamalarını biraz iyileştirmek ve daha iyi **otomatik tamamlama**, **satır içi hatalar** vb. elde etmek için ince bir katman olarak başka bir kütüphane daha oluşturdum. Ayrıca **kendi async kodunuzu** anlamanıza ve yazmanıza yardımcı olacak dostça bir giriş ve eğitim içerir:
Asyncer. Özellikle **async kodu normal** (bloklayan/senkron) **kodla birleştirmeniz** gerektiğinde faydalı olacaktır.
-### Asenkron kodun diğer biçimleri
+### Asenkron kodun diğer biçimleri { #other-forms-of-asynchronous-code }
-Bu `async` ve `await` kullanimi oldukça yenidir.
+`async` ve `await` kullanma tarzı, dilde nispeten yenidir.
-Ancak asenkron kodla çalışmayı çok daha kolay hale getirir.
+Ama asenkron kodla çalışmayı çok daha kolaylaştırır.
-Aynı sözdizimi (hemen hemen aynı) son zamanlarda JavaScript'in modern sürümlerine de dahil edildi (Tarayıcı ve NodeJS'de).
+Aynı (ya da neredeyse aynı) sözdizimi yakın zamanda modern JavaScript sürümlerine (Tarayıcı ve NodeJS) de eklendi.
-Ancak bundan önce, asenkron kodu işlemek oldukça karmaşık ve zordu.
+Bundan önce, asenkron kodu ele almak oldukça daha karmaşık ve zordu.
-Python'un önceki sürümlerinde, threadlerı veya
Gevent kullanıyor olabilirdin. Ancak kodu anlamak, hata ayıklamak ve düşünmek çok daha karmaşık olurdu.
+Python’un önceki sürümlerinde thread’ler veya
Gevent kullanabilirdiniz. Ama kodu anlamak, hata ayıklamak ve üzerine düşünmek çok daha zordu.
-NodeJS / Browser JavaScript'in önceki sürümlerinde, "callback" kullanırdınız. Bu da "callbacks cehennemine" yol açar.
+NodeJS / Tarayıcı JavaScript’in önceki sürümlerinde "callback" kullanırdınız. Bu da "callback cehennemi"ne yol açardı.
-## Coroutine'ler
+## Coroutine'ler { #coroutines }
-**Coroutine**, bir `async def` fonksiyonu tarafından döndürülen değer için çok süslü bir terimdir. Python bunun bir fonksiyon gibi bir noktada başlayıp biteceğini bilir, ancak içinde bir `await` olduğunda dahili olarak da duraklatılabilir ⏸.
+**Coroutine**, bir `async def` fonksiyonunun döndürdüğü şeye verilen süslü isimdir. Python bunun bir fonksiyona benzer bir şey olduğunu, bir noktada başlayıp biteceğini bilir; ama içinde bir `await` olduğunda dahili olarak duraklatılabileceğini ⏸ de bilir.
-Ancak, `async` ve `await` ile asenkron kod kullanmanın tüm bu işlevselliği, çoğu zaman "Coroutine" kullanmak olarak adlandırılır. Go'nun ana özelliği olan "Goroutines" ile karşılaştırılabilir.
+`async` ve `await` ile asenkron kod kullanmanın bu işlevselliği çoğu zaman "coroutine" kullanmak olarak özetlenir. Go’nun ana kilit özelliği olan "Goroutines" ile karşılaştırılabilir.
-## Sonuç
+## Sonuç { #conclusion }
-Aynı ifadeyi yukarıdan görelim:
+Yukarıdaki cümleyi tekrar görelim:
-> Python'ın modern sürümleri, **"async" ve "await"** sözdizimi ile birlikte **"coroutines"** adlı bir özelliği kullanan **"asenkron kod"** desteğine sahiptir.
+> Python’un modern sürümleri, **`async` ve `await`** sözdizimiyle, **"coroutines"** denilen bir yapıyı kullanarak **"asenkron kod"** desteğine sahiptir.
-Şimdi daha mantıklı gelmeli. ✨
+Artık daha anlamlı gelmeli. ✨
-FastAPI'ye (Starlette aracılığıyla) güç veren ve bu kadar etkileyici bir performansa sahip olmasını sağlayan şey budur.
+Bunların hepsi, FastAPI’ye (Starlette aracılığıyla) güç verir ve böylesine etkileyici bir performansa sahip olmasını sağlar.
-## Çok Teknik Detaylar
+## Çok Teknik Detaylar { #very-technical-details }
-/// warning
+/// warning | Uyarı
-Muhtemelen burayı atlayabilirsiniz.
+Büyük ihtimalle burayı atlayabilirsiniz.
-Bunlar, **FastAPI**'nin altta nasıl çalıştığına dair çok teknik ayrıntılardır.
+Bunlar, **FastAPI**’nin altında nasıl çalıştığına dair oldukça teknik ayrıntılardır.
-Biraz teknik bilginiz varsa (co-routines, threads, blocking, vb)ve FastAPI'nin "async def" ile normal "def" arasındaki farkı nasıl işlediğini merak ediyorsanız, devam edin.
+Coroutine’ler, thread’ler, blocking vb. hakkında teknik bilginiz varsa ve FastAPI’nin `async def` ile normal `def` arasındaki farkı nasıl ele aldığını merak ediyorsanız, devam edin.
///
-### Path fonksiyonu
+### Path Operasyon Fonksiyonları { #path-operation-functions }
-"async def" yerine normal "def" ile bir *yol işlem işlevi* bildirdiğinizde, doğrudan çağrılmak yerine (sunucuyu bloke edeceğinden) daha sonra beklenen harici bir iş parçacığı havuzunda çalıştırılır.
+Bir *path operasyon fonksiyonunu* `async def` yerine normal `def` ile tanımladığınızda, (sunucuyu bloklayacağından) doğrudan çağrılmak yerine, harici bir thread pool’da çalıştırılır ve ardından beklenir.
-Yukarıda açıklanan şekilde çalışmayan başka bir asenkron framework'den geliyorsanız ve küçük bir performans kazancı (yaklaşık 100 nanosaniye) için "def" ile *path fonksiyonu* tanımlamaya alışkınsanız, **FastAPI**'de tam tersi olacağını unutmayın. Bu durumlarda, *path fonksiyonu*
G/Ç engelleyen durum oluşturmadıkça "async def" kullanmak daha iyidir.
+Yukarıda açıklanan şekilde çalışmayan başka bir async framework’ten geliyorsanız ve ufak bir performans kazancı (yaklaşık 100 nanosaniye) için yalnızca hesaplama yapan basit *path operasyon fonksiyonlarını* düz `def` ile tanımlamaya alışkınsanız, **FastAPI**’de etkinin tam tersi olacağını unutmayın. Bu durumlarda, *path operasyon fonksiyonlarınız* bloklayan
I/O yapan kod kullanmadıkça `async def` kullanmak daha iyidir.
-Yine de, her iki durumda da, **FastAPI**'nin önceki frameworkden [hala daha hızlı](index.md#performans){.internal-link target=_blank} (veya en azından karşılaştırılabilir) olma olasılığı vardır.
+Yine de her iki durumda da, **FastAPI**’nin önceki framework’ünüzden [hala daha hızlı](index.md#performance){.internal-link target=_blank} (ya da en azından karşılaştırılabilir) olması muhtemeldir.
-### Bagımlılıklar
+### Bağımlılıklar { #dependencies }
-Aynısı bağımlılıklar için de geçerlidir. Bir bağımlılık, "async def" yerine standart bir "def" işleviyse, harici iş parçacığı havuzunda çalıştırılır.
+Aynısı [bağımlılıklar](tutorial/dependencies/index.md){.internal-link target=_blank} için de geçerlidir. Bir bağımlılık `async def` yerine standart bir `def` fonksiyonuysa, harici thread pool’da çalıştırılır.
-### Alt-bağımlıklar
+### Alt-bağımlılıklar { #sub-dependencies }
-Birbirini gerektiren (fonksiyonlarin parametreleri olarak) birden fazla bağımlılık ve alt bağımlılıklarınız olabilir, bazıları 'async def' ve bazıları normal 'def' ile oluşturulabilir. Yine de normal 'def' ile oluşturulanlar, "await" kulanilmadan harici bir iş parçacığında (iş parçacığı havuzundan) çağrılır.
+Birbirini gerektiren birden çok bağımlılık ve [alt-bağımlılık](tutorial/dependencies/sub-dependencies.md){.internal-link target=_blank} olabilir (fonksiyon tanımlarının parametreleri olarak). Bazıları `async def` ile, bazıları normal `def` ile oluşturulmuş olabilir. Yine de çalışır ve normal `def` ile oluşturulanlar "await" edilmek yerine harici bir thread’de (thread pool’dan) çağrılır.
-### Diğer yardımcı fonksiyonlar
+### Diğer yardımcı fonksiyonlar { #other-utility-functions }
-Doğrudan çağırdığınız diğer herhangi bir yardımcı fonksiyonu, normal "def" veya "async def" ile tanimlayabilirsiniz. FastAPI onu çağırma şeklinizi etkilemez.
+Doğrudan çağırdığınız diğer yardımcı fonksiyonları normal `def` veya `async def` ile tanımlayabilirsiniz ve FastAPI onları çağırma biçiminizi etkilemez.
-Bu, FastAPI'nin sizin için çağırdığı fonksiyonlarin tam tersidir: *path fonksiyonu* ve bağımlılıklar.
+Bu, FastAPI’nin sizin için çağırdığı fonksiyonların tersidir: *path operasyon fonksiyonları* ve bağımlılıklar.
-Yardımcı program fonksiyonunuz 'def' ile normal bir işlevse, bir iş parçacığı havuzunda değil doğrudan (kodunuzda yazdığınız gibi) çağrılır, işlev 'async def' ile oluşturulmuşsa çağırıldığı yerde 'await' ile beklemelisiniz.
+Yardımcı fonksiyonunuz `def` ile tanımlı normal bir fonksiyonsa, bir thread pool’da değil doğrudan (kodunuzda yazdığınız gibi) çağrılır; fonksiyon `async def` ile tanımlıysa kodunuzda çağırırken onu `await` etmelisiniz.
---
-Yeniden, bunlar, onları aramaya geldiğinizde muhtemelen işinize yarayacak çok teknik ayrıntılardır.
+Yine, bunlar muhtemelen özellikle aradığınızda işinize yarayacak çok teknik ayrıntılardır.
-Aksi takdirde, yukarıdaki bölümdeki yönergeleri iyi bilmelisiniz:
Aceleniz mi var?.
+Aksi hâlde, yukarıdaki bölümdeki yönergeler yeterlidir:
Aceleniz mi var?.
diff --git a/docs/tr/docs/deployment/concepts.md b/docs/tr/docs/deployment/concepts.md
index d0f5681469..f5ee988c9a 100644
--- a/docs/tr/docs/deployment/concepts.md
+++ b/docs/tr/docs/deployment/concepts.md
@@ -13,7 +13,7 @@ Bir **FastAPI** uygulamasını (hatta genel olarak herhangi bir web API'yi) depl
Bunların **deployment**'ları nasıl etkilediğine bakalım.
-Nihai hedef, **API client**'larınıza **güvenli** bir şekilde hizmet verebilmek, **kesintileri** önlemek ve **hesaplama kaynaklarını** (ör. uzak server'lar/sanal makineler) olabildiğince verimli kullanmaktır.
+Nihai hedef, **API client**'larınıza **güvenli** bir şekilde hizmet verebilmek, **kesintileri** önlemek ve **hesaplama kaynaklarını** (ör. uzak server'lar/sanal makineler) olabildiğince verimli kullanmaktır. 🚀
Burada bu **kavramlar** hakkında biraz daha bilgi vereceğim. Böylece, çok farklı ortamlarda—hatta bugün var olmayan **gelecekteki** ortamlarda bile—API'nizi nasıl deploy edeceğinize karar verirken ihtiyaç duyacağınız **sezgiyi** kazanmış olursunuz.
@@ -21,7 +21,7 @@ Bu kavramları dikkate alarak, **kendi API**'leriniz için en iyi deployment yak
Sonraki bölümlerde, FastAPI uygulamalarını deploy etmek için daha **somut tarifler** (recipes) paylaşacağım.
-Ama şimdilik, bu önemli **kavramsal fikirleri** inceleyelim. Bu kavramlar diğer tüm web API türleri için de geçerlidir.
+Ama şimdilik, bu önemli **kavramsal fikirleri** inceleyelim. Bu kavramlar diğer tüm web API türleri için de geçerlidir. 💡
## Güvenlik - HTTPS { #security-https }
@@ -36,16 +36,16 @@ Ve **HTTPS sertifikalarını yenilemekten** sorumlu bir şey olmalıdır; bu ayn
TLS Termination Proxy olarak kullanabileceğiniz bazı araçlar:
* Traefik
- * Sertifika yenilemelerini otomatik yönetir
+ * Sertifika yenilemelerini otomatik yönetir ✨
* Caddy
- * Sertifika yenilemelerini otomatik yönetir
+ * Sertifika yenilemelerini otomatik yönetir ✨
* Nginx
* Sertifika yenilemeleri için Certbot gibi harici bir bileşenle
* HAProxy
* Sertifika yenilemeleri için Certbot gibi harici bir bileşenle
* Nginx gibi bir Ingress Controller ile Kubernetes
* Sertifika yenilemeleri için cert-manager gibi harici bir bileşenle
-* Bir cloud provider tarafından servislerinin parçası olarak içeride yönetilmesi (aşağıyı okuyun)
+* Bir cloud provider tarafından servislerinin parçası olarak içeride yönetilmesi (aşağıyı okuyun 👇)
Bir diğer seçenek de, HTTPS kurulumunu da dahil olmak üzere işin daha büyük kısmını yapan bir **cloud service** kullanmaktır. Bunun bazı kısıtları olabilir veya daha pahalı olabilir vb. Ancak bu durumda TLS Termination Proxy'yi kendiniz kurmak zorunda kalmazsınız.
@@ -100,7 +100,7 @@ Bu yöntem çalışır ve **geliştirme sırasında** faydalıdır.
Ancak server'a olan bağlantınız koparsa, **çalışan process** muhtemelen ölür.
-Ve server yeniden başlatılırsa (örneğin update'lerden sonra ya da cloud provider'ın migration'larından sonra) bunu muhtemelen **fark etmezsiniz**. Dolayısıyla process'i manuel yeniden başlatmanız gerektiğini de bilmezsiniz. Sonuçta API'niz ölü kalır.
+Ve server yeniden başlatılırsa (örneğin update'lerden sonra ya da cloud provider'ın migration'larından sonra) bunu muhtemelen **fark etmezsiniz**. Dolayısıyla process'i manuel yeniden başlatmanız gerektiğini de bilmezsiniz. Sonuçta API'niz ölü kalır. 😱
### Startup'ta Otomatik Çalıştırma { #run-automatically-on-startup }
@@ -131,19 +131,19 @@ Uygulamanızın startup'ta çalıştığından emin olmaya benzer şekilde, hata
### Hata Yaparız { #we-make-mistakes }
-Biz insanlar sürekli **hata** yaparız. Yazılımın neredeyse *her zaman* farklı yerlerinde gizli **bug**'lar vardır.
+Biz insanlar sürekli **hata** yaparız. Yazılımın neredeyse *her zaman* farklı yerlerinde gizli **bug**'lar vardır. 🐛
-Ve biz geliştiriciler bu bug'ları buldukça ve yeni özellikler ekledikçe code'u iyileştiririz (muhtemelen yeni bug'lar da ekleyerek).
+Ve biz geliştiriciler bu bug'ları buldukça ve yeni özellikler ekledikçe code'u iyileştiririz (muhtemelen yeni bug'lar da ekleyerek 😅).
### Küçük Hatalar Otomatik Yönetilir { #small-errors-automatically-handled }
-FastAPI ile web API geliştirirken, code'umuzda bir hata olursa FastAPI genellikle bunu hatayı tetikleyen tek request ile sınırlar.
+FastAPI ile web API geliştirirken, code'umuzda bir hata olursa FastAPI genellikle bunu hatayı tetikleyen tek request ile sınırlar. 🛡
Client o request için **500 Internal Server Error** alır; ancak uygulama tamamen çöküp durmak yerine sonraki request'ler için çalışmaya devam eder.
### Daha Büyük Hatalar - Çökmeler { #bigger-errors-crashes }
-Yine de bazı durumlarda, yazdığımız bir code **tüm uygulamayı çökertip** Uvicorn ve Python'ın crash olmasına neden olabilir.
+Yine de bazı durumlarda, yazdığımız bir code **tüm uygulamayı çökertip** Uvicorn ve Python'ın crash olmasına neden olabilir. 💥
Böyle bir durumda, tek bir noktadaki hata yüzünden uygulamanın ölü kalmasını istemezsiniz; bozuk olmayan *path operations* en azından çalışmaya devam etsin istersiniz.
@@ -206,7 +206,7 @@ Ve birden fazla process normalde **belleği paylaşmaz**. Yani her çalışan pr
Örneğin code'unuz **1 GB** boyutunda bir Machine Learning modelini yüklüyorsa, API'niz tek process ile çalışırken en az 1 GB RAM tüketir. **4 process** (4 worker) başlatırsanız her biri 1 GB RAM tüketir. Yani toplamda API'niz **4 GB RAM** tüketir.
-Uzak server'ınız veya sanal makineniz yalnızca 3 GB RAM'e sahipse, 4 GB'tan fazla RAM yüklemeye çalışmak sorun çıkarır.
+Uzak server'ınız veya sanal makineniz yalnızca 3 GB RAM'e sahipse, 4 GB'tan fazla RAM yüklemeye çalışmak sorun çıkarır. 🚨
### Birden Fazla Process - Bir Örnek { #multiple-processes-an-example }
@@ -265,7 +265,7 @@ Elbette bazı durumlarda ön adımları birden fazla kez çalıştırmak sorun d
Ayrıca, kurulumunuza bağlı olarak bazı durumlarda uygulamanızı başlatmadan önce **hiç ön adıma ihtiyaç duymayabilirsiniz**.
-Bu durumda bunların hiçbirini düşünmeniz gerekmez.
+Bu durumda bunların hiçbirini düşünmeniz gerekmez. 🤷
///
@@ -291,7 +291,7 @@ Server(lar)ınız bir **kaynaktır**. Programlarınızla CPU'lardaki hesaplama z
Sistem kaynaklarının ne kadarını tüketmek/kullanmak istersiniz? "Az" demek kolaydır; ancak pratikte hedef genellikle **çökmeden mümkün olduğunca fazla** kullanmaktır.
-3 server için para ödüyor ama onların RAM ve CPU'sunun yalnızca küçük bir kısmını kullanıyorsanız, muhtemelen **para israf ediyorsunuz** ve muhtemelen **elektrik tüketimini** de gereksiz yere artırıyorsunuz vb.
+3 server için para ödüyor ama onların RAM ve CPU'sunun yalnızca küçük bir kısmını kullanıyorsanız, muhtemelen **para israf ediyorsunuz** 💸 ve muhtemelen **elektrik tüketimini** de gereksiz yere artırıyorsunuz 🌎 vb.
Bu durumda 2 server ile devam edip onların kaynaklarını (CPU, bellek, disk, ağ bant genişliği vb.) daha yüksek oranlarda kullanmak daha iyi olabilir.
@@ -316,6 +316,6 @@ Uygulamanızı nasıl deploy edeceğinize karar verirken aklınızda tutmanız g
* Bellek
* Başlatmadan önceki adımlar
-Bu fikirleri ve nasıl uygulayacağınızı anlamak, deployment'larınızı yapılandırırken ve ince ayar yaparken ihtiyaç duyacağınız sezgiyi kazanmanızı sağlamalıdır.
+Bu fikirleri ve nasıl uygulayacağınızı anlamak, deployment'larınızı yapılandırırken ve ince ayar yaparken ihtiyaç duyacağınız sezgiyi kazanmanızı sağlamalıdır. 🤓
-Sonraki bölümlerde, izleyebileceğiniz stratejilere dair daha somut örnekler paylaşacağım.
+Sonraki bölümlerde, izleyebileceğiniz stratejilere dair daha somut örnekler paylaşacağım. 🚀
diff --git a/docs/tr/docs/deployment/docker.md b/docs/tr/docs/deployment/docker.md
index 6c8f74c778..6d38a2ce13 100644
--- a/docs/tr/docs/deployment/docker.md
+++ b/docs/tr/docs/deployment/docker.md
@@ -14,7 +14,7 @@ Aceleniz var ve bunları zaten biliyor musunuz? Aşağıdaki [`Dockerfile`'a atl
Dockerfile Önizleme 👀
```Dockerfile
-FROM python:3.9
+FROM python:3.14
WORKDIR /code
@@ -166,7 +166,7 @@ def read_item(item_id: int, q: str | None = None):
```{ .dockerfile .annotate }
# (1)!
-FROM python:3.9
+FROM python:3.14
# (2)!
WORKDIR /code
@@ -390,7 +390,7 @@ FastAPI uygulamanız tek bir dosyaysa; örneğin `./app` dizini olmadan sadece `
Bu durumda `Dockerfile` içinde dosyayı kopyaladığınız path'leri buna göre değiştirmeniz yeterlidir:
```{ .dockerfile .annotate hl_lines="10 13" }
-FROM python:3.9
+FROM python:3.14
WORKDIR /code
@@ -454,7 +454,7 @@ Container kullanmadan, uygulamaları startup'ta çalıştırmak ve restart mekan
## Replication - Process Sayısı { #replication-number-of-processes }
-Kubernetes, Docker Swarm Mode, Nomad veya benzeri, birden fazla makinede dağıtık container'ları yöneten karmaşık bir sistemle kurulmuş bir
cluster'ınız varsa, replication'ı her container içinde bir **process manager** (ör. worker'lı Uvicorn) kullanarak yönetmek yerine, muhtemelen **cluster seviyesinde** ele almak istersiniz.
+Eğer bir
küme (cluster) olarak yapılandırılmış makineler grubunuz varsa ve bunları **Kubernetes**, Docker Swarm Mode, Nomad veya benzeri, birden çok makinede dağıtık container'ları yöneten karmaşık bir sistemle yönetiyorsanız, replication'ı her container içinde bir **process manager** (ör. worker'lı Uvicorn) kullanarak yönetmek yerine, muhtemelen **küme seviyesinde (cluster level)** ele almak istersiniz.
Kubernetes gibi dağıtık container yönetim sistemleri, gelen request'ler için **load balancing** desteği sunarken aynı zamanda **container replication**'ını yönetmek için entegre mekanizmalara sahiptir. Hepsi **cluster seviyesinde**.
@@ -499,7 +499,7 @@ Elbette bazı **özel durumlarda** bir container içinde birden fazla **Uvicorn
Bu durumlarda çalıştırmak istediğiniz worker sayısını `--workers` komut satırı seçeneğiyle ayarlayabilirsiniz:
```{ .dockerfile .annotate }
-FROM python:3.9
+FROM python:3.14
WORKDIR /code
diff --git a/docs/tr/docs/deployment/https.md b/docs/tr/docs/deployment/https.md
index bb70883aa7..de9716520e 100644
--- a/docs/tr/docs/deployment/https.md
+++ b/docs/tr/docs/deployment/https.md
@@ -65,7 +65,7 @@ Burada, bir HTTPS API’nin adım adım nasıl görünebileceğine dair, özelli
Muhtemelen her şey, bir **domain adı** **temin etmenizle** başlar. Sonra bunu bir DNS server’ında (muhtemelen aynı cloud provider’ınızda) yapılandırırsınız.
-Muhtemelen bir cloud server (virtual machine) ya da benzeri bir şey alırsınız ve bunun
fixed bir **public IP adresi** olur.
+Muhtemelen bir cloud server (virtual machine) ya da benzeri bir şey alırsınız ve bunun
sabit bir **public IP adresi** olur.
DNS server(lar)ında, bir kaydı ("`A record`") **domain**’inizi server’ınızın **public IP adresine** yönlendirecek şekilde yapılandırırsınız.
diff --git a/docs/tr/docs/deployment/index.md b/docs/tr/docs/deployment/index.md
index 055d999294..c9efcef991 100644
--- a/docs/tr/docs/deployment/index.md
+++ b/docs/tr/docs/deployment/index.md
@@ -1,8 +1,8 @@
-# Deployment { #deployment }
+# Dağıtım { #deployment }
**FastAPI** uygulamasını deploy etmek nispeten kolaydır.
-## Deployment Ne Anlama Gelir? { #what-does-deployment-mean }
+## Dağıtım Ne Anlama Gelir? { #what-does-deployment-mean }
Bir uygulamayı **deploy** etmek, onu **kullanıcılara erişilebilir hale getirmek** için gerekli adımları gerçekleştirmek anlamına gelir.
@@ -10,7 +10,7 @@ Bir **web API** için bu süreç normalde uygulamayı **uzak bir makineye** yerl
Bu, kodu sürekli olarak değiştirdiğiniz, bozup düzelttiğiniz, geliştirme sunucusunu durdurup yeniden başlattığınız vb. **geliştirme** aşamalarının tam tersidir.
-## Deployment Stratejileri { #deployment-strategies }
+## Dağıtım Stratejileri { #deployment-strategies }
Kullanım durumunuza ve kullandığınız araçlara bağlı olarak bunu yapmanın birkaç yolu vardır.
diff --git a/docs/tr/docs/deployment/manually.md b/docs/tr/docs/deployment/manually.md
index 561ba86772..8c7fd990e7 100644
--- a/docs/tr/docs/deployment/manually.md
+++ b/docs/tr/docs/deployment/manually.md
@@ -46,7 +46,7 @@ Bu, çoğu durumda işinizi görür. 😎
Şimdi biraz daha detaya inelim.
-FastAPI, Python web framework'leri ve sunucularını inşa etmek için kullanılan
ASGI adlı bir standardı kullanır. FastAPI bir ASGI web framework'üdür.
+FastAPI, Python web framework'leri ve sunucularını inşa etmek için kullanılan
ASGI adlı bir standardı kullanır. FastAPI bir ASGI web framework'üdür.
Uzak bir sunucu makinesinde **FastAPI** uygulamasını (veya herhangi bir ASGI uygulamasını) çalıştırmak için gereken ana şey, **Uvicorn** gibi bir ASGI server programıdır. `fastapi` komutuyla varsayılan olarak gelen de budur.
@@ -74,7 +74,7 @@ FastAPI'yi kurduğunuzda, production sunucusu olarak Uvicorn da beraberinde geli
Ancak bir ASGI server'ı manuel olarak da kurabilirsiniz.
-Bir [virtual environment](../virtual-environments.md){.internal-link target=_blank} oluşturduğunuzdan, etkinleştirdiğinizden emin olun; ardından server uygulamasını kurabilirsiniz.
+Bir [sanal ortam](../virtual-environments.md){.internal-link target=_blank} oluşturduğunuzdan, etkinleştirdiğinizden emin olun; ardından server uygulamasını kurabilirsiniz.
Örneğin Uvicorn'u kurmak için:
diff --git a/docs/tr/docs/environment-variables.md b/docs/tr/docs/environment-variables.md
index e4f769a16e..8b546c77a7 100644
--- a/docs/tr/docs/environment-variables.md
+++ b/docs/tr/docs/environment-variables.md
@@ -153,7 +153,7 @@ Hello World from Python
/// tip | İpucu
-Bu konuyla ilgili daha fazlasını
The Twelve-Factor App: Config bölümünde okuyabilirsiniz.
+Bu konuyla ilgili daha fazlasını
Twelve-Factor Uygulaması: Config bölümünde okuyabilirsiniz.
///
@@ -291,7 +291,7 @@ Bu bilgiler, [Virtual Environments](virtual-environments.md){.internal-link targ
Buraya kadar **ortam değişkenleri**nin ne olduğuna ve Python’da nasıl kullanılacağına dair temel bir fikir edinmiş olmalısınız.
-Ayrıca
Wikipedia for Environment Variable sayfasından daha fazlasını da okuyabilirsiniz.
+Ayrıca
Ortam Değişkeni için Wikipedia sayfasından daha fazlasını da okuyabilirsiniz.
Çoğu zaman ortam değişkenlerinin hemen nasıl işe yarayacağı ilk bakışta çok net olmayabilir. Ancak geliştirme yaparken birçok farklı senaryoda tekrar tekrar karşınıza çıkarlar; bu yüzden bunları bilmek faydalıdır.
diff --git a/docs/tr/docs/features.md b/docs/tr/docs/features.md
index 86085c5e93..5c651e4917 100644
--- a/docs/tr/docs/features.md
+++ b/docs/tr/docs/features.md
@@ -1,59 +1,55 @@
-# Özelikler
+# Özellikler { #features }
-## FastAPI özellikleri
+## FastAPI Özellikleri { #fastapi-features }
-**FastAPI** sana bunları sağlıyor
+**FastAPI** size şunları sağlar:
-### Açık standartları temel alır
+### Açık Standartlara Dayalı { #based-on-open-standards }
-* API oluşturma işlemlerinde
OpenAPI buna
path operasyonları parametreleri, body talebi, güvenlik gibi şeyler dahil olmak üzere deklare bunların deklare edilmesi.
-* Otomatik olarak data modelinin
JSON Schema ile beraber dokümante edilmesi (OpenAPI'n kendisi zaten JSON Schema'ya dayanıyor).
-* Titiz bir çalışmanın sonucunda yukarıdaki standartlara uygun bir framework oluşturduk. Standartları pastanın üzerine sonradan eklenmiş bir çilek olarak görmedik.
-* Ayrıca bu bir çok dilde kullanılabilecek **client code generator** kullanımına da izin veriyor.
+* API oluşturmada
OpenAPI, buna
path operasyonları, parametreler, request body'leri, güvenlik vb. deklarasyonları dahildir.
+*
JSON Schema ile otomatik veri modeli dokümantasyonu (OpenAPI zaten JSON Schema'ya dayanır).
+* Bu standartlar etrafında, titiz bir çalışmanın ardından tasarlandı; sonradan eklenmiş bir katman değil.
+* Bu sayede birçok dilde otomatik **client code generation** da kullanılabilir.
-### Otomatik dokümantasyon
+### Otomatik Dokümantasyon { #automatic-docs }
+Etkileşimli API dokümantasyonu ve keşif için web arayüzleri. Framework OpenAPI’ye dayandığından, birden fazla seçenek vardır; varsayılan olarak 2’si dahildir.
-OpenAPI standartlarına dayalı olan bir framework olarak, geliştiricilerin birden çok seçeneği var, varsayılan olarak gelen 2 farklı interaktif API dokümantasyonu ve web kullanıcı arayüzü var.
-
-
-*
Swagger UI interaktif olarak API'ınızı tarayıcı üzerinden çağırıp test edebilmenize olanak sağlıyor.
+*
Swagger UI ile etkileşimli keşif; API’nizi tarayıcıdan doğrudan çağırıp test edin.

-*
ReDoc ile beraber alternatif API dokümantasyonu.
+*
ReDoc ile alternatif API dokümantasyonu.

-### Sadece modern Python
+### Sadece Modern Python { #just-modern-python }
-Tamamiyle standartlar **Python 3.8**'nın type hintlerine dayanıyor (Pydantic'in sayesinde). Yeni bir syntax öğrenmene gerek yok. Sadece modern Python.
+Her şey standart **Python type** deklarasyonlarına dayanır (Pydantic sayesinde). Öğrenilecek yeni bir söz dizimi yok. Sadece standart, modern Python.
+Python type’larını nasıl kullanacağınıza dair 2 dakikalık bir hatırlatmaya ihtiyacınız varsa (FastAPI kullanmasanız bile) kısa eğitime göz atın: [Python Types](python-types.md){.internal-link target=_blank}.
-Eğer Python type hintlerini bilmiyorsan veya bir hatırlatmaya ihtiyacın var ise(FastAPI kullanmasan bile) şu iki dakikalık küçük bilgilendirici içeriğe bir göz at: [Python Types](python-types.md){.internal-link target=_blank}.
-
-Standart Python'u typelarını belirterek yazıyorsun:
+Türleriyle standart Python yazarsınız:
```Python
-from typing import List, Dict
from datetime import date
from pydantic import BaseModel
-# Değişkeni str olarak belirt
-# ve o fonksiyon için harika bir editör desteği al
+# Bir değişkeni str olarak belirt
+# ve fonksiyon içinde editör desteği al
def main(user_id: str):
return user_id
-# Pydantic modeli
+# Bir Pydantic modeli
class User(BaseModel):
id: int
name: str
joined: date
```
-Sonrasında bu şekilde kullanabilirsin
+Sonra şöyle kullanabilirsiniz:
```Python
my_user: User = User(id=3, name="John Doe", joined="2018-07-19")
@@ -67,25 +63,26 @@ second_user_data = {
my_second_user: User = User(**second_user_data)
```
+
/// info
-`**second_user_data` şu anlama geliyor:
+`**second_user_data` şu anlama gelir:
-Key-Value çiftini direkt olarak `second_user_data` dictionarysine kaydet , yaptığın şey buna eşit olacak: `User(id=4, name="Mary", joined="2018-11-30")`
+`second_user_data` dict’indeki anahtar ve değerleri doğrudan anahtar-değer argümanları olarak geç; şu ifadeye eşdeğerdir: `User(id=4, name="Mary", joined="2018-11-30")`
///
-### Editor desteği
+### Editör Desteği { #editor-support }
-Bütün framework kullanılması kolay ve sezgileri güçlü olması için tasarlandı, verilen bütün kararlar geliştiricilere en iyi geliştirme deneyimini yaşatmak üzere, bir çok editör üzerinde test edildi.
+Tüm framework, kullanımı kolay ve sezgisel olacak şekilde tasarlandı; en iyi geliştirme deneyimini sağlamak için geliştirmeye başlamadan önce bile alınan kararlar birden çok editörde test edildi.
-Son yapılan Python geliştiricileri anketinde, açık ara
en çok kullanılan özellik "oto-tamamlama" idi..
+Python geliştirici anketlerinde açıkça görülüyor ki
en çok kullanılan özelliklerden biri "otomatik tamamlama".
-Bütün **FastAPI** frameworkü oto-tamamlama açısından geliştiriciyi tatmin etmek üzerine tasarlandı. Otomatik tamamlama her yerde çalışıyor.
+Tüm **FastAPI** bunun tatmin edilmesi üzerine kuruldu. Otomatik tamamlama her yerde çalışır.
-Dokümantasyona tekrardan çok nadir olarak geleceksin.
+Dokümana geri dönmeniz nadiren gerekecek.
-Editörün sana nasıl yardım ettiğine bir bak:
+Editörünüz şöyle yardımcı olabilir:
*
Visual Studio Code ile:
@@ -95,115 +92,111 @@ Editörün sana nasıl yardım ettiğine bir bak:

+Daha önce imkânsız olduğunu düşünebileceğiniz yerlerde bile tamamlama alırsınız. Örneğin, bir request’ten gelen (iç içe de olabilir) JSON body içindeki `price` anahtarı için.
-Daha önceden düşünüp en imkansız diyebileceğin durumlarda bile otomatik tamamlama alacaksın, örnek olarak `price` JSON body içerisinde (nested bir JSON body de olabilirdi.) direkt olarak istekten geliyor, bu durumda bile oto-tammalama sağlıyor.
+Artık anahtar adlarını yanlış yazmak, dokümana gidip gelmek ya da sonunda `username` mi `user_name` mi kullandığınızı bulmak için sayfayı yukarı aşağı kaydırmak yok.
-Artık key isimlerini yanlış yazma, dokümantasyona dönüp deliler gibi yukarı aşağı sayfada gezmek ve en sonunda `username` mi yoksa `user_name` mi kullandım gibi sorular yok.
+### Kısa { #short }
-### Kısa
+Her şey için mantıklı **varsayılanlar** ve her yerde isteğe bağlı yapılandırmalar vardır. Tüm parametreler, ihtiyacınızı karşılayacak şekilde ince ayar yapılarak tanımlamak istediğiniz API’yi oluşturabilir.
-Her şey için mantıklı bir **varsayılanı** var. Parametrelerini opsiyonel olarak tanımlayıp API'nı istediğin gibi modifiye edebilirsin.
+Ancak varsayılan hâliyle hepsi **“hemen çalışır”**.
-Hepsi varsayılan olarak **çalışıyor**.
+### Doğrulama { #validation }
+* Çoğu (veya hepsi?) Python **veri tipi** için doğrulama, şunlar dâhil:
+ * JSON nesneleri (`dict`).
+ * Eleman tipleri tanımlanan JSON dizileri (`list`).
+ * Minimum ve maksimum uzunlukları tanımlanan String (`str`) alanları.
+ * Min ve max değerleri olan sayılar (`int`, `float`) vb.
-### Doğrulama
-
-* Neredeyse bütün (ya da hepsi?) Python **data typeları** için doğrulama, kapsadıkları:
- * JSON objeleri (`dict`).
- * JSON array (`list`) item type'ı belirtirken.
- * String (`str`) parametresi, minimum ve maksimum uzunluk gibi sınırlandırmalar yaparken.
- * Numaralar (`int`, `float`) maksimum ve minimum gibi sınırlandırmalar yaparken.
-
-* Bunlar gibi en egzotik typelarla bile doğrulama yapabiliyorsunuz.:
+* Daha “egzotik” tipler için doğrulama:
* URL.
* Email.
* UUID.
* ...ve diğerleri.
-Bütün doğrulama olayları çok güçlü bir kütüphane sayesinde yapılıyor, **Pydantic**.
+Tüm doğrulama köklü ve sağlam **Pydantic** tarafından yapılır.
-### Güvenlik ve kimlik doğrulama
+### Güvenlik ve Kimlik Doğrulama { #security-and-authentication }
-Güvenlik ve doğrulama database ve data modellerinden taviz vermeden entegre edilebilir durumda.
+Güvenlik ve kimlik doğrulama entegredir. Veritabanları veya veri modelleriyle ilgili hiçbir taviz yoktur.
-Bütün güvenlik şemaları OpenAPI'da tanımlanmış durumda, kapsadıkları:
+OpenAPI’da tanımlanan tüm güvenlik şemaları, şunlar dâhil:
* HTTP Basic.
-* **OAuth2** (ve **JWT tokenleriyle** beraber). Bu öğretici içeriğe göz atabilirsin [OAuth2 with JWT](tutorial/security/oauth2-jwt.md){.internal-link target=_blank}.
+* **OAuth2** (ayrıca **JWT token**’larla). Şu eğitime göz atın: [OAuth2 with JWT](tutorial/security/oauth2-jwt.md){.internal-link target=_blank}.
* API anahtarları:
- * Headerlar.
- * Query parametreleri.
- * Cookies, vs.
-
-Bütün güvenlik özellikleri Starlette'den geliyor (**session cookies'de** dahil olmak üzere).
+ * Header’larda.
+ * Query parametrelerinde.
+ * Cookie’lerde vb.
-Bütün hepsi tekrardan kullanılabilir aletler ve bileşenler olarak, kolayca sistemlerinize, data depolarınıza, ilişkisel ve NoSQL databaselerinize entegre edebileceğiniz şekilde yapıldı.
+Buna ek olarak Starlette’in tüm güvenlik özellikleri (**session cookies** dâhil).
-### Dependency injection
+Tümü, sistemleriniz, veri depolarınız, ilişkisel ve NoSQL veritabanlarınız vb. ile kolayca entegre edilebilen, yeniden kullanılabilir araçlar ve bileşenler olarak inşa edilmiştir.
-FastAPI'ın inanılmaz derecede kullanımı kolay, fakat inanılmaz derecede güçlü
Dependency Injection sistemi var.
+### Dependency Injection { #dependency-injection }
-* Dependencylerin bile dependencies'i olabiliyor, FastAPI bunun için **graph of "dependency"** yaratıyor.
-* Hepsi **otomatik olarak** FastAPI tarafından hallediliyor.
-* Bütün zorunlulukların gelen datalara bağlı olarak farklı gereksinimleri olabiliyor, ilave path operasyonlarının kısıtlamaları ve otomatik dokümantasyonu da ayrıca yapılıyor .
-* Path operasyonu parametreleri içerisinde belirtilen gereksinimler için bile **Otomatik doğrulama** yapılabiliyor.
-* Kompleks kimlik doğrulama sistemleri için destek, **database bağlantıları**, vs.
-* **Taviz yok** hiçbir şeyden taviz vermeden, database frontend vs. Bütün hepsinin kolayca entegre edilebiliyor.
+FastAPI, son derece kolay kullanımlı ama son derece güçlü bir
Dependency Injection sistemine sahiptir.
-### Sınırsız "plug-inler"
+* Bağımlılıkların da kendi bağımlılıkları olabilir; böylece bir hiyerarşi veya **bağımlılıklar "grafı"** oluşur.
+* Tüm süreç framework tarafından **otomatik olarak yönetilir**.
+* Tüm bağımlılıklar, request’lerden veri talep edebilir ve *path operation* kısıtlarını ve otomatik dokümantasyonu **zenginleştirebilir**.
+* Bağımlılıklarda tanımlanan *path operation* parametreleri için bile **otomatik doğrulama**.
+* Karmaşık kullanıcı kimlik doğrulama sistemleri, **veritabanı bağlantıları** vb. için destek.
+* Veritabanları, frontend’ler vb. ile **taviz yok**; ancak hepsiyle kolay entegrasyon.
-Başka bir deyişle, plug-inlere ihtiyacımız yok, import edip direkt olarak kullanmaya başlayabiliriz.
+### Sınırsız "Plug-in" { #unlimited-plug-ins }
-Bütün entegrasyonlar kullanımı kolay olmak üzere (zorunluluklar ile beraber) tasarlandı, sen bir "plug-in" yaratıp 2 satır kod ile, *path operasyonlarında* kullandığımız syntax ve aynı yapı ile koduna entregre edebilirsin.
+Başka bir deyişle, onlara gerek yok; ihtiyaç duyduğunuz kodu import edin ve kullanın.
+Her entegrasyon (bağımlılıklar ile) o kadar basit olacak şekilde tasarlanmıştır ki, uygulamanız için, *path operations* ile kullandığınız aynı yapı ve söz dizimiyle sadece 2 satırda bir “plug-in” yazabilirsiniz.
-### Test edildi
+### Test Edildi { #tested }
-* 100%
test coverage.
-* 100%
typeları belirtilmiş codebase.
-* FastAPI ile yapılan bir çok proje insanlar tarafından kullanılıyor.
+* %100
test kapsayıcılığı.
+* %100
type annotated kod tabanı.
+* Üretimde kullanılan uygulamalarda kullanılıyor.
-## Starlette özellikleri
+## Starlette Özellikleri { #starlette-features }
-**FastAPI**,
Starlette ile tamamiyle uyumlu ve üzerine kurulu. Yani FastAPI üzerine ekleme yapacağınız herhangi bir Starlette kodu da çalışacaktır.
+**FastAPI**,
Starlette ile tamamen uyumludur (ve onun üzerine kuruludur). Dolayısıyla elinizdeki ek Starlette kodları da çalışır.
-`FastAPI` aslında `Starlette`'nin bir sub-class'ı. Eğer Starlette'nin nasıl kullanılacağını biliyor isen, çoğu işlevini aynı şekilde yapıyor.
+`FastAPI` aslında `Starlette`’in bir alt sınıfıdır. Starlette’i zaten biliyor veya kullanıyorsanız, işlevlerin çoğu aynı şekilde çalışır.
-**FastAPI** ile beraber **Starlette**'nin bütün özelliklerine de sahip olacaksınız (FastAPI aslında Starlette'nin steroid basmış hali):
+**FastAPI** ile **Starlette**’in tüm özelliklerini elde edersiniz (FastAPI, steroid basılmış Starlette gibidir):
-* Gerçekten etkileyici bir performansa sahip.Python'un ise en hızlı frameworklerinden bir tanesi,
**NodeJS** ve **Go** ile ise eşdeğer performansa sahip..
+* Cidden etkileyici performans.
Mevcut en hızlı Python frameworklerinden biridir; **NodeJS** ve **Go** ile aynı seviyededir.
* **WebSocket** desteği.
-* **GraphQL** desteği.
-* Kullanım halinde arka plan işlevleri.
-* Başlatma ve kapatma eventleri(startup and shutdown).
-* Test sunucusu HTTPX üzerine kurulu.
-* **CORS**, GZip, Static dosyalar, Streaming responseları.
-* **Session and Cookie** desteği.
-* 100% test kapsayıcılığı.
-* 100% typeları belirtilmiş codebase.
+* Süreç içi arka plan görevleri.
+* Başlatma ve kapatma olayları.
+* HTTPX üzerine kurulu test istemcisi.
+* **CORS**, GZip, Static Files, Streaming response’lar.
+* **Session** ve **Cookie** desteği.
+* %100 test kapsayıcılığı.
+* %100 type annotated kod tabanı.
-## Pydantic özellikleri
+## Pydantic Özellikleri { #pydantic-features }
-**FastAPI** ile
Pydantic tamamiyle uyumlu ve üzerine kurulu. Yani FastAPI üzerine ekleme yapacağınız herhangi bir Pydantic kodu da çalışacaktır.
+**FastAPI**,
Pydantic ile tamamen uyumludur (ve onun üzerine kuruludur). Dolayısıyla elinizdeki ek Pydantic kodları da çalışır.
-Bunlara Pydantic üzerine kurulu
ORM databaseler ve ,
ODM kütüphaneler de dahil olmak üzere.
+Pydantic’e dayanan harici kütüphaneler de dâhildir; veritabanları için
ORM’ler,
ODM’ler gibi.
-Bu ayrıca şu anlama da geliyor, bir çok durumda requestten gelen objeyi **direkt olarak database**'e her şeyi otomatik olarak doğrulanmış bir biçimde aktarabilirisin.
+Bu aynı zamanda, birçok durumda request’ten aldığınız nesneyi **doğrudan veritabanına** iletebileceğiniz anlamına gelir; zira her şey otomatik olarak doğrulanır.
-Aynı şekilde, databaseden gelen objeyi de **direkt olarak isteğe** de tamamiyle doğrulanmış bir biçimde gönderebilirsiniz.
+Tersi yönde de geçerlidir; birçok durumda veritabanından aldığınız nesneyi **doğrudan client**’a gönderebilirsiniz.
-**FastAPI** ile beraber **Pydantic**'in bütün özelliklerine sahip olacaksınız (FastAPI data kontrolünü Pydantic'in üzerine kurduğu için):
+**FastAPI** ile **Pydantic**’in tüm özelliklerini elde edersiniz (FastAPI, tüm veri işlemede Pydantic’e dayanır):
* **Kafa karıştırmaz**:
- * Farklı bir syntax öğrenmenize gerek kalmaz,
- * Eğer Python typelarını nasıl kullanacağını biliyorsan Pydantic kullanmayı da biliyorsundur.
-* Kullandığın geliştirme araçları ile iyi çalışır **
IDE/
linter/brain**:
- * Pydantic'in veri yapıları aslında sadece senin tanımladığın classlar; Bu yüzden doğrulanmış dataların ile otomatik tamamlama, linting ve mypy'ı kullanarak sorunsuz bir şekilde çalışabilirsin
-* **En kompleks** yapıları bile doğrula:
- * Hiyerarşik Pydantic modellerinin kullanımı ile beraber, Python `typing`’s `List` and `Dict`, vs gibi şeyleri doğrula.
- * Doğrulayıcılar en kompleks data şemalarının bile temiz ve kolay bir şekilde tanımlanmasına izin veriyor, ve hepsi JSON şeması olarak dokümante ediliyor
- * Pydantic, JSON objen ne kadar derin (nested) olursa olsun doğrulamasını ve gösterimini yapıyor
+ * Öğrenmeniz gereken yeni bir şema tanımlama mikro-dili yok.
+ * Python type’larını biliyorsanız Pydantic’i nasıl kullanacağınızı da biliyorsunuz.
+* **
IDE/
linter/beyin**’inizle iyi anlaşır:
+ * Pydantic veri yapıları, sizin tanımladığınız sınıfların örnekleridir; bu nedenle doğrulanmış verilerinizle otomatik tamamlama, linting ve mypy sorunsuz çalışır, sezgileriniz de yol gösterir.
+* **Karmaşık yapıları** doğrulayın:
+ * Hiyerarşik Pydantic modelleri, Python `typing`’in `List` ve `Dict`’i vb. kullanımı.
+ * Doğrulayıcılar (validators), karmaşık veri şemalarının net ve kolay şekilde tanımlanmasını, kontrol edilmesini ve JSON Schema olarak dokümante edilmesini sağlar.
+ * Derinlemesine iç içe **JSON** nesnelerine sahip olabilir, hepsinin doğrulanmasını ve anotasyonlanmasını sağlayabilirsiniz.
* **Genişletilebilir**:
- * Pydantic özelleştirilmiş data tiplerinin tanımlanmasının yapılmasına izin veriyor ayrıca validator decoratorü ile senin doğrulamaları genişletip, kendi doğrulayıcılarını yazmana izin veriyor.
-* 100% test kapsayıcılığı.
+ * Pydantic, özel veri tiplerinin tanımlanmasına izin verir; ayrıca validator decorator’üyle bir modeldeki metodlarla doğrulamayı genişletebilirsiniz.
+* %100 test kapsayıcılığı.
diff --git a/docs/tr/docs/history-design-future.md b/docs/tr/docs/history-design-future.md
index 764a519571..d70e45104b 100644
--- a/docs/tr/docs/history-design-future.md
+++ b/docs/tr/docs/history-design-future.md
@@ -44,7 +44,7 @@ Sonrasında, (**FastAPI** kullanan bir geliştirici olarak) sahip olmak istediğ
Çeşitli fikirleri en popüler Python editörlerinde test ettim: PyCharm, VS Code, Jedi tabanlı editörler.
-Bu test, en son
Python Developer Survey'ine göre, kullanıcıların yaklaşık %80'inin kullandığı editörleri kapsıyor.
+Bu test, en son
Python Geliştirici Anketi'ine göre, kullanıcıların yaklaşık %80'inin kullandığı editörleri kapsıyor.
Bu da demek oluyor ki **FastAPI**, Python geliştiricilerinin %80'inin kullandığı editörlerle test edildi. Ve diğer editörlerin çoğu benzer şekilde çalıştığından, avantajları neredeyse tüm editörlerde çalışacaktır.
diff --git a/docs/tr/docs/how-to/authentication-error-status-code.md b/docs/tr/docs/how-to/authentication-error-status-code.md
index 579673624b..a22bef1cb1 100644
--- a/docs/tr/docs/how-to/authentication-error-status-code.md
+++ b/docs/tr/docs/how-to/authentication-error-status-code.md
@@ -8,7 +8,7 @@ Ancak herhangi bir nedenle client'larınız eski davranışa bağlıysa, securit
Örneğin, varsayılan `401 Unauthorized` hatası yerine `403 Forbidden` hatası döndüren bir `HTTPBearer` alt sınıfı oluşturabilirsiniz:
-{* ../../docs_src/authentication_error_status_code/tutorial001_an_py39.py hl[9:13] *}
+{* ../../docs_src/authentication_error_status_code/tutorial001_an_py310.py hl[9:13] *}
/// tip | İpucu
diff --git a/docs/tr/docs/how-to/conditional-openapi.md b/docs/tr/docs/how-to/conditional-openapi.md
index 9562637c47..32b799fa7c 100644
--- a/docs/tr/docs/how-to/conditional-openapi.md
+++ b/docs/tr/docs/how-to/conditional-openapi.md
@@ -4,9 +4,9 @@ Gerekirse, ayarlar ve environment variable'ları kullanarak OpenAPI'yi ortama g
## Güvenlik, API'ler ve dokümantasyon hakkında { #about-security-apis-and-docs }
-Production ortamında dokümantasyon arayüzlerini gizlemek, API'nizi korumanın yolu *olmamalıdır*.
+Production ortamında dokümantasyon arayüzlerini gizlemek, API'nizi korumanın yolu olmamalıdır.
-Bu, API'nize ekstra bir güvenlik katmanı eklemez; *path operation*'lar bulundukları yerde yine erişilebilir olacaktır.
+Bu, API'nize ekstra bir güvenlik katmanı eklemez; path operation'lar bulundukları yerde yine erişilebilir olacaktır.
Kodunuzda bir güvenlik açığı varsa, o açık yine var olmaya devam eder.
@@ -29,7 +29,7 @@ Yine de, bazı ortamlarda (örn. production) veya environment variable'lardan ge
Örneğin:
-{* ../../docs_src/conditional_openapi/tutorial001_py39.py hl[6,11] *}
+{* ../../docs_src/conditional_openapi/tutorial001_py310.py hl[6,11] *}
Burada `openapi_url` ayarını, varsayılanı `"/openapi.json"` olacak şekilde tanımlıyoruz.
diff --git a/docs/tr/docs/how-to/configure-swagger-ui.md b/docs/tr/docs/how-to/configure-swagger-ui.md
index 6c051a1215..54e27d5dcc 100644
--- a/docs/tr/docs/how-to/configure-swagger-ui.md
+++ b/docs/tr/docs/how-to/configure-swagger-ui.md
@@ -18,7 +18,7 @@ Ayarları değiştirmeden bırakırsanız, syntax highlighting varsayılan olara
Ancak `syntaxHighlight` değerini `False` yaparak devre dışı bırakabilirsiniz:
-{* ../../docs_src/configure_swagger_ui/tutorial001_py39.py hl[3] *}
+{* ../../docs_src/configure_swagger_ui/tutorial001_py310.py hl[3] *}
...ve ardından Swagger UI artık syntax highlighting'i göstermeyecektir:
@@ -28,7 +28,7 @@ Ancak `syntaxHighlight` değerini `False` yaparak devre dışı bırakabilirsini
Aynı şekilde, `"syntaxHighlight.theme"` anahtarıyla (ortasında bir nokta olduğuna dikkat edin) syntax highlighting temasını ayarlayabilirsiniz:
-{* ../../docs_src/configure_swagger_ui/tutorial002_py39.py hl[3] *}
+{* ../../docs_src/configure_swagger_ui/tutorial002_py310.py hl[3] *}
Bu yapılandırma, syntax highlighting renk temasını değiştirir:
@@ -46,13 +46,13 @@ FastAPI, çoğu kullanım senaryosu için uygun bazı varsayılan yapılandırma
Örneğin `deepLinking`'i devre dışı bırakmak için `swagger_ui_parameters`'a şu ayarları geçebilirsiniz:
-{* ../../docs_src/configure_swagger_ui/tutorial003_py39.py hl[3] *}
+{* ../../docs_src/configure_swagger_ui/tutorial003_py310.py hl[3] *}
## Diğer Swagger UI Parametreleri { #other-swagger-ui-parameters }
Kullanabileceğiniz diğer tüm olası yapılandırmaları görmek için, resmi
Swagger UI parametreleri dokümantasyonunu okuyun.
-## Yalnızca JavaScript ayarları { #javascript-only-settings }
+## Yalnızca JavaScript Ayarları { #javascript-only-settings }
Swagger UI ayrıca bazı yapılandırmaların **yalnızca JavaScript** nesneleri olmasına izin verir (örneğin JavaScript fonksiyonları).
diff --git a/docs/tr/docs/how-to/custom-docs-ui-assets.md b/docs/tr/docs/how-to/custom-docs-ui-assets.md
index bdd2d02440..4a843b40f4 100644
--- a/docs/tr/docs/how-to/custom-docs-ui-assets.md
+++ b/docs/tr/docs/how-to/custom-docs-ui-assets.md
@@ -18,7 +18,7 @@ Bu, örneğin bazı URL'leri kısıtlayan bir ülkede yaşıyorsanız faydalı o
Bunları devre dışı bırakmak için `FastAPI` uygulamanızı oluştururken URL'lerini `None` olarak ayarlayın:
-{* ../../docs_src/custom_docs_ui/tutorial001_py39.py hl[8] *}
+{* ../../docs_src/custom_docs_ui/tutorial001_py310.py hl[8] *}
### Özel dokümanları ekleyin { #include-the-custom-docs }
@@ -34,7 +34,7 @@ Dokümanlar için HTML sayfalarını üretmek üzere FastAPI'nin dahili fonksiyo
ReDoc için de benzer şekilde...
-{* ../../docs_src/custom_docs_ui/tutorial001_py39.py hl[2:6,11:19,22:24,27:33] *}
+{* ../../docs_src/custom_docs_ui/tutorial001_py310.py hl[2:6,11:19,22:24,27:33] *}
/// tip | İpucu
@@ -50,7 +50,7 @@ Swagger UI bunu arka planda sizin için yönetir, ancak bu "redirect" yardımcı
Şimdi her şeyin çalıştığını test edebilmek için bir *path operation* oluşturun:
-{* ../../docs_src/custom_docs_ui/tutorial001_py39.py hl[36:38] *}
+{* ../../docs_src/custom_docs_ui/tutorial001_py310.py hl[36:38] *}
### Test edin { #test-it }
@@ -118,7 +118,7 @@ Bundan sonra dosya yapınız şöyle görünebilir:
* `StaticFiles` içe aktarın.
* Belirli bir path'te bir `StaticFiles()` instance'ını "mount" edin.
-{* ../../docs_src/custom_docs_ui/tutorial002_py39.py hl[7,11] *}
+{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[7,11] *}
### Statik dosyaları test edin { #test-the-static-files }
@@ -144,7 +144,7 @@ Bu, uygulamanızdan statik dosyaları servis edebildiğinizi ve dokümanlar içi
Bunları devre dışı bırakmak için `FastAPI` uygulamanızı oluştururken URL'lerini `None` olarak ayarlayın:
-{* ../../docs_src/custom_docs_ui/tutorial002_py39.py hl[9] *}
+{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[9] *}
### Statik dosyalar için özel dokümanları ekleyin { #include-the-custom-docs-for-static-files }
@@ -160,7 +160,7 @@ Yine FastAPI'nin dahili fonksiyonlarını kullanarak dokümanlar için HTML sayf
ReDoc için de benzer şekilde...
-{* ../../docs_src/custom_docs_ui/tutorial002_py39.py hl[2:6,14:22,25:27,30:36] *}
+{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[2:6,14:22,25:27,30:36] *}
/// tip | İpucu
@@ -176,7 +176,7 @@ Swagger UI bunu arka planda sizin için yönetir, ancak bu "redirect" yardımcı
Şimdi her şeyin çalıştığını test edebilmek için bir *path operation* oluşturun:
-{* ../../docs_src/custom_docs_ui/tutorial002_py39.py hl[39:41] *}
+{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[39:41] *}
### Statik Dosyalar UI'ını Test Edin { #test-static-files-ui }
diff --git a/docs/tr/docs/how-to/extending-openapi.md b/docs/tr/docs/how-to/extending-openapi.md
index 99691946c2..9998f0bacd 100644
--- a/docs/tr/docs/how-to/extending-openapi.md
+++ b/docs/tr/docs/how-to/extending-openapi.md
@@ -4,7 +4,7 @@ Oluşturulan OpenAPI şemasını değiştirmeniz gereken bazı durumlar olabilir
Bu bölümde bunun nasıl yapılacağını göreceksiniz.
-## Normal süreç { #the-normal-process }
+## Normal Süreç { #the-normal-process }
Normal (varsayılan) süreç şöyledir.
@@ -33,7 +33,7 @@ Ve `get_openapi()` fonksiyonu şu parametreleri alır:
///
-## Varsayılanları ezme { #overriding-the-defaults }
+## Varsayılanları Ezme { #overriding-the-defaults }
Yukarıdaki bilgileri kullanarak aynı yardımcı fonksiyonla OpenAPI şemasını üretebilir ve ihtiyacınız olan her parçayı override edebilirsiniz.
@@ -43,21 +43,21 @@ Yukarıdaki bilgileri kullanarak aynı yardımcı fonksiyonla OpenAPI şemasın
Önce, tüm **FastAPI** uygulamanızı her zamanki gibi yazın:
-{* ../../docs_src/extending_openapi/tutorial001_py39.py hl[1,4,7:9] *}
+{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[1,4,7:9] *}
-### OpenAPI şemasını üretme { #generate-the-openapi-schema }
+### OpenAPI Şemasını Üretme { #generate-the-openapi-schema }
Ardından, bir `custom_openapi()` fonksiyonunun içinde aynı yardımcı fonksiyonu kullanarak OpenAPI şemasını üretin:
-{* ../../docs_src/extending_openapi/tutorial001_py39.py hl[2,15:21] *}
+{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[2,15:21] *}
-### OpenAPI şemasını değiştirme { #modify-the-openapi-schema }
+### OpenAPI Şemasını Değiştirme { #modify-the-openapi-schema }
Artık OpenAPI şemasındaki `info` "object"'ine özel bir `x-logo` ekleyerek ReDoc extension'ını ekleyebilirsiniz:
-{* ../../docs_src/extending_openapi/tutorial001_py39.py hl[22:24] *}
+{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[22:24] *}
-### OpenAPI şemasını cache'leme { #cache-the-openapi-schema }
+### OpenAPI Şemasını Cache'leme { #cache-the-openapi-schema }
Ürettiğiniz şemayı saklamak için `.openapi_schema` özelliğini bir "cache" gibi kullanabilirsiniz.
@@ -65,15 +65,15 @@ Böylece bir kullanıcı API docs'larınızı her açtığında uygulamanız şe
Şema yalnızca bir kez üretilecektir; sonraki request'ler için de aynı cache'lenmiş şema kullanılacaktır.
-{* ../../docs_src/extending_openapi/tutorial001_py39.py hl[13:14,25:26] *}
+{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[13:14,25:26] *}
-### Metodu override etme { #override-the-method }
+### Metodu Override Etme { #override-the-method }
Şimdi `.openapi()` metodunu yeni fonksiyonunuzla değiştirebilirsiniz.
-{* ../../docs_src/extending_openapi/tutorial001_py39.py hl[29] *}
+{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[29] *}
-### Kontrol edin { #check-it }
+### Kontrol Edin { #check-it }
http://127.0.0.1:8000/redoc adresine gittiğinizde, özel logonuzu kullandığınızı göreceksiniz (bu örnekte **FastAPI**'nin logosu):
diff --git a/docs/tr/docs/how-to/general.md b/docs/tr/docs/how-to/general.md
index e3154921a4..ad1ed3fbcc 100644
--- a/docs/tr/docs/how-to/general.md
+++ b/docs/tr/docs/how-to/general.md
@@ -14,7 +14,7 @@ Döndürmeniz gerekenden daha fazla veri döndürmediğinizden emin olmak için,
*path operation*'larınıza özet ve açıklama eklemek ve bunları dokümantasyon arayüzünde göstermek için, [Tutorial - Path Operation Configurations - Summary and Description](../tutorial/path-operation-configuration.md#summary-and-description){.internal-link target=_blank} dokümantasyonunu okuyun.
-## Dokümantasyon Yanıt Açıklaması - OpenAPI { #documentation-response-description-openapi }
+## Dokümantasyon Response Açıklaması - OpenAPI { #documentation-response-description-openapi }
Dokümantasyon arayüzünde gösterilen response açıklamasını tanımlamak için, [Tutorial - Path Operation Configurations - Response description](../tutorial/path-operation-configuration.md#response-description){.internal-link target=_blank} dokümantasyonunu okuyun.
diff --git a/docs/tr/docs/how-to/graphql.md b/docs/tr/docs/how-to/graphql.md
index fbf0188740..99123cf2a3 100644
--- a/docs/tr/docs/how-to/graphql.md
+++ b/docs/tr/docs/how-to/graphql.md
@@ -35,7 +35,7 @@ Kullanım senaryonuza göre farklı bir kütüphaneyi tercih edebilirsiniz; anca
Strawberry'yi FastAPI ile nasıl entegre edebileceğinize dair küçük bir ön izleme:
-{* ../../docs_src/graphql_/tutorial001_py39.py hl[3,22,25] *}
+{* ../../docs_src/graphql_/tutorial001_py310.py hl[3,22,25] *}
Strawberry hakkında daha fazlasını
Strawberry dokümantasyonunda öğrenebilirsiniz.
diff --git a/docs/tr/docs/how-to/index.md b/docs/tr/docs/how-to/index.md
index 5ec2e0268f..928911c0e8 100644
--- a/docs/tr/docs/how-to/index.md
+++ b/docs/tr/docs/how-to/index.md
@@ -8,6 +8,6 @@ Projeniz için ilginç ve yararlı görünen bir şey varsa devam edin ve incele
/// tip | İpucu
-**FastAPI**'ı yapılandırılmış bir şekilde (önerilir) **öğrenmek** istiyorsanız bunun yerine [Öğretici - Kullanıcı Rehberi](../tutorial/index.md){.internal-link target=_blank}'ni bölüm bölüm okuyun.
+**FastAPI**'yi yapılandırılmış bir şekilde (önerilir) **öğrenmek** istiyorsanız bunun yerine [Öğretici - Kullanıcı Rehberi](../tutorial/index.md){.internal-link target=_blank}'ni bölüm bölüm okuyun.
///
diff --git a/docs/tr/docs/how-to/migrate-from-pydantic-v1-to-pydantic-v2.md b/docs/tr/docs/how-to/migrate-from-pydantic-v1-to-pydantic-v2.md
index 275ac5fd17..6d732c1dfa 100644
--- a/docs/tr/docs/how-to/migrate-from-pydantic-v1-to-pydantic-v2.md
+++ b/docs/tr/docs/how-to/migrate-from-pydantic-v1-to-pydantic-v2.md
@@ -88,7 +88,7 @@ graph TB
style V2Field fill:#f9fff3
```
-...ancak aynı uygulamada Pydantic v1 ve v2 kullanarak **ayrı (separated)** modeller tanımlayabilirsiniz.
+...ancak aynı uygulamada Pydantic v1 ve v2 kullanarak **ayrı** modeller tanımlayabilirsiniz.
```mermaid
graph TB
diff --git a/docs/tr/docs/index.md b/docs/tr/docs/index.md
index 16c425f5d7..f240a96914 100644
--- a/docs/tr/docs/index.md
+++ b/docs/tr/docs/index.md
@@ -40,7 +40,7 @@ Temel özellikleri şunlardır:
* **Hızlı**: Çok yüksek performanslı, **NodeJS** ve **Go** ile eşit düzeyde (Starlette ve Pydantic sayesinde). [Mevcut en hızlı Python framework'lerinden biri](#performance).
* **Kodlaması Hızlı**: Özellik geliştirme hızını yaklaşık %200 ile %300 aralığında artırır. *
* **Daha az hata**: İnsan (geliştirici) kaynaklı hataları yaklaşık %40 azaltır. *
-* **Sezgisel**: Harika bir editör desteği. Her yerde
Completion. Hata ayıklamaya daha az zaman.
+* **Sezgisel**: Harika bir editör desteği. Her yerde
Tamamlama. Hata ayıklamaya daha az zaman.
* **Kolay**: Kullanımı ve öğrenmesi kolay olacak şekilde tasarlandı. Doküman okumaya daha az zaman.
* **Kısa**: Kod tekrarını minimize eder. Her parametre tanımından birden fazla özellik. Daha az hata.
* **Sağlam**: Production'a hazır kod elde edersiniz. Otomatik etkileşimli dokümantasyon ile birlikte.
@@ -127,7 +127,7 @@ Temel özellikleri şunlardır:

-Web API yerine terminalde kullanılacak bir
CLI uygulaması geliştiriyorsanız
**Typer**'a göz atın.
+Web API yerine terminalde kullanılacak bir
CLI uygulaması geliştiriyorsanız
**Typer**'a göz atın.
**Typer**, FastAPI'ın küçük kardeşi. Ve hedefi CLI'ların **FastAPI'ı** olmak. ⌨️ 🚀
@@ -368,7 +368,7 @@ item: Item
* Verinin doğrulanması:
* Veri geçersiz olduğunda otomatik ve anlaşılır hatalar.
* Çok derin iç içe JSON nesneleri için bile doğrulama.
-* Girdi verisinin
Dönüşümü: network'ten gelen veriyi Python verisine ve type'larına çevirir. Şunlardan okur:
+* Girdi verisinin
Dönüşümü: network'ten gelen veriyi Python verisine ve type'larına çevirir. Şunlardan okur:
* JSON.
* Path parameter'lar.
* Query parameter'lar.
@@ -376,7 +376,7 @@ item: Item
* Header'lar.
* Form'lar.
* File'lar.
-* Çıktı verisinin
Dönüşümü: Python verisini ve type'larını network verisine çevirir (JSON olarak):
+* Çıktı verisinin
Dönüşümü: Python verisini ve type'larını network verisine çevirir (JSON olarak):
* Python type'larını dönüştürür (`str`, `int`, `float`, `bool`, `list`, vb.).
* `datetime` nesneleri.
* `UUID` nesneleri.
@@ -439,7 +439,7 @@ Daha fazla özellik içeren daha kapsamlı bir örnek için
Dependency Injection** sistemi.
+* Çok güçlü ve kullanımı kolay bir **Bağımlılık Enjeksiyonu** sistemi.
* **JWT tokens** ve **HTTP Basic** auth ile **OAuth2** desteği dahil güvenlik ve kimlik doğrulama.
* **Çok derin iç içe JSON modelleri** tanımlamak için daha ileri (ama aynı derecede kolay) teknikler (Pydantic sayesinde).
* Strawberry ve diğer kütüphaneler ile **GraphQL** entegrasyonu.
@@ -524,7 +524,7 @@ Starlette tarafından kullanılanlar:
*
httpx - `TestClient` kullanmak istiyorsanız gereklidir.
*
jinja2 - varsayılan template yapılandırmasını kullanmak istiyorsanız gereklidir.
-*
python-multipart - `request.form()` ile, form
"parsing" desteği istiyorsanız gereklidir.
+*
python-multipart - `request.form()` ile, form
"ayrıştırma" desteği istiyorsanız gereklidir.
FastAPI tarafından kullanılanlar:
@@ -534,7 +534,7 @@ FastAPI tarafından kullanılanlar:
### `standard` Bağımlılıkları Olmadan { #without-standard-dependencies }
-`standard` opsiyonel bağımlılıklarını dahil etmek istemiyorsanız, `pip install "fastapi[standard]"` yerine `pip install fastapi` ile kurabilirsiniz.
+`standard` opsiyonel bağımlılıklarını dahil etmek istemiyorsanız, `pip install fastapi` ile kurabilirsiniz.
### `fastapi-cloud-cli` Olmadan { #without-fastapi-cloud-cli }
diff --git a/docs/tr/docs/python-types.md b/docs/tr/docs/python-types.md
index 01a3efe98c..9477e4fabc 100644
--- a/docs/tr/docs/python-types.md
+++ b/docs/tr/docs/python-types.md
@@ -2,9 +2,9 @@
Python, isteğe bağlı "type hints" (diğer adıyla "type annotations") desteğine sahiptir.
-Bu **"type hints"** veya annotations, bir değişkenin
type'ını bildirmeye yarayan özel bir sözdizimidir.
+Bu **"type hints"** veya annotations, bir değişkenin
tip'ini bildirmeye yarayan özel bir sözdizimidir.
-Değişkenleriniz için type bildirerek, editörler ve araçlar size daha iyi destek sağlayabilir.
+Değişkenleriniz için tip bildirerek, editörler ve araçlar size daha iyi destek sağlayabilir.
Bu, Python type hints hakkında sadece **hızlı bir eğitim / bilgi tazeleme** dokümanıdır. **FastAPI** ile kullanmak için gereken minimum bilgiyi kapsar... ki aslında bu çok azdır.
@@ -22,7 +22,7 @@ Eğer bir Python uzmanıysanız ve type hints hakkında her şeyi zaten biliyors
Basit bir örnekle başlayalım:
-{* ../../docs_src/python_types/tutorial001_py39.py *}
+{* ../../docs_src/python_types/tutorial001_py310.py *}
Bu programı çalıştırınca şu çıktıyı alırsınız:
@@ -34,9 +34,9 @@ Fonksiyon şunları yapar:
* `first_name` ve `last_name` değerlerini alır.
* `title()` ile her birinin ilk harfini büyük harfe çevirir.
-* Ortada bir boşluk olacak şekilde
Concatenates eder.
+* Ortada bir boşluk olacak şekilde
Birleştirir.
-{* ../../docs_src/python_types/tutorial001_py39.py hl[2] *}
+{* ../../docs_src/python_types/tutorial001_py310.py hl[2] *}
### Düzenleyelim { #edit-it }
@@ -78,7 +78,7 @@ Bu kadar.
Bunlar "type hints":
-{* ../../docs_src/python_types/tutorial002_py39.py hl[1] *}
+{* ../../docs_src/python_types/tutorial002_py310.py hl[1] *}
Bu, aşağıdaki gibi default değerler bildirmekle aynı şey değildir:
@@ -106,7 +106,7 @@ Bununla birlikte, seçenekleri görerek kaydırabilirsiniz; ta ki "tanıdık gel
Şu fonksiyona bakın, zaten type hints içeriyor:
-{* ../../docs_src/python_types/tutorial003_py39.py hl[1] *}
+{* ../../docs_src/python_types/tutorial003_py310.py hl[1] *}
Editör değişkenlerin tiplerini bildiği için, sadece completion değil, aynı zamanda hata kontrolleri de alırsınız:
@@ -114,9 +114,9 @@ Editör değişkenlerin tiplerini bildiği için, sadece completion değil, ayn
Artık bunu düzeltmeniz gerektiğini, `age`'i `str(age)` ile string'e çevirmeniz gerektiğini biliyorsunuz:
-{* ../../docs_src/python_types/tutorial004_py39.py hl[2] *}
+{* ../../docs_src/python_types/tutorial004_py310.py hl[2] *}
-## Tipleri bildirmek { #declaring-types }
+## Tipleri Bildirmek { #declaring-types }
Type hints bildirmek için ana yeri az önce gördünüz: fonksiyon parametreleri.
@@ -133,29 +133,32 @@ Sadece `str` değil, tüm standart Python tiplerini bildirebilirsiniz.
* `bool`
* `bytes`
-{* ../../docs_src/python_types/tutorial005_py39.py hl[1] *}
+{* ../../docs_src/python_types/tutorial005_py310.py hl[1] *}
-### Tip parametreleri ile Generic tipler { #generic-types-with-type-parameters }
+### `typing` modülü { #typing-module }
-`dict`, `list`, `set` ve `tuple` gibi, başka değerler içerebilen bazı veri yapıları vardır. Ve iç değerlerin kendi tipi de olabilir.
+Bazı ek kullanım durumları için standart kütüphanedeki `typing` modülünden bazı şeyleri import etmeniz gerekebilir. Örneğin bir şeyin "herhangi bir tip" olabileceğini bildirmek istediğinizde, `typing` içindeki `Any`'yi kullanabilirsiniz:
-İç tipleri olan bu tiplere "**generic**" tipler denir. Ve bunları, iç tipleriyle birlikte bildirmek mümkündür.
+```python
+from typing import Any
-Bu tipleri ve iç tipleri bildirmek için standart Python modülü `typing`'i kullanabilirsiniz. Bu modül, özellikle bu type hints desteği için vardır.
-#### Python'un daha yeni sürümleri { #newer-versions-of-python }
-
-`typing` kullanan sözdizimi, Python 3.6'dan en yeni sürümlere kadar (Python 3.9, Python 3.10, vb. dahil) tüm sürümlerle **uyumludur**.
+def some_function(data: Any):
+ print(data)
+```
-Python geliştikçe, **daha yeni sürümler** bu type annotations için daha iyi destekle gelir ve çoğu durumda type annotations bildirmek için `typing` modülünü import edip kullanmanız bile gerekmez.
+### Generic tipler { #generic-types }
-Projeniz için daha yeni bir Python sürümü seçebiliyorsanız, bu ek sadelikten yararlanabilirsiniz.
+Bazı tipler, köşeli parantez içinde "type parameters" alarak iç tiplerini tanımlayabilir; örneğin "string listesi" `list[str]` olarak bildirilir.
-Tüm dokümanlarda her Python sürümüyle uyumlu örnekler vardır (fark olduğunda).
+Bu şekilde type parameter alabilen tiplere **Generic types** veya **Generics** denir.
-Örneğin "**Python 3.6+**", Python 3.6 veya üstüyle (3.7, 3.8, 3.9, 3.10, vb. dahil) uyumludur. "**Python 3.9+**" ise Python 3.9 veya üstüyle (3.10 vb. dahil) uyumludur.
+Aynı builtin tipleri generics olarak kullanabilirsiniz (köşeli parantez ve içinde tiplerle):
-Eğer **Python'un en güncel sürümlerini** kullanabiliyorsanız, en güncel sürüme ait örnekleri kullanın; bunlar **en iyi ve en basit sözdizimine** sahip olur, örneğin "**Python 3.10+**".
+* `list`
+* `tuple`
+* `set`
+* `dict`
#### List { #list }
@@ -163,11 +166,11 @@ Eğer **Python'un en güncel sürümlerini** kullanabiliyorsanız, en güncel s
Değişkeni, aynı iki nokta (`:`) sözdizimiyle bildirin.
-Type olarak `list` yazın.
+Tip olarak `list` yazın.
`list`, bazı iç tipleri barındıran bir tip olduğundan, bunları köşeli parantez içine yazarsınız:
-{* ../../docs_src/python_types/tutorial006_py39.py hl[1] *}
+{* ../../docs_src/python_types/tutorial006_py310.py hl[1] *}
/// info | Bilgi
@@ -193,7 +196,7 @@ Ve yine de editör bunun bir `str` olduğunu bilir ve buna göre destek sağlar.
`tuple`'ları ve `set`'leri bildirmek için de aynısını yaparsınız:
-{* ../../docs_src/python_types/tutorial007_py39.py hl[1] *}
+{* ../../docs_src/python_types/tutorial007_py310.py hl[1] *}
Bu şu anlama gelir:
@@ -208,7 +211,7 @@ Bir `dict` tanımlamak için, virgülle ayrılmış 2 type parameter verirsiniz.
İkinci type parameter, `dict`'in value'ları içindir:
-{* ../../docs_src/python_types/tutorial008_py39.py hl[1] *}
+{* ../../docs_src/python_types/tutorial008_py310.py hl[1] *}
Bu şu anlama gelir:
@@ -220,44 +223,20 @@ Bu şu anlama gelir:
Bir değişkenin **birkaç tipten herhangi biri** olabileceğini bildirebilirsiniz; örneğin bir `int` veya bir `str`.
-Python 3.6 ve üzeri sürümlerde (Python 3.10 dahil), `typing` içinden `Union` tipini kullanabilir ve köşeli parantez içine kabul edilecek olası tipleri yazabilirsiniz.
-
-Python 3.10'da ayrıca, olası tipleri
vertical bar (`|`) ile ayırabildiğiniz **yeni bir sözdizimi** de vardır.
+Bunu tanımlamak için, her iki tipi ayırmak üzere
dikey çizgi (`|`) kullanırsınız.
-//// tab | Python 3.10+
+Buna "union" denir, çünkü değişken bu iki tip kümesinin birleşimindeki herhangi bir şey olabilir.
```Python hl_lines="1"
{!> ../../docs_src/python_types/tutorial008b_py310.py!}
```
-////
-
-//// tab | Python 3.9+
-
-```Python hl_lines="1 4"
-{!> ../../docs_src/python_types/tutorial008b_py39.py!}
-```
-
-////
-
-Her iki durumda da bu, `item`'ın `int` veya `str` olabileceği anlamına gelir.
+Bu, `item`'ın `int` veya `str` olabileceği anlamına gelir.
#### Muhtemelen `None` { #possibly-none }
Bir değerin `str` gibi bir tipi olabileceğini ama aynı zamanda `None` da olabileceğini bildirebilirsiniz.
-Python 3.6 ve üzeri sürümlerde (Python 3.10 dahil), `typing` modülünden `Optional` import edip kullanarak bunu bildirebilirsiniz.
-
-```Python hl_lines="1 4"
-{!../../docs_src/python_types/tutorial009_py39.py!}
-```
-
-Sadece `str` yerine `Optional[str]` kullanmak, aslında değer `None` olabilecekken her zaman `str` olduğunu varsaydığınız hataları editörün yakalamanıza yardımcı olmasını sağlar.
-
-`Optional[Something]`, aslında `Union[Something, None]` için bir kısayoldur; eşdeğerdirler.
-
-Bu aynı zamanda Python 3.10'da `Something | None` kullanabileceğiniz anlamına gelir:
-
//// tab | Python 3.10+
```Python hl_lines="1"
@@ -266,96 +245,7 @@ Bu aynı zamanda Python 3.10'da `Something | None` kullanabileceğiniz anlamına
////
-//// tab | Python 3.9+
-
-```Python hl_lines="1 4"
-{!> ../../docs_src/python_types/tutorial009_py39.py!}
-```
-
-////
-
-//// tab | Python 3.9+ alternatif
-
-```Python hl_lines="1 4"
-{!> ../../docs_src/python_types/tutorial009b_py39.py!}
-```
-
-////
-
-#### `Union` veya `Optional` kullanmak { #using-union-or-optional }
-
-Python sürümünüz 3.10'un altındaysa, benim oldukça **öznel** bakış açıma göre küçük bir ipucu:
-
-* 🚨 `Optional[SomeType]` kullanmaktan kaçının
-* Bunun yerine ✨ **`Union[SomeType, None]` kullanın** ✨.
-
-İkisi eşdeğerdir ve altta aynı şeydir; ama ben `Optional` yerine `Union` önermeyi tercih ederim. Çünkü "**optional**" kelimesi değerin optional olduğunu ima ediyor gibi durur; ama gerçekte anlamı "değer `None` olabilir"dir. Değer optional olmasa ve hâlâ required olsa bile.
-
-Bence `Union[SomeType, None]` ne anlama geldiğini daha açık şekilde ifade ediyor.
-
-Bu, tamamen kelimeler ve isimlendirmelerle ilgili. Ancak bu kelimeler, sizin ve ekip arkadaşlarınızın kod hakkında nasıl düşündüğünü etkileyebilir.
-
-Örnek olarak şu fonksiyonu ele alalım:
-
-{* ../../docs_src/python_types/tutorial009c_py39.py hl[1,4] *}
-
-`name` parametresi `Optional[str]` olarak tanımlanmış, ama **optional değil**; parametre olmadan fonksiyonu çağıramazsınız:
-
-```Python
-say_hi() # Oh, no, this throws an error! 😱
-```
-
-`name` parametresi **hâlâ required**'dır (*optional* değildir) çünkü bir default değeri yoktur. Yine de `name`, değer olarak `None` kabul eder:
-
-```Python
-say_hi(name=None) # This works, None is valid 🎉
-```
-
-İyi haber şu ki, Python 3.10'a geçtiğinizde bununla uğraşmanız gerekmeyecek; çünkü tiplerin union'larını tanımlamak için doğrudan `|` kullanabileceksiniz:
-
-{* ../../docs_src/python_types/tutorial009c_py310.py hl[1,4] *}
-
-Ve böylece `Optional` ve `Union` gibi isimlerle de uğraşmanız gerekmeyecek. 😎
-
-#### Generic tipler { #generic-types }
-
-Köşeli parantez içinde type parameter alan bu tiplere **Generic types** veya **Generics** denir, örneğin:
-
-//// tab | Python 3.10+
-
-Aynı builtin tipleri generics olarak kullanabilirsiniz (köşeli parantez ve içindeki tiplerle):
-
-* `list`
-* `tuple`
-* `set`
-* `dict`
-
-Ve önceki Python sürümlerinde olduğu gibi `typing` modülünden:
-
-* `Union`
-* `Optional`
-* ...and others.
-
-Python 3.10'da, `Union` ve `Optional` generics'lerini kullanmaya alternatif olarak, tip union'larını bildirmek için
vertical bar (`|`) kullanabilirsiniz; bu çok daha iyi ve daha basittir.
-
-////
-
-//// tab | Python 3.9+
-
-Aynı builtin tipleri generics olarak kullanabilirsiniz (köşeli parantez ve içindeki tiplerle):
-
-* `list`
-* `tuple`
-* `set`
-* `dict`
-
-Ve `typing` modülünden gelen generics:
-
-* `Union`
-* `Optional`
-* ...and others.
-
-////
+Sadece `str` yerine `str | None` kullanmak, aslında değer `None` olabilecekken her zaman `str` olduğunu varsaydığınız hataları editörün yakalamanıza yardımcı olur.
### Tip olarak sınıflar { #classes-as-types }
@@ -363,11 +253,11 @@ Bir sınıfı da bir değişkenin tipi olarak bildirebilirsiniz.
Örneğin, adı olan bir `Person` sınıfınız olsun:
-{* ../../docs_src/python_types/tutorial010_py39.py hl[1:3] *}
+{* ../../docs_src/python_types/tutorial010_py310.py hl[1:3] *}
Sonra bir değişkeni `Person` tipinde olacak şekilde bildirebilirsiniz:
-{* ../../docs_src/python_types/tutorial010_py39.py hl[6] *}
+{* ../../docs_src/python_types/tutorial010_py310.py hl[6] *}
Ve sonra, yine tüm editör desteğini alırsınız:
@@ -401,21 +291,15 @@ Daha fazlasını öğrenmek için
Required Optional fields bölümünde okuyabilirsiniz.
-
-///
+Bunların pratikte nasıl çalıştığını [Eğitim - Kullanım Kılavuzu](tutorial/index.md){.internal-link target=_blank} içinde çok daha fazla göreceksiniz.
## Metadata Annotations ile Type Hints { #type-hints-with-metadata-annotations }
-Python'da ayrıca, `Annotated` kullanarak bu type hints içine **ek
metadata** koymayı sağlayan bir özellik de vardır.
+Python'da ayrıca, `Annotated` kullanarak bu type hints içine **ek
üstveri** koymayı sağlayan bir özellik de vardır.
-Python 3.9'dan itibaren `Annotated`, standart kütüphanenin bir parçasıdır; bu yüzden `typing` içinden import edebilirsiniz.
+`Annotated`'ı `typing` içinden import edebilirsiniz.
-{* ../../docs_src/python_types/tutorial013_py39.py hl[1,4] *}
+{* ../../docs_src/python_types/tutorial013_py310.py hl[1,4] *}
Python'un kendisi bu `Annotated` ile bir şey yapmaz. Editörler ve diğer araçlar için tip hâlâ `str`'dir.
@@ -446,14 +330,14 @@ Ayrıca kodunuzun pek çok başka Python aracı ve kütüphanesiyle çok uyumlu
...ve **FastAPI** aynı bildirimleri şunlar için de kullanır:
-* **Gereksinimleri tanımlamak**: request path parameters, query parameters, headers, bodies, dependencies, vb.
+* **Gereksinimleri tanımlamak**: request path parameters, query parameters, headers, bodies, bağımlılıklar (dependencies), vb.
* **Veriyi dönüştürmek**: request'ten gerekli tipe.
* **Veriyi doğrulamak**: her request'ten gelen veriyi:
* Veri geçersiz olduğunda client'a dönen **otomatik hatalar** üretmek.
* OpenAPI kullanarak API'yi **dokümante etmek**:
* bu, daha sonra otomatik etkileşimli dokümantasyon kullanıcı arayüzleri tarafından kullanılır.
-Bunların hepsi kulağa soyut gelebilir. Merak etmeyin. Tüm bunları [Tutorial - User Guide](tutorial/index.md){.internal-link target=_blank} içinde çalışırken göreceksiniz.
+Bunların hepsi kulağa soyut gelebilir. Merak etmeyin. Tüm bunları [Eğitim - Kullanım Kılavuzu](tutorial/index.md){.internal-link target=_blank} içinde çalışırken göreceksiniz.
Önemli olan, standart Python tiplerini tek bir yerde kullanarak (daha fazla sınıf, decorator vb. eklemek yerine), **FastAPI**'nin sizin için işin büyük kısmını yapmasıdır.
diff --git a/docs/tr/docs/translation-banner.md b/docs/tr/docs/translation-banner.md
index b52578f71d..7491e61b8d 100644
--- a/docs/tr/docs/translation-banner.md
+++ b/docs/tr/docs/translation-banner.md
@@ -4,7 +4,7 @@ Bu çeviri, insanlar tarafından yönlendirilen bir yapay zekâ ile oluşturuldu
Orijinal anlamın yanlış anlaşılması ya da kulağa doğal gelmeme gibi hatalar içerebilir. 🤖
-[Yapay zekâyı daha iyi yönlendirmemize yardımcı olarak](https://fastapi.tiangolo.com/tr/contributing/#translations) bu çeviriyi iyileştirebilirsiniz.
+[Yapay zekâ LLM'ini daha iyi yönlendirmemize yardımcı olarak](https://fastapi.tiangolo.com/tr/contributing/#translations) bu çeviriyi iyileştirebilirsiniz.
[İngilizce sürüm](ENGLISH_VERSION_URL)
diff --git a/docs/tr/docs/tutorial/background-tasks.md b/docs/tr/docs/tutorial/background-tasks.md
index 4cb67d8224..a6dfbe5ea8 100644
--- a/docs/tr/docs/tutorial/background-tasks.md
+++ b/docs/tr/docs/tutorial/background-tasks.md
@@ -15,7 +15,7 @@ Bu, request’ten sonra yapılması gereken; ancak client’ın response’u alm
Önce `BackgroundTasks`’i import edin ve *path operation function*’ınızda `BackgroundTasks` tip bildirimi olan bir parametre tanımlayın:
-{* ../../docs_src/background_tasks/tutorial001_py39.py hl[1,13] *}
+{* ../../docs_src/background_tasks/tutorial001_py310.py hl[1,13] *}
**FastAPI**, sizin için `BackgroundTasks` tipinde bir obje oluşturur ve onu ilgili parametre olarak geçirir.
@@ -31,13 +31,13 @@ Bu örnekte görev fonksiyonu bir dosyaya yazacaktır (email göndermeyi simüle
Ve yazma işlemi `async` ve `await` kullanmadığı için fonksiyonu normal `def` ile tanımlarız:
-{* ../../docs_src/background_tasks/tutorial001_py39.py hl[6:9] *}
+{* ../../docs_src/background_tasks/tutorial001_py310.py hl[6:9] *}
## Arka Plan Görevini Ekleyin { #add-the-background-task }
*Path operation function*’ınızın içinde, görev fonksiyonunuzu `.add_task()` metodu ile *background tasks* objesine ekleyin:
-{* ../../docs_src/background_tasks/tutorial001_py39.py hl[14] *}
+{* ../../docs_src/background_tasks/tutorial001_py310.py hl[14] *}
`.add_task()` şu argümanları alır:
diff --git a/docs/tr/docs/tutorial/bigger-applications.md b/docs/tr/docs/tutorial/bigger-applications.md
index d8a4b8208b..9dbaae601d 100644
--- a/docs/tr/docs/tutorial/bigger-applications.md
+++ b/docs/tr/docs/tutorial/bigger-applications.md
@@ -85,7 +85,7 @@ Bu module için *path operation*’ları `APIRouter` kullanarak oluşturabilirsi
`FastAPI` class’ında yaptığınız gibi import edip bir "instance" oluşturursunuz:
-{* ../../docs_src/bigger_applications/app_an_py39/routers/users.py hl[1,3] title["app/routers/users.py"] *}
+{* ../../docs_src/bigger_applications/app_an_py310/routers/users.py hl[1,3] title["app/routers/users.py"] *}
### `APIRouter` ile *Path Operations* { #path-operations-with-apirouter }
@@ -93,7 +93,7 @@ Sonra bunu kullanarak *path operation*’larınızı tanımlarsınız.
`FastAPI` class’ını nasıl kullanıyorsanız aynı şekilde kullanın:
-{* ../../docs_src/bigger_applications/app_an_py39/routers/users.py hl[6,11,16] title["app/routers/users.py"] *}
+{* ../../docs_src/bigger_applications/app_an_py310/routers/users.py hl[6,11,16] title["app/routers/users.py"] *}
`APIRouter`’ı "mini bir `FastAPI`" class’ı gibi düşünebilirsiniz.
@@ -117,7 +117,7 @@ Bu yüzden onları ayrı bir `dependencies` module’üne koyuyoruz (`app/depend
Şimdi, özel bir `X-Token` header'ını okumak için basit bir dependency kullanalım:
-{* ../../docs_src/bigger_applications/app_an_py39/dependencies.py hl[3,6:8] title["app/dependencies.py"] *}
+{* ../../docs_src/bigger_applications/app_an_py310/dependencies.py hl[3,6:8] title["app/dependencies.py"] *}
/// tip | İpucu
@@ -149,7 +149,7 @@ Bu module’deki tüm *path operation*’ların şu ortak özelliklere sahip old
Dolayısıyla bunları her *path operation*’a tek tek eklemek yerine `APIRouter`’a ekleyebiliriz.
-{* ../../docs_src/bigger_applications/app_an_py39/routers/items.py hl[5:10,16,21] title["app/routers/items.py"] *}
+{* ../../docs_src/bigger_applications/app_an_py310/routers/items.py hl[5:10,16,21] title["app/routers/items.py"] *}
Her *path operation*’ın path’i aşağıdaki gibi `/` ile başlamak zorunda olduğundan:
@@ -208,7 +208,7 @@ Dependency function’ını ise `app.dependencies` module’ünden, yani `app/de
Bu yüzden dependency’ler için `..` ile relative import kullanıyoruz:
-{* ../../docs_src/bigger_applications/app_an_py39/routers/items.py hl[3] title["app/routers/items.py"] *}
+{* ../../docs_src/bigger_applications/app_an_py310/routers/items.py hl[3] title["app/routers/items.py"] *}
#### Relative Import Nasıl Çalışır { #how-relative-imports-work }
@@ -279,7 +279,7 @@ Artık nasıl çalıştığını bildiğinize göre, uygulamalarınız ne kadar
Ama yine de belirli bir *path operation*’a uygulanacak _ek_ `tags` tanımlayabilir, ayrıca o *path operation*’a özel `responses` ekleyebiliriz:
-{* ../../docs_src/bigger_applications/app_an_py39/routers/items.py hl[30:31] title["app/routers/items.py"] *}
+{* ../../docs_src/bigger_applications/app_an_py310/routers/items.py hl[30:31] title["app/routers/items.py"] *}
/// tip | İpucu
@@ -305,13 +305,13 @@ Normal şekilde bir `FastAPI` class’ı oluşturursunuz.
Hatta her `APIRouter` için olan dependency’lerle birleştirilecek [global dependencies](dependencies/global-dependencies.md){.internal-link target=_blank} bile tanımlayabilirsiniz:
-{* ../../docs_src/bigger_applications/app_an_py39/main.py hl[1,3,7] title["app/main.py"] *}
+{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[1,3,7] title["app/main.py"] *}
### `APIRouter` Import Edin { #import-the-apirouter }
Şimdi `APIRouter` içeren diğer submodule’leri import ediyoruz:
-{* ../../docs_src/bigger_applications/app_an_py39/main.py hl[4:5] title["app/main.py"] *}
+{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[4:5] title["app/main.py"] *}
`app/routers/users.py` ve `app/routers/items.py` dosyaları aynı Python package’i olan `app`’in parçası olan submodule’ler olduğu için, onları "relative import" ile tek bir nokta `.` kullanarak import edebiliriz.
@@ -374,13 +374,13 @@ from .routers.users import router
Bu yüzden ikisini de aynı dosyada kullanabilmek için submodule’leri doğrudan import ediyoruz:
-{* ../../docs_src/bigger_applications/app_an_py39/main.py hl[5] title["app/main.py"] *}
+{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[5] title["app/main.py"] *}
### `users` ve `items` için `APIRouter`’ları Dahil Edin { #include-the-apirouters-for-users-and-items }
Şimdi `users` ve `items` submodule’lerindeki `router`’ları dahil edelim:
-{* ../../docs_src/bigger_applications/app_an_py39/main.py hl[10:11] title["app/main.py"] *}
+{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[10:11] title["app/main.py"] *}
/// info | Bilgi
@@ -420,13 +420,13 @@ Bu dosyada, kurumunuzun birden fazla proje arasında paylaştığı bazı admin
Bu örnekte çok basit olacak. Ancak kurum içinde başka projelerle paylaşıldığı için, bunu değiştirip `prefix`, `dependencies`, `tags` vs. doğrudan `APIRouter`’a ekleyemediğimizi varsayalım:
-{* ../../docs_src/bigger_applications/app_an_py39/internal/admin.py hl[3] title["app/internal/admin.py"] *}
+{* ../../docs_src/bigger_applications/app_an_py310/internal/admin.py hl[3] title["app/internal/admin.py"] *}
Yine de bu `APIRouter`’ı dahil ederken özel bir `prefix` ayarlamak istiyoruz ki tüm *path operation*’ları `/admin` ile başlasın; ayrıca bu projede hâlihazırda kullandığımız `dependencies` ile güvene almak, `tags` ve `responses` eklemek istiyoruz.
Orijinal `APIRouter`’ı değiştirmeden, bu parametreleri `app.include_router()`’a vererek hepsini tanımlayabiliriz:
-{* ../../docs_src/bigger_applications/app_an_py39/main.py hl[14:17] title["app/main.py"] *}
+{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[14:17] title["app/main.py"] *}
Böylece orijinal `APIRouter` değişmeden kalır; yani aynı `app/internal/admin.py` dosyasını kurum içindeki diğer projelerle de paylaşmaya devam edebiliriz.
@@ -447,7 +447,7 @@ Dolayısıyla örneğin diğer projeler aynı `APIRouter`’ı farklı bir authe
Burada bunu yapıyoruz... sadece yapabildiğimizi göstermek için 🤷:
-{* ../../docs_src/bigger_applications/app_an_py39/main.py hl[21:23] title["app/main.py"] *}
+{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[21:23] title["app/main.py"] *}
ve `app.include_router()` ile eklenen diğer tüm *path operation*’larla birlikte doğru şekilde çalışır.
diff --git a/docs/tr/docs/tutorial/body-multiple-params.md b/docs/tr/docs/tutorial/body-multiple-params.md
index 29970ca40e..4cd381b869 100644
--- a/docs/tr/docs/tutorial/body-multiple-params.md
+++ b/docs/tr/docs/tutorial/body-multiple-params.md
@@ -106,12 +106,6 @@ Varsayılan olarak tekil değerler query parametresi olarak yorumlandığı içi
q: str | None = None
```
-Ya da Python 3.9'da:
-
-```Python
-q: Union[str, None] = None
-```
-
Örneğin:
{* ../../docs_src/body_multiple_params/tutorial004_an_py310.py hl[28] *}
diff --git a/docs/tr/docs/tutorial/body-nested-models.md b/docs/tr/docs/tutorial/body-nested-models.md
index b4ffef3f15..b661d175d6 100644
--- a/docs/tr/docs/tutorial/body-nested-models.md
+++ b/docs/tr/docs/tutorial/body-nested-models.md
@@ -95,7 +95,7 @@ Yine, sadece bu tanımı yaparak **FastAPI** ile şunları elde edersiniz:
`str`, `int`, `float` vb. normal tekil tiplerin yanında, `str`’den türeyen daha karmaşık tekil tipleri de kullanabilirsiniz.
-Tüm seçenekleri görmek için
Pydantic Type Overview sayfasına göz atın. Sonraki bölümde bazı örnekleri göreceksiniz.
+Tüm seçenekleri görmek için
Pydantic Türlerine Genel Bakış sayfasına göz atın. Sonraki bölümde bazı örnekleri göreceksiniz.
Örneğin `Image` modelinde bir `url` alanımız olduğuna göre, bunu `str` yerine Pydantic’in `HttpUrl` tipinden bir instance olacak şekilde tanımlayabiliriz:
@@ -163,7 +163,7 @@ images: list[Image]
şu örnekte olduğu gibi:
-{* ../../docs_src/body_nested_models/tutorial008_py39.py hl[13] *}
+{* ../../docs_src/body_nested_models/tutorial008_py310.py hl[13] *}
## Her yerde editör desteği { #editor-support-everywhere }
@@ -193,7 +193,7 @@ Burada göreceğimiz şey de bu.
Bu durumda, `int` key’lere ve `float` value’lara sahip olduğu sürece herhangi bir `dict` kabul edersiniz:
-{* ../../docs_src/body_nested_models/tutorial009_py39.py hl[7] *}
+{* ../../docs_src/body_nested_models/tutorial009_py310.py hl[7] *}
/// tip | İpucu
diff --git a/docs/tr/docs/tutorial/body.md b/docs/tr/docs/tutorial/body.md
index 0557ef737a..47fee67014 100644
--- a/docs/tr/docs/tutorial/body.md
+++ b/docs/tr/docs/tutorial/body.md
@@ -155,7 +155,7 @@ Fonksiyon parametreleri şu şekilde tanınır:
FastAPI, `q` değerinin zorunlu olmadığını `= None` default değerinden anlayacaktır.
-`str | None` (Python 3.10+) veya `Union[str, None]` (Python 3.9+) içindeki `Union`, FastAPI tarafından bu değerin zorunlu olmadığını belirlemek için kullanılmaz; FastAPI bunun zorunlu olmadığını `= None` default değeri olduğu için bilir.
+`str | None`, FastAPI tarafından bu değerin zorunlu olmadığını belirlemek için kullanılmaz; FastAPI bunun zorunlu olmadığını `= None` default değeri olduğu için bilir.
Ancak type annotation'larını eklemek, editor'ünüzün size daha iyi destek vermesini ve hataları yakalamasını sağlar.
diff --git a/docs/tr/docs/tutorial/cookie-param-models.md b/docs/tr/docs/tutorial/cookie-param-models.md
index a5bf515609..0fa399c6ae 100644
--- a/docs/tr/docs/tutorial/cookie-param-models.md
+++ b/docs/tr/docs/tutorial/cookie-param-models.md
@@ -1,18 +1,18 @@
-# Cookie Parameter Models { #cookie-parameter-models }
+# Cookie Parametre Modelleri { #cookie-parameter-models }
-Birbirleriyle ilişkili bir **cookie** grubunuz varsa, bunları tanımlamak için bir **Pydantic model** oluşturabilirsiniz.
+Birbirleriyle ilişkili bir **cookie** grubunuz varsa, bunları tanımlamak için bir **Pydantic model** oluşturabilirsiniz. 🍪
-Bu sayede **model'i yeniden kullanabilir**, **birden fazla yerde** tekrar tekrar kullanabilir ve tüm parametreler için validation ve metadata'yı tek seferde tanımlayabilirsiniz.
+Bu sayede **model'i yeniden kullanabilir**, **birden fazla yerde** tekrar tekrar kullanabilir ve tüm parametreler için validation ve metadata'yı tek seferde tanımlayabilirsiniz. 😎
/// note | Not
-Bu özellik FastAPI `0.115.0` sürümünden beri desteklenmektedir.
+This is supported since FastAPI version `0.115.0`. 🤓
///
/// tip | İpucu
-Aynı teknik `Query`, `Cookie` ve `Header` için de geçerlidir.
+Aynı teknik `Query`, `Cookie` ve `Header` için de geçerlidir. 😎
///
@@ -42,11 +42,11 @@ Ancak verileri **doldurup** "Execute" düğmesine tıklasanız bile, docs UI **J
///
-## Fazladan Cookies'leri Yasaklayın { #forbid-extra-cookies }
+## Fazladan Cookie'leri Yasaklayın { #forbid-extra-cookies }
Bazı özel kullanım senaryolarında (muhtemelen çok yaygın değildir) almak istediğiniz cookie'leri **kısıtlamak** isteyebilirsiniz.
-API'niz artık kendi
cookie consent'ını kontrol etme gücüne sahip.
+API'niz artık kendi
cookie onayı'nı kontrol etme gücüne sahip. 🤪🍪
Pydantic'in model configuration'ını kullanarak `extra` olan herhangi bir field'ı `forbid` edebilirsiniz:
@@ -54,9 +54,9 @@ Pydantic'in model configuration'ını kullanarak `extra` olan herhangi bir field
Bir client **fazladan cookie** göndermeye çalışırsa, bir **error** response alır.
-Onayınızı almak için bunca çaba harcayan zavallı cookie banner'ları...
API'nin bunu reddetmesi için.
+Onayınızı almak için bunca çaba harcayan zavallı cookie banner'ları...
API'nin bunu reddetmesi için. 🍪
-Örneğin client, değeri `good-list-please` olan bir `santa_tracker` cookie'si göndermeye çalışırsa, client `santa_tracker`
cookie is not allowed diyen bir **error** response alır:
+Örneğin client, değeri `good-list-please` olan bir `santa_tracker` cookie'si göndermeye çalışırsa, client `santa_tracker`
cookie'ye izin verilmiyor diyen bir **error** response alır:
```json
{
@@ -73,4 +73,4 @@ Onayınızı almak için bunca çaba harcayan zavallı cookie banner'ları...
**cookies** tanımlamak için **Pydantic model**'lerini kullanabilirsiniz. 😎
+**FastAPI**'de **cookie** tanımlamak için **Pydantic model**'lerini kullanabilirsiniz. 😎
diff --git a/docs/tr/docs/tutorial/cookie-params.md b/docs/tr/docs/tutorial/cookie-params.md
index 18eedab7f0..28b57fd7e1 100644
--- a/docs/tr/docs/tutorial/cookie-params.md
+++ b/docs/tr/docs/tutorial/cookie-params.md
@@ -1,4 +1,4 @@
-# Çerez (Cookie) Parametreleri { #cookie-parameters }
+# Cookie (Çerez) Parametreleri { #cookie-parameters }
`Query` ve `Path` parametrelerini tanımladığınız şekilde Cookie parametreleri tanımlayabilirsiniz.
@@ -26,20 +26,20 @@ Ancak `fastapi`'dan `Query`, `Path`, `Cookie` ve diğerlerini import ettiğinizd
/// info | Bilgi
-Çerezleri tanımlamak için `Cookie` kullanmanız gerekir, aksi halde parametreler query parametreleri olarak yorumlanır.
+Cookie'leri tanımlamak için `Cookie` kullanmanız gerekir, aksi halde parametreler query parametreleri olarak yorumlanır.
///
/// info | Bilgi
-**Tarayıcılar çerezleri** özel şekillerde ve arka planda işlediği için, **JavaScript**'in onlara dokunmasına kolayca izin **vermezler**.
+**Tarayıcılar cookie'leri** özel şekillerde ve arka planda işlediği için, **JavaScript**'in onlara dokunmasına kolayca izin **vermezler**.
-`/docs` adresindeki **API docs UI**'a giderseniz, *path operation*'larınız için çerezlerin **dokümantasyonunu** görebilirsiniz.
+`/docs` adresindeki **API docs UI**'a giderseniz, *path operation*'larınız için cookie'lerin **dokümantasyonunu** görebilirsiniz.
-Ancak **veriyi doldurup** "Execute" düğmesine tıklasanız bile, docs UI **JavaScript** ile çalıştığı için çerezler gönderilmez ve herhangi bir değer yazmamışsınız gibi bir **hata** mesajı görürsünüz.
+Ancak **veriyi doldurup** "Execute" düğmesine tıklasanız bile, docs UI **JavaScript** ile çalıştığı için cookie'ler gönderilmez ve herhangi bir değer yazmamışsınız gibi bir **hata** mesajı görürsünüz.
///
## Özet { #recap }
-`Query` ve `Path` ile aynı ortak deseni kullanarak, çerezleri `Cookie` ile tanımlayın.
+`Query` ve `Path` ile aynı ortak deseni kullanarak, cookie'leri `Cookie` ile tanımlayın.
diff --git a/docs/tr/docs/tutorial/cors.md b/docs/tr/docs/tutorial/cors.md
index aae560022a..c3c853fddf 100644
--- a/docs/tr/docs/tutorial/cors.md
+++ b/docs/tr/docs/tutorial/cors.md
@@ -46,7 +46,7 @@ Ayrıca backend’in şunlara izin verip vermediğini de belirtebilirsiniz:
* Belirli HTTP method’ları (`POST`, `PUT`) veya wildcard `"*"` ile hepsini.
* Belirli HTTP header’ları veya wildcard `"*"` ile hepsini.
-{* ../../docs_src/cors/tutorial001_py39.py hl[2,6:11,13:19] *}
+{* ../../docs_src/cors/tutorial001_py310.py hl[2,6:11,13:19] *}
`CORSMiddleware` implementasyonu tarafından kullanılan varsayılan parametreler kısıtlayıcıdır; bu nedenle tarayıcıların Cross-Domain bağlamında kullanmasına izin vermek için belirli origin’leri, method’ları veya header’ları açıkça etkinleştirmeniz gerekir.
@@ -78,7 +78,7 @@ Bu durumda middleware gelen request’i intercept eder ve uygun CORS header’la
## Daha Fazla Bilgi { #more-info }
-CORS hakkında daha fazla bilgi için Mozilla CORS dokümantasyonuna bakın.
+
CORS hakkında daha fazla bilgi için
Mozilla CORS dokümantasyonuna bakın.
/// note | Teknik Detaylar
diff --git a/docs/tr/docs/tutorial/debugging.md b/docs/tr/docs/tutorial/debugging.md
index 54d5c9252a..839277b6db 100644
--- a/docs/tr/docs/tutorial/debugging.md
+++ b/docs/tr/docs/tutorial/debugging.md
@@ -6,7 +6,7 @@ Visual Studio Code veya PyCharm gibi editörünüzde debugger'ı bağlayabilirsi
FastAPI uygulamanızda `uvicorn`'ı import edip doğrudan çalıştırın:
-{* ../../docs_src/debugging/tutorial001_py39.py hl[1,15] *}
+{* ../../docs_src/debugging/tutorial001_py310.py hl[1,15] *}
### `__name__ == "__main__"` Hakkında { #about-name-main }
diff --git a/docs/tr/docs/tutorial/dependencies/classes-as-dependencies.md b/docs/tr/docs/tutorial/dependencies/classes-as-dependencies.md
index 9ee57cb291..989e93b406 100644
--- a/docs/tr/docs/tutorial/dependencies/classes-as-dependencies.md
+++ b/docs/tr/docs/tutorial/dependencies/classes-as-dependencies.md
@@ -101,7 +101,7 @@ Artık bu class'ı kullanarak dependency'nizi tanımlayabilirsiniz.
Yukarıdaki kodda `CommonQueryParams`'ı iki kez yazdığımıza dikkat edin:
-//// tab | Python 3.9+
+//// tab | Python 3.10+
```Python
commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]
@@ -109,7 +109,7 @@ commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]
////
-//// tab | Python 3.9+ Annotated Olmadan
+//// tab | Python 3.10+ Annotated Olmadan
/// tip | İpucu
@@ -137,7 +137,7 @@ FastAPI tanımlanan parametreleri buradan çıkarır ve aslında çağıracağı
Bu durumda, şuradaki ilk `CommonQueryParams`:
-//// tab | Python 3.9+
+//// tab | Python 3.10+
```Python
commons: Annotated[CommonQueryParams, ...
@@ -145,7 +145,7 @@ commons: Annotated[CommonQueryParams, ...
////
-//// tab | Python 3.9+ Annotated Olmadan
+//// tab | Python 3.10+ Annotated Olmadan
/// tip | İpucu
@@ -163,7 +163,7 @@ commons: CommonQueryParams ...
Hatta şunu bile yazabilirsiniz:
-//// tab | Python 3.9+
+//// tab | Python 3.10+
```Python
commons: Annotated[Any, Depends(CommonQueryParams)]
@@ -171,7 +171,7 @@ commons: Annotated[Any, Depends(CommonQueryParams)]
////
-//// tab | Python 3.9+ Annotated Olmadan
+//// tab | Python 3.10+ Annotated Olmadan
/// tip | İpucu
@@ -197,7 +197,7 @@ Ancak type'ı belirtmeniz önerilir; böylece editor'ünüz `commons` parametres
Ama burada bir miktar kod tekrarımız olduğunu görüyorsunuz; `CommonQueryParams`'ı iki kez yazıyoruz:
-//// tab | Python 3.9+
+//// tab | Python 3.10+
```Python
commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]
@@ -205,7 +205,7 @@ commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]
////
-//// tab | Python 3.9+ Annotated Olmadan
+//// tab | Python 3.10+ Annotated Olmadan
/// tip | İpucu
@@ -225,7 +225,7 @@ Bu özel durumlarda şunu yapabilirsiniz:
Şunu yazmak yerine:
-//// tab | Python 3.9+
+//// tab | Python 3.10+
```Python
commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]
@@ -233,7 +233,7 @@ commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]
////
-//// tab | Python 3.9+ Annotated Olmadan
+//// tab | Python 3.10+ Annotated Olmadan
/// tip | İpucu
@@ -249,7 +249,7 @@ commons: CommonQueryParams = Depends(CommonQueryParams)
...şunu yazarsınız:
-//// tab | Python 3.9+
+//// tab | Python 3.10+
```Python
commons: Annotated[CommonQueryParams, Depends()]
@@ -257,7 +257,7 @@ commons: Annotated[CommonQueryParams, Depends()]
////
-//// tab | Python 3.9+ Annotated Olmadan
+//// tab | Python 3.10+ Annotated Olmadan
/// tip | İpucu
diff --git a/docs/tr/docs/tutorial/dependencies/dependencies-in-path-operation-decorators.md b/docs/tr/docs/tutorial/dependencies/dependencies-in-path-operation-decorators.md
index 4903aec4a4..cbb6363424 100644
--- a/docs/tr/docs/tutorial/dependencies/dependencies-in-path-operation-decorators.md
+++ b/docs/tr/docs/tutorial/dependencies/dependencies-in-path-operation-decorators.md
@@ -14,7 +14,7 @@ Bu gibi durumlarda, `Depends` ile bir *path operation function* parametresi tan
Bu, `Depends()` öğelerinden oluşan bir `list` olmalıdır:
-{* ../../docs_src/dependencies/tutorial006_an_py39.py hl[19] *}
+{* ../../docs_src/dependencies/tutorial006_an_py310.py hl[19] *}
Bu dependency'ler normal dependency'lerle aynı şekilde çalıştırılır/çözülür. Ancak (eğer bir değer döndürüyorlarsa) bu değer *path operation function*'ınıza aktarılmaz.
@@ -44,13 +44,13 @@ Normalde kullandığınız aynı dependency *function*'larını burada da kullan
Request gereksinimleri (header'lar gibi) veya başka alt dependency'ler tanımlayabilirler:
-{* ../../docs_src/dependencies/tutorial006_an_py39.py hl[8,13] *}
+{* ../../docs_src/dependencies/tutorial006_an_py310.py hl[8,13] *}
### Exception Fırlatmak { #raise-exceptions }
Bu dependency'ler, normal dependency'lerde olduğu gibi `raise` ile exception fırlatabilir:
-{* ../../docs_src/dependencies/tutorial006_an_py39.py hl[10,15] *}
+{* ../../docs_src/dependencies/tutorial006_an_py310.py hl[10,15] *}
### Return Değerleri { #return-values }
@@ -58,7 +58,7 @@ Ayrıca değer döndürebilirler ya da döndürmeyebilirler; dönen değer kulla
Yani başka bir yerde zaten kullandığınız, değer döndüren normal bir dependency'yi tekrar kullanabilirsiniz; değer kullanılmasa bile dependency çalıştırılacaktır:
-{* ../../docs_src/dependencies/tutorial006_an_py39.py hl[11,16] *}
+{* ../../docs_src/dependencies/tutorial006_an_py310.py hl[11,16] *}
## Bir *Path Operation* Grubu İçin Dependency'ler { #dependencies-for-a-group-of-path-operations }
diff --git a/docs/tr/docs/tutorial/dependencies/dependencies-with-yield.md b/docs/tr/docs/tutorial/dependencies/dependencies-with-yield.md
index bd025f799b..445110ae02 100644
--- a/docs/tr/docs/tutorial/dependencies/dependencies-with-yield.md
+++ b/docs/tr/docs/tutorial/dependencies/dependencies-with-yield.md
@@ -1,12 +1,12 @@
# `yield` ile Dependency'ler { #dependencies-with-yield }
-FastAPI, işini bitirdikten sonra
ek adımlar çalıştıran dependency'leri destekler.
+FastAPI, işini bitirdikten sonra
ek adımlar çalıştıran dependency'leri destekler.
Bunu yapmak için `return` yerine `yield` kullanın ve ek adımları (kodu) `yield` satırından sonra yazın.
/// tip | İpucu
-Her dependency için yalnızca **bir kez** `yield` kullandığınızdan emin olun.
+Her dependency için yalnızca bir kez `yield` kullandığınızdan emin olun.
///
@@ -29,15 +29,15 @@ Hatta FastAPI bu iki decorator'ı içeride (internally) kullanır.
Response oluşturulmadan önce yalnızca `yield` satırına kadar olan (ve `yield` dahil) kod çalıştırılır:
-{* ../../docs_src/dependencies/tutorial007_py39.py hl[2:4] *}
+{* ../../docs_src/dependencies/tutorial007_py310.py hl[2:4] *}
`yield` edilen değer, *path operation*'lara ve diğer dependency'lere enjekte edilen (injected) değerdir:
-{* ../../docs_src/dependencies/tutorial007_py39.py hl[4] *}
+{* ../../docs_src/dependencies/tutorial007_py310.py hl[4] *}
Response'dan sonra `yield` satırını takip eden kod çalıştırılır:
-{* ../../docs_src/dependencies/tutorial007_py39.py hl[5:6] *}
+{* ../../docs_src/dependencies/tutorial007_py310.py hl[5:6] *}
/// tip | İpucu
@@ -57,7 +57,7 @@ Dolayısıyla `except SomeException` ile dependency içinde o spesifik exception
Aynı şekilde, exception olsun ya da olmasın çıkış (exit) adımlarının çalıştırılmasını garanti etmek için `finally` kullanabilirsiniz.
-{* ../../docs_src/dependencies/tutorial007_py39.py hl[3,5] *}
+{* ../../docs_src/dependencies/tutorial007_py310.py hl[3,5] *}
## `yield` ile Alt Dependency'ler { #sub-dependencies-with-yield }
@@ -67,7 +67,7 @@ Her boyutta ve şekilde alt dependency'ler ve alt dependency "ağaçları" (tree
Örneğin, `dependency_c`, `dependency_b`'ye; `dependency_b` de `dependency_a`'ya bağlı olabilir:
-{* ../../docs_src/dependencies/tutorial008_an_py39.py hl[6,14,22] *}
+{* ../../docs_src/dependencies/tutorial008_an_py310.py hl[6,14,22] *}
Ve hepsi `yield` kullanabilir.
@@ -75,7 +75,7 @@ Bu durumda `dependency_c`, exit code'unu çalıştırabilmek için `dependency_b
Aynı şekilde `dependency_b` de exit code'u için `dependency_a`'dan gelen değerin (burada `dep_a`) erişilebilir olmasına ihtiyaç duyar.
-{* ../../docs_src/dependencies/tutorial008_an_py39.py hl[18:19,26:27] *}
+{* ../../docs_src/dependencies/tutorial008_an_py310.py hl[18:19,26:27] *}
Benzer şekilde, bazı dependency'ler `yield`, bazıları `return` kullanabilir ve bunların bazıları diğerlerine bağlı olabilir.
@@ -109,7 +109,7 @@ Ama ihtiyaç duyarsanız diye burada. 🤓
///
-{* ../../docs_src/dependencies/tutorial008b_an_py39.py hl[18:22,31] *}
+{* ../../docs_src/dependencies/tutorial008b_an_py310.py hl[18:22,31] *}
Exception yakalayıp buna göre özel bir response oluşturmak istiyorsanız bir [Custom Exception Handler](../handling-errors.md#install-custom-exception-handlers){.internal-link target=_blank} oluşturun.
@@ -117,7 +117,7 @@ Exception yakalayıp buna göre özel bir response oluşturmak istiyorsanız bir
`yield` kullanan bir dependency içinde `except` ile bir exception yakalar ve bunu tekrar fırlatmazsanız (ya da yeni bir exception fırlatmazsanız), FastAPI normal Python'da olduğu gibi bir exception olduğunu fark edemez:
-{* ../../docs_src/dependencies/tutorial008c_an_py39.py hl[15:16] *}
+{* ../../docs_src/dependencies/tutorial008c_an_py310.py hl[15:16] *}
Bu durumda client, biz `HTTPException` veya benzeri bir şey fırlatmadığımız için olması gerektiği gibi *HTTP 500 Internal Server Error* response'u görür; ancak server **hiç log üretmez** ve hatanın ne olduğuna dair başka bir işaret de olmaz. 😱
@@ -127,7 +127,7 @@ Bu durumda client, biz `HTTPException` veya benzeri bir şey fırlatmadığımı
Aynı exception'ı `raise` ile tekrar fırlatabilirsiniz:
-{* ../../docs_src/dependencies/tutorial008d_an_py39.py hl[17] *}
+{* ../../docs_src/dependencies/tutorial008d_an_py310.py hl[17] *}
Artık client yine aynı *HTTP 500 Internal Server Error* response'unu alır, ama server log'larda bizim özel `InternalError`'ımızı görür. 😎
@@ -190,7 +190,7 @@ Normalde `yield` kullanan dependency'lerin exit code'u, client'a response gönde
Ama *path operation function*'dan döndükten sonra dependency'yi kullanmayacağınızı biliyorsanız, `Depends(scope="function")` kullanarak FastAPI'ye dependency'yi *path operation function* döndükten sonra kapatmasını, ancak **response gönderilmeden önce** kapatmasını söyleyebilirsiniz.
-{* ../../docs_src/dependencies/tutorial008e_an_py39.py hl[12,16] *}
+{* ../../docs_src/dependencies/tutorial008e_an_py310.py hl[12,16] *}
`Depends()` şu değerleri alabilen bir `scope` parametresi alır:
@@ -234,7 +234,6 @@ participant operation as Path Operation
`yield` kullanan dependency'ler, zaman içinde farklı kullanım senaryolarını kapsamak ve bazı sorunları düzeltmek için gelişti.
FastAPI'nin farklı sürümlerinde nelerin değiştiğini görmek isterseniz, advanced guide'da şu bölümü okuyabilirsiniz: [Advanced Dependencies - Dependencies with `yield`, `HTTPException`, `except` and Background Tasks](../../advanced/advanced-dependencies.md#dependencies-with-yield-httpexception-except-and-background-tasks){.internal-link target=_blank}.
-
## Context Managers { #context-managers }
### "Context Managers" Nedir? { #what-are-context-managers }
@@ -269,7 +268,7 @@ Python'da Context Manager'ları,
Dependency Injection** sistemine sahiptir.
+**FastAPI**, çok güçlü ama aynı zamanda sezgisel bir **Bağımlılık Enjeksiyonu** sistemine sahiptir.
Kullanımı çok basit olacak şekilde tasarlanmıştır ve herhangi bir geliştiricinin diğer bileşenleri **FastAPI** ile entegre etmesini kolaylaştırır.
diff --git a/docs/tr/docs/tutorial/dependencies/sub-dependencies.md b/docs/tr/docs/tutorial/dependencies/sub-dependencies.md
index 184db839bc..ab196d829f 100644
--- a/docs/tr/docs/tutorial/dependencies/sub-dependencies.md
+++ b/docs/tr/docs/tutorial/dependencies/sub-dependencies.md
@@ -58,11 +58,11 @@ query_extractor --> query_or_cookie_extractor --> read_query
Bağımlılıklarınızdan biri aynı *path operation* için birden fazla kez tanımlanırsa (örneğin birden fazla bağımlılığın ortak bir alt bağımlılığı varsa), **FastAPI** o alt bağımlılığı request başına yalnızca bir kez çağıracağını bilir.
-Dönen değeri bir "cache" içinde saklar ve aynı request içinde buna ihtiyaç duyan tüm "dependant"lara aktarır; böylece aynı request için bağımlılığı tekrar tekrar çağırmaz.
+Dönen değeri bir "önbellek" içinde saklar ve aynı request içinde buna ihtiyaç duyan tüm "dependant"lara aktarır; böylece aynı request için bağımlılığı tekrar tekrar çağırmaz.
Daha ileri bir senaryoda, "cached" değeri kullanmak yerine aynı request içinde her adımda (muhtemelen birden fazla kez) bağımlılığın çağrılması gerektiğini biliyorsanız, `Depends` kullanırken `use_cache=False` parametresini ayarlayabilirsiniz:
-//// tab | Python 3.9+
+//// tab | Python 3.10+
```Python hl_lines="1"
async def needy_dependency(fresh_value: Annotated[str, Depends(get_value, use_cache=False)]):
@@ -71,7 +71,7 @@ async def needy_dependency(fresh_value: Annotated[str, Depends(get_value, use_ca
////
-//// tab | Python 3.9+ Annotated olmayan
+//// tab | Python 3.10+ Annotated olmayan
/// tip | İpucu
diff --git a/docs/tr/docs/tutorial/extra-data-types.md b/docs/tr/docs/tutorial/extra-data-types.md
index 464d3a82a9..534efefc49 100644
--- a/docs/tr/docs/tutorial/extra-data-types.md
+++ b/docs/tr/docs/tutorial/extra-data-types.md
@@ -23,32 +23,32 @@ Kullanabileceğiniz ek veri tiplerinden bazıları şunlardır:
* `UUID`:
* Birçok veritabanı ve sistemde ID olarak yaygın kullanılan, standart bir "Universally Unique Identifier".
- * request ve response'larda `str` olarak temsil edilir.
+ * request'lerde ve response'larda `str` olarak temsil edilir.
* `datetime.datetime`:
* Python `datetime.datetime`.
- * request ve response'larda ISO 8601 formatında bir `str` olarak temsil edilir, örn: `2008-09-15T15:53:00+05:00`.
+ * request'lerde ve response'larda ISO 8601 formatında bir `str` olarak temsil edilir, örn: `2008-09-15T15:53:00+05:00`.
* `datetime.date`:
* Python `datetime.date`.
- * request ve response'larda ISO 8601 formatında bir `str` olarak temsil edilir, örn: `2008-09-15`.
+ * request'lerde ve response'larda ISO 8601 formatında bir `str` olarak temsil edilir, örn: `2008-09-15`.
* `datetime.time`:
* Python `datetime.time`.
- * request ve response'larda ISO 8601 formatında bir `str` olarak temsil edilir, örn: `14:23:55.003`.
+ * request'lerde ve response'larda ISO 8601 formatında bir `str` olarak temsil edilir, örn: `14:23:55.003`.
* `datetime.timedelta`:
* Python `datetime.timedelta`.
- * request ve response'larda toplam saniye sayısını ifade eden bir `float` olarak temsil edilir.
+ * request'lerde ve response'larda toplam saniye sayısını ifade eden bir `float` olarak temsil edilir.
* Pydantic, bunu ayrıca bir "ISO 8601 time diff encoding" olarak temsil etmeye de izin verir, daha fazla bilgi için dokümanlara bakın.
* `frozenset`:
- * request ve response'larda, `set` ile aynı şekilde ele alınır:
+ * request'lerde ve response'larda, `set` ile aynı şekilde ele alınır:
* request'lerde bir list okunur, tekrarlar kaldırılır ve `set`'e dönüştürülür.
* response'larda `set`, `list`'e dönüştürülür.
* Üretilen schema, `set` değerlerinin benzersiz olduğunu belirtir (JSON Schema'nın `uniqueItems` özelliğini kullanarak).
* `bytes`:
* Standart Python `bytes`.
- * request ve response'larda `str` gibi ele alınır.
+ * request'lerde ve response'larda `str` gibi ele alınır.
* Üretilen schema, bunun `binary` "format"ına sahip bir `str` olduğunu belirtir.
* `Decimal`:
* Standart Python `Decimal`.
- * request ve response'larda `float` ile aynı şekilde işlenir.
+ * request'lerde ve response'larda `float` ile aynı şekilde işlenir.
* Geçerli tüm Pydantic veri tiplerini burada görebilirsiniz:
Pydantic data types.
## Örnek { #example }
diff --git a/docs/tr/docs/tutorial/extra-models.md b/docs/tr/docs/tutorial/extra-models.md
index 9aae28e05f..f2bcf7a010 100644
--- a/docs/tr/docs/tutorial/extra-models.md
+++ b/docs/tr/docs/tutorial/extra-models.md
@@ -8,7 +8,7 @@ Bu durum özellikle kullanıcı modellerinde sık görülür, çünkü:
* **output modeli** `password` içermemelidir.
* **database modeli** büyük ihtimalle hash'lenmiş bir `password` tutmalıdır.
-/// danger
+/// danger | Tehlike
Kullanıcının düz metin (plaintext) `password`'ünü asla saklamayın. Her zaman sonradan doğrulayabileceğiniz "güvenli bir hash" saklayın.
@@ -132,7 +132,7 @@ UserInDB(
)
```
-/// warning
+/// warning | Uyarı
Ek destek fonksiyonları olan `fake_password_hasher` ve `fake_save_user` sadece verinin olası bir akışını göstermek içindir; elbette gerçek bir güvenlik sağlamazlar.
@@ -164,7 +164,7 @@ OpenAPI'de bu `anyOf` ile tanımlanır.
Bunu yapmak için standart Python type hint'i olan
`typing.Union`'ı kullanın:
-/// note
+/// note | Not
Bir
`Union` tanımlarken en spesifik type'ı önce, daha az spesifik olanı sonra ekleyin. Aşağıdaki örnekte daha spesifik olan `PlaneItem`, `Union[PlaneItem, CarItem]` içinde `CarItem`'dan önce gelir.
@@ -190,9 +190,9 @@ Ancak bunu `response_model=PlaneItem | CarItem` atamasına koyarsak hata alırı
Aynı şekilde, nesne listesi döndüren response'ları da tanımlayabilirsiniz.
-Bunun için standart Python `typing.List`'i (ya da Python 3.9 ve üzeri için sadece `list`) kullanın:
+Bunun için standart Python `list`'i kullanın:
-{* ../../docs_src/extra_models/tutorial004_py39.py hl[18] *}
+{* ../../docs_src/extra_models/tutorial004_py310.py hl[18] *}
## Rastgele `dict` ile Response { #response-with-arbitrary-dict }
@@ -200,9 +200,9 @@ Bir Pydantic modeli kullanmadan, sadece key ve value type'larını belirterek d
Bu, geçerli field/attribute adlarını (Pydantic modeli için gerekli olurdu) önceden bilmiyorsanız kullanışlıdır.
-Bu durumda `typing.Dict` (ya da Python 3.9 ve üzeri için sadece `dict`) kullanabilirsiniz:
+Bu durumda `dict` kullanabilirsiniz:
-{* ../../docs_src/extra_models/tutorial005_py39.py hl[6] *}
+{* ../../docs_src/extra_models/tutorial005_py310.py hl[6] *}
## Özet { #recap }
diff --git a/docs/tr/docs/tutorial/first-steps.md b/docs/tr/docs/tutorial/first-steps.md
index 332f5c5590..4b645778f7 100644
--- a/docs/tr/docs/tutorial/first-steps.md
+++ b/docs/tr/docs/tutorial/first-steps.md
@@ -2,7 +2,7 @@
En sade FastAPI dosyası şu şekilde görünür:
-{* ../../docs_src/first_steps/tutorial001_py39.py *}
+{* ../../docs_src/first_steps/tutorial001_py310.py *}
Yukarıdakini `main.py` adlı bir dosyaya kopyalayın.
@@ -183,7 +183,7 @@ Bu kadar! Artık uygulamanıza o URL üzerinden erişebilirsiniz. ✨
### Adım 1: `FastAPI` import edin { #step-1-import-fastapi }
-{* ../../docs_src/first_steps/tutorial001_py39.py hl[1] *}
+{* ../../docs_src/first_steps/tutorial001_py310.py hl[1] *}
`FastAPI`, API'nız için tüm işlevselliği sağlayan bir Python class'ıdır.
@@ -197,7 +197,7 @@ Bu kadar! Artık uygulamanıza o URL üzerinden erişebilirsiniz. ✨
### Adım 2: bir `FastAPI` "instance"ı oluşturun { #step-2-create-a-fastapi-instance }
-{* ../../docs_src/first_steps/tutorial001_py39.py hl[3] *}
+{* ../../docs_src/first_steps/tutorial001_py310.py hl[3] *}
Burada `app` değişkeni `FastAPI` class'ının bir "instance"ı olacaktır.
@@ -266,12 +266,12 @@ Biz de bunlara "**operation**" diyeceğiz.
#### Bir *path operation decorator* tanımlayın { #define-a-path-operation-decorator }
-{* ../../docs_src/first_steps/tutorial001_py39.py hl[6] *}
+{* ../../docs_src/first_steps/tutorial001_py310.py hl[6] *}
`@app.get("/")`, **FastAPI**'a hemen altındaki fonksiyonun şuraya giden request'leri ele almakla sorumlu olduğunu söyler:
* path `/`
-*
get operation kullanarak
+*
get operation kullanarak
/// info | `@decorator` Bilgisi
@@ -320,7 +320,7 @@ Bu bizim "**path operation function**"ımız:
* **operation**: `get`.
* **function**: "decorator"ün altındaki fonksiyondur (`@app.get("/")`'in altındaki).
-{* ../../docs_src/first_steps/tutorial001_py39.py hl[7] *}
+{* ../../docs_src/first_steps/tutorial001_py310.py hl[7] *}
Bu bir Python fonksiyonudur.
@@ -332,7 +332,7 @@ Bu durumda, bu bir `async` fonksiyondur.
Bunu `async def` yerine normal bir fonksiyon olarak da tanımlayabilirsiniz:
-{* ../../docs_src/first_steps/tutorial003_py39.py hl[7] *}
+{* ../../docs_src/first_steps/tutorial003_py310.py hl[7] *}
/// note | Not
@@ -342,7 +342,7 @@ Eğer farkı bilmiyorsanız, [Async: *"Aceleniz mi var?"*](../async.md#in-a-hurr
### Adım 5: içeriği döndürün { #step-5-return-the-content }
-{* ../../docs_src/first_steps/tutorial001_py39.py hl[8] *}
+{* ../../docs_src/first_steps/tutorial001_py310.py hl[8] *}
Bir `dict`, `list`, `str`, `int` vb. tekil değerler döndürebilirsiniz.
diff --git a/docs/tr/docs/tutorial/handling-errors.md b/docs/tr/docs/tutorial/handling-errors.md
index a4d6937922..a74e1a76ad 100644
--- a/docs/tr/docs/tutorial/handling-errors.md
+++ b/docs/tr/docs/tutorial/handling-errors.md
@@ -25,7 +25,7 @@ Client’a hata içeren HTTP response’ları döndürmek için `HTTPException`
### `HTTPException`’ı Import Etme { #import-httpexception }
-{* ../../docs_src/handling_errors/tutorial001_py39.py hl[1] *}
+{* ../../docs_src/handling_errors/tutorial001_py310.py hl[1] *}
### Kodunuzda Bir `HTTPException` Raise Etme { #raise-an-httpexception-in-your-code }
@@ -39,7 +39,7 @@ Bir değer döndürmek yerine exception raise etmenin faydası, Dependencies ve
Bu örnekte, client var olmayan bir ID ile bir item istediğinde, `404` status code’u ile bir exception raise edelim:
-{* ../../docs_src/handling_errors/tutorial001_py39.py hl[11] *}
+{* ../../docs_src/handling_errors/tutorial001_py310.py hl[11] *}
### Ortaya Çıkan Response { #the-resulting-response }
@@ -77,7 +77,7 @@ Muhtemelen bunu doğrudan kendi kodunuzda kullanmanız gerekmeyecek.
Ama ileri seviye bir senaryo için ihtiyaç duyarsanız, özel header’lar ekleyebilirsiniz:
-{* ../../docs_src/handling_errors/tutorial002_py39.py hl[14] *}
+{* ../../docs_src/handling_errors/tutorial002_py310.py hl[14] *}
## Özel Exception Handler’ları Kurmak { #install-custom-exception-handlers }
@@ -89,7 +89,7 @@ Ve bu exception’ı FastAPI ile global olarak handle etmek istiyorsunuz.
`@app.exception_handler()` ile özel bir exception handler ekleyebilirsiniz:
-{* ../../docs_src/handling_errors/tutorial003_py39.py hl[5:7,13:18,24] *}
+{* ../../docs_src/handling_errors/tutorial003_py310.py hl[5:7,13:18,24] *}
Burada `/unicorns/yolo` için request atarsanız, *path operation* bir `UnicornException` `raise` eder.
@@ -127,7 +127,7 @@ Override etmek için `RequestValidationError`’ı import edin ve exception hand
Exception handler, bir `Request` ve exception’ı alır.
-{* ../../docs_src/handling_errors/tutorial004_py39.py hl[2,14:19] *}
+{* ../../docs_src/handling_errors/tutorial004_py310.py hl[2,14:19] *}
Artık `/items/foo`’ya giderseniz, şu varsayılan JSON hatası yerine:
@@ -159,7 +159,7 @@ Benzer şekilde `HTTPException` handler’ını da override edebilirsiniz.
Örneğin bu hatalar için JSON yerine plain text response döndürmek isteyebilirsiniz:
-{* ../../docs_src/handling_errors/tutorial004_py39.py hl[3:4,9:11,25] *}
+{* ../../docs_src/handling_errors/tutorial004_py310.py hl[3:4,9:11,25] *}
/// note | Teknik Detaylar
@@ -183,7 +183,7 @@ Ancak bu, eğer sadece string’e çevirip bu bilgiyi doğrudan response olarak
Uygulamanızı geliştirirken body’yi log’lamak, debug etmek, kullanıcıya döndürmek vb. için bunu kullanabilirsiniz.
-{* ../../docs_src/handling_errors/tutorial005_py39.py hl[14] *}
+{* ../../docs_src/handling_errors/tutorial005_py310.py hl[14] *}
Şimdi şu gibi geçersiz bir item göndermeyi deneyin:
@@ -239,6 +239,6 @@ from starlette.exceptions import HTTPException as StarletteHTTPException
Exception’ı, **FastAPI**’nin aynı varsayılan exception handler’larıyla birlikte kullanmak isterseniz, varsayılan exception handler’ları `fastapi.exception_handlers` içinden import edip yeniden kullanabilirsiniz:
-{* ../../docs_src/handling_errors/tutorial006_py39.py hl[2:5,15,21] *}
+{* ../../docs_src/handling_errors/tutorial006_py310.py hl[2:5,15,21] *}
Bu örnekte sadece oldukça açıklayıcı bir mesajla hatayı yazdırıyorsunuz; ama fikir anlaşılıyor. Exception’ı kullanıp ardından varsayılan exception handler’ları olduğu gibi yeniden kullanabilirsiniz.
diff --git a/docs/tr/docs/tutorial/index.md b/docs/tr/docs/tutorial/index.md
index f672c9e20b..6047e83ca4 100644
--- a/docs/tr/docs/tutorial/index.md
+++ b/docs/tr/docs/tutorial/index.md
@@ -62,7 +62,7 @@ Editörünüzde kullanmak FastAPI'nin avantajlarını gerçekten gösterir: ne k
İlk adım FastAPI'yi kurmaktır.
-Bir [virtual environment](../virtual-environments.md){.internal-link target=_blank} oluşturduğunuzdan emin olun, etkinleştirin ve ardından **FastAPI'yi kurun**:
+Bir [sanal ortam](../virtual-environments.md){.internal-link target=_blank} oluşturduğunuzdan emin olun, etkinleştirin ve ardından **FastAPI'yi kurun**:
diff --git a/docs/tr/docs/tutorial/metadata.md b/docs/tr/docs/tutorial/metadata.md
index dacd68cf56..0cc5adee4e 100644
--- a/docs/tr/docs/tutorial/metadata.md
+++ b/docs/tr/docs/tutorial/metadata.md
@@ -18,7 +18,7 @@ OpenAPI spesifikasyonunda ve otomatik API doküman arayüzlerinde kullanılan ş
Şu şekilde ayarlayabilirsiniz:
-{* ../../docs_src/metadata/tutorial001_py39.py hl[3:16, 19:32] *}
+{* ../../docs_src/metadata/tutorial001_py310.py hl[3:16, 19:32] *}
/// tip | İpucu
@@ -36,7 +36,7 @@ OpenAPI 3.1.0 ve FastAPI 0.99.0 sürümünden itibaren, `license_info` içinde `
Örneğin:
-{* ../../docs_src/metadata/tutorial001_1_py39.py hl[31] *}
+{* ../../docs_src/metadata/tutorial001_1_py310.py hl[31] *}
## Tag'ler için Metadata { #metadata-for-tags }
@@ -58,7 +58,7 @@ Her sözlük şunları içerebilir:
Tag'leriniz için metadata oluşturup `openapi_tags` parametresine geçin:
-{* ../../docs_src/metadata/tutorial004_py39.py hl[3:16,18] *}
+{* ../../docs_src/metadata/tutorial004_py310.py hl[3:16,18] *}
Açıklamaların içinde Markdown kullanabileceğinizi unutmayın; örneğin "login" kalın (**login**) ve "fancy" italik (_fancy_) olarak gösterilecektir.
@@ -72,7 +72,7 @@ Kullandığınız tüm tag'ler için metadata eklemek zorunda değilsiniz.
*path operation*'larınızı (ve `APIRouter`'ları) farklı tag'lere atamak için `tags` parametresini kullanın:
-{* ../../docs_src/metadata/tutorial004_py39.py hl[21,26] *}
+{* ../../docs_src/metadata/tutorial004_py310.py hl[21,26] *}
/// info | Bilgi
@@ -100,7 +100,7 @@ Ancak bunu `openapi_url` parametresiyle yapılandırabilirsiniz.
Örneğin `/api/v1/openapi.json` adresinden sunulacak şekilde ayarlamak için:
-{* ../../docs_src/metadata/tutorial002_py39.py hl[3] *}
+{* ../../docs_src/metadata/tutorial002_py310.py hl[3] *}
OpenAPI şemasını tamamen kapatmak isterseniz `openapi_url=None` ayarlayabilirsiniz; bu, onu kullanan dokümantasyon arayüzlerini de devre dışı bırakır.
@@ -117,4 +117,4 @@ Dahil gelen iki dokümantasyon arayüzünü yapılandırabilirsiniz:
Örneğin Swagger UI'yi `/documentation` adresinden sunup ReDoc'u kapatmak için:
-{* ../../docs_src/metadata/tutorial003_py39.py hl[3] *}
+{* ../../docs_src/metadata/tutorial003_py310.py hl[3] *}
diff --git a/docs/tr/docs/tutorial/middleware.md b/docs/tr/docs/tutorial/middleware.md
index 68222265e7..7ee0ef2491 100644
--- a/docs/tr/docs/tutorial/middleware.md
+++ b/docs/tr/docs/tutorial/middleware.md
@@ -31,7 +31,7 @@ Middleware fonksiyonu şunları alır:
* Ardından ilgili *path operation* tarafından üretilen `response`'u döndürür.
* Sonrasında `response`'u döndürmeden önce ayrıca değiştirebilirsiniz.
-{* ../../docs_src/middleware/tutorial001_py39.py hl[8:9,11,14] *}
+{* ../../docs_src/middleware/tutorial001_py310.py hl[8:9,11,14] *}
/// tip | İpucu
@@ -57,7 +57,7 @@ Ayrıca `response` üretildikten sonra, geri döndürmeden önce de kod çalış
Örneğin, request'i işleyip response üretmenin kaç saniye sürdüğünü içeren `X-Process-Time` adlı özel bir header ekleyebilirsiniz:
-{* ../../docs_src/middleware/tutorial001_py39.py hl[10,12:13] *}
+{* ../../docs_src/middleware/tutorial001_py310.py hl[10,12:13] *}
/// tip | İpucu
@@ -92,4 +92,4 @@ Bu stack davranışı, middleware'lerin öngörülebilir ve kontrol edilebilir b
Diğer middleware'ler hakkında daha fazlasını daha sonra [Advanced User Guide: Advanced Middleware](../advanced/middleware.md){.internal-link target=_blank} bölümünde okuyabilirsiniz.
-Bir sonraki bölümde, middleware ile
CORS'un nasıl ele alınacağını göreceksiniz.
+Bir sonraki bölümde, middleware ile
CORS'un nasıl ele alınacağını göreceksiniz.
diff --git a/docs/tr/docs/tutorial/path-operation-configuration.md b/docs/tr/docs/tutorial/path-operation-configuration.md
index 3fe24dc0a4..c65d3696f8 100644
--- a/docs/tr/docs/tutorial/path-operation-configuration.md
+++ b/docs/tr/docs/tutorial/path-operation-configuration.md
@@ -46,7 +46,7 @@ Bu durumlarda tag’leri bir `Enum` içinde tutmak mantıklı olabilir.
**FastAPI** bunu düz string’lerde olduğu gibi aynı şekilde destekler:
-{* ../../docs_src/path_operation_configuration/tutorial002b_py39.py hl[1,8:10,13,18] *}
+{* ../../docs_src/path_operation_configuration/tutorial002b_py310.py hl[1,8:10,13,18] *}
## Özet ve açıklama { #summary-and-description }
@@ -54,9 +54,9 @@ Bir `summary` ve `description` ekleyebilirsiniz:
{* ../../docs_src/path_operation_configuration/tutorial003_py310.py hl[17:18] *}
-## Docstring’den Description { #description-from-docstring }
+## Docstring’den Açıklama { #description-from-docstring }
-Açıklamalar genelde uzun olur ve birden fazla satıra yayılır; bu yüzden *path operation* açıklamasını, fonksiyonun içinde
docstring olarak tanımlayabilirsiniz; **FastAPI** de onu buradan okur.
+Açıklamalar genelde uzun olur ve birden fazla satıra yayılır; bu yüzden *path operation* açıklamasını, fonksiyonun içinde
docstring olarak tanımlayabilirsiniz; **FastAPI** de onu buradan okur.
Docstring içinde
Markdown yazabilirsiniz; doğru şekilde yorumlanır ve gösterilir (docstring girintisi dikkate alınarak).
@@ -90,9 +90,9 @@ Bu yüzden siz sağlamazsanız, **FastAPI** otomatik olarak "Successful response
## Bir *path operation*’ı Deprecate Etmek { #deprecate-a-path-operation }
-Bir *path operation*’ı kaldırmadan,
deprecated olarak işaretlemeniz gerekiyorsa `deprecated` parametresini verin:
+Bir *path operation*’ı kaldırmadan,
deprecated olarak işaretlemeniz gerekiyorsa `deprecated` parametresini verin:
-{* ../../docs_src/path_operation_configuration/tutorial006_py39.py hl[16] *}
+{* ../../docs_src/path_operation_configuration/tutorial006_py310.py hl[16] *}
Interactive docs’ta deprecated olduğu net şekilde işaretlenecektir:
diff --git a/docs/tr/docs/tutorial/path-params-numeric-validations.md b/docs/tr/docs/tutorial/path-params-numeric-validations.md
index e0118d71da..63506a1f24 100644
--- a/docs/tr/docs/tutorial/path-params-numeric-validations.md
+++ b/docs/tr/docs/tutorial/path-params-numeric-validations.md
@@ -54,11 +54,11 @@ Bu **FastAPI** için önemli değildir. FastAPI parametreleri isimlerine, tipler
Dolayısıyla fonksiyonunuzu şöyle tanımlayabilirsiniz:
-{* ../../docs_src/path_params_numeric_validations/tutorial002_py39.py hl[7] *}
+{* ../../docs_src/path_params_numeric_validations/tutorial002_py310.py hl[7] *}
Ancak şunu unutmayın: `Annotated` kullanırsanız bu problem olmaz; çünkü `Query()` veya `Path()` için fonksiyon parametresi default değerlerini kullanmıyorsunuz.
-{* ../../docs_src/path_params_numeric_validations/tutorial002_an_py39.py *}
+{* ../../docs_src/path_params_numeric_validations/tutorial002_an_py310.py *}
## Parametreleri İhtiyacınıza Göre Sıralayın: Küçük Hileler { #order-the-parameters-as-you-need-tricks }
@@ -81,15 +81,15 @@ Ancak şunu unutmayın: `Annotated` kullanırsanız bu problem olmaz; çünkü `
Fonksiyonun ilk parametresi olarak `*` geçin.
-Python bu `*` ile bir şey yapmaz; ama bundan sonraki tüm parametrelerin keyword argument (anahtar-değer çiftleri) olarak çağrılması gerektiğini bilir; buna
kwargs da denir. Default değerleri olmasa bile.
+Python bu `*` ile bir şey yapmaz; ama bundan sonraki tüm parametrelerin keyword argument (anahtar-değer çiftleri) olarak çağrılması gerektiğini bilir; buna
kwargs da denir. Default değerleri olmasa bile.
-{* ../../docs_src/path_params_numeric_validations/tutorial003_py39.py hl[7] *}
+{* ../../docs_src/path_params_numeric_validations/tutorial003_py310.py hl[7] *}
### `Annotated` ile Daha İyi { #better-with-annotated }
Şunu da unutmayın: `Annotated` kullanırsanız, fonksiyon parametresi default değerlerini kullanmadığınız için bu sorun ortaya çıkmaz ve muhtemelen `*` kullanmanız da gerekmez.
-{* ../../docs_src/path_params_numeric_validations/tutorial003_an_py39.py hl[10] *}
+{* ../../docs_src/path_params_numeric_validations/tutorial003_an_py310.py hl[10] *}
## Sayı Doğrulamaları: Büyük Eşit { #number-validations-greater-than-or-equal }
@@ -97,7 +97,7 @@ Python bu `*` ile bir şey yapmaz; ama bundan sonraki tüm parametrelerin keywor
Burada `ge=1` ile, `item_id` değerinin `1`'den "`g`reater than or `e`qual" olacak şekilde bir tam sayı olması gerekir.
-{* ../../docs_src/path_params_numeric_validations/tutorial004_an_py39.py hl[10] *}
+{* ../../docs_src/path_params_numeric_validations/tutorial004_an_py310.py hl[10] *}
## Sayı Doğrulamaları: Büyük ve Küçük Eşit { #number-validations-greater-than-and-less-than-or-equal }
@@ -106,19 +106,19 @@ Aynısı şunlar için de geçerlidir:
* `gt`: `g`reater `t`han
* `le`: `l`ess than or `e`qual
-{* ../../docs_src/path_params_numeric_validations/tutorial005_an_py39.py hl[10] *}
+{* ../../docs_src/path_params_numeric_validations/tutorial005_an_py310.py hl[10] *}
## Sayı Doğrulamaları: `float` Değerler, Büyük ve Küçük { #number-validations-floats-greater-than-and-less-than }
Sayı doğrulamaları `float` değerler için de çalışır.
-Burada
gt tanımlayabilmek (sadece
ge değil) önemli hale gelir. Çünkü örneğin bir değerin `0`'dan büyük olmasını isteyebilirsiniz; `1`'den küçük olsa bile.
+Burada
gt tanımlayabilmek (sadece
ge değil) önemli hale gelir. Çünkü örneğin bir değerin `0`'dan büyük olmasını isteyebilirsiniz; `1`'den küçük olsa bile.
Bu durumda `0.5` geçerli bir değer olur. Ancak `0.0` veya `0` geçerli olmaz.
-Aynısı
lt için de geçerlidir.
+Aynısı
lt için de geçerlidir.
-{* ../../docs_src/path_params_numeric_validations/tutorial006_an_py39.py hl[13] *}
+{* ../../docs_src/path_params_numeric_validations/tutorial006_an_py310.py hl[13] *}
## Özet { #recap }
diff --git a/docs/tr/docs/tutorial/path-params.md b/docs/tr/docs/tutorial/path-params.md
index db676f1eed..cbcec05d4c 100644
--- a/docs/tr/docs/tutorial/path-params.md
+++ b/docs/tr/docs/tutorial/path-params.md
@@ -2,7 +2,7 @@
Python
string biçimlemede kullanılan sözdizimiyle path "parametreleri"ni veya "değişkenleri"ni tanımlayabilirsiniz:
-{* ../../docs_src/path_params/tutorial001_py39.py hl[6:7] *}
+{* ../../docs_src/path_params/tutorial001_py310.py hl[6:7] *}
Path parametresi `item_id`'nin değeri, fonksiyonunuza `item_id` argümanı olarak aktarılacaktır.
@@ -16,7 +16,7 @@ Yani, bu örneği çalıştırıp
conversion { #data-conversion }
+## Veri dönüştürme { #data-conversion }
Bu örneği çalıştırıp tarayıcınızda http://127.0.0.1:8000/items/3 adresini açarsanız, şöyle bir response görürsünüz:
@@ -38,7 +38,7 @@ Bu örneği çalıştırıp tarayıcınızda
"parsing" sağlar.
+Yani, bu tip tanımıyla birlikte **FastAPI** size otomatik request "ayrıştırma" sağlar.
///
@@ -118,13 +118,13 @@ Sonra belirli bir kullanıcı hakkında, kullanıcı ID'si ile veri almak için
*Path operation*'lar sırayla değerlendirildiği için, `/users/me` için olan path'in `/users/{user_id}` olandan önce tanımlandığından emin olmanız gerekir:
-{* ../../docs_src/path_params/tutorial003_py39.py hl[6,11] *}
+{* ../../docs_src/path_params/tutorial003_py310.py hl[6,11] *}
Aksi halde, `/users/{user_id}` için olan path, `"me"` değerini `user_id` parametresi olarak aldığını "düşünerek" `/users/me` için de eşleşir.
Benzer şekilde, bir path operation'ı yeniden tanımlayamazsınız:
-{* ../../docs_src/path_params/tutorial003b_py39.py hl[6,11] *}
+{* ../../docs_src/path_params/tutorial003b_py310.py hl[6,11] *}
Path önce eşleştiği için her zaman ilk olan kullanılır.
@@ -140,11 +140,11 @@ Bir *path operation*'ınız *path parameter* alıyorsa ama olası geçerli *path
Sonra, kullanılabilir geçerli değerler olacak sabit değerli class attribute'ları oluşturun:
-{* ../../docs_src/path_params/tutorial005_py39.py hl[1,6:9] *}
+{* ../../docs_src/path_params/tutorial005_py310.py hl[1,6:9] *}
/// tip | İpucu
-Merak ediyorsanız: "AlexNet", "ResNet" ve "LeNet", Makine Öğrenmesi modellerinin sadece isimleridir.
+Merak ediyorsanız: "AlexNet", "ResNet" ve "LeNet", Makine Öğrenmesi modellerinin sadece isimleridir.
///
@@ -152,7 +152,7 @@ Merak ediyorsanız: "AlexNet", "ResNet" ve "LeNet", Makine Öğrenmesi parsing"
+* Veri "ayrıştırma"
* Veri doğrulama
* API annotation ve otomatik dokümantasyon
diff --git a/docs/tr/docs/tutorial/query-params-str-validations.md b/docs/tr/docs/tutorial/query-params-str-validations.md
index 18f0249e54..3bdbd7aae7 100644
--- a/docs/tr/docs/tutorial/query-params-str-validations.md
+++ b/docs/tr/docs/tutorial/query-params-str-validations.md
@@ -16,7 +16,7 @@ FastAPI, `q`’nun zorunlu olmadığını `= None` varsayılan değerinden anlar
///
-## Ek doğrulama { #additional-validation }
+## Ek Doğrulama { #additional-validation }
`q` opsiyonel olsa bile, verildiği durumda **uzunluğunun 50 karakteri geçmemesini** zorlayacağız.
@@ -47,40 +47,16 @@ Daha eski bir sürüm kullanıyorsanız `Annotated` kullanmaya çalışırken ha
Şu tip anotasyonuna sahiptik:
-//// tab | Python 3.10+
-
```Python
q: str | None = None
```
-////
-
-//// tab | Python 3.9+
-
-```Python
-q: Union[str, None] = None
-```
-
-////
-
Şimdi bunu `Annotated` ile saracağız; şöyle olacak:
-//// tab | Python 3.10+
-
```Python
q: Annotated[str | None] = None
```
-////
-
-//// tab | Python 3.9+
-
-```Python
-q: Annotated[Union[str, None]] = None
-```
-
-////
-
Bu iki sürüm de aynı anlama gelir: `q`, `str` veya `None` olabilen bir parametredir ve varsayılan olarak `None`’dır.
Şimdi işin eğlenceli kısmına geçelim. 🎉
@@ -109,7 +85,7 @@ FastAPI artık şunları yapacak:
## Alternatif (eski): Varsayılan değer olarak `Query` { #alternative-old-query-as-the-default-value }
-FastAPI’nin önceki sürümlerinde (0.95.0 öncesi) `Query`’yi `Annotated` içine koymak yerine, parametrenizin varsayılan değeri olarak kullanmanız gerekiyordu. Etrafta bu şekilde yazılmış kod görme ihtimaliniz yüksek; bu yüzden açıklayalım.
+FastAPI’nin önceki sürümlerinde ( 0.95.0 öncesi) `Query`’yi `Annotated` içine koymak yerine, parametrenizin varsayılan değeri olarak kullanmanız gerekiyordu. Etrafta bu şekilde yazılmış kod görme ihtimaliniz yüksek; bu yüzden açıklayalım.
/// tip | İpucu
@@ -131,6 +107,7 @@ q: str | None = Query(default=None)
...parametreyi `None` varsayılan değeriyle opsiyonel yapar; şununla aynı:
+
```Python
q: str | None = None
```
@@ -179,7 +156,7 @@ Fonksiyon parametrelerindeki varsayılan değer stiline göre **`Annotated` kull
Aynı fonksiyonu FastAPI olmadan **başka yerlerde** de **çağırabilirsiniz** ve **beklendiği gibi çalışır**. Eğer **zorunlu** bir parametre varsa (varsayılan değer yoksa) editörünüz hata ile bunu belirtir; ayrıca gerekli parametreyi vermeden çalıştırırsanız **Python** da şikayet eder.
-`Annotated` kullanmayıp bunun yerine **(eski) varsayılan değer stilini** kullanırsanız, o fonksiyonu FastAPI olmadan **başka yerlerde** çağırdığınızda doğru çalışması için argümanları geçmeniz gerektiğini **hatırlamak** zorunda kalırsınız; yoksa değerler beklediğinizden farklı olur (ör. `str` yerine `QueryInfo` veya benzeri). Üstelik editörünüz de şikayet etmez ve Python da fonksiyonu çalıştırırken şikayet etmez; ancak içerideki operasyonlar hata verince ortaya çıkar.
+`Annotated` kullanmayıp bunun yerine **(eski) varsayılan değer stilini** kullanırsanız, o fonksiyonu FastAPI olmadan **başka yerlerde** çağırdığınızda doğru çalışması için argümanları geçmeniz gerektiğini **hatırlamak** zorunda kalırsınız; yoksa değerler beklediğinizden farklı olur (ör. `QueryInfo` veya benzeri). Üstelik editörünüz de şikayet etmez ve Python da fonksiyonu çalıştırırken şikayet etmez; ancak içerideki operasyonlar hata verince ortaya çıkar.
`Annotated` birden fazla metadata anotasyonu alabildiği için, artık aynı fonksiyonu Typer gibi başka araçlarla da kullanabilirsiniz. 🚀
@@ -191,7 +168,7 @@ Aynı fonksiyonu FastAPI olmadan **başka yerlerde** de **çağırabilirsiniz**
## Regular expression ekleyin { #add-regular-expressions }
-Parametrenin eşleşmesi gereken bir `pattern`
regular expression tanımlayabilirsiniz:
+Parametrenin eşleşmesi gereken bir `pattern`
düzenli ifade tanımlayabilirsiniz:
{* ../../docs_src/query_params_str_validations/tutorial004_an_py310.py hl[11] *}
@@ -211,7 +188,7 @@ Elbette `None` dışında varsayılan değerler de kullanabilirsiniz.
Örneğin `q` query parametresi için `min_length` değerini `3` yapmak ve varsayılan değer olarak `"fixedquery"` vermek istediğinizi düşünelim:
-{* ../../docs_src/query_params_str_validations/tutorial005_an_py39.py hl[9] *}
+{* ../../docs_src/query_params_str_validations/tutorial005_an_py310.py hl[9] *}
/// note | Not
@@ -233,7 +210,7 @@ q: str
q: str | None = None
```
-Ancak biz artık `Query` ile tanımlıyoruz; örneğin şöyle:
+Acak biz artık `Query` ile tanımlıyoruz; örneğin şöyle:
```Python
q: Annotated[str | None, Query(min_length=3)] = None
@@ -241,7 +218,7 @@ q: Annotated[str | None, Query(min_length=3)] = None
Dolayısıyla `Query` kullanırken bir değeri zorunlu yapmak istediğinizde, varsayılan değer tanımlamamanız yeterlidir:
-{* ../../docs_src/query_params_str_validations/tutorial006_an_py39.py hl[9] *}
+{* ../../docs_src/query_params_str_validations/tutorial006_an_py310.py hl[9] *}
### Zorunlu ama `None` olabilir { #required-can-be-none }
@@ -292,7 +269,7 @@ Etkileşimli API dokümanları da buna göre güncellenir ve birden fazla değer
Hiç değer verilmezse varsayılan bir `list` de tanımlayabilirsiniz:
-{* ../../docs_src/query_params_str_validations/tutorial012_an_py39.py hl[9] *}
+{* ../../docs_src/query_params_str_validations/tutorial012_an_py310.py hl[9] *}
Şu adrese giderseniz:
@@ -315,7 +292,7 @@ http://localhost:8000/items/
`list[str]` yerine doğrudan `list` de kullanabilirsiniz:
-{* ../../docs_src/query_params_str_validations/tutorial013_an_py39.py hl[9] *}
+{* ../../docs_src/query_params_str_validations/tutorial013_an_py310.py hl[9] *}
/// note | Not
@@ -371,7 +348,7 @@ O zaman bir `alias` tanımlayabilirsiniz; bu alias, parametre değerini bulmak i
Diyelim ki artık bu parametreyi istemiyorsunuz.
-Bazı client’lar hâlâ kullandığı için bir süre tutmanız gerekiyor, ama dokümanların bunu açıkça
deprecated olarak göstermesini istiyorsunuz.
+Bazı client’lar hâlâ kullandığı için bir süre tutmanız gerekiyor, ama dokümanların bunu açıkça
deprecated olarak göstermesini istiyorsunuz.
O zaman `Query`’ye `deprecated=True` parametresini geçin:
@@ -401,7 +378,7 @@ Pydantic’te
ISBN kitap numarası için `isbn-` ile veya IMDB film URL ID’si için `imdb-` ile başladığını kontrol eder:
+Örneğin bu custom validator, bir item ID’sinin ISBN kitap numarası için `isbn-` ile veya IMDB film URL ID’si için `imdb-` ile başladığını kontrol eder:
{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py hl[5,16:19,24] *}
@@ -435,9 +412,9 @@ Fark ettiniz mi? `value.startswith()` ile bir string, tuple alabilir ve tuple i
#### Rastgele Bir Item { #a-random-item }
-`data.items()` ile, her dictionary öğesi için key ve value içeren tuple’lardan oluşan bir iterable object elde ederiz.
+`data.items()` ile, her dictionary öğesi için key ve value içeren tuple’lardan oluşan bir yinelemeli nesne elde ederiz.
-Bu iterable object’i `list(data.items())` ile düzgün bir `list`’e çeviririz.
+Bu yinelemeli nesneyi `list(data.items())` ile düzgün bir `list`’e çeviririz.
Ardından `random.choice()` ile list’ten **rastgele bir değer** alırız; yani `(id, name)` içeren bir tuple elde ederiz. Şuna benzer: `("imdb-tt0371724", "The Hitchhiker's Guide to the Galaxy")`.
diff --git a/docs/tr/docs/tutorial/query-params.md b/docs/tr/docs/tutorial/query-params.md
index 89cfa3fb35..4a9f688ca3 100644
--- a/docs/tr/docs/tutorial/query-params.md
+++ b/docs/tr/docs/tutorial/query-params.md
@@ -2,7 +2,7 @@
Fonksiyonda path parametrelerinin parçası olmayan diğer parametreleri tanımladığınızda, bunlar otomatik olarak "query" parametreleri olarak yorumlanır.
-{* ../../docs_src/query_params/tutorial001_py39.py hl[9] *}
+{* ../../docs_src/query_params/tutorial001_py310.py hl[9] *}
Query, bir URL'de `?` işaretinden sonra gelen ve `&` karakterleriyle ayrılan anahtar-değer çiftlerinin kümesidir.
@@ -24,7 +24,7 @@ Ancak, bunları Python tipleriyle (yukarıdaki örnekte `int` olarak) tanımlad
Path parametreleri için geçerli olan aynı süreç query parametreleri için de geçerlidir:
* Editör desteği (tabii ki)
-* Veri "parsing"
+* Veri "ayrıştırma"
* Veri doğrulama
* Otomatik dokümantasyon
@@ -46,7 +46,7 @@ http://127.0.0.1:8000/items/
http://127.0.0.1:8000/items/?skip=0&limit=10
```
-Ancak örneğin şuraya giderseniz:
+Namunak örneğin şuraya giderseniz:
```
http://127.0.0.1:8000/items/?skip=20
@@ -128,7 +128,7 @@ Belirli bir değer eklemek istemiyor ama sadece opsiyonel olmasını istiyorsan
Ancak bir query parametresini zorunlu yapmak istediğinizde, herhangi bir varsayılan değer tanımlamamanız yeterlidir:
-{* ../../docs_src/query_params/tutorial005_py39.py hl[6:7] *}
+{* ../../docs_src/query_params/tutorial005_py310.py hl[6:7] *}
Burada query parametresi `needy`, `str` tipinde zorunlu bir query parametresidir.
diff --git a/docs/tr/docs/tutorial/request-files.md b/docs/tr/docs/tutorial/request-files.md
index 0bbc557e01..8ebef15e2f 100644
--- a/docs/tr/docs/tutorial/request-files.md
+++ b/docs/tr/docs/tutorial/request-files.md
@@ -20,13 +20,13 @@ Bunun nedeni, upload edilen dosyaların "form data" olarak gönderilmesidir.
`fastapi` içinden `File` ve `UploadFile` import edin:
-{* ../../docs_src/request_files/tutorial001_an_py39.py hl[3] *}
+{* ../../docs_src/request_files/tutorial001_an_py310.py hl[3] *}
## `File` Parametrelerini Tanımlayın { #define-file-parameters }
`Body` veya `Form` için yaptığınız gibi dosya parametreleri oluşturun:
-{* ../../docs_src/request_files/tutorial001_an_py39.py hl[9] *}
+{* ../../docs_src/request_files/tutorial001_an_py310.py hl[9] *}
/// info | Bilgi
@@ -54,7 +54,7 @@ Ancak bazı durumlarda `UploadFile` kullanmak size fayda sağlayabilir.
Tipi `UploadFile` olan bir dosya parametresi tanımlayın:
-{* ../../docs_src/request_files/tutorial001_an_py39.py hl[14] *}
+{* ../../docs_src/request_files/tutorial001_an_py310.py hl[14] *}
`UploadFile` kullanmanın `bytes`’a göre birkaç avantajı vardır:
@@ -121,7 +121,7 @@ Formlardan gelen veri, dosya içermiyorsa normalde "media type" olarak `applicat
Ancak form dosya içeriyorsa `multipart/form-data` olarak encode edilir. `File` kullanırsanız, **FastAPI** dosyaları body’nin doğru kısmından alması gerektiğini bilir.
-Bu encoding’ler ve form alanları hakkında daha fazla okumak isterseniz MDN web dokümanlarındaki POST sayfasına bakın.
+Bu encoding’ler ve form alanları hakkında daha fazla okumak isterseniz
MDN web dokümanlarındaki POST sayfasına bakın.
///
@@ -143,7 +143,7 @@ Standart type annotation’ları kullanıp varsayılan değeri `None` yaparak bi
Ek metadata ayarlamak için `UploadFile` ile birlikte `File()` da kullanabilirsiniz. Örneğin:
-{* ../../docs_src/request_files/tutorial001_03_an_py39.py hl[9,15] *}
+{* ../../docs_src/request_files/tutorial001_03_an_py310.py hl[9,15] *}
## Birden Fazla Dosya Upload { #multiple-file-uploads }
@@ -153,7 +153,7 @@ Bu dosyalar, "form data" ile gönderilen aynı "form field" ile ilişkilendirili
Bunu kullanmak için `bytes` veya `UploadFile` listesini tanımlayın:
-{* ../../docs_src/request_files/tutorial002_an_py39.py hl[10,15] *}
+{* ../../docs_src/request_files/tutorial002_an_py310.py hl[10,15] *}
Tanımladığınız gibi, `bytes` veya `UploadFile`’lardan oluşan bir `list` alırsınız.
@@ -169,7 +169,7 @@ Tanımladığınız gibi, `bytes` veya `UploadFile`’lardan oluşan bir `list`
Daha önce olduğu gibi, `UploadFile` için bile ek parametreler ayarlamak amacıyla `File()` kullanabilirsiniz:
-{* ../../docs_src/request_files/tutorial003_an_py39.py hl[11,18:20] *}
+{* ../../docs_src/request_files/tutorial003_an_py310.py hl[11,18:20] *}
## Özet { #recap }
diff --git a/docs/tr/docs/tutorial/request-form-models.md b/docs/tr/docs/tutorial/request-form-models.md
index c35f956fce..75693190f4 100644
--- a/docs/tr/docs/tutorial/request-form-models.md
+++ b/docs/tr/docs/tutorial/request-form-models.md
@@ -24,7 +24,7 @@ Bu özellik FastAPI `0.113.0` sürümünden itibaren desteklenmektedir. 🤓
Sadece, **form field** olarak almak istediğiniz alanlarla bir **Pydantic model** tanımlayın ve ardından parametreyi `Form` olarak bildirin:
-{* ../../docs_src/request_form_models/tutorial001_an_py39.py hl[9:11,15] *}
+{* ../../docs_src/request_form_models/tutorial001_an_py310.py hl[9:11,15] *}
**FastAPI**, request içindeki **form data**'dan **her bir field** için veriyi **çıkarır** ve size tanımladığınız Pydantic model'ini verir.
@@ -48,7 +48,7 @@ Bu özellik FastAPI `0.114.0` sürümünden itibaren desteklenmektedir. 🤓
Herhangi bir `extra` field'ı `forbid` etmek için Pydantic'in model konfigürasyonunu kullanabilirsiniz:
-{* ../../docs_src/request_form_models/tutorial002_an_py39.py hl[12] *}
+{* ../../docs_src/request_form_models/tutorial002_an_py310.py hl[12] *}
Bir client fazladan veri göndermeye çalışırsa, bir **error** response alır.
diff --git a/docs/tr/docs/tutorial/request-forms-and-files.md b/docs/tr/docs/tutorial/request-forms-and-files.md
index 86d26b4989..69926af5e1 100644
--- a/docs/tr/docs/tutorial/request-forms-and-files.md
+++ b/docs/tr/docs/tutorial/request-forms-and-files.md
@@ -16,13 +16,13 @@ $ pip install python-multipart
## `File` ve `Form` Import Edin { #import-file-and-form }
-{* ../../docs_src/request_forms_and_files/tutorial001_an_py39.py hl[3] *}
+{* ../../docs_src/request_forms_and_files/tutorial001_an_py310.py hl[3] *}
## `File` ve `Form` Parametrelerini Tanımlayın { #define-file-and-form-parameters }
Dosya ve form parametrelerini, `Body` veya `Query` için yaptığınız şekilde oluşturun:
-{* ../../docs_src/request_forms_and_files/tutorial001_an_py39.py hl[10:12] *}
+{* ../../docs_src/request_forms_and_files/tutorial001_an_py310.py hl[10:12] *}
Dosyalar ve form alanları form data olarak upload edilir ve siz de dosyaları ve form alanlarını alırsınız.
diff --git a/docs/tr/docs/tutorial/request-forms.md b/docs/tr/docs/tutorial/request-forms.md
index 4608a6b79b..1a5303b3e0 100644
--- a/docs/tr/docs/tutorial/request-forms.md
+++ b/docs/tr/docs/tutorial/request-forms.md
@@ -18,17 +18,17 @@ $ pip install python-multipart
`Form`'u `fastapi`'den import edin:
-{* ../../docs_src/request_forms/tutorial001_an_py39.py hl[3] *}
+{* ../../docs_src/request_forms/tutorial001_an_py310.py hl[3] *}
## `Form` Parametrelerini Tanımlayın { #define-form-parameters }
Form parametrelerini `Body` veya `Query` için yaptığınız gibi oluşturun:
-{* ../../docs_src/request_forms/tutorial001_an_py39.py hl[9] *}
+{* ../../docs_src/request_forms/tutorial001_an_py310.py hl[9] *}
Örneğin OAuth2 spesifikasyonunun kullanılabileceği ("password flow" olarak adlandırılan) yollardan birinde, form alanları olarak bir `username` ve `password` göndermek zorunludur.
-
spec, alanların adının tam olarak `username` ve `password` olmasını ve JSON değil form alanları olarak gönderilmesini gerektirir.
+
Spesifikasyon, alanların adının tam olarak `username` ve `password` olmasını ve JSON değil form alanları olarak gönderilmesini gerektirir.
`Form` ile `Body` (ve `Query`, `Path`, `Cookie`) ile yaptığınız aynı konfigürasyonları tanımlayabilirsiniz; validasyon, örnekler, alias (örn. `username` yerine `user-name`) vb. dahil.
@@ -56,13 +56,13 @@ Formlardan gelen veri normalde "media type" `application/x-www-form-urlencoded`
Ancak form dosyalar içerdiğinde `multipart/form-data` olarak encode edilir. Dosyaları ele almayı bir sonraki bölümde okuyacaksınız.
-Bu encoding'ler ve form alanları hakkında daha fazla okumak isterseniz,
MDN web docs for POST sayfasına gidin.
+Bu encoding'ler ve form alanları hakkında daha fazla okumak isterseniz,
MDN web docs for POST sayfasına gidin.
///
/// warning | Uyarı
-Bir *path operation* içinde birden fazla `Form` parametresi tanımlayabilirsiniz, ancak JSON olarak almayı beklediğiniz `Body` alanlarını da ayrıca tanımlayamazsınız; çünkü bu durumda request'in body'si `application/json` yerine `application/x-www-form-urlencoded` ile encode edilmiş olur.
+Bir *path operation* içinde birden fazla `Form` parametresi tanımlayabilirsiniz, ancak JSON olarak almayı beklediğiniz `Body` alanlarını da ayrıca tanımlayamazsınız; çünkü bu durumda request'in body'si `application/x-www-form-urlencoded` ile encode edilmiş olur.
Bu **FastAPI**'ın bir kısıtlaması değildir, HTTP protokolünün bir parçasıdır.
diff --git a/docs/tr/docs/tutorial/response-model.md b/docs/tr/docs/tutorial/response-model.md
index f1d1f7d15e..2bf04bd9ec 100644
--- a/docs/tr/docs/tutorial/response-model.md
+++ b/docs/tr/docs/tutorial/response-model.md
@@ -97,7 +97,7 @@ Artık bir browser password ile user oluşturduğunda, API response içinde ayn
Bu örnekte sorun olmayabilir; çünkü password’ü gönderen kullanıcı zaten aynı kişi.
-Ancak aynı modeli başka bir *path operation* için kullanırsak, kullanıcının password’lerini her client’a gönderiyor olabiliriz.
+Namun ancak aynı modeli başka bir *path operation* için kullanırsak, kullanıcının password’lerini her client’a gönderiyor olabiliriz.
/// danger
@@ -183,7 +183,7 @@ Bazı durumlarda Pydantic field olarak geçerli olmayan bir şey döndürebilir
En yaygın durum, [ileri seviye dokümanlarda daha sonra anlatıldığı gibi doğrudan bir Response döndürmektir](../advanced/response-directly.md){.internal-link target=_blank}.
-{* ../../docs_src/response_model/tutorial003_02_py39.py hl[8,10:11] *}
+{* ../../docs_src/response_model/tutorial003_02_py310.py hl[8,10:11] *}
Bu basit durum FastAPI tarafından otomatik olarak ele alınır; çünkü dönüş tipi annotation’ı `Response` class’ıdır (veya onun bir subclass’ı).
@@ -193,7 +193,7 @@ Araçlar da memnun olur; çünkü hem `RedirectResponse` hem `JSONResponse`, `Re
Type annotation içinde `Response`’un bir subclass’ını da kullanabilirsiniz:
-{* ../../docs_src/response_model/tutorial003_03_py39.py hl[8:9] *}
+{* ../../docs_src/response_model/tutorial003_03_py310.py hl[8:9] *}
Bu da çalışır; çünkü `RedirectResponse`, `Response`’un subclass’ıdır ve FastAPI bu basit durumu otomatik olarak yönetir.
@@ -201,7 +201,7 @@ Bu da çalışır; çünkü `RedirectResponse`, `Response`’un subclass’ıdı
Ancak geçerli bir Pydantic tipi olmayan başka rastgele bir obje (ör. bir veritabanı objesi) döndürür ve fonksiyonu da öyle annotate ederseniz, FastAPI bu type annotation’dan bir Pydantic response model oluşturmaya çalışır ve başarısız olur.
-Aynı şey, farklı tipler arasında bir
union kullandığınızda ve bu tiplerden biri veya birkaçı geçerli bir Pydantic tipi değilse de olur; örneğin şu kullanım patlar 💥:
+Aynı şey, farklı tipler arasında bir
birleşim kullandığınızda ve bu tiplerden biri veya birkaçı geçerli bir Pydantic tipi değilse de olur; örneğin şu kullanım patlar 💥:
{* ../../docs_src/response_model/tutorial003_04_py310.py hl[8] *}
diff --git a/docs/tr/docs/tutorial/response-status-code.md b/docs/tr/docs/tutorial/response-status-code.md
index 57ae7bde34..d2270a3343 100644
--- a/docs/tr/docs/tutorial/response-status-code.md
+++ b/docs/tr/docs/tutorial/response-status-code.md
@@ -8,7 +8,7 @@ Bir response model tanımlayabildiğiniz gibi, herhangi bir *path operation* iç
* `@app.delete()`
* vb.
-{* ../../docs_src/response_status_code/tutorial001_py39.py hl[6] *}
+{* ../../docs_src/response_status_code/tutorial001_py310.py hl[6] *}
/// note | Not
@@ -66,7 +66,7 @@ Kısaca:
/// tip | İpucu
-Her bir status code hakkında daha fazla bilgi almak ve hangi kodun ne için kullanıldığını görmek için
HTTP status code'lar hakkında MDN dokümantasyonuna göz atın.
+Her bir status code hakkında daha fazla bilgi almak ve hangi kodun ne için kullanıldığını görmek için
MDN dokümantasyonu: HTTP status code'lar hakkında göz atın.
///
@@ -74,7 +74,7 @@ Her bir status code hakkında daha fazla bilgi almak ve hangi kodun ne için kul
Önceki örneğe tekrar bakalım:
-{* ../../docs_src/response_status_code/tutorial001_py39.py hl[6] *}
+{* ../../docs_src/response_status_code/tutorial001_py310.py hl[6] *}
`201`, "Created" için kullanılan status code'dur.
@@ -82,7 +82,7 @@ Ancak bu kodların her birinin ne anlama geldiğini ezberlemek zorunda değilsin
`fastapi.status` içindeki kolaylık değişkenlerini (convenience variables) kullanabilirsiniz.
-{* ../../docs_src/response_status_code/tutorial002_py39.py hl[1,6] *}
+{* ../../docs_src/response_status_code/tutorial002_py310.py hl[1,6] *}
Bunlar sadece kolaylık sağlar; aynı sayıyı taşırlar. Ancak bu şekilde editörün autocomplete özelliğiyle kolayca bulabilirsiniz:
diff --git a/docs/tr/docs/tutorial/schema-extra-example.md b/docs/tr/docs/tutorial/schema-extra-example.md
index a91dda8924..7e29b2309e 100644
--- a/docs/tr/docs/tutorial/schema-extra-example.md
+++ b/docs/tr/docs/tutorial/schema-extra-example.md
@@ -74,7 +74,7 @@ Elbette birden fazla `examples` da geçebilirsiniz:
Bunu yaptığınızda, örnekler bu body verisi için dahili **JSON Schema**’nın bir parçası olur.
-Buna rağmen,
time of writing this, doküman arayüzünü gösteren araç olan Swagger UI, **JSON Schema** içindeki veriler için birden fazla örneği göstermeyi desteklemiyor. Ancak aşağıda bir çözüm yolu var.
+Buna rağmen,
bu yazı yazılırken, doküman arayüzünü gösteren araç olan Swagger UI, **JSON Schema** içindeki veriler için birden fazla örneği göstermeyi desteklemiyor. Ancak aşağıda bir çözüm yolu var.
### OpenAPI’ye özel `examples` { #openapi-specific-examples }
diff --git a/docs/tr/docs/tutorial/security/first-steps.md b/docs/tr/docs/tutorial/security/first-steps.md
index 7e0a70a02c..0f72d0c830 100644
--- a/docs/tr/docs/tutorial/security/first-steps.md
+++ b/docs/tr/docs/tutorial/security/first-steps.md
@@ -20,7 +20,7 @@ Güvenliği yönetmek için **FastAPI**’nin sunduğu araçları kullanalım.
Örneği `main.py` adlı bir dosyaya kopyalayın:
-{* ../../docs_src/security/tutorial001_an_py39.py *}
+{* ../../docs_src/security/tutorial001_an_py310.py *}
## Çalıştırın { #run-it }
@@ -132,7 +132,7 @@ Bu durumda bile **FastAPI**, onu oluşturabilmeniz için gereken araçları suna
`OAuth2PasswordBearer` sınıfının bir instance’ını oluştururken `tokenUrl` parametresini veririz. Bu parametre, client’ın (kullanıcının browser’ında çalışan frontend’in) token almak için `username` ve `password` göndereceği URL’yi içerir.
-{* ../../docs_src/security/tutorial001_an_py39.py hl[8] *}
+{* ../../docs_src/security/tutorial001_an_py310.py hl[8] *}
/// tip | İpucu
@@ -170,7 +170,7 @@ Dolayısıyla `Depends` ile kullanılabilir.
Artık `Depends` ile bir dependency olarak `oauth2_scheme`’i geçebilirsiniz.
-{* ../../docs_src/security/tutorial001_an_py39.py hl[12] *}
+{* ../../docs_src/security/tutorial001_an_py310.py hl[12] *}
Bu dependency, *path operation function* içindeki `token` parametresine atanacak bir `str` sağlar.
diff --git a/docs/tr/docs/tutorial/security/get-current-user.md b/docs/tr/docs/tutorial/security/get-current-user.md
index 9f56c76289..cc7f7a51b9 100644
--- a/docs/tr/docs/tutorial/security/get-current-user.md
+++ b/docs/tr/docs/tutorial/security/get-current-user.md
@@ -2,7 +2,7 @@
Önceki bölümde güvenlik sistemi (dependency injection sistemine dayanır) *path operation function*'a `str` olarak bir `token` veriyordu:
-{* ../../docs_src/security/tutorial001_an_py39.py hl[12] *}
+{* ../../docs_src/security/tutorial001_an_py310.py hl[12] *}
Ancak bu hâlâ pek kullanışlı değil.
diff --git a/docs/tr/docs/tutorial/security/oauth2-jwt.md b/docs/tr/docs/tutorial/security/oauth2-jwt.md
index 716761157c..ad991d322a 100644
--- a/docs/tr/docs/tutorial/security/oauth2-jwt.md
+++ b/docs/tr/docs/tutorial/security/oauth2-jwt.md
@@ -116,7 +116,11 @@ Sonra, alınan password'ün kayıttaki hash ile eşleşip eşleşmediğini doğr
Bir tane de kullanıcıyı authenticate edip geri döndüren bir yardımcı fonksiyon ekleyelim.
-{* ../../docs_src/security/tutorial004_an_py310.py hl[8,49,56:57,60:61,70:76] *}
+{* ../../docs_src/security/tutorial004_an_py310.py hl[8,49,51,58:59,62:63,72:79] *}
+
+`authenticate_user`, veritabanında var olmayan bir username ile çağrıldığında, yine de sahte (dummy) bir hash'e karşı `verify_password` çalıştırıyoruz.
+
+Bu, username geçerli olsun ya da olmasın endpoint'in yaklaşık aynı sürede yanıt vermesini sağlar; böylece mevcut username'leri saymaya yarayabilecek zamanlama saldırılarını (timing attacks) engeller.
/// note | Not
@@ -152,7 +156,7 @@ Response için token endpoint'inde kullanılacak bir Pydantic Model tanımlayın
Yeni bir access token üretmek için bir yardımcı fonksiyon oluşturun.
-{* ../../docs_src/security/tutorial004_an_py310.py hl[4,7,13:15,29:31,79:87] *}
+{* ../../docs_src/security/tutorial004_an_py310.py hl[4,7,13:15,29:31,82:90] *}
## Dependency'leri güncelleme { #update-the-dependencies }
@@ -162,7 +166,7 @@ Gelen token'ı decode edin, doğrulayın ve mevcut kullanıcıyı döndürün.
Token geçersizse, hemen bir HTTP hatası döndürün.
-{* ../../docs_src/security/tutorial004_an_py310.py hl[90:107] *}
+{* ../../docs_src/security/tutorial004_an_py310.py hl[93:110] *}
## `/token` *path operation*'ını güncelleme { #update-the-token-path-operation }
@@ -170,7 +174,7 @@ Token'ın süre sonu için bir `timedelta` oluşturun.
Gerçek bir JWT access token üretip döndürün.
-{* ../../docs_src/security/tutorial004_an_py310.py hl[118:133] *}
+{* ../../docs_src/security/tutorial004_an_py310.py hl[121:136] *}
### JWT "subject" `sub` Hakkında Teknik Detaylar { #technical-details-about-the-jwt-subject-sub }
diff --git a/docs/tr/docs/tutorial/sql-databases.md b/docs/tr/docs/tutorial/sql-databases.md
index e1638cb04f..0a02b47aec 100644
--- a/docs/tr/docs/tutorial/sql-databases.md
+++ b/docs/tr/docs/tutorial/sql-databases.md
@@ -8,7 +8,7 @@ Burada
"ORMs" olarak adlandırılır). FastAPI sizi hiçbir şeye zorlamaz.
+İstediğiniz başka bir SQL veya NoSQL veritabanı kütüphanesini kullanabilirsiniz (bazı durumlarda "ORMs" olarak adlandırılır). FastAPI sizi hiçbir şeye zorlamaz. 😎
///
@@ -49,7 +49,7 @@ $ pip install sqlmodel
Önce, tek bir **SQLModel** modeliyle uygulamanın en basit ilk sürümünü oluşturacağız.
-Aşağıda, **birden fazla model** kullanarak güvenliği ve esnekliği artırıp geliştireceğiz.
+Aşağıda, **birden fazla model** kullanarak güvenliği ve esnekliği artırıp geliştireceğiz. 🤓
### Modelleri Oluşturma { #create-models }
@@ -93,7 +93,7 @@ Sonra `SQLModel.metadata.create_all(engine)` kullanan bir fonksiyon ekleyerek t
Bir **`Session`**, **nesneleri memory’de** tutar ve verideki gerekli değişiklikleri takip eder; ardından veritabanıyla iletişim kurmak için **`engine` kullanır**.
-`yield` ile, her request için yeni bir `Session` sağlayacak bir FastAPI **dependency** oluşturacağız. Bu da her request’te tek session kullanmamızı garanti eder.
+`yield` ile, her request için yeni bir `Session` sağlayacak bir FastAPI **dependency** oluşturacağız. Bu da her request’te tek session kullanmamızı garanti eder. 🤓
Ardından bu dependency’yi kullanacak kodun geri kalanını sadeleştirmek için `Annotated` ile `SessionDep` dependency’sini oluştururuz.
@@ -107,7 +107,7 @@ Uygulama başlarken veritabanı table’larını oluşturacağız.
Burada bir uygulama startup event’inde table’ları oluşturuyoruz.
-Production’da büyük ihtimalle uygulamayı başlatmadan önce çalışan bir migration script’i kullanırsınız.
+Production’da büyük ihtimalle uygulamayı başlatmadan önce çalışan bir migration script’i kullanırsınız. 🤓
/// tip | İpucu
@@ -169,19 +169,19 @@ Sonra `/docs` arayüzüne gidin; **FastAPI**’nin API’yi **dokümante etmek**
Şimdi bu uygulamayı biraz **refactor** edelim ve **güvenliği** ile **esnekliği** artıralım.
-Önceki uygulamaya bakarsanız, UI’da şu ana kadar client’ın oluşturulacak `Hero`’nun `id` değerini belirlemesine izin verdiğini görebilirsiniz.
+Önceki uygulamaya bakarsanız, UI’da şu ana kadar client’ın oluşturulacak `Hero`’nun `id` değerini belirlemesine izin verdiğini görebilirsiniz. 😱
Buna izin vermemeliyiz; DB’de zaten atanmış bir `id`’yi ezebilirler. `id` belirlemek **client** tarafından değil, **backend** veya **veritabanı** tarafından yapılmalıdır.
-Ayrıca hero için bir `secret_name` oluşturuyoruz ama şimdiye kadar her yerde geri döndürüyoruz; bu pek de **secret** sayılmaz...
+Ayrıca hero için bir `secret_name` oluşturuyoruz ama şimdiye kadar her yerde geri döndürüyoruz; bu pek de **secret** sayılmaz... 😅
-Bunları birkaç **ek model** ekleyerek düzelteceğiz. SQLModel’in parlayacağı yer de burası.
+Bunları birkaç **ek model** ekleyerek düzelteceğiz. SQLModel’in parlayacağı yer de burası. ✨
### Birden Fazla Model Oluşturma { #create-multiple-models }
**SQLModel**’de, `table=True` olan herhangi bir model sınıfı bir **table model**’dir.
-`table=True` olmayan her model sınıfı ise bir **data model**’dir; bunlar aslında sadece Pydantic modelleridir (bazı küçük ek özelliklerle).
+`table=True` olmayan her model sınıfı ise bir **data model**’dir; bunlar aslında sadece Pydantic modelleridir (bazı küçük ek özelliklerle). 🤓
SQLModel ile **inheritance** kullanarak her durumda tüm alanları tekrar tekrar yazmaktan **kaçınabiliriz**.
@@ -216,7 +216,7 @@ Sonraki adımda `HeroPublic` modelini oluştururuz; bu model API client’ların
`HeroBase` ile aynı alanlara sahiptir; dolayısıyla `secret_name` içermez.
-Sonunda kahramanlarımızın kimliği korunmuş oldu!
+Sonunda kahramanlarımızın kimliği korunmuş oldu! 🥷
Ayrıca `id: int` alanını yeniden tanımlar. Bunu yaparak API client’larıyla bir **contract** (sözleşme) oluşturmuş oluruz; böylece `id` alanının her zaman var olacağını ve `int` olacağını (asla `None` olmayacağını) bilirler.
@@ -224,7 +224,7 @@ Ayrıca `id: int` alanını yeniden tanımlar. Bunu yaparak API client’larıyl
Return model’in bir değerin her zaman mevcut olduğunu ve her zaman `int` olduğunu (`None` değil) garanti etmesi API client’ları için çok faydalıdır; bu kesinlik sayesinde daha basit kod yazabilirler.
-Ayrıca **otomatik üretilen client**’ların arayüzleri de daha basit olur; böylece API’nizle çalışan geliştiriciler için süreç çok daha rahat olur.
+Ayrıca **otomatik üretilen client**’ların arayüzleri de daha basit olur; böylece API’nizle çalışan geliştiriciler için süreç çok daha rahat olur. 😎
///
@@ -262,13 +262,13 @@ Ayrıca password değerlerini saklamadan önce **hash** etmelisiniz; **asla plai
#### `HeroUpdate` - hero güncellemek için *data model* { #heroupdate-the-data-model-to-update-a-hero }
-Uygulamanın önceki sürümünde bir hero’yu **güncellemenin** bir yolu yoktu; ancak artık **birden fazla model** ile bunu yapabiliriz.
+Uygulamanın önceki sürümünde bir hero’yu **güncellemenin** bir yolu yoktu; ancak artık **birden fazla model** ile bunu yapabiliriz. 🎉
`HeroUpdate` *data model* biraz özeldir: yeni bir hero oluşturmak için gereken alanların **tamamına** sahiptir, ancak tüm alanlar **opsiyoneldir** (hepsinin bir default değeri vardır). Bu sayede hero güncellerken sadece güncellemek istediğiniz alanları gönderebilirsiniz.
Tüm **alanlar aslında değiştiği** için (tip artık `None` içeriyor ve default değerleri `None` oluyor), onları **yeniden tanımlamamız** gerekir.
-Aslında `HeroBase`’ten miras almamız gerekmiyor; çünkü tüm alanları yeniden tanımlıyoruz. Tutarlılık için miras almayı bırakıyorum ama bu gerekli değil. Daha çok kişisel tercih meselesi.
+Aslında `HeroBase`’ten miras almamız gerekmiyor; çünkü tüm alanları yeniden tanımlıyoruz. Tutarlılık için miras almayı bırakıyorum ama bu gerekli değil. Daha çok kişisel tercih meselesi. 🤷
`HeroUpdate` alanları:
@@ -316,7 +316,7 @@ Tek bir hero’yu **okuyabiliriz**:
Bir hero’yu **güncelleyebiliriz**. Bunun için HTTP `PATCH` operasyonu kullanırız.
-Kodda, client’ın gönderdiği tüm verilerle bir `dict` alırız; **yalnızca client’ın gönderdiği veriler**, yani sadece default değer oldukları için orada bulunan değerler hariç. Bunu yapmak için `exclude_unset=True` kullanırız. Asıl numara bu.
+Kodda, client’ın gönderdiği tüm verilerle bir `dict` alırız; **yalnızca client’ın gönderdiği veriler**, yani sadece default değer oldukları için orada bulunan değerler hariç. Bunu yapmak için `exclude_unset=True` kullanırız. Asıl numara bu. 🪄
Sonra `hero_db.sqlmodel_update(hero_data)` ile `hero_db`’yi `hero_data` içindeki verilerle güncelleriz.
@@ -326,7 +326,7 @@ Sonra `hero_db.sqlmodel_update(hero_data)` ile `hero_db`’yi `hero_data` içind
Bir hero’yu **silmek** büyük ölçüde aynı kalıyor.
-Bu örnekte her şeyi refactor etme isteğimizi bastıracağız.
+Bu örnekte her şeyi refactor etme isteğimizi bastıracağız. 😅
{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[96:103] hl[101] *}
@@ -354,4 +354,4 @@ $ fastapi dev main.py
Bir SQL veritabanıyla etkileşim kurmak için **SQLModel** kullanabilir ve *data model* ile *table model* yaklaşımıyla kodu sadeleştirebilirsiniz.
-**SQLModel** dokümantasyonunda çok daha fazlasını öğrenebilirsiniz; **FastAPI** ile SQLModel kullanımı için daha uzun bir mini
tutorial da bulunuyor.
+**SQLModel** dokümantasyonunda çok daha fazlasını öğrenebilirsiniz; **FastAPI** ile SQLModel kullanımı için daha uzun bir mini
tutorial da bulunuyor. 🚀
diff --git a/docs/tr/docs/tutorial/static-files.md b/docs/tr/docs/tutorial/static-files.md
index d30b4389d0..e49b14bd86 100644
--- a/docs/tr/docs/tutorial/static-files.md
+++ b/docs/tr/docs/tutorial/static-files.md
@@ -7,7 +7,7 @@
* `StaticFiles`'ı import edin.
* Belirli bir path'te bir `StaticFiles()` örneğini "mount" edin.
-{* ../../docs_src/static_files/tutorial001_py39.py hl[2,6] *}
+{* ../../docs_src/static_files/tutorial001_py310.py hl[2,6] *}
/// note | Teknik Detaylar
@@ -23,7 +23,7 @@
Bu, bir `APIRouter` kullanmaktan farklıdır; çünkü mount edilen uygulama tamamen bağımsızdır. Ana uygulamanızın OpenAPI ve docs'ları, mount edilen uygulamadan hiçbir şey içermez, vb.
-Bununla ilgili daha fazla bilgiyi [Advanced User Guide](../advanced/index.md){.internal-link target=_blank} içinde okuyabilirsiniz.
+Bununla ilgili daha fazla bilgiyi [Gelişmiş Kullanıcı Kılavuzu](../advanced/index.md){.internal-link target=_blank} içinde okuyabilirsiniz.
## Detaylar { #details }
diff --git a/docs/tr/docs/tutorial/testing.md b/docs/tr/docs/tutorial/testing.md
index 8871566066..18e0dd96c0 100644
--- a/docs/tr/docs/tutorial/testing.md
+++ b/docs/tr/docs/tutorial/testing.md
@@ -12,7 +12,7 @@ Bununla birlikte **FastAPI** ile
`httpx`'i kurun.
-Bir [virtual environment](../virtual-environments.md){.internal-link target=_blank} oluşturduğunuzdan, onu aktifleştirdiğinizden ve sonra kurulumu yaptığınızdan emin olun; örneğin:
+Bir [Sanal Ortam](../virtual-environments.md){.internal-link target=_blank} oluşturduğunuzdan, onu aktifleştirdiğinizden ve sonra kurulumu yaptığınızdan emin olun; örneğin:
```console
$ pip install httpx
@@ -30,7 +30,7 @@ Adı `test_` ile başlayan fonksiyonlar oluşturun (bu, `pytest`'in standart kon
Kontrol etmeniz gereken şeyler için standart Python ifadeleriyle basit `assert` satırları yazın (bu da `pytest` standardıdır).
-{* ../../docs_src/app_testing/tutorial001_py39.py hl[2,12,15:18] *}
+{* ../../docs_src/app_testing/tutorial001_py310.py hl[2,12,15:18] *}
/// tip | İpucu
@@ -52,7 +52,7 @@ Bu sayede `pytest`'i ek bir karmaşıklık olmadan doğrudan kullanabilirsiniz.
/// tip | İpucu
-FastAPI uygulamanıza request göndermenin dışında testlerinizde `async` fonksiyonlar çağırmak istiyorsanız (örn. asenkron veritabanı fonksiyonları), ileri seviye bölümdeki [Async Tests](../advanced/async-tests.md){.internal-link target=_blank} dokümanına göz atın.
+FastAPI uygulamanıza request göndermenin dışında testlerinizde `async` fonksiyonlar çağırmak istiyorsanız (örn. asenkron veritabanı fonksiyonları), ileri seviye bölümdeki [Asenkron Testler](../advanced/async-tests.md){.internal-link target=_blank} dokümanına göz atın.
///
@@ -64,7 +64,7 @@ Ayrıca **FastAPI** uygulamanız birden fazla dosya/modül vb. ile de oluşturul
### **FastAPI** Uygulama Dosyası { #fastapi-app-file }
-[Bigger Applications](bigger-applications.md){.internal-link target=_blank}'te anlatılan şekilde bir dosya yapınız olduğunu varsayalım:
+[Daha Büyük Uygulamalar](bigger-applications.md){.internal-link target=_blank}'te anlatılan şekilde bir dosya yapınız olduğunu varsayalım:
```
.
@@ -75,7 +75,7 @@ Ayrıca **FastAPI** uygulamanız birden fazla dosya/modül vb. ile de oluşturul
`main.py` dosyasında **FastAPI** uygulamanız bulunuyor olsun:
-{* ../../docs_src/app_testing/app_a_py39/main.py *}
+{* ../../docs_src/app_testing/app_a_py310/main.py *}
### Test Dosyası { #testing-file }
@@ -91,7 +91,7 @@ Sonra testlerinizin olduğu bir `test_main.py` dosyanız olabilir. Bu dosya ayn
Bu dosya aynı package içinde olduğu için, `main` modülünden (`main.py`) `app` nesnesini import etmek üzere relative import kullanabilirsiniz:
-{* ../../docs_src/app_testing/app_a_py39/test_main.py hl[3] *}
+{* ../../docs_src/app_testing/app_a_py310/test_main.py hl[3] *}
...ve test kodunu da öncekiyle aynı şekilde yazabilirsiniz.
@@ -145,7 +145,7 @@ Backend'e veri geçme hakkında daha fazla bilgi için (`httpx` veya `TestClient
`TestClient`'ın Pydantic model'lerini değil, JSON'a dönüştürülebilen verileri aldığını unutmayın.
-Testinizde bir Pydantic model'iniz varsa ve test sırasında verisini uygulamaya göndermek istiyorsanız, [JSON Compatible Encoder](encoder.md){.internal-link target=_blank} içinde açıklanan `jsonable_encoder`'ı kullanabilirsiniz.
+Testinizde bir Pydantic model'iniz varsa ve test sırasında verisini uygulamaya göndermek istiyorsanız, [JSON Uyumlu Encoder](encoder.md){.internal-link target=_blank} içinde açıklanan `jsonable_encoder`'ı kullanabilirsiniz.
///
@@ -153,7 +153,7 @@ Testinizde bir Pydantic model'iniz varsa ve test sırasında verisini uygulamaya
Bundan sonra yapmanız gereken tek şey `pytest`'i kurmaktır.
-Bir [virtual environment](../virtual-environments.md){.internal-link target=_blank} oluşturduğunuzdan, onu aktifleştirdiğinizden ve sonra kurulumu yaptığınızdan emin olun; örneğin:
+Bir [Sanal Ortam](../virtual-environments.md){.internal-link target=_blank} oluşturduğunuzdan, onu aktifleştirdiğinizden ve sonra kurulumu yaptığınızdan emin olun; örneğin:
diff --git a/docs/tr/docs/virtual-environments.md b/docs/tr/docs/virtual-environments.md
index cf7fab778b..668a3d5a95 100644
--- a/docs/tr/docs/virtual-environments.md
+++ b/docs/tr/docs/virtual-environments.md
@@ -53,7 +53,7 @@ $ cd awesome-project
## Virtual Environment Oluşturun { #create-a-virtual-environment }
-Bir Python projesi üzerinde **ilk kez** çalışmaya başladığınızda, projenizin içinde **
virtual environment** oluşturun.
+Bir Python projesi üzerinde **ilk kez** çalışmaya başladığınızda, **virtual environment**'i
projenizin içinde oluşturun.
/// tip | İpucu
diff --git a/docs/uk/docs/_llm-test.md b/docs/uk/docs/_llm-test.md
new file mode 100644
index 0000000000..0dbfaa3db4
--- /dev/null
+++ b/docs/uk/docs/_llm-test.md
@@ -0,0 +1,502 @@
+# Тестовий файл LLM { #llm-test-file }
+
+Цей документ перевіряє, чи розуміє
LLM, який перекладає документацію, `general_prompt` у `scripts/translate.py` та мовно-специфічну підсказку в `docs/{language code}/llm-prompt.md`. Мовно-специфічна підсказка додається до `general_prompt`.
+
+Тести, додані тут, побачать усі автори мовно-специфічних підсказок.
+
+Використовуйте так:
+
+* Майте мовно-специфічну підсказку - `docs/{language code}/llm-prompt.md`.
+* Зробіть свіжий переклад цього документа на бажану цільову мову (див., наприклад, команду `translate-page` у `translate.py`). Це створить переклад у `docs/{language code}/docs/_llm-test.md`.
+* Перевірте, чи все гаразд у перекладі.
+* За потреби покращіть вашу мовно-специфічну підсказку, загальну підсказку або англійський документ.
+* Потім вручну виправте решту проблем у перекладі, щоб він був якісним.
+* Перекладіть повторно, маючи якісний переклад на місці. Ідеальний результат - коли LLM більше не вносить змін до перекладу. Це означає, що загальна підсказка та ваша мовно-специфічна підсказка настільки добрі, наскільки це можливо (інколи він робитиме кілька, здавалося б, випадкових змін, причина в тому, що
LLM-и не є детерміністичними алгоритмами).
+
+Тести:
+
+## Фрагменти коду { #code-snippets }
+
+//// tab | Тест
+
+Це фрагмент коду: `foo`. А це ще один фрагмент коду: `bar`. І ще один: `baz quux`.
+
+////
+
+//// tab | Інформація
+
+Вміст фрагментів коду слід залишати без змін.
+
+Див. розділ `### Content of code snippets` в загальній підсказці в `scripts/translate.py`.
+
+////
+
+## Цитати { #quotes }
+
+//// tab | Тест
+
+Вчора мій друг написав: «Якщо ви правильно напишете "incorrectly", ви написали це неправильно». На що я відповів: «Правильно, але 'incorrectly' - це неправильно, а не '"incorrectly"'».
+
+/// note | Примітка
+
+LLM, ймовірно, перекладе це неправильно. Цікаво лише те, чи збереже він виправлений переклад під час повторного перекладу.
+
+///
+
+////
+
+//// tab | Інформація
+
+Автор підсказки може обрати, чи конвертувати нейтральні лапки в типографські. Можна залишити як є.
+
+Див., наприклад, розділ `### Quotes` у `docs/de/llm-prompt.md`.
+
+////
+
+## Лапки у фрагментах коду { #quotes-in-code-snippets }
+
+//// tab | Тест
+
+`pip install "foo[bar]"`
+
+Приклади строкових літералів у фрагментах коду: `"this"`, `'that'`.
+
+Складний приклад строкових літералів у фрагментах коду: `f"I like {'oranges' if orange else "apples"}"`
+
+Хардкор: `Yesterday, my friend wrote: "If you spell incorrectly correctly, you have spelled it incorrectly". To which I answered: "Correct, but 'incorrectly' is incorrectly not '"incorrectly"'"`
+
+////
+
+//// tab | Інформація
+
+... Однак лапки всередині фрагментів коду мають залишатися як є.
+
+////
+
+## Блоки коду { #code-blocks }
+
+//// tab | Тест
+
+Приклад коду Bash...
+
+```bash
+# Вивести привітання всесвіту
+echo "Hello universe"
+```
+
+...і приклад коду консолі...
+
+```console
+$
fastapi run
main.py
+
FastAPI Starting server
+ Searching for package file structure
+```
+
+...і ще один приклад коду консолі...
+
+```console
+// Створіть каталог "code"
+$ mkdir code
+// Перейдіть до цього каталогу
+$ cd code
+```
+
+...і приклад коду Python...
+
+```Python
+wont_work() # Це не спрацює 😱
+works(foo="bar") # Це працює 🎉
+```
+
+...і це все.
+
+////
+
+//// tab | Інформація
+
+Код у блоках коду не слід змінювати, за винятком коментарів.
+
+Див. розділ `### Content of code blocks` в загальній підсказці в `scripts/translate.py`.
+
+////
+
+## Вкладки та кольорові блоки { #tabs-and-colored-boxes }
+
+//// tab | Тест
+
+/// info | Інформація
+Some text
+///
+
+/// note | Примітка
+Some text
+///
+
+/// note | Технічні деталі
+Some text
+///
+
+/// check | Перевірте
+Some text
+///
+
+/// tip | Порада
+Some text
+///
+
+/// warning | Попередження
+Some text
+///
+
+/// danger | Обережно
+Some text
+///
+
+////
+
+//// tab | Інформація
+
+У вкладках і блоках `Info`/`Note`/`Warning`/тощо необхідно додати переклад їхнього заголовка після вертикальної риски (`|`).
+
+Див. розділи `### Special blocks` і `### Tab blocks` в загальній підсказці в `scripts/translate.py`.
+
+////
+
+## Веб- і внутрішні посилання { #web-and-internal-links }
+
+//// tab | Тест
+
+Текст посилання має бути перекладений, адреса посилання має залишитися незмінною:
+
+* [Посилання на заголовок вище](#code-snippets)
+* [Внутрішнє посилання](index.md#installation){.internal-link target=_blank}
+*
Зовнішнє посилання
+*
Посилання на стиль
+*
Посилання на скрипт
+*
Посилання на зображення
+
+Текст посилання має бути перекладений, адреса посилання має вказувати на переклад:
+
+*
Посилання на FastAPI
+
+////
+
+//// tab | Інформація
+
+Посилання слід перекладати, але їхні адреси мають лишатися незмінними. Виняток - абсолютні посилання на сторінки документації FastAPI. У такому випадку вони мають вказувати на переклад.
+
+Див. розділ `### Links` в загальній підсказці в `scripts/translate.py`.
+
+////
+
+## Елементи HTML «abbr» { #html-abbr-elements }
+
+//// tab | Тест
+
+Ось деякі речі, обгорнуті в елементи HTML «abbr» (деякі вигадані):
+
+### Скорочення містить повну фразу { #the-abbr-gives-a-full-phrase }
+
+*
GTD
+*
lt
+*
XWT
+*
PSGI
+
+### Скорочення містить повну фразу та пояснення { #the-abbr-gives-a-full-phrase-and-an-explanation }
+
+*
MDN
+*
I/O.
+
+////
+
+//// tab | Інформація
+
+Атрибути "title" елементів "abbr" перекладаються за певними інструкціями.
+
+Переклади можуть додавати власні елементи "abbr", які LLM не повинен прибирати. Наприклад, щоб пояснити англійські слова.
+
+Див. розділ `### HTML abbr elements` в загальній підсказці в `scripts/translate.py`.
+
+////
+
+## Елементи HTML «dfn» { #html-dfn-elements }
+
+*
кластер
+*
Глибоке навчання
+
+## Заголовки { #headings }
+
+//// tab | Тест
+
+### Розробка вебзастосунку - навчальний посібник { #develop-a-webapp-a-tutorial }
+
+Привіт.
+
+### Підказки типів та - анотації { #type-hints-and-annotations }
+
+Ще раз привіт.
+
+### Супер- та підкласи { #super-and-subclasses }
+
+Ще раз привіт.
+
+////
+
+//// tab | Інформація
+
+Єдине жорстке правило для заголовків - LLM має залишати хеш-частину в фігурних дужках незмінною, щоб посилання не ламалися.
+
+Див. розділ `### Headings` у загальній підсказці в `scripts/translate.py`.
+
+Для деяких мовно-специфічних інструкцій див., наприклад, розділ `### Headings` у `docs/de/llm-prompt.md`.
+
+////
+
+## Терміни, що використовуються в документації { #terms-used-in-the-docs }
+
+//// tab | Тест
+
+* ви
+* ваш
+
+* напр.
+* тощо
+
+* `foo` як `int`
+* `bar` як `str`
+* `baz` як `list`
+
+* навчальний посібник - Керівництво користувача
+* просунутий посібник користувача
+* документація SQLModel
+* документація API
+* автоматична документація
+
+* Наука про дані
+* глибоке навчання
+* машинне навчання
+* впровадження залежностей
+* HTTP базова автентифікація
+* HTTP дайджест
+* формат ISO
+* стандарт Схеми JSON
+* Схема JSON
+* визначення схеми
+* потік паролю
+* мобільний
+
+* застаріле
+* спроєктовано
+* недійсний
+* на льоту
+* стандарт
+* типове
+* чутливий до регістру
+* нечутливий до регістру
+
+* обслуговувати застосунок
+* обслуговувати сторінку
+
+* застосунок
+* застосунок
+
+* запит
+* відповідь
+* відповідь з помилкою
+
+* операція шляху
+* декоратор операції шляху
+* функція операції шляху
+
+* тіло
+* тіло запиту
+* тіло відповіді
+* тіло JSON
+* тіло форми
+* тіло функції
+
+* параметр
+* параметр тіла
+* параметр шляху
+* параметр запиту
+* параметр кукі
+* параметр заголовка
+* параметр форми
+* параметр функції
+
+* подія
+* подія запуску
+* запуск сервера
+* подія вимкнення
+* подія тривалості життя
+
+* обробник
+* обробник події
+* обробник винятків
+* обробляти
+
+* модель
+* модель Pydantic
+* модель даних
+* модель бази даних
+* модель форми
+* об'єкт моделі
+
+* клас
+* базовий клас
+* батьківський клас
+* підклас
+* дочірній клас
+* споріднений клас
+* метод класу
+
+* заголовок
+* заголовки
+* заголовок авторизації
+* заголовок `Authorization`
+* направлений заголовок
+
+* система впровадження залежностей
+* залежність
+* залежний
+* залежний
+
+* I/O-обмежений
+* CPU-обмежений
+* рівночасність
+* паралелізм
+* багатопроцесорність
+
+* змінна оточення
+* змінна оточення
+* `PATH`
+* змінна `PATH`
+
+* автентифікація
+* постачальник автентифікації
+* авторизація
+* форма авторизації
+* постачальник авторизації
+* користувач автентифікується
+* система автентифікує користувача
+
+* CLI
+* інтерфейс командного рядка
+
+* сервер
+* клієнт
+
+* хмарний постачальник
+* хмарний сервіс
+
+* розробка
+* етапи розробки
+
+* словник
+* словник
+* перелік
+* перелік
+* елемент переліку
+
+* кодувальник
+* декодувальник
+* кодувати
+* декодувати
+
+* виняток
+* породжувати
+
+* вираз
+* оператор
+
+* фронтенд
+* бекенд
+
+* обговорення GitHub
+* проблема GitHub
+
+* продуктивність
+* оптимізація продуктивності
+
+* тип, що повертається
+* повернене значення
+
+* безпека
+* схема безпеки
+
+* завдання
+* фонове завдання
+* функція завдання
+
+* шаблон
+* рушій шаблонів
+
+* анотація типу
+* підказка типу
+
+* серверний працівник
+* працівник Uvicorn
+* працівник Gunicorn
+* процес працівника
+* клас працівника
+* робоче навантаження
+
+* розгортання
+* розгортати
+
+* SDK
+* набір для розробки програмного забезпечення
+
+* `APIRouter`
+* `requirements.txt`
+* токен носія
+* несумісна зміна
+* помилка
+* кнопка
+* викликаємий
+* код
+* фіксація
+* менеджер контексту
+* співпрограма
+* сеанс бази даних
+* диск
+* домен
+* рушій
+* фальшивий X
+* метод HTTP GET
+* предмет
+* бібліотека
+* тривалість життя
+* блокування
+* проміжне програмне забезпечення
+* мобільний застосунок
+* модуль
+* монтування
+* мережа
+* джерело
+* переписування
+* корисне навантаження
+* процесор
+* властивість
+* представник
+* запит на витяг
+* запит
+* пам'ять з довільним доступом
+* віддалена машина
+* код статусу
+* строка
+* мітка
+* веб-фреймворк
+* дика карта
+* повертати
+* перевіряти
+
+////
+
+//// tab | Інформація
+
+Це неповний і не нормативний список (переважно) технічних термінів, що зустрічаються в документації. Він може бути корисним автору підсказки, щоб зрозуміти, для яких термінів LLM потрібна допомога. Наприклад, коли він постійно повертає хороший переклад до менш вдалого. Або коли йому складно відмінювати термін вашою мовою.
+
+Див., наприклад, розділ `### List of English terms and their preferred German translations` у `docs/de/llm-prompt.md`.
+
+////
diff --git a/docs/uk/docs/about/index.md b/docs/uk/docs/about/index.md
new file mode 100644
index 0000000000..198fd828e5
--- /dev/null
+++ b/docs/uk/docs/about/index.md
@@ -0,0 +1,3 @@
+# Про { #about }
+
+Про FastAPI, його проєктування, натхнення та інше. 🤓
diff --git a/docs/uk/docs/advanced/additional-responses.md b/docs/uk/docs/advanced/additional-responses.md
new file mode 100644
index 0000000000..089967a51a
--- /dev/null
+++ b/docs/uk/docs/advanced/additional-responses.md
@@ -0,0 +1,247 @@
+# Додаткові відповіді в OpenAPI { #additional-responses-in-openapi }
+
+/// warning | Попередження
+
+Це доволі просунута тема.
+
+Якщо ви лише починаєте з **FastAPI**, ймовірно, вам це не потрібно.
+
+///
+
+Ви можете оголосити додаткові відповіді з додатковими кодами статусу, типами медіа, описами тощо.
+
+Ці додаткові відповіді буде включено до схеми OpenAPI, тож вони з'являться і в документації API.
+
+Але для таких додаткових відповідей потрібно повертати `Response` на кшталт `JSONResponse` безпосередньо, із потрібним кодом статусу та вмістом.
+
+## Додаткова відповідь з `model` { #additional-response-with-model }
+
+Ви можете передати вашим декораторам операцій шляху параметр `responses`.
+
+Він приймає `dict`: ключі - це коди статусу для кожної відповіді (наприклад, `200`), а значення - інші `dict` з інформацією для кожної з них.
+
+Кожен із цих словників відповіді може мати ключ `model`, що містить Pydantic-модель, подібно до `response_model`.
+
+**FastAPI** візьме цю модель, згенерує її Схему JSON і додасть у відповідне місце в OpenAPI.
+
+Наприклад, щоб оголосити іншу відповідь з кодом статусу `404` і Pydantic-моделлю `Message`, ви можете написати:
+
+{* ../../docs_src/additional_responses/tutorial001_py310.py hl[18,22] *}
+
+/// note | Примітка
+
+Майте на увазі, що потрібно повертати `JSONResponse` безпосередньо.
+
+///
+
+/// info | Інформація
+
+Ключ `model` не є частиною OpenAPI.
+
+**FastAPI** візьме звідти Pydantic-модель, згенерує Схему JSON і помістить у відповідне місце.
+
+Відповідне місце це:
+
+- У ключі `content`, значенням якого є інший JSON-об'єкт (`dict`), що містить:
+ - Ключ із типом медіа, напр. `application/json`, значенням якого є інший JSON-об'єкт, що містить:
+ - Ключ `schema`, значенням якого є Схема JSON з моделі - ось це і є правильне місце.
+ - **FastAPI** додає тут посилання на глобальні Схеми JSON в іншому місці вашого OpenAPI замість прямого включення. Так інші застосунки та клієнти можуть напряму використовувати ці Схеми JSON, надавати кращі інструменти генерації коду тощо.
+
+///
+
+Згенеровані відповіді в OpenAPI для цієї операції шляху будуть такими:
+
+```JSON hl_lines="3-12"
+{
+ "responses": {
+ "404": {
+ "description": "Additional Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/Message"
+ }
+ }
+ }
+ },
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/Item"
+ }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ }
+ }
+ }
+}
+```
+
+Схеми посилаються на інше місце всередині схеми OpenAPI:
+
+```JSON hl_lines="4-16"
+{
+ "components": {
+ "schemas": {
+ "Message": {
+ "title": "Message",
+ "required": [
+ "message"
+ ],
+ "type": "object",
+ "properties": {
+ "message": {
+ "title": "Message",
+ "type": "string"
+ }
+ }
+ },
+ "Item": {
+ "title": "Item",
+ "required": [
+ "id",
+ "value"
+ ],
+ "type": "object",
+ "properties": {
+ "id": {
+ "title": "Id",
+ "type": "string"
+ },
+ "value": {
+ "title": "Value",
+ "type": "string"
+ }
+ }
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": [
+ "loc",
+ "msg",
+ "type"
+ ],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "msg": {
+ "title": "Message",
+ "type": "string"
+ },
+ "type": {
+ "title": "Error Type",
+ "type": "string"
+ }
+ }
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/ValidationError"
+ }
+ }
+ }
+ }
+ }
+ }
+}
+```
+
+## Додаткові типи медіа для основної відповіді { #additional-media-types-for-the-main-response }
+
+Можна використати цей самий параметр `responses`, щоб додати різні типи медіа для тієї ж основної відповіді.
+
+Наприклад, можна додати додатковий тип медіа `image/png`, оголосивши, що ваша операція шляху може повертати JSON-об'єкт (з типом медіа `application/json`) або PNG-зображення:
+
+{* ../../docs_src/additional_responses/tutorial002_py310.py hl[17:22,26] *}
+
+/// note | Примітка
+
+Зверніть увагу, що потрібно повертати зображення безпосередньо за допомогою `FileResponse`.
+
+///
+
+/// info | Інформація
+
+Поки ви явно не вкажете інший тип медіа в параметрі `responses`, FastAPI вважатиме, що відповідь має той самий тип медіа, що й основний клас відповіді (типово `application/json`).
+
+Але якщо ви вказали власний клас відповіді з `None` як типом медіа, FastAPI використає `application/json` для будь-якої додаткової відповіді, що має пов'язану модель.
+
+///
+
+## Комбінування інформації { #combining-information }
+
+Ви також можете поєднувати інформацію про відповіді з кількох місць, зокрема з параметрів `response_model`, `status_code` і `responses`.
+
+Ви можете оголосити `response_model`, використовуючи типовий код статусу `200` (або власний за потреби), а потім оголосити додаткову інформацію для цієї ж відповіді в `responses`, безпосередньо в схемі OpenAPI.
+
+**FastAPI** збереже додаткову інформацію з `responses` і поєднає її зі Схемою JSON з вашої моделі.
+
+Наприклад, ви можете оголосити відповідь з кодом статусу `404`, яка використовує Pydantic-модель і має власний `description`.
+
+І відповідь з кодом статусу `200`, яка використовує ваш `response_model`, але містить власний `example`:
+
+{* ../../docs_src/additional_responses/tutorial003_py310.py hl[20:31] *}
+
+Усе це буде поєднано та включено до вашого OpenAPI і показано в документації API:
+
+

+
+## Комбінуйте попередньо визначені та власні відповіді { #combine-predefined-responses-and-custom-ones }
+
+Можливо, ви захочете мати кілька попередньо визначених відповідей, що застосовуються до багатьох операцій шляху, але поєднувати їх із власними відповідями, потрібними для кожної операції шляху.
+
+Для таких випадків можна скористатися прийомом Python «розпакування» `dict` за допомогою `**dict_to_unpack`:
+
+```Python
+old_dict = {
+ "old key": "old value",
+ "second old key": "second old value",
+}
+new_dict = {**old_dict, "new key": "new value"}
+```
+
+Тут `new_dict` міститиме всі пари ключ-значення з `old_dict` плюс нову пару ключ-значення:
+
+```Python
+{
+ "old key": "old value",
+ "second old key": "second old value",
+ "new key": "new value",
+}
+```
+
+Цей прийом можна використати, щоб перевикористовувати деякі попередньо визначені відповіді у ваших операціях шляху та поєднувати їх із додатковими власними.
+
+Наприклад:
+
+{* ../../docs_src/additional_responses/tutorial004_py310.py hl[11:15,24] *}
+
+## Докладніше про відповіді OpenAPI { #more-information-about-openapi-responses }
+
+Щоб побачити, що саме можна включати у відповіді, ознайомтеся з цими розділами специфікації OpenAPI:
+
+-
Об'єкт відповідей OpenAPI, він включає `Response Object`.
+-
Об'єкт відповіді OpenAPI, ви можете включити будь-що з цього безпосередньо в кожну відповідь у параметрі `responses`. Зокрема `description`, `headers`, `content` (усередині нього ви оголошуєте різні типи медіа та Схеми JSON) і `links`.
diff --git a/docs/uk/docs/advanced/additional-status-codes.md b/docs/uk/docs/advanced/additional-status-codes.md
new file mode 100644
index 0000000000..afba933e20
--- /dev/null
+++ b/docs/uk/docs/advanced/additional-status-codes.md
@@ -0,0 +1,41 @@
+# Додаткові коди статусу { #additional-status-codes }
+
+За замовчуванням **FastAPI** повертатиме відповіді за допомогою `JSONResponse`, поміщаючи вміст, який ви повертаєте з вашої *операції шляху*, у цей `JSONResponse`.
+
+Він використовуватиме код статусу за замовчуванням або той, який ви встановите у своїй *операції шляху*.
+
+## Додаткові коди статусу { #additional-status-codes_1 }
+
+Якщо ви хочете повертати додаткові коди статусу, окрім основного, зробіть це, повертаючи `Response` безпосередньо, наприклад `JSONResponse`, і встановіть додатковий код статусу напряму.
+
+Наприклад, припустімо, ви хочете мати *операцію шляху*, яка дозволяє оновлювати предмети та повертає код статусу HTTP 200 «OK» у разі успіху.
+
+Але ви також хочете приймати нові предмети. І коли таких предметів раніше не існувало, операція створює їх і повертає код статусу HTTP 201 «Created».
+
+Щоб це реалізувати, імпортуйте `JSONResponse` і поверніть ваш вміст безпосередньо там, встановивши потрібний `status_code`:
+
+{* ../../docs_src/additional_status_codes/tutorial001_an_py310.py hl[4,25] *}
+
+/// warning | Попередження
+
+Коли ви повертаєте `Response` безпосередньо, як у прикладі вище, він і буде повернений безпосередньо.
+
+Він не буде серіалізований за допомогою моделі тощо.
+
+Переконайтеся, що він містить саме ті дані, які вам потрібні, і що значення є коректним JSON (якщо ви використовуєте `JSONResponse`).
+
+///
+
+/// note | Технічні деталі
+
+Ви також можете використати `from starlette.responses import JSONResponse`.
+
+**FastAPI** надає ті самі `starlette.responses` як `fastapi.responses` просто для вашої зручності як розробника. Але більшість доступних відповідей надходить безпосередньо зі Starlette. Те саме і зі `status`.
+
+///
+
+## OpenAPI і документація API { #openapi-and-api-docs }
+
+Якщо ви повертаєте додаткові коди статусу та відповіді безпосередньо, вони не будуть включені до схеми OpenAPI (документації API), адже FastAPI не має способу заздалегідь знати, що саме ви повернете.
+
+Але ви можете задокументувати це у своєму коді, використовуючи: [Додаткові відповіді](additional-responses.md){.internal-link target=_blank}.
diff --git a/docs/uk/docs/advanced/advanced-dependencies.md b/docs/uk/docs/advanced/advanced-dependencies.md
new file mode 100644
index 0000000000..0c6f8cbb34
--- /dev/null
+++ b/docs/uk/docs/advanced/advanced-dependencies.md
@@ -0,0 +1,163 @@
+# Просунуті залежності { #advanced-dependencies }
+
+## Параметризовані залежності { #parameterized-dependencies }
+
+Усі залежності, які ми бачили, - це фіксована функція або клас.
+
+Але можуть бути випадки, коли ви хочете мати змогу задавати параметри залежності, не оголошуючи багато різних функцій або класів.
+
+Уявімо, що ми хочемо мати залежність, яка перевіряє, чи параметр запиту `q` містить певний фіксований вміст.
+
+Але ми хочемо мати змогу параметризувати цей фіксований вміст.
+
+## Екземпляр «callable» { #a-callable-instance }
+
+У Python є спосіб зробити екземпляр класу «callable».
+
+Не сам клас (який уже є «callable»), а екземпляр цього класу.
+
+Щоб це зробити, оголошуємо метод `__call__`:
+
+{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[12] *}
+
+У цьому випадку саме `__call__` **FastAPI** використає для перевірки додаткових параметрів і підзалежностей, і саме його буде викликано, щоб передати значення параметру у вашу *функцію операції шляху* пізніше.
+
+## Параметризувати екземпляр { #parameterize-the-instance }
+
+Тепер ми можемо використати `__init__`, щоб оголосити параметри екземпляра, які можна застосувати для «параметризації» залежності:
+
+{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[9] *}
+
+У цьому випадку **FastAPI** ніколи не торкається `__init__` і не покладається на нього - ми використовуватимемо його безпосередньо у своєму коді.
+
+## Створити екземпляр { #create-an-instance }
+
+Ми можемо створити екземпляр цього класу так:
+
+{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[18] *}
+
+Таким чином ми «параметризуємо» нашу залежність, яка тепер містить «bar» як атрибут `checker.fixed_content`.
+
+## Використовувати екземпляр як залежність { #use-the-instance-as-a-dependency }
+
+Далі ми можемо використати цей `checker` у `Depends(checker)` замість `Depends(FixedContentQueryChecker)`, адже залежністю є екземпляр `checker`, а не сам клас.
+
+Коли залежність розв'язується, **FastAPI** викличе цей `checker` так:
+
+```Python
+checker(q="somequery")
+```
+
+...і передасть усе, що він поверне, як значення залежності у нашій *функції операції шляху* як параметр `fixed_content_included`:
+
+{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[22] *}
+
+/// tip | Порада
+
+Усе це може здаватися надуманим. І поки що може бути не дуже зрозуміло, навіщо це корисно.
+
+Ці приклади навмисно прості, але показують, як усе працює.
+
+У розділах про безпеку є утилітарні функції, реалізовані таким самим способом.
+
+Якщо ви все це зрозуміли, ви вже знаєте, як під капотом працюють ті утиліти для безпеки.
+
+///
+
+## Залежності з `yield`, `HTTPException`, `except` та фоновими задачами { #dependencies-with-yield-httpexception-except-and-background-tasks }
+
+/// warning | Попередження
+
+Найімовірніше, вам не знадобляться ці технічні деталі.
+
+Вони корисні головно, якщо у вас був застосунок FastAPI старіший за 0.121.0 і ви стикаєтеся з проблемами залежностей із `yield`.
+
+///
+
+Залежності з `yield` еволюціонували з часом, щоб охопити різні сценарії використання та виправити деякі проблеми, ось підсумок змін.
+
+### Залежності з `yield` і `scope` { #dependencies-with-yield-and-scope }
+
+У версії 0.121.0 **FastAPI** додано підтримку `Depends(scope="function")` для залежностей з `yield`.
+
+З `Depends(scope="function")` завершальний код після `yield` виконується одразу після завершення *функції операції шляху*, до того як відповідь буде надіслана клієнту.
+
+А при використанні `Depends(scope="request")` (типове значення) завершальний код після `yield` виконується після відправлення відповіді.
+
+Докладніше читайте в документації: [Залежності з `yield` - Ранній вихід і `scope`](../tutorial/dependencies/dependencies-with-yield.md#early-exit-and-scope).
+
+### Залежності з `yield` і `StreamingResponse`, технічні деталі { #dependencies-with-yield-and-streamingresponse-technical-details }
+
+До **FastAPI** 0.118.0, якщо ви використовували залежність із `yield`, завершальний код виконувався після повернення з *функції операції шляху*, але безпосередньо перед відправленням відповіді.
+
+Метою було уникнути утримання ресурсів довше, ніж потрібно, очікуючи, поки відповідь пройде мережею.
+
+Це також означало, що якщо ви повертали `StreamingResponse`, завершальний код залежності з `yield` уже було б виконано.
+
+Наприклад, якщо у залежності з `yield` була сесія бази даних, `StreamingResponse` не зміг би використовувати цю сесію під час потокової передачі даних, тому що сесію вже закрито в завершальному коді після `yield`.
+
+Цю поведінку змінено у 0.118.0: завершальний код після `yield` знову виконується після відправлення відповіді.
+
+/// info | Інформація
+
+Як побачите нижче, це дуже схоже на поведінку до версії 0.106.0, але з кількома покращеннями та виправленнями помилок у крайових випадках.
+
+///
+
+#### Випадки використання з раннім завершальним кодом { #use-cases-with-early-exit-code }
+
+Є кілька сценаріїв із певними умовами, які можуть виграти від старої поведінки - виконувати завершальний код залежностей з `yield` до надсилання відповіді.
+
+Наприклад, уявіть, що у вас є код, який використовує сесію бази даних у залежності з `yield` лише для перевірки користувача, але сесія більше не використовується у *функції операції шляху*, тільки в залежності, і відправлення відповіді триває довго - як у `StreamingResponse`, що повільно надсилає дані, але з якоїсь причини не використовує базу даних.
+
+У такому разі сесія БД утримувалася б до завершення відправлення відповіді, але якщо ви її не використовуєте, утримувати її немає потреби.
+
+Ось як це може виглядати:
+
+{* ../../docs_src/dependencies/tutorial013_an_py310.py *}
+
+Завершальний код - автоматичне закриття `Session` у:
+
+{* ../../docs_src/dependencies/tutorial013_an_py310.py ln[19:21] *}
+
+...виконається після того, як відповідь завершить надсилати повільні дані:
+
+{* ../../docs_src/dependencies/tutorial013_an_py310.py ln[30:38] hl[31:33] *}
+
+Але оскільки `generate_stream()` не використовує сесію бази даних, немає реальної потреби тримати сесію відкритою під час надсилання відповіді.
+
+Якщо у вас саме такий випадок із SQLModel (або SQLAlchemy), ви можете явно закрити сесію, коли вона більше не потрібна:
+
+{* ../../docs_src/dependencies/tutorial014_an_py310.py ln[24:28] hl[28] *}
+
+Так сесія звільнить з'єднання з базою даних, і його зможуть використовувати інші запити.
+
+Якщо у вас інший сценарій, де потрібно раннє завершення залежності з `yield`, створіть, будь ласка,
питання в обговореннях GitHub із вашим конкретним випадком і поясненням, чому вам корисне раннє закриття для залежностей з `yield`.
+
+Якщо будуть переконливі приклади для раннього закриття в залежностях з `yield`, я розгляну додавання нового способу увімкнути раннє закриття.
+
+### Залежності з `yield` і `except`, технічні деталі { #dependencies-with-yield-and-except-technical-details }
+
+До **FastAPI** 0.110.0, якщо ви використовували залежність із `yield`, перехоплювали виняток через `except` у цій залежності і не піднімали його знову, виняток автоматично піднімався/пересилався до будь-яких обробників винятків або внутрішнього обробника помилок сервера.
+
+Це змінено у версії 0.110.0, щоб усунути неконтрольоване споживання пам'яті від пересланих винятків без обробника (внутрішні помилки сервера) та зробити поведінку узгодженою зі звичайним Python-кодом.
+
+### Фонові задачі та залежності з `yield`, технічні деталі { #background-tasks-and-dependencies-with-yield-technical-details }
+
+До **FastAPI** 0.106.0 піднімати винятки після `yield` було неможливо: завершальний код у залежностях з `yield` виконувався після надсилання відповіді, тож [обробники винятків](../tutorial/handling-errors.md#install-custom-exception-handlers){.internal-link target=_blank} уже відпрацювали б.
+
+Так було спроєктовано головно для того, щоб дозволити використовувати ті самі об'єкти, «віддані» залежностями через `yield`, усередині фонових задач, оскільки завершальний код виконувався після завершення фонових задач.
+
+У **FastAPI** 0.106.0 це змінено, щоб не утримувати ресурси під час очікування, поки відповідь піде мережею.
+
+/// tip | Порада
+
+Крім того, фонова задача зазвичай є незалежним набором логіки, який слід обробляти окремо, з власними ресурсами (наприклад, власним з'єднанням з базою даних).
+
+Тож так у вас, ймовірно, буде чистіший код.
+
+///
+
+Якщо ви раніше покладалися на цю поведінку, тепер слід створювати ресурси для фонових задач усередині самої фонової задачі та використовувати всередині лише дані, що не залежать від ресурсів залежностей із `yield`.
+
+Наприклад, замість використання тієї самої сесії бази даних ви створюватимете нову сесію в самій фоновій задачі та отримуватимете об'єкти з бази даних, використовуючи цю нову сесію. І далі, замість передавання об'єкта з бази даних як параметра у функцію фонової задачі, ви передасте ідентифікатор цього об'єкта, а потім отримаєте об'єкт знову всередині функції фонової задачі.
diff --git a/docs/uk/docs/advanced/advanced-python-types.md b/docs/uk/docs/advanced/advanced-python-types.md
new file mode 100644
index 0000000000..9eedc48568
--- /dev/null
+++ b/docs/uk/docs/advanced/advanced-python-types.md
@@ -0,0 +1,61 @@
+# Просунуті типи Python { #advanced-python-types }
+
+Ось кілька додаткових ідей, які можуть бути корисні під час роботи з типами в Python.
+
+## Використання `Union` або `Optional` { #using-union-or-optional }
+
+Якщо ваш код з якоїсь причини не може використовувати `|`, наприклад, якщо це не анотація типів, а щось на кшталт `response_model=`, замість вертикальної риски (`|`) ви можете використати `Union` з `typing`.
+
+Наприклад, ви можете оголосити, що щось може бути `str` або `None`:
+
+```python
+from typing import Union
+
+
+def say_hi(name: Union[str, None]):
+ print(f"Hi {name}!")
+```
+
+У `typing` також є скорочення, щоб оголосити, що щось може бути `None`, - `Optional`.
+
+Ось порада з моєї дуже «суб'єктивної» точки зору:
+
+- 🚨 Уникайте використання `Optional[SomeType]`
+- Натомість ✨ **використовуйте `Union[SomeType, None]`** ✨.
+
+Обидва варіанти еквівалентні і під капотом однакові, але я рекомендую `Union` замість `Optional`, тому що слово «**optional**» ніби натякає, що значення є необов'язковим, а насправді означає «може бути `None`», навіть якщо воно не є необов'язковим і все ще обов'язкове.
+
+Вважаю, `Union[SomeType, None]` більш явно це передає.
+
+Йдеться лише про слова та назви. Але ці слова можуть впливати на те, як ви та ваша команда думаєте про код.
+
+Як приклад, розгляньмо цю функцію:
+
+```python
+from typing import Optional
+
+
+def say_hi(name: Optional[str]):
+ print(f"Hey {name}!")
+```
+
+Параметр `name` визначено як `Optional[str]`, але він не є необов'язковим, ви не можете викликати функцію без цього параметра:
+
+```Python
+say_hi() # О ні, це викликає помилку! 😱
+```
+
+Параметр `name` все ще обов'язковий (не «необов'язковий»), тому що не має значення за замовчуванням. Водночас `name` приймає `None` як значення:
+
+```Python
+say_hi(name=None) # Це працює, None припустимий 🎉
+```
+
+Гарна новина: у більшості випадків ви зможете просто використовувати `|`, щоб визначати об'єднання типів:
+
+```python
+def say_hi(name: str | None):
+ print(f"Hey {name}!")
+```
+
+Тож зазвичай вам не доведеться перейматися такими назвами, як `Optional` і `Union`. 😎
diff --git a/docs/uk/docs/advanced/async-tests.md b/docs/uk/docs/advanced/async-tests.md
new file mode 100644
index 0000000000..51d0d57610
--- /dev/null
+++ b/docs/uk/docs/advanced/async-tests.md
@@ -0,0 +1,99 @@
+# Асинхронні тести { #async-tests }
+
+Ви вже бачили, як тестувати ваші застосунки **FastAPI** за допомогою наданого `TestClient`. До цього часу ви бачили лише, як писати синхронні тести, без використання функцій `async`.
+
+Можливість використовувати асинхронні функції у тестах може бути корисною, наприклад, коли ви асинхронно звертаєтеся до бази даних. Уявіть, що ви хочете протестувати надсилання запитів до вашого застосунку FastAPI, а потім перевірити, що ваш бекенд успішно записав коректні дані в базу даних, використовуючи асинхронну бібліотеку для бази даних.
+
+Розгляньмо, як це реалізувати.
+
+## pytest.mark.anyio { #pytest-mark-anyio }
+
+Якщо ми хочемо викликати асинхронні функції у тестах, самі тестові функції мають бути асинхронними. AnyIO надає зручний плагін, який дозволяє вказати, що деякі тестові функції слід виконувати асинхронно.
+
+## HTTPX { #httpx }
+
+Навіть якщо ваш застосунок **FastAPI** використовує звичайні функції `def` замість `async def`, під капотом це все одно `async`-застосунок.
+
+`TestClient` робить певну «магію» всередині, щоб викликати асинхронний застосунок FastAPI у ваших звичайних тестових функціях `def`, використовуючи стандартний pytest. Але ця «магія» більше не працює, коли ми використовуємо його всередині асинхронних функцій. Запускаючи тести асинхронно, ми більше не можемо використовувати `TestClient` у наших тестових функціях.
+
+`TestClient` побудований на основі
HTTPX, і на щастя, ми можемо використовувати його безпосередньо для тестування API.
+
+## Приклад { #example }
+
+Для простого прикладу розгляньмо структуру файлів, подібну до описаної в [Більші застосунки](../tutorial/bigger-applications.md){.internal-link target=_blank} та [Тестування](../tutorial/testing.md){.internal-link target=_blank}:
+
+```
+.
+├── app
+│ ├── __init__.py
+│ ├── main.py
+│ └── test_main.py
+```
+
+Файл `main.py` міститиме:
+
+{* ../../docs_src/async_tests/app_a_py310/main.py *}
+
+Файл `test_main.py` міститиме тести для `main.py`, тепер це може виглядати так:
+
+{* ../../docs_src/async_tests/app_a_py310/test_main.py *}
+
+## Запуск { #run-it }
+
+Ви можете запустити тести як зазвичай:
+
+
+
+```console
+$ pytest
+
+---> 100%
+```
+
+
+
+## Докладно { #in-detail }
+
+Маркер `@pytest.mark.anyio` повідомляє pytest, що цю тестову функцію слід викликати асинхронно:
+
+{* ../../docs_src/async_tests/app_a_py310/test_main.py hl[7] *}
+
+/// tip | Порада
+
+Зауважте, що тестова функція тепер `async def` замість просто `def`, як це було раніше при використанні `TestClient`.
+
+///
+
+Далі ми можемо створити `AsyncClient` із застосунком і надсилати до нього асинхронні запити, використовуючи `await`.
+
+{* ../../docs_src/async_tests/app_a_py310/test_main.py hl[9:12] *}
+
+Це еквівалентно:
+
+```Python
+response = client.get('/')
+```
+
+...що ми раніше використовували для надсилання запитів за допомогою `TestClient`.
+
+/// tip | Порада
+
+Зауважте, що ми використовуємо async/await із новим `AsyncClient` - запит є асинхронним.
+
+///
+
+/// warning | Попередження
+
+Якщо ваш застосунок залежить від подій тривалості життя, `AsyncClient` не ініціюватиме ці події. Щоб гарантувати їх ініціалізацію, використовуйте `LifespanManager` з
florimondmanca/asgi-lifespan.
+
+///
+
+## Інші асинхронні виклики функцій { #other-asynchronous-function-calls }
+
+Оскільки тестова функція тепер асинхронна, ви також можете викликати (і `await`) інші `async`-функції окрім надсилання запитів до вашого застосунку FastAPI у тестах - так само, як ви робили б це будь-де у вашому коді.
+
+/// tip | Порада
+
+Якщо ви натрапили на `RuntimeError: Task attached to a different loop` під час інтеграції асинхронних викликів у ваші тести (наприклад, при використанні
MongoDB's MotorClient), пам'ятайте створювати об'єкти, яким потрібен цикл подій, лише всередині асинхронних функцій, наприклад, у зворотному виклику `@app.on_event("startup")`.
+
+///
diff --git a/docs/uk/docs/advanced/behind-a-proxy.md b/docs/uk/docs/advanced/behind-a-proxy.md
new file mode 100644
index 0000000000..66bb4c0827
--- /dev/null
+++ b/docs/uk/docs/advanced/behind-a-proxy.md
@@ -0,0 +1,466 @@
+# За представником { #behind-a-proxy }
+
+У багатьох випадках ви будете використовувати **представника** на кшталт Traefik або Nginx перед вашим застосунком FastAPI.
+
+Такі представники можуть обробляти сертифікати HTTPS та інші речі.
+
+## Направлені заголовки представника { #proxy-forwarded-headers }
+
+**Представник** перед вашим застосунком зазвичай встановлює деякі заголовки на льоту перед відправленням запитів до вашого **сервера**, щоб повідомити серверу, що запит було **направлено** через представника, вказати оригінальну (публічну) URL-адресу, включно з доменом, що використовується HTTPS тощо.
+
+Програмний **сервер** (наприклад, **Uvicorn** через **FastAPI CLI**) здатний інтерпретувати ці заголовки і передавати цю інформацію вашому застосунку.
+
+Але з міркувань безпеки, оскільки сервер не знає, що він працює за довіреним представником, він не інтерпретуватиме ці заголовки.
+
+/// note | Технічні деталі
+
+Заголовки представника:
+
+*
X-Forwarded-For
+*
X-Forwarded-Proto
+*
X-Forwarded-Host
+
+///
+
+### Увімкнути направлені заголовки представника { #enable-proxy-forwarded-headers }
+
+Ви можете запустити FastAPI CLI з *опцією CLI* `--forwarded-allow-ips` і передати IP-адреси, яким слід довіряти для читання цих направлених заголовків.
+
+Якщо ви встановите `--forwarded-allow-ips="*"`, це означатиме довіру до всіх вхідних IP.
+
+Якщо ваш **сервер** знаходиться за довіреним **представником** і тільки представник спілкується з ним, це змусить сервер приймати будь-яку IP-адресу цього **представника**.
+
+
+
+```console
+$ fastapi run --forwarded-allow-ips="*"
+
+INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
+```
+
+
+
+### Перенаправлення з HTTPS { #redirects-with-https }
+
+Наприклад, припустимо, ви визначили *операцію шляху* `/items/`:
+
+{* ../../docs_src/behind_a_proxy/tutorial001_01_py310.py hl[6] *}
+
+Якщо клієнт спробує перейти до `/items`, за замовчуванням буде виконано перенаправлення на `/items/`.
+
+Але до встановлення *опції CLI* `--forwarded-allow-ips` це могло б перенаправити на `http://localhost:8000/items/`.
+
+Втім, можливо ваш застосунок розміщено на `https://mysuperapp.com`, і перенаправлення має бути на `https://mysuperapp.com/items/`.
+
+Налаштувавши `--proxy-headers`, FastAPI зможе перенаправляти на правильну адресу. 😎
+
+```
+https://mysuperapp.com/items/
+```
+
+/// tip | Порада
+
+Якщо хочете дізнатися більше про HTTPS, перегляньте посібник [Про HTTPS](../deployment/https.md){.internal-link target=_blank}.
+
+///
+
+### Як працюють направлені заголовки представника { #how-proxy-forwarded-headers-work }
+
+Ось візуальне подання того, як **представник** додає направлені заголовки між клієнтом і **сервером застосунку**:
+
+```mermaid
+sequenceDiagram
+ participant Client
+ participant Proxy as Proxy/Load Balancer
+ participant Server as FastAPI Server
+
+ Client->>Proxy: HTTPS Request
Host: mysuperapp.com
Path: /items
+
+ Note over Proxy: Proxy adds forwarded headers
+
+ Proxy->>Server: HTTP Request
X-Forwarded-For: [client IP]
X-Forwarded-Proto: https
X-Forwarded-Host: mysuperapp.com
Path: /items
+
+ Note over Server: Server interprets headers
(if --forwarded-allow-ips is set)
+
+ Server->>Proxy: HTTP Response
with correct HTTPS URLs
+
+ Proxy->>Client: HTTPS Response
+```
+
+**Представник** перехоплює початковий запит клієнта і додає спеціальні *направлені* заголовки (`X-Forwarded-*`) перед передачею запиту на **сервер застосунку**.
+
+Ці заголовки зберігають інформацію про оригінальний запит, яка інакше була б втрачена:
+
+- X-Forwarded-For: оригінальна IP-адреса клієнта
+- X-Forwarded-Proto: оригінальний протокол (`https`)
+- X-Forwarded-Host: оригінальний хост (`mysuperapp.com`)
+
+Коли **FastAPI CLI** налаштовано з `--forwarded-allow-ips`, він довіряє цим заголовкам і використовує їх, наприклад, для побудови коректних URL-адрес у перенаправленнях.
+
+## Представник із вилученим префіксом шляху { #proxy-with-a-stripped-path-prefix }
+
+У вас може бути представник, що додає префікс шляху до вашого застосунку.
+
+У таких випадках ви можете використати `root_path` для конфігурації застосунку.
+
+`root_path` - це механізм, наданий специфікацією ASGI (на якій побудовано FastAPI через Starlette).
+
+`root_path` використовується для обробки саме таких випадків.
+
+Його також використано внутрішньо під час монтування підзастосунків.
+
+Наявність представника з вилученим префіксом шляху означає, що ви могли б оголосити шлях `/app` у вашому коді, але потім додати шар зверху (представника), який розмістить ваш застосунок **FastAPI** під шляхом на кшталт `/api/v1`.
+
+У такому разі початковий шлях `/app` фактично буде доступний за `/api/v1/app`.
+
+Хоча весь ваш код написано з припущенням, що є лише `/app`.
+
+{* ../../docs_src/behind_a_proxy/tutorial001_py310.py hl[6] *}
+
+І представник буде **«зрізати»** **префікс шляху** на льоту перед передачею запиту серверу застосунку (ймовірно, Uvicorn через FastAPI CLI), зберігаючи переконання вашого застосунку, що його обслуговують за `/app`, тож вам не доведеться оновлювати весь код, щоб додати префікс `/api/v1`.
+
+Дотепер усе працювало б як зазвичай.
+
+Але коли ви відкриєте вбудований інтерфейс документації (фронтенд), він очікуватиме отримати схему OpenAPI за `/openapi.json`, замість `/api/v1/openapi.json`.
+
+Отже, фронтенд (що працює у браузері) спробує звернутися до `/openapi.json` і не зможе отримати схему OpenAPI.
+
+Оскільки у нас є представник з префіксом шляху `/api/v1` для нашого застосунку, фронтенду потрібно отримувати схему OpenAPI за `/api/v1/openapi.json`.
+
+```mermaid
+graph LR
+
+browser("Browser")
+proxy["Proxy on http://0.0.0.0:9999/api/v1/app"]
+server["Server on http://127.0.0.1:8000/app"]
+
+browser --> proxy
+proxy --> server
+```
+
+/// tip | Порада
+
+IP `0.0.0.0` зазвичай означає, що програма слухає на всіх IP-адресах, доступних на цій машині/сервері.
+
+///
+
+Інтерфейсу документації також потрібно, щоб схема OpenAPI оголошувала, що цей `server` API розташований за `/api/v1` (за представником). Наприклад:
+
+```JSON hl_lines="4-8"
+{
+ "openapi": "3.1.0",
+ // Ще дещо тут
+ "servers": [
+ {
+ "url": "/api/v1"
+ }
+ ],
+ "paths": {
+ // Ще дещо тут
+ }
+}
+```
+
+У цьому прикладі «Proxy» може бути чимось на кшталт **Traefik**. А сервером буде щось на кшталт FastAPI CLI з **Uvicorn**, який запускає ваш застосунок FastAPI.
+
+### Задання `root_path` { #providing-the-root-path }
+
+Щоб цього досягти, ви можете використати опцію командного рядка `--root-path`, наприклад:
+
+
+
+```console
+$ fastapi run main.py --forwarded-allow-ips="*" --root-path /api/v1
+
+INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
+```
+
+
+
+Якщо ви використовуєте Hypercorn, у нього також є опція `--root-path`.
+
+/// note | Технічні деталі
+
+Специфікація ASGI визначає `root_path` для такого випадку використання.
+
+А опція командного рядка `--root-path` надає цей `root_path`.
+
+///
+
+### Перевірка поточного `root_path` { #checking-the-current-root-path }
+
+Ви можете отримати поточний `root_path`, який використовує ваш застосунок для кожного запиту, він є частиною словника `scope` (це частина специфікації ASGI).
+
+Тут ми додаємо його у повідомлення лише для демонстрації.
+
+{* ../../docs_src/behind_a_proxy/tutorial001_py310.py hl[8] *}
+
+Потім, якщо ви запустите Uvicorn так:
+
+
+
+```console
+$ fastapi run main.py --forwarded-allow-ips="*" --root-path /api/v1
+
+INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
+```
+
+
+
+Відповідь буде приблизно такою:
+
+```JSON
+{
+ "message": "Hello World",
+ "root_path": "/api/v1"
+}
+```
+
+### Встановлення `root_path` у застосунку FastAPI { #setting-the-root-path-in-the-fastapi-app }
+
+Альтернативно, якщо у вас немає способу передати опцію командного рядка на кшталт `--root-path` чи еквівалентну, ви можете встановити параметр `root_path` під час створення вашого застосунку FastAPI:
+
+{* ../../docs_src/behind_a_proxy/tutorial002_py310.py hl[3] *}
+
+Передача `root_path` до `FastAPI` еквівалентна передачі опції командного рядка `--root-path` до Uvicorn або Hypercorn.
+
+### Про `root_path` { #about-root-path }
+
+Майте на увазі, що сервер (Uvicorn) не використовуватиме `root_path` ні для чого, окрім передачі його застосунку.
+
+Але якщо ви перейдете у вашому браузері на
http://127.0.0.1:8000/app, ви побачите звичайну відповідь:
+
+```JSON
+{
+ "message": "Hello World",
+ "root_path": "/api/v1"
+}
+```
+
+Тобто він не очікуватиме доступу за адресою `http://127.0.0.1:8000/api/v1/app`.
+
+Uvicorn очікуватиме, що представник буде звертатися до Uvicorn на `http://127.0.0.1:8000/app`, і тоді саме представник відповідатиме за додавання додаткового префікса `/api/v1` зверху.
+
+## Про представників із вилученим префіксом шляху { #about-proxies-with-a-stripped-path-prefix }
+
+Майте на увазі, що представник із вилученим префіксом шляху - це лише один зі способів його налаштування.
+
+Ймовірно, в багатьох випадках за замовчуванням представник не матиме вилученого префікса шляху.
+
+У такому випадку (без вилученого префікса шляху) представник слухатиме щось на кшталт `https://myawesomeapp.com`, і коли браузер перейде на `https://myawesomeapp.com/api/v1/app`, а ваш сервер (наприклад, Uvicorn) слухає на `http://127.0.0.1:8000`, представник (без вилученого префікса) звернеться до Uvicorn за тим самим шляхом: `http://127.0.0.1:8000/api/v1/app`.
+
+## Локальне тестування з Traefik { #testing-locally-with-traefik }
+
+Ви можете легко провести експеримент локально з вилученим префіксом шляху, використовуючи
Traefik.
+
+
Завантажте Traefik, це один бінарний файл, ви можете розпакувати архів і запустити його безпосередньо з термінала.
+
+Потім створіть файл `traefik.toml` з таким вмістом:
+
+```TOML hl_lines="3"
+[entryPoints]
+ [entryPoints.http]
+ address = ":9999"
+
+[providers]
+ [providers.file]
+ filename = "routes.toml"
+```
+
+Це вказує Traefik слухати порт 9999 і використовувати інший файл `routes.toml`.
+
+/// tip | Порада
+
+Ми використовуємо порт 9999 замість стандартного HTTP-порту 80, щоб вам не довелося запускати його з адмін-повноваженнями (`sudo`).
+
+///
+
+Тепер створіть інший файл `routes.toml`:
+
+```TOML hl_lines="5 12 20"
+[http]
+ [http.middlewares]
+
+ [http.middlewares.api-stripprefix.stripPrefix]
+ prefixes = ["/api/v1"]
+
+ [http.routers]
+
+ [http.routers.app-http]
+ entryPoints = ["http"]
+ service = "app"
+ rule = "PathPrefix(`/api/v1`)"
+ middlewares = ["api-stripprefix"]
+
+ [http.services]
+
+ [http.services.app]
+ [http.services.app.loadBalancer]
+ [[http.services.app.loadBalancer.servers]]
+ url = "http://127.0.0.1:8000"
+```
+
+Цей файл налаштовує Traefik на використання префікса шляху `/api/v1`.
+
+Потім Traefik переспрямовуватиме свої запити до вашого Uvicorn, який працює на `http://127.0.0.1:8000`.
+
+Тепер запустіть Traefik:
+
+
+
+```console
+$ ./traefik --configFile=traefik.toml
+
+INFO[0000] Configuration loaded from file: /home/user/awesomeapi/traefik.toml
+```
+
+
+
+А тепер запустіть ваш застосунок, використовуючи опцію `--root-path`:
+
+
+
+```console
+$ fastapi run main.py --forwarded-allow-ips="*" --root-path /api/v1
+
+INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
+```
+
+
+
+### Перевірте відповіді { #check-the-responses }
+
+Тепер, якщо ви перейдете за URL із портом Uvicorn:
http://127.0.0.1:8000/app, ви побачите звичайну відповідь:
+
+```JSON
+{
+ "message": "Hello World",
+ "root_path": "/api/v1"
+}
+```
+
+/// tip | Порада
+
+Зверніть увагу, що хоча ви звертаєтеся за адресою `http://127.0.0.1:8000/app`, відображається `root_path` `/api/v1`, взятий із опції `--root-path`.
+
+///
+
+А тепер відкрийте URL із портом Traefik, включно з префіксом шляху:
http://127.0.0.1:9999/api/v1/app.
+
+Ми отримуємо ту саму відповідь:
+
+```JSON
+{
+ "message": "Hello World",
+ "root_path": "/api/v1"
+}
+```
+
+але цього разу за URL із префіксом шляху, який надає представник: `/api/v1`.
+
+Звісно, ідея полягає в тому, що всі мають доступатися до застосунку через представника, тож варіант із префіксом шляху `/api/v1` є «правильним».
+
+А варіант без префікса шляху (`http://127.0.0.1:8000/app`), який надає безпосередньо Uvicorn, має бути виключно для того, щоб _представник_ (Traefik) звертався до нього.
+
+Це демонструє, як Представник (Traefik) використовує префікс шляху і як сервер (Uvicorn) використовує `root_path` з опції `--root-path`.
+
+### Перевірте інтерфейс документації { #check-the-docs-ui }
+
+А тепер до цікавої частини. ✨
+
+«Офіційний» спосіб доступу до застосунку - через представника з префіксом шляху, який ми визначили. Тож, як і очікується, якщо ви спробуєте інтерфейс документації, який обслуговує безпосередньо Uvicorn без префікса шляху в URL, це не запрацює, оскільки він очікує доступу через представника.
+
+Ви можете перевірити це на
http://127.0.0.1:8000/docs:
+
+

+
+Але якщо ми звернемося до інтерфейсу документації за «офіційним» URL, використовуючи представника з портом `9999`, за адресою `/api/v1/docs`, усе працює коректно! 🎉
+
+Ви можете перевірити це на
http://127.0.0.1:9999/api/v1/docs:
+
+

+
+Саме так, як ми хотіли. ✔️
+
+Це тому, що FastAPI використовує `root_path`, щоб створити типовий `server` в OpenAPI з URL, наданою `root_path`.
+
+## Додаткові сервери { #additional-servers }
+
+/// warning | Попередження
+
+Це більш просунутий випадок використання. Можете пропустити його.
+
+///
+
+За замовчуванням **FastAPI** створить `server` у схемі OpenAPI з URL для `root_path`.
+
+Але ви також можете надати інші альтернативні `servers`, наприклад, якщо хочете, щоб той самий інтерфейс документації взаємодіяв і зі стейджингом, і з продакшном.
+
+Якщо ви передасте власний список `servers`, і є `root_path` (тому що ваш API знаходиться за представником), **FastAPI** вставить «server» з цим `root_path` на початок списку.
+
+Наприклад:
+
+{* ../../docs_src/behind_a_proxy/tutorial003_py310.py hl[4:7] *}
+
+Буде згенерована схема OpenAPI на кшталт:
+
+```JSON hl_lines="5-7"
+{
+ "openapi": "3.1.0",
+ // Ще дещо тут
+ "servers": [
+ {
+ "url": "/api/v1"
+ },
+ {
+ "url": "https://stag.example.com",
+ "description": "Staging environment"
+ },
+ {
+ "url": "https://prod.example.com",
+ "description": "Production environment"
+ }
+ ],
+ "paths": {
+ // Ще дещо тут
+ }
+}
+```
+
+/// tip | Порада
+
+Зверніть увагу на автоматично згенерований сервер із значенням `url` `/api/v1`, взятим із `root_path`.
+
+///
+
+В інтерфейсі документації за адресою
http://127.0.0.1:9999/api/v1/docs це виглядатиме так:
+
+

+
+/// tip | Порада
+
+Інтерфейс документації взаємодіятиме з сервером, який ви оберете.
+
+///
+
+/// note | Технічні деталі
+
+Властивість `servers` у специфікації OpenAPI є необовʼязковою.
+
+Якщо ви не вкажете параметр `servers`, і `root_path` дорівнює `/`, властивість `servers` у згенерованій схемі OpenAPI буде повністю пропущено за замовчуванням, що еквівалентно одному серверу зі значенням `url` рівним `/`.
+
+///
+
+### Вимкнути автоматичний сервер із `root_path` { #disable-automatic-server-from-root-path }
+
+Якщо ви не хочете, щоб **FastAPI** додавав автоматичний сервер, використовуючи `root_path`, скористайтеся параметром `root_path_in_servers=False`:
+
+{* ../../docs_src/behind_a_proxy/tutorial004_py310.py hl[9] *}
+
+і тоді він не буде включений у схему OpenAPI.
+
+## Монтування підзастосунку { #mounting-a-sub-application }
+
+Якщо вам потрібно змонтувати підзастосунок (як описано в [Підзастосунки - монтування](sub-applications.md){.internal-link target=_blank}), одночасно використовуючи представника з `root_path`, ви можете робити це звичайним чином, як і очікуєте.
+
+FastAPI внутрішньо розумно використовуватиме `root_path`, тож усе просто працюватиме. ✨
diff --git a/docs/uk/docs/advanced/custom-response.md b/docs/uk/docs/advanced/custom-response.md
new file mode 100644
index 0000000000..ebd0ec24a1
--- /dev/null
+++ b/docs/uk/docs/advanced/custom-response.md
@@ -0,0 +1,312 @@
+# Користувацька відповідь - HTML, стрім, файл, інше { #custom-response-html-stream-file-others }
+
+Типово **FastAPI** повертатиме відповіді, використовуючи `JSONResponse`.
+
+Ви можете переписати це, повернувши безпосередньо `Response`, як показано в [Повернути відповідь безпосередньо](response-directly.md){.internal-link target=_blank}.
+
+Але якщо ви повертаєте `Response` безпосередньо (або будь-який його підклас, як-от `JSONResponse`), дані не будуть автоматично конвертовані (навіть якщо ви оголосите `response_model`), і документація не буде автоматично згенерована (наприклад, із включенням конкретного «медіа-типу» в HTTP-заголовку `Content-Type` як частини згенерованого OpenAPI).
+
+Ви також можете оголосити `Response`, який слід використовувати (наприклад, будь-який підклас `Response`), у декораторі операції шляху через параметр `response_class`.
+
+Вміст, який ви повертаєте з вашої функції операції шляху, буде поміщений усередину цього `Response`.
+
+І якщо цей `Response` має JSON медіа-тип (`application/json`), як у випадку з `JSONResponse` та `UJSONResponse`, дані, що повертаються, будуть автоматично перетворені (і відфільтровані) з урахуванням будь-якого Pydantic `response_model`, який ви оголосили в декораторі операції шляху.
+
+/// note | Примітка
+
+Якщо ви використовуєте клас відповіді без медіа-типу, FastAPI очікуватиме, що у вашої відповіді не буде вмісту, тож формат відповіді не буде задокументовано в згенерованих OpenAPI-документах.
+
+///
+
+## Використовуйте `ORJSONResponse` { #use-orjsonresponse }
+
+Наприклад, якщо ви максимально оптимізуєте продуктивність, можете встановити та використовувати
`orjson` і встановити відповідь як `ORJSONResponse`.
+
+Імпортуйте потрібний клас `Response` (підклас) і оголосіть його в декораторі операції шляху.
+
+Для великих відповідей повернення `Response` безпосередньо значно швидше, ніж повернення словника.
+
+Це тому, що за замовчуванням FastAPI перевірятиме кожен елемент усередині та переконуватиметься, що його можна серіалізувати як JSON, використовуючи той самий [Сумісний кодувальник JSON](../tutorial/encoder.md){.internal-link target=_blank}, описаний у навчальному посібнику. Саме це дозволяє повертати довільні об'єкти, наприклад моделі бази даних.
+
+Але якщо ви впевнені, що вміст, який повертається, серіалізується в JSON, ви можете передати його безпосередньо класу відповіді та уникнути додаткових витрат FastAPI на пропускання вашого вмісту через `jsonable_encoder` перед передаванням його класу відповіді.
+
+{* ../../docs_src/custom_response/tutorial001b_py310.py hl[2,7] *}
+
+/// info | Інформація
+
+Параметр `response_class` також визначатиме «медіа-тип» відповіді.
+
+У цьому випадку HTTP-заголовок `Content-Type` буде встановлено в `application/json`.
+
+І це буде задокументовано відповідно в OpenAPI.
+
+///
+
+/// tip | Порада
+
+`ORJSONResponse` доступний лише у FastAPI, не в Starlette.
+
+///
+
+## HTML-відповідь { #html-response }
+
+Щоб повернути відповідь із HTML безпосередньо з **FastAPI**, використовуйте `HTMLResponse`.
+
+- Імпортуйте `HTMLResponse`.
+- Передайте `HTMLResponse` як параметр `response_class` вашого декоратора операції шляху.
+
+{* ../../docs_src/custom_response/tutorial002_py310.py hl[2,7] *}
+
+/// info | Інформація
+
+Параметр `response_class` також визначатиме «медіа-тип» відповіді.
+
+У цьому випадку HTTP-заголовок `Content-Type` буде встановлено в `text/html`.
+
+І це буде задокументовано відповідно в OpenAPI.
+
+///
+
+### Повернути `Response` { #return-a-response }
+
+Як показано в [Повернути відповідь безпосередньо](response-directly.md){.internal-link target=_blank}, ви також можете переписати відповідь безпосередньо у вашій операції шляху, просто повернувши її.
+
+Той самий приклад вище, що повертає `HTMLResponse`, може виглядати так:
+
+{* ../../docs_src/custom_response/tutorial003_py310.py hl[2,7,19] *}
+
+/// warning | Попередження
+
+`Response`, повернений безпосередньо вашою функцією операції шляху, не буде задокументовано в OpenAPI (наприклад, `Content-Type` не буде задокументовано) і не буде видно в автоматичній інтерактивній документації.
+
+///
+
+/// info | Інформація
+
+Звісно, фактичні заголовок `Content-Type`, код статусу тощо прийдуть з об'єкта `Response`, який ви повернули.
+
+///
+
+### Задокументуйте в OpenAPI і перепишіть `Response` { #document-in-openapi-and-override-response }
+
+Якщо ви хочете переписати відповідь усередині функції, але водночас задокументувати «медіа-тип» в OpenAPI, ви можете використати параметр `response_class` І повернути об'єкт `Response`.
+
+Тоді `response_class` буде використано лише для документування операції шляху в OpenAPI, а ваша `Response` буде використана як є.
+
+#### Повернути `HTMLResponse` безпосередньо { #return-an-htmlresponse-directly }
+
+Наприклад, це може бути щось на кшталт:
+
+{* ../../docs_src/custom_response/tutorial004_py310.py hl[7,21,23] *}
+
+У цьому прикладі функція `generate_html_response()` уже генерує та повертає `Response` замість повернення HTML як `str`.
+
+Повертаючи результат виклику `generate_html_response()`, ви вже повертаєте `Response`, яка перепише типову поведінку **FastAPI**.
+
+Але оскільки ви також передали `HTMLResponse` у `response_class`, **FastAPI** знатиме, як задокументувати це в OpenAPI та інтерактивній документації як HTML з `text/html`:
+
+

+
+## Доступні відповіді { #available-responses }
+
+Ось деякі з доступних відповідей.
+
+Майте на увазі, що ви можете використовувати `Response`, щоб повертати що завгодно інше, або навіть створити власний підклас.
+
+/// note | Технічні деталі
+
+Ви також можете використати `from starlette.responses import HTMLResponse`.
+
+**FastAPI** надає ті ж `starlette.responses` як `fastapi.responses` лише для вашої зручності як розробника. Але більшість доступних відповідей надходять безпосередньо зі Starlette.
+
+///
+
+### `Response` { #response }
+
+Головний клас `Response`, від якого успадковуються всі інші відповіді.
+
+Ви можете повертати його безпосередньо.
+
+Він приймає такі параметри:
+
+- `content` - `str` або `bytes`.
+- `status_code` - `int` - код статусу HTTP.
+- `headers` - `dict` строк.
+- `media_type` - `str`, що задає медіа-тип, напр. `"text/html"`.
+
+FastAPI (насправді Starlette) автоматично додасть заголовок Content-Length. Також буде додано заголовок Content-Type, на основі `media_type` з додаванням набору символів для текстових типів.
+
+{* ../../docs_src/response_directly/tutorial002_py310.py hl[1,18] *}
+
+### `HTMLResponse` { #htmlresponse }
+
+Приймає текст або байти та повертає HTML-відповідь, як описано вище.
+
+### `PlainTextResponse` { #plaintextresponse }
+
+Приймає текст або байти та повертає відповідь звичайним текстом.
+
+{* ../../docs_src/custom_response/tutorial005_py310.py hl[2,7,9] *}
+
+### `JSONResponse` { #jsonresponse }
+
+Приймає дані та повертає відповідь, закодовану як `application/json`.
+
+Це типова відповідь, яку використовує **FastAPI**, як зазначено вище.
+
+### `ORJSONResponse` { #orjsonresponse }
+
+Швидка альтернативна JSON-відповідь з використанням
`orjson`, як описано вище.
+
+/// info | Інформація
+
+Потрібно встановити `orjson`, наприклад `pip install orjson`.
+
+///
+
+### `UJSONResponse` { #ujsonresponse }
+
+Альтернативна JSON-відповідь з використанням
`ujson`.
+
+/// info | Інформація
+
+Потрібно встановити `ujson`, наприклад `pip install ujson`.
+
+///
+
+/// warning | Попередження
+
+`ujson` менш обережний, ніж вбудована реалізація Python, у поводженні з деякими крайніми випадками.
+
+///
+
+{* ../../docs_src/custom_response/tutorial001_py310.py hl[2,7] *}
+
+/// tip | Порада
+
+Ймовірно, `ORJSONResponse` може бути швидшою альтернативою.
+
+///
+
+### `RedirectResponse` { #redirectresponse }
+
+Повертає HTTP-перенаправлення. Типово використовує код статусу 307 (Temporary Redirect).
+
+Ви можете повернути `RedirectResponse` безпосередньо:
+
+{* ../../docs_src/custom_response/tutorial006_py310.py hl[2,9] *}
+
+---
+
+Або ви можете використати його в параметрі `response_class`:
+
+{* ../../docs_src/custom_response/tutorial006b_py310.py hl[2,7,9] *}
+
+У такому разі ви можете повертати URL безпосередньо з вашої функції операції шляху.
+
+У цьому випадку `status_code` буде типовим для `RedirectResponse`, тобто `307`.
+
+---
+
+Ви також можете використати параметр `status_code` разом із параметром `response_class`:
+
+{* ../../docs_src/custom_response/tutorial006c_py310.py hl[2,7,9] *}
+
+### `StreamingResponse` { #streamingresponse }
+
+Приймає async-генератор або звичайний генератор/ітератор і транслює тіло відповіді потоково.
+
+{* ../../docs_src/custom_response/tutorial007_py310.py hl[2,14] *}
+
+#### Використання `StreamingResponse` з об'єктами типу file-like { #using-streamingresponse-with-file-like-objects }
+
+Якщо у вас є
file-like об'єкт (наприклад, об'єкт, що повертається `open()`), ви можете створити генераторну функцію для ітерації по цьому file-like об'єкту.
+
+Таким чином, вам не потрібно спочатку читати все в пам'ять, і ви можете передати цю генераторну функцію в `StreamingResponse` і повернути її.
+
+Сюди входить багато бібліотек для взаємодії з хмарними сховищами, обробки відео та інші.
+
+{* ../../docs_src/custom_response/tutorial008_py310.py hl[2,10:12,14] *}
+
+1. Це генераторна функція. Вона є «генераторною функцією», бо містить оператори `yield` усередині.
+2. Використовуючи блок `with`, ми гарантуємо, що file-like об'єкт буде закрито після завершення роботи генераторної функції. Тобто після того, як вона завершить надсилання відповіді.
+3. Цей `yield from` вказує функції ітеруватися по об'єкту з назвою `file_like`. А потім, для кожної ітерованої частини, повертати цю частину, ніби вона надходить з цієї генераторної функції (`iterfile`).
+
+ Тож це генераторна функція, яка всередині передає роботу «генерації» чомусь іншому.
+
+ Роблячи це таким чином, ми можемо помістити її в блок `with` і таким чином гарантувати, що file-like об'єкт буде закрито після завершення.
+
+/// tip | Порада
+
+Зверніть увагу, що тут ми використовуємо стандартний `open()`, який не підтримує `async` та `await`, тому ми оголошуємо операцію шляху звичайною `def`.
+
+///
+
+### `FileResponse` { #fileresponse }
+
+Асинхронно транслює файл як відповідь.
+
+Приймає інший набір аргументів для створення екземпляра, ніж інші типи відповідей:
+
+- `path` - шлях до файлу для трансляції.
+- `headers` - будь-які користувацькі заголовки як словник.
+- `media_type` - строка, що задає медіа-тип. Якщо не встановлено, медіа-тип буде виведено з імені файлу або шляху.
+- `filename` - якщо встановлено, буде включено до `Content-Disposition` відповіді.
+
+Відповіді з файлами включатимуть відповідні заголовки `Content-Length`, `Last-Modified` і `ETag`.
+
+{* ../../docs_src/custom_response/tutorial009_py310.py hl[2,10] *}
+
+Ви також можете використати параметр `response_class`:
+
+{* ../../docs_src/custom_response/tutorial009b_py310.py hl[2,8,10] *}
+
+У цьому випадку ви можете повертати шлях до файлу безпосередньо з вашої функції операції шляху.
+
+## Власний клас відповіді { #custom-response-class }
+
+Ви можете створити власний клас відповіді, успадкувавши його від `Response`, і використовувати його.
+
+Наприклад, скажімо, ви хочете використовувати
`orjson`, але з деякими користувацькими налаштуваннями, які не використовуються у вбудованому класі `ORJSONResponse`.
+
+Припустімо, ви хочете, щоб повертався відформатований із відступами JSON, тож ви хочете використати опцію orjson `orjson.OPT_INDENT_2`.
+
+Ви можете створити `CustomORJSONResponse`. Головне, що потрібно зробити, це створити метод `Response.render(content)`, який повертає вміст як `bytes`:
+
+{* ../../docs_src/custom_response/tutorial009c_py310.py hl[9:14,17] *}
+
+Тепер замість повернення:
+
+```json
+{"message": "Hello World"}
+```
+
+...ця відповідь повертатиме:
+
+```json
+{
+ "message": "Hello World"
+}
+```
+
+Звісно, ви, ймовірно, знайдете значно кращі способи скористатися цим, ніж просто форматування JSON. 😉
+
+## Типова відповідь за замовчуванням { #default-response-class }
+
+Створюючи екземпляр класу **FastAPI** або `APIRouter`, ви можете вказати, який клас відповіді використовувати за замовчуванням.
+
+Параметр, що це визначає, - `default_response_class`.
+
+У прикладі нижче **FastAPI** використовуватиме `ORJSONResponse` за замовчуванням в усіх операціях шляху замість `JSONResponse`.
+
+{* ../../docs_src/custom_response/tutorial010_py310.py hl[2,4] *}
+
+/// tip | Порада
+
+Ви все одно можете переписати `response_class` в операціях шляху, як і раніше.
+
+///
+
+## Додаткова документація { #additional-documentation }
+
+Ви також можете оголосити медіа-тип і багато інших деталей в OpenAPI, використовуючи `responses`: [Додаткові відповіді в OpenAPI](additional-responses.md){.internal-link target=_blank}.
diff --git a/docs/uk/docs/advanced/dataclasses.md b/docs/uk/docs/advanced/dataclasses.md
new file mode 100644
index 0000000000..a41e6e5890
--- /dev/null
+++ b/docs/uk/docs/advanced/dataclasses.md
@@ -0,0 +1,95 @@
+# Використання dataclasses { #using-dataclasses }
+
+FastAPI побудовано поверх **Pydantic**, і я показував вам, як використовувати моделі Pydantic для оголошення запитів і відповідей.
+
+Але FastAPI також підтримує використання
`dataclasses` таким самим чином:
+
+{* ../../docs_src/dataclasses_/tutorial001_py310.py hl[1,6:11,18:19] *}
+
+Це підтримується завдяки **Pydantic**, адже він має
внутрішню підтримку `dataclasses`.
+
+Тож навіть із наведеним вище кодом, який явно не використовує Pydantic, FastAPI використовує Pydantic, щоб перетворити стандартні dataclasses у власний варіант dataclasses Pydantic.
+
+І, звісно, підтримується те саме:
+
+* валідація даних
+* серіалізація даних
+* документація даних тощо
+
+Це працює так само, як із моделями Pydantic. Насправді під капотом це також досягається за допомогою Pydantic.
+
+/// info | Інформація
+
+Майте на увазі, що dataclasses не можуть робити все те, що можуть моделі Pydantic.
+
+Тож вам усе ще може знадобитися використовувати моделі Pydantic.
+
+Але якщо у вас вже є чимало dataclasses, це зручний трюк, щоб задіяти їх для веб-API на FastAPI. 🤓
+
+///
+
+## Dataclasses у `response_model` { #dataclasses-in-response-model }
+
+Ви також можете використовувати `dataclasses` у параметрі `response_model`:
+
+{* ../../docs_src/dataclasses_/tutorial002_py310.py hl[1,6:12,18] *}
+
+Dataclass буде автоматично перетворено на dataclass Pydantic.
+
+Таким чином його схема з'явиться в інтерфейсі користувача документації API:
+
+

+
+## Dataclasses у вкладених структурах даних { #dataclasses-in-nested-data-structures }
+
+Можна поєднувати `dataclasses` з іншими анотаціями типів, щоб створювати вкладені структури даних.
+
+У деяких випадках вам усе ж доведеться використовувати варіант `dataclasses` від Pydantic. Наприклад, якщо виникають помилки з автоматично згенерованою документацією API.
+
+У такому разі ви можете просто замінити стандартні `dataclasses` на `pydantic.dataclasses`, що є взаємозамінником:
+
+{* ../../docs_src/dataclasses_/tutorial003_py310.py hl[1,4,7:10,13:16,22:24,27] *}
+
+1. Ми все ще імпортуємо `field` зі стандартних `dataclasses`.
+
+2. `pydantic.dataclasses` - це взаємозамінник для `dataclasses`.
+
+3. Dataclass `Author` містить список dataclass `Item`.
+
+4. Dataclass `Author` використовується як параметр `response_model`.
+
+5. Ви можете використовувати інші стандартні анотації типів із dataclasses як тіло запиту.
+
+ У цьому випадку це список dataclass `Item`.
+
+6. Тут ми повертаємо словник, що містить `items`, який є списком dataclass.
+
+ FastAPI усе ще здатний
серіалізувати дані до JSON.
+
+7. Тут у `response_model` використано анотацію типу список dataclass `Author`.
+
+ Знову ж, ви можете поєднувати `dataclasses` зі стандартними анотаціями типів.
+
+8. Зверніть увагу, що ця *функція операції шляху* використовує звичайний `def` замість `async def`.
+
+ Як завжди, у FastAPI ви можете поєднувати `def` і `async def` за потреби.
+
+ Якщо вам потрібне коротке нагадування, коли що використовувати, перегляньте розділ _«Поспішаєте?»_ у документації про [`async` та `await`](../async.md#in-a-hurry){.internal-link target=_blank}.
+
+9. Ця *функція операції шляху* не повертає dataclasses (хоча могла б), а список словників із внутрішніми даними.
+
+ FastAPI використає параметр `response_model` (що включає dataclasses), щоб перетворити відповідь.
+
+Ви можете поєднувати `dataclasses` з іншими анотаціями типів у багатьох поєднаннях, щоб формувати складні структури даних.
+
+Перегляньте підказки щодо анотацій у коді вище, щоб побачити більше деталей.
+
+## Дізнатися більше { #learn-more }
+
+Можна поєднувати `dataclasses` з іншими моделями Pydantic, наслідувати їх, включати у власні моделі тощо.
+
+Щоб дізнатися більше, перегляньте
документацію Pydantic про dataclasses.
+
+## Версія { #version }
+
+Доступно починаючи з версії FastAPI `0.67.0`. 🔖
diff --git a/docs/uk/docs/advanced/events.md b/docs/uk/docs/advanced/events.md
new file mode 100644
index 0000000000..7c05ee4a4e
--- /dev/null
+++ b/docs/uk/docs/advanced/events.md
@@ -0,0 +1,165 @@
+# Події тривалості життя { #lifespan-events }
+
+Ви можете визначити логіку (код), яку слід виконати перед тим, як застосунок запуститься. Це означає, що цей код буде виконано один раз, перед тим як застосунок почне отримувати запити.
+
+Так само ви можете визначити логіку (код), яку слід виконати під час вимкнення застосунку. У цьому випадку код буде виконано один раз, після обробки можливо багатьох запитів.
+
+Оскільки цей код виконується перед тим, як застосунок почне приймати запити, і одразу після того, як він завершить їх обробку, він охоплює всю тривалість життя застосунку (слово «lifespan» буде важливим за мить 😉).
+
+Це дуже корисно для налаштування ресурсів, які потрібні для всього застосунку, які спільні між запитами, та/або які потрібно потім прибрати. Наприклад, пул з’єднань з базою даних або завантаження спільної моделі машинного навчання.
+
+## Випадок використання { #use-case }
+
+Почнемо з прикладу випадку використання, а потім подивимось, як це вирішити.
+
+Уявімо, що у вас є моделі машинного навчання, якими ви хочете обробляти запити. 🤖
+
+Ті самі моделі спільні між запитами, тобто це не окрема модель на запит чи на користувача.
+
+Уявімо, що завантаження моделі може займати чимало часу, бо треба читати багато даних з диска. Тож ви не хочете робити це для кожного запиту.
+
+Ви могли б завантажити її на верхньому рівні модуля/файлу, але це означало б, що модель завантажиться навіть якщо ви просто запускаєте простий автоматизований тест - тоді тест буде повільним, бо йому доведеться чекати завантаження моделі перед виконанням незалежної частини коду.
+
+Ось це ми й вирішимо: завантажимо модель перед обробкою запитів, але лише безпосередньо перед тим, як застосунок почне отримувати запити, а не під час завантаження коду.
+
+## Тривалість життя { #lifespan }
+
+Ви можете визначити цю логіку запуску і вимкнення за допомогою параметра `lifespan` застосунку `FastAPI` та «менеджера контексту» (зараз покажу, що це).
+
+Почнемо з прикладу, а потім розберемо детально.
+
+Ми створюємо асинхронну функцію `lifespan()` з `yield` так:
+
+{* ../../docs_src/events/tutorial003_py310.py hl[16,19] *}
+
+Тут ми імітуємо дорогу операцію запуску із завантаженням моделі, поміщаючи (фальшиву) функцію моделі у словник з моделями машинного навчання перед `yield`. Цей код буде виконано перед тим, як застосунок почне приймати запити, під час запуску.
+
+А одразу після `yield` ми розвантажуємо модель. Цей код буде виконано після того, як застосунок завершить обробку запитів, безпосередньо перед вимкненням. Це, наприклад, може звільнити ресурси на кшталт пам’яті або GPU.
+
+/// tip | Порада
+
+Подія `shutdown` відбувається, коли ви зупиняєте застосунок.
+
+Можливо, вам треба запустити нову версію, або ви просто втомилися її запускати. 🤷
+
+///
+
+### Функція тривалості життя { #lifespan-function }
+
+Перше, на що слід звернути увагу: ми визначаємо асинхронну функцію з `yield`. Це дуже схоже на залежності з `yield`.
+
+{* ../../docs_src/events/tutorial003_py310.py hl[14:19] *}
+
+Перша частина функції до `yield` буде виконана перед запуском застосунку.
+
+А частина після `yield` буде виконана після завершення роботи застосунку.
+
+### Асинхронний менеджер контексту { #async-context-manager }
+
+Якщо придивитися, функція задекорована за допомогою `@asynccontextmanager`.
+
+Це перетворює функцію на так званий «асинхронний менеджер контексту».
+
+{* ../../docs_src/events/tutorial003_py310.py hl[1,13] *}
+
+Менеджер контексту в Python - це те, що можна використовувати в операторі `with`, наприклад, `open()` можна використовувати як менеджер контексту:
+
+```Python
+with open("file.txt") as file:
+ file.read()
+```
+
+У новіших версіях Python також є асинхронний менеджер контексту. Його використовують з `async with`:
+
+```Python
+async with lifespan(app):
+ await do_stuff()
+```
+
+Коли ви створюєте менеджер контексту або асинхронний менеджер контексту, як вище, перед входом у блок `with` буде виконано код перед `yield`, а після виходу з блоку `with` буде виконано код після `yield`.
+
+У нашому прикладі коду вище ми не використовуємо його напряму, а передаємо його до FastAPI, щоб він його використав.
+
+Параметр `lifespan` застосунку `FastAPI` приймає асинхронний менеджер контексту, тож ми можемо передати йому наш новий асинхронний менеджер контексту `lifespan`.
+
+{* ../../docs_src/events/tutorial003_py310.py hl[22] *}
+
+## Альтернативні події (застаріло) { #alternative-events-deprecated }
+
+/// warning | Попередження
+
+Рекомендований спосіб обробляти запуск і вимкнення - використовувати параметр `lifespan` застосунку `FastAPI`, як описано вище. Якщо ви надаєте параметр `lifespan`, обробники подій `startup` і `shutdown` більше не будуть викликані. Або все через `lifespan`, або все через події - не обидва одночасно.
+
+Можете, ймовірно, пропустити цю частину.
+
+///
+
+Є альтернативний спосіб визначити логіку, яку слід виконати під час запуску і під час вимкнення.
+
+Ви можете визначити обробники подій (функції), які потрібно виконати перед запуском застосунку або коли застосунок вимикається.
+
+Ці функції можна оголошувати як з `async def`, так і звичайним `def`.
+
+### Подія `startup` { #startup-event }
+
+Щоб додати функцію, яку слід виконати перед запуском застосунку, оголосіть її з подією `"startup"`:
+
+{* ../../docs_src/events/tutorial001_py310.py hl[8] *}
+
+У цьому випадку функція-обробник події `startup` ініціалізує «базу даних» предметів (це лише `dict`) деякими значеннями.
+
+Ви можете додати більше ніж один обробник події.
+
+І ваш застосунок не почне приймати запити, доки всі обробники події `startup` не завершаться.
+
+### Подія `shutdown` { #shutdown-event }
+
+Щоб додати функцію, яку слід виконати, коли застосунок вимикається, оголосіть її з подією `"shutdown"`:
+
+{* ../../docs_src/events/tutorial002_py310.py hl[6] *}
+
+Тут функція-обробник події `shutdown` запише текстовий рядок `"Application shutdown"` у файл `log.txt`.
+
+/// info | Інформація
+
+У функції `open()` параметр `mode="a"` означає «append», тож рядок буде додано після всього, що є у файлі, без перезапису попереднього вмісту.
+
+///
+
+/// tip | Порада
+
+Зауважте, що в цьому випадку ми використовуємо стандартну Python-функцію `open()`, яка працює з файлом.
+
+Тобто вона включає I/O (input/output), де потрібно «чекати», поки дані буде записано на диск.
+
+Але `open()` не використовує `async` і `await`.
+
+Тому ми оголошуємо функцію-обробник події зі стандартним `def`, а не `async def`.
+
+///
+
+### Разом `startup` і `shutdown` { #startup-and-shutdown-together }
+
+Велика ймовірність, що логіка для вашого запуску і вимкнення пов’язана: ви можете хотіти щось запустити, а потім завершити, отримати ресурс, а потім звільнити його тощо.
+
+Робити це в окремих функціях, які не діляться логікою чи змінними, складніше - доведеться зберігати значення у глобальних змінних або вдаватися до подібних трюків.
+
+Тому зараз рекомендується натомість використовувати `lifespan`, як пояснено вище.
+
+## Технічні деталі { #technical-details }
+
+Невелика технічна деталь для допитливих нердів. 🤓
+
+Під капотом, у технічній специфікації ASGI, це частина
Протоколу тривалості життя, і там визначені події `startup` і `shutdown`.
+
+/// info | Інформація
+
+Ви можете прочитати більше про обробники `lifespan` у
документації Starlette про Lifespan.
+
+Зокрема, як працювати зі станом тривалості життя, який можна використовувати в інших ділянках вашого коду.
+
+///
+
+## Підзастосунки { #sub-applications }
+
+🚨 Майте на увазі, що ці події тривалості життя (startup і shutdown) виконуються лише для головного застосунку, а не для [Підзастосунки - монтування](sub-applications.md){.internal-link target=_blank}.
diff --git a/docs/uk/docs/advanced/generate-clients.md b/docs/uk/docs/advanced/generate-clients.md
new file mode 100644
index 0000000000..66e9193ac3
--- /dev/null
+++ b/docs/uk/docs/advanced/generate-clients.md
@@ -0,0 +1,208 @@
+# Генерація SDK { #generating-sdks }
+
+Оскільки **FastAPI** базується на специфікації **OpenAPI**, його API можна описати у стандартному форматі, який розуміють багато інструментів.
+
+Це спрощує створення актуальної **документації**, клієнтських бібліотек (
**SDKs**) багатьма мовами, а також **тестування** чи **автоматизованих робочих процесів**, що залишаються синхронізованими з вашим кодом.
+
+У цьому посібнику ви дізнаєтеся, як згенерувати **TypeScript SDK** для вашого бекенда на FastAPI.
+
+## Генератори SDK з відкритим кодом { #open-source-sdk-generators }
+
+Універсальним варіантом є
OpenAPI Generator, який підтримує **багато мов програмування** та може генерувати SDK з вашої специфікації OpenAPI.
+
+Для **клієнтів TypeScript**
Hey API — спеціалізоване рішення, що надає оптимізований досвід для екосистеми TypeScript.
+
+Більше генераторів SDK ви можете знайти на
OpenAPI.Tools.
+
+/// tip | Порада
+
+FastAPI автоматично генерує специфікації **OpenAPI 3.1**, тож будь-який інструмент, який ви використовуєте, має підтримувати цю версію.
+
+///
+
+## Генератори SDK від спонсорів FastAPI { #sdk-generators-from-fastapi-sponsors }
+
+У цьому розділі представлено рішення від компаній, що спонсорують FastAPI: вони мають **венчурну підтримку** та **корпоративну підтримку**. Ці продукти надають **додаткові можливості** та **інтеграції** поверх високоякісно згенерованих SDK.
+
+Завдяки ✨ [**спонсорству FastAPI**](../help-fastapi.md#sponsor-the-author){.internal-link target=_blank} ✨ ці компанії допомагають підтримувати фреймворк та його **екосистему** здоровими та **сталими**.
+
+Їхня підтримка також демонструє сильну відданість **спільноті** FastAPI (вам), показуючи, що їм важливо не лише надавати **відмінний сервіс**, а й підтримувати **міцний і процвітаючий фреймворк**, FastAPI. 🙇
+
+Наприклад, ви можете спробувати:
+
+*
Speakeasy
+*
Stainless
+*
liblab
+
+Деякі з цих рішень також можуть бути з відкритим кодом або мати безкоштовні тарифи, тож ви можете спробувати їх без фінансових зобов'язань. Інші комерційні генератори SDK також доступні й їх можна знайти онлайн. 🤓
+
+## Створити TypeScript SDK { #create-a-typescript-sdk }
+
+Почнімо з простого застосунку FastAPI:
+
+{* ../../docs_src/generate_clients/tutorial001_py310.py hl[7:9,12:13,16:17,21] *}
+
+Зверніть увагу, що *операції шляху* визначають моделі, які вони використовують для корисного навантаження запиту та корисного навантаження відповіді, використовуючи моделі `Item` і `ResponseMessage`.
+
+### Документація API { #api-docs }
+
+Якщо ви перейдете до `/docs`, ви побачите **схеми** даних, які надсилаються в запитах і приймаються у відповідях:
+
+

+
+Ви бачите ці схеми, оскільки їх було оголошено як моделі в застосунку.
+
+Ця інформація доступна у **схемі OpenAPI** застосунку, а потім показується в документації API.
+
+Та сама інформація з моделей, яку включено до OpenAPI, може бути використана для **генерації клієнтського коду**.
+
+### Hey API { #hey-api }
+
+Коли у нас є застосунок FastAPI з моделями, ми можемо використати Hey API для генерації клієнта TypeScript. Найшвидший спосіб зробити це — через npx.
+
+```sh
+npx @hey-api/openapi-ts -i http://localhost:8000/openapi.json -o src/client
+```
+
+Це згенерує TypeScript SDK у `./src/client`.
+
+Ви можете дізнатися, як
встановити `@hey-api/openapi-ts`, і почитати про
згенерований результат на їхньому сайті.
+
+### Використання SDK { #using-the-sdk }
+
+Тепер ви можете імпортувати та використовувати клієнтський код. Це може виглядати так; зверніть увагу, що ви отримуєте «автодоповнення» для методів:
+
+

+
+Ви також отримаєте автодоповнення для корисного навантаження, яке надсилаєте:
+
+

+
+/// tip | Порада
+
+Зверніть увагу на автодоповнення для `name` і `price`, які були визначені в застосунку FastAPI, у моделі `Item`.
+
+///
+
+Ви бачитимете вбудовані помилки для даних, які надсилаєте:
+
+

+
+Об'єкт відповіді також матиме автодоповнення:
+
+

+
+## Застосунок FastAPI з мітками { #fastapi-app-with-tags }
+
+У багатьох випадках ваш застосунок FastAPI буде більшим, і ви, ймовірно, використовуватимете мітки, щоб розділяти різні групи *операцій шляху*.
+
+Наприклад, у вас може бути секція для **items** і окрема секція для **users**, і їх можна розділити мітками:
+
+{* ../../docs_src/generate_clients/tutorial002_py310.py hl[21,26,34] *}
+
+### Згенерувати TypeScript-клієнт із мітками { #generate-a-typescript-client-with-tags }
+
+Якщо ви згенеруєте клієнт для застосунку FastAPI, що використовує мітки, зазвичай клієнтський код також буде розділено за цими мітками.
+
+Таким чином, ви матимете правильно впорядковані та згруповані частини клієнтського коду:
+
+

+
+У цьому випадку у вас є:
+
+* `ItemsService`
+* `UsersService`
+
+### Назви методів клієнта { #client-method-names }
+
+Зараз згенеровані назви методів на кшталт `createItemItemsPost` виглядають не дуже охайно:
+
+```TypeScript
+ItemsService.createItemItemsPost({name: "Plumbus", price: 5})
+```
+
+...це тому, що генератор клієнта використовує внутрішній OpenAPI **operation ID** для кожної *операції шляху*.
+
+OpenAPI вимагає, щоб кожен operation ID був унікальним для всіх *операцій шляху*, тому FastAPI використовує **назву функції**, **шлях** і **HTTP-метод/операцію** для генерації цього operation ID, адже так воно може гарантувати унікальність operation ID.
+
+Але далі я покажу, як це покращити. 🤓
+
+## Користувацькі operation ID та кращі назви методів { #custom-operation-ids-and-better-method-names }
+
+Ви можете **змінити** спосіб **генерації** цих operation ID, щоб зробити їх простішими та мати **простіші назви методів** у клієнтах.
+
+У цьому випадку вам потрібно буде іншим способом гарантувати, що кожен operation ID є **унікальним**.
+
+Наприклад, ви можете переконатися, що кожна *операція шляху* має мітку, а потім генерувати operation ID на основі **мітки** та **назви** *операції шляху* (назви функції).
+
+### Користувацька функція генерування унікального ID { #custom-generate-unique-id-function }
+
+FastAPI використовує **унікальний ID** для кожної *операції шляху*, який застосовується для **operation ID**, а також для назв будь-яких потрібних користувацьких моделей для запитів чи відповідей.
+
+Ви можете налаштувати цю функцію. Вона приймає `APIRoute` і повертає строку.
+
+Наприклад, тут використовується перша мітка (у вас, ймовірно, буде лише одна мітка) і назва *операції шляху* (назва функції).
+
+Потім ви можете передати цю користувацьку функцію до **FastAPI** як параметр `generate_unique_id_function`:
+
+{* ../../docs_src/generate_clients/tutorial003_py310.py hl[6:7,10] *}
+
+### Згенерувати TypeScript-клієнт з користувацькими operation ID { #generate-a-typescript-client-with-custom-operation-ids }
+
+Тепер, якщо ви згенеруєте клієнт знову, ви побачите покращені назви методів:
+
+

+
+Як бачите, тепер у назвах методів є мітка, а потім назва функції; вони більше не містять інформації з URL-шляху та HTTP-операції.
+
+### Попередня обробка специфікації OpenAPI для генератора клієнта { #preprocess-the-openapi-specification-for-the-client-generator }
+
+У згенерованому коді все ще є певна **дубльована інформація**.
+
+Ми вже знаємо, що цей метод стосується **items**, адже це слово є в `ItemsService` (взято з мітки), але все ще маємо назву мітки як префікс у назві методу. 😕
+
+Ми, ймовірно, все одно захочемо зберегти це загалом для OpenAPI, адже так гарантується унікальність operation ID.
+
+Але для згенерованого клієнта ми можемо **змінити** operation ID в OpenAPI безпосередньо перед генерацією клієнтів, просто щоб зробити назви методів приємнішими та **чистішими**.
+
+Ми можемо завантажити JSON OpenAPI у файл `openapi.json`, а потім **прибрати цей префікс із міткою** за допомогою такого скрипту:
+
+{* ../../docs_src/generate_clients/tutorial004_py310.py *}
+
+//// tab | Node.js
+
+```Javascript
+{!> ../../docs_src/generate_clients/tutorial004.js!}
+```
+
+////
+
+Після цього operation ID буде перейменовано з чогось на кшталт `items-get_items` просто на `get_items`, тож генератор клієнта зможе створити простіші назви методів.
+
+### Згенерувати TypeScript-клієнт із попередньо обробленим OpenAPI { #generate-a-typescript-client-with-the-preprocessed-openapi }
+
+Оскільки кінцевий результат тепер у файлі `openapi.json`, вам потрібно оновити шлях до вхідних даних:
+
+```sh
+npx @hey-api/openapi-ts -i ./openapi.json -o src/client
+```
+
+Після генерації нового клієнта ви отримаєте **чисті назви методів**, із усім **автодоповненням**, **вбудованими помилками** тощо:
+
+

+
+## Переваги { #benefits }
+
+Використовуючи автоматично згенеровані клієнти, ви отримаєте **автодоповнення** для:
+
+* Методів.
+* Корисного навантаження запиту в тілі, параметрах запиту тощо.
+* Корисного навантаження відповіді.
+
+Також ви матимете **вбудовані помилки** для всього.
+
+І щоразу, коли ви оновлюєте код бекенда та **перегенеровуєте** фронтенд, у ньому з'являтимуться нові *операції шляху* як методи, старі буде видалено, а будь-які інші зміни відобразяться у згенерованому коді. 🤓
+
+Це також означає, що якщо щось змінилося, це буде **відображено** в клієнтському коді автоматично. А якщо ви **зіберете** клієнт, буде повідомлено про помилку, якщо є будь-яка **невідповідність** у використаних даних.
+
+Таким чином, ви **виявлятимете багато помилок** дуже рано в циклі розробки, замість того, щоб чекати, поки помилки проявляться у ваших кінцевих користувачів у продакшені, і лише потім намагатися з'ясувати, у чому проблема. ✨
diff --git a/docs/uk/docs/advanced/index.md b/docs/uk/docs/advanced/index.md
new file mode 100644
index 0000000000..1cffe0cecd
--- /dev/null
+++ b/docs/uk/docs/advanced/index.md
@@ -0,0 +1,21 @@
+# Просунутий посібник користувача { #advanced-user-guide }
+
+## Додаткові можливості { #additional-features }
+
+Основний [Навчальний посібник - Посібник користувача](../tutorial/index.md){.internal-link target=_blank} має бути достатнім, щоб провести вас через усі основні можливості **FastAPI**.
+
+У наступних розділах ви побачите інші опції, конфігурації та додаткові можливості.
+
+/// tip | Порада
+
+Наступні розділи не обов'язково «просунуті».
+
+І можливо, що рішення для вашого випадку використання може бути в одному з них.
+
+///
+
+## Спершу прочитайте навчальний посібник { #read-the-tutorial-first }
+
+Ви все ще можете використовувати більшість можливостей **FastAPI**, маючи знання з основного [Навчального посібника - Посібника користувача](../tutorial/index.md){.internal-link target=_blank}.
+
+А в наступних розділах передбачається, що ви вже його прочитали і знайомі з основними ідеями.
diff --git a/docs/uk/docs/advanced/middleware.md b/docs/uk/docs/advanced/middleware.md
new file mode 100644
index 0000000000..207ca96e0a
--- /dev/null
+++ b/docs/uk/docs/advanced/middleware.md
@@ -0,0 +1,97 @@
+# Просунуте проміжне програмне забезпечення { #advanced-middleware }
+
+У головному навчальному посібнику ви читали, як додати [Користувацьке проміжне ПЗ](../tutorial/middleware.md){.internal-link target=_blank} до вашого застосунку.
+
+Також ви читали, як обробляти [CORS за допомогою `CORSMiddleware`](../tutorial/cors.md){.internal-link target=_blank}.
+
+У цьому розділі розглянемо, як використовувати інше проміжне ПЗ.
+
+## Додавання middleware ASGI { #adding-asgi-middlewares }
+
+Оскільки **FastAPI** базується на Starlette і реалізує специфікацію
ASGI, ви можете використовувати будь-яке проміжне ПЗ ASGI.
+
+Middleware не обов'язково має бути створене саме для FastAPI або Starlette, головне - щоб воно відповідало специфікації ASGI.
+
+Загалом, middleware ASGI — це класи, які очікують отримати застосунок ASGI як перший аргумент.
+
+Тож у документації до сторонніх middleware ASGI вам, імовірно, порадять зробити приблизно так:
+
+```Python
+from unicorn import UnicornMiddleware
+
+app = SomeASGIApp()
+
+new_app = UnicornMiddleware(app, some_config="rainbow")
+```
+
+Але FastAPI (точніше Starlette) надає простіший спосіб, який гарантує, що внутрішнє middleware обробляє помилки сервера, а користувацькі обробники винятків працюють коректно.
+
+Для цього використовуйте `app.add_middleware()` (як у прикладі для CORS).
+
+```Python
+from fastapi import FastAPI
+from unicorn import UnicornMiddleware
+
+app = FastAPI()
+
+app.add_middleware(UnicornMiddleware, some_config="rainbow")
+```
+
+`app.add_middleware()` приймає клас middleware як перший аргумент і будь-які додаткові аргументи, що будуть передані цьому middleware.
+
+## Вбудоване middleware { #integrated-middlewares }
+
+**FastAPI** містить кілька middleware для поширених випадків використання, далі розглянемо, як їх використовувати.
+
+/// note | Технічні деталі
+
+У наступних прикладах ви також можете використовувати `from starlette.middleware.something import SomethingMiddleware`.
+
+**FastAPI** надає кілька middleware у `fastapi.middleware` виключно для зручності розробника. Але більшість доступних middleware походять безпосередньо зі Starlette.
+
+///
+
+## `HTTPSRedirectMiddleware` { #httpsredirectmiddleware }
+
+Примушує, щоб усі вхідні запити були або `https`, або `wss`.
+
+Будь-який вхідний запит до `http` або `ws` буде перенаправлено на захищену схему.
+
+{* ../../docs_src/advanced_middleware/tutorial001_py310.py hl[2,6] *}
+
+## `TrustedHostMiddleware` { #trustedhostmiddleware }
+
+Примушує, щоб усі вхідні запити мали коректно встановлений заголовок `Host`, щоб захиститися від атак HTTP Host Header.
+
+{* ../../docs_src/advanced_middleware/tutorial002_py310.py hl[2,6:8] *}
+
+Підтримуються такі аргументи:
+
+- `allowed_hosts` - Список доменних імен, які слід дозволити як імена хостів. Підтримуються домени з «дикою картою», такі як `*.example.com`, для зіставлення піддоменів. Щоб дозволити будь-яке ім'я хоста, або використовуйте `allowed_hosts=["*"]`, або не додавайте це middleware.
+- `www_redirect` - Якщо встановлено True, запити до не-www версій дозволених хостів буде перенаправлено до їхніх www-варіантів. Типово `True`.
+
+Якщо вхідний запит не проходить перевірку, буде надіслано відповідь `400`.
+
+## `GZipMiddleware` { #gzipmiddleware }
+
+Обробляє відповіді GZip для будь-якого запиту, що містить `"gzip"` у заголовку `Accept-Encoding`.
+
+Middleware обробляє як стандартні, так і потокові відповіді.
+
+{* ../../docs_src/advanced_middleware/tutorial003_py310.py hl[2,6] *}
+
+Підтримуються такі аргументи:
+
+- `minimum_size` - Не GZip-увати відповіді, менші за цей мінімальний розмір у байтах. Типово `500`.
+- `compresslevel` - Використовується під час стиснення GZip. Це ціле число в діапазоні від 1 до 9. Типово `9`. Менше значення дає швидше стиснення, але більший розмір файлів; більше значення дає повільніше стиснення, але менший розмір файлів.
+
+## Інше middleware { #other-middlewares }
+
+Є багато іншого проміжного ПЗ ASGI.
+
+Наприклад:
+
+-
`ProxyHeadersMiddleware` з Uvicorn
+-
MessagePack
+
+Щоб переглянути інші доступні middleware, ознайомтеся з
документацією Starlette щодо middleware та
списком ASGI Awesome.
diff --git a/docs/uk/docs/advanced/openapi-callbacks.md b/docs/uk/docs/advanced/openapi-callbacks.md
new file mode 100644
index 0000000000..1f2adb1fc0
--- /dev/null
+++ b/docs/uk/docs/advanced/openapi-callbacks.md
@@ -0,0 +1,186 @@
+# Зворотні виклики OpenAPI { #openapi-callbacks }
+
+Ви можете створити API з операцією шляху, яка ініціюватиме запит до зовнішнього API, створеного кимось іншим (ймовірно тим самим розробником, який буде використовувати ваш API).
+
+Процес, що відбувається, коли ваш застосунок API викликає зовнішній API, називається «зворотний виклик». Тому що програмне забезпечення, написане зовнішнім розробником, надсилає запит до вашого API, а потім ваш API виконує зворотний виклик, надсилаючи запит до зовнішнього API (його, ймовірно, також створив той самий розробник).
+
+У такому випадку вам може знадобитися задокументувати, яким має бути той зовнішній API: які операції шляху він має мати, яке тіло очікувати, яку відповідь повертати тощо.
+
+## Застосунок зі зворотними викликами { #an-app-with-callbacks }
+
+Розгляньмо це на прикладі.
+
+Уявімо, що ви розробляєте застосунок для створення рахунків.
+
+Ці рахунки матимуть `id`, `title` (необов'язково), `customer` і `total`.
+
+Користувач вашого API (зовнішній розробник) створить рахунок у вашому API за допомогою POST-запиту.
+
+Потім ваш API буде (уявімо):
+
+- Надсилати рахунок деякому клієнту зовнішнього розробника.
+- Отримувати оплату.
+- Надсилати сповіщення назад користувачу API (зовнішньому розробнику).
+ - Це буде зроблено шляхом надсилання POST-запиту (з вашого API) до деякого зовнішнього API, наданого тим зовнішнім розробником (це і є «зворотний виклик»).
+
+## Звичайний застосунок FastAPI { #the-normal-fastapi-app }
+
+Спочатку подивімося, як виглядав би звичайний застосунок API до додавання зворотного виклику.
+
+Він матиме операцію шляху, яка отримуватиме тіло `Invoice`, і параметр запиту `callback_url`, що міститиме URL для зворотного виклику.
+
+Ця частина цілком звична, більшість коду вам, ймовірно, уже знайома:
+
+{* ../../docs_src/openapi_callbacks/tutorial001_py310.py hl[7:11,34:51] *}
+
+/// tip | Порада
+
+Параметр запиту `callback_url` використовує тип Pydantic
Url.
+
+///
+
+Єдина нова річ - це `callbacks=invoices_callback_router.routes` як аргумент декоратора операції шляху. Далі розглянемо, що це таке.
+
+## Документування зворотного виклику { #documenting-the-callback }
+
+Фактичний код зворотного виклику сильно залежатиме від вашого застосунку API.
+
+І, ймовірно, сильно відрізнятиметься від застосунку до застосунку.
+
+Це можуть бути лише один-два рядки коду, наприклад:
+
+```Python
+callback_url = "https://example.com/api/v1/invoices/events/"
+httpx.post(callback_url, json={"description": "Invoice paid", "paid": True})
+```
+
+Але, можливо, найважливіша частина зворотного виклику - переконатися, що користувач вашого API (зовнішній розробник) правильно реалізує зовнішній API відповідно до даних, які ваш API надсилатиме в тілі запиту зворотного виклику тощо.
+
+Тому далі ми додамо код, щоб задокументувати, яким має бути цей зовнішній API, щоб приймати зворотний виклик від вашого API.
+
+Ця документація з'явиться в Swagger UI за адресою `/docs` у вашому API і дасть змогу зовнішнім розробникам зрозуміти, як створити зовнішній API.
+
+У цьому прикладі сам зворотний виклик не реалізовано (це може бути лише один рядок коду), лише частину з документацією.
+
+/// tip | Порада
+
+Фактичний зворотний виклик - це просто HTTP-запит.
+
+Реалізуючи зворотний виклик самостійно, ви можете скористатися, наприклад,
HTTPX або
Requests.
+
+///
+
+## Напишіть код документації для зворотного виклику { #write-the-callback-documentation-code }
+
+Цей код не виконуватиметься у вашому застосунку, він потрібен лише, щоб задокументувати, яким має бути зовнішній API.
+
+Але ви вже знаєте, як легко створювати автоматичну документацію для API за допомогою FastAPI.
+
+Тож ми скористаємося цими знаннями, щоб задокументувати, яким має бути зовнішній API... створивши операції шляху, які має реалізувати зовнішній API (ті, які викликатиме ваш API).
+
+/// tip | Порада
+
+Пишучи код для документування зворотного виклику, корисно уявити, що ви - той *зовнішній розробник*. І що ви зараз реалізуєте *зовнішній API*, а не *ваш API*.
+
+Тимчасово прийнявши цю точку зору ( *зовнішнього розробника* ), вам буде очевидніше, куди помістити параметри, яку Pydantic-модель використати для тіла, для відповіді тощо для того *зовнішнього API*.
+
+///
+
+### Створіть callback `APIRouter` { #create-a-callback-apirouter }
+
+Спочатку створіть новий `APIRouter`, який міститиме один або кілька зворотних викликів.
+
+{* ../../docs_src/openapi_callbacks/tutorial001_py310.py hl[1,23] *}
+
+### Створіть операцію шляху зворотного виклику { #create-the-callback-path-operation }
+
+Щоб створити операцію шляху зворотного виклику, використайте той самий `APIRouter`, який ви створили вище.
+
+Вона має виглядати як звичайна операція шляху FastAPI:
+
+- Ймовірно має містити оголошення тіла, яке вона приймає, напр. `body: InvoiceEvent`.
+- І також може містити оголошення відповіді, яку вона повертає, напр. `response_model=InvoiceEventReceived`.
+
+{* ../../docs_src/openapi_callbacks/tutorial001_py310.py hl[14:16,19:20,26:30] *}
+
+Є 2 основні відмінності від звичайної операції шляху:
+
+- Їй не потрібен реальний код, адже ваш застосунок ніколи не викликатиме цей код. Вона використовується лише для документування зовнішнього API. Тому функція може просто містити `pass`.
+- Шлях може містити
вираз OpenAPI 3 (див. нижче), де можна використовувати змінні з параметрами та частини оригінального запиту, надісланого до вашого API.
+
+### Вираз шляху зворотного виклику { #the-callback-path-expression }
+
+Шлях зворотного виклику може містити
вираз OpenAPI 3, який включає частини оригінального запиту, надісланого до вашого API.
+
+У цьому випадку це строка:
+
+```Python
+"{$callback_url}/invoices/{$request.body.id}"
+```
+
+Отже, якщо користувач вашого API (зовнішній розробник) надішле запит до *вашого API* на:
+
+```
+https://yourapi.com/invoices/?callback_url=https://www.external.org/events
+```
+
+з JSON-тілом:
+
+```JSON
+{
+ "id": "2expen51ve",
+ "customer": "Mr. Richie Rich",
+ "total": "9999"
+}
+```
+
+тоді *ваш API* опрацює рахунок і згодом надішле запит зворотного виклику на `callback_url` ( *зовнішній API* ):
+
+```
+https://www.external.org/events/invoices/2expen51ve
+```
+
+з JSON-тілом на кшталт:
+
+```JSON
+{
+ "description": "Payment celebration",
+ "paid": true
+}
+```
+
+і очікуватиме відповідь від того *зовнішнього API* з JSON-тілом на кшталт:
+
+```JSON
+{
+ "ok": true
+}
+```
+
+/// tip | Порада
+
+Зверніть увагу, що використаний URL зворотного виклику містить URL, отриманий як параметр запиту в `callback_url` (`https://www.external.org/events`), а також `id` рахунку зсередини JSON-тіла (`2expen51ve`).
+
+///
+
+### Додайте маршрутизатор зворотного виклику { #add-the-callback-router }
+
+На цьому етапі ви маєте потрібні операції шляху зворотного виклику (ті, які має реалізувати *зовнішній розробник* у *зовнішньому API*) у створеному вище маршрутизаторі зворотного виклику.
+
+Тепер використайте параметр `callbacks` у декораторі операції шляху вашого API, щоб передати атрибут `.routes` (це насправді просто `list` маршрутів/операцій шляху) з цього маршрутизатора зворотного виклику:
+
+{* ../../docs_src/openapi_callbacks/tutorial001_py310.py hl[33] *}
+
+/// tip | Порада
+
+Зверніть увагу, що ви передаєте не сам маршрутизатор (`invoices_callback_router`) у `callback=`, а атрибут `.routes`, тобто `invoices_callback_router.routes`.
+
+///
+
+### Перевірте документацію { #check-the-docs }
+
+Тепер ви можете запустити застосунок і перейти за адресою
http://127.0.0.1:8000/docs.
+
+Ви побачите вашу документацію з розділом «Callbacks» для вашої операції шляху, який показує, як має виглядати зовнішній API:
+
+

diff --git a/docs/uk/docs/advanced/openapi-webhooks.md b/docs/uk/docs/advanced/openapi-webhooks.md
new file mode 100644
index 0000000000..0d8a7f4c5f
--- /dev/null
+++ b/docs/uk/docs/advanced/openapi-webhooks.md
@@ -0,0 +1,55 @@
+# Вебхуки OpenAPI { #openapi-webhooks }
+
+Бувають випадки, коли ви хочете повідомити **користувачів** вашого API, що ваш застосунок може викликати *їхній* застосунок (надсилаючи запит) із деякими даними, зазвичай щоб **сповістити** про певний тип **події**.
+
+Це означає, що замість звичного процесу, коли ваші користувачі надсилають запити до вашого API, саме **ваш API** (або ваш застосунок) може **надсилати запити до їхньої системи** (до їх API, їх застосунку).
+
+Зазвичай це називають **вебхуком**.
+
+## Кроки вебхуків { #webhooks-steps }
+
+Зазвичай процес такий: ви визначаєте у своєму коді, яке повідомлення надсилатимете, тобто **тіло запиту**.
+
+Ви також якимось чином визначаєте моменти, коли ваш застосунок надсилатиме ці запити або події.
+
+А **ваші користувачі** якимось чином (наприклад, у веб-дашборді) визначають **URL**, куди ваш застосунок має надсилати ці запити.
+
+Уся **логіка** щодо реєстрації URL для вебхуків і код для фактичного надсилання цих запитів - на ваш розсуд. Ви пишете це у **власному коді** так, як вважаєте за потрібне.
+
+## Документування вебхуків у **FastAPI** та OpenAPI { #documenting-webhooks-with-fastapi-and-openapi }
+
+У **FastAPI**, використовуючи OpenAPI, ви можете визначити назви цих вебхуків, типи HTTP-операцій, які ваш застосунок може надсилати (наприклад, `POST`, `PUT` тощо), і **тіла** запитів, які ваш застосунок надсилатиме.
+
+Це значно спростить для ваших користувачів **реалізацію їхніх API** для отримання ваших запитів **вебхуків**; вони навіть зможуть згенерувати частину власного коду API автоматично.
+
+/// info | Інформація
+
+Вебхуки доступні в OpenAPI 3.1.0 і вище, підтримуються FastAPI `0.99.0` і вище.
+
+///
+
+## Застосунок із вебхуками { #an-app-with-webhooks }
+
+Коли ви створюєте застосунок **FastAPI**, є атрибут `webhooks`, який можна використати для визначення *вебхуків* так само, як ви визначаєте *операції шляху*, наприклад за допомогою `@app.webhooks.post()`.
+
+{* ../../docs_src/openapi_webhooks/tutorial001_py310.py hl[9:12,15:20] *}
+
+Визначені вами вебхуки потраплять до **схеми OpenAPI** та автоматичного **інтерфейсу документації**.
+
+/// info | Інформація
+
+Об'єкт `app.webhooks` насправді є просто `APIRouter` - тим самим типом, який ви використовуєте, структуризуючи застосунок у кількох файлах.
+
+///
+
+Зверніть увагу, що з вебхуками ви фактично не оголошуєте *шлях* (на кшталт `/items/`), текст, який ви передаєте там, - це лише **ідентифікатор** вебхука (назва події). Наприклад, у `@app.webhooks.post("new-subscription")` назва вебхука - `new-subscription`.
+
+Це тому, що очікується, що **ваші користувачі** іншим способом (наприклад, у веб-дашборді) визначать фактичний **URL-шлях**, де вони хочуть отримувати запит вебхука.
+
+### Перевірте документацію { #check-the-docs }
+
+Тепер ви можете запустити свій застосунок і перейти за адресою
http://127.0.0.1:8000/docs.
+
+Ви побачите у своїй документації звичайні *операції шляху*, а також деякі **вебхуки**:
+
+

diff --git a/docs/uk/docs/advanced/path-operation-advanced-configuration.md b/docs/uk/docs/advanced/path-operation-advanced-configuration.md
new file mode 100644
index 0000000000..202f9317ed
--- /dev/null
+++ b/docs/uk/docs/advanced/path-operation-advanced-configuration.md
@@ -0,0 +1,172 @@
+# Додаткова конфігурація операцій шляху { #path-operation-advanced-configuration }
+
+## OpenAPI operationId { #openapi-operationid }
+
+/// warning | Попередження
+
+Якщо ви не «експерт» з OpenAPI, імовірно, вам це не потрібно.
+
+///
+
+Ви можете встановити OpenAPI `operationId`, який буде використано у вашій *операції шляху*, за допомогою параметра `operation_id`.
+
+Потрібно переконатися, що він унікальний для кожної операції.
+
+{* ../../docs_src/path_operation_advanced_configuration/tutorial001_py310.py hl[6] *}
+
+### Використання назви *функції операції шляху* як operationId { #using-the-path-operation-function-name-as-the-operationid }
+
+Якщо ви хочете використовувати назви функцій ваших API як `operationId`, ви можете пройтися по всіх них і переписати `operation_id` кожної *операції шляху*, використовуючи їхній `APIRoute.name`.
+
+Зробіть це після додавання всіх *операцій шляху*.
+
+{* ../../docs_src/path_operation_advanced_configuration/tutorial002_py310.py hl[2, 12:21, 24] *}
+
+/// tip | Порада
+
+Якщо ви вручну викликаєте `app.openapi()`, оновіть значення `operationId` до цього.
+
+///
+
+/// warning | Попередження
+
+Якщо ви робите це, переконайтеся, що кожна з ваших *функцій операцій шляху* має унікальну назву.
+
+Навіть якщо вони в різних модулях (файлах Python).
+
+///
+
+## Виключення з OpenAPI { #exclude-from-openapi }
+
+Щоб виключити *операцію шляху* зі згенерованої Схеми OpenAPI (а отже, і з автоматичних систем документації), використайте параметр `include_in_schema` і встановіть його в `False`:
+
+{* ../../docs_src/path_operation_advanced_configuration/tutorial003_py310.py hl[6] *}
+
+## Розширений опис із docstring { #advanced-description-from-docstring }
+
+Ви можете обмежити кількість рядків із docstring *функції операції шляху*, що використовуються для OpenAPI.
+
+Додавання `\f` (екранованого символу «form feed») змусить **FastAPI** обрізати вивід для OpenAPI в цій точці.
+
+Це не з’явиться в документації, але інші інструменти (такі як Sphinx) зможуть використати решту.
+
+{* ../../docs_src/path_operation_advanced_configuration/tutorial004_py310.py hl[17:27] *}
+
+## Додаткові відповіді { #additional-responses }
+
+Ймовірно, ви вже бачили, як оголошувати `response_model` і `status_code` для *операції шляху*.
+
+Це визначає метадані про основну відповідь *операції шляху*.
+
+Також можна оголосити додаткові відповіді з їхніми моделями, кодами статусу тощо.
+
+У документації є цілий розділ про це, ви можете прочитати його тут: [Додаткові відповіді в OpenAPI](additional-responses.md){.internal-link target=_blank}.
+
+## Додатково в OpenAPI { #openapi-extra }
+
+Коли ви оголошуєте *операцію шляху* у своєму застосунку, **FastAPI** автоматично генерує відповідні метадані про цю *операцію шляху* для включення в Схему OpenAPI.
+
+/// note | Технічні деталі
+
+У специфікації OpenAPI це називається
Об'єкт Operation.
+
+///
+
+Він містить усю інформацію про *операцію шляху* і використовується для побудови автоматичної документації.
+
+Він включає `tags`, `parameters`, `requestBody`, `responses` тощо.
+
+Цю OpenAPI-схему, специфічну для *операції шляху*, зазвичай генерує **FastAPI** автоматично, але ви також можете її розширити.
+
+/// tip | Порада
+
+Це низькорівнева точка розширення.
+
+Якщо вам потрібно лише оголосити додаткові відповіді, зручніше зробити це через [Додаткові відповіді в OpenAPI](additional-responses.md){.internal-link target=_blank}.
+
+///
+
+Ви можете розширити OpenAPI-схему для *операції шляху*, використовуючи параметр `openapi_extra`.
+
+### Розширення OpenAPI { #openapi-extensions }
+
+`openapi_extra` може бути корисним, наприклад, для оголошення [OpenAPI Extensions](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#specificationExtensions):
+
+{* ../../docs_src/path_operation_advanced_configuration/tutorial005_py310.py hl[6] *}
+
+Якщо ви відкриєте автоматичну документацію API, ваше розширення з’явиться внизу конкретної *операції шляху*.
+
+

+
+І якщо ви відкриєте згенерований OpenAPI (за адресою `/openapi.json` у вашому API), ви також побачите своє розширення як частину конкретної *операції шляху*:
+
+```JSON hl_lines="22"
+{
+ "openapi": "3.1.0",
+ "info": {
+ "title": "FastAPI",
+ "version": "0.1.0"
+ },
+ "paths": {
+ "/items/": {
+ "get": {
+ "summary": "Read Items",
+ "operationId": "read_items_items__get",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {}
+ }
+ }
+ }
+ },
+ "x-aperture-labs-portal": "blue"
+ }
+ }
+ }
+}
+```
+
+### Власна схема OpenAPI для *операції шляху* { #custom-openapi-path-operation-schema }
+
+Словник у `openapi_extra` буде глибоко об’єднано з автоматично згенерованою OpenAPI-схемою для *операції шляху*.
+
+Тож ви можете додати додаткові дані до автоматично згенерованої схеми.
+
+Наприклад, ви можете вирішити читати та перевіряти запит власним кодом, не використовуючи автоматичні можливості FastAPI з Pydantic, але все ж захотіти визначити запит у Схемі OpenAPI.
+
+Ви можете зробити це за допомогою `openapi_extra`:
+
+{* ../../docs_src/path_operation_advanced_configuration/tutorial006_py310.py hl[19:36, 39:40] *}
+
+У цьому прикладі ми не оголошували жодної моделі Pydantic. Насправді тіло запиту навіть не
розібрано як JSON, воно читається безпосередньо як `bytes`, а функція `magic_data_reader()` відповідатиме за його розбір певним чином.
+
+Водночас ми можемо оголосити очікувану схему для тіла запиту.
+
+### Власний тип вмісту OpenAPI { #custom-openapi-content-type }
+
+Використовуючи той самий прийом, ви можете застосувати модель Pydantic, щоб визначити Схему JSON, яка потім включається в користувацький розділ OpenAPI-схеми для *операції шляху*.
+
+І ви можете зробити це, навіть якщо тип даних у запиті - не JSON.
+
+Наприклад, у цьому застосунку ми не використовуємо вбудовану функціональність FastAPI для отримання Схеми JSON з моделей Pydantic і не використовуємо автоматичну валідацію для JSON. Насправді ми оголошуємо тип вмісту запиту як YAML, а не JSON:
+
+{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py310.py hl[15:20, 22] *}
+
+Попри те, що ми не використовуємо типову вбудовану функціональність, ми все одно використовуємо модель Pydantic, щоб вручну згенерувати Схему JSON для даних, які хочемо отримати у форматі YAML.
+
+Потім ми працюємо із запитом безпосередньо і отримуємо тіло як `bytes`. Це означає, що FastAPI навіть не намагатиметься розібрати корисне навантаження запиту як JSON.
+
+Далі у нашому коді ми безпосередньо розбираємо цей YAML-вміст і знову використовуємо ту саму модель Pydantic, щоб перевірити YAML-вміст:
+
+{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py310.py hl[24:31] *}
+
+/// tip | Порада
+
+Тут ми перевикористовуємо ту саму модель Pydantic.
+
+Але так само ми могли б перевіряти дані іншим способом.
+
+///
diff --git a/docs/uk/docs/advanced/response-change-status-code.md b/docs/uk/docs/advanced/response-change-status-code.md
new file mode 100644
index 0000000000..fdf9f81c56
--- /dev/null
+++ b/docs/uk/docs/advanced/response-change-status-code.md
@@ -0,0 +1,31 @@
+# Відповідь - зміна коду статусу { #response-change-status-code }
+
+Ймовірно, ви вже читали, що можна встановити типовий [код статусу відповіді](../tutorial/response-status-code.md){.internal-link target=_blank}.
+
+Але інколи потрібно повернути інший код статусу, ніж типовий.
+
+## Випадок використання { #use-case }
+
+Наприклад, уявімо, що ви хочете за замовчуванням повертати код статусу HTTP «OK» `200`.
+
+Але якщо даних не існувало, ви хочете створити їх і повернути код статусу HTTP «CREATED» `201`.
+
+Водночас ви все одно хочете мати змогу фільтрувати та перетворювати повернені дані за допомогою `response_model`.
+
+Для таких випадків ви можете використати параметр `Response`.
+
+## Використовуйте параметр `Response` { #use-a-response-parameter }
+
+Ви можете оголосити параметр типу `Response` у своїй функції операції шляху (так само, як для кукі та заголовків).
+
+Потім ви можете встановити `status_code` у цьому *тимчасовому* об'єкті відповіді.
+
+{* ../../docs_src/response_change_status_code/tutorial001_py310.py hl[1,9,12] *}
+
+Після цього ви можете повернути будь-який потрібний об'єкт, як зазвичай (`dict`, модель бази даних тощо).
+
+І якщо ви оголосили `response_model`, він усе одно буде використаний для фільтрації та перетворення поверненого об'єкта.
+
+**FastAPI** використає цей *тимчасовий* об'єкт відповіді, щоб отримати код статусу (а також кукі та заголовки), і помістить їх у фінальну відповідь, що містить повернуте вами значення, відфільтроване за допомогою `response_model`.
+
+Ви також можете оголосити параметр `Response` у залежностях і встановлювати там код статусу. Але майте на увазі: останнє встановлене значення матиме пріоритет.
diff --git a/docs/uk/docs/advanced/response-cookies.md b/docs/uk/docs/advanced/response-cookies.md
new file mode 100644
index 0000000000..826602e708
--- /dev/null
+++ b/docs/uk/docs/advanced/response-cookies.md
@@ -0,0 +1,51 @@
+# Кукі у відповіді { #response-cookies }
+
+## Використовуйте параметр `Response` { #use-a-response-parameter }
+
+Ви можете оголосити параметр типу `Response` у вашій *функції операції шляху*.
+
+Потім ви можете встановити кукі в цьому *тимчасовому* об'єкті відповіді.
+
+{* ../../docs_src/response_cookies/tutorial002_py310.py hl[1, 8:9] *}
+
+Після цього ви можете повернути будь-який потрібний об'єкт, як зазвичай (наприклад, `dict`, модель бази даних тощо).
+
+І якщо ви оголосили `response_model`, він усе одно буде використаний для фільтрації та перетворення об'єкта, який ви повернули.
+
+**FastAPI** використає цю *тимчасову* відповідь, щоб витягнути кукі (а також заголовки та код статусу) і помістить їх у фінальну відповідь, що містить значення, яке ви повернули, відфільтроване будь-якою `response_model`.
+
+Ви також можете оголосити параметр `Response` у залежностях і встановлювати в них кукі (і заголовки).
+
+## Повертайте `Response` безпосередньо { #return-a-response-directly }
+
+Ви також можете створювати кукі, повертаючи `Response` безпосередньо у вашому коді.
+
+Для цього ви можете створити відповідь, як описано в [Повернути відповідь безпосередньо](response-directly.md){.internal-link target=_blank}.
+
+Потім встановіть у ньому кукі і поверніть його:
+
+{* ../../docs_src/response_cookies/tutorial001_py310.py hl[10:12] *}
+
+/// tip | Порада
+
+Майте на увазі, що якщо ви повертаєте відповідь безпосередньо замість використання параметра `Response`, FastAPI поверне її напряму.
+
+Тому вам потрібно переконатися, що ваші дані мають коректний тип. Наприклад, сумісні з JSON, якщо ви повертаєте `JSONResponse`.
+
+А також що ви не надсилаєте дані, які мали б бути відфільтровані за допомогою `response_model`.
+
+///
+
+### Більше інформації { #more-info }
+
+/// note | Технічні деталі
+
+Ви також можете використати `from starlette.responses import Response` або `from starlette.responses import JSONResponse`.
+
+**FastAPI** надає ті самі `starlette.responses` як `fastapi.responses` лише для зручності для вас, розробника. Але більшість доступних відповідей надходять безпосередньо зі Starlette.
+
+І оскільки `Response` часто використовується для встановлення заголовків і кукі, **FastAPI** також надає його як `fastapi.Response`.
+
+///
+
+Щоб побачити всі доступні параметри та опції, перегляньте
документацію в Starlette.
diff --git a/docs/uk/docs/advanced/response-directly.md b/docs/uk/docs/advanced/response-directly.md
new file mode 100644
index 0000000000..7396ab7565
--- /dev/null
+++ b/docs/uk/docs/advanced/response-directly.md
@@ -0,0 +1,65 @@
+# Повернення Response безпосередньо { #return-a-response-directly }
+
+Коли ви створюєте операцію шляху FastAPI, зазвичай ви можете повертати з неї будь-які дані: `dict`, `list`, модель Pydantic, модель бази даних тощо.
+
+Типово FastAPI автоматично перетворить це значення повернення на JSON, використовуючи `jsonable_encoder`, описаний у [Сумісному з JSON кодері](../tutorial/encoder.md){.internal-link target=_blank}.
+
+Потім, за лаштунками, він помістить ці дані, сумісні з JSON (наприклад, `dict`), у `JSONResponse`, який буде використано для надсилання відповіді клієнту.
+
+Але ви можете повертати `JSONResponse` безпосередньо з ваших операцій шляху.
+
+Це може бути корисним, наприклад, щоб повертати власні заголовки або кукі.
+
+## Повернення `Response` { #return-a-response }
+
+Насправді ви можете повертати будь-який `Response` або будь-який його підклас.
+
+/// tip | Порада
+
+`JSONResponse` сам є підкласом `Response`.
+
+///
+
+І коли ви повертаєте `Response`, FastAPI передасть його безпосередньо.
+
+Він не виконуватиме жодних перетворень даних за допомогою моделей Pydantic, не перетворюватиме вміст на будь-який тип тощо.
+
+Це дає вам багато гнучкості. Ви можете повертати будь-які типи даних, переписувати будь-які оголошення або перевірки даних тощо.
+
+## Використання `jsonable_encoder` у `Response` { #using-the-jsonable-encoder-in-a-response }
+
+Оскільки FastAPI не вносить змін у `Response`, який ви повертаєте, вам потрібно впевнитися, що його вміст готовий.
+
+Наприклад, ви не можете покласти модель Pydantic у `JSONResponse`, не перетворивши її спочатку на `dict` з усіма типами даних (як-от `datetime`, `UUID` тощо), перетвореними на типи, сумісні з JSON.
+
+Для таких випадків ви можете використати `jsonable_encoder`, щоб перетворити ваші дані перед тим, як передати їх у відповідь:
+
+{* ../../docs_src/response_directly/tutorial001_py310.py hl[5:6,20:21] *}
+
+/// note | Технічні деталі
+
+Ви також можете використати `from starlette.responses import JSONResponse`.
+
+FastAPI надає ті самі `starlette.responses` як `fastapi.responses` просто як зручність для вас, розробника. Але більшість доступних `Response` походять безпосередньо зі Starlette.
+
+///
+
+## Повернення власного `Response` { #returning-a-custom-response }
+
+Наведений вище приклад показує всі необхідні частини, але він ще не дуже корисний, адже ви могли просто повернути `item` безпосередньо, і FastAPI помістив би його у `JSONResponse`, перетворивши на `dict` тощо. Усе це відбувається за замовчуванням.
+
+Тепер подивімося, як це використати, щоб повернути власну відповідь.
+
+Припустімо, ви хочете повернути відповідь
XML.
+
+Ви можете помістити свій вміст XML у строку, помістити це в `Response` і повернути:
+
+{* ../../docs_src/response_directly/tutorial002_py310.py hl[1,18] *}
+
+## Примітки { #notes }
+
+Коли ви повертаєте `Response` безпосередньо, його дані не перевіряються, не перетворюються (серіалізуються) і не документуються автоматично.
+
+Але ви все ще можете задокументувати це, як описано в [Додаткових відповідях в OpenAPI](additional-responses.md){.internal-link target=_blank}.
+
+У подальших розділах ви побачите, як використовувати/оголошувати ці власні `Response`, водночас зберігаючи автоматичне перетворення даних, документацію тощо.
diff --git a/docs/uk/docs/advanced/response-headers.md b/docs/uk/docs/advanced/response-headers.md
new file mode 100644
index 0000000000..1c9d4e6773
--- /dev/null
+++ b/docs/uk/docs/advanced/response-headers.md
@@ -0,0 +1,41 @@
+# Заголовки відповіді { #response-headers }
+
+## Використовуйте параметр `Response` { #use-a-response-parameter }
+
+Ви можете оголосити параметр типу `Response` у вашій функції операції шляху (так само, як і для кукі).
+
+Потім ви можете встановлювати заголовки в цьому *тимчасовому* обʼєкті відповіді.
+
+{* ../../docs_src/response_headers/tutorial002_py310.py hl[1, 7:8] *}
+
+Далі ви можете повернути будь-який потрібний обʼєкт, як зазвичай (наприклад, `dict`, модель бази даних тощо).
+
+Якщо ви оголосили `response_model`, його все одно буде використано для фільтрації та перетворення поверненого обʼєкта.
+
+FastAPI використає цей *тимчасовий* обʼєкт відповіді, щоб витягти заголовки (а також кукі та код статусу) і помістить їх у кінцеву відповідь, яка міститиме повернуте вами значення, відфільтроване будь-яким `response_model`.
+
+Також ви можете оголосити параметр `Response` у залежностях і встановлювати в них заголовки (та кукі).
+
+## Поверніть `Response` безпосередньо { #return-a-response-directly }
+
+Ви також можете додавати заголовки, коли повертаєте `Response` безпосередньо.
+
+Створіть відповідь, як описано в [Повернення Response безпосередньо](response-directly.md){.internal-link target=_blank}, і передайте заголовки як додатковий параметр:
+
+{* ../../docs_src/response_headers/tutorial001_py310.py hl[10:12] *}
+
+/// note | Технічні деталі
+
+Ви також можете використати `from starlette.responses import Response` або `from starlette.responses import JSONResponse`.
+
+FastAPI надає ті самі `starlette.responses` як `fastapi.responses` просто для зручності для вас, розробника. Але більшість доступних типів відповідей походять безпосередньо зі Starlette.
+
+Оскільки `Response` часто використовують для встановлення заголовків і кукі, FastAPI також надає його як `fastapi.Response`.
+
+///
+
+## Власні заголовки { #custom-headers }
+
+Майте на увазі, що власні закриті заголовки можна додавати
за допомогою префікса `X-`.
+
+Але якщо у вас є власні заголовки, які клієнт у браузері має бачити, вам потрібно додати їх у вашу конфігурацію CORS (докладніше в [CORS (Cross-Origin Resource Sharing)](../tutorial/cors.md){.internal-link target=_blank}), використовуючи параметр `expose_headers`, задокументований у
документації Starlette щодо CORS.
diff --git a/docs/uk/docs/advanced/security/http-basic-auth.md b/docs/uk/docs/advanced/security/http-basic-auth.md
new file mode 100644
index 0000000000..e0578772d3
--- /dev/null
+++ b/docs/uk/docs/advanced/security/http-basic-auth.md
@@ -0,0 +1,107 @@
+# HTTP Basic Auth { #http-basic-auth }
+
+Для найпростіших випадків ви можете використовувати HTTP Basic Auth.
+
+У HTTP Basic Auth застосунок очікує заголовок, що містить ім'я користувача та пароль.
+
+Якщо він його не отримує, повертається помилка HTTP 401 «Unauthorized».
+
+І повертається заголовок `WWW-Authenticate` зі значенням `Basic` та необов'язковим параметром `realm`.
+
+Це каже браузеру показати вбудовану підсказку для введення імені користувача та пароля.
+
+Потім, коли ви введете це ім'я користувача та пароль, браузер автоматично надішле їх у заголовку.
+
+## Простий HTTP Basic Auth { #simple-http-basic-auth }
+
+- Імпортуйте `HTTPBasic` і `HTTPBasicCredentials`.
+- Створіть «`security` scheme» за допомогою `HTTPBasic`.
+- Використайте цей `security` як залежність у вашій операції шляху.
+- Він повертає об'єкт типу `HTTPBasicCredentials`:
+ - Він містить надіслані `username` і `password`.
+
+{* ../../docs_src/security/tutorial006_an_py310.py hl[4,8,12] *}
+
+Коли ви спробуєте відкрити URL вперше (або натиснете кнопку «Execute» у документації), браузер попросить вас ввести ім'я користувача та пароль:
+
+

+
+## Перевірте ім'я користувача { #check-the-username }
+
+Ось більш повний приклад.
+
+Використайте залежність, щоб перевірити, чи правильні ім'я користувача та пароль.
+
+Для цього використайте стандартний модуль Python
`secrets`, щоб перевірити ім'я користувача та пароль.
+
+`secrets.compare_digest()` повинен отримувати `bytes` або `str`, що містить лише ASCII-символи (англійські), це означає, що він не працюватиме з символами на кшталт `á`, як у `Sebastián`.
+
+Щоб це обійти, ми спочатку перетворюємо `username` і `password` у `bytes`, кодувавши їх у UTF-8.
+
+Потім ми можемо використати `secrets.compare_digest()`, щоб упевнитися, що `credentials.username` дорівнює `"stanleyjobson"`, а `credentials.password` дорівнює `"swordfish"`.
+
+{* ../../docs_src/security/tutorial007_an_py310.py hl[1,12:24] *}
+
+Це було б подібно до:
+
+```Python
+if not (credentials.username == "stanleyjobson") or not (credentials.password == "swordfish"):
+ # Return some error
+ ...
+```
+
+Але використовуючи `secrets.compare_digest()`, це буде захищено від типу атак, що називаються «атаки за часом» (timing attacks).
+
+### Атаки за часом { #timing-attacks }
+
+Що таке «атака за часом»?
+
+Уявімо, що зловмисники намагаються вгадати ім'я користувача та пароль.
+
+Вони надсилають запит з ім'ям користувача `johndoe` та паролем `love123`.
+
+Тоді Python-код у вашому застосунку буде еквівалентний чомусь на кшталт:
+
+```Python
+if "johndoe" == "stanleyjobson" and "love123" == "swordfish":
+ ...
+```
+
+Але в той момент, коли Python порівнює першу `j` у `johndoe` з першою `s` у `stanleyjobson`, він поверне `False`, тому що вже знає, що ці дві строки не однакові, «немає сенсу витрачати обчислення на порівняння решти літер». І ваш застосунок скаже «Невірні ім'я користувача або пароль».
+
+А потім зловмисники спробують з ім'ям користувача `stanleyjobsox` і паролем `love123`.
+
+І ваш код застосунку зробить щось на кшталт:
+
+```Python
+if "stanleyjobsox" == "stanleyjobson" and "love123" == "swordfish":
+ ...
+```
+
+Python доведеться порівняти весь `stanleyjobso` у обох `stanleyjobsox` і `stanleyjobson`, перш ніж зрозуміти, що строки різні. Тому відповідь «Невірні ім'я користувача або пароль» займе на кілька мікросекунд довше.
+
+#### Час відповіді допомагає зловмисникам { #the-time-to-answer-helps-the-attackers }
+
+У цей момент, помітивши, що сервер витратив на кілька мікросекунд більше, щоб надіслати відповідь «Невірні ім'я користувача або пароль», зловмисники знатимуть, що вони щось вгадали, деякі початкові літери правильні.
+
+І тоді вони можуть спробувати знову, знаючи, що це, ймовірно, щось більш схоже на `stanleyjobsox`, ніж на `johndoe`.
+
+#### «Професійна» атака { #a-professional-attack }
+
+Звісно, зловмисники не робитимуть усе це вручну, вони напишуть програму, можливо з тисячами або мільйонами перевірок за секунду. І вони отримуватимуть лише по одній правильній літері за раз.
+
+Але так за кілька хвилин або годин зловмисники вгадають правильні ім'я користувача та пароль, «за допомогою» нашого застосунку, просто використовуючи час, потрібний для відповіді.
+
+#### Виправте за допомогою `secrets.compare_digest()` { #fix-it-with-secrets-compare-digest }
+
+Але в нашому коді ми насправді використовуємо `secrets.compare_digest()`.
+
+Коротко, він витрачає однаковий час на порівняння `stanleyjobsox` зі `stanleyjobson`, як і на порівняння `johndoe` зі `stanleyjobson`. І так само для пароля.
+
+Таким чином, використовуючи `secrets.compare_digest()` у коді вашого застосунку, він буде захищений від усього цього класу атак безпеки.
+
+### Поверніть помилку { #return-the-error }
+
+Після виявлення, що облікові дані неправильні, поверніть `HTTPException` з кодом статусу 401 (такий самий повертається, коли облікові дані не надані) і додайте заголовок `WWW-Authenticate`, щоб браузер знову показав підсказку входу:
+
+{* ../../docs_src/security/tutorial007_an_py310.py hl[26:30] *}
diff --git a/docs/uk/docs/advanced/security/index.md b/docs/uk/docs/advanced/security/index.md
new file mode 100644
index 0000000000..a3479794f8
--- /dev/null
+++ b/docs/uk/docs/advanced/security/index.md
@@ -0,0 +1,19 @@
+# Просунута безпека { #advanced-security }
+
+## Додаткові можливості { #additional-features }
+
+Є кілька додаткових можливостей для роботи з безпекою, окрім тих, що розглянуті в [Навчальний посібник - Посібник користувача: Безпека](../../tutorial/security/index.md){.internal-link target=_blank}.
+
+/// tip | Порада
+
+Наступні розділи не обов'язково «просунуті».
+
+І можливо, що для вашого випадку використання рішення є в одному з них.
+
+///
+
+## Спершу прочитайте навчальний посібник { #read-the-tutorial-first }
+
+У наступних розділах передбачається, що ви вже прочитали основний [Навчальний посібник - Посібник користувача: Безпека](../../tutorial/security/index.md){.internal-link target=_blank}.
+
+Усі вони базуються на тих самих концепціях, але надають деякі додаткові можливості.
diff --git a/docs/uk/docs/advanced/security/oauth2-scopes.md b/docs/uk/docs/advanced/security/oauth2-scopes.md
new file mode 100644
index 0000000000..34ef04a288
--- /dev/null
+++ b/docs/uk/docs/advanced/security/oauth2-scopes.md
@@ -0,0 +1,274 @@
+# OAuth2 scopes { #oauth2-scopes }
+
+Ви можете використовувати OAuth2 scopes безпосередньо з **FastAPI**, вони інтегровані для безшовної роботи.
+
+Це дозволить мати більш детальну систему дозволів, відповідно до стандарту OAuth2, інтегровану у ваш застосунок OpenAPI (і документацію API).
+
+OAuth2 зі scopes - це механізм, який використовують багато великих провайдерів автентифікації, як-от Facebook, Google, GitHub, Microsoft, X (Twitter) тощо. Вони застосовують його, щоб надавати конкретні дозволи користувачам і застосункам.
+
+Кожного разу, коли ви «log in with» Facebook, Google, GitHub, Microsoft, X (Twitter), цей застосунок використовує OAuth2 зі scopes.
+
+У цьому розділі ви побачите, як керувати автентифікацією та авторизацією за допомогою того ж OAuth2 зі scopes у вашому застосунку **FastAPI**.
+
+/// warning | Попередження
+
+Це більш-менш просунутий розділ. Якщо ви тільки починаєте, можете пропустити його.
+
+Вам не обов’язково потрібні OAuth2 scopes, ви можете керувати автентифікацією та авторизацією будь-яким зручним способом.
+
+Але OAuth2 зі scopes можна гарно інтегрувати у ваш API (з OpenAPI) і документацію API.
+
+Водночас ви все одно примушуєте виконувати ці scopes або будь-які інші вимоги безпеки/авторизації так, як потрібно, у своєму коді.
+
+У багатьох випадках OAuth2 зі scopes - це надмірність.
+
+Але якщо ви знаєте, що це потрібно, або просто цікаво, читайте далі.
+
+///
+
+## OAuth2 scopes та OpenAPI { #oauth2-scopes-and-openapi }
+
+Специфікація OAuth2 визначає «scopes» як список строк, розділених пробілами.
+
+Вміст кожної з цих строк може мати будь-який формат, але не повинен містити пробілів.
+
+Ці scopes представляють «дозволи».
+
+В OpenAPI (наприклад, у документації API) ви можете визначати «схеми безпеки».
+
+Коли одна з цих схем безпеки використовує OAuth2, ви також можете оголошувати та використовувати scopes.
+
+Кожен «scope» - це просто строка (без пробілів).
+
+Зазвичай їх використовують для оголошення конкретних дозволів безпеки, наприклад:
+
+- `users:read` або `users:write` - поширені приклади.
+- `instagram_basic` використовується Facebook / Instagram.
+- `https://www.googleapis.com/auth/drive` використовується Google.
+
+/// info | Інформація
+
+В OAuth2 «scope» - це просто строка, що декларує конкретний потрібний дозвіл.
+
+Не має значення, чи містить вона інші символи на кшталт `:` або чи це URL.
+
+Ці деталі специфічні для реалізації.
+
+Для OAuth2 це просто строки.
+
+///
+
+## Загальний огляд { #global-view }
+
+Спочатку швидко подивімося на частини, що відрізняються від прикладів у головному **Навчальному посібнику - Керівництві користувача** для [OAuth2 з паролем (і хешуванням), Bearer з JWT-токенами](../../tutorial/security/oauth2-jwt.md){.internal-link target=_blank}. Тепер із використанням OAuth2 scopes:
+
+{* ../../docs_src/security/tutorial005_an_py310.py hl[5,9,13,47,65,106,108:116,122:126,130:136,141,157] *}
+
+Тепер розгляньмо ці зміни крок за кроком.
+
+## Схема безпеки OAuth2 { #oauth2-security-scheme }
+
+Перша зміна - тепер ми оголошуємо схему безпеки OAuth2 з двома доступними scopes: `me` і `items`.
+
+Параметр `scopes` приймає `dict`, де кожен scope - це ключ, а опис - значення:
+
+{* ../../docs_src/security/tutorial005_an_py310.py hl[63:66] *}
+
+Оскільки тепер ми оголошуємо ці scopes, вони з’являться в документації API, коли ви увійдете/авторизуєтеся.
+
+І ви зможете обрати, які scopes надати доступ: `me` і `items`.
+
+Це той самий механізм, який використовується, коли ви надаєте дозволи під час входу через Facebook, Google, GitHub тощо:
+
+

+
+## JWT токен зі scopes { #jwt-token-with-scopes }
+
+Тепер змініть операцію шляху токена, щоб повертати запитані scopes.
+
+Ми все ще використовуємо той самий `OAuth2PasswordRequestForm`. Він містить властивість `scopes` зі `list` з `str`, по одному scope, отриманому в запиті.
+
+І ми повертаємо scopes як частину JWT токена.
+
+/// danger | Обережно
+
+Для простоти тут ми просто додаємо отримані scopes безпосередньо до токена.
+
+Але у вашому застосунку, з міркувань безпеки, переконайтеся, що ви додаєте лише ті scopes, які користувач дійсно може мати, або ті, що ви попередньо визначили.
+
+///
+
+{* ../../docs_src/security/tutorial005_an_py310.py hl[157] *}
+
+## Оголосіть scopes в операціях шляху та залежностях { #declare-scopes-in-path-operations-and-dependencies }
+
+Тепер ми оголошуємо, що операція шляху для `/users/me/items/` вимагає scope `items`.
+
+Для цього імпортуємо і використовуємо `Security` з `fastapi`.
+
+Ви можете використовувати `Security` для оголошення залежностей (так само як `Depends`), але `Security` також приймає параметр `scopes` зі списком scopes (строк).
+
+У цьому випадку ми передаємо функцію-залежність `get_current_active_user` до `Security` (так само, як зробили б із `Depends`).
+
+А також передаємо `list` scopes, у цьому випадку лише один scope: `items` (їх могло б бути більше).
+
+І функція-залежність `get_current_active_user` також може оголошувати підзалежності не лише з `Depends`, а й з `Security`. Оголошуючи свою підзалежність (`get_current_user`) і додаткові вимоги до scopes.
+
+У цьому випадку вона вимагає scope `me` (вона могла б вимагати більш ніж один scope).
+
+/// note | Примітка
+
+Вам не обов’язково додавати різні scopes у різних місцях.
+
+Ми робимо це тут, щоб показати, як **FastAPI** обробляє scopes, оголошені на різних рівнях.
+
+///
+
+{* ../../docs_src/security/tutorial005_an_py310.py hl[5,141,172] *}
+
+/// info | Технічні деталі
+
+`Security` насправді є підкласом `Depends`, і має лише один додатковий параметр, який ми побачимо пізніше.
+
+Але використовуючи `Security` замість `Depends`, **FastAPI** знатиме, що можна оголошувати scopes безпеки, використовувати їх внутрішньо та документувати API через OpenAPI.
+
+Коли ви імпортуєте `Query`, `Path`, `Depends`, `Security` та інші з `fastapi`, це насправді функції, що повертають спеціальні класи.
+
+///
+
+## Використовуйте `SecurityScopes` { #use-securityscopes }
+
+Тепер оновіть залежність `get_current_user`.
+
+Вона використовується наведеними вище залежностями.
+
+Тут ми використовуємо ту саму схему OAuth2, створену раніше, оголошуючи її як залежність: `oauth2_scheme`.
+
+Оскільки ця функція-залежність не має власних вимог до scopes, ми можемо використовувати `Depends` з `oauth2_scheme`, немає потреби застосовувати `Security`, коли не потрібно вказувати scopes безпеки.
+
+Ми також оголошуємо спеціальний параметр типу `SecurityScopes`, імпортований з `fastapi.security`.
+
+Клас `SecurityScopes` подібний до `Request` (у `Request` ми напряму отримували об’єкт запиту).
+
+{* ../../docs_src/security/tutorial005_an_py310.py hl[9,106] *}
+
+## Використовуйте scopes { #use-the-scopes }
+
+Параметр `security_scopes` матиме тип `SecurityScopes`.
+
+Він матиме властивість `scopes` зі списком, що містить усі scopes, потрібні самій функції та всім залежним, які використовують її як підзалежність. Тобто всім «залежним»... це може звучати заплутано, нижче пояснено ще раз.
+
+Об’єкт `security_scopes` (класу `SecurityScopes`) також надає атрибут `scope_str` з одним рядком, що містить ці scopes, розділені пробілами (ми його використаємо).
+
+Ми створюємо `HTTPException`, який зможемо повторно використати (`raise`) у кількох місцях.
+
+У цьому винятку ми включаємо потрібні scopes (якщо є) як строку, розділену пробілами (використовуючи `scope_str`). Ми поміщаємо цю строку зі scopes в заголовок `WWW-Authenticate` (це частина специфікації).
+
+{* ../../docs_src/security/tutorial005_an_py310.py hl[106,108:116] *}
+
+## Перевірте `username` і структуру даних { #verify-the-username-and-data-shape }
+
+Ми перевіряємо, що отримали `username`, і видобуваємо scopes.
+
+Потім валідовуємо ці дані за допомогою Pydantic-моделі (перехоплюючи виняток `ValidationError`), і якщо виникає помилка читання JWT токена або валідації даних Pydantic, підіймаємо раніше створений `HTTPException`.
+
+Для цього ми оновлюємо Pydantic-модель `TokenData` новою властивістю `scopes`.
+
+Валідувавши дані через Pydantic, ми гарантуємо, що, наприклад, маємо саме `list` із `str` для scopes і `str` для `username`.
+
+Замість, наприклад, `dict` або чогось іншого, що може зламати застосунок далі, створивши ризик безпеки.
+
+Ми також перевіряємо, що існує користувач із цим username, інакше підіймаємо той самий виняток.
+
+{* ../../docs_src/security/tutorial005_an_py310.py hl[47,117:129] *}
+
+## Перевірте `scopes` { #verify-the-scopes }
+
+Тепер перевіряємо, що всі потрібні scopes - для цієї залежності та всіх залежних (включно з операціями шляху) - містяться в scopes, наданих у отриманому токені, інакше підіймаємо `HTTPException`.
+
+Для цього використовуємо `security_scopes.scopes`, що містить `list` із усіма цими scopes як `str`.
+
+{* ../../docs_src/security/tutorial005_an_py310.py hl[130:136] *}
+
+## Дерево залежностей і scopes { #dependency-tree-and-scopes }
+
+Ще раз розгляньмо дерево залежностей і scopes.
+
+Оскільки залежність `get_current_active_user` має підзалежність `get_current_user`, scope «me», оголошений у `get_current_active_user`, буде включений до списку потрібних scopes у `security_scopes.scopes`, переданого до `get_current_user`.
+
+Сама операція шляху також оголошує scope «items», отже він також буде у списку `security_scopes.scopes`, переданому до `get_current_user`.
+
+Ось як виглядає ієрархія залежностей і scopes:
+
+- Операція шляху `read_own_items` має:
+ - Потрібні scopes `["items"]` із залежністю:
+ - `get_current_active_user`:
+ - Функція-залежність `get_current_active_user` має:
+ - Потрібні scopes `["me"]` із залежністю:
+ - `get_current_user`:
+ - Функція-залежність `get_current_user` має:
+ - Власних scopes не потребує.
+ - Залежність, що використовує `oauth2_scheme`.
+ - Параметр `security_scopes` типу `SecurityScopes`:
+ - Цей параметр `security_scopes` має властивість `scopes` із `list`, що містить усі наведені вище scopes, отже:
+ - `security_scopes.scopes` міститиме `["me", "items"]` для операції шляху `read_own_items`.
+ - `security_scopes.scopes` міститиме `["me"]` для операції шляху `read_users_me`, адже він оголошений у залежності `get_current_active_user`.
+ - `security_scopes.scopes` міститиме `[]` (нічого) для операції шляху `read_system_status`, бо вона не оголошує жодного `Security` зі `scopes`, і її залежність `get_current_user` також не оголошує жодних `scopes`.
+
+/// tip | Порада
+
+Важливе і «магічне» тут у тому, що `get_current_user` матиме різні списки `scopes` для перевірки для кожної операції шляху.
+
+Усе залежить від `scopes`, оголошених у кожній операції шляху та кожній залежності в дереві залежностей для конкретної операції шляху.
+
+///
+
+## Більше деталей про `SecurityScopes` { #more-details-about-securityscopes }
+
+Ви можете використовувати `SecurityScopes` у будь-якому місці й у кількох місцях, він не обов’язково має бути в «кореневій» залежності.
+
+Він завжди міститиме scopes безпеки, оголошені в поточних залежностях `Security` і всіх залежних для **цієї конкретної** операції шляху і **цього конкретного** дерева залежностей.
+
+Оскільки `SecurityScopes` міститиме всі scopes, оголошені залежними, ви можете використовувати його, щоб перевірити, що токен має потрібні scopes, у центральній функції-залежності, а потім оголошувати різні вимоги до scopes у різних операціях шляху.
+
+Вони перевірятимуться незалежно для кожної операції шляху.
+
+## Перевірте { #check-it }
+
+Якщо ви відкриєте документацію API, ви зможете автентифікуватися і вказати, які scopes хочете авторизувати.
+
+

+
+Якщо ви не оберете жодного scope, ви будете «автентифіковані», але при спробі доступу до `/users/me/` або `/users/me/items/` отримаєте помилку про недостатні дозволи. Ви все ще матимете доступ до `/status/`.
+
+Якщо оберете scope `me`, але не scope `items`, ви зможете отримати доступ до `/users/me/`, але не до `/users/me/items/`.
+
+Так станеться зі стороннім застосунком, який спробує звернутися до однієї з цих операцій шляху з токеном, наданим користувачем, залежно від того, скільки дозволів користувач надав застосунку.
+
+## Про сторонні інтеграції { #about-third-party-integrations }
+
+У цьому прикладі ми використовуємо «потік паролю» OAuth2.
+
+Це доречно, коли ми входимо у власний застосунок, ймовірно, з власним фронтендом.
+
+Адже ми можемо довіряти йому отримання `username` і `password`, бо ми його контролюємо.
+
+Але якщо ви створюєте OAuth2-застосунок, до якого підключатимуться інші (тобто якщо ви створюєте провайдера автентифікації на кшталт Facebook, Google, GitHub тощо), слід використовувати один з інших потоків.
+
+Найпоширеніший - неявний потік (implicit flow).
+
+Найбезпечніший - потік коду (code flow), але його складніше реалізувати, оскільки він потребує більше кроків. Через складність багато провайдерів у підсумку радять неявний потік.
+
+/// note | Примітка
+
+Часто кожен провайдер автентифікації називає свої потоки по-різному, роблячи це частиною свого бренду.
+
+Але зрештою вони реалізують той самий стандарт OAuth2.
+
+///
+
+**FastAPI** містить утиліти для всіх цих потоків автентифікації OAuth2 у `fastapi.security.oauth2`.
+
+## `Security` у параметрі декоратора `dependencies` { #security-in-decorator-dependencies }
+
+Так само як ви можете визначити `list` із `Depends` у параметрі `dependencies` декоратора (як пояснено в [Залежності в декораторах операцій шляху](../../tutorial/dependencies/dependencies-in-path-operation-decorators.md){.internal-link target=_blank}), ви також можете використовувати там `Security` зі `scopes`.
diff --git a/docs/uk/docs/advanced/settings.md b/docs/uk/docs/advanced/settings.md
new file mode 100644
index 0000000000..dccb4b0911
--- /dev/null
+++ b/docs/uk/docs/advanced/settings.md
@@ -0,0 +1,302 @@
+# Налаштування та змінні оточення { #settings-and-environment-variables }
+
+У багатьох випадках вашому застосунку можуть знадобитися зовнішні налаштування або конфігурації, наприклад секретні ключі, облікові дані бази даних, облікові дані для email-сервісів тощо.
+
+Більшість із цих налаштувань змінні (можуть змінюватися), як-от URL-адреси баз даних. І багато з них можуть бути чутливими, як-от секрети.
+
+З цієї причини поширено надавати їх у змінних оточення, які зчитуються застосунком.
+
+/// tip | Порада
+
+Щоб зрозуміти змінні оточення, ви можете прочитати [Змінні оточення](../environment-variables.md){.internal-link target=_blank}.
+
+///
+
+## Типи та перевірка { #types-and-validation }
+
+Ці змінні оточення можуть містити лише текстові строки, оскільки вони зовнішні до Python і мають бути сумісні з іншими програмами та рештою системи (і навіть з різними операційними системами, як-от Linux, Windows, macOS).
+
+Це означає, що будь-яке значення, прочитане в Python зі змінної оточення, буде `str`, і будь-яке перетворення в інший тип або будь-яка перевірка мають виконуватися в коді.
+
+## Pydantic `Settings` { #pydantic-settings }
+
+На щастя, Pydantic надає чудовий інструмент для обробки цих налаштувань із змінних оточення -
Pydantic: Settings management.
+
+### Встановіть `pydantic-settings` { #install-pydantic-settings }
+
+Спершу переконайтеся, що ви створили [віртуальне оточення](../virtual-environments.md){.internal-link target=_blank}, активували його, а потім встановили пакет `pydantic-settings`:
+
+
+
+```console
+$ pip install pydantic-settings
+---> 100%
+```
+
+
+
+Він також входить у склад, якщо ви встановлюєте додаткові можливості «all» за допомогою:
+
+
+
+```console
+$ pip install "fastapi[all]"
+---> 100%
+```
+
+
+
+### Створіть об'єкт `Settings` { #create-the-settings-object }
+
+Імпортуйте `BaseSettings` із Pydantic і створіть підклас, дуже подібно до моделі Pydantic.
+
+Так само, як і з моделями Pydantic, ви оголошуєте атрибути класу з анотаціями типів і, за потреби, значеннями за замовчуванням.
+
+Ви можете використовувати всі ті самі можливості перевірки та інструменти, що й для моделей Pydantic, як-от різні типи даних і додаткові перевірки з `Field()`.
+
+{* ../../docs_src/settings/tutorial001_py310.py hl[2,5:8,11] *}
+
+/// tip | Порада
+
+Якщо вам потрібно щось швидко скопіювати й вставити, не використовуйте цей приклад, скористайтеся останнім нижче.
+
+///
+
+Потім, коли ви створите екземпляр цього класу `Settings` (у цьому випадку в об'єкті `settings`), Pydantic зчитуватиме змінні оточення без урахування регістру, тож верхньорегістрова змінна `APP_NAME` все одно буде прочитана для атрибута `app_name`.
+
+Далі він перетворить і перевірить дані. Тож коли ви використовуватимете об'єкт `settings`, у вас будуть дані тих типів, які ви оголосили (наприклад, `items_per_user` буде `int`).
+
+### Використовуйте `settings` { #use-the-settings }
+
+Потім ви можете використати новий об'єкт `settings` у вашому застосунку:
+
+{* ../../docs_src/settings/tutorial001_py310.py hl[18:20] *}
+
+### Запустіть сервер { #run-the-server }
+
+Далі ви б запустили сервер, передаючи конфігурації як змінні оточення, наприклад, ви можете встановити `ADMIN_EMAIL` і `APP_NAME` так:
+
+
+
+```console
+$ ADMIN_EMAIL="deadpool@example.com" APP_NAME="ChimichangApp" fastapi run main.py
+
+INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
+```
+
+
+
+/// tip | Порада
+
+Щоб встановити кілька змінних оточення для однієї команди, просто розділіть їх пробілами і розмістіть усі перед командою.
+
+///
+
+Після цього налаштування `admin_email` буде встановлено в `"deadpool@example.com"`.
+
+`app_name` буде `"ChimichangApp"`.
+
+А `items_per_user` збереже своє значення за замовчуванням `50`.
+
+## Налаштування в іншому модулі { #settings-in-another-module }
+
+Ви можете розмістити ці налаштування в іншому модулі, як ви бачили в [Більші застосунки - кілька файлів](../tutorial/bigger-applications.md){.internal-link target=_blank}.
+
+Наприклад, у вас може бути файл `config.py` з:
+
+{* ../../docs_src/settings/app01_py310/config.py *}
+
+А потім використати його у файлі `main.py`:
+
+{* ../../docs_src/settings/app01_py310/main.py hl[3,11:13] *}
+
+/// tip | Порада
+
+Вам також знадобиться файл `__init__.py`, як ви бачили в [Більші застосунки - кілька файлів](../tutorial/bigger-applications.md){.internal-link target=_blank}.
+
+///
+
+## Налаштування як залежність { #settings-in-a-dependency }
+
+Іноді може бути корисно надавати налаштування через залежність, замість того, щоб мати глобальний об'єкт `settings`, який використовується всюди.
+
+Це може бути особливо корисно під час тестування, оскільки дуже легко переписати залежність власними налаштуваннями.
+
+### Файл конфігурації { #the-config-file }
+
+Продовжуючи попередній приклад, ваш файл `config.py` може виглядати так:
+
+{* ../../docs_src/settings/app02_an_py310/config.py hl[10] *}
+
+Зверніть увагу, що тепер ми не створюємо екземпляр за замовчуванням `settings = Settings()`.
+
+### Основний файл застосунку { #the-main-app-file }
+
+Тепер ми створюємо залежність, яка повертає новий `config.Settings()`.
+
+{* ../../docs_src/settings/app02_an_py310/main.py hl[6,12:13] *}
+
+/// tip | Порада
+
+Ми обговоримо `@lru_cache` трохи згодом.
+
+Поки що можете вважати, що `get_settings()` - це звичайна функція.
+
+///
+
+А далі ми можемо вимагати її у *функції операції шляху* як залежність і використовувати будь-де, де це потрібно.
+
+{* ../../docs_src/settings/app02_an_py310/main.py hl[17,19:21] *}
+
+### Налаштування і тестування { #settings-and-testing }
+
+Потім буде дуже просто надати інший об'єкт налаштувань під час тестування, створивши переписування залежності для `get_settings`:
+
+{* ../../docs_src/settings/app02_an_py310/test_main.py hl[9:10,13,21] *}
+
+У переписуванні залежності ми встановлюємо нове значення `admin_email` під час створення нового об'єкта `Settings`, а потім повертаємо цей новий об'єкт.
+
+Після цього ми можемо перевірити, що саме він використовується.
+
+## Читання файлу `.env` { #reading-a-env-file }
+
+Якщо у вас багато налаштувань, які можуть часто змінюватися, можливо в різних оточеннях, може бути корисно розмістити їх у файлі, а потім зчитувати їх із нього так, ніби це змінні оточення.
+
+Ця практика достатньо поширена, тож має назву - ці змінні оточення зазвичай розміщуються у файлі `.env`, а сам файл називається «dotenv».
+
+/// tip | Порада
+
+Файл, що починається з крапки (`.`), є прихованим у системах, подібних до Unix, як-от Linux і macOS.
+
+Але файл dotenv не обов'язково має мати саме таку назву.
+
+///
+
+Pydantic має підтримку читання з таких типів файлів за допомогою зовнішньої бібліотеки. Ви можете дізнатися більше тут:
Pydantic Settings: Dotenv (.env) support.
+
+/// tip | Порада
+
+Щоб це працювало, потрібно виконати `pip install python-dotenv`.
+
+///
+
+### Файл `.env` { #the-env-file }
+
+У вас може бути файл `.env` із вмістом:
+
+```bash
+ADMIN_EMAIL="deadpool@example.com"
+APP_NAME="ChimichangApp"
+```
+
+### Зчитування налаштувань із `.env` { #read-settings-from-env }
+
+Потім оновіть ваш `config.py` так:
+
+{* ../../docs_src/settings/app03_an_py310/config.py hl[9] *}
+
+/// tip | Порада
+
+Атрибут `model_config` використовується лише для конфігурації Pydantic. Докладніше:
Pydantic: Concepts: Configuration.
+
+///
+
+Тут ми визначаємо конфіг `env_file` усередині вашого класу Pydantic `Settings` і задаємо значення - ім'я файла з dotenv, який ми хочемо використати.
+
+### Створення `Settings` лише один раз за допомогою `lru_cache` { #creating-the-settings-only-once-with-lru-cache }
+
+Читання файла з диска зазвичай є дорогою (повільною) операцією, тож, імовірно, ви захочете робити це лише один раз і потім перевикористовувати той самий об'єкт налаштувань замість зчитування для кожного запиту.
+
+Але щоразу, коли ми робимо:
+
+```Python
+Settings()
+```
+
+буде створено новий об'єкт `Settings`, і під час створення він знову зчитуватиме файл `.env`.
+
+Якби функція залежності виглядала так:
+
+```Python
+def get_settings():
+ return Settings()
+```
+
+ми створювали б цей об'єкт для кожного запиту і читали б файл `.env` для кожного запиту. ⚠️
+
+Але оскільки ми використовуємо декоратор `@lru_cache` зверху, об'єкт `Settings` буде створено лише один раз, під час першого виклику. ✔️
+
+{* ../../docs_src/settings/app03_an_py310/main.py hl[1,11] *}
+
+Потім для будь-якого подальшого виклику `get_settings()` у залежностях для наступних запитів, замість виконання внутрішнього коду `get_settings()` і створення нового об'єкта `Settings`, він повертатиме той самий об'єкт, що був повернутий під час першого виклику, знову і знову.
+
+#### Технічні деталі `lru_cache` { #lru-cache-technical-details }
+
+`@lru_cache` модифікує функцію, яку він декорує, так, щоб вона повертала те саме значення, що й уперше, замість повторного обчислення, виконуючи код функції щоразу.
+
+Тобто функція під ним буде виконана один раз для кожної комбінації аргументів. А потім значення, повернені кожною з цих комбінацій аргументів, використовуватимуться знову і знову щоразу, коли функцію викликають із точно такою ж комбінацією аргументів.
+
+Наприклад, якщо у вас є функція:
+
+```Python
+@lru_cache
+def say_hi(name: str, salutation: str = "Ms."):
+ return f"Hello {salutation} {name}"
+```
+
+ваша програма може виконуватись так:
+
+```mermaid
+sequenceDiagram
+
+participant code as Code
+participant function as say_hi()
+participant execute as Execute function
+
+ rect rgba(0, 255, 0, .1)
+ code ->> function: say_hi(name="Camila")
+ function ->> execute: execute function code
+ execute ->> code: return the result
+ end
+
+ rect rgba(0, 255, 255, .1)
+ code ->> function: say_hi(name="Camila")
+ function ->> code: return stored result
+ end
+
+ rect rgba(0, 255, 0, .1)
+ code ->> function: say_hi(name="Rick")
+ function ->> execute: execute function code
+ execute ->> code: return the result
+ end
+
+ rect rgba(0, 255, 0, .1)
+ code ->> function: say_hi(name="Rick", salutation="Mr.")
+ function ->> execute: execute function code
+ execute ->> code: return the result
+ end
+
+ rect rgba(0, 255, 255, .1)
+ code ->> function: say_hi(name="Rick")
+ function ->> code: return stored result
+ end
+
+ rect rgba(0, 255, 255, .1)
+ code ->> function: say_hi(name="Camila")
+ function ->> code: return stored result
+ end
+```
+
+У випадку з нашою залежністю `get_settings()` функція взагалі не приймає жодних аргументів, тож вона завжди повертає те саме значення.
+
+Таким чином, вона поводиться майже так само, якби це була просто глобальна змінна. Але оскільки використовується функція залежності, ми можемо легко переписати її для тестування.
+
+`@lru_cache` є частиною `functools`, що входить до стандартної бібліотеки Python, більше про це можна прочитати в
документації Python для `@lru_cache`.
+
+## Підсумок { #recap }
+
+Ви можете використовувати Pydantic Settings для обробки налаштувань або конфігурацій вашого застосунку, з усією потужністю моделей Pydantic.
+
+- Використовуючи залежність, ви можете спростити тестування.
+- Ви можете використовувати з ним файли `.env`.
+- Використання `@lru_cache` дає змогу уникнути повторного читання файла dotenv для кожного запиту, водночас дозволяючи переписувати його під час тестування.
diff --git a/docs/uk/docs/advanced/sub-applications.md b/docs/uk/docs/advanced/sub-applications.md
new file mode 100644
index 0000000000..5e611c6ff2
--- /dev/null
+++ b/docs/uk/docs/advanced/sub-applications.md
@@ -0,0 +1,67 @@
+# Підзастосунки - монтування { #sub-applications-mounts }
+
+Якщо вам потрібно мати два незалежні застосунки FastAPI з власними незалежними OpenAPI та власними інтерфейсами документації, ви можете мати головний застосунок і «змонтувати» один або кілька підзастосунків.
+
+## Монтування застосунку **FastAPI** { #mounting-a-fastapi-application }
+
+«Монтування» означає додавання повністю «незалежного» застосунку на конкретний шлях, який далі обробляє все під цим шляхом за допомогою _операцій шляху_, оголошених у цьому підзастосунку.
+
+### Застосунок верхнього рівня { #top-level-application }
+
+Спочатку створіть головний, верхньорівневий застосунок **FastAPI** та його _операції шляху_:
+
+{* ../../docs_src/sub_applications/tutorial001_py310.py hl[3, 6:8] *}
+
+### Підзастосунок { #sub-application }
+
+Потім створіть свій підзастосунок та його _операції шляху_.
+
+Цей підзастосунок - просто ще один стандартний застосунок FastAPI, але саме його буде «змонтовано»:
+
+{* ../../docs_src/sub_applications/tutorial001_py310.py hl[11, 14:16] *}
+
+### Змонтуйте підзастосунок { #mount-the-sub-application }
+
+У вашому застосунку верхнього рівня, `app`, змонтуйте підзастосунок `subapi`.
+
+У цьому випадку його буде змонтовано за шляхом `/subapi`:
+
+{* ../../docs_src/sub_applications/tutorial001_py310.py hl[11, 19] *}
+
+### Перевірте автоматичну документацію API { #check-the-automatic-api-docs }
+
+Тепер запустіть команду `fastapi` з вашим файлом:
+
+
+
+```console
+$ fastapi dev main.py
+
+INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
+```
+
+
+
+І відкрийте документацію за адресою
http://127.0.0.1:8000/docs.
+
+Ви побачите автоматичну документацію API для головного застосунку, що містить лише його власні _операції шляху_:
+
+

+
+А потім відкрийте документацію для підзастосунку за адресою
http://127.0.0.1:8000/subapi/docs.
+
+Ви побачите автоматичну документацію API для підзастосунку, що містить лише його власні _операції шляху_, усі з правильним префіксом підшляху `/subapi`:
+
+

+
+Якщо ви спробуєте взаємодіяти з будь-яким із двох інтерфейсів користувача, вони працюватимуть коректно, адже браузер зможе спілкуватися з кожним конкретним застосунком або підзастосунком.
+
+### Технічні деталі: `root_path` { #technical-details-root-path }
+
+Коли ви монтуєте підзастосунок, як описано вище, FastAPI подбає про передачу шляху монтування для підзастосунку, використовуючи механізм зі специфікації ASGI під назвою `root_path`.
+
+Таким чином підзастосунок знатиме, що слід використовувати цей префікс шляху для інтерфейсу документації.
+
+Підзастосунок також може мати власні змонтовані підзастосунки, і все працюватиме коректно, оскільки FastAPI автоматично обробляє всі ці `root_path`.
+
+Ви дізнаєтеся більше про `root_path` і як використовувати його явно в розділі [За представником](behind-a-proxy.md){.internal-link target=_blank}.
diff --git a/docs/uk/docs/advanced/templates.md b/docs/uk/docs/advanced/templates.md
new file mode 100644
index 0000000000..9e1ce3709b
--- /dev/null
+++ b/docs/uk/docs/advanced/templates.md
@@ -0,0 +1,126 @@
+# Шаблони { #templates }
+
+Ви можете використовувати будь-який рушій шаблонів з **FastAPI**.
+
+Поширений вибір - Jinja2, той самий, що використовується у Flask та інших інструментах.
+
+Є утиліти для простої конфігурації, які ви можете використовувати безпосередньо у вашому застосунку **FastAPI** (надає Starlette).
+
+## Встановіть залежності { #install-dependencies }
+
+Переконайтеся, що ви створили [віртуальне оточення](../virtual-environments.md){.internal-link target=_blank}, активували його та встановили `jinja2`:
+
+
+
+```console
+$ pip install jinja2
+
+---> 100%
+```
+
+
+
+## Використання `Jinja2Templates` { #using-jinja2templates }
+
+- Імпортуйте `Jinja2Templates`.
+- Створіть об'єкт `templates`, який ви зможете перевикористовувати.
+- Оголосіть параметр `Request` в *операції шляху*, яка повертатиме шаблон.
+- Використайте створені `templates`, щоб зрендерити та повернути `TemplateResponse`; передайте назву шаблону, об'єкт `request` і словник «контекст» з парами ключ-значення, які будуть використані всередині шаблону Jinja2.
+
+{* ../../docs_src/templates/tutorial001_py310.py hl[4,11,15:18] *}
+
+/// note | Примітка
+
+До FastAPI 0.108.0, Starlette 0.29.0, параметр `name` був першим.
+
+Також раніше, у попередніх версіях, об'єкт `request` передавався як частина пар ключ-значення в контексті для Jinja2.
+
+///
+
+/// tip | Порада
+
+Якщо вказати `response_class=HTMLResponse`, інтерфейс документації знатиме, що відповідь буде HTML.
+
+///
+
+/// note | Технічні деталі
+
+Можна також використати `from starlette.templating import Jinja2Templates`.
+
+**FastAPI** надає той самий `starlette.templating` як `fastapi.templating` просто для зручності для вас, розробника. Але більшість доступних відповідей надходять безпосередньо зі Starlette. Так само з `Request` і `StaticFiles`.
+
+///
+
+## Створення шаблонів { #writing-templates }
+
+Потім ви можете написати шаблон у `templates/item.html`, наприклад:
+
+```jinja hl_lines="7"
+{!../../docs_src/templates/templates/item.html!}
+```
+
+### Значення контексту шаблону { #template-context-values }
+
+У HTML, який містить:
+
+{% raw %}
+
+```jinja
+Item ID: {{ id }}
+```
+
+{% endraw %}
+
+...буде показано `id`, взятий із «контексту» `dict`, який ви передали:
+
+```Python
+{"id": id}
+```
+
+Наприклад, з ID `42` це буде відображено як:
+
+```html
+Item ID: 42
+```
+
+### Аргументи `url_for` у шаблоні { #template-url-for-arguments }
+
+Ви також можете використовувати `url_for()` у шаблоні - вона приймає ті самі аргументи, що й ваша *функція операції шляху*.
+
+Тож фрагмент:
+
+{% raw %}
+
+```jinja
+
+```
+
+{% endraw %}
+
+...згенерує посилання на той самий URL, який оброблятиме *функція операції шляху* `read_item(id=id)`.
+
+Наприклад, з ID `42` це буде відображено як:
+
+```html
+
+```
+
+## Шаблони і статичні файли { #templates-and-static-files }
+
+Ви також можете використовувати `url_for()` у шаблоні, наприклад з `StaticFiles`, які ви змонтували з `name="static"`.
+
+```jinja hl_lines="4"
+{!../../docs_src/templates/templates/item.html!}
+```
+
+У цьому прикладі це посилатиметься на файл CSS у `static/styles.css` за допомогою:
+
+```CSS hl_lines="4"
+{!../../docs_src/templates/static/styles.css!}
+```
+
+І оскільки ви використовуєте `StaticFiles`, цей файл CSS буде автоматично обслуговуватись вашим застосунком **FastAPI** за URL `/static/styles.css`.
+
+## Детальніше { #more-details }
+
+Докладніше, зокрема як тестувати шаблони, дивіться документацію Starlette щодо шаблонів.
diff --git a/docs/uk/docs/advanced/testing-dependencies.md b/docs/uk/docs/advanced/testing-dependencies.md
new file mode 100644
index 0000000000..3061e745d3
--- /dev/null
+++ b/docs/uk/docs/advanced/testing-dependencies.md
@@ -0,0 +1,53 @@
+# Тестування залежностей з переписуваннями { #testing-dependencies-with-overrides }
+
+## Переписування залежностей під час тестування { #overriding-dependencies-during-testing }
+
+Є сценарії, коли ви можете захотіти переписати залежність під час тестування.
+
+Ви не хочете запускати оригінальну залежність (ані будь-які її підзалежності).
+
+Натомість ви хочете надати іншу залежність, яку буде використано лише під час тестів (можливо, тільки в окремих тестах), і яка повертатиме значення, що підставляється всюди, де раніше використовувалося значення оригінальної залежності.
+
+### Випадки використання: зовнішній сервіс { #use-cases-external-service }
+
+Наприклад, у вас є зовнішній постачальник автентифікації, який потрібно викликати.
+
+Ви надсилаєте йому токен, і він повертає автентифікованого користувача.
+
+Такий постачальник може стягувати плату за кожний запит, а виклик може займати більше часу, ніж використання фіксованого фальшивого користувача для тестів.
+
+Ймовірно, ви хочете протестувати зовнішнього постачальника один раз, але не обов'язково викликати його для кожного тесту.
+
+У такому разі ви можете переписати залежність, що викликає цього постачальника, і використати власну залежність, яка повертає фальшивого користувача, лише для ваших тестів.
+
+### Використовуйте атрибут `app.dependency_overrides` { #use-the-app-dependency-overrides-attribute }
+
+Для таких випадків ваш застосунок FastAPI має атрибут `app.dependency_overrides`, це простий `dict`.
+
+Щоб переписати залежність для тестування, вкажіть у ключі оригінальну залежність (функцію), а значенням - ваше переписування залежності (іншу функцію).
+
+Після цього FastAPI викликатиме це переписування замість оригінальної залежності.
+
+{* ../../docs_src/dependency_testing/tutorial001_an_py310.py hl[26:27,30] *}
+
+/// tip | Порада
+
+Ви можете налаштувати переписування для залежності, яка використовується де завгодно у вашому застосунку FastAPI.
+
+Оригінальна залежність може використовуватися у функції операції шляху, у декораторі операції шляху (коли ви не використовуєте повернуте значення), у виклику `.include_router()` тощо.
+
+FastAPI усе одно зможе її переписати.
+
+///
+
+Потім ви можете скинути переписування (видалити їх), встановивши для `app.dependency_overrides` порожній `dict`:
+
+```Python
+app.dependency_overrides = {}
+```
+
+/// tip | Порада
+
+Якщо ви хочете переписувати залежність лише під час окремих тестів, встановіть переписування на початку тесту (всередині тестової функції) і скиньте його наприкінці (в кінці тестової функції).
+
+///
diff --git a/docs/uk/docs/advanced/testing-events.md b/docs/uk/docs/advanced/testing-events.md
new file mode 100644
index 0000000000..040b4f756f
--- /dev/null
+++ b/docs/uk/docs/advanced/testing-events.md
@@ -0,0 +1,11 @@
+# Тестування подій: тривалість життя та запуск - вимкнення { #testing-events-lifespan-and-startup-shutdown }
+
+Коли вам потрібно, щоб `lifespan` виконувався у ваших тестах, ви можете використати `TestClient` з оператором `with`:
+
+{* ../../docs_src/app_testing/tutorial004_py310.py hl[9:15,18,27:28,30:32,41:43] *}
+
+Ви можете прочитати більше у [«Запуск тривалості життя у тестах на офіційному сайті документації Starlette.»](https://www.starlette.dev/lifespan/#running-lifespan-in-tests)
+
+Для застарілих подій `startup` і `shutdown` ви можете використовувати `TestClient` так:
+
+{* ../../docs_src/app_testing/tutorial003_py310.py hl[9:12,20:24] *}
diff --git a/docs/uk/docs/advanced/testing-websockets.md b/docs/uk/docs/advanced/testing-websockets.md
new file mode 100644
index 0000000000..cec576fddf
--- /dev/null
+++ b/docs/uk/docs/advanced/testing-websockets.md
@@ -0,0 +1,13 @@
+# Тестування WebSocket { #testing-websockets }
+
+Ви можете використовувати той самий `TestClient` для тестування WebSocket.
+
+Для цього використайте `TestClient` в інструкції `with`, підключаючись до WebSocket:
+
+{* ../../docs_src/app_testing/tutorial002_py310.py hl[27:31] *}
+
+/// note | Примітка
+
+Докладніше дивіться документацію Starlette з
тестування WebSocket.
+
+///
diff --git a/docs/uk/docs/advanced/using-request-directly.md b/docs/uk/docs/advanced/using-request-directly.md
new file mode 100644
index 0000000000..81b90f19b9
--- /dev/null
+++ b/docs/uk/docs/advanced/using-request-directly.md
@@ -0,0 +1,55 @@
+# Використання Request безпосередньо { #using-the-request-directly }
+
+Дотепер ви оголошували потрібні вам частини запиту разом з їх типами.
+
+Отримуючи дані з:
+- шляху як параметрів;
+- заголовків;
+- кукі;
+- тощо.
+
+І таким чином **FastAPI** перевіряє ці дані, перетворює їх і автоматично генерує документацію для вашого API.
+
+Але бувають ситуації, коли може знадобитися доступ до об'єкта `Request` безпосередньо.
+
+## Деталі про об'єкт `Request` { #details-about-the-request-object }
+
+Оскільки під капотом **FastAPI** - це **Starlette** з шаром інструментів зверху, ви можете за потреби використовувати
об'єкт `Request` Starlette безпосередньо.
+
+Це також означає, що якщо ви отримуєте дані безпосередньо з об'єкта `Request` (наприклад, читаєте тіло), FastAPI не буде їх перевіряти, перетворювати або документувати (через OpenAPI для автоматичного інтерфейсу користувача API).
+
+Водночас будь-який інший параметр, оголошений звичайним способом (наприклад, тіло з моделлю Pydantic), і надалі буде перевірений, перетворений, анотований тощо.
+
+Але є окремі випадки, коли корисно отримати об'єкт `Request`.
+
+## Використовуйте об'єкт `Request` безпосередньо { #use-the-request-object-directly }
+
+Припустімо, ви хочете отримати IP-адресу/хост клієнта всередині вашої функції операції шляху.
+
+Для цього потрібно звернутися до запиту безпосередньо.
+
+{* ../../docs_src/using_request_directly/tutorial001_py310.py hl[1,7:8] *}
+
+Якщо вказати у функції операції шляху параметр типу `Request`, **FastAPI** передасть у нього об'єкт `Request`.
+
+/// tip | Порада
+
+Зауважте, що в цьому прикладі ми оголошуємо параметр шляху поряд із параметром запиту.
+
+Тому параметр шляху буде витягнуто, перевірено, перетворено до вказаного типу та анотовано в OpenAPI.
+
+Так само ви можете оголошувати будь-які інші параметри звичайним чином і додатково отримувати `Request`.
+
+///
+
+## Документація `Request` { #request-documentation }
+
+Докладніше про
об'єкт `Request` на офіційному сайті документації Starlette.
+
+/// note | Технічні деталі
+
+Ви також можете використати `from starlette.requests import Request`.
+
+**FastAPI** надає його безпосередньо як зручність для вас, розробника. Але він походить безпосередньо із Starlette.
+
+///
diff --git a/docs/uk/docs/advanced/websockets.md b/docs/uk/docs/advanced/websockets.md
new file mode 100644
index 0000000000..21bb61d7e9
--- /dev/null
+++ b/docs/uk/docs/advanced/websockets.md
@@ -0,0 +1,186 @@
+# WebSockets { #websockets }
+
+Ви можете використовувати
WebSockets з **FastAPI**.
+
+## Встановіть `websockets` { #install-websockets }
+
+Переконайтеся, що ви створили [віртуальне оточення](../virtual-environments.md){.internal-link target=_blank}, активували його та встановили `websockets` (бібліотеку Python, що полегшує використання протоколу «WebSocket»):
+
+
+
+```console
+$ pip install websockets
+
+---> 100%
+```
+
+
+
+## Клієнт WebSockets { #websockets-client }
+
+### У продакшені { #in-production }
+
+У вашій продакшен-системі у вас, напевно, є фронтенд, створений за допомогою сучасного фреймворку на кшталт React, Vue.js або Angular.
+
+Для спілкування через WebSockets з бекендом ви, ймовірно, використовуватимете утиліти вашого фронтенду.
+
+Або у вас може бути нативний мобільний застосунок, що напряму спілкується з вашим WebSocket-бекендом нативним кодом.
+
+Або будь-який інший спосіб спілкування з кінцевою точкою WebSocket.
+
+---
+
+Але для цього прикладу ми використаємо дуже простий HTML-документ з невеликим JavaScript, усе всередині довгого рядка.
+
+Звісно, це не оптимально і ви б не використовували це у продакшені.
+
+У продакшені ви б використали один з варіантів вище.
+
+Але це найпростіший спосіб зосередитися на серверній частині WebSockets і мати робочий приклад:
+
+{* ../../docs_src/websockets/tutorial001_py310.py hl[2,6:38,41:43] *}
+
+## Створіть `websocket` { #create-a-websocket }
+
+У вашому застосунку **FastAPI** створіть `websocket`:
+
+{* ../../docs_src/websockets/tutorial001_py310.py hl[1,46:47] *}
+
+/// note | Технічні деталі
+
+Ви також можете використати `from starlette.websockets import WebSocket`.
+
+**FastAPI** надає той самий `WebSocket` напряму як зручність для вас, розробника. Але він походить безпосередньо зі Starlette.
+
+///
+
+## Очікуйте повідомлення та надсилайте повідомлення { #await-for-messages-and-send-messages }
+
+У вашому маршруті WebSocket ви можете `await` повідомлення і надсилати повідомлення.
+
+{* ../../docs_src/websockets/tutorial001_py310.py hl[48:52] *}
+
+Ви можете отримувати та надсилати бінарні, текстові та JSON-дані.
+
+## Спробуйте { #try-it }
+
+Якщо ваш файл називається `main.py`, запустіть ваш застосунок командою:
+
+
+
+```console
+$ fastapi dev main.py
+
+INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
+```
+
+
+
+Відкрийте у браузері
http://127.0.0.1:8000.
+
+Ви побачите просту сторінку на кшталт:
+
+

+
+Ви можете вводити повідомлення у поле вводу та надсилати їх:
+
+

+
+І ваш застосунок **FastAPI** з WebSockets відповість:
+
+

+
+Ви можете надсилати (і отримувати) багато повідомлень:
+
+

+
+І всі вони використовуватимуть те саме з'єднання WebSocket.
+
+## Використання `Depends` та іншого { #using-depends-and-others }
+
+У кінцевих точках WebSocket ви можете імпортувати з `fastapi` і використовувати:
+
+* `Depends`
+* `Security`
+* `Cookie`
+* `Header`
+* `Path`
+* `Query`
+
+Вони працюють так само, як для інших ендпойнтів FastAPI/*операцій шляху*:
+
+{* ../../docs_src/websockets/tutorial002_an_py310.py hl[68:69,82] *}
+
+/// info
+
+Оскільки це WebSocket, не має сенсу піднімати `HTTPException`, натомість ми піднімаємо `WebSocketException`.
+
+Ви можете використати код закриття з
чинних кодів, визначених у специфікації.
+
+///
+
+### Спробуйте WebSockets із залежностями { #try-the-websockets-with-dependencies }
+
+Якщо ваш файл називається `main.py`, запустіть ваш застосунок командою:
+
+
+
+```console
+$ fastapi dev main.py
+
+INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
+```
+
+
+
+Відкрийте у браузері
http://127.0.0.1:8000.
+
+Там ви можете встановити:
+
+* «Item ID», який використовується у шляху.
+* «Token», який використовується як параметр запиту.
+
+/// tip
+
+Зверніть увагу, що параметр запиту `token` буде оброблено залежністю.
+
+///
+
+Після цього ви зможете під'єднати WebSocket, а далі надсилати й отримувати повідомлення:
+
+

+
+## Обробка відключень і кількох клієнтів { #handling-disconnections-and-multiple-clients }
+
+Коли з'єднання WebSocket закривається, `await websocket.receive_text()` підніме виняток `WebSocketDisconnect`, який ви можете перехопити й обробити, як у цьому прикладі.
+
+{* ../../docs_src/websockets/tutorial003_py310.py hl[79:81] *}
+
+Щоб спробувати:
+
+* Відкрийте застосунок у кількох вкладках браузера.
+* Надсилайте з них повідомлення.
+* Потім закрийте одну з вкладок.
+
+Це підніме виняток `WebSocketDisconnect`, і всі інші клієнти отримають повідомлення на кшталт:
+
+```
+Client #1596980209979 left the chat
+```
+
+/// tip
+
+Застосунок вище - це мінімальний і простий приклад, що демонструє, як обробляти та розсилати повідомлення кільком з'єднанням WebSocket.
+
+Але майте на увазі, що оскільки все обробляється в пам'яті, в одному списку, це працюватиме лише поки процес запущений, і лише з одним процесом.
+
+Якщо вам потрібне щось просте для інтеграції з FastAPI, але більш надійне, з підтримкою Redis, PostgreSQL чи інших, перегляньте
encode/broadcaster.
+
+///
+
+## Детальніше { #more-info }
+
+Щоб дізнатися більше про можливості, перегляньте документацію Starlette:
+
+*
Клас `WebSocket`.
+*
Обробка WebSocket на основі класів.
diff --git a/docs/uk/docs/advanced/wsgi.md b/docs/uk/docs/advanced/wsgi.md
new file mode 100644
index 0000000000..8969241350
--- /dev/null
+++ b/docs/uk/docs/advanced/wsgi.md
@@ -0,0 +1,51 @@
+# Підключення WSGI - Flask, Django та інші { #including-wsgi-flask-django-others }
+
+Ви можете монтувати застосунки WSGI, як ви бачили в [Підзастосунки - монтування](sub-applications.md){.internal-link target=_blank}, [За представником](behind-a-proxy.md){.internal-link target=_blank}.
+
+Для цього ви можете використати `WSGIMiddleware` і обгорнути ним ваш застосунок WSGI, наприклад Flask, Django тощо.
+
+## Використання `WSGIMiddleware` { #using-wsgimiddleware }
+
+/// info | Інформація
+
+Для цього потрібно встановити `a2wsgi`, наприклад за допомогою `pip install a2wsgi`.
+
+///
+
+Потрібно імпортувати `WSGIMiddleware` з `a2wsgi`.
+
+Потім обгорніть застосунок WSGI (напр., Flask) цим проміжним програмним забезпеченням.
+
+І змонтуйте його під певним шляхом.
+
+{* ../../docs_src/wsgi/tutorial001_py310.py hl[1,3,23] *}
+
+/// note | Примітка
+
+Раніше рекомендувалося використовувати `WSGIMiddleware` з `fastapi.middleware.wsgi`, але тепер його визнано застарілим.
+
+Замість цього радимо використовувати пакет `a2wsgi`. Використання залишається таким самим.
+
+Просто переконайтеся, що у вас встановлено пакет `a2wsgi`, і імпортуйте `WSGIMiddleware` коректно з `a2wsgi`.
+
+///
+
+## Перевірте { #check-it }
+
+Тепер кожен запит за шляхом `/v1/` оброблятиметься застосунком Flask.
+
+А решта - **FastAPI**.
+
+Якщо ви запустите це й перейдете на
http://localhost:8000/v1/, ви побачите відповідь від Flask:
+
+```txt
+Hello, World from Flask!
+```
+
+А якщо ви перейдете на
http://localhost:8000/v2, ви побачите відповідь від FastAPI:
+
+```JSON
+{
+ "message": "Hello World"
+}
+```
diff --git a/docs/uk/docs/alternatives.md b/docs/uk/docs/alternatives.md
index d44ca794f8..5dbf8a96ba 100644
--- a/docs/uk/docs/alternatives.md
+++ b/docs/uk/docs/alternatives.md
@@ -58,9 +58,9 @@ Flask — це «мікрофреймворк», він не включає ін
/// check | Надихнуло **FastAPI** на
-Бути мікрофреймоворком. Зробити легким комбінування та поєднання необхідних інструментів та частин.
+Бути мікрофреймворком. Зробити легким комбінування та поєднання необхідних інструментів та частин.
- Мати просту та легку у використанні систему маршрутизації.
+Мати просту та легку у використанні систему маршрутизації.
///
@@ -100,9 +100,9 @@ def read_url():
/// check | Надихнуло **FastAPI** на
-* Майте простий та інтуїтивно зрозумілий API.
-* Використовуйте імена (операції) методів HTTP безпосередньо, простим та інтуїтивно зрозумілим способом.
-* Розумні параметри за замовчуванням, але потужні налаштування.
+* Мати простий та інтуїтивно зрозумілий API.
+* Використовувати імена (операції) методів HTTP безпосередньо, простим та інтуїтивно зрозумілим способом.
+* Мати розумні параметри за замовчуванням, але потужні налаштування.
///
@@ -122,12 +122,12 @@ def read_url():
Прийняти і використовувати відкритий стандарт для специфікацій API замість спеціальної схеми.
- Інтегрувати інструменти інтерфейсу на основі стандартів:
+Інтегрувати інструменти інтерфейсу на основі стандартів:
*
Інтерфейс Swagger
*
ReDoc
- Ці два було обрано через те, що вони досить популярні та стабільні, але, виконавши швидкий пошук, ви можете знайти десятки додаткових альтернативних інтерфейсів для OpenAPI (які можна використовувати з **FastAPI**).
+Ці два було обрано через те, що вони досить популярні та стабільні, але, виконавши швидкий пошук, ви можете знайти десятки додаткових альтернативних інтерфейсів для OpenAPI (які можна використовувати з **FastAPI**).
///
@@ -137,7 +137,7 @@ def read_url():
###
Marshmallow { #marshmallow }
-Однією з головних функцій, необхідних для систем API, є "
серіалізація", яка бере дані з коду (Python) і перетворює їх на щось, що можна надіслати через мережу. Наприклад, перетворення об’єкта, що містить дані з бази даних, на об’єкт JSON. Перетворення об’єктів `datetime` на строки тощо.
+Однією з головних функцій, необхідних для систем API, є "
серіалізація", яка бере дані з коду (Python) і перетворює їх на щось, що можна надіслати через мережу. Наприклад, перетворення об’єкта, що містить дані з бази даних, на об’єкт JSON. Перетворення об’єктів `datetime` на строки тощо.
Іншою важливою функцією, необхідною для API, є перевірка даних, яка забезпечує дійсність даних за певними параметрами. Наприклад, що деяке поле є `int`, а не деяка випадкова строка. Це особливо корисно для вхідних даних.
@@ -145,7 +145,7 @@ def read_url():
Marshmallow створено для забезпечення цих функцій. Це чудова бібліотека, і я часто нею користувався раніше.
-Але він був створений до того, як існували підказки типу Python. Отже, щоб визначити кожну
схему, вам потрібно використовувати спеціальні утиліти та класи, надані Marshmallow.
+Але він був створений до того, як існували підказки типу Python. Отже, щоб визначити кожну
схему, вам потрібно використовувати спеціальні утиліти та класи, надані Marshmallow.
/// check | Надихнуло **FastAPI** на
@@ -155,7 +155,7 @@ Marshmallow створено для забезпечення цих функці
###
Webargs { #webargs }
-Іншою важливою функцією, необхідною для API, є
аналіз даних із вхідних запитів.
+Іншою важливою функцією, необхідною для API, є
аналіз даних із вхідних запитів.
Webargs — це інструмент, створений, щоб забезпечити це поверх кількох фреймворків, включаючи Flask.
@@ -217,7 +217,7 @@ APISpec був створений тими ж розробниками Marshmall
Ця комбінація Flask, Flask-apispec із Marshmallow і Webargs була моїм улюбленим бекенд-стеком до створення **FastAPI**.
-Їі використання призвело до створення кількох генераторів повного стека Flask. Це основний стек, який я (та кілька зовнішніх команд) використовував досі:
+Її використання призвело до створення кількох генераторів повного стека Flask. Це основний стек, який я (та кілька зовнішніх команд) використовував досі:
*
https://github.com/tiangolo/full-stack
*
https://github.com/tiangolo/full-stack-flask-couchbase
@@ -255,7 +255,7 @@ Flask-apispec був створений тими ж розробниками Mar
Використовувати типи Python, щоб мати чудову підтримку редактора.
- Мати потужну систему впровадження залежностей. Знайдіть спосіб звести до мінімуму повторення коду.
+Мати потужну систему впровадження залежностей. Знайдіть спосіб звести до мінімуму повторення коду.
///
@@ -267,7 +267,7 @@ Flask-apispec був створений тими ж розробниками Mar
Він використовував
`uvloop` замість стандартного циклу Python `asyncio`. Ось що зробило його таким швидким.
- Це явно надихнуло Uvicorn і Starlette, які зараз швидші за Sanic у відкритих тестах.
+Це явно надихнуло Uvicorn і Starlette, які зараз швидші за Sanic у відкритих тестах.
///
@@ -275,7 +275,7 @@ Flask-apispec був створений тими ж розробниками Mar
Знайти спосіб отримати божевільну продуктивність.
- Ось чому **FastAPI** базується на Starlette, оскільки це найшвидша доступна структура (перевірена тестами сторонніх розробників).
+Ось чому **FastAPI** базується на Starlette, оскільки це найшвидша доступна структура (перевірена тестами сторонніх розробників).
///
@@ -291,9 +291,9 @@ Falcon — ще один високопродуктивний фреймворк
Знайти способи отримати чудову продуктивність.
- Разом із Hug (оскільки Hug базується на Falcon) надихнув **FastAPI** оголосити параметр `response` у функціях.
+Разом із Hug (оскільки Hug базується на Falcon) надихнув **FastAPI** оголосити параметр `response` у функціях.
- Хоча у FastAPI це необов’язково, і використовується в основному для встановлення заголовків, файлів cookie та альтернативних кодів стану.
+Хоча у FastAPI це необов’язково, і використовується в основному для встановлення заголовків, файлів cookie та альтернативних кодів статусу.
///
@@ -317,7 +317,7 @@ Falcon — ще один високопродуктивний фреймворк
Визначити додаткові перевірки для типів даних, використовуючи значення "за замовчуванням" атрибутів моделі. Це покращує підтримку редактора, а раніше вона була недоступна в Pydantic.
- Це фактично надихнуло оновити частини Pydantic, щоб підтримувати той самий стиль оголошення перевірки (всі ці функції вже доступні в Pydantic).
+Це фактично надихнуло оновити частини Pydantic, щоб підтримувати той самий стиль оголошення перевірки (всі ці функції вже доступні в Pydantic).
///
@@ -341,13 +341,13 @@ Hug створив Тімоті Крослі, той самий творець <
///
-/// check | Надихнуло **FastAPI** на
+/// check | Ідеї, що надихнули **FastAPI**
Hug надихнув частину APIStar і був одним із найбільш перспективних інструментів, поряд із APIStar.
- Hug надихнув **FastAPI** на використання підказок типу Python для оголошення параметрів і автоматичного створення схеми, що визначає API.
+Hug надихнув **FastAPI** на використання підказок типу Python для оголошення параметрів і автоматичного створення схеми, що визначає API.
- Hug надихнув **FastAPI** оголосити параметр `response` у функціях для встановлення заголовків і файлів cookie.
+Hug надихнув **FastAPI** оголосити параметр `response` у функціях для встановлення заголовків і файлів cookie.
///
@@ -389,13 +389,13 @@ APIStar створив Том Крісті. Той самий хлопець, я
Існувати.
- Ідею оголошення кількох речей (перевірки даних, серіалізації та документації) за допомогою тих самих типів Python, які в той же час забезпечували чудову підтримку редактора, я вважав геніальною ідеєю.
+Ідею оголошення кількох речей (перевірки даних, серіалізації та документації) за допомогою тих самих типів Python, які в той же час забезпечували чудову підтримку редактора, я вважав геніальною ідеєю.
- І після тривалого пошуку подібної структури та тестування багатьох різних альтернатив, APIStar став найкращим доступним варіантом.
+І після тривалого пошуку подібної структури та тестування багатьох різних альтернатив, APIStar став найкращим доступним варіантом.
- Потім APIStar перестав існувати як сервер, і було створено Starlette, який став новою кращою основою для такої системи. Це стало останнім джерелом натхнення для створення **FastAPI**.
+Потім APIStar перестав існувати як сервер, і було створено Starlette, який став новою кращою основою для такої системи. Це стало останнім джерелом натхнення для створення **FastAPI**.
- Я вважаю **FastAPI** «духовним спадкоємцем» APIStar, удосконалюючи та розширюючи функції, систему типізації та інші частини на основі досвіду, отриманого від усіх цих попередніх інструментів.
+Я вважаю **FastAPI** «духовним спадкоємцем» APIStar, удосконалюючи та розширюючи функції, систему типізації та інші частини на основі досвіду, отриманого від усіх цих попередніх інструментів.
///
@@ -403,7 +403,7 @@ APIStar створив Том Крісті. Той самий хлопець, я
###
Pydantic { #pydantic }
-Pydantic — це бібліотека для визначення перевірки даних, серіалізації та документації (за допомогою схеми JSON) на основі підказок типу Python.
+Pydantic — це бібліотека для визначення перевірки даних, серіалізації та документації (за допомогою Схеми JSON) на основі підказок типу Python.
Це робить його надзвичайно інтуїтивним.
@@ -411,15 +411,15 @@ Pydantic — це бібліотека для визначення переві
/// check | **FastAPI** використовує його для
-Виконання перевірки всіх даних, серіалізації даних і автоматичної документацію моделі (на основі схеми JSON).
+Виконання перевірки всіх даних, серіалізації даних і автоматичної документації моделі (на основі Схеми JSON).
- Потім **FastAPI** бере ці дані схеми JSON і розміщує їх у OpenAPI, окремо від усіх інших речей, які він робить.
+Потім **FastAPI** бере ці дані Схеми JSON і розміщує їх у OpenAPI, окремо від усіх інших речей, які він робить.
///
###
Starlette { #starlette }
-Starlette — це легкий фреймворк/набір інструментів
ASGI, який ідеально підходить для створення високопродуктивних asyncio сервісів.
+Starlette — це легкий фреймворк/набір інструментів
ASGI, який ідеально підходить для створення високопродуктивних asyncio сервісів.
Він дуже простий та інтуїтивно зрозумілий. Його розроблено таким чином, щоб його можна було легко розширювати та мати модульні компоненти.
@@ -448,7 +448,7 @@ Starlette надає всі основні функції веб-мікрофр
ASGI — це новий «стандарт», який розробляється членами основної команди Django. Це ще не «стандарт Python» (PEP), хоча вони в процесі цього.
- Тим не менш, він уже використовується як «стандарт» кількома інструментами. Це значно покращує сумісність, оскільки ви можете переключити Uvicorn на будь-який інший сервер ASGI (наприклад, Daphne або Hypercorn), або ви можете додати інструменти, сумісні з ASGI, як-от `python-socketio`.
+Тим не менш, він уже використовується як «стандарт» кількома інструментами. Це значно покращує сумісність, оскільки ви можете переключити Uvicorn на будь-який інший сервер ASGI (наприклад, Daphne або Hypercorn), або ви можете додати інструменти, сумісні з ASGI, як-от `python-socketio`.
///
@@ -456,9 +456,9 @@ ASGI — це новий «стандарт», який розробляєтьс
Керування всіма основними веб-частинами. Додавання функцій зверху.
- Сам клас `FastAPI` безпосередньо успадковує клас `Starlette`.
+Сам клас `FastAPI` безпосередньо успадковує клас `Starlette`.
- Отже, усе, що ви можете робити зі Starlette, ви можете робити це безпосередньо за допомогою **FastAPI**, оскільки це, по суті, Starlette на стероїдах.
+Отже, усе, що ви можете робити зі Starlette, ви можете робити це безпосередньо за допомогою **FastAPI**, оскільки це, по суті, Starlette на стероїдах.
///
@@ -474,9 +474,9 @@ Uvicorn — це блискавичний сервер ASGI, побудован
Основний веб-сервер для запуску програм **FastAPI**.
- Ви також можете використати параметр командного рядка `--workers`, щоб мати асинхронний багатопроцесний сервер.
+Ви також можете використати параметр командного рядка `--workers`, щоб мати асинхронний багатопроцесний сервер.
- Додаткову інформацію див. у розділі [Розгортання](deployment/index.md){.internal-link target=_blank}.
+Додаткову інформацію див. у розділі [Розгортання](deployment/index.md){.internal-link target=_blank}.
///
diff --git a/docs/uk/docs/async.md b/docs/uk/docs/async.md
new file mode 100644
index 0000000000..baf4720542
--- /dev/null
+++ b/docs/uk/docs/async.md
@@ -0,0 +1,444 @@
+# Рівночасність і async / await { #concurrency-and-async-await }
+
+Деталі щодо синтаксису `async def` для функцій операції шляху і деякі відомості про асинхронний код, рівночасність і паралелізм.
+
+## Поспішаєте? { #in-a-hurry }
+
+
TL;DR:
+
+Якщо ви використовуєте сторонні бібліотеки, які вимагають виклику з `await`, наприклад:
+
+```Python
+results = await some_library()
+```
+
+Тоді оголошуйте ваші функції операції шляху з `async def`, наприклад:
+
+```Python hl_lines="2"
+@app.get('/')
+async def read_results():
+ results = await some_library()
+ return results
+```
+
+/// note | Примітка
+
+Ви можете використовувати `await` лише всередині функцій, створених з `async def`.
+
+///
+
+---
+
+Якщо ви використовуєте сторонню бібліотеку, яка взаємодіє з чимось (база даних, API, файлова система тощо) і не підтримує використання `await` (наразі це стосується більшості бібліотек баз даних), тоді оголошуйте ваші функції операції шляху як зазвичай, просто з `def`, наприклад:
+
+```Python hl_lines="2"
+@app.get('/')
+def results():
+ results = some_library()
+ return results
+```
+
+---
+
+Якщо ваш застосунок (якимось чином) не має комунікувати з чимось іншим і чекати на відповідь, використовуйте `async def`, навіть якщо вам не потрібно використовувати `await` всередині.
+
+---
+
+Якщо ви не певні, використовуйте звичайний `def`.
+
+---
+
+Примітка: ви можете змішувати `def` і `async def` у ваших функціях операції шляху скільки завгодно і визначати кожну з них найкращим для вас способом. FastAPI зробить з ними все правильно.
+
+У будь-якому з наведених випадків FastAPI все одно працюватиме асинхронно і буде надзвичайно швидким.
+
+Але слідуючи крокам вище, він зможе зробити деякі оптимізації продуктивності.
+
+## Технічні деталі { #technical-details }
+
+Сучасні версії Python мають підтримку «асинхронного коду» за допомогою так званих «співпрограм» з синтаксисом **`async` і `await`**.
+
+Розгляньмо цю фразу по частинах у секціях нижче:
+
+- Асинхронний код
+- `async` і `await`
+- Співпрограми
+
+## Асинхронний код { #asynchronous-code }
+
+Асинхронний код означає, що мова 💬 має спосіб сказати комп’ютеру/програмі 🤖, що в певний момент у коді він 🤖 має почекати, поки «щось інше» завершиться десь ще. Скажімо, це «щось інше» називається «slow-file» 📝.
+
+Отже, в цей час комп’ютер може піти і зробити іншу роботу, доки «slow-file» 📝 завершується.
+
+Далі комп’ютер/програма 🤖 повертатиметься щоразу, коли матиме можливість, бо знову чекає, або коли він 🤖 завершив усю роботу, яка була в нього на той момент. І він 🤖 перевірить, чи якась із задач, на які він чекав, уже завершилася, виконавши все, що потрібно.
+
+Потім він 🤖 бере першу завершену задачу (скажімо, наш «slow-file» 📝) і продовжує робити те, що потрібно було зробити з нею.
+
+Це «чекати на щось інше» зазвичай стосується операцій
I/O, які відносно «повільні» (порівняно зі швидкістю процесора та пам’яті з довільним доступом), наприклад, очікування:
+
+- даних від клієнта, що надсилаються мережею
+- даних, надісланих вашим застосунком, які клієнт має отримати мережею
+- вмісту файла на диску, який система має прочитати і передати вашому застосунку
+- вмісту, який ваш застосунок передав системі, щоб він був записаний на диск
+- віддаленої операції API
+- завершення операції бази даних
+- повернення результатів запиту до бази даних
+- тощо
+
+Оскільки час виконання переважно витрачається на очікування операцій
I/O, їх називають операціями «I/O bound».
+
+Це називається «асинхронним», тому що комп’ютеру/програмі не потрібно бути «синхронізованими» з повільною задачею, очікуючи точного моменту її завершення, нічого не роблячи, лише щоб отримати результат задачі та продовжити роботу.
+
+Натомість, у «асинхронній» системі щойно завершена задача може трохи зачекати в черзі (кілька мікросекунд), доки комп’ютер/програма завершить те, що пішов робити, а потім повернеться, щоб забрати результати і продовжити роботу з ними.
+
+Для «синхронного» (на противагу «асинхронному») часто також використовують термін «послідовний», бо комп’ютер/програма слідує всім крокам послідовно, перш ніж перемкнутися на іншу задачу, навіть якщо ці кроки включають очікування.
+
+### Рівночасність і бургери { #concurrency-and-burgers }
+
+Ідею **асинхронного** коду, описану вище, інколи також називають **«рівночасністю»**. Вона відрізняється від **«паралелізму»**.
+
+І рівночасність, і паралелізм стосуються «різних речей, що відбуваються більш-менш одночасно».
+
+Але деталі між рівночасністю і паралелізмом досить різні.
+
+Щоб побачити різницю, уявімо таку історію про бургери:
+
+### Рівночасні бургери { #concurrent-burgers }
+
+Ви йдете зі своєю симпатією по фастфуд, стаєте в чергу, доки касир приймає замовлення у людей перед вами. 😍
+
+

+
+Потім ваша черга, ви замовляєте 2 дуже вишукані бургери для вашої симпатії і для себе. 🍔🍔
+
+

+
+Касир каже щось кухарю на кухні, щоб той знав, що треба приготувати ваші бургери (хоча зараз він готує бургери для попередніх клієнтів).
+
+

+
+Ви платите. 💸
+
+Касир дає вам номер вашої черги.
+
+

+
+Поки ви чекаєте, ви з вашою симпатією обираєте столик, сідаєте і довго розмовляєте (адже ваші бургери дуже вишукані і потребують часу на приготування).
+
+Сидячи за столиком із вашою симпатією, доки чекаєте бургери, ви можете витратити цей час, милуючись тим, яка ваша симпатія класна, мила і розумна ✨😍✨.
+
+

+
+Чекаючи і спілкуючись із вашою симпатією, час від часу ви перевіряєте номер на табло біля прилавка, щоб побачити, чи вже ваша черга.
+
+І от нарешті ваша черга. Ви підходите до прилавка, забираєте бургери і повертаєтеся до столика.
+
+

+
+Ви з вашою симпатією їсте бургери і гарно проводите час. ✨
+
+

+
+/// info | Інформація
+
+Прекрасні ілюстрації від
Ketrina Thompson. 🎨
+
+///
+
+---
+
+Уявіть, що в цій історії ви - комп’ютер/програма 🤖.
+
+Поки ви в черзі, ви просто бездіяльні 😴, чекаєте своєї черги, нічого «продуктивного» не роблячи. Але черга рухається швидко, бо касир лише приймає замовлення (а не готує їх), тож це нормально.
+
+Коли ж ваша черга, ви виконуєте справді «продуктивну» роботу: переглядаєте меню, вирішуєте, що бажаєте, дізнаєтеся вибір вашої симпатії, платите, перевіряєте, що віддаєте правильну купюру чи картку, що з вас правильно списали кошти, що замовлення містить правильні позиції тощо.
+
+Але потім, хоча у вас ще немає бургерів, ваша взаємодія з касиром «на паузі» ⏸, бо вам доводиться чекати 🕙, поки бургери будуть готові.
+
+Втім, відійшовши від прилавка і сівши за столик із номерком, ви можете перемкнути 🔀 увагу на свою симпатію і «попрацювати» ⏯ 🤓 над цим. Тоді ви знову робите щось дуже «продуктивне» - фліртуєте зі своєю симпатією 😍.
+
+Потім касир 💁 каже «Я закінчив робити бургери», виводячи ваш номер на табло прилавка, але ви не підстрибуєте миттєво, щойно номер змінюється на ваш. Ви знаєте, що ніхто не вкраде ваші бургери, адже у вас є номер вашої черги, а в інших - свій.
+
+Тож ви чекаєте, поки ваша симпатія завершить історію (завершить поточну роботу ⏯/задачу 🤓), лагідно усміхаєтеся і кажете, що підете за бургерами ⏸.
+
+Потім ви йдете до прилавка 🔀, до початкової задачі, яку тепер завершено ⏯, забираєте бургери, дякуєте і несете їх до столу. Це завершує той крок/задачу взаємодії з прилавком ⏹. Натомість з’являється нова задача «їсти бургери» 🔀 ⏯, але попередня «отримати бургери» завершена ⏹.
+
+### Паралельні бургери { #parallel-burgers }
+
+А тепер уявімо, що це не «рівночасні бургери», а «паралельні бургери».
+
+Ви йдете зі своєю симпатією по паралельний фастфуд.
+
+Ви стаєте в чергу, поки кілька (скажімо, 8) касирів, які водночас є кухарями, приймають замовлення у людей перед вами.
+
+Кожен перед вами чекає, поки його бургери будуть готові, перш ніж відійти від прилавка, тому що кожен з 8 касирів одразу йде і готує бургер, перш ніж приймати наступне замовлення.
+
+

+
+Нарешті ваша черга, ви замовляєте 2 дуже вишукані бургери для вашої симпатії і для себе.
+
+Ви платите 💸.
+
+

+
+Касир іде на кухню.
+
+Ви чекаєте, стоячи перед прилавком 🕙, щоб ніхто інший не забрав ваші бургери раніше, ніж ви, адже номерків черги немає.
+
+

+
+Оскільки ви з вашою симпатією зайняті тим, щоб ніхто не став перед вами і не забрав ваші бургери, щойно вони з’являться, ви не можете приділяти увагу своїй симпатії. 😞
+
+Це «синхронна» робота, ви «синхронізовані» з касиром/кухарем 👨🍳. Вам доводиться чекати 🕙 і бути тут у точний момент, коли касир/кухар 👨🍳 завершить бургери і віддасть їх вам, інакше хтось інший може їх забрати.
+
+

+
+Потім ваш касир/кухар 👨🍳 нарешті повертається з вашими бургерами після довгого очікування 🕙 перед прилавком.
+
+

+
+Ви берете бургери і йдете до столика зі своєю симпатією.
+
+Ви просто їх їсте - і все. ⏹
+
+

+
+Багато розмов чи флірту не було, бо більшість часу пішла на очікування 🕙 перед прилавком. 😞
+
+/// info | Інформація
+
+Прекрасні ілюстрації від
Ketrina Thompson. 🎨
+
+///
+
+---
+
+У цьому сценарії паралельних бургерів ви - комп’ютер/програма 🤖 з двома процесорами (ви і ваша симпатія), які обидва чекають 🕙 і приділяють увагу ⏯ «очікуванню біля прилавка» 🕙 тривалий час.
+
+У закладу фастфуду 8 процесорів (касира/кухаря). У той час як у закладі з рівночасними бургерами могло бути лише 2 (один касир і один кухар).
+
+Та все одно фінальний досвід не найкращий. 😞
+
+---
+
+Це була б паралельна історія про бургери. 🍔
+
+Для більш «реального» прикладу уявіть банк.
+
+До недавнього часу більшість банків мали кілька касирів 👨💼👨💼👨💼👨💼 і велику чергу 🕙🕙🕙🕙🕙🕙🕙🕙.
+
+Усі касири робили всю роботу з одним клієнтом за іншим 👨💼⏯.
+
+І вам доводилося 🕙 довго стояти в черзі, інакше ви втратите свою чергу.
+
+Ви, напевно, не хотіли б брати свою симпатію 😍 із собою у справи до банку 🏦.
+
+### Висновок про бургери { #burger-conclusion }
+
+У цьому сценарії «фастфуд із вашою симпатією», оскільки є багато очікування 🕙, значно доцільніше мати рівночасну систему ⏸🔀⏯.
+
+Так є у більшості вебзастосунків.
+
+Багато-багато користувачів, але ваш сервер чекає 🕙 на їхнє не надто гарне з’єднання, щоб вони надіслали свої запити.
+
+А потім знову чекає 🕙 на повернення відповідей.
+
+Це «очікування» 🕙 вимірюється у мікросекундах, але все ж, у сумі - це багато очікування в підсумку.
+
+Ось чому дуже логічно використовувати асинхронний ⏸🔀⏯ код для веб API.
+
+Такий тип асинхронності зробив NodeJS популярним (хоча NodeJS не є паралельним), і це сила Go як мови програмування.
+
+І такий самий рівень продуктивності ви отримуєте з **FastAPI**.
+
+А оскільки можна мати паралелізм і асинхронність одночасно, ви отримуєте вищу продуктивність, ніж більшість протестованих фреймворків NodeJS, і на рівні з Go, який є компільованою мовою, ближчою до C
(усе завдяки Starlette).
+
+### Чи краща рівночасність за паралелізм? { #is-concurrency-better-than-parallelism }
+
+Ні! Це не мораль історії.
+
+Рівночасність відрізняється від паралелізму. І вона краща у конкретних сценаріях, що містять багато очікування. Через це зазвичай вона значно краща за паралелізм для розробки вебзастосунків. Але не для всього.
+
+Щоб урівноважити це, уявімо коротку історію:
+
+> Ви маєте прибрати великий брудний будинок.
+
+*Так, це вся історія*.
+
+---
+
+Тут немає очікування 🕙 - просто багато роботи, яку треба зробити, у багатьох місцях будинку.
+
+У вас могли б бути «черги» як у прикладі з бургерами: спочатку вітальня, потім кухня. Але оскільки ви ні на що не чекаєте 🕙, а просто прибираєте, «черги» нічого не змінять.
+
+Завершення займе той самий час із «чергами» чи без (рівночасність), і ви виконаєте той самий обсяг роботи.
+
+Але в цьому випадку, якби ви могли привести 8 колишніх касирів/кухарів/тепер прибиральників, і кожен з них (разом із вами) взяв би свою зону будинку для прибирання, ви могли б виконати всю роботу паралельно — з додатковою допомогою — і завершити значно швидше.
+
+У цьому сценарії кожен з прибиральників (включно з вами) був би процесором, що виконує свою частину роботи.
+
+І оскільки більшість часу виконання займає реальна робота (а не очікування), а роботу на комп’ютері виконує
CPU, ці проблеми називають «CPU bound».
+
+---
+
+Поширені приклади «CPU bound» операцій - це речі, що потребують складної математичної обробки.
+
+Наприклад:
+
+- **Обробка аудіо** або **зображень**.
+- **Комп’ютерний зір**: зображення складається з мільйонів пікселів, кожен піксель має 3 значення/кольори, обробка зазвичай потребує обчислення чогось над цими пікселями, усіма одночасно.
+- **Машинне навчання**: зазвичай потребує великої кількості множень «матриць» і «векторів». Уявіть величезну таблицю з числами і множення всіх їх разом одночасно.
+- **Глибоке навчання**: це підгалузь машинного навчання, тож те саме застосовується. Просто тут не одна таблиця чисел для множення, а величезний їх набір, і в багатьох випадках ви використовуєте спеціальний процесор для побудови та/або використання цих моделей.
+
+### Рівночасність + паралелізм: веб + машинне навчання { #concurrency-parallelism-web-machine-learning }
+
+З **FastAPI** ви можете скористатися рівночасністю, що дуже поширена у веброзробці (та ж головна принада NodeJS).
+
+Але ви також можете використати переваги паралелізму і багатопроцесорності (наявність кількох процесів, що працюють паралельно) для навантажень «CPU bound», як у системах машинного навчання.
+
+Це, плюс простий факт, що Python є основною мовою для **Data Science**, машинного навчання і особливо глибокого навчання, робить FastAPI дуже вдалим вибором для веб API та застосунків Data Science / машинного навчання (серед багатьох інших).
+
+Щоб побачити, як досягти цього паралелізму у продакшні, див. розділ про [Розгортання](deployment/index.md){.internal-link target=_blank}.
+
+## `async` і `await` { #async-and-await }
+
+Сучасні версії Python мають дуже інтуїтивний спосіб визначення асинхронного коду. Це робить його схожим на звичайний «послідовний» код і виконує «очікування» за вас у відповідні моменти.
+
+Коли є операція, яка вимагатиме очікування перед поверненням результатів і має підтримку цих нових можливостей Python, ви можете написати її так:
+
+```Python
+burgers = await get_burgers(2)
+```
+
+Ключ тут - `await`. Він каже Python, що потрібно почекати ⏸, поки `get_burgers(2)` завершить свою роботу 🕙, перш ніж зберегти результати в `burgers`. Завдяки цьому Python знатиме, що може піти і зробити щось інше 🔀 ⏯ тим часом (наприклад, прийняти інший запит).
+
+Щоб `await` працював, він має бути всередині функції, що підтримує цю асинхронність. Для цього просто оголосіть її як `async def`:
+
+```Python hl_lines="1"
+async def get_burgers(number: int):
+ # Виконайте деякі асинхронні дії, щоб створити бургери
+ return burgers
+```
+
+...замість `def`:
+
+```Python hl_lines="2"
+# Це не асинхронно
+def get_sequential_burgers(number: int):
+ # Виконайте деякі послідовні дії, щоб створити бургери
+ return burgers
+```
+
+З `async def` Python знає, що всередині цієї функції він має відслідковувати вирази `await`, і що він може «ставити на паузу» ⏸ виконання цієї функції і йти робити щось інше 🔀, перш ніж повернутися.
+
+Коли ви хочете викликати функцію, визначену з `async def`, ви маєте «очікувати» її. Тож це не спрацює:
+
+```Python
+# Це не спрацює, тому що get_burgers визначено як: async def
+burgers = get_burgers(2)
+```
+
+---
+
+Отже, якщо ви використовуєте бібліотеку, яку можна викликати з `await`, вам потрібно створити функцію операції шляху, що її використовує, з `async def`, як тут:
+
+```Python hl_lines="2-3"
+@app.get('/burgers')
+async def read_burgers():
+ burgers = await get_burgers(2)
+ return burgers
+```
+
+### Більше технічних деталей { #more-technical-details }
+
+Ви могли помітити, що `await` можна використовувати лише всередині функцій, визначених з `async def`.
+
+А водночас функції, визначені з `async def`, потрібно «очікувати». Тож функції з `async def` також можна викликати лише всередині функцій, визначених з `async def`.
+
+Тож як же викликати першу `async`-функцію - курка чи яйце?
+
+Якщо ви працюєте з **FastAPI**, вам не потрібно про це турбуватися, адже цією «першою» функцією буде ваша функція операції шляху, і FastAPI знатиме, як учинити правильно.
+
+Але якщо ви хочете використовувати `async` / `await` без FastAPI, ви також можете це зробити.
+
+### Пишемо свій власний async-код { #write-your-own-async-code }
+
+Starlette (і **FastAPI**) базуються на
AnyIO, що робить їх сумісними як зі стандартною бібліотекою Python
asyncio, так і з
Trio.
+
+Зокрема, ви можете безпосередньо використовувати
AnyIO для ваших просунутих сценаріїв рівночасності, що потребують складніших патернів у вашому коді.
+
+І навіть якщо ви не використовували FastAPI, ви могли б писати свої власні async-застосунки з
AnyIO, щоб мати високу сумісність і отримати його переваги (наприклад, *структурована рівночасність*).
+
+Я створив іншу бібліотеку поверх AnyIO, як тонкий шар, щоб дещо покращити анотації типів і отримати кращу **автодопомогу** (autocompletion), **вбудовані помилки** (inline errors) тощо. Вона також має дружній вступ і навчальний посібник, щоб допомогти вам **зрозуміти** і написати **власний async-код**:
Asyncer. Вона буде особливо корисною, якщо вам потрібно **поєднувати async-код зі звичайним** (блокуючим/синхронним) кодом.
+
+### Інші форми асинхронного коду { #other-forms-of-asynchronous-code }
+
+Такий стиль використання `async` і `await` відносно новий у мові.
+
+Але він значно полегшує роботу з асинхронним кодом.
+
+Такий самий (або майже ідентичний) синтаксис нещодавно з’явився в сучасних версіях JavaScript (у Browser і NodeJS).
+
+До цього робота з асинхронним кодом була значно складнішою.
+
+У попередніх версіях Python ви могли використовувати потоки (threads) або
Gevent. Але код набагато складніший для розуміння, налагодження і мислення про нього.
+
+У попередніх версіях NodeJS/Browser JavaScript ви б використовували «callbacks», що призводить до «callback hell».
+
+## Співпрограми { #coroutines }
+
+**Співпрограма** - це просто дуже вишукана назва для об’єкта, який повертає функція `async def`. Python знає, що це щось на кшталт функції, яку можна запустити і яка завершиться в певний момент, але яку також можна поставити на паузу ⏸ всередині, коли є `await`.
+
+Але всю цю функціональність використання асинхронного коду з `async` і `await` часто підсумовують як використання «співпрограм». Це порівняно з головною ключовою особливістю Go - «Goroutines».
+
+## Висновок { #conclusion }
+
+Погляньмо на ту саму фразу ще раз:
+
+> Сучасні версії Python мають підтримку «асинхронного коду» за допомогою так званих «співпрограм», з синтаксисом **`async` і `await`**.
+
+Тепер це має більше сенсу. ✨
+
+Усе це приводить у дію FastAPI (через Starlette) і дає йому таку вражаючу продуктивність.
+
+## Дуже технічні деталі { #very-technical-details }
+
+/// warning | Попередження
+
+Ймовірно, ви можете пропустити це.
+
+Це дуже технічні деталі про те, як **FastAPI** працює «під капотом».
+
+Якщо у вас є чимало технічних знань (співпрограми, потоки, блокування тощо) і вам цікаво, як FastAPI обробляє `async def` проти звичайного `def`, - вперед.
+
+///
+
+### Функції операції шляху { #path-operation-functions }
+
+Коли ви оголошуєте функцію операції шляху зі звичайним `def` замість `async def`, вона виконується у зовнішньому пулі потоків (threadpool), який потім «очікується», замість прямого виклику (оскільки прямий виклик блокував би сервер).
+
+Якщо ви прийшли з іншого async-фреймворку, який не працює так, як описано вище, і звикли визначати тривіальні, лише обчислювальні функції операції шляху зі звичайним `def` заради крихітного виграшу у продуктивності (близько 100 наносекунд), зверніть увагу, що у **FastAPI** ефект буде протилежним. У таких випадках краще використовувати `async def`, якщо тільки ваші функції операції шляху не використовують код, що виконує блокуюче
I/O.
+
+Втім, у будь-якій ситуації є велика ймовірність, що **FastAPI** [все одно буде швидшим](index.md#performance){.internal-link target=_blank} (або принаймні порівнянним) за ваш попередній фреймворк.
+
+### Залежності { #dependencies }
+
+Те саме стосується і [залежностей](tutorial/dependencies/index.md){.internal-link target=_blank}. Якщо залежність є стандартною функцією `def` замість `async def`, вона виконується у зовнішньому пулі потоків.
+
+### Підзалежності { #sub-dependencies }
+
+Ви можете мати кілька залежностей і [підзалежностей](tutorial/dependencies/sub-dependencies.md){.internal-link target=_blank}, які вимагають одна одну (як параметри визначень функцій). Деякі з них можуть бути створені з `async def`, а деякі - зі звичайним `def`. Все працюватиме, і ті, що створені зі звичайним `def`, будуть викликані у зовнішньому потоці (з пулу потоків), а не «очікувані».
+
+### Інші допоміжні функції { #other-utility-functions }
+
+Будь-яка інша допоміжна функція, яку ви викликаєте безпосередньо, може бути створена зі звичайним `def` або `async def`, і FastAPI не впливатиме на спосіб її виклику.
+
+Це відрізняється від функцій, які FastAPI викликає за вас: функції операції шляху і залежності.
+
+Якщо ваша допоміжна функція є звичайною функцією з `def`, її буде викликано безпосередньо (як ви написали у своєму коді), не в пулі потоків; якщо функція створена з `async def`, тоді вам слід використовувати `await` при її виклику у вашому коді.
+
+---
+
+Знову ж таки, це дуже технічні деталі, які, ймовірно, стануть у пригоді, якщо ви спеціально їх шукали.
+
+Інакше вам вистачить настанов із розділу вище:
Поспішаєте?.
diff --git a/docs/uk/docs/benchmarks.md b/docs/uk/docs/benchmarks.md
new file mode 100644
index 0000000000..d53b7ee989
--- /dev/null
+++ b/docs/uk/docs/benchmarks.md
@@ -0,0 +1,34 @@
+# Бенчмарки { #benchmarks }
+
+Незалежні бенчмарки TechEmpower показують, що застосунки FastAPI, запущені під керуванням Uvicorn, є
одним із найшвидших доступних фреймворків Python, поступаючись лише самим Starlette і Uvicorn (використовуються FastAPI внутрішньо).
+
+Але переглядаючи бенчмарки та порівняння, майте на увазі таке.
+
+## Бенчмарки та швидкість { #benchmarks-and-speed }
+
+Під час перегляду бенчмарків часто порівнюють кілька інструментів різних типів як рівноцінні.
+
+Зокрема, разом порівнюють Uvicorn, Starlette і FastAPI (серед багатьох інших інструментів).
+
+Чим простіше завдання, яке розв'язує інструмент, тим кращою буде продуктивність. І більшість бенчмарків не перевіряють додаткові можливості, що надає інструмент.
+
+Ієрархія приблизно така:
+
+* Uvicorn: сервер ASGI
+ * Starlette: (використовує Uvicorn) веб-мікрофреймворк
+ * FastAPI: (використовує Starlette) мікрофреймворк для API з низкою додаткових можливостей для створення API, з валідацією даних тощо.
+
+* Uvicorn:
+ * Матиме найвищу продуктивність, адже майже не містить додаткового коду окрім власне сервера.
+ * Ви не писатимете застосунок безпосередньо на Uvicorn. Це означало б, що ваш код мав би включати принаймні приблизно весь код, який надає Starlette (або FastAPI). І якщо зробити так, ваш кінцевий застосунок матиме ті самі накладні витрати, що й під час використання фреймворку, який мінімізує код застосунку та помилки.
+ * Якщо ви порівнюєте Uvicorn, порівнюйте його з Daphne, Hypercorn, uWSGI тощо. Сервери застосунків.
+* Starlette:
+ * Матиме наступну за швидкістю продуктивність після Uvicorn. Насправді Starlette використовує Uvicorn для запуску. Тож вона може бути «повільнішою» за Uvicorn лише через необхідність виконувати більше коду.
+ * Але надає інструменти для створення простих веб-застосунків із маршрутизацією на основі шляхів тощо.
+ * Якщо ви порівнюєте Starlette, порівнюйте її з Sanic, Flask, Django тощо. Веб-фреймворки (або мікрофреймворки).
+* FastAPI:
+ * Аналогічно до того, як Starlette використовує Uvicorn і не може бути швидшою за нього, FastAPI використовує Starlette, тож не може бути швидшою за неї.
+ * FastAPI надає більше можливостей поверх Starlette. Можливості, які майже завжди потрібні під час створення API, як-от валідація та серіалізація даних. І, використовуючи його, ви безкоштовно отримуєте автоматичну документацію (автоматична документація навіть не додає накладних витрат під час роботи застосунку - вона генерується під час запуску).
+ * Якби ви не використовували FastAPI і застосували Starlette безпосередньо (або інший інструмент, наприклад Sanic, Flask, Responder тощо), вам довелося б самостійно реалізувати всю валідацію та серіалізацію даних. Тож ваш кінцевий застосунок усе одно мав би ті самі накладні витрати, ніби він був створений із використанням FastAPI. І в багатьох випадках саме ця валідація та серіалізація даних становить найбільший обсяг коду в застосунках.
+ * Отже, використовуючи FastAPI, ви заощаджуєте час розробки, зменшуєте кількість помилок і рядків коду та, ймовірно, отримуєте таку саму (або кращу) продуктивність, як і без нього (адже інакше вам довелося б реалізувати все це у власному коді).
+ * Якщо ви порівнюєте FastAPI, порівнюйте його з веб-фреймворком (або набором інструментів), який надає валідацію даних, серіалізацію та документацію, наприклад Flask-apispec, NestJS, Molten тощо. Фреймворки з вбудованою автоматичною валідацією даних, серіалізацією та документацією.
diff --git a/docs/uk/docs/deployment/cloud.md b/docs/uk/docs/deployment/cloud.md
new file mode 100644
index 0000000000..a17aaf2591
--- /dev/null
+++ b/docs/uk/docs/deployment/cloud.md
@@ -0,0 +1,24 @@
+# Розгортання FastAPI у хмарних постачальників { #deploy-fastapi-on-cloud-providers }
+
+Ви можете використовувати практично **будь-якого хмарного постачальника**, щоб розгорнути свій застосунок FastAPI.
+
+У більшості випадків основні хмарні постачальники мають інструкції з розгортання FastAPI у них.
+
+## FastAPI Cloud { #fastapi-cloud }
+
+**
FastAPI Cloud** створено тим самим автором і командою, що стоять за **FastAPI**.
+
+Воно спрощує процес **створення**, **розгортання** та **доступу** до API з мінімальними зусиллями.
+
+Воно переносить той самий **досвід розробника** зі створення застосунків із FastAPI на їх **розгортання** у хмарі. 🎉
+
+FastAPI Cloud є основним спонсором і джерелом фінансування проєктів з відкритим кодом *FastAPI and friends*. ✨
+
+## Хмарні постачальники - спонсори { #cloud-providers-sponsors }
+
+Деякі інші хмарні постачальники ✨ [**спонсорують FastAPI**](../help-fastapi.md#sponsor-the-author){.internal-link target=_blank} ✨ також. 🙇
+
+Можливо, ви захочете розглянути їх, щоб дотримуватися їхніх інструкцій і спробувати їхні сервіси:
+
+*
Render
+*
Railway
diff --git a/docs/uk/docs/deployment/concepts.md b/docs/uk/docs/deployment/concepts.md
new file mode 100644
index 0000000000..07ad314405
--- /dev/null
+++ b/docs/uk/docs/deployment/concepts.md
@@ -0,0 +1,321 @@
+# Концепції розгортання { #deployments-concepts }
+
+Під час розгортання застосунку **FastAPI** (або будь-якого веб-API) є кілька концепцій, які, ймовірно, вас цікавлять, і, спираючись на них, ви зможете знайти **найвідповідніший** спосіб **розгорнути ваш застосунок**.
+
+Деякі важливі концепції:
+
+- Безпека - HTTPS
+- Запуск під час старту
+- Перезапуски
+- Реплікація (кількість запущених процесів)
+- Пам'ять
+- Попередні кроки перед стартом
+
+Подивимось, як вони впливають на **розгортання**.
+
+Зрештою головна мета - **обслуговувати клієнтів вашого API** так, щоб це було **безпечним**, з **мінімумом перерв у роботі**, і щоб **обчислювальні ресурси** (наприклад, віддалені сервери/віртуальні машини) використовувалися якомога ефективніше. 🚀
+
+Нижче я трохи більше розповім про ці **концепції**, і, сподіваюся, це дасть вам потрібну **інтуїцію**, щоб вирішувати, як розгортати ваш API в дуже різних середовищах, можливо, навіть у **майбутніх**, яких ще не існує.
+
+Враховуючи ці концепції, ви зможете **оцінювати та проєктувати** найкращий спосіб розгортання **ваших власних API**.
+
+У наступних розділах я наведу більш **конкретні рецепти** розгортання застосунків FastAPI.
+
+А поки перегляньмо ці важливі **концептуальні ідеї**. Вони також застосовні до будь-якого іншого типу веб-API. 💡
+
+## Безпека - HTTPS { #security-https }
+
+У [попередньому розділі про HTTPS](https.md){.internal-link target=_blank} ми дізналися, як HTTPS забезпечує шифрування для вашого API.
+
+Ми також бачили, що HTTPS зазвичай надається компонентом, **зовнішнім** щодо вашого серверного застосунку, - **TLS Termination Proxy**.
+
+І має бути щось, що відповідає за **оновлення сертифікатів HTTPS** - це може бути той самий компонент або інший.
+
+### Приклади інструментів для HTTPS { #example-tools-for-https }
+
+Деякі інструменти, які можна використовувати як TLS Termination Proxy:
+
+- Traefik
+ - Автоматично обробляє оновлення сертифікатів ✨
+- Caddy
+ - Автоматично обробляє оновлення сертифікатів ✨
+- Nginx
+ - З зовнішнім компонентом на кшталт Certbot для оновлення сертифікатів
+- HAProxy
+ - З зовнішнім компонентом на кшталт Certbot для оновлення сертифікатів
+- Kubernetes з Ingress Controller, наприклад Nginx
+ - З зовнішнім компонентом на кшталт cert-manager для оновлення сертифікатів
+- Обробляється внутрішньо хмарним провайдером як частина їхніх сервісів (див. нижче 👇)
+
+Ще один варіант - використати **хмарний сервіс**, який зробить більше роботи, зокрема налаштує HTTPS. Можуть бути обмеження або додаткова вартість тощо. Але у такому разі вам не потрібно самостійно налаштовувати TLS Termination Proxy.
+
+У наступних розділах я покажу кілька конкретних прикладів.
+
+---
+
+Далі всі наступні концепції стосуються програми, яка запускає ваш фактичний API (наприклад, Uvicorn).
+
+## Програма і процес { #program-and-process }
+
+Ми багато говоритимемо про запущений «процес», тож корисно чітко розуміти, що це означає, і чим відрізняється від слова «програма».
+
+### Що таке програма { #what-is-a-program }
+
+Слово **програма** зазвичай вживають для опису багатьох речей:
+
+- **Код**, який ви пишете, **файли Python**.
+- **Файл**, який може бути **виконаний** операційною системою, наприклад: `python`, `python.exe` або `uvicorn`.
+- Конкретна програма під час **виконання** в операційній системі, що використовує CPU та зберігає дані в пам'яті. Це також називають **процесом**.
+
+### Що таке процес { #what-is-a-process }
+
+Слово **процес** зазвичай використовують у більш специфічному значенні, маючи на увазі саме те, що виконується в операційній системі (як у попередньому пункті):
+
+- Конкретна програма під час **виконання** в операційній системі.
+ - Це не про файл і не про код, це **конкретно** про те, що **виконується** та керується операційною системою.
+- Будь-яка програма, будь-який код **може щось робити** лише під час **виконання**. Тобто коли **процес запущений**.
+- Процес може бути **завершений** (або «kill») вами чи операційною системою. У цей момент він припиняє виконання і **більше нічого не може робити**.
+- Кожен застосунок, який працює на вашому комп'ютері, має певний процес за собою: кожна запущена програма, кожне вікно тощо. Зазвичай на комп'ютері одночасно працює **багато процесів**.
+- **Кілька процесів** **однієї й тієї самої програми** можуть працювати одночасно.
+
+Якщо ви відкриєте «диспетчер завдань» або «системний монітор» (чи подібні інструменти) в операційній системі, ви побачите багато таких процесів.
+
+Наприклад, ви, ймовірно, побачите кілька процесів того самого браузера (Firefox, Chrome, Edge тощо). Зазвичай він запускає один процес на вкладку плюс деякі додаткові процеси.
+
+

+
+---
+
+Тепер, коли ми знаємо різницю між термінами **процес** і **програма**, продовжимо говорити про розгортання.
+
+## Запуск під час старту { #running-on-startup }
+
+У більшості випадків, коли ви створюєте веб-API, ви хочете, щоб він **працював постійно**, без перерв, щоб клієнти завжди мали до нього доступ. Звісно, якщо немає особливих причин запускати його лише в певних ситуаціях. Але зазвичай ви хочете, щоб він постійно працював і був **доступний**.
+
+### На віддаленому сервері { #in-a-remote-server }
+
+Коли ви налаштовуєте віддалений сервер (хмарний сервер, віртуальну машину тощо), найпростіше - використовувати `fastapi run` (який використовує Uvicorn) або щось схоже, вручну, так само, як під час локальної розробки.
+
+І це працюватиме та буде корисним **під час розробки**.
+
+Але якщо ви втратите з'єднання з сервером, **запущений процес**, найімовірніше, завершиться.
+
+І якщо сервер буде перезавантажено (наприклад, після оновлень або міграцій у хмарного провайдера), ви, ймовірно, **не помітите цього**. І через це ви навіть не знатимете, що треба вручну перезапустити процес. У результаті ваш API просто залишиться «мертвим». 😱
+
+### Автоматичний запуск під час старту { #run-automatically-on-startup }
+
+Загалом ви, напевно, захочете, щоб серверна програма (наприклад, Uvicorn) запускалася автоматично під час старту сервера і без будь-якого **людського втручання**, щоб завжди був запущений процес із вашим API (наприклад, Uvicorn із вашим FastAPI-застосунком).
+
+### Окрема програма { #separate-program }
+
+Щоб цього досягти, зазвичай використовують **окрему програму**, яка гарантує запуск вашого застосунку під час старту. І в багатьох випадках вона також забезпечує запуск інших компонентів або застосунків, наприклад бази даних.
+
+### Приклади інструментів для запуску під час старту { #example-tools-to-run-at-startup }
+
+Приклади інструментів, які можуть це робити:
+
+- Docker
+- Kubernetes
+- Docker Compose
+- Docker у режимі Swarm
+- Systemd
+- Supervisor
+- Обробляється внутрішньо хмарним провайдером як частина їхніх сервісів
+- Інші...
+
+У наступних розділах я наведу більш конкретні приклади.
+
+## Перезапуски { #restarts }
+
+Подібно до забезпечення запуску застосунку під час старту системи, ви, ймовірно, також захочете гарантувати його **перезапуск** після збоїв.
+
+### Ми помиляємося { #we-make-mistakes }
+
+Ми, люди, постійно робимо **помилки**. Майже завжди у програмному забезпеченні є приховані **помилки**. 🐛
+
+І ми як розробники постійно покращуємо код, знаходячи ці помилки та додаючи нові можливості (можливо, теж додаючи нові помилки 😅).
+
+### Невеликі помилки обробляються автоматично { #small-errors-automatically-handled }
+
+Створюючи веб-API з FastAPI, якщо в нашому коді є помилка, FastAPI зазвичай обмежує її одним запитом, який цю помилку спровокував. 🛡
+
+Клієнт отримає **500 Internal Server Error** для цього запиту, але застосунок продовжить працювати для наступних запитів замість повного краху.
+
+### Великі помилки - крахи { #bigger-errors-crashes }
+
+Втім, бувають випадки, коли ми пишемо код, який **падає весь застосунок**, спричиняючи крах Uvicorn і Python. 💥
+
+І все ж ви, ймовірно, не захочете, щоб застосунок залишався «мертвим» через помилку в одному місці - ви, напевно, хочете, щоб він **продовжував працювати** принаймні для тих *операцій шляху*, що не зламані.
+
+### Перезапуск після краху { #restart-after-crash }
+
+Але в таких випадках із серйозними помилками, що призводять до краху запущеного **процесу**, потрібен зовнішній компонент, відповідальний за **перезапуск** процесу, принаймні кілька разів...
+
+/// tip | Порада
+
+...Хоча якщо весь застосунок просто **миттєво падає**, безглуздо перезапускати його безкінечно. Але в таких випадках ви, ймовірно, помітите це під час розробки або принаймні відразу після розгортання.
+
+Тож зосередьмося на основних випадках, коли у майбутньому він може повністю падати за певних обставин, і тоді все ще має сенс його перезапускати.
+
+///
+
+Ймовірно, ви захочете мати відокремлений **зовнішній компонент**, який відповідає за перезапуск застосунку, адже до того моменту сам застосунок з Uvicorn і Python уже впав, і нічого в тому ж коді цієї ж програми зробити не зможе.
+
+### Приклади інструментів для автоматичного перезапуску { #example-tools-to-restart-automatically }
+
+У більшості випадків той самий інструмент, який використовується для **запуску програми під час старту**, також використовується для автоматичних **перезапусків**.
+
+Наприклад, це можуть забезпечувати:
+
+- Docker
+- Kubernetes
+- Docker Compose
+- Docker у режимі Swarm
+- Systemd
+- Supervisor
+- Обробляється внутрішньо хмарним провайдером як частина їхніх сервісів
+- Інші...
+
+## Реплікація - процеси та пам'ять { #replication-processes-and-memory }
+
+У застосунку FastAPI, використовуючи серверну програму, як-от команду `fastapi`, що запускає Uvicorn, один запуск в **одному процесі** може обслуговувати кількох клієнтів рівночасно.
+
+Але часто ви захочете запускати кілька процесів-працівників одночасно.
+
+### Кілька процесів - працівники { #multiple-processes-workers }
+
+Якщо у вас більше клієнтів, ніж може обробити один процес (наприклад, якщо віртуальна машина не надто потужна) і на сервері є **кілька ядер** CPU, тоді ви можете запустити **кілька процесів** із тим самим застосунком паралельно і розподіляти запити між ними.
+
+Коли ви запускаєте **кілька процесів** того самого програмного забезпечення API, їх зазвичай називають **працівниками** (workers).
+
+### Процеси-працівники і порти { #worker-processes-and-ports }
+
+Пам'ятаєте з документації [Про HTTPS](https.md){.internal-link target=_blank}, що на сервері лише один процес може слухати певну комбінацію порту та IP-адреси?
+
+Це досі так.
+
+Отже, щоб мати **кілька процесів** одночасно, має бути **єдиний процес, який слухає порт**, і який далі якимось чином передає комунікацію кожному процесу-працівнику.
+
+### Пам'ять на процес { #memory-per-process }
+
+Коли програма завантажує щось у пам'ять, наприклад модель машинного навчання в змінну або вміст великого файлу в змінну, все це **споживає частину пам'яті (RAM)** сервера.
+
+І кілька процесів зазвичай **не діляться пам'яттю**. Це означає, що кожен запущений процес має власні речі, змінні та пам'ять. І якщо у вашому коді споживається багато пам'яті, **кожен процес** споживатиме еквівалентний обсяг пам'яті.
+
+### Пам'ять сервера { #server-memory }
+
+Наприклад, якщо ваш код завантажує модель машинного навчання розміром **1 GB**, то при запуску одного процесу з вашим API він споживатиме щонайменше 1 GB RAM. А якщо ви запустите **4 процеси** (4 працівники) - кожен споживатиме 1 GB RAM. Отже, загалом ваш API споживатиме **4 GB RAM**.
+
+І якщо ваш віддалений сервер або віртуальна машина має лише 3 GB RAM, спроба використати понад 4 GB призведе до проблем. 🚨
+
+### Кілька процесів - приклад { #multiple-processes-an-example }
+
+У цьому прикладі є **керівний процес** (Manager Process), який запускає і контролює два **процеси-працівники**.
+
+Цей керівний процес, імовірно, саме і слухатиме **порт** на IP. І він передаватиме всю комунікацію процесам-працівникам.
+
+Ці процеси-працівники виконуватимуть ваш застосунок, здійснюватимуть основні обчислення, щоб отримати **запит** і повернути **відповідь**, і завантажуватимуть усе, що ви зберігаєте в змінних у RAM.
+
+

+
+Звісно, на тій самій машині, окрім вашого застосунку, зазвичай працюватимуть **інші процеси**.
+
+Цікавий момент: відсоток **використання CPU** кожним процесом може сильно **варіюватися** з часом, тоді як **пам'ять (RAM)** зазвичай залишається більш-менш **стабільною**.
+
+Якщо у вас API, що виконує порівняний обсяг обчислень щоразу і у вас багато клієнтів, тоді **використання CPU** також, ймовірно, буде *стабільним* (замість постійних швидких коливань).
+
+### Приклади інструментів і стратегій реплікації { #examples-of-replication-tools-and-strategies }
+
+Є кілька підходів для цього, і про конкретні стратегії я розповім у наступних розділах, наприклад, коли говоритимемо про Docker і контейнери.
+
+Головне обмеження: має бути **єдиний** компонент, що обробляє **порт** на **публічній IP-адресі**. А тоді він має мати спосіб **передавати** комунікацію реплікованим **процесам/працівникам**.
+
+Ось кілька можливих комбінацій і стратегій:
+
+- **Uvicorn** з `--workers`
+ - Один **менеджер процесів** Uvicorn слухатиме **IP** і **порт** та запускатиме **кілька процесів-працівників Uvicorn**.
+- **Kubernetes** та інші розподілені **системи контейнерів**
+ - Щось на рівні **Kubernetes** слухатиме **IP** і **порт**. Реплікація відбуватиметься через **кілька контейнерів**, у кожному з яких запущено **один процес Uvicorn**.
+- **Хмарні сервіси**, що роблять це за вас
+ - Хмарний сервіс, ймовірно, **забезпечить реплікацію за вас**. Він може дозволяти визначити **процес для запуску** або **образ контейнера** для використання; у будь-якому разі це, найімовірніше, буде **один процес Uvicorn**, а сервіс відповідатиме за його реплікацію.
+
+/// tip | Порада
+
+Не хвилюйтеся, якщо деякі пункти про **контейнери**, Docker чи Kubernetes поки що не дуже зрозумілі.
+
+Я розповім більше про образи контейнерів, Docker, Kubernetes тощо в майбутньому розділі: [FastAPI у контейнерах - Docker](docker.md){.internal-link target=_blank}.
+
+///
+
+## Попередні кроки перед стартом { #previous-steps-before-starting }
+
+Є багато випадків, коли потрібно виконати деякі кроки **перед стартом** вашого застосунку.
+
+Наприклад, ви можете захотіти запустити **міграції бази даних**.
+
+Але найчастіше ці кроки потрібно виконувати лише **один раз**.
+
+Отже, ви захочете мати **єдиний процес**, який виконає ці **попередні кроки** перед запуском застосунку.
+
+І потрібно переконатися, що їх виконує саме один процес навіть якщо потім ви запускаєте **кілька процесів** (кілька працівників) для самого застосунку. Якщо ці кроки виконуватимуться **кількома процесами**, вони **подвоюватимуть** роботу, виконуючи її **паралельно**, і якщо кроки делікатні, як-от міграції бази даних, це може призвести до конфліктів.
+
+Звісно, бувають випадки, коли немає проблеми запускати попередні кроки кілька разів - тоді все набагато простіше.
+
+/// tip | Порада
+
+Також майте на увазі, що залежно від вашого налаштування інколи **попередні кроки взагалі не потрібні** перед запуском застосунку.
+
+У такому разі про це можна не турбуватися. 🤷
+
+///
+
+### Приклади стратегій попередніх кроків { #examples-of-previous-steps-strategies }
+
+Це **значною мірою залежить** від способу **розгортання вашої системи** і, ймовірно, буде пов'язано зі способом запуску програм, обробки перезапусків тощо.
+
+Ось кілька можливих ідей:
+
+- «Init Container» у Kubernetes, який виконується перед вашим контейнером застосунку
+- bash-скрипт, який виконує попередні кроки, а потім запускає ваш застосунок
+ - Вам усе одно потрібен спосіб запускати/перезапускати цей bash-скрипт, виявляти помилки тощо.
+
+/// tip | Порада
+
+Я наведу більш конкретні приклади для цього з контейнерами у майбутньому розділі: [FastAPI у контейнерах - Docker](docker.md){.internal-link target=_blank}.
+
+///
+
+## Використання ресурсів { #resource-utilization }
+
+Ваш сервер(и) - це **ресурс**, який ви можете споживати/**використовувати** вашими програмами: час обчислень на CPU та доступну RAM.
+
+Скільки системних ресурсів ви хочете споживати/використовувати? Легко подумати «небагато», але насправді ви, ймовірно, захочете споживати **настільки багато, наскільки можливо без краху**.
+
+Якщо ви платите за 3 сервери, але використовуєте лише трохи їх RAM і CPU, ви, ймовірно, **марнуєте гроші** 💸 і, можливо, **електроенергію серверів** 🌎 тощо.
+
+У такому разі може бути краще мати лише 2 сервери й використовувати більший відсоток їхніх ресурсів (CPU, пам'ять, диск, пропускну здатність мережі тощо).
+
+З іншого боку, якщо у вас 2 сервери і ви використовуєте **100% їхнього CPU та RAM**, у певний момент якийсь процес попросить більше пам'яті, і сервер муситиме використати диск як «пам'ять» (що може бути у тисячі разів повільнішим) або навіть **впасти**. Або процесу знадобляться обчислення, і він чекатиме, доки CPU знову звільниться.
+
+У цьому випадку краще додати **ще один сервер** і запустити частину процесів на ньому, щоб у всіх було **достатньо RAM та часу CPU**.
+
+Також можлива ситуація, коли з певної причини ви отримаєте **стрибок** використання вашого API. Можливо, він став вірусним або його почали використовувати інші сервіси чи боти. І ви можете захотіти мати додаткові ресурси на випадок таких ситуацій.
+
+Ви можете встановити **довільний цільовий** рівень, наприклад, **між 50% і 90%** використання ресурсів. Суть у тому, що це, ймовірно, головні речі, які ви захочете вимірювати й використовувати для налаштування розгортань.
+
+Ви можете використати прості інструменти, як-от `htop`, щоб побачити використання CPU і RAM на сервері або кількість, спожиту кожним процесом. Або складніші засоби моніторингу, розподілені між серверами тощо.
+
+## Підсумок { #recap }
+
+Тут ви прочитали про основні концепції, які, ймовірно, потрібно тримати в голові, вирішуючи, як розгортати ваш застосунок:
+
+- Безпека - HTTPS
+- Запуск під час старту
+- Перезапуски
+- Реплікація (кількість запущених процесів)
+- Пам'ять
+- Попередні кроки перед стартом
+
+Розуміння цих ідей і того, як їх застосовувати, має дати вам інтуїцію, необхідну для прийняття рішень під час конфігурування і тонкого налаштування ваших розгортань. 🤓
+
+У наступних розділах я наведу більше конкретних прикладів можливих стратегій, якими ви можете скористатися. 🚀
diff --git a/docs/uk/docs/deployment/docker.md b/docs/uk/docs/deployment/docker.md
new file mode 100644
index 0000000000..d6faacfe5e
--- /dev/null
+++ b/docs/uk/docs/deployment/docker.md
@@ -0,0 +1,618 @@
+# FastAPI у контейнерах - Docker { #fastapi-in-containers-docker }
+
+Під час розгортання застосунків FastAPI поширений підхід - збирати образи контейнерів Linux. Зазвичай це робиться за допомогою
Docker. Потім ви можете розгорнути цей образ контейнера кількома різними способами.
+
+Використання контейнерів Linux має кілька переваг, зокрема безпека, відтворюваність, простота та інші.
+
+/// tip | Порада
+
+Поспішаєте і вже все це знаєте? Перейдіть до [`Dockerfile` нижче 👇](#build-a-docker-image-for-fastapi).
+
+///
+
+
+Попередній перегляд Dockerfile 👀
+
+```Dockerfile
+FROM python:3.14
+
+WORKDIR /code
+
+COPY ./requirements.txt /code/requirements.txt
+
+RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
+
+COPY ./app /code/app
+
+CMD ["fastapi", "run", "app/main.py", "--port", "80"]
+
+# Якщо запускаєте за представником на кшталт Nginx або Traefik, додайте --proxy-headers
+# CMD ["fastapi", "run", "app/main.py", "--port", "80", "--proxy-headers"]
+```
+
+
+
+## Що таке контейнер { #what-is-a-container }
+
+Контейнери (переважно контейнери Linux) - це дуже легкий спосіб упакувати застосунки з усіма їхніми залежностями та потрібними файлами, ізолювавши їх від інших контейнерів (інших застосунків або компонентів) у тій самій системі.
+
+Контейнери Linux працюють, використовуючи той самий ядро Linux, що й хост (машина, віртуальна машина, хмарний сервер тощо). Це означає, що вони дуже легкі (у порівнянні з повними віртуальними машинами, які емулюють цілу операційну систему).
+
+Таким чином контейнери споживають мало ресурсів, приблизно як безпосередньо запущені процеси (віртуальна машина споживала б значно більше).
+
+У контейнерів також є власні ізольовані процеси виконання (зазвичай лише один процес), файлові системи та мережі, що спрощує розгортання, безпеку, розробку тощо.
+
+## Що таке образ контейнера { #what-is-a-container-image }
+
+Контейнер запускається з образу контейнера.
+
+Образ контейнера - це статична версія всіх файлів, змінних оточення та типова команда/програма, яка має бути присутня в контейнері. Тут «статична» означає, що образ контейнера не запущений, він не виконується, це лише упаковані файли та метадані.
+
+На противагу «образу контейнера», що є збереженим статичним вмістом, «контейнер» зазвичай означає запущений екземпляр, те, що виконується.
+
+Коли контейнер запущено (запущений з образу контейнера), він може створювати або змінювати файли, змінні оточення тощо. Ці зміни існуватимуть лише в цьому контейнері, але не збережуться в базовому образі контейнера (не будуть записані на диск).
+
+Образ контейнера можна порівняти з файлом і вмістом програми, наприклад `python` і файлом `main.py`.
+
+А сам контейнер (на відміну від образу) - це фактично запущений екземпляр образу, порівнянний із процесом. Насправді контейнер працює лише тоді, коли в ньому працює процес (і зазвичай це один процес). Контейнер зупиняється, коли в ньому не працює жоден процес.
+
+## Образи контейнерів { #container-images }
+
+Docker був одним з основних інструментів для створення та керування образами контейнерів і контейнерами.
+
+Існує публічний
Docker Hub з готовими офіційними образами для багатьох інструментів, середовищ, баз даних і застосунків.
+
+Наприклад, є офіційний
образ Python.
+
+І є багато інших образів для різних речей, як-от бази даних, наприклад для:
+
+*
PostgreSQL
+*
MySQL
+*
MongoDB
+*
Redis тощо.
+
+Використовуючи готовий образ контейнера, дуже легко поєднувати та використовувати різні інструменти. Наприклад, щоб випробувати нову базу даних. У більшості випадків ви можете використати офіційні образи та просто налаштувати їх змінними оточення.
+
+Таким чином, у багатьох випадках ви зможете навчитися працювати з контейнерами і Docker та повторно використати ці знання з багатьма різними інструментами і компонентами.
+
+Тобто ви запускатимете кілька контейнерів з різними речами, як-от базу даних, застосунок на Python, вебсервер із фронтендом на React, і з’єднаєте їх через внутрішню мережу.
+
+Усі системи керування контейнерами (як Docker чи Kubernetes) мають ці мережеві можливості вбудовано.
+
+## Контейнери і процеси { #containers-and-processes }
+
+Образ контейнера зазвичай містить у своїх метаданих типову програму або команду, яку слід виконати під час запуску контейнера, і параметри для цієї програми. Дуже схоже на те, що ви б виконали в командному рядку.
+
+Коли контейнер запускається, він виконає цю команду/програму (хоча ви можете перевизначити її і запустити іншу команду/програму).
+
+Контейнер працює доти, доки працює головний процес (команда або програма).
+
+Зазвичай контейнер має один процес, але також можливо запускати підпроцеси з головного процесу, і таким чином у вас може бути кілька процесів у тому самому контейнері.
+
+Але неможливо мати запущений контейнер без принаймні одного запущеного процесу. Якщо головний процес зупиняється, контейнер зупиняється.
+
+## Зібрати Docker-образ для FastAPI { #build-a-docker-image-for-fastapi }
+
+Гаразд, зберімо щось зараз! 🚀
+
+Я покажу вам, як зібрати образ Docker для FastAPI з нуля на основі офіційного образу Python.
+
+Це те, що ви захочете робити у більшості випадків, наприклад:
+
+* Використання Kubernetes або подібних інструментів
+* Під час запуску на Raspberry Pi
+* Використання хмарного сервісу, який запустить для вас образ контейнера тощо
+
+### Вимоги до пакетів { #package-requirements }
+
+Зазвичай ви маєте вимоги до пакетів для вашого застосунку в окремому файлі.
+
+Це залежить переважно від інструменту, який ви використовуєте для встановлення цих вимог.
+
+Найпоширеніший спосіб - мати файл `requirements.txt` з назвами пакетів і їхніми версіями, по одному на рядок.
+
+Звісно, ви застосуєте ті самі ідеї з [Про версії FastAPI](versions.md){.internal-link target=_blank}, щоб задати діапазони версій.
+
+Наприклад, ваш `requirements.txt` може виглядати так:
+
+```
+fastapi[standard]>=0.113.0,<0.114.0
+pydantic>=2.7.0,<3.0.0
+```
+
+І зазвичай ви встановлюватимете ці залежності пакетів через `pip`, наприклад:
+
+
+
+```console
+$ pip install -r requirements.txt
+---> 100%
+Successfully installed fastapi pydantic
+```
+
+
+
+/// info | Інформація
+
+Існують інші формати та інструменти для визначення і встановлення залежностей пакетів.
+
+///
+
+### Створіть код **FastAPI** { #create-the-fastapi-code }
+
+* Створіть директорію `app` і перейдіть у неї.
+* Створіть порожній файл `__init__.py`.
+* Створіть файл `main.py` з вмістом:
+
+```Python
+from fastapi import FastAPI
+
+app = FastAPI()
+
+
+@app.get("/")
+def read_root():
+ return {"Hello": "World"}
+
+
+@app.get("/items/{item_id}")
+def read_item(item_id: int, q: str | None = None):
+ return {"item_id": item_id, "q": q}
+```
+
+### Dockerfile { #dockerfile }
+
+Тепер у тій самій директорії проєкту створіть файл `Dockerfile` з вмістом:
+
+```{ .dockerfile .annotate }
+# (1)!
+FROM python:3.14
+
+# (2)!
+WORKDIR /code
+
+# (3)!
+COPY ./requirements.txt /code/requirements.txt
+
+# (4)!
+RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
+
+# (5)!
+COPY ./app /code/app
+
+# (6)!
+CMD ["fastapi", "run", "app/main.py", "--port", "80"]
+```
+
+1. Почніть з офіційного базового образу Python.
+
+2. Встановіть поточну робочу директорію в `/code`.
+
+ Саме сюди ми помістимо файл `requirements.txt` і директорію `app`.
+
+3. Скопіюйте файл з вимогами в директорію `/code`.
+
+ Спочатку скопіюйте лише файл з вимогами, а не решту коду.
+
+ Оскільки цей файл змінюється нечасто, Docker виявить це і використає кеш для цього кроку, що також увімкне кеш і для наступного кроку.
+
+4. Встановіть залежності пакетів із файлу вимог.
+
+ Опція `--no-cache-dir` каже `pip` не зберігати завантажені пакети локально, адже це потрібно лише тоді, якщо `pip` буде запущено знову для встановлення тих самих пакетів, але в роботі з контейнерами це не так.
+
+ /// note | Примітка
+
+ `--no-cache-dir` стосується лише `pip`, це не має відношення до Docker чи контейнерів.
+
+ ///
+
+ Опція `--upgrade` каже `pip` оновити пакети, якщо вони вже встановлені.
+
+ Оскільки попередній крок копіювання файлу може бути виявлений кешем Docker, цей крок також використовуватиме кеш Docker, коли це можливо.
+
+ Використання кешу на цьому кроці збереже вам багато часу під час повторних збірок образу в розробці, замість того щоб завжди завантажувати і встановлювати всі залежності.
+
+5. Скопіюйте директорію `./app` у директорію `/code`.
+
+ Оскільки тут увесь код, який змінюється найчастіше, кеш Docker не буде легко використаний для цього або будь-яких наступних кроків.
+
+ Тому важливо розмістити це ближче до кінця `Dockerfile`, щоб оптимізувати час збірки образу контейнера.
+
+6. Встановіть команду для використання `fastapi run`, яка всередині використовує Uvicorn.
+
+ `CMD` приймає список строк, кожна з яких - це те, що ви б набирали в командному рядку, розділене пробілами.
+
+ Ця команда буде виконана з поточної робочої директорії, тієї самої `/code`, яку ви вказали вище через `WORKDIR /code`.
+
+/// tip | Порада
+
+Перегляньте, що робить кожен рядок, клацнувши на кожну номерну позначку в коді. 👆
+
+///
+
+/// warning | Попередження
+
+Обов’язково завжди використовуйте exec form інструкції `CMD`, як пояснено нижче.
+
+///
+
+#### Використовуйте `CMD` - exec form { #use-cmd-exec-form }
+
+Інструкцію Docker
`CMD` можна записати у двох формах:
+
+✅ Exec form:
+
+```Dockerfile
+# ✅ Робіть так
+CMD ["fastapi", "run", "app/main.py", "--port", "80"]
+```
+
+⛔️ Shell form:
+
+```Dockerfile
+# ⛔️ Не робіть так
+CMD fastapi run app/main.py --port 80
+```
+
+Обов’язково завжди використовуйте exec form, щоб FastAPI міг коректно завершувати роботу та щоб були викликані [події тривалості життя](../advanced/events.md){.internal-link target=_blank}.
+
+Докладніше про це можна прочитати в
документації Docker про shell та exec form.
+
+Це може бути особливо помітно при використанні `docker compose`. Див. розділ FAQ Docker Compose для технічних деталей:
Чому мої сервіси потребують 10 секунд, щоб пересотворитися або зупинитися?.
+
+#### Структура директорій { #directory-structure }
+
+Зараз у вас має бути така структура директорій:
+
+```
+.
+├── app
+│ ├── __init__.py
+│ └── main.py
+├── Dockerfile
+└── requirements.txt
+```
+
+#### За представником з термінацією TLS { #behind-a-tls-termination-proxy }
+
+Якщо ви запускаєте контейнер за представником з термінацією TLS (балансувальником навантаження), наприклад Nginx або Traefik, додайте опцію `--proxy-headers`. Це скаже Uvicorn (через CLI FastAPI) довіряти заголовкам, що надсилаються цим представником, які вказують, що застосунок працює за HTTPS тощо.
+
+```Dockerfile
+CMD ["fastapi", "run", "app/main.py", "--proxy-headers", "--port", "80"]
+```
+
+#### Кеш Docker { #docker-cache }
+
+У цьому `Dockerfile` є важливий трюк: спочатку ми копіюємо лише файл із залежностями, а не решту коду. Ось чому.
+
+```Dockerfile
+COPY ./requirements.txt /code/requirements.txt
+```
+
+Docker та інші інструменти збирають ці образи контейнерів інкрементально, додаючи один шар поверх іншого, починаючи з верхньої частини `Dockerfile` і додаючи будь-які файли, створені кожною інструкцією в `Dockerfile`.
+
+Docker та подібні інструменти також використовують внутрішній кеш під час збірки образу. Якщо файл не змінювався з моменту останньої збірки, тоді він повторно використає той самий шар, створений востаннє, замість копіювання файлу знову та створення нового шару з нуля.
+
+Просте уникнення копіювання файлів не обов’язково суттєво покращує ситуацію, але оскільки для цього кроку використано кеш, він може використати кеш і для наступного кроку. Наприклад, він може використати кеш для інструкції, яка встановлює залежності:
+
+```Dockerfile
+RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
+```
+
+Файл із вимогами до пакетів змінюватиметься нечасто. Отже, копіюючи лише цей файл, Docker зможе використати кеш для цього кроку.
+
+А потім Docker зможе використати кеш і для наступного кроку, який завантажує та встановлює ці залежності. І саме тут ми заощаджуємо багато часу. ✨ ...і уникаємо нудного очікування. 😪😆
+
+Завантаження і встановлення залежностей пакетів може займати хвилини, але використання кешу займе максимум секунди.
+
+І оскільки ви збиратимете образ контейнера знову і знову під час розробки, щоб перевіряти, що зміни у вашому коді працюють, це заощадить багато накопиченого часу.
+
+Потім, ближче до кінця `Dockerfile`, ми копіюємо весь код. Оскільки це те, що змінюється найчастіше, ми розміщуємо це ближче до кінця, адже майже завжди все після цього кроку не зможе використати кеш.
+
+```Dockerfile
+COPY ./app /code/app
+```
+
+### Зберіть Docker-образ { #build-the-docker-image }
+
+Тепер, коли всі файли на місці, зберімо образ контейнера.
+
+* Перейдіть у директорію проєкту (де ваш `Dockerfile`, який містить директорію `app`).
+* Зберіть ваш образ FastAPI:
+
+
+
+```console
+$ docker build -t myimage .
+
+---> 100%
+```
+
+
+
+/// tip | Порада
+
+Зверніть увагу на `.` в кінці. Це еквівалент `./`. Воно каже Docker, яку директорію використовувати для збірки образу контейнера.
+
+У цьому випадку - це поточна директорія (`.`).
+
+///
+
+### Запустіть Docker-контейнер { #start-the-docker-container }
+
+* Запустіть контейнер на основі вашого образу:
+
+
+
+```console
+$ docker run -d --name mycontainer -p 80:80 myimage
+```
+
+
+
+## Перевірте { #check-it }
+
+Ви маєте змогу перевірити це за URL вашого Docker-контейнера, наприклад:
http://192.168.99.100/items/5?q=somequery або
http://127.0.0.1/items/5?q=somequery (або еквівалент, використовуючи ваш Docker-хост).
+
+Ви побачите щось таке:
+
+```JSON
+{"item_id": 5, "q": "somequery"}
+```
+
+## Інтерактивна документація API { #interactive-api-docs }
+
+Тепер ви можете перейти на
http://192.168.99.100/docs або
http://127.0.0.1/docs (або еквівалент, використовуючи ваш Docker-хост).
+
+Ви побачите автоматичну інтерактивну документацію API (надається
Swagger UI):
+
+
+
+## Альтернативна документація API { #alternative-api-docs }
+
+Також ви можете перейти на
http://192.168.99.100/redoc або
http://127.0.0.1/redoc (або еквівалент, використовуючи ваш Docker-хост).
+
+Ви побачите альтернативну автоматичну документацію (надається
ReDoc):
+
+
+
+## Збірка Docker-образу з FastAPI в одному файлі { #build-a-docker-image-with-a-single-file-fastapi }
+
+Якщо ваш FastAPI - це один файл, наприклад `main.py` без директорії `./app`, структура файлів може виглядати так:
+
+```
+.
+├── Dockerfile
+├── main.py
+└── requirements.txt
+```
+
+Тоді вам потрібно лише змінити відповідні шляхи для копіювання файлу всередині `Dockerfile`:
+
+```{ .dockerfile .annotate hl_lines="10 13" }
+FROM python:3.14
+
+WORKDIR /code
+
+COPY ./requirements.txt /code/requirements.txt
+
+RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
+
+# (1)!
+COPY ./main.py /code/
+
+# (2)!
+CMD ["fastapi", "run", "main.py", "--port", "80"]
+```
+
+1. Скопіюйте файл `main.py` безпосередньо у директорію `/code` (без будь-якої директорії `./app`).
+
+2. Використовуйте `fastapi run`, щоб обслуговувати ваш застосунок з одного файлу `main.py`.
+
+Коли ви передаєте файл у `fastapi run`, воно автоматично визначить, що це один файл, а не частина пакета, і знатиме, як імпортувати його та запустити ваш застосунок FastAPI. 😎
+
+## Концепції розгортання { #deployment-concepts }
+
+Поговорімо знову про деякі з тих самих [Концепцій розгортання](concepts.md){.internal-link target=_blank} у термінах контейнерів.
+
+Контейнери - це переважно інструмент для спрощення процесу збирання та розгортання застосунку, але вони не нав’язують конкретний підхід до обробки цих концепцій розгортання, і існує кілька можливих стратегій.
+
+Гарна новина полягає в тому, що для кожної стратегії є спосіб покрити всі концепції розгортання. 🎉
+
+Розгляньмо ці концепції розгортання в контексті контейнерів:
+
+* HTTPS
+* Автозапуск
+* Перезапуски
+* Реплікація (кількість запущених процесів)
+* Пам’ять
+* Попередні кроки перед запуском
+
+## HTTPS { #https }
+
+Якщо зосередитись лише на образі контейнера для застосунку FastAPI (а згодом на запущеному контейнері), HTTPS зазвичай обробляється зовнішнім іншим інструментом.
+
+Це може бути інший контейнер, наприклад з
Traefik, що обробляє HTTPS і автоматичне отримання сертифікатів.
+
+/// tip | Порада
+
+Traefik має інтеграції з Docker, Kubernetes та іншими, тож налаштувати і сконфігурувати HTTPS для ваших контейнерів з ним дуже просто.
+
+///
+
+Альтернативно, HTTPS може оброблятись хмарним провайдером як один з їхніх сервісів (при цьому застосунок усе ще працює в контейнері).
+
+## Автозапуск і перезапуски { #running-on-startup-and-restarts }
+
+Зазвичай інший інструмент відповідає за запуск і виконання вашого контейнера.
+
+Це може бути безпосередньо Docker, Docker Compose, Kubernetes, хмарний сервіс тощо.
+
+У більшості (або всіх) випадків є проста опція, щоб увімкнути запуск контейнера при старті системи та перезапуски у разі збоїв. Наприклад, у Docker це опція командного рядка `--restart`.
+
+Без використання контейнерів змусити застосунки запускатися при старті системи та з перезапусками може бути клопітно і складно. Але під час роботи з контейнерами у більшості випадків ця функціональність вбудована за замовчуванням. ✨
+
+## Реплікація - кількість процесів { #replication-number-of-processes }
+
+Якщо у вас є
кластер машин із Kubernetes, Docker Swarm Mode, Nomad або іншою подібною складною системою для керування розподіленими контейнерами на кількох машинах, тоді ви, ймовірно, захочете обробляти реплікацію на рівні кластера замість використання менеджера процесів (як-от Uvicorn з працівниками) у кожному контейнері.
+
+Одна з таких розподілених систем керування контейнерами, як-от Kubernetes, зазвичай має інтегровані способи обробляти реплікацію контейнерів, підтримуючи водночас балансування навантаження для вхідних запитів. Усе це - на рівні кластера.
+
+У таких випадках ви, ймовірно, захочете зібрати Docker-образ з нуля, як [пояснено вище](#dockerfile), встановивши ваші залежності і запустивши один процес Uvicorn замість використання кількох працівників Uvicorn.
+
+### Балансувальник навантаження { #load-balancer }
+
+При використанні контейнерів зазвичай є якийсь компонент, що слухає на головному порту. Це може бути інший контейнер, який також є представником з термінацією TLS для обробки HTTPS, або подібний інструмент.
+
+Оскільки цей компонент приймає навантаження запитів і розподіляє його між працівниками (сподіваємось) збалансовано, його також часто називають балансувальником навантаження.
+
+/// tip | Порада
+
+Той самий компонент представника з термінацією TLS, що використовується для HTTPS, швидше за все, також буде балансувальником навантаження.
+
+///
+
+І під час роботи з контейнерами та сама система, яку ви використовуєте для їх запуску і керування ними, вже матиме внутрішні інструменти для передавання мережевої комунікації (наприклад, HTTP-запитів) від цього балансувальника навантаження (який також може бути представником з термінацією TLS) до контейнерів із вашим застосунком.
+
+### Один балансувальник навантаження - кілька контейнерів-працівників { #one-load-balancer-multiple-worker-containers }
+
+Під час роботи з Kubernetes або подібними розподіленими системами керування контейнерами використання їхніх внутрішніх мережевих механізмів дозволяє єдиному балансувальнику навантаження, що слухає на головному порту, передавати комунікацію (запити) до кількох контейнерів, у яких запущено ваш застосунок.
+
+Кожен з цих контейнерів із вашим застосунком зазвичай має лише один процес (наприклад, процес Uvicorn, що запускає ваш застосунок FastAPI). Усі вони будуть ідентичними контейнерами, які запускають те саме, але кожен зі своїм процесом, пам’яттю тощо. Таким чином ви використаєте переваги паралелізму на різних ядрах процесора або навіть на різних машинах.
+
+А розподілена система контейнерів із балансувальником навантаження розподілятиме запити між кожним із контейнерів із вашим застосунком по черзі. Тож кожен запит може оброблятися одним із кількох реплікованих контейнерів, що запускають ваш застосунок.
+
+І зазвичай цей балансувальник навантаження зможе обробляти запити, які йдуть до інших застосунків у вашому кластері (наприклад, до іншого домену або під іншим префіксом шляху URL), і передаватиме комунікацію до відповідних контейнерів для того іншого застосунку, що працює у вашому кластері.
+
+### Один процес на контейнер { #one-process-per-container }
+
+У такому сценарії ви, ймовірно, захочете мати один (Uvicorn) процес на контейнер, адже ви вже обробляєте реплікацію на рівні кластера.
+
+Тобто в цьому випадку ви не захочете мати кількох працівників у контейнері, наприклад через опцію командного рядка `--workers`. Ви захочете мати лише один процес Uvicorn на контейнер (але, ймовірно, кілька контейнерів).
+
+Наявність іншого менеджера процесів всередині контейнера (як це було б із кількома працівниками) лише додасть зайвої складності, яку, найімовірніше, ви вже вирішуєте на рівні кластера.
+
+### Контейнери з кількома процесами та особливі випадки { #containers-with-multiple-processes-and-special-cases }
+
+Звісно, є особливі випадки, коли ви можете захотіти мати контейнер із кількома процесами-працівниками Uvicorn всередині.
+
+У таких випадках ви можете використати опцію командного рядка `--workers`, щоб задати кількість працівників, яких потрібно запустити:
+
+```{ .dockerfile .annotate }
+FROM python:3.14
+
+WORKDIR /code
+
+COPY ./requirements.txt /code/requirements.txt
+
+RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
+
+COPY ./app /code/app
+
+# (1)!
+CMD ["fastapi", "run", "app/main.py", "--port", "80", "--workers", "4"]
+```
+
+1. Тут ми використовуємо опцію командного рядка `--workers`, щоб встановити кількість працівників 4.
+
+Ось кілька прикладів, коли це може мати сенс:
+
+#### Простий застосунок { #a-simple-app }
+
+Ви можете захотіти менеджер процесів у контейнері, якщо ваш застосунок достатньо простий, щоб запускати його на одному сервері, а не на кластері.
+
+#### Docker Compose { #docker-compose }
+
+Ви можете розгортати на одному сервері (не в кластері) за допомогою Docker Compose, тож у вас не буде простого способу керувати реплікацією контейнерів (у Docker Compose), зберігаючи спільну мережу та балансування навантаження.
+
+Тоді ви можете захотіти мати один контейнер із менеджером процесів, що запускає кілька процесів-працівників всередині.
+
+---
+
+Головна думка: це не правила, викарбувані в камені, яких потрібно сліпо дотримуватися. Ви можете використати ці ідеї, щоб оцінити власний кейс і вирішити, який підхід найкращий для вашої системи, розглядаючи, як керувати такими концепціями:
+
+* Безпека - HTTPS
+* Автозапуск
+* Перезапуски
+* Реплікація (кількість запущених процесів)
+* Пам’ять
+* Попередні кроки перед запуском
+
+## Пам’ять { #memory }
+
+Якщо ви запускаєте один процес на контейнер, ви матимете більш-менш чітко визначений, стабільний і обмежений обсяг пам’яті, що споживається кожним із цих контейнерів (їх може бути більше одного, якщо вони репліковані).
+
+Потім ви можете встановити ті самі ліміти та вимоги до пам’яті у ваших конфігураціях для системи керування контейнерами (наприклад, у Kubernetes). Таким чином вона зможе реплікувати контейнери на доступних машинах, враховуючи обсяг пам’яті, потрібний їм, і обсяг доступної пам’яті на машинах у кластері.
+
+Якщо ваш застосунок простий, імовірно, це не буде проблемою, і вам може не знадобитися задавати жорсткі ліміти пам’яті. Але якщо ви використовуєте багато пам’яті (наприклад, із моделями машинного навчання), вам слід перевірити, скільки пам’яті ви споживаєте, і відкоригувати кількість контейнерів, що запускаються на кожній машині (і, можливо, додати більше машин у ваш кластер).
+
+Якщо ви запускаєте кілька процесів на контейнер, вам потрібно переконатися, що кількість запущених процесів не споживає більше пам’яті, ніж доступно.
+
+## Попередні кроки перед запуском і контейнери { #previous-steps-before-starting-and-containers }
+
+Якщо ви використовуєте контейнери (наприклад, Docker, Kubernetes), то є два основні підходи.
+
+### Кілька контейнерів { #multiple-containers }
+
+Якщо у вас кілька контейнерів, імовірно кожен запускає один процес (наприклад, у кластері Kubernetes), тоді ви, ймовірно, захочете мати окремий контейнер, який виконає попередні кроки в одному контейнері, запустивши один процес, перед запуском реплікованих контейнерів-працівників.
+
+/// info | Інформація
+
+Якщо ви використовуєте Kubernetes, це, ймовірно, буде
Init Container.
+
+///
+
+Якщо у вашому випадку немає проблеми запускати ці попередні кроки кілька разів паралельно (наприклад, якщо ви не виконуєте міграції бази даних, а лише перевіряєте, чи база вже готова), тоді ви також можете просто помістити їх у кожен контейнер безпосередньо перед запуском головного процесу.
+
+### Один контейнер { #single-container }
+
+Якщо у вас просте налаштування з одним контейнером, який потім запускає кілька процесів-працівників (або теж лише один процес), тоді ви можете виконати ці попередні кроки в тому ж контейнері безпосередньо перед запуском процесу із застосунком.
+
+### Базовий образ Docker { #base-docker-image }
+
+Колись існував офіційний образ Docker для FastAPI:
tiangolo/uvicorn-gunicorn-fastapi. Але зараз він застарілий. ⛔️
+
+Ймовірно, вам не слід використовувати цей базовий образ Docker (або будь-який інший подібний).
+
+Якщо ви використовуєте Kubernetes (або інші) і вже налаштовуєте реплікацію на рівні кластера з кількома контейнерами. У таких випадках краще зібрати образ з нуля, як описано вище: [Зібрати Docker-образ для FastAPI](#build-a-docker-image-for-fastapi).
+
+А якщо вам потрібно мати кілька працівників, ви можете просто використати опцію командного рядка `--workers`.
+
+/// note | Технічні деталі
+
+Цей образ Docker було створено тоді, коли Uvicorn не підтримував керування та перезапуск «мертвих» працівників, тому потрібно було використовувати Gunicorn з Uvicorn, що додавало чимало складності лише для того, щоб Gunicorn керував та перезапускав процеси-працівники Uvicorn.
+
+Але тепер, коли Uvicorn (і команда `fastapi`) підтримують використання `--workers`, немає причин використовувати базовий образ Docker замість того, щоб зібрати власний (це приблизно та сама кількість коду 😅).
+
+///
+
+## Розгорнути образ контейнера { #deploy-the-container-image }
+
+Після отримання образу контейнера (Docker) є кілька способів його розгорнути.
+
+Наприклад:
+
+* З Docker Compose на одному сервері
+* З кластером Kubernetes
+* З кластером Docker Swarm Mode
+* З іншим інструментом, як-от Nomad
+* З хмарним сервісом, який бере ваш образ контейнера і розгортає його
+
+## Образ Docker з `uv` { #docker-image-with-uv }
+
+Якщо ви використовуєте
uv для встановлення та керування вашим проєктом, ви можете скористатися їхнім
посібником Docker для uv.
+
+## Підсумок { #recap }
+
+Використовуючи системи контейнерів (наприклад, з Docker і Kubernetes), досить просто обробляти всі концепції розгортання:
+
+* HTTPS
+* Автозапуск
+* Перезапуски
+* Реплікація (кількість запущених процесів)
+* Пам’ять
+* Попередні кроки перед запуском
+
+У більшості випадків ви, ймовірно, не захочете використовувати будь-який базовий образ, а натомість зібрати образ контейнера з нуля на основі офіційного образу Python для Docker.
+
+Дотримуючись порядку інструкцій у `Dockerfile` і використовуючи кеш Docker, ви можете мінімізувати час збірки, щоб максимізувати свою продуктивність (і уникнути нудьги). 😎
diff --git a/docs/uk/docs/deployment/fastapicloud.md b/docs/uk/docs/deployment/fastapicloud.md
new file mode 100644
index 0000000000..4b4f3e59be
--- /dev/null
+++ b/docs/uk/docs/deployment/fastapicloud.md
@@ -0,0 +1,65 @@
+# FastAPI Cloud { #fastapi-cloud }
+
+Ви можете розгорнути свій застосунок FastAPI на
FastAPI Cloud однією командою, приєднуйтесь до списку очікування, якщо ще ні. 🚀
+
+## Вхід { #login }
+
+Переконайтеся, що у вас вже є обліковий запис **FastAPI Cloud** (ми запросили вас зі списку очікування 😉).
+
+Потім увійдіть:
+
+
+
+```console
+$ fastapi login
+
+You are logged in to FastAPI Cloud 🚀
+```
+
+
+
+## Розгортання { #deploy }
+
+Тепер розгорніть свій застосунок однією командою:
+
+
+
+```console
+$ fastapi deploy
+
+Deploying to FastAPI Cloud...
+
+✅ Deployment successful!
+
+🐔 Ready the chicken! Your app is ready at https://myapp.fastapicloud.dev
+```
+
+
+
+Ось і все! Тепер ви можете отримати доступ до свого застосунку за цим URL. ✨
+
+## Про FastAPI Cloud { #about-fastapi-cloud }
+
+**
FastAPI Cloud** створено тим самим автором і командою, що стоїть за **FastAPI**.
+
+Він спрощує процес **створення**, **розгортання** та **доступу** до API з мінімальними зусиллями.
+
+Він переносить той самий **досвід розробника**, що і під час створення застосунків з FastAPI, на їх **розгортання** у хмарі. 🎉
+
+Він також подбає про більшість речей, які вам потрібні під час розгортання застосунку, як-от:
+
+- HTTPS
+- реплікація з автомасштабуванням на основі запитів
+- тощо
+
+FastAPI Cloud - основний спонсор і джерело фінансування для відкритих проєктів *«FastAPI та друзі»*. ✨
+
+## Розгортання в інших хмарних провайдерів { #deploy-to-other-cloud-providers }
+
+FastAPI є відкритим кодом і базується на стандартах. Ви можете розгортати застосунки FastAPI в будь-якого хмарного провайдера за вашим вибором.
+
+Дотримуйтесь інструкцій вашого хмарного провайдера, щоб розгортати застосунки FastAPI у них. 🤓
+
+## Розгортання на вашому сервері { #deploy-your-own-server }
+
+Пізніше в цьому розділі **Розгортання** я також навчу вас усім деталям, щоб ви розуміли, що відбувається, що потрібно зробити і як розгортати застосунки FastAPI самостійно, зокрема на власних серверах. 🤓
diff --git a/docs/uk/docs/deployment/https.md b/docs/uk/docs/deployment/https.md
new file mode 100644
index 0000000000..29329c88f0
--- /dev/null
+++ b/docs/uk/docs/deployment/https.md
@@ -0,0 +1,231 @@
+# Про HTTPS { #about-https }
+
+Легко припустити, що HTTPS - це щось, що просто «увімкнено» або ні.
+
+Але все значно складніше.
+
+/// tip | Порада
+
+Якщо ви поспішаєте або це неважливо для вас, переходьте до наступних розділів для покрокових інструкцій із налаштування всього різними техніками.
+
+///
+
+Щоб вивчити основи HTTPS з точки зору споживача, перегляньте
https://howhttps.works/.
+
+Тепер, з точки зору розробника, ось кілька речей, які варто пам'ятати, розмірковуючи про HTTPS:
+
+* Для HTTPS сервер має мати «сертифікати», видані третьою стороною.
+ * Насправді ці сертифікати «отримуються» у третьої сторони, а не «генеруються».
+* Сертифікати мають строк дії.
+ * Їхній строк дії спливає.
+ * І тоді їх потрібно поновити, знову отримавши у третьої сторони.
+* Шифрування з'єднання відбувається на рівні TCP.
+ * Це один шар нижче від HTTP.
+ * Тож обробка сертифіката та шифрування виконується до HTTP.
+* TCP не знає про «домени». Лише про IP-адреси.
+ * Інформація про конкретний домен, який запитується, міститься в даних HTTP.
+* Сертифікати HTTPS «засвідчують» певний домен, але протокол і шифрування працюють на рівні TCP, до того як відомо, з яким доменом маємо справу.
+* Типово це означало б, що на одну IP-адресу можна мати лише один сертифікат HTTPS.
+ * Неважливо, наскільки великий ваш сервер або наскільки малий кожен застосунок на ньому.
+ * Однак для цього є рішення.
+* Є розширення протоколу TLS (який обробляє шифрування на рівні TCP, до HTTP), що називається
SNI.
+ * Це розширення SNI дозволяє одному серверу (з однією IP-адресою) мати кілька сертифікатів HTTPS і обслуговувати кілька доменів/застосунків по HTTPS.
+ * Щоб це працювало, один-єдиний компонент (програма), що працює на сервері та слухає публічну IP-адресу, має мати всі сертифікати HTTPS на сервері.
+* Після отримання захищеного з'єднання протокол обміну все ще HTTP.
+ * Вміст зашифровано, хоча він надсилається протоколом HTTP.
+
+Поширена практика мати одну програму/HTTP-сервер, що працює на сервері (машині, хості тощо) і керує всіма частинами HTTPS: приймає зашифровані HTTPS-запити, надсилає розшифровані HTTP-запити до фактичного HTTP-застосунку, що працює на тому ж сервері (у нашому випадку застосунок FastAPI), отримує HTTP-відповідь від застосунку, шифрує її за допомогою відповідного сертифіката HTTPS і надсилає її назад клієнту через HTTPS. Такий сервер часто називають
TLS Termination Proxy.
+
+Деякі варіанти, які ви можете використати як TLS Termination Proxy:
+
+* Traefik (також може виконувати поновлення сертифікатів)
+* Caddy (також може виконувати поновлення сертифікатів)
+* Nginx
+* HAProxy
+
+## Let's Encrypt { #lets-encrypt }
+
+До Let's Encrypt ці сертифікати HTTPS продавалися довіреними третіми сторонами.
+
+Процес отримання одного з таких сертифікатів був громіздким, вимагав чимало паперової роботи, а самі сертифікати були доволі дорогими.
+
+Але потім з'явився проєкт
Let's Encrypt.
+
+Це проєкт Linux Foundation. Він надає сертифікати HTTPS безкоштовно, в автоматизований спосіб. Ці сертифікати використовують усі стандартні криптографічні механізми безпеки і є короткостроковими (близько 3 місяців), тож безпека насправді краща завдяки зменшеній тривалості життя.
+
+Домени безпечно перевіряються, а сертифікати генеруються автоматично. Це також дозволяє автоматизувати поновлення цих сертифікатів.
+
+Ідея полягає в автоматизації отримання та поновлення цих сертифікатів, щоб ви могли мати безпечний HTTPS безкоштовно та назавжди.
+
+## HTTPS для розробників { #https-for-developers }
+
+Ось приклад того, як може виглядати HTTPS API, крок за кроком, зосереджуючись переважно на ідеях, важливих для розробників.
+
+### Доменне ім'я { #domain-name }
+
+Ймовірно, все почнеться з того, що ви придбаєте якесь доменне ім'я. Потім ви налаштуєте його на сервері DNS (можливо, у вашого ж хмарного провайдера).
+
+Ви, скоріш за все, отримаєте хмарний сервер (віртуальну машину) або щось подібне, і він матиме
фіксовану публічну IP-адресу.
+
+На сервері(ах) DNS ви налаштуєте запис («`A record`»), щоб спрямувати ваш домен на публічну IP-адресу вашого сервера.
+
+Ймовірно, ви зробите це лише один раз, уперше, коли все налаштовуватимете.
+
+/// tip | Порада
+
+Частина про доменне ім'я значно раніше за HTTPS, але оскільки все залежить від домену та IP-адреси, варто згадати це тут.
+
+///
+
+### DNS { #dns }
+
+Тепер зосередьмося на всіх власне частинах HTTPS.
+
+Спочатку браузер звернеться до серверів DNS, щоб дізнатися, яка IP-адреса для домену, у цьому випадку `someapp.example.com`.
+
+Сервери DNS повідомлять браузеру використати конкретну IP-адресу. Це буде публічна IP-адреса, яку використовує ваш сервер і яку ви налаштували на серверах DNS.
+
+

+
+### Початок TLS рукостискання { #tls-handshake-start }
+
+Потім браузер зв'яжеться з цією IP-адресою на порту 443 (порт HTTPS).
+
+Перша частина комунікації - це просто встановлення з'єднання між клієнтом і сервером та узгодження криптографічних ключів тощо.
+
+

+
+Ця взаємодія між клієнтом і сервером для встановлення з'єднання TLS називається TLS рукостисканням.
+
+### TLS із розширенням SNI { #tls-with-sni-extension }
+
+Лише один процес на сервері може слухати конкретний порт на конкретній IP-адресі. Інші процеси можуть слухати інші порти на тій самій IP-адресі, але лише один для кожної комбінації IP-адреси та порту.
+
+TLS (HTTPS) за замовчуванням використовує конкретний порт `443`. Отже, це порт, який нам потрібен.
+
+Оскільки лише один процес може слухати цей порт, процесом, що робитиме це, буде TLS Termination Proxy.
+
+TLS Termination Proxy матиме доступ до одного або кількох сертифікатів TLS (сертифікатів HTTPS).
+
+Використовуючи обговорене вище розширення SNI, TLS Termination Proxy перевірить, який із наявних сертифікатів TLS (HTTPS) слід використати для цього з'єднання, обравши той, що відповідає домену, очікуваному клієнтом.
+
+У цьому випадку він використає сертифікат для `someapp.example.com`.
+
+

+
+Клієнт уже довіряє сутності, яка видала цей сертифікат TLS (у цьому випадку Let's Encrypt, але про це згодом), тож він може перевірити, що сертифікат дійсний.
+
+Потім, використовуючи сертифікат, клієнт і TLS Termination Proxy узгоджують, як шифрувати решту TCP-комунікації. На цьому частина TLS рукостискання завершується.
+
+Після цього клієнт і сервер мають зашифроване TCP-з'єднання - саме це надає TLS. І тоді вони можуть використати це з'єднання, щоб почати власне HTTP-комунікацію.
+
+І це і є HTTPS: це звичайний HTTP усередині захищеного TLS-з'єднання замість чистого (незашифрованого) TCP-з'єднання.
+
+/// tip | Порада
+
+Зверніть увагу, що шифрування комунікації відбувається на рівні TCP, а не на рівні HTTP.
+
+///
+
+### HTTPS-запит { #https-request }
+
+Тепер, коли клієнт і сервер (конкретно браузер і TLS Termination Proxy) мають зашифроване TCP-з'єднання, вони можуть почати HTTP-комунікацію.
+
+Отже, клієнт надсилає HTTPS-запит. Це просто HTTP-запит через зашифроване TLS-з'єднання.
+
+

+
+### Розшифрування запиту { #decrypt-the-request }
+
+TLS Termination Proxy використає узгоджене шифрування, щоб розшифрувати запит, і передасть звичайний (розшифрований) HTTP-запит процесу, що запускає застосунок (наприклад, процесу з Uvicorn, який запускає застосунок FastAPI).
+
+

+
+### HTTP-відповідь { #http-response }
+
+Застосунок обробить запит і надішле звичайну (незашифровану) HTTP-відповідь TLS Termination Proxy.
+
+

+
+### HTTPS-відповідь { #https-response }
+
+Потім TLS Termination Proxy зашифрує відповідь, використовуючи попередньо узгоджену криптографію (що почалася із сертифіката для `someapp.example.com`), і надішле її назад у браузер.
+
+Далі браузер перевірить, що відповідь дійсна й зашифрована правильним криптографічним ключем тощо. Потім він розшифрує відповідь і обробить її.
+
+

+
+Клієнт (браузер) знатиме, що відповідь надходить від правильного сервера, тому що використовується узгоджена раніше криптографія з використанням сертифіката HTTPS.
+
+### Кілька застосунків { #multiple-applications }
+
+На тому самому сервері (або серверах) може бути кілька застосунків, наприклад інші програми API або база даних.
+
+Лише один процес може обробляти конкретну IP-адресу і порт (TLS Termination Proxy у нашому прикладі), але інші застосунки/процеси також можуть працювати на сервері(ах), доки вони не намагаються використати ту саму комбінацію публічної IP-адреси й порту.
+
+

+
+Таким чином, TLS Termination Proxy може обробляти HTTPS і сертифікати для кількох доменів, для кількох застосунків, а потім передавати запити до відповідного застосунку в кожному випадку.
+
+### Поновлення сертифіката { #certificate-renewal }
+
+У певний момент у майбутньому строк дії кожного сертифіката спливе (приблизно через 3 місяці після його отримання).
+
+Потім інша програма (в деяких випадках це інша програма, а в деяких - той самий TLS Termination Proxy) зв'яжеться з Let's Encrypt і поновить сертифікат(и).
+
+

+
+Сертифікати TLS пов'язані з доменним іменем, а не з IP-адресою.
+
+Тому, щоб поновити сертифікати, програма поновлення має довести авторитету (Let's Encrypt), що вона справді «володіє» і контролює цей домен.
+
+Щоб зробити це й задовольнити різні потреби застосунків, є кілька способів. Деякі популярні:
+
+* Змінити деякі записи DNS.
+ * Для цього програма поновлення має підтримувати API провайдера DNS, тож залежно від того, якого провайдера DNS ви використовуєте, це може бути або не бути варіантом.
+* Запуститися як сервер (принаймні під час процесу отримання сертифіката) на публічній IP-адресі, пов'язаній із доменом.
+ * Як ми казали вище, лише один процес може слухати конкретну IP-адресу та порт.
+ * Це одна з причин, чому дуже зручно, коли той самий TLS Termination Proxy також займається процесом поновлення сертифікатів.
+ * Інакше вам, можливо, доведеться на мить зупинити TLS Termination Proxy, запустити програму поновлення, щоб отримати сертифікати, потім налаштувати їх у TLS Termination Proxy і перезапустити TLS Termination Proxy. Це неідеально, оскільки ваші застосунки будуть недоступні під час вимкнення TLS Termination Proxy.
+
+Увесь цей процес поновлення, паралельно з обслуговуванням застосунку, - одна з головних причин, чому ви можете захотіти мати окрему систему для обробки HTTPS за допомогою TLS Termination Proxy замість того, щоб просто використовувати сертифікати TLS безпосередньо з сервером застосунку (наприклад, Uvicorn).
+
+## Направлені заголовки проксі { #proxy-forwarded-headers }
+
+Коли ви використовуєте проксі для обробки HTTPS, ваш сервер застосунку (наприклад, Uvicorn через FastAPI CLI) нічого не знає про процес HTTPS, він спілкується звичайним HTTP із TLS Termination Proxy.
+
+Цей проксі зазвичай динамічно встановлює деякі HTTP-заголовки перед передачею запиту серверу застосунку, щоб дати йому знати, що запит направляється проксі.
+
+/// note | Технічні деталі
+
+Заголовки проксі:
+
+*
X-Forwarded-For
+*
X-Forwarded-Proto
+*
X-Forwarded-Host
+
+///
+
+Втім, оскільки сервер застосунку не знає, що він стоїть за довіреним проксі, за замовчуванням він не довірятиме цим заголовкам.
+
+Але ви можете налаштувати сервер застосунку, щоб довіряти направленим заголовкам, надісланим проксі. Якщо ви використовуєте FastAPI CLI, ви можете скористатися курсивною *опцією CLI* `--forwarded-allow-ips`, щоб повідомити, з яких IP-адрес слід довіряти цим направленим заголовкам.
+
+Наприклад, якщо сервер застосунку отримує комунікацію лише від довіреного проксі, ви можете встановити `--forwarded-allow-ips="*"`, щоб довіряти всім вхідним IP-адресам, оскільки він отримуватиме запити лише з тієї IP-адреси, яку використовує проксі.
+
+Так застосунок зможе знати свою публічну URL-адресу, чи використовує він HTTPS, домен тощо.
+
+Це буде корисно, наприклад, для коректної обробки перенаправлень.
+
+/// tip | Порада
+
+Ви можете дізнатися більше про це в документації [За проксі - Увімкнути направлені заголовки проксі](../advanced/behind-a-proxy.md#enable-proxy-forwarded-headers){.internal-link target=_blank}
+
+///
+
+## Підсумок { #recap }
+
+Наявність HTTPS дуже важлива і в більшості випадків критична. Більшість зусиль, які вам як розробнику доведеться докласти навколо HTTPS, полягають лише в розумінні цих концепцій і того, як вони працюють.
+
+Але як тільки ви знаєте базову інформацію про HTTPS для розробників, ви можете легко комбінувати й налаштовувати різні інструменти, щоб керувати всім просто.
+
+У деяких наступних розділах я покажу кілька конкретних прикладів налаштування HTTPS для застосунків FastAPI. 🔒
diff --git a/docs/uk/docs/deployment/index.md b/docs/uk/docs/deployment/index.md
new file mode 100644
index 0000000000..7386681397
--- /dev/null
+++ b/docs/uk/docs/deployment/index.md
@@ -0,0 +1,23 @@
+# Розгортання { #deployment }
+
+Розгортання застосунку **FastAPI** відносно просте.
+
+## Що означає розгортання { #what-does-deployment-mean }
+
+Розгорнути застосунок - це виконати необхідні кроки, щоб зробити його доступним для користувачів.
+
+Для **веб API** це зазвичай означає розміщення його на **віддаленій машині** з **серверною програмою**, що забезпечує хорошу продуктивність, стабільність тощо, щоб ваші **користувачі** могли **отримувати доступ** до застосунку ефективно та без перерв чи проблем.
+
+Це відрізняється від етапів **розробки**, коли ви постійно змінюєте код, ламаєте й виправляєте його, зупиняєте та перезапускаєте сервер розробки тощо.
+
+## Стратегії розгортання { #deployment-strategies }
+
+Існує кілька способів зробити це залежно від вашого конкретного випадку використання та інструментів, які ви використовуєте.
+
+Ви можете розгорнути сервер самостійно, використовуючи комбінацію інструментів, можете скористатися **хмарним сервісом**, який виконує частину роботи за вас, або обрати інші варіанти.
+
+Наприклад, ми, команда, що стоїть за FastAPI, створили
**FastAPI Cloud**, щоб зробити розгортання застосунків FastAPI у хмарі якомога простішим і з тим самим досвідом розробки, що й під час роботи з FastAPI.
+
+Я покажу вам кілька основних концепцій, про які, ймовірно, варто пам'ятати під час розгортання **FastAPI**-застосунку (хоча більшість із них стосується будь-яких інших типів веб-застосунків).
+
+У наступних розділах ви побачите більше деталей, на які варто зважати, та деякі техніки, як це зробити. ✨
diff --git a/docs/uk/docs/deployment/manually.md b/docs/uk/docs/deployment/manually.md
new file mode 100644
index 0000000000..d70ec5d5d0
--- /dev/null
+++ b/docs/uk/docs/deployment/manually.md
@@ -0,0 +1,157 @@
+# Запустіть сервер вручну { #run-a-server-manually }
+
+## Використовуйте команду `fastapi run` { #use-the-fastapi-run-command }
+
+Коротко: використовуйте `fastapi run`, щоб запустити ваш застосунок FastAPI:
+
+
+
+```console
+$ fastapi run main.py
+
+ FastAPI Starting production server 🚀
+
+ Searching for package file structure from directories
+ with __init__.py files
+ Importing from /home/user/code/awesomeapp
+
+ module 🐍 main.py
+
+ code Importing the FastAPI app object from the module with
+ the following code:
+
+ from main import app
+
+ app Using import string: main:app
+
+ server Server started at http://0.0.0.0:8000
+ server Documentation at http://0.0.0.0:8000/docs
+
+ Logs:
+
+ INFO Started server process [2306215]
+ INFO Waiting for application startup.
+ INFO Application startup complete.
+ INFO Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C
+ to quit)
+```
+
+
+
+Це спрацює в більшості випадків. 😎
+
+Цю команду можна використати, наприклад, щоб запустити ваш застосунок FastAPI у контейнері, на сервері тощо.
+
+## Сервери ASGI { #asgi-servers }
+
+Розгляньмо деталі.
+
+FastAPI використовує стандарт для побудови Python вебфреймворків і серверів під назвою
ASGI. FastAPI - це ASGI вебфреймворк.
+
+Головне, що потрібно, щоб запустити застосунок **FastAPI** (або будь-який інший ASGI-застосунок) на віддаленій серверній машині, - це програма ASGI-сервера на кшталт **Uvicorn**; саме вона постачається за замовчуванням у команді `fastapi`.
+
+Є кілька альтернатив, зокрема:
+
+*
Uvicorn: високопродуктивний ASGI-сервер.
+*
Hypercorn: ASGI-сервер, сумісний з HTTP/2 і Trio, серед інших можливостей.
+*
Daphne: ASGI-сервер, створений для Django Channels.
+*
Granian: Rust HTTP-сервер для Python-застосунків.
+*
NGINX Unit: NGINX Unit - легке й універсальне середовище виконання вебзастосунків.
+
+## Серверна машина і серверна програма { #server-machine-and-server-program }
+
+Є невелика деталь щодо назв, яку варто пам'ятати. 💡
+
+Слово «**сервер**» зазвичай означає і віддалений/хмарний комп'ютер (фізична або віртуальна машина), і програму, що працює на цій машині (наприклад, Uvicorn).
+
+Майте на увазі, що коли ви бачите слово «сервер» загалом, воно може стосуватися будь-якого з цих двох значень.
+
+Коли йдеться про віддалену машину, її часто називають «сервер», а також «машина», «VM» (віртуальна машина), «вузол». Усе це означає різновиди віддаленої машини, зазвичай з Linux, на якій ви запускаєте програми.
+
+## Встановіть серверну програму { #install-the-server-program }
+
+Після встановлення FastAPI ви отримуєте продакшн-сервер Uvicorn і можете запускати його командою `fastapi run`.
+
+Але ви також можете встановити ASGI-сервер вручну.
+
+Переконайтеся, що ви створили [віртуальне оточення](../virtual-environments.md){.internal-link target=_blank}, активували його, після чого можете встановити серверну програму.
+
+Наприклад, щоб установити Uvicorn:
+
+
+
+```console
+$ pip install "uvicorn[standard]"
+
+---> 100%
+```
+
+
+
+Подібний процес застосовується до будь-якої іншої ASGI-серверної програми.
+
+/// tip | Порада
+
+Додавши `standard`, Uvicorn встановить і використовуватиме деякі рекомендовані додаткові залежності.
+
+Зокрема `uvloop` - високопродуктивну заміну «без змін у коді» для `asyncio`, що суттєво підвищує рівночасність і продуктивність.
+
+Якщо ви встановлюєте FastAPI через `pip install "fastapi[standard]"`, ви вже отримаєте і `uvicorn[standard]`.
+
+///
+
+## Запустіть серверну програму { #run-the-server-program }
+
+Якщо ви встановили ASGI-сервер вручну, зазвичай потрібно передати рядок імпорту в спеціальному форматі, щоб він імпортував ваш застосунок FastAPI:
+
+
+
+```console
+$ uvicorn main:app --host 0.0.0.0 --port 80
+
+INFO: Uvicorn running on http://0.0.0.0:80 (Press CTRL+C to quit)
+```
+
+
+
+/// note | Примітка
+
+Команда `uvicorn main:app` означає:
+
+* `main`: файл `main.py` (Python «модуль»).
+* `app`: об'єкт, створений у `main.py` рядком `app = FastAPI()`.
+
+Це еквівалентно:
+
+```Python
+from main import app
+```
+
+///
+
+Кожна альтернативна ASGI-серверна програма матиме подібну команду; читайте більше в їхній документації.
+
+/// warning | Попередження
+
+Uvicorn та інші сервери підтримують опцію `--reload`, корисну під час розробки.
+
+Опція `--reload` споживає значно більше ресурсів, є менш стабільною тощо.
+
+Вона дуже допомагає під час розробки, але її не слід використовувати в продакшні.
+
+///
+
+## Концепції розгортання { #deployment-concepts }
+
+Ці приклади запускають серверну програму (наприклад, Uvicorn), піднімаючи один процес, що слухає всі IP (`0.0.0.0`) на визначеному порту (наприклад, `80`).
+
+Це базова ідея. Але, ймовірно, вам знадобиться подбати ще про таке:
+
+* Безпека - HTTPS
+* Автозапуск
+* Перезапуски
+* Реплікація (кількість запущених процесів)
+* Пам'ять
+* Попередні кроки перед стартом
+
+У наступних розділах я розповім більше про кожну з цих концепцій, як про них думати, і наведу конкретні приклади та стратегії для їх опрацювання. 🚀
diff --git a/docs/uk/docs/deployment/server-workers.md b/docs/uk/docs/deployment/server-workers.md
new file mode 100644
index 0000000000..81a8bd2a4d
--- /dev/null
+++ b/docs/uk/docs/deployment/server-workers.md
@@ -0,0 +1,139 @@
+# Працівники сервера - Uvicorn з працівниками { #server-workers-uvicorn-with-workers }
+
+Повернімося до попередніх концепцій розгортання:
+
+- Безпека - HTTPS
+- Запуск під час старту
+- Перезапуски
+- Реплікація (кількість процесів, що виконуються)
+- Пам'ять
+- Попередні кроки перед запуском
+
+До цього моменту, проходячи всі навчальні посібники в документації, ви, ймовірно, запускали серверну програму, наприклад, використовуючи команду `fastapi`, яка запускає Uvicorn у вигляді одного процесу.
+
+Під час розгортання застосунків ви, найімовірніше, захочете мати реплікацію процесів, щоб використовувати кілька ядер і обробляти більше запитів.
+
+Як ви бачили в попередньому розділі про [Концепції розгортання](concepts.md){.internal-link target=_blank}, існує кілька стратегій, які можна використовувати.
+
+Тут я покажу, як використовувати Uvicorn із процесами-працівниками за допомогою команди `fastapi` або безпосередньо команди `uvicorn`.
+
+/// info | Інформація
+
+Якщо ви використовуєте контейнери, наприклад з Docker або Kubernetes, я розповім про це більше в наступному розділі: [FastAPI у контейнерах - Docker](docker.md){.internal-link target=_blank}.
+
+Зокрема, під час запуску в Kubernetes вам, найімовірніше, не варто використовувати працівників, натомість запускати один процес Uvicorn на контейнер. Але про це я розповім пізніше в тому розділі.
+
+///
+
+## Кілька працівників { #multiple-workers }
+
+Ви можете запустити кілька працівників за допомогою параметра командного рядка `--workers`:
+
+//// tab | `fastapi`
+
+Якщо ви використовуєте команду `fastapi`:
+
+
+
+```console
+$ fastapi run --workers 4 main.py
+
+ FastAPI Starting production server 🚀
+
+ Searching for package file structure from directories with
+ __init__.py files
+ Importing from /home/user/code/awesomeapp
+
+ module 🐍 main.py
+
+ code Importing the FastAPI app object from the module with the
+ following code:
+
+ from main import app
+
+ app Using import string: main:app
+
+ server Server started at http://0.0.0.0:8000
+ server Documentation at http://0.0.0.0:8000/docs
+
+ Logs:
+
+ INFO Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to
+ quit)
+ INFO Started parent process [27365]
+ INFO Started server process [27368]
+ INFO Started server process [27369]
+ INFO Started server process [27370]
+ INFO Started server process [27367]
+ INFO Waiting for application startup.
+ INFO Waiting for application startup.
+ INFO Waiting for application startup.
+ INFO Waiting for application startup.
+ INFO Application startup complete.
+ INFO Application startup complete.
+ INFO Application startup complete.
+ INFO Application startup complete.
+```
+
+
+
+////
+
+//// tab | `uvicorn`
+
+Якщо ви віддаєте перевагу використовувати команду `uvicorn` безпосередньо:
+
+
+
+```console
+$ uvicorn main:app --host 0.0.0.0 --port 8080 --workers 4
+INFO: Uvicorn running on http://0.0.0.0:8080 (Press CTRL+C to quit)
+INFO: Started parent process [27365]
+INFO: Started server process [27368]
+INFO: Waiting for application startup.
+INFO: Application startup complete.
+INFO: Started server process [27369]
+INFO: Waiting for application startup.
+INFO: Application startup complete.
+INFO: Started server process [27370]
+INFO: Waiting for application startup.
+INFO: Application startup complete.
+INFO: Started server process [27367]
+INFO: Waiting for application startup.
+INFO: Application startup complete.
+```
+
+
+
+////
+
+Єдина нова опція тут — `--workers`, яка вказує Uvicorn запустити 4 процеси-працівники.
+
+Також ви можете побачити, що виводиться PID кожного процесу: `27365` для батьківського процесу (це менеджер процесів) і по одному для кожного процесу-працівника: `27368`, `27369`, `27370` і `27367`.
+
+## Концепції розгортання { #deployment-concepts }
+
+Тут ви побачили, як використовувати кілька працівників, щоб паралелізувати виконання застосунку, використати кілька ядер процесора та обслуговувати більше запитів.
+
+Із наведеного вище списку концепцій розгортання, використання працівників головним чином допоможе з частиною про реплікацію і трохи з перезапусками, але про інше все ще треба подбати:
+
+- Безпека - HTTPS
+- Запуск під час старту
+- ***Перезапуски***
+- Реплікація (кількість процесів, що виконуються)
+- Пам'ять
+- Попередні кроки перед запуском
+
+## Контейнери і Docker { #containers-and-docker }
+
+У наступному розділі про [FastAPI у контейнерах - Docker](docker.md){.internal-link target=_blank} я поясню кілька стратегій, які ви можете використати для інших концепцій розгортання.
+
+Я покажу, як побудувати власний образ з нуля для запуску одного процесу Uvicorn. Це простий процес і, ймовірно, саме те, що потрібно при використанні розподіленої системи керування контейнерами, такої як Kubernetes.
+
+## Підсумок { #recap }
+
+Ви можете використовувати кілька процесів-працівників за допомогою параметра CLI `--workers` у командах `fastapi` або `uvicorn`, щоб скористатися перевагами багатоядерних процесорів і запускати кілька процесів паралельно.
+
+Ви можете застосувати ці інструменти та ідеї, якщо налаштовуєте власну систему розгортання і самостійно дбаєте про інші концепції розгортання.
+
+Перегляньте наступний розділ, щоб дізнатися про FastAPI з контейнерами (наприклад Docker і Kubernetes). Ви побачите, що ці інструменти також мають прості способи вирішити інші концепції розгортання. ✨
diff --git a/docs/uk/docs/deployment/versions.md b/docs/uk/docs/deployment/versions.md
new file mode 100644
index 0000000000..4f6d1b01a2
--- /dev/null
+++ b/docs/uk/docs/deployment/versions.md
@@ -0,0 +1,93 @@
+# Про версії FastAPI { #about-fastapi-versions }
+
+**FastAPI** уже використовується у продакшні в багатьох застосунках і системах. Покриття тестами підтримується на рівні 100%. Але розробка все ще рухається швидко.
+
+Нові можливості додаються часто, помилки регулярно виправляються, а код постійно поліпшується.
+
+Тому поточні версії все ще `0.x.x`, це відображає те, що кожна версія потенційно може містити несумісні зміни. Це відповідає правилам
Семантичного версіонування.
+
+Ви можете створювати продакшн-застосунки з **FastAPI** вже зараз (і, ймовірно, робите це вже певний час), просто переконайтеся, що ви використовуєте версію, яка коректно працює з рештою вашого коду.
+
+## Зафіксуйте версію `fastapi` { #pin-your-fastapi-version }
+
+Перше, що слід зробити, - «зафіксувати» версію **FastAPI**, яку ви використовуєте, до конкретної останньої версії, що, як ви знаєте, правильно працює для вашого застосунку.
+
+Наприклад, припустімо, що у вашому застосунку використовується версія `0.112.0`.
+
+Якщо ви використовуєте файл `requirements.txt`, ви можете вказати версію так:
+
+```txt
+fastapi[standard]==0.112.0
+```
+
+це означатиме, що ви використовуватимете саме версію `0.112.0`.
+
+Або ви також можете зафіксувати так:
+
+```txt
+fastapi[standard]>=0.112.0,<0.113.0
+```
+
+це означатиме, що ви використовуватимете версії `0.112.0` і вище, але менше `0.113.0`, наприклад, версія `0.112.2` все ще буде прийнятною.
+
+Якщо ви використовуєте інший інструмент для керування встановленнями, як-от `uv`, Poetry, Pipenv чи інші, у всіх них є спосіб визначати конкретні версії для ваших пакетів.
+
+## Доступні версії { #available-versions }
+
+Ви можете переглянути доступні версії (наприклад, щоб перевірити поточну останню) в [Примітках до випусків](../release-notes.md){.internal-link target=_blank}.
+
+## Про версії { #about-versions }
+
+Відповідно до правил Семантичного версіонування, будь-яка версія нижче `1.0.0` потенційно може містити несумісні зміни.
+
+FastAPI також дотримується правила, що будь-яка зміна «PATCH»-версії - це виправлення помилок і зміни без порушень сумісності.
+
+/// tip | Порада
+
+«PATCH» - це останнє число, наприклад, у `0.2.3` PATCH-версія - це `3`.
+
+///
+
+Тож ви можете зафіксувати версію так:
+
+```txt
+fastapi>=0.45.0,<0.46.0
+```
+
+Несумісні зміни та нові можливості додаються у «MINOR»-версіях.
+
+/// tip | Порада
+
+«MINOR» - це число посередині, наприклад, у `0.2.3` MINOR-версія - це `2`.
+
+///
+
+## Оновлення версій FastAPI { #upgrading-the-fastapi-versions }
+
+Ви повинні додати тести для вашого застосунку.
+
+З **FastAPI** це дуже легко (завдяки Starlette), перегляньте документацію: [Тестування](../tutorial/testing.md){.internal-link target=_blank}
+
+Після того як у вас є тести, ви можете оновити версію **FastAPI** до новішої і переконатися, що весь ваш код працює правильно, запустивши тести.
+
+Якщо все працює або після внесення необхідних змін і проходження всіх тестів, зафіксуйте вашу версію `fastapi` на цій новій версії.
+
+## Про Starlette { #about-starlette }
+
+Не варто фіксувати версію `starlette`.
+
+Різні версії **FastAPI** використовуватимуть конкретну новішу версію Starlette.
+
+Отже, просто дозвольте **FastAPI** використовувати відповідну версію Starlette.
+
+## Про Pydantic { #about-pydantic }
+
+Pydantic включає тести для **FastAPI** разом із власними тестами, тому нові версії Pydantic (вище `1.0.0`) завжди сумісні з FastAPI.
+
+Ви можете зафіксувати Pydantic на будь-якій версії вище `1.0.0`, яка вам підходить.
+
+Наприклад:
+
+```txt
+pydantic>=2.7.0,<3.0.0
+```
diff --git a/docs/uk/docs/environment-variables.md b/docs/uk/docs/environment-variables.md
new file mode 100644
index 0000000000..b61fd011f6
--- /dev/null
+++ b/docs/uk/docs/environment-variables.md
@@ -0,0 +1,298 @@
+# Змінні оточення { #environment-variables }
+
+/// tip | Порада
+
+Якщо ви вже знаєте, що таке «змінні оточення» і як їх використовувати, можете пропустити цей розділ.
+
+///
+
+Змінна оточення (також відома як «env var») - це змінна, що існує поза кодом Python, в операційній системі, і може бути прочитана вашим кодом Python (а також іншими програмами).
+
+Змінні оточення корисні для роботи з налаштуваннями застосунку, як частина встановлення Python тощо.
+
+## Створення і використання змінних оточення { #create-and-use-env-vars }
+
+Ви можете створювати і використовувати змінні оточення в оболонці (терміналі) без участі Python:
+
+//// tab | Linux, macOS, Windows Bash
+
+
+
+```console
+// Ви можете створити змінну оточення MY_NAME командою
+$ export MY_NAME="Wade Wilson"
+
+// Потім можна використати її з іншими програмами, наприклад
+$ echo "Hello $MY_NAME"
+
+Hello Wade Wilson
+```
+
+
+
+////
+
+//// tab | Windows PowerShell
+
+
+
+```console
+// Створіть змінну оточення MY_NAME
+$ $Env:MY_NAME = "Wade Wilson"
+
+// Використайте її з іншими програмами, наприклад
+$ echo "Hello $Env:MY_NAME"
+
+Hello Wade Wilson
+```
+
+
+
+////
+
+## Читання змінних оточення в Python { #read-env-vars-in-python }
+
+Ви також можете створити змінні оточення поза Python, у терміналі (або будь-яким іншим способом), а потім зчитати їх у Python.
+
+Наприклад, у вас може бути файл `main.py` з:
+
+```Python hl_lines="3"
+import os
+
+name = os.getenv("MY_NAME", "World")
+print(f"Hello {name} from Python")
+```
+
+/// tip | Порада
+
+Другий аргумент до
`os.getenv()` - це значення за замовчуванням, яке буде повернено.
+
+Якщо його не вказано, за замовчуванням це `None`. Тут ми надаємо `"World"` як значення за замовчуванням.
+
+///
+
+Потім ви можете запустити цю програму Python:
+
+//// tab | Linux, macOS, Windows Bash
+
+
+
+```console
+// Тут ми ще не встановлюємо змінну оточення
+$ python main.py
+
+// Оскільки ми не встановили змінну оточення, отримуємо значення за замовчуванням
+
+Hello World from Python
+
+// Але якщо спочатку створимо змінну оточення
+$ export MY_NAME="Wade Wilson"
+
+// А потім знову викличемо програму
+$ python main.py
+
+// Тепер вона може прочитати змінну оточення
+
+Hello Wade Wilson from Python
+```
+
+
+
+////
+
+//// tab | Windows PowerShell
+
+
+
+```console
+// Тут ми ще не встановлюємо змінну оточення
+$ python main.py
+
+// Оскільки ми не встановили змінну оточення, отримуємо значення за замовчуванням
+
+Hello World from Python
+
+// Але якщо спочатку створимо змінну оточення
+$ $Env:MY_NAME = "Wade Wilson"
+
+// А потім знову викличемо програму
+$ python main.py
+
+// Тепер вона може прочитати змінну оточення
+
+Hello Wade Wilson from Python
+```
+
+
+
+////
+
+Оскільки змінні оточення можна встановлювати поза кодом, але читати в коді, і їх не потрібно зберігати (фіксувати у `git`) разом з іншими файлами, їх часто використовують для конфігурацій або налаштувань.
+
+Ви також можете створити змінну оточення лише для конкретного запуску програми, вона буде доступна тільки цій програмі і лише на час її виконання.
+
+Щоб зробити це, створіть її безпосередньо перед командою запуску програми, в тому самому рядку:
+
+
+
+```console
+// Створіть змінну оточення MY_NAME безпосередньо в цьому виклику програми
+$ MY_NAME="Wade Wilson" python main.py
+
+// Тепер вона може прочитати змінну оточення
+
+Hello Wade Wilson from Python
+
+// Після цього змінна оточення більше не існує
+$ python main.py
+
+Hello World from Python
+```
+
+
+
+/// tip | Порада
+
+Докладніше про це можна прочитати у
The Twelve-Factor App: Config.
+
+///
+
+## Типи і перевірка { #types-and-validation }
+
+Ці змінні оточення можуть містити лише текстові строки, оскільки вони зовнішні щодо Python і мають бути сумісними з іншими програмами та рештою системи (і навіть з різними операційними системами, як-от Linux, Windows, macOS).
+
+Це означає, що будь-яке значення, прочитане в Python зі змінної оточення, буде `str`, а будь-яке перетворення до іншого типу або будь-яка перевірка має виконуватися в коді.
+
+Ви дізнаєтеся більше про використання змінних оточення для роботи з налаштуваннями застосунку в розділі [Просунутий посібник користувача - Налаштування і змінні оточення](./advanced/settings.md){.internal-link target=_blank}.
+
+## Змінна оточення `PATH` { #path-environment-variable }
+
+Є спеціальна змінна оточення `PATH`, яку використовують операційні системи (Linux, macOS, Windows) для пошуку програм для запуску.
+
+Значення змінної `PATH` - це довга строка, що складається з каталогів, розділених двокрапкою `:` у Linux і macOS та крапкою з комою `;` у Windows.
+
+Наприклад, змінна оточення `PATH` може виглядати так:
+
+//// tab | Linux, macOS
+
+```plaintext
+/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
+```
+
+Це означає, що система має шукати програми в каталогах:
+
+* `/usr/local/bin`
+* `/usr/bin`
+* `/bin`
+* `/usr/sbin`
+* `/sbin`
+
+////
+
+//// tab | Windows
+
+```plaintext
+C:\Program Files\Python312\Scripts;C:\Program Files\Python312;C:\Windows\System32
+```
+
+Це означає, що система має шукати програми в каталогах:
+
+* `C:\Program Files\Python312\Scripts`
+* `C:\Program Files\Python312`
+* `C:\Windows\System32`
+
+////
+
+Коли ви вводите команду в терміналі, операційна система шукає програму в кожному з тих каталогів, перелічених у змінній оточення `PATH`.
+
+Наприклад, коли ви вводите `python` у терміналі, операційна система шукає програму з назвою `python` у першому каталозі цього списку.
+
+Якщо знайде, вона використає її. Інакше продовжить пошук в інших каталогах.
+
+### Встановлення Python і оновлення `PATH` { #installing-python-and-updating-the-path }
+
+Під час встановлення Python вас можуть запитати, чи хочете ви оновити змінну оточення `PATH`.
+
+//// tab | Linux, macOS
+
+Припустімо, ви встановлюєте Python і він опиняється в каталозі `/opt/custompython/bin`.
+
+Якщо ви погодитеся оновити змінну оточення `PATH`, інсталятор додасть `/opt/custompython/bin` до змінної `PATH`.
+
+Це може виглядати так:
+
+```plaintext
+/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/custompython/bin
+```
+
+Тепер, коли ви введете `python` у терміналі, система знайде програму Python у `/opt/custompython/bin` (останній каталог) і використає саме її.
+
+////
+
+//// tab | Windows
+
+Припустімо, ви встановлюєте Python і він опиняється в каталозі `C:\opt\custompython\bin`.
+
+Якщо ви погодитеся оновити змінну оточення `PATH`, інсталятор додасть `C:\opt\custompython\bin` до змінної `PATH`.
+
+```plaintext
+C:\Program Files\Python312\Scripts;C:\Program Files\Python312;C:\Windows\System32;C:\opt\custompython\bin
+```
+
+Тепер, коли ви введете `python` у терміналі, система знайде програму Python у `C:\opt\custompython\bin` (останній каталог) і використає саме її.
+
+////
+
+Отже, якщо ви введете:
+
+
+
+```console
+$ python
+```
+
+
+
+//// tab | Linux, macOS
+
+Система знайде програму `python` у `/opt/custompython/bin` і запустить її.
+
+Це приблизно еквівалентно введенню:
+
+
+
+```console
+$ /opt/custompython/bin/python
+```
+
+
+
+////
+
+//// tab | Windows
+
+Система знайде програму `python` у `C:\opt\custompython\bin\python` і запустить її.
+
+Це приблизно еквівалентно введенню:
+
+
+
+```console
+$ C:\opt\custompython\bin\python
+```
+
+
+
+////
+
+Ця інформація стане у пригоді під час вивчення [Віртуальних середовищ](virtual-environments.md){.internal-link target=_blank}.
+
+## Висновок { #conclusion }
+
+Тепер ви маєте базове розуміння того, що таке змінні оточення і як їх використовувати в Python.
+
+Також можна прочитати більше у
Вікіпедії про змінну оточення.
+
+У багатьох випадках не одразу очевидно, як змінні оточення будуть корисними та застосовними. Але вони постійно з’являються в різних сценаріях під час розробки, тож варто про них знати.
+
+Наприклад, вам знадобиться ця інформація в наступному розділі про [Віртуальні середовища](virtual-environments.md).
diff --git a/docs/uk/docs/features.md b/docs/uk/docs/features.md
index d8233115fd..db044bf947 100644
--- a/docs/uk/docs/features.md
+++ b/docs/uk/docs/features.md
@@ -6,7 +6,7 @@
### На основі відкритих стандартів { #based-on-open-standards }
-*
OpenAPI для створення API, включаючи оголошення
шляхів,
операцій, параметрів, тіл запитів, безпеки тощо.
+*
OpenAPI для створення API, включаючи оголошення
шляхів,
операцій, параметрів, тіл запитів, безпеки тощо.
* Автоматична документація моделей даних за допомогою
JSON Schema (оскільки OpenAPI базується саме на JSON Schema).
* Розроблено на основі цих стандартів після ретельного аналізу, а не як додатковий рівень поверх основної архітектури.
* Це також дає змогу використовувати автоматичну **генерацію клієнтського коду** багатьма мовами.
@@ -136,7 +136,7 @@ FastAPI має розумні **налаштування за замовчува
### Впровадження залежностей { #dependency-injection }
-FastAPI містить надзвичайно просту у використанні, але надзвичайно потужну систему
Dependency Injection.
+FastAPI містить надзвичайно просту у використанні, але надзвичайно потужну систему
Впровадження залежностей.
* Навіть залежності можуть мати власні залежності, утворюючи ієрархію або **«граф» залежностей**.
* Усе **автоматично обробляється** фреймворком.
@@ -153,8 +153,8 @@ FastAPI містить надзвичайно просту у використа
### Протестовано { #tested }
-* 100%
покриття тестами.
-* 100%
анотована типами кодова база.
+* 100%
покриття тестами.
+* 100%
анотована типами кодова база.
* Використовується в production-застосунках.
## Можливості Starlette { #starlette-features }
@@ -190,7 +190,7 @@ FastAPI містить надзвичайно просту у використа
* **Ніякої плутанини**:
* Не потрібно вчити нову мікромову для визначення схем.
* Якщо ви знаєте типи Python, ви знаєте, як використовувати Pydantic.
-* Легко працює з вашим **
IDE/
linter/мозком**:
+* Легко працює з вашим **
IDE/
linter/мозком**:
* Оскільки структури даних pydantic є просто екземплярами класів, які ви визначаєте; автодоповнення, лінтинг, mypy і ваша інтуїція повинні добре працювати з вашими перевіреними даними.
* Валідує **складні структури**:
* Використання ієрархічних моделей Pydantic, Python `typing`’s `List` і `Dict` тощо.
diff --git a/docs/uk/docs/help-fastapi.md b/docs/uk/docs/help-fastapi.md
new file mode 100644
index 0000000000..a98e56c260
--- /dev/null
+++ b/docs/uk/docs/help-fastapi.md
@@ -0,0 +1,256 @@
+# Допоможіть FastAPI - отримайте допомогу { #help-fastapi-get-help }
+
+Вам подобається **FastAPI**?
+
+Хочете допомогти FastAPI, іншим користувачам та автору?
+
+Або ви хочете отримати допомогу щодо **FastAPI**?
+
+Є дуже прості способи допомогти (деякі потребують лише одного-двох кліків).
+
+І є кілька способів отримати допомогу.
+
+## Підпишіться на розсилку { #subscribe-to-the-newsletter }
+
+Ви можете підписатися на (нечасту) розсилку [**FastAPI and friends**](newsletter.md){.internal-link target=_blank}, щоб бути в курсі:
+
+* Новин про FastAPI та друзів 🚀
+* Посібників 📝
+* Можливостей ✨
+* Несумісних змін 🚨
+* Порад і трюків ✅
+
+## Стежте за FastAPI в X (Twitter) { #follow-fastapi-on-x-twitter }
+
+
Стежте за @fastapi в **X (Twitter)**, щоб отримувати найсвіжіші новини про **FastAPI**. 🐦
+
+## Додайте зірочку **FastAPI** на GitHub { #star-fastapi-in-github }
+
+Ви можете «поставити зірочку» FastAPI на GitHub (натиснувши кнопку зірочки у верхньому правому куті):
https://github.com/fastapi/fastapi. ⭐️
+
+Додавши зірочку, іншим користувачам буде легше його знайти і побачити, що він уже був корисним для інших.
+
+## Стежте за випусками в репозиторії GitHub { #watch-the-github-repository-for-releases }
+
+Ви можете «спостерігати» за FastAPI на GitHub (натиснувши кнопку «watch» у верхньому правому куті):
https://github.com/fastapi/fastapi. 👀
+
+Там ви можете вибрати «Releases only».
+
+Зробивши це, ви отримуватимете сповіщення (на вашу електронну пошту) щоразу, коли вийде новий реліз (нова версія) **FastAPI** з виправленнями помилок і новими можливостями.
+
+## Зв'яжіться з автором { #connect-with-the-author }
+
+Ви можете зв'язатися зі
мною (Sebastián Ramírez / `tiangolo`), автором.
+
+Ви можете:
+
+*
Стежити за мною на **GitHub**.
+ * Подивитися інші Open Source-проєкти, які я створив і які можуть вам допомогти.
+ * Стежити, щоб бачити, коли я створюю новий Open Source-проєкт.
+*
Стежити за мною в **X (Twitter)** або
Mastodon.
+ * Розкажіть мені, як ви використовуєте FastAPI (мені дуже приємно це чути).
+ * Дізнаватися, коли я роблю оголошення або випускаю нові інструменти.
+ * Також ви можете
стежити за @fastapi в X (Twitter) (окремий акаунт).
+*
Стежити за мною в **LinkedIn**.
+ * Дізнаватися, коли я роблю оголошення або випускаю нові інструменти (хоча X (Twitter) я використовую частіше 🤷♂).
+* Читати, що я пишу (або стежити за мною) на
**Dev.to** або
**Medium**.
+ * Читати інші ідеї, статті та про інструменти, які я створив.
+ * Стежити, щоб читати нове, коли я щось публікую.
+
+## Твітніть про **FastAPI** { #tweet-about-fastapi }
+
+
Твітніть про **FastAPI** і дайте мені та іншим знати, чому він вам подобається. 🎉
+
+Мені дуже подобається дізнаватися, як використовують **FastAPI**, що вам у ньому сподобалося, у якому проєкті/компанії ви його застосовуєте тощо.
+
+## Голосуйте за FastAPI { #vote-for-fastapi }
+
+*
Проголосуйте за **FastAPI** на Slant.
+*
Проголосуйте за **FastAPI** на AlternativeTo.
+*
Повідомте, що ви використовуєте **FastAPI**, на StackShare.
+
+## Допомагайте іншим з питаннями на GitHub { #help-others-with-questions-in-github }
+
+Ви можете спробувати допомагати іншим з їхніми питаннями у:
+
+*
GitHub Discussions
+*
GitHub Issues
+
+У багатьох випадках ви вже можете знати відповідь на ці питання. 🤓
+
+Якщо ви багато допомагаєте людям із їхніми питаннями, ви станете офіційним [Експертом FastAPI](fastapi-people.md#fastapi-experts){.internal-link target=_blank}. 🎉
+
+Пам'ятайте, найважливіше: намагайтеся бути добрими. Люди приходять зі своєю фрустрацією і часто питають не найкращим чином, але постарайтеся бути якомога доброзичливішими. 🤗
+
+Ідея в тому, щоб спільнота **FastAPI** була доброзичливою та гостинною. Водночас не терпіть булінг чи неповажну поведінку щодо інших. Ми маємо піклуватися одне про одного.
+
+---
+
+Ось як допомагати іншим із питаннями (у discussions або issues):
+
+### Зрозумійте питання { #understand-the-question }
+
+* Перевірте, чи розумієте ви **мету** та варіант використання людини, яка питає.
+
+* Потім перевірте, чи **чітке** саме питання (переважна більшість — це питання).
+
+* Часто запит стосується уявного рішення користувача, але може бути **краще**. Якщо ви краще зрозумієте проблему та варіант використання, зможете запропонувати кращу **альтернативу**.
+
+* Якщо ви не розумієте питання, попросіть більше **подробиць**.
+
+### Відтворіть проблему { #reproduce-the-problem }
+
+У більшості випадків і запитань мова йде про **оригінальний код** людини.
+
+Часто вони наводять лише фрагмент коду, але цього недостатньо, щоб **відтворити проблему**.
+
+* Ви можете попросити надати
мінімальний, відтворюваний приклад, який ви зможете **скопіювати-вставити** і запустити локально, щоб побачити ту саму помилку або поведінку, яку бачать вони, або краще зрозуміти їхній варіант використання.
+
+* Якщо ви дуже щедрі, можете спробувати **створити такий приклад** самостійно, лише на основі опису проблеми. Просто майте на увазі, що це може зайняти багато часу, і краще спочатку попросити їх уточнити проблему.
+
+### Запропонуйте рішення { #suggest-solutions }
+
+* Після того як ви змогли зрозуміти питання, дайте можливу **відповідь**.
+
+* Часто краще зрозуміти їхню **первинну проблему або варіант використання**, адже може бути кращий спосіб її вирішити, ніж те, що вони намагаються зробити.
+
+### Попросіть закрити { #ask-to-close }
+
+Якщо вони відповіли, дуже ймовірно, що ви розв'язали їхню проблему. Вітаю, **ви герой**! 🦸
+
+* Тепер, якщо це вирішило їхню проблему, ви можете попросити:
+
+ * У GitHub Discussions: позначити коментар як **відповідь**.
+ * У GitHub Issues: **закрити** issue.
+
+## Стежте за репозиторієм GitHub { #watch-the-github-repository }
+
+Ви можете «спостерігати» за FastAPI на GitHub (натиснувши кнопку «watch» у верхньому правому куті):
https://github.com/fastapi/fastapi. 👀
+
+Якщо вибрати «Watching» замість «Releases only», ви отримуватимете сповіщення, коли хтось створює нове issue або питання. Ви також можете вказати, що хочете отримувати сповіщення лише про нові issues, або discussions, або PR тощо.
+
+Тоді ви зможете спробувати допомогти їм вирішити ці питання.
+
+## Ставте питання { #ask-questions }
+
+Ви можете
створити нове питання у репозиторії GitHub, наприклад, щоб:
+
+* Поставити **питання** або запитати про **проблему**.
+* Запропонувати нову **можливість**.
+
+**Примітка**: якщо ви це зробите, я попрошу вас також допомагати іншим. 😉
+
+## Переглядайте запити на витяг { #review-pull-requests }
+
+Ви можете допомогти мені переглядати запити на витяг інших.
+
+І знову, будь ласка, намагайтеся бути якомога доброзичливішими. 🤗
+
+---
+
+Ось що слід пам'ятати і як переглядати запит на витяг:
+
+### Зрозумійте проблему { #understand-the-problem }
+
+* Спочатку переконайтеся, що ви **розумієте проблему**, яку намагається вирішити запит на витяг. Може бути довша дискусія у GitHub Discussion або issue.
+
+* Також є велика ймовірність, що запит на витяг насправді не потрібен, бо проблему можна розв'язати **іншим способом**. Тоді ви можете про це запропонувати або запитати.
+
+### Не переймайтеся стилем { #dont-worry-about-style }
+
+* Не надто хвилюйтеся про стиль повідомлень фіксацій, я зроблю squash and merge, налаштувавши фіксацію вручну.
+
+* Також не переймайтеся правилами стилю, вже є автоматизовані інструменти, що це перевіряють.
+
+А якщо будуть інші вимоги щодо стилю чи узгодженості, я попрошу про це безпосередньо або додам зверху фіксації з потрібними змінами.
+
+### Перевірте код { #check-the-code }
+
+* Перегляньте та прочитайте код, оцініть, чи він має сенс, **запустіть його локально** і перевірте, чи справді він розв'язує проблему.
+
+* Потім залиште **коментар**, що ви це зробили, так я знатиму, що ви справді перевірили.
+
+/// info | Інформація
+
+На жаль, я не можу просто довіряти PR, які мають кілька схвалень.
+
+Бувало не раз, що PR мали 3, 5 або більше схвалень, мабуть тому, що опис привабливий, але коли я перевіряв PR, вони виявлялися зламаними, мали помилку або не розв'язували заявлену проблему. 😅
+
+Тож дуже важливо, щоб ви справді прочитали і запустили код та повідомили в коментарях, що ви це зробили. 🤓
+
+///
+
+* Якщо PR можна якось спростити, ви можете про це попросити, але немає потреби бути надто прискіпливими, адже може бути багато суб'єктивних точок зору (і в мене також є своя 🙈), тож краще зосередитися на фундаментальних речах.
+
+### Тести { #tests }
+
+* Допоможіть перевірити, що PR має **тести**.
+
+* Переконайтеся, що тести **падають** до PR. 🚨
+
+* Потім перевірте, що тести **проходять** після PR. ✅
+
+* Багато PRів не мають тестів, ви можете **нагадати** додати тести або навіть **запропонувати** деякі тести самі. Це одна з речей, яка найбільше забирає часу, і ви дуже допоможете.
+
+* Потім також прокоментуйте, що саме ви спробували, так я знатиму, що ви це перевірили. 🤓
+
+## Створіть запит на витяг { #create-a-pull-request }
+
+Ви можете [зробити внесок](contributing.md){.internal-link target=_blank} у вихідний код із запитами на витяг, наприклад:
+
+* Щоб виправити описку, знайдену в документації.
+* Щоб поділитися статтею, відео або подкастом про FastAPI, який ви створили або знайшли,
відредагувавши цей файл.
+ * Обов'язково додайте ваше посилання на початок відповідного розділу.
+* Щоб допомогти [перекласти документацію](contributing.md#translations){.internal-link target=_blank} вашою мовою.
+ * Ви також можете допомогти з переглядом перекладів, створених іншими.
+* Щоб запропонувати нові розділи документації.
+* Щоб виправити наявну проблему/помилку.
+ * Обов'язково додайте тести.
+* Щоб додати нову можливість.
+ * Обов'язково додайте тести.
+ * Обов'язково додайте документацію, якщо це доречно.
+
+## Допоможіть підтримувати FastAPI { #help-maintain-fastapi }
+
+Допоможіть мені підтримувати **FastAPI**! 🤓
+
+Роботи багато, і більшу її частину можете зробити **ВИ**.
+
+Основні завдання, які ви можете виконувати вже зараз:
+
+* [Допомагайте іншим з питаннями на GitHub](#help-others-with-questions-in-github){.internal-link target=_blank} (див. розділ вище).
+* [Переглядайте запити на витяг](#review-pull-requests){.internal-link target=_blank} (див. розділ вище).
+
+Ці два завдання **найбільше споживають час**. Це основна робота з підтримки FastAPI.
+
+Якщо ви можете допомогти мені з цим, **ви допомагаєте підтримувати FastAPI** і гарантуєте, що він **рухатиметься швидше й краще**. 🚀
+
+## Долучайтеся до чату { #join-the-chat }
+
+Долучайтеся до 👥
серверу чату Discord 👥 і спілкуйтеся з іншими в спільноті FastAPI.
+
+/// tip | Порада
+
+Для запитань ставте їх у
GitHub Discussions, там значно вища ймовірність, що вам допоможуть [Експерти FastAPI](fastapi-people.md#fastapi-experts){.internal-link target=_blank}.
+
+Використовуйте чат лише для інших загальних розмов.
+
+///
+
+### Не використовуйте чат для запитань { #dont-use-the-chat-for-questions }
+
+Майте на увазі, що оскільки чати дозволяють більше «вільної розмови», легко ставити надто загальні питання, на які складніше відповісти, тож ви можете не отримати відповідей.
+
+У GitHub шаблон підкаже вам, як написати правильне питання, щоб ви легше отримали хорошу відповідь, або навіть вирішили проблему самостійно ще до запиту. І в GitHub я можу гарантувати, що завжди на все відповім, навіть якщо це займе трохи часу. Особисто я не можу робити це в чатах. 😅
+
+Розмови в чатах також не так просто шукати, як у GitHub, тож питання та відповіді можуть загубитися. І лише ті, що в GitHub, зараховуються, щоб стати [Експертом FastAPI](fastapi-people.md#fastapi-experts){.internal-link target=_blank}, тож швидше за все ви отримаєте більше уваги саме в GitHub.
+
+З іншого боку, у чатах є тисячі користувачів, тож дуже ймовірно, що ви майже завжди знайдете там співрозмовника. 😄
+
+## Спонсоруйте автора { #sponsor-the-author }
+
+Якщо ваш **продукт/компанія** залежить від **FastAPI** або пов'язана з ним і ви хочете охопити його користувачів, ви можете спонсорувати автора (мене) через
GitHub sponsors. Залежно від рівня ви можете отримати додаткові переваги, наприклад значок у документації. 🎁
+
+---
+
+Дякую! 🚀
diff --git a/docs/uk/docs/history-design-future.md b/docs/uk/docs/history-design-future.md
new file mode 100644
index 0000000000..1897807c84
--- /dev/null
+++ b/docs/uk/docs/history-design-future.md
@@ -0,0 +1,79 @@
+# Історія, проєктування і майбутнє { #history-design-and-future }
+
+Деякий час тому
користувач **FastAPI** запитав:
+
+> Яка історія цього проєкту? Здається, він нізвідки за кілька тижнів став чудовим [...]
+
+Ось трохи цієї історії.
+
+## Альтернативи { #alternatives }
+
+Я створював API зі складними вимогами протягом кількох років (машинне навчання, розподілені системи, асинхронні завдання, бази даних NoSQL тощо), очолюючи кілька команд розробників.
+
+У межах цього мені довелося досліджувати, тестувати й використовувати багато альтернатив.
+
+Історія **FastAPI** значною мірою - це історія його попередників.
+
+Як сказано в розділі [Альтернативи](alternatives.md){.internal-link target=_blank}:
+
+
+
+**FastAPI** не існував би без попередньої роботи інших.
+
+Було створено багато інструментів, які надихнули на його створення.
+
+Я роками уникав створення нового фреймворку. Спочатку я намагався вирішити всі можливості, які покриває **FastAPI**, використовуючи різні фреймворки, плагіни та інструменти.
+
+Але в певний момент не залишилося іншого варіанту, окрім створити щось, що надає всі ці можливості, узявши найкращі ідеї з попередніх інструментів і поєднавши їх якнайкраще, використовуючи можливості самої мови, яких раніше взагалі не було (підказки типів Python 3.6+).
+
+
+
+## Дослідження { #investigation }
+
+Використовуючи всі попередні альтернативи, я мав змогу повчитися в кожної, узяти ідеї й поєднати їх якнайкраще для себе та команд розробників, з якими працював.
+
+Наприклад, було очевидно, що в ідеалі все має ґрунтуватися на стандартних підказках типів Python.
+
+Також найкращим підходом було використовувати вже наявні стандарти.
+
+Тож, ще до початку написання коду **FastAPI**, я провів кілька місяців, вивчаючи специфікації OpenAPI, Схеми JSON, OAuth2 тощо. Розуміючи їхні взаємозв'язки, перетини та відмінності.
+
+## Проєктування { #design }
+
+Потім я приділив час проєктуванню «API» для розробника, яке я хотів мати як користувач (як розробник, що використовує FastAPI).
+
+Я протестував кілька ідей у найпопулярніших Python-редакторах: PyCharm, VS Code, редакторах на основі Jedi.
+
+За даними
Python Developer Survey, це охоплює близько 80% користувачів.
+
+Це означає, що **FastAPI** спеціально тестувався з редакторами, якими користуються 80% розробників Python. І оскільки більшість інших редакторів працюють подібно, усі ці переваги мають працювати практично у всіх редакторах.
+
+Так я зміг знайти найкращі способи максимально зменшити дублювання коду, забезпечити автодоповнення всюди, перевірки типів і помилок тощо.
+
+І все це так, щоб надати найкращий досвід розробки для всіх розробників.
+
+## Вимоги { #requirements }
+
+Після перевірки кількох альтернатив я вирішив використовувати
**Pydantic** через його переваги.
+
+Потім я зробив внески до нього, щоб зробити його повністю сумісним із Схемою JSON, додати підтримку різних способів оголошення обмежень і поліпшити підтримку редакторів (перевірки типів, автодоповнення) на основі тестів у кількох редакторах.
+
+Під час розробки я також зробив внески до
**Starlette**, іншої ключової залежності.
+
+## Розробка { #development }
+
+Коли я взявся безпосередньо за створення **FastAPI**, більшість складових уже були на місцях: дизайн визначено, вимоги та інструменти підготовлено, знання про стандарти й специфікації - чіткі та свіжі.
+
+## Майбутнє { #future }
+
+На цей момент уже зрозуміло, що **FastAPI** зі своїми ідеями корисний для багатьох.
+
+Його обирають замість попередніх альтернатив, бо він краще відповідає багатьом сценаріям використання.
+
+Багато розробників і команд уже залежать від **FastAPI** у своїх проєктах (включно зі мною та моєю командою).
+
+Але попереду ще багато покращень і можливостей.
+
+**FastAPI** має велике майбутнє.
+
+І [ваша допомога](help-fastapi.md){.internal-link target=_blank} дуже цінується.
diff --git a/docs/uk/docs/how-to/authentication-error-status-code.md b/docs/uk/docs/how-to/authentication-error-status-code.md
new file mode 100644
index 0000000000..58016f261b
--- /dev/null
+++ b/docs/uk/docs/how-to/authentication-error-status-code.md
@@ -0,0 +1,17 @@
+# Використовуйте старі коди статусу помилки автентифікації 403 { #use-old-403-authentication-error-status-codes }
+
+До версії FastAPI `0.122.0`, коли інтегровані засоби безпеки повертали клієнту помилку після невдалої автентифікації, вони використовували HTTP код статусу `403 Forbidden`.
+
+Починаючи з версії FastAPI `0.122.0`, вони використовують більш доречний HTTP код статусу `401 Unauthorized` і повертають змістовний заголовок `WWW-Authenticate` у відповіді, відповідно до специфікацій HTTP,
RFC 7235,
RFC 9110.
+
+Але якщо з якоїсь причини ваші клієнти залежать від старої поведінки, ви можете повернутися до неї, переписавши метод `make_not_authenticated_error` у ваших класах безпеки.
+
+Наприклад, ви можете створити підклас `HTTPBearer`, який повертатиме помилку `403 Forbidden` замість типового `401 Unauthorized`:
+
+{* ../../docs_src/authentication_error_status_code/tutorial001_an_py310.py hl[9:13] *}
+
+/// tip | Порада
+
+Зверніть увагу, що функція повертає екземпляр винятку, вона не породжує його. Породження відбувається в іншій частині внутрішнього коду.
+
+///
diff --git a/docs/uk/docs/how-to/conditional-openapi.md b/docs/uk/docs/how-to/conditional-openapi.md
new file mode 100644
index 0000000000..f8bbaa6498
--- /dev/null
+++ b/docs/uk/docs/how-to/conditional-openapi.md
@@ -0,0 +1,56 @@
+# Умовний OpenAPI { #conditional-openapi }
+
+Якщо потрібно, ви можете використовувати налаштування і змінні оточення, щоб умовно налаштовувати OpenAPI залежно від середовища, а також повністю вимикати його.
+
+## Про безпеку, API та документацію { #about-security-apis-and-docs }
+
+Приховування інтерфейсів документації у продукційному середовищі *не має* бути способом захисту вашого API.
+
+Це не додає жодної додаткової безпеки вашому API, *операції шляху* й надалі будуть доступні там, де вони є.
+
+Якщо у вашому коді є вразливість, вона залишиться.
+
+Приховування документації лише ускладнює розуміння того, як взаємодіяти з вашим API, і може ускладнити для вас його налагодження у продакшні. Це можна вважати просто формою
Безпека через неясність.
+
+Якщо ви хочете захистити ваш API, є кілька кращих дій, які ви можете зробити, наприклад:
+
+- Переконайтеся, що у вас добре визначені моделі Pydantic для тіл запитів і відповідей.
+- Налаштуйте потрібні дозволи та ролі за допомогою залежностей.
+- Ніколи не зберігайте паролі у відкритому вигляді, лише хеші паролів.
+- Реалізуйте та використовуйте відомі криптографічні інструменти, як-от pwdlib і токени JWT.
+- Додайте більш детальний контроль дозволів із областями OAuth2 там, де це потрібно.
+- ...тощо.
+
+Втім, у вас може бути дуже специфічний випадок використання, коли справді потрібно вимкнути документацію API для певного середовища (наприклад, для продакшну) або залежно від конфігурацій зі змінних оточення.
+
+## Умовний OpenAPI з налаштувань і змінних оточення { #conditional-openapi-from-settings-and-env-vars }
+
+Ви можете легко використати ті самі налаштування Pydantic, щоб налаштувати згенерований OpenAPI та інтерфейси документації.
+
+Наприклад:
+
+{* ../../docs_src/conditional_openapi/tutorial001_py310.py hl[6,11] *}
+
+Тут ми оголошуємо налаштування `openapi_url` з тим самим значенням за замовчуванням `"/openapi.json"`.
+
+Потім ми використовуємо його під час створення застосунку `FastAPI`.
+
+Далі ви можете вимкнути OpenAPI (включно з інтерфейсами документації), встановивши змінну оточення `OPENAPI_URL` у пусту строку, наприклад:
+
+
+
+```console
+$ OPENAPI_URL= uvicorn main:app
+
+INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
+```
+
+
+
+Потім, якщо ви перейдете за URL `/openapi.json`, `/docs` або `/redoc`, ви просто отримаєте помилку `404 Not Found` на кшталт:
+
+```JSON
+{
+ "detail": "Not Found"
+}
+```
diff --git a/docs/uk/docs/how-to/configure-swagger-ui.md b/docs/uk/docs/how-to/configure-swagger-ui.md
new file mode 100644
index 0000000000..f8c4470dfa
--- /dev/null
+++ b/docs/uk/docs/how-to/configure-swagger-ui.md
@@ -0,0 +1,70 @@
+# Налаштуйте Swagger UI { #configure-swagger-ui }
+
+Ви можете налаштувати додаткові
параметри Swagger UI.
+
+Щоб їх налаштувати, передайте аргумент `swagger_ui_parameters` під час створення об’єкта додатка `FastAPI()` або до функції `get_swagger_ui_html()`.
+
+`swagger_ui_parameters` отримує словник із налаштуваннями, що передаються безпосередньо до Swagger UI.
+
+FastAPI перетворює ці налаштування на **JSON**, щоб зробити їх сумісними з JavaScript, оскільки саме це потрібно Swagger UI.
+
+## Вимкніть підсвітку синтаксису { #disable-syntax-highlighting }
+
+Наприклад, ви можете вимкнути підсвітку синтаксису в Swagger UI.
+
+Без змін у налаштуваннях підсвітка синтаксису увімкнена за замовчуванням:
+
+

+
+Але ви можете вимкнути її, встановивши `syntaxHighlight` у `False`:
+
+{* ../../docs_src/configure_swagger_ui/tutorial001_py310.py hl[3] *}
+
+...після цього Swagger UI більше не показуватиме підсвітку синтаксису:
+
+

+
+## Змініть тему { #change-the-theme }
+
+Так само ви можете задати тему підсвітки синтаксису ключем `"syntaxHighlight.theme"` (зверніть увагу, що посередині є крапка):
+
+{* ../../docs_src/configure_swagger_ui/tutorial002_py310.py hl[3] *}
+
+Це налаштування змінить колірну тему підсвітки синтаксису:
+
+

+
+## Змініть параметри Swagger UI за замовчуванням { #change-default-swagger-ui-parameters }
+
+FastAPI містить деякі параметри конфігурації за замовчуванням, що підходять для більшості випадків.
+
+Вони включають такі типові налаштування:
+
+{* ../../fastapi/openapi/docs.py ln[9:24] hl[18:24] *}
+
+Ви можете переписати будь-яке з них, задавши інше значення в аргументі `swagger_ui_parameters`.
+
+Наприклад, щоб вимкнути `deepLinking`, ви можете передати такі налаштування до `swagger_ui_parameters`:
+
+{* ../../docs_src/configure_swagger_ui/tutorial003_py310.py hl[3] *}
+
+## Інші параметри Swagger UI { #other-swagger-ui-parameters }
+
+Щоб побачити всі можливі налаштування, які ви можете використовувати, прочитайте офіційну
документацію щодо параметрів Swagger UI.
+
+## Налаштування лише для JavaScript { #javascript-only-settings }
+
+Swagger UI також дозволяє інші налаштування як об’єкти, що є тільки для **JavaScript** (наприклад, функції JavaScript).
+
+FastAPI також включає такі налаштування `presets`, що є лише для JavaScript:
+
+```JavaScript
+presets: [
+ SwaggerUIBundle.presets.apis,
+ SwaggerUIBundle.SwaggerUIStandalonePreset
+]
+```
+
+Це об’єкти **JavaScript**, а не строки, тому ви не можете передати їх безпосередньо з коду Python.
+
+Якщо вам потрібно використати такі налаштування лише для JavaScript, скористайтеся одним із методів вище. Повністю перепишіть операцію шляху Swagger UI та вручну напишіть потрібний JavaScript.
diff --git a/docs/uk/docs/how-to/custom-docs-ui-assets.md b/docs/uk/docs/how-to/custom-docs-ui-assets.md
new file mode 100644
index 0000000000..faea3ccc4a
--- /dev/null
+++ b/docs/uk/docs/how-to/custom-docs-ui-assets.md
@@ -0,0 +1,185 @@
+# Користувацькі статичні ресурси інтерфейсу документації (самохостинг) { #custom-docs-ui-static-assets-self-hosting }
+
+Документація API використовує **Swagger UI** і **ReDoc**, і кожному з них потрібні файли JavaScript та CSS.
+
+Типово ці файли віддаються з
CDN.
+
+Але це можна налаштувати: ви можете вказати конкретний CDN або віддавати файли самостійно.
+
+## Власний CDN для JavaScript і CSS { #custom-cdn-for-javascript-and-css }
+
+Припустімо, що ви хочете використовувати інший
CDN, наприклад `https://unpkg.com/`.
+
+Це може бути корисно, якщо, наприклад, ви живете в країні, що обмежує деякі URL-адреси.
+
+### Вимкніть автоматичну документацію { #disable-the-automatic-docs }
+
+Перший крок - вимкнути автоматичну документацію, адже типово вона використовує стандартний CDN.
+
+Щоб їх вимкнути, встановіть їхні URL у `None` під час створення вашого застосунку `FastAPI`:
+
+{* ../../docs_src/custom_docs_ui/tutorial001_py310.py hl[8] *}
+
+### Додайте користувацьку документацію { #include-the-custom-docs }
+
+Тепер ви можете створити *операції шляху* для користувацької документації.
+
+Ви можете перевикористати внутрішні функції FastAPI для створення HTML-сторінок документації і передати їм потрібні аргументи:
+
+- `openapi_url`: URL, за яким HTML-сторінка документації зможе отримати схему OpenAPI для вашого API. Тут можна використати атрибут `app.openapi_url`.
+- `title`: заголовок вашого API.
+- `oauth2_redirect_url`: тут можна використати `app.swagger_ui_oauth2_redirect_url`, щоб узяти значення за замовчуванням.
+- `swagger_js_url`: URL, за яким HTML для Swagger UI зможе отримати файл **JavaScript**. Це URL вашого користувацького CDN.
+- `swagger_css_url`: URL, за яким HTML для Swagger UI зможе отримати файл **CSS**. Це URL вашого користувацького CDN.
+
+Аналогічно для ReDoc...
+
+{* ../../docs_src/custom_docs_ui/tutorial001_py310.py hl[2:6,11:19,22:24,27:33] *}
+
+/// tip | Порада
+
+*Операція шляху* для `swagger_ui_redirect` - це допоміжний маршрут, коли ви використовуєте OAuth2.
+
+Якщо ви інтегруєте ваш API з провайдером OAuth2, ви зможете автентифікуватися і повернутися до документації API з отриманими обліковими даними. І взаємодіяти з ним, використовуючи реальну автентифікацію OAuth2.
+
+Swagger UI впорається з цим «за лаштунками», але йому потрібен цей «redirect» хелпер.
+
+///
+
+### Створіть операцію шляху для перевірки { #create-a-path-operation-to-test-it }
+
+Тепер, щоб перевірити, що все працює, створіть *операцію шляху*:
+
+{* ../../docs_src/custom_docs_ui/tutorial001_py310.py hl[36:38] *}
+
+### Перевірте { #test-it }
+
+Тепер ви маєте змогу відкрити документацію за
http://127.0.0.1:8000/docs і перезавантажити сторінку, вона завантажить ці ресурси з нового CDN.
+
+## Самохостинг JavaScript і CSS для документації { #self-hosting-javascript-and-css-for-docs }
+
+Самохостинг JavaScript і CSS може бути корисним, якщо, наприклад, ваш застосунок має працювати офлайн, без доступу до Інтернету, або в локальній мережі.
+
+Тут ви побачите, як віддавати ці файли самостійно, у тому самому застосунку FastAPI, і налаштувати документацію на їх використання.
+
+### Структура файлів проєкту { #project-file-structure }
+
+Припустімо, що структура файлів вашого проєкту виглядає так:
+
+```
+.
+├── app
+│ ├── __init__.py
+│ ├── main.py
+```
+
+Тепер створіть каталог для збереження цих статичних файлів.
+
+Нова структура файлів може виглядати так:
+
+```
+.
+├── app
+│ ├── __init__.py
+│ ├── main.py
+└── static/
+```
+
+### Завантажте файли { #download-the-files }
+
+Завантажте статичні файли, потрібні для документації, і помістіть їх у каталог `static/`.
+
+Ви, ймовірно, можете натиснути правою кнопкою на кожному посиланні і вибрати опцію на кшталт «Зберегти посилання як...».
+
+**Swagger UI** використовує файли:
+
+-
`swagger-ui-bundle.js`
+-
`swagger-ui.css`
+
+А **ReDoc** використовує файл:
+
+-
`redoc.standalone.js`
+
+Після цього ваша структура файлів може виглядати так:
+
+```
+.
+├── app
+│ ├── __init__.py
+│ ├── main.py
+└── static
+ ├── redoc.standalone.js
+ ├── swagger-ui-bundle.js
+ └── swagger-ui.css
+```
+
+### Обслуговуйте статичні файли { #serve-the-static-files }
+
+- Імпортуйте `StaticFiles`.
+- Змонтуйте екземпляр `StaticFiles()` у певному шляху.
+
+{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[7,11] *}
+
+### Перевірте статичні файли { #test-the-static-files }
+
+Запустіть ваш застосунок і перейдіть до
http://127.0.0.1:8000/static/redoc.standalone.js.
+
+Ви маєте побачити дуже довгий файл JavaScript для **ReDoc**.
+
+Він може починатися приблизно так:
+
+```JavaScript
+/*! For license information please see redoc.standalone.js.LICENSE.txt */
+!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t(require("null")):
+...
+```
+
+Це підтверджує, що ви можете віддавати статичні файли з вашого застосунку і що ви розмістили статичні файли для документації у правильному місці.
+
+Тепер ми можемо налаштувати застосунок на використання цих статичних файлів для документації.
+
+### Вимкніть автоматичну документацію для статичних файлів { #disable-the-automatic-docs-for-static-files }
+
+Як і при використанні користувацького CDN, першим кроком є вимкнення автоматичної документації, оскільки типово вона використовує CDN.
+
+Щоб їх вимкнути, встановіть їхні URL у `None` під час створення вашого застосунку `FastAPI`:
+
+{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[9] *}
+
+### Додайте користувацьку документацію для статичних файлів { #include-the-custom-docs-for-static-files }
+
+Аналогічно користувацькому CDN, тепер ви можете створити *операції шляху* для користувацької документації.
+
+Знову ж, ви можете перевикористати внутрішні функції FastAPI для створення HTML-сторінок документації і передати їм потрібні аргументи:
+
+- `openapi_url`: URL, за яким HTML-сторінка документації зможе отримати схему OpenAPI для вашого API. Тут можна використати атрибут `app.openapi_url`.
+- `title`: заголовок вашого API.
+- `oauth2_redirect_url`: тут можна використати `app.swagger_ui_oauth2_redirect_url`, щоб узяти значення за замовчуванням.
+- `swagger_js_url`: URL, за яким HTML для Swagger UI зможе отримати файл **JavaScript**. **Це той файл, який тепер віддає ваш власний застосунок**.
+- `swagger_css_url`: URL, за яким HTML для Swagger UI зможе отримати файл **CSS**. **Це той файл, який тепер віддає ваш власний застосунок**.
+
+Аналогічно для ReDoc...
+
+{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[2:6,14:22,25:27,30:36] *}
+
+/// tip | Порада
+
+*Операція шляху* для `swagger_ui_redirect` - це допоміжний маршрут, коли ви використовуєте OAuth2.
+
+Якщо ви інтегруєте ваш API з провайдером OAuth2, ви зможете автентифікуватися і повернутися до документації API з отриманими обліковими даними. І взаємодіяти з ним, використовуючи реальну автентифікацію OAuth2.
+
+Swagger UI впорається з цим «за лаштунками», але йому потрібен цей «redirect» хелпер.
+
+///
+
+### Створіть операцію шляху для перевірки статичних файлів { #create-a-path-operation-to-test-static-files }
+
+Тепер, щоб перевірити, що все працює, створіть *операцію шляху*:
+
+{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[39:41] *}
+
+### Перевірте UI зі статичними файлами { #test-static-files-ui }
+
+Тепер ви маєте змогу вимкнути WiFi, відкрити документацію за
http://127.0.0.1:8000/docs і перезавантажити сторінку.
+
+І навіть без Інтернету ви зможете побачити документацію для вашого API і взаємодіяти з ним.
diff --git a/docs/uk/docs/how-to/custom-request-and-route.md b/docs/uk/docs/how-to/custom-request-and-route.md
new file mode 100644
index 0000000000..9f21da7a86
--- /dev/null
+++ b/docs/uk/docs/how-to/custom-request-and-route.md
@@ -0,0 +1,109 @@
+# Користувацькі класи Request та APIRoute { #custom-request-and-apiroute-class }
+
+У деяких випадках ви можете захотіти перевизначити логіку, яку використовують класи `Request` та `APIRoute`.
+
+Зокрема, це може бути доброю альтернативою логіці в проміжному програмному забезпеченні.
+
+Наприклад, якщо потрібно прочитати або змінити тіло запиту до того, як його обробить ваш застосунок.
+
+/// danger | Обережно
+
+Це «просунута» можливість.
+
+Якщо ви тільки починаєте працювати з **FastAPI**, можливо, варто пропустити цей розділ.
+
+///
+
+## Випадки використання { #use-cases }
+
+Деякі варіанти використання:
+
+- Перетворення не-JSON тіл запитів на JSON (наприклад,
`msgpack`).
+- Розпакування тіл запитів, стиснених gzip.
+- Автоматичне логування всіх тіл запитів.
+
+## Обробка користувацьких кодувань тіла запиту { #handling-custom-request-body-encodings }
+
+Розгляньмо, як використати користувацький підклас `Request` для розпакування gzip-запитів.
+
+А також підклас `APIRoute`, щоб застосувати цей користувацький клас запиту.
+
+### Створіть користувацький клас `GzipRequest` { #create-a-custom-gziprequest-class }
+
+/// tip | Порада
+
+Це навчальний приклад, щоб продемонструвати принцип роботи. Якщо вам потрібна підтримка Gzip, скористайтеся вбудованим [`GzipMiddleware`](../advanced/middleware.md#gzipmiddleware){.internal-link target=_blank}.
+
+///
+
+Спочатку створимо клас `GzipRequest`, який перевизначить метод `Request.body()`, щоб розпаковувати тіло за наявності відповідного заголовка.
+
+Якщо в заголовку немає `gzip`, він не намагатиметься розпаковувати тіло.
+
+Таким чином один і той самий клас маршруту зможе обробляти як стиснені gzip, так і нестиснені запити.
+
+{* ../../docs_src/custom_request_and_route/tutorial001_an_py310.py hl[9:16] *}
+
+### Створіть користувацький клас `GzipRoute` { #create-a-custom-gziproute-class }
+
+Далі створимо користувацький підклас `fastapi.routing.APIRoute`, який використовуватиме `GzipRequest`.
+
+Цього разу він перевизначить метод `APIRoute.get_route_handler()`.
+
+Цей метод повертає функцію. І саме ця функція прийме запит і поверне відповідь.
+
+Тут ми використовуємо її, щоб створити `GzipRequest` з початкового запиту.
+
+{* ../../docs_src/custom_request_and_route/tutorial001_an_py310.py hl[19:27] *}
+
+/// note | Технічні деталі
+
+У `Request` є атрибут `request.scope` - це просто Python `dict`, що містить метадані, пов'язані із запитом.
+
+Також `Request` має `request.receive` - це функція для «отримання» тіла запиту.
+
+`scope` `dict` і функція `receive` є частиною специфікації ASGI.
+
+І саме ці дві сутності - `scope` та `receive` - потрібні для створення нового екземпляра `Request`.
+
+Щоб дізнатися більше про `Request`, перегляньте
документацію Starlette про запити.
+
+///
+
+Єдине, що робить інакше функція, повернена `GzipRequest.get_route_handler`, - перетворює `Request` на `GzipRequest`.
+
+Завдяки цьому наш `GzipRequest` подбає про розпакування даних (за потреби) перед передаванням їх у наші *операції шляху*.
+
+Після цього вся логіка обробки залишається тією самою.
+
+А завдяки змінам у `GzipRequest.body` тіло запиту за потреби буде автоматично розпаковане під час завантаження **FastAPI**.
+
+## Доступ до тіла запиту в обробнику виключень { #accessing-the-request-body-in-an-exception-handler }
+
+/// tip | Порада
+
+Щоб розв’язати це саме завдання, скоріш за все, простіше використати `body` у користувацькому обробнику `RequestValidationError` ([Обробка помилок](../tutorial/handling-errors.md#use-the-requestvalidationerror-body){.internal-link target=_blank}).
+
+Але цей приклад усе ще корисний і показує, як взаємодіяти з внутрішніми компонентами.
+
+///
+
+Ми також можемо скористатися цим підходом, щоб отримати доступ до тіла запиту в обробнику виключень.
+
+Усе, що потрібно, - обробити запит усередині блоку `try`/`except`:
+
+{* ../../docs_src/custom_request_and_route/tutorial002_an_py310.py hl[14,16] *}
+
+Якщо станеться виключення, екземпляр `Request` усе ще буде у видимості, тож ми зможемо прочитати й використати тіло запиту під час обробки помилки:
+
+{* ../../docs_src/custom_request_and_route/tutorial002_an_py310.py hl[17:19] *}
+
+## Користувацький клас `APIRoute` у маршрутизаторі { #custom-apiroute-class-in-a-router }
+
+Можна також встановити параметр `route_class` у `APIRouter`:
+
+{* ../../docs_src/custom_request_and_route/tutorial003_py310.py hl[26] *}
+
+У цьому прикладі *операції шляху* в `router` використовуватимуть користувацький клас `TimedRoute` і матимуть додатковий заголовок відповіді `X-Response-Time` із часом, витраченим на формування відповіді:
+
+{* ../../docs_src/custom_request_and_route/tutorial003_py310.py hl[13:20] *}
diff --git a/docs/uk/docs/how-to/extending-openapi.md b/docs/uk/docs/how-to/extending-openapi.md
new file mode 100644
index 0000000000..1597cbc762
--- /dev/null
+++ b/docs/uk/docs/how-to/extending-openapi.md
@@ -0,0 +1,80 @@
+# Розширення OpenAPI { #extending-openapi }
+
+У деяких випадках вам може знадобитися змінити згенеровану схему OpenAPI.
+
+У цьому розділі ви побачите як це зробити.
+
+## Звичайний процес { #the-normal-process }
+
+Звичайний (типовий) процес такий.
+
+Застосунок `FastAPI` (екземпляр) має метод `.openapi()`, який має повертати схему OpenAPI.
+
+Під час створення об'єкта застосунку реєструється *операція шляху* для `/openapi.json` (або для того значення, яке ви встановили в `openapi_url`).
+
+Вона просто повертає відповідь JSON з результатом методу `.openapi()` застосунку.
+
+Типово метод `.openapi()` перевіряє властивість `.openapi_schema`, і якщо там вже є дані, повертає їх.
+
+Якщо ні, він генерує їх за допомогою утилітарної функції `fastapi.openapi.utils.get_openapi`.
+
+Функція `get_openapi()` приймає такі параметри:
+
+- `title`: Заголовок OpenAPI, показується в документації.
+- `version`: Версія вашого API, напр. `2.5.0`.
+- `openapi_version`: Версія специфікації OpenAPI, що використовується. Типово остання: `3.1.0`.
+- `summary`: Короткий підсумок API.
+- `description`: Опис вашого API; може містити markdown і буде показаний у документації.
+- `routes`: Список маршрутів, це кожна з зареєстрованих *операцій шляху*. Їх беруть з `app.routes`.
+
+/// info | Інформація
+
+Параметр `summary` доступний в OpenAPI 3.1.0 і вище, підтримується FastAPI 0.99.0 і вище.
+
+///
+
+## Переписування типових значень { #overriding-the-defaults }
+
+Використовуючи наведене вище, ви можете скористатися тією ж утилітарною функцією для генерації схеми OpenAPI і переписати потрібні частини.
+
+Наприклад, додаймо
розширення OpenAPI для ReDoc для додавання власного логотипа.
+
+### Звичайний **FastAPI** { #normal-fastapi }
+
+Спочатку напишіть ваш застосунок **FastAPI** як зазвичай:
+
+{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[1,4,7:9] *}
+
+### Згенерувати схему OpenAPI { #generate-the-openapi-schema }
+
+Далі використайте ту ж утилітарну функцію для генерації схеми OpenAPI всередині функції `custom_openapi()`:
+
+{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[2,15:21] *}
+
+### Змінити схему OpenAPI { #modify-the-openapi-schema }
+
+Тепер можна додати розширення ReDoc, додавши власний `x-logo` до «об'єкта» `info` у схемі OpenAPI:
+
+{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[22:24] *}
+
+### Кешувати схему OpenAPI { #cache-the-openapi-schema }
+
+Ви можете використовувати властивість `.openapi_schema` як «кеш» для збереження згенерованої схеми.
+
+Так вашому застосунку не доведеться щоразу генерувати схему, коли користувач відкриває документацію вашого API.
+
+Вона буде згенерована лише один раз, а потім та сама закешована схема використовуватиметься для наступних запитів.
+
+{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[13:14,25:26] *}
+
+### Переписати метод { #override-the-method }
+
+Тепер ви можете замінити метод `.openapi()` вашою новою функцією.
+
+{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[29] *}
+
+### Перевірте { #check-it }
+
+Коли ви перейдете за адресою
http://127.0.0.1:8000/redoc, побачите, що використовується ваш власний логотип (у цьому прикладі логотип **FastAPI**):
+
+

diff --git a/docs/uk/docs/how-to/general.md b/docs/uk/docs/how-to/general.md
new file mode 100644
index 0000000000..f33ae195c6
--- /dev/null
+++ b/docs/uk/docs/how-to/general.md
@@ -0,0 +1,39 @@
+# Загальне - Як зробити - Рецепти { #general-how-to-recipes }
+
+Нижче наведено кілька вказівок до інших розділів документації для загальних або частих питань.
+
+## Фільтрування даних - Безпека { #filter-data-security }
+
+Щоб гарантувати, що ви не повертаєте більше даних, ніж слід, прочитайте документацію [Навчальний посібник - Модель відповіді - Тип повернення](../tutorial/response-model.md){.internal-link target=_blank}.
+
+## Мітки документації - OpenAPI { #documentation-tags-openapi }
+
+Щоб додати мітки до ваших *операцій шляху* та згрупувати їх в інтерфейсі документації, прочитайте документацію [Навчальний посібник - Налаштування операції шляху - Мітки](../tutorial/path-operation-configuration.md#tags){.internal-link target=_blank}.
+
+## Короткий опис і опис - OpenAPI { #documentation-summary-and-description-openapi }
+
+Щоб додати короткий опис і опис до ваших *операцій шляху* і показати їх в інтерфейсі документації, прочитайте документацію [Навчальний посібник - Налаштування операції шляху - Короткий опис і опис](../tutorial/path-operation-configuration.md#summary-and-description){.internal-link target=_blank}.
+
+## Опис відповіді в документації - OpenAPI { #documentation-response-description-openapi }
+
+Щоб визначити опис відповіді, що відображається в інтерфейсі документації, прочитайте документацію [Навчальний посібник - Налаштування операції шляху - Опис відповіді](../tutorial/path-operation-configuration.md#response-description){.internal-link target=_blank}.
+
+## Позначити застарілою *операцію шляху* - OpenAPI { #documentation-deprecate-a-path-operation-openapi }
+
+Щоб позначити *операцію шляху* як застарілу і показати це в інтерфейсі документації, прочитайте документацію [Навчальний посібник - Налаштування операції шляху - Позначення як застаріле](../tutorial/path-operation-configuration.md#deprecate-a-path-operation){.internal-link target=_blank}.
+
+## Перетворити будь-які дані на сумісні з JSON { #convert-any-data-to-json-compatible }
+
+Щоб перетворити будь-які дані на сумісні з JSON, прочитайте документацію [Навчальний посібник - Кодувальник, сумісний з JSON](../tutorial/encoder.md){.internal-link target=_blank}.
+
+## Метадані OpenAPI - Документація { #openapi-metadata-docs }
+
+Щоб додати метадані до вашої схеми OpenAPI, зокрема ліцензію, версію, контактні дані тощо, прочитайте документацію [Навчальний посібник - Метадані та URL документації](../tutorial/metadata.md){.internal-link target=_blank}.
+
+## Власний URL OpenAPI { #openapi-custom-url }
+
+Щоб налаштувати URL OpenAPI (або прибрати його), прочитайте документацію [Навчальний посібник - Метадані та URL документації](../tutorial/metadata.md#openapi-url){.internal-link target=_blank}.
+
+## URL документації OpenAPI { #openapi-docs-urls }
+
+Щоб оновити URL, які використовуються для автоматично згенерованих інтерфейсів користувача документації, прочитайте документацію [Навчальний посібник - Метадані та URL документації](../tutorial/metadata.md#docs-urls){.internal-link target=_blank}.
diff --git a/docs/uk/docs/how-to/graphql.md b/docs/uk/docs/how-to/graphql.md
new file mode 100644
index 0000000000..2d0e355ea4
--- /dev/null
+++ b/docs/uk/docs/how-to/graphql.md
@@ -0,0 +1,60 @@
+# GraphQL { #graphql }
+
+Оскільки FastAPI базується на стандарті ASGI, дуже просто інтегрувати будь-яку бібліотеку GraphQL, сумісну з ASGI.
+
+Ви можете поєднувати звичайні *операції шляху* FastAPI з GraphQL в одному застосунку.
+
+/// tip | Порада
+
+GraphQL розв’язує деякі дуже специфічні сценарії використання.
+
+Порівняно зі звичайними веб-API він має переваги та недоліки.
+
+Переконайтеся, що переваги для вашого випадку використання переважають недоліки. 🤓
+
+///
+
+## Бібліотеки GraphQL { #graphql-libraries }
+
+Ось деякі бібліотеки GraphQL з підтримкою ASGI. Ви можете використовувати їх із FastAPI:
+
+*
Strawberry 🍓
+ * З
документацією для FastAPI
+*
Ariadne
+ * З
документацією для FastAPI
+*
Tartiflette
+ * З
Tartiflette ASGI для інтеграції з ASGI
+*
Graphene
+ * З
starlette-graphene3
+
+## GraphQL зі Strawberry { #graphql-with-strawberry }
+
+Якщо вам потрібен або ви хочете використовувати GraphQL,
Strawberry - рекомендована бібліотека, адже її дизайн найближчий до дизайну FastAPI; усе базується на анотаціях типів.
+
+Залежно від вашого сценарію використання ви можете надати перевагу іншій бібліотеці, але якби ви запитали мене, я, ймовірно, порадив би спробувати Strawberry.
+
+Ось невеликий приклад того, як інтегрувати Strawberry з FastAPI:
+
+{* ../../docs_src/graphql_/tutorial001_py310.py hl[3,22,25] *}
+
+Більше про Strawberry ви можете дізнатися в
документації Strawberry.
+
+І також
документацію про Strawberry з FastAPI.
+
+## Застарілий `GraphQLApp` зі Starlette { #older-graphqlapp-from-starlette }
+
+Попередні версії Starlette містили клас `GraphQLApp` для інтеграції з
Graphene.
+
+Його вилучено з Starlette як застарілий, але якщо у вас є код, що його використовував, ви можете легко мігрувати на
starlette-graphene3, який покриває той самий сценарій використання та має майже ідентичний інтерфейс.
+
+/// tip | Порада
+
+Якщо вам потрібен GraphQL, я все ж рекомендую звернути увагу на
Strawberry, адже він базується на анотаціях типів, а не на власних класах і типах.
+
+///
+
+## Дізнайтеся більше { #learn-more }
+
+Ви можете дізнатися більше про GraphQL в
офіційній документації GraphQL.
+
+Також ви можете почитати більше про кожну з цих бібліотек за наведеними посиланнями.
diff --git a/docs/uk/docs/how-to/index.md b/docs/uk/docs/how-to/index.md
new file mode 100644
index 0000000000..ac2dd16eb9
--- /dev/null
+++ b/docs/uk/docs/how-to/index.md
@@ -0,0 +1,13 @@
+# Як зробити - Рецепти { #how-to-recipes }
+
+Тут ви побачите різні рецепти або керівництва «як зробити» з **різних тем**.
+
+Більшість із цих ідей є більш-менш **незалежними**, і в більшості випадків вам слід вивчати їх лише тоді, коли вони безпосередньо стосуються **вашого проєкту**.
+
+Якщо щось здається цікавим і корисним для вашого проєкту, сміливо перевірте це, інакше, ймовірно, просто пропустіть.
+
+/// tip | Порада
+
+Якщо ви хочете **вивчити FastAPI** у структурований спосіб (рекомендується), натомість прочитайте [Навчальний посібник - Посібник користувача](../tutorial/index.md){.internal-link target=_blank} розділ за розділом.
+
+///
diff --git a/docs/uk/docs/how-to/migrate-from-pydantic-v1-to-pydantic-v2.md b/docs/uk/docs/how-to/migrate-from-pydantic-v1-to-pydantic-v2.md
new file mode 100644
index 0000000000..0f5d1c924e
--- /dev/null
+++ b/docs/uk/docs/how-to/migrate-from-pydantic-v1-to-pydantic-v2.md
@@ -0,0 +1,135 @@
+# Перехід з Pydantic v1 на Pydantic v2 { #migrate-from-pydantic-v1-to-pydantic-v2 }
+
+Якщо у вас стара програма FastAPI, можливо, ви використовуєте Pydantic версії 1.
+
+FastAPI версії 0.100.0 підтримував як Pydantic v1, так і v2. Використовувалася та версія, яку ви встановили.
+
+FastAPI версії 0.119.0 запровадив часткову підтримку Pydantic v1 всередині Pydantic v2 (як `pydantic.v1`), щоб спростити перехід на v2.
+
+FastAPI 0.126.0 припинив підтримку Pydantic v1, водночас ще певний час підтримував `pydantic.v1`.
+
+/// warning | Попередження
+
+Команда Pydantic припинила підтримку Pydantic v1 для останніх версій Python, починаючи з Python 3.14.
+
+Це стосується і `pydantic.v1`, який більше не підтримується в Python 3.14 і новіших.
+
+Якщо ви хочете використовувати найновіші можливості Python, вам потрібно переконатися, що ви використовуєте Pydantic v2.
+
+///
+
+Якщо у вас стара програма FastAPI з Pydantic v1, нижче я покажу, як мігрувати на Pydantic v2, а також можливості FastAPI 0.119.0, які допоможуть з поступовою міграцією.
+
+## Офіційний посібник { #official-guide }
+
+У Pydantic є офіційний
Посібник з міграції з v1 на v2.
+
+Там описано, що змінилося, як перевірки тепер стали коректнішими та суворішими, можливі застереження тощо.
+
+Прочитайте його, щоб краще зрозуміти зміни.
+
+## Тести { #tests }
+
+Переконайтеся, що у вашій програмі є [тести](../tutorial/testing.md){.internal-link target=_blank} і що ви запускаєте їх у системі безперервної інтеграції (CI).
+
+Так ви зможете виконати оновлення і впевнитися, що все працює як очікується.
+
+## `bump-pydantic` { #bump-pydantic }
+
+У багатьох випадках, якщо ви використовуєте звичайні моделі Pydantic без налаштувань, більшу частину процесу міграції з Pydantic v1 на Pydantic v2 можна автоматизувати.
+
+Ви можете скористатися
`bump-pydantic` від тієї ж команди Pydantic.
+
+Цей інструмент допоможе автоматично змінити більшість коду, який потрібно змінити.
+
+Після цього запустіть тести й перевірте, чи все працює. Якщо так - ви все завершили. 😎
+
+## Pydantic v1 у v2 { #pydantic-v1-in-v2 }
+
+Pydantic v2 містить усе з Pydantic v1 як підмодуль `pydantic.v1`. Але це більше не підтримується у версіях Python вище 3.13.
+
+Це означає, що ви можете встановити останню версію Pydantic v2 та імпортувати і використовувати старі компоненти Pydantic v1 з цього підмодуля, ніби у вас встановлено старий Pydantic v1.
+
+{* ../../docs_src/pydantic_v1_in_v2/tutorial001_an_py310.py hl[1,4] *}
+
+### Підтримка FastAPI для Pydantic v1 у v2 { #fastapi-support-for-pydantic-v1-in-v2 }
+
+Починаючи з FastAPI 0.119.0, також є часткова підтримка Pydantic v1 всередині Pydantic v2, щоб спростити перехід на v2.
+
+Тож ви можете оновити Pydantic до останньої версії 2 і змінити імпорти на використання підмодуля `pydantic.v1`, і в багатьох випадках усе просто запрацює.
+
+{* ../../docs_src/pydantic_v1_in_v2/tutorial002_an_py310.py hl[2,5,15] *}
+
+/// warning | Попередження
+
+Майте на увазі, що оскільки команда Pydantic більше не підтримує Pydantic v1 у нових версіях Python, починаючи з Python 3.14, використання `pydantic.v1` також не підтримується в Python 3.14 і новіших.
+
+///
+
+### Pydantic v1 і v2 в одній програмі { #pydantic-v1-and-v2-on-the-same-app }
+
+Pydantic не підтримує ситуацію, коли модель Pydantic v2 має власні поля, визначені як моделі Pydantic v1, або навпаки.
+
+```mermaid
+graph TB
+ subgraph "❌ Not Supported"
+ direction TB
+ subgraph V2["Pydantic v2 Model"]
+ V1Field["Pydantic v1 Model"]
+ end
+ subgraph V1["Pydantic v1 Model"]
+ V2Field["Pydantic v2 Model"]
+ end
+ end
+
+ style V2 fill:#f9fff3
+ style V1 fill:#fff6f0
+ style V1Field fill:#fff6f0
+ style V2Field fill:#f9fff3
+```
+
+...але в одній програмі ви можете мати окремі моделі на Pydantic v1 і v2.
+
+```mermaid
+graph TB
+ subgraph "✅ Supported"
+ direction TB
+ subgraph V2["Pydantic v2 Model"]
+ V2Field["Pydantic v2 Model"]
+ end
+ subgraph V1["Pydantic v1 Model"]
+ V1Field["Pydantic v1 Model"]
+ end
+ end
+
+ style V2 fill:#f9fff3
+ style V1 fill:#fff6f0
+ style V1Field fill:#fff6f0
+ style V2Field fill:#f9fff3
+```
+
+У деяких випадках можна навіть використовувати моделі і Pydantic v1, і v2 в одній операції шляху у вашій програмі FastAPI:
+
+{* ../../docs_src/pydantic_v1_in_v2/tutorial003_an_py310.py hl[2:3,6,12,21:22] *}
+
+У наведеному вище прикладі вхідна модель - це модель Pydantic v1, а вихідна модель (визначена як `response_model=ItemV2`) - модель Pydantic v2.
+
+### Параметри Pydantic v1 { #pydantic-v1-parameters }
+
+Якщо вам потрібно використовувати деякі специфічні для FastAPI інструменти для параметрів, як-от `Body`, `Query`, `Form` тощо, з моделями Pydantic v1, ви можете імпортувати їх з `fastapi.temp_pydantic_v1_params`, поки завершуєте міграцію на Pydantic v2:
+
+{* ../../docs_src/pydantic_v1_in_v2/tutorial004_an_py310.py hl[4,18] *}
+
+### Покрокова міграція { #migrate-in-steps }
+
+/// tip | Порада
+
+Спершу спробуйте `bump-pydantic`: якщо ваші тести проходять і все працює - ви впоралися однією командою. ✨
+
+///
+
+Якщо `bump-pydantic` не підходить для вашого випадку, скористайтеся підтримкою одночасно Pydantic v1 і v2 в одній програмі, щоб виконати поступову міграцію на Pydantic v2.
+
+Спочатку ви можете оновити Pydantic до останньої версії 2 і змінити імпорти на `pydantic.v1` для всіх ваших моделей.
+
+Потім починайте переносити моделі з Pydantic v1 на v2 групами, поступовими кроками. 🚶
diff --git a/docs/uk/docs/how-to/separate-openapi-schemas.md b/docs/uk/docs/how-to/separate-openapi-schemas.md
new file mode 100644
index 0000000000..7e6fcbf5f9
--- /dev/null
+++ b/docs/uk/docs/how-to/separate-openapi-schemas.md
@@ -0,0 +1,101 @@
+# Окремі схеми OpenAPI для введення та виведення, чи ні { #separate-openapi-schemas-for-input-and-output-or-not }
+
+Відколи вийшов **Pydantic v2**, згенерований OpenAPI став трохи точнішим і більш коректним, ніж раніше. 😎
+
+Насправді подекуди буде навіть **дві схеми JSON** в OpenAPI для тієї самої моделі Pydantic: для введення та для виведення - залежно від наявності значень за замовчуванням.
+
+Розгляньмо, як це працює, і як це змінити за потреби.
+
+## Моделі Pydantic для введення та виведення { #pydantic-models-for-input-and-output }
+
+Припустімо, у вас є модель Pydantic зі значеннями за замовчуванням, наприклад:
+
+{* ../../docs_src/separate_openapi_schemas/tutorial001_py310.py ln[1:7] hl[7] *}
+
+### Модель для введення { #model-for-input }
+
+Якщо ви використовуєте цю модель як введення, як тут:
+
+{* ../../docs_src/separate_openapi_schemas/tutorial001_py310.py ln[1:15] hl[14] *}
+
+…тоді поле `description` не буде обов'язковим, адже воно має значення за замовчуванням `None`.
+
+### Модель для введення в документації { #input-model-in-docs }
+
+У документації ви побачите, що поле `description` не має **червоної зірочки** - воно не позначене як обов'язкове:
+
+
+

+
+
+### Модель для виведення { #model-for-output }
+
+Але якщо ви використовуєте цю саму модель для виведення, як тут:
+
+{* ../../docs_src/separate_openapi_schemas/tutorial001_py310.py hl[19] *}
+
+…тоді, оскільки `description` має значення за замовчуванням, якщо ви нічого не повернете для цього поля, воно все одно матиме це **значення за замовчуванням**.
+
+### Модель для даних відповіді при виведенні { #model-for-output-response-data }
+
+Якщо ви скористаєтеся документацією та перевірите відповідь, навіть попри те, що код нічого не додав в одне з полів `description`, JSON-відповідь містить значення за замовчуванням (`null`):
+
+
+

+
+
+Це означає, що воно **завжди матиме значення** - просто іноді це значення може бути `None` (або `null` у JSON).
+
+Отже, клієнтам, які використовують ваш API, не потрібно перевіряти, чи існує значення - вони можуть **припустити, що поле завжди буде присутнє**, але в окремих випадках воно матиме значення за замовчуванням `None`.
+
+У OpenAPI це описується тим, що поле позначається як **обов'язкове**, адже воно завжди присутнє.
+
+Тому Схема JSON для моделі може відрізнятися залежно від того, чи використовується вона для **введення або виведення**:
+- для **введення** `description` не буде обов'язковим
+- для **виведення** воно буде **обов'язковим** (і можливо `None`, або в термінах JSON - `null`)
+
+### Модель для виведення в документації { #model-for-output-in-docs }
+
+У документації ви також можете перевірити модель для виведення: **і** `name`, і `description` позначені як **обов'язкові** червоною зірочкою:
+
+
+

+
+
+### Модель для введення та виведення в документації { #model-for-input-and-output-in-docs }
+
+Якщо відкрити всі наявні Схеми (схеми JSON) в OpenAPI, то ви побачите дві: `Item-Input` і `Item-Output`.
+
+Для `Item-Input` поле `description` **не є обов'язковим** - червоної зірочки немає.
+
+А для `Item-Output` `description` **є обов'язковим** - є червона зірочка.
+
+
+

+
+
+Завдяки цій можливості у **Pydantic v2** ваша документація API стає більш **точною**, а якщо у вас є згенеровані клієнти та SDK, вони також будуть точнішими - з кращим **досвідом розробника** та узгодженістю. 🎉
+
+## Не розділяти схеми { #do-not-separate-schemas }
+
+Втім іноді може знадобитися мати **одну й ту саму схему для введення та виведення**.
+
+Основний випадок - коли у вас вже є згенерований клієнтський код/SDK, і ви поки не бажаєте оновлювати весь такий згенерований код/SDK. Ймовірно, ви зробите це пізніше, але не зараз.
+
+У такому разі ви можете вимкнути цю можливість у **FastAPI** параметром `separate_input_output_schemas=False`.
+
+/// info | Інформація
+
+Підтримку `separate_input_output_schemas` додано у FastAPI `0.102.0`. 🤓
+
+///
+
+{* ../../docs_src/separate_openapi_schemas/tutorial002_py310.py hl[10] *}
+
+### Одна схема для моделей введення та виведення в документації { #same-schema-for-input-and-output-models-in-docs }
+
+Тепер для цієї моделі буде лише одна спільна схема для введення та виведення - тільки `Item`, і в ній `description` буде **не обов'язковим**:
+
+
+

+
diff --git a/docs/uk/docs/how-to/testing-database.md b/docs/uk/docs/how-to/testing-database.md
new file mode 100644
index 0000000000..2e6b21ced0
--- /dev/null
+++ b/docs/uk/docs/how-to/testing-database.md
@@ -0,0 +1,7 @@
+# Тестування бази даних { #testing-a-database }
+
+Ви можете ознайомитися з базами даних, SQL і SQLModel у
документації SQLModel. 🤓
+
+Є невеликий
навчальний посібник про використання SQLModel з FastAPI. ✨
+
+Цей навчальний посібник містить розділ про
тестування баз даних SQL. 😎
diff --git a/docs/uk/docs/index.md b/docs/uk/docs/index.md
index 4f089c4e1a..0a6788502a 100644
--- a/docs/uk/docs/index.md
+++ b/docs/uk/docs/index.md
@@ -40,7 +40,7 @@ FastAPI - це сучасний, швидкий (високопродуктив
* **Швидкий**: дуже висока продуктивність, на рівні з **NodeJS** та **Go** (завдяки Starlette та Pydantic). [Один із найшвидших Python-фреймворків](#performance).
* **Швидке написання коду**: пришвидшує розробку функціоналу приблизно на 200%–300%. *
* **Менше помилок**: зменшує приблизно на 40% кількість помилок, спричинених людиною (розробником). *
-* **Інтуїтивний**: чудова підтримка редакторами коду.
Автодоповнення всюди. Менше часу на налагодження.
+* **Інтуїтивний**: чудова підтримка редакторами коду.
Автодоповнення всюди. Менше часу на налагодження.
* **Простий**: спроєктований так, щоб бути простим у використанні та вивченні. Менше часу на читання документації.
* **Короткий**: мінімізує дублювання коду. Кілька можливостей з кожного оголошення параметра. Менше помилок.
* **Надійний**: ви отримуєте код, готовий до продакшину. З автоматичною інтерактивною документацією.
@@ -127,7 +127,7 @@ FastAPI - це сучасний, швидкий (високопродуктив

-Якщо ви створюєте застосунок
CLI для використання в терміналі замість веб-API, зверніть увагу на
**Typer**.
+Якщо ви створюєте застосунок
CLI для використання в терміналі замість веб-API, зверніть увагу на
**Typer**.
**Typer** - молодший брат FastAPI. І його задумано як **FastAPI для CLI**. ⌨️ 🚀
@@ -368,7 +368,7 @@ item: Item
* Валідацію даних:
* Автоматичні та зрозумілі помилки, коли дані некоректні.
* Валідацію навіть для глибоко вкладених JSON-обʼєктів.
-*
Перетворення вхідних даних: з мережі до даних і типів Python. Читання з:
+*
Перетворення вхідних даних: з мережі до даних і типів Python. Читання з:
* JSON.
* Параметрів шляху.
* Параметрів запиту.
@@ -376,7 +376,7 @@ item: Item
* Headers.
* Forms.
* Files.
-*
Перетворення вихідних даних: перетворення з даних і типів Python у мережеві дані (як JSON):
+*
Перетворення вихідних даних: перетворення з даних і типів Python у мережеві дані (як JSON):
* Перетворення типів Python (`str`, `int`, `float`, `bool`, `list`, тощо).
* Обʼєктів `datetime`.
* Обʼєктів `UUID`.
@@ -439,7 +439,7 @@ item: Item
* Оголошення **параметрів** з інших різних місць, як-от: **headers**, **cookies**, **form fields** та **files**.
* Як встановлювати **обмеження валідації** як `maximum_length` або `regex`.
-* Дуже потужну і просту у використанні систему **
Dependency Injection**.
+* Дуже потужну і просту у використанні систему **
Впровадження залежностей**.
* Безпеку та автентифікацію, включно з підтримкою **OAuth2** з **JWT tokens** та **HTTP Basic** auth.
* Досконаліші (але однаково прості) техніки для оголошення **глибоко вкладених моделей JSON** (завдяки Pydantic).
* Інтеграцію **GraphQL** з
Strawberry та іншими бібліотеками.
@@ -524,7 +524,7 @@ FastAPI залежить від Pydantic і Starlette.
*
httpx - потрібно, якщо ви хочете використовувати `TestClient`.
*
jinja2 - потрібно, якщо ви хочете використовувати конфігурацію шаблонів за замовчуванням.
-*
python-multipart - потрібно, якщо ви хочете підтримувати
«parsing» форм за допомогою `request.form()`.
+*
python-multipart - потрібно, якщо ви хочете підтримувати форми з
«парсингом» через `request.form()`.
Використовується FastAPI:
diff --git a/docs/uk/docs/learn/index.md b/docs/uk/docs/learn/index.md
index 6e28d414ad..ad468fea18 100644
--- a/docs/uk/docs/learn/index.md
+++ b/docs/uk/docs/learn/index.md
@@ -1,5 +1,5 @@
# Навчання { #learn }
-У цьому розділі надані вступні розділи та навчальні матеріали для вивчення **FastAPI**.
+У цьому розділі надані вступні розділи та навчальні посібники для вивчення **FastAPI**.
Це можна розглядати як **книгу**, **курс**, або **офіційний** та рекомендований спосіб освоїти FastAPI. 😎
diff --git a/docs/uk/docs/project-generation.md b/docs/uk/docs/project-generation.md
new file mode 100644
index 0000000000..4899090d42
--- /dev/null
+++ b/docs/uk/docs/project-generation.md
@@ -0,0 +1,28 @@
+# Шаблон Full Stack FastAPI { #full-stack-fastapi-template }
+
+Шаблони, хоча зазвичай постачаються з певним налаштуванням, спроєктовані бути гнучкими та налаштовуваними. Це дає змогу змінювати їх і адаптувати до вимог вашого проєкту, що робить їх чудовою відправною точкою. 🏁
+
+Ви можете використати цей шаблон для старту, адже в ньому вже виконано значну частину початкового налаштування, безпеки, роботи з базою даних і деяких кінцевих точок API.
+
+Репозиторій GitHub:
Шаблон Full Stack FastAPI
+
+## Шаблон Full Stack FastAPI - стек технологій і можливості { #full-stack-fastapi-template-technology-stack-and-features }
+
+- ⚡ [**FastAPI**](https://fastapi.tiangolo.com/uk) для бекенд API на Python.
+ - 🧰 [SQLModel](https://sqlmodel.tiangolo.com) для взаємодії з SQL-базою даних у Python (ORM).
+ - 🔍 [Pydantic](https://docs.pydantic.dev), який використовується FastAPI, для перевірки даних і керування налаштуваннями.
+ - 💾 [PostgreSQL](https://www.postgresql.org) як SQL-база даних.
+- 🚀 [React](https://react.dev) для фронтенду.
+ - 💃 Використання TypeScript, хуків, Vite та інших частин сучасного фронтенд-стеку.
+ - 🎨 [Tailwind CSS](https://tailwindcss.com) і [shadcn/ui](https://ui.shadcn.com) для фронтенд-компонентів.
+ - 🤖 Автоматично згенерований фронтенд-клієнт.
+ - 🧪 [Playwright](https://playwright.dev) для End-to-End тестування.
+ - 🦇 Підтримка темного режиму.
+- 🐋 [Docker Compose](https://www.docker.com) для розробки та продакшену.
+- 🔒 Безпечне хешування паролів за замовчуванням.
+- 🔑 Автентифікація JWT (JSON Web Token).
+- 📫 Відновлення пароля на основі електронної пошти.
+- ✅ Тести з [Pytest](https://pytest.org).
+- 📞 [Traefik](https://traefik.io) як зворотний представник / балансувальник навантаження.
+- 🚢 Інструкції з розгортання з Docker Compose, включно з налаштуванням фронтенд-представника Traefik для автоматичних HTTPS-сертифікатів.
+- 🏭 CI (безперервна інтеграція) і CD (безперервне розгортання) на базі GitHub Actions.
diff --git a/docs/uk/docs/python-types.md b/docs/uk/docs/python-types.md
index a82d13a285..deeeb2f9c5 100644
--- a/docs/uk/docs/python-types.md
+++ b/docs/uk/docs/python-types.md
@@ -2,11 +2,11 @@
Python підтримує додаткові «підказки типів» (також звані «анотаціями типів»).
-Ці **«підказки типів»** або анотації — це спеціальний синтаксис, що дозволяє оголошувати
тип змінної.
+Ці **«підказки типів»** або анотації — це спеціальний синтаксис, що дозволяє оголошувати
тип змінної.
За допомогою оголошення типів для ваших змінних редактори та інструменти можуть надати вам кращу підтримку.
-Це лише **швидкий туторіал / нагадування** про підказки типів у Python. Він покриває лише мінімум, необхідний щоб використовувати їх з **FastAPI**... що насправді дуже мало.
+Це лише **швидкий навчальний посібник / нагадування** про підказки типів у Python. Він покриває лише мінімум, необхідний щоб використовувати їх з **FastAPI**... що насправді дуже мало.
**FastAPI** повністю базується на цих підказках типів, вони дають йому багато переваг і користі.
@@ -22,7 +22,7 @@ Python підтримує додаткові «підказки типів» (т
Давайте почнемо з простого прикладу:
-{* ../../docs_src/python_types/tutorial001_py39.py *}
+{* ../../docs_src/python_types/tutorial001_py310.py *}
Виклик цієї програми виводить:
@@ -34,9 +34,9 @@ John Doe
* Бере `first_name` та `last_name`.
* Перетворює першу літеру кожного з них у верхній регістр за допомогою `title()`.
-*
Конкатенує їх разом із пробілом по середині.
+*
Конкатенує їх разом із пробілом по середині.
-{* ../../docs_src/python_types/tutorial001_py39.py hl[2] *}
+{* ../../docs_src/python_types/tutorial001_py310.py hl[2] *}
### Редагуйте це { #edit-it }
@@ -78,7 +78,7 @@ John Doe
Це «підказки типів»:
-{* ../../docs_src/python_types/tutorial002_py39.py hl[1] *}
+{* ../../docs_src/python_types/tutorial002_py310.py hl[1] *}
Це не те саме, що оголошення значень за замовчуванням, як це було б з:
@@ -106,15 +106,15 @@ John Doe
Перевірте цю функцію, вона вже має підказки типів:
-{* ../../docs_src/python_types/tutorial003_py39.py hl[1] *}
+{* ../../docs_src/python_types/tutorial003_py310.py hl[1] *}
Оскільки редактор знає типи змінних, ви не тільки отримаєте автозаповнення, ви також отримаєте перевірку помилок:

-Тепер ви знаєте, щоб виправити це, вам потрібно перетворити `age` у рядок за допомогою `str(age)`:
+Тепер ви знаєте, щоб виправити це, вам потрібно перетворити `age` у строку за допомогою `str(age)`:
-{* ../../docs_src/python_types/tutorial004_py39.py hl[2] *}
+{* ../../docs_src/python_types/tutorial004_py310.py hl[2] *}
## Оголошення типів { #declaring-types }
@@ -133,29 +133,32 @@ John Doe
* `bool`
* `bytes`
-{* ../../docs_src/python_types/tutorial005_py39.py hl[1] *}
+{* ../../docs_src/python_types/tutorial005_py310.py hl[1] *}
-### Generic-типи з параметрами типів { #generic-types-with-type-parameters }
+### Модуль `typing` { #typing-module }
-Існують деякі структури даних, які можуть містити інші значення, наприклад `dict`, `list`, `set` та `tuple`. І внутрішні значення також можуть мати свій тип.
+Для деяких додаткових випадків використання може знадобитися імпортувати елементи зі стандартної бібліотеки, модуля `typing`. Наприклад, коли ви хочете оголосити, що щось має «будь-який тип», ви можете використати `Any` з `typing`:
-Ці типи, які мають внутрішні типи, називаються «**generic**» типами. І оголосити їх можна навіть із внутрішніми типами.
+```python
+from typing import Any
-Щоб оголосити ці типи та внутрішні типи, ви можете використовувати стандартний модуль Python `typing`. Він існує спеціально для підтримки цих підказок типів.
-#### Новіші версії Python { #newer-versions-of-python }
-
-Синтаксис із використанням `typing` **сумісний** з усіма версіями, від Python 3.6 до останніх, включаючи Python 3.9, Python 3.10 тощо.
+def some_function(data: Any):
+ print(data)
+```
-У міру розвитку Python **новіші версії** мають покращену підтримку цих анотацій типів і в багатьох випадках вам навіть не потрібно буде імпортувати та використовувати модуль `typing` для оголошення анотацій типів.
+### Generic типи { #generic-types }
-Якщо ви можете вибрати новішу версію Python для свого проекту, ви зможете скористатися цією додатковою простотою.
+Деякі типи можуть приймати «параметри типів» у квадратних дужках, щоб визначити їх внутрішні типи. Наприклад, «list строк» буде оголошений як `list[str]`.
-У всій документації є приклади, сумісні з кожною версією Python (коли є різниця).
+Ці типи, які можуть приймати параметри типів, називаються **generic типами** або **generics**.
-Наприклад, «**Python 3.6+**» означає, що це сумісно з Python 3.6 або вище (включно з 3.7, 3.8, 3.9, 3.10 тощо). А «**Python 3.9+**» означає, що це сумісно з Python 3.9 або вище (включаючи 3.10 тощо).
+Ви можете використовувати ті самі вбудовані типи як generics (з квадратними дужками та типами всередині):
-Якщо ви можете використовувати **останні версії Python**, використовуйте приклади для останньої версії — вони матимуть **найкращий і найпростіший синтаксис**, наприклад, «**Python 3.10+**».
+* `list`
+* `tuple`
+* `set`
+* `dict`
#### List { #list }
@@ -167,7 +170,7 @@ John Doe
Оскільки список є типом, який містить деякі внутрішні типи, ви поміщаєте їх у квадратні дужки:
-{* ../../docs_src/python_types/tutorial006_py39.py hl[1] *}
+{* ../../docs_src/python_types/tutorial006_py310.py hl[1] *}
/// info | Інформація
@@ -193,7 +196,7 @@ John Doe
Ви повинні зробити те ж саме, щоб оголосити `tuple` і `set`:
-{* ../../docs_src/python_types/tutorial007_py39.py hl[1] *}
+{* ../../docs_src/python_types/tutorial007_py310.py hl[1] *}
Це означає:
@@ -208,56 +211,32 @@ John Doe
Другий параметр типу для значень у `dict`:
-{* ../../docs_src/python_types/tutorial008_py39.py hl[1] *}
+{* ../../docs_src/python_types/tutorial008_py310.py hl[1] *}
Це означає:
* Змінна `prices` — це `dict`:
- * Ключі цього `dict` мають тип `str` (скажімо, назва кожного елементу).
- * Значення цього `dict` мають тип `float` (скажімо, ціна кожного елементу).
+ * Ключі цього `dict` мають тип `str` (скажімо, назва кожного предмета).
+ * Значення цього `dict` мають тип `float` (скажімо, ціна кожного предмета).
#### Union { #union }
Ви можете оголосити, що змінна може бути будь-яким із **кількох типів**, наприклад `int` або `str`.
-У Python 3.6 і вище (включаючи Python 3.10) ви можете використовувати тип `Union` з `typing` і вставляти в квадратні дужки можливі типи, які можна прийняти.
-
-У Python 3.10 також є **новий синтаксис**, у якому ви можете розділити можливі типи за допомогою
вертикальної смуги (`|`).
+Щоб визначити це, використовуйте
вертикальну риску (`|`), щоб розділити обидва типи.
-//// tab | Python 3.10+
+Це називається «union», тому що змінна може бути чимось із об’єднання цих двох множин типів.
```Python hl_lines="1"
{!> ../../docs_src/python_types/tutorial008b_py310.py!}
```
-////
-
-//// tab | Python 3.9+
-
-```Python hl_lines="1 4"
-{!> ../../docs_src/python_types/tutorial008b_py39.py!}
-```
-
-////
-
-В обох випадках це означає, що `item` може бути `int` або `str`.
+Це означає, що `item` може бути `int` або `str`.
#### Можливо `None` { #possibly-none }
Ви можете оголосити, що значення може мати тип, наприклад `str`, але також може бути `None`.
-У Python 3.6 і вище (включаючи Python 3.10) ви можете оголосити його, імпортувавши та використовуючи `Optional` з модуля `typing`.
-
-```Python hl_lines="1 4"
-{!../../docs_src/python_types/tutorial009_py39.py!}
-```
-
-Використання `Optional[str]` замість просто `str` дозволить редактору допомогти вам виявити помилки, коли ви могли б вважати, що значенням завжди є `str`, хоча насправді воно також може бути `None`.
-
-`Optional[Something]` насправді є скороченням для `Union[Something, None]`, вони еквівалентні.
-
-Це також означає, що в Python 3.10 ви можете використовувати `Something | None`:
-
//// tab | Python 3.10+
```Python hl_lines="1"
@@ -266,96 +245,7 @@ John Doe
////
-//// tab | Python 3.9+
-
-```Python hl_lines="1 4"
-{!> ../../docs_src/python_types/tutorial009_py39.py!}
-```
-
-////
-
-//// tab | Python 3.9+ alternative
-
-```Python hl_lines="1 4"
-{!> ../../docs_src/python_types/tutorial009b_py39.py!}
-```
-
-////
-
-#### Використання `Union` або `Optional` { #using-union-or-optional }
-
-Якщо ви використовуєте версію Python нижче 3.10, ось порада з моєї дуже **суб’єктивної** точки зору:
-
-* 🚨 Уникайте використання `Optional[SomeType]`
-* Натомість ✨ **використовуйте `Union[SomeType, None]`** ✨.
-
-Обидва варіанти еквівалентні й «під капотом» це одне й те саме, але я рекомендую `Union` замість `Optional`, тому що слово «**optional**» може створювати враження, ніби значення є необов’язковим, хоча насправді це означає «воно може бути `None`», навіть якщо воно не є необов’язковим і все одно є обов’язковим.
-
-Я вважаю, що `Union[SomeType, None]` більш явно показує, що саме мається на увазі.
-
-Це лише про слова й назви. Але ці слова можуть впливати на те, як ви та ваша команда думаєте про код.
-
-Як приклад, розгляньмо цю функцію:
-
-{* ../../docs_src/python_types/tutorial009c_py39.py hl[1,4] *}
-
-Параметр `name` визначено як `Optional[str]`, але він **не є необов’язковим**, ви не можете викликати функцію без параметра:
-
-```Python
-say_hi() # Ой, ні, це викликає помилку! 😱
-```
-
-Параметр `name` **все ще є обов’язковим** (не *optional*), тому що він не має значення за замовчуванням. Водночас `name` приймає `None` як значення:
-
-```Python
-say_hi(name=None) # Це працює, None є валідним 🎉
-```
-
-Добра новина: щойно ви перейдете на Python 3.10, вам не доведеться про це хвилюватися, адже ви зможете просто використовувати `|` для визначення об’єднань типів:
-
-{* ../../docs_src/python_types/tutorial009c_py310.py hl[1,4] *}
-
-І тоді вам не доведеться хвилюватися про назви на кшталт `Optional` і `Union`. 😎
-
-#### Generic типи { #generic-types }
-
-Ці типи, які приймають параметри типу у квадратних дужках, називаються **Generic types** or **Generics**, наприклад:
-
-//// tab | Python 3.10+
-
-Ви можете використовувати ті самі вбудовані типи як generic (з квадратними дужками та типами всередині):
-
-* `list`
-* `tuple`
-* `set`
-* `dict`
-
-І так само, як і в попередніх версіях Python, з модуля `typing`:
-
-* `Union`
-* `Optional`
-* ...та інші.
-
-У Python 3.10 як альтернативу використанню generic `Union` та `Optional` ви можете використовувати
вертикальну смугу (`|`) для оголошення об’єднань типів — це значно краще й простіше.
-
-////
-
-//// tab | Python 3.9+
-
-Ви можете використовувати ті самі вбудовані типи як generic (з квадратними дужками та типами всередині):
-
-* `list`
-* `tuple`
-* `set`
-* `dict`
-
-І generic з модуля `typing`:
-
-* `Union`
-* `Optional`
-* ...та інші.
-
-////
+Використання `str | None` замість просто `str` дозволить редактору допомогти вам виявити помилки, коли ви могли б вважати, що значенням завжди є `str`, хоча насправді воно також може бути `None`.
### Класи як типи { #classes-as-types }
@@ -363,11 +253,11 @@ say_hi(name=None) # Це працює, None є валідним 🎉
Скажімо, у вас є клас `Person` з імʼям:
-{* ../../docs_src/python_types/tutorial010_py39.py hl[1:3] *}
+{* ../../docs_src/python_types/tutorial010_py310.py hl[1:3] *}
Потім ви можете оголосити змінну типу `Person`:
-{* ../../docs_src/python_types/tutorial010_py39.py hl[6] *}
+{* ../../docs_src/python_types/tutorial010_py310.py hl[6] *}
І знову ж таки, ви отримуєте всю підтримку редактора:
@@ -401,21 +291,15 @@ say_hi(name=None) # Це працює, None є валідним 🎉
**FastAPI** повністю базується на Pydantic.
-Ви побачите набагато більше цього всього на практиці в [Tutorial - User Guide](tutorial/index.md){.internal-link target=_blank}.
-
-/// tip | Порада
-
-Pydantic має спеціальну поведінку, коли ви використовуєте `Optional` або `Union[Something, None]` без значення за замовчуванням; детальніше про це можна прочитати в документації Pydantic про
Required Optional fields.
-
-///
+Ви побачите набагато більше цього всього на практиці в [Навчальний посібник - Посібник користувача](tutorial/index.md){.internal-link target=_blank}.
## Підказки типів з анотаціями метаданих { #type-hints-with-metadata-annotations }
-У Python також є можливість додавати **додаткові
метадані** до цих підказок типів за допомогою `Annotated`.
+У Python також є можливість додавати **додаткові
метадані** до цих підказок типів за допомогою `Annotated`.
-Починаючи з Python 3.9, `Annotated` є частиною стандартної бібліотеки, тож ви можете імпортувати його з `typing`.
+Ви можете імпортувати `Annotated` з `typing`.
-{* ../../docs_src/python_types/tutorial013_py39.py hl[1,4] *}
+{* ../../docs_src/python_types/tutorial013_py310.py hl[1,4] *}
Сам Python нічого не робить із цим `Annotated`. А для редакторів та інших інструментів тип усе ще є `str`.
@@ -435,7 +319,7 @@ Pydantic має спеціальну поведінку, коли ви вико
///
-## Анотації типів у **FastAPI** { #type-hints-in-fastapi }
+## Підказки типів у **FastAPI** { #type-hints-in-fastapi }
**FastAPI** використовує ці підказки типів для виконання кількох речей.
@@ -453,12 +337,12 @@ Pydantic має спеціальну поведінку, коли ви вико
* **Документування** API за допомогою OpenAPI:
* який потім використовується для автоматичної інтерактивної документації користувальницьких інтерфейсів.
-Все це може здатися абстрактним. Не хвилюйтеся. Ви побачите все це в дії в [Tutorial - User Guide](tutorial/index.md){.internal-link target=_blank}.
+Все це може здатися абстрактним. Не хвилюйтеся. Ви побачите все це в дії в [Навчальний посібник - Посібник користувача](tutorial/index.md){.internal-link target=_blank}.
Важливо те, що за допомогою стандартних типів Python в одному місці (замість того, щоб додавати більше класів, декораторів тощо), **FastAPI** зробить багато роботи за вас.
/// info | Інформація
-Якщо ви вже пройшли весь туторіал і повернулися, щоб дізнатися більше про типи, ось хороший ресурс:
«шпаргалка» від `mypy`.
+Якщо ви вже пройшли весь навчальний посібник і повернулися, щоб дізнатися більше про типи, ось хороший ресурс:
«шпаргалка» від `mypy`.
///
diff --git a/docs/uk/docs/resources/index.md b/docs/uk/docs/resources/index.md
new file mode 100644
index 0000000000..353992fad4
--- /dev/null
+++ b/docs/uk/docs/resources/index.md
@@ -0,0 +1,3 @@
+# Ресурси { #resources }
+
+Додаткові ресурси, зовнішні посилання та інше. ✈️
diff --git a/docs/uk/docs/translation-banner.md b/docs/uk/docs/translation-banner.md
new file mode 100644
index 0000000000..8640803994
--- /dev/null
+++ b/docs/uk/docs/translation-banner.md
@@ -0,0 +1,11 @@
+/// details | 🌐 Переклад ШІ та людьми
+
+Цей переклад виконано ШІ під керівництвом людей. 🤝
+
+Можливі помилки через неправильне розуміння початкового змісту або неприродні формулювання тощо. 🤖
+
+Ви можете покращити цей переклад, [допомігши нам краще спрямовувати AI LLM](https://fastapi.tiangolo.com/uk/contributing/#translations).
+
+[Англійська версія](ENGLISH_VERSION_URL)
+
+///
diff --git a/docs/uk/docs/tutorial/background-tasks.md b/docs/uk/docs/tutorial/background-tasks.md
index 6d7804195e..71266a8b10 100644
--- a/docs/uk/docs/tutorial/background-tasks.md
+++ b/docs/uk/docs/tutorial/background-tasks.md
@@ -1,6 +1,6 @@
# Фонові задачі { #background-tasks }
-Ви можете створювати фонові задачі, які будуть виконуватися *після* повернення відповіді.
+Ви можете створювати фонові задачі, які будуть виконуватися після повернення відповіді.
Це корисно для операцій, які потрібно виконати після обробки запиту, але клієнту не обов’язково чекати завершення цієї операції перед отриманням відповіді.
@@ -13,9 +13,9 @@
## Використання `BackgroundTasks` { #using-backgroundtasks }
-Спочатку імпортуйте `BackgroundTasks` і оголосіть параметр у вашій *функції операції шляху* з анотацією типу `BackgroundTasks`:
+Спочатку імпортуйте `BackgroundTasks` і оголосіть параметр у вашій функції операції шляху з анотацією типу `BackgroundTasks`:
-{* ../../docs_src/background_tasks/tutorial001_py39.py hl[1,13] *}
+{* ../../docs_src/background_tasks/tutorial001_py310.py hl[1,13] *}
**FastAPI** створить для вас об’єкт типу `BackgroundTasks` і передасть його як цей параметр.
@@ -31,13 +31,13 @@
І оскільки операція запису не використовує `async` та `await`, ми визначаємо функцію як звичайну `def`:
-{* ../../docs_src/background_tasks/tutorial001_py39.py hl[6:9] *}
+{* ../../docs_src/background_tasks/tutorial001_py310.py hl[6:9] *}
## Додавання фонової задачі { #add-the-background-task }
-Усередині вашої *функції операції шляху*, передайте функцію задачі в об'єкт *background tasks*, використовуючи метод `.add_task()`:
+Усередині вашої функції операції шляху, передайте функцію задачі в об'єкт background tasks, використовуючи метод `.add_task()`:
-{* ../../docs_src/background_tasks/tutorial001_py39.py hl[14] *}
+{* ../../docs_src/background_tasks/tutorial001_py310.py hl[14] *}
`.add_task()` приймає аргументи:
@@ -47,17 +47,17 @@
## Впровадження залежностей { #dependency-injection }
-Використання `BackgroundTasks` також працює з системою впровадження залежностей. Ви можете оголосити параметр типу `BackgroundTasks` на різних рівнях: у *функції операції шляху*, у залежності (dependable), у підзалежності тощо.
+Використання `BackgroundTasks` також працює з системою впровадження залежностей. Ви можете оголосити параметр типу `BackgroundTasks` на різних рівнях: у функції операції шляху, у залежності (залежний), у підзалежності тощо.
-**FastAPI** знає, як діяти в кожному випадку і як повторно використовувати один і той самий об'єкт, щоб усі фонові задачі були об’єднані та виконувалися у фоновому режимі після завершення основного запиту:
+**FastAPI** знає, як діяти в кожному випадку і як повторно використовувати один і той самий об'єкт, щоб усі фонові задачі були об’єднані та виконувалися у фоновому режимі після завершення основного запиту:
{* ../../docs_src/background_tasks/tutorial002_an_py310.py hl[13,15,22,25] *}
-У цьому прикладі повідомлення будуть записані у файл `log.txt` *після* того, як відповідь буде надіслана.
+У цьому прикладі повідомлення будуть записані у файл `log.txt` після того, як відповідь буде надіслана.
-Якщо у запиті був переданий query, він буде записаний у лог у фоновій задачі.
+Якщо у запиті був переданий параметр запиту, він буде записаний у лог у фоновій задачі.
-А потім інша фонова задача, згенерована у *функції операції шляху*, запише повідомлення з використанням path параметра `email`.
+А потім інша фонова задача, згенерована у функції операції шляху, запише повідомлення з використанням параметра шляху `email`.
## Технічні деталі { #technical-details }
@@ -65,7 +65,7 @@
Він імпортується/включається безпосередньо у FastAPI, щоб ви могли імпортувати його з `fastapi` і випадково не імпортували альтернативний `BackgroundTask` (без `s` в кінці) з `starlette.background`.
-Якщо використовувати лише `BackgroundTasks` (а не `BackgroundTask`), то його можна передавати як параметр у *функції операції шляху*, і **FastAPI** подбає про все інше, так само як і про використання об'єкта `Request`.
+Якщо використовувати лише `BackgroundTasks` (а не `BackgroundTask`), то його можна передавати як параметр у функції операції шляху, і **FastAPI** подбає про все інше, так само як і про використання об'єкта `Request`.
Також можна використовувати `BackgroundTask` окремо в FastAPI, але для цього вам доведеться створити об'єкт у коді та повернути Starlette `Response`, включаючи його.
@@ -81,4 +81,4 @@
## Підсумок { #recap }
-Імпортуйте та використовуйте `BackgroundTasks` як параметри у *функціях операції шляху* та залежностях, щоб додавати фонові задачі.
+Імпортуйте та використовуйте `BackgroundTasks` як параметри у функціях операції шляху та залежностях, щоб додавати фонові задачі.
diff --git a/docs/uk/docs/tutorial/bigger-applications.md b/docs/uk/docs/tutorial/bigger-applications.md
new file mode 100644
index 0000000000..a75da2ac6d
--- /dev/null
+++ b/docs/uk/docs/tutorial/bigger-applications.md
@@ -0,0 +1,504 @@
+# Більші застосунки - кілька файлів { #bigger-applications-multiple-files }
+
+Якщо ви створюєте застосунок або веб-API, рідко вдається вмістити все в один файл.
+
+**FastAPI** надає зручний інструмент для структурування вашого застосунку, зберігаючи всю гнучкість.
+
+/// info | Інформація
+
+Якщо ви прийшли з Flask, це еквівалент «Blueprints» у Flask.
+
+///
+
+## Приклад структури файлів { #an-example-file-structure }
+
+Припустімо, у вас така структура файлів:
+
+```
+.
+├── app
+│ ├── __init__.py
+│ ├── main.py
+│ ├── dependencies.py
+│ └── routers
+│ │ ├── __init__.py
+│ │ ├── items.py
+│ │ └── users.py
+│ └── internal
+│ ├── __init__.py
+│ └── admin.py
+```
+
+/// tip | Порада
+
+Тут кілька файлів `__init__.py`: по одному в кожному каталозі та підкаталозі.
+
+Саме це дозволяє імпортувати код з одного файлу в інший.
+
+Наприклад, у `app/main.py` ви можете мати рядок:
+
+```
+from app.routers import items
+```
+
+///
+
+* Каталог `app` містить усе. І він має порожній файл `app/__init__.py`, тож це «пакет Python» (збірка «модулів Python»): `app`.
+* Він містить файл `app/main.py`. Оскільки він усередині пакета Python (каталог з файлом `__init__.py`), це «модуль» цього пакета: `app.main`.
+* Є також файл `app/dependencies.py`, так само як `app/main.py`, це «модуль»: `app.dependencies`.
+* Є підкаталог `app/routers/` з іншим файлом `__init__.py`, отже це «підпакет Python»: `app.routers`.
+* Файл `app/routers/items.py` знаходиться в пакеті `app/routers/`, отже це підмодуль: `app.routers.items`.
+* Так само і `app/routers/users.py`, це інший підмодуль: `app.routers.users`.
+* Є також підкаталог `app/internal/` з іншим файлом `__init__.py`, отже це інший «підпакет Python»: `app.internal`.
+* І файл `app/internal/admin.py` - ще один підмодуль: `app.internal.admin`.
+
+

+
+Та сама структура файлів з коментарями:
+
+```bash
+.
+├── app # «app» - це пакет Python
+│ ├── __init__.py # цей файл робить «app» «пакетом Python»
+│ ├── main.py # модуль «main», напр. import app.main
+│ ├── dependencies.py # модуль «dependencies», напр. import app.dependencies
+│ └── routers # «routers» - це «підпакет Python»
+│ │ ├── __init__.py # робить «routers» «підпакетом Python»
+│ │ ├── items.py # підмодуль «items», напр. import app.routers.items
+│ │ └── users.py # підмодуль «users», напр. import app.routers.users
+│ └── internal # «internal» - це «підпакет Python»
+│ ├── __init__.py # робить «internal» «підпакетом Python»
+│ └── admin.py # підмодуль «admin», напр. import app.internal.admin
+```
+
+## `APIRouter` { #apirouter }
+
+Припустімо, файл, присвячений обробці лише користувачів, - це підмодуль у `/app/routers/users.py`.
+
+Ви хочете мати *операції шляху*, пов'язані з користувачами, відокремлено від решти коду, щоб зберегти порядок.
+
+Але це все одно частина того самого застосунку/веб-API **FastAPI** (це частина того самого «пакета Python»).
+
+Ви можете створювати *операції шляху* для цього модуля, використовуючи `APIRouter`.
+
+### Імпортуйте `APIRouter` { #import-apirouter }
+
+Імпортуйте його та створіть «екземпляр» так само, як ви б робили з класом `FastAPI`:
+
+{* ../../docs_src/bigger_applications/app_an_py310/routers/users.py hl[1,3] title["app/routers/users.py"] *}
+
+### *Операції шляху* з `APIRouter` { #path-operations-with-apirouter }
+
+Потім використовуйте його для оголошення *операцій шляху*.
+
+Використовуйте його так само, як і клас `FastAPI`:
+
+{* ../../docs_src/bigger_applications/app_an_py310/routers/users.py hl[6,11,16] title["app/routers/users.py"] *}
+
+Можете думати про `APIRouter` як про «міні `FastAPI`».
+
+Підтримуються ті самі опції.
+
+Ті самі `parameters`, `responses`, `dependencies`, `tags` тощо.
+
+/// tip | Порада
+
+У цьому прикладі змінна називається `router`, але ви можете назвати її як завгодно.
+
+///
+
+Ми включимо цей `APIRouter` у основний застосунок `FastAPI`, але спочатку розгляньмо залежності та інший `APIRouter`.
+
+## Залежності { #dependencies }
+
+Бачимо, що нам знадобляться кілька залежностей, які використовуються в різних місцях застосунку.
+
+Тож помістимо їх у власний модуль `dependencies` (`app/dependencies.py`).
+
+Тепер використаємо просту залежність для читання користувацького заголовка `X-Token`:
+
+{* ../../docs_src/bigger_applications/app_an_py310/dependencies.py hl[3,6:8] title["app/dependencies.py"] *}
+
+/// tip | Порада
+
+Ми використовуємо вигаданий заголовок, щоб спростити приклад.
+
+Але в реальних випадках ви отримаєте кращі результати, використовуючи інтегровані [засоби безпеки](security/index.md){.internal-link target=_blank}.
+
+///
+
+## Інший модуль з `APIRouter` { #another-module-with-apirouter }
+
+Припустімо, у вас також є кінцеві точки для обробки «items» у модулі `app/routers/items.py`.
+
+У вас є *операції шляху* для:
+
+* `/items/`
+* `/items/{item_id}`
+
+Структура така сама, як у `app/routers/users.py`.
+
+Але ми хочемо бути розумнішими й трохи спростити код.
+
+Ми знаємо, що всі *операції шляху* в цьому модулі мають однакові:
+
+* Префікс шляху `prefix`: `/items`.
+* `tags`: (лише одна мітка: `items`).
+* Додаткові `responses`.
+* `dependencies`: усім потрібна залежність `X-Token`, яку ми створили.
+
+Тож замість додавання цього до кожної *операції шляху*, ми можемо додати це до `APIRouter`.
+
+{* ../../docs_src/bigger_applications/app_an_py310/routers/items.py hl[5:10,16,21] title["app/routers/items.py"] *}
+
+Оскільки шлях кожної *операції шляху* має починатися з `/`, як у:
+
+```Python hl_lines="1"
+@router.get("/{item_id}")
+async def read_item(item_id: str):
+ ...
+```
+
+...префікс не має містити кінцевий `/`.
+
+Отже, у цьому випадку префікс - це `/items`.
+
+Ми також можемо додати список `tags` та додаткові `responses`, які застосовуватимуться до всіх *операцій шляху*, включених у цей router.
+
+І ми можемо додати список `dependencies`, які буде додано до всіх *операцій шляху* у router і які виконуватимуться/вирішуватимуться для кожного запиту до них.
+
+/// tip | Порада
+
+Зверніть увагу, що так само як і для [залежностей у декораторах *операцій шляху*](dependencies/dependencies-in-path-operation-decorators.md){.internal-link target=_blank}, жодне значення не буде передано вашій *функції операції шляху*.
+
+///
+
+У підсумку шляхи предметів тепер:
+
+* `/items/`
+* `/items/{item_id}`
+
+...як ми і планували.
+
+* Вони будуть позначені списком міток, що містить один рядок `"items"`.
+ * Ці «мітки» особливо корисні для автоматичної інтерактивної документації (за допомогою OpenAPI).
+* Усі вони включатимуть наперед визначені `responses`.
+* Для всіх цих *операцій шляху* список `dependencies` буде оцінений/виконаний перед ними.
+ * Якщо ви також оголосите залежності в конкретній *операції шляху*, **вони також будуть виконані**.
+ * Спочатку виконуються залежності router'а, потім [`dependencies` у декораторі](dependencies/dependencies-in-path-operation-decorators.md){.internal-link target=_blank}, а потім звичайні параметричні залежності.
+ * Ви також можете додати [`Security` залежності з `scopes`](../advanced/security/oauth2-scopes.md){.internal-link target=_blank}.
+
+/// tip | Порада
+
+Наявність `dependencies` у `APIRouter` можна використати, наприклад, щоб вимагати автентифікацію для всієї групи *операцій шляху*. Навіть якщо залежності не додані до кожної з них окремо.
+
+///
+
+/// check | Перевірте
+
+Параметри `prefix`, `tags`, `responses` і `dependencies` - це (як і в багатьох інших випадках) просто можливість **FastAPI**, яка допомагає уникати дублювання коду.
+
+///
+
+### Імпортуйте залежності { #import-the-dependencies }
+
+Цей код живе в модулі `app.routers.items`, у файлі `app/routers/items.py`.
+
+І нам потрібно отримати функцію залежності з модуля `app.dependencies`, файлу `app/dependencies.py`.
+
+Тож ми використовуємо відносний імпорт з `..` для залежностей:
+
+{* ../../docs_src/bigger_applications/app_an_py310/routers/items.py hl[3] title["app/routers/items.py"] *}
+
+#### Як працюють відносні імпорти { #how-relative-imports-work }
+
+/// tip | Порада
+
+Якщо ви досконало знаєте, як працюють імпорти, перейдіть до наступного розділу нижче.
+
+///
+
+Одна крапка `.`, як у:
+
+```Python
+from .dependencies import get_token_header
+```
+
+означає:
+
+* Починаючи в тому самому пакеті, де знаходиться цей модуль (файл `app/routers/items.py`) (каталог `app/routers/`)...
+* знайти модуль `dependencies` (уявний файл `app/routers/dependencies.py`)...
+* і з нього імпортувати функцію `get_token_header`.
+
+Але такого файлу не існує, наші залежності у файлі `app/dependencies.py`.
+
+Згадайте, як виглядає структура нашого застосунку/файлів:
+
+

+
+---
+
+Дві крапки `..`, як у:
+
+```Python
+from ..dependencies import get_token_header
+```
+
+означають:
+
+* Починаючи в тому самому пакеті, де знаходиться цей модуль (файл `app/routers/items.py`) (каталог `app/routers/`)...
+* перейти до батьківського пакета (каталог `app/`)...
+* і там знайти модуль `dependencies` (файл `app/dependencies.py`)...
+* і з нього імпортувати функцію `get_token_header`.
+
+Це працює правильно! 🎉
+
+---
+
+Так само, якби ми використали три крапки `...`, як у:
+
+```Python
+from ...dependencies import get_token_header
+```
+
+це б означало:
+
+* Починаючи в тому самому пакеті, де знаходиться цей модуль (файл `app/routers/items.py`) (каталог `app/routers/`)...
+* перейти до батьківського пакета (каталог `app/`)...
+* потім перейти до батьківського пакета від того (немає батьківського пакета, `app` - верхній рівень 😱)...
+* і там знайти модуль `dependencies` (файл `app/dependencies.py`)...
+* і з нього імпортувати функцію `get_token_header`.
+
+Це б посилалося на якийсь пакет вище за `app/` з власним файлом `__init__.py` тощо. Але в нас такого немає. Тож у нашому прикладі це спричинить помилку. 🚨
+
+Але тепер ви знаєте, як це працює, тож можете використовувати відносні імпорти у власних застосунках, незалежно від їхньої складності. 🤓
+
+### Додайте користувацькі `tags`, `responses` і `dependencies` { #add-some-custom-tags-responses-and-dependencies }
+
+Ми не додаємо префікс `/items` ані `tags=["items"]` до кожної *операції шляху*, бо додали їх до `APIRouter`.
+
+Але ми все ще можемо додати _ще_ `tags`, які будуть застосовані до конкретної *операції шляху*, а також додаткові `responses`, специфічні для цієї *операції шляху*:
+
+{* ../../docs_src/bigger_applications/app_an_py310/routers/items.py hl[30:31] title["app/routers/items.py"] *}
+
+/// tip | Порада
+
+Остання операція шляху матиме комбінацію міток: `["items", "custom"]`.
+
+І вона також матиме в документації обидві відповіді: одну для `404` і одну для `403`.
+
+///
+
+## Основний `FastAPI` { #the-main-fastapi }
+
+Тепер розгляньмо модуль `app/main.py`.
+
+Тут ви імпортуєте і використовуєте клас `FastAPI`.
+
+Це буде головний файл вашого застосунку, який усе поєднує.
+
+І оскільки більшість вашої логіки тепер житиме у власних модулях, головний файл буде досить простим.
+
+### Імпортуйте `FastAPI` { #import-fastapi }
+
+Імпортуйте та створіть клас `FastAPI`, як зазвичай.
+
+І ми навіть можемо оголосити [глобальні залежності](dependencies/global-dependencies.md){.internal-link target=_blank}, які будуть поєднані із залежностями кожного `APIRouter`:
+
+{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[1,3,7] title["app/main.py"] *}
+
+### Імпортуйте `APIRouter` { #import-the-apirouter }
+
+Тепер імпортуємо інші підмодулі, що мають `APIRouter`:
+
+{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[4:5] title["app/main.py"] *}
+
+Оскільки файли `app/routers/users.py` та `app/routers/items.py` - це підмодулі, що є частиною того самого пакета Python `app`, ми можемо використати одну крапку `.` для «відносних імпортів».
+
+### Як працює імпорт { #how-the-importing-works }
+
+Розділ:
+
+```Python
+from .routers import items, users
+```
+
+означає:
+
+* Починаючи в тому самому пакеті, де знаходиться цей модуль (файл `app/main.py`) (каталог `app/`)...
+* знайти підпакет `routers` (каталог `app/routers/`)...
+* і з нього імпортувати підмодулі `items` (файл `app/routers/items.py`) і `users` (файл `app/routers/users.py`)...
+
+Модуль `items` матиме змінну `router` (`items.router`). Це та сама, що ми створили у файлі `app/routers/items.py`, це об’єкт `APIRouter`.
+
+Потім ми робимо те саме для модуля `users`.
+
+Ми також могли б імпортувати їх так:
+
+```Python
+from app.routers import items, users
+```
+
+/// info | Інформація
+
+Перша версія - «відносний імпорт»:
+
+```Python
+from .routers import items, users
+```
+
+Друга версія - «абсолютний імпорт»:
+
+```Python
+from app.routers import items, users
+```
+
+Щоб дізнатися більше про пакети й модулі Python, прочитайте
офіційну документацію Python про модулі.
+
+///
+
+### Уникайте колізій імен { #avoid-name-collisions }
+
+Ми імпортуємо підмодуль `items` напряму, замість імпорту лише його змінної `router`.
+
+Це тому, що в підмодулі `users` також є змінна з назвою `router`.
+
+Якби ми імпортували один за одним, як:
+
+```Python
+from .routers.items import router
+from .routers.users import router
+```
+
+`router` з `users` перезаписав би той, що з `items`, і ми не змогли б використовувати їх одночасно.
+
+Щоб мати змогу використовувати обидва в одному файлі, ми імпортуємо підмодулі напряму:
+
+{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[5] title["app/main.py"] *}
+
+### Додайте `APIRouter` для `users` і `items` { #include-the-apirouters-for-users-and-items }
+
+Тепер додаймо `router` з підмодулів `users` і `items`:
+
+{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[10:11] title["app/main.py"] *}
+
+/// info | Інформація
+
+`users.router` містить `APIRouter` у файлі `app/routers/users.py`.
+
+А `items.router` містить `APIRouter` у файлі `app/routers/items.py`.
+
+///
+
+За допомогою `app.include_router()` ми можемо додати кожен `APIRouter` до основного застосунку `FastAPI`.
+
+Це включить усі маршрути з цього router'а як частину застосунку.
+
+/// note | Технічні деталі
+
+Фактично, всередині для кожної *операції шляху*, оголошеної в `APIRouter`, буде створена окрема *операція шляху*.
+
+Тобто за лаштунками все працюватиме так, ніби це один і той самий застосунок.
+
+///
+
+/// check | Перевірте
+
+Вам не потрібно перейматися продуктивністю під час включення router'ів.
+
+Це займе мікросекунди і відбуватиметься лише під час запуску.
+
+Тож це не вплине на продуктивність. ⚡
+
+///
+
+### Додайте `APIRouter` з власними `prefix`, `tags`, `responses` і `dependencies` { #include-an-apirouter-with-a-custom-prefix-tags-responses-and-dependencies }
+
+Уявімо, що ваша організація надала вам файл `app/internal/admin.py`.
+
+Він містить `APIRouter` з кількома адміністративними *операціями шляху*, які організація спільно використовує між кількома проєктами.
+
+Для цього прикладу він буде дуже простим. Але припустімо, що оскільки його спільно використовують з іншими проєктами організації, ми не можемо модифікувати його та додавати `prefix`, `dependencies`, `tags` тощо прямо до `APIRouter`:
+
+{* ../../docs_src/bigger_applications/app_an_py310/internal/admin.py hl[3] title["app/internal/admin.py"] *}
+
+Але ми все одно хочемо встановити користувацький `prefix` під час включення `APIRouter`, щоб усі його *операції шляху* починалися з `/admin`, хочемо захистити його за допомогою `dependencies`, які вже є в цьому проєкті, і хочемо додати `tags` та `responses`.
+
+Ми можемо оголосити все це, не змінюючи оригінальний `APIRouter`, передавши ці параметри до `app.include_router()`:
+
+{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[14:17] title["app/main.py"] *}
+
+Таким чином, вихідний `APIRouter` залишиться без змін, тож ми все ще зможемо спільно використовувати той самий файл `app/internal/admin.py` з іншими проєктами в організації.
+
+У результаті в нашому застосунку кожна з *операцій шляху* з модуля `admin` матиме:
+
+* Префікс `/admin`.
+* Мітку `admin`.
+* Залежність `get_token_header`.
+* Відповідь `418`. 🍵
+
+Але це вплине лише на цей `APIRouter` у нашому застосунку, а не на будь-який інший код, який його використовує.
+
+Наприклад, інші проєкти можуть використовувати той самий `APIRouter` з іншим методом автентифікації.
+
+### Додайте *операцію шляху* { #include-a-path-operation }
+
+Ми також можемо додавати *операції шляху* безпосередньо до застосунку `FastAPI`.
+
+Тут ми це робимо... просто щоб показати, що так можна 🤷:
+
+{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[21:23] title["app/main.py"] *}
+
+і це працюватиме коректно разом з усіма іншими *операціями шляху*, доданими через `app.include_router()`.
+
+/// info | Дуже технічні деталі
+
+Примітка: це дуже технічна деталь, яку ви, ймовірно, можете просто пропустити.
+
+---
+
+`APIRouter` не «монтуються», вони не ізольовані від решти застосунку.
+
+Це тому, що ми хочемо включати їхні *операції шляху* в схему OpenAPI та інтерфейси користувача.
+
+Оскільки ми не можемо просто ізолювати їх і «змонтувати» незалежно від решти, *операції шляху* «клонуються» (створюються заново), а не включаються безпосередньо.
+
+///
+
+## Перевірте автоматичну документацію API { #check-the-automatic-api-docs }
+
+Тепер запустіть ваш застосунок:
+
+
+
+```console
+$ fastapi dev app/main.py
+
+INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
+```
+
+
+
+І відкрийте документацію за адресою
http://127.0.0.1:8000/docs.
+
+Ви побачите автоматичну документацію API, що включає шляхи з усіх підмодулів, з правильними шляхами (і префіксами) та правильними мітками:
+
+

+
+## Включайте той самий router кілька разів з різними `prefix` { #include-the-same-router-multiple-times-with-different-prefix }
+
+Ви також можете використовувати `.include_router()` кілька разів з одним і тим самим router'ом, але з різними префіксами.
+
+Це може бути корисно, наприклад, щоб публікувати той самий API під різними префіксами, наприклад `/api/v1` і `/api/latest`.
+
+Це просунуте використання, яке вам може й не знадобитися, але воно є на випадок, якщо потрібно.
+
+## Включіть один `APIRouter` до іншого { #include-an-apirouter-in-another }
+
+Так само як ви можете включити `APIRouter` у застосунок `FastAPI`, ви можете включити `APIRouter` в інший `APIRouter`, використовуючи:
+
+```Python
+router.include_router(other_router)
+```
+
+Переконайтеся, що ви робите це до включення `router` в застосунок `FastAPI`, щоб *операції шляху* з `other_router` також були включені.
diff --git a/docs/uk/docs/tutorial/body-multiple-params.md b/docs/uk/docs/tutorial/body-multiple-params.md
index f541beea76..a0db2b1865 100644
--- a/docs/uk/docs/tutorial/body-multiple-params.md
+++ b/docs/uk/docs/tutorial/body-multiple-params.md
@@ -18,7 +18,7 @@
## Декілька параметрів тіла { #multiple-body-parameters }
-У попередньому прикладі *операції шляху* очікували б JSON-тіло з атрибутами `Item`, наприклад:
+У попередньому прикладi *операції шляху* очікували б JSON-тіло з атрибутами `Item`, наприклад:
```JSON
{
@@ -106,13 +106,6 @@
q: str | None = None
```
-Або в Python 3.9:
-
-```Python
-q: Union[str, None] = None
-```
-
-
Наприклад:
{* ../../docs_src/body_multiple_params/tutorial004_an_py310.py hl[28] *}
diff --git a/docs/uk/docs/tutorial/body-nested-models.md b/docs/uk/docs/tutorial/body-nested-models.md
index 6d0669358a..a56ae484df 100644
--- a/docs/uk/docs/tutorial/body-nested-models.md
+++ b/docs/uk/docs/tutorial/body-nested-models.md
@@ -164,7 +164,7 @@ images: list[Image]
наприклад:
-{* ../../docs_src/body_nested_models/tutorial008_py39.py hl[13] *}
+{* ../../docs_src/body_nested_models/tutorial008_py310.py hl[13] *}
## Підтримка в редакторі всюди { #editor-support-everywhere }
@@ -194,7 +194,7 @@ images: list[Image]
У цьому випадку ви можете приймати будь-який `dict`, якщо його ключі — це `int`, а значення — `float`:
-{* ../../docs_src/body_nested_models/tutorial009_py39.py hl[7] *}
+{* ../../docs_src/body_nested_models/tutorial009_py310.py hl[7] *}
/// tip | Порада
@@ -216,6 +216,6 @@ images: list[Image]
* Підтримка в редакторі (автодоповнення всюди!)
* Конвертація даних (парсинг/сериалізація)
-* Валідацію даних
+* Валідація даних
* Документація схем
* Автоматичне створення документації
diff --git a/docs/uk/docs/tutorial/body.md b/docs/uk/docs/tutorial/body.md
index ca1f308ab5..615f0274cc 100644
--- a/docs/uk/docs/tutorial/body.md
+++ b/docs/uk/docs/tutorial/body.md
@@ -8,7 +8,7 @@
Щоб оголосити тіло **запиту**, ви використовуєте
Pydantic моделі з усією їх потужністю та перевагами.
-/// info | Інформація
+/// info
Щоб надіслати дані, ви повинні використовувати один із: `POST` (більш поширений), `PUT`, `DELETE` або `PATCH`.
@@ -73,8 +73,8 @@
* Якщо дані недійсні, він поверне гарну та чітку помилку, вказуючи, де саме і які дані були неправильними.
* Надавати отримані дані у параметрі `item`.
* Оскільки ви оголосили його у функції як тип `Item`, ви також матимете всю підтримку редактора (автозаповнення, тощо) для всіх атрибутів та їх типів.
-* Генерувати
JSON Schema визначення для вашої моделі, ви також можете використовувати їх де завгодно, якщо це має сенс для вашого проекту.
-* Ці схеми будуть частиною згенерованої схеми OpenAPI і використовуватимуться автоматичною документацією
UIs.
+* Генерувати визначення
Схеми JSON для вашої моделі, ви також можете використовувати їх де завгодно, якщо це має сенс для вашого проекту.
+* Ці схеми будуть частиною згенерованої схеми OpenAPI і використовуватимуться автоматичною документацією
UIs.
## Автоматична документація { #automatic-docs }
@@ -108,7 +108,7 @@

-/// tip | Порада
+/// tip
Якщо ви використовуєте
PyCharm як ваш редактор, ви можете використати
Pydantic PyCharm Plugin.
@@ -151,11 +151,11 @@
* Якщо параметр має **сингулярний тип** (наприклад, `int`, `float`, `str`, `bool` тощо), він буде інтерпретуватися як параметр **запиту**.
* Якщо параметр оголошується як тип **Pydantic моделі**, він інтерпретується як **тіло** **запиту**.
-/// note | Примітка
+/// note
FastAPI буде знати, що значення `q` не є обов'язковим через значення за замовчуванням `= None`.
-`str | None` (Python 3.10+) або `Union` у `Union[str, None]` (Python 3.9+) FastAPI не використовує, щоб визначити, що значення не є обов’язковим — він знатиме, що воно не є обов’язковим, тому що має значення за замовчуванням `= None`.
+`str | None` FastAPI не використовує, щоб визначити, що значення не є обов’язковим - він знатиме, що воно не є обов’язковим, тому що має значення за замовчуванням `= None`.
Але додавання анотацій типів дозволить вашому редактору надати вам кращу підтримку та виявляти помилки.
@@ -163,4 +163,4 @@ FastAPI буде знати, що значення `q` не є обов'язко
## Без Pydantic { #without-pydantic }
-Якщо ви не хочете використовувати моделі Pydantic, ви також можете використовувати параметри **Body**. Перегляньте документацію для [Body - Multiple Parameters: Singular values in body](body-multiple-params.md#singular-values-in-body){.internal-link target=_blank}.
+Якщо ви не хочете використовувати моделі Pydantic, ви також можете використовувати параметри **Body**. Перегляньте документацію для [Тіло - Кілька параметрів: Окремі значення в тілі](body-multiple-params.md#singular-values-in-body){.internal-link target=_blank}.
diff --git a/docs/uk/docs/tutorial/cookie-param-models.md b/docs/uk/docs/tutorial/cookie-param-models.md
index 3c6407716e..dab57c5365 100644
--- a/docs/uk/docs/tutorial/cookie-param-models.md
+++ b/docs/uk/docs/tutorial/cookie-param-models.md
@@ -1,8 +1,8 @@
# Моделі параметрів Cookie { #cookie-parameter-models }
-Якщо у Вас є група **cookies**, які пов'язані між собою, Ви можете створити **Pydantic-модель**, щоб оголосити їх. 🍪
+Якщо у вас є група **cookies**, які пов'язані між собою, ви можете створити **Pydantic-модель**, щоб оголосити їх. 🍪
-Це дозволить Вам повторно **використовувати модель** у **різних місцях**, а також оголосити валідацію та метадані для всіх параметрів одночасно. 😎
+Це дозволить вам повторно **використовувати модель** у **різних місцях**, а також оголосити валідацію та метадані для всіх параметрів одночасно. 😎
/// note | Примітка
@@ -18,11 +18,11 @@
## Cookie з Pydantic-моделлю { #cookies-with-a-pydantic-model }
-Оголосіть **cookie**-параметри, які Вам потрібні, у **Pydantic-моделі**, а потім оголосіть параметр як `Cookie`:
+Оголосіть **cookie**-параметри, які вам потрібні, у **Pydantic-моделі**, а потім оголосіть параметр як `Cookie`:
{* ../../docs_src/cookie_param_models/tutorial001_an_py310.py hl[9:12,16] *}
-**FastAPI** буде **витягувати** дані для **кожного поля** з **cookies**, отриманих у запиті, і передавати Вам Pydantic-модель, яку Ви визначили.
+**FastAPI** буде **витягувати** дані для **кожного поля** з **cookies**, отриманих у запиті, і передавати вам Pydantic-модель, яку ви визначили.
## Перевірка у документації { #check-the-docs }
@@ -36,17 +36,17 @@
Майте на увазі, що оскільки **браузери обробляють cookies** особливим чином і «за лаштунками», вони **не** дозволяють **JavaScript** легко з ними працювати.
-Якщо Ви зайдете до **інтерфейсу документації API** за адресою `/docs`, Ви зможете побачити **документацію** для cookies у Ваших *операціях шляху*.
+Якщо ви зайдете до **інтерфейсу документації API** за адресою `/docs`, ви зможете побачити **документацію** для cookies у ваших *операціях шляху*.
-Але навіть якщо Ви заповните дані й натиснете "Execute", оскільки інтерфейс документації працює з **JavaScript**, cookies не будуть відправлені, і Ви побачите **помилку**, ніби Ви не ввели жодних значень.
+Але навіть якщо ви заповните дані й натиснете "Execute", оскільки інтерфейс документації працює з **JavaScript**, cookies не будуть відправлені, і ви побачите **помилку**, ніби ви не ввели жодних значень.
///
## Заборона додаткових cookie { #forbid-extra-cookies }
-У деяких спеціальних випадках (ймовірно, не дуже поширених) Ви можете захотіти **обмежити** cookies, які хочете отримувати.
+У деяких спеціальних випадках (ймовірно, не дуже поширених) ви можете захотіти **обмежити** cookies, які хочете отримувати.
-Ваша API тепер має можливість контролювати власну
згоду на cookie. 🤪🍪
+Ваш API тепер має можливість контролювати власну
згоду на cookies. 🤪🍪
Ви можете використовувати налаштування моделі Pydantic, щоб `forbid` будь-які `extra` поля:
@@ -54,9 +54,9 @@
Якщо клієнт спробує надіслати якісь **додаткові cookies**, він отримає відповідь з **помилкою**.
-Бідні банери cookie, які так старанно намагаються отримати Вашу згоду, щоб
API її відхилила. 🍪
+Бідні банери cookie, які так старанно намагаються отримати вашу згоду, щоб
API її відхилила. 🍪
-Наприклад, якщо клієнт спробує надіслати cookie `santa_tracker` зі значенням `good-list-please`, він отримає відповідь з помилкою, яка повідомить, що `santa_tracker`
cookie не дозволено:
+Наприклад, якщо клієнт спробує надіслати cookie `santa_tracker` зі значенням `good-list-please`, він отримає відповідь з помилкою, яка повідомить, що `santa_tracker`
cookie не дозволено:
```json
{
@@ -73,4 +73,4 @@
## Підсумок { #summary }
-Ви можете використовувати **Pydantic-моделі** для оголошення
**cookies** у **FastAPI**. 😎
+Ви можете використовувати **Pydantic-моделі** для оголошення
**cookies** у **FastAPI**. 😎
diff --git a/docs/uk/docs/tutorial/cookie-params.md b/docs/uk/docs/tutorial/cookie-params.md
index 8a5b44e8aa..3a2e6fa24e 100644
--- a/docs/uk/docs/tutorial/cookie-params.md
+++ b/docs/uk/docs/tutorial/cookie-params.md
@@ -1,6 +1,6 @@
-# Параметри Cookie { #cookie-parameters }
+# Параметри кукі { #cookie-parameters }
-Ви можете визначати параметри Cookie таким же чином, як визначаються параметри `Query` і `Path`.
+Ви можете визначати параметри кукі таким же чином, як визначаються параметри `Query` і `Path`.
## Імпорт `Cookie` { #import-cookie }
@@ -10,7 +10,7 @@
## Визначення параметрів `Cookie` { #declare-cookie-parameters }
-Потім визначте параметри cookie, використовуючи таку ж конструкцію як для `Path` і `Query`.
+Потім визначте параметри кукі, використовуючи таку ж конструкцію як для `Path` і `Query`.
Ви можете визначити значення за замовчуванням, а також усі додаткові параметри валідації чи анотації:
@@ -26,20 +26,20 @@
/// info
-Для визначення cookies ви маєте використовувати `Cookie`, тому що в іншому випадку параметри будуть інтерпритовані, як параметри запиту.
+Для визначення кукі ви маєте використовувати `Cookie`, тому що в іншому випадку параметри будуть інтерпретовані як параметри запиту.
///
/// info
-Майте на увазі, що оскільки **браузери обробляють cookies** спеціальним чином і за лаштунками, вони **не** дозволяють **JavaScript** легко взаємодіяти з ними.
+Майте на увазі, що оскільки **браузери обробляють кукі** спеціальним чином і за лаштунками, вони **не** дозволяють **JavaScript** легко взаємодіяти з ними.
-Якщо ви перейдете до **інтерфейсу документації API** за адресою `/docs`, ви зможете побачити **документацію** для cookies для ваших *операцій шляху*.
+Якщо ви перейдете до **інтерфейсу документації API** за адресою `/docs`, ви зможете побачити **документацію** для кукі для ваших *операцій шляху*.
-Але навіть якщо ви **заповните дані** і натиснете "Execute", оскільки інтерфейс документації працює з **JavaScript**, cookies не буде надіслано, і ви побачите повідомлення про **помилку**, ніби ви не ввели жодних значень.
+Але навіть якщо ви **заповните дані** і натиснете "Execute", оскільки інтерфейс документації працює з **JavaScript**, кукі не буде надіслано, і ви побачите повідомлення про **помилку**, ніби ви не ввели жодних значень.
///
## Підсумки { #recap }
-Визначайте cookies за допомогою `Cookie`, використовуючи той же спільний шаблон, що і `Query` та `Path`.
+Визначайте кукі за допомогою `Cookie`, використовуючи той же спільний шаблон, що і `Query` та `Path`.
diff --git a/docs/uk/docs/tutorial/cors.md b/docs/uk/docs/tutorial/cors.md
index f3ed8a7d94..5c959cef18 100644
--- a/docs/uk/docs/tutorial/cors.md
+++ b/docs/uk/docs/tutorial/cors.md
@@ -1,6 +1,6 @@
# CORS (Обмін ресурсами між різними джерелами) { #cors-cross-origin-resource-sharing }
-
CORS або "Cross-Origin Resource Sharing" є ситуація, коли фронтенд, що працює в браузері, містить JavaScript-код, який взаємодіє з бекендом, розташованим в іншому "джерелі" (origin).
+
CORS або «Cross-Origin Resource Sharing» є ситуація, коли фронтенд, що працює в браузері, містить JavaScript-код, який взаємодіє з бекендом, розташованим в іншому «джерелі» (origin).
## Джерело (Origin) { #origin }
@@ -13,50 +13,49 @@
* `https://localhost`
* `http://localhost:8080`
-Навіть якщо вони всі містять `localhost`, вони мають різні протоколи або порти, що робить їх окремими "джерелами".
+Навіть якщо вони всі містять `localhost`, вони мають різні протоколи або порти, що робить їх окремими «джерелами».
## Кроки { #steps }
-Припустимо, що Ваш фронтенд працює в браузері на `http://localhost:8080`, а його JavaScript намагається відправити запит до бекенду, який працює на `http://localhost` (Оскільки ми не вказуємо порт, браузер за замовчуванням припускає порт `80`).
+Припустимо, що ваш фронтенд працює в браузері на `http://localhost:8080`, а його JavaScript намагається відправити запит до бекенду, який працює на `http://localhost` (Оскільки ми не вказуємо порт, браузер за замовчуванням припускає порт `80`).
Потім браузер надішле HTTP-запит `OPTIONS` до бекенду на порту `:80`, і якщо бекенд надішле відповідні заголовки, що дозволяють комунікацію з цього іншого джерела (`http://localhost:8080`), тоді браузер на порту `:8080` дозволить JavaScript у фронтенді надіслати свій запит до бекенду на порту `:80`.
-Щоб досягти цього, бекенд на порту `:80` повинен мати список "дозволених джерел".
+Щоб досягти цього, бекенд на порту `:80` повинен мати список «дозволених джерел».
У цьому випадку список має містити `http://localhost:8080`, щоб фронтенд на порту `:8080` працював коректно.
-## Символьне підставляння { #wildcards }
+## Дикі карти { #wildcards }
-Можна також оголосити список як `"*"` ("символьне підставляння"), що означає дозвіл для всіх джерел.
+Можна також оголосити список як `"*"` (дика карта), що означає дозвіл для всіх джерел.
-Однак це дозволить лише певні типи комунікації, виключаючи все, що пов'язане з обліковими даними: Cookies, заголовки авторизації, такі як ті, що використовуються з Bearer Tokens, тощо.
+Однак це дозволить лише певні типи комунікації, виключаючи все, що пов'язане з обліковими даними: Cookies, заголовки авторизації, як-от ті, що використовуються з токенами носія, тощо.
Тому для коректної роботи краще явно вказувати дозволені джерела.
## Використання `CORSMiddleware` { #use-corsmiddleware }
-Ви можете налаштувати це у Вашому додатку **FastAPI** за допомогою `CORSMiddleware`.
+Ви можете налаштувати це у вашому додатку **FastAPI** за допомогою `CORSMiddleware`.
* Імпортуйте `CORSMiddleware`.
* Створіть список дозволених джерел (у вигляді рядків).
-* Додайте його як "middleware" у Ваш додаток **FastAPI**.
+* Додайте його як «проміжне програмне забезпечення» у ваш додаток **FastAPI**.
-
-Також можна вказати, чи дозволяє Ваш бекенд:
+Також можна вказати, чи дозволяє ваш бекенд:
* Облікові дані (заголовки авторизації, Cookies, тощо).
* Конкретні HTTP-методи (`POST`, `PUT`) або всі за допомогою `"*"`
* Конкретні HTTP-заголовки або всі за допомогою `"*"`.
-{* ../../docs_src/cors/tutorial001_py39.py hl[2,6:11,13:19] *}
+{* ../../docs_src/cors/tutorial001_py310.py hl[2,6:11,13:19] *}
-Параметри за замовчуванням у реалізації `CORSMiddleware` є досить обмеженими, тому Вам потрібно явно увімкнути конкретні джерела, методи або заголовки, щоб браузерам було дозволено використовувати їх у міждоменному контексті.
+Параметри за замовчуванням у реалізації `CORSMiddleware` є досить обмеженими, тому вам потрібно явно увімкнути конкретні джерела, методи або заголовки, щоб браузерам було дозволено використовувати їх у міждоменному контексті.
Підтримуються такі аргументи:
-* `allow_origins` - Список джерел, яким дозволено здійснювати міждоменні запити. Наприклад `['https://example.org', 'https://www.example.org']`. Ви можете використовувати `['*']`, щоб дозволити будь-яке джерело.
+* `allow_origins` - Список джерел, яким дозволено здійснювати міждоменні запити. Наприклад `['https://example.org', 'https://www.example.org']`. Ви можете використовувати `['*']`, щоб дозволити будь-яке джерело.
* `allow_origin_regex` - Рядок регулярного виразу для відповідності джерелам, яким дозволено здійснювати міждоменні запити. Наприклад, `'https://.*\.example\.org'`.
* `allow_methods` - Список HTTP-методів, дозволених для міждоменних запитів. За замовчуванням `['GET']`. Ви можете використовувати `['*']`, щоб дозволити всі стандартні методи.
* `allow_headers` - Список HTTP-заголовків запиту, які підтримуються для міждоменних запитів. За замовчуванням `[]`. Ви можете використовувати `['*']`, щоб дозволити всі заголовки. Заголовки `Accept`, `Accept-Language`, `Content-Language` і `Content-Type` завжди дозволені для
простих CORS-запитів.
@@ -67,7 +66,7 @@
* `expose_headers` - Вказує, які заголовки відповіді повинні бути доступні для браузера. За замовчуванням `[]`.
* `max_age` - Встановлює максимальний час (у секундах) для кешування CORS-відповідей у браузерах. За замовчуванням `600`.
-Цей middleware обробляє два типи HTTP-запитів...
+Це проміжне програмне забезпечення обробляє два типи HTTP-запитів...
### Попередні CORS-запити { #cors-preflight-requests }
@@ -81,7 +80,7 @@
## Додаткова інформація { #more-info }
-Більше про
CORS можна дізнатися в
документації Mozilla про CORS.
+Більше про
CORS можна дізнатися в
документації Mozilla про CORS.
/// note | Технічні деталі
diff --git a/docs/uk/docs/tutorial/debugging.md b/docs/uk/docs/tutorial/debugging.md
index 0db418dcc9..679018cc2f 100644
--- a/docs/uk/docs/tutorial/debugging.md
+++ b/docs/uk/docs/tutorial/debugging.md
@@ -6,7 +6,7 @@
У вашому FastAPI-додатку імпортуйте та запустіть `uvicorn` безпосередньо:
-{* ../../docs_src/debugging/tutorial001_py39.py hl[1,15] *}
+{* ../../docs_src/debugging/tutorial001_py310.py hl[1,15] *}
### Про `__name__ == "__main__"` { #about-name-main }
diff --git a/docs/uk/docs/tutorial/dependencies/classes-as-dependencies.md b/docs/uk/docs/tutorial/dependencies/classes-as-dependencies.md
new file mode 100644
index 0000000000..e64f90ae24
--- /dev/null
+++ b/docs/uk/docs/tutorial/dependencies/classes-as-dependencies.md
@@ -0,0 +1,288 @@
+# Класи як залежності { #classes-as-dependencies }
+
+Перш ніж заглибитися у систему **впровадження залежностей**, оновімо попередній приклад.
+
+## `dict` з попереднього прикладу { #a-dict-from-the-previous-example }
+
+У попередньому прикладі ми повертали `dict` із нашого «залежного»:
+
+{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[9] *}
+
+Але тоді ми отримуємо `dict` у параметрі `commons` функції операції шляху.
+
+І ми знаємо, що редактори не можуть надати багато підтримки (наприклад, автодоповнення) для `dict`, адже вони не знають їхніх ключів і типів значень.
+
+Можна зробити краще…
+
+## Що робить об’єкт залежністю { #what-makes-a-dependency }
+
+Дотепер ви бачили залежності, оголошені як функції.
+
+Але це не єдиний спосіб оголошувати залежності (хоча, ймовірно, найпоширеніший).
+
+Ключовий момент у тому, що залежність має бути «викликаємим».
+
+«Викликаємий» у Python - це будь-що, що Python може «викликати», як функцію.
+
+Отже, якщо у вас є об’єкт `something` (який може й не бути функцією) і ви можете «викликати» його (виконати) так:
+
+```Python
+something()
+```
+
+або
+
+```Python
+something(some_argument, some_keyword_argument="foo")
+```
+
+тоді це «викликаємий».
+
+## Класи як залежності { #classes-as-dependencies_1 }
+
+Ви могли помітити, що для створення екземпляра класу Python ви використовуєте той самий синтаксис.
+
+Наприклад:
+
+```Python
+class Cat:
+ def __init__(self, name: str):
+ self.name = name
+
+
+fluffy = Cat(name="Mr Fluffy")
+```
+
+У цьому випадку `fluffy` - екземпляр класу `Cat`.
+
+А для створення `fluffy` ви «викликаєте» `Cat`.
+
+Отже, клас Python також є **викликаємим**.
+
+Тож у **FastAPI** ви можете використовувати клас Python як залежність.
+
+Насправді **FastAPI** перевіряє, що це «викликаємий» об’єкт (функція, клас чи щось інше) і які параметри в нього оголошені.
+
+Якщо ви передаєте «викликаємий» як залежність у **FastAPI**, він проаналізує параметри цього об’єкта і обробить їх так само, як параметри для функції операції шляху. Включно з підзалежностями.
+
+Це також стосується викликаємих без жодних параметрів. Так само, як і для функцій операцій шляху без параметрів.
+
+Тоді ми можемо змінити залежність `common_parameters` вище на клас `CommonQueryParams`:
+
+{* ../../docs_src/dependencies/tutorial002_an_py310.py hl[11:15] *}
+
+Зверніть увагу на метод `__init__`, який використовують для створення екземпляра класу:
+
+{* ../../docs_src/dependencies/tutorial002_an_py310.py hl[12] *}
+
+…він має ті самі параметри, що й наш попередній `common_parameters`:
+
+{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[8] *}
+
+Саме ці параметри **FastAPI** використає, щоб «розв’язати» залежність.
+
+В обох випадках буде:
+
+- Необов’язковий параметр запиту `q`, який є `str`.
+- Параметр запиту `skip`, який є `int`, зі значенням за замовчуванням `0`.
+- Параметр запиту `limit`, який є `int`, зі значенням за замовчуванням `100`.
+
+В обох випадках дані будуть перетворені, перевірені й задокументовані в схемі OpenAPI тощо.
+
+## Використання { #use-it }
+
+Тепер ви можете оголосити залежність, використовуючи цей клас.
+
+{* ../../docs_src/dependencies/tutorial002_an_py310.py hl[19] *}
+
+**FastAPI** викликає клас `CommonQueryParams`. Це створює «екземпляр» цього класу, і цей екземпляр буде передано як параметр `commons` у вашу функцію.
+
+## Анотація типів проти `Depends` { #type-annotation-vs-depends }
+
+Зверніть увагу, що вище ми двічі пишемо `CommonQueryParams`:
+
+//// tab | Python 3.10+
+
+```Python
+commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]
+```
+
+////
+
+//// tab | Python 3.10+ без Annotated
+
+/// tip | Порада
+
+Надавайте перевагу варіанту з `Annotated`, якщо це можливо.
+
+///
+
+```Python
+commons: CommonQueryParams = Depends(CommonQueryParams)
+```
+
+////
+
+Останній `CommonQueryParams` у:
+
+```Python
+... Depends(CommonQueryParams)
+```
+
+ - це те, що **FastAPI** фактично використає, щоб дізнатися, яка залежність.
+
+Саме з нього **FastAPI** витягне оголошені параметри і саме його **FastAPI** буде викликати.
+
+---
+
+У цьому випадку перший `CommonQueryParams` у:
+
+//// tab | Python 3.10+
+
+```Python
+commons: Annotated[CommonQueryParams, ...
+```
+
+////
+
+//// tab | Python 3.10+ без Annotated
+
+/// tip | Порада
+
+Надавайте перевагу варіанту з `Annotated`, якщо це можливо.
+
+///
+
+```Python
+commons: CommonQueryParams ...
+```
+
+////
+
+…не має жодного особливого значення для **FastAPI**. FastAPI не використовуватиме його для перетворення даних, перевірки тощо (адже для цього використовується `Depends(CommonQueryParams)`).
+
+Насправді ви могли б написати просто:
+
+//// tab | Python 3.10+
+
+```Python
+commons: Annotated[Any, Depends(CommonQueryParams)]
+```
+
+////
+
+//// tab | Python 3.10+ без Annotated
+
+/// tip | Порада
+
+Надавайте перевагу варіанту з `Annotated`, якщо це можливо.
+
+///
+
+```Python
+commons = Depends(CommonQueryParams)
+```
+
+////
+
+…як у:
+
+{* ../../docs_src/dependencies/tutorial003_an_py310.py hl[19] *}
+
+Але оголошувати тип рекомендується - так ваш редактор знатиме, що буде передано в параметр `commons`, і зможе допомагати з автодоповненням, перевірками типів тощо:
+
+

+
+## Скорочення { #shortcut }
+
+Але ви бачите, що тут маємо деяке дублювання коду - `CommonQueryParams` пишемо двічі:
+
+//// tab | Python 3.10+
+
+```Python
+commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]
+```
+
+////
+
+//// tab | Python 3.10+ без Annotated
+
+/// tip | Порада
+
+Надавайте перевагу варіанту з `Annotated`, якщо це можливо.
+
+///
+
+```Python
+commons: CommonQueryParams = Depends(CommonQueryParams)
+```
+
+////
+
+**FastAPI** надає скорочення для таких випадків, коли залежність - це саме клас, який **FastAPI** «викличе», щоб створити екземпляр цього класу.
+
+Для таких випадків ви можете зробити так:
+
+Замість того щоб писати:
+
+//// tab | Python 3.10+
+
+```Python
+commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]
+```
+
+////
+
+//// tab | Python 3.10+ без Annotated
+
+/// tip | Порада
+
+Надавайте перевагу варіанту з `Annotated`, якщо це можливо.
+
+///
+
+```Python
+commons: CommonQueryParams = Depends(CommonQueryParams)
+```
+
+////
+
+…напишіть:
+
+//// tab | Python 3.10+
+
+```Python
+commons: Annotated[CommonQueryParams, Depends()]
+```
+
+////
+
+//// tab | Python 3.10+ без Annotated
+
+/// tip | Порада
+
+Надавайте перевагу варіанту з `Annotated`, якщо це можливо.
+
+///
+
+```Python
+commons: CommonQueryParams = Depends()
+```
+
+////
+
+Ви оголошуєте залежність як тип параметра і використовуєте `Depends()` без параметрів, замість того щоб вдруге писати повний клас усередині `Depends(CommonQueryParams)`.
+
+Той самий приклад виглядатиме так:
+
+{* ../../docs_src/dependencies/tutorial004_an_py310.py hl[19] *}
+
+…і **FastAPI** знатиме, що робити.
+
+/// tip | Порада
+
+Якщо це здається заплутанішим, ніж корисним, просто не використовуйте це - воно не є обов’язковим.
+
+Це лише скорочення. Адже **FastAPI** дбає про мінімізацію дублювання коду.
+
+///
diff --git a/docs/uk/docs/tutorial/dependencies/dependencies-in-path-operation-decorators.md b/docs/uk/docs/tutorial/dependencies/dependencies-in-path-operation-decorators.md
new file mode 100644
index 0000000000..4614c626c5
--- /dev/null
+++ b/docs/uk/docs/tutorial/dependencies/dependencies-in-path-operation-decorators.md
@@ -0,0 +1,69 @@
+# Залежності в декораторах операцій шляху { #dependencies-in-path-operation-decorators }
+
+Іноді вам насправді не потрібне значення, яке повертає залежність, у вашій *функції операції шляху*.
+
+Або залежність узагалі не повертає значення.
+
+Але її все одно потрібно виконати/опрацювати.
+
+Для таких випадків, замість оголошення параметра *функції операції шляху* з `Depends`, ви можете додати `list` `dependencies` до *декоратора операції шляху*.
+
+## Додайте `dependencies` до *декоратора операції шляху* { #add-dependencies-to-the-path-operation-decorator }
+
+*Декоратор операції шляху* приймає необов'язковий аргумент `dependencies`.
+
+Це має бути `list` з `Depends()`:
+
+{* ../../docs_src/dependencies/tutorial006_an_py310.py hl[19] *}
+
+Ці залежності будуть виконані/оброблені так само, як звичайні залежності. Але їхні значення (якщо щось повертають) не передаватимуться у вашу *функцію операції шляху*.
+
+/// tip | Порада
+
+Деякі редактори перевіряють невикористані параметри функцій і показують їх як помилки.
+
+Використовуючи ці `dependencies` у *декораторі операції шляху*, ви можете гарантувати їх виконання та водночас уникнути помилок редактора/інструментів.
+
+Це також може допомогти уникнути плутанини для нових розробників, які бачать невикористаний параметр у вашому коді й можуть вирішити, що він зайвий.
+
+///
+
+/// info | Інформація
+
+У цьому прикладі ми використовуємо вигадані власні заголовки `X-Key` і `X-Token`.
+
+Але в реальних випадках, під час впровадження безпеки, ви отримаєте більше користі, використовуючи вбудовані [Інструменти безпеки (наступний розділ)](../security/index.md){.internal-link target=_blank}.
+
+///
+
+## Помилки залежностей і значення, що повертаються { #dependencies-errors-and-return-values }
+
+Ви можете використовувати ті самі *функції* залежностей, що й зазвичай.
+
+### Вимоги залежностей { #dependency-requirements }
+
+Вони можуть оголошувати вимоги до запиту (наприклад, заголовки) або інші підзалежності:
+
+{* ../../docs_src/dependencies/tutorial006_an_py310.py hl[8,13] *}
+
+### Підіймати винятки { #raise-exceptions }
+
+Ці залежності можуть `raise` винятки, так само як і звичайні залежності:
+
+{* ../../docs_src/dependencies/tutorial006_an_py310.py hl[10,15] *}
+
+### Значення, що повертаються { #return-values }
+
+Вони можуть повертати значення або ні - ці значення не використовуватимуться.
+
+Отже, ви можете перевикористати звичайну залежність (яка повертає значення), яку вже застосовуєте деінде, і навіть якщо значення не буде використано, залежність буде виконана:
+
+{* ../../docs_src/dependencies/tutorial006_an_py310.py hl[11,16] *}
+
+## Залежності для групи операцій шляху { #dependencies-for-a-group-of-path-operations }
+
+Далі, читаючи про структурування великих застосунків ([Більші застосунки - декілька файлів](../../tutorial/bigger-applications.md){.internal-link target=_blank}), можливо з кількома файлами, ви дізнаєтеся, як оголосити один параметр `dependencies` для групи *операцій шляху*.
+
+## Глобальні залежності { #global-dependencies }
+
+Далі ми побачимо, як додати залежності до всього застосунку `FastAPI`, щоб вони застосовувалися до кожної *операції шляху*.
diff --git a/docs/uk/docs/tutorial/dependencies/dependencies-with-yield.md b/docs/uk/docs/tutorial/dependencies/dependencies-with-yield.md
new file mode 100644
index 0000000000..70d4210a1c
--- /dev/null
+++ b/docs/uk/docs/tutorial/dependencies/dependencies-with-yield.md
@@ -0,0 +1,289 @@
+# Залежності з yield { #dependencies-with-yield }
+
+FastAPI підтримує залежності, які виконують деякі
додаткові кроки після завершення.
+
+Щоб це зробити, використовуйте `yield` замість `return` і напишіть додаткові кроки (код) після нього.
+
+/// tip | Порада
+
+Переконайтесь, що ви використовуєте `yield` лише один раз на залежність.
+
+///
+
+/// note | Технічні деталі
+
+Будь-яка функція, яку можна використовувати з:
+
+*
`@contextlib.contextmanager` або
+*
`@contextlib.asynccontextmanager`
+
+буде придатною як залежність у **FastAPI**.
+
+Насправді FastAPI використовує ці два декоратори внутрішньо.
+
+///
+
+## Залежність бази даних з `yield` { #a-database-dependency-with-yield }
+
+Наприклад, ви можете використати це, щоб створити сесію бази даних і закрити її після завершення.
+
+Перед створенням відповіді виконується лише код до і включно з оператором `yield`:
+
+{* ../../docs_src/dependencies/tutorial007_py310.py hl[2:4] *}
+
+Значення, передане `yield`, впроваджується в *операції шляху* та інші залежності:
+
+{* ../../docs_src/dependencies/tutorial007_py310.py hl[4] *}
+
+Код після оператора `yield` виконується після відповіді:
+
+{* ../../docs_src/dependencies/tutorial007_py310.py hl[5:6] *}
+
+/// tip | Порада
+
+Можете використовувати як `async`, так і звичайні функції.
+
+**FastAPI** зробить усе правильно з кожною з них, так само як і зі звичайними залежностями.
+
+///
+
+## Залежність з `yield` та `try` { #a-dependency-with-yield-and-try }
+
+Якщо ви використовуєте блок `try` в залежності з `yield`, ви отримаєте будь-який виняток, який був згенерований під час використання залежності.
+
+Наприклад, якщо якийсь код десь посередині, в іншій залежності або в *операції шляху*, зробив «rollback» транзакції бази даних або створив будь-який інший виняток, ви отримаєте цей виняток у своїй залежності.
+
+Тож ви можете обробити цей конкретний виняток усередині залежності за допомогою `except SomeException`.
+
+Так само ви можете використовувати `finally`, щоб гарантувати виконання завершальних кроків незалежно від того, був виняток чи ні.
+
+{* ../../docs_src/dependencies/tutorial007_py310.py hl[3,5] *}
+
+## Підзалежності з `yield` { #sub-dependencies-with-yield }
+
+Ви можете мати підзалежності та «дерева» підзалежностей будь-якого розміру і форми, і будь-яка або всі з них можуть використовувати `yield`.
+
+**FastAPI** гарантує, що «exit code» у кожній залежності з `yield` буде виконано в правильному порядку.
+
+Наприклад, `dependency_c` може залежати від `dependency_b`, а `dependency_b` - від `dependency_a`:
+
+{* ../../docs_src/dependencies/tutorial008_an_py310.py hl[6,14,22] *}
+
+І всі вони можуть використовувати `yield`.
+
+У цьому випадку `dependency_c`, щоб виконати свій завершальний код, потребує, щоб значення з `dependency_b` (тут `dep_b`) все ще було доступним.
+
+І, у свою чергу, `dependency_b` потребує, щоб значення з `dependency_a` (тут `dep_a`) було доступним для свого завершального коду.
+
+{* ../../docs_src/dependencies/tutorial008_an_py310.py hl[18:19,26:27] *}
+
+Так само ви можете мати деякі залежності з `yield`, а інші - з `return`, і частина з них може залежати від інших.
+
+І ви можете мати одну залежність, яка вимагає кілька інших залежностей з `yield` тощо.
+
+Ви можете мати будь-які комбінації залежностей, які вам потрібні.
+
+**FastAPI** подбає, щоб усе виконувалося в правильному порядку.
+
+/// note | Технічні деталі
+
+Це працює завдяки
Менеджерам контексту Python.
+
+**FastAPI** використовує їх внутрішньо, щоб досягти цього.
+
+///
+
+## Залежності з `yield` та `HTTPException` { #dependencies-with-yield-and-httpexception }
+
+Ви бачили, що можна використовувати залежності з `yield` і мати блоки `try`, які намагаються виконати деякий код, а потім запускають завершальний код після `finally`.
+
+Також можна використовувати `except`, щоб перехопити згенерований виняток і щось із ним зробити.
+
+Наприклад, ви можете підняти інший виняток, як-от `HTTPException`.
+
+/// tip | Порада
+
+Це доволі просунута техніка, і в більшості випадків вона вам не знадобиться, адже ви можете піднімати винятки (включно з `HTTPException`) всередині іншого коду вашого застосунку, наприклад, у *функції операції шляху*.
+
+Але вона є, якщо вам це потрібно. 🤓
+
+///
+
+{* ../../docs_src/dependencies/tutorial008b_an_py310.py hl[18:22,31] *}
+
+Якщо ви хочете перехоплювати винятки та створювати на їх основі користувацьку відповідь, створіть [Користувацький обробник винятків](../handling-errors.md#install-custom-exception-handlers){.internal-link target=_blank}.
+
+## Залежності з `yield` та `except` { #dependencies-with-yield-and-except }
+
+Якщо ви перехоплюєте виняток за допомогою `except` у залежності з `yield` і не піднімаєте його знову (або не піднімаєте новий виняток), FastAPI не зможе помітити, що стався виняток, так само як це було б у звичайному Python:
+
+{* ../../docs_src/dependencies/tutorial008c_an_py310.py hl[15:16] *}
+
+У цьому випадку клієнт побачить відповідь *HTTP 500 Internal Server Error*, як і має бути, з огляду на те, що ми не піднімаємо `HTTPException` або подібний виняток, але на сервері **не буде жодних логів** чи інших ознак того, що це була за помилка. 😱
+
+### Завжди використовуйте `raise` у залежностях з `yield` та `except` { #always-raise-in-dependencies-with-yield-and-except }
+
+Якщо ви перехоплюєте виняток у залежності з `yield`, якщо тільки ви не піднімаєте інший `HTTPException` або подібний, **вам слід повторно підняти початковий виняток**.
+
+Ви можете повторно підняти той самий виняток, використовуючи `raise`:
+
+{* ../../docs_src/dependencies/tutorial008d_an_py310.py hl[17] *}
+
+Тепер клієнт отримає ту саму відповідь *HTTP 500 Internal Server Error*, але сервер матиме наш користувацький `InternalError` у логах. 😎
+
+## Виконання залежностей з `yield` { #execution-of-dependencies-with-yield }
+
+Послідовність виконання приблизно така, як на цій діаграмі. Час тече зверху вниз. І кожна колонка - це одна з частин, що взаємодіють або виконують код.
+
+```mermaid
+sequenceDiagram
+
+participant client as Client
+participant handler as Exception handler
+participant dep as Dep with yield
+participant operation as Path Operation
+participant tasks as Background tasks
+
+ Note over client,operation: Can raise exceptions, including HTTPException
+ client ->> dep: Start request
+ Note over dep: Run code up to yield
+ opt raise Exception
+ dep -->> handler: Raise Exception
+ handler -->> client: HTTP error response
+ end
+ dep ->> operation: Run dependency, e.g. DB session
+ opt raise
+ operation -->> dep: Raise Exception (e.g. HTTPException)
+ opt handle
+ dep -->> dep: Can catch exception, raise a new HTTPException, raise other exception
+ end
+ handler -->> client: HTTP error response
+ end
+
+ operation ->> client: Return response to client
+ Note over client,operation: Response is already sent, can't change it anymore
+ opt Tasks
+ operation -->> tasks: Send background tasks
+ end
+ opt Raise other exception
+ tasks -->> tasks: Handle exceptions in the background task code
+ end
+```
+
+/// info | Інформація
+
+Лише **одна відповідь** буде надіслана клієнту. Це може бути одна з помилкових відповідей або відповідь від *операції шляху*.
+
+Після відправлення однієї з цих відповідей іншу відправити не можна.
+
+///
+
+/// tip | Порада
+
+Якщо ви піднімаєте будь-який виняток у коді з *функції операції шляху*, він буде переданий у залежності з `yield`, включно з `HTTPException`. У більшості випадків ви захочете повторно підняти той самий виняток або новий із залежності з `yield`, щоб переконатися, що його коректно оброблено.
+
+///
+
+## Ранній вихід і `scope` { #early-exit-and-scope }
+
+Зазвичай завершальний код залежностей з `yield` виконується **після того**, як відповідь надіслано клієнту.
+
+Але якщо ви знаєте, що вам не потрібно використовувати залежність після повернення з *функції операції шляху*, ви можете використати `Depends(scope="function")`, щоб сказати FastAPI, що слід закрити залежність після повернення з *функції операції шляху*, але **до** надсилання **відповіді**.
+
+{* ../../docs_src/dependencies/tutorial008e_an_py310.py hl[12,16] *}
+
+`Depends()` приймає параметр `scope`, який може бути:
+
+* `"function"`: запустити залежність перед *функцією операції шляху*, що обробляє запит, завершити залежність після завершення *функції операції шляху*, але **до** того, як відповідь буде відправлена клієнту. Тобто функція залежності буде виконуватися **навколо** *функції операції **шляху***.
+* `"request"`: запустити залежність перед *функцією операції шляху*, що обробляє запит (подібно до `"function"`), але завершити **після** того, як відповідь буде відправлена клієнту. Тобто функція залежності буде виконуватися **навколо** циклу **запиту** та відповіді.
+
+Якщо не вказано, і залежність має `yield`, за замовчуванням `scope` дорівнює `"request"`.
+
+### `scope` для підзалежностей { #scope-for-sub-dependencies }
+
+Коли ви оголошуєте залежність із `scope="request"` (за замовчуванням), будь-яка підзалежність також має мати `scope` рівний `"request"`.
+
+Але залежність з `scope` рівним `"function"` може мати залежності з `scope` `"function"` і `scope` `"request"`.
+
+Це тому, що будь-яка залежність має бути здатною виконати свій завершальний код раніше за підзалежності, оскільки вона може все ще потребувати їх під час свого завершального коду.
+
+```mermaid
+sequenceDiagram
+
+participant client as Client
+participant dep_req as Dep scope="request"
+participant dep_func as Dep scope="function"
+participant operation as Path Operation
+
+ client ->> dep_req: Start request
+ Note over dep_req: Run code up to yield
+ dep_req ->> dep_func: Pass dependency
+ Note over dep_func: Run code up to yield
+ dep_func ->> operation: Run path operation with dependency
+ operation ->> dep_func: Return from path operation
+ Note over dep_func: Run code after yield
+ Note over dep_func: ✅ Dependency closed
+ dep_func ->> client: Send response to client
+ Note over client: Response sent
+ Note over dep_req: Run code after yield
+ Note over dep_req: ✅ Dependency closed
+```
+
+## Залежності з `yield`, `HTTPException`, `except` і фоновими задачами { #dependencies-with-yield-httpexception-except-and-background-tasks }
+
+Залежності з `yield` еволюціонували з часом, щоб покрити різні сценарії та виправити деякі проблеми.
+
+Якщо ви хочете дізнатися, що змінювалося в різних версіях FastAPI, прочитайте про це в просунутому посібнику користувача: [Розширені залежності - Залежності з `yield`, `HTTPException`, `except` і фоновими задачами](../../advanced/advanced-dependencies.md#dependencies-with-yield-httpexception-except-and-background-tasks){.internal-link target=_blank}.
+## Менеджери контексту { #context-managers }
+
+### Що таке «Менеджери контексту» { #what-are-context-managers }
+
+«Менеджери контексту» - це будь-які Python-об'єкти, які можна використовувати в операторі `with`.
+
+Наприклад,
можна використати `with`, щоб прочитати файл:
+
+```Python
+with open("./somefile.txt") as f:
+ contents = f.read()
+ print(contents)
+```
+
+Під капотом `open("./somefile.txt")` створює об'єкт, який називається «Менеджер контексту».
+
+Коли блок `with` завершується, він гарантує закриття файлу, навіть якщо були винятки.
+
+Коли ви створюєте залежність з `yield`, **FastAPI** внутрішньо створить для неї менеджер контексту й поєднає його з іншими пов'язаними інструментами.
+
+### Використання менеджерів контексту в залежностях з `yield` { #using-context-managers-in-dependencies-with-yield }
+
+/// warning | Попередження
+
+Це, загалом, «просунута» ідея.
+
+Якщо ви тільки починаєте з **FastAPI**, можливо, варто наразі пропустити це.
+
+///
+
+У Python ви можете створювати Менеджери контексту,
створивши клас із двома методами: `__enter__()` і `__exit__()`.
+
+Ви також можете використовувати їх усередині залежностей **FastAPI** з `yield`, використовуючи
+`with` або `async with` у середині функції залежності:
+
+{* ../../docs_src/dependencies/tutorial010_py310.py hl[1:9,13] *}
+
+/// tip | Порада
+
+Інший спосіб створити менеджер контексту:
+
+*
`@contextlib.contextmanager` або
+*
`@contextlib.asynccontextmanager`
+
+використовуючи їх для декорування функції з одним `yield`.
+
+Саме це **FastAPI** використовує внутрішньо для залежностей з `yield`.
+
+Але вам не потрібно використовувати ці декоратори для залежностей FastAPI (і не варто).
+
+FastAPI зробить це за вас внутрішньо.
+
+///
diff --git a/docs/uk/docs/tutorial/dependencies/global-dependencies.md b/docs/uk/docs/tutorial/dependencies/global-dependencies.md
new file mode 100644
index 0000000000..3cffa1752c
--- /dev/null
+++ b/docs/uk/docs/tutorial/dependencies/global-dependencies.md
@@ -0,0 +1,15 @@
+# Глобальні залежності { #global-dependencies }
+
+Для деяких типів застосунків ви можете захотіти додати залежності до всього застосунку.
+
+Подібно до того, як ви можете [додавати `dependencies` до *декораторів операцій шляху*](dependencies-in-path-operation-decorators.md){.internal-link target=_blank}, ви можете додати їх до застосунку `FastAPI`.
+
+У такому разі вони будуть застосовані до всіх *операцій шляху* в застосунку:
+
+{* ../../docs_src/dependencies/tutorial012_an_py310.py hl[17] *}
+
+Усі ідеї з розділу про [додавання `dependencies` до *декораторів операцій шляху*](dependencies-in-path-operation-decorators.md){.internal-link target=_blank} так само застосовні, але в цьому випадку - до всіх *операцій шляху* в застосунку.
+
+## Залежності для груп *операцій шляху* { #dependencies-for-groups-of-path-operations }
+
+Пізніше, читаючи про структуру більших застосунків ([Більші застосунки - кілька файлів](../../tutorial/bigger-applications.md){.internal-link target=_blank}), можливо з кількома файлами, ви дізнаєтеся, як оголосити єдиний параметр `dependencies` для групи *операцій шляху*.
diff --git a/docs/uk/docs/tutorial/dependencies/index.md b/docs/uk/docs/tutorial/dependencies/index.md
new file mode 100644
index 0000000000..cbcf693077
--- /dev/null
+++ b/docs/uk/docs/tutorial/dependencies/index.md
@@ -0,0 +1,250 @@
+# Залежності { #dependencies }
+
+**FastAPI** має дуже потужну, але інтуїтивну систему **
Впровадження залежностей**.
+
+Вона створена так, щоб бути дуже простою у використанні та щоб полегшити будь-якому розробнику інтеграцію інших компонентів з **FastAPI**.
+
+## Що таке «Впровадження залежностей» { #what-is-dependency-injection }
+
+У програмуванні **«Впровадження залежностей»** означає, що існує спосіб для вашого коду (у цьому випадку ваших *функцій операцій шляху*) задекларувати речі, які йому потрібні для роботи: «залежності».
+
+А потім ця система (у цьому випадку **FastAPI**) подбає про все необхідне, щоб надати вашому коду ці потрібні залежності («інжектувати» залежності).
+
+Це дуже корисно, коли вам потрібно:
+
+* Мати спільну логіку (одна й та сама логіка знову і знову).
+* Ділитися з’єднаннями з базою даних.
+* Примусово застосовувати безпеку, автентифікацію, вимоги до ролей тощо.
+* І багато іншого...
+
+Все це з мінімізацією дублювання коду.
+
+## Перші кроки { #first-steps }
+
+Розгляньмо дуже простий приклад. Він буде таким простим, що поки що не дуже корисним.
+
+Але так ми зможемо зосередитися на тому, як працює система **Впровадження залежностей**.
+
+### Створіть залежність або «залежний» { #create-a-dependency-or-dependable }
+
+Спочатку зосередьмося на залежності.
+
+Це просто функція, яка може приймати ті самі параметри, що й *функція операції шляху*:
+
+{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[8:9] *}
+
+Ось і все.
+
+**2 рядки**.
+
+І вона має ту саму форму та структуру, що й усі ваші *функції операцій шляху*.
+
+Можете думати про неї як про *функцію операції шляху* без «декоратора» (без `@app.get("/some-path")`).
+
+І вона може повертати будь-що.
+
+У цьому випадку ця залежність очікує:
+
+* Необов’язковий параметр запиту `q` типу `str`.
+* Необов’язковий параметр запиту `skip` типу `int`, за замовчуванням `0`.
+* Необов’язковий параметр запиту `limit` типу `int`, за замовчуванням `100`.
+
+Потім вона просто повертає `dict`, що містить ці значення.
+
+/// info | Інформація
+
+FastAPI додав підтримку `Annotated` (і почав її рекомендувати) у версії 0.95.0.
+
+Якщо у вас старіша версія, ви отримаєте помилки при спробі використати `Annotated`.
+
+Переконайтеся, що ви [Оновіть версію FastAPI](../../deployment/versions.md#upgrading-the-fastapi-versions){.internal-link target=_blank} щонайменше до 0.95.1 перед використанням `Annotated`.
+
+///
+
+### Імпортуйте `Depends` { #import-depends }
+
+{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[3] *}
+
+### Оголосіть залежність у «залежному» { #declare-the-dependency-in-the-dependant }
+
+Так само, як ви використовуєте `Body`, `Query` тощо з параметрами вашої *функції операції шляху*, використовуйте `Depends` з новим параметром:
+
+{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[13,18] *}
+
+Хоча ви використовуєте `Depends` у параметрах вашої функції так само, як `Body`, `Query` тощо, `Depends` працює трохи інакше.
+
+Ви передаєте в `Depends` лише один параметр.
+
+Цей параметр має бути чимось на кшталт функції.
+
+Ви її не викликаєте безпосередньо (не додавайте дужки в кінці), ви просто передаєте її як параметр у `Depends()`.
+
+І ця функція приймає параметри так само, як і *функції операцій шляху*.
+
+/// tip | Порада
+
+У наступному розділі ви побачите, які ще «речі», окрім функцій, можна використовувати як залежності.
+
+///
+
+Щоразу, коли надходить новий запит, **FastAPI** подбає про:
+
+* Виклик вашої функції-залежності («залежного») з правильними параметрами.
+* Отримання результату з вашої функції.
+* Присвоєння цього результату параметру у вашій *функції операції шляху*.
+
+```mermaid
+graph TB
+
+common_parameters(["common_parameters"])
+read_items["/items/"]
+read_users["/users/"]
+
+common_parameters --> read_items
+common_parameters --> read_users
+```
+
+Таким чином ви пишете спільний код один раз, а **FastAPI** подбає про його виклик для ваших *операцій шляху*.
+
+/// check | Перевірте
+
+Зверніть увагу, що вам не потрібно створювати спеціальний клас і передавати його кудись у **FastAPI**, щоб «зареєструвати» його чи щось подібне.
+
+Ви просто передаєте його в `Depends`, і **FastAPI** знає, що робити далі.
+
+///
+
+## Спільне використання залежностей `Annotated` { #share-annotated-dependencies }
+
+У наведених вище прикладах видно невелике **дублювання коду**.
+
+Коли вам потрібно використати залежність `common_parameters()`, доводиться писати весь параметр з анотацією типу та `Depends()`:
+
+```Python
+commons: Annotated[dict, Depends(common_parameters)]
+```
+
+Але оскільки ми використовуємо `Annotated`, ми можемо зберегти це значення `Annotated` у змінній і використовувати його в кількох місцях:
+
+{* ../../docs_src/dependencies/tutorial001_02_an_py310.py hl[12,16,21] *}
+
+/// tip | Порада
+
+Це просто стандартний Python, це називається «псевдонім типу» і насправді не є специфічним для **FastAPI**.
+
+Але оскільки **FastAPI** базується на стандартах Python, включно з `Annotated`, ви можете використати цей трюк у своєму коді. 😎
+
+///
+
+Залежності продовжать працювати як очікується, і **найкраще** те, що **інформація про типи буде збережена**, а це означає, що ваш редактор зможе й надалі надавати **автозаповнення**, **помилки в рядку** тощо. Те саме і для інших інструментів, як-от `mypy`.
+
+Це буде особливо корисно у **великій кодовій базі**, де ви використовуєте **одні й ті самі залежності** знову і знову в **багатьох *операціях шляху***.
+
+## Бути `async` чи не бути `async` { #to-async-or-not-to-async }
+
+Оскільки залежності також викликатимуться **FastAPI** (так само, як і ваші *функції операцій шляху*), під час визначення ваших функцій діють ті самі правила.
+
+Ви можете використовувати `async def` або звичайний `def`.
+
+І ви можете оголошувати залежності з `async def` всередині звичайних *функцій операцій шляху* з `def`, або залежності з `def` всередині *функцій операцій шляху* з `async def` тощо.
+
+Це не має значення. **FastAPI** знатиме, що робити.
+
+/// note | Примітка
+
+Якщо ви не впевнені, перегляньте розділ [Async: *"In a hurry?"*](../../async.md#in-a-hurry){.internal-link target=_blank} про `async` і `await` у документації.
+
+///
+
+## Інтегровано з OpenAPI { #integrated-with-openapi }
+
+Усі декларації запитів, перевірки та вимоги ваших залежностей (і субзалежностей) будуть інтегровані в ту саму схему OpenAPI.
+
+Тож інтерактивна документація також міститиме всю інформацію з цих залежностей:
+
+

+
+## Просте використання { #simple-usage }
+
+Якщо придивитися, *функції операцій шляху* оголошуються для використання щоразу, коли збігаються *шлях* та *операція*, а потім **FastAPI** подбає про виклик функції з правильними параметрами, витягуючи дані із запиту.
+
+Насправді всі (або більшість) вебфреймворків працюють так само.
+
+Ви ніколи не викликаєте ці функції безпосередньо. Їх викликає ваш фреймворк (у цьому випадку **FastAPI**).
+
+За допомогою системи впровадження залежностей ви також можете вказати **FastAPI**, що ваша *функція операції шляху* також «залежить» від чогось, що має бути виконано до вашої *функції операції шляху*, і **FastAPI** подбає про виконання цього та «інжектування» результатів.
+
+Інші поширені терміни для цієї самої ідеї «впровадження залежностей»:
+
+* ресурси
+* провайдери
+* сервіси
+* інжектовані об’єкти
+* компоненти
+
+## Плагіни **FastAPI** { #fastapi-plug-ins }
+
+Інтеграції та «плагіни» можна будувати за допомогою системи **Впровадження залежностей**. Але насправді **немає потреби створювати «плагіни»**, оскільки, використовуючи залежності, можна оголосити безмежну кількість інтеграцій та взаємодій, які стають доступними для ваших *функцій операцій шляху*.
+
+І залежності можна створювати дуже просто та інтуїтивно, що дозволяє вам просто імпортувати потрібні пакунки Python і інтегрувати їх з вашими функціями API за кілька рядків коду, буквально.
+
+Ви побачите приклади цього в наступних розділах, про реляційні та NoSQL бази даних, безпеку тощо.
+
+## Сумісність **FastAPI** { #fastapi-compatibility }
+
+Простота системи впровадження залежностей робить **FastAPI** сумісним з:
+
+* усіма реляційними базами даних
+* NoSQL базами даних
+* зовнішніми пакунками
+* зовнішніми API
+* системами автентифікації та авторизації
+* системами моніторингу використання API
+* системами інжекції даних у відповідь
+* тощо.
+
+## Просто і потужно { #simple-and-powerful }
+
+Хоча ієрархічна система впровадження залежностей дуже проста у визначенні та використанні, вона все ще дуже потужна.
+
+Ви можете визначати залежності, які своєю чергою можуть визначати власні залежності.
+
+Зрештою будується ієрархічне дерево залежностей, і система **Впровадження залежностей** подбає про розв’язання всіх цих залежностей (і їхніх субзалежностей) та надання (інжектування) результатів на кожному кроці.
+
+Наприклад, припустімо, у вас є 4 кінцеві точки API (*операції шляху*):
+
+* `/items/public/`
+* `/items/private/`
+* `/users/{user_id}/activate`
+* `/items/pro/`
+
+тоді ви могли б додати різні вимоги до дозволів для кожної з них лише за допомогою залежностей і субзалежностей:
+
+```mermaid
+graph TB
+
+current_user(["current_user"])
+active_user(["active_user"])
+admin_user(["admin_user"])
+paying_user(["paying_user"])
+
+public["/items/public/"]
+private["/items/private/"]
+activate_user["/users/{user_id}/activate"]
+pro_items["/items/pro/"]
+
+current_user --> active_user
+active_user --> admin_user
+active_user --> paying_user
+
+current_user --> public
+active_user --> private
+admin_user --> activate_user
+paying_user --> pro_items
+```
+
+## Інтегровано з **OpenAPI** { #integrated-with-openapi_1 }
+
+Усі ці залежності, декларуючи свої вимоги, також додають параметри, перевірки тощо до ваших *операцій шляху*.
+
+**FastAPI** подбає про додавання всього цього до схеми OpenAPI, щоб це відображалося в інтерактивних системах документації.
diff --git a/docs/uk/docs/tutorial/dependencies/sub-dependencies.md b/docs/uk/docs/tutorial/dependencies/sub-dependencies.md
new file mode 100644
index 0000000000..4e7488086a
--- /dev/null
+++ b/docs/uk/docs/tutorial/dependencies/sub-dependencies.md
@@ -0,0 +1,105 @@
+# Підзалежності { #sub-dependencies }
+
+Ви можете створювати залежності, які мають підзалежності.
+
+Вони можуть бути настільки глибокими, наскільки потрібно.
+
+FastAPI подбає про їх розв'язання.
+
+## Перша залежність «dependable» { #first-dependency-dependable }
+
+Можна створити першу залежність («dependable») так:
+
+{* ../../docs_src/dependencies/tutorial005_an_py310.py hl[8:9] *}
+
+Вона оголошує необов'язковий параметр запиту `q` типу `str`, а потім просто повертає його.
+
+Це досить просто (не дуже корисно), але допоможе зосередитися на тому, як працюють підзалежності.
+
+## Друга залежність, «dependable» і «dependant» { #second-dependency-dependable-and-dependant }
+
+Далі ви можете створити іншу функцію залежності («dependable»), яка водночас оголошує власну залежність (тож вона також є «dependant»):
+
+{* ../../docs_src/dependencies/tutorial005_an_py310.py hl[13] *}
+
+Зосередьмося на оголошених параметрах:
+
+- Хоча ця функція сама є залежністю («dependable»), вона також оголошує іншу залежність (вона «залежить» від чогось).
+ - Вона залежить від `query_extractor` і присвоює значення, яке він повертає, параметру `q`.
+- Вона також оголошує необов'язкове кукі `last_query` типу `str`.
+ - Якщо користувач не надав параметр запиту `q`, ми використовуємо останній запит, який зберегли раніше в кукі.
+
+## Використання залежності { #use-the-dependency }
+
+Потім ми можемо використати залежність так:
+
+{* ../../docs_src/dependencies/tutorial005_an_py310.py hl[23] *}
+
+/// info | Інформація
+
+Зверніть увагу, що ми оголошуємо лише одну залежність у функції операції шляху — `query_or_cookie_extractor`.
+
+Але FastAPI знатиме, що спочатку треба розв'язати `query_extractor`, щоб передати його результат у `query_or_cookie_extractor` під час виклику.
+
+///
+
+```mermaid
+graph TB
+
+query_extractor(["query_extractor"])
+query_or_cookie_extractor(["query_or_cookie_extractor"])
+
+read_query["/items/"]
+
+query_extractor --> query_or_cookie_extractor --> read_query
+```
+
+## Використання тієї ж залежності кілька разів { #using-the-same-dependency-multiple-times }
+
+Якщо одна з ваших залежностей оголошена кілька разів для однієї операції шляху, наприклад, кілька залежностей мають спільну підзалежність, FastAPI знатиме, що цю підзалежність потрібно викликати лише один раз на запит.
+
+І він збереже повернуте значення у
«кеш» і передасть його всім «dependants», яким воно потрібне в цьому конкретному запиті, замість того щоб викликати залежність кілька разів для одного й того ж запиту.
+
+У просунутому сценарії, коли ви знаєте, що залежність має викликатися на кожному кроці (можливо, кілька разів) у межах того самого запиту замість використання «кешованого» значення, ви можете встановити параметр `use_cache=False` при використанні `Depends`:
+
+//// tab | Python 3.10+
+
+```Python hl_lines="1"
+async def needy_dependency(fresh_value: Annotated[str, Depends(get_value, use_cache=False)]):
+ return {"fresh_value": fresh_value}
+```
+
+////
+
+//// tab | Python 3.10+ без Annotated
+
+/// tip | Порада
+
+Надавайте перевагу версії з `Annotated`, якщо це можливо.
+
+///
+
+```Python hl_lines="1"
+async def needy_dependency(fresh_value: str = Depends(get_value, use_cache=False)):
+ return {"fresh_value": fresh_value}
+```
+
+////
+
+## Підсумок { #recap }
+
+Попри всі модні терміни, система впровадження залежностей досить проста.
+
+Це просто функції, які виглядають так само, як функції операцій шляху.
+
+Втім вона дуже потужна і дозволяє оголошувати довільно глибоко вкладені «графи» залежностей (дерева).
+
+/// tip | Порада
+
+Усе це може здаватися не надто корисним на простих прикладах.
+
+Але ви побачите, наскільки це корисно, у розділах про **безпеку**.
+
+І також побачите, скільки коду це вам заощадить.
+
+///
diff --git a/docs/uk/docs/tutorial/extra-models.md b/docs/uk/docs/tutorial/extra-models.md
new file mode 100644
index 0000000000..25930b8c0b
--- /dev/null
+++ b/docs/uk/docs/tutorial/extra-models.md
@@ -0,0 +1,211 @@
+# Додаткові моделі { #extra-models }
+
+Продовжуючи попередній приклад, часто потрібно мати більше ніж одну пов’язану модель.
+
+Особливо це стосується моделей користувача, тому що:
+
+* **вхідна модель** повинна мати пароль.
+* **вихідна модель** не повинна містити пароль.
+* **модель бази даних**, ймовірно, повинна містити хеш пароля.
+
+/// danger | Обережно
+
+Ніколи не зберігайте паролі користувачів у відкритому вигляді. Завжди зберігайте «безпечний хеш», який потім можна перевірити.
+
+Якщо ви ще не знаєте, що таке «хеш пароля», ви дізнаєтесь у [розділах про безпеку](security/simple-oauth2.md#password-hashing){.internal-link target=_blank}.
+
+///
+
+## Кілька моделей { #multiple-models }
+
+Ось загальна ідея того, як можуть виглядати моделі з їхніми полями пароля та місцями використання:
+
+{* ../../docs_src/extra_models/tutorial001_py310.py hl[7,9,14,20,22,27:28,31:33,38:39] *}
+
+### Про `**user_in.model_dump()` { #about-user-in-model-dump }
+
+#### `.model_dump()` у Pydantic { #pydantics-model-dump }
+
+`user_in` - це модель Pydantic класу `UserIn`.
+
+Моделі Pydantic мають метод `.model_dump()`, який повертає `dict` з даними моделі.
+
+Отже, якщо ми створимо об’єкт Pydantic `user_in` так:
+
+```Python
+user_in = UserIn(username="john", password="secret", email="john.doe@example.com")
+```
+
+і викличемо:
+
+```Python
+user_dict = user_in.model_dump()
+```
+
+тепер ми маємо `dict` з даними у змінній `user_dict` (це `dict`, а не об’єкт моделі Pydantic).
+
+А якщо викликати:
+
+```Python
+print(user_dict)
+```
+
+ми отримаємо Python `dict` з:
+
+```Python
+{
+ 'username': 'john',
+ 'password': 'secret',
+ 'email': 'john.doe@example.com',
+ 'full_name': None,
+}
+```
+
+#### Розпакування `dict` { #unpacking-a-dict }
+
+Якщо взяти `dict`, наприклад `user_dict`, і передати його у функцію (або клас) як `**user_dict`, Python «розпакує» його. Ключі та значення `user_dict` будуть передані безпосередньо як іменовані аргументи.
+
+Отже, продовжуючи з `user_dict` вище, запис:
+
+```Python
+UserInDB(**user_dict)
+```
+
+дасть еквівалентний результат:
+
+```Python
+UserInDB(
+ username="john",
+ password="secret",
+ email="john.doe@example.com",
+ full_name=None,
+)
+```
+
+А точніше, використовуючи безпосередньо `user_dict`, з будь-яким його вмістом у майбутньому:
+
+```Python
+UserInDB(
+ username = user_dict["username"],
+ password = user_dict["password"],
+ email = user_dict["email"],
+ full_name = user_dict["full_name"],
+)
+```
+
+#### Модель Pydantic зі вмісту іншої { #a-pydantic-model-from-the-contents-of-another }
+
+Як у прикладі вище ми отримали `user_dict` з `user_in.model_dump()`, цей код:
+
+```Python
+user_dict = user_in.model_dump()
+UserInDB(**user_dict)
+```
+
+буде еквівалентним:
+
+```Python
+UserInDB(**user_in.model_dump())
+```
+
+...тому що `user_in.model_dump()` повертає `dict`, а ми змушуємо Python «розпакувати» його, передаючи в `UserInDB` з префіксом `**`.
+
+Тож ми отримуємо модель Pydantic з даних іншої моделі Pydantic.
+
+#### Розпакування `dict` і додаткові ключові аргументи { #unpacking-a-dict-and-extra-keywords }
+
+Додаючи додатковий іменований аргумент `hashed_password=hashed_password`, як тут:
+
+```Python
+UserInDB(**user_in.model_dump(), hashed_password=hashed_password)
+```
+
+...у підсумку це дорівнює:
+
+```Python
+UserInDB(
+ username = user_dict["username"],
+ password = user_dict["password"],
+ email = user_dict["email"],
+ full_name = user_dict["full_name"],
+ hashed_password = hashed_password,
+)
+```
+
+/// warning | Попередження
+
+Додаткові допоміжні функції `fake_password_hasher` і `fake_save_user` лише демонструють можливий потік даних і, звісно, не забезпечують реальної безпеки.
+
+///
+
+## Зменшення дублювання { #reduce-duplication }
+
+Зменшення дублювання коду - одна з ключових ідей у **FastAPI**.
+
+Адже дублювання коду підвищує ймовірність помилок, проблем безпеки, розсинхронізації коду (коли ви оновлюєте в одному місці, але не в інших) тощо.
+
+І ці моделі спільно використовують багато даних та дублюють назви і типи атрибутів.
+
+Можна зробити краще.
+
+Можна оголосити модель `UserBase`, яка буде базовою для інших моделей. Потім створити підкласи цієї моделі, що наслідуватимуть її атрибути (оголошення типів, валідацію тощо).
+
+Уся конвертація даних, валідація, документація тощо працюватимуть як зазвичай.
+
+Таким чином, ми оголошуємо лише відмінності між моделями (з відкритим `password`, з `hashed_password` і без пароля):
+
+{* ../../docs_src/extra_models/tutorial002_py310.py hl[7,13:14,17:18,21:22] *}
+
+## `Union` або `anyOf` { #union-or-anyof }
+
+Ви можете оголосити відповідь як `Union` двох або більше типів - це означає, що відповідь може бути будь-якого з них.
+
+В OpenAPI це буде визначено як `anyOf`.
+
+Для цього використайте стандартну підказку типу Python
`typing.Union`:
+
+/// note | Примітка
+
+Під час визначення
`Union` спочатку вказуйте найконкретніший тип, а потім менш конкретний. У прикладі нижче більш конкретний `PlaneItem` стоїть перед `CarItem` у `Union[PlaneItem, CarItem]`.
+
+///
+
+{* ../../docs_src/extra_models/tutorial003_py310.py hl[1,14:15,18:20,33] *}
+
+### `Union` у Python 3.10 { #union-in-python-3-10 }
+
+У цьому прикладі ми передаємо `Union[PlaneItem, CarItem]` як значення аргументу `response_model`.
+
+Оскільки ми передаємо його як значення аргументу, а не в анотації типу, потрібно використовувати `Union` навіть у Python 3.10.
+
+Якби це була анотація типу, можна було б використати вертикальну риску, наприклад:
+
+```Python
+some_variable: PlaneItem | CarItem
+```
+
+Але якщо записати це як присвоєння `response_model=PlaneItem | CarItem`, отримаємо помилку, тому що Python спробує виконати невалідну операцію між `PlaneItem` і `CarItem`, замість того щоб трактувати це як анотацію типу.
+
+## Список моделей { #list-of-models }
+
+Аналогічно можна оголошувати відповіді як списки об’єктів.
+
+Для цього використайте стандартний Python `list`:
+
+{* ../../docs_src/extra_models/tutorial004_py310.py hl[18] *}
+
+## Відповідь з довільним `dict` { #response-with-arbitrary-dict }
+
+Також можна оголосити відповідь, використовуючи звичайний довільний `dict`, вказавши лише типи ключів і значень, без моделі Pydantic.
+
+Це корисно, якщо ви заздалегідь не знаєте допустимі назви полів/атрибутів (які були б потрібні для моделі Pydantic).
+
+У такому разі можна використати `dict`:
+
+{* ../../docs_src/extra_models/tutorial005_py310.py hl[6] *}
+
+## Підсумок { #recap }
+
+Використовуйте кілька моделей Pydantic і вільно наслідуйте для кожного випадку.
+
+Не обов’язково мати одну модель даних на сутність, якщо ця сутність може мати різні «стани». Як у випадку сутності користувача зі станами: з `password`, з `password_hash` і без пароля.
diff --git a/docs/uk/docs/tutorial/first-steps.md b/docs/uk/docs/tutorial/first-steps.md
index 5f3750010c..f03a120a09 100644
--- a/docs/uk/docs/tutorial/first-steps.md
+++ b/docs/uk/docs/tutorial/first-steps.md
@@ -2,7 +2,7 @@
Найпростіший файл FastAPI може виглядати так:
-{* ../../docs_src/first_steps/tutorial001_py39.py *}
+{* ../../docs_src/first_steps/tutorial001_py310.py *}
Скопіюйте це до файлу `main.py`.
@@ -183,7 +183,7 @@ Deploying to FastAPI Cloud...
### Крок 1: імпортуємо `FastAPI` { #step-1-import-fastapi }
-{* ../../docs_src/first_steps/tutorial001_py39.py hl[1] *}
+{* ../../docs_src/first_steps/tutorial001_py310.py hl[1] *}
`FastAPI` — це клас у Python, який надає всю функціональність для вашого API.
@@ -197,7 +197,7 @@ Deploying to FastAPI Cloud...
### Крок 2: створюємо «екземпляр» `FastAPI` { #step-2-create-a-fastapi-instance }
-{* ../../docs_src/first_steps/tutorial001_py39.py hl[3] *}
+{* ../../docs_src/first_steps/tutorial001_py310.py hl[3] *}
Тут змінна `app` буде «екземпляром» класу `FastAPI`.
@@ -221,7 +221,7 @@ https://example.com/items/foo
/items/foo
```
-/// info | Інформація
+/// info
«Шлях» також зазвичай називають «ендпоінтом» або «маршрутом».
@@ -266,12 +266,12 @@ https://example.com/items/foo
#### Визначте *декоратор операції шляху* { #define-a-path-operation-decorator }
-{* ../../docs_src/first_steps/tutorial001_py39.py hl[6] *}
+{* ../../docs_src/first_steps/tutorial001_py310.py hl[6] *}
Декоратор `@app.get("/")` повідомляє **FastAPI**, що функція одразу нижче відповідає за обробку запитів, які надходять до:
* шляху `/`
-* використовуючи
get операцію
+* використовуючи
get операція
/// info | `@decorator` Інформація
@@ -300,7 +300,7 @@ https://example.com/items/foo
* `@app.patch()`
* `@app.trace()`
-/// tip | Порада
+/// tip
Ви можете використовувати кожну операцію (HTTP-метод) як забажаєте.
@@ -320,7 +320,7 @@ https://example.com/items/foo
* **операція**: це `get`.
* **функція**: це функція нижче «декоратора» (нижче `@app.get("/")`).
-{* ../../docs_src/first_steps/tutorial001_py39.py hl[7] *}
+{* ../../docs_src/first_steps/tutorial001_py310.py hl[7] *}
Це функція Python.
@@ -332,9 +332,9 @@ https://example.com/items/foo
Ви також можете визначити її як звичайну функцію замість `async def`:
-{* ../../docs_src/first_steps/tutorial003_py39.py hl[7] *}
+{* ../../docs_src/first_steps/tutorial003_py310.py hl[7] *}
-/// note | Примітка
+/// note
Якщо ви не знаєте різницю, подивіться [Асинхронність: *«Поспішаєте?»*](../async.md#in-a-hurry){.internal-link target=_blank}.
@@ -342,7 +342,7 @@ https://example.com/items/foo
### Крок 5: поверніть вміст { #step-5-return-the-content }
-{* ../../docs_src/first_steps/tutorial001_py39.py hl[8] *}
+{* ../../docs_src/first_steps/tutorial001_py310.py hl[8] *}
Ви можете повернути `dict`, `list`, а також окремі значення `str`, `int` тощо.
diff --git a/docs/uk/docs/tutorial/handling-errors.md b/docs/uk/docs/tutorial/handling-errors.md
index 53b8b12f61..28a83127ff 100644
--- a/docs/uk/docs/tutorial/handling-errors.md
+++ b/docs/uk/docs/tutorial/handling-errors.md
@@ -25,7 +25,7 @@
### Імпорт `HTTPException` { #import-httpexception }
-{* ../../docs_src/handling_errors/tutorial001_py39.py hl[1] *}
+{* ../../docs_src/handling_errors/tutorial001_py310.py hl[1] *}
### Згенеруйте `HTTPException` у своєму коді { #raise-an-httpexception-in-your-code }
@@ -39,7 +39,7 @@
У цьому прикладі, коли клієнт запитує елемент за ID, якого не існує, згенеруйте виключення зі статус-кодом `404`:
-{* ../../docs_src/handling_errors/tutorial001_py39.py hl[11] *}
+{* ../../docs_src/handling_errors/tutorial001_py310.py hl[11] *}
### Отримана відповідь { #the-resulting-response }
@@ -77,7 +77,7 @@
Але якщо вам знадобиться це для складного сценарію, ви можете додати власні заголовки:
-{* ../../docs_src/handling_errors/tutorial002_py39.py hl[14] *}
+{* ../../docs_src/handling_errors/tutorial002_py310.py hl[14] *}
## Встановлення власних обробників виключень { #install-custom-exception-handlers }
@@ -89,7 +89,7 @@
Ви можете додати власний обробник виключень за допомогою `@app.exception_handler()`:
-{* ../../docs_src/handling_errors/tutorial003_py39.py hl[5:7,13:18,24] *}
+{* ../../docs_src/handling_errors/tutorial003_py310.py hl[5:7,13:18,24] *}
Тут, якщо ви звернетеся до `/unicorns/yolo`, *операція шляху* згенерує (`raise`) `UnicornException`.
@@ -127,7 +127,7 @@
Обробник виключень отримає `Request` і саме виключення.
-{* ../../docs_src/handling_errors/tutorial004_py39.py hl[2,14:19] *}
+{* ../../docs_src/handling_errors/tutorial004_py310.py hl[2,14:19] *}
Тепер, якщо ви перейдете за посиланням `/items/foo`, замість того, щоб отримати стандартну JSON-помилку:
@@ -159,7 +159,7 @@ Field: ('path', 'item_id'), Error: Input should be a valid integer, unable to pa
Наприклад, ви можете захотіти повернути відповідь у вигляді простого тексту замість JSON для цих помилок:
-{* ../../docs_src/handling_errors/tutorial004_py39.py hl[3:4,9:11,25] *}
+{* ../../docs_src/handling_errors/tutorial004_py310.py hl[3:4,9:11,25] *}
/// note | Технічні деталі
@@ -183,7 +183,7 @@ Field: ('path', 'item_id'), Error: Input should be a valid integer, unable to pa
Ви можете використовувати це під час розробки свого додатка, щоб логувати тіло запиту та налагоджувати його, повертати користувачеві тощо.
-{* ../../docs_src/handling_errors/tutorial005_py39.py hl[14] *}
+{* ../../docs_src/handling_errors/tutorial005_py310.py hl[14] *}
Тепер спробуйте надіслати некоректний елемент, наприклад:
@@ -239,6 +239,6 @@ from starlette.exceptions import HTTPException as StarletteHTTPException
Якщо ви хочете використовувати виключення разом із такими ж обробниками виключень за замовчуванням, як у **FastAPI**, ви можете імпортувати та повторно використати обробники виключень за замовчуванням із `fastapi.exception_handlers`:
-{* ../../docs_src/handling_errors/tutorial006_py39.py hl[2:5,15,21] *}
+{* ../../docs_src/handling_errors/tutorial006_py310.py hl[2:5,15,21] *}
У цьому прикладі ви просто друкуєте помилку з дуже виразним повідомленням, але ви зрозуміли основну ідею. Ви можете використовувати виключення, а потім просто повторно використати обробники виключень за замовчуванням.
diff --git a/docs/uk/docs/tutorial/header-param-models.md b/docs/uk/docs/tutorial/header-param-models.md
index c080c19f06..dd734eaee7 100644
--- a/docs/uk/docs/tutorial/header-param-models.md
+++ b/docs/uk/docs/tutorial/header-param-models.md
@@ -1,8 +1,8 @@
# Моделі параметрів заголовків { #header-parameter-models }
-Якщо у Вас є група пов’язаних **параметрів заголовків**, Ви можете створити **Pydantic модель** для їх оголошення.
+Якщо у вас є група пов’язаних **параметрів заголовків**, ви можете створити **Pydantic модель** для їх оголошення.
-Це дозволить Вам повторно **використовувати модель** в **різних місцях**, а також оголосити валідації та метадані для всіх параметрів одночасно. 😎
+Це дозволить вам повторно **використовувати модель** в **різних місцях**, а також оголосити валідації та метадані для всіх параметрів одночасно. 😎
/// note | Примітка
@@ -16,7 +16,7 @@
{* ../../docs_src/header_param_models/tutorial001_an_py310.py hl[9:14,18] *}
-**FastAPI** буде **витягувати** дані для **кожного поля** з **заголовків** у запиті та передавати їх у створену Вами Pydantic модель.
+**FastAPI** буде **витягувати** дані для **кожного поля** з **заголовків** у запиті та передавати їх у створену вами Pydantic модель.
## Перевірка в документації { #check-the-docs }
@@ -28,7 +28,7 @@
## Заборонити додаткові заголовки { #forbid-extra-headers }
-У деяких особливих випадках (ймовірно, не дуже поширених) Ви можете захотіти **обмежити** заголовки, які хочете отримати.
+У деяких особливих випадках (ймовірно, не дуже поширених) ви можете захотіти **обмежити** заголовки, які хочете отримати.
Ви можете використати конфігурацію моделі Pydantic, щоб `заборонити` будь-які `додаткові` поля:
@@ -55,9 +55,9 @@
Так само, як і зі звичайними параметрами заголовків, коли у назвах параметрів є символи підкреслення, вони **автоматично перетворюються на дефіси**.
-Наприклад, якщо у коді у Вас є параметр заголовка `save_data`, очікуваний HTTP-заголовок буде `save-data`, і він так само відображатиметься в документації.
+Наприклад, якщо у коді у вас є параметр заголовка `save_data`, очікуваний HTTP-заголовок буде `save-data`, і він так само відображатиметься в документації.
-Якщо з якоїсь причини Вам потрібно вимкнути це автоматичне перетворення, Ви також можете зробити це для Pydantic моделей для параметрів заголовків.
+Якщо з якоїсь причини вам потрібно вимкнути це автоматичне перетворення, ви також можете зробити це для Pydantic моделей для параметрів заголовків.
{* ../../docs_src/header_param_models/tutorial003_an_py310.py hl[19] *}
diff --git a/docs/uk/docs/tutorial/header-params.md b/docs/uk/docs/tutorial/header-params.md
index f5a4ea18d1..9e564d27ab 100644
--- a/docs/uk/docs/tutorial/header-params.md
+++ b/docs/uk/docs/tutorial/header-params.md
@@ -50,7 +50,7 @@
/// warning | Попередження
-Перед тим як встановити `convert_underscores` в `False`, пам’ятайте, що деякі HTTP-проксі та сервери забороняють використання заголовків із підкресленнями.
+Перед тим як встановити `convert_underscores` в `False`, пам’ятайте, що деякі HTTP-представники та сервери забороняють використання заголовків із підкресленнями.
///
diff --git a/docs/uk/docs/tutorial/index.md b/docs/uk/docs/tutorial/index.md
index 6848090ecc..ed53ac7728 100644
--- a/docs/uk/docs/tutorial/index.md
+++ b/docs/uk/docs/tutorial/index.md
@@ -84,12 +84,12 @@ $ pip install "fastapi[standard]"
///
-## Розширений посібник користувача { #advanced-user-guide }
+## Просунутий посібник користувача { #advanced-user-guide }
-Існує також **Розширений посібник користувача**, який ви зможете прочитати пізніше після цього **Туторіал - Посібник користувача**.
+Існує також **Просунутий посібник користувача**, який ви зможете прочитати пізніше після цього **Туторіал - Посібник користувача**.
-**Розширений посібник користувача** засновано на цьому, використовує ті самі концепції та навчає вас деяким додатковим функціям.
+**Просунутий посібник користувача** засновано на цьому, використовує ті самі концепції та навчає вас деяким додатковим функціям.
Але вам слід спочатку прочитати **Туторіал - Посібник користувача** (те, що ви зараз читаєте).
-Він розроблений таким чином, що ви можете створити повну програму лише за допомогою **Туторіал - Посібник користувача**, а потім розширити її різними способами, залежно від ваших потреб, використовуючи деякі з додаткових ідей з **Розширеного посібника користувача**.
+Він розроблений таким чином, що ви можете створити повну програму лише за допомогою **Туторіал - Посібник користувача**, а потім розширити її різними способами, залежно від ваших потреб, використовуючи деякі з додаткових ідей з **Просунутого посібника користувача**.
diff --git a/docs/uk/docs/tutorial/metadata.md b/docs/uk/docs/tutorial/metadata.md
index cf17045628..ebe8dc40e1 100644
--- a/docs/uk/docs/tutorial/metadata.md
+++ b/docs/uk/docs/tutorial/metadata.md
@@ -18,7 +18,7 @@
Ви можете налаштувати їх наступним чином:
-{* ../../docs_src/metadata/tutorial001_py39.py hl[3:16, 19:32] *}
+{* ../../docs_src/metadata/tutorial001_py310.py hl[3:16, 19:32] *}
/// tip | Порада
@@ -36,7 +36,7 @@
Наприклад:
-{* ../../docs_src/metadata/tutorial001_1_py39.py hl[31] *}
+{* ../../docs_src/metadata/tutorial001_1_py310.py hl[31] *}
## Метадані для тегів { #metadata-for-tags }
@@ -58,7 +58,7 @@
Створіть метадані для своїх тегів і передайте їх у параметр `openapi_tags`:
-{* ../../docs_src/metadata/tutorial004_py39.py hl[3:16,18] *}
+{* ../../docs_src/metadata/tutorial004_py310.py hl[3:16,18] *}
Зверніть увагу, що в описах можна використовувати Markdown, наприклад, "login" буде показано жирним шрифтом (**login**), а "fancy" буде показано курсивом (_fancy_).
@@ -72,7 +72,7 @@
Використовуйте параметр `tags` зі своїми *операціями шляху* (і `APIRouter`s), щоб призначити їх до різних тегів:
-{* ../../docs_src/metadata/tutorial004_py39.py hl[21,26] *}
+{* ../../docs_src/metadata/tutorial004_py310.py hl[21,26] *}
/// info | Інформація
@@ -100,7 +100,7 @@
Наприклад, щоб налаштувати його на `/api/v1/openapi.json`:
-{* ../../docs_src/metadata/tutorial002_py39.py hl[3] *}
+{* ../../docs_src/metadata/tutorial002_py310.py hl[3] *}
Якщо Ви хочете повністю вимкнути схему OpenAPI, Ви можете встановити `openapi_url=None`, це також вимкне інтерфейси документації, які її використовують.
@@ -117,4 +117,4 @@
Наприклад, щоб налаштувати Swagger UI на `/documentation` і вимкнути ReDoc:
-{* ../../docs_src/metadata/tutorial003_py39.py hl[3] *}
+{* ../../docs_src/metadata/tutorial003_py310.py hl[3] *}
diff --git a/docs/uk/docs/tutorial/middleware.md b/docs/uk/docs/tutorial/middleware.md
index 2d1580e49e..961fb179e7 100644
--- a/docs/uk/docs/tutorial/middleware.md
+++ b/docs/uk/docs/tutorial/middleware.md
@@ -31,9 +31,9 @@
* Потім вона поверне `response`, згенеровану відповідною *операцією шляху*.
* Потім ви можете додатково змінити `response` перед тим, як повернути її.
-{* ../../docs_src/middleware/tutorial001_py39.py hl[8:9,11,14] *}
+{* ../../docs_src/middleware/tutorial001_py310.py hl[8:9,11,14] *}
-/// tip | Порада
+/// tip
Пам’ятайте, що власні пропрієтарні заголовки можна додавати
використовуючи префікс `X-`.
@@ -57,9 +57,9 @@
Наприклад, ви можете додати власний заголовок `X-Process-Time`, який міститиме час у секундах, який витратився на обробку запиту та генерацію відповіді:
-{* ../../docs_src/middleware/tutorial001_py39.py hl[10,12:13] *}
+{* ../../docs_src/middleware/tutorial001_py310.py hl[10,12:13] *}
-/// tip | Порада
+/// tip
Тут ми використовуємо
`time.perf_counter()` замість `time.time()` оскільки він може бути більш точним для таких випадків. 🤓
@@ -92,4 +92,4 @@ app.add_middleware(MiddlewareB)
Ви можете пізніше прочитати більше про інші middlewares в [Advanced User Guide: Advanced Middleware](../advanced/middleware.md){.internal-link target=_blank}.
-Ви дізнаєтесь, як обробляти
CORS за допомогою middleware в наступному розділі.
+Ви дізнаєтесь, як обробляти
CORS за допомогою middleware в наступному розділі.
diff --git a/docs/uk/docs/tutorial/path-operation-configuration.md b/docs/uk/docs/tutorial/path-operation-configuration.md
new file mode 100644
index 0000000000..91b58b24ec
--- /dev/null
+++ b/docs/uk/docs/tutorial/path-operation-configuration.md
@@ -0,0 +1,107 @@
+# Налаштування операції шляху { #path-operation-configuration }
+
+Є кілька параметрів, які ви можете передати вашому «декоратору операції шляху» для налаштування.
+
+/// warning | Попередження
+
+Зверніть увагу, що ці параметри передаються безпосередньо «декоратору операції шляху», а не вашій «функції операції шляху».
+
+///
+
+## Код статусу відповіді { #response-status-code }
+
+Ви можете визначити (HTTP) `status_code`, який буде використано у відповіді вашої «операції шляху».
+
+Можна передати безпосередньо цілий код, наприклад `404`.
+
+Якщо ви не пам'ятаєте призначення числових кодів, скористайтеся скороченими константами в `status`:
+
+{* ../../docs_src/path_operation_configuration/tutorial001_py310.py hl[1,15] *}
+
+Цей код статусу буде використано у відповіді та додано до схеми OpenAPI.
+
+/// note | Технічні деталі
+
+Ви також можете використати `from starlette import status`.
+
+FastAPI надає той самий `starlette.status` як `fastapi.status` для вашої зручності як розробника. Але він походить безпосередньо зі Starlette.
+
+///
+
+## Мітки { #tags }
+
+Ви можете додати мітки до вашої «операції шляху», передайте параметр `tags` зі `list` із `str` (зазвичай лише один `str`):
+
+{* ../../docs_src/path_operation_configuration/tutorial002_py310.py hl[15,20,25] *}
+
+Вони будуть додані до схеми OpenAPI та використані інтерфейсами автоматичної документації:
+
+

+
+### Мітки з переліками { #tags-with-enums }
+
+У великому застосунку ви можете накопичити багато міток і захочете переконатися, що завжди використовуєте ту саму мітку для пов'язаних «операцій шляху».
+
+У таких випадках має сенс зберігати мітки в `Enum`.
+
+FastAPI підтримує це так само, як і зі звичайними строками:
+
+{* ../../docs_src/path_operation_configuration/tutorial002b_py310.py hl[1,8:10,13,18] *}
+
+## Короткий опис і опис { #summary-and-description }
+
+Ви можете додати `summary` і `description`:
+
+{* ../../docs_src/path_operation_configuration/tutorial003_py310.py hl[17:18] *}
+
+## Опис зі строки документації { #description-from-docstring }
+
+Оскільки описи зазвичай довгі та займають кілька рядків, ви можете оголосити опис «операції шляху» у
строці документації функції, і FastAPI прочитає його звідти.
+
+Ви можете писати
Markdown у строці документації, його буде інтерпретовано та показано коректно (з урахуванням відступів у строці документації).
+
+{* ../../docs_src/path_operation_configuration/tutorial004_py310.py hl[17:25] *}
+
+Його буде використано в інтерактивній документації:
+
+

+
+## Опис відповіді { #response-description }
+
+Ви можете вказати опис відповіді параметром `response_description`:
+
+{* ../../docs_src/path_operation_configuration/tutorial005_py310.py hl[18] *}
+
+/// info | Інформація
+
+Зверніть увагу, що `response_description` стосується саме відповіді, а `description` стосується «операції шляху» загалом.
+
+///
+
+/// check | Перевірте
+
+OpenAPI визначає, що кожна «операція шляху» потребує опису відповіді.
+
+Тому, якщо ви його не надасте, FastAPI автоматично згенерує «Successful response».
+
+///
+
+

+
+## Позначити операцію шляху як застарілу { #deprecate-a-path-operation }
+
+Якщо потрібно позначити «операцію шляху» як
застарілу, але не видаляючи її, передайте параметр `deprecated`:
+
+{* ../../docs_src/path_operation_configuration/tutorial006_py310.py hl[16] *}
+
+У інтерактивній документації вона буде чітко позначена як застаріла:
+
+

+
+Подивіться, як виглядають застарілі та незастарілі «операції шляху»:
+
+

+
+## Підсумок { #recap }
+
+Ви можете легко налаштовувати та додавати метадані до ваших «операцій шляху», передаючи параметри «декораторам операцій шляху».
diff --git a/docs/uk/docs/tutorial/path-params-numeric-validations.md b/docs/uk/docs/tutorial/path-params-numeric-validations.md
index f6aa920193..9458436fd3 100644
--- a/docs/uk/docs/tutorial/path-params-numeric-validations.md
+++ b/docs/uk/docs/tutorial/path-params-numeric-validations.md
@@ -54,11 +54,11 @@ Python видасть помилку, якщо розмістити значен
Тому ви можете оголосити вашу функцію так:
-{* ../../docs_src/path_params_numeric_validations/tutorial002_py39.py hl[7] *}
+{* ../../docs_src/path_params_numeric_validations/tutorial002_py310.py hl[7] *}
Але майте на увазі, що якщо ви використовуєте `Annotated`, цієї проблеми не буде, це не матиме значення, оскільки ви не використовуєте значення за замовчуванням параметрів функції для `Query()` або `Path()`.
-{* ../../docs_src/path_params_numeric_validations/tutorial002_an_py39.py *}
+{* ../../docs_src/path_params_numeric_validations/tutorial002_an_py310.py *}
## Упорядковуйте параметри, як вам потрібно: хитрощі { #order-the-parameters-as-you-need-tricks }
@@ -81,15 +81,15 @@ Python видасть помилку, якщо розмістити значен
Передайте `*` як перший параметр функції.
-Python нічого не зробить із цією `*`, але розпізнає, що всі наступні параметри слід викликати як аргументи за ключовим словом (пари ключ-значення), також відомі як
kwargs. Навіть якщо вони не мають значення за замовчуванням.
+Python нічого не зробить із цією `*`, але розпізнає, що всі наступні параметри слід викликати як аргументи за ключовим словом (пари ключ-значення), також відомі як
kwargs. Навіть якщо вони не мають значення за замовчуванням.
-{* ../../docs_src/path_params_numeric_validations/tutorial003_py39.py hl[7] *}
+{* ../../docs_src/path_params_numeric_validations/tutorial003_py310.py hl[7] *}
### Краще з `Annotated` { #better-with-annotated }
Майте на увазі, що якщо ви використовуєте `Annotated`, оскільки ви не використовуєте значення за замовчуванням параметрів функції, цієї проблеми не буде, і, ймовірно, вам не потрібно буде використовувати `*`.
-{* ../../docs_src/path_params_numeric_validations/tutorial003_an_py39.py hl[10] *}
+{* ../../docs_src/path_params_numeric_validations/tutorial003_an_py310.py hl[10] *}
## Валідація числових даних: більше або дорівнює { #number-validations-greater-than-or-equal }
@@ -97,7 +97,7 @@ Python нічого не зробить із цією `*`, але розпізн
Тут, завдяки `ge=1`, `item_id` має бути цілим числом, яке "`g`reater than or `e`qual" (більше або дорівнює) `1`.
-{* ../../docs_src/path_params_numeric_validations/tutorial004_an_py39.py hl[10] *}
+{* ../../docs_src/path_params_numeric_validations/tutorial004_an_py310.py hl[10] *}
## Валідація числових даних: більше ніж і менше або дорівнює { #number-validations-greater-than-and-less-than-or-equal }
@@ -106,19 +106,19 @@ Python нічого не зробить із цією `*`, але розпізн
* `gt`: `g`reater `t`han
* `le`: `l`ess than or `e`qual
-{* ../../docs_src/path_params_numeric_validations/tutorial005_an_py39.py hl[10] *}
+{* ../../docs_src/path_params_numeric_validations/tutorial005_an_py310.py hl[10] *}
## Валідація числових даних: float, більше ніж і менше ніж { #number-validations-floats-greater-than-and-less-than }
Валідація чисел також працює для значень типу `float`.
-Ось де стає важливо мати можливість оголошувати
gt, а не тільки
ge. Це дозволяє, наприклад, вимагати, щоб значення було більше `0`, навіть якщо воно менше `1`.
+Ось де стає важливо мати можливість оголошувати
gt, а не тільки
ge. Це дозволяє, наприклад, вимагати, щоб значення було більше `0`, навіть якщо воно менше `1`.
Таким чином, значення `0.5` буде допустимим. Але `0.0` або `0` — ні.
-Те саме стосується
lt.
+Те саме стосується
lt.
-{* ../../docs_src/path_params_numeric_validations/tutorial006_an_py39.py hl[13] *}
+{* ../../docs_src/path_params_numeric_validations/tutorial006_an_py310.py hl[13] *}
## Підсумок { #recap }
diff --git a/docs/uk/docs/tutorial/path-params.md b/docs/uk/docs/tutorial/path-params.md
index 0598905495..17b99cf39a 100644
--- a/docs/uk/docs/tutorial/path-params.md
+++ b/docs/uk/docs/tutorial/path-params.md
@@ -2,7 +2,7 @@
Ви можете оголосити «параметри» або «змінні» шляху, використовуючи той самий синтаксис, що й у форматованих рядках Python:
-{* ../../docs_src/path_params/tutorial001_py39.py hl[6:7] *}
+{* ../../docs_src/path_params/tutorial001_py310.py hl[6:7] *}
Значення параметра шляху `item_id` буде передано у вашу функцію як аргумент `item_id`.
@@ -16,17 +16,17 @@
Ви можете оголосити тип параметра шляху у функції, використовуючи стандартні анотації типів Python:
-{* ../../docs_src/path_params/tutorial002_py39.py hl[7] *}
+{* ../../docs_src/path_params/tutorial002_py310.py hl[7] *}
У цьому випадку `item_id` оголошено як `int`.
-/// check | Примітка
+/// check | Перевірте
Це дасть вам підтримку редактора всередині функції з перевірками помилок, автодоповненням тощо.
///
-##
Перетворення даних { #data-conversion }
+##
Перетворення даних { #data-conversion }
Якщо ви запустите цей приклад і відкриєте у браузері
http://127.0.0.1:8000/items/3, то побачите відповідь:
@@ -34,11 +34,11 @@
{"item_id":3}
```
-/// check | Примітка
+/// check | Перевірте
Зверніть увагу, що значення, яке отримала (і повернула) ваша функція, — це `3`, як Python `int`, а не рядок `"3"`.
-Отже, з таким оголошенням типу **FastAPI** надає вам автоматичний
«parsing» запиту.
+Отже, з таким оголошенням типу **FastAPI** надає вам автоматичний запит
«парсинг».
///
@@ -66,7 +66,7 @@
Та сама помилка з’явиться, якщо ви передасте `float` замість `int`, як у:
http://127.0.0.1:8000/items/4.2
-/// check | Примітка
+/// check | Перевірте
Отже, з тим самим оголошенням типу в Python **FastAPI** надає вам валідацію даних.
@@ -82,7 +82,7 @@

-/// check | Примітка
+/// check | Перевірте
Знову ж таки, лише з тим самим оголошенням типу в Python **FastAPI** надає вам автоматичну, інтерактивну документацію (з інтеграцією Swagger UI).
@@ -118,19 +118,19 @@
Оскільки *операції шляху* оцінюються по черзі, вам потрібно переконатися, що шлях для `/users/me` оголошено перед шляхом для `/users/{user_id}`:
-{* ../../docs_src/path_params/tutorial003_py39.py hl[6,11] *}
+{* ../../docs_src/path_params/tutorial003_py310.py hl[6,11] *}
Інакше шлях для `/users/{user_id}` також відповідатиме `/users/me`, «вважаючи», що отримує параметр `user_id` зі значенням `"me"`.
Так само ви не можете перевизначити операцію шляху:
-{* ../../docs_src/path_params/tutorial003b_py39.py hl[6,11] *}
+{* ../../docs_src/path_params/tutorial003b_py310.py hl[6,11] *}
Завжди використовуватиметься перша, оскільки шлях збігається першим.
## Попередньо визначені значення { #predefined-values }
-Якщо у вас є *операція шляху*, яка отримує *параметр шляху*, але ви хочете, щоб можливі коректні значення *параметра шляху* були попередньо визначені, ви можете використати стандартний Python
`Enum`.
+Якщо у вас є *операція шляху*, яка отримує *параметр шляху*, але ви хочете, щоб можливі коректні значення *параметра шляху* були попередньо визначені, ви можете використати стандартний Python
`Enum`.
### Створіть клас `Enum` { #create-an-enum-class }
@@ -140,11 +140,11 @@
Після цього створіть атрибути класу з фіксованими значеннями, які будуть доступними коректними значеннями:
-{* ../../docs_src/path_params/tutorial005_py39.py hl[1,6:9] *}
+{* ../../docs_src/path_params/tutorial005_py310.py hl[1,6:9] *}
/// tip | Порада
-Якщо вам цікаво, «AlexNet», «ResNet» та «LeNet» — це просто назви Machine Learning
models.
+Якщо вам цікаво, «AlexNet», «ResNet» та «LeNet» — це просто назви моделей машинного навчання
моделі.
///
@@ -152,7 +152,7 @@
Потім створіть *параметр шляху* з анотацією типу, використовуючи створений вами клас enum (`ModelName`):
-{* ../../docs_src/path_params/tutorial005_py39.py hl[16] *}
+{* ../../docs_src/path_params/tutorial005_py310.py hl[16] *}
### Перевірте документацію { #check-the-docs }
@@ -168,13 +168,13 @@
Ви можете порівнювати його з *елементом перелічування* у створеному вами enum `ModelName`:
-{* ../../docs_src/path_params/tutorial005_py39.py hl[17] *}
+{* ../../docs_src/path_params/tutorial005_py310.py hl[17] *}
#### Отримайте *значення перелічування* { #get-the-enumeration-value }
Ви можете отримати фактичне значення (у цьому випадку це `str`), використовуючи `model_name.value`, або загалом `your_enum_member.value`:
-{* ../../docs_src/path_params/tutorial005_py39.py hl[20] *}
+{* ../../docs_src/path_params/tutorial005_py310.py hl[20] *}
/// tip | Порада
@@ -188,7 +188,7 @@
Вони будуть перетворені на відповідні значення (у цьому випадку рядки) перед поверненням клієнту:
-{* ../../docs_src/path_params/tutorial005_py39.py hl[18,21,23] *}
+{* ../../docs_src/path_params/tutorial005_py310.py hl[18,21,23] *}
На стороні клієнта ви отримаєте відповідь у форматі JSON, наприклад:
@@ -227,7 +227,7 @@ OpenAPI не підтримує спосіб оголошення *параме
Отже, ви можете використати його так:
-{* ../../docs_src/path_params/tutorial004_py39.py hl[6] *}
+{* ../../docs_src/path_params/tutorial004_py310.py hl[6] *}
/// tip | Порада
@@ -242,7 +242,7 @@ OpenAPI не підтримує спосіб оголошення *параме
З **FastAPI**, використовуючи короткі, інтуїтивно зрозумілі та стандартні оголошення типів Python, ви отримуєте:
* Підтримку редактора: перевірка помилок, автодоповнення тощо.
-* Перетворення даних «
parsing»
+* Перетворення даних «
парсинг»
* Валідацію даних
* Анотацію API та автоматичну документацію
diff --git a/docs/uk/docs/tutorial/query-param-models.md b/docs/uk/docs/tutorial/query-param-models.md
index a28bf6c27c..5affc8a6c2 100644
--- a/docs/uk/docs/tutorial/query-param-models.md
+++ b/docs/uk/docs/tutorial/query-param-models.md
@@ -1,6 +1,6 @@
# Моделі параметрів запиту { #query-parameter-models }
-Якщо у Вас є група **query параметрів**, які пов’язані між собою, Ви можете створити **Pydantic-модель** для їх оголошення.
+Якщо у Вас є група **параметрів запиту**, які пов’язані між собою, Ви можете створити **Pydantic-модель** для їх оголошення.
Це дозволить Вам **повторно використовувати модель** у **різних місцях**, а також оголошувати перевірки та метадані для всіх параметрів одночасно. 😎
@@ -10,13 +10,13 @@
///
-## Query параметри з Pydantic-моделлю { #query-parameters-with-a-pydantic-model }
+## Параметри запиту з Pydantic-моделлю { #query-parameters-with-a-pydantic-model }
-Оголосіть **query параметри**, які Вам потрібні, у **Pydantic-моделі**, а потім оголосіть цей параметр як `Query`:
+Оголосіть **параметри запиту**, які Вам потрібні, у **Pydantic-моделі**, а потім оголосіть цей параметр як `Query`:
{* ../../docs_src/query_param_models/tutorial001_an_py310.py hl[9:13,17] *}
-**FastAPI** буде **витягувати** дані для **кожного поля** з **query параметрів** у запиті та передавати їх у визначену вами Pydantic-модель.
+**FastAPI** буде **витягувати** дані для **кожного поля** з **параметрів запиту** у запиті та передавати їх у визначену вами Pydantic-модель.
## Перевірте документацію { #check-the-docs }
@@ -26,23 +26,23 @@
-## Заборона зайвих Query параметрів { #forbid-extra-query-parameters }
+## Заборона зайвих параметрів запиту { #forbid-extra-query-parameters }
-У деяких особливих випадках (ймовірно, не дуже поширених) Ви можете захотіти **обмежити** query параметри, які дозволено отримувати.
+У деяких особливих випадках (ймовірно, не дуже поширених) Ви можете захотіти **обмежити** параметри запиту, які дозволено отримувати.
Ви можете використати конфігурацію моделі Pydantic, щоб заборонити (`forbid`) будь-які зайві (`extra`) поля:
{* ../../docs_src/query_param_models/tutorial002_an_py310.py hl[10] *}
-Якщо клієнт спробує надіслати **зайві** дані у **query параметрах**, він отримає **помилку** відповідь.
+Якщо клієнт спробує надіслати **зайві** дані у **параметрах запиту**, він отримає **відповідь з помилкою**.
-Наприклад, якщо клієнт спробує надіслати query параметр `tool` зі значенням `plumbus`, як у цьому запиті:
+Наприклад, якщо клієнт спробує надіслати параметр запиту `tool` зі значенням `plumbus`, як у цьому запиті:
```http
https://example.com/items/?limit=10&tool=plumbus
```
-Він отримає відповідь з **помилкою**, яка повідомить, що query параметр `tool ` не дозволено:
+Він отримає відповідь з **помилкою**, яка повідомить, що параметр запиту `tool` не дозволено:
```json
{
@@ -59,10 +59,10 @@ https://example.com/items/?limit=10&tool=plumbus
## Підсумок { #summary }
-Ви можете використовувати **Pydantic-моделі** для оголошення **query параметрів** у **FastAPI**. 😎
+Ви можете використовувати **Pydantic-моделі** для оголошення **параметрів запиту** у **FastAPI**. 😎
/// tip | Порада
-Спойлер: Ви також можете використовувати Pydantic-моделі для оголошення cookie та заголовків, але про це Ви дізнаєтеся пізніше в цьому посібнику. 🤫
+Спойлер: Ви також можете використовувати Pydantic-моделі для оголошення кукі та заголовків, але про це Ви дізнаєтеся пізніше в цьому посібнику. 🤫
///
diff --git a/docs/uk/docs/tutorial/query-params-str-validations.md b/docs/uk/docs/tutorial/query-params-str-validations.md
index 414987880b..706dc670aa 100644
--- a/docs/uk/docs/tutorial/query-params-str-validations.md
+++ b/docs/uk/docs/tutorial/query-params-str-validations.md
@@ -18,7 +18,7 @@ FastAPI знатиме, що значення `q` не є обов’язков
## Додаткова валідація { #additional-validation }
-Ми хочемо, щоб навіть якщо `q` є необов’язковим, коли його передають, **його довжина не перевищувала 50 символів**.
+Ми хочемо, щоб навіть якщо `q` є необов’язковим, коли його передають, його довжина не перевищувала 50 символів.
### Імпорт `Query` та `Annotated` { #import-query-and-annotated }
@@ -47,40 +47,16 @@ FastAPI додав підтримку `Annotated` (і почав рекомен
Раніше ми мали таку анотацію типу:
-//// tab | Python 3.10+
-
```Python
q: str | None = None
```
-////
-
-//// tab | Python 3.9+
-
-```Python
-q: Union[str, None] = None
-```
-
-////
-
Тепер ми загорнемо її у `Annotated`, і отримаємо:
-//// tab | Python 3.10+
-
```Python
q: Annotated[str | None] = None
```
-////
-
-//// tab | Python 3.9+
-
-```Python
-q: Annotated[Union[str, None]] = None
-```
-
-////
-
Обидві ці версії означають одне й те саме: `q` — це параметр, який може бути `str` або `None`, і за замовчуванням має значення `None`.
А тепер переходимо до цікавого! 🎉
@@ -93,23 +69,23 @@ q: Annotated[Union[str, None]] = None
Зверніть увагу, що значення за замовчуванням усе ще `None`, тому параметр залишається необов'язковим.
-Але тепер, додавши `Query(max_length=50)` всередину `Annotated`, ми повідомляємо FastAPI, що хочемо **додаткову валідацію** для цього значення: ми хочемо, щоб воно мало максимум 50 символів. 😎
+Але тепер, додавши `Query(max_length=50)` всередину `Annotated`, ми повідомляємо FastAPI, що хочемо додаткову валідацію для цього значення: ми хочемо, щоб воно мало максимум 50 символів. 😎
/// tip | Порада
-Тут ми використовуємо `Query()`, оскільки це **query параметр**. Далі ми розглянемо інші варіанти, як-от `Path()`, `Body()`, `Header()` та `Cookie()`, які приймають ті самі аргументи, що й `Query()`.
+Тут ми використовуємо `Query()`, оскільки це query параметр. Далі ми розглянемо інші варіанти, як-от `Path()`, `Body()`, `Header()` та `Cookie()`, які приймають ті самі аргументи, що й `Query()`.
///
Тепер FastAPI:
-* **Перевірить** дані, щоб переконатися, що їхня максимальна довжина — 50 символів
-* Покажe **чітку помилку** клієнту, якщо дані недійсні
-* **Задокументує** параметр в OpenAPI-схемі *операції шляху* (що відобразиться в **автоматично згенерованій документації**)
+* Перевірить дані, щоб переконатися, що їхня максимальна довжина — 50 символів
+* Покажe чітку помилку клієнту, якщо дані недійсні
+* Задокументує параметр в OpenAPI-схемі операції шляху (що відобразиться в автоматично згенерованій документації)
## Альтернативний (застарілий) метод: `Query` як значення за замовчуванням { #alternative-old-query-as-the-default-value }
-У попередніх версіях FastAPI (до
0.95.0) потрібно було використовувати `Query` як значення за замовчуванням параметра, замість того, щоб додавати його в `Annotated`. Є висока ймовірність, що ви зустрінете код із таким підходом, тож я поясню його.
+У попередніх версіях FastAPI (до
0.95.0) потрібно було використовувати `Query` як значення за замовчуванням параметра, замість того, щоб додавати його в `Annotated`. Є висока ймовірність, що ви зустрінете код із таким підходом, тож я поясню його.
/// tip | Порада
@@ -131,7 +107,6 @@ q: str | None = Query(default=None)
...робить параметр необов’язковим зі значенням за замовчуванням `None`, що еквівалентно:
-
```Python
q: str | None = None
```
@@ -144,7 +119,7 @@ q: str | None = None
q: str | None = Query(default=None, max_length=50)
```
-Це забезпечить валідацію даних, виведе зрозумілу помилку у разі недійсних даних і задокументує параметр у схемі OpenAPI *операції шляху*.
+Це забезпечить валідацію даних, виведе зрозумілу помилку у разі недійсних даних і задокументує параметр у схемі OpenAPI операції шляху.
### `Query` як значення за замовчуванням або всередині `Annotated` { #query-as-the-default-value-or-in-annotated }
@@ -174,13 +149,13 @@ q: str = Query(default="rick")
### Переваги використання `Annotated` { #advantages-of-annotated }
-**Використання `Annotated` є рекомендованим** замість задання значення за замовчуванням у параметрах функції, оскільки воно **краще** з кількох причин. 🤓
+Використання `Annotated` є рекомендованим замість задання значення за замовчуванням у параметрах функції, оскільки воно краще з кількох причин. 🤓
-Значення **за замовчуванням** параметра **функції** є **фактичним значенням за замовчуванням**, що є більш інтуїтивним у Python загалом. 😌
+Значення за замовчуванням параметра функції є фактичним значенням за замовчуванням, що є більш інтуїтивним у Python загалом. 😌
-Ви можете **викликати** ту саму функцію **в інших місцях** без FastAPI, і вона **працюватиме очікувано**. Якщо параметр є **обов’язковим** (без значення за замовчуванням), ваш **редактор** повідомить про помилку, а **Python** також видасть помилку, якщо ви виконаєте функцію без передавання цього параметра.
+Ви можете викликати ту саму функцію в інших місцях без FastAPI, і вона працюватиме очікувано. Якщо параметр є обов’язковим (без значення за замовчуванням), ваш редактор повідомить про помилку, а Python також видасть помилку, якщо ви виконаєте функцію без передавання цього параметра.
-Якщо ви не використовуєте `Annotated`, а використовуєте **(старий) стиль значень за замовчуванням**, то при виклику цієї функції без FastAPI **в інших місцях**, потрібно **пам’ятати** передати їй аргументи, щоб вона працювала коректно, інакше значення будуть відрізнятися від очікуваних (наприклад, ви отримаєте `QueryInfo` або щось подібне замість `str`). І ваш редактор не повідомить про помилку, і Python не скаржитиметься під час запуску цієї функції — лише коли операції всередині завершаться помилкою.
+Якщо ви не використовуєте `Annotated`, а використовуєте (старий) стиль значень за замовчуванням, то при виклику цієї функції без FastAPI в інших місцях потрібно пам’ятати передати їй аргументи, щоб вона працювала коректно, інакше значення будуть відрізнятися від очікуваних (наприклад, ви отримаєте `QueryInfo` або щось подібне замість `str`). І ваш редактор не повідомить про помилку, і Python не скаржитиметься під час запуску цієї функції — лише коли операції всередині завершаться помилкою.
Оскільки `Annotated` може містити кілька анотацій метаданих, тепер ви навіть можете використовувати ту саму функцію з іншими інструментами, такими як
Typer. 🚀
@@ -192,7 +167,7 @@ q: str = Query(default="rick")
## Додавання регулярних виразів { #add-regular-expressions }
-Ви можете визначити
regular expression `pattern`, якому має відповідати параметр:
+Ви можете визначити
регулярний вираз `pattern`, якому має відповідати параметр:
{* ../../docs_src/query_params_str_validations/tutorial004_an_py310.py hl[11] *}
@@ -212,7 +187,7 @@ q: str = Query(default="rick")
Припустімо, що ви хочете оголосити query параметр `q` з `min_length` `3` і значенням за замовчуванням `"fixedquery"`:
-{* ../../docs_src/query_params_str_validations/tutorial005_an_py39.py hl[9] *}
+{* ../../docs_src/query_params_str_validations/tutorial005_an_py310.py hl[9] *}
/// note | Примітка
@@ -242,7 +217,7 @@ q: Annotated[str | None, Query(min_length=3)] = None
Тому, якщо вам потрібно оголосити значення як обов’язкове під час використання `Query`, просто не вказуйте значення за замовчуванням:
-{* ../../docs_src/query_params_str_validations/tutorial006_an_py39.py hl[9] *}
+{* ../../docs_src/query_params_str_validations/tutorial006_an_py310.py hl[9] *}
### Обов’язковий, може бути `None` { #required-can-be-none }
@@ -266,7 +241,7 @@ q: Annotated[str | None, Query(min_length=3)] = None
http://localhost:8000/items/?q=foo&q=bar
```
-ви отримаєте кілька значень `q` *query параметрів* (`foo` і `bar`) у вигляді Python `list` у вашій *функції операції шляху*, у *параметрі функції* `q`.
+ви отримаєте кілька значень `q` query параметрів (`foo` і `bar`) у вигляді Python `list` у вашій функції операції шляху, у параметрі функції `q`.
Отже, відповідь на цей URL буде:
@@ -293,7 +268,7 @@ http://localhost:8000/items/?q=foo&q=bar
Ви також можете визначити значення за замовчуванням `list`, якщо жодне значення не було передане:
-{* ../../docs_src/query_params_str_validations/tutorial012_an_py39.py hl[9] *}
+{* ../../docs_src/query_params_str_validations/tutorial012_an_py310.py hl[9] *}
Якщо ви перейдете за посиланням:
@@ -316,7 +291,7 @@ http://localhost:8000/items/
Ви також можете використовувати `list` напряму замість `list[str]`:
-{* ../../docs_src/query_params_str_validations/tutorial013_an_py39.py hl[9] *}
+{* ../../docs_src/query_params_str_validations/tutorial013_an_py310.py hl[9] *}
/// note | Примітка
@@ -372,7 +347,7 @@ http://127.0.0.1:8000/items/?item-query=foobaritems
Припустімо, що вам більше не подобається цей параметр.
-Вам потрібно залишити його на деякий час, оскільки ним користуються клієнти, але ви хочете, щоб документація чітко показувала, що він є
deprecated.
+Вам потрібно залишити його на деякий час, оскільки ним користуються клієнти, але ви хочете, щоб документація чітко показувала, що він є
застарілий.
Тоді передайте параметр `deprecated=True` до `Query`:
@@ -390,9 +365,9 @@ http://127.0.0.1:8000/items/?item-query=foobaritems
## Кастомна валідація { #custom-validation }
-Можуть бути випадки, коли вам потрібно провести **кастомну валідацію**, яку не можна реалізувати за допомогою параметрів, показаних вище.
+Можуть бути випадки, коли вам потрібно провести кастомну валідацію, яку не можна реалізувати за допомогою параметрів, показаних вище.
-У таких випадках ви можете використати **кастомну функцію-валідатор**, яка буде застосована після звичайної валідації (наприклад, після перевірки, що значення є типом `str`).
+У таких випадках ви можете використати кастомну функцію-валідатор, яка буде застосована після звичайної валідації (наприклад, після перевірки, що значення є типом `str`).
Це можна досягти за допомогою
Pydantic's `AfterValidator` в середині `Annotated`.
@@ -402,7 +377,7 @@ Pydantic також має
ISBN або з `imdb-` для ID URL фільму на IMDB:
+Наприклад, цей кастомний валідатор перевіряє, чи починається ID елемента з `isbn-` для номера книги ISBN або з `imdb-` для ID URL фільму на IMDB:
{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py hl[5,16:19,24] *}
@@ -414,15 +389,15 @@ Pydantic також має iterable object із кортежами, що містять ключ і значення для кожного елемента словника.
+За допомогою `data.items()` ми отримуємо ітерабельний об'єкт із кортежами, що містять ключ і значення для кожного елемента словника.
-Ми перетворюємо цей iterable object у звичайний `list` за допомогою `list(data.items())`.
+Ми перетворюємо цей ітерабельний об'єкт у звичайний `list` за допомогою `list(data.items())`.
-Потім, використовуючи `random.choice()`, ми можемо отримати **випадкове значення** зі списку, тобто отримуємо кортеж із `(id, name)`. Це може бути щось на зразок `("imdb-tt0371724", "The Hitchhiker's Guide to the Galaxy")`.
+Потім, використовуючи `random.choice()`, ми можемо отримати випадкове значення зі списку, тобто отримуємо кортеж із `(id, name)`. Це може бути щось на зразок `("imdb-tt0371724", "The Hitchhiker's Guide to the Galaxy")`.
-Далі ми **присвоюємо ці два значення** кортежу змінним `id` і `name`.
+Далі ми присвоюємо ці два значення кортежу змінним `id` і `name`.
Тож, якщо користувач не вказав ID елемента, він все одно отримає випадкову рекомендацію.
-...ми робимо все це в **одному простому рядку**. 🤯 Хіба ви не любите Python? 🐍
+...ми робимо все це в одному простому рядку. 🤯 Хіба ви не любите Python? 🐍
{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py ln[22:30] hl[29] *}
diff --git a/docs/uk/docs/tutorial/query-params.md b/docs/uk/docs/tutorial/query-params.md
index a9068aa8f9..4888f4c461 100644
--- a/docs/uk/docs/tutorial/query-params.md
+++ b/docs/uk/docs/tutorial/query-params.md
@@ -2,7 +2,7 @@
Коли ви оголошуєте інші параметри функції, які не є частиною параметрів шляху, вони автоматично інтерпретуються як параметри «query».
-{* ../../docs_src/query_params/tutorial001_py39.py hl[9] *}
+{* ../../docs_src/query_params/tutorial001_py310.py hl[9] *}
Query — це набір пар ключ-значення, що йдуть після символу `?` в URL, розділені символами `&`.
@@ -24,7 +24,7 @@ http://127.0.0.1:8000/items/?skip=0&limit=10
Увесь той самий процес, який застосовується до параметрів шляху, також застосовується до параметрів query:
* Підтримка в редакторі (очевидно)
-* «parsing» даних
+* «парсинг» даних
* Валідація даних
* Автоматична документація
@@ -65,7 +65,7 @@ http://127.0.0.1:8000/items/?skip=20
У цьому випадку параметр функції `q` буде необов’язковим і за замовчуванням матиме значення `None`.
-/// check | Примітка
+/// check | Перевірте
Також зверніть увагу, що **FastAPI** достатньо розумний, щоб визначити, що параметр шляху `item_id` є параметром шляху, а `q` — ні, отже, це параметр query.
@@ -128,7 +128,7 @@ http://127.0.0.1:8000/items/foo?short=yes
Але якщо ви хочете зробити параметр query обов’язковим, просто не вказуйте для нього значення за замовчуванням:
-{* ../../docs_src/query_params/tutorial005_py39.py hl[6:7] *}
+{* ../../docs_src/query_params/tutorial005_py310.py hl[6:7] *}
Тут параметр query `needy` — обов’язковий параметр query типу `str`.
@@ -183,6 +183,6 @@ http://127.0.0.1:8000/items/foo-item?needy=sooooneedy
/// tip | Порада
-Ви також можете використовувати `Enum` так само, як і з [Path Parameters](path-params.md#predefined-values){.internal-link target=_blank}.
+Ви також можете використовувати `Enum` так само, як і з [Параметри шляху](path-params.md#predefined-values){.internal-link target=_blank}.
///
diff --git a/docs/uk/docs/tutorial/request-files.md b/docs/uk/docs/tutorial/request-files.md
index a6ff70dc09..8e64b12c38 100644
--- a/docs/uk/docs/tutorial/request-files.md
+++ b/docs/uk/docs/tutorial/request-files.md
@@ -20,13 +20,13 @@ $ pip install python-multipart
Імпортуйте `File` та `UploadFile` з `fastapi`:
-{* ../../docs_src/request_files/tutorial001_an_py39.py hl[3] *}
+{* ../../docs_src/request_files/tutorial001_an_py310.py hl[3] *}
## Визначення параметрів `File` { #define-file-parameters }
Створіть параметри файлів так само як ви б створювали `Body` або `Form`:
-{* ../../docs_src/request_files/tutorial001_an_py39.py hl[9] *}
+{* ../../docs_src/request_files/tutorial001_an_py310.py hl[9] *}
/// info | Інформація
@@ -54,7 +54,7 @@ $ pip install python-multipart
Визначте параметр файлу з типом `UploadFile`:
-{* ../../docs_src/request_files/tutorial001_an_py39.py hl[14] *}
+{* ../../docs_src/request_files/tutorial001_an_py310.py hl[14] *}
Використання `UploadFile` має кілька переваг перед `bytes`:
@@ -121,7 +121,7 @@ contents = myfile.file.read()
Але якщо форма містить файли, вона кодується як `multipart/form-data`. Якщо ви використовуєте `File`, **FastAPI** знатиме, що потрібно отримати файли з правильної частини тіла.
-Якщо ви хочете дізнатися більше про ці типи кодування та формові поля, ознайомтеся з MDN web docs для POST.
+Якщо ви хочете дізнатися більше про ці типи кодування та формові поля, ознайомтеся з
MDN web docs для POST.
///
@@ -143,7 +143,7 @@ contents = myfile.file.read()
Ви також можете використовувати `File()` разом із `UploadFile`, наприклад, щоб встановити додаткові метадані:
-{* ../../docs_src/request_files/tutorial001_03_an_py39.py hl[9,15] *}
+{* ../../docs_src/request_files/tutorial001_03_an_py310.py hl[9,15] *}
## Завантаження кількох файлів { #multiple-file-uploads }
@@ -153,7 +153,7 @@ contents = myfile.file.read()
Щоб це реалізувати, потрібно оголосити список `bytes` або `UploadFile`:
-{* ../../docs_src/request_files/tutorial002_an_py39.py hl[10,15] *}
+{* ../../docs_src/request_files/tutorial002_an_py310.py hl[10,15] *}
Ви отримаєте, як і було оголошено, `list` із `bytes` або `UploadFile`.
@@ -169,7 +169,7 @@ contents = myfile.file.read()
Так само як і раніше, ви можете використовувати `File()`, щоб встановити додаткові параметри навіть для `UploadFile`:
-{* ../../docs_src/request_files/tutorial003_an_py39.py hl[11,18:20] *}
+{* ../../docs_src/request_files/tutorial003_an_py310.py hl[11,18:20] *}
## Підсумок { #recap }
diff --git a/docs/uk/docs/tutorial/request-form-models.md b/docs/uk/docs/tutorial/request-form-models.md
index 1bfd368d60..86510be589 100644
--- a/docs/uk/docs/tutorial/request-form-models.md
+++ b/docs/uk/docs/tutorial/request-form-models.md
@@ -24,7 +24,7 @@ $ pip install python-multipart
Вам просто потрібно оголосити **Pydantic-модель** з полями, які ви хочете отримати як **поля форми**, а потім оголосити параметр як `Form`:
-{* ../../docs_src/request_form_models/tutorial001_an_py39.py hl[9:11,15] *}
+{* ../../docs_src/request_form_models/tutorial001_an_py310.py hl[9:11,15] *}
**FastAPI** **витягне** дані для **кожного поля** з **формових даних** у запиті та надасть вам Pydantic-модель, яку ви визначили.
@@ -48,7 +48,7 @@ $ pip install python-multipart
Ви можете використати конфігурацію Pydantic-моделі, щоб заборонити `forbid` будь-які додаткові `extra` поля:
-{* ../../docs_src/request_form_models/tutorial002_an_py39.py hl[12] *}
+{* ../../docs_src/request_form_models/tutorial002_an_py310.py hl[12] *}
Якщо клієнт спробує надіслати додаткові дані, він отримає **відповідь з помилкою**.
diff --git a/docs/uk/docs/tutorial/request-forms-and-files.md b/docs/uk/docs/tutorial/request-forms-and-files.md
index e809bee225..817769b714 100644
--- a/docs/uk/docs/tutorial/request-forms-and-files.md
+++ b/docs/uk/docs/tutorial/request-forms-and-files.md
@@ -6,7 +6,7 @@
Щоб отримувати завантажені файли та/або дані форми, спочатку встановіть
`python-multipart`.
-Переконайтеся, що Ви створили [віртуальне середовище](../virtual-environments.md){.internal-link target=_blank}, активували його, а потім встановили бібліотеку, наприклад:
+Переконайтеся, що ви створили [віртуальне середовище](../virtual-environments.md){.internal-link target=_blank}, активували його, а потім встановили бібліотеку, наприклад:
```console
$ pip install python-multipart
@@ -16,15 +16,15 @@ $ pip install python-multipart
## Імпорт `File` та `Form` { #import-file-and-form }
-{* ../../docs_src/request_forms_and_files/tutorial001_an_py39.py hl[3] *}
+{* ../../docs_src/request_forms_and_files/tutorial001_an_py310.py hl[3] *}
## Оголошення параметрів `File` та `Form` { #define-file-and-form-parameters }
Створіть параметри файлів та форми так само як і для `Body` або `Query`:
-{* ../../docs_src/request_forms_and_files/tutorial001_an_py39.py hl[10:12] *}
+{* ../../docs_src/request_forms_and_files/tutorial001_an_py310.py hl[10:12] *}
-Файли та поля форми будуть завантажені як формові дані, і Ви отримаєте файли та поля форми.
+Файли та поля форми будуть завантажені як формові дані, і ви отримаєте файли та поля форми.
Ви також можете оголосити деякі файли як `bytes`, а деякі як `UploadFile`.
diff --git a/docs/uk/docs/tutorial/request-forms.md b/docs/uk/docs/tutorial/request-forms.md
index 2a22ad922a..7f0c6e9bb3 100644
--- a/docs/uk/docs/tutorial/request-forms.md
+++ b/docs/uk/docs/tutorial/request-forms.md
@@ -1,6 +1,6 @@
# Дані форми { #form-data }
-Якщо вам потрібно отримувати поля форми замість JSON, ви можете використовувати `Form`.
+Коли вам потрібно отримувати поля форми замість JSON, ви можете використовувати `Form`.
/// info | Інформація
@@ -18,17 +18,17 @@ $ pip install python-multipart
Імпортуйте `Form` з `fastapi`:
-{* ../../docs_src/request_forms/tutorial001_an_py39.py hl[3] *}
+{* ../../docs_src/request_forms/tutorial001_an_py310.py hl[3] *}
## Оголошення параметрів `Form` { #define-form-parameters }
Створюйте параметри форми так само як ви б створювали `Body` або `Query`:
-{* ../../docs_src/request_forms/tutorial001_an_py39.py hl[9] *}
+{* ../../docs_src/request_forms/tutorial001_an_py310.py hl[9] *}
-Наприклад, один зі способів використання специфікації OAuth2 (так званий "password flow") вимагає надсилати `username` та `password` як поля форми.
+Наприклад, один зі способів використання специфікації OAuth2 (так званий «password flow») вимагає надсилати `username` та `password` як поля форми.
-
spec вимагає, щоб ці поля мали точні назви `username` і `password` та надсилалися у вигляді полів форми, а не JSON.
+
специфікація вимагає, щоб ці поля мали точні назви `username` і `password` та надсилалися у вигляді полів форми, а не JSON.
З `Form` ви можете оголошувати ті ж конфігурації, що і з `Body` (та `Query`, `Path`, `Cookie`), включаючи валідацію, приклади, псевдоніми (наприклад, `user-name` замість `username`) тощо.
@@ -44,19 +44,19 @@ $ pip install python-multipart
///
-## Про "поля форми" { #about-form-fields }
+## Про «поля форми» { #about-form-fields }
-HTML-форми (`
`) надсилають дані на сервер у "спеціальному" кодуванні, яке відрізняється від JSON.
+HTML-форми (`
`) надсилають дані на сервер у «спеціальному» кодуванні, яке відрізняється від JSON.
**FastAPI** подбає про те, щоб зчитати ці дані з правильного місця, а не з JSON.
/// note | Технічні деталі
-Дані з форм зазвичай кодуються за допомогою "типу медіа" `application/x-www-form-urlencoded`.
+Дані з форм зазвичай кодуються за допомогою «типу медіа» `application/x-www-form-urlencoded`.
Але якщо форма містить файли, вона кодується як `multipart/form-data`. Ви дізнаєтеся про обробку файлів у наступному розділі.
-Якщо ви хочете дізнатися більше про ці кодування та поля форм, зверніться до
MDN вебдокументації для POST.
+Якщо ви хочете дізнатися більше про ці кодування та поля форм, зверніться до
MDN вебдокументації для POST.
///
diff --git a/docs/uk/docs/tutorial/response-model.md b/docs/uk/docs/tutorial/response-model.md
index 2fcad94387..fcf765c9da 100644
--- a/docs/uk/docs/tutorial/response-model.md
+++ b/docs/uk/docs/tutorial/response-model.md
@@ -81,7 +81,7 @@ FastAPI використовуватиме цей `response_model` для вик
$ pip install email-validator
```
-or with:
+або так:
```console
$ pip install "pydantic[email]"
@@ -183,7 +183,7 @@ FastAPI виконує кілька внутрішніх операцій з Pyd
Найпоширенішим випадком буде [повернення Response напряму, як пояснюється пізніше у розширеній документації](../advanced/response-directly.md){.internal-link target=_blank}.
-{* ../../docs_src/response_model/tutorial003_02_py39.py hl[8,10:11] *}
+{* ../../docs_src/response_model/tutorial003_02_py310.py hl[8,10:11] *}
Цей простий випадок автоматично обробляється FastAPI, тому що анотація типу повернення — це клас (або підклас) `Response`.
@@ -193,7 +193,7 @@ FastAPI виконує кілька внутрішніх операцій з Pyd
Ви також можете використати підклас `Response` в анотації типу:
-{* ../../docs_src/response_model/tutorial003_03_py39.py hl[8:9] *}
+{* ../../docs_src/response_model/tutorial003_03_py310.py hl[8:9] *}
Це теж працюватиме, бо `RedirectResponse` — підклас `Response`, і FastAPI автоматично обробить цей простий випадок.
@@ -201,7 +201,7 @@ FastAPI виконує кілька внутрішніх операцій з Pyd
Але коли ви повертаєте якийсь інший довільний об’єкт, що не є валідним типом Pydantic (наприклад, об’єкт бази даних), і анотуєте його так у функції, FastAPI спробує створити модель відповіді Pydantic на основі цієї анотації типу і це завершиться помилкою.
-Те саме станеться, якщо ви використаєте
union між різними типами, де один або більше не є валідними типами Pydantic, наприклад, це завершиться помилкою 💥:
+Те саме станеться, якщо у вас буде
об'єднання між різними типами, де один або більше не є валідними типами Pydantic, наприклад, це завершиться помилкою 💥:
{* ../../docs_src/response_model/tutorial003_04_py310.py hl[8] *}
diff --git a/docs/uk/docs/tutorial/response-status-code.md b/docs/uk/docs/tutorial/response-status-code.md
index 5a08ee46b5..c9ceb8f508 100644
--- a/docs/uk/docs/tutorial/response-status-code.md
+++ b/docs/uk/docs/tutorial/response-status-code.md
@@ -8,7 +8,7 @@
* `@app.delete()`
* тощо.
-{* ../../docs_src/response_status_code/tutorial001_py39.py hl[6] *}
+{* ../../docs_src/response_status_code/tutorial001_py310.py hl[6] *}
/// note | Примітка
@@ -66,7 +66,7 @@ FastAPI знає про це і створить документацію OpenAP
/// tip | Порада
-Щоб дізнатися більше про кожен код статусу і для чого призначений кожен із них, перегляньте документацію
MDN про HTTP коди статусу.
+Щоб дізнатися більше про кожен код статусу і для чого призначений кожен із них, перегляньте документацію
MDN про HTTP коди статусу.
///
@@ -74,7 +74,7 @@ FastAPI знає про це і створить документацію OpenAP
Розглянемо попередній приклад ще раз:
-{* ../../docs_src/response_status_code/tutorial001_py39.py hl[6] *}
+{* ../../docs_src/response_status_code/tutorial001_py310.py hl[6] *}
`201` — це код статусу для «Created».
@@ -82,7 +82,7 @@ FastAPI знає про це і створить документацію OpenAP
Ви можете використовувати зручні змінні з `fastapi.status`.
-{* ../../docs_src/response_status_code/tutorial002_py39.py hl[1,6] *}
+{* ../../docs_src/response_status_code/tutorial002_py310.py hl[1,6] *}
Вони — просто для зручності, містять те саме число, але так ви можете скористатися автозаповненням редактора, щоб знайти їх:
diff --git a/docs/uk/docs/tutorial/schema-extra-example.md b/docs/uk/docs/tutorial/schema-extra-example.md
index 54608c2ab1..38ce0eb303 100644
--- a/docs/uk/docs/tutorial/schema-extra-example.md
+++ b/docs/uk/docs/tutorial/schema-extra-example.md
@@ -40,7 +40,7 @@ OpenAPI 3.1.0 (який використовується починаючи з F
{* ../../docs_src/schema_extra_example/tutorial002_py310.py hl[2,8:11] *}
-## `examples` у JSON-схемі — OpenAPI { #examples-in-json-schema-openapi }
+## `examples` у JSON-схемі - OpenAPI { #examples-in-json-schema-openapi }
При використанні будь-кого з наступного:
@@ -74,7 +74,7 @@ OpenAPI 3.1.0 (який використовується починаючи з F
Коли Ви це робите, приклади будуть частиною внутрішньої **JSON-схеми** для цих даних тіла.
-Втім, на момент написання цього (
час написання цього), Swagger UI — інструмент, який відповідає за відображення UI документації — не підтримує показ кількох прикладів для даних у **JSON-схемі**. Але нижче можна прочитати про обхідний шлях.
+Втім, на
час написання цього, Swagger UI — інструмент, який відповідає за відображення UI документації — не підтримує показ кількох прикладів для даних у **JSON-схемі**. Але нижче можна прочитати про обхідний шлях.
### Специфічні для OpenAPI `examples` { #openapi-specific-examples }
diff --git a/docs/uk/docs/tutorial/security/first-steps.md b/docs/uk/docs/tutorial/security/first-steps.md
new file mode 100644
index 0000000000..491328d865
--- /dev/null
+++ b/docs/uk/docs/tutorial/security/first-steps.md
@@ -0,0 +1,203 @@
+# Безпека - перші кроки { #security-first-steps }
+
+Уявімо, що ваш **backend** API працює на певному домені.
+
+А **frontend** - на іншому домені або в іншому шляху того ж домену (або у мобільному застосунку).
+
+І ви хочете, щоб frontend міг автентифікуватися в backend, використовуючи ім'я користувача та пароль.
+
+Ми можемо використати **OAuth2**, щоб збудувати це з **FastAPI**.
+
+Але заощадимо вам час на читання всієї довгої специфікації, щоб знайти лише потрібні дрібниці.
+
+Скористаймося інструментами, які надає **FastAPI**, щоб обробляти безпеку.
+
+## Як це виглядає { #how-it-looks }
+
+Спочатку просто запустімо код і подивімося, як він працює, а потім повернемося, щоб розібратися, що відбувається.
+
+## Створіть `main.py` { #create-main-py }
+
+Скопіюйте приклад у файл `main.py`:
+
+{* ../../docs_src/security/tutorial001_an_py310.py *}
+
+## Запустіть { #run-it }
+
+/// info | Інформація
+
+Пакет
`python-multipart` автоматично встановлюється з **FastAPI**, коли ви виконуєте команду `pip install "fastapi[standard]"`.
+
+Однак, якщо ви використовуєте команду `pip install fastapi`, пакет `python-multipart` за замовчуванням не включено.
+
+Щоб встановити його вручну, переконайтеся, що ви створили [віртуальне оточення](../../virtual-environments.md){.internal-link target=_blank}, активували його, а потім встановили:
+
+```console
+$ pip install python-multipart
+```
+
+Це тому, що **OAuth2** використовує «form data» для надсилання `username` та `password`.
+
+///
+
+Запустіть приклад:
+
+
+
+```console
+$ fastapi dev main.py
+
+INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
+```
+
+
+
+## Перевірте { #check-it }
+
+Перейдіть до інтерактивної документації:
http://127.0.0.1:8000/docs.
+
+Ви побачите щось подібне:
+
+

+
+/// check | Кнопка Authorize!
+
+У вас уже є нова блискуча кнопка «Authorize».
+
+А ваша *операція шляху* має маленький замок у правому верхньому куті, на який можна натиснути.
+
+///
+
+Якщо натиснути її, з’явиться маленька форма авторизації, щоб ввести `username` і `password` (та інші необов’язкові поля):
+
+

+
+/// note | Примітка
+
+Неважливо, що ви введете у форму, поки що це не спрацює. Але ми скоро це доробимо.
+
+///
+
+Звісно, це не frontend для кінцевих користувачів, але це чудовий інструмент для інтерактивної документації всього вашого API.
+
+Ним може користуватися команда frontend (якою можете бути і ви самі).
+
+Ним можуть користуватися сторонні застосунки та системи.
+
+І ним також можете користуватися ви самі, щоб налагоджувати, перевіряти та тестувати той самий застосунок.
+
+## Потік паролю { #the-password-flow }
+
+Тепер повернімося трохи назад і розберімося, що це все таке.
+
+`password` «flow» - це один зі способів («flows»), визначених в OAuth2, для обробки безпеки та автентифікації.
+
+OAuth2 був спроєктований так, щоб backend або API могли бути незалежними від сервера, який автентифікує користувача.
+
+Але в нашому випадку той самий застосунок **FastAPI** оброблятиме і API, і автентифікацію.
+
+Тож розгляньмо це у спрощеному вигляді:
+
+- Користувач вводить `username` і `password` у frontend і натискає `Enter`.
+- Frontend (у браузері користувача) надсилає ці `username` і `password` на специфічну URL-адресу нашого API (оголошену як `tokenUrl="token"`).
+- API перевіряє ці `username` і `password` та повертає «токен» (ми ще нічого з цього не реалізували).
+ - «Токен» - це просто строка з деяким вмістом, який ми можемо пізніше використати, щоб перевірити цього користувача.
+ - Зазвичай токен налаштований на завершення строку дії через певний час.
+ - Тож користувачу доведеться знову увійти пізніше.
+ - І якщо токен викрадуть, ризик менший. Це не як постійний ключ, який працюватиме завжди (у більшості випадків).
+- Frontend тимчасово зберігає цей токен десь.
+- Користувач клікає у frontend, щоб перейти до іншого розділу вебзастосунку.
+- Frontend має отримати ще дані з API.
+ - Але для того конкретного кінцевого пункту потрібна автентифікація.
+ - Тож, щоб автентифікуватися в нашому API, він надсилає заголовок `Authorization` зі значенням `Bearer ` плюс токен.
+ - Якщо токен містить `foobar`, вміст заголовка `Authorization` буде: `Bearer foobar`.
+
+## `OAuth2PasswordBearer` у **FastAPI** { #fastapis-oauth2passwordbearer }
+
+**FastAPI** надає кілька інструментів на різних рівнях абстракції, щоб реалізувати ці функції безпеки.
+
+У цьому прикладі ми використаємо **OAuth2** з потоком **Password**, використовуючи токен **Bearer**. Це робиться за допомогою класу `OAuth2PasswordBearer`.
+
+/// info | Інформація
+
+«Bearer»-токен - не єдиний варіант.
+
+Але це найкращий для нашого сценарію.
+
+І, можливо, найкращий для більшості сценаріїв, якщо ви не експерт з OAuth2 і точно не знаєте, чому інша опція краще відповідає вашим потребам.
+
+У такому разі **FastAPI** теж надає інструменти, щоб це збудувати.
+
+///
+
+Коли ми створюємо екземпляр класу `OAuth2PasswordBearer`, ми передаємо параметр `tokenUrl`. Цей параметр містить URL, який клієнт (frontend у браузері користувача) використовуватиме, щоб надіслати `username` і `password` для отримання токена.
+
+{* ../../docs_src/security/tutorial001_an_py310.py hl[8] *}
+
+/// tip | Порада
+
+Тут `tokenUrl="token"` відноситься до відносної URL-адреси `token`, яку ми ще не створили. Оскільки це відносна URL-адреса, вона еквівалентна `./token`.
+
+Тому, якщо ваш API розміщений на `https://example.com/`, це буде `https://example.com/token`. А якщо на `https://example.com/api/v1/`, тоді це буде `https://example.com/api/v1/token`.
+
+Використання відносної URL-адреси важливе, щоб ваша програма продовжувала працювати навіть у просунутому сценарії, як-от [Behind a Proxy](../../advanced/behind-a-proxy.md){.internal-link target=_blank}.
+
+///
+
+Цей параметр не створює той endpoint / *операцію шляху*, а декларує, що URL `/token` буде тим, який клієнт має використовувати, щоб отримати токен. Ця інформація використовується в OpenAPI, а потім - у системах інтерактивної документації API.
+
+Незабаром ми також створимо фактичну операцію шляху.
+
+/// info | Інформація
+
+Якщо ви дуже строгий «Pythonista», вам може не подобатися стиль імені параметра `tokenUrl` замість `token_url`.
+
+Це тому, що використано ту саму назву, що і в специфікації OpenAPI. Тож якщо вам потрібно буде дослідити ці схеми безпеки глибше, ви зможете просто скопіювати та вставити її, щоб знайти більше інформації.
+
+///
+
+Змінна `oauth2_scheme` - це екземпляр `OAuth2PasswordBearer`, але це також і «викликаємий» об’єкт.
+
+Його можна викликати так:
+
+```Python
+oauth2_scheme(some, parameters)
+```
+
+Тож його можна використовувати з `Depends`.
+
+### Використання { #use-it }
+
+Тепер ви можете передати `oauth2_scheme` як залежність через `Depends`.
+
+{* ../../docs_src/security/tutorial001_an_py310.py hl[12] *}
+
+Ця залежність надасть `str`, який буде присвоєний параметру `token` *функції операції шляху*.
+
+**FastAPI** знатиме, що може використати цю залежність, щоб визначити «схему безпеки» в схемі OpenAPI (і в автоматичній документації API).
+
+/// info | Технічні деталі
+
+**FastAPI** знатиме, що може використати клас `OAuth2PasswordBearer` (оголошений у залежності), щоб визначити схему безпеки в OpenAPI, тому що він наслідує `fastapi.security.oauth2.OAuth2`, який своєю чергою наслідує `fastapi.security.base.SecurityBase`.
+
+Усі утиліти безпеки, які інтегруються з OpenAPI (і автоматичною документацією API), наслідують `SecurityBase`. Так **FastAPI** розуміє, як інтегрувати їх в OpenAPI.
+
+///
+
+## Що відбувається { #what-it-does }
+
+Вона шукатиме в запиті заголовок `Authorization`, перевірить, чи його значення - це `Bearer ` плюс деякий токен, і поверне токен як `str`.
+
+Якщо заголовка `Authorization` немає або значення не містить токена `Bearer `, вона одразу відповість помилкою зі статус-кодом 401 (`UNAUTHORIZED`).
+
+Вам навіть не потрібно перевіряти, чи існує токен, щоб повернути помилку. Ви можете бути певні: якщо ваша функція виконується, у параметрі токена буде `str`.
+
+Ви вже можете спробувати це в інтерактивній документації:
+
+

+
+Ми ще не перевіряємо дійсність токена, але це вже початок.
+
+## Підсумок { #recap }
+
+Отже, лише 3-4 додатковими рядками ви вже маєте деяку примітивну форму безпеки.
diff --git a/docs/uk/docs/tutorial/security/get-current-user.md b/docs/uk/docs/tutorial/security/get-current-user.md
new file mode 100644
index 0000000000..2371ad9fc0
--- /dev/null
+++ b/docs/uk/docs/tutorial/security/get-current-user.md
@@ -0,0 +1,105 @@
+# Отримати поточного користувача { #get-current-user }
+
+У попередньому розділі система безпеки (яка базується на системі впровадження залежностей) передавала функції операції шляху `token` як `str`:
+
+{* ../../docs_src/security/tutorial001_an_py310.py hl[12] *}
+
+Але це ще не дуже корисно.
+
+Зробімо так, щоб вона повертала поточного користувача.
+
+## Створити модель користувача { #create-a-user-model }
+
+Спочатку створімо модель користувача в Pydantic.
+
+Так само, як ми використовуємо Pydantic для оголошення тіл, ми можемо використовувати його будь-де:
+
+{* ../../docs_src/security/tutorial002_an_py310.py hl[5,12:6] *}
+
+## Створити залежність `get_current_user` { #create-a-get-current-user-dependency }
+
+Створімо залежність `get_current_user`.
+
+Пам'ятаєте, що залежності можуть мати підзалежності?
+
+`get_current_user` матиме залежність із тим самим `oauth2_scheme`, який ми створили раніше.
+
+Так само, як ми робили раніше безпосередньо в операції шляху, наша нова залежність `get_current_user` отримає `token` як `str` від підзалежності `oauth2_scheme`:
+
+{* ../../docs_src/security/tutorial002_an_py310.py hl[25] *}
+
+## Отримати користувача { #get-the-user }
+
+`get_current_user` використає (фальшиву) утилітну функцію, яку ми створили, що приймає `token` як `str` і повертає нашу Pydantic-модель `User`:
+
+{* ../../docs_src/security/tutorial002_an_py310.py hl[19:22,26:27] *}
+
+## Впровадити поточного користувача { #inject-the-current-user }
+
+Тепер ми можемо використати той самий `Depends` з нашим `get_current_user` в операції шляху:
+
+{* ../../docs_src/security/tutorial002_an_py310.py hl[31] *}
+
+Зверніть увагу, що ми оголошуємо тип `current_user` як Pydantic-модель `User`.
+
+Це допоможе всередині функції з автодоповненням і перевірками типів.
+
+/// tip | Порада
+
+Можливо, ви пам'ятаєте, що тіла запиту також оголошуються моделями Pydantic.
+
+Тут **FastAPI** не заплутається, тому що ви використовуєте `Depends`.
+
+///
+
+/// check | Перевірте
+
+Те, як спроєктована ця система залежностей, дозволяє мати різні залежності (різні «залежні»), які всі повертають модель `User`.
+
+Ми не обмежені наявністю лише однієї залежності, що може повертати такі дані.
+
+///
+
+## Інші моделі { #other-models }
+
+Тепер ви можете отримувати поточного користувача безпосередньо у функціях операцій шляху та працювати з механізмами безпеки на рівні **впровадження залежностей**, використовуючи `Depends`.
+
+І ви можете використовувати будь-яку модель або дані для вимог безпеки (у цьому випадку Pydantic-модель `User`).
+
+Але ви не обмежені використанням якоїсь конкретної модели даних, класу чи типу.
+
+Хочете мати id та email і не мати жодного username у вашій моделі? Без проблем. Ви можете використовувати ті самі інструменти.
+
+Хочете мати просто `str`? Або лише `dict`? Або безпосередньо екземпляр класу моделі бази даних? Усе працює так само.
+
+У вашій програмі насправді входять не користувачі, а роботи, боти чи інші системи, що мають лише токен доступу? Знову ж, усе працює так само.
+
+Просто використовуйте будь-який тип моделі, будь-який клас, будь-яку базу даних, які потрібні вашій програмі. **FastAPI** подбає про це завдяки системі впровадження залежностей.
+
+## Розмір коду { #code-size }
+
+Цей приклад може здаватися багатослівним. Майте на увазі, що ми змішуємо безпеку, моделі даних, утилітні функції та операції шляху в одному файлі.
+
+Але ось ключовий момент.
+
+Речі, пов'язані з безпекою та впровадженням залежностей, пишуться один раз.
+
+І ви можете зробити це настільки складним, наскільки потрібно. І все одно мати це написаним лише один раз, в одному місці. З усією гнучкістю.
+
+Зате ви можете мати тисячі кінцевих точок (операцій шляху), що використовують одну й ту саму систему безпеки.
+
+І всі вони (або будь-яка їхня частина, яку ви захочете) можуть скористатися повторним використанням цих залежностей або будь-яких інших, які ви створите.
+
+І всі ці тисячі операцій шляху можуть бути всього у 3 рядки:
+
+{* ../../docs_src/security/tutorial002_an_py310.py hl[30:32] *}
+
+## Підсумок { #recap }
+
+Тепер ви можете отримувати поточного користувача безпосередньо у вашій функції операції шляху.
+
+Ми вже на півдорозі.
+
+Потрібно лише додати операцію шляху, щоб користувач/клієнт міг фактично надіслати `username` і `password`.
+
+Далі саме це.
diff --git a/docs/uk/docs/tutorial/security/index.md b/docs/uk/docs/tutorial/security/index.md
index f1fb25178d..de09c728bc 100644
--- a/docs/uk/docs/tutorial/security/index.md
+++ b/docs/uk/docs/tutorial/security/index.md
@@ -73,11 +73,11 @@ OpenAPI визначає такі схеми безпеки:
* `apiKey`: специфічний для застосунку ключ, який може передаватися через:
* Параметр запиту.
* Заголовок.
- * Cookie.
+ * Кукі.
* `http`: стандартні системи HTTP-автентифікації, включаючи:
* `bearer`: заголовок `Authorization` зі значенням `Bearer ` та токеном. Це успадковано з OAuth2.
- * HTTP Basic автентифікацію.
- * HTTP Digest тощо.
+ * базову автентифікацію HTTP.
+ * HTTP дайджест тощо.
* `oauth2`: усі способи обробки безпеки за допомогою OAuth2 (так звані «потоки»).
* Декілька з цих потоків підходять для створення провайдера автентифікації OAuth 2.0 (наприклад, Google, Facebook, X (Twitter), GitHub тощо):
* `implicit`
diff --git a/docs/uk/docs/tutorial/security/oauth2-jwt.md b/docs/uk/docs/tutorial/security/oauth2-jwt.md
new file mode 100644
index 0000000000..f94abb897b
--- /dev/null
+++ b/docs/uk/docs/tutorial/security/oauth2-jwt.md
@@ -0,0 +1,277 @@
+# OAuth2 з паролем (і хешуванням), Bearer з токенами JWT { #oauth2-with-password-and-hashing-bearer-with-jwt-tokens }
+
+Тепер, коли ми маємо весь потік безпеки, зробімо застосунок справді захищеним, використовуючи токени
JWT і безпечне хешування паролів.
+
+Цей код ви можете реально використовувати у своєму застосунку, зберігати хеші паролів у своїй базі даних тощо.
+
+Ми почнемо з того місця, де зупинилися в попередньому розділі, і розширимо його.
+
+## Про JWT { #about-jwt }
+
+JWT означає «JSON Web Tokens».
+
+Це стандарт кодування об'єкта JSON у довгий щільний рядок без пробілів. Він виглядає так:
+
+```
+eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
+```
+
+Він не зашифрований, тому кожен може відновити інформацію з вмісту.
+
+Але він підписаний. Тож коли ви отримуєте токен, який ви видали, ви можете перевірити, що справді його видали ви.
+
+Таким чином, ви можете створити токен із терміном дії, наприклад, 1 тиждень. І коли користувач повернеться наступного дня з токеном, ви знатимете, що користувач досі увійшов у вашу систему.
+
+Через тиждень токен завершить термін дії, і користувач не буде авторизований та має знову увійти, щоб отримати новий токен. І якщо користувач (або третя сторона) намагатиметься змінити токен, щоб змінити термін дії, ви це виявите, бо підписи не співпадатимуть.
+
+Якщо хочете «погратися» з токенами JWT і побачити, як вони працюють, перегляньте
https://jwt.io.
+
+## Встановіть `PyJWT` { #install-pyjwt }
+
+Нам потрібно встановити `PyJWT`, щоб створювати та перевіряти токени JWT у Python.
+
+Переконайтеся, що ви створили [віртуальне оточення](../../virtual-environments.md){.internal-link target=_blank}, активували його і тоді встановіть `pyjwt`:
+
+
+
+```console
+$ pip install pyjwt
+
+---> 100%
+```
+
+
+
+/// info | Інформація
+
+Якщо ви плануєте використовувати алгоритми цифрового підпису на кшталт RSA або ECDSA, слід встановити залежність криптобібліотеки `pyjwt[crypto]`.
+
+Докладніше про це можна прочитати у
документації з встановлення PyJWT.
+
+///
+
+## Хешування паролів { #password-hashing }
+
+«Хешування» означає перетворення деякого вмісту (у цьому випадку пароля) на послідовність байтів (просто строку), що виглядає як нісенітниця.
+
+Кожного разу, коли ви передаєте точно той самий вміст (точно той самий пароль), ви отримуєте точно ту саму «нісенітницю».
+
+Але не можна перетворити цю «нісенітницю» назад у пароль.
+
+### Навіщо використовувати хешування паролів { #why-use-password-hashing }
+
+Якщо вашу базу даних вкрадуть, зловмисник не матиме відкритих паролів ваших користувачів, а лише хеші.
+
+Тож зловмисник не зможе спробувати використати цей пароль в іншій системі (оскільки багато користувачів використовують той самий пароль всюди, це було б небезпечно).
+
+## Встановіть `pwdlib` { #install-pwdlib }
+
+pwdlib - це чудовий пакет Python для роботи з хешами паролів.
+
+Він підтримує багато безпечних алгоритмів хешування та утиліт для роботи з ними.
+
+Рекомендований алгоритм - «Argon2».
+
+Переконайтеся, що ви створили [віртуальне оточення](../../virtual-environments.md){.internal-link target=_blank}, активували його і тоді встановіть pwdlib з Argon2:
+
+
+
+```console
+$ pip install "pwdlib[argon2]"
+
+---> 100%
+```
+
+
+
+/// tip | Порада
+
+З `pwdlib` ви навіть можете налаштувати його так, щоб він умів читати паролі, створені **Django**, плагіном безпеки **Flask** або багатьма іншими.
+
+Тож ви зможете, наприклад, спільно використовувати ті самі дані з застосунку Django в базі даних із застосунком FastAPI. Або поступово мігрувати застосунок Django, використовуючи ту саму базу даних.
+
+І ваші користувачі зможуть входити як із вашого застосунку Django, так і з вашого застосунку **FastAPI** одночасно.
+
+///
+
+## Хешування і перевірка паролів { #hash-and-verify-the-passwords }
+
+Імпортуйте потрібні інструменти з `pwdlib`.
+
+Створіть екземпляр PasswordHash з рекомендованими налаштуваннями - він буде використаний для хешування та перевірки паролів.
+
+/// tip | Порада
+
+pwdlib також підтримує алгоритм хешування bcrypt, але не включає застарілі алгоритми - для роботи із застарілими хешами рекомендується використовувати бібліотеку passlib.
+
+Наприклад, ви можете використати її для читання і перевірки паролів, згенерованих іншою системою (наприклад, Django), але хешувати будь-які нові паролі іншим алгоритмом, таким як Argon2 або Bcrypt.
+
+І бути сумісними з усіма ними одночасно.
+
+///
+
+Створіть утилітарну функцію для хешування пароля, що надходить від користувача.
+
+І ще одну утиліту для перевірки, чи отриманий пароль відповідає збереженому хешу.
+
+І ще одну - для автентифікації та повернення користувача.
+
+{* ../../docs_src/security/tutorial004_an_py310.py hl[8,49,51,58:59,62:63,72:79] *}
+
+Коли `authenticate_user` викликається з ім'ям користувача, якого немає в базі даних, ми все одно запускаємо `verify_password` для «підставного» хешу.
+
+Це забезпечує приблизно однаковий час відповіді кінцевої точки незалежно від того, чи є ім'я користувача дійсним, запобігаючи **атакам за часом**, які могли б бути використані для перелічення наявних імен користувачів.
+
+/// note | Примітка
+
+Якщо ви перевірите нову (фальшиву) базу даних `fake_users_db`, побачите, як зараз виглядає хеш пароля: `"$argon2id$v=19$m=65536,t=3,p=4$wagCPXjifgvUFBzq4hqe3w$CYaIb8sB+wtD+Vu/P4uod1+Qof8h+1g7bbDlBID48Rc"`.
+
+///
+
+## Опрацювання токенів JWT { #handle-jwt-tokens }
+
+Імпортуйте встановлені модулі.
+
+Створіть випадковий секретний ключ, який буде використано для підписання токенів JWT.
+
+Щоб згенерувати безпечний випадковий секретний ключ, використайте команду:
+
+
+
+```console
+$ openssl rand -hex 32
+
+09d25e094faa6ca2556c818166b7a9563b93f7099f6f0f4caa6cf63b88e8d3e7
+```
+
+
+
+І скопіюйте вивід у змінну `SECRET_KEY` (не використовуйте той, що в прикладі).
+
+Створіть змінну `ALGORITHM` з алгоритмом для підписання токена JWT і встановіть її в `"HS256"`.
+
+Створіть змінну для терміну дії токена.
+
+Визначте модель Pydantic, яка буде використана в кінцевій точці токена для відповіді.
+
+Створіть утилітарну функцію для генерації нового токена доступу.
+
+{* ../../docs_src/security/tutorial004_an_py310.py hl[4,7,13:15,29:31,82:90] *}
+
+## Оновіть залежності { #update-the-dependencies }
+
+Оновіть `get_current_user`, щоб отримувати той самий токен, що й раніше, але цього разу - токен JWT.
+
+Декодуйте отриманий токен, перевірте його та поверніть поточного користувача.
+
+Якщо токен недійсний, одразу поверніть помилку HTTP.
+
+{* ../../docs_src/security/tutorial004_an_py310.py hl[93:110] *}
+
+## Оновіть операцію шляху `/token` { #update-the-token-path-operation }
+
+Створіть `timedelta` з часом життя токена.
+
+Створіть справжній токен доступу JWT і поверніть його.
+
+{* ../../docs_src/security/tutorial004_an_py310.py hl[121:136] *}
+
+### Технічні деталі про «subject» `sub` у JWT { #technical-details-about-the-jwt-subject-sub }
+
+Специфікація JWT каже, що існує ключ `sub` із суб'єктом токена.
+
+Використовувати його не обов'язково, але саме туди зазвичай поміщають ідентифікатор користувача, тож ми використовуємо його тут.
+
+JWT може використовуватися й для інших речей, окрім ідентифікації користувача та надання йому можливості безпосередньо виконувати операції з вашою API.
+
+Наприклад, ви можете ідентифікувати «автомобіль» або «допис у блозі».
+
+Тоді ви можете додати дозволи щодо цієї сутності, як-от «керувати» (для автомобіля) або «редагувати» (для допису).
+
+І потім ви можете видати цей токен JWT користувачу (або боту), і він зможе виконувати ці дії (керувати автомобілем або редагувати допис), навіть не маючи облікового запису - лише з токеном JWT, який ваша API для цього згенерувала.
+
+Використовуючи ці ідеї, JWT можна застосовувати у значно складніших сценаріях.
+
+У таких випадках кілька сутностей можуть мати однакові ідентифікатори, скажімо `foo` (користувач `foo`, автомобіль `foo` і допис `foo`).
+
+Щоб уникнути колізій ідентифікаторів, під час створення токена JWT для користувача ви можете додати префікс до значення ключа `sub`, наприклад `username:`. Отже, у цьому прикладі значення `sub` могло б бути: `username:johndoe`.
+
+Важливо пам'ятати, що ключ `sub` має містити унікальний ідентифікатор у межах усього застосунку і має бути строкою.
+
+## Перевірте { #check-it }
+
+Запустіть сервер і перейдіть до документації:
http://127.0.0.1:8000/docs.
+
+Ви побачите такий інтерфейс користувача:
+
+

+
+Авторизуйте застосунок так само, як раніше.
+
+Використайте облікові дані:
+
+Username: `johndoe`
+Password: `secret`
+
+/// check | Перевірте
+
+Зверніть увагу, що ніде в коді немає відкритого пароля "`secret`", ми маємо лише хешовану версію.
+
+///
+
+

+
+Викличте кінцеву точку `/users/me/`, ви отримаєте відповідь:
+
+```JSON
+{
+ "username": "johndoe",
+ "email": "johndoe@example.com",
+ "full_name": "John Doe",
+ "disabled": false
+}
+```
+
+

+
+Якщо відкриєте інструменти розробника, ви побачите, що у відправлених даних є лише токен, пароль надсилається тільки в першому запиті для автентифікації користувача та отримання токена доступу, але не надсилається далі:
+
+

+
+/// note | Примітка
+
+Зверніть увагу на заголовок `Authorization` зі значенням, що починається з `Bearer `.
+
+///
+
+## Просунуте використання зі `scopes` { #advanced-usage-with-scopes }
+
+OAuth2 має поняття «scopes».
+
+Ви можете використовувати їх, щоб додати конкретний набір дозволів до токена JWT.
+
+Потім ви можете видати цей токен користувачу напряму або третій стороні для взаємодії з вашою API із набором обмежень.
+
+Ви можете дізнатися, як їх використовувати і як вони інтегровані з **FastAPI** пізніше у **просунутому посібнику користувача**.
+
+## Підсумок { #recap }
+
+Маючи все, що ви бачили досі, ви можете налаштувати захищений застосунок **FastAPI**, використовуючи стандарти на кшталт OAuth2 і JWT.
+
+Майже в будь-якому фреймворку опрацювання безпеки дуже швидко стає досить складною темою.
+
+Багато пакетів, що сильно це спрощують, змушені йти на численні компроміси з моделлю даних, базою даних і доступними можливостями. Дехто з цих пакетів, які надто все спрощують, насправді мають приховані вади безпеки.
+
+---
+
+**FastAPI** не йде на жодні компроміси з будь-якою базою даних, моделлю даних чи інструментом.
+
+Він дає вам усю гнучкість, щоб обрати ті, які найкраще підходять вашому проєкту.
+
+І ви можете напряму використовувати добре підтримувані та широко застосовувані пакети на кшталт `pwdlib` і `PyJWT`, адже **FastAPI** не вимагає жодних складних механізмів для інтеграції зовнішніх пакетів.
+
+Водночас він надає інструменти, щоб максимально спростити процес без компромісів у гнучкості, надійності чи безпеці.
+
+І ви можете використовувати та впроваджувати безпечні стандартні протоколи, як-от OAuth2, відносно простим способом.
+
+У **просунутому посібнику користувача** ви можете дізнатися більше про те, як використовувати «scopes» в OAuth2 для більш детальної системи дозволів, дотримуючись тих самих стандартів. OAuth2 зі scopes - це механізм, який використовують багато великих провайдерів автентифікації, як-от Facebook, Google, GitHub, Microsoft, X (Twitter) тощо, щоб авторизувати сторонні застосунки на взаємодію з їхніми API від імені користувачів.
diff --git a/docs/uk/docs/tutorial/security/simple-oauth2.md b/docs/uk/docs/tutorial/security/simple-oauth2.md
new file mode 100644
index 0000000000..05f949738d
--- /dev/null
+++ b/docs/uk/docs/tutorial/security/simple-oauth2.md
@@ -0,0 +1,289 @@
+# Простий OAuth2 з паролем і Bearer { #simple-oauth2-with-password-and-bearer }
+
+Тепер продовжимо з попереднього розділу і додамо відсутні частини, щоб отримати повний потік безпеки.
+
+## Отримайте `username` і `password` { #get-the-username-and-password }
+
+Ми використаємо утиліти безпеки **FastAPI**, щоб отримати `username` і `password`.
+
+OAuth2 визначає, що під час використання «потоку паролю» (який ми використовуємо) клієнт/користувач має надіслати поля `username` і `password` як дані форми.
+
+І специфікація каже, що поля мають називатися саме так. Тому `user-name` або `email` не підійдуть.
+
+Але не хвилюйтеся, у фронтенді ви можете відображати це так, як забажаєте, для кінцевих користувачів.
+
+І ваші моделі бази даних можуть використовувати будь-які інші назви.
+
+Але для *операції шляху* входу ми маємо використовувати саме ці назви, щоб бути сумісними зі специфікацією (і мати змогу, наприклад, користуватися вбудованою системою документації API).
+
+Специфікація також вказує, що `username` і `password` мають надсилатися як дані форми (тобто без JSON).
+
+### `scope` { #scope }
+
+Специфікація також каже, що клієнт може надіслати інше поле форми «`scope`».
+
+Назва поля форми — `scope` (в однині), але насправді це довга строка зі «scopes», розділеними пробілами.
+
+Кожен «scope» — це просто строка (без пробілів).
+
+Їх зазвичай використовують для оголошення конкретних прав доступу, наприклад:
+
+- `users:read` або `users:write` — поширені приклади.
+- `instagram_basic` використовується Facebook / Instagram.
+- `https://www.googleapis.com/auth/drive` використовується Google.
+
+/// info | Інформація
+
+У OAuth2 «scope» — це просто строка, що оголошує конкретний потрібний дозвіл.
+
+Не має значення, чи містить вона інші символи на кшталт `:` або чи це URL.
+
+Ці деталі залежать від реалізації.
+
+Для OAuth2 це просто строки.
+
+///
+
+## Код для отримання `username` і `password` { #code-to-get-the-username-and-password }
+
+Тепер скористаймося утилітами, наданими **FastAPI**, щоб обробити це.
+
+### `OAuth2PasswordRequestForm` { #oauth2passwordrequestform }
+
+Спочатку імпортуйте `OAuth2PasswordRequestForm` і використайте його як залежність із `Depends` в *операції шляху* для `/token`:
+
+{* ../../docs_src/security/tutorial003_an_py310.py hl[4,78] *}
+
+`OAuth2PasswordRequestForm` — це клас залежності, що оголошує тіло форми з:
+
+- `username`.
+- `password`.
+- Необов'язковим полем `scope` як великою строкою, складеною зі строк, розділених пробілами.
+- Необов'язковим `grant_type`.
+
+/// tip | Порада
+
+Специфікація OAuth2 насправді вимагає поле `grant_type` із фіксованим значенням `password`, але `OAuth2PasswordRequestForm` цього не примушує.
+
+Якщо вам потрібно це примусити, використовуйте `OAuth2PasswordRequestFormStrict` замість `OAuth2PasswordRequestForm`.
+
+///
+
+- Необов'язковим `client_id` (для нашого прикладу не потрібно).
+- Необов'язковим `client_secret` (для нашого прикладу не потрібно).
+
+/// info | Інформація
+
+`OAuth2PasswordRequestForm` — не спеціальний клас для **FastAPI**, як `OAuth2PasswordBearer`.
+
+`OAuth2PasswordBearer` робить так, що **FastAPI** знає, що це схема безпеки. Тому її додають таким чином до OpenAPI.
+
+Але `OAuth2PasswordRequestForm` — це просто клас залежності, який ви могли б написати самі, або ви могли б напряму оголосити параметри `Form`.
+
+Оскільки це типова задача, **FastAPI** надає його безпосередньо, щоб спростити роботу.
+
+///
+
+### Використовуйте дані форми { #use-the-form-data }
+
+/// tip | Порада
+
+Екземпляр класу залежності `OAuth2PasswordRequestForm` не матиме атрибута `scope` з довгою строкою, розділеною пробілами, натомість він матиме атрибут `scopes` зі справжнім списком строк для кожного надісланого scope.
+
+У цьому прикладі ми не використовуємо `scopes`, але ця можливість є, якщо знадобиться.
+
+///
+
+Тепер отримайте дані користувача з (фальшивої) бази даних, використовуючи `username` з поля форми.
+
+Якщо такого користувача немає, повертаємо помилку «Incorrect username or password».
+
+Для помилки використовуємо виняток `HTTPException`:
+
+{* ../../docs_src/security/tutorial003_an_py310.py hl[3,79:81] *}
+
+### Перевірте пароль { #check-the-password }
+
+На цьому етапі ми маємо дані користувача з нашої бази даних, але ще не перевірили пароль.
+
+Спершу розмістимо ці дані в Pydantic-моделі `UserInDB`.
+
+Ви ніколи не повинні зберігати паролі у відкритому вигляді, тож ми використаємо (фальшиву) систему хешування паролів.
+
+Якщо паролі не збігаються, повертаємо ту саму помилку.
+
+#### Хешування паролів { #password-hashing }
+
+«Хешування» означає: перетворення деякого вмісту (у цьому випадку пароля) у послідовність байтів (просто строку), яка виглядає як нісенітниця.
+
+Кожного разу, коли ви передаєте точно той самий вміст (точно той самий пароль), ви отримуєте точно ту саму «нісенітницю».
+
+Але ви не можете перетворити цю «нісенітницю» назад у пароль.
+
+##### Навіщо використовувати хешування паролів { #why-use-password-hashing }
+
+Якщо вашу базу даних вкрадуть, зловмисник не матиме паролів користувачів у відкритому вигляді, лише хеші.
+
+Тож зловмисник не зможе спробувати використати ті самі паролі в іншій системі (оскільки багато користувачів використовують той самий пароль всюди, це було б небезпечно).
+
+{* ../../docs_src/security/tutorial003_an_py310.py hl[82:85] *}
+
+#### Про `**user_dict` { #about-user-dict }
+
+`UserInDB(**user_dict)` означає:
+
+Передати ключі та значення з `user_dict` безпосередньо як аргументи ключ-значення, еквівалентно до:
+
+```Python
+UserInDB(
+ username = user_dict["username"],
+ email = user_dict["email"],
+ full_name = user_dict["full_name"],
+ disabled = user_dict["disabled"],
+ hashed_password = user_dict["hashed_password"],
+)
+```
+
+/// info | Інформація
+
+Для повнішого пояснення `**user_dict` перегляньте [документацію для **Додаткових моделей**](../extra-models.md#about-user-in-dict){.internal-link target=_blank}.
+
+///
+
+## Поверніть токен { #return-the-token }
+
+Відповідь точки входу `token` має бути об'єктом JSON.
+
+Вона повинна містити `token_type`. У нашому випадку, оскільки ми використовуємо токени «Bearer», тип токена має бути «`bearer`».
+
+Також має бути `access_token` зі строкою, що містить наш токен доступу.
+
+Для цього простого прикладу ми зробимо повністю небезпечно і повернемо той самий `username` як токен.
+
+/// tip | Порада
+
+У наступному розділі ви побачите справді безпечну реалізацію з хешуванням паролів і токенами
JWT.
+
+А поки зосередьмося на конкретних деталях, які нам потрібні.
+
+///
+
+{* ../../docs_src/security/tutorial003_an_py310.py hl[87] *}
+
+/// tip | Порада
+
+Згідно зі специфікацією, ви маєте повертати JSON з `access_token` і `token_type`, як у цьому прикладі.
+
+Це те, що ви маєте зробити самостійно у своєму коді, і переконатися, що використовуєте саме ці ключі JSON.
+
+Це майже єдине, що ви маєте зробити правильно самі, щоб відповідати специфікації.
+
+Решту **FastAPI** зробить за вас.
+
+///
+
+## Оновіть залежності { #update-the-dependencies }
+
+Тепер оновимо наші залежності.
+
+Ми хочемо отримати `current_user` лише якщо цей користувач активний.
+
+Тому створимо додаткову залежність `get_current_active_user`, яка своєю чергою використовує як залежність `get_current_user`.
+
+Обидві ці залежності просто повернуть HTTP-помилку, якщо користувача не існує або він неактивний.
+
+Отже, у нашій кінцевій точці ми отримаємо користувача лише якщо він існує, був правильно автентифікований і є активним:
+
+{* ../../docs_src/security/tutorial003_an_py310.py hl[58:66,69:74,94] *}
+
+/// info | Інформація
+
+Додатковий заголовок `WWW-Authenticate` зі значенням `Bearer`, який ми тут повертаємо, також є частиною специфікації.
+
+Будь-який HTTP (помилка) зі статус-кодом 401 «UNAUTHORIZED» також має повертати заголовок `WWW-Authenticate`.
+
+У випадку токенів носія (наш випадок) значенням цього заголовка має бути `Bearer`.
+
+Фактично ви можете пропустити цей додатковий заголовок, і все одно працюватиме.
+
+Але він наданий тут, щоб відповідати специфікаціям.
+
+Також можуть існувати інструменти, які очікують і використовують його (зараз або в майбутньому), і це може бути корисно вам або вашим користувачам, зараз або в майбутньому.
+
+У цьому користь стандартів...
+
+///
+
+## Подивіться в дії { #see-it-in-action }
+
+Відкрийте інтерактивну документацію:
http://127.0.0.1:8000/docs.
+
+### Автентифікація { #authenticate }
+
+Натисніть кнопку «Authorize».
+
+Використайте облікові дані:
+
+Користувач: `johndoe`
+
+Пароль: `secret`
+
+

+
+Після автентифікації в системі ви побачите таке:
+
+

+
+### Отримайте власні дані користувача { #get-your-own-user-data }
+
+Тепер використайте операцію `GET` зі шляхом `/users/me`.
+
+Ви отримаєте дані свого користувача, наприклад:
+
+```JSON
+{
+ "username": "johndoe",
+ "email": "johndoe@example.com",
+ "full_name": "John Doe",
+ "disabled": false,
+ "hashed_password": "fakehashedsecret"
+}
+```
+
+

+
+Якщо натиснути значок замка й вийти з системи, а потім знову спробувати ту саму операцію, ви отримаєте помилку HTTP 401 такого вигляду:
+
+```JSON
+{
+ "detail": "Not authenticated"
+}
+```
+
+### Неактивний користувач { #inactive-user }
+
+Тепер спробуйте з неактивним користувачем, автентифікуйтеся з:
+
+Користувач: `alice`
+
+Пароль: `secret2`
+
+І спробуйте використати операцію `GET` зі шляхом `/users/me`.
+
+Ви отримаєте помилку «Inactive user», наприклад:
+
+```JSON
+{
+ "detail": "Inactive user"
+}
+```
+
+## Підсумок { #recap }
+
+Тепер у вас є інструменти для реалізації повної системи безпеки на основі `username` і `password` для вашого API.
+
+Використовуючи ці інструменти, ви можете зробити систему безпеки сумісною з будь-якою базою даних і з будь-якою моделлю користувача чи даних.
+
+Єдина відсутня деталь у тому, що наразі це ще не «безпечна» реалізація.
+
+У наступному розділі ви побачите, як використовувати безпечну бібліотеку для хешування паролів і токени
JWT.
diff --git a/docs/uk/docs/tutorial/sql-databases.md b/docs/uk/docs/tutorial/sql-databases.md
new file mode 100644
index 0000000000..991d1e33aa
--- /dev/null
+++ b/docs/uk/docs/tutorial/sql-databases.md
@@ -0,0 +1,357 @@
+# SQL (реляційні) бази даних { #sql-relational-databases }
+
+**FastAPI** не вимагає від вас використовувати SQL (реляційну) базу даних. Але ви можете скористатися будь-якою базою даних, яку забажаєте.
+
+Тут ми розглянемо приклад з
SQLModel.
+
+**SQLModel** побудовано поверх
SQLAlchemy та Pydantic. Її створив той самий автор, що і **FastAPI**, як ідеальну пару для застосунків FastAPI, яким потрібні **SQL бази даних**.
+
+/// tip | Порада
+
+Ви можете використовувати будь-яку іншу бібліотеку для SQL або NoSQL баз (інколи їх називають
"ORMs"), FastAPI нічого не нав’язує. 😎
+
+///
+
+Оскільки SQLModel базується на SQLAlchemy, ви можете легко використовувати будь-яку базу даних, яку підтримує SQLAlchemy (а отже й SQLModel), наприклад:
+
+* PostgreSQL
+* MySQL
+* SQLite
+* Oracle
+* Microsoft SQL Server тощо
+
+У цьому прикладі ми використаємо **SQLite**, оскільки вона зберігається в одному файлі, а Python має вбудовану підтримку. Тож ви можете скопіювати цей приклад і запустити «як є».
+
+Пізніше, для вашого продакшн-застосунку, ви можете перейти на сервер бази даних, наприклад **PostgreSQL**.
+
+/// tip | Порада
+
+Існує офіційний генератор проєкту з **FastAPI** та **PostgreSQL**, включно з фронтендом та іншими інструментами:
https://github.com/fastapi/full-stack-fastapi-template
+
+///
+
+Це дуже простий і короткий навчальний посібник. Якщо ви хочете вивчити бази даних загалом, SQL або більш просунуті можливості, зверніться до
документації SQLModel.
+
+## Встановіть `SQLModel` { #install-sqlmodel }
+
+Спочатку переконайтеся, що ви створили [віртуальне оточення](../virtual-environments.md){.internal-link target=_blank}, активували його та встановили `sqlmodel`:
+
+
+
+```console
+$ pip install sqlmodel
+---> 100%
+```
+
+
+
+## Створіть застосунок з однією моделлю { #create-the-app-with-a-single-model }
+
+Спершу створимо найпростішу версію застосунку з однією моделлю **SQLModel**.
+
+Потім нижче покращимо безпеку і гнучкість за допомогою кількох моделей. 🤓
+
+### Створіть моделі { #create-models }
+
+Імпортуйте `SQLModel` і створіть модель бази даних:
+
+{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[1:11] hl[7:11] *}
+
+Клас `Hero` дуже схожий на модель Pydantic (фактично, під капотом це і є модель Pydantic).
+
+Є кілька відмінностей:
+
+* `table=True` каже SQLModel, що це «таблична модель» - вона має представляти **таблицю** в SQL базі даних, а не просто «модель даних» (як будь-який інший звичайний клас Pydantic).
+
+* `Field(primary_key=True)` каже SQLModel, що `id` - це **первинний ключ** у SQL базі даних (більше про первинні ключі в SQL див. у документації SQLModel).
+
+ Примітка: Ми використовуємо `int | None` для поля первинного ключа, щоб у Python-коді можна було створити об’єкт без `id` (`id=None`), припускаючи, що база даних згенерує його під час збереження. SQLModel розуміє, що `id` надасть база даних, і визначає стовпець як ненульовий `INTEGER` у схемі бази даних. Докладніше див.
документацію SQLModel про первинні ключі.
+
+* `Field(index=True)` каже SQLModel створити **SQL-індекс** для цього стовпця, що дозволить швидше виконувати пошук у базі даних під час читання даних, відфільтрованих за цим стовпцем.
+
+ SQLModel знатиме, що оголошене як `str` стане SQL-стовпцем типу `TEXT` (або `VARCHAR`, залежно від бази).
+
+### Створіть рушій { #create-an-engine }
+
+`engine` SQLModel (під капотом це `engine` SQLAlchemy) - це те, що **утримує з’єднання** з базою даних.
+
+У вас має бути **єдиний об’єкт `engine`** для всього коду, що під’єднується до тієї самої бази.
+
+{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[14:18] hl[14:15,17:18] *}
+
+Використання `check_same_thread=False` дозволяє FastAPI використовувати ту саму базу SQLite у різних потоках. Це необхідно, адже **один запит** може використати **понад один потік** (наприклад, у залежностях).
+
+Не переймайтеся, завдяки структурі коду ми далі забезпечимо **одну сесію SQLModel на запит**, власне цього і прагне `check_same_thread`.
+
+### Створіть таблиці { #create-the-tables }
+
+Додамо функцію, яка використовує `SQLModel.metadata.create_all(engine)`, щоб **створити таблиці** для всіх «табличних моделей».
+
+{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[21:22] hl[21:22] *}
+
+### Створіть залежність сесії { #create-a-session-dependency }
+
+**`Session`** зберігає **об’єкти в пам’яті** та відстежує зміни у даних, а потім **використовує `engine`** для взаємодії з базою даних.
+
+Ми створимо **залежність** FastAPI з `yield`, яка надаватиме нову `Session` для кожного запиту. Це й гарантує, що ми використовуємо одну сесію на запит. 🤓
+
+Далі створимо залежність `Annotated` - `SessionDep`, щоб спростити решту коду, який її використовуватиме.
+
+{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[25:30] hl[25:27,30] *}
+
+### Створюйте таблиці під час запуску { #create-database-tables-on-startup }
+
+Ми створимо таблиці бази під час запуску застосунку.
+
+{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[32:37] hl[35:37] *}
+
+Тут ми створюємо таблиці на події запуску застосунку.
+
+У продакшні ви, ймовірно, використаєте міграційний скрипт, який виконується перед стартом застосунку. 🤓
+
+/// tip | Порада
+
+SQLModel матиме утиліти міграцій-обгортки над Alembic, але поки що ви можете використовувати
Alembic напряму.
+
+///
+
+### Створіть героя { #create-a-hero }
+
+Оскільки кожна модель SQLModel також є моделлю Pydantic, ви можете використовувати її в тих самих **анотаціях типів**, що і моделі Pydantic.
+
+Наприклад, якщо ви оголосите параметр типу `Hero`, він буде прочитаний з **JSON-тіла**.
+
+Так само ви можете оголосити її як **тип, що повертається** функції, і форма даних з’явиться в автоматичному UI документації API.
+
+{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[40:45] hl[40:45] *}
+
+Тут ми використовуємо залежність `SessionDep` (`Session`), щоб додати нового `Hero` до екземпляра `Session`, закомітити зміни до бази, оновити дані в `hero`, а потім повернути його.
+
+### Читання героїв { #read-heroes }
+
+Ми можемо **читати** `Hero` з бази даних, використовуючи `select()`. Ми можемо додати `limit` і `offset` для пагінації результатів.
+
+{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[48:55] hl[51:52,54] *}
+
+### Читання одного героя { #read-one-hero }
+
+Ми можемо **прочитати** одного `Hero`.
+
+{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[58:63] hl[60] *}
+
+### Видалення героя { #delete-a-hero }
+
+Ми також можемо **видалити** `Hero`.
+
+{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[66:73] hl[71] *}
+
+### Запуск застосунку { #run-the-app }
+
+Ви можете запустити застосунок:
+
+
+
+```console
+$ fastapi dev main.py
+
+INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
+```
+
+
+
+Потім перейдіть до інтерфейсу `/docs`, ви побачите, що **FastAPI** використовує ці **моделі** для **документування** API, а також для **серіалізації** та **валідації** даних.
+
+
+

+
+
+## Оновіть застосунок кількома моделями { #update-the-app-with-multiple-models }
+
+Тепер трохи **відрефакторимо** застосунок, щоб підвищити **безпеку** та **гнучкість**.
+
+Якщо подивитися на попередній варіант, у UI видно, що наразі клієнт може сам обирати `id` для створюваного `Hero`. 😱
+
+Цього допускати не можна - вони можуть перезаписати `id`, який уже призначений у БД. Визначення `id` має виконувати **бекенд** або **база даних**, **а не клієнт**.
+
+Крім того, ми створюємо для героя `secret_name`, але наразі повертаємо його всюди - це не дуже «секретно»... 😅
+
+Виправимо це, додавши кілька **додаткових моделей**. Ось де SQLModel засяє. ✨
+
+### Створіть кілька моделей { #create-multiple-models }
+
+У **SQLModel** будь-який клас моделі з `table=True` - це **таблична модель**.
+
+А будь-який клас моделі без `table=True` - це **модель даних**; це, по суті, просто моделі Pydantic (з парою невеликих доповнень). 🤓
+
+З SQLModel ми можемо використовувати **успадкування**, щоб **уникати дублювання** полів у всіх випадках.
+
+#### `HeroBase` - базовий клас { #herobase-the-base-class }
+
+Почнімо з моделі `HeroBase`, яка містить усі **спільні поля** для всіх моделей:
+
+* `name`
+* `age`
+
+{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:9] hl[7:9] *}
+
+#### `Hero` - «таблична модель» { #hero-the-table-model }
+
+Потім створімо `Hero`, фактичну «табличну модель», з **додатковими полями**, яких немає в інших моделях завжди:
+
+* `id`
+* `secret_name`
+
+Оскільки `Hero` успадковується від `HeroBase`, вона **також** містить **поля**, оголошені в `HeroBase`, тож усі поля `Hero` такі:
+
+* `id`
+* `name`
+* `age`
+* `secret_name`
+
+{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:14] hl[12:14] *}
+
+#### `HeroPublic` - публічна «модель даних» { #heropublic-the-public-data-model }
+
+Далі створимо модель `HeroPublic` - це та, що буде **повертатися** клієнтам API.
+
+Вона має ті самі поля, що й `HeroBase`, отже не включатиме `secret_name`.
+
+Нарешті, особистості наших героїв захищено! 🥷
+
+Вона також перевизначає `id: int`. Роблячи це, ми укладаємо **контракт** з клієнтами API, що `id` завжди буде присутній і буде типу `int` (ніколи не `None`).
+
+/// tip | Порада
+
+Наявність у моделі відповіді гарантії, що значення завжди доступне і завжди `int` (не `None`), дуже корисна для клієнтів API - вони можуть писати значно простіший код, маючи цю визначеність.
+
+Також **автоматично згенеровані клієнти** матимуть простіші інтерфейси, тож розробникам, які взаємодіють з вашим API, буде значно зручніше. 😎
+
+///
+
+Усі поля в `HeroPublic` такі самі, як у `HeroBase`, з `id`, оголошеним як `int` (не `None`):
+
+* `id`
+* `name`
+* `age`
+
+{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:18] hl[17:18] *}
+
+#### `HeroCreate` - «модель даних» для створення героя { #herocreate-the-data-model-to-create-a-hero }
+
+Тепер створимо модель `HeroCreate` - вона **валідуватиме** дані, отримані від клієнтів.
+
+Вона має ті ж поля, що й `HeroBase`, а також `secret_name`.
+
+Тепер, коли клієнти **створюють нового героя**, вони надсилають `secret_name`, він зберігається в базі даних, але ці секретні імена не повертаються клієнтам у API.
+
+/// tip | Порада
+
+Так слід поводитися з **паролями**. Приймайте їх, але не повертайте в API.
+
+Також потрібно **хешувати** значення паролів перед збереженням, **ніколи не зберігайте їх у відкритому вигляді**.
+
+///
+
+Поля `HeroCreate`:
+
+* `name`
+* `age`
+* `secret_name`
+
+{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:22] hl[21:22] *}
+
+#### `HeroUpdate` - «модель даних» для оновлення героя { #heroupdate-the-data-model-to-update-a-hero }
+
+У попередній версії у нас не було способу **оновлювати героя**, але тепер, маючи **кілька моделей**, ми можемо це зробити. 🎉
+
+«Модель даних» `HeroUpdate` дещо особлива: вона має **всі ті самі поля**, що й для створення нового героя, але всі поля **необов’язкові** (усі мають значення за замовчуванням). Таким чином, під час оновлення героя ви можете надіслати лише ті поля, які хочете змінити.
+
+Оскільки **поля фактично змінюються** (тип тепер включає `None` і значення за замовчуванням - `None`), нам потрібно **оголосити їх заново**.
+
+Насправді немає потреби успадковуватися від `HeroBase`, бо ми перевизначаємо всі поля. Я залишу успадкування для послідовності, але це не обов’язково. Це радше питання смаку. 🤷
+
+Поля `HeroUpdate`:
+
+* `name`
+* `age`
+* `secret_name`
+
+{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:28] hl[25:28] *}
+
+### Створення з `HeroCreate` і повернення `HeroPublic` { #create-with-herocreate-and-return-a-heropublic }
+
+Тепер, коли в нас **кілька моделей**, ми можемо оновити частини застосунку, що їх використовують.
+
+У запиті ми отримуємо «модель даних» `HeroCreate`, і з неї створюємо «табличну модель» `Hero`.
+
+Ця нова «таблична модель» `Hero` міститиме поля, надіслані клієнтом, а також матиме `id`, згенерований базою даних.
+
+Далі ми повертаємо з функції цю ж «табличну модель» `Hero`. Але оскільки ми оголошуємо `response_model` як «модель даних» `HeroPublic`, **FastAPI** використає `HeroPublic` для валідації та серіалізації даних.
+
+{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[56:62] hl[56:58] *}
+
+/// tip | Порада
+
+Тепер ми використовуємо `response_model=HeroPublic` замість **анотації типу, що повертається** `-> HeroPublic`, тому що значення, яке ми повертаємо, насправді - не `HeroPublic`.
+
+Якби ми оголосили `-> HeroPublic`, ваш редактор і лінтер справедливо зауважили б, що ви повертаєте `Hero`, а не `HeroPublic`.
+
+Оголошуючи це в `response_model`, ми кажемо **FastAPI** зробити свою справу, не втручаючись в анотації типів та підказки від вашого редактора й інших інструментів.
+
+///
+
+### Читання героїв з `HeroPublic` { #read-heroes-with-heropublic }
+
+Можемо зробити те саме, що й раніше, щоб **читати** `Hero`, знову використовуємо `response_model=list[HeroPublic]`, щоб гарантувати коректну валідацію та серіалізацію даних.
+
+{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[65:72] hl[65] *}
+
+### Читання одного героя з `HeroPublic` { #read-one-hero-with-heropublic }
+
+Ми можемо **прочитати** одного героя:
+
+{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[75:80] hl[77] *}
+
+### Оновлення героя з `HeroUpdate` { #update-a-hero-with-heroupdate }
+
+Ми можемо **оновити героя**. Для цього використовуємо HTTP-операцію `PATCH`.
+
+У коді ми отримуємо `dict` з усіма даними, які надіслав клієнт, - лише з тими даними, які надіслав клієнт, виключаючи будь-які значення, присутні лише як значення за замовчуванням. Для цього використовуємо `exclude_unset=True`. Це головний трюк. 🪄
+
+Потім використовуємо `hero_db.sqlmodel_update(hero_data)`, щоб оновити `hero_db` даними з `hero_data`.
+
+{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[83:93] hl[83:84,88:89] *}
+
+### Знову видалення героя { #delete-a-hero-again }
+
+**Видалення** героя майже не змінилося.
+
+Ми не задовольнимо бажання відрефакторити все в цьому місці. 😅
+
+{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[96:103] hl[101] *}
+
+### Знову запустіть застосунок { #run-the-app-again }
+
+Ви можете знову запустити застосунок:
+
+
+
+```console
+$ fastapi dev main.py
+
+INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
+```
+
+
+
+Якщо ви перейдете до UI `/docs`, побачите, що він оновився і більше не очікуватиме отримати `id` від клієнта під час створення героя тощо.
+
+
+

+
+
+## Підсумок { #recap }
+
+Ви можете використовувати
**SQLModel** для взаємодії з SQL базою даних і спростити код за допомогою «моделей даних» та «табличних моделей».
+
+Багато чого ще можна дізнатися в документації **SQLModel**, там є розширений міні-
навчальний посібник з використання SQLModel з **FastAPI**. 🚀
diff --git a/docs/uk/docs/tutorial/static-files.md b/docs/uk/docs/tutorial/static-files.md
index 32ca1311d2..7f45973df3 100644
--- a/docs/uk/docs/tutorial/static-files.md
+++ b/docs/uk/docs/tutorial/static-files.md
@@ -7,7 +7,7 @@
* Імпортуйте `StaticFiles`.
* «Під'єднати» екземпляр `StaticFiles()` з вказанням необхідного шляху.
-{* ../../docs_src/static_files/tutorial001_py39.py hl[2,6] *}
+{* ../../docs_src/static_files/tutorial001_py310.py hl[2,6] *}
/// note | Технічні деталі
diff --git a/docs/uk/docs/tutorial/testing.md b/docs/uk/docs/tutorial/testing.md
index 462592829f..ff32e9fb66 100644
--- a/docs/uk/docs/tutorial/testing.md
+++ b/docs/uk/docs/tutorial/testing.md
@@ -30,7 +30,7 @@ $ pip install httpx
Записуйте прості `assert`-вирази зі стандартними виразами Python, які потрібно перевірити (це також стандарт для `pytest`).
-{* ../../docs_src/app_testing/tutorial001_py39.py hl[2,12,15:18] *}
+{* ../../docs_src/app_testing/tutorial001_py310.py hl[2,12,15:18] *}
/// tip | Порада
@@ -76,7 +76,7 @@ $ pip install httpx
У файлі `main.py` знаходиться ваш застосунок **FastAPI**:
-{* ../../docs_src/app_testing/app_a_py39/main.py *}
+{* ../../docs_src/app_testing/app_a_py310/main.py *}
### Файл тестування { #testing-file }
@@ -90,9 +90,9 @@ $ pip install httpx
│ └── test_main.py
```
-Оскільки цей файл знаходиться в тому ж пакеті, ви можете використовувати відносний імпорт, щоб імпортувати об'єкт `app` із модуля `main` (`main.py`):
+Оскільки цей файл знаходиться в тому ж пакеті, ви можете використовувати відносний імпорт, щоб імпортувати об'єкт `app` із модуля `main` (`main.py`):
-{* ../../docs_src/app_testing/app_a_py39/test_main.py hl[3] *}
+{* ../../docs_src/app_testing/app_a_py310/test_main.py hl[3] *}
...і написати код для тестів так само як і раніше.
diff --git a/docs/uk/docs/virtual-environments.md b/docs/uk/docs/virtual-environments.md
new file mode 100644
index 0000000000..78e7ab32f5
--- /dev/null
+++ b/docs/uk/docs/virtual-environments.md
@@ -0,0 +1,862 @@
+# Віртуальні середовища { #virtual-environments }
+
+Коли ви працюєте над проєктами Python, вам, імовірно, слід використовувати віртуальне середовище (або схожий механізм), щоб ізолювати пакети, які ви встановлюєте для кожного проєкту.
+
+/// info | Інформація
+
+Якщо ви вже знаєте про віртуальні середовища, як їх створювати та використовувати, можете пропустити цей розділ. 🤓
+
+///
+
+/// tip | Порада
+
+Віртуальне середовище відрізняється від змінної оточення.
+
+Змінна оточення - це змінна в системі, яку можуть використовувати програми.
+
+Віртуальне середовище - це каталог із файлами в ньому.
+
+///
+
+/// info | Інформація
+
+На цій сторінці ви дізнаєтеся, як використовувати віртуальні середовища і як вони працюють.
+
+Якщо ви готові прийняти інструмент, що керує всім за вас (включно з установленням Python), спробуйте
uv.
+
+///
+
+## Створіть проєкт { #create-a-project }
+
+Спочатку створіть каталог для вашого проєкту.
+
+Зазвичай я створюю каталог з назвою `code` у моєму домашньому каталозі користувача.
+
+І всередині нього я створюю окремий каталог на кожен проєкт.
+
+
+
+```console
+// Перейдіть до домашнього каталогу
+$ cd
+// Створіть каталог для всіх ваших проєктів з кодом
+$ mkdir code
+// Перейдіть у цей каталог code
+$ cd code
+// Створіть каталог для цього проєкту
+$ mkdir awesome-project
+// Перейдіть до каталогу цього проєкту
+$ cd awesome-project
+```
+
+
+
+## Створіть віртуальне середовище { #create-a-virtual-environment }
+
+Коли ви починаєте працювати над проєктом Python уперше, створіть віртуальне середовище у вашому проєкті **
у вашому проєкті**.
+
+/// tip | Порада
+
+Це потрібно робити лише один раз на проєкт, не щоразу, коли ви працюєте.
+
+///
+
+//// tab | `venv`
+
+Щоб створити віртуальне середовище, ви можете використати модуль `venv`, який постачається разом із Python.
+
+
+
+```console
+$ python -m venv .venv
+```
+
+
+
+/// details | Що означає ця команда
+
+* `python`: використати програму з назвою `python`
+* `-m`: викликати модуль як скрипт, далі ми вкажемо, який модуль
+* `venv`: використати модуль з назвою `venv`, який зазвичай уже встановлено з Python
+* `.venv`: створити віртуальне середовище в новому каталозі `.venv`
+
+///
+
+////
+
+//// tab | `uv`
+
+Якщо у вас встановлено
`uv`, ви можете використати його для створення віртуального середовища.
+
+
+
+```console
+$ uv venv
+```
+
+
+
+/// tip | Порада
+
+Типово `uv` створить віртуальне середовище в каталозі з назвою `.venv`.
+
+Але ви можете налаштувати це, передавши додатковий аргумент з назвою каталогу.
+
+///
+
+////
+
+Ця команда створює нове віртуальне середовище в каталозі з назвою `.venv`.
+
+/// details | `.venv` або інша назва
+
+Ви можете створити віртуальне середовище в іншому каталозі, але існує усталена домовленість називати його `.venv`.
+
+///
+
+## Активуйте віртуальне середовище { #activate-the-virtual-environment }
+
+Активуйте нове віртуальне середовище, щоб будь-яка команда Python, яку ви запускаєте, або пакет, який ви встановлюєте, використовували його.
+
+/// tip | Порада
+
+Робіть це щоразу, коли ви починаєте нову сесію термінала для роботи над проєктом.
+
+///
+
+//// tab | Linux, macOS
+
+
+
+```console
+$ source .venv/bin/activate
+```
+
+
+
+////
+
+//// tab | Windows PowerShell
+
+
+
+```console
+$ .venv\Scripts\Activate.ps1
+```
+
+
+
+////
+
+//// tab | Windows Bash
+
+Або якщо ви використовуєте Bash для Windows (напр.,
Git Bash):
+
+
+
+```console
+$ source .venv/Scripts/activate
+```
+
+
+
+////
+
+/// tip | Порада
+
+Кожного разу, коли ви встановлюєте новий пакет у це середовище, активуйте середовище знову.
+
+Це гарантує, що якщо ви використовуєте програму термінала (
CLI), встановлену цим пакетом, ви використовуєте саме ту з вашого віртуального середовища, а не будь-яку іншу, яка може бути встановлена глобально, імовірно з іншою версією, ніж вам потрібно.
+
+///
+
+## Перевірте активність віртуального середовища { #check-the-virtual-environment-is-active }
+
+Перевірте, що віртуальне середовище активне (попередня команда спрацювала).
+
+/// tip | Порада
+
+Це необов'язково, але це гарний спосіб перевірити, що все працює як очікується і ви використовуєте саме те віртуальне середовище, яке планували.
+
+///
+
+//// tab | Linux, macOS, Windows Bash
+
+
+
+```console
+$ which python
+
+/home/user/code/awesome-project/.venv/bin/python
+```
+
+
+
+Якщо показано бінарний файл `python` за шляхом `.venv/bin/python` усередині вашого проєкту (у цьому випадку `awesome-project`), тоді все спрацювало. 🎉
+
+////
+
+//// tab | Windows PowerShell
+
+
+
+```console
+$ Get-Command python
+
+C:\Users\user\code\awesome-project\.venv\Scripts\python
+```
+
+
+
+Якщо показано бінарний файл `python` за шляхом `.venv\Scripts\python` усередині вашого проєкту (у цьому випадку `awesome-project`), тоді все спрацювало. 🎉
+
+////
+
+## Оновіть `pip` { #upgrade-pip }
+
+/// tip | Порада
+
+Якщо ви використовуєте
`uv`, ви використовуватимете його для встановлення замість `pip`, тож вам не потрібно оновлювати `pip`. 😎
+
+///
+
+Якщо ви використовуєте `pip` для встановлення пакетів (він іде за замовчуванням із Python), вам слід оновити його до найновішої версії.
+
+Багато дивних помилок під час встановлення пакета вирішуються тим, що спочатку оновлюють `pip`.
+
+/// tip | Порада
+
+Зазвичай це роблять один раз, відразу після створення віртуального середовища.
+
+///
+
+Переконайтеся, що віртуальне середовище активне (командою вище), а потім виконайте:
+
+
+
+```console
+$ python -m pip install --upgrade pip
+
+---> 100%
+```
+
+
+
+/// tip | Порада
+
+Іноді ви можете отримати помилку **`No module named pip`** при спробі оновити pip.
+
+Якщо це сталося, встановіть і оновіть pip за допомогою команди нижче:
+
+
+
+```console
+$ python -m ensurepip --upgrade
+
+---> 100%
+```
+
+
+
+Ця команда встановить pip, якщо він ще не встановлений, і також гарантує, що встановлена версія pip принаймні така ж нова, як доступна в `ensurepip`.
+
+///
+
+## Додайте `.gitignore` { #add-gitignore }
+
+Якщо ви використовуєте Git (варто це робити), додайте файл `.gitignore`, щоб виключити з Git усе у вашому `.venv`.
+
+/// tip | Порада
+
+Якщо ви використали
`uv` для створення віртуального середовища, він уже зробив це за вас, можете пропустити цей крок. 😎
+
+///
+
+/// tip | Порада
+
+Зробіть це один раз, відразу після створення віртуального середовища.
+
+///
+
+
+
+```console
+$ echo "*" > .venv/.gitignore
+```
+
+
+
+/// details | Що означає ця команда
+
+* `echo "*"`: «виведе» текст `*` у термінал (наступна частина трохи це змінює)
+* `>`: усе, що команда ліворуч від `>` «виводить» у термінал, не слід друкувати, натомість записати у файл, вказаний праворуч від `>`
+* `.gitignore`: назва файлу, куди слід записати текст
+
+А `*` для Git означає «все». Тож він ігноруватиме все в каталозі `.venv`.
+
+Ця команда створить файл `.gitignore` із вмістом:
+
+```gitignore
+*
+```
+
+///
+
+## Встановіть пакети { #install-packages }
+
+Після активації середовища ви можете встановлювати в нього пакети.
+
+/// tip | Порада
+
+Робіть це один раз під час встановлення або оновлення пакетів, потрібних вашому проєкту.
+
+Якщо вам потрібно оновити версію або додати новий пакет, ви зробите це знову.
+
+///
+
+### Встановіть пакети безпосередньо { #install-packages-directly }
+
+Якщо ви поспішаєте та не хочете використовувати файл для оголошення вимог вашого проєкту до пакетів, ви можете встановити їх безпосередньо.
+
+/// tip | Порада
+
+Дуже добра ідея - записати пакети та версії, потрібні вашій програмі, у файл (наприклад, `requirements.txt` або `pyproject.toml`).
+
+///
+
+//// tab | `pip`
+
+
+
+```console
+$ pip install "fastapi[standard]"
+
+---> 100%
+```
+
+
+
+////
+
+//// tab | `uv`
+
+Якщо у вас є
`uv`:
+
+
+
+```console
+$ uv pip install "fastapi[standard]"
+---> 100%
+```
+
+
+
+////
+
+### Встановіть з `requirements.txt` { #install-from-requirements-txt }
+
+Якщо у вас є `requirements.txt`, ви можете використати його для встановлення перелічених там пакетів.
+
+//// tab | `pip`
+
+
+
+```console
+$ pip install -r requirements.txt
+---> 100%
+```
+
+
+
+////
+
+//// tab | `uv`
+
+Якщо у вас є
`uv`:
+
+
+
+```console
+$ uv pip install -r requirements.txt
+---> 100%
+```
+
+
+
+////
+
+/// details | `requirements.txt`
+
+`requirements.txt` із деякими пакетами може виглядати так:
+
+```requirements.txt
+fastapi[standard]==0.113.0
+pydantic==2.8.0
+```
+
+///
+
+## Запустіть вашу програму { #run-your-program }
+
+Після активації віртуального середовища ви можете запустити вашу програму, і вона використовуватиме Python із вашого віртуального середовища з пакетами, які ви там встановили.
+
+
+
+```console
+$ python main.py
+
+Hello World
+```
+
+
+
+## Налаштуйте ваш редактор { #configure-your-editor }
+
+Ймовірно, ви використовуєте редактор коду, переконайтеся, що ви налаштували його на використання того самого віртуального середовища, яке ви створили (швидше за все, він визначить його автоматично), щоб отримувати автодоповнення та підсвічування помилок.
+
+Наприклад:
+
+*
VS Code
+*
PyCharm
+
+/// tip | Порада
+
+Зазвичай це потрібно робити лише один раз, коли ви створюєте віртуальне середовище.
+
+///
+
+## Деактивуйте віртуальне середовище { #deactivate-the-virtual-environment }
+
+Коли ви завершили роботу над проєктом, ви можете деактивувати віртуальне середовище.
+
+
+
+```console
+$ deactivate
+```
+
+
+
+Таким чином, коли ви запустите `python`, він не намагатиметься запускатися з того віртуального середовища з установленими там пакетами.
+
+## Готові до роботи { #ready-to-work }
+
+Тепер ви готові почати працювати над вашим проєктом.
+
+/// tip | Порада
+
+Хочете зрозуміти, що це все було вище?
+
+Продовжуйте читати. 👇🤓
+
+///
+
+## Навіщо віртуальні середовища { #why-virtual-environments }
+
+Щоб працювати з FastAPI, вам потрібно встановити
Python.
+
+Після цього вам потрібно буде встановити FastAPI та інші пакети, які ви хочете використовувати.
+
+Для встановлення пакетів зазвичай використовують команду `pip`, що постачається з Python (або схожі альтернативи).
+
+Однак, якщо ви просто користуватиметеся `pip` напряму, пакети встановлюватимуться у ваше глобальне середовище Python (глобальну інсталяцію Python).
+
+### Проблема { #the-problem }
+
+То в чому ж проблема встановлення пакетів у глобальне середовище Python?
+
+З часом ви, вірогідно, писатимете багато різних програм, які залежать від різних пакетів. І деякі з цих ваших проєктів залежатимуть від різних версій одного й того ж пакета. 😱
+
+Наприклад, ви можете створити проєкт із назвою `philosophers-stone`, ця програма залежить від іншого пакета з назвою `harry`, використовуючи версію `1`. Тож вам потрібно встановити `harry`.
+
+```mermaid
+flowchart LR
+ stone(philosophers-stone) -->|requires| harry-1[harry v1]
+```
+
+Потім, трохи згодом, ви створюєте інший проєкт із назвою `prisoner-of-azkaban`, і цей проєкт також залежить від `harry`, але йому потрібна версія `harry` `3`.
+
+```mermaid
+flowchart LR
+ azkaban(prisoner-of-azkaban) --> |requires| harry-3[harry v3]
+```
+
+Але тепер проблема в тому, що якщо ви встановлюєте пакети глобально (у глобальне середовище), а не у локальне віртуальне середовище, вам доведеться вибирати, яку версію `harry` встановити.
+
+Якщо ви хочете запустити `philosophers-stone`, вам спочатку потрібно встановити `harry` версії `1`, наприклад, так:
+
+
+
+```console
+$ pip install "harry==1"
+```
+
+
+
+У підсумку у вас буде встановлено `harry` версії `1` у глобальному середовищі Python.
+
+```mermaid
+flowchart LR
+ subgraph global[global env]
+ harry-1[harry v1]
+ end
+ subgraph stone-project[philosophers-stone project]
+ stone(philosophers-stone) -->|requires| harry-1
+ end
+```
+
+Але якщо ви захочете запустити `prisoner-of-azkaban`, вам доведеться видалити `harry` версії `1` і встановити `harry` версії `3` (або просто встановлення версії `3` автоматично видалить версію `1`).
+
+
+
+```console
+$ pip install "harry==3"
+```
+
+
+
+У підсумку у вас буде встановлено `harry` версії `3` у глобальному середовищі Python.
+
+А якщо ви знову спробуєте запустити `philosophers-stone`, є шанс, що він не працюватиме, тому що йому потрібен `harry` версії `1`.
+
+```mermaid
+flowchart LR
+ subgraph global[global env]
+ harry-1[
harry v1]
+ style harry-1 fill:#ccc,stroke-dasharray: 5 5
+ harry-3[harry v3]
+ end
+ subgraph stone-project[philosophers-stone project]
+ stone(philosophers-stone) -.-x|⛔️| harry-1
+ end
+ subgraph azkaban-project[prisoner-of-azkaban project]
+ azkaban(prisoner-of-azkaban) --> |requires| harry-3
+ end
+```
+
+/// tip | Порада
+
+У пакетах Python дуже поширена практика намагатися якнайкраще уникати несумісних змін у нових версіях, але краще підстрахуватися та встановлювати новіші версії свідомо і тоді, коли ви можете запустити тести, щоб перевірити, що все працює коректно.
+
+///
+
+Тепер уявіть те саме з багатьма іншими пакетами, від яких залежать усі ваші проєкти. Це дуже складно керувати. І ви, імовірно, запускатимете деякі проєкти з деякими несумісними версіями пакетів і не розумітимете, чому щось не працює.
+
+Також, залежно від вашої операційної системи (напр., Linux, Windows, macOS), у ній може бути вже встановлений Python. І в такому разі, імовірно, уже будуть попередньо встановлені деякі пакети з певними версіями, потрібними вашій системі. Якщо ви встановлюєте пакети в глобальне середовище Python, ви можете зламати деякі програми, що постачаються з вашою операційною системою.
+
+## Де встановлюються пакети { #where-are-packages-installed }
+
+Коли ви встановлюєте Python, він створює на вашому комп'ютері кілька каталогів із деякими файлами.
+
+Деякі з цих каталогів відповідають за зберігання всіх пакетів, які ви встановлюєте.
+
+Коли ви запускаєте:
+
+
+
+```console
+// Не запускайте це зараз, це лише приклад 🤓
+$ pip install "fastapi[standard]"
+---> 100%
+```
+
+
+
+Це завантажить стиснений файл з кодом FastAPI, зазвичай із
PyPI.
+
+Також будуть завантажені файли для інших пакетів, від яких залежить FastAPI.
+
+Потім усе це буде розпаковано та покладено в каталог на вашому комп'ютері.
+
+Типово ці завантажені та розпаковані файли будуть покладені в каталог, що постачається з вашою інсталяцією Python, це глобальне середовище.
+
+## Що таке віртуальні середовища { #what-are-virtual-environments }
+
+Рішенням проблеми з наявністю всіх пакетів у глобальному середовищі є використання віртуального середовища для кожного проєкту, над яким ви працюєте.
+
+Віртуальне середовище - це каталог, дуже схожий на глобальний, у якому ви можете встановлювати пакети для конкретного проєкту.
+
+Таким чином кожен проєкт матиме власне віртуальне середовище (каталог `.venv`) із власними пакетами.
+
+```mermaid
+flowchart TB
+ subgraph stone-project[philosophers-stone project]
+ stone(philosophers-stone) --->|requires| harry-1
+ subgraph venv1[.venv]
+ harry-1[harry v1]
+ end
+ end
+ subgraph azkaban-project[prisoner-of-azkaban project]
+ azkaban(prisoner-of-azkaban) --->|requires| harry-3
+ subgraph venv2[.venv]
+ harry-3[harry v3]
+ end
+ end
+ stone-project ~~~ azkaban-project
+```
+
+## Що означає активація віртуального середовища { #what-does-activating-a-virtual-environment-mean }
+
+Коли ви активуєте віртуальне середовище, наприклад так:
+
+//// tab | Linux, macOS
+
+
+
+```console
+$ source .venv/bin/activate
+```
+
+
+
+////
+
+//// tab | Windows PowerShell
+
+
+
+```console
+$ .venv\Scripts\Activate.ps1
+```
+
+
+
+////
+
+//// tab | Windows Bash
+
+Або якщо ви використовуєте Bash для Windows (напр.,
Git Bash):
+
+
+
+```console
+$ source .venv/Scripts/activate
+```
+
+
+
+////
+
+Ця команда створить або змінить деякі [Змінні оточення](environment-variables.md){.internal-link target=_blank}, які будуть доступні для наступних команд.
+
+Однією з цих змінних є змінна `PATH`.
+
+/// tip | Порада
+
+Ви можете дізнатися більше про змінну оточення `PATH` у розділі [Змінні оточення](environment-variables.md#path-environment-variable){.internal-link target=_blank}.
+
+///
+
+Активація віртуального середовища додає його шлях `.venv/bin` (на Linux і macOS) або `.venv\Scripts` (на Windows) до змінної оточення `PATH`.
+
+Скажімо, до активації середовища змінна `PATH` виглядала так:
+
+//// tab | Linux, macOS
+
+```plaintext
+/usr/bin:/bin:/usr/sbin:/sbin
+```
+
+Це означає, що система шукатиме програми в:
+
+* `/usr/bin`
+* `/bin`
+* `/usr/sbin`
+* `/sbin`
+
+////
+
+//// tab | Windows
+
+```plaintext
+C:\Windows\System32
+```
+
+Це означає, що система шукатиме програми в:
+
+* `C:\Windows\System32`
+
+////
+
+Після активації віртуального середовища змінна `PATH` виглядатиме приблизно так:
+
+//// tab | Linux, macOS
+
+```plaintext
+/home/user/code/awesome-project/.venv/bin:/usr/bin:/bin:/usr/sbin:/sbin
+```
+
+Це означає, що система тепер спочатку шукатиме програми в:
+
+```plaintext
+/home/user/code/awesome-project/.venv/bin
+```
+
+перед тим, як шукати в інших каталогах.
+
+Тож коли ви введете `python` у терміналі, система знайде програму Python у
+
+```plaintext
+/home/user/code/awesome-project/.venv/bin/python
+```
+
+і використає саме її.
+
+////
+
+//// tab | Windows
+
+```plaintext
+C:\Users\user\code\awesome-project\.venv\Scripts;C:\Windows\System32
+```
+
+Це означає, що система тепер спочатку шукатиме програми в:
+
+```plaintext
+C:\Users\user\code\awesome-project\.venv\Scripts
+```
+
+перед тим, як шукати в інших каталогах.
+
+Тож коли ви введете `python` у терміналі, система знайде програму Python у
+
+```plaintext
+C:\Users\user\code\awesome-project\.venv\Scripts\python
+```
+
+і використає саме її.
+
+////
+
+Важлива деталь: шлях до віртуального середовища буде додано на початок змінної `PATH`. Система знайде його раніше за будь-який інший доступний Python. Таким чином, коли ви запускаєте `python`, використовується саме Python із віртуального середовища, а не будь-який інший `python` (наприклад, з глобального середовища).
+
+Активація віртуального середовища також змінює ще кілька речей, але це одна з найважливіших.
+
+## Перевірка віртуального середовища { #checking-a-virtual-environment }
+
+Коли ви перевіряєте, чи активне віртуальне середовище, наприклад так:
+
+//// tab | Linux, macOS, Windows Bash
+
+
+
+```console
+$ which python
+
+/home/user/code/awesome-project/.venv/bin/python
+```
+
+
+
+////
+
+//// tab | Windows PowerShell
+
+
+
+```console
+$ Get-Command python
+
+C:\Users\user\code\awesome-project\.venv\Scripts\python
+```
+
+
+
+////
+
+Це означає, що програма `python`, яка буде використана, знаходиться у віртуальному середовищі.
+
+На Linux і macOS використовують `which`, а в Windows PowerShell - `Get-Command`.
+
+Принцип роботи цієї команди в тому, що вона перевіряє змінну оточення `PATH`, проходячи по кожному шляху по порядку, шукаючи програму з назвою `python`. Щойно вона її знайде, вона покаже вам шлях до цієї програми.
+
+Найважливіше, що коли ви викликаєте `python`, це рівно той «`python`», який буде виконаний.
+
+Отже, ви можете підтвердити, чи перебуваєте в правильному віртуальному середовищі.
+
+/// tip | Порада
+
+Легко активувати одне віртуальне середовище, отримати один Python, а потім перейти до іншого проєкту.
+
+І другий проєкт не працюватиме, бо ви використовуєте некоректний Python з віртуального середовища іншого проєкту.
+
+Корисно вміти перевіряти, який саме `python` використовується. 🤓
+
+///
+
+## Навіщо деактивувати віртуальне середовище { #why-deactivate-a-virtual-environment }
+
+Наприклад, ви працюєте над проєктом `philosophers-stone`, активували його віртуальне середовище, встановили пакети та працюєте з цим середовищем.
+
+А потім ви хочете працювати над іншим проєктом `prisoner-of-azkaban`.
+
+Ви переходите до цього проєкту:
+
+
+
+```console
+$ cd ~/code/prisoner-of-azkaban
+```
+
+
+
+Якщо ви не деактивуєте віртуальне середовище для `philosophers-stone`, коли ви запустите `python` у терміналі, він спробує використовувати Python із `philosophers-stone`.
+
+
+
+```console
+$ cd ~/code/prisoner-of-azkaban
+
+$ python main.py
+
+// Помилка імпорту sirius, його не встановлено 😱
+Traceback (most recent call last):
+ File "main.py", line 1, in
+ import sirius
+```
+
+
+
+Але якщо ви деактивуєте віртуальне середовище і активуєте нове для `prisoner-of-askaban`, тоді при запуску `python` він використовуватиме Python із віртуального середовища в `prisoner-of-azkaban`.
+
+
+
+```console
+$ cd ~/code/prisoner-of-azkaban
+
+// Вам не потрібно бути в старому каталозі, щоб деактивувати, це можна зробити будь-де, навіть після переходу до іншого проєкту 😎
+$ deactivate
+
+// Активуйте віртуальне середовище в prisoner-of-azkaban/.venv 🚀
+$ source .venv/bin/activate
+
+// Тепер, коли ви запускаєте python, він знайде пакет sirius, встановлений у цьому віртуальному середовищі ✨
+$ python main.py
+
+I solemnly swear 🐺
+```
+
+
+
+## Альтернативи { #alternatives }
+
+Це простий посібник, щоб ви швидко стартували та зрозуміли, як усе працює «під капотом».
+
+Існує багато альтернатив керування віртуальними середовищами, залежностями пакетів (вимогами), проєктами.
+
+Коли будете готові й захочете використовувати інструмент для керування всім проєктом, залежностями пакетів, віртуальними середовищами тощо, я раджу спробувати
uv.
+
+`uv` уміє багато чого, зокрема:
+
+* Встановлювати Python для вас, включно з різними версіями
+* Керувати віртуальним середовищем ваших проєктів
+* Встановлювати пакети
+* Керувати залежностями пакетів і версіями у вашому проєкті
+* Гарантувати, що у вас є точний набір пакетів і версій для встановлення, включно з їхніми залежностями, щоб ви були певні, що зможете запустити ваш проєкт у продакшені точно так само, як і на вашому комп'ютері під час розробки - це називається блокуванням
+* І багато іншого
+
+## Висновок { #conclusion }
+
+Якщо ви все це прочитали й зрозуміли, тепер ви знаєте значно більше про віртуальні середовища, ніж багато розробників. 🤓
+
+Знання цих деталей, найімовірніше, стане в пригоді в майбутньому, коли ви налагоджуватимете щось, що виглядає складним, але ви знатимете, як усе працює «під капотом». 😎
diff --git a/docs/zh-hant/docs/_llm-test.md b/docs/zh-hant/docs/_llm-test.md
new file mode 100644
index 0000000000..85cfd22991
--- /dev/null
+++ b/docs/zh-hant/docs/_llm-test.md
@@ -0,0 +1,503 @@
+# LLM 測試檔案 { #llm-test-file }
+
+本文件用來測試用於翻譯文件的
LLM 是否理解 `scripts/translate.py` 中的 `general_prompt`,以及 `docs/{language code}/llm-prompt.md` 中的語言特定提示。語言特定提示會附加在 `general_prompt` 後面。
+
+此處新增的測試會提供給所有語言特定提示的設計者參考。
+
+使用方式:
+
+* 準備語言特定提示 - `docs/{language code}/llm-prompt.md`。
+* 針對本文件做一次全新的翻譯為你想要的目標語言(例如使用 `translate.py` 的 `translate-page` 指令)。這會在 `docs/{language code}/docs/_llm-test.md` 產生翻譯檔。
+* 檢查翻譯是否正確。
+* 如有需要,改進你的語言特定提示、通用提示,或英文原文。
+* 然後手動修正翻譯中剩下的問題,讓它成為一個好的譯文。
+* 重新翻譯,並保留這份好的譯文。理想結果是 LLM 不再對該譯文做任何變更。這代表通用提示與你的語言特定提示已經盡可能完善(有時它仍可能做出幾個看似隨機的變更,原因是
LLMs 並非決定性演算法)。
+
+測試:
+
+## 程式碼片段 { #code-snippets }
+
+//// tab | 測試
+
+這是一個程式碼片段:`foo`。這是另一個程式碼片段:`bar`。還有一個:`baz quux`。
+
+////
+
+//// tab | 資訊
+
+程式碼片段內的內容應保持原樣。
+
+請見 `scripts/translate.py` 中通用提示的 `### Content of code snippets` 小節。
+
+////
+
+## 引號 { #quotes }
+
+//// tab | 測試
+
+Yesterday, my friend wrote: "If you spell incorrectly correctly, you have spelled it incorrectly". To which I answered: "Correct, but 'incorrectly' is incorrectly not '"incorrectly"'".
+
+/// note | 注意
+
+LLM 很可能會把這段翻譯錯。重點只在於重新翻譯時是否能保留已修正的翻譯。
+
+///
+
+////
+
+//// tab | 資訊
+
+提示設計者可以選擇是否將中性引號轉換為排印引號。保留原樣也可以。
+
+例如請見 `docs/de/llm-prompt.md` 中的 `### Quotes` 小節。
+
+////
+
+## 程式碼片段中的引號 { #quotes-in-code-snippets }
+
+//// tab | 測試
+
+`pip install "foo[bar]"`
+
+程式碼片段中字串常值的例子:"this"、'that'。
+
+較難的程式碼片段中字串常值例子:`f"I like {'oranges' if orange else "apples"}"`
+
+進階:`Yesterday, my friend wrote: "If you spell incorrectly correctly, you have spelled it incorrectly". To which I answered: "Correct, but 'incorrectly' is incorrectly not '"incorrectly"'"`
+
+////
+
+//// tab | 資訊
+
+... 不過,程式碼片段中的引號必須保持原樣。
+
+////
+
+## 程式碼區塊 { #code-blocks }
+
+//// tab | 測試
+
+一個 Bash 程式碼範例...
+
+```bash
+# 向宇宙輸出問候
+echo "Hello universe"
+```
+
+...以及一個主控台範例...
+
+```console
+$
fastapi run
main.py
+
FastAPI Starting server
+ Searching for package file structure
+```
+
+...以及另一個主控台範例...
+
+```console
+// 建立目錄 "code"
+$ mkdir code
+// 切換到該目錄
+$ cd code
+```
+
+...以及一個 Python 程式碼範例...
+
+```Python
+wont_work() # 這不會運作 😱
+works(foo="bar") # 這可以運作 🎉
+```
+
+...就是這樣。
+
+////
+
+//// tab | 資訊
+
+程式碼區塊中的程式碼不應修改,註解除外。
+
+請見 `scripts/translate.py` 中通用提示的 `### Content of code blocks` 小節。
+
+////
+
+## 分頁與色塊 { #tabs-and-colored-boxes }
+
+//// tab | 測試
+
+/// info | 資訊
+Some text
+///
+
+/// note | 注意
+Some text
+///
+
+/// note | 技術細節
+Some text
+///
+
+/// check | 檢查
+Some text
+///
+
+/// tip | 提示
+Some text
+///
+
+/// warning | 警告
+Some text
+///
+
+/// danger | 危險
+Some text
+///
+
+////
+
+//// tab | 資訊
+
+分頁與 `Info`/`Note`/`Warning`/等區塊,應在直線(`|`)後加入其標題的翻譯。
+
+請見 `scripts/translate.py` 中通用提示的 `### Special blocks` 與 `### Tab blocks` 小節。
+
+////
+
+## 網頁與內部連結 { #web-and-internal-links }
+
+//// tab | 測試
+
+連結文字應被翻譯,連結位址應保持不變:
+
+* [連結到上方標題](#code-snippets)
+* [內部連結](index.md#installation){.internal-link target=_blank}
+*
外部連結
+*
連結到樣式
+*
連結到腳本
+*
連結到圖片
+
+連結文字應被翻譯,連結位址應指向對應的翻譯版本:
+
+*
FastAPI 連結
+
+////
+
+//// tab | 資訊
+
+連結應翻譯其文字,但位址需保持不變。例外是指向 FastAPI 文件網站的絕對連結,該情況下位址應指向對應的翻譯版本。
+
+請見 `scripts/translate.py` 中通用提示的 `### Links` 小節。
+
+////
+
+## HTML「abbr」元素 { #html-abbr-elements }
+
+//// tab | 測試
+
+以下是一些包在 HTML「abbr」元素中的內容(部分為杜撰):
+
+### abbr 提供完整詞組 { #the-abbr-gives-a-full-phrase }
+
+*
GTD
+*
lt
+*
XWT
+*
PSGI
+
+### abbr 提供完整詞組與說明 { #the-abbr-gives-a-full-phrase-and-an-explanation }
+
+*
MDN
+*
I/O.
+
+////
+
+//// tab | 資訊
+
+「abbr」元素的「title」屬性需依特定規則翻譯。
+
+翻譯可以自行新增「abbr」元素(例如為解釋英文單字),LLM 不應移除它們。
+
+請見 `scripts/translate.py` 中通用提示的 `### HTML abbr elements` 小節。
+
+////
+
+## HTML「dfn」元素 { #html-dfn-elements }
+
+*
叢集
+*
深度學習
+
+## 標題 { #headings }
+
+//// tab | 測試
+
+### 開發網頁應用程式 - 教學 { #develop-a-webapp-a-tutorial }
+
+Hello.
+
+### 型別提示與註解 { #type-hints-and-annotations }
+
+Hello again.
+
+### 超類與子類別 { #super-and-subclasses }
+
+Hello again.
+
+////
+
+//// tab | 資訊
+
+標題唯一的硬性規則是保留花括號中的雜湊片段不變,以確保連結不會失效。
+
+請見 `scripts/translate.py` 中通用提示的 `### Headings` 小節。
+
+關於語言特定的說明,參見例如 `docs/de/llm-prompt.md` 中的 `### Headings` 小節。
+
+////
+
+## 文件中使用的術語 { #terms-used-in-the-docs }
+
+//// tab | 測試
+
+* you
+* your
+
+* e.g.
+* etc.
+
+* `foo` as an `int`
+* `bar` as a `str`
+* `baz` as a `list`
+
+* 教學 - 使用者指南
+* 進階使用者指南
+* SQLModel 文件
+* API 文件
+* 自動文件
+
+* 資料科學
+* 深度學習
+* 機器學習
+* 相依性注入
+* HTTP 基本驗證
+* HTTP 摘要驗證
+* ISO 格式
+* JSON Schema 標準
+* JSON 結構描述
+* 結構描述定義
+* 密碼流程
+* 行動裝置
+
+* 已棄用
+* 設計的
+* 無效
+* 即時
+* 標準
+* 預設
+* 區分大小寫
+* 不區分大小寫
+
+* 提供應用程式服務
+* 提供頁面服務
+
+* 應用程式
+* 應用程式
+
+* 請求
+* 回應
+* 錯誤回應
+
+* 路徑操作
+* 路徑操作裝飾器
+* 路徑操作函式
+
+* 主體
+* 請求主體
+* 回應主體
+* JSON 主體
+* 表單主體
+* 檔案主體
+* 函式主體
+
+* 參數
+* 主體參數
+* 路徑參數
+* 查詢參數
+* Cookie 參數
+* 標頭參數
+* 表單參數
+* 函式參數
+
+* 事件
+* 啟動事件
+* 伺服器的啟動
+* 關閉事件
+* 生命週期事件
+
+* 處理器
+* 事件處理器
+* 例外處理器
+* 處理
+
+* 模型
+* Pydantic 模型
+* 資料模型
+* 資料庫模型
+* 表單模型
+* 模型物件
+
+* 類別
+* 基底類別
+* 父類別
+* 子類別
+* 子類別
+* 同級類別
+* 類別方法
+
+* 標頭
+* 標頭
+* 授權標頭
+* `Authorization` 標頭
+* 轉送標頭
+
+* 相依性注入系統
+* 相依項
+* 可相依對象
+* 相依者
+
+* I/O 受限
+* CPU 受限
+* 並發
+* 平行處理
+* 多處理程序
+
+* 環境變數
+* 環境變數
+* `PATH`
+* `PATH` 變數
+
+* 驗證
+* 驗證提供者
+* 授權
+* 授權表單
+* 授權提供者
+* 使用者進行驗證
+* 系統驗證使用者
+
+* CLI
+* 命令列介面
+
+* 伺服器
+* 用戶端
+
+* 雲端提供者
+* 雲端服務
+
+* 開發
+* 開發階段
+
+* dict
+* 字典
+* 列舉
+* enum
+* 列舉成員
+
+* 編碼器
+* 解碼器
+* 編碼
+* 解碼
+
+* 例外
+* 拋出
+
+* 運算式
+* 陳述式
+
+* 前端
+* 後端
+
+* GitHub 討論
+* GitHub 議題
+
+* 效能
+* 效能優化
+
+* 回傳型別
+* 回傳值
+
+* 安全性
+* 安全性機制
+
+* 任務
+* 背景任務
+* 任務函式
+
+* 樣板
+* 樣板引擎
+
+* 型別註解
+* 型別提示
+
+* 伺服器工作進程
+* Uvicorn 工作進程
+* Gunicorn 工作進程
+* 工作進程
+* worker 類別
+* 工作負載
+
+* 部署
+* 部署
+
+* SDK
+* 軟體開發工具組
+
+* `APIRouter`
+* `requirements.txt`
+* Bearer Token
+* 相容性破壞變更
+* 錯誤
+* 按鈕
+* 可呼叫對象
+* 程式碼
+* 提交
+* 情境管理器
+* 協程
+* 資料庫工作階段
+* 磁碟
+* 網域
+* 引擎
+* 假的 X
+* HTTP GET 方法
+* 項目
+* 函式庫
+* 生命週期
+* 鎖
+* 中介軟體
+* 行動應用程式
+* 模組
+* 掛載
+* 網路
+* 來源
+* 覆寫
+* 有效負載
+* 處理器
+* 屬性
+* 代理
+* pull request
+* 查詢
+* RAM
+* 遠端機器
+* 狀態碼
+* 字串
+* 標籤
+* Web 框架
+* 萬用字元
+* 回傳
+* 驗證
+
+////
+
+//// tab | 資訊
+
+這是一份不完整且非規範性的(多為)技術術語清單,來源為文件內容。它可能有助於提示設計者判斷哪些術語需要 LLM 的特別協助。例如當 LLM 反覆把好的翻譯改回成較差的版本,或在你的語言中對某詞的詞形變化處理有困難時。
+
+請見例如 `docs/de/llm-prompt.md` 中的 `### List of English terms and their preferred German translations` 小節。
+
+////
diff --git a/docs/zh-hant/docs/advanced/additional-responses.md b/docs/zh-hant/docs/advanced/additional-responses.md
new file mode 100644
index 0000000000..bb2bf259bd
--- /dev/null
+++ b/docs/zh-hant/docs/advanced/additional-responses.md
@@ -0,0 +1,247 @@
+# OpenAPI 中的額外回應 { #additional-responses-in-openapi }
+
+/// warning | 警告
+
+這是一個偏進階的主題。
+
+如果你剛開始使用 **FastAPI**,大多情況下不需要用到它。
+
+///
+
+你可以宣告額外的回應,包含額外的狀態碼、媒體型別、描述等。
+
+這些額外回應會被包含在 OpenAPI 中,因此也會顯示在 API 文件裡。
+
+但對於這些額外回應,你必須直接回傳像 `JSONResponse` 這樣的 `Response`,並包含你的狀態碼與內容。
+
+## 使用 `model` 的額外回應 { #additional-response-with-model }
+
+你可以在你的「路徑操作裝飾器」中傳入參數 `responses`。
+
+它接收一個 `dict`:鍵是各回應的狀態碼(例如 `200`),值是另一個 `dict`,其中包含每個回應的資訊。
+
+每個回應的 `dict` 都可以有一個鍵 `model`,包含一個 Pydantic 模型,與 `response_model` 類似。
+
+**FastAPI** 會取用該模型、產生其 JSON Schema,並把它放到 OpenAPI 中正確的位置。
+
+例如,要宣告一個狀態碼為 `404` 的額外回應,並使用 Pydantic 模型 `Message`,你可以這樣寫:
+
+{* ../../docs_src/additional_responses/tutorial001_py310.py hl[18,22] *}
+
+/// note | 注意
+
+請記住你必須直接回傳 `JSONResponse`。
+
+///
+
+/// info | 說明
+
+`model` 這個鍵不屬於 OpenAPI。
+
+**FastAPI** 會從這裡取出 Pydantic 模型,產生 JSON Schema,並放到正確位置。
+
+正確的位置是:
+
+* 在 `content` 這個鍵中,其值是一個 JSON 物件(`dict`),包含:
+ * 一個媒體型別作為鍵,例如 `application/json`,其值是另一個 JSON 物件,當中包含:
+ * 鍵 `schema`,其值是該模型的 JSON Schema,這裡就是正確的位置。
+ * **FastAPI** 會在這裡加入一個指向你 OpenAPI 中全域 JSON Schemas 的參照,而不是直接把它嵌入。如此一來,其他應用與用戶端可以直接使用那些 JSON Schemas,提供更好的程式碼產生工具等。
+
+///
+
+這個路徑操作在 OpenAPI 中產生的回應將會是:
+
+```JSON hl_lines="3-12"
+{
+ "responses": {
+ "404": {
+ "description": "Additional Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/Message"
+ }
+ }
+ }
+ },
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/Item"
+ }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ }
+ }
+ }
+}
+```
+
+這些 Schemas 會在 OpenAPI 中以參照的方式指向其他位置:
+
+```JSON hl_lines="4-16"
+{
+ "components": {
+ "schemas": {
+ "Message": {
+ "title": "Message",
+ "required": [
+ "message"
+ ],
+ "type": "object",
+ "properties": {
+ "message": {
+ "title": "Message",
+ "type": "string"
+ }
+ }
+ },
+ "Item": {
+ "title": "Item",
+ "required": [
+ "id",
+ "value"
+ ],
+ "type": "object",
+ "properties": {
+ "id": {
+ "title": "Id",
+ "type": "string"
+ },
+ "value": {
+ "title": "Value",
+ "type": "string"
+ }
+ }
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": [
+ "loc",
+ "msg",
+ "type"
+ ],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "msg": {
+ "title": "Message",
+ "type": "string"
+ },
+ "type": {
+ "title": "Error Type",
+ "type": "string"
+ }
+ }
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/ValidationError"
+ }
+ }
+ }
+ }
+ }
+ }
+}
+```
+
+## 主回應的其他媒體型別 { #additional-media-types-for-the-main-response }
+
+你可以用同一個 `responses` 參數,替相同的主回應新增不同的媒體型別。
+
+例如,你可以新增 `image/png` 這種媒體型別,宣告你的「路徑操作」可以回傳 JSON 物件(媒體型別為 `application/json`)或一張 PNG 圖片:
+
+{* ../../docs_src/additional_responses/tutorial002_py310.py hl[17:22,26] *}
+
+/// note | 注意
+
+請注意你必須直接用 `FileResponse` 回傳圖片。
+
+///
+
+/// info | 說明
+
+除非你在 `responses` 參數中明確指定不同的媒體型別,否則 FastAPI 會假設回應的媒體型別與主回應類別相同(預設為 `application/json`)。
+
+但如果你指定了一個自訂的回應類別,且其媒體型別為 `None`,那麼對於任何具關聯模型的額外回應,FastAPI 會使用 `application/json`。
+
+///
+
+## 結合資訊 { #combining-information }
+
+你也可以從多個地方結合回應資訊,包括 `response_model`、`status_code` 與 `responses` 參數。
+
+你可以宣告一個 `response_model`,使用預設狀態碼 `200`(或你需要的自訂狀態碼),然後在 `responses` 中直接於 OpenAPI Schema 為相同的回應宣告額外資訊。
+
+**FastAPI** 會保留 `responses` 提供的額外資訊,並把它和你模型的 JSON Schema 結合。
+
+例如,你可以宣告一個狀態碼為 `404` 的回應,使用一個 Pydantic 模型,並帶有自訂的 `description`。
+
+以及一個狀態碼為 `200` 的回應,使用你的 `response_model`,但包含自訂的 `example`:
+
+{* ../../docs_src/additional_responses/tutorial003_py310.py hl[20:31] *}
+
+以上都會被結合並包含在你的 OpenAPI 中,並顯示在 API 文件:
+
+

+
+## 結合預先定義與自訂的回應 { #combine-predefined-responses-and-custom-ones }
+
+你可能想要有一些適用於多個「路徑操作」的預先定義回應,但也想與每個「路徑操作」所需的自訂回應結合。
+
+在這些情況下,你可以使用 Python 的「解包」`dict` 技巧,透過 `**dict_to_unpack`:
+
+```Python
+old_dict = {
+ "old key": "old value",
+ "second old key": "second old value",
+}
+new_dict = {**old_dict, "new key": "new value"}
+```
+
+此處,`new_dict` 會包含 `old_dict` 的所有鍵值配對,再加上新的鍵值配對:
+
+```Python
+{
+ "old key": "old value",
+ "second old key": "second old value",
+ "new key": "new value",
+}
+```
+
+你可以用這個技巧在「路徑操作」中重用一些預先定義的回應,並與其他自訂回應結合。
+
+例如:
+
+{* ../../docs_src/additional_responses/tutorial004_py310.py hl[11:15,24] *}
+
+## 關於 OpenAPI 回應的更多資訊 { #more-information-about-openapi-responses }
+
+若要查看回應中究竟可以包含哪些內容,你可以參考 OpenAPI 規範中的這些章節:
+
+*
OpenAPI Responses 物件,其中包含 `Response Object`。
+*
OpenAPI Response 物件,你可以把這裡的任何內容直接放到 `responses` 參數內各個回應中。包含 `description`、`headers`、`content`(在其中宣告不同的媒體型別與 JSON Schemas)、以及 `links`。
diff --git a/docs/zh-hant/docs/advanced/additional-status-codes.md b/docs/zh-hant/docs/advanced/additional-status-codes.md
new file mode 100644
index 0000000000..450a4705aa
--- /dev/null
+++ b/docs/zh-hant/docs/advanced/additional-status-codes.md
@@ -0,0 +1,41 @@
+# 額外的狀態碼 { #additional-status-codes }
+
+在預設情況下,**FastAPI** 會使用 `JSONResponse` 傳回回應,並把你從你的「路徑操作(path operation)」回傳的內容放進該 `JSONResponse` 中。
+
+它會使用預設的狀態碼,或你在路徑操作中設定的狀態碼。
+
+## 額外的狀態碼 { #additional-status-codes_1 }
+
+如果你想在主要狀態碼之外再回傳其他狀態碼,可以直接回傳一個 `Response`(例如 `JSONResponse`),並直接設定你想要的額外狀態碼。
+
+例如,你想要有一個允許更新項目的路徑操作,成功時回傳 HTTP 狀態碼 200 "OK"。
+
+但你也希望它能接受新項目;當項目先前不存在時就建立它們,並回傳 HTTP 狀態碼 201 "Created"。
+
+要達成這點,匯入 `JSONResponse`,直接在那裡回傳內容,並設定你想要的 `status_code`:
+
+{* ../../docs_src/additional_status_codes/tutorial001_an_py310.py hl[4,25] *}
+
+/// warning
+
+當你直接回傳一個 `Response`(就像上面的範例),它會原封不動地被送出。
+
+不會再經過模型序列化等處理。
+
+請確認其中包含你要的資料,且各值是合法的 JSON(如果你使用的是 `JSONResponse`)。
+
+///
+
+/// note | 注意
+
+你也可以使用 `from starlette.responses import JSONResponse`。
+
+**FastAPI** 也將同樣的 `starlette.responses` 以 `fastapi.responses` 的形式提供,純粹是為了讓你(開發者)更方便。但大多數可用的回應類別其實都直接來自 Starlette。`status` 也一樣。
+
+///
+
+## OpenAPI 與 API 文件 { #openapi-and-api-docs }
+
+如果你直接回傳額外的狀態碼與回應,它們不會被包含進 OpenAPI 綱要(API 文件)中,因為 FastAPI 無法事先知道你會回傳什麼。
+
+但你可以在程式碼中補充文件,使用:[額外的回應](additional-responses.md){.internal-link target=_blank}。
diff --git a/docs/zh-hant/docs/advanced/advanced-dependencies.md b/docs/zh-hant/docs/advanced/advanced-dependencies.md
new file mode 100644
index 0000000000..472cf470b1
--- /dev/null
+++ b/docs/zh-hant/docs/advanced/advanced-dependencies.md
@@ -0,0 +1,163 @@
+# 進階相依 { #advanced-dependencies }
+
+## 參數化的相依 { #parameterized-dependencies }
+
+到目前為止看到的相依都是固定的函式或類別。
+
+但有些情況下,你可能想要能為相依設定參數,而不必宣告許多不同的函式或類別。
+
+想像我們想要一個相依,用來檢查查詢參數 `q` 是否包含某些固定內容。
+
+同時我們希望能將那個固定內容參數化。
+
+## 「callable」的實例 { #a-callable-instance }
+
+在 Python 中有一種方式可以讓一個類別的實例變成「callable」。
+
+不是類別本身(類別本來就可呼叫),而是該類別的實例。
+
+要做到這點,我們宣告一個 `__call__` 方法:
+
+{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[12] *}
+
+在這個情境中,**FastAPI** 會用這個 `__call__` 來檢查額外的參數與子相依,並在之後呼叫它,把回傳值傳遞給你的「路徑操作函式」中的參數。
+
+## 讓實例可參數化 { #parameterize-the-instance }
+
+接著,我們可以用 `__init__` 來宣告這個實例的參數,用以「參數化」這個相依:
+
+{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[9] *}
+
+在這裡,**FastAPI** 完全不會接觸或在意 `__init__`,我們會直接在自己的程式碼中使用它。
+
+## 建立一個實例 { #create-an-instance }
+
+我們可以這樣建立該類別的實例:
+
+{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[18] *}
+
+如此一來我們就能「參數化」相依,現在它內部含有 `"bar"`,作為屬性 `checker.fixed_content`。
+
+## 將實例作為相依使用 { #use-the-instance-as-a-dependency }
+
+然後,我們可以在 `Depends(checker)` 中使用這個 `checker`,而不是 `Depends(FixedContentQueryChecker)`,因為相依是那個實例 `checker`,不是類別本身。
+
+當解析相依時,**FastAPI** 會像這樣呼叫這個 `checker`:
+
+```Python
+checker(q="somequery")
+```
+
+...並將其回傳值,作為相依的值,以參數 `fixed_content_included` 傳給我們的「路徑操作函式」:
+
+{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[22] *}
+
+/// tip | 提示
+
+這一切現在看起來也許有點牽強,而且目前可能還不太清楚有何用途。
+
+這些範例刻意保持簡單,但展示了整個機制如何運作。
+
+在關於安全性的章節裡,有一些工具函式也是用同樣的方式實作。
+
+如果你理解了以上內容,你其實已經知道那些安全性工具在底層是如何運作的。
+
+///
+
+## 同時含有 `yield`、`HTTPException`、`except` 與背景任務的相依 { #dependencies-with-yield-httpexception-except-and-background-tasks }
+
+/// warning | 警告
+
+你很可能不需要這些技術細節。
+
+這些細節主要在於:如果你有一個 0.121.0 之前的 FastAPI 應用,並且在使用含有 `yield` 的相依時遇到問題,會對你有幫助。
+
+///
+
+含有 `yield` 的相依隨著時間演進,以涵蓋不同的使用情境並修正一些問題。以下是變更摘要。
+
+### 含有 `yield` 與 `scope` 的相依 { #dependencies-with-yield-and-scope }
+
+在 0.121.0 版中,FastAPI 為含有 `yield` 的相依加入了 `Depends(scope="function")` 的支援。
+
+使用 `Depends(scope="function")` 時,`yield` 之後的結束程式碼會在「路徑操作函式」執行完畢後立刻執行,在回應發送回客戶端之前。
+
+而當使用 `Depends(scope="request")`(預設值)時,`yield` 之後的結束程式碼會在回應送出之後才執行。
+
+你可以在文件中閱讀更多:[含有 `yield` 的相依 - 提前結束與 `scope`](../tutorial/dependencies/dependencies-with-yield.md#early-exit-and-scope)。
+
+### 含有 `yield` 與 `StreamingResponse` 的相依,技術細節 { #dependencies-with-yield-and-streamingresponse-technical-details }
+
+在 FastAPI 0.118.0 之前,如果你使用含有 `yield` 的相依,它會在「路徑操作函式」回傳之後、發送回應之前,執行結束程式碼。
+
+這樣做的用意是避免在等待回應穿越網路時,比必要的時間更久地占用資源。
+
+但這也意味著,如果你回傳的是 `StreamingResponse`,該含有 `yield` 的相依的結束程式碼早已執行完畢。
+
+例如,如果你在含有 `yield` 的相依中使用了一個資料庫 session,`StreamingResponse` 在串流資料時將無法使用該 session,因為它已在 `yield` 之後的結束程式碼中被關閉了。
+
+這個行為在 0.118.0 被還原,使得 `yield` 之後的結束程式碼會在回應送出之後才被執行。
+
+/// info | 資訊
+
+如下所見,這與 0.106.0 之前的行為非常類似,但對一些邊界情況做了多項改進與錯誤修正。
+
+///
+
+#### 需要提早執行結束程式碼的情境 { #use-cases-with-early-exit-code }
+
+有些特定條件的使用情境,可能會受益於舊行為(在送出回應之前執行含有 `yield` 的相依的結束程式碼)。
+
+例如,假設你在含有 `yield` 的相依中只用資料庫 session 來驗證使用者,而這個 session 之後並未在「路徑操作函式」中使用,僅在相依中使用,且回應需要很長時間才會送出,例如一個慢速傳送資料的 `StreamingResponse`,但它並沒有使用資料庫。
+
+在這種情況下,資料庫 session 會一直被保留到回應傳送完畢為止,但如果你根本不會用到它,就沒有必要一直持有它。
+
+可能會像這樣:
+
+{* ../../docs_src/dependencies/tutorial013_an_py310.py *}
+
+結束程式碼(自動關閉 `Session`)在:
+
+{* ../../docs_src/dependencies/tutorial013_an_py310.py ln[19:21] *}
+
+...會在回應完成傳送這些慢速資料後才執行:
+
+{* ../../docs_src/dependencies/tutorial013_an_py310.py ln[30:38] hl[31:33] *}
+
+但因為 `generate_stream()` 並未使用資料庫 session,實際上不需要在傳送回應時保持 session 開啟。
+
+如果你用的是 SQLModel(或 SQLAlchemy)且有這種特定情境,你可以在不再需要時明確關閉該 session:
+
+{* ../../docs_src/dependencies/tutorial014_an_py310.py ln[24:28] hl[28] *}
+
+如此一來,該 session 就會釋放資料庫連線,讓其他請求可以使用。
+
+如果你有不同的情境,需要從含有 `yield` 的相依中提早結束,請建立一個
GitHub 討論問題,描述你的具體情境,以及為何提早關閉含有 `yield` 的相依對你有幫助。
+
+如果有令人信服的案例需要在含有 `yield` 的相依中提前關閉,我會考慮加入一種新的選項,讓你可以選擇性啟用提前關閉。
+
+### 含有 `yield` 與 `except` 的相依,技術細節 { #dependencies-with-yield-and-except-technical-details }
+
+在 FastAPI 0.110.0 之前,如果你使用含有 `yield` 的相依,並且在該相依中用 `except` 捕捉到例外,且沒有再次拋出,那個例外會自動被拋出/轉交給任何例外處理器或內部伺服器錯誤處理器。
+
+在 0.110.0 版本中,這被修改以修復沒有處理器(內部伺服器錯誤)而被轉交的例外所造成的未處理記憶體消耗,並使其行為與一般 Python 程式碼一致。
+
+### 背景任務與含有 `yield` 的相依,技術細節 { #background-tasks-and-dependencies-with-yield-technical-details }
+
+在 FastAPI 0.106.0 之前,不可能在 `yield` 之後拋出例外;含有 `yield` 的相依的結束程式碼會在回應送出之後才執行,因此[例外處理器](../tutorial/handling-errors.md#install-custom-exception-handlers){.internal-link target=_blank} 早就已經跑完了。
+
+當初這樣設計主要是為了允許在背景任務中使用由相依「yield」出來的同一組物件,因為結束程式碼會在背景任務結束後才執行。
+
+在 FastAPI 0.106.0 中,這個行為被修改,目的是在等待回應穿越網路的期間,不要持有資源。
+
+/// tip | 提示
+
+此外,背景任務通常是一組獨立的邏輯,應該用自己的資源(例如自己的資料庫連線)來處理。
+
+這樣你的程式碼通常會更乾淨。
+
+///
+
+如果你先前依賴這種行為,現在應該在背景任務本身裡建立所需資源,並且只使用不依賴含有 `yield` 的相依之資源的資料。
+
+例如,不要共用同一個資料庫 session,而是在背景任務中建立一個新的資料庫 session,並用這個新的 session 從資料庫取得物件。接著,在呼叫背景任務函式時,不是傳遞資料庫物件本身,而是傳遞該物件的 ID,然後在背景任務函式內再透過這個 ID 取得物件。
diff --git a/docs/zh-hant/docs/advanced/advanced-python-types.md b/docs/zh-hant/docs/advanced/advanced-python-types.md
new file mode 100644
index 0000000000..ffa139427a
--- /dev/null
+++ b/docs/zh-hant/docs/advanced/advanced-python-types.md
@@ -0,0 +1,61 @@
+# 進階 Python 型別 { #advanced-python-types }
+
+以下是一些在使用 Python 型別時可能有用的額外想法。
+
+## 使用 `Union` 或 `Optional` { #using-union-or-optional }
+
+如果你的程式碼因某些原因無法使用 `|`,例如不是在型別註記中,而是在像 `response_model=` 之類的參數位置,那麼你可以用 `typing` 中的 `Union` 來取代豎線(`|`)。
+
+例如,你可以宣告某個值可以是 `str` 或 `None`:
+
+```python
+from typing import Union
+
+
+def say_hi(name: Union[str, None]):
+ print(f"Hi {name}!")
+```
+
+在 `typing` 中也有用 `Optional` 宣告某個值可以是 `None` 的速記法。
+
+以下是我個人(非常主觀)的建議:
+
+* 🚨 避免使用 `Optional[SomeType]`
+* 改為 ✨ 使用 `Union[SomeType, None]` ✨。
+
+兩者等價且底層相同,但我會推薦用 `Union` 而不要用 `Optional`,因為「optional」這個詞看起來會讓人以為這個值是可選的,但實際上它的意思是「可以是 `None`」,即使它不是可選的、仍然是必填。
+
+我認為 `Union[SomeType, None]` 更能清楚表達其含義。
+
+這只是措辭與命名問題,但這些詞會影響你與團隊成員對程式碼的理解。
+
+例如,看看下面這個函式:
+
+```python
+from typing import Optional
+
+
+def say_hi(name: Optional[str]):
+ print(f"Hey {name}!")
+```
+
+參數 `name` 被標註為 `Optional[str]`,但它並不是可選的;你不能在沒有該參數的情況下呼叫這個函式:
+
+```Python
+say_hi() # 糟了,這會拋出錯誤!😱
+```
+
+參數 `name` 仍是必填(不是可選),因為它沒有預設值。不過,`name` 可以接受 `None` 作為值:
+
+```Python
+say_hi(name=None) # 這可行,None 是有效的 🎉
+```
+
+好消息是,多數情況下你可以直接用 `|` 來定義型別聯集:
+
+```python
+def say_hi(name: str | None):
+ print(f"Hey {name}!")
+```
+
+因此,通常你不必為 `Optional` 與 `Union` 這些名稱操心。😎
diff --git a/docs/zh-hant/docs/advanced/async-tests.md b/docs/zh-hant/docs/advanced/async-tests.md
new file mode 100644
index 0000000000..cb7430bf6e
--- /dev/null
+++ b/docs/zh-hant/docs/advanced/async-tests.md
@@ -0,0 +1,99 @@
+# 非同步測試 { #async-tests }
+
+你已經看過如何使用提供的 `TestClient` 來測試你的 FastAPI 應用。到目前為止,你只看到如何撰寫同步測試,沒有使用 `async` 函式。
+
+在測試中能使用非同步函式會很有用,例如當你以非同步方式查詢資料庫時。想像你想測試發送請求到 FastAPI 應用,然後在使用非同步資料庫函式庫時,驗證後端是否成功把正確資料寫入資料庫。
+
+來看看怎麼做。
+
+## pytest.mark.anyio { #pytest-mark-anyio }
+
+若要在測試中呼叫非同步函式,測試函式本身也必須是非同步的。AnyIO 為此提供了一個好用的外掛,讓我們可以標示某些測試函式以非同步方式執行。
+
+## HTTPX { #httpx }
+
+即使你的 FastAPI 應用使用一般的 `def` 函式而非 `async def`,它在底層仍然是個 `async` 應用。
+
+`TestClient` 在內部做了一些魔法,讓我們能在一般的 `def` 測試函式中,使用標準 pytest 來呼叫非同步的 FastAPI 應用。但當我們在非同步函式中使用它時,這個魔法就不再奏效了。也就是說,當以非同步方式執行測試時,就不能在測試函式內使用 `TestClient`。
+
+`TestClient` 是建立在
HTTPX 之上,所幸我們可以直接使用它來測試 API。
+
+## 範例 { #example }
+
+作為簡單範例,讓我們考慮與[更大型的應用](../tutorial/bigger-applications.md){.internal-link target=_blank}與[測試](../tutorial/testing.md){.internal-link target=_blank}中描述的類似檔案結構:
+
+```
+.
+├── app
+│ ├── __init__.py
+│ ├── main.py
+│ └── test_main.py
+```
+
+檔案 `main.py` 會是:
+
+{* ../../docs_src/async_tests/app_a_py310/main.py *}
+
+檔案 `test_main.py` 會包含針對 `main.py` 的測試,現在可能像這樣:
+
+{* ../../docs_src/async_tests/app_a_py310/test_main.py *}
+
+## 執行 { #run-it }
+
+如常執行測試:
+
+
+
+```console
+$ pytest
+
+---> 100%
+```
+
+
+
+## 詳解 { #in-detail }
+
+標記 `@pytest.mark.anyio` 告訴 pytest 這個測試函式應以非同步方式執行:
+
+{* ../../docs_src/async_tests/app_a_py310/test_main.py hl[7] *}
+
+/// tip
+
+注意,測試函式現在是 `async def`,而不是像使用 `TestClient` 時那樣僅用 `def`。
+
+///
+
+接著,我們可以用該應用建立 `AsyncClient`,並以 `await` 發送非同步請求。
+
+{* ../../docs_src/async_tests/app_a_py310/test_main.py hl[9:12] *}
+
+這等同於:
+
+```Python
+response = client.get('/')
+```
+
+也就是先前用 `TestClient` 發送請求時所用的寫法。
+
+/// tip
+
+注意,對新的 `AsyncClient` 需搭配 async/await —— 請求是非同步的。
+
+///
+
+/// warning
+
+如果你的應用仰賴 lifespan 事件,`AsyncClient` 不會觸發這些事件。若要確保它們被觸發,請使用
florimondmanca/asgi-lifespan 的 `LifespanManager`。
+
+///
+
+## 其他非同步函式呼叫 { #other-asynchronous-function-calls }
+
+由於測試函式現在是非同步的,你也可以在測試中呼叫(並 `await`)其他 `async` 函式,和在程式碼其他地方一樣。
+
+/// tip
+
+如果在將非同步呼叫整合進測試時遇到 `RuntimeError: Task attached to a different loop`(例如使用
MongoDB 的 MotorClient 時),請記得:需要事件迴圈的物件只應在非同步函式內實例化,例如在 `@app.on_event("startup")` 回呼中。
+
+///
diff --git a/docs/zh-hant/docs/advanced/behind-a-proxy.md b/docs/zh-hant/docs/advanced/behind-a-proxy.md
new file mode 100644
index 0000000000..71a0557afd
--- /dev/null
+++ b/docs/zh-hant/docs/advanced/behind-a-proxy.md
@@ -0,0 +1,466 @@
+# 在代理之後 { #behind-a-proxy }
+
+在許多情況下,你會在 FastAPI 應用前面放一個「代理」(proxy),例如 Traefik 或 Nginx。
+
+這些代理可以處理 HTTPS 憑證等事務。
+
+## 代理轉發標頭 { #proxy-forwarded-headers }
+
+在你的應用前方的「代理」通常會在將請求送給你的「伺服器」之前,臨時加入一些標頭,讓伺服器知道這個請求是由代理「轉發」過來的,並告訴它原始(公開)的 URL,包括網域、是否使用 HTTPS 等。
+
+「伺服器」程式(例如透過 FastAPI CLI 啟動的 Uvicorn)能夠解讀這些標頭,然後把該資訊傳遞給你的應用。
+
+但出於安全考量,因為伺服器並不知道自己位於受信任的代理之後,所以它不會解讀那些標頭。
+
+/// note | 技術細節
+
+代理相關的標頭有:
+
+*
X-Forwarded-For
+*
X-Forwarded-Proto
+*
X-Forwarded-Host
+
+///
+
+### 啟用代理轉發標頭 { #enable-proxy-forwarded-headers }
+
+你可以在啟動 FastAPI CLI 時使用「CLI 選項」`--forwarded-allow-ips`,並傳入允許解析這些轉發標頭的受信任 IP 位址。
+
+如果將其設為 `--forwarded-allow-ips="*"`,就會信任所有進來的 IP。
+
+如果你的「伺服器」位於受信任的「代理」之後,且只有代理會與它通訊,這樣會讓它接受該「代理」的任何 IP。
+
+
+
+```console
+$ fastapi run --forwarded-allow-ips="*"
+
+INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
+```
+
+
+
+### 使用 HTTPS 的重新導向 { #redirects-with-https }
+
+例如,假設你定義了一個「路徑操作(path operation)」`/items/`:
+
+{* ../../docs_src/behind_a_proxy/tutorial001_01_py310.py hl[6] *}
+
+如果用戶端嘗試前往 `/items`,預設會被重新導向到 `/items/`。
+
+但在設定「CLI 選項」`--forwarded-allow-ips` 之前,它可能會被重新導向到 `http://localhost:8000/items/`。
+
+不過,也許你的應用實際部署在 `https://mysuperapp.com`,那重新導向就應該是 `https://mysuperapp.com/items/`。
+
+設定 `--proxy-headers` 之後,FastAPI 就能重新導向到正確的位置。😎
+
+```
+https://mysuperapp.com/items/
+```
+
+/// tip
+
+如果你想了解更多 HTTPS 的內容,請參考指南[[關於 HTTPS](../deployment/https.md){.internal-link target=_blank}]。
+
+///
+
+### 代理轉發標頭如何運作 { #how-proxy-forwarded-headers-work }
+
+以下是「代理」在用戶端與「應用伺服器」之間加入轉發標頭的視覺化示意:
+
+```mermaid
+sequenceDiagram
+ participant Client
+ participant Proxy as Proxy/Load Balancer
+ participant Server as FastAPI Server
+
+ Client->>Proxy: HTTPS Request
Host: mysuperapp.com
Path: /items
+
+ Note over Proxy: Proxy adds forwarded headers
+
+ Proxy->>Server: HTTP Request
X-Forwarded-For: [client IP]
X-Forwarded-Proto: https
X-Forwarded-Host: mysuperapp.com
Path: /items
+
+ Note over Server: Server interprets headers
(if --forwarded-allow-ips is set)
+
+ Server->>Proxy: HTTP Response
with correct HTTPS URLs
+
+ Proxy->>Client: HTTPS Response
+```
+
+「代理」會攔截原始用戶端請求,並在將其轉交給「應用伺服器」之前加入特殊的「轉發」標頭(`X-Forwarded-*`)。
+
+這些標頭會保留原始請求中原本會遺失的資訊:
+
+* X-Forwarded-For:原始用戶端的 IP 位址
+* X-Forwarded-Proto:原始協定(`https`)
+* X-Forwarded-Host:原始主機(`mysuperapp.com`)
+
+當以 `--forwarded-allow-ips` 設定好 FastAPI CLI 後,它會信任並使用這些標頭,例如在重新導向時產生正確的 URL。
+
+## 具有移除路徑前綴的代理 { #proxy-with-a-stripped-path-prefix }
+
+你可能會有一個會為你的應用加入路徑前綴的代理。
+
+在這些情況下,你可以使用 `root_path` 來設定你的應用。
+
+`root_path` 是 ASGI 規格(FastAPI 透過 Starlette 所遵循的規格)所提供的機制。
+
+`root_path` 用來處理這些特定情境。
+
+在掛載子應用時,內部也會使用它。
+
+這種「具有移除路徑前綴的代理」情況,代表你在程式碼中宣告了 `/app` 的路徑,但你在上面又加了一層(代理),把你的 FastAPI 應用放在像是 `/api/v1` 這樣的路徑底下。
+
+在這種情況下,原本的 `/app` 路徑實際上會以 `/api/v1/app` 對外提供服務。
+
+即使你的程式碼都是以只有 `/app` 為前提撰寫的。
+
+{* ../../docs_src/behind_a_proxy/tutorial001_py310.py hl[6] *}
+
+而代理會在把請求轉交給應用伺服器(多半是透過 FastAPI CLI 啟動的 Uvicorn)之前,動態地「移除」這個「路徑前綴」,讓你的應用仍然以為自己是在 `/app` 底下被提供,這樣你就不需要把整個程式碼都改成包含 `/api/v1` 這個前綴。
+
+到目前為止,一切都會如常運作。
+
+但是,當你打開整合的文件 UI(前端)時,它會預期在 `/openapi.json` 取得 OpenAPI 模式,而不是在 `/api/v1/openapi.json`。
+
+因此,前端(在瀏覽器中執行)會嘗試存取 `/openapi.json`,但無法取得 OpenAPI 模式。
+
+因為我們的應用前面有一個將路徑前綴設定為 `/api/v1` 的代理,所以前端需要從 `/api/v1/openapi.json` 取得 OpenAPI 模式。
+
+```mermaid
+graph LR
+
+browser("Browser")
+proxy["Proxy on http://0.0.0.0:9999/api/v1/app"]
+server["Server on http://127.0.0.1:8000/app"]
+
+browser --> proxy
+proxy --> server
+```
+
+/// tip
+
+IP `0.0.0.0` 通常用來表示程式在該機器/伺服器上的所有可用 IP 上監聽。
+
+///
+
+文件 UI 也需要 OpenAPI 模式宣告此 API 的 `server` 位在 `/api/v1`(代理之後)。例如:
+
+```JSON hl_lines="4-8"
+{
+ "openapi": "3.1.0",
+ // 其他內容
+ "servers": [
+ {
+ "url": "/api/v1"
+ }
+ ],
+ "paths": {
+ // 其他內容
+ }
+}
+```
+
+在這個例子中,「Proxy」可以是 **Traefik**。而伺服器可以是以 **Uvicorn** 啟動的 FastAPI CLI,運行你的 FastAPI 應用。
+
+### 提供 `root_path` { #providing-the-root-path }
+
+要達成這一點,你可以像這樣使用命令列選項 `--root-path`:
+
+
+
+```console
+$ fastapi run main.py --forwarded-allow-ips="*" --root-path /api/v1
+
+INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
+```
+
+
+
+如果你使用 Hypercorn,它也有 `--root-path` 這個選項。
+
+/// note | 技術細節
+
+ASGI 規格針對這種用例定義了 `root_path`。
+
+而命令列選項 `--root-path` 就是提供該 `root_path`。
+
+///
+
+### 檢視目前的 `root_path` { #checking-the-current-root-path }
+
+你可以在每個請求中取得應用使用的 `root_path`,它是 `scope` 字典的一部分(ASGI 規格的一部分)。
+
+這裡我們把它放到回傳訊息中只是為了示範。
+
+{* ../../docs_src/behind_a_proxy/tutorial001_py310.py hl[8] *}
+
+接著,如果你用下列方式啟動 Uvicorn:
+
+
+
+```console
+$ fastapi run main.py --forwarded-allow-ips="*" --root-path /api/v1
+
+INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
+```
+
+
+
+回應會像是:
+
+```JSON
+{
+ "message": "Hello World",
+ "root_path": "/api/v1"
+}
+```
+
+### 在 FastAPI 應用中設定 `root_path` { #setting-the-root-path-in-the-fastapi-app }
+
+或者,如果你無法提供像 `--root-path` 這樣的命令列選項(或等效方式),你可以在建立 FastAPI 應用時設定 `root_path` 參數:
+
+{* ../../docs_src/behind_a_proxy/tutorial002_py310.py hl[3] *}
+
+把 `root_path` 傳給 `FastAPI` 等同於在 Uvicorn 或 Hypercorn 上使用命令列選項 `--root-path`。
+
+### 關於 `root_path` { #about-root-path }
+
+請記住,伺服器(Uvicorn)除了把 `root_path` 傳給應用之外,不會拿它做其他用途。
+
+但如果你用瀏覽器前往
http://127.0.0.1:8000/app,你會看到一般的回應:
+
+```JSON
+{
+ "message": "Hello World",
+ "root_path": "/api/v1"
+}
+```
+
+因此,它不會預期被以 `http://127.0.0.1:8000/api/v1/app` 的方式存取。
+
+Uvicorn 會預期代理以 `http://127.0.0.1:8000/app` 來存取 Uvicorn,而由代理負責在上層加上額外的 `/api/v1` 前綴。
+
+## 關於「移除路徑前綴」的代理 { #about-proxies-with-a-stripped-path-prefix }
+
+請記住,具有「移除路徑前綴」的代理只是其中一種設定方式。
+
+在許多情況下,預設可能是不移除路徑前綴。
+
+在那種情況(沒有移除路徑前綴)下,代理會監聽像是 `https://myawesomeapp.com`,然後當瀏覽器前往 `https://myawesomeapp.com/api/v1/app`,而你的伺服器(例如 Uvicorn)在 `http://127.0.0.1:8000` 監聽時,該代理(不移除路徑前綴)就會以同樣的路徑去存取 Uvicorn:`http://127.0.0.1:8000/api/v1/app`。
+
+## 在本機使用 Traefik 測試 { #testing-locally-with-traefik }
+
+你可以很容易地用
Traefik 在本機跑一個「移除路徑前綴」的測試。
+
+
下載 Traefik,它是一個單一的執行檔,你可以解壓縮後直接在終端機執行。
+
+然後建立一個 `traefik.toml` 檔案,內容如下:
+
+```TOML hl_lines="3"
+[entryPoints]
+ [entryPoints.http]
+ address = ":9999"
+
+[providers]
+ [providers.file]
+ filename = "routes.toml"
+```
+
+這告訴 Traefik 監聽 9999 埠,並使用另一個檔案 `routes.toml`。
+
+/// tip
+
+我們使用 9999 埠而不是標準的 HTTP 80 埠,這樣你就不需要以管理員(`sudo`)權限來執行。
+
+///
+
+接著建立另一個 `routes.toml` 檔案:
+
+```TOML hl_lines="5 12 20"
+[http]
+ [http.middlewares]
+
+ [http.middlewares.api-stripprefix.stripPrefix]
+ prefixes = ["/api/v1"]
+
+ [http.routers]
+
+ [http.routers.app-http]
+ entryPoints = ["http"]
+ service = "app"
+ rule = "PathPrefix(`/api/v1`)"
+ middlewares = ["api-stripprefix"]
+
+ [http.services]
+
+ [http.services.app]
+ [http.services.app.loadBalancer]
+ [[http.services.app.loadBalancer.servers]]
+ url = "http://127.0.0.1:8000"
+```
+
+這個檔案把 Traefik 設定為使用 `/api/v1` 的路徑前綴。
+
+然後 Traefik 會把它的請求轉發到在 `http://127.0.0.1:8000` 上運行的 Uvicorn。
+
+現在啟動 Traefik:
+
+
+
+```console
+$ ./traefik --configFile=traefik.toml
+
+INFO[0000] Configuration loaded from file: /home/user/awesomeapi/traefik.toml
+```
+
+
+
+然後啟動你的應用,使用 `--root-path` 選項:
+
+
+
+```console
+$ fastapi run main.py --forwarded-allow-ips="*" --root-path /api/v1
+
+INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
+```
+
+
+
+### 檢查回應 { #check-the-responses }
+
+現在,如果你前往 Uvicorn 的埠:
http://127.0.0.1:8000/app,你會看到一般的回應:
+
+```JSON
+{
+ "message": "Hello World",
+ "root_path": "/api/v1"
+}
+```
+
+/// tip
+
+注意,儘管你是用 `http://127.0.0.1:8000/app` 存取,它仍然顯示從 `--root-path` 選項取得的 `root_path` 為 `/api/v1`。
+
+///
+
+接著打開使用 Traefik 埠且包含路徑前綴的 URL:
http://127.0.0.1:9999/api/v1/app。
+
+我們會得到相同的回應:
+
+```JSON
+{
+ "message": "Hello World",
+ "root_path": "/api/v1"
+}
+```
+
+但這次是在由代理提供的、帶有前綴路徑的 URL:`/api/v1`。
+
+當然,這裡的重點是大家都會透過代理來存取應用,所以帶有 `/api/v1` 路徑前綴的版本才是「正確」的。
+
+而沒有路徑前綴的版本(`http://127.0.0.1:8000/app`),也就是直接由 Uvicorn 提供的,應該只給「代理」(Traefik)來存取。
+
+這展示了代理(Traefik)如何使用路徑前綴,以及伺服器(Uvicorn)如何使用 `--root-path` 選項提供的 `root_path`。
+
+### 檢查文件 UI { #check-the-docs-ui }
+
+接下來是有趣的部分。✨
+
+「正式」的存取方式應該是透過我們定義了路徑前綴的代理。因此,如我們預期,如果你直接透過 Uvicorn 供應的文件 UI、而 URL 中沒有該路徑前綴,那它不會運作,因為它預期要透過代理來存取。
+
+你可以在
http://127.0.0.1:8000/docs 檢查:
+
+

+
+但如果我們改用「正式」的 URL,也就是使用埠號 `9999` 的代理、並在 `/api/v1/docs`,它就能正確運作了!🎉
+
+你可以在
http://127.0.0.1:9999/api/v1/docs 檢查:
+
+

+
+正如我們所希望的那樣。✔️
+
+這是因為 FastAPI 使用這個 `root_path` 來在 OpenAPI 中建立預設的 `server`,其 URL 就是 `root_path` 所提供的值。
+
+## 其他 servers { #additional-servers }
+
+/// warning
+
+這是更進階的用法。你可以選擇略過。
+
+///
+
+預設情況下,FastAPI 會在 OpenAPI 模式中建立一個 `server`,其 URL 為 `root_path`。
+
+但你也可以另外提供其他 `servers`,例如你想要用「同一份」文件 UI 來與測試(staging)與正式(production)環境互動。
+
+如果你傳入自訂的 `servers` 清單,且同時存在 `root_path`(因為你的 API 位於代理之後),FastAPI 會在清單開頭插入一個 `server`,其 URL 為該 `root_path`。
+
+例如:
+
+{* ../../docs_src/behind_a_proxy/tutorial003_py310.py hl[4:7] *}
+
+將會產生如下的 OpenAPI 模式:
+
+```JSON hl_lines="5-7"
+{
+ "openapi": "3.1.0",
+ // 其他內容
+ "servers": [
+ {
+ "url": "/api/v1"
+ },
+ {
+ "url": "https://stag.example.com",
+ "description": "Staging environment"
+ },
+ {
+ "url": "https://prod.example.com",
+ "description": "Production environment"
+ }
+ ],
+ "paths": {
+ // 其他內容
+ }
+}
+```
+
+/// tip
+
+注意自動產生的 server,其 `url` 值為 `/api/v1`,取自 `root_path`。
+
+///
+
+在位於
http://127.0.0.1:9999/api/v1/docs 的文件 UI 中看起來會像這樣:
+
+

+
+/// tip
+
+文件 UI 會與你所選擇的 server 互動。
+
+///
+
+/// note | 技術細節
+
+OpenAPI 規格中的 `servers` 屬性是可選的。
+
+如果你沒有指定 `servers` 參數,且 `root_path` 等於 `/`,則在產生的 OpenAPI 模式中會完全省略 `servers` 屬性(預設行為),這等同於只有一個 `url` 值為 `/` 的 server。
+
+///
+
+### 停用從 `root_path` 自動加入的 server { #disable-automatic-server-from-root-path }
+
+如果你不希望 FastAPI 使用 `root_path` 自動加入一個 server,你可以使用參數 `root_path_in_servers=False`:
+
+{* ../../docs_src/behind_a_proxy/tutorial004_py310.py hl[9] *}
+
+這樣它就不會被包含在 OpenAPI 模式中。
+
+## 掛載子應用 { #mounting-a-sub-application }
+
+如果你需要在同時使用具有 `root_path` 的代理時,掛載一個子應用(如[[子應用 - 掛載](sub-applications.md){.internal-link target=_blank}]中所述),可以像平常一樣操作,正如你所預期的那樣。
+
+FastAPI 會在內部智慧地使用 `root_path`,所以一切都能順利運作。✨
diff --git a/docs/zh-hant/docs/advanced/custom-response.md b/docs/zh-hant/docs/advanced/custom-response.md
new file mode 100644
index 0000000000..b723aa82f6
--- /dev/null
+++ b/docs/zh-hant/docs/advanced/custom-response.md
@@ -0,0 +1,312 @@
+# 自訂回應——HTML、串流、檔案與其他 { #custom-response-html-stream-file-others }
+
+預設情況下,**FastAPI** 會使用 `JSONResponse` 傳回回應。
+
+你可以像在[直接回傳 Response](response-directly.md){.internal-link target=_blank} 中所示,直接回傳一個 `Response` 來覆寫它。
+
+但如果你直接回傳一個 `Response`(或其子類別,如 `JSONResponse`),資料將不會被自動轉換(即使你宣告了 `response_model`),而且文件也不會自動產生(例如,在產生的 OpenAPI 中包含 HTTP 標頭 `Content-Type` 的特定「media type」)。
+
+你也可以在「路徑操作裝飾器」中使用 `response_class` 參數,宣告要使用的 `Response`(例如任意 `Response` 子類別)。
+
+你從「路徑操作函式」回傳的內容,會被放進該 `Response` 中。
+
+若該 `Response` 的 media type 是 JSON(`application/json`),像 `JSONResponse` 與 `UJSONResponse`,則你回傳的資料會自動以你在「路徑操作裝飾器」中宣告的 Pydantic `response_model` 進行轉換(與過濾)。
+
+/// note
+
+若你使用的回應類別沒有 media type,FastAPI 會假設你的回應沒有內容,因此不會在產生的 OpenAPI 文件中記錄回應格式。
+
+///
+
+## 使用 `ORJSONResponse` { #use-orjsonresponse }
+
+例如,若你在追求效能,你可以安裝並使用
`orjson`,並將回應設為 `ORJSONResponse`。
+
+匯入你想使用的 `Response` 類別(子類),並在「路徑操作裝飾器」中宣告它。
+
+對於大型回應,直接回傳 `Response` 會比回傳 `dict` 快得多。
+
+這是因為預設情況下,FastAPI 會檢查每個項目並確認它能被序列化為 JSON,使用與教學中說明的相同[JSON 相容編碼器](../tutorial/encoder.md){.internal-link target=_blank}。這使你可以回傳「任意物件」,例如資料庫模型。
+
+但如果你確定你回傳的內容「可以用 JSON 序列化」,你可以直接將它傳給回應類別,避免 FastAPI 在把你的回傳內容交給回應類別之前,先經過 `jsonable_encoder` 所帶來的額外開銷。
+
+{* ../../docs_src/custom_response/tutorial001b_py310.py hl[2,7] *}
+
+/// info
+
+參數 `response_class` 也會用來定義回應的「media type」。
+
+在此情況下,HTTP 標頭 `Content-Type` 會被設為 `application/json`。
+
+而且它會以此形式被記錄到 OpenAPI 中。
+
+///
+
+/// tip
+
+`ORJSONResponse` 只在 FastAPI 中可用,在 Starlette 中不可用。
+
+///
+
+## HTML 回應 { #html-response }
+
+要直接從 **FastAPI** 回傳 HTML,使用 `HTMLResponse`。
+
+- 匯入 `HTMLResponse`。
+- 在「路徑操作裝飾器」中,將 `HTMLResponse` 傳給 `response_class` 參數。
+
+{* ../../docs_src/custom_response/tutorial002_py310.py hl[2,7] *}
+
+/// info
+
+參數 `response_class` 也會用來定義回應的「media type」。
+
+在此情況下,HTTP 標頭 `Content-Type` 會被設為 `text/html`。
+
+而且它會以此形式被記錄到 OpenAPI 中。
+
+///
+
+### 回傳 `Response` { #return-a-response }
+
+如[直接回傳 Response](response-directly.md){.internal-link target=_blank} 所示,你也可以在「路徑操作」中直接回傳以覆寫回應。
+
+上面的相同範例,回傳 `HTMLResponse`,可以像這樣:
+
+{* ../../docs_src/custom_response/tutorial003_py310.py hl[2,7,19] *}
+
+/// warning
+
+由你的「路徑操作函式」直接回傳的 `Response` 不會被記錄進 OpenAPI(例如不會記錄 `Content-Type`),也不會出現在自動產生的互動式文件中。
+
+///
+
+/// info
+
+當然,實際的 `Content-Type` 標頭、狀態碼等,會來自你回傳的 `Response` 物件。
+
+///
+
+### 在 OpenAPI 中文件化並覆寫 `Response` { #document-in-openapi-and-override-response }
+
+如果你想在函式內覆寫回應,同時又要在 OpenAPI 中記錄「media type」,你可以同時使用 `response_class` 參數並回傳一個 `Response` 物件。
+
+此時,`response_class` 只會用於記錄該 OpenAPI「路徑操作」,而你回傳的 `Response` 將會如實使用。
+
+#### 直接回傳 `HTMLResponse` { #return-an-htmlresponse-directly }
+
+例如,可能會像這樣:
+
+{* ../../docs_src/custom_response/tutorial004_py310.py hl[7,21,23] *}
+
+在這個例子中,函式 `generate_html_response()` 已經產生並回傳了一個 `Response`,而不是把 HTML 當作 `str` 回傳。
+
+透過回傳 `generate_html_response()` 的結果,你其實已經回傳了一個 `Response`,這會覆寫 **FastAPI** 的預設行為。
+
+但因為你同時也在 `response_class` 中傳入了 `HTMLResponse`,**FastAPI** 便能在 OpenAPI 與互動式文件中,將其以 `text/html` 的 HTML 形式記錄:
+
+

+
+## 可用的回應 { #available-responses }
+
+以下是一些可用的回應類別。
+
+記得你可以用 `Response` 回傳其他任何東西,甚至建立自訂的子類別。
+
+/// note | 技術細節
+
+你也可以使用 `from starlette.responses import HTMLResponse`。
+
+**FastAPI** 將 `starlette.responses` 以 `fastapi.responses` 提供給你(開發者)做為方便之用。但大多數可用的回應其實直接來自 Starlette。
+
+///
+
+### `Response` { #response }
+
+主要的 `Response` 類別,其他回應皆繼承自它。
+
+你也可以直接回傳它。
+
+它接受以下參數:
+
+- `content` - `str` 或 `bytes`。
+- `status_code` - `int` 類型的 HTTP 狀態碼。
+- `headers` - 由字串組成的 `dict`。
+- `media_type` - 描述 media type 的 `str`。例如 `"text/html"`。
+
+FastAPI(實際上是 Starlette)會自動包含 Content-Length 標頭。也會根據 `media_type`(並為文字型別附加 charset)包含 Content-Type 標頭。
+
+{* ../../docs_src/response_directly/tutorial002_py310.py hl[1,18] *}
+
+### `HTMLResponse` { #htmlresponse }
+
+接收文字或位元組並回傳 HTML 回應,如上所述。
+
+### `PlainTextResponse` { #plaintextresponse }
+
+接收文字或位元組並回傳純文字回應。
+
+{* ../../docs_src/custom_response/tutorial005_py310.py hl[2,7,9] *}
+
+### `JSONResponse` { #jsonresponse }
+
+接收資料並回傳 `application/json` 編碼的回應。
+
+這是 **FastAPI** 的預設回應,如上所述。
+
+### `ORJSONResponse` { #orjsonresponse }
+
+使用
`orjson` 的快速替代 JSON 回應,如上所述。
+
+/// info
+
+這需要安裝 `orjson`,例如使用 `pip install orjson`。
+
+///
+
+### `UJSONResponse` { #ujsonresponse }
+
+使用
`ujson` 的替代 JSON 回應。
+
+/// info
+
+這需要安裝 `ujson`,例如使用 `pip install ujson`。
+
+///
+
+/// warning
+
+`ujson` 在處理某些邊界情況時,沒那麼嚴謹,較 Python 內建實作更「隨意」。
+
+///
+
+{* ../../docs_src/custom_response/tutorial001_py310.py hl[2,7] *}
+
+/// tip
+
+`ORJSONResponse` 可能是更快的替代方案。
+
+///
+
+### `RedirectResponse` { #redirectresponse }
+
+回傳一個 HTTP 重新導向。預設使用 307 狀態碼(Temporary Redirect)。
+
+你可以直接回傳 `RedirectResponse`:
+
+{* ../../docs_src/custom_response/tutorial006_py310.py hl[2,9] *}
+
+---
+
+或者你可以在 `response_class` 參數中使用它:
+
+{* ../../docs_src/custom_response/tutorial006b_py310.py hl[2,7,9] *}
+
+若這麼做,你就可以在「路徑操作函式」中直接回傳 URL。
+
+在此情況下,所使用的 `status_code` 會是 `RedirectResponse` 的預設值 `307`。
+
+---
+
+你也可以同時搭配 `status_code` 與 `response_class` 參數:
+
+{* ../../docs_src/custom_response/tutorial006c_py310.py hl[2,7,9] *}
+
+### `StreamingResponse` { #streamingresponse }
+
+接收一個 async 產生器或一般的產生器/疊代器,並以串流方式傳送回應本文。
+
+{* ../../docs_src/custom_response/tutorial007_py310.py hl[2,14] *}
+
+#### 對「類檔案物件」使用 `StreamingResponse` { #using-streamingresponse-with-file-like-objects }
+
+如果你有一個
類檔案(file-like)物件(例如 `open()` 回傳的物件),你可以建立一個產生器函式來疊代該類檔案物件。
+
+如此一來,你不必先把它全部讀進記憶體,就能將那個產生器函式傳給 `StreamingResponse` 並回傳。
+
+這也包含許多用於雲端儲存、影像/影音處理等的函式庫。
+
+{* ../../docs_src/custom_response/tutorial008_py310.py hl[2,10:12,14] *}
+
+1. 這是產生器函式。因為它內含 `yield` 陳述式,所以是「產生器函式」。
+2. 透過 `with` 區塊,我們確保在產生器函式結束後關閉類檔案物件。因此,在完成傳送回應後就會關閉。
+3. 這個 `yield from` 告訴函式去疊代名為 `file_like` 的東西。對於每個被疊代到的部分,就把該部分當作此產生器函式(`iterfile`)的輸出進行 `yield`。
+
+ 因此,這是一個把「生成」工作在內部轉交給其他東西的產生器函式。
+
+ 透過這樣做,我們可以把它放進 `with` 區塊,藉此確保在完成後關閉類檔案物件。
+
+/// tip
+
+注意,這裡我們使用的是標準的 `open()`,它不支援 `async` 與 `await`,因此我們用一般的 `def` 來宣告路徑操作。
+
+///
+
+### `FileResponse` { #fileresponse }
+
+以非同步串流方式將檔案作為回應。
+
+它在初始化時所需的參數與其他回應型別不同:
+
+- `path` - 要串流的檔案路徑。
+- `headers` - 要包含的自訂標頭,字典形式。
+- `media_type` - 描述 media type 的字串。若未設定,將根據檔名或路徑推斷 media type。
+- `filename` - 若設定,會包含在回應的 `Content-Disposition` 中。
+
+檔案回應會包含適當的 `Content-Length`、`Last-Modified` 與 `ETag` 標頭。
+
+{* ../../docs_src/custom_response/tutorial009_py310.py hl[2,10] *}
+
+你也可以使用 `response_class` 參數:
+
+{* ../../docs_src/custom_response/tutorial009b_py310.py hl[2,8,10] *}
+
+在此情況下,你可以在「路徑操作函式」中直接回傳檔案路徑。
+
+## 自訂回應類別 { #custom-response-class }
+
+你可以建立自己的自訂回應類別,繼承自 `Response` 並加以使用。
+
+例如,假設你要使用
`orjson`,但想套用一些未包含在 `ORJSONResponse` 類別中的自訂設定。
+
+假設你想回傳縮排且格式化的 JSON,因此要使用 orjson 選項 `orjson.OPT_INDENT_2`。
+
+你可以建立 `CustomORJSONResponse`。你主要需要做的是建立一個 `Response.render(content)` 方法,將內容以 `bytes` 回傳:
+
+{* ../../docs_src/custom_response/tutorial009c_py310.py hl[9:14,17] *}
+
+現在,不再是回傳:
+
+```json
+{"message": "Hello World"}
+```
+
+……這個回應會回傳:
+
+```json
+{
+ "message": "Hello World"
+}
+```
+
+當然,你大概能找到比格式化 JSON 更好的方式來利用這個能力。😉
+
+## 預設回應類別 { #default-response-class }
+
+在建立 **FastAPI** 類別實例或 `APIRouter` 時,你可以指定預設要使用哪個回應類別。
+
+用來設定的是 `default_response_class` 參數。
+
+在下面的例子中,**FastAPI** 會在所有「路徑操作」中預設使用 `ORJSONResponse`,而不是 `JSONResponse`。
+
+{* ../../docs_src/custom_response/tutorial010_py310.py hl[2,4] *}
+
+/// tip
+
+你仍然可以在「路徑操作」中像以前一樣覆寫 `response_class`。
+
+///
+
+## 其他文件化選項 { #additional-documentation }
+
+你也可以在 OpenAPI 中使用 `responses` 宣告 media type 與其他許多細節:[在 OpenAPI 中的額外回應](additional-responses.md){.internal-link target=_blank}。
diff --git a/docs/zh-hant/docs/advanced/dataclasses.md b/docs/zh-hant/docs/advanced/dataclasses.md
new file mode 100644
index 0000000000..d586bd6844
--- /dev/null
+++ b/docs/zh-hant/docs/advanced/dataclasses.md
@@ -0,0 +1,87 @@
+# 使用 Dataclasses { #using-dataclasses }
+
+FastAPI 建立在 **Pydantic** 之上,我之前示範過如何使用 Pydantic 模型來宣告請求與回應。
+
+但 FastAPI 也同樣支援以相同方式使用
`dataclasses`:
+
+{* ../../docs_src/dataclasses_/tutorial001_py310.py hl[1,6:11,18:19] *}
+
+這之所以可行,要感謝 **Pydantic**,因為它
內建支援 `dataclasses`。
+
+所以,即使上面的程式碼沒有明確使用 Pydantic,FastAPI 仍會使用 Pydantic 將那些標準的 dataclass 轉換為 Pydantic 版本的 dataclass。
+
+而且當然一樣支援:
+
+- 資料驗證
+- 資料序列化
+- 資料文件化等
+
+它的運作方式與 Pydantic 模型相同;實際上,底層就是透過 Pydantic 達成的。
+
+/// info
+
+請記得,dataclass 無法做到 Pydantic 模型能做的一切。
+
+所以你可能仍然需要使用 Pydantic 模型。
+
+但如果你手邊剛好有一堆 dataclass,這是個不錯的小技巧,可以用來用 FastAPI 驅動一個 Web API。🤓
+
+///
+
+## 在 `response_model` 中使用 Dataclasses { #dataclasses-in-response-model }
+
+你也可以在 `response_model` 參數中使用 `dataclasses`:
+
+{* ../../docs_src/dataclasses_/tutorial002_py310.py hl[1,6:12,18] *}
+
+該 dataclass 會自動轉換為 Pydantic 的 dataclass。
+
+如此一來,其結構描述(schema)會顯示在 API 文件介面中:
+
+

+
+## 巢狀資料結構中的 Dataclasses { #dataclasses-in-nested-data-structures }
+
+你也可以將 `dataclasses` 與其他型別註記結合,建立巢狀的資料結構。
+
+在某些情況下,你可能仍需要使用 Pydantic 版本的 `dataclasses`。例如,當自動產生的 API 文件出現錯誤時。
+
+這種情況下,你可以把標準的 `dataclasses` 直接換成 `pydantic.dataclasses`,它是可直接替換(drop-in replacement)的:
+
+{* ../../docs_src/dataclasses_/tutorial003_py310.py hl[1,4,7:10,13:16,22:24,27] *}
+
+1. 我們仍然從標準的 `dataclasses` 匯入 `field`。
+2. `pydantic.dataclasses` 是 `dataclasses` 的可直接替換版本。
+3. `Author` dataclass 內含一個 `Item` dataclass 的清單。
+4. `Author` dataclass 被用作 `response_model` 參數。
+5. 你可以將其他標準型別註記與 dataclass 一起用作請求本文。
+
+ 在此例中,它是 `Item` dataclass 的清單。
+6. 這裡我們回傳一個字典,其中的 `items` 是一個 dataclass 清單。
+
+ FastAPI 仍能將資料
序列化為 JSON。
+7. 這裡 `response_model` 使用的是「`Author` dataclass 的清單」這種型別註記。
+
+ 同樣地,你可以把 `dataclasses` 與標準型別註記組合使用。
+8. 注意這個「路徑操作函式」使用的是一般的 `def` 而非 `async def`。
+
+ 一如往常,在 FastAPI 中你可以視需要混用 `def` 與 `async def`。
+
+ 如果需要複習何時用哪個,請參考文件中關於 [`async` 與 `await`](../async.md#in-a-hurry){.internal-link target=_blank} 的章節「In a hurry?」。
+9. 這個「路徑操作函式」回傳的不是 dataclass(雖然也可以),而是一個包含內部資料的字典清單。
+
+ FastAPI 會使用 `response_model` 參數(其中包含 dataclass)來轉換回應。
+
+你可以把 `dataclasses` 與其他型別註記以多種方式組合,形成複雜的資料結構。
+
+查看上面程式碼中的註解提示以了解更具體的細節。
+
+## 延伸閱讀 { #learn-more }
+
+你也可以將 `dataclasses` 與其他 Pydantic 模型結合、從它們繼承、把它們包含進你的自訂模型等。
+
+想了解更多,請參考
Pydantic 關於 dataclasses 的文件。
+
+## 版本 { #version }
+
+自 FastAPI 版本 `0.67.0` 起可用。🔖
diff --git a/docs/zh-hant/docs/advanced/events.md b/docs/zh-hant/docs/advanced/events.md
new file mode 100644
index 0000000000..e5c0afe48f
--- /dev/null
+++ b/docs/zh-hant/docs/advanced/events.md
@@ -0,0 +1,165 @@
+# 生命週期事件 { #lifespan-events }
+
+你可以定義在應用程式**啟動**之前要執行的邏輯(程式碼)。也就是說,這段程式碼會在應用開始接收請求**之前**、**只執行一次**。
+
+同樣地,你也可以定義在應用程式**關閉**時要執行的邏輯(程式碼)。在這種情況下,這段程式碼會在處理了**許多請求**之後、**只執行一次**。
+
+因為這些程式碼分別在應用開始接收請求**之前**與**完成**處理請求之後執行,所以涵蓋了整個應用的**生命週期**(「lifespan」這個詞稍後會很重要 😉)。
+
+這對於為整個應用設定需要**共用**於多個請求的**資源**,以及在之後進行**清理**,非常有用。比如資料庫連線池、或載入一個共用的機器學習模型。
+
+## 使用情境 { #use-case }
+
+先從一個**使用情境**開始,然後看看如何用這個機制解決。
+
+想像你有一些要用來處理請求的**機器學習模型**。🤖
+
+同一組模型會在多個請求間共用,所以不是每個請求或每個使用者各有一個模型。
+
+再想像一下,載入模型**需要一段時間**,因為它必須從**磁碟**讀取大量資料。所以你不想在每個請求都做一次。
+
+你可以在模組/檔案的最上層載入,但這也表示即使只是要跑一個簡單的自動化測試,也會去**載入模型**,導致測試**變慢**,因為它得等模型載入完才能執行與模型無關的程式碼部分。
+
+我們要解決的正是這件事:在開始處理請求之前再載入模型,但只在應用程式即將開始接收請求時載入,而不是在匯入程式碼時就載入。
+
+## 生命週期(Lifespan) { #lifespan }
+
+你可以使用 `FastAPI` 應用的 `lifespan` 參數,搭配「context manager」(稍後會示範),來定義這些 *startup* 與 *shutdown* 邏輯。
+
+先看一個例子,接著再深入說明。
+
+我們建立一個帶有 `yield` 的非同步函式 `lifespan()`,如下:
+
+{* ../../docs_src/events/tutorial003_py310.py hl[16,19] *}
+
+這裡我們透過在 `yield` 之前把(假的)模型函式放進機器學習模型的字典中,來模擬昂貴的 *startup* 載入模型操作。這段程式會在應用**開始接收請求之前**執行,也就是 *startup* 階段。
+
+接著,在 `yield` 之後,我們卸載模型。這段程式會在應用**完成處理請求之後**、也就是 *shutdown* 前執行。這可以用來釋放資源,例如記憶體或 GPU。
+
+/// tip
+
+`shutdown` 會在你**停止**應用程式時發生。
+
+也許你要啟動新版本,或只是不想再跑它了。🤷
+
+///
+
+### Lifespan 函式 { #lifespan-function }
+
+首先要注意的是,我們定義了一個帶有 `yield` 的 async 函式。這和帶有 `yield` 的依賴(Dependencies)非常相似。
+
+{* ../../docs_src/events/tutorial003_py310.py hl[14:19] *}
+
+函式在 `yield` 之前的部分,會在應用啟動前先執行。
+
+`yield` 之後的部分,會在應用結束後再執行。
+
+### 非同步內容管理器(Async Context Manager) { #async-context-manager }
+
+你會看到這個函式被 `@asynccontextmanager` 裝飾。
+
+它會把函式轉換成所謂的「**非同步內容管理器(async context manager)**」。
+
+{* ../../docs_src/events/tutorial003_py310.py hl[1,13] *}
+
+Python 中的**內容管理器(context manager)**可以用在 `with` 陳述式中,例如 `open()` 可以作為內容管理器使用:
+
+```Python
+with open("file.txt") as file:
+ file.read()
+```
+
+在較新的 Python 版本中,也有**非同步內容管理器**。你可以用 `async with` 來使用它:
+
+```Python
+async with lifespan(app):
+ await do_stuff()
+```
+
+當你像上面那樣建立一個內容管理器或非同步內容管理器時,在進入 `with` 區塊之前,會先執行 `yield` 之前的程式碼;離開 `with` 區塊之後,會執行 `yield` 之後的程式碼。
+
+在我們的範例中,並不是直接用它,而是把它傳給 FastAPI 來使用。
+
+`FastAPI` 應用的 `lifespan` 參數需要一個**非同步內容管理器**,所以我們可以把剛寫好的 `lifespan` 非同步內容管理器傳給它。
+
+{* ../../docs_src/events/tutorial003_py310.py hl[22] *}
+
+## 替代事件(已棄用) { #alternative-events-deprecated }
+
+/// warning
+
+目前建議使用上面所述,透過 `FastAPI` 應用的 `lifespan` 參數來處理 *startup* 與 *shutdown*。如果你提供了 `lifespan` 參數,`startup` 與 `shutdown` 事件處理器將不會被呼叫。要嘛全用 `lifespan`,要嘛全用事件,不能同時混用。
+
+你大概可以直接跳過這一節。
+
+///
+
+也有另一種方式可以定義在 *startup* 與 *shutdown* 期間要執行的邏輯。
+
+你可以定義事件處理器(函式)來在應用啟動前或關閉時執行。
+
+這些函式可以用 `async def` 或一般的 `def` 宣告。
+
+### `startup` 事件 { #startup-event }
+
+要加入一個在應用啟動前執行的函式,使用事件 `"startup"` 來宣告:
+
+{* ../../docs_src/events/tutorial001_py310.py hl[8] *}
+
+在這個例子中,`startup` 事件處理器函式會用一些值來初始化 items 的「資料庫」(其實就是個 `dict`)。
+
+你可以註冊多個事件處理函式。
+
+而且在所有 `startup` 事件處理器都完成之前,你的應用不會開始接收請求。
+
+### `shutdown` 事件 { #shutdown-event }
+
+要加入一個在應用關閉時執行的函式,使用事件 `"shutdown"` 來宣告:
+
+{* ../../docs_src/events/tutorial002_py310.py hl[6] *}
+
+在這裡,`shutdown` 事件處理器函式會把一行文字 `"Application shutdown"` 寫入檔案 `log.txt`。
+
+/// info
+
+在 `open()` 函式中,`mode="a"` 表示「append(附加)」;也就是說,這行文字會加在檔案現有內容之後,而不會覆寫先前的內容。
+
+///
+
+/// tip
+
+注意這裡我們使用的是標準 Python 的 `open()` 函式來操作檔案。
+
+這涉及 I/O(輸入/輸出),也就是需要「等待」資料寫入磁碟。
+
+但 `open()` 並不使用 `async` 與 `await`。
+
+所以我們用一般的 `def` 來宣告事件處理器,而不是 `async def`。
+
+///
+
+### 同時使用 `startup` 與 `shutdown` { #startup-and-shutdown-together }
+
+你的 *startup* 與 *shutdown* 邏輯很可能是相關聯的:你可能會先啟動某個東西再把它結束、先取得資源再釋放它,等等。
+
+如果把它們拆成兩個彼此不共享邏輯或變數的獨立函式,會比較麻煩,你得把值存在全域變數或用其他技巧。
+
+因此,現在建議改用上面介紹的 `lifespan`。
+
+## 技術細節 { #technical-details }
+
+給有興趣鑽研的同好一點技術細節。🤓
+
+在底層的 ASGI 技術規範中,這屬於
Lifespan Protocol 的一部分,並定義了 `startup` 與 `shutdown` 兩種事件。
+
+/// info
+
+你可以在
Starlette 的 Lifespan 文件 讀到更多關於 Starlette `lifespan` 處理器的資訊。
+
+也包含如何處理可在程式其他區域使用的 lifespan 狀態。
+
+///
+
+## 子應用程式 { #sub-applications }
+
+🚨 請記住,這些生命週期事件(startup 與 shutdown)只會在主應用程式上執行,不會在[子應用程式 - 掛載](sub-applications.md){.internal-link target=_blank}上執行。
diff --git a/docs/zh-hant/docs/advanced/generate-clients.md b/docs/zh-hant/docs/advanced/generate-clients.md
new file mode 100644
index 0000000000..8d374566cd
--- /dev/null
+++ b/docs/zh-hant/docs/advanced/generate-clients.md
@@ -0,0 +1,208 @@
+# 產生 SDK { #generating-sdks }
+
+由於 **FastAPI** 建立在 **OpenAPI** 規格之上,其 API 能以許多工具都能理解的標準格式來描述。
+
+這讓你能輕鬆產生最新的**文件**、多語言的用戶端程式庫(
**SDKs**),以及與程式碼保持同步的**測試**或**自動化工作流程**。
+
+在本指南中,你將學會如何為你的 FastAPI 後端產生 **TypeScript SDK**。
+
+## 開源 SDK 產生器 { #open-source-sdk-generators }
+
+其中一個相當萬用的選擇是
OpenAPI Generator,它支援**多種程式語言**,並能從你的 OpenAPI 規格產生 SDK。
+
+針對 **TypeScript 用戶端**,
Hey API 是專門打造的解決方案,為 TypeScript 生態系提供最佳化的體驗。
+
+你可以在
OpenAPI.Tools 找到更多 SDK 產生器。
+
+/// tip
+
+FastAPI 會自動產生 **OpenAPI 3.1** 規格,因此你使用的任何工具都必須支援這個版本。
+
+///
+
+## 來自 FastAPI 贊助商的 SDK 產生器 { #sdk-generators-from-fastapi-sponsors }
+
+本節重點介紹由贊助 FastAPI 的公司提供的**創投支持**與**公司維運**的解決方案。這些產品在高品質的自動產生 SDK 之外,還提供**額外功能**與**整合**。
+
+透過 ✨ [**贊助 FastAPI**](../help-fastapi.md#sponsor-the-author){.internal-link target=_blank} ✨,這些公司幫助確保框架與其**生態系**維持健康且**永續**。
+
+他們的贊助也展現對 FastAPI **社群**(你)的高度承諾,不僅關心提供**優良服務**,也支持 **FastAPI** 作為一個**穩健且蓬勃的框架**。🙇
+
+例如,你可以嘗試:
+
+*
Speakeasy
+*
Stainless
+*
liblab
+
+其中有些方案也可能是開源或提供免費方案,讓你不需財務承諾就能試用。其他商業的 SDK 產生器也不少,你可以在網路上找到。🤓
+
+## 建立 TypeScript SDK { #create-a-typescript-sdk }
+
+先從一個簡單的 FastAPI 應用開始:
+
+{* ../../docs_src/generate_clients/tutorial001_py310.py hl[7:9,12:13,16:17,21] *}
+
+注意這些 *路徑操作* 為請求與回應的有效載荷定義了所用的模型,使用了 `Item` 與 `ResponseMessage` 這兩個模型。
+
+### API 文件 { #api-docs }
+
+如果你前往 `/docs`,你會看到其中包含了請求要送出的資料與回應接收的資料之**結構(schemas)**:
+
+

+
+你之所以能看到這些結構,是因為它們在應用內以模型宣告了。
+
+這些資訊都在應用的 **OpenAPI 結構**中,並顯示在 API 文件裡。
+
+同樣包含在 OpenAPI 中的模型資訊,也可以用來**產生用戶端程式碼**。
+
+### Hey API { #hey-api }
+
+當我們有含模型的 FastAPI 應用後,就能用 Hey API 來產生 TypeScript 用戶端。最快的方法是透過 npx:
+
+```sh
+npx @hey-api/openapi-ts -i http://localhost:8000/openapi.json -o src/client
+```
+
+這會在 `./src/client` 產生一個 TypeScript SDK。
+
+你可以在他們的網站了解如何
安裝 `@hey-api/openapi-ts`,以及閱讀
產生的輸出內容。
+
+### 使用 SDK { #using-the-sdk }
+
+現在你可以匯入並使用用戶端程式碼。大致看起來會像這樣,你會發現方法有自動完成:
+
+

+
+你也會對要送出的有效載荷獲得自動完成:
+
+

+
+/// tip
+
+注意 `name` 與 `price` 的自動完成,這是由 FastAPI 應用中的 `Item` 模型所定義。
+
+///
+
+你在送出的資料上也會看到行內錯誤:
+
+

+
+回應物件同樣有自動完成:
+
+

+
+## 含標籤的 FastAPI 應用 { #fastapi-app-with-tags }
+
+在許多情況下,你的 FastAPI 應用會更大,你可能會用標籤將不同群組的 *路徑操作* 分開。
+
+例如,你可以有一個 **items** 區塊與另一個 **users** 區塊,並透過標籤區分:
+
+{* ../../docs_src/generate_clients/tutorial002_py310.py hl[21,26,34] *}
+
+### 使用標籤產生 TypeScript 用戶端 { #generate-a-typescript-client-with-tags }
+
+若你為使用標籤的 FastAPI 應用產生用戶端,產生器通常也會依標籤將用戶端程式碼分開。
+
+如此一來,用戶端程式碼就能有條理地正確分組與排列:
+
+

+
+在此例中,你會有:
+
+* `ItemsService`
+* `UsersService`
+
+### 用戶端方法名稱 { #client-method-names }
+
+目前像 `createItemItemsPost` 這樣的產生方法名稱看起來不太俐落:
+
+```TypeScript
+ItemsService.createItemItemsPost({name: "Plumbus", price: 5})
+```
+
+……那是因為用戶端產生器對每個 *路徑操作* 都使用 OpenAPI 內部的**操作 ID(operation ID)**。
+
+OpenAPI 要求每個操作 ID 在所有 *路徑操作* 之間必須唯一,因此 FastAPI 會用**函式名稱**、**路徑**與 **HTTP 方法/操作**來產生該操作 ID,如此便能確保操作 ID 的唯一性。
+
+接下來我會示範如何把它變得更好看。🤓
+
+## 自訂 Operation ID 與更好的方法名稱 { #custom-operation-ids-and-better-method-names }
+
+你可以**修改**這些操作 ID 的**產生方式**,讓它們更簡潔,並在用戶端中得到**更簡潔的方法名稱**。
+
+在這種情況下,你需要用其他方式確保每個操作 ID 都是**唯一**的。
+
+例如,你可以確保每個 *路徑操作* 都有標籤,接著根據**標籤**與 *路徑操作* 的**名稱**(函式名稱)來產生操作 ID。
+
+### 自訂唯一 ID 產生函式 { #custom-generate-unique-id-function }
+
+FastAPI 會為每個 *路徑操作* 使用一個**唯一 ID**,它會被用於**操作 ID**,以及任何請求或回應所需的自訂模型名稱。
+
+你可以自訂該函式。它接收一個 APIRoute 並回傳字串。
+
+例如,下面使用第一個標籤(你通常只會有一個標籤)以及 *路徑操作* 的名稱(函式名稱)。
+
+接著你可以將這個自訂函式以 `generate_unique_id_function` 參數傳給 **FastAPI**:
+
+{* ../../docs_src/generate_clients/tutorial003_py310.py hl[6:7,10] *}
+
+### 使用自訂 Operation ID 產生 TypeScript 用戶端 { #generate-a-typescript-client-with-custom-operation-ids }
+
+現在,如果你再次產生用戶端,會看到方法名稱已改善:
+
+

+
+如你所見,方法名稱現在包含標籤與函式名稱,不再包含 URL 路徑與 HTTP 操作的資訊。
+
+### 為用戶端產生器預處理 OpenAPI 規格 { #preprocess-the-openapi-specification-for-the-client-generator }
+
+產生的程式碼仍有一些**重複資訊**。
+
+我們已經知道這個方法與 **items** 相關,因為該字已出現在 `ItemsService`(取自標籤)中,但方法名稱仍然加上了標籤名稱做前綴。😕
+
+對於 OpenAPI 本身,我們可能仍想保留,因為那能確保操作 ID 是**唯一**的。
+
+但就產生用戶端而言,我們可以在產生前**修改** OpenAPI 的操作 ID,來讓方法名稱更**簡潔**、更**乾淨**。
+
+我們可以把 OpenAPI JSON 下載到 `openapi.json` 檔案,然後用像這樣的腳本**移除該標籤前綴**:
+
+{* ../../docs_src/generate_clients/tutorial004_py310.py *}
+
+//// tab | Node.js
+
+```Javascript
+{!> ../../docs_src/generate_clients/tutorial004.js!}
+```
+
+////
+
+如此一來,操作 ID 會從 `items-get_items` 之類的字串,變成單純的 `get_items`,讓用戶端產生器能產生更簡潔的方法名稱。
+
+### 使用預處理後的 OpenAPI 產生 TypeScript 用戶端 { #generate-a-typescript-client-with-the-preprocessed-openapi }
+
+由於最終結果現在是在 `openapi.json` 檔案中,你需要更新輸入位置:
+
+```sh
+npx @hey-api/openapi-ts -i ./openapi.json -o src/client
+```
+
+產生新的用戶端後,你現在會得到**乾淨的方法名稱**,同時保有所有的**自動完成**、**行內錯誤**等功能:
+
+

+
+## 好處 { #benefits }
+
+使用自動產生的用戶端時,你會得到以下項目的**自動完成**:
+
+* 方法
+* 本文中的請求有效載荷、查詢參數等
+* 回應的有效載荷
+
+你也會對所有內容獲得**行內錯誤**提示。
+
+而且每當你更新後端程式碼並**重新產生**前端(用戶端),新的 *路徑操作* 會以方法形式可用、舊的會被移除,其他任何變更也都會反映到產生的程式碼中。🤓
+
+這也代表只要有任何變更,便會自動**反映**到用戶端程式碼;而當你**建置**用戶端時,如果使用的資料有任何**不匹配**,就會直接報錯。
+
+因此,你能在開發週期的很早期就**偵測到許多錯誤**,而不必等到錯誤在正式環境的最終使用者那裡才出現,然後才開始追查問題所在。✨
diff --git a/docs/zh-hant/docs/advanced/index.md b/docs/zh-hant/docs/advanced/index.md
new file mode 100644
index 0000000000..cfbc17afec
--- /dev/null
+++ b/docs/zh-hant/docs/advanced/index.md
@@ -0,0 +1,21 @@
+# 進階使用者指南 { #advanced-user-guide }
+
+## 更多功能 { #additional-features }
+
+主要的[教學 - 使用者指南](../tutorial/index.md){.internal-link target=_blank} 應足以帶你快速瀏覽 **FastAPI** 的所有核心功能。
+
+在接下來的章節中,你會看到其他選項、設定,以及更多功能。
+
+/// tip
+
+接下來的章節不一定「進階」。
+
+而且對於你的使用情境,解法很可能就在其中某一節。
+
+///
+
+## 先閱讀教學 { #read-the-tutorial-first }
+
+只要掌握主要[教學 - 使用者指南](../tutorial/index.md){.internal-link target=_blank} 的內容,你就能使用 **FastAPI** 的大多數功能。
+
+接下來的章節也假設你已經讀過,並已了解那些主要觀念。
diff --git a/docs/zh-hant/docs/advanced/middleware.md b/docs/zh-hant/docs/advanced/middleware.md
new file mode 100644
index 0000000000..80cda345c3
--- /dev/null
+++ b/docs/zh-hant/docs/advanced/middleware.md
@@ -0,0 +1,97 @@
+# 進階中介軟體 { #advanced-middleware }
+
+在主要教學中你已學過如何將[自訂中介軟體](../tutorial/middleware.md){.internal-link target=_blank}加入到你的應用程式。
+
+你也讀過如何使用 `CORSMiddleware` 處理 [CORS](../tutorial/cors.md){.internal-link target=_blank}。
+
+本節將示範如何使用其他中介軟體。
+
+## 新增 ASGI 中介軟體 { #adding-asgi-middlewares }
+
+由於 **FastAPI** 建立在 Starlette 上並實作了
ASGI 規範,你可以使用任何 ASGI 中介軟體。
+
+中介軟體不一定要為 FastAPI 或 Starlette 專門撰寫,只要遵循 ASGI 規範即可運作。
+
+一般來說,ASGI 中介軟體是類別,預期第一個參數接收一個 ASGI 應用程式。
+
+因此,在第三方 ASGI 中介軟體的文件中,通常會指示你這樣做:
+
+```Python
+from unicorn import UnicornMiddleware
+
+app = SomeASGIApp()
+
+new_app = UnicornMiddleware(app, some_config="rainbow")
+```
+
+但 FastAPI(實際上是 Starlette)提供了一種更簡單的方式,確保內部中介軟體能處理伺服器錯誤,且自訂例外處理器可正常運作。
+
+為此,你可以使用 `app.add_middleware()`(如同 CORS 範例)。
+
+```Python
+from fastapi import FastAPI
+from unicorn import UnicornMiddleware
+
+app = FastAPI()
+
+app.add_middleware(UnicornMiddleware, some_config="rainbow")
+```
+
+`app.add_middleware()` 將中介軟體類別作為第一個引數,並接收要傳遞給該中介軟體的其他引數。
+
+## 內建中介軟體 { #integrated-middlewares }
+
+**FastAPI** 內建數個常見用途的中介軟體,以下將示範如何使用。
+
+/// note | 技術細節
+
+在接下來的範例中,你也可以使用 `from starlette.middleware.something import SomethingMiddleware`。
+
+**FastAPI** 在 `fastapi.middleware` 中提供了一些中介軟體,純粹是為了方便你這位開發者。但大多數可用的中介軟體直接來自 Starlette。
+
+///
+
+## `HTTPSRedirectMiddleware` { #httpsredirectmiddleware }
+
+強制所有傳入請求必須使用 `https` 或 `wss`。
+
+任何指向 `http` 或 `ws` 的請求都會被重新導向至對應的安全協定。
+
+{* ../../docs_src/advanced_middleware/tutorial001_py310.py hl[2,6] *}
+
+## `TrustedHostMiddleware` { #trustedhostmiddleware }
+
+強制所有傳入請求正確設定 `Host` 標頭,以防範 HTTP Host Header 攻擊。
+
+{* ../../docs_src/advanced_middleware/tutorial002_py310.py hl[2,6:8] *}
+
+支援以下參數:
+
+- `allowed_hosts` - 允許作為主機名稱的網域名稱清單。支援萬用字元網域(例如 `*.example.com`)以比對子網域。若要允許任意主機名稱,可使用 `allowed_hosts=["*"]`,或乾脆不要加上此中介軟體。
+- `www_redirect` - 若設為 True,對允許主機的不含 www 版本的請求會被重新導向至其 www 對應版本。預設為 `True`。
+
+若傳入請求驗證失敗,將回傳 `400` 回應。
+
+## `GZipMiddleware` { #gzipmiddleware }
+
+處理在 `Accept-Encoding` 標頭中包含 `"gzip"` 的請求之 GZip 壓縮回應。
+
+此中介軟體會處理一般與串流回應。
+
+{* ../../docs_src/advanced_middleware/tutorial003_py310.py hl[2,6] *}
+
+支援以下參數:
+
+- `minimum_size` - 小於此位元組大小的回應不會進行 GZip。預設為 `500`。
+- `compresslevel` - GZip 壓縮時使用的等級。為 1 到 9 的整數。預設為 `9`。值越小壓縮越快但檔案較大,值越大壓縮較慢但檔案較小。
+
+## 其他中介軟體 { #other-middlewares }
+
+還有許多其他 ASGI 中介軟體。
+
+例如:
+
+-
Uvicorn 的 `ProxyHeadersMiddleware`
+-
MessagePack
+
+想瞭解更多可用的中介軟體,請參考
Starlette 的中介軟體文件 與
ASGI 精選清單。
diff --git a/docs/zh-hant/docs/advanced/openapi-callbacks.md b/docs/zh-hant/docs/advanced/openapi-callbacks.md
new file mode 100644
index 0000000000..b1a16be249
--- /dev/null
+++ b/docs/zh-hant/docs/advanced/openapi-callbacks.md
@@ -0,0 +1,186 @@
+# OpenAPI 回呼 { #openapi-callbacks }
+
+你可以建立一個含有「路徑操作(path operation)」的 API,該操作會觸發對某個「外部 API(external API)」的請求(通常由使用你 API 的同一位開發者提供)。
+
+當你的 API 應用呼叫「外部 API」時發生的過程稱為「回呼(callback)」。因為外部開發者撰寫的軟體會先向你的 API 發出請求,接著你的 API 再「回呼」,也就是向(可能同一位開發者建立的)外部 API 發送請求。
+
+在這種情況下,你可能想要文件化說明該外部 API 應該長什麼樣子。它應該有哪些「路徑操作」、應該接受什麼 body、應該回傳什麼 response,等等。
+
+## 帶有回呼的應用 { #an-app-with-callbacks }
+
+我們用一個例子來看。
+
+想像你開發了一個允許建立發票的應用。
+
+這些發票會有 `id`、`title`(可選)、`customer` 和 `total`。
+
+你的 API 的使用者(外部開發者)會透過一個 POST 請求在你的 API 中建立一張發票。
+
+然後你的 API 會(讓我們想像):
+
+* 將發票寄給該外部開發者的某位客戶。
+* 代收款項。
+* 再把通知回傳給 API 使用者(外部開發者)。
+ * 這會透過從「你的 API」向該外部開發者提供的「外部 API」送出 POST 請求完成(這就是「回呼」)。
+
+## 一般的 **FastAPI** 應用 { #the-normal-fastapi-app }
+
+先看看在加入回呼之前,一個一般的 API 應用會長什麼樣子。
+
+它會有一個接收 `Invoice` body 的「路徑操作」,以及一個查詢參數 `callback_url`,其中包含用於回呼的 URL。
+
+這部分很正常,多數程式碼你應該已經很熟悉了:
+
+{* ../../docs_src/openapi_callbacks/tutorial001_py310.py hl[7:11,34:51] *}
+
+/// tip
+
+`callback_url` 查詢參數使用的是 Pydantic 的
Url 型別。
+
+///
+
+唯一新的地方是在「路徑操作裝飾器」中加入參數 `callbacks=invoices_callback_router.routes`。我們接下來會看到那是什麼。
+
+## 文件化回呼 { #documenting-the-callback }
+
+實際的回呼程式碼會高度依賴你的 API 應用本身。
+
+而且很可能每個應用都差很多。
+
+它可能就只有一兩行,例如:
+
+```Python
+callback_url = "https://example.com/api/v1/invoices/events/"
+httpx.post(callback_url, json={"description": "Invoice paid", "paid": True})
+```
+
+但回呼中最重要的部分,可能是在確保你的 API 使用者(外部開發者)能正確實作「外部 API」,符合「你的 API」在回呼請求 body 中要送出的資料格式,等等。
+
+因此,接下來我們要加上用來「文件化」說明,該「外部 API」應該長什麼樣子,才能接收來自「你的 API」的回呼。
+
+這份文件會出現在你的 API 的 Swagger UI `/docs`,讓外部開發者知道該如何建置「外部 API」。
+
+這個範例不會實作回呼本身(那可能就只是一行程式碼),只會實作文件的部分。
+
+/// tip
+
+實際的回呼就是一個 HTTP 請求。
+
+當你自己實作回呼時,可以使用像是
HTTPX 或
Requests。
+
+///
+
+## 撰寫回呼的文件化程式碼 { #write-the-callback-documentation-code }
+
+這段程式碼在你的應用中不會被執行,我們只需要它來「文件化」說明那個「外部 API」應該長什麼樣子。
+
+不過,你已經知道如何用 **FastAPI** 輕鬆為 API 建立自動文件。
+
+所以我們會用同樣的方式,來文件化「外部 API」應該長什麼樣子... 也就是建立外部 API 應該實作的「路徑操作(們)」(那些「你的 API」會去呼叫的操作)。
+
+/// tip
+
+在撰寫回呼的文件化程式碼時,把自己想像成那位「外部開發者」會很有幫助。而且你現在是在實作「外部 API」,不是「你的 API」。
+
+暫時採用這個(外部開發者)的視角,有助於讓你更直覺地決定該把參數、body 的 Pydantic 模型、response 的模型等放在哪裡,對於那個「外部 API」會更清楚。
+
+///
+
+### 建立一個回呼用的 `APIRouter` { #create-a-callback-apirouter }
+
+先建立一個新的 `APIRouter`,用來放一個或多個回呼。
+
+{* ../../docs_src/openapi_callbacks/tutorial001_py310.py hl[1,23] *}
+
+### 建立回呼的「路徑操作」 { #create-the-callback-path-operation }
+
+要建立回呼的「路徑操作」,就使用你上面建立的同一個 `APIRouter`。
+
+它看起來就像一般的 FastAPI「路徑操作」:
+
+* 可能需要宣告它應該接收的 body,例如 `body: InvoiceEvent`。
+* 也可以宣告它應該回傳的 response,例如 `response_model=InvoiceEventReceived`。
+
+{* ../../docs_src/openapi_callbacks/tutorial001_py310.py hl[14:16,19:20,26:30] *}
+
+和一般「路徑操作」相比有兩個主要差異:
+
+* 不需要任何實際程式碼,因為你的應用永遠不會呼叫這段程式。它只用來文件化「外部 API」。因此函式可以只有 `pass`。
+* 「路徑」可以包含一個
OpenAPI 3 表達式(見下文),可使用參數與原始送到「你的 API」的請求中的部分欄位。
+
+### 回呼路徑表達式 { #the-callback-path-expression }
+
+回呼的「路徑」可以包含一個
OpenAPI 3 表達式,能引用原本送到「你的 API」的請求中的部分內容。
+
+在這個例子中,它是一個 `str`:
+
+```Python
+"{$callback_url}/invoices/{$request.body.id}"
+```
+
+所以,如果你的 API 使用者(外部開發者)向「你的 API」送出這樣的請求:
+
+```
+https://yourapi.com/invoices/?callback_url=https://www.external.org/events
+```
+
+並附上這個 JSON body:
+
+```JSON
+{
+ "id": "2expen51ve",
+ "customer": "Mr. Richie Rich",
+ "total": "9999"
+}
+```
+
+那麼「你的 API」會處理這張發票,並在稍後某個時點,向 `callback_url`(也就是「外部 API」)送出回呼請求:
+
+```
+https://www.external.org/events/invoices/2expen51ve
+```
+
+其 JSON body 大致包含:
+
+```JSON
+{
+ "description": "Payment celebration",
+ "paid": true
+}
+```
+
+而它會預期該「外部 API」回傳的 JSON body 例如:
+
+```JSON
+{
+ "ok": true
+}
+```
+
+/// tip
+
+注意回呼所用的 URL,包含了在查詢參數 `callback_url` 中收到的 URL(`https://www.external.org/events`),以及來自 JSON body 內的發票 `id`(`2expen51ve`)。
+
+///
+
+### 加入回呼 router { #add-the-callback-router }
+
+此時你已經在先前建立的回呼 router 中,擁有所需的回呼「路徑操作(們)」(也就是「外部開發者」應該在「外部 API」中實作的那些)。
+
+現在在「你的 API 的路徑操作裝飾器」中使用參數 `callbacks`,將該回呼 router 的屬性 `.routes`(實際上就是一個由路由/「路徑操作」所組成的 `list`)傳入:
+
+{* ../../docs_src/openapi_callbacks/tutorial001_py310.py hl[33] *}
+
+/// tip
+
+注意你傳給 `callback=` 的不是整個 router 本身(`invoices_callback_router`),而是它的屬性 `.routes`,也就是 `invoices_callback_router.routes`。
+
+///
+
+### 檢查文件 { #check-the-docs }
+
+現在你可以啟動應用,並前往
http://127.0.0.1:8000/docs。
+
+你會在文件中看到你的「路徑操作」包含一個「Callbacks」區塊,顯示「外部 API」應該長什麼樣子:
+
+

diff --git a/docs/zh-hant/docs/advanced/openapi-webhooks.md b/docs/zh-hant/docs/advanced/openapi-webhooks.md
new file mode 100644
index 0000000000..ef52c3884f
--- /dev/null
+++ b/docs/zh-hant/docs/advanced/openapi-webhooks.md
@@ -0,0 +1,55 @@
+# OpenAPI Webhook { #openapi-webhooks }
+
+有些情況下,你會想告訴你的 API 使用者,你的應用程式可能會攜帶一些資料去呼叫他們的應用程式(發送請求),通常是為了通知某種類型的事件。
+
+這表示,與其由使用者向你的 API 發送請求,改為你的 API(或你的應用)可能會向他們的系統(他們的 API、他們的應用)發送請求。
+
+這通常稱為 webhook。
+
+## Webhook 步驟 { #webhooks-steps }
+
+流程通常是:你在程式碼中定義要發送的訊息,也就是請求的主體(request body)。
+
+你也會以某種方式定義應用在哪些時刻會發送那些請求或事件。
+
+而你的使用者則會以某種方式(例如在某個 Web 控制台)設定你的應用應該將這些請求送往的 URL。
+
+關於如何註冊 webhook 的 URL,以及實際發送那些請求的程式碼等所有邏輯,都由你決定。你可以在自己的程式碼中用你想要的方式撰寫。
+
+## 使用 FastAPI 與 OpenAPI 記錄 webhook { #documenting-webhooks-with-fastapi-and-openapi }
+
+在 FastAPI 中,透過 OpenAPI,你可以定義這些 webhook 的名稱、你的應用將發送的 HTTP 操作類型(例如 `POST`、`PUT` 等),以及你的應用要發送的請求主體。
+
+這能讓你的使用者更容易實作他們的 API 以接收你的 webhook 請求,甚至可能自動產生部分他們自己的 API 程式碼。
+
+/// info
+
+Webhook 功能自 OpenAPI 3.1.0 起提供,FastAPI `0.99.0` 以上版本支援。
+
+///
+
+## 含有 webhook 的應用 { #an-app-with-webhooks }
+
+建立 FastAPI 應用時,會有一個 `webhooks` 屬性可用來定義 webhook,方式與定義路徑操作相同,例如使用 `@app.webhooks.post()`。
+
+{* ../../docs_src/openapi_webhooks/tutorial001_py310.py hl[9:12,15:20] *}
+
+你定義的 webhook 會出現在 OpenAPI 結構描述與自動產生的文件 UI 中。
+
+/// info
+
+`app.webhooks` 其實就是一個 `APIRouter`,與你在將應用拆分為多個檔案時所使用的型別相同。
+
+///
+
+注意,使用 webhook 時你其實不是在宣告路徑(例如 `/items/`),你傳入的文字只是該 webhook 的識別名稱(事件名稱)。例如在 `@app.webhooks.post("new-subscription")` 中,webhook 名稱是 `new-subscription`。
+
+這是因為預期由你的使用者以其他方式(例如 Web 控制台)來設定實際要接收 webhook 請求的 URL 路徑。
+
+### 查看文件 { #check-the-docs }
+
+現在你可以啟動應用,然後前往
http://127.0.0.1:8000/docs。
+
+你會在文件中看到一般的路徑操作,另外還有一些 webhook:
+
+

diff --git a/docs/zh-hant/docs/advanced/path-operation-advanced-configuration.md b/docs/zh-hant/docs/advanced/path-operation-advanced-configuration.md
new file mode 100644
index 0000000000..4f25eb9878
--- /dev/null
+++ b/docs/zh-hant/docs/advanced/path-operation-advanced-configuration.md
@@ -0,0 +1,172 @@
+# 路徑操作進階設定 { #path-operation-advanced-configuration }
+
+## OpenAPI operationId { #openapi-operationid }
+
+/// warning
+
+如果你不是 OpenAPI 的「專家」,大概不需要這個。
+
+///
+
+你可以用參數 `operation_id` 為你的*路徑操作(path operation)*設定要使用的 OpenAPI `operationId`。
+
+你必須確保每個操作的 `operationId` 都是唯一的。
+
+{* ../../docs_src/path_operation_advanced_configuration/tutorial001_py310.py hl[6] *}
+
+### 使用路徑操作函式(path operation function)的名稱作為 operationId { #using-the-path-operation-function-name-as-the-operationid }
+
+如果你想用 API 的函式名稱作為 `operationId`,你可以遍歷所有路徑,並使用各自的 `APIRoute.name` 覆寫每個*路徑操作*的 `operation_id`。
+
+應在加入所有*路徑操作*之後再這麼做。
+
+{* ../../docs_src/path_operation_advanced_configuration/tutorial002_py310.py hl[2, 12:21, 24] *}
+
+/// tip
+
+如果你會手動呼叫 `app.openapi()`,請務必先更新所有 `operationId` 再呼叫。
+
+///
+
+/// warning
+
+如果你這樣做,必須確保每個*路徑操作函式*都有唯一的名稱,
+
+即使它們位於不同的模組(Python 檔案)中。
+
+///
+
+## 從 OpenAPI 排除 { #exclude-from-openapi }
+
+若要從產生的 OpenAPI 結構(也就是自動文件系統)中排除某個*路徑操作*,使用參數 `include_in_schema` 並將其設為 `False`:
+
+{* ../../docs_src/path_operation_advanced_configuration/tutorial003_py310.py hl[6] *}
+
+## 從 docstring 提供進階描述 { #advanced-description-from-docstring }
+
+你可以限制 OpenAPI 從*路徑操作函式*的 docstring 中使用的內容行數。
+
+加上一個 `\f`(跳頁字元,form feed)會讓 FastAPI 在此處截斷用於 OpenAPI 的輸出。
+
+這個字元不會出現在文件中,但其他工具(例如 Sphinx)仍可使用其後的內容。
+
+{* ../../docs_src/path_operation_advanced_configuration/tutorial004_py310.py hl[17:27] *}
+
+## 額外回應 { #additional-responses }
+
+你大概已看過如何為*路徑操作*宣告 `response_model` 與 `status_code`。
+
+這會定義該*路徑操作*主要回應的中繼資料。
+
+你也可以宣告額外的回應及其模型、狀態碼等。
+
+文件中有完整章節說明,請見 [OpenAPI 中的額外回應](additional-responses.md){.internal-link target=_blank}。
+
+## OpenAPI 額外資訊 { #openapi-extra }
+
+當你在應用程式中宣告一個*路徑操作*時,FastAPI 會自動產生該*路徑操作*的相關中繼資料,並納入 OpenAPI 結構中。
+
+/// note | 技術細節
+
+在 OpenAPI 規格中,這稱為
Operation 物件。
+
+///
+
+它包含關於*路徑操作*的所有資訊,並用於產生自動文件。
+
+其中包含 `tags`、`parameters`、`requestBody`、`responses` 等。
+
+這個針對單一路徑操作的 OpenAPI 結構通常由 FastAPI 自動產生,但你也可以擴充它。
+
+/// tip
+
+這是一個較低階的擴充介面。
+
+如果你只需要宣告額外回應,更方便的方式是使用 [OpenAPI 中的額外回應](additional-responses.md){.internal-link target=_blank}。
+
+///
+
+你可以使用參數 `openapi_extra` 來擴充某個*路徑操作*的 OpenAPI 結構。
+
+### OpenAPI 擴充 { #openapi-extensions }
+
+`openapi_extra` 可用來宣告例如 [OpenAPI 擴充](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#specificationExtensions) 的資料:
+
+{* ../../docs_src/path_operation_advanced_configuration/tutorial005_py310.py hl[6] *}
+
+打開自動產生的 API 文件時,你的擴充會顯示在該*路徑操作*頁面的底部。
+
+

+
+而在檢視產生出的 OpenAPI(位於你的 API 的 `/openapi.json`)時,也可以在相應*路徑操作*中看到你的擴充:
+
+```JSON hl_lines="22"
+{
+ "openapi": "3.1.0",
+ "info": {
+ "title": "FastAPI",
+ "version": "0.1.0"
+ },
+ "paths": {
+ "/items/": {
+ "get": {
+ "summary": "Read Items",
+ "operationId": "read_items_items__get",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {}
+ }
+ }
+ }
+ },
+ "x-aperture-labs-portal": "blue"
+ }
+ }
+ }
+}
+```
+
+### 自訂 OpenAPI 路徑操作結構 { #custom-openapi-path-operation-schema }
+
+`openapi_extra` 中的字典會與自動產生的該*路徑操作*之 OpenAPI 結構進行深度合併。
+
+因此你可以在自動產生的結構上加入額外資料。
+
+例如,你可以選擇用自己的程式碼讀取並驗證請求,而不使用 FastAPI 與 Pydantic 的自動功能,但仍然希望在 OpenAPI 結構中定義該請求。
+
+你可以透過 `openapi_extra` 辦到:
+
+{* ../../docs_src/path_operation_advanced_configuration/tutorial006_py310.py hl[19:36, 39:40] *}
+
+在這個範例中,我們沒有宣告任何 Pydantic 模型。事實上,請求本文甚至不會被
解析 為 JSON,而是直接以 `bytes` 讀取,並由函式 `magic_data_reader()` 以某種方式負責解析。
+
+儘管如此,我們仍可宣告請求本文的預期結構。
+
+### 自訂 OpenAPI Content-Type { #custom-openapi-content-type }
+
+用同樣的方法,你可以使用 Pydantic 模型來定義 JSON Schema,並把它包含到該*路徑操作*的自訂 OpenAPI 區段中。
+
+即使請求中的資料型別不是 JSON 也可以這麼做。
+
+例如,在這個應用中,我們不使用 FastAPI 內建的從 Pydantic 模型擷取 JSON Schema 的功能,也不使用 JSON 的自動驗證。實際上,我們將請求的 content type 宣告為 YAML,而非 JSON:
+
+{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py310.py hl[15:20, 22] *}
+
+儘管沒有使用預設的內建功能,我們仍透過 Pydantic 模型手動產生想以 YAML 接收之資料的 JSON Schema。
+
+接著我們直接使用請求,並將本文擷取為 `bytes`。這表示 FastAPI 甚至不會嘗試把請求負載解析為 JSON。
+
+然後在程式中直接解析該 YAML 內容,並再次使用相同的 Pydantic 模型來驗證該 YAML 內容:
+
+{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py310.py hl[24:31] *}
+
+/// tip
+
+這裡我們重複使用同一個 Pydantic 模型。
+
+不過也可以用其他方式進行驗證。
+
+///
diff --git a/docs/zh-hant/docs/advanced/response-change-status-code.md b/docs/zh-hant/docs/advanced/response-change-status-code.md
new file mode 100644
index 0000000000..4b8d459ca2
--- /dev/null
+++ b/docs/zh-hant/docs/advanced/response-change-status-code.md
@@ -0,0 +1,31 @@
+# 回應 - 變更狀態碼 { #response-change-status-code }
+
+你可能已經讀過,可以設定預設的[回應狀態碼](../tutorial/response-status-code.md){.internal-link target=_blank}。
+
+但有些情況你需要回傳與預設不同的狀態碼。
+
+## 使用情境 { #use-case }
+
+例如,假設你預設想回傳 HTTP 狀態碼 "OK" `200`。
+
+但如果資料不存在,你想要建立它,並回傳 HTTP 狀態碼 "CREATED" `201`。
+
+同時你仍希望能用 `response_model` 過濾並轉換所回傳的資料。
+
+在這些情況下,你可以使用 `Response` 參數。
+
+## 使用 `Response` 參數 { #use-a-response-parameter }
+
+你可以在你的路徑操作函式(path operation function)中宣告一個 `Response` 型別的參數(就像你可以對 Cookies 和標頭那樣)。
+
+接著你可以在那個「*暫時的*」回應物件上設定 `status_code`。
+
+{* ../../docs_src/response_change_status_code/tutorial001_py310.py hl[1,9,12] *}
+
+然後你可以照常回傳任何需要的物件(例如 `dict`、資料庫模型等)。
+
+若你宣告了 `response_model`,它仍會被用來過濾並轉換你回傳的物件。
+
+FastAPI 會使用那個「*暫時的*」回應來取得狀態碼(以及 Cookies 和標頭),並將它們放入最終回應中;最終回應包含你回傳的值,且會被任何 `response_model` 過濾。
+
+你也可以在相依性(dependencies)中宣告 `Response` 參數,並在其中設定狀態碼。但請注意,最後被設定的值會生效。
diff --git a/docs/zh-hant/docs/advanced/response-cookies.md b/docs/zh-hant/docs/advanced/response-cookies.md
new file mode 100644
index 0000000000..b7225d571c
--- /dev/null
+++ b/docs/zh-hant/docs/advanced/response-cookies.md
@@ -0,0 +1,51 @@
+# 回應 Cookie { #response-cookies }
+
+## 使用 `Response` 參數 { #use-a-response-parameter }
+
+你可以在路徑操作函式(path operation function)中宣告一個型別為 `Response` 的參數。
+
+接著你可以在那個「暫時」的 `Response` 物件上設定 Cookie。
+
+{* ../../docs_src/response_cookies/tutorial002_py310.py hl[1, 8:9] *}
+
+之後如常回傳你需要的任何物件(例如 `dict`、資料庫模型等)。
+
+如果你宣告了 `response_model`,它仍會用來過濾並轉換你回傳的物件。
+
+FastAPI 會使用那個暫時的 `Response` 取出 Cookie(以及標頭與狀態碼),並將它們放入最終回應;最終回應包含你回傳的值,且會套用任何 `response_model` 的過濾。
+
+你也可以在相依項(dependencies)中宣告 `Response` 參數,並在其中設定 Cookie(與標頭)。
+
+## 直接回傳 `Response` { #return-a-response-directly }
+
+當你在程式碼中直接回傳 `Response` 時,也可以建立 Cookie。
+
+要這麼做,你可以依照 [直接回傳 Response](response-directly.md){.internal-link target=_blank} 中的說明建立一個回應。
+
+接著在其中設定 Cookie,然後回傳它:
+
+{* ../../docs_src/response_cookies/tutorial001_py310.py hl[10:12] *}
+
+/// tip | 提示
+
+請注意,如果你不是使用 `Response` 參數,而是直接回傳一個 `Response`,FastAPI 會原樣回傳它。
+
+因此你必須確保資料型別正確;例如,如果你回傳的是 `JSONResponse`,就要確保資料可與 JSON 相容。
+
+同時也要確認沒有送出原本應該由 `response_model` 過濾的資料。
+
+///
+
+### 更多資訊 { #more-info }
+
+/// note | 技術細節
+
+你也可以使用 `from starlette.responses import Response` 或 `from starlette.responses import JSONResponse`。
+
+為了方便開發者,FastAPI 也將相同的 `starlette.responses` 透過 `fastapi.responses` 提供。不過,大多數可用的回應類別都直接來自 Starlette。
+
+另外由於 `Response` 常用於設定標頭與 Cookie,FastAPI 也在 `fastapi.Response` 提供了它。
+
+///
+
+想查看所有可用的參數與選項,請參閱
Starlette 文件。
diff --git a/docs/zh-hant/docs/advanced/response-directly.md b/docs/zh-hant/docs/advanced/response-directly.md
new file mode 100644
index 0000000000..5603548934
--- /dev/null
+++ b/docs/zh-hant/docs/advanced/response-directly.md
@@ -0,0 +1,65 @@
+# 直接回傳 Response { #return-a-response-directly }
+
+當你建立一個 **FastAPI** 的路徑操作 (path operation) 時,通常可以從中回傳任何資料:`dict`、`list`、Pydantic 模型、資料庫模型等。
+
+預設情況下,**FastAPI** 會使用在[JSON 相容編碼器](../tutorial/encoder.md){.internal-link target=_blank}中說明的 `jsonable_encoder`,自動將回傳值轉為 JSON。
+
+然後在幕後,它會把這些與 JSON 相容的資料(例如 `dict`)放進 `JSONResponse`,用來把回應傳回給用戶端。
+
+但你也可以直接從路徑操作回傳 `JSONResponse`。
+
+例如,當你需要回傳自訂的 headers 或 cookies 時就很有用。
+
+## 回傳 `Response` { #return-a-response }
+
+其實,你可以回傳任何 `Response`,或其任何子類別。
+
+/// tip
+
+`JSONResponse` 本身就是 `Response` 的子類別。
+
+///
+
+當你回傳一個 `Response` 時,**FastAPI** 會直接傳遞它。
+
+它不會對 Pydantic 模型做任何資料轉換,也不會把內容轉成其他型別等。
+
+這給了你很大的彈性。你可以回傳任何資料型別、覆寫任何資料宣告或驗證等。
+
+## 在 `Response` 中使用 `jsonable_encoder` { #using-the-jsonable-encoder-in-a-response }
+
+因為 **FastAPI** 不會對你回傳的 `Response` 做任何更動,你需要自行確保它的內容已經準備好。
+
+例如,你不能直接把一個 Pydantic 模型放進 `JSONResponse`,需要先把它轉成 `dict`,並將所有資料型別(像是 `datetime`、`UUID` 等)轉成與 JSON 相容的型別。
+
+在這些情況下,你可以先用 `jsonable_encoder` 把資料轉好,再傳給回應物件:
+
+{* ../../docs_src/response_directly/tutorial001_py310.py hl[5:6,20:21] *}
+
+/// note | 技術細節
+
+你也可以使用 `from starlette.responses import JSONResponse`。
+
+**FastAPI** 為了方便開發者,將 `starlette.responses` 也提供為 `fastapi.responses`。但大多數可用的回應類型其實直接來自 Starlette。
+
+///
+
+## 回傳自訂 `Response` { #returning-a-custom-response }
+
+上面的範例展示了所需的各個部分,但目前還不太實用,因為你其實可以直接回傳 `item`,**FastAPI** 就會幫你把它放進 `JSONResponse`,轉成 `dict` 等,這些都是預設行為。
+
+現在來看看如何用它來回傳自訂回應。
+
+假設你想要回傳一個
XML 回應。
+
+你可以把 XML 內容放進一個字串,把它放進 `Response`,然後回傳它:
+
+{* ../../docs_src/response_directly/tutorial002_py310.py hl[1,18] *}
+
+## 注意事項 { #notes }
+
+當你直接回傳 `Response` 時,其資料不會自動被驗證、轉換(序列化)或文件化。
+
+但你仍然可以依照[在 OpenAPI 中的額外回應](additional-responses.md){.internal-link target=_blank}中的說明進行文件化。
+
+在後續章節中,你會看到如何在仍保有自動資料轉換、文件化等的同時,使用/宣告這些自訂的 `Response`。
diff --git a/docs/zh-hant/docs/advanced/response-headers.md b/docs/zh-hant/docs/advanced/response-headers.md
new file mode 100644
index 0000000000..6e32ca1b39
--- /dev/null
+++ b/docs/zh-hant/docs/advanced/response-headers.md
@@ -0,0 +1,41 @@
+# 回應標頭 { #response-headers }
+
+## 使用 `Response` 參數 { #use-a-response-parameter }
+
+你可以在你的*路徑操作函式(path operation function)*中宣告一個 `Response` 型別的參數(就像處理 Cookie 一樣)。
+
+然後你可以在那個*暫時性的* `Response` 物件上設定標頭。
+
+{* ../../docs_src/response_headers/tutorial002_py310.py hl[1, 7:8] *}
+
+接著你可以像平常一樣回傳任何你需要的物件(`dict`、資料庫模型等)。
+
+如果你宣告了 `response_model`,它仍會用來過濾並轉換你回傳的物件。
+
+FastAPI 會使用那個暫時性的回應來擷取標頭(還有 Cookie 與狀態碼),並把它們放到最終回應中;最終回應包含你回傳的值,且會依任何 `response_model` 進行過濾。
+
+你也可以在依賴中宣告 `Response` 參數,並在其中設定標頭(與 Cookie)。
+
+## 直接回傳 `Response` { #return-a-response-directly }
+
+當你直接回傳 `Response` 時,也能加入標頭。
+
+依照[直接回傳 Response](response-directly.md){.internal-link target=_blank}中的說明建立回應,並把標頭作為額外參數傳入:
+
+{* ../../docs_src/response_headers/tutorial001_py310.py hl[10:12] *}
+
+/// note | 技術細節
+
+你也可以使用 `from starlette.responses import Response` 或 `from starlette.responses import JSONResponse`。
+
+為了方便開發者,FastAPI 提供與 `starlette.responses` 相同的內容於 `fastapi.responses`。但大多數可用的回應類型其實直接來自 Starlette。
+
+由於 `Response` 常用來設定標頭與 Cookie,FastAPI 也在 `fastapi.Response` 提供了它。
+
+///
+
+## 自訂標頭 { #custom-headers }
+
+請記住,專有的自訂標頭可以
使用 `X-` 前綴來新增。
+
+但如果你有自訂標頭並希望瀏覽器端的客戶端能看見它們,你需要把這些標頭加入到 CORS 設定中(詳見 [CORS(跨來源資源共用)](../tutorial/cors.md){.internal-link target=_blank}),使用在
Starlette 的 CORS 文件中記載的 `expose_headers` 參數。
diff --git a/docs/zh-hant/docs/advanced/security/http-basic-auth.md b/docs/zh-hant/docs/advanced/security/http-basic-auth.md
new file mode 100644
index 0000000000..ea3d528292
--- /dev/null
+++ b/docs/zh-hant/docs/advanced/security/http-basic-auth.md
@@ -0,0 +1,107 @@
+# HTTP 基本認證 { #http-basic-auth }
+
+在最簡單的情況下,你可以使用 HTTP Basic 認證。
+
+在 HTTP Basic 認證中,應用程式會期待一個包含使用者名稱與密碼的標頭。
+
+如果沒有接收到,會回傳 HTTP 401「Unauthorized」錯誤。
+
+並回傳一個 `WWW-Authenticate` 標頭,其值為 `Basic`,以及可選的 `realm` 參數。
+
+這會告訴瀏覽器顯示內建的使用者名稱與密碼提示視窗。
+
+接著,當你輸入該使用者名稱與密碼時,瀏覽器會自動在標頭中送出它們。
+
+## 簡單的 HTTP 基本認證 { #simple-http-basic-auth }
+
+- 匯入 `HTTPBasic` 與 `HTTPBasicCredentials`。
+- 使用 `HTTPBasic` 建立一個「`security` scheme」。
+- 在你的*路徑操作*中以依賴的方式使用該 `security`。
+- 它會回傳一個 `HTTPBasicCredentials` 型別的物件:
+ - 其中包含傳來的 `username` 與 `password`。
+
+{* ../../docs_src/security/tutorial006_an_py310.py hl[4,8,12] *}
+
+當你第一次嘗試開啟該 URL(或在文件中點擊 "Execute" 按鈕)時,瀏覽器會要求輸入你的使用者名稱與密碼:
+
+

+
+## 檢查使用者名稱 { #check-the-username }
+
+以下是一個更完整的範例。
+
+使用一個依賴來檢查使用者名稱與密碼是否正確。
+
+為此,使用 Python 標準模組
`secrets` 來比對使用者名稱與密碼。
+
+`secrets.compare_digest()` 需要接收 `bytes`,或是只包含 ASCII 字元(英文字符)的 `str`。這表示它無法處理像 `á` 這樣的字元,例如 `Sebastián`。
+
+為了處理這點,我們會先將 `username` 與 `password` 以 UTF-8 編碼成 `bytes`。
+
+接著我們可以使用 `secrets.compare_digest()` 來確認 `credentials.username` 等於 `"stanleyjobson"`,而 `credentials.password` 等於 `"swordfish"`。
+
+{* ../../docs_src/security/tutorial007_an_py310.py hl[1,12:24] *}
+
+這大致等同於:
+
+```Python
+if not (credentials.username == "stanleyjobson") or not (credentials.password == "swordfish"):
+ # 回傳錯誤
+ ...
+```
+
+但藉由使用 `secrets.compare_digest()`,可以防禦一種稱為「計時攻擊」的攻擊。
+
+### 計時攻擊 { #timing-attacks }
+
+什麼是「計時攻擊」呢?
+
+想像有攻擊者在嘗試猜測使用者名稱與密碼。
+
+他們送出一個帶有使用者名稱 `johndoe` 與密碼 `love123` 的請求。
+
+接著,你的應用程式中的 Python 程式碼等同於:
+
+```Python
+if "johndoe" == "stanleyjobson" and "love123" == "swordfish":
+ ...
+```
+
+當 Python 比較 `johndoe` 的第一個 `j` 與 `stanleyjobson` 的第一個 `s` 時,會立刻回傳 `False`,因為已經知道兩個字串不同,覺得「沒必要浪費計算資源繼續比較剩下的字元」。你的應用程式便會回應「Incorrect username or password」。
+
+但接著攻擊者改用使用者名稱 `stanleyjobsox` 與密碼 `love123` 嘗試。
+
+你的應用程式程式碼會做類似:
+
+```Python
+if "stanleyjobsox" == "stanleyjobson" and "love123" == "swordfish":
+ ...
+```
+
+Python 會必須先比較完整的 `stanleyjobso`(在 `stanleyjobsox` 與 `stanleyjobson` 之中都一樣),才會發現兩個字串不同。因此回覆「Incorrect username or password」會多花一些微秒。
+
+#### 回應時間幫了攻擊者 { #the-time-to-answer-helps-the-attackers }
+
+此時,透過觀察伺服器回覆「Incorrect username or password」多花了幾個微秒,攻擊者就知道他們有某些地方猜對了,前幾個字母是正確的。
+
+接著他們會再嘗試,知道它更可能接近 `stanleyjobsox` 而不是 `johndoe`。
+
+#### 「專業」的攻擊 { #a-professional-attack }
+
+當然,攻擊者不會手動嘗試這一切,他們會寫程式來做,可能每秒進行上千或上百萬次測試,一次只多猜中一個正確字母。
+
+但這樣做,幾分鐘或幾小時內,他們就能在我們應用程式「協助」下,僅靠回應時間就猜出正確的使用者名稱與密碼。
+
+#### 用 `secrets.compare_digest()` 修正 { #fix-it-with-secrets-compare-digest }
+
+但在我們的程式碼中實際使用的是 `secrets.compare_digest()`。
+
+簡而言之,將 `stanleyjobsox` 與 `stanleyjobson` 比較所花的時間,會與將 `johndoe` 與 `stanleyjobson` 比較所花的時間相同;密碼也一樣。
+
+如此一來,在應用程式程式碼中使用 `secrets.compare_digest()`,就能安全地防禦這整類的安全攻擊。
+
+### 回傳錯誤 { #return-the-error }
+
+在偵測到憑證不正確之後,回傳一個狀態碼為 401 的 `HTTPException`(與未提供憑證時相同),並加上 `WWW-Authenticate` 標頭,讓瀏覽器再次顯示登入提示:
+
+{* ../../docs_src/security/tutorial007_an_py310.py hl[26:30] *}
diff --git a/docs/zh-hant/docs/advanced/security/index.md b/docs/zh-hant/docs/advanced/security/index.md
new file mode 100644
index 0000000000..9a4cfbbfd6
--- /dev/null
+++ b/docs/zh-hant/docs/advanced/security/index.md
@@ -0,0 +1,19 @@
+# 進階安全性 { #advanced-security }
+
+## 額外功能 { #additional-features }
+
+除了[教學 - 使用者指南:安全性](../../tutorial/security/index.md){.internal-link target=_blank}中涵蓋的內容外,還有一些用來處理安全性的額外功能。
+
+/// tip
+
+以下各節不一定是「進階」內容。
+
+而且你的情境很可能可以在其中找到解決方案。
+
+///
+
+## 請先閱讀教學 { #read-the-tutorial-first }
+
+以下各節假設你已閱讀主要的[教學 - 使用者指南:安全性](../../tutorial/security/index.md){.internal-link target=_blank}。
+
+它們都建立在相同的概念之上,但提供一些額外的功能。
diff --git a/docs/zh-hant/docs/advanced/security/oauth2-scopes.md b/docs/zh-hant/docs/advanced/security/oauth2-scopes.md
new file mode 100644
index 0000000000..029572d433
--- /dev/null
+++ b/docs/zh-hant/docs/advanced/security/oauth2-scopes.md
@@ -0,0 +1,274 @@
+# OAuth2 範圍(scopes) { #oauth2-scopes }
+
+你可以直接在 FastAPI 中使用 OAuth2 的 scopes,已整合可無縫運作。
+
+這能讓你在 OpenAPI 應用(以及 API 文件)中,依照 OAuth2 標準,實作更細粒度的權限系統。
+
+帶有 scopes 的 OAuth2 是許多大型身分驗證提供者(如 Facebook、Google、GitHub、Microsoft、X(Twitter)等)所使用的機制。他們用它來為使用者與應用程式提供特定權限。
+
+每次你「使用」Facebook、Google、GitHub、Microsoft、X(Twitter)「登入」時,那個應用就是在使用帶有 scopes 的 OAuth2。
+
+在本節中,你將看到如何在你的 FastAPI 應用中,用同樣的帶有 scopes 的 OAuth2 管理驗證與授權。
+
+/// warning
+
+這一節算是進階內容。如果你剛開始,可以先跳過。
+
+你不一定需要 OAuth2 scopes,你可以用任何你想要的方式處理驗證與授權。
+
+但帶有 scopes 的 OAuth2 可以很漂亮地整合進你的 API(透過 OpenAPI)與 API 文件。
+
+無論如何,你仍然會在程式碼中,依你的需求,強制檢查那些 scopes,或其他任何安全性/授權需求。
+
+在許多情況下,帶有 scopes 的 OAuth2 可能有點大材小用。
+
+但如果你確定需要,或是好奇,請繼續閱讀。
+
+///
+
+## OAuth2 scopes 與 OpenAPI { #oauth2-scopes-and-openapi }
+
+OAuth2 規格將「scopes」定義為以空白分隔的一串字串列表。
+
+每個字串的內容可以有任意格式,但不應包含空白。
+
+這些 scopes 代表「權限」。
+
+在 OpenAPI(例如 API 文件)中,你可以定義「security schemes」。
+
+當某個 security scheme 使用 OAuth2 時,你也可以宣告並使用 scopes。
+
+每個「scope」就是一個(不含空白的)字串。
+
+它們通常用來宣告特定的安全性權限,例如:
+
+- `users:read` 或 `users:write` 是常見的例子。
+- `instagram_basic` 是 Facebook / Instagram 使用的。
+- `https://www.googleapis.com/auth/drive` 是 Google 使用的。
+
+/// info
+
+在 OAuth2 中,「scope」只是宣告所需特定權限的一個字串。
+
+是否包含像 `:` 這樣的字元,或是否是一個 URL,都沒差。
+
+那些細節取決於實作。
+
+對 OAuth2 而言,它們就是字串。
+
+///
+
+## 全局概觀 { #global-view }
+
+先快速看看相對於主教學「使用密碼(與雜湊)、Bearer 與 JWT token 的 OAuth2」的差異([OAuth2 with Password (and hashing), Bearer with JWT tokens](../../tutorial/security/oauth2-jwt.md){.internal-link target=_blank})。現在加入了 OAuth2 scopes:
+
+{* ../../docs_src/security/tutorial005_an_py310.py hl[5,9,13,47,65,106,108:116,122:126,130:136,141,157] *}
+
+接著我們一步一步檢視這些變更。
+
+## OAuth2 安全性方案 { #oauth2-security-scheme }
+
+第一個變更是:我們現在宣告了帶有兩個可用 scope 的 OAuth2 安全性方案,`me` 與 `items`。
+
+參數 `scopes` 接收一個 `dict`,以各 scope 為鍵、其描述為值:
+
+{* ../../docs_src/security/tutorial005_an_py310.py hl[63:66] *}
+
+由於現在宣告了這些 scopes,當你登入/授權時,它們會出現在 API 文件中。
+
+你可以選擇要授予哪些 scopes 存取權:`me` 與 `items`。
+
+這與你使用 Facebook、Google、GitHub 等登入時所授與權限的機制相同:
+
+

+
+## 內含 scopes 的 JWT token { #jwt-token-with-scopes }
+
+現在,修改 token 的路徑操作以回傳所請求的 scopes。
+
+我們仍然使用相同的 `OAuth2PasswordRequestForm`。它包含屬性 `scopes`,其為 `list` 的 `str`,列出請求中收到的每個 scope。
+
+並且我們將這些 scopes 作為 JWT token 的一部分回傳。
+
+/// danger
+
+為了簡化,這裡我們只是直接把接收到的 scopes 加進 token。
+
+但在你的應用中,為了安全性,你應確保只加入該使用者實際可擁有或你預先定義的 scopes。
+
+///
+
+{* ../../docs_src/security/tutorial005_an_py310.py hl[157] *}
+
+## 在路徑操作與相依性中宣告 scopes { #declare-scopes-in-path-operations-and-dependencies }
+
+現在我們宣告 `/users/me/items/` 這個路徑操作需要 `items` 這個 scope。
+
+為此,我們從 `fastapi` 匯入並使用 `Security`。
+
+你可以使用 `Security` 來宣告相依性(就像 `Depends`),但 `Security` 也能接收參數 `scopes`,其為 scopes(字串)的列表。
+
+在這裡,我們將相依函式 `get_current_active_user` 傳給 `Security`(就像使用 `Depends` 一樣)。
+
+但同時也傳入一個 `list` 的 scopes,這裡只有一個 scope:`items`(當然也可以有更多)。
+
+而相依函式 `get_current_active_user` 也能宣告子相依性,不只用 `Depends`,也能用 `Security`。它宣告了自己的子相依函式(`get_current_user`),並加入更多 scope 要求。
+
+在這個例子中,它要求 `me` 這個 scope(也可以要求多個)。
+
+/// note
+
+你不一定需要在不同地方加上不同的 scopes。
+
+我們在這裡這樣做,是為了示範 FastAPI 如何處理在不同層級宣告的 scopes。
+
+///
+
+{* ../../docs_src/security/tutorial005_an_py310.py hl[5,141,172] *}
+
+/// info | 技術細節
+
+`Security` 其實是 `Depends` 的子類別,僅多了一個我們稍後會看到的參數。
+
+改用 `Security` 而不是 `Depends`,能讓 FastAPI 知道可以宣告安全性 scopes、在內部使用它們,並用 OpenAPI 文件化 API。
+
+另外,當你從 `fastapi` 匯入 `Query`、`Path`、`Depends`、`Security` 等時,實際上它們是回傳特殊類別的函式。
+
+///
+
+## 使用 `SecurityScopes` { #use-securityscopes }
+
+現在更新相依性 `get_current_user`。
+
+上面的相依性就是使用它。
+
+這裡我們使用先前建立的相同 OAuth2 scheme,並將其宣告為相依性:`oauth2_scheme`。
+
+因為此相依函式本身沒有任何 scope 要求,所以我們可以用 `Depends` 搭配 `oauth2_scheme`,當不需要指定安全性 scopes 時就不必用 `Security`。
+
+我們也宣告了一個型別為 `SecurityScopes` 的特殊參數,從 `fastapi.security` 匯入。
+
+這個 `SecurityScopes` 類似於 `Request`(`Request` 用來直接取得請求物件)。
+
+{* ../../docs_src/security/tutorial005_an_py310.py hl[9,106] *}
+
+## 使用這些 `scopes` { #use-the-scopes }
+
+參數 `security_scopes` 的型別是 `SecurityScopes`。
+
+它會有屬性 `scopes`,包含一個列表,內含此函式本身與所有使用它為子相依性的相依性所要求的所有 scopes。也就是所有「相依者(dependants)」... 這聽起來可能有點混亂,下面會再解釋。
+
+`security_scopes` 物件(類別 `SecurityScopes`)也提供 `scope_str` 屬性,為一個字串,包含那些以空白分隔的 scopes(我們會用到)。
+
+我們建立一個可在多處重複丟出(`raise`)的 `HTTPException`。
+
+在這個例外中,我們把所需的 scopes(若有)以空白分隔的字串形式(透過 `scope_str`)加入,並將該包含 scopes 的字串放在 `WWW-Authenticate` 標頭中(這是規格的一部分)。
+
+{* ../../docs_src/security/tutorial005_an_py310.py hl[106,108:116] *}
+
+## 驗證 `username` 與資料結構 { #verify-the-username-and-data-shape }
+
+我們先確認取得了 `username`,並取出 scopes。
+
+接著用 Pydantic 模型驗證這些資料(捕捉 `ValidationError` 例外),若在讀取 JWT token 或用 Pydantic 驗證資料時出錯,就丟出先前建立的 `HTTPException`。
+
+為此,我們更新了 Pydantic 模型 `TokenData`,加入新屬性 `scopes`。
+
+透過 Pydantic 驗證資料,我們可以確保,例如,scopes 正好是 `list` 的 `str`,而 `username` 是 `str`。
+
+否則若是 `dict` 或其他型別,可能在後續某處使應用壞掉,造成安全風險。
+
+我們也會確認該 `username` 對應的使用者是否存在,否則同樣丟出之前建立的例外。
+
+{* ../../docs_src/security/tutorial005_an_py310.py hl[47,117:129] *}
+
+## 驗證 `scopes` { #verify-the-scopes }
+
+我們現在要驗證,此相依性與所有相依者(包含路徑操作)所要求的所有 scopes,是否都包含在收到的 token 內所提供的 scopes 中;否則就丟出 `HTTPException`。
+
+為此,我們使用 `security_scopes.scopes`,其中包含一個 `list`,列出所有這些 `str` 形式的 scopes。
+
+{* ../../docs_src/security/tutorial005_an_py310.py hl[130:136] *}
+
+## 相依性樹與 scopes { #dependency-tree-and-scopes }
+
+我們再回顧一次這個相依性樹與 scopes。
+
+由於 `get_current_active_user` 相依於 `get_current_user`,因此在 `get_current_active_user` 宣告的 `"me"` 這個 scope 會包含在傳給 `get_current_user` 的 `security_scopes.scopes` 的必須 scopes 清單中。
+
+路徑操作本身也宣告了 `"items"` 這個 scope,因此它也會包含在傳給 `get_current_user` 的 `security_scopes.scopes` 中。
+
+以下是相依性與 scopes 的階層關係:
+
+- 路徑操作 `read_own_items` 具有:
+ - 需要的 scopes `["items"]`,並有相依性:
+ - `get_current_active_user`:
+ - 相依函式 `get_current_active_user` 具有:
+ - 需要的 scopes `["me"]`,並有相依性:
+ - `get_current_user`:
+ - 相依函式 `get_current_user` 具有:
+ - 自身沒有需要的 scopes。
+ - 一個使用 `oauth2_scheme` 的相依性。
+ - 一個型別為 `SecurityScopes` 的 `security_scopes` 參數:
+ - 這個 `security_scopes` 參數有屬性 `scopes`,其為一個 `list`,包含了上面宣告的所有 scopes,因此:
+ - 對於路徑操作 `read_own_items`,`security_scopes.scopes` 會包含 `["me", "items"]`。
+ - 對於路徑操作 `read_users_me`,因為它在相依性 `get_current_active_user` 中被宣告,`security_scopes.scopes` 會包含 `["me"]`。
+ - 對於路徑操作 `read_system_status`,因為它沒有宣告任何帶 `scopes` 的 `Security`,且其相依性 `get_current_user` 也未宣告任何 `scopes`,所以 `security_scopes.scopes` 會包含 `[]`(空)。
+
+/// tip
+
+這裡重要且「神奇」的是:`get_current_user` 在每個路徑操作中,會有不同的 `scopes` 清單需要檢查。
+
+這完全取決於該路徑操作與其相依性樹中每個相依性所宣告的 `scopes`。
+
+///
+
+## 更多關於 `SecurityScopes` 的細節 { #more-details-about-securityscopes }
+
+你可以在任意位置、多個地方使用 `SecurityScopes`,它不需要位於「根」相依性。
+
+它會永遠帶有對於「該特定」路徑操作與「該特定」相依性樹中,目前 `Security` 相依性所宣告的安全性 scopes(以及所有相依者):
+
+因為 `SecurityScopes` 會擁有由相依者宣告的所有 scopes,你可以在一個集中式相依函式中用它來驗證 token 是否具有所需 scopes,然後在不同路徑操作中宣告不同的 scope 要求。
+
+它們會在每個路徑操作被各自獨立檢查。
+
+## 試用看看 { #check-it }
+
+如果你打開 API 文件,你可以先驗證並指定你要授權的 scopes。
+
+

+
+如果你沒有選任何 scope,你仍會「通過驗證」,但當你嘗試存取 `/users/me/` 或 `/users/me/items/` 時,會收到沒有足夠權限的錯誤。你仍能存取 `/status/`。
+
+若你只選了 `me` 而未選 `items`,你能存取 `/users/me/`,但無法存取 `/users/me/items/`。
+
+這就是第三方應用在取得使用者提供的 token 後,嘗試存取上述路徑操作時,會依使用者授與該應用的權限多寡而有不同結果。
+
+## 關於第三方整合 { #about-third-party-integrations }
+
+在這個範例中,我們使用 OAuth2 的「password」流程。
+
+當我們登入自己的應用(可能也有自己的前端)時,這是合適的。
+
+因為我們可以信任它接收 `username` 與 `password`,因為我們掌控它。
+
+但如果你要打造一個讓他人連接的 OAuth2 應用(也就是你要建立一個相當於 Facebook、Google、GitHub 等的身分驗證提供者),你應該使用其他流程之一。
+
+最常見的是 Implicit Flow(隱式流程)。
+
+最安全的是 Authorization Code Flow(授權碼流程),但它需要更多步驟、實作也更複雜。因為較複雜,許多提供者最後會建議使用隱式流程。
+
+/// note
+
+很常見的是,每個身分驗證提供者會用不同的方式命名他們的流程,讓它成為品牌的一部分。
+
+但最終,他們實作的都是相同的 OAuth2 標準。
+
+///
+
+FastAPI 在 `fastapi.security.oauth2` 中提供了所有這些 OAuth2 驗證流程的工具。
+
+## 在裝飾器 `dependencies` 中使用 `Security` { #security-in-decorator-dependencies }
+
+就像你可以在裝飾器的 `dependencies` 參數中定義一個 `Depends` 的 `list` 一樣(詳見[路徑操作裝飾器中的相依性](../../tutorial/dependencies/dependencies-in-path-operation-decorators.md){.internal-link target=_blank}),你也可以在那裡使用帶有 `scopes` 的 `Security`。
diff --git a/docs/zh-hant/docs/advanced/settings.md b/docs/zh-hant/docs/advanced/settings.md
new file mode 100644
index 0000000000..1ee5ad7cc2
--- /dev/null
+++ b/docs/zh-hant/docs/advanced/settings.md
@@ -0,0 +1,302 @@
+# 設定與環境變數 { #settings-and-environment-variables }
+
+在許多情況下,你的應用程式可能需要一些外部設定或組態,例如密鑰、資料庫憑證、電子郵件服務的憑證等。
+
+這些設定大多是可變的(可能會改變),像是資料庫 URL。也有許多可能是敏感資訊,例如密鑰。
+
+因此,通常會透過環境變數提供這些設定,讓應用程式去讀取。
+
+/// tip
+
+若想了解環境變數,你可以閱讀[環境變數](../environment-variables.md){.internal-link target=_blank}。
+
+///
+
+## 型別與驗證 { #types-and-validation }
+
+這些環境變數只能處理文字字串,因為它們在 Python 之外,必須與其他程式與系統的其餘部分相容(甚至跨作業系統,如 Linux、Windows、macOS)。
+
+這表示在 Python 中自環境變數讀取到的任何值都會是 `str`,而任何轉型成其他型別或驗證都必須在程式碼中完成。
+
+## Pydantic `Settings` { #pydantic-settings }
+
+幸好,Pydantic 提供了很好的工具,可用來處理由環境變數而來的設定:
Pydantic:設定管理。
+
+### 安裝 `pydantic-settings` { #install-pydantic-settings }
+
+首先,請先建立你的[虛擬環境](../virtual-environments.md){.internal-link target=_blank},啟用它,然後安裝 `pydantic-settings` 套件:
+
+
+
+```console
+$ pip install pydantic-settings
+---> 100%
+```
+
+
+
+當你用 `all` extras 安裝時,它也會一併包含在內:
+
+
+
+```console
+$ pip install "fastapi[all]"
+---> 100%
+```
+
+
+
+### 建立 `Settings` 物件 { #create-the-settings-object }
+
+從 Pydantic 匯入 `BaseSettings` 並建立子類別,與建立 Pydantic model 的方式非常類似。
+
+就像使用 Pydantic model 一樣,你用型別註解宣告類別屬性,並可選擇性地提供預設值。
+
+你可以使用與 Pydantic model 相同的所有驗證功能與工具,例如不同的資料型別與透過 `Field()` 進行額外驗證。
+
+{* ../../docs_src/settings/tutorial001_py310.py hl[2,5:8,11] *}
+
+/// tip
+
+如果你想要可以直接複製貼上的範例,先別用這個,請改用本文最後一個範例。
+
+///
+
+接著,當你建立該 `Settings` 類別的實例(此處為 `settings` 物件)時,Pydantic 會以不區分大小寫的方式讀取環境變數,因此,即使環境變數是大寫的 `APP_NAME`,也會被讀入屬性 `app_name`。
+
+然後它會轉換並驗證資料。因此,當你使用該 `settings` 物件時,你會得到你宣告的型別的資料(例如 `items_per_user` 會是 `int`)。
+
+### 使用 `settings` { #use-the-settings }
+
+接著你可以在應用程式中使用新的 `settings` 物件:
+
+{* ../../docs_src/settings/tutorial001_py310.py hl[18:20] *}
+
+### 執行伺服器 { #run-the-server }
+
+接下來,你可以在啟動伺服器時,將設定以環境變數傳入。舉例來說,你可以設定 `ADMIN_EMAIL` 與 `APP_NAME`:
+
+
+
+```console
+$ ADMIN_EMAIL="deadpool@example.com" APP_NAME="ChimichangApp" fastapi run main.py
+
+INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
+```
+
+
+
+/// tip
+
+要為單一指令設定多個環境變數,只要用空白分隔它們,並全部放在指令前面即可。
+
+///
+
+如此一來,`admin_email` 設定會被設為 `"deadpool@example.com"`。
+
+`app_name` 會是 `"ChimichangApp"`。
+
+而 `items_per_user` 則會保留其預設值 `50`。
+
+## 在另一個模組中的設定 { #settings-in-another-module }
+
+你也可以把這些設定放在另一個模組檔案中,就像在[更大的應用程式 - 多個檔案](../tutorial/bigger-applications.md){.internal-link target=_blank}所示。
+
+例如,你可以有一個 `config.py` 檔案如下:
+
+{* ../../docs_src/settings/app01_py310/config.py *}
+
+然後在 `main.py` 檔案中使用它:
+
+{* ../../docs_src/settings/app01_py310/main.py hl[3,11:13] *}
+
+/// tip
+
+你也需要一個 `__init__.py` 檔案,詳見[更大的應用程式 - 多個檔案](../tutorial/bigger-applications.md){.internal-link target=_blank}。
+
+///
+
+## 在相依中的設定 { #settings-in-a-dependency }
+
+在某些情境中,從相依(dependency)提供設定,會比在各處使用一個全域的 `settings` 物件更有用。
+
+這在測試時特別實用,因為你可以很容易用自訂的設定來覆寫一個相依。
+
+### 設定檔 { #the-config-file }
+
+延續前一個範例,你的 `config.py` 可以像這樣:
+
+{* ../../docs_src/settings/app02_an_py310/config.py hl[10] *}
+
+注意現在我們不再建立預設實例 `settings = Settings()`。
+
+### 主應用程式檔案 { #the-main-app-file }
+
+現在我們建立一個相依,回傳新的 `config.Settings()`。
+
+{* ../../docs_src/settings/app02_an_py310/main.py hl[6,12:13] *}
+
+/// tip
+
+我們稍後會討論 `@lru_cache`。
+
+現在你可以先把 `get_settings()` 視為一般函式。
+
+///
+
+接著我們可以在*路徑操作函式 (path operation function)* 中將它宣告為相依,並在需要的地方使用它。
+
+{* ../../docs_src/settings/app02_an_py310/main.py hl[17,19:21] *}
+
+### 設定與測試 { #settings-and-testing }
+
+接著,在測試時要提供不同的設定物件會非常容易,只要為 `get_settings` 建立相依覆寫(dependency override)即可:
+
+{* ../../docs_src/settings/app02_an_py310/test_main.py hl[9:10,13,21] *}
+
+在相依覆寫中,我們在建立新的 `Settings` 物件時設定 `admin_email` 的新值,然後回傳該新物件。
+
+接著我們就可以測試它是否被使用。
+
+## 讀取 `.env` 檔 { #reading-a-env-file }
+
+如果你有許多設定,而且在不同環境中可能常常變動,將它們放在一個檔案中,然後像讀取環境變數一樣自該檔案讀取,可能會很實用。
+
+這種作法很常見,這些環境變數通常放在 `.env` 檔中,而該檔案被稱為「dotenv」。
+
+/// tip
+
+在類 Unix 系統(如 Linux 與 macOS)中,以點(`.`)開頭的檔案是隱藏檔。
+
+但 dotenv 檔並不一定必須使用這個確切的檔名。
+
+///
+
+Pydantic 透過外部函式庫支援讀取這類型的檔案。你可以閱讀更多:
Pydantic Settings:Dotenv (.env) 支援。
+
+/// tip
+
+要讓這個功能運作,你需要 `pip install python-dotenv`。
+
+///
+
+### `.env` 檔 { #the-env-file }
+
+你可以有一個 `.env` 檔如下:
+
+```bash
+ADMIN_EMAIL="deadpool@example.com"
+APP_NAME="ChimichangApp"
+```
+
+### 從 `.env` 讀取設定 { #read-settings-from-env }
+
+然後更新你的 `config.py`:
+
+{* ../../docs_src/settings/app03_an_py310/config.py hl[9] *}
+
+/// tip
+
+`model_config` 屬性僅用於 Pydantic 的設定。你可以閱讀更多:
Pydantic:概念:設定。
+
+///
+
+在這裡我們在 Pydantic 的 `Settings` 類別中定義設定 `env_file`,並將其值設為要使用的 dotenv 檔名。
+
+### 使用 `lru_cache` 只建立一次 `Settings` { #creating-the-settings-only-once-with-lru-cache }
+
+從磁碟讀取檔案通常是昂貴(慢)的操作,所以你可能希望只做一次,然後重複使用同一個設定物件,而不是在每個請求都讀取。
+
+但每次我們這樣做:
+
+```Python
+Settings()
+```
+
+都會建立一個新的 `Settings` 物件,而且在建立時會再次讀取 `.env` 檔。
+
+如果相依函式只是像這樣:
+
+```Python
+def get_settings():
+ return Settings()
+```
+
+我們就會為每個請求建立該物件,並在每個請求都讀取 `.env` 檔。⚠️
+
+但由於我們在上方使用了 `@lru_cache` 裝飾器,`Settings` 物件只會在第一次呼叫時建立一次。✔️
+
+{* ../../docs_src/settings/app03_an_py310/main.py hl[1,11] *}
+
+之後在下一批請求的相依中任何對 `get_settings()` 的呼叫,都不會再執行 `get_settings()` 的內部程式碼與建立新的 `Settings` 物件,而是會一再回傳第一次呼叫時回傳的同一個物件。
+
+#### `lru_cache` 技術細節 { #lru-cache-technical-details }
+
+`@lru_cache` 會修改它所裝飾的函式,使其回傳第一次回傳的相同值,而不是每次都重新計算、執行函式碼。
+
+因此,被裝飾的函式對於每組參數組合只會執行一次。之後,凡是以完全相同參數組合呼叫時,都會重複使用先前對應的回傳值。
+
+例如,如果你有一個函式:
+
+```Python
+@lru_cache
+def say_hi(name: str, salutation: str = "Ms."):
+ return f"Hello {salutation} {name}"
+```
+
+你的程式可能會這樣執行:
+
+```mermaid
+sequenceDiagram
+
+participant code as Code
+participant function as say_hi()
+participant execute as Execute function
+
+ rect rgba(0, 255, 0, .1)
+ code ->> function: say_hi(name="Camila")
+ function ->> execute: execute function code
+ execute ->> code: return the result
+ end
+
+ rect rgba(0, 255, 255, .1)
+ code ->> function: say_hi(name="Camila")
+ function ->> code: return stored result
+ end
+
+ rect rgba(0, 255, 0, .1)
+ code ->> function: say_hi(name="Rick")
+ function ->> execute: execute function code
+ execute ->> code: return the result
+ end
+
+ rect rgba(0, 255, 0, .1)
+ code ->> function: say_hi(name="Rick", salutation="Mr.")
+ function ->> execute: execute function code
+ execute ->> code: return the result
+ end
+
+ rect rgba(0, 255, 255, .1)
+ code ->> function: say_hi(name="Rick")
+ function ->> code: return stored result
+ end
+
+ rect rgba(0, 255, 255, .1)
+ code ->> function: say_hi(name="Camila")
+ function ->> code: return stored result
+ end
+```
+
+在我們的相依 `get_settings()` 這個案例中,該函式甚至不帶任何參數,因此它總是回傳相同的值。
+
+如此一來,它的行為幾乎就像全域變數。但因為它使用相依函式,因此我們可以在測試時輕鬆將其覆寫。
+
+`@lru_cache` 是 `functools` 的一部分,而 `functools` 是 Python 標準程式庫的一部分。你可以在
Python 文件中閱讀 `@lru_cache` 以了解更多。
+
+## 回顧 { #recap }
+
+你可以使用 Pydantic Settings 來處理應用程式的設定或組態,並享有 Pydantic model 的全部能力。
+
+- 透過相依可以讓測試更容易。
+- 你可以搭配 `.env` 檔使用。
+- 使用 `@lru_cache` 可以避免每個請求都重複讀取 dotenv 檔,同時仍可在測試時覆寫設定。
diff --git a/docs/zh-hant/docs/advanced/sub-applications.md b/docs/zh-hant/docs/advanced/sub-applications.md
new file mode 100644
index 0000000000..773bc4b886
--- /dev/null
+++ b/docs/zh-hant/docs/advanced/sub-applications.md
@@ -0,0 +1,67 @@
+# 子應用程式 - 掛載 { #sub-applications-mounts }
+
+若你需要兩個彼此獨立的 FastAPI 應用程式,各自擁有獨立的 OpenAPI 與文件 UI,你可以有一個主應用,並「掛載」一個(或多個)子應用程式。
+
+## 掛載一個 **FastAPI** 應用程式 { #mounting-a-fastapi-application }
+
+「掛載」是指在某個特定路徑下加入一個完全「獨立」的應用程式,之後該應用程式會負責處理該路徑底下的一切,使用該子應用程式中宣告的*路徑操作(path operation)*。
+
+### 頂層應用程式 { #top-level-application }
+
+先建立主(頂層)**FastAPI** 應用程式以及它的*路徑操作*:
+
+{* ../../docs_src/sub_applications/tutorial001_py310.py hl[3, 6:8] *}
+
+### 子應用程式 { #sub-application }
+
+接著,建立你的子應用程式及其*路徑操作*。
+
+這個子應用程式就是另一個標準的 FastAPI 應用,但這個會被「掛載」:
+
+{* ../../docs_src/sub_applications/tutorial001_py310.py hl[11, 14:16] *}
+
+### 掛載子應用程式 { #mount-the-sub-application }
+
+在你的頂層應用程式 `app` 中,掛載子應用程式 `subapi`。
+
+在此範例中,它會被掛載在路徑 `/subapi`:
+
+{* ../../docs_src/sub_applications/tutorial001_py310.py hl[11, 19] *}
+
+### 檢查自動 API 文件 { #check-the-automatic-api-docs }
+
+現在,用你的檔案執行 `fastapi` 指令:
+
+
+
+```console
+$ fastapi dev main.py
+
+INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
+```
+
+
+
+然後開啟位於
http://127.0.0.1:8000/docs 的文件。
+
+你會看到主應用的自動 API 文件,只包含它自己的*路徑操作*:
+
+

+
+接著,開啟子應用程式的文件:
http://127.0.0.1:8000/subapi/docs。
+
+你會看到子應用程式的自動 API 文件,只包含它自己的*路徑操作*,而且都在正確的子路徑前綴 `/subapi` 之下:
+
+

+
+如果你嘗試在任一介面中互動,它們都會正常運作,因為瀏覽器能與各自的應用程式或子應用程式通訊。
+
+### 技術細節:`root_path` { #technical-details-root-path }
+
+當你像上面那樣掛載子應用程式時,FastAPI 會使用 ASGI 規範中的一個機制 `root_path`,將子應用程式的掛載路徑告知它。
+
+如此一來,子應用程式就會知道在文件 UI 使用該路徑前綴。
+
+而且子應用程式也能再掛載自己的子應用程式,一切都能正確運作,因為 FastAPI 會自動處理所有這些 `root_path`。
+
+你可以在[在代理伺服器之後](behind-a-proxy.md){.internal-link target=_blank}一節中進一步了解 `root_path` 與如何顯式使用它。
diff --git a/docs/zh-hant/docs/advanced/templates.md b/docs/zh-hant/docs/advanced/templates.md
new file mode 100644
index 0000000000..ffc7599ae2
--- /dev/null
+++ b/docs/zh-hant/docs/advanced/templates.md
@@ -0,0 +1,126 @@
+# 模板 { #templates }
+
+你可以在 **FastAPI** 中使用任意你想要的模板引擎。
+
+常見的選擇是 Jinja2,與 Flask 與其他工具所使用的一樣。
+
+有一些工具可讓你輕鬆設定,並可直接在你的 **FastAPI** 應用程式中使用(由 Starlette 提供)。
+
+## 安裝相依套件 { #install-dependencies }
+
+請先建立一個[虛擬環境](../virtual-environments.md){.internal-link target=_blank}、啟用它,然後安裝 `jinja2`:
+
+
+
+```console
+$ pip install jinja2
+
+---> 100%
+```
+
+
+
+## 使用 `Jinja2Templates` { #using-jinja2templates }
+
+- 匯入 `Jinja2Templates`。
+- 建立一個可重複使用的 `templates` 物件。
+- 在會回傳模板的「*路徑操作(path operation)*」中宣告一個 `Request` 參數。
+- 使用你建立的 `templates` 來渲染並回傳 `TemplateResponse`,傳入模板名稱、`request` 物件,以及在 Jinja2 模板中使用的「context」鍵值對字典。
+
+{* ../../docs_src/templates/tutorial001_py310.py hl[4,11,15:18] *}
+
+/// note
+
+在 FastAPI 0.108.0、Starlette 0.29.0 之前,`name` 是第一個參數。
+
+此外,在更早的版本中,`request` 物件是作為 context 的鍵值對之一傳給 Jinja2 的。
+
+///
+
+/// tip
+
+透過宣告 `response_class=HTMLResponse`,文件 UI 能夠知道回應將會是 HTML。
+
+///
+
+/// note | 技術細節
+
+你也可以使用 `from starlette.templating import Jinja2Templates`。
+
+**FastAPI** 以 `fastapi.templating` 的形式提供與 `starlette.templating` 相同的內容,僅為了方便你(開發者)。但大多數可用的回應類別都直接來自 Starlette,`Request` 與 `StaticFiles` 也是如此。
+
+///
+
+## 撰寫模板 { #writing-templates }
+
+接著你可以在 `templates/item.html` 編寫模板,例如:
+
+```jinja hl_lines="7"
+{!../../docs_src/templates/templates/item.html!}
+```
+
+### 模板 context 值 { #template-context-values }
+
+在包含以下內容的 HTML 中:
+
+{% raw %}
+
+```jinja
+Item ID: {{ id }}
+```
+
+{% endraw %}
+
+...它會顯示你在傳入的 context `dict` 中提供的 `id`:
+
+```Python
+{"id": id}
+```
+
+例如,若 ID 為 `42`,會渲染為:
+
+```html
+Item ID: 42
+```
+
+### 模板 `url_for` 參數 { #template-url-for-arguments }
+
+你也可以在模板中使用 `url_for()`,它所接受的參數與你的「*路徑操作函式(path operation function)*」所使用的參數相同。
+
+因此,包含以下內容的區塊:
+
+{% raw %}
+
+```jinja
+
+```
+
+{% endraw %}
+
+...會產生指向與「*路徑操作函式*」`read_item(id=id)` 相同 URL 的連結。
+
+例如,若 ID 為 `42`,會渲染為:
+
+```html
+
+```
+
+## 模板與靜態檔案 { #templates-and-static-files }
+
+你也可以在模板中使用 `url_for()`,例如搭配你以 `name="static"` 掛載的 `StaticFiles` 使用。
+
+```jinja hl_lines="4"
+{!../../docs_src/templates/templates/item.html!}
+```
+
+在這個例子中,它會連結到 `static/styles.css` 的 CSS 檔案,內容為:
+
+```CSS hl_lines="4"
+{!../../docs_src/templates/static/styles.css!}
+```
+
+而且因為你使用了 `StaticFiles`,該 CSS 檔案會由你的 **FastAPI** 應用程式在 URL `/static/styles.css` 自動提供。
+
+## 更多細節 { #more-details }
+
+想了解更多細節(包含如何測試模板),請參考 Starlette 的模板說明文件。
diff --git a/docs/zh-hant/docs/advanced/testing-dependencies.md b/docs/zh-hant/docs/advanced/testing-dependencies.md
new file mode 100644
index 0000000000..3ce72ccab8
--- /dev/null
+++ b/docs/zh-hant/docs/advanced/testing-dependencies.md
@@ -0,0 +1,53 @@
+# 用覆寫測試相依 { #testing-dependencies-with-overrides }
+
+## 在測試期間覆寫相依 { #overriding-dependencies-during-testing }
+
+有些情境你可能想在測試時覆寫(override)某個相依(dependency)。
+
+你不希望執行原本的相依(以及它可能具有的任何子相依)。
+
+相反地,你想提供一個只在測試期間使用的不同相依(可能只在特定測試中),並回傳一個可以在原本相依值被使用之處使用的值。
+
+### 使用情境:外部服務 { #use-cases-external-service }
+
+例如你有一個需要呼叫的外部驗證提供者。
+
+你傳送一個 token,它會回傳一個已驗證的使用者。
+
+這個提供者可能按每個請求收費,而且呼叫它可能比在測試中使用固定的模擬使用者多花一些時間。
+
+你大概只想對外部提供者測試一次,而不需要在每個測試都呼叫它。
+
+在這種情況下,你可以覆寫用來呼叫該提供者的相依,並在測試中使用自訂的相依來回傳一個模擬使用者。
+
+### 使用 `app.dependency_overrides` 屬性 { #use-the-app-dependency-overrides-attribute }
+
+對這些情況,你的 FastAPI 應用程式有一個屬性 `app.dependency_overrides`,它是一個簡單的 `dict`。
+
+要在測試時覆寫某個相依,把原始相依(函式)作為鍵,並把你的覆寫相依(另一個函式)作為值。
+
+接著 FastAPI 會呼叫這個覆寫,而不是原本的相依。
+
+{* ../../docs_src/dependency_testing/tutorial001_an_py310.py hl[26:27,30] *}
+
+/// tip
+
+你可以為應用程式中任何地方使用到的相依設定覆寫。
+
+原始相依可以用在*路徑操作函式*、*路徑操作裝飾器*(當你不使用其回傳值時)、`.include_router()` 呼叫等。
+
+FastAPI 仍然能夠將其覆寫。
+
+///
+
+然後你可以將 `app.dependency_overrides` 設為空的 `dict` 以重設(移除)所有覆寫:
+
+```Python
+app.dependency_overrides = {}
+```
+
+/// tip
+
+如果只想在某些測試中覆寫相依,你可以在測試開始時(測試函式內)設定覆寫,並在結束時(測試函式結尾)重設。
+
+///
diff --git a/docs/zh-hant/docs/advanced/testing-events.md b/docs/zh-hant/docs/advanced/testing-events.md
new file mode 100644
index 0000000000..db678977a3
--- /dev/null
+++ b/docs/zh-hant/docs/advanced/testing-events.md
@@ -0,0 +1,11 @@
+# 測試事件:lifespan 與 startup - shutdown { #testing-events-lifespan-and-startup-shutdown }
+
+當你需要在測試中執行 lifespan(生命週期)時,你可以使用 TestClient 並搭配 with 陳述式:
+
+{* ../../docs_src/app_testing/tutorial004_py310.py hl[9:15,18,27:28,30:32,41:43] *}
+
+你可以閱讀更多細節:[在測試中執行 lifespan](https://www.starlette.dev/lifespan/#running-lifespan-in-tests)(Starlette 官方文件)。
+
+對於已棄用的 `startup` 和 `shutdown` 事件,你可以這樣使用 TestClient:
+
+{* ../../docs_src/app_testing/tutorial003_py310.py hl[9:12,20:24] *}
diff --git a/docs/zh-hant/docs/advanced/testing-websockets.md b/docs/zh-hant/docs/advanced/testing-websockets.md
new file mode 100644
index 0000000000..7348e60fdf
--- /dev/null
+++ b/docs/zh-hant/docs/advanced/testing-websockets.md
@@ -0,0 +1,13 @@
+# 測試 WebSocket { #testing-websockets }
+
+你可以使用相同的 `TestClient` 來測試 WebSocket。
+
+為此,你可以在 `with` 陳述式中使用 `TestClient`,連線到該 WebSocket:
+
+{* ../../docs_src/app_testing/tutorial002_py310.py hl[27:31] *}
+
+/// note | 注意
+
+想了解更多,請參考 Starlette 的
測試 WebSocket 文件。
+
+///
diff --git a/docs/zh-hant/docs/advanced/using-request-directly.md b/docs/zh-hant/docs/advanced/using-request-directly.md
new file mode 100644
index 0000000000..f1dae9bf29
--- /dev/null
+++ b/docs/zh-hant/docs/advanced/using-request-directly.md
@@ -0,0 +1,56 @@
+# 直接使用 Request { #using-the-request-directly }
+
+到目前為止,你都是用對應的型別來宣告你需要的請求各部分。
+
+例如從以下來源取得資料:
+
+- 路徑中的參數。
+- 標頭。
+- Cookies。
+- 等等。
+
+這麼做時,FastAPI 會自動驗證並轉換這些資料,還會為你的 API 產生文件。
+
+但有些情況你可能需要直接存取 `Request` 物件。
+
+## 關於 `Request` 物件的細節 { #details-about-the-request-object }
+
+由於 FastAPI 底層其實是 Starlette,再加上一層工具,因此在需要時你可以直接使用 Starlette 的
`Request` 物件。
+
+同時也代表,如果你直接從 `Request` 物件取得資料(例如讀取 body),FastAPI 不會替它做驗證、轉換或文件化(透過 OpenAPI 為自動化的 API 介面產生文件)。
+
+不過,其他以一般方式宣告的參數(例如以 Pydantic 模型宣告的 body)仍然會被驗證、轉換、加上標註等。
+
+但在某些特定情境下,直接取得 `Request` 物件會很實用。
+
+## 直接使用 `Request` 物件 { #use-the-request-object-directly }
+
+假設你想在你的 路徑操作函式(path operation function) 中取得用戶端的 IP 位址/主機。
+
+為此,你需要直接存取請求。
+
+{* ../../docs_src/using_request_directly/tutorial001_py310.py hl[1,7:8] *}
+
+只要在 路徑操作函式 中宣告一個型別為 `Request` 的參數,FastAPI 就會將當前的 `Request` 傳入該參數。
+
+/// tip
+
+注意在這個例子中,除了 request 參數之外,我們也宣告了一個路徑參數。
+
+因此,路徑參數會被擷取、驗證、轉換為指定型別,並在 OpenAPI 中加入標註。
+
+同理,你可以照常宣告其他參數,並另外同時取得 `Request`。
+
+///
+
+## `Request` 文件 { #request-documentation }
+
+你可以在
Starlette 官方文件站點中的 `Request` 物件 了解更多細節。
+
+/// note | 技術細節
+
+你也可以使用 `from starlette.requests import Request`。
+
+FastAPI 之所以直接提供它,是為了讓開發者更方便;但它本身是來自 Starlette。
+
+///
diff --git a/docs/zh-hant/docs/advanced/websockets.md b/docs/zh-hant/docs/advanced/websockets.md
new file mode 100644
index 0000000000..c4e904f6f6
--- /dev/null
+++ b/docs/zh-hant/docs/advanced/websockets.md
@@ -0,0 +1,186 @@
+# WebSockets { #websockets }
+
+你可以在 **FastAPI** 中使用
WebSockets。
+
+## 安裝 `websockets` { #install-websockets }
+
+請先建立[虛擬環境](../virtual-environments.md){.internal-link target=_blank}、啟用它,然後安裝 `websockets`(一個讓你更容易使用「WebSocket」通訊協定的 Python 套件):
+
+
+
+```console
+$ pip install websockets
+
+---> 100%
+```
+
+
+
+## WebSockets 用戶端 { #websockets-client }
+
+### 在生產環境 { #in-production }
+
+在你的生產系統中,你很可能有一個使用現代框架(如 React、Vue.js 或 Angular)建立的前端。
+
+而為了透過 WebSockets 與後端通訊,你通常會使用前端的工具。
+
+或者你可能有一個原生行動應用,使用原生程式碼直接與 WebSocket 後端通訊。
+
+又或者你有其他任何方式與 WebSocket 端點通訊。
+
+---
+
+但在這個範例中,我們會用一個非常簡單的 HTML 文件與一些 JavaScript,全都寫在一個長字串裡。
+
+當然,這並不理想,你不會在生產環境這樣做。
+
+在生產環境你通常會用上述其中一種方式。
+
+但這是能讓我們專注於 WebSocket 伺服端並跑起一個可運作範例的最簡單方式:
+
+{* ../../docs_src/websockets/tutorial001_py310.py hl[2,6:38,41:43] *}
+
+## 建立一個 `websocket` { #create-a-websocket }
+
+在你的 **FastAPI** 應用中,建立一個 `websocket`:
+
+{* ../../docs_src/websockets/tutorial001_py310.py hl[1,46:47] *}
+
+/// note | 技術細節
+
+你也可以使用 `from starlette.websockets import WebSocket`。
+
+**FastAPI** 直接提供相同的 `WebSocket` 只是為了方便你這位開發者,但它其實是直接來自 Starlette。
+
+///
+
+## 等待與傳送訊息 { #await-for-messages-and-send-messages }
+
+在你的 WebSocket 路由中,你可以 `await` 接收訊息並傳送訊息。
+
+{* ../../docs_src/websockets/tutorial001_py310.py hl[48:52] *}
+
+你可以接收與傳送二進位、文字與 JSON 資料。
+
+## 試試看 { #try-it }
+
+如果你的檔案名為 `main.py`,用以下指令執行應用:
+
+
+
+```console
+$ fastapi dev main.py
+
+INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
+```
+
+
+
+在瀏覽器開啟
http://127.0.0.1:8000。
+
+你會看到一個像這樣的簡單頁面:
+
+

+
+你可以在輸入框輸入訊息並送出:
+
+

+
+你的 **FastAPI** 應用會透過 WebSockets 回應:
+
+

+
+你可以傳送(與接收)多則訊息:
+
+

+
+而且它們都會使用同一個 WebSocket 連線。
+
+## 使用 `Depends` 與其他功能 { #using-depends-and-others }
+
+在 WebSocket 端點中,你可以從 `fastapi` 匯入並使用:
+
+* `Depends`
+* `Security`
+* `Cookie`
+* `Header`
+* `Path`
+* `Query`
+
+它們的運作方式與其他 FastAPI 端點/*路徑操作* 相同:
+
+{* ../../docs_src/websockets/tutorial002_an_py310.py hl[68:69,82] *}
+
+/// info
+
+因為這是 WebSocket,拋出 `HTTPException` 並沒有意義,因此我們改為拋出 `WebSocketException`。
+
+你可以使用規範中定義的
有效關閉代碼之一。
+
+///
+
+### 用依賴試用 WebSocket { #try-the-websockets-with-dependencies }
+
+如果你的檔案名為 `main.py`,用以下指令執行應用:
+
+
+
+```console
+$ fastapi dev main.py
+
+INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
+```
+
+
+
+在瀏覽器開啟
http://127.0.0.1:8000。
+
+在那裡你可以設定:
+
+* "Item ID",用於路徑。
+* "Token",作為查詢參數。
+
+/// tip
+
+注意查詢參數 `token` 會由一個依賴處理。
+
+///
+
+之後你就能連線到 WebSocket,並開始收發訊息:
+
+

+
+## 處理斷線與多個用戶端 { #handling-disconnections-and-multiple-clients }
+
+當 WebSocket 連線關閉時,`await websocket.receive_text()` 會拋出 `WebSocketDisconnect` 例外,你可以像範例中那樣捕捉並處理。
+
+{* ../../docs_src/websockets/tutorial003_py310.py hl[79:81] *}
+
+試用方式:
+
+* 用多個瀏覽器分頁開啟該應用。
+* 從每個分頁傳送訊息。
+* 然後關閉其中一個分頁。
+
+這會引發 `WebSocketDisconnect` 例外,其他所有用戶端都會收到類似以下的訊息:
+
+```
+Client #1596980209979 left the chat
+```
+
+/// tip
+
+上面的應用是一個極簡範例,用來示範如何處理並向多個 WebSocket 連線廣播訊息。
+
+但請注意,因為所有狀態都在記憶體中的單一 list 裡管理,它只會在該程序執行期間生效,且僅適用於單一程序。
+
+如果你需要一個容易與 FastAPI 整合、但更健壯,且可由 Redis、PostgreSQL 等後端支援的方案,請參考
encode/broadcaster。
+
+///
+
+## 更多資訊 { #more-info }
+
+想了解更多選項,請參考 Starlette 的文件:
+
+*
`WebSocket` 類別。
+*
以類別為基礎的 WebSocket 處理。
diff --git a/docs/zh-hant/docs/advanced/wsgi.md b/docs/zh-hant/docs/advanced/wsgi.md
new file mode 100644
index 0000000000..9d03b56924
--- /dev/null
+++ b/docs/zh-hant/docs/advanced/wsgi.md
@@ -0,0 +1,51 @@
+# 包含 WSGI:Flask、Django 等 { #including-wsgi-flask-django-others }
+
+你可以像在 [子應用程式 - 掛載](sub-applications.md){.internal-link target=_blank}、[在 Proxy 後方](behind-a-proxy.md){.internal-link target=_blank} 中所見那樣掛載 WSGI 應用。
+
+為此,你可以使用 `WSGIMiddleware` 來包住你的 WSGI 應用,例如 Flask、Django 等。
+
+## 使用 `WSGIMiddleware` { #using-wsgimiddleware }
+
+/// info
+
+這需要先安裝 `a2wsgi`,例如使用 `pip install a2wsgi`。
+
+///
+
+你需要從 `a2wsgi` 匯入 `WSGIMiddleware`。
+
+然後用該 middleware 包住 WSGI(例如 Flask)應用。
+
+接著把它掛載到某個路徑下。
+
+{* ../../docs_src/wsgi/tutorial001_py310.py hl[1,3,23] *}
+
+/// note
+
+先前建議使用來自 `fastapi.middleware.wsgi` 的 `WSGIMiddleware`,但現在已棄用。
+
+建議改用 `a2wsgi` 套件。用法保持相同。
+
+只要確保已安裝 `a2wsgi`,並從 `a2wsgi` 正確匯入 `WSGIMiddleware` 即可。
+
+///
+
+## 試試看 { #check-it }
+
+現在,位於路徑 `/v1/` 底下的所有請求都會由 Flask 應用處理。
+
+其餘則由 **FastAPI** 處理。
+
+如果你啟動它並前往
http://localhost:8000/v1/,你會看到來自 Flask 的回應:
+
+```txt
+Hello, World from Flask!
+```
+
+如果你前往
http://localhost:8000/v2,你會看到來自 FastAPI 的回應:
+
+```JSON
+{
+ "message": "Hello World"
+}
+```
diff --git a/docs/zh-hant/docs/alternatives.md b/docs/zh-hant/docs/alternatives.md
new file mode 100644
index 0000000000..340c47d8ba
--- /dev/null
+++ b/docs/zh-hant/docs/alternatives.md
@@ -0,0 +1,485 @@
+# 替代方案、靈感與比較 { #alternatives-inspiration-and-comparisons }
+
+啟發 FastAPI 的來源、與其他方案的比較,以及從中學到的內容。
+
+## 介紹 { #intro }
+
+沒有前人的工作,就不會有 **FastAPI**。
+
+在它誕生之前,已經有許多工具啟發了它的設計。
+
+我多年來一直避免打造新框架。起初我嘗試用許多不同的框架、外掛與工具,來實作 **FastAPI** 涵蓋的所有功能。
+
+但在某個時間點,除了創建一個能提供所有這些功能、汲取前人工具的優點,並以最佳方式組合起來、同時運用過去甚至不存在的語言特性(Python 3.6+ 的型別提示)之外,已別無他法。
+
+## 先前的工具 { #previous-tools }
+
+###
Django { #django }
+
+它是最受歡迎且廣受信任的 Python 框架。像 Instagram 等系統就是用它打造的。
+
+它與關聯式資料庫(如 MySQL 或 PostgreSQL)相對緊密耦合,因此要以 NoSQL 資料庫(如 Couchbase、MongoDB、Cassandra 等)作為主要儲存引擎並不容易。
+
+它一開始是為在後端產生 HTML 而設計,而非為了建立提供現代前端(如 React、Vue.js、Angular)或其他系統(如
IoT 裝置)使用的 API。
+
+###
Django REST Framework { #django-rest-framework }
+
+Django REST framework 的目標是成為一套在 Django 之上構建 Web API 的彈性工具組,以強化其 API 能力。
+
+它被 Mozilla、Red Hat、Eventbrite 等眾多公司使用。
+
+它是「自動 API 文件」的早期典範之一,而這正是啟發我「尋找」**FastAPI** 的第一個想法。
+
+/// note | 注意
+
+Django REST Framework 由 Tom Christie 創建。他同時也是 Starlette 與 Uvicorn 的作者,而 **FastAPI** 就是建立在它們之上。
+
+///
+
+/// check | 啟發 **FastAPI**
+
+提供自動化的 API 文件網頁使用者介面。
+
+///
+
+###
Flask { #flask }
+
+Flask 是一個「微框架」,它不包含資料庫整合,也沒有像 Django 那樣內建許多功能。
+
+這種簡單與彈性,讓你可以把 NoSQL 資料庫作為主要的資料儲存系統。
+
+由於它非常簡單,學起來相對直觀,儘管文件在某些地方會變得較技術性。
+
+它也常用於其他不一定需要資料庫、使用者管理或 Django 內建眾多功能的應用程式。雖然這些功能中的許多都可以用外掛新增。
+
+這種元件的解耦,以及作為可擴充以精準滿足需求的「微框架」,是我想要保留的關鍵特性。
+
+基於 Flask 的簡潔,它看起來很適合用來構建 API。接下來要找的,就是 Flask 世界裡的「Django REST Framework」。
+
+/// check | 啟發 **FastAPI**
+
+成為一個微框架,讓所需的工具與元件能輕鬆搭配組合。
+
+具備簡單、易用的路由系統。
+
+///
+
+###
Requests { #requests }
+
+**FastAPI** 其實不是 **Requests** 的替代品。兩者的範疇截然不同。
+
+在 FastAPI 應用程式「內部」使用 Requests 其實很常見。
+
+儘管如此,FastAPI 仍從 Requests 得到了不少啟發。
+
+**Requests** 是一個「與 API 互動」(作為用戶端)的程式庫,而 **FastAPI** 是一個「建立 API」(作為伺服端)的程式庫。
+
+它們大致位於相反兩端,彼此互補。
+
+Requests 設計非常簡單直觀、容易使用,且有合理的預設值。同時它也非常強大且可自訂。
+
+因此,如其官網所言:
+
+> Requests is one of the most downloaded Python packages of all time
+
+用法非常簡單。例如,發出一個 `GET` 請求,你會寫:
+
+```Python
+response = requests.get("http://example.com/some/url")
+```
+
+相對地,FastAPI 的 API 路徑操作(path operation)可能像這樣:
+
+```Python hl_lines="1"
+@app.get("/some/url")
+def read_url():
+ return {"message": "Hello World"}
+```
+
+看看 `requests.get(...)` 與 `@app.get(...)` 的相似之處。
+
+/// check | 啟發 **FastAPI**
+
+* 擁有簡單直觀的 API。
+* 直接使用 HTTP 方法名稱(操作),以直接、直觀的方式表達。
+* 具備合理的預設值,同時提供強大的自訂能力。
+
+///
+
+###
Swagger /
OpenAPI { #swagger-openapi }
+
+我想從 Django REST Framework 得到的主要功能是自動 API 文件。
+
+後來我發現有一個使用 JSON(或 YAML,JSON 的延伸)來描述 API 的標準,叫做 Swagger。
+
+而且已有對 Swagger API 的網頁使用者介面。因此,只要能為 API 產生 Swagger 文件,就可以自動使用這個網頁介面。
+
+之後 Swagger 交由 Linux 基金會管理,並更名為 OpenAPI。
+
+因此,談到 2.0 版時常說「Swagger」,而 3+ 版則是「OpenAPI」。
+
+/// check | 啟發 **FastAPI**
+
+採用並使用開放的 API 規格標準,而非自訂格式。
+
+並整合基於標準的使用者介面工具:
+
+*
Swagger UI
+*
ReDoc
+
+選擇這兩個是因為它們相當受歡迎且穩定,但稍加搜尋,你會發現有數十種 OpenAPI 的替代使用者介面(都能與 **FastAPI** 一起使用)。
+
+///
+
+### Flask 的 REST 框架 { #flask-rest-frameworks }
+
+有幾個 Flask 的 REST 框架,但在投入時間調查後,我發現許多已停止維護或被棄置,且存在一些關鍵問題使之不適用。
+
+###
Marshmallow { #marshmallow }
+
+API 系統需要的主要功能之一是資料「
序列化」,也就是把程式中的資料(Python)轉成能透過網路傳輸的形式。例如,將含有資料庫資料的物件轉成 JSON 物件、把 `datetime` 物件轉成字串等等。
+
+API 需要的另一個重要功能是資料驗證,確保資料在特定條件下有效。例如,某個欄位必須是 `int`,而不是隨便的字串。這對於輸入資料特別有用。
+
+沒有資料驗證系統的話,你就得在程式碼中手動逐一檢查。
+
+這些功能正是 Marshmallow 所要提供的。它是很棒的函式庫,我之前也大量使用。
+
+但它誕生於 Python 型別提示出現之前。因此,為了定義每個
結構(schema),你需要使用 Marshmallow 提供的特定工具與類別。
+
+/// check | 啟發 **FastAPI**
+
+用程式碼定義能自動提供資料型別與驗證的「schemas」。
+
+///
+
+###
Webargs { #webargs }
+
+API 所需的另一項大功能,是從傳入請求中
解析資料。
+
+Webargs 是在多個框架(包含 Flask)之上提供該功能的工具。
+
+它底層使用 Marshmallow 來做資料驗證,且由同一群開發者建立。
+
+它是一個很棒的工具,在有 **FastAPI** 之前我也經常使用。
+
+/// info
+
+Webargs 由與 Marshmallow 相同的開發者創建。
+
+///
+
+/// check | 啟發 **FastAPI**
+
+自動驗證傳入請求資料。
+
+///
+
+###
APISpec { #apispec }
+
+Marshmallow 與 Webargs 以外掛提供驗證、解析與序列化。
+
+但文件仍然缺失,於是 APISpec 出現了。
+
+它是多個框架的外掛(Starlette 也有對應外掛)。
+
+它的作法是:你在處理路由的每個函式的 docstring 中,用 YAML 格式撰寫結構定義。
+
+然後它會產生 OpenAPI schemas。
+
+在 Flask、Starlette、Responder 等框架中都是這樣運作。
+
+但這又帶來一個問題:在 Python 字串中(大型 YAML)加入一段微語法。
+
+編輯器幫不上太多忙。而且如果我們修改了參數或 Marshmallow 的 schemas 卻忘了同步修改 YAML docstring,產生的結構就會過時。
+
+/// info
+
+APISpec 由與 Marshmallow 相同的開發者創建。
+
+///
+
+/// check | 啟發 **FastAPI**
+
+支援 API 的開放標準 OpenAPI。
+
+///
+
+###
Flask-apispec { #flask-apispec }
+
+這是一個 Flask 外掛,把 Webargs、Marshmallow 與 APISpec 串在一起。
+
+它使用 Webargs 與 Marshmallow 的資訊,透過 APISpec 自動產生 OpenAPI 結構。
+
+它是個很棒但被低估的工具。它理應比許多 Flask 外掛更受歡迎,可能因為它的文件過於簡潔與抽象。
+
+這解決了在 Python 文件字串中撰寫 YAML(另一種語法)的问题。
+
+在打造 **FastAPI** 前,我最喜歡的後端技術組合就是 Flask、Flask-apispec、Marshmallow 與 Webargs。
+
+使用它促成了數個 Flask 全端(full-stack)產生器。這些是我(以及若干外部團隊)至今主要使用的技術組合:
+
+*
https://github.com/tiangolo/full-stack
+*
https://github.com/tiangolo/full-stack-flask-couchbase
+*
https://github.com/tiangolo/full-stack-flask-couchdb
+
+而這些全端產生器,也成為了 [**FastAPI** 專案產生器](project-generation.md){.internal-link target=_blank} 的基礎。
+
+/// info
+
+Flask-apispec 由與 Marshmallow 相同的開發者創建。
+
+///
+
+/// check | 啟發 **FastAPI**
+
+從定義序列化與驗證的相同程式碼,自動產生 OpenAPI 結構(schema)。
+
+///
+
+###
NestJS(與
Angular) { #nestjs-and-angular }
+
+這甚至不是 Python。NestJS 是受 Angular 啟發的 JavaScript(TypeScript)NodeJS 框架。
+
+它達成的效果與 Flask-apispec 能做的有點相似。
+
+它有一套受 Angular 2 啟發的整合式相依性注入(Dependency Injection)系統。需要預先註冊「可注入」元件(就像我所知的其他相依性注入系統一樣),因此會增加冗長與重複程式碼。
+
+由於參數以 TypeScript 型別描述(與 Python 型別提示相似),編輯器支援相當不錯。
+
+但因為 TypeScript 的型別在編譯成 JavaScript 後不會被保留,它無法僅靠型別同時定義驗證、序列化與文件。由於這點以及部分設計決定,若要取得驗證、序列化與自動結構產生,就需要在許多地方加上裝飾器,因此會相當冗長。
+
+它無法很好地處理巢狀模型。若請求的 JSON 主體中有內層欄位,且這些內層欄位又是巢狀 JSON 物件,就無法被妥善地文件化與驗證。
+
+/// check | 啟發 **FastAPI**
+
+使用 Python 型別以獲得優秀的編輯器支援。
+
+提供強大的相依性注入系統,並想辦法將重複程式碼降到最低。
+
+///
+
+###
Sanic { #sanic }
+
+它是最早基於 `asyncio` 的極高速 Python 框架之一,並做得很像 Flask。
+
+/// note | 技術細節
+
+它使用
`uvloop` 取代預設的 Python `asyncio` 事件圈。這也是它如此之快的原因。
+
+它明顯啟發了 Uvicorn 與 Starlette,而在公開的基準測試中,它們目前比 Sanic 更快。
+
+///
+
+/// check | 啟發 **FastAPI**
+
+想辦法達到瘋狂的效能。
+
+這就是為什麼 **FastAPI** 建立於 Starlette 之上,因為它是可用的最快框架(由第三方評測)。
+
+///
+
+###
Falcon { #falcon }
+
+Falcon 是另一個高效能 Python 框架,設計上極簡,並作為其他框架(如 Hug)的基礎。
+
+它設計為函式接收兩個參數,一個是「request」,一個是「response」。然後你從 request「讀取」資料、往 response「寫入」資料。由於這種設計,無法使用標準的 Python 型別提示,直接以函式參數宣告請求參數與主體。
+
+因此,資料驗證、序列化與文件必須以程式碼手動完成,無法自動化。或者需在 Falcon 之上實作另一層框架(如 Hug)。其他受 Falcon 設計啟發的框架也有同樣的區別:將 request 與 response 物件作為參數。
+
+/// check | 啟發 **FastAPI**
+
+設法取得優秀的效能。
+
+連同 Hug(Hug 建立於 Falcon 之上)一起,也啟發 **FastAPI** 在函式中宣告一個 `response` 參數。
+
+不過在 FastAPI 中它是可選的,主要用來設定標頭、Cookie 與替代狀態碼。
+
+///
+
+###
Molten { #molten }
+
+我在 **FastAPI** 打造的早期發現了 Molten。它有一些相當類似的想法:
+
+* 基於 Python 型別提示。
+* 從這些型別取得驗證與文件。
+* 相依性注入系統。
+
+它沒有使用像 Pydantic 這樣的第三方資料驗證、序列化與文件庫,而是有自己的。因此,這些資料型別定義較不容易重複使用。
+
+它需要更為冗長的設定。而且因為它基於 WSGI(而非 ASGI),並未設計來享受如 Uvicorn、Starlette、Sanic 等工具所提供的高效能。
+
+其相依性注入系統需要預先註冊依賴,並且依據宣告的型別來解析依賴。因此,無法宣告多個能提供相同型別的「元件」。
+
+路由需要在單一地方宣告,使用在其他地方宣告的函式(而不是用可以直接放在端點處理函式上方的裝飾器)。這更接近 Django 的作法,而不是 Flask(與 Starlette)的作法。它在程式碼中分離了其實相當緊密耦合的事物。
+
+/// check | 啟發 **FastAPI**
+
+用模型屬性的「預設值」來定義資料型別的額外驗證。這提升了編輯器支援,而這在當時的 Pydantic 還不支援。
+
+這實際上也啟發了 Pydantic 的部分更新,以支援相同的驗證宣告風格(這些功能現在已在 Pydantic 中可用)。
+
+///
+
+###
Hug { #hug }
+
+Hug 是最早使用 Python 型別提示來宣告 API 參數型別的框架之一。這是個很棒的點子,也啟發了其他工具。
+
+它在宣告中使用自訂型別而非標準 Python 型別,但仍然是巨大的一步。
+
+它也是最早能以 JSON 產出自訂結構、描述整個 API 的框架之一。
+
+它不是基於 OpenAPI 與 JSON Schema 等標準。因此,與其他工具(如 Swagger UI)的整合並不直覺。但它仍是一個非常創新的想法。
+
+它有個有趣、少見的功能:同一個框架可同時建立 API 與 CLI。
+
+由於它基於同步 Python 網頁框架的舊標準(WSGI),無法處理 WebSocket 與其他功能,儘管效能仍然很高。
+
+/// info
+
+Hug 由 Timothy Crosley 創建,他同時也是
`isort` 的作者,一個自動排序 Python 匯入的好工具。
+
+///
+
+/// check | 啟發 **FastAPI** 的想法
+
+Hug 啟發了 APIStar 的部分設計,也是我覺得最有前景的工具之一,與 APIStar 並列。
+
+Hug 啟發 **FastAPI** 使用 Python 型別提示宣告參數,並自動產生定義 API 的結構。
+
+Hug 啟發 **FastAPI** 在函式中宣告 `response` 參數以設定標頭與 Cookie。
+
+///
+
+###
APIStar (<= 0.5) { #apistar-0-5 }
+
+在決定打造 **FastAPI** 之前,我找到了 **APIStar** 伺服器。它幾乎具備我所尋找的一切,而且設計很出色。
+
+它是我見過最早使用 Python 型別提示來宣告參數與請求的框架實作之一(早於 NestJS 與 Molten)。我與 Hug 幾乎在同時間發現它。不過 APIStar 使用的是 OpenAPI 標準。
+
+它基於相同的型別提示,在多處自動進行資料驗證、資料序列化與 OpenAPI 結構產生。
+
+主體結構(body schema)的定義並未使用像 Pydantic 那樣的 Python 型別提示,更像 Marshmallow,因此編輯器支援沒有那麼好,但整體而言,APIStar 是當時最好的選擇。
+
+它在當時的效能評測中名列前茅(僅被 Starlette 超越)。
+
+一開始它沒有自動 API 文件的網頁 UI,但我知道我可以替它加上 Swagger UI。
+
+它有相依性注入系統。需要預先註冊元件,與上面提到的其他工具相同。不過這仍是很棒的功能。
+
+我從未能在完整專案中使用它,因為它沒有安全性整合,所以無法取代我用 Flask-apispec 全端產生器所擁有的全部功能。我曾把新增該功能的 pull request 放在待辦清單中。
+
+但之後,專案的重心改變了。
+
+它不再是 API 網頁框架,因為作者需要專注於 Starlette。
+
+現在的 APIStar 是一套用於驗證 OpenAPI 規格的工具,不是網頁框架。
+
+/// info
+
+APIStar 由 Tom Christie 創建。他也創建了:
+
+* Django REST Framework
+* Starlette(**FastAPI** 建立於其上)
+* Uvicorn(Starlette 與 **FastAPI** 使用)
+
+///
+
+/// check | 啟發 **FastAPI**
+
+存在。
+
+用相同的 Python 型別同時宣告多件事(資料驗證、序列化與文件),並同時提供出色的編輯器支援,這是一個極好的點子。
+
+在長時間尋找並測試多種不同替代方案後,APIStar 是最好的可用選擇。
+
+當 APIStar 不再作為伺服器存在,而 Starlette 誕生並成為更好的基礎時,這成為打造 **FastAPI** 的最後一個靈感。
+
+我將 **FastAPI** 視為 APIStar 的「精神繼承者」,同時基於所有這些先前工具的經驗,改進並擴增了功能、型別系統與其他部分。
+
+///
+
+## **FastAPI** 所採用的工具 { #used-by-fastapi }
+
+###
Pydantic { #pydantic }
+
+Pydantic 是基於 Python 型別提示,定義資料驗證、序列化與文件(使用 JSON Schema)的函式庫。
+
+這讓它非常直覺。
+
+它可與 Marshmallow 相提並論。儘管在效能測試中它比 Marshmallow 更快。而且因為它基於相同的 Python 型別提示,編輯器支援也很出色。
+
+/// check | **FastAPI** 用於
+
+處理所有資料驗證、資料序列化與自動模型文件(基於 JSON Schema)。
+
+**FastAPI** 接著會把這些 JSON Schema 資料放入 OpenAPI 中,此外還有其他許多功能。
+
+///
+
+###
Starlette { #starlette }
+
+Starlette 是一個輕量的
ASGI 框架/工具集,非常適合用來建構高效能的 asyncio 服務。
+
+它非常簡單直觀。設計上易於擴充,且元件化。
+
+它具備:
+
+* 令人印象深刻的效能。
+* WebSocket 支援。
+* 行程內(in-process)背景任務。
+* 啟動與關閉事件。
+* 建立在 HTTPX 上的測試用戶端。
+* CORS、GZip、靜態檔案、串流回應。
+* Session 與 Cookie 支援。
+* 100% 測試涵蓋率。
+* 100% 型別註解的程式碼庫。
+* 幾乎沒有硬性相依。
+
+Starlette 目前是測試中最快的 Python 框架。僅次於 Uvicorn(它不是框架,而是伺服器)。
+
+Starlette 提供所有網頁微框架的基礎功能。
+
+但它不提供自動的資料驗證、序列化或文件。
+
+這正是 **FastAPI** 在其上方加入的主要功能之一,且全部基於 Python 型別提示(使用 Pydantic)。此外還有相依性注入系統、安全性工具、OpenAPI 結構產生等。
+
+/// note | 技術細節
+
+ASGI 是由 Django 核心團隊成員正在開發的新「標準」。它尚未成為「Python 標準」(PEP),但他們正著手進行中。
+
+儘管如此,它已被多個工具作為「標準」採用。這大幅提升了互通性,例如你可以把 Uvicorn 換成其他 ASGI 伺服器(如 Daphne 或 Hypercorn),或加入相容 ASGI 的工具,如 `python-socketio`。
+
+///
+
+/// check | **FastAPI** 用於
+
+處理所有核心網頁部分,並在其上加上功能。
+
+`FastAPI` 這個類別本身直接繼承自 `Starlette` 類別。
+
+因此,凡是你能用 Starlette 做的事,你幾乎都能直接用 **FastAPI** 完成,因為它基本上就是加強版的 Starlette。
+
+///
+
+###
Uvicorn { #uvicorn }
+
+Uvicorn 是基於 uvloop 與 httptools 的極速 ASGI 伺服器。
+
+它不是網頁框架,而是伺服器。例如,它不提供依據路徑路由的工具。這是像 Starlette(或 **FastAPI**)這樣的框架在其上方提供的功能。
+
+它是 Starlette 與 **FastAPI** 推薦使用的伺服器。
+
+/// check | **FastAPI** 建議用作
+
+執行 **FastAPI** 應用的主要網頁伺服器。
+
+你也可以使用 `--workers` 命令列選項,取得非同步的多製程伺服器。
+
+更多細節請見[部署](deployment/index.md){.internal-link target=_blank}章節。
+
+///
+
+## 效能與速度 { #benchmarks-and-speed }
+
+想了解、比較並看出 Uvicorn、Starlette 與 FastAPI 之間的差異,請參考[效能評測](benchmarks.md){.internal-link target=_blank}。
diff --git a/docs/zh-hant/docs/async.md b/docs/zh-hant/docs/async.md
index 09e2bf9949..a03d71815f 100644
--- a/docs/zh-hant/docs/async.md
+++ b/docs/zh-hant/docs/async.md
@@ -1,10 +1,10 @@
-# 並行與 async / await
+# 並行與 async / await { #concurrency-and-async-await }
有關*路徑操作函式*的 `async def` 語法的細節與非同步 (asynchronous) 程式碼、並行 (concurrency) 與平行 (parallelism) 的一些背景知識。
-## 趕時間嗎?
+## 趕時間嗎? { #in-a-hurry }
-
TL;DR:
+
TL;DR:
如果你正在使用要求你以 `await` 語法呼叫的第三方函式庫,例如:
@@ -41,7 +41,7 @@ def results():
---
-如果你的應用程式不需要與外部資源進行任何通訊並等待其回應,請使用 `async def`。
+如果你的應用程式不需要與外部資源進行任何通訊並等待其回應,請使用 `async def`,即使內部不需要使用 `await` 也可以。
---
@@ -55,7 +55,7 @@ def results():
但透過遵循上述步驟,它將能進行一些效能最佳化。
-## 技術細節
+## 技術細節 { #technical-details }
現代版本的 Python 支援使用 **「協程」** 的 **`async` 和 `await`** 語法來寫 **「非同步程式碼」**。
@@ -65,7 +65,7 @@ def results():
* **`async` 和 `await`**
* **協程**
-## 非同步程式碼
+## 非同步程式碼 { #asynchronous-code }
非同步程式碼僅意味著程式語言 💬 有辦法告訴電腦/程式 🤖 在程式碼中的某個點,它 🤖 需要等待某些事情完成。讓我們假設這些事情被稱為「慢速檔案」📝。
@@ -74,7 +74,7 @@ def results():
接著程式 🤖 會在有空檔時回來查看是否有等待的工作已經完成,並執行必要的後續操作。
接下來,它 🤖 完成第一個工作(例如我們的「慢速檔案」📝)並繼續執行相關的所有操作。
-這個「等待其他事情」通常指的是一些相對較慢的(與處理器和 RAM 記憶體的速度相比)的
I/O 操作,比如說:
+這個「等待其他事情」通常指的是一些相對較慢的(與處理器和 RAM 記憶體的速度相比)的
I/O 操作,比如說:
* 透過網路傳送來自用戶端的資料
* 從網路接收來自用戶端的資料
@@ -85,7 +85,7 @@ def results():
* 資料庫查詢
* 等等
-由於大部分的執行時間都消耗在等待
I/O 操作上,因此這些操作被稱為 "I/O 密集型" 操作。
+由於大部分的執行時間都消耗在等待
I/O 操作上,因此這些操作被稱為 "I/O 密集型" 操作。
之所以稱為「非同步」,是因為電腦/程式不需要與那些耗時的任務「同步」,等待任務完成的精確時間,然後才能取得結果並繼續工作。
@@ -93,7 +93,7 @@ def results():
相對於「非同步」(asynchronous),「同步」(synchronous)也常被稱作「順序性」(sequential),因為電腦/程式會依序執行所有步驟,即便這些步驟涉及等待,才會切換到其他任務。
-### 並行與漢堡
+### 並行與漢堡 { #concurrency-and-burgers }
上述非同步程式碼的概念有時也被稱為「並行」,它不同於「平行」。
@@ -103,7 +103,7 @@ def results():
為了理解差異,請想像以下有關漢堡的故事:
-### 並行漢堡
+### 並行漢堡 { #concurrent-burgers }
你和你的戀人去速食店,排隊等候時,收銀員正在幫排在你前面的人點餐。😍
@@ -163,7 +163,7 @@ def results():
然後你走向櫃檯 🔀,回到已經完成的最初任務 ⏯,拿起漢堡,說聲謝謝,並帶回桌上。這就結束了與櫃檯的互動步驟/任務 ⏹,接下來會產生一個新的任務,「吃漢堡」 🔀 ⏯,而先前的「拿漢堡」任務已經完成了 ⏹。
-### 平行漢堡
+### 平行漢堡 { #parallel-burgers }
現在,讓我們來想像這裡不是「並行漢堡」,而是「平行漢堡」。
@@ -233,7 +233,7 @@ def results():
所以,你不會想帶你的戀人 😍 一起去銀行辦事 🏦。
-### 漢堡結論
+### 漢堡結論 { #burger-conclusion }
在「和戀人一起吃速食漢堡」的這個場景中,由於有大量的等待 🕙,使用並行系統 ⏸🔀⏯ 更有意義。
@@ -253,7 +253,7 @@ def results():
你可以同時利用並行性和平行性,進一步提升效能,這比大多數已測試的 NodeJS 框架都更快,並且與 Go 語言相當,而 Go 是一種更接近 C 的編譯語言(
感謝 Starlette)。
-### 並行比平行更好嗎?
+### 並行比平行更好嗎? { #is-concurrency-better-than-parallelism }
不是的!這不是故事的本意。
@@ -277,7 +277,7 @@ def results():
在這個場景中,每個清潔工(包括你)都是一個處理器,完成工作的一部分。
-由於大多數的執行時間都花在實際的工作上(而不是等待),而電腦中的工作由
CPU 完成,因此這些問題被稱為「CPU 密集型」。
+由於大多數的執行時間都花在實際的工作上(而不是等待),而電腦中的工作由
CPU 完成,因此這些問題被稱為「CPU 密集型」。
---
@@ -290,7 +290,7 @@ def results():
* **機器學習**: 通常需要大量的「矩陣」和「向量」運算。想像一個包含數字的巨大電子表格,並所有的數字同時相乘;
* **深度學習**: 這是機器學習的子領域,同樣適用。只不過這不僅僅是一張數字表格,而是大量的數據集合,並且在很多情況下,你會使用特殊的處理器來構建或使用這些模型。
-### 並行 + 平行: Web + 機器學習
+### 並行 + 平行: Web + 機器學習 { #concurrency-parallelism-web-machine-learning }
使用 **FastAPI**,你可以利用並行的優勢,這在 Web 開發中非常常見(這也是 NodeJS 的最大吸引力)。
@@ -300,9 +300,9 @@ def results():
想了解如何在生產環境中實現這種平行性,請參見 [部屬](deployment/index.md){.internal-link target=_blank}。
-## `async` 和 `await`
+## `async` 和 `await` { #async-and-await }
-現代 Python 版本提供一種非常直觀的方式定義非同步程式碼。這使得它看起來就像正常的「順序」程式碼,並在適當的時機「等待」。
+現代 Python 版本提供一種非常直觀的方式定義非同步程式碼。這使得它看起來就像正常的「順序」程式碼,並在適當的時機替你「等待」。
當某個操作需要等待才能回傳結果,並且支援這些新的 Python 特性時,你可以像這樣編寫程式碼:
@@ -329,7 +329,7 @@ def get_sequential_burgers(number: int):
return burgers
```
-使用 `async def`,Python Python 知道在該函式內需要注意 `await`,並且它可以「暫停」 ⏸ 執行該函式,然後執行其他任務 🔀 後回來。
+使用 `async def`,Python 知道在該函式內需要注意 `await`,並且它可以「暫停」 ⏸ 執行該函式,然後執行其他任務 🔀 後回來。
當你想要呼叫 `async def` 函式時,必須使用「await」。因此,這樣寫將無法運行:
@@ -349,11 +349,11 @@ async def read_burgers():
return burgers
```
-### 更多技術細節
+### 更多技術細節 { #more-technical-details }
你可能已經注意到,`await` 只能在 `async def` 定義的函式內使用。
-但同時,使用 `async def` 定義的函式本身也必須被「等待」。所以,帶有 `async def` 函式只能在其他使用 `async def` 定義的函式內呼叫。
+但同時,使用 `async def` 定義的函式本身也必須被「等待」。所以,帶有 `async def` 的函式只能在其他使用 `async def` 定義的函式內呼叫。
那麼,這就像「先有雞還是先有蛋」的問題,要如何呼叫第一個 `async` 函式呢?
@@ -361,35 +361,37 @@ async def read_burgers():
但如果你想在沒有 FastAPI 的情況下使用 `async` / `await`,你也可以這樣做。
-### 編寫自己的非同步程式碼
+### 編寫自己的非同步程式碼 { #write-your-own-async-code }
-Starlette (和 **FastAPI**) 是基於
AnyIO 實作的,這使得它們與 Python 標準函式庫相容
asyncio 和
Trio。
+Starlette(和 **FastAPI**)是基於
AnyIO 實作的,這使得它們與 Python 標準函式庫
asyncio 和
Trio 相容。
特別是,你可以直接使用
AnyIO 來處理更複雜的並行使用案例,這些案例需要你在自己的程式碼中使用更高階的模式。
-即使你不使用 **FastAPI**,你也可以使用
AnyIO 來撰寫自己的非同步應用程式,並獲得高相容性及一些好處(例如結構化並行)。
+即使你不使用 **FastAPI**,你也可以使用
AnyIO 來撰寫自己的非同步應用程式,並獲得高相容性及一些好處(例如「結構化並行」)。
-### 其他形式的非同步程式碼
+我另外在 AnyIO 之上做了一個薄封裝的函式庫,稍微改進型別註解以獲得更好的**自動補全**、**即時錯誤**等。同時它也提供友善的介紹與教學,幫助你**理解**並撰寫**自己的非同步程式碼**:
Asyncer。當你需要**將非同步程式碼與一般**(阻塞/同步)**程式碼整合**時,它特別實用。
+
+### 其他形式的非同步程式碼 { #other-forms-of-asynchronous-code }
使用 `async` 和 `await` 的風格在語言中相對較新。
-但它使處理異步程式碼變得更加容易。
+但它使處理非同步程式碼變得更加容易。
相同的語法(或幾乎相同的語法)最近也被包含在現代 JavaScript(無論是瀏覽器還是 NodeJS)中。
-但在此之前,處理異步程式碼要更加複雜和困難。
+但在此之前,處理非同步程式碼要更加複雜和困難。
在較舊的 Python 版本中,你可能會使用多執行緒或
Gevent。但這些程式碼要更難以理解、調試和思考。
在較舊的 NodeJS / 瀏覽器 JavaScript 中,你會使用「回呼」,這可能會導致“回呼地獄”。
-## 協程
+## 協程 { #coroutines }
-**協程** 只是 `async def` 函式所回傳的非常特殊的事物名稱。Python 知道它是一個類似函式的東西,可以啟動它,並且在某個時刻它會結束,但它也可能在內部暫停 ⏸,只要遇到 `await`。
+「協程」只是 `async def` 函式所回傳的非常特殊的事物名稱。Python 知道它是一個類似函式的東西,可以啟動它,並且在某個時刻它會結束,但它也可能在內部暫停 ⏸,只要遇到 `await`。
這種使用 `async` 和 `await` 的非同步程式碼功能通常被概括為「協程」。這與 Go 語言的主要特性「Goroutines」相似。
-## 結論
+## 結論 { #conclusion }
讓我們再次回顧之前的句子:
@@ -397,9 +399,9 @@ Starlette (和 **FastAPI**) 是基於
I/O 的程式碼。
+如果你來自於其他不以這種方式運作的非同步框架,而且你習慣於使用普通的 `def` 定義僅進行簡單計算的*路徑操作函式*,目的是獲得微小的性能增益(大約 100 奈秒),請注意,在 FastAPI 中,效果會完全相反。在這些情況下,最好使用 `async def`,除非你的*路徑操作函式*執行阻塞的 I/O 的程式碼。
-不過,在這兩種情況下,**FastAPI** [仍然很快](index.md#_11){.internal-link target=_blank}至少與你之前的框架相當(或者更快)。
+不過,在這兩種情況下,**FastAPI** [仍然很快](index.md#performance){.internal-link target=_blank},至少與你之前的框架相當(或者更快)。
-### 依賴項(Dependencies)
+### 依賴項(Dependencies) { #dependencies }
同樣適用於[依賴項](tutorial/dependencies/index.md){.internal-link target=_blank}。如果依賴項是一個標準的 `def` 函式,而不是 `async def`,那麼它在外部的執行緒池被運行。
-### 子依賴項
+### 子依賴項 { #sub-dependencies }
-你可以擁有多個相互依賴的依賴項和[子依賴項](tutorial/dependencies/sub-dependencies.md){.internal-link target=_blank} (作為函式定義的參數),其中一些可能是用 `async def` 宣告,也可能是用 `def` 宣告。它們仍然可以正常運作,用 `def` 定義的那些將會在外部的執行緒中呼叫(來自執行緒池),而不是被「等待」。
+你可以擁有多個相互依賴的依賴項和[子依賴項](tutorial/dependencies/sub-dependencies.md){.internal-link target=_blank}(作為函式定義的參數),其中一些可能是用 `async def` 宣告,也可能是用 `def` 宣告。它們仍然可以正常運作,用 `def` 定義的那些將會在外部的執行緒中呼叫(來自執行緒池),而不是被「等待」。
-### 其他輔助函式
+### 其他輔助函式 { #other-utility-functions }
你可以直接呼叫任何使用 `def` 或 `async def` 建立的其他輔助函式,FastAPI 不會影響你呼叫它們的方式。
@@ -439,4 +441,4 @@ Starlette (和 **FastAPI**) 是基於 趕時間嗎?.
+否則,只需遵循上面提到的指引即可:
趕時間嗎?。
diff --git a/docs/zh-hant/docs/benchmarks.md b/docs/zh-hant/docs/benchmarks.md
index df49621c53..c5b76700b3 100644
--- a/docs/zh-hant/docs/benchmarks.md
+++ b/docs/zh-hant/docs/benchmarks.md
@@ -6,7 +6,7 @@
## 基準測試和速度 { #benchmarks-and-speed }
-當你查看基準測試時,時常會見到幾個不同類型的工具被同時進行測試。
+當你查看基準測試時,常見到不同類型的多個工具被視為等同來比較。
具體來說,是將 Uvicorn、Starlette 和 FastAPI 同時進行比較(以及許多其他工具)。
@@ -20,7 +20,7 @@
* **Uvicorn**:
* 具有最佳效能,因為除了伺服器本身之外,它沒有太多額外的程式碼。
- * 你不會直接在 Uvicorn 中編寫應用程式。這意味著你的程式碼必須或多或少地包含 Starlette(或 **FastAPI**)提供的所有程式碼。如果你這樣做,你的最終應用程式將具有與使用框架相同的開銷並最大限度地減少應用程式程式碼和錯誤。
+ * 你不會直接在 Uvicorn 中編寫應用程式。這意味著你的程式碼必須或多或少地包含 Starlette(或 **FastAPI**)提供的所有程式碼。如果你這樣做,你的最終應用程式將具有與使用框架相同的開銷,且無法像使用框架那樣減少應用程式程式碼與錯誤。
* 如果你要比較 Uvicorn,請將其與 Daphne、Hypercorn、uWSGI 等應用程式伺服器進行比較。
* **Starlette**:
* 繼 Uvicorn 之後的次佳表現。事實上,Starlette 使用 Uvicorn 來運行。因此它將可能只透過執行更多程式碼而變得比 Uvicorn「慢」。
diff --git a/docs/zh-hant/docs/deployment/concepts.md b/docs/zh-hant/docs/deployment/concepts.md
new file mode 100644
index 0000000000..0cca31d260
--- /dev/null
+++ b/docs/zh-hant/docs/deployment/concepts.md
@@ -0,0 +1,321 @@
+# 部署概念 { #deployments-concepts }
+
+當你要部署一個 FastAPI 應用,或其實任何類型的 Web API 時,有幾個你可能在意的概念。掌握這些概念後,你就能找出最適合部署你應用的方式。
+
+一些重要的概念包括:
+
+- 安全性 - HTTPS
+- 開機自動執行
+- 重新啟動
+- 複本(執行中的行程數量)
+- 記憶體
+- 啟動前的前置步驟
+
+我們將看看它們如何影響部署。
+
+最終目標是能夠以安全、避免中斷,並盡可能高效使用運算資源(例如遠端伺服器/虛擬機)的方式來服務你的 API 用戶端。🚀
+
+我會在這裡多介紹一些這些觀念,希望能幫你建立必要的直覺,讓你能在非常不同、甚至尚未出現的未來環境中決定要如何部署你的 API。
+
+在思考這些概念之後,你將能夠評估與設計最適合部署你自己 API 的方式。
+
+在接下來的章節,我會提供更具體的部署 FastAPI 應用的食譜。
+
+但現在,先來看看這些重要的概念想法。這些概念同樣適用於任何其他類型的 Web API。💡
+
+## 安全性 - HTTPS { #security-https }
+
+在[前一章關於 HTTPS](https.md){.internal-link target=_blank} 中,我們學到 HTTPS 如何為你的 API 提供加密。
+
+我們也看到,HTTPS 通常由應用伺服器外部的元件提供,即 TLS Termination Proxy。
+
+而且必須有某個東西負責續期 HTTPS 憑證,可能是同一個元件,也可能是不同的東西。
+
+### HTTPS 工具範例 { #example-tools-for-https }
+
+你可以用來作為 TLS Termination Proxy 的工具包括:
+
+- Traefik
+ - 自動處理憑證續期 ✨
+- Caddy
+ - 自動處理憑證續期 ✨
+- Nginx
+ - 搭配像 Certbot 這類外部元件進行憑證續期
+- HAProxy
+ - 搭配像 Certbot 這類外部元件進行憑證續期
+- Kubernetes,使用如 Nginx 的 Ingress Controller
+ - 搭配像 cert-manager 這類外部元件進行憑證續期
+- 由雲端供應商在其服務內部處理(見下文 👇)
+
+另一個選項是使用能幫你做更多事情的雲端服務(包含設定 HTTPS)。它可能有一些限制或要額外付費等。但在那種情況下,你就不必自己設定 TLS Termination Proxy。
+
+我會在後續章節展示一些具體例子。
+
+---
+
+接下來要考慮的概念都與實際執行你的 API 的程式(例如 Uvicorn)有關。
+
+## 程式與行程 { #program-and-process }
+
+我們會常提到執行中的「行程(process)」,因此先釐清它的意思,以及與「程式(program)」的差異很有幫助。
+
+### 什麼是程式 { #what-is-a-program }
+
+「程式(program)」一詞常用來描述許多東西:
+
+- 你寫的原始碼,也就是 Python 檔案。
+- 可由作業系統執行的檔案,例如:`python`、`python.exe` 或 `uvicorn`。
+- 在作業系統上執行中的特定程式,使用 CPU 並將資料存於記憶體。這也稱為「行程」。
+
+### 什麼是行程 { #what-is-a-process }
+
+「行程(process)」通常以更特定的方式使用,只指作業系統中正在執行的東西(如上面最後一點):
+
+- 在作業系統上「執行中」的特定程式。
+ - 這不是指檔案或原始碼,而是特指正在被作業系統執行並管理的那個東西。
+- 任何程式、任何程式碼,只有在「被執行」時才能做事。所以,當有「行程在執行」時才能運作。
+- 行程可以被你或作業系統終止(kill)。此時它就停止執行,無法再做任何事。
+- 你電腦上執行的每個應用程式、每個視窗等,背後都有一些行程。而且在電腦開機時,通常會同時有許多行程在跑。
+- 同一個程式可以同時有多個行程在執行。
+
+如果你打開作業系統的「工作管理員」或「系統監控器」(或類似工具),就能看到許多正在執行的行程。
+
+例如,你大概會看到同一個瀏覽器(Firefox、Chrome、Edge 等)會有多個行程在執行。它們通常每個分頁一個行程,外加其他一些額外行程。
+
+

+
+---
+
+現在我們知道「行程」與「程式」的差異了,繼續談部署。
+
+## 開機自動執行 { #running-on-startup }
+
+多數情況下,當你建立一個 Web API,你會希望它「一直在執行」,不中斷,讓客戶端隨時可用。除非你有特定理由只在某些情況下才執行,但大部分時候你會希望它持續運作並且可用。
+
+### 在遠端伺服器上 { #in-a-remote-server }
+
+當你設定一台遠端伺服器(雲端伺服器、虛擬機等),最簡單的作法就是像本機開發時一樣,手動使用 `fastapi run`(它使用 Uvicorn)或類似的方式。
+
+這在「開發期間」會運作良好而且有用。
+
+但如果你與伺服器的連線中斷,正在執行的行程很可能會死掉。
+
+而如果伺服器被重新啟動(例如更新後、或雲端供應商進行遷移),你大概「不會注意到」。因此你甚至不知道要手動重啟行程。你的 API 就會一直掛著。😱
+
+### 開機自動啟動 { #run-automatically-on-startup }
+
+通常你會希望伺服器程式(例如 Uvicorn)在伺服器開機時自動啟動,且不需任何「人工介入」,讓你的 API(例如 Uvicorn 執行你的 FastAPI 應用)總是有行程在跑。
+
+### 獨立程式 { #separate-program }
+
+為了達成這點,你通常會有一個「獨立的程式」來確保你的應用在開機時會被啟動。很多情況下,它也會確保其他元件或應用一併啟動,例如資料庫。
+
+### 開機自動啟動的工具範例 { #example-tools-to-run-at-startup }
+
+能做到這件事的工具包括:
+
+- Docker
+- Kubernetes
+- Docker Compose
+- Docker 的 Swarm 模式
+- Systemd
+- Supervisor
+- 由雲端供應商在其服務內部處理
+- 其他...
+
+我會在後續章節給出更具體的例子。
+
+## 重新啟動 { #restarts }
+
+和確保你的應用在開機時會執行一樣,你大概也會希望在發生失敗之後,它能「自動重新啟動」。
+
+### 人都會犯錯 { #we-make-mistakes }
+
+我們身為人,常常會犯錯。軟體幾乎總是有藏在各處的「臭蟲(bugs)」🐛
+
+而我們開發者會在發現這些 bug 後持續改進程式碼、實作新功能(也可能順便加進新的 bug 😅)。
+
+### 小錯誤自動處理 { #small-errors-automatically-handled }
+
+使用 FastAPI 建構 Web API 時,如果我們的程式碼出錯,FastAPI 通常會把它限制在觸發該錯誤的單次請求之中。🛡
+
+用戶端會收到「500 Internal Server Error」,但應用會繼續處理之後的請求,而不是整個崩潰。
+
+### 更嚴重的錯誤 - 當機 { #bigger-errors-crashes }
+
+然而,仍可能有一些情況,我們寫的程式碼「讓整個應用當機」,使 Uvicorn 與 Python 都崩潰。💥
+
+即便如此,你大概也不會希望應用因為某處錯誤就一直處於死亡狀態,你可能會希望它「繼續運作」,至少讓沒有壞掉的「路徑操作(path operations)」能持續服務。
+
+### 當機後重新啟動 { #restart-after-crash }
+
+在這些會讓「執行中行程」整個崩潰的嚴重錯誤案例裡,你會希望有個外部元件負責「重新啟動」該行程,至少嘗試幾次...
+
+/// tip
+
+...不過,如果整個應用「一啟動就立刻」崩潰,那持續無止境地重啟大概沒有意義。但在這類情況下,你很可能會在開發過程中就發現,或至少在部署後馬上注意到。
+
+所以讓我們專注在主要情境:應用在未來某些特定案例中可能會整體崩潰,但此時重新啟動仍然是有意義的。
+
+///
+
+你大概會希望把負責重新啟動應用的東西放在「外部元件」,因為那個時候,應用本身連同 Uvicorn 與 Python 都已經掛了,在同一個應用的程式碼裡也無法做什麼。
+
+### 自動重新啟動的工具範例 { #example-tools-to-restart-automatically }
+
+多數情況下,用來「在開機時啟動程式」的同一套工具,也會負責處理自動「重新啟動」。
+
+例如,可以由下列工具處理:
+
+- Docker
+- Kubernetes
+- Docker Compose
+- Docker 的 Swarm 模式
+- Systemd
+- Supervisor
+- 由雲端供應商在其服務內部處理
+- 其他...
+
+## 複本:行程與記憶體 { #replication-processes-and-memory }
+
+在 FastAPI 應用中,使用像 `fastapi` 指令(執行 Uvicorn)的伺服器程式,即使只在「一個行程」中執行,也能同時服務多個客戶端。
+
+但很多情況下,你會想同時執行多個工作行程(workers)。
+
+### 多個行程 - Workers { #multiple-processes-workers }
+
+如果你的客戶端比單一行程所能處理的更多(例如虛擬機規格不大),而伺服器 CPU 有「多核心」,那你可以同時執行「多個行程」載入相同的應用,並把所有請求分散給它們。
+
+當你執行同一個 API 程式的「多個行程」時,通常稱為「workers(工作行程)」。
+
+### 工作行程與連接埠 { #worker-processes-and-ports }
+
+還記得文件中[關於 HTTPS](https.md){.internal-link target=_blank} 的說明嗎:在一台伺服器上,一組 IP 與連接埠的組合只能由「一個行程」監聽?
+
+這裡同樣適用。
+
+因此,若要同時擁有「多個行程」,就必須有「單一行程」在該連接埠上監聽,然後以某種方式把通信傳遞給各個工作行程。
+
+### 每個行程的記憶體 { #memory-per-process }
+
+當程式把東西載入記憶體時,例如把機器學習模型存到變數中,或把大型檔案內容讀到變數中,這些都會「消耗一些伺服器的記憶體(RAM)」。
+
+而多個行程通常「不共享記憶體」。這表示每個執行中的行程都有自己的東西、變數與記憶體。如果你的程式碼會用掉大量記憶體,「每個行程」都會消耗等量的記憶體。
+
+### 伺服器記憶體 { #server-memory }
+
+例如,如果你的程式碼載入一個「1 GB 大小」的機器學習模型,當你用一個行程執行你的 API,它就會至少吃掉 1 GB 的 RAM。若你啟動「4 個行程」(4 個 workers),每個會吃 1 GB RAM。總計你的 API 會吃掉「4 GB RAM」。
+
+如果你的遠端伺服器或虛擬機只有 3 GB RAM,嘗試載入超過 4 GB 的 RAM 就會出問題。🚨
+
+### 多個行程 - 範例 { #multiple-processes-an-example }
+
+在這個例子中,有一個「管理行程(Manager Process)」會啟動並控制兩個「工作行程(Worker Processes)」。
+
+這個管理行程大概就是在 IP 的「連接埠」上監聽的那個。它會把所有通信轉發到各個工作行程。
+
+那些工作行程才是實際執行你的應用的,它們會完成主要的計算,接收「請求」並回傳「回應」,也會把你放在變數中的東西載入 RAM。
+
+

+
+當然,同一台機器上除了你的應用之外,通常也會有「其他行程」在執行。
+
+有個有趣的細節是,每個行程的「CPU 使用率」百分比會隨時間大幅「變動」,但「記憶體(RAM)」通常維持相對「穩定」。
+
+如果你的 API 每次做的計算量相近,且客戶很多,那「CPU 使用率」也可能「相對穩定」(而不是快速上下起伏)。
+
+### 複本與擴展的工具與策略範例 { #examples-of-replication-tools-and-strategies }
+
+要達成這些有很多種作法。我會在後續章節(例如談到 Docker 與容器時)介紹更具體的策略。
+
+主要的限制是:必須有「單一」元件負責處理「公開 IP」上的「連接埠」。接著它必須能把通信「轉發」到被複製的「行程/workers」。
+
+以下是一些可能的組合與策略:
+
+- Uvicorn 搭配 `--workers`
+ - 一個 Uvicorn「管理行程」會在「IP」與「連接埠」上監聽,並啟動「多個 Uvicorn 工作行程」。
+- Kubernetes 與其他分散式「容器系統」
+ - 由「Kubernetes」層在「IP」與「連接埠」上監聽。複本的方式是有「多個容器」,每個容器內執行「一個 Uvicorn 行程」。
+- 由「雲端服務」替你處理
+ - 雲端服務很可能「替你處理複本」。它可能讓你定義「要執行的行程」或「容器映像」,無論如何,多半會是「單一 Uvicorn 行程」,而由雲端服務負責進行複製。
+
+/// tip
+
+先別擔心這裡提到的「容器」、Docker 或 Kubernetes 如果現在還不太懂。
+
+我會在未來的章節進一步說明容器映像、Docker、Kubernetes 等等:[容器中的 FastAPI - Docker](docker.md){.internal-link target=_blank}。
+
+///
+
+## 啟動前的前置步驟 { #previous-steps-before-starting }
+
+很多情況下,你會希望在應用「啟動之前」先執行一些步驟。
+
+例如,你可能想先執行「資料庫遷移」。
+
+但在多數情況下,你會希望這些步驟只執行「一次」。
+
+所以,你會希望用「單一行程」來執行那些「前置步驟」,在啟動應用之前完成。
+
+而且即使之後你要為應用本身啟動「多個行程」(多個 workers),你也必須確保只有一個行程在跑那些前置步驟。若由「多個行程」去跑,會在「平行」中重複同樣的工作;而如果那些步驟像是資料庫遷移這類敏感操作,它們之間可能會互相衝突。
+
+當然,也有一些情況,重複執行前置步驟不會有問題;在那種情況下就容易處理得多。
+
+/// tip
+
+另外請記住,依照你的設定,在某些情況下你「甚至可能不需要任何前置步驟」才能啟動應用。
+
+這種情況下,你就不用為此費心了。🤷
+
+///
+
+### 前置步驟策略範例 { #examples-of-previous-steps-strategies }
+
+這會「高度取決於」你「部署系統」的方式,而且很可能與你如何啟動程式、處理重新啟動等有關。
+
+以下是一些可能的做法:
+
+- 在 Kubernetes 中使用一個「Init Container」,它會在你的應用容器之前先執行
+- 一個 bash 腳本先跑前置步驟,然後再啟動你的應用
+ - 你仍然需要有機制來啟動/重新啟動「那個」bash 腳本、偵測錯誤等
+
+/// tip
+
+我會在未來關於容器的章節提供更具體的範例:[容器中的 FastAPI - Docker](docker.md){.internal-link target=_blank}。
+
+///
+
+## 資源使用率 { #resource-utilization }
+
+你的伺服器(群)是可以被「消耗/利用」的「資源」,你的程式會使用 CPU 的計算時間,以及可用的 RAM 記憶體。
+
+你想要消耗/利用多少系統資源?直覺上可能會想「不要太多」,但實際上,你大概會希望在「不當機」的前提下「盡可能用多一點」。
+
+如果你花錢租了 3 台伺服器,卻只用了它們少量的 RAM 與 CPU,那你可能是在「浪費金錢」💸、也「浪費伺服器電力」🌎 等。
+
+在那種情況下,可能更好的是只用 2 台伺服器,並以更高的比例使用它們的資源(CPU、記憶體、磁碟、網路頻寬等)。
+
+另一方面,如果你有 2 台伺服器,且你使用了它們「100% 的 CPU 與 RAM」,某個時刻一個行程會要求更多記憶體,伺服器就得用磁碟當作「記憶體」(這可能慢上數千倍),甚至「當機」。或是某個行程需要做計算時,必須等到 CPU 再度空閒。
+
+這種情況下,最好是再加一台伺服器,並在上面跑部分行程,讓所有行程都有「足夠的 RAM 與 CPU 時間」。
+
+也有機會因為某些原因,你的 API 使用量出現「尖峰」。也許它爆紅了,或是其他服務或機器人開始使用它。在這些情況下,你可能會希望留有一些額外資源以策安全。
+
+你可以設定一個「目標數字」,例如資源使用率落在「50% 到 90%」之間。重點是,這些大概就是你會想測量並用來調校部署的主要指標。
+
+你可以用像 `htop` 這樣的簡單工具,查看伺服器的 CPU 與 RAM 使用量,或各行程的使用量。也可以用更複雜的監控工具,分散式地監看多台伺服器,等等。
+
+## 重點回顧 { #recap }
+
+這裡介紹了一些你在決定如何部署應用時應該記住的主要概念:
+
+- 安全性 - HTTPS
+- 開機自動執行
+- 重新啟動
+- 複本(執行中的行程數量)
+- 記憶體
+- 啟動前的前置步驟
+
+理解這些想法與如何套用它們,應能給你足夠的直覺,在設定與調整部署時做出各種決策。🤓
+
+在接下來的章節,我會提供更多可行策略的具體範例。🚀
diff --git a/docs/zh-hant/docs/deployment/docker.md b/docs/zh-hant/docs/deployment/docker.md
new file mode 100644
index 0000000000..87f4e6f9f0
--- /dev/null
+++ b/docs/zh-hant/docs/deployment/docker.md
@@ -0,0 +1,618 @@
+# 在容器中使用 FastAPI - Docker { #fastapi-in-containers-docker }
+
+部署 FastAPI 應用時,一個常見做法是建置一個「Linux 容器映像(container image)」。通常使用
Docker 來完成。之後你可以用多種方式部署該容器映像。
+
+使用 Linux 容器有多種優點,包括安全性、可重現性、簡單性等。
+
+/// tip | 提示
+
+趕時間而且已經懂這些?直接跳到下面的 [`Dockerfile` 👇](#build-a-docker-image-for-fastapi)。
+
+///
+
+
+Dockerfile 預覽 👀
+
+```Dockerfile
+FROM python:3.14
+
+WORKDIR /code
+
+COPY ./requirements.txt /code/requirements.txt
+
+RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
+
+COPY ./app /code/app
+
+CMD ["fastapi", "run", "app/main.py", "--port", "80"]
+
+# 若在 Nginx 或 Traefik 等代理伺服器後方執行,請加入 --proxy-headers
+# CMD ["fastapi", "run", "app/main.py", "--port", "80", "--proxy-headers"]
+```
+
+
+
+## 什麼是容器 { #what-is-a-container }
+
+容器(主要是 Linux 容器)是一種非常輕量的方式,用來封裝應用及其所有相依與必要檔案,並讓其與同一系統中的其他容器(其他應用或元件)隔離。
+
+Linux 容器使用與主機(機器、虛擬機、雲端伺服器等)相同的 Linux kernel。這意味著它們非常輕量(相較於完整模擬整個作業系統的虛擬機)。
+
+因此,容器只消耗很少的資源,與直接執行行程相當(而虛擬機會消耗更多)。
+
+容器也有其各自隔離的執行行程(通常只有一個行程)、檔案系統與網路,簡化部署、安全性與開發等。
+
+## 什麼是容器映像 { #what-is-a-container-image }
+
+容器是由容器映像啟動執行的。
+
+容器映像是所有檔案、環境變數,以及在容器中應該執行的預設指令/程式的靜態版本。這裡的「靜態」意指容器映像不在執行,它只是被封裝的檔案與 metadata。
+
+相對於儲存的靜態內容「容器映像」,「容器」通常指執行中的實例,也就是正在被執行的東西。
+
+當容器啟動並執行時(自容器映像啟動),它可以建立或變更檔案、環境變數等。這些變更只會存在於該容器中,不會持久化回底層的容器映像(不會寫回磁碟)。
+
+容器映像可類比為程式檔與其內容,例如 `python` 與某個 `main.py` 檔案。
+
+而容器本身(相對於容器映像)是映像的實際執行實例,類比為「行程」。事實上,容器只有在有行程執行時才在運作(通常只有單一行程)。當其中沒有行程在執行時,容器就會停止。
+
+## 容器映像 { #container-images }
+
+Docker 是用來建立與管理容器映像與容器的主要工具之一。
+
+也有一個公開的
Docker Hub,內含許多工具、環境、資料庫與應用的預先製作「官方映像」。
+
+例如,有官方的
Python 映像。
+
+也有許多其他針對不同用途的映像,例如資料庫:
+
+*
PostgreSQL
+*
MySQL
+*
MongoDB
+*
Redis 等。
+
+使用預製的容器映像很容易「組合」並使用不同工具。例如,嘗試一個新資料庫。多數情況下,你可以使用官方映像,並僅用環境變數加以設定。
+
+如此,你可以學會關於容器與 Docker 的知識,並將這些知識重複運用到許多不同工具與元件上。
+
+因此,你會執行多個容器,內容各不相同,例如一個資料庫、一個 Python 應用、一個帶有 React 前端應用的網頁伺服器,並透過它們的內部網路把它們連接在一起。
+
+所有容器管理系統(例如 Docker 或 Kubernetes)都內建了這些網路功能。
+
+## 容器與行程 { #containers-and-processes }
+
+容器映像通常在其 metadata 中包含當容器啟動時應執行的預設程式或指令,以及要傳給該程式的參數。這與在命令列要執行的內容非常類似。
+
+當容器啟動時,它會執行該指令/程式(雖然你可以覆寫它,讓它執行不同的指令/程式)。
+
+只要主要行程(指令或程式)在執行,容器就會運作。
+
+容器通常只有單一行程,但也可以由主要行程啟動子行程,如此你會在同一個容器內有多個行程。
+
+但不可能在沒有至少一個執行中行程的情況下讓容器運作。若主要行程停止,容器也會停止。
+
+## 建置 FastAPI 的 Docker 映像 { #build-a-docker-image-for-fastapi }
+
+好了,現在來動手做點東西吧!🚀
+
+我會示範如何從零開始,基於官方的 Python 映像,為 FastAPI 建置一個 Docker 映像。
+
+這是你在多數情況下會想做的事,例如:
+
+* 使用 Kubernetes 或類似工具
+* 在 Raspberry Pi 上執行
+* 使用會替你執行容器映像的雲端服務等
+
+### 套件需求 { #package-requirements }
+
+你的應用通常會把「套件需求」放在某個檔案中。
+
+這主要取決於你用什麼工具來安裝那些需求。
+
+最常見的方式是準備一個 `requirements.txt` 檔案,逐行列出套件名稱與版本。
+
+當然,你會用與在 [關於 FastAPI 版本](versions.md){.internal-link target=_blank} 中讀到的相同概念,來設定版本範圍。
+
+例如,你的 `requirements.txt` 可能像這樣:
+
+```
+fastapi[standard]>=0.113.0,<0.114.0
+pydantic>=2.7.0,<3.0.0
+```
+
+接著你通常會用 `pip` 來安裝這些套件相依,例如:
+
+
+
+```console
+$ pip install -r requirements.txt
+---> 100%
+Successfully installed fastapi pydantic
+```
+
+
+
+/// info | 資訊
+
+還有其他格式與工具可以用來定義與安裝套件相依。
+
+///
+
+### 建立 FastAPI 程式碼 { #create-the-fastapi-code }
+
+* 建立一個 `app` 目錄並進入。
+* 建立一個空的 `__init__.py` 檔案。
+* 建立一個 `main.py` 檔案,內容如下:
+
+```Python
+from fastapi import FastAPI
+
+app = FastAPI()
+
+
+@app.get("/")
+def read_root():
+ return {"Hello": "World"}
+
+
+@app.get("/items/{item_id}")
+def read_item(item_id: int, q: str | None = None):
+ return {"item_id": item_id, "q": q}
+```
+
+### Dockerfile { #dockerfile }
+
+現在在同一個專案目錄建立一個 `Dockerfile` 檔案,內容如下:
+
+```{ .dockerfile .annotate }
+# (1)!
+FROM python:3.14
+
+# (2)!
+WORKDIR /code
+
+# (3)!
+COPY ./requirements.txt /code/requirements.txt
+
+# (4)!
+RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
+
+# (5)!
+COPY ./app /code/app
+
+# (6)!
+CMD ["fastapi", "run", "app/main.py", "--port", "80"]
+```
+
+1. 從官方的 Python 基底映像開始。
+
+2. 將目前工作目錄設為 `/code`。
+
+ 我們會把 `requirements.txt` 檔案與 `app` 目錄放在這裡。
+
+3. 將需求檔案複製到 `/code` 目錄。
+
+ 先只複製需求檔案,不要複製其他程式碼。
+
+ 因為這個檔案不常變動,Docker 能偵測並在此步驟使用快取,也能啟用下一步的快取。
+
+4. 安裝需求檔案中的套件相依。
+
+ `--no-cache-dir` 選項告訴 `pip` 不要把下載的套件保存在本機,因為那只在 `pip` 之後還會再次安裝相同套件時才有用,而在使用容器時並非如此。
+
+ /// note | 注意
+
+ `--no-cache-dir` 只跟 `pip` 有關,與 Docker 或容器無關。
+
+ ///
+
+ `--upgrade` 選項告訴 `pip` 若套件已安裝則升級它們。
+
+ 因為前一步複製檔案可能被 Docker 快取偵測到,這一步也會在可用時使用 Docker 快取。
+
+ 在此步驟使用快取可以在開發期間反覆建置映像時,為你省下大量時間,而不必每次都重新下載並安裝所有相依。
+
+5. 將 `./app` 目錄複製到 `/code` 目錄中。
+
+ 由於這包含了所有程式碼,也是最常變動的部分,Docker 的快取在這一步或之後的步驟將不容易被使用。
+
+ 因此,重要的是把這一步放在 `Dockerfile` 的接近結尾處,以最佳化容器映像的建置時間。
+
+6. 設定指令使用 `fastapi run`,其底層使用 Uvicorn。
+
+ `CMD` 接受字串清單,每個字串對應你在命令列中用空白分隔所輸入的內容。
+
+ 這個指令會從目前的工作目錄執行,也就是你先前用 `WORKDIR /code` 設定的 `/code` 目錄。
+
+/// tip | 提示
+
+點擊程式碼中的每個數字泡泡來查看每一行在做什麼。👆
+
+///
+
+/// warning | 警告
+
+務必「總是」使用 `CMD` 指令的「exec 形式」,如下所述。
+
+///
+
+#### 使用 `CMD` 的 Exec 形式 { #use-cmd-exec-form }
+
+Docker 的
`CMD` 指令可以有兩種寫法:
+
+✅ Exec 形式:
+
+```Dockerfile
+# ✅ 請這樣做
+CMD ["fastapi", "run", "app/main.py", "--port", "80"]
+```
+
+⛔️ Shell 形式:
+
+```Dockerfile
+# ⛔️ 請不要這樣做
+CMD fastapi run app/main.py --port 80
+```
+
+務必總是使用 exec 形式,以確保 FastAPI 能夠優雅地關閉,並觸發 [lifespan events](../advanced/events.md){.internal-link target=_blank}。
+
+你可以在
Docker 關於 shell 與 exec 形式的文件閱讀更多。
+
+使用 `docker compose` 時這會特別明顯。技術細節請見這段 Docker Compose 常見問題:
為什麼我的服務要花 10 秒才重新建立或停止?
+
+#### 目錄結構 { #directory-structure }
+
+你現在應該會有如下的目錄結構:
+
+```
+.
+├── app
+│ ├── __init__.py
+│ └── main.py
+├── Dockerfile
+└── requirements.txt
+```
+
+#### 位於 TLS 終止代理之後 { #behind-a-tls-termination-proxy }
+
+如果你在 TLS 終止代理(負載平衡器)如 Nginx 或 Traefik 之後執行容器,請加上 `--proxy-headers` 選項,這會告訴 Uvicorn(透過 FastAPI CLI)信任該代理所送來的標頭,表示應用在 HTTPS 後方執行等。
+
+```Dockerfile
+CMD ["fastapi", "run", "app/main.py", "--proxy-headers", "--port", "80"]
+```
+
+#### Docker 快取 { #docker-cache }
+
+這個 `Dockerfile` 中有個重要技巧:我們先只複製「相依檔案」,而不是其他程式碼。原因如下。
+
+```Dockerfile
+COPY ./requirements.txt /code/requirements.txt
+```
+
+Docker 與其他工具會「增量式」建置容器映像,從 `Dockerfile` 頂端開始,逐層加入,每個指令所建立的檔案都會形成一層。
+
+Docker 與類似工具在建置映像時也會使用內部快取;如果某檔案自上次建置以來未變更,則會重用上次建立的同一層,而不是再次複製並從零建立新層。
+
+僅僅避免複製檔案本身或許幫助不大,但因為該步驟使用了快取,接下來的步驟也就能「使用快取」。例如,安裝相依的這個指令就能使用快取:
+
+```Dockerfile
+RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
+```
+
+套件相依的檔案「不會經常變動」。因此,只複製該檔案,Docker 就能在此步驟「使用快取」。
+
+接著,Docker 也就能對下一步「下載並安裝這些相依」使用快取。這正是我們能「省下大量時間」的地方。✨ 也能避免無聊的等待。😪😆
+
+下載與安裝套件相依「可能要花好幾分鐘」,但使用「快取」最多只需幾秒。
+
+在開發期間,你會一再建置容器映像以測試程式碼變更是否生效,累積下來這能省下許多時間。
+
+之後,在 `Dockerfile` 的接近結尾處,我們才複製所有程式碼。由於這是「最常變動」的部分,我們把它放在接近結尾,因為幾乎總是此步驟之後的任何步驟都無法使用快取。
+
+```Dockerfile
+COPY ./app /code/app
+```
+
+### 建置 Docker 映像 { #build-the-docker-image }
+
+現在所有檔案就緒,來建置容器映像。
+
+* 進到專案目錄(你的 `Dockerfile` 所在,且包含 `app` 目錄)。
+* 建置你的 FastAPI 映像:
+
+
+
+```console
+$ docker build -t myimage .
+
+---> 100%
+```
+
+
+
+/// tip | 提示
+
+注意最後的 `.`,等同於 `./`,它告訴 Docker 要用哪個目錄來建置容器映像。
+
+這裡是目前的目錄(`.`)。
+
+///
+
+### 啟動 Docker 容器 { #start-the-docker-container }
+
+* 以你的映像為基礎執行一個容器:
+
+
+
+```console
+$ docker run -d --name mycontainer -p 80:80 myimage
+```
+
+
+
+## 檢查 { #check-it }
+
+你應該可以透過 Docker 容器的網址檢查,例如:
http://192.168.99.100/items/5?q=somequery 或
http://127.0.0.1/items/5?q=somequery(或等效的、使用你的 Docker 主機)。
+
+你會看到類似這樣:
+
+```JSON
+{"item_id": 5, "q": "somequery"}
+```
+
+## 互動式 API 文件 { #interactive-api-docs }
+
+現在你可以前往
http://192.168.99.100/docs 或
http://127.0.0.1/docs(或等效的、使用你的 Docker 主機)。
+
+你會看到自動產生的互動式 API 文件(由
Swagger UI 提供):
+
+
+
+## 替代的 API 文件 { #alternative-api-docs }
+
+你也可以前往
http://192.168.99.100/redoc 或
http://127.0.0.1/redoc(或等效的、使用你的 Docker 主機)。
+
+你會看到另一種自動產生的文件(由
ReDoc 提供):
+
+
+
+## 為單檔 FastAPI 建置 Docker 映像 { #build-a-docker-image-with-a-single-file-fastapi }
+
+如果你的 FastAPI 是單一檔案,例如沒有 `./app` 目錄的 `main.py`,你的檔案結構可能像這樣:
+
+```
+.
+├── Dockerfile
+├── main.py
+└── requirements.txt
+```
+
+接著你只需要在 `Dockerfile` 中調整對應的路徑以複製該檔案:
+
+```{ .dockerfile .annotate hl_lines="10 13" }
+FROM python:3.14
+
+WORKDIR /code
+
+COPY ./requirements.txt /code/requirements.txt
+
+RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
+
+# (1)!
+COPY ./main.py /code/
+
+# (2)!
+CMD ["fastapi", "run", "main.py", "--port", "80"]
+```
+
+1. 將 `main.py` 直接複製到 `/code` 目錄(不需要 `./app` 目錄)。
+
+2. 使用 `fastapi run` 來服務單檔的 `main.py` 應用。
+
+當你把檔案傳給 `fastapi run`,它會自動偵測這是一個單一檔案而非套件的一部分,並知道如何匯入並服務你的 FastAPI 應用。😎
+
+## 部署概念 { #deployment-concepts }
+
+我們用容器的角度再談一次部分相同的[部署概念](concepts.md){.internal-link target=_blank}。
+
+容器主要是簡化應用「建置與部署」流程的工具,但它們不強制特定的方式來處理這些「部署概念」,而是有多種策略可選。
+
+好消息是,每種不同的策略都能涵蓋所有部署概念。🎉
+
+讓我們用容器的角度回顧這些部署概念:
+
+* HTTPS
+* 開機自動執行
+* 失敗重啟
+* 複本(執行的行程數量)
+* 記憶體
+* 啟動前的前置步驟
+
+## HTTPS { #https }
+
+若僅聚焦於 FastAPI 應用的「容器映像」(以及稍後的執行中「容器」),HTTPS 通常會由另一個工具在「外部」處理。
+
+它可以是另一個容器,例如使用
Traefik,來處理「HTTPS」以及「自動」取得「憑證」。
+
+/// tip | 提示
+
+Traefik 與 Docker、Kubernetes 等整合良好,因此為你的容器設定與配置 HTTPS 非常容易。
+
+///
+
+或者,HTTPS 也可能由雲端供應商以其服務來處理(同時應用仍以容器執行)。
+
+## 開機自動執行與重啟 { #running-on-startup-and-restarts }
+
+通常會有另一個工具負責「啟動並執行」你的容器。
+
+可能是直接用 Docker、Docker Compose、Kubernetes、某個雲端服務等。
+
+在大多數(或全部)情況下,都有簡單的選項可以在開機時自動執行容器,並在失敗時重啟。例如,在 Docker 中,可用命令列選項 `--restart`。
+
+如果不使用容器,讓應用在開機時自動執行並支援重啟可能既繁瑣又困難。但在「使用容器」時,這類功能在多數情況下都是預設包含的。✨
+
+## 複本 - 行程數量 { #replication-number-of-processes }
+
+如果你在有 Kubernetes、Docker Swarm Mode、Nomad,或其他類似的分散式容器管理系統的「叢集」上運作,那你大概會希望在「叢集層級」處理「複本」,而不是在每個容器內使用「行程管理器」(例如帶有 workers 的 Uvicorn)。
+
+像 Kubernetes 這類的分散式容器管理系統,通常內建處理「容器複本」以及支援進入請求的「負載平衡」的能力——全部都在「叢集層級」。
+
+在這些情況下,你大概會想要如[上面所述](#dockerfile)從零開始建置一個 Docker 映像,安裝你的相依,並且只執行「單一 Uvicorn 行程」,而不是使用多個 Uvicorn workers。
+
+### 負載平衡器 { #load-balancer }
+
+使用容器時,通常會有某個元件在「主埠口」上監聽。它也可能是另一個同時做為「TLS 終止代理」的容器來處理「HTTPS」,或類似的工具。
+
+由於這個元件會承接請求的「負載」,並將其分配給 workers,使其(希望)「平衡」,因此也常被稱為「負載平衡器(Load Balancer)」。
+
+/// tip | 提示
+
+用於 HTTPS 的同一個「TLS 終止代理」元件通常也會是「負載平衡器」。
+
+///
+
+而在使用容器時,你用來啓動與管理它們的系統,已內建把「網路通訊」(例如 HTTP 請求)從該「負載平衡器」(也可能是「TLS 終止代理」)傳遞到你的應用容器的工具。
+
+### 一個負載平衡器 - 多個工作容器 { #one-load-balancer-multiple-worker-containers }
+
+使用 Kubernetes 或類似的分散式容器管理系統時,使用其內部網路機制可以讓在主「埠口」上監聽的單一「負載平衡器」,把通訊(請求)傳遞給可能的「多個執行你應用的容器」。
+
+每個執行你應用的容器通常只有「單一行程」(例如執行你的 FastAPI 應用的 Uvicorn 行程)。它們都是「相同的容器」,執行相同的東西,但各自擁有自己的行程、記憶體等。如此即可在 CPU 的「不同核心」、甚至是「不同機器」上發揮「平行化」的效益。
+
+而分散式容器系統中的「負載平衡器」會「輪流」把請求分配給各個執行你應用的容器。因此,每個請求都可能由多個「複製的容器」中的其中一個來處理。
+
+通常這個「負載平衡器」也能處理送往叢集中「其他」應用的請求(例如不同網域,或不同 URL 路徑前綴),並把通訊轉送到該「其他」應用對應的容器。
+
+### 每個容器一個行程 { #one-process-per-container }
+
+在這種情境中,你大概會希望「每個容器只有一個(Uvicorn)行程」,因為你已在叢集層級處理了複本。
+
+所以這種情況下,你「不會」想在容器中使用多個 workers(例如用 `--workers` 命令列選項)。你會想每個容器只執行「一個 Uvicorn 行程」(但可能有多個容器)。
+
+在容器內再放一個行程管理器(如同多 workers 的情況)只會增加「不必要的複雜度」,而你很可能已用叢集系統處理好了。
+
+### 多行程容器與特殊情境 { #containers-with-multiple-processes-and-special-cases }
+
+當然,有些「特殊情況」你可能會想在「一個容器內」執行數個「Uvicorn worker 行程」。
+
+在這些情況中,你可以用 `--workers` 命令列選項來設定要啟動的 workers 數量:
+
+```{ .dockerfile .annotate }
+FROM python:3.14
+
+WORKDIR /code
+
+COPY ./requirements.txt /code/requirements.txt
+
+RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
+
+COPY ./app /code/app
+
+# (1)!
+CMD ["fastapi", "run", "app/main.py", "--port", "80", "--workers", "4"]
+```
+
+1. 這裡我們使用 `--workers` 命令列選項把 worker 數量設定為 4。
+
+以下是一些合理的例子:
+
+#### 簡單應用 { #a-simple-app }
+
+如果你的應用「足夠簡單」,可以在「單一伺服器」而非叢集上執行,你可能會希望在容器內使用行程管理器。
+
+#### Docker Compose { #docker-compose }
+
+如果你部署到「單一伺服器」(非叢集),且使用「Docker Compose」,那麼你無法輕易(用 Docker Compose)在保有共用網路與「負載平衡」的同時管理容器複本。
+
+那你可能會想要「單一容器」搭配「行程管理器」,在其中啟動「多個 worker 行程」。
+
+---
+
+重點是,這些「都不是」必須盲目遵守的「鐵律」。你可以用這些想法來「評估你的使用情境」,並決定對你的系統最好的做法,看看如何管理以下概念:
+
+* 安全性 - HTTPS
+* 開機自動執行
+* 失敗重啟
+* 複本(執行的行程數量)
+* 記憶體
+* 啟動前的前置步驟
+
+## 記憶體 { #memory }
+
+如果你採用「每個容器一個行程」,那每個容器(若有複本則多個容器)所消耗的記憶體會是相對明確、穩定且有限的。
+
+接著你可以在容器管理系統(例如 Kubernetes)的設定中為容器設定相同的記憶體限制與需求。如此,它就能在「可用的機器」上「複製容器」,並考量容器所需的記憶體量與叢集中機器的可用記憶體。
+
+若你的應用「很簡單」,這可能「不是問題」,你可能不需要指定嚴格的記憶體限制。但如果你「使用大量記憶體」(例如使用機器學習模型),你應該檢查實際消耗的記憶體,並調整「每台機器上執行的容器數量」(也許還要為叢集加機器)。
+
+若你採用「每個容器多個行程」,你就得確保啟動的行程數量不會「超過可用記憶體」。
+
+## 啟動前的前置步驟與容器 { #previous-steps-before-starting-and-containers }
+
+如果你使用容器(例如 Docker、Kubernetes),那有兩種主要做法可用。
+
+### 多個容器 { #multiple-containers }
+
+如果你有「多個容器」,且每個容器大概都只執行「單一行程」(例如在一個 Kubernetes 叢集中),那你可能會想要一個「獨立的容器」來完成「前置步驟」的工作,並只在單一容器、單一行程中執行,接著才啟動多個複本的工作容器。
+
+/// info | 資訊
+
+如果你使用 Kubernetes,這大概會是一個
Init Container。
+
+///
+
+如果你的情境中,讓那些前置步驟「平行重複執行多次」沒有問題(例如不是在跑資料庫遷移,而只是檢查資料庫是否就緒),那也可以把這些步驟放在每個容器中、在啟動主要行程前執行。
+
+### 單一容器 { #single-container }
+
+如果你的架構很簡單,只有「單一容器」,接著在其中啟動多個「worker 行程」(或也可能就一個行程),那你可以在相同的容器中、於啟動應用行程前先執行這些前置步驟。
+
+### 基底 Docker 映像 { #base-docker-image }
+
+曾經有一個官方的 FastAPI Docker 映像:
tiangolo/uvicorn-gunicorn-fastapi。但現在已被棄用。⛔️
+
+你大概「不應該」使用這個基底 Docker 映像(或其他類似的)。
+
+如果你使用 Kubernetes(或其他)並已在叢集層級設定「複本」、使用多個「容器」。在這些情況下,更好的做法是如上所述[從零建置映像](#build-a-docker-image-for-fastapi)。
+
+若你需要多個 workers,只要使用 `--workers` 命令列選項即可。
+
+/// note | 技術細節
+
+這個 Docker 映像是在 Uvicorn 尚未支援管理與重啟死亡 workers 的年代所建立,因此需要用 Gunicorn 搭配 Uvicorn,為了讓 Gunicorn 管理並重啟 Uvicorn workers,而引入了相當多的複雜度。
+
+但現在 Uvicorn(以及 `fastapi` 指令)已支援使用 `--workers`,因此沒有理由使用一個基底 Docker 映像,而不是建置你自己的(而且實際上程式碼量也差不多 😅)。
+
+///
+
+## 部署容器映像 { #deploy-the-container-image }
+
+擁有容器(Docker)映像後,有多種部署方式。
+
+例如:
+
+* 在單一伺服器上使用 Docker Compose
+* 使用 Kubernetes 叢集
+* 使用 Docker Swarm Mode 叢集
+* 使用像 Nomad 之類的其他工具
+* 使用會接收你的容器映像並代為部署的雲端服務
+
+## 使用 `uv` 的 Docker 映像 { #docker-image-with-uv }
+
+如果你使用
uv 來安裝與管理專案,你可以參考他們的
uv Docker 指南。
+
+## 總結 { #recap }
+
+使用容器系統(例如 Docker 與 Kubernetes)可以相對直接地處理所有「部署概念」:
+
+* HTTPS
+* 開機自動執行
+* 失敗重啟
+* 複本(執行的行程數量)
+* 記憶體
+* 啟動前的前置步驟
+
+多數情況下,你大概不會想用任何基底映像,而是「從零建置容器映像」,以官方的 Python Docker 映像為基礎。
+
+善用 `Dockerfile` 中指令的「順序」與「Docker 快取」,你可以「最小化建置時間」,提升生產力(並避免無聊)。😎
diff --git a/docs/zh-hant/docs/deployment/fastapicloud.md b/docs/zh-hant/docs/deployment/fastapicloud.md
new file mode 100644
index 0000000000..5663590d14
--- /dev/null
+++ b/docs/zh-hant/docs/deployment/fastapicloud.md
@@ -0,0 +1,65 @@
+# FastAPI Cloud { #fastapi-cloud }
+
+你可以用「一行指令」把你的 FastAPI 應用程式部署到
FastAPI Cloud。如果你還沒加入,快去登記等候名單吧!🚀
+
+## 登入 { #login }
+
+請先確認你已經有 **FastAPI Cloud** 帳號(我們已從等候名單邀請你 😉)。
+
+然後登入:
+
+
+
+```console
+$ fastapi login
+
+You are logged in to FastAPI Cloud 🚀
+```
+
+
+
+## 部署 { #deploy }
+
+現在用「一行指令」部署你的應用:
+
+
+
+```console
+$ fastapi deploy
+
+Deploying to FastAPI Cloud...
+
+✅ Deployment successful!
+
+🐔 Ready the chicken! Your app is ready at https://myapp.fastapicloud.dev
+```
+
+
+
+就這樣!現在你可以透過該 URL 造訪你的應用。✨
+
+## 關於 FastAPI Cloud { #about-fastapi-cloud }
+
+**
FastAPI Cloud** 由 **FastAPI** 的作者與團隊打造。
+
+它以最少的心力,精簡化建立、部署與存取 API 的流程。
+
+它把使用 FastAPI 開發應用的優異開發體驗,延伸到將它們部署到雲端。🎉
+
+它也會為你處理部署應用時多數需要面對的事項,例如:
+
+* HTTPS
+* 多副本,並可依據請求自動擴縮
+* 等等。
+
+FastAPI Cloud 是 *FastAPI and friends* 開源專案的主要贊助者與資金提供者。✨
+
+## 部署到其他雲端供應商 { #deploy-to-other-cloud-providers }
+
+FastAPI 是基於標準的開源專案。你可以把 FastAPI 應用部署到你選擇的任何雲端供應商。
+
+請依照你的雲端供應商的指南,使用他們的方式部署 FastAPI 應用。🤓
+
+## 部署到你自己的伺服器 { #deploy-your-own-server }
+
+在這份「部署」指南的後續內容中,我也會教你所有細節,讓你了解背後發生了什麼、需要做哪些事,以及如何自行部署 FastAPI 應用,包括在你自己的伺服器上。🤓
diff --git a/docs/zh-hant/docs/deployment/https.md b/docs/zh-hant/docs/deployment/https.md
new file mode 100644
index 0000000000..0934b02831
--- /dev/null
+++ b/docs/zh-hant/docs/deployment/https.md
@@ -0,0 +1,231 @@
+# 關於 HTTPS { #about-https }
+
+人們很容易以為 HTTPS 只是「啟用或未啟用」的功能。
+
+但實際上複雜得多。
+
+/// tip
+
+如果你趕時間或不在意細節,可以直接看後續章節,依照逐步指引用不同方式完成設定。
+
+///
+
+想從使用者角度學習 HTTPS 基礎,請參考
https://howhttps.works/。
+
+接著以開發者角度,談幾個關於 HTTPS 需要注意的重點:
+
+* 對於 HTTPS,伺服器需要擁有由**第三方**簽發的**「憑證」**。
+ * 這些憑證實際上是向第三方**取得**,不是「自己產生」。
+* 憑證有**有效期**。
+ * 會**過期**。
+ * 過期後需要**續期**,也就是再向第三方**重新取得**。
+* 連線加密發生在 **TCP 層**。
+ * 那是在 **HTTP 的下一層**。
+ * 因此,**憑證與加密**的處理會在 **進入 HTTP 之前**完成。
+* **TCP 不知道「網域」**,只知道 IP 位址。
+ * 關於**特定網域**的資訊會放在 **HTTP 資料**中。
+* **HTTPS 憑證**是為某個**特定網域**背書,但通訊協定與加密在 TCP 層進行,發生在**尚未知道**要處理哪個網域之前。
+* **預設**情況下,這表示你每個 IP 位址**只能**使用**一張 HTTPS 憑證**。
+ * 不論你的伺服器多強或你在上面跑的應用多小。
+ * 不過,這是有**解法**的。
+* 在 **TLS** 協定(在 HTTP 之前於 TCP 層處理加密的協定)上有個**擴充**稱為 **
SNI**。
+ * 這個 SNI 擴充讓單一伺服器(單一 IP 位址)可以擁有**多張 HTTPS 憑證**,並服務**多個 HTTPS 網域/應用**。
+ * 要讓它運作,伺服器上必須有一個**單一**的元件(程式)在**公用 IP**上監聽,且持有伺服器上的**所有 HTTPS 憑證**。
+* 在取得安全連線**之後**,通訊協定**仍然是 HTTP**。
+ * 雖然透過 **HTTP 協定**傳送,但內容是**加密**的。
+
+常見做法是讓伺服器(機器、主機等)上跑**一個程式/HTTP 伺服器**來**管理所有 HTTPS 相關工作**:接收**加密的 HTTPS 請求**、將其**解密**成**純 HTTP 請求**轉交給同台伺服器上實際運行的 HTTP 應用(本例為 **FastAPI** 應用)、從應用取得 **HTTP 回應**、再用合適的 **HTTPS 憑證**將其**加密**並以 **HTTPS** 傳回給用戶端。這類伺服器常被稱為 **
TLS 終止代理 (TLS Termination Proxy)**。
+
+可作為 TLS 終止代理的選項包括:
+
+* Traefik(也可處理憑證續期)
+* Caddy(也可處理憑證續期)
+* Nginx
+* HAProxy
+
+## Let's Encrypt { #lets-encrypt }
+
+在 Let's Encrypt 之前,這些 **HTTPS 憑證**是由受信任的第三方販售。
+
+取得這些憑證的流程過去相當繁瑣,需要許多手續,且憑證相當昂貴。
+
+之後出現了 **
Let's Encrypt**。
+
+它是 Linux Foundation 的專案,能**免費**且自動化地提供 **HTTPS 憑證**。這些憑證採用標準的密碼學安全機制,且有效期較短(約 3 個月),因此因為壽命短,**安全性其實更好**。
+
+網域會被安全驗證,憑證會自動產生。這也讓憑證續期得以自動化。
+
+目標是讓憑證的申請與續期自動化,讓你**永遠免費使用安全的 HTTPS**。
+
+## 給開發者的 HTTPS { #https-for-developers }
+
+以下以逐步範例說明一個 HTTPS API 可能長什麼樣子,著重於對開發者重要的概念。
+
+### 網域名稱 { #domain-name }
+
+通常會先**取得**一個**網域名稱**,接著在 DNS 伺服器(可能是同一個雲端供應商)中設定它。
+
+你可能會租一台雲端伺服器(虛擬機)或類似的服務,並擁有一個
固定的**公用 IP 位址**。
+
+在 DNS 伺服器中,你會設定一個紀錄(「`A record`」)指向**你的網域**所對應的**伺服器公用 IP 位址**。
+
+這通常在初次建置時設定一次即可。
+
+/// tip
+
+「網域名稱」是發生在 HTTPS 之前的事情,但一切都依賴網域與 IP 位址,因此在此一併說明。
+
+///
+
+### DNS { #dns }
+
+現在聚焦在實際的 HTTPS 部分。
+
+首先,瀏覽器會向 **DNS 伺服器**查詢該**網域的 IP**,例如 `someapp.example.com`。
+
+DNS 伺服器會回覆要使用的**IP 位址**,那就是你在 DNS 伺服器中設定的、伺服器對外的公用 IP 位址。
+
+

+
+### TLS 握手開始 { #tls-handshake-start }
+
+接著瀏覽器會連線到該 IP 的 **443 埠**(HTTPS 預設埠)。
+
+通訊的第一部分是建立用戶端與伺服器之間的連線,並協商要使用哪些金鑰等密碼參數。
+
+

+
+用戶端與伺服器為建立 TLS 連線而進行的這段互動稱為 **TLS 握手**。
+
+### 帶 SNI 擴充的 TLS { #tls-with-sni-extension }
+
+在特定的**IP 位址**與特定**埠**上,同一時間**只能有一個行程**在監聽。可以在同一個 IP 上監聽不同埠,但每個 IP 與埠的組合只能有一個行程。
+
+TLS(HTTPS)預設使用 `443` 埠,因此我們需要用到這個埠。
+
+由於只能有一個行程監聽該埠,負責監聽的會是 **TLS 終止代理**。
+
+TLS 終止代理會存取一張或多張 **TLS 憑證**(HTTPS 憑證)。
+
+透過上面提到的 **SNI 擴充**,TLS 終止代理會根據用戶端預期的網域,從可用的 TLS(HTTPS)憑證中挑選本次連線要用的憑證。
+
+在這個例子中,會使用 `someapp.example.com` 的憑證。
+
+

+
+用戶端**信任**簽發該 TLS 憑證的單位(本例為 Let's Encrypt,稍後會再談),因此可以**驗證**憑證有效。
+
+接著,用戶端與 TLS 終止代理會以該憑證為基礎,**協商後續如何加密**整段 **TCP 通訊**。至此完成 **TLS 握手**。
+
+之後,用戶端與伺服器之間就有一條**已加密的 TCP 連線**,這就是 TLS 所提供的能力。接著他們可以在這條連線上開始實際的 **HTTP** 通訊。
+
+這也就是 **HTTPS** 的本質:在**安全的 TLS 連線**內傳送一般的 **HTTP**,而非在純(未加密)的 TCP 連線上。
+
+/// tip
+
+請注意,加密發生在 **TCP 層**,不是在 HTTP 層。
+
+///
+
+### HTTPS 請求 { #https-request }
+
+現在用戶端與伺服器(更精確地說,是瀏覽器與 TLS 終止代理)之間已有**加密的 TCP 連線**,他們可以開始進行 **HTTP** 通訊。
+
+因此,用戶端送出一個 **HTTPS 請求**。它其實就是透過加密的 TLS 連線發送的一個 HTTP 請求。
+
+

+
+### 解密請求 { #decrypt-the-request }
+
+TLS 終止代理會依照先前協商的方式**解密請求**,並將**純(已解密)的 HTTP 請求**轉交給運行應用的行程(例如以 Uvicorn 執行的 FastAPI 應用行程)。
+
+

+
+### HTTP 回應 { #http-response }
+
+應用會處理該請求,並將**純(未加密)的 HTTP 回應**送回 TLS 終止代理。
+
+

+
+### HTTPS 回應 { #https-response }
+
+TLS 終止代理接著會依照先前協商(起點是 `someapp.example.com` 的憑證)的方式**加密回應**,並傳回給瀏覽器。
+
+接著,瀏覽器會驗證回應是否合法、是否使用正確的金鑰加密等。然後**解密回應**並處理。
+
+

+
+用戶端(瀏覽器)會知道回應來自正確的伺服器,因為它使用了先前依據 **HTTPS 憑證**所協商的密碼機制。
+
+### 多個應用 { #multiple-applications }
+
+同一台(或多台)伺服器上可以有**多個應用**,例如其他 API 程式或資料庫。
+
+雖然只有一個行程可以處理特定 IP 與埠的組合(本例中的 TLS 終止代理),但其他應用/行程也都能在伺服器上運行,只要它們不使用相同的**公用 IP 與埠**組合即可。
+
+

+
+如此一來,TLS 終止代理就能為**多個網域**、多個應用處理 HTTPS 與憑證,並把請求轉發到對應的應用。
+
+### 憑證續期 { #certificate-renewal }
+
+在未來某個時間點,每張憑證都會**過期**(自取得起約 3 個月)。
+
+之後,會有另一個程式(有時是另一個程式,有時也可能就是同一個 TLS 終止代理)與 Let's Encrypt 溝通並續期憑證。
+
+

+
+**TLS 憑證**是**綁定網域名稱**,不是綁定 IP 位址。
+
+因此,要續期憑證時,續期程式需要向憑證機構(Let's Encrypt)**證明**它的確**擁有並控制該網域**。
+
+為了達成這點、並兼顧不同應用情境,有幾種常見方式:
+
+* **修改部分 DNS 紀錄**。
+ * 為此,續期程式需要支援該 DNS 供應商的 API,因此依你使用的 DNS 供應商不同,這方式可能可行或不可行。
+* **作為伺服器運行**(至少在憑證申請過程中)於該網域對應的公用 IP 上。
+ * 如前所述,同一時間只有一個行程能在特定 IP 與埠上監聽。
+ * 這也是為什麼讓同一個 TLS 終止代理一併處理憑證續期非常實用的原因之一。
+ * 否則你可能得暫停 TLS 終止代理、啟動續期程式申請憑證、將憑證配置到 TLS 終止代理,然後再重啟 TLS 終止代理。這並不理想,因為在 TLS 終止代理停機期間,你的應用將不可用。
+
+在不中斷服務的同時完成整個續期流程,是你會想用**獨立系統(TLS 終止代理)來處理 HTTPS**、而不是直接把 TLS 憑證掛在應用伺服器(例如 Uvicorn)上的主要原因之一。
+
+## 代理轉發標頭 { #proxy-forwarded-headers }
+
+當你使用代理處理 HTTPS 時,你的**應用伺服器**(例如透過 FastAPI CLI 啟動的 Uvicorn)其實不知道任何 HTTPS 的處理流程,它是用純 HTTP 與 **TLS 終止代理**通訊。
+
+這個**代理**通常會在把請求轉發給**應用伺服器**之前,臨時加入一些 HTTP 標頭,讓應用伺服器知道該請求是由代理**轉發**過來的。
+
+/// note | 技術細節
+
+這些代理標頭包括:
+
+*
X-Forwarded-For
+*
X-Forwarded-Proto
+*
X-Forwarded-Host
+
+///
+
+然而,因為**應用伺服器**並不知道自己在受信任的**代理**之後,預設情況下它不會信任這些標頭。
+
+但你可以設定**應用伺服器**去信任由**代理**送來的「轉發」標頭。若你使用 FastAPI CLI,可以用 *CLI 參數* `--forwarded-allow-ips` 指定應信任哪些 IP 來的「轉發」標頭。
+
+例如,如果**應用伺服器**只會接收來自受信任**代理**的連線,你可以設定 `--forwarded-allow-ips="*"`,也就是信任所有來源 IP,因為實際上它只會收到**代理**那個 IP 送來的請求。
+
+如此一來,應用就能知道自己的對外 URL、是否使用 HTTPS、網域為何等資訊。
+
+這在正確處理重新導向等情境時很有用。
+
+/// tip
+
+你可以在文件 [在代理後方 - 啟用代理轉發標頭](../advanced/behind-a-proxy.md#enable-proxy-forwarded-headers){.internal-link target=_blank} 中了解更多。
+
+///
+
+## 重點回顧 { #recap }
+
+擁有 **HTTPS** 非常重要,而且在多數情況都相當**關鍵**。作為開發者,你在 HTTPS 上的大部分投入其實是**理解這些概念**及其運作方式。
+
+一旦掌握了**給開發者的 HTTPS 基礎**,你就能輕鬆組合並設定不同工具,讓一切管理變得簡單。
+
+在接下來的章節中,我會示範幾個為 **FastAPI** 應用設定 **HTTPS** 的具體例子。🔒
diff --git a/docs/zh-hant/docs/deployment/index.md b/docs/zh-hant/docs/deployment/index.md
index 9edd3368b2..ddf533efc9 100644
--- a/docs/zh-hant/docs/deployment/index.md
+++ b/docs/zh-hant/docs/deployment/index.md
@@ -8,7 +8,7 @@
對於一個 **Web API**,部署通常涉及將其放置在**遠端伺服器**上,並使用性能優良且穩定的**伺服器程式**,確保使用者能夠高效、無中斷地存取應用程式,且不會遇到問題。
-這與**開發**階段形成鮮明對比,在**開發**階段,你會不斷更改程式碼、破壞程式碼、修復程式碼,然後停止和重新啟動伺服器等。
+這與**開發**階段形成鮮明對比,在**開發**階段,你會不斷更改程式碼、破壞程式碼、修復程式碼,然後停止和重新啟動開發伺服器等。
## 部署策略 { #deployment-strategies }
diff --git a/docs/zh-hant/docs/deployment/manually.md b/docs/zh-hant/docs/deployment/manually.md
new file mode 100644
index 0000000000..bf9f6a93f4
--- /dev/null
+++ b/docs/zh-hant/docs/deployment/manually.md
@@ -0,0 +1,157 @@
+# 手動執行伺服器 { #run-a-server-manually }
+
+## 使用 `fastapi run` 指令 { #use-the-fastapi-run-command }
+
+簡而言之,使用 `fastapi run` 來啟動你的 FastAPI 應用:
+
+
+
+```console
+$ fastapi run main.py
+
+ FastAPI Starting production server 🚀
+
+ Searching for package file structure from directories
+ with __init__.py files
+ Importing from /home/user/code/awesomeapp
+
+ module 🐍 main.py
+
+ code Importing the FastAPI app object from the module with
+ the following code:
+
+ from main import app
+
+ app Using import string: main:app
+
+ server Server started at http://0.0.0.0:8000
+ server Documentation at http://0.0.0.0:8000/docs
+
+ Logs:
+
+ INFO Started server process [2306215]
+ INFO Waiting for application startup.
+ INFO Application startup complete.
+ INFO Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C
+ to quit)
+```
+
+
+
+這在多數情況下都適用。😎
+
+你可以用這個指令在容器、伺服器等環境中啟動你的 FastAPI 應用。
+
+## ASGI 伺服器 { #asgi-servers }
+
+我們再深入一些細節。
+
+FastAPI 採用建立 Python 網頁框架與伺服器的標準
ASGI。FastAPI 是一個 ASGI 網頁框架。
+
+在遠端伺服器機器上執行 FastAPI 應用(或任何 ASGI 應用)所需的關鍵是 ASGI 伺服器程式,例如 Uvicorn;`fastapi` 指令預設就是使用它。
+
+有數個替代方案,包括:
+
+*
Uvicorn:高效能 ASGI 伺服器。
+*
Hypercorn:支援 HTTP/2 與 Trio 等功能的 ASGI 伺服器。
+*
Daphne:為 Django Channels 打造的 ASGI 伺服器。
+*
Granian:針對 Python 應用的 Rust HTTP 伺服器。
+*
NGINX Unit:NGINX Unit 是輕量且多功能的網頁應用執行環境。
+
+## 伺服器機器與伺服器程式 { #server-machine-and-server-program }
+
+有個命名上的小細節請留意。💡
+
+「server(伺服器)」一詞常同時用來指遠端/雲端電腦(實體或虛擬機器),也用來指在該機器上執行的程式(例如 Uvicorn)。
+
+因此看到「server」時,文意可能指這兩者之一。
+
+指涉遠端機器時,常稱為 server、machine、VM(虛擬機器)、node 等,這些都指某種遠端機器(通常執行 Linux),你會在其上執行程式。
+
+## 安裝伺服器程式 { #install-the-server-program }
+
+安裝 FastAPI 時會附帶一個可用於生產環境的伺服器 Uvicorn,你可以用 `fastapi run` 來啟動它。
+
+但你也可以手動安裝 ASGI 伺服器。
+
+請先建立並啟用一個 [虛擬環境](../virtual-environments.md){.internal-link target=_blank},接著再安裝伺服器程式。
+
+例如,安裝 Uvicorn:
+
+
+
+```console
+$ pip install "uvicorn[standard]"
+
+---> 100%
+```
+
+
+
+其他 ASGI 伺服器的安裝流程也大致相同。
+
+/// tip
+
+加入 `standard` 會讓 Uvicorn 安裝並使用一些建議的額外相依套件。
+
+其中包含 `uvloop`,它是 `asyncio` 的高效能替代實作,可大幅提升並行效能。
+
+當你用 `pip install "fastapi[standard]"` 安裝 FastAPI 時,也會一併取得 `uvicorn[standard]`。
+
+///
+
+## 執行伺服器程式 { #run-the-server-program }
+
+如果你是手動安裝 ASGI 伺服器,通常需要提供特定格式的 import 字串,讓它能匯入你的 FastAPI 應用:
+
+
+
+```console
+$ uvicorn main:app --host 0.0.0.0 --port 80
+
+INFO: Uvicorn running on http://0.0.0.0:80 (Press CTRL+C to quit)
+```
+
+
+
+/// note
+
+指令 `uvicorn main:app` 指的是:
+
+* `main`:檔案 `main.py`(Python「模組」)。
+* `app`:在 `main.py` 中以 `app = FastAPI()` 建立的物件。
+
+等同於:
+
+```Python
+from main import app
+```
+
+///
+
+其他 ASGI 伺服器也有類似的指令,詳見各自的文件。
+
+/// warning
+
+Uvicorn 與其他伺服器支援 `--reload` 選項,對開發期間很有幫助。
+
+`--reload` 會消耗更多資源,也較不穩定等。
+
+它在開發階段很實用,但在生產環境中不應使用。
+
+///
+
+## 部署觀念 { #deployment-concepts }
+
+上述範例會啟動伺服器程式(如 Uvicorn),以單一行程在指定連接埠(如 `80`)上監聽所有 IP(`0.0.0.0`)。
+
+這是基本概念。但你很可能還需要處理一些額外事項,例如:
+
+* 安全性 - HTTPS
+* 開機自動啟動
+* 自動重啟
+* 多副本(執行的行程數量)
+* 記憶體
+* 啟動前需要執行的前置步驟
+
+在下一章節我會進一步說明這些觀念、思考方式,以及對應的處理策略與實作範例。🚀
diff --git a/docs/zh-hant/docs/deployment/server-workers.md b/docs/zh-hant/docs/deployment/server-workers.md
new file mode 100644
index 0000000000..56569e49ad
--- /dev/null
+++ b/docs/zh-hant/docs/deployment/server-workers.md
@@ -0,0 +1,139 @@
+# 伺服器工作處理序 - 使用 Uvicorn Workers { #server-workers-uvicorn-with-workers }
+
+我們回顧一下先前提到的部署概念:
+
+* 安全 - HTTPS
+* 系統啟動時執行
+* 重啟
+* **副本(正在執行的處理序數量)**
+* 記憶體
+* 啟動前的前置作業
+
+到目前為止,依照文件中的教學,你大多是透過 `fastapi` 指令啟動一個執行 Uvicorn 的伺服器程式,且只跑單一處理序。
+
+在部署應用時,你通常會希望有一些處理序的複製來善用多核心,並能處理更多請求。
+
+如同前一章關於 [部署概念](concepts.md){.internal-link target=_blank} 所示,你可以採用多種策略。
+
+這裡會示範如何使用 `fastapi` 指令或直接使用 `uvicorn` 指令,搭配 Uvicorn 的工作處理序(worker processes)。
+
+/// info
+
+如果你使用容器(例如 Docker 或 Kubernetes),我會在下一章說明更多:[容器中的 FastAPI - Docker](docker.md){.internal-link target=_blank}。
+
+特別是,在 **Kubernetes** 上執行時,你多半會選擇不要使用 workers,而是每個容器只跑一個 **Uvicorn 單一處理序**。我會在該章節中進一步說明。
+
+///
+
+## 多個工作處理序 { #multiple-workers }
+
+你可以用命令列選項 `--workers` 來啟動多個 workers:
+
+//// tab | `fastapi`
+
+如果你使用 `fastapi` 指令:
+
+
+
+```console
+$ fastapi run --workers 4 main.py
+
+ FastAPI Starting production server 🚀
+
+ Searching for package file structure from directories with
+ __init__.py files
+ Importing from /home/user/code/awesomeapp
+
+ module 🐍 main.py
+
+ code Importing the FastAPI app object from the module with the
+ following code:
+
+ from main import app
+
+ app Using import string: main:app
+
+ server Server started at http://0.0.0.0:8000
+ server Documentation at http://0.0.0.0:8000/docs
+
+ Logs:
+
+ INFO Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to
+ quit)
+ INFO Started parent process [27365]
+ INFO Started server process [27368]
+ INFO Started server process [27369]
+ INFO Started server process [27370]
+ INFO Started server process [27367]
+ INFO Waiting for application startup.
+ INFO Waiting for application startup.
+ INFO Waiting for application startup.
+ INFO Waiting for application startup.
+ INFO Application startup complete.
+ INFO Application startup complete.
+ INFO Application startup complete.
+ INFO Application startup complete.
+```
+
+
+
+////
+
+//// tab | `uvicorn`
+
+如果你偏好直接使用 `uvicorn` 指令:
+
+
+
+```console
+$ uvicorn main:app --host 0.0.0.0 --port 8080 --workers 4
+INFO: Uvicorn running on http://0.0.0.0:8080 (Press CTRL+C to quit)
+INFO: Started parent process [27365]
+INFO: Started server process [27368]
+INFO: Waiting for application startup.
+INFO: Application startup complete.
+INFO: Started server process [27369]
+INFO: Waiting for application startup.
+INFO: Application startup complete.
+INFO: Started server process [27370]
+INFO: Waiting for application startup.
+INFO: Application startup complete.
+INFO: Started server process [27367]
+INFO: Waiting for application startup.
+INFO: Application startup complete.
+```
+
+
+
+////
+
+這裡唯一新增的選項是 `--workers`,告訴 Uvicorn 要啟動 4 個工作處理序。
+
+你也會看到它顯示每個處理序的 **PID**,`27365` 是父處理序(這是**處理序管理器**),另外每個工作處理序各有一個:`27368`、`27369`、`27370`、`27367`。
+
+## 部署概念 { #deployment-concepts }
+
+你已經看到如何使用多個 **workers** 來將應用的執行進行**平行化**,善用 CPU 的**多核心**,並能服務**更多請求**。
+
+在上面的部署概念清單中,使用 workers 主要能幫助到**副本**這一塊,並對**重啟**也有一點幫助,但你仍需要處理其他部分:
+
+* **安全 - HTTPS**
+* **系統啟動時執行**
+* ***重啟***
+* 副本(正在執行的處理序數量)
+* **記憶體**
+* **啟動前的前置作業**
+
+## 容器與 Docker { #containers-and-docker }
+
+在下一章 [容器中的 FastAPI - Docker](docker.md){.internal-link target=_blank} 我會說明一些策略,幫你處理其他的**部署概念**。
+
+我會示範如何**從零建立你的映像檔**來執行單一 Uvicorn 處理序。這個流程相當簡單,而且在使用像 **Kubernetes** 這類分散式容器管理系統時,大多情況也會這麼做。
+
+## 重點回顧 { #recap }
+
+你可以在 `fastapi` 或 `uvicorn` 指令中使用 `--workers` 這個 CLI 選項來啟動多個工作處理序,以善用**多核心 CPU**,**平行**執行多個處理序。
+
+如果你要自行建置**自己的部署系統**,你可以運用這些工具與想法,同時自行處理其他部署概念。
+
+接著看看下一章關於在容器(例如 Docker 與 Kubernetes)中使用 **FastAPI**。你會看到那些工具也有簡單的方法來解決其他**部署概念**。✨
diff --git a/docs/zh-hant/docs/deployment/versions.md b/docs/zh-hant/docs/deployment/versions.md
new file mode 100644
index 0000000000..c4f9c52624
--- /dev/null
+++ b/docs/zh-hant/docs/deployment/versions.md
@@ -0,0 +1,93 @@
+# 關於 FastAPI 版本 { #about-fastapi-versions }
+
+**FastAPI** 已經在許多應用與系統的生產環境中使用,且測試涵蓋率維持在 100%。同時開發仍在快速推進。
+
+經常加入新功能、定期修復錯誤,程式碼也在持續改進。
+
+這就是為什麼目前版本仍為 `0.x.x`,這表示每個版本都可能包含破壞性變更。這遵循
語意化版本(Semantic Versioning) 的慣例。
+
+你現在就可以用 **FastAPI** 建置生產環境的應用(而且你可能已經這麼做一段時間了),只要確保你使用的版本能與其餘程式碼正確相容。
+
+## 鎖定你的 `fastapi` 版本 { #pin-your-fastapi-version }
+
+首先,你應該將你使用的 **FastAPI** 版本「鎖定(pin)」到你知道對你的應用可正常運作的最新特定版本。
+
+例如,假設你的應用使用 `0.112.0` 版本。
+
+如果你使用 `requirements.txt` 檔案,可以這樣指定版本:
+
+```txt
+fastapi[standard]==0.112.0
+```
+
+這表示你會使用完全相同的 `0.112.0` 版本。
+
+或你也可以這樣鎖定:
+
+```txt
+fastapi[standard]>=0.112.0,<0.113.0
+```
+
+這表示會使用 `0.112.0`(含)以上但小於 `0.113.0` 的版本,例如 `0.112.2` 也會被接受。
+
+如果你使用其他安裝管理工具,例如 `uv`、Poetry、Pipenv 等,它們也都有可用來指定套件特定版本的方法。
+
+## 可用版本 { #available-versions }
+
+你可以在 [發行說明](../release-notes.md){.internal-link target=_blank} 查看可用版本(例如用來確認目前最新版本)。
+
+## 關於版本 { #about-versions }
+
+依照語意化版本的慣例,任何低於 `1.0.0` 的版本都可能加入破壞性變更。
+
+FastAPI 也遵循慣例:任何「PATCH」版本變更僅用於修正錯誤與非破壞性變更。
+
+/// tip
+
+「PATCH」是最後一個數字,例如在 `0.2.3` 中,PATCH 版本是 `3`。
+
+///
+
+因此,你可以將版本鎖定為如下形式:
+
+```txt
+fastapi>=0.45.0,<0.46.0
+```
+
+破壞性變更與新功能會在「MINOR」版本加入。
+
+/// tip
+
+「MINOR」是中間的數字,例如在 `0.2.3` 中,MINOR 版本是 `2`。
+
+///
+
+## 升級 FastAPI 版本 { #upgrading-the-fastapi-versions }
+
+你應該為你的應用撰寫測試。
+
+在 **FastAPI** 中這很容易(感謝 Starlette),請參考文件:[測試](../tutorial/testing.md){.internal-link target=_blank}
+
+有了測試之後,你就可以將 **FastAPI** 升級到較新的版本,並透過執行測試來確保所有程式碼都能正確運作。
+
+如果一切正常,或在完成必要調整且所有測試通過之後,就可以把你的 `fastapi` 鎖定到該新的版本。
+
+## 關於 Starlette { #about-starlette }
+
+你不應鎖定 `starlette` 的版本。
+
+不同的 **FastAPI** 版本會使用特定較新的 Starlette 版本。
+
+因此,你可以直接讓 **FastAPI** 使用正確的 Starlette 版本。
+
+## 關於 Pydantic { #about-pydantic }
+
+Pydantic 在其測試中涵蓋了 **FastAPI** 的測試,因此 Pydantic 的新版本(高於 `1.0.0`)一律與 FastAPI 相容。
+
+你可以將 Pydantic 鎖定到任何高於 `1.0.0`、適合你的版本。
+
+例如:
+
+```txt
+pydantic>=2.7.0,<3.0.0
+```
diff --git a/docs/zh-hant/docs/fastapi-cli.md b/docs/zh-hant/docs/fastapi-cli.md
index b107e7e73f..57b5ec98f2 100644
--- a/docs/zh-hant/docs/fastapi-cli.md
+++ b/docs/zh-hant/docs/fastapi-cli.md
@@ -1,4 +1,4 @@
-# FastAPI CLI
+# FastAPI CLI { #fastapi-cli }
**FastAPI CLI** 是一個命令列程式,能用來運行你的 FastAPI 應用程式、管理你的 FastAPI 專案等。
@@ -9,72 +9,64 @@
```console
-$ fastapi dev main.py
-INFO Using path main.py
-INFO Resolved absolute path /home/user/code/awesomeapp/main.py
-INFO Searching for package file structure from directories with __init__.py files
-INFO Importing from /home/user/code/awesomeapp
-
- ╭─ Python module file ─╮
- │ │
- │ 🐍 main.py │
- │ │
- ╰──────────────────────╯
-
-INFO Importing module main
-INFO Found importable FastAPI app
-
- ╭─ Importable FastAPI app ─╮
- │ │
- │ from main import app │
- │ │
- ╰──────────────────────────╯
-
-INFO Using import string main:app
-
- ╭────────── FastAPI CLI - Development mode ───────────╮
- │ │
- │ Serving at: http://127.0.0.1:8000 │
- │ │
- │ API docs: http://127.0.0.1:8000/docs │
- │ │
- │ Running in development mode, for production use: │
- │ │
- │ fastapi run │
- │ │
- ╰─────────────────────────────────────────────────────╯
-
-INFO: Will watch for changes in these directories: ['/home/user/code/awesomeapp']
-INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
-INFO: Started reloader process [2265862] using WatchFiles
-INFO: Started server process [2265873]
-INFO: Waiting for application startup.
-INFO: Application startup complete.
+$ fastapi dev main.py
+
+ FastAPI Starting development server 🚀
+
+ Searching for package file structure from directories with
+ __init__.py files
+ Importing from /home/user/code/awesomeapp
+
+ module 🐍 main.py
+
+ code Importing the FastAPI app object from the module with the
+ following code:
+
+ from main import app
+
+ app Using import string: main:app
+
+ server Server started at http://127.0.0.1:8000
+ server Documentation at http://127.0.0.1:8000/docs
+
+ tip Running in development mode, for production use:
+ fastapi run
+
+ Logs:
+
+ INFO Will watch for changes in these directories:
+ ['/home/user/code/awesomeapp']
+ INFO Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to
+ quit)
+ INFO Started reloader process [383138] using WatchFiles
+ INFO Started server process [383153]
+ INFO Waiting for application startup.
+ INFO Application startup complete.
```
-`fastapi` 命令列程式就是 **FastAPI CLI**。
+名為 `fastapi` 的命令列程式就是 **FastAPI CLI**。
-FastAPI CLI 接收你的 Python 程式路徑(例如 `main.py`),並自動檢測 FastAPI 實例(通常命名為 `app`),確定正確的引入模組流程,然後運行該應用程式。
+FastAPI CLI 接收你的 Python 程式路徑(例如 `main.py`),並自動檢測 `FastAPI` 實例(通常命名為 `app`),確定正確的引入模組流程,然後運行該應用程式。
在生產環境,你應該使用 `fastapi run` 命令。 🚀
**FastAPI CLI** 內部使用了
Uvicorn,這是一個高效能、適合生產環境的 ASGI 伺服器。 😎
-## `fastapi dev`
+## `fastapi dev` { #fastapi-dev }
執行 `fastapi dev` 會啟動開發模式。
預設情況下,**auto-reload** 功能是啟用的,當你對程式碼進行修改時,伺服器會自動重新載入。這會消耗較多資源,並且可能比禁用時更不穩定。因此,你應該只在開發環境中使用此功能。它也會在 IP 位址 `127.0.0.1` 上監聽,這是用於你的機器與自身通訊的 IP 位址(`localhost`)。
-## `fastapi run`
+## `fastapi run` { #fastapi-run }
執行 `fastapi run` 會以生產模式啟動 FastAPI。
-預設情況下,**auto-reload** 功能是禁用的。它也會在 IP 位址 `0.0.0.0` 上監聽,表示會監聽所有可用的 IP 地址,這樣任何能與該機器通訊的人都可以公開存取它。這通常是你在生產環境中運行應用程式的方式,例如在容器中運行時。
+預設情況下,**auto-reload** 功能是禁用的。它也會在 IP 位址 `0.0.0.0` 上監聽,表示會監聽所有可用的 IP 位址,這樣任何能與該機器通訊的人都可以公開存取它。這通常是你在生產環境中運行應用程式的方式,例如在容器中運行時。
-在大多數情況下,你會(也應該)有一個「終止代理」來處理 HTTPS,這取決於你如何部署你的應用程式,你的服務供應商可能會為你做這件事,或者你需要自己設置它。
+在大多數情況下,你會(也應該)有一個「終止代理」在外層幫你處理 HTTPS;這取決於你如何部署應用程式,你的服務供應商可能會幫你處理,或者你需要自己設置。
/// tip
diff --git a/docs/zh-hant/docs/features.md b/docs/zh-hant/docs/features.md
index f44d28a7f8..77c0203073 100644
--- a/docs/zh-hant/docs/features.md
+++ b/docs/zh-hant/docs/features.md
@@ -1,17 +1,17 @@
-# 特性
+# 特性 { #features }
-## FastAPI 特性
+## FastAPI 特性 { #fastapi-features }
-**FastAPI** 提供了以下内容:
+**FastAPI** 提供了以下內容:
-### 建立在開放標準的基礎上
+### 建立在開放標準的基礎上 { #based-on-open-standards }
-* 使用
OpenAPI 來建立 API,包含
路徑操作、參數、請求內文、安全性等聲明。
+* 使用
OpenAPI 來建立 API,包含
路徑、
操作、參數、請求內文、安全性等宣告。
* 使用
JSON Schema(因為 OpenAPI 本身就是基於 JSON Schema)自動生成資料模型文件。
* 經過縝密的研究後圍繞這些標準進行設計,而不是事後在已有系統上附加的一層功能。
* 這也讓我們在多種語言中可以使用自動**用戶端程式碼生成**。
-### 能夠自動生成文件
+### 能夠自動生成文件 { #automatic-docs }
FastAPI 能生成互動式 API 文件和探索性的 Web 使用者介面。由於該框架基於 OpenAPI,因此有多種選擇,預設提供了兩種。
@@ -19,12 +19,11 @@ FastAPI 能生成互動式 API 文件和探索性的 Web 使用者介面。由

-*
ReDoc 提供結構性的文件,讓你可以在瀏覽器中查看。
+* 使用
ReDoc 的替代 API 文件。

-
-### 現代 Python
+### 現代 Python { #just-modern-python }
這一切都基於標準的 **Python 型別**宣告(感謝 Pydantic)。無需學習新的語法,只需使用標準的現代 Python。
@@ -32,7 +31,7 @@ FastAPI 能生成互動式 API 文件和探索性的 Web 使用者介面。由
如果你寫帶有 Python 型別的程式碼:
-```python
+```Python
from datetime import date
from pydantic import BaseModel
@@ -50,10 +49,9 @@ class User(BaseModel):
joined: date
```
-
可以像這樣來使用:
-```python
+```Python
my_user: User = User(id=3, name="John Doe", joined="2018-07-19")
second_user_data = {
@@ -65,7 +63,6 @@ second_user_data = {
my_second_user: User = User(**second_user_data)
```
-
/// info
`**second_user_data` 意思是:
@@ -74,11 +71,11 @@ my_second_user: User = User(**second_user_data)
///
-### 多種編輯器支援
+### 多種編輯器支援 { #editor-support }
整個框架的設計是為了讓使用變得簡單且直觀,在開始開發之前,所有決策都在多個編輯器上進行了測試,以確保提供最佳的開發體驗。
-在最近的 Python 開發者調查中,我們能看到
被使用最多的功能是 autocompletion,此功能可以預測將要輸入文字,並自動補齊。
+在最近的 Python 開發者調查中,我們能看到
被使用最多的功能是 autocompletion。
整個 **FastAPI** 框架就是基於這一點,任何地方都可以進行自動補齊。
@@ -86,11 +83,11 @@ my_second_user: User = User(**second_user_data)
在這裡,你的編輯器可能會這樣幫助你:
-*
Visual Studio Code 中:
+* 在
Visual Studio Code 中:

-*
PyCharm 中:
+* 在
PyCharm 中:

@@ -98,17 +95,13 @@ my_second_user: User = User(**second_user_data)
這樣比較不會輸錯鍵名,不用來回翻看文件,也不用來回滾動尋找你最後使用的 `username` 或者 `user_name`。
-
-
-### 簡潔
+### 簡潔 { #short }
FastAPI 為你提供了**預設值**,讓你不必在初期進行繁瑣的配置,一切都可以自動運作。如果你有更具體的需求,則可以進行調整和自定義,
-但在大多數情況下,你只需要直接使用預設值,就能順利完成 API 開發。
+但預設情況下,一切都「直接可用」。
-### 驗證
-
-所有的驗證都由完善且強大的 **Pydantic** 處理。
+### 驗證 { #validation }
* 驗證大部分(甚至所有?)的 Python **資料型別**,包括:
* JSON 物件 (`dict`)。
@@ -120,9 +113,11 @@ FastAPI 為你提供了**預設值**,讓你不必在初期進行繁瑣的配
* URL
* Email
* UUID
+ * ...等等。
+所有的驗證都由完善且強大的 **Pydantic** 處理。
-### 安全性及身份驗證
+### 安全性及身份驗證 { #security-and-authentication }
FastAPI 已經整合了安全性和身份驗證的功能,但不會強制與特定的資料庫或資料模型進行綁定。
@@ -139,10 +134,9 @@ OpenAPI 中定義的安全模式,包括:
所有的這些都是可重複使用的工具和套件,可以輕鬆與你的系統、資料儲存(Data Stores)、關聯式資料庫(RDBMS)以及非關聯式資料庫(NoSQL)等等整合。
+### 依賴注入(Dependency Injection) { #dependency-injection }
-### 依賴注入(Dependency Injection)
-
-FastAPI 有一個使用簡單,但是非常強大的
依賴注入系統。
+FastAPI 有一個使用簡單,但是非常強大的
依賴注入 系統。
* 依賴項甚至可以有自己的依賴,從而形成一個層級或**依賴圖**的結構。
* 所有**自動化處理**都由框架完成。
@@ -151,23 +145,21 @@ FastAPI 有一個使用簡單,但是非常強大的
Pydantic。所以,你有其他 Pydantic 程式碼也能正常工作。
-相容包括基於 Pydantic 的外部函式庫, 例如用於資料庫的 ORMs, ODMs。
+相容包括基於 Pydantic 的外部函式庫,例如用於資料庫的 ORMs、ODMs。
這也意味著在很多情況下,你可以把從請求中獲得的物件**直接傳到資料庫**,因為所有資料都會自動進行驗證。
@@ -196,7 +188,7 @@ FastAPI 有一個使用簡單,但是非常強大的發一則關於 **FastAPI** 的推文,讓我與其他人知道你為什麼喜歡它。🎉
+
+我很樂於聽到 **FastAPI** 是如何被使用、你喜歡它的哪些地方、在哪個專案/公司使用它等等。
+
+## 為 FastAPI 投票 { #vote-for-fastapi }
+
+* 在 Slant 為 **FastAPI** 投票。
+* 在 AlternativeTo 為 **FastAPI** 投票。
+* 在 StackShare 表示你使用 **FastAPI**。
+
+## 在 GitHub 幫助他人解答問題 { #help-others-with-questions-in-github }
+
+你可以嘗試幫助他人回答以下地方的問題:
+
+* GitHub Discussions
+* GitHub Issues
+
+很多時候你可能已經知道這些問題的解答。🤓
+
+如果你經常幫大家解決問題,你會成為官方的 [FastAPI 專家](fastapi-people.md#fastapi-experts){.internal-link target=_blank}。🎉
+
+請記得,最重要的是:盡量友善。大家可能帶著挫折而來,很多時候提問方式不夠理想,但請盡你所能保持友善。🤗
+
+**FastAPI** 社群的理念是友善且歡迎大家。同時,也不要接受霸凌或對他人不尊重的行為。我們要彼此照顧。
+
+---
+
+以下是在(Discussions 或 Issues)中幫助他人解決問題的方式:
+
+### 先理解問題 { #understand-the-question }
+
+* 先確認你是否能理解提問者的**目的**與使用情境。
+
+* 接著看看問題(絕大多數是提問)是否**清楚**。
+
+* 很多時候,提問是基於使用者自己想像中的解法,但可能有**更好**的方法。如果你能更理解他們的問題與使用情境,你也許能提出更好的**替代解法**。
+
+* 如果你無法理解問題,請要求提供更多**細節**。
+
+### 重現問題 { #reproduce-the-problem }
+
+在大多數情況與問題中,都會與對方的**原始程式碼**有關。
+
+很多時候他們只會貼出一小段程式碼,但那不足以**重現問題**。
+
+* 你可以請他們提供一個最小可重現範例,讓你可以**複製貼上**並在本機執行,看到與他們相同的錯誤或行為,或更好地理解他們的使用情境。
+
+* 如果你有心力,你也可以嘗試自己**建立一個範例**,僅依據問題描述來還原。不過請記得這可能很耗時,或許更好的是先請他們把問題說清楚。
+
+### 提出解法建議 { #suggest-solutions }
+
+* 在能夠理解問題後,你可以給出可能的**答案**。
+
+* 很多時候,最好能理解他們的**底層問題或使用情境**,因為可能有比他們嘗試的方法更好的解決之道。
+
+### 請求關閉議題 { #ask-to-close }
+
+如果他們回覆了,你很可能已經解決了他們的問題,恭喜,**你是英雄**!🦸
+
+* 現在,如果問題已解決,你可以請他們:
+ * 在 GitHub Discussions:把某則留言標記為**答案**。
+ * 在 GitHub Issues:**關閉**該 issue。
+
+## 追蹤 GitHub 儲存庫 { #watch-the-github-repository }
+
+你可以在 GitHub「watch」FastAPI(點擊右上角的「watch」按鈕):https://github.com/fastapi/fastapi。👀
+
+如果你選擇「Watching」而不是「Releases only」,當有人建立新的 issue 或問題時你會收到通知。你也可以指定只想被通知新的 issues、discussions、PR 等等。
+
+接著你就可以嘗試幫忙解決那些問題。
+
+## 提問 { #ask-questions }
+
+你可以在 GitHub 儲存庫建立一個新的問題(Question),例如用來:
+
+* 提出**問題**或詢問某個**疑難**。
+* 建議一個新的**功能**。
+
+**注意**:如果你這麼做,那我也會請你去幫助其他人。😉
+
+## 審核 Pull Request { #review-pull-requests }
+
+你可以幫我審查他人的 Pull Request。
+
+再強調一次,請盡量保持友善。🤗
+
+---
+
+以下是審查 Pull Request 時需要注意與如何進行:
+
+### 先理解要解的問題 { #understand-the-problem }
+
+* 首先,確認你**理解了該 Pull Request 想解決的問題**。可能在 GitHub Discussion 或 issue 中有更長的討論。
+
+* 也很有可能這個 Pull Request 其實不需要,因為問題可以用**不同的方法**解決。那你就可以提出或詢問那個方向。
+
+### 不用太在意風格 { #dont-worry-about-style }
+
+* 不要太擔心像是提交訊息(commit message)的風格,我會用 squash and merge 並手動調整提交內容。
+
+* 也不用太在意程式碼風格規範,已經有自動化工具在檢查。
+
+如果還有其他風格或一致性的需求,我會直接提出請求,或是在上面再補上需要的修改提交。
+
+### 檢查程式碼 { #check-the-code }
+
+* 檢查並閱讀程式碼,看看是否合理,**在本機執行**並確認它是否真的解決了問題。
+
+* 然後**留言**說你做了這些,這樣我才知道你真的檢查過了。
+
+/// info
+
+很遺憾,我不能僅因為一個 PR 有好幾個核可就直接信任它。
+
+發生過好幾次,PR 有 3、5 個甚至更多核可,可能是因為描述很吸引人,但當我實際檢查時,它其實是壞的、有 bug,或是根本沒有解決它宣稱要解決的問題。😅
+
+所以,真的很重要的是你要實際閱讀並執行程式碼,並在留言中讓我知道你做過了。🤓
+
+///
+
+* 如果 PR 有機會再被簡化,你可以提出要求,但沒必要太過挑剔,很多事情是主觀的(我自己也會有主觀看法 🙈),所以最好聚焦在關鍵的事情上。
+
+### 測試 { #tests }
+
+* 幫我確認 PR 有**測試**。
+
+* 檢查在 PR 之前,測試會**失敗**。🚨
+
+* 然後檢查在 PR 之後,測試會**通過**。✅
+
+* 很多 PR 並沒有測試,你可以**提醒**他們加上測試,或甚至**建議**一些測試。這是最花時間的事之一,而你可以在這方面幫上很大的忙。
+
+* 接著也請留言你嘗試了什麼,這樣我就知道你有檢查過。🤓
+
+## 建立 Pull Request { #create-a-pull-request }
+
+你可以透過 Pull Request 來[貢獻](contributing.md){.internal-link target=_blank}原始碼,例如:
+
+* 修正文檔中你發現的錯字。
+* 分享你建立或發現的 FastAPI 相關文章、影片或 podcast,方法是編輯這個檔案。
+ * 請確保把你的連結加到對應章節的開頭。
+* 協助把[文件翻譯](contributing.md#translations){.internal-link target=_blank}成你的語言。
+ * 你也可以幫忙審查他人提交的翻譯。
+* 提議新的文件章節。
+* 修復既有的 issue/bug。
+ * 記得要加上測試。
+* 新增一個功能。
+ * 記得要加上測試。
+ * 若相關,請記得補上文件。
+
+## 協助維護 FastAPI { #help-maintain-fastapi }
+
+幫我一起維護 **FastAPI**!🤓
+
+有很多事情要做,而其中大多數其實**你**就能完成。
+
+你現在就能做的主要任務有:
+
+* [在 GitHub 幫助他人解答問題](#help-others-with-questions-in-github){.internal-link target=_blank}(見上方章節)。
+* [審核 Pull Request](#review-pull-requests){.internal-link target=_blank}(見上方章節)。
+
+這兩件事是**最耗時**的。這也是維護 FastAPI 的主要工作。
+
+如果你能在這方面幫我,**你就是在幫我維護 FastAPI**,並確保它能**更快更好地前進**。🚀
+
+## 加入聊天室 { #join-the-chat }
+
+加入 👥 Discord 聊天伺服器 👥,與 FastAPI 社群的其他人一起交流。
+
+/// tip
+
+若要提問,請到 GitHub Discussions,在那裡更有機會獲得[FastAPI 專家](fastapi-people.md#fastapi-experts){.internal-link target=_blank}的協助。
+
+聊天室請僅用於其他一般性的交流。
+
+///
+
+### 不要在聊天室提問 { #dont-use-the-chat-for-questions }
+
+請記得,由於聊天室允許較「自由的對話」,很容易提出過於籠統、較難回答的問題,因此你可能不會得到答案。
+
+在 GitHub 上,模板會引導你寫出合適的提問,讓你更容易得到好的解答,甚至在提問前就自己解決問題。而且在 GitHub 上,我能確保最終都會回覆(即使需要一些時間)。我個人無法在聊天系統做到這一點。😅
+
+聊天系統中的對話也不像 GitHub 那樣容易被搜尋,因此問題與答案可能在對話中淹沒。而且只有 GitHub 上的問題與回答才會被計入成為[FastAPI 專家](fastapi-people.md#fastapi-experts){.internal-link target=_blank},因此你在 GitHub 上更有機會獲得關注。
+
+另一方面,聊天室裡有成千上萬的使用者,所以幾乎隨時都有很大的機會能找到人聊天。😄
+
+## 贊助作者 { #sponsor-the-author }
+
+如果你的**產品/公司**依賴或與 **FastAPI** 相關,且你想觸及它的使用者,你可以透過 GitHub sponsors 贊助作者(我)。依據不同級別,你可能會得到一些額外福利,例如在文件中顯示徽章。🎁
+
+---
+
+感謝!🚀
diff --git a/docs/zh-hant/docs/history-design-future.md b/docs/zh-hant/docs/history-design-future.md
new file mode 100644
index 0000000000..b7f57a3636
--- /dev/null
+++ b/docs/zh-hant/docs/history-design-future.md
@@ -0,0 +1,79 @@
+# 歷史、設計與未來 { #history-design-and-future }
+
+不久之前,一位 **FastAPI** 使用者提問:
+
+> 這個專案的歷史是什麼?看起來它在短短幾週內從默默無名變得非常厲害 [...]
+
+以下是其中一小段歷史。
+
+## 替代方案 { #alternatives }
+
+多年來我一直在打造具有複雜需求的 API(機器學習、分散式系統、非同步工作、NoSQL 資料庫等),並帶領多個開發團隊。
+
+在此過程中,我需要調查、測試並使用許多替代方案。
+
+**FastAPI** 的歷史,在很大程度上也是其前身工具的歷史。
+
+如在[替代方案](alternatives.md){.internal-link target=_blank}章節所述:
+
+
+
+若沒有他人的前期成果,就不會有 **FastAPI**。
+
+先前已有許多工具啟發了它的誕生。
+
+我曾經多年避免再去打造一個新框架。起初我嘗試用各種不同的框架、外掛與工具,來滿足 **FastAPI** 涵蓋的所有功能。
+
+但在某個時刻,別無選擇,只能打造一個同時提供所有這些功能的東西,取過去工具之長,並以可能的最佳方式加以結合,還運用了以往甚至不存在的語言功能(Python 3.6+ 的型別提示)。
+
+
+
+## 調研 { #investigation }
+
+透過實際使用這些替代方案,我得以向它們學習、汲取想法,並以我能為自己與合作開發團隊找到的最佳方式加以整合。
+
+例如,很清楚理想上應以標準的 Python 型別提示為基礎。
+
+同時,最佳做法就是採用現有標準。
+
+因此,在開始撰寫 **FastAPI** 之前,我花了好幾個月研究 OpenAPI、JSON Schema、OAuth2 等規範,了解它們之間的關係、重疊與差異。
+
+## 設計 { #design }
+
+接著,我花時間設計作為使用者(作為使用 FastAPI 的開發者)時希望擁有的開發者「API」。
+
+我在最受歡迎的 Python 編輯器中測試了多個想法:PyCharm、VS Code、基於 Jedi 的編輯器。
+
+根據最新的 Python 開發者調查,這些工具涵蓋約 80% 的使用者。
+
+這表示 **FastAPI** 已針對 80% 的 Python 開發者所使用的編輯器進行過專門測試。而由於其他多數編輯器的行為也類似,這些優點幾乎在所有編輯器上都能生效。
+
+藉此我找到了盡可能減少程式碼重複、在各處提供自動補全、型別與錯誤檢查等的最佳方式。
+
+一切都是為了讓所有開發者都能擁有最佳的開發體驗。
+
+## 需求 { #requirements }
+
+在測試多種替代方案後,我決定採用 **Pydantic**,因為它的優勢。
+
+隨後我也對它做出貢獻,使其完全符合 JSON Schema、支援以不同方式定義約束,並依據在多款編輯器中的測試結果改進編輯器支援(型別檢查、自動補全)。
+
+在開發過程中,我也對 **Starlette**(另一個關鍵依賴)做出貢獻。
+
+## 開發 { #development }
+
+當我開始著手實作 **FastAPI** 本身時,多數拼圖已經就緒,設計已定,需求與工具已備齊,對各項標準與規範的理解也清晰且新鮮。
+
+## 未來 { #future }
+
+到目前為止,**FastAPI** 及其理念已經對許多人有幫助。
+
+相較先前的替代方案,它更適合許多使用情境,因而被選用。
+
+許多開發者與團隊(包括我和我的團隊)已經在他們的專案中依賴 **FastAPI**。
+
+但仍有許多改進與功能即將到來。
+
+**FastAPI** 的前景非常光明。
+
+也非常感謝[你的幫助](help-fastapi.md){.internal-link target=_blank}。
diff --git a/docs/zh-hant/docs/how-to/authentication-error-status-code.md b/docs/zh-hant/docs/how-to/authentication-error-status-code.md
new file mode 100644
index 0000000000..9a8de4c910
--- /dev/null
+++ b/docs/zh-hant/docs/how-to/authentication-error-status-code.md
@@ -0,0 +1,15 @@
+# 使用舊的 403 身分驗證錯誤狀態碼 { #use-old-403-authentication-error-status-codes }
+
+在 FastAPI 版本 `0.122.0` 之前,當內建的安全工具在身分驗證失敗後回傳錯誤給用戶端時,會使用 HTTP 狀態碼 `403 Forbidden`。
+
+從 FastAPI 版本 `0.122.0` 起,改為使用更合適的 HTTP 狀態碼 `401 Unauthorized`,並在回應中依據 HTTP 規範加上合理的 `WWW-Authenticate` 標頭,參考 RFC 7235、RFC 9110。
+
+但如果你的用戶端因某些原因依賴於舊行為,你可以在你的 security 類別中覆寫 `make_not_authenticated_error` 方法以恢復舊的行為。
+
+例如,你可以建立 `HTTPBearer` 的子類別,讓它回傳 `403 Forbidden` 錯誤,而不是預設的 `401 Unauthorized` 錯誤:
+
+{* ../../docs_src/authentication_error_status_code/tutorial001_an_py310.py hl[9:13] *}
+
+/// tip
+注意這個函式回傳的是例外物件本身,而不是直接拋出它。拋出的動作會在其餘的內部程式碼中處理。
+///
diff --git a/docs/zh-hant/docs/how-to/conditional-openapi.md b/docs/zh-hant/docs/how-to/conditional-openapi.md
new file mode 100644
index 0000000000..5c091e5b7b
--- /dev/null
+++ b/docs/zh-hant/docs/how-to/conditional-openapi.md
@@ -0,0 +1,56 @@
+# 條件式 OpenAPI { #conditional-openapi }
+
+如果需要,你可以用設定與環境變數,依據執行環境有條件地調整 OpenAPI,甚至完全停用它。
+
+## 關於安全性、API 與文件 { #about-security-apis-and-docs }
+
+在正式環境中隱藏文件 UI *不應該* 是用來保護 API 的方式。
+
+這並不會為你的 API 增添任何額外的安全性,*路徑操作* 仍舊照常可用。
+
+若你的程式碼有安全性缺陷,它依然會存在。
+
+隱藏文件只會讓他人更難理解如何與你的 API 互動,也可能讓你在正式環境除錯更困難。這通常僅被視為一種 以隱匿求安全。
+
+如果你想保護 API,有許多更好的作法,例如:
+
+- 確保針對請求本文與回應,具備定義良好的 Pydantic 模型。
+- 透過依賴設定所需的權限與角色。
+- 切勿儲存明文密碼,只儲存密碼雜湊。
+- 實作並使用成熟且廣為人知的密碼學工具,例如 pwdlib 與 JWT 權杖等。
+- 視需要以 OAuth2 scopes 新增更細緻的權限控管。
+- ...等。
+
+儘管如此,在某些特定情境下,你可能確實需要在某些環境(例如正式環境)停用 API 文件,或依據環境變數的設定來決定是否啟用。
+
+## 透過設定與環境變數的條件式 OpenAPI { #conditional-openapi-from-settings-and-env-vars }
+
+你可以用相同的 Pydantic 設定,來配置產生的 OpenAPI 與文件 UI。
+
+例如:
+
+{* ../../docs_src/conditional_openapi/tutorial001_py310.py hl[6,11] *}
+
+這裡我們宣告 `openapi_url` 設定,預設值同樣是 `"/openapi.json"`。
+
+接著在建立 `FastAPI` 應用時使用它。
+
+然後你可以將環境變數 `OPENAPI_URL` 設為空字串,以停用 OpenAPI(包含文件 UI),如下:
+
+
+
+```console
+$ OPENAPI_URL= uvicorn main:app
+
+INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
+```
+
+
+
+之後若你造訪 `/openapi.json`、`/docs` 或 `/redoc`,會看到如下的 `404 Not Found` 錯誤:
+
+```JSON
+{
+ "detail": "Not Found"
+}
+```
diff --git a/docs/zh-hant/docs/how-to/configure-swagger-ui.md b/docs/zh-hant/docs/how-to/configure-swagger-ui.md
new file mode 100644
index 0000000000..e5b6d7d1e3
--- /dev/null
+++ b/docs/zh-hant/docs/how-to/configure-swagger-ui.md
@@ -0,0 +1,70 @@
+# 設定 Swagger UI { #configure-swagger-ui }
+
+你可以設定一些額外的 Swagger UI 參數。
+
+要設定它們,建立 `FastAPI()` 應用物件時,或呼叫 `get_swagger_ui_html()` 函式時,傳入參數 `swagger_ui_parameters`。
+
+`swagger_ui_parameters` 接受一個 dict,內容會直接傳給 Swagger UI 作為設定。
+
+FastAPI 會把這些設定轉換成 JSON,以便與 JavaScript 相容,因為 Swagger UI 需要的是這種格式。
+
+## 停用語法醒目提示 { #disable-syntax-highlighting }
+
+例如,你可以在 Swagger UI 中停用語法醒目提示(syntax highlighting)。
+
+不更動設定時,語法醒目提示預設為啟用:
+
+
+
+但你可以將 `syntaxHighlight` 設為 `False` 來停用它:
+
+{* ../../docs_src/configure_swagger_ui/tutorial001_py310.py hl[3] *}
+
+...然後 Swagger UI 就不會再顯示語法醒目提示:
+
+
+
+## 更換主題 { #change-the-theme }
+
+同樣地,你可以用鍵 `"syntaxHighlight.theme"` 設定語法醒目提示主題(注意中間有一個點):
+
+{* ../../docs_src/configure_swagger_ui/tutorial002_py310.py hl[3] *}
+
+這個設定會變更語法醒目提示的配色主題:
+
+
+
+## 更改預設的 Swagger UI 參數 { #change-default-swagger-ui-parameters }
+
+FastAPI 內建一些預設參數,適用於大多數情境。
+
+包含以下預設設定:
+
+{* ../../fastapi/openapi/docs.py ln[9:24] hl[18:24] *}
+
+你可以在 `swagger_ui_parameters` 參數中提供不同的值來覆蓋其中任一項。
+
+例如,要停用 `deepLinking`,可以在 `swagger_ui_parameters` 傳入以下設定:
+
+{* ../../docs_src/configure_swagger_ui/tutorial003_py310.py hl[3] *}
+
+## 其他 Swagger UI 參數 { #other-swagger-ui-parameters }
+
+若要查看所有可用的設定,請參考官方的 Swagger UI 參數文件。
+
+## 僅限 JavaScript 的設定 { #javascript-only-settings }
+
+Swagger UI 也允許某些設定是僅限 JavaScript 的物件(例如 JavaScript 函式)。
+
+FastAPI 也包含以下僅限 JavaScript 的 `presets` 設定:
+
+```JavaScript
+presets: [
+ SwaggerUIBundle.presets.apis,
+ SwaggerUIBundle.SwaggerUIStandalonePreset
+]
+```
+
+這些是 JavaScript 物件,而不是字串,因此無法直接從 Python 程式碼傳遞。
+
+若需要使用這類僅限 JavaScript 的設定,你可以使用上面介紹的方法:覆寫所有 Swagger UI 的路徑操作(path operation),並手動撰寫所需的 JavaScript。
diff --git a/docs/zh-hant/docs/how-to/custom-docs-ui-assets.md b/docs/zh-hant/docs/how-to/custom-docs-ui-assets.md
new file mode 100644
index 0000000000..4b53945891
--- /dev/null
+++ b/docs/zh-hant/docs/how-to/custom-docs-ui-assets.md
@@ -0,0 +1,185 @@
+# 自訂文件 UI 靜態資源(自我託管) { #custom-docs-ui-static-assets-self-hosting }
+
+API 文件使用 Swagger UI 與 ReDoc,它們各自需要一些 JavaScript 與 CSS 檔案。
+
+預設情況下,這些檔案會從 CDN 提供。
+
+但你可以自訂:你可以指定特定的 CDN,或自行提供這些檔案。
+
+## 為 JavaScript 和 CSS 使用自訂 CDN { #custom-cdn-for-javascript-and-css }
+
+假設你想使用不同的 CDN,例如使用 `https://unpkg.com/`。
+
+若你所在的國家限制部分網址,這會很有用。
+
+### 停用自動產生的文件 { #disable-the-automatic-docs }
+
+第一步是停用自動文件,因為預設會使用預設的 CDN。
+
+要停用它們,建立 `FastAPI` 應用時把相關 URL 設為 `None`:
+
+{* ../../docs_src/custom_docs_ui/tutorial001_py310.py hl[8] *}
+
+### 加入自訂文件 { #include-the-custom-docs }
+
+現在你可以為自訂文件建立「路徑操作(path operation)」。
+
+你可以重用 FastAPI 的內部函式來建立文件的 HTML 頁面,並傳入所需參數:
+
+* `openapi_url`:文件 HTML 頁面用來取得你 API 的 OpenAPI schema 的 URL。可使用屬性 `app.openapi_url`。
+* `title`:你的 API 標題。
+* `oauth2_redirect_url`:可使用 `app.swagger_ui_oauth2_redirect_url` 以沿用預設值。
+* `swagger_js_url`:Swagger UI 文件 HTML 用來取得「JavaScript」檔案的 URL。這是你的自訂 CDN 位址。
+* `swagger_css_url`:Swagger UI 文件 HTML 用來取得「CSS」檔案的 URL。這是你的自訂 CDN 位址。
+
+ReDoc 也類似...
+
+{* ../../docs_src/custom_docs_ui/tutorial001_py310.py hl[2:6,11:19,22:24,27:33] *}
+
+/// tip
+
+當你使用 OAuth2 時,`swagger_ui_redirect` 的路徑操作是個輔助端點。
+
+如果你把 API 與 OAuth2 提供者整合,便能完成認證並帶著取得的憑證回到 API 文件,接著以真正的 OAuth2 驗證與之互動。
+
+Swagger UI 會在背後幫你處理,不過它需要這個「redirect」輔助端點。
+
+///
+
+### 建立路徑操作以進行測試 { #create-a-path-operation-to-test-it }
+
+現在,為了測試一切是否正常,建立一個路徑操作:
+
+{* ../../docs_src/custom_docs_ui/tutorial001_py310.py hl[36:38] *}
+
+### 測試 { #test-it }
+
+現在你應該能造訪 http://127.0.0.1:8000/docs,重新載入頁面後,資源會從新的 CDN 載入。
+
+## 自行託管文件所需的 JavaScript 與 CSS { #self-hosting-javascript-and-css-for-docs }
+
+若你需要應用在離線、無公共網路或僅在區域網路中也能運作,自行託管 JavaScript 與 CSS 會很實用。
+
+以下示範如何在同一個 FastAPI 應用中自行提供這些檔案,並設定文件使用它們。
+
+### 專案檔案結構 { #project-file-structure }
+
+假設你的專案檔案結構如下:
+
+```
+.
+├── app
+│ ├── __init__.py
+│ ├── main.py
+```
+
+現在建立一個目錄來存放這些靜態檔案。
+
+新的檔案結構可能如下:
+
+```
+.
+├── app
+│ ├── __init__.py
+│ ├── main.py
+└── static/
+```
+
+### 下載檔案 { #download-the-files }
+
+下載文件所需的靜態檔案並放到 `static/` 目錄中。
+
+你可以在各連結上按右鍵,選擇類似「另存連結為...」的選項。
+
+Swagger UI 需要以下檔案:
+
+* `swagger-ui-bundle.js`
+* `swagger-ui.css`
+
+而 ReDoc 需要以下檔案:
+
+* `redoc.standalone.js`
+
+之後,你的檔案結構可能如下:
+
+```
+.
+├── app
+│ ├── __init__.py
+│ ├── main.py
+└── static
+ ├── redoc.standalone.js
+ ├── swagger-ui-bundle.js
+ └── swagger-ui.css
+```
+
+### 提供靜態檔案 { #serve-the-static-files }
+
+* 匯入 `StaticFiles`。
+* 在特定路徑「掛載」一個 `StaticFiles()` 實例。
+
+{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[7,11] *}
+
+### 測試靜態檔案 { #test-the-static-files }
+
+啟動你的應用並前往 http://127.0.0.1:8000/static/redoc.standalone.js。
+
+你應該會看到一個很長的 **ReDoc** JavaScript 檔案。
+
+它可能會以如下內容開頭:
+
+```JavaScript
+/*! For license information please see redoc.standalone.js.LICENSE.txt */
+!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t(require("null")):
+...
+```
+
+這表示你的應用已能提供靜態檔案,且文件用的靜態檔已放在正確位置。
+
+接著把應用設定為讓文件使用這些靜態檔。
+
+### 為靜態檔案停用自動文件 { #disable-the-automatic-docs-for-static-files }
+
+和使用自訂 CDN 一樣,第一步是停用自動文件,因為預設會使用 CDN。
+
+要停用它們,建立 `FastAPI` 應用時把相關 URL 設為 `None`:
+
+{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[9] *}
+
+### 加入使用靜態檔案的自訂文件 { #include-the-custom-docs-for-static-files }
+
+同樣地,現在你可以為自訂文件建立路徑操作。
+
+再次重用 FastAPI 的內部函式來建立文件的 HTML 頁面,並傳入所需參數:
+
+* `openapi_url`:文件 HTML 頁面用來取得你 API 的 OpenAPI schema 的 URL。可使用屬性 `app.openapi_url`。
+* `title`:你的 API 標題。
+* `oauth2_redirect_url`:可使用 `app.swagger_ui_oauth2_redirect_url` 以沿用預設值。
+* `swagger_js_url`:Swagger UI 文件 HTML 用來取得「JavaScript」檔案的 URL。這就是你的應用現在提供的檔案。
+* `swagger_css_url`:Swagger UI 文件 HTML 用來取得「CSS」檔案的 URL。這就是你的應用現在提供的檔案。
+
+ReDoc 也類似...
+
+{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[2:6,14:22,25:27,30:36] *}
+
+/// tip
+
+當你使用 OAuth2 時,`swagger_ui_redirect` 的路徑操作是個輔助端點。
+
+如果你把 API 與 OAuth2 提供者整合,便能完成認證並帶著取得的憑證回到 API 文件,接著以真正的 OAuth2 驗證與之互動。
+
+Swagger UI 會在背後幫你處理,不過它需要這個「redirect」輔助端點。
+
+///
+
+### 建立路徑操作以測試靜態檔案 { #create-a-path-operation-to-test-static-files }
+
+現在,為了測試一切是否正常,建立一個路徑操作:
+
+{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[39:41] *}
+
+### 測試使用靜態檔案的 UI { #test-static-files-ui }
+
+現在,你應該可以關閉 WiFi,造訪你的文件 http://127.0.0.1:8000/docs,並重新載入頁面。
+
+即使沒有網際網路,也能看到你的 API 文件並與之互動。
diff --git a/docs/zh-hant/docs/how-to/custom-request-and-route.md b/docs/zh-hant/docs/how-to/custom-request-and-route.md
new file mode 100644
index 0000000000..99c3410e47
--- /dev/null
+++ b/docs/zh-hant/docs/how-to/custom-request-and-route.md
@@ -0,0 +1,109 @@
+# 自訂 Request 與 APIRoute 類別 { #custom-request-and-apiroute-class }
+
+在某些情況下,你可能想要覆寫 `Request` 與 `APIRoute` 類別所使用的邏輯。
+
+特別是,這可能是替代中介軟體(middleware)中實作邏輯的一個好方法。
+
+例如,如果你想在應用程式處理之前讀取或操作請求本文(request body)。
+
+/// danger
+
+這是進階功能。
+
+如果你剛開始使用 **FastAPI**,可以先跳過本節。
+
+///
+
+## 使用情境 { #use-cases }
+
+可能的使用情境包括:
+
+* 將非 JSON 的請求本文轉換為 JSON(例如 `msgpack`)。
+* 解壓縮以 gzip 壓縮的請求本文。
+* 自動記錄所有請求本文。
+
+## 處理自訂請求本文編碼 { #handling-custom-request-body-encodings }
+
+讓我們看看如何使用自訂的 `Request` 子類別來解壓縮 gzip 請求。
+
+並透過 `APIRoute` 子類別來使用該自訂的請求類別。
+
+### 建立自訂的 `GzipRequest` 類別 { #create-a-custom-gziprequest-class }
+
+/// tip
+
+這是一個示範用的簡化範例;如果你需要 Gzip 支援,可以直接使用提供的 [`GzipMiddleware`](../advanced/middleware.md#gzipmiddleware){.internal-link target=_blank}。
+
+///
+
+首先,我們建立 `GzipRequest` 類別,它會覆寫 `Request.body()` 方法,當存在對應的標頭時解壓縮本文。
+
+如果標頭中沒有 `gzip`,它就不會嘗試解壓縮本文。
+
+如此一來,相同的路由類別即可同時處理經 gzip 壓縮與未壓縮的請求.
+
+{* ../../docs_src/custom_request_and_route/tutorial001_an_py310.py hl[9:16] *}
+
+### 建立自訂的 `GzipRoute` 類別 { #create-a-custom-gziproute-class }
+
+接著,我們建立 `fastapi.routing.APIRoute` 的自訂子類別,讓它使用 `GzipRequest`。
+
+這次,它會覆寫 `APIRoute.get_route_handler()` 方法。
+
+這個方法會回傳一個函式,而該函式會接收請求並回傳回應。
+
+在這裡,我們用它將原始的請求包裝成 `GzipRequest`。
+
+{* ../../docs_src/custom_request_and_route/tutorial001_an_py310.py hl[19:27] *}
+
+/// note | 技術細節
+
+`Request` 具有 `request.scope` 屬性,它其實就是一個 Python 的 `dict`,包含與該請求相關的中繼資料。
+
+`Request` 也有 `request.receive`,那是一個用來「接收」請求本文的函式。
+
+`scope` 這個 `dict` 與 `receive` 函式都是 ASGI 規格的一部分。
+
+而 `scope` 與 `receive` 這兩者,就是建立一個新的 `Request` 實例所需的資料。
+
+想了解更多 `Request`,請參考 Starlette 的 Request 文件。
+
+///
+
+由 `GzipRequest.get_route_handler` 回傳的函式,唯一不同之處在於它會把 `Request` 轉換成 `GzipRequest`。
+
+這麼做之後,`GzipRequest` 會在把資料交給 *路徑操作* 之前(若有需要)先負責解壓縮。
+
+之後的處理邏輯完全相同。
+
+但由於我們修改了 `GzipRequest.body`,在 **FastAPI** 需要讀取本文時,請求本文會自動解壓縮。
+
+## 在例外處理器中存取請求本文 { #accessing-the-request-body-in-an-exception-handler }
+
+/// tip
+
+要解決相同問題,使用針對 `RequestValidationError` 的自訂處理器來讀取 `body` 通常更簡單([處理錯誤](../tutorial/handling-errors.md#use-the-requestvalidationerror-body){.internal-link target=_blank})。
+
+但本範例仍然有效,並示範了如何與內部元件互動。
+
+///
+
+我們也可以用同樣的方法,在例外處理器中存取請求本文。
+
+我們只需要在 `try`/`except` 區塊中處理請求即可:
+
+{* ../../docs_src/custom_request_and_route/tutorial002_an_py310.py hl[14,16] *}
+
+若發生例外,`Request` 實例依然在作用域內,因此在處理錯誤時我們仍可讀取並使用請求本文:
+
+{* ../../docs_src/custom_request_and_route/tutorial002_an_py310.py hl[17:19] *}
+
+## 在路由器中自訂 `APIRoute` 類別 { #custom-apiroute-class-in-a-router }
+
+你也可以在 `APIRouter` 上設定 `route_class` 參數:
+
+{* ../../docs_src/custom_request_and_route/tutorial003_py310.py hl[26] *}
+
+在此範例中,`router` 底下的路徑操作會使用自訂的 `TimedRoute` 類別,並在回應中多加上一個 `X-Response-Time` 標頭,標示產生該回應所花費的時間:
+
+{* ../../docs_src/custom_request_and_route/tutorial003_py310.py hl[13:20] *}
diff --git a/docs/zh-hant/docs/how-to/extending-openapi.md b/docs/zh-hant/docs/how-to/extending-openapi.md
new file mode 100644
index 0000000000..c51e896f32
--- /dev/null
+++ b/docs/zh-hant/docs/how-to/extending-openapi.md
@@ -0,0 +1,80 @@
+# 擴充 OpenAPI { #extending-openapi }
+
+有些情況你可能需要修改自動產生的 OpenAPI 結構(schema)。
+
+本章將示範如何做。
+
+## 一般流程 { #the-normal-process }
+
+一般(預設)的流程如下。
+
+`FastAPI` 應用程式(實例)有一個 `.openapi()` 方法,會回傳 OpenAPI 結構。
+
+在建立應用物件時,會同時註冊一個 `/openapi.json`(或你在 `openapi_url` 設定的路徑)的路徑操作(path operation)。
+
+這個路徑只會回傳一個 JSON 回應,內容就是應用的 `.openapi()` 方法結果。
+
+預設情況下,`.openapi()` 會先檢查 `.openapi_schema` 屬性是否已有內容,有的話就直接回傳。
+
+若沒有,則會呼叫 `fastapi.openapi.utils.get_openapi` 這個工具函式來產生。
+
+`get_openapi()` 函式會接收以下參數:
+
+* `title`:OpenAPI 的標題,會顯示在文件中。
+* `version`:你的 API 版本,例如 `2.5.0`。
+* `openapi_version`:所使用的 OpenAPI 規格版本。預設為最新版本:`3.1.0`。
+* `summary`:API 的簡短摘要。
+* `description`:API 的描述,可包含 Markdown,會顯示在文件中。
+* `routes`:路由列表,也就是所有已註冊的路徑操作。來源為 `app.routes`。
+
+/// info
+
+`summary` 參數在 OpenAPI 3.1.0 以上可用,且需 FastAPI 0.99.0 以上版本支援。
+
+///
+
+## 覆寫預設行為 { #overriding-the-defaults }
+
+基於上述資訊,你可以用相同的工具函式來產生 OpenAPI 結構,並覆寫你需要客製的部分。
+
+例如,我們要加入 ReDoc 的 OpenAPI 擴充,插入自訂 logo。
+
+### 一般的 **FastAPI** { #normal-fastapi }
+
+先照常撰寫你的 **FastAPI** 應用:
+
+{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[1,4,7:9] *}
+
+### 產生 OpenAPI 結構 { #generate-the-openapi-schema }
+
+接著,在 `custom_openapi()` 函式內,使用相同的工具函式來產生 OpenAPI 結構:
+
+{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[2,15:21] *}
+
+### 修改 OpenAPI 結構 { #modify-the-openapi-schema }
+
+現在可以加入 ReDoc 擴充,在 OpenAPI 結構的 `info`「物件」中新增自訂的 `x-logo`:
+
+{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[22:24] *}
+
+### 快取 OpenAPI 結構 { #cache-the-openapi-schema }
+
+你可以把 `.openapi_schema` 屬性當作「快取」來儲存已產生的結構。
+
+這樣使用者每次開啟 API 文件時,應用就不必重複產生結構。
+
+結構只會產生一次,之後的請求都會使用相同的快取結果。
+
+{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[13:14,25:26] *}
+
+### 覆寫方法 { #override-the-method }
+
+現在你可以用新的函式取代 `.openapi()` 方法。
+
+{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[29] *}
+
+### 檢查看看 { #check-it }
+
+造訪 http://127.0.0.1:8000/redoc 後,你會看到自訂的 logo(此例為 **FastAPI** 的 logo):
+
+
diff --git a/docs/zh-hant/docs/how-to/general.md b/docs/zh-hant/docs/how-to/general.md
new file mode 100644
index 0000000000..96a71d62dd
--- /dev/null
+++ b/docs/zh-hant/docs/how-to/general.md
@@ -0,0 +1,39 @@
+# 通用 - 操作指南 - 實用範例 { #general-how-to-recipes }
+
+以下是文件中其他位置的指引連結,適用於一般或常見問題。
+
+## 篩選資料 - 安全性 { #filter-data-security }
+
+為確保你不會回傳超出應有的資料,請參閱[教學 - 回應模型 - 回傳型別](../tutorial/response-model.md){.internal-link target=_blank}。
+
+## 文件標籤 - OpenAPI { #documentation-tags-openapi }
+
+要在你的*路徑操作(path operation)*加入標籤,並在文件 UI 中分組,請參閱[教學 - 路徑操作設定 - 標籤](../tutorial/path-operation-configuration.md#tags){.internal-link target=_blank}。
+
+## 文件摘要與描述 - OpenAPI { #documentation-summary-and-description-openapi }
+
+要為你的*路徑操作*加入摘要與描述,並在文件 UI 中顯示,請參閱[教學 - 路徑操作設定 - 摘要與描述](../tutorial/path-operation-configuration.md#summary-and-description){.internal-link target=_blank}。
+
+## 文件回應描述 - OpenAPI { #documentation-response-description-openapi }
+
+要定義在文件 UI 中顯示的回應描述,請參閱[教學 - 路徑操作設定 - 回應描述](../tutorial/path-operation-configuration.md#response-description){.internal-link target=_blank}。
+
+## 文件將*路徑操作*標記為已棄用 - OpenAPI { #documentation-deprecate-a-path-operation-openapi }
+
+要將*路徑操作*標記為已棄用,並在文件 UI 中顯示,請參閱[教學 - 路徑操作設定 - 棄用](../tutorial/path-operation-configuration.md#deprecate-a-path-operation){.internal-link target=_blank}。
+
+## 將任意資料轉換為 JSON 相容格式 { #convert-any-data-to-json-compatible }
+
+要將任意資料轉換為 JSON 相容格式,請參閱[教學 - JSON 相容編碼器](../tutorial/encoder.md){.internal-link target=_blank}。
+
+## OpenAPI 中繼資料 - 文件 { #openapi-metadata-docs }
+
+要在你的 OpenAPI 綱要中加入中繼資料(包含授權、版本、聯絡方式等),請參閱[教學 - 中繼資料與文件 URL](../tutorial/metadata.md){.internal-link target=_blank}。
+
+## 自訂 OpenAPI URL { #openapi-custom-url }
+
+要自訂(或移除)OpenAPI 的 URL,請參閱[教學 - 中繼資料與文件 URL](../tutorial/metadata.md#openapi-url){.internal-link target=_blank}。
+
+## OpenAPI 文件 URL { #openapi-docs-urls }
+
+要更新自動產生的文件使用者介面所使用的 URL,請參閱[教學 - 中繼資料與文件 URL](../tutorial/metadata.md#docs-urls){.internal-link target=_blank}。
diff --git a/docs/zh-hant/docs/how-to/graphql.md b/docs/zh-hant/docs/how-to/graphql.md
new file mode 100644
index 0000000000..51933210c5
--- /dev/null
+++ b/docs/zh-hant/docs/how-to/graphql.md
@@ -0,0 +1,60 @@
+# GraphQL { #graphql }
+
+由於 FastAPI 基於 ASGI 標準,整合任何與 ASGI 相容的 GraphQL 函式庫都很容易。
+
+你可以在同一個應用程式中同時使用一般的 FastAPI 路徑操作 (path operation) 與 GraphQL。
+
+/// tip
+
+GraphQL 解決某些非常特定的使用情境。
+
+與一般的 Web API 相比,它有優點也有缺點。
+
+請確認在你的使用情境中,這些效益是否足以彌補其限制。 🤓
+
+///
+
+## GraphQL 函式庫 { #graphql-libraries }
+
+下面是支援 ASGI 的部分 GraphQL 函式庫,你可以與 FastAPI 一起使用:
+
+* Strawberry 🍓
+ * 提供 FastAPI 文件
+* Ariadne
+ * 提供 FastAPI 文件
+* Tartiflette
+ * 使用 Tartiflette ASGI 提供 ASGI 整合
+* Graphene
+ * 搭配 starlette-graphene3
+
+## 使用 Strawberry 的 GraphQL { #graphql-with-strawberry }
+
+如果你需要或想使用 GraphQL,Strawberry 是推薦的函式庫,因為它的設計與 FastAPI 最接近,全部都基於型別註解 (type annotations)。
+
+視你的使用情境而定,你可能會偏好其他函式庫,但如果你問我,我大概會建議你先試試 Strawberry。
+
+以下是如何將 Strawberry 與 FastAPI 整合的一個小例子:
+
+{* ../../docs_src/graphql_/tutorial001_py310.py hl[3,22,25] *}
+
+你可以在 Strawberry 文件 中進一步了解 Strawberry。
+
+也可以參考關於 Strawberry 與 FastAPI 的文件。
+
+## 來自 Starlette 的較舊 `GraphQLApp` { #older-graphqlapp-from-starlette }
+
+早期版本的 Starlette 提供 `GraphQLApp` 類別以整合 Graphene。
+
+它已在 Starlette 中被棄用,但如果你的程式碼使用了它,可以輕鬆遷移到 starlette-graphene3,涵蓋相同的使用情境,且介面幾乎相同。
+
+/// tip
+
+如果你需要 GraphQL,我仍建議你看看 Strawberry,因為它基於型別註解,而不是自訂的類別與型別。
+
+///
+
+## 進一步了解 { #learn-more }
+
+你可以在 官方 GraphQL 文件 中進一步了解 GraphQL。
+
+你也可以透過上述連結閱讀各個函式庫的更多內容。
diff --git a/docs/zh-hant/docs/how-to/migrate-from-pydantic-v1-to-pydantic-v2.md b/docs/zh-hant/docs/how-to/migrate-from-pydantic-v1-to-pydantic-v2.md
new file mode 100644
index 0000000000..109e57bc81
--- /dev/null
+++ b/docs/zh-hant/docs/how-to/migrate-from-pydantic-v1-to-pydantic-v2.md
@@ -0,0 +1,135 @@
+# 從 Pydantic v1 遷移到 Pydantic v2 { #migrate-from-pydantic-v1-to-pydantic-v2 }
+
+如果你有一個舊的 FastAPI 應用,可能正在使用 Pydantic 1 版。
+
+FastAPI 0.100.0 同時支援 Pydantic v1 或 v2,會使用你已安裝的那個版本。
+
+FastAPI 0.119.0 透過 Pydantic v2 內的 `pydantic.v1` 提供對 Pydantic v1 的部分支援,以便遷移到 v2。
+
+FastAPI 0.126.0 移除了對 Pydantic v1 的支援,但在一段時間內仍支援 `pydantic.v1`。
+
+/// warning
+
+Pydantic 團隊自 **Python 3.14** 起,已停止在最新的 Python 版本中支援 Pydantic v1。
+
+這也包含 `pydantic.v1`,在 Python 3.14 及以上版本不再支援。
+
+如果你想使用最新的 Python 功能,就需要確保使用 Pydantic v2。
+
+///
+
+如果你的舊 FastAPI 應用仍使用 Pydantic v1,這裡會示範如何遷移到 Pydantic v2,並介紹 **FastAPI 0.119.0** 中可協助你逐步遷移的功能。
+
+## 官方指南 { #official-guide }
+
+Pydantic 提供從 v1 遷移到 v2 的官方遷移指南。
+
+其中包含變更內容、驗證如何更正確且更嚴格、可能的注意事項等。
+
+你可以先閱讀以更好理解具體變更。
+
+## 測試 { #tests }
+
+確保你的應用有[測試](../tutorial/testing.md){.internal-link target=_blank},並在 CI(持續整合)上執行。
+
+如此一來,你可以升級後確認一切仍如預期運作。
+
+## `bump-pydantic` { #bump-pydantic }
+
+在許多情況下,若你使用的是未自訂的標準 Pydantic 模型,多數遷移步驟都能自動化完成。
+
+你可以使用 Pydantic 團隊提供的 `bump-pydantic`。
+
+這個工具會自動修改大部分需要變更的程式碼。
+
+之後執行測試確認一切正常即可完成。😎
+
+## v2 中的 Pydantic v1 { #pydantic-v1-in-v2 }
+
+Pydantic v2 內含子模組 `pydantic.v1`,提供 Pydantic v1 的所有內容。但在 Python 3.13 以上版本不再支援。
+
+這表示你可以安裝最新的 Pydantic v2,並從該子模組匯入並使用舊的 Pydantic v1 元件,就像安裝了舊版 Pydantic v1 一樣。
+
+{* ../../docs_src/pydantic_v1_in_v2/tutorial001_an_py310.py hl[1,4] *}
+
+### FastAPI 對 v2 中 Pydantic v1 的支援 { #fastapi-support-for-pydantic-v1-in-v2 }
+
+自 FastAPI 0.119.0 起,也支援透過 Pydantic v2 內的 Pydantic v1(部分)以協助遷移至 v2。
+
+因此,你可以先升級到最新的 Pydantic v2,並將匯入改為使用 `pydantic.v1` 子模組,在多數情況下即可正常運作。
+
+{* ../../docs_src/pydantic_v1_in_v2/tutorial002_an_py310.py hl[2,5,15] *}
+
+/// warning
+
+請注意,由於 Pydantic 團隊自 Python 3.14 起不再支援 Pydantic v1,因此在 Python 3.14 及以上版本中也不支援使用 `pydantic.v1`。
+
+///
+
+### 同一應用同時使用 Pydantic v1 與 v2 { #pydantic-v1-and-v2-on-the-same-app }
+
+Pydantic 不支援在 Pydantic v2 模型的欄位中使用 Pydantic v1 模型,反之亦然。
+
+```mermaid
+graph TB
+ subgraph "❌ Not Supported"
+ direction TB
+ subgraph V2["Pydantic v2 Model"]
+ V1Field["Pydantic v1 Model"]
+ end
+ subgraph V1["Pydantic v1 Model"]
+ V2Field["Pydantic v2 Model"]
+ end
+ end
+
+ style V2 fill:#f9fff3
+ style V1 fill:#fff6f0
+ style V1Field fill:#fff6f0
+ style V2Field fill:#f9fff3
+```
+
+...但你可以在同一應用中同時存在分開的 Pydantic v1 與 v2 模型。
+
+```mermaid
+graph TB
+ subgraph "✅ Supported"
+ direction TB
+ subgraph V2["Pydantic v2 Model"]
+ V2Field["Pydantic v2 Model"]
+ end
+ subgraph V1["Pydantic v1 Model"]
+ V1Field["Pydantic v1 Model"]
+ end
+ end
+
+ style V2 fill:#f9fff3
+ style V1 fill:#fff6f0
+ style V1Field fill:#fff6f0
+ style V2Field fill:#f9fff3
+```
+
+在某些情況下,你甚至可以在同一個 FastAPI 路徑操作(path operation)中同時使用 Pydantic v1 與 v2 模型:
+
+{* ../../docs_src/pydantic_v1_in_v2/tutorial003_an_py310.py hl[2:3,6,12,21:22] *}
+
+在上面的範例中,輸入模型是 Pydantic v1,輸出模型(於 `response_model=ItemV2` 定義)是 Pydantic v2。
+
+### Pydantic v1 參數 { #pydantic-v1-parameters }
+
+若你需要在 Pydantic v1 模型上使用 FastAPI 的參數工具(例如 `Body`、`Query`、`Form` 等),在完成遷移到 Pydantic v2 之前,可以從 `fastapi.temp_pydantic_v1_params` 匯入:
+
+{* ../../docs_src/pydantic_v1_in_v2/tutorial004_an_py310.py hl[4,18] *}
+
+### 分步遷移 { #migrate-in-steps }
+
+/// tip
+
+先嘗試使用 `bump-pydantic`,如果測試通過且一切正常,你就能用一條指令完成遷移。✨
+
+///
+
+若 `bump-pydantic` 不適用於你的情境,可以利用在同一應用同時支援 Pydantic v1 與 v2 的能力,逐步完成遷移。
+
+你可以先升級 Pydantic 到最新 v2,並將所有模型的匯入改為使用 `pydantic.v1`。
+
+接著按群組逐步把模型從 Pydantic v1 遷移到 v2。🚶
diff --git a/docs/zh-hant/docs/how-to/separate-openapi-schemas.md b/docs/zh-hant/docs/how-to/separate-openapi-schemas.md
new file mode 100644
index 0000000000..2ecb6afbc1
--- /dev/null
+++ b/docs/zh-hant/docs/how-to/separate-openapi-schemas.md
@@ -0,0 +1,102 @@
+# 是否將輸入與輸出使用不同的 OpenAPI 結構描述 { #separate-openapi-schemas-for-input-and-output-or-not }
+
+自從 Pydantic v2 發佈後,生成的 OpenAPI 比以往更精確也更正確。😎
+
+實際上,在某些情況下,同一個 Pydantic 模型在 OpenAPI 中會同時有兩個 JSON Schema:分別用於輸入與輸出,這取決於它是否有預設值。
+
+來看看它如何運作,以及若需要時該如何調整。
+
+## 作為輸入與輸出的 Pydantic 模型 { #pydantic-models-for-input-and-output }
+
+假設你有一個帶有預設值的 Pydantic 模型,如下所示:
+
+{* ../../docs_src/separate_openapi_schemas/tutorial001_py310.py ln[1:7] hl[7] *}
+
+### 輸入用模型 { #model-for-input }
+
+如果你把這個模型用作輸入,如下所示:
+
+{* ../../docs_src/separate_openapi_schemas/tutorial001_py310.py ln[1:15] hl[14] *}
+
+...則 `description` 欄位將不是必填。因為它的預設值是 `None`。
+
+### 文件中的輸入模型 { #input-model-in-docs }
+
+你可以在文件中確認,`description` 欄位沒有紅色星號,表示不是必填:
+
+
+

+
+
+### 輸出用模型 { #model-for-output }
+
+但如果你把同一個模型用作輸出,如下所示:
+
+{* ../../docs_src/separate_openapi_schemas/tutorial001_py310.py hl[19] *}
+
+...由於 `description` 有預設值,就算你沒有為該欄位回傳任何內容,它仍會有那個預設值。
+
+### 輸出回應資料的模型 { #model-for-output-response-data }
+
+在互動式文件中試用並檢視回應時,儘管程式碼沒有為其中一個 `description` 欄位加入任何內容,JSON 回應仍包含預設值(`null`):
+
+
+

+
+
+這代表該欄位一定會有值,只是有時候值可能是 `None`(在 JSON 中為 `null`)。
+
+因此,使用你 API 的用戶端不必檢查值是否存在,可以假設該欄位一定存在;只是有些情況下它的值會是預設的 `None`。
+
+在 OpenAPI 中,描述這種情況的方式是將該欄位標記為必填,因為它一定存在。
+
+因此,同一個模型的 JSON Schema 會依用於輸入或輸出而不同:
+
+- 用於輸入時,`description` 不是必填
+- 用於輸出時,`description` 是必填(且可能為 `None`,在 JSON 中為 `null`)
+
+### 文件中的輸出模型 { #model-for-output-in-docs }
+
+你也可以在文件中檢視輸出模型,`name` 與 `description` 都以紅色星號標示為必填:
+
+
+

+
+
+### 文件中的輸入與輸出模型 { #model-for-input-and-output-in-docs }
+
+如果你查看 OpenAPI 中所有可用的結構描述(JSON Schema),會看到有兩個:`Item-Input` 與 `Item-Output`。
+
+對於 `Item-Input`,`description` 不是必填,沒有紅色星號。
+
+但對於 `Item-Output`,`description` 是必填,有紅色星號。
+
+
+

+
+
+有了 Pydantic v2 的這個特性,你的 API 文件會更精確;若你有自動產生的用戶端與 SDK,它們也會更精確,提供更好的開發者體驗與一致性。🎉
+
+## 不要分開結構描述 { #do-not-separate-schemas }
+
+不過,在某些情況下,你可能會希望輸入與輸出使用相同的結構描述。
+
+最常見的情境是:你已經有一些自動產生的用戶端程式碼/SDK,目前還不想全部更新;也許之後會做,但不是現在。
+
+在這種情況下,你可以在 FastAPI 中透過參數 `separate_input_output_schemas=False` 停用這個功能。
+
+/// info
+
+自 FastAPI `0.102.0` 起新增 `separate_input_output_schemas` 的支援。🤓
+
+///
+
+{* ../../docs_src/separate_openapi_schemas/tutorial002_py310.py hl[10] *}
+
+### 文件中輸入與輸出使用相同結構描述的模型 { #same-schema-for-input-and-output-models-in-docs }
+
+此時輸入與輸出將共用同一個模型結構描述,只有 `Item`,其中 `description` 不是必填:
+
+
+

+
diff --git a/docs/zh-hant/docs/how-to/testing-database.md b/docs/zh-hant/docs/how-to/testing-database.md
new file mode 100644
index 0000000000..cbaecc2389
--- /dev/null
+++ b/docs/zh-hant/docs/how-to/testing-database.md
@@ -0,0 +1,7 @@
+# 測試資料庫 { #testing-a-database }
+
+你可以在 SQLModel 文件 中學習關於資料庫、SQL 與 SQLModel。 🤓
+
+有一個迷你 將 SQLModel 與 FastAPI 搭配使用的教學。 ✨
+
+該教學包含一節介紹 測試 SQL 資料庫。 😎
diff --git a/docs/zh-hant/docs/index.md b/docs/zh-hant/docs/index.md
index a31647f3cd..77eba9b149 100644
--- a/docs/zh-hant/docs/index.md
+++ b/docs/zh-hant/docs/index.md
@@ -40,7 +40,7 @@ FastAPI 是一個現代、快速(高效能)的 Web 框架,用於以 Python
* **快速**:非常高的效能,可與 **NodeJS** 和 **Go** 相當(歸功於 Starlette 和 Pydantic)。[最快的 Python 框架之一](#performance)。
* **極速開發**:開發功能的速度可提升約 200% 至 300%。*
* **更少的 Bug**:減少約 40% 的人為(開發者)錯誤。*
-* **直覺**:具有出色的編輯器支援,處處都有 自動補全。更少的偵錯時間。
+* **直覺**:具有出色的編輯器支援,處處都有 自動補全。更少的偵錯時間。
* **簡單**:設計上易於使用與學習。更少的讀文件時間。
* **簡潔**:最小化程式碼重複性。每個參數宣告可帶來多個功能。更少的錯誤。
* **穩健**:立即獲得可投入生產的程式碼,並自動生成互動式文件。
@@ -368,7 +368,7 @@ item: Item
* 資料驗證:
* 當資料無效時,自動且清楚的錯誤。
* 即使是深度巢狀的 JSON 物件也能驗證。
-* 輸入資料的 轉換:從網路讀入到 Python 資料與型別。包含:
+* 輸入資料的 轉換:從網路讀入到 Python 資料與型別。包含:
* JSON。
* 路徑參數。
* 查詢參數。
@@ -376,7 +376,7 @@ item: Item
* 標頭。
* 表單。
* 檔案。
-* 輸出資料的 轉換:從 Python 資料與型別轉換為網路資料(JSON):
+* 輸出資料的 轉換:從 Python 資料與型別轉換為網路資料(JSON):
* 轉換 Python 型別(`str`、`int`、`float`、`bool`、`list` 等)。
* `datetime` 物件。
* `UUID` 物件。
@@ -439,7 +439,7 @@ item: Item
* 來自不同來源的**參數**宣告:例如 **headers**、**cookies**、**form fields** 和 **files**。
* 如何設定**驗證限制**,如 `maximum_length` 或 `regex`。
-* 一個非常強大且易用的 **依賴注入** 系統。
+* 一個非常強大且易用的 **依賴注入** 系統。
* 安全與驗證,包含支援 **OAuth2** 搭配 **JWT tokens** 與 **HTTP Basic** 驗證。
* 宣告**深度巢狀 JSON 模型**的進階(但同樣簡單)技巧(感謝 Pydantic)。
* 與 Strawberry 及其他函式庫的 **GraphQL** 整合。
@@ -524,7 +524,7 @@ Starlette 會使用:
* httpx - 若要使用 `TestClient` 必須安裝。
* jinja2 - 若要使用預設的模板設定必須安裝。
-* python-multipart - 若要支援表單 "解析",搭配 `request.form()`。
+* python-multipart - 若要支援表單 "解析",搭配 `request.form()`。
FastAPI 會使用:
diff --git a/docs/zh-hant/docs/project-generation.md b/docs/zh-hant/docs/project-generation.md
new file mode 100644
index 0000000000..7fa92ce558
--- /dev/null
+++ b/docs/zh-hant/docs/project-generation.md
@@ -0,0 +1,28 @@
+# 全端 FastAPI 範本 { #full-stack-fastapi-template }
+
+範本通常附帶特定的設定,但設計上具有彈性且可自訂。這讓你可以依專案需求調整與擴充,因此非常適合作為起點。🏁
+
+你可以使用此範本快速起步,裡面已替你完成大量初始設定、安全性、資料庫,以及部分 API 端點。
+
+GitHub 儲存庫:全端 FastAPI 範本
+
+## 全端 FastAPI 範本 - 技術堆疊與功能 { #full-stack-fastapi-template-technology-stack-and-features }
+
+- ⚡ [**FastAPI**](https://fastapi.tiangolo.com/zh-hant) 作為 Python 後端 API。
+ - 🧰 [SQLModel](https://sqlmodel.tiangolo.com) 作為 Python 與 SQL 資料庫互動(ORM)。
+ - 🔍 [Pydantic](https://docs.pydantic.dev)(由 FastAPI 使用)用於資料驗證與設定管理。
+ - 💾 [PostgreSQL](https://www.postgresql.org) 作為 SQL 資料庫。
+- 🚀 [React](https://react.dev) 作為前端。
+ - 💃 使用 TypeScript、hooks、Vite,以及現代前端技術堆疊的其他組件。
+ - 🎨 [Tailwind CSS](https://tailwindcss.com) 與 [shadcn/ui](https://ui.shadcn.com) 作為前端元件。
+ - 🤖 自動產生的前端用戶端。
+ - 🧪 [Playwright](https://playwright.dev) 用於端到端測試。
+ - 🦇 支援深色模式。
+- 🐋 [Docker Compose](https://www.docker.com) 用於開發與正式環境。
+- 🔒 預設即採用安全的密碼雜湊。
+- 🔑 JWT(JSON Web Token)驗證。
+- 📫 以 Email 為基礎的密碼重設。
+- ✅ 使用 [Pytest](https://pytest.org) 的測試。
+- 📞 [Traefik](https://traefik.io) 作為反向代理/負載平衡器。
+- 🚢 使用 Docker Compose 的部署指引,包含如何設定前端 Traefik 代理以自動處理 HTTPS 憑證。
+- 🏭 基於 GitHub Actions 的 CI(持續整合)與 CD(持續部署)。
diff --git a/docs/zh-hant/docs/python-types.md b/docs/zh-hant/docs/python-types.md
new file mode 100644
index 0000000000..4f498ab734
--- /dev/null
+++ b/docs/zh-hant/docs/python-types.md
@@ -0,0 +1,348 @@
+# Python 型別入門 { #python-types-intro }
+
+Python 支援可選用的「型別提示」(也稱為「型別註記」)。
+
+這些「型別提示」或註記是一種特殊語法,用來宣告變數的型別。
+
+為你的變數宣告型別後,編輯器與工具就能提供更好的支援。
+
+這裡只是關於 Python 型別提示的快速教學/複習。它只涵蓋使用在 **FastAPI** 時所需的最低限度...其實非常少。
+
+**FastAPI** 完全是以這些型別提示為基礎,並因此帶來許多優勢與好處。
+
+但就算你從不使用 **FastAPI**,學一點型別提示也會有幫助。
+
+/// note | 注意
+
+如果你是 Python 專家,而且已經完全了解型別提示,可以直接跳到下一章。
+
+///
+
+## 動機 { #motivation }
+
+先從一個簡單的例子開始:
+
+{* ../../docs_src/python_types/tutorial001_py310.py *}
+
+執行這個程式會輸出:
+
+```
+John Doe
+```
+
+這個函式會做以下事情:
+
+* 接收 `first_name` 與 `last_name`。
+* 用 `title()` 把每個字的第一個字母轉成大寫。
+* 用一個空白把它們串接起來。
+
+{* ../../docs_src/python_types/tutorial001_py310.py hl[2] *}
+
+### 編輯它 { #edit-it }
+
+這是一個非常簡單的程式。
+
+但現在想像你正從零開始寫它。
+
+在某個時間點你會開始定義函式,參數都準備好了...
+
+接著你需要呼叫「那個把第一個字母轉大寫的方法」。
+
+是 `upper`?還是 `uppercase`?`first_uppercase`?`capitalize`?
+
+然後你試著用老牌程式設計師的好朋友——編輯器自動完成。
+
+你輸入函式的第一個參數 `first_name`,接著打一個點(`.`),然後按下 `Ctrl+Space` 觸發自動完成。
+
+但很遺憾,你什麼有用的也沒得到:
+
+
+
+### 加上型別 { #add-types }
+
+我們來修改前一版中的一行。
+
+我們只要把函式參數這一段,從:
+
+```Python
+ first_name, last_name
+```
+
+改成:
+
+```Python
+ first_name: str, last_name: str
+```
+
+就這樣。
+
+那些就是「型別提示」:
+
+{* ../../docs_src/python_types/tutorial002_py310.py hl[1] *}
+
+這和宣告預設值不同,例如:
+
+```Python
+ first_name="john", last_name="doe"
+```
+
+這是不同的東西。
+
+我們使用的是冒號(`:`),不是等號(`=`)。
+
+而且加上型別提示通常不會改變執行結果,和不加時是一樣的。
+
+不過現在,想像你又在撰寫那個函式,但這次有型別提示。
+
+在同樣的地方,你按 `Ctrl+Space` 嘗試自動完成,然後你會看到:
+
+
+
+有了這些,你可以往下捲動查看選項,直到找到一個「看起來眼熟」的:
+
+
+
+## 更多動機 { #more-motivation }
+
+看這個函式,它已經有型別提示了:
+
+{* ../../docs_src/python_types/tutorial003_py310.py hl[1] *}
+
+因為編輯器知道變數的型別,你不只會得到自動完成,還會得到錯誤檢查:
+
+
+
+現在你知道要修正它,把 `age` 用 `str(age)` 轉成字串:
+
+{* ../../docs_src/python_types/tutorial004_py310.py hl[2] *}
+
+## 宣告型別 { #declaring-types }
+
+你剛剛看到宣告型別提示的主要位置:函式參數。
+
+這也是你在 **FastAPI** 中最常使用它們的地方。
+
+### 簡單型別 { #simple-types }
+
+你可以宣告所有標準的 Python 型別,不只 `str`。
+
+例如你可以用:
+
+* `int`
+* `float`
+* `bool`
+* `bytes`
+
+{* ../../docs_src/python_types/tutorial005_py310.py hl[1] *}
+
+### `typing` 模組 { #typing-module }
+
+在一些其他情境中,你可能需要從標準程式庫的 `typing` 模組匯入一些東西,比如當你想宣告某個東西可以是「任何型別」時,可以用 `typing` 裡的 `Any`:
+
+```python
+from typing import Any
+
+
+def some_function(data: Any):
+ print(data)
+```
+
+### 泛型(Generic types) { #generic-types }
+
+有些型別可以在方括號中接收「型別參數」,以定義其內部元素的型別,例如「字串的 list」可以宣告為 `list[str]`。
+
+這些能接收型別參數的型別稱為「泛型(Generic types)」或「Generics」。
+
+你可以將相同的內建型別用作泛型(使用方括號並在裡面放型別):
+
+* `list`
+* `tuple`
+* `set`
+* `dict`
+
+#### List { #list }
+
+例如,讓我們定義一個變數是 `str` 的 `list`。
+
+宣告變數,使用相同的冒號(`:`)語法。
+
+型別填 `list`。
+
+由於 list 是一種包含內部型別的型別,你要把內部型別放在方括號中:
+
+{* ../../docs_src/python_types/tutorial006_py310.py hl[1] *}
+
+/// info | 資訊
+
+方括號裡的那些內部型別稱為「型別參數」。
+
+在這個例子中,`str` 是傳給 `list` 的型別參數。
+
+///
+
+這表示:「變數 `items` 是一個 `list`,而這個清單中的每個元素都是 `str`」。
+
+這麼做之後,你的編輯器甚至在處理清單裡的項目時也能提供支援:
+
+
+
+沒有型別時,幾乎不可能做到這點。
+
+請注意,變數 `item` 是清單 `items` 中的一個元素。
+
+即便如此,編輯器仍然知道它是 `str`,並提供相應的支援。
+
+#### Tuple 與 Set { #tuple-and-set }
+
+你也可以用相同方式來宣告 `tuple` 與 `set`:
+
+{* ../../docs_src/python_types/tutorial007_py310.py hl[1] *}
+
+這代表:
+
+* 變數 `items_t` 是一個有 3 個項目的 `tuple`,分別是 `int`、`int` 和 `str`。
+* 變數 `items_s` 是一個 `set`,而其中每個項目都是 `bytes` 型別。
+
+#### Dict { #dict }
+
+定義 `dict` 時,你需要傳入 2 個以逗號分隔的型別參數。
+
+第一個型別參數是 `dict` 的鍵(key)。
+
+第二個型別參數是 `dict` 的值(value):
+
+{* ../../docs_src/python_types/tutorial008_py310.py hl[1] *}
+
+這代表:
+
+* 變數 `prices` 是個 `dict`:
+ * 這個 `dict` 的鍵是 `str`(例如每個項目的名稱)。
+ * 這個 `dict` 的值是 `float`(例如每個項目的價格)。
+
+#### Union { #union }
+
+你可以宣告一個變數可以是「多種型別」中的任一種,例如 `int` 或 `str`。
+
+要這麼定義,你使用豎線(`|`)來分隔兩種型別。
+
+這稱為「union」,因為變數可以是這兩種型別集合的聯集中的任一種。
+
+```Python hl_lines="1"
+{!> ../../docs_src/python_types/tutorial008b_py310.py!}
+```
+
+這表示 `item` 可以是 `int` 或 `str`。
+
+#### 可能為 `None` { #possibly-none }
+
+你可以宣告某個值可以是某個型別(例如 `str`),但它也可能是 `None`。
+
+//// tab | Python 3.10+
+
+```Python hl_lines="1"
+{!> ../../docs_src/python_types/tutorial009_py310.py!}
+```
+
+////
+
+使用 `str | None` 而不是單純的 `str`,可以讓編輯器幫你偵測錯誤,例如你以為某個值一定是 `str`,但它其實也可能是 `None`。
+
+### 類別作為型別 { #classes-as-types }
+
+你也可以用類別來宣告變數的型別。
+
+假設你有一個 `Person` 類別,帶有名稱:
+
+{* ../../docs_src/python_types/tutorial010_py310.py hl[1:3] *}
+
+接著你可以宣告一個變數為 `Person` 型別:
+
+{* ../../docs_src/python_types/tutorial010_py310.py hl[6] *}
+
+然後,你一樣會得到完整的編輯器支援:
+
+
+
+請注意,這表示「`one_person` 是類別 `Person` 的『實例(instance)』」。
+
+並不是「`one_person` 就是名為 `Person` 的『類別(class)』」。
+
+## Pydantic 模型 { #pydantic-models }
+
+Pydantic 是一個用來做資料驗證的 Python 程式庫。
+
+你以帶有屬性的類別來宣告資料的「形狀」。
+
+而每個屬性都有其型別。
+
+接著你用一些值建立這個類別的實例,它會驗證這些值、在需要時把它們轉換成適當的型別,然後回給你一個包含所有資料的物件。
+
+你也會對這個產生的物件得到完整的編輯器支援。
+
+以下是來自 Pydantic 官方文件的例子:
+
+{* ../../docs_src/python_types/tutorial011_py310.py *}
+
+/// info | 資訊
+
+想了解更多 Pydantic,請查看它的文件。
+
+///
+
+**FastAPI** 完全是以 Pydantic 為基礎。
+
+你會在[教學 - 使用者指南](tutorial/index.md){.internal-link target=_blank}中看到更多實際範例。
+
+## 含中繼資料的型別提示 { #type-hints-with-metadata-annotations }
+
+Python 也有一個功能,允許使用 `Annotated` 在這些型別提示中放入額外的中繼資料。
+
+你可以從 `typing` 匯入 `Annotated`。
+
+{* ../../docs_src/python_types/tutorial013_py310.py hl[1,4] *}
+
+Python 本身不會對這個 `Annotated` 做任何事。對編輯器與其他工具而言,該型別仍然是 `str`。
+
+但你可以利用 `Annotated` 這個空間,來提供 **FastAPI** 額外的中繼資料,告訴它你希望應用程式如何運作。
+
+重要的是要記住,傳給 `Annotated` 的「第一個型別參數」才是「真正的型別」。其餘的,都是給其他工具用的中繼資料。
+
+目前你只需要知道 `Annotated` 的存在,而且它是標準的 Python。😎
+
+之後你會看到它有多「強大」。
+
+/// tip | 提示
+
+因為這是「標準 Python」,所以你在編輯器、分析與重構程式碼的工具等方面,仍然能獲得「最佳的開發體驗」。✨
+
+而且你的程式碼也會與許多其他 Python 工具與程式庫非常相容。🚀
+
+///
+
+## 在 **FastAPI** 中的型別提示 { #type-hints-in-fastapi }
+
+**FastAPI** 善用這些型別提示來完成多項工作。
+
+在 **FastAPI** 中,你用型別提示來宣告參數,然後你會得到:
+
+* 編輯器支援
+* 型別檢查
+
+...而 **FastAPI** 也會用同樣的宣告來:
+
+* 定義需求:來自請求的路徑參數、查詢參數、標頭、主體(body)、相依性等
+* 轉換資料:把請求中的資料轉成所需型別
+* 驗證資料:來自每個請求的資料:
+ * 當資料無效時,自動產生錯誤並回傳給用戶端
+* 使用 OpenAPI 書寫 API 文件:
+ * 之後會由自動的互動式文件介面所使用
+
+這些現在聽起來可能有點抽象。別擔心。你會在[教學 - 使用者指南](tutorial/index.md){.internal-link target=_blank}中看到它們的實際運作。
+
+重點是,透過在單一位置使用標準的 Python 型別(而不是新增更多類別、裝飾器等),**FastAPI** 會幫你完成很多工作。
+
+/// info | 資訊
+
+如果你已經完整讀完整個教學,並回來想多看一些關於型別的內容,一個不錯的資源是 `mypy` 的「小抄」。
+
+///
diff --git a/docs/zh-hant/docs/translation-banner.md b/docs/zh-hant/docs/translation-banner.md
new file mode 100644
index 0000000000..58b49965a9
--- /dev/null
+++ b/docs/zh-hant/docs/translation-banner.md
@@ -0,0 +1,11 @@
+/// details | 🌐 AI 與人類共同完成的翻譯
+
+此翻譯由人類指導的 AI 完成。🤝
+
+可能會有對原意的誤解,或讀起來不自然等問題。🤖
+
+你可以透過[協助我們更好地引導 AI LLM](https://fastapi.tiangolo.com/zh-hant/contributing/#translations)來改進此翻譯。
+
+[英文版](ENGLISH_VERSION_URL)
+
+///
diff --git a/docs/zh-hant/docs/tutorial/background-tasks.md b/docs/zh-hant/docs/tutorial/background-tasks.md
new file mode 100644
index 0000000000..63e4e5a160
--- /dev/null
+++ b/docs/zh-hant/docs/tutorial/background-tasks.md
@@ -0,0 +1,84 @@
+# 背景任務 { #background-tasks }
+
+你可以定義背景任務,讓它們在傳回回應之後執行。
+
+這對於那些需要在請求之後發生、但用戶端其實不必在收到回應前等它完成的操作很有用。
+
+例如:
+
+* 在執行某個動作後發送電子郵件通知:
+ * 由於連線到郵件伺服器並寄送郵件通常較「慢」(數秒),你可以先立即回應,並在背景中發送郵件通知。
+* 處理資料:
+ * 例如,收到一個需要經過較慢處理流程的檔案時,你可以先回應「Accepted」(HTTP 202),再在背景處理該檔案。
+
+## 使用 `BackgroundTasks` { #using-backgroundtasks }
+
+首先,匯入 `BackgroundTasks`,並在你的路徑操作函式中定義一個型別為 `BackgroundTasks` 的參數:
+
+{* ../../docs_src/background_tasks/tutorial001_py310.py hl[1,13] *}
+
+**FastAPI** 會為你建立 `BackgroundTasks` 物件,並以該參數傳入。
+
+## 建立任務函式 { #create-a-task-function }
+
+建立一個作為背景任務執行的函式。
+
+它只是個可接收參數的一般函式。
+
+它可以是 `async def`,也可以是一般的 `def`,**FastAPI** 都能正確處理。
+
+在此例中,任務函式會寫入檔案(模擬寄送電子郵件)。
+
+由於寫入操作未使用 `async` 與 `await`,因此以一般的 `def` 定義該函式:
+
+{* ../../docs_src/background_tasks/tutorial001_py310.py hl[6:9] *}
+
+## 新增背景任務 { #add-the-background-task }
+
+在路徑操作函式內,使用 `.add_task()` 將任務函式加入背景任務物件:
+
+{* ../../docs_src/background_tasks/tutorial001_py310.py hl[14] *}
+
+`.add_task()` 的引數包括:
+
+* 要在背景執行的任務函式(`write_notification`)。
+* 依序傳給任務函式的位置引數(`email`)。
+* 要傳給任務函式的關鍵字引數(`message="some notification"`)。
+
+## 相依性注入 { #dependency-injection }
+
+在相依性注入系統中也可使用 `BackgroundTasks`。你可以在多個層級宣告 `BackgroundTasks` 型別的參數:路徑操作函式、相依項(dependable)、次級相依項等。
+
+**FastAPI** 會在各種情況下正確處理並重用同一個物件,將所有背景任務合併,並在之後於背景執行:
+
+{* ../../docs_src/background_tasks/tutorial002_an_py310.py hl[13,15,22,25] *}
+
+在此範例中,訊息會在回應送出之後寫入 `log.txt` 檔案。
+
+如果請求中有查詢參數,會以背景任務寫入日誌。
+
+接著,在路徑操作函式中建立的另一個背景任務會使用 `email` 路徑參數寫入訊息。
+
+## 技術細節 { #technical-details }
+
+類別 `BackgroundTasks` 直接來自 `starlette.background`。
+
+它被直接匯入/包含到 FastAPI 中,因此你可以從 `fastapi` 匯入它,並避免不小心從 `starlette.background` 匯入另一個同名的 `BackgroundTask`(結尾沒有 s)。
+
+只使用 `BackgroundTasks`(而非 `BackgroundTask`)時,你就能把它當作路徑操作函式的參數,並讓 **FastAPI** 幫你處理其餘部分,就像直接使用 `Request` 物件一樣。
+
+在 FastAPI 中仍可單獨使用 `BackgroundTask`,但你需要在程式碼中自行建立該物件,並回傳包含它的 Starlette `Response`。
+
+更多細節請參閱 Starlette 官方的 Background Tasks 文件。
+
+## 注意事項 { #caveat }
+
+如果你需要執行繁重的背景計算,且不一定要由同一個行程執行(例如不需要共用記憶體、變數等),可以考慮使用更大型的工具,例如 Celery。
+
+這類工具通常需要較複雜的設定,以及訊息/工作佇列管理器(如 RabbitMQ 或 Redis),但它們允許你在多個行程,甚至多台伺服器上執行背景任務。
+
+但如果你需要存取同一個 **FastAPI** 應用中的變數與物件,或只需執行小型的背景任務(例如寄送郵件通知),僅使用 `BackgroundTasks` 即可。
+
+## 重點回顧 { #recap }
+
+在路徑操作函式與相依項中匯入並使用 `BackgroundTasks` 參數,以新增背景任務。
diff --git a/docs/zh-hant/docs/tutorial/bigger-applications.md b/docs/zh-hant/docs/tutorial/bigger-applications.md
new file mode 100644
index 0000000000..d8b8c9bff8
--- /dev/null
+++ b/docs/zh-hant/docs/tutorial/bigger-applications.md
@@ -0,0 +1,504 @@
+# 更大型的應用程式 - 多個檔案 { #bigger-applications-multiple-files }
+
+如果你正在建置一個應用程式或 Web API,很少會把所有東西都放在單一檔案裡。
+
+FastAPI 提供了一個方便的工具,讓你在維持彈性的同時,幫你組織應用程式的結構。
+
+/// info | 資訊
+
+如果你來自 Flask,這相當於 Flask 的 Blueprints。
+
+///
+
+## 範例檔案結構 { #an-example-file-structure }
+
+假設你有如下的檔案結構:
+
+```
+.
+├── app
+│ ├── __init__.py
+│ ├── main.py
+│ ├── dependencies.py
+│ └── routers
+│ │ ├── __init__.py
+│ │ ├── items.py
+│ │ └── users.py
+│ └── internal
+│ ├── __init__.py
+│ └── admin.py
+```
+
+/// tip | 提示
+
+有好幾個 `__init__.py` 檔案:每個目錄或子目錄各一個。
+
+這讓我們可以把一個檔案中的程式碼匯入到另一個檔案。
+
+例如,在 `app/main.py` 你可以有一行:
+
+```
+from app.routers import items
+```
+
+///
+
+* `app` 目錄包含所有內容。它有一個空的 `app/__init__.py` 檔案,所以它是一個「Python 套件」(「Python 模組」的集合):`app`。
+* 它包含一個 `app/main.py` 檔案。因為它在一個 Python 套件中(有 `__init__.py` 檔案的目錄),它是該套件的一個「模組」:`app.main`。
+* 還有一個 `app/dependencies.py` 檔案,就像 `app/main.py` 一樣,它是一個「模組」:`app.dependencies`。
+* 有一個子目錄 `app/routers/`,裡面有另一個 `__init__.py` 檔案,所以它是一個「Python 子套件」:`app.routers`。
+* 檔案 `app/routers/items.py` 在一個套件 `app/routers/` 內,因此它是一個子模組:`app.routers.items`。
+* 同樣地,`app/routers/users.py` 是另一個子模組:`app.routers.users`。
+* 還有一個子目錄 `app/internal/`,裡面有另一個 `__init__.py` 檔案,所以它又是一個「Python 子套件」:`app.internal`。
+* 檔案 `app/internal/admin.py` 是另一個子模組:`app.internal.admin`。
+
+
+
+同樣的檔案結構,附上註解:
+
+```bash
+.
+├── app # 「app」是一個 Python 套件
+│ ├── __init__.py # 這個檔案讓「app」成為「Python 套件」
+│ ├── main.py # 「main」模組,例如 import app.main
+│ ├── dependencies.py # 「dependencies」模組,例如 import app.dependencies
+│ └── routers # 「routers」是一個「Python 子套件」
+│ │ ├── __init__.py # 讓「routers」成為「Python 子套件」
+│ │ ├── items.py # 「items」子模組,例如 import app.routers.items
+│ │ └── users.py # 「users」子模組,例如 import app.routers.users
+│ └── internal # 「internal」是一個「Python 子套件」
+│ ├── __init__.py # 讓「internal」成為「Python 子套件」
+│ └── admin.py # 「admin」子模組,例如 import app.internal.admin
+```
+
+## `APIRouter` { #apirouter }
+
+假設專門處理使用者的檔案是位於 `/app/routers/users.py` 的子模組。
+
+你希望把與使用者相關的「路徑操作 (path operation)」從其他程式碼分離,讓結構更有條理。
+
+但它仍然是同一個 FastAPI 應用程式 / Web API 的一部分(屬於同一個「Python 套件」)。
+
+你可以使用 `APIRouter` 為該模組建立路徑操作。
+
+### 匯入 `APIRouter` { #import-apirouter }
+
+你可以像對 `FastAPI` 類別那樣匯入並建立一個「實例」:
+
+{* ../../docs_src/bigger_applications/app_an_py310/routers/users.py hl[1,3] title["app/routers/users.py"] *}
+
+### 使用 `APIRouter` 宣告路徑操作 { #path-operations-with-apirouter }
+
+然後用它來宣告你的路徑操作。
+
+用法就和 `FastAPI` 類別一樣:
+
+{* ../../docs_src/bigger_applications/app_an_py310/routers/users.py hl[6,11,16] title["app/routers/users.py"] *}
+
+你可以把 `APIRouter` 想成是「迷你版的 `FastAPI`」類別。
+
+所有相同的選項都支援。
+
+同樣的 `parameters`、`responses`、`dependencies`、`tags` 等全都可用。
+
+/// tip | 提示
+
+在這個範例中,變數名叫 `router`,但你可以用任何你想用的名稱。
+
+///
+
+我們稍後會把這個 `APIRouter` 加進主要的 `FastAPI` 應用程式中,但先來看看相依性與另一個 `APIRouter`。
+
+## 相依性 { #dependencies }
+
+我們發現應用程式的多個地方會用到一些相依性。
+
+所以把它們放進獨立的 `dependencies` 模組(`app/dependencies.py`)。
+
+接下來我們會用一個簡單的相依性來讀取自訂的 `X-Token` 標頭:
+
+{* ../../docs_src/bigger_applications/app_an_py310/dependencies.py hl[3,6:8] title["app/dependencies.py"] *}
+
+/// tip | 提示
+
+為了簡化範例,我們使用了一個虛構的標頭。
+
+但在真實情況下,使用內建的[安全工具](security/index.md){.internal-link target=_blank}會有更好的效果。
+
+///
+
+## 另一個帶有 `APIRouter` 的模組 { #another-module-with-apirouter }
+
+假設你還有一個模組 `app/routers/items.py`,專門處理應用程式中的「items」。
+
+你有以下路徑操作:
+
+* `/items/`
+* `/items/{item_id}`
+
+其結構與 `app/routers/users.py` 相同。
+
+但我們想要更聰明地簡化一些程式碼。
+
+我們知道這個模組中的所有路徑操作都有相同的:
+
+* 路徑 `prefix`:`/items`
+* `tags`:(只有一個標籤:`items`)
+* 額外的 `responses`
+* `dependencies`:它們都需要我們先前建立的 `X-Token` 相依性
+
+因此,我們可以不必把這些都加在每個路徑操作上,而是把它們加在 `APIRouter` 上。
+
+{* ../../docs_src/bigger_applications/app_an_py310/routers/items.py hl[5:10,16,21] title["app/routers/items.py"] *}
+
+由於每個路徑操作的路徑都必須以 `/` 開頭,例如:
+
+```Python hl_lines="1"
+@router.get("/{item_id}")
+async def read_item(item_id: str):
+ ...
+```
+
+...所以 prefix 末尾不能帶有 `/`。
+
+因此,此處的 prefix 是 `/items`。
+
+我們也可以加上一個 `tags` 清單,以及會套用在此 router 內所有路徑操作上的額外 `responses`。
+
+我們還可以加上一個 `dependencies` 清單,這些相依性會加入此 router 內所有的路徑操作,並在對它們的每個請求上執行 / 解決。
+
+/// tip | 提示
+
+請注意,就像在[路徑操作裝飾器中的相依性](dependencies/dependencies-in-path-operation-decorators.md){.internal-link target=_blank}一樣,不會把任何值傳遞給你的路徑操作函式(path operation function)。
+
+///
+
+最後的結果是這些 item 的路徑如下:
+
+* `/items/`
+* `/items/{item_id}`
+
+...正如我們預期的。
+
+* 它們會被標記為只有一個字串 `"items"` 的標籤清單。
+ * 這些「標籤」對自動互動式文件系統(使用 OpenAPI)特別有用。
+* 它們都會包含預先定義的 `responses`。
+* 這些路徑操作都會在執行前評估 / 執行其 `dependencies` 清單。
+ * 如果你也在特定的路徑操作中宣告了相依性,這些相依性也會被執行。
+ * Router 的相依性會先執行,然後是[裝飾器中的 `dependencies`](dependencies/dependencies-in-path-operation-decorators.md){.internal-link target=_blank},最後是一般參數相依性。
+ * 你也可以加入帶有 `scopes` 的 [`Security` 相依性](../advanced/security/oauth2-scopes.md){.internal-link target=_blank}。
+
+/// tip | 提示
+
+在 `APIRouter` 中設定 `dependencies`,例如可以用來對一整組路徑操作要求驗證。即使沒有在每個路徑操作個別加入相依性也沒關係。
+
+///
+
+/// check | 檢查
+
+`prefix`、`tags`、`responses` 與 `dependencies` 參數(就像許多其他情況一樣)只是 FastAPI 提供的功能,幫助你避免重複程式碼。
+
+///
+
+### 匯入相依性 { #import-the-dependencies }
+
+這段程式碼在模組 `app.routers.items`(檔案 `app/routers/items.py`)中。
+
+我們需要從模組 `app.dependencies`(檔案 `app/dependencies.py`)取得相依性函式。
+
+因此我們用 `..` 做相對匯入相依性:
+
+{* ../../docs_src/bigger_applications/app_an_py310/routers/items.py hl[3] title["app/routers/items.py"] *}
+
+#### 相對匯入如何運作 { #how-relative-imports-work }
+
+/// tip | 提示
+
+如果你對匯入的運作方式十分了解,可以直接跳到下一節。
+
+///
+
+單一的點號 `.`,如下:
+
+```Python
+from .dependencies import get_token_header
+```
+
+代表:
+
+* 從此模組(檔案 `app/routers/items.py`)所在的相同套件(目錄 `app/routers/`)開始...
+* 找到模組 `dependencies`(想像的檔案 `app/routers/dependencies.py`)...
+* 並從中匯入函式 `get_token_header`。
+
+但那個檔案不存在,我們的相依性在 `app/dependencies.py`。
+
+回想一下我們的應用 / 檔案結構長這樣:
+
+
+
+---
+
+兩個點號 `..`,如下:
+
+```Python
+from ..dependencies import get_token_header
+```
+
+代表:
+
+* 從此模組(檔案 `app/routers/items.py`)所在的相同套件(目錄 `app/routers/`)開始...
+* 前往其父套件(目錄 `app/`)...
+* 然後在那裡找到模組 `dependencies`(檔案 `app/dependencies.py`)...
+* 並從中匯入函式 `get_token_header`。
+
+這就正確了!🎉
+
+---
+
+同樣地,如果我們用三個點號 `...`,如下:
+
+```Python
+from ...dependencies import get_token_header
+```
+
+就代表:
+
+* 從此模組(檔案 `app/routers/items.py`)所在的相同套件(目錄 `app/routers/`)開始...
+* 前往其父套件(目錄 `app/`)...
+* 再前往那個套件的父層(沒有更上層的套件了,`app` 已是最上層 😱)...
+* 然後在那裡找到模組 `dependencies`(檔案 `app/dependencies.py`)...
+* 並從中匯入函式 `get_token_header`。
+
+那會指向 `app/` 之上的某個套件,該套件需有自己的 `__init__.py` 等等。但我們沒有。所以在這個例子中會丟出錯誤。🚨
+
+不過現在你知道它的運作方式了,因此無論你的應用有多複雜,你都可以使用相對匯入。🤓
+
+### 加上一些自訂的 `tags`、`responses` 與 `dependencies` { #add-some-custom-tags-responses-and-dependencies }
+
+我們沒有把 `/items` 的 prefix 以及 `tags=["items"]` 加在每個路徑操作上,因為我們已經把它們加在 `APIRouter` 上了。
+
+但我們仍可以在特定的路徑操作上再加上更多的 `tags`,以及一些只屬於該路徑操作的額外 `responses`:
+
+{* ../../docs_src/bigger_applications/app_an_py310/routers/items.py hl[30:31] title["app/routers/items.py"] *}
+
+/// tip | 提示
+
+這最後一個路徑操作會有組合後的標籤:`["items", "custom"]`。
+
+而且在文件中同時會有 `404` 與 `403` 兩種回應。
+
+///
+
+## 主程式 `FastAPI` { #the-main-fastapi }
+
+現在,來看看 `app/main.py` 這個模組。
+
+你會在這裡匯入並使用 `FastAPI` 類別。
+
+這會是你的應用程式中把一切串起來的主檔案。
+
+而隨著大多數的邏輯都放在各自的模組中,主檔案會相當簡潔。
+
+### 匯入 `FastAPI` { #import-fastapi }
+
+照常匯入並建立 `FastAPI` 類別。
+
+我們甚至可以宣告[全域相依性](dependencies/global-dependencies.md){.internal-link target=_blank},它們會與各 `APIRouter` 的相依性合併:
+
+{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[1,3,7] title["app/main.py"] *}
+
+### 匯入 `APIRouter` { #import-the-apirouter }
+
+現在我們匯入包含 `APIRouter` 的其他子模組:
+
+{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[4:5] title["app/main.py"] *}
+
+由於 `app/routers/users.py` 與 `app/routers/items.py` 是同一個 Python 套件 `app` 的子模組,我們可以用單一的點號 `.` 來進行「相對匯入」。
+
+### 匯入如何運作 { #how-the-importing-works }
+
+這段:
+
+```Python
+from .routers import items, users
+```
+
+代表:
+
+* 從此模組(檔案 `app/main.py`)所在的相同套件(目錄 `app/`)開始...
+* 尋找子套件 `routers`(目錄 `app/routers/`)...
+* 並從中匯入子模組 `items`(檔案 `app/routers/items.py`)與 `users`(檔案 `app/routers/users.py`)...
+
+模組 `items` 會有一個變數 `router`(`items.router`)。這就是我們在 `app/routers/items.py` 建立的那個 `APIRouter` 物件。
+
+接著我們對 `users` 模組做一樣的事。
+
+我們也可以這樣匯入:
+
+```Python
+from app.routers import items, users
+```
+
+/// info | 資訊
+
+第一種是「相對匯入」:
+
+```Python
+from .routers import items, users
+```
+
+第二種是「絕對匯入」:
+
+```Python
+from app.routers import items, users
+```
+
+想了解更多關於 Python 套件與模組,請閱讀官方的模組說明文件。
+
+///
+
+### 避免名稱衝突 { #avoid-name-collisions }
+
+我們直接匯入子模組 `items`,而不是只匯入它的變數 `router`。
+
+這是因為在子模組 `users` 中也有另一個名為 `router` 的變數。
+
+如果我們像下面這樣一個接一個匯入:
+
+```Python
+from .routers.items import router
+from .routers.users import router
+```
+
+來自 `users` 的 `router` 會覆蓋掉 `items` 的 `router`,我們就無法同時使用兩者。
+
+因此,為了能在同一個檔案中同時使用它們,我們直接匯入子模組:
+
+{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[5] title["app/main.py"] *}
+
+### 將 `users` 與 `items` 的 `APIRouter` 納入 { #include-the-apirouters-for-users-and-items }
+
+現在,把子模組 `users` 與 `items` 的 `router` 納入:
+
+{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[10:11] title["app/main.py"] *}
+
+/// info | 資訊
+
+`users.router` 是位於 `app/routers/users.py` 檔案內的 `APIRouter`。
+
+而 `items.router` 是位於 `app/routers/items.py` 檔案內的 `APIRouter`。
+
+///
+
+透過 `app.include_router()`,我們可以把每個 `APIRouter` 加到主要的 `FastAPI` 應用程式。
+
+它會把該 router 的所有路由都納入成為應用的一部分。
+
+/// note | 技術細節
+
+實際上,它會在內部為 `APIRouter` 中宣告的每一個「路徑操作」建立一個對應的「路徑操作」。
+
+所以在幕後,它實際運作起來就像是一個單一的應用。
+
+///
+
+/// check | 檢查
+
+把 router 納入時不需要擔心效能。
+
+這只會在啟動時花費微秒等級,且只發生一次。
+
+因此不會影響效能。⚡
+
+///
+
+### 以自訂的 `prefix`、`tags`、`responses` 與 `dependencies` 納入一個 `APIRouter` { #include-an-apirouter-with-a-custom-prefix-tags-responses-and-dependencies }
+
+現在,假設你的組織提供了一個 `app/internal/admin.py` 檔案給你。
+
+它包含一個帶有一些管理員路徑操作的 `APIRouter`,並在組織內多個專案之間共用。
+
+為了這個範例它會非常簡單。但假設因為它會與組織內的其他專案共用,我們不能直接修改它並把 `prefix`、`dependencies`、`tags` 等加在 `APIRouter` 上:
+
+{* ../../docs_src/bigger_applications/app_an_py310/internal/admin.py hl[3] title["app/internal/admin.py"] *}
+
+但當我們把這個 `APIRouter` 納入時,仍然希望設定自訂的 `prefix`,讓它所有的路徑操作都以 `/admin` 開頭;我們想用這個專案已經有的 `dependencies` 來保護它,並且要加入 `tags` 與 `responses`。
+
+我們可以在不修改原始 `APIRouter` 的情況下,將這些參數傳給 `app.include_router()` 來達成:
+
+{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[14:17] title["app/main.py"] *}
+
+如此一來,原始的 `APIRouter` 將保持不變,因此我們仍然可以把同一個 `app/internal/admin.py` 檔案與組織中的其他專案共用。
+
+結果是在我們的應用中,來自 `admin` 模組的每個路徑操作都會有:
+
+* 前綴 `/admin`
+* 標籤 `admin`
+* 相依性 `get_token_header`
+* 回應 `418` 🍵
+
+但這只會影響我們應用中的那個 `APIRouter`,不會影響任何其他使用它的程式碼。
+
+例如,其他專案可以用不同的驗證方式搭配相同的 `APIRouter`。
+
+### 加上一個路徑操作 { #include-a-path-operation }
+
+我們也可以直接把路徑操作加到 `FastAPI` 應用中。
+
+這裡我們就加一下... 只是為了示範可以這麼做 🤷:
+
+{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[21:23] title["app/main.py"] *}
+
+而且它會和透過 `app.include_router()` 加入的其他路徑操作正確地一起運作。
+
+/// info | 非常技術細節
+
+注意:這是個非常技術性的細節,你大概可以直接略過。
+
+---
+
+`APIRouter` 不是被「掛載 (mount)」的,它們不會與應用的其他部分隔離開來。
+
+這是因為我們要把它們的路徑操作包含進 OpenAPI 結構與使用者介面中。
+
+由於無法將它們隔離並獨立「掛載」,所以這些路徑操作會被「複製」(重新建立),而不是直接包含進來。
+
+///
+
+## 檢查自動產生的 API 文件 { #check-the-automatic-api-docs }
+
+現在,執行你的應用:
+
+
+
+```console
+$ fastapi dev app/main.py
+
+INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
+```
+
+
+
+然後開啟位於 http://127.0.0.1:8000/docs 的文件。
+
+你會看到自動產生的 API 文件,包含來自所有子模組的路徑,使用正確的路徑(與前綴)與正確的標籤:
+
+
+
+## 以不同的 `prefix` 多次納入同一個 router { #include-the-same-router-multiple-times-with-different-prefix }
+
+你也可以用不同的前綴,對同一個 router 多次呼叫 `.include_router()`。
+
+例如,這對於在不同前綴下提供相同的 API 很有用,如 `/api/v1` 與 `/api/latest`。
+
+這是進階用法,你可能不會需要,但若有需要它就在那裡。
+
+## 在另一個 `APIRouter` 中納入一個 `APIRouter` { #include-an-apirouter-in-another }
+
+就像你可以在 `FastAPI` 應用中納入一個 `APIRouter` 一樣,你也可以在另一個 `APIRouter` 中納入一個 `APIRouter`,用法如下:
+
+```Python
+router.include_router(other_router)
+```
+
+請確保在把 `router` 納入 `FastAPI` 應用之前先這麼做,這樣 `other_router` 的路徑操作也會被包含進去。
diff --git a/docs/zh-hant/docs/tutorial/body-fields.md b/docs/zh-hant/docs/tutorial/body-fields.md
new file mode 100644
index 0000000000..a16e756b7c
--- /dev/null
+++ b/docs/zh-hant/docs/tutorial/body-fields.md
@@ -0,0 +1,61 @@
+# Body - 欄位 { #body-fields }
+
+就像你可以在「路徑操作函式 (path operation function)」的參數中用 `Query`、`Path` 和 `Body` 宣告額外的驗證與中繼資料一樣,你也可以在 Pydantic 模型中使用 Pydantic 的 `Field` 來宣告驗證與中繼資料。
+
+## 匯入 `Field` { #import-field }
+
+首先,你需要匯入它:
+
+{* ../../docs_src/body_fields/tutorial001_an_py310.py hl[4] *}
+
+
+/// warning
+
+請注意,`Field` 是直接從 `pydantic` 匯入的,不像其他(如 `Query`、`Path`、`Body` 等)是從 `fastapi` 匯入。
+
+///
+
+## 宣告模型屬性 { #declare-model-attributes }
+
+接著你可以在模型屬性上使用 `Field`:
+
+{* ../../docs_src/body_fields/tutorial001_an_py310.py hl[11:14] *}
+
+`Field` 的用法與 `Query`、`Path`、`Body` 相同,擁有相同的參數等。
+
+/// note | 技術細節
+
+實際上,你接下來會看到的 `Query`、`Path` 等,會建立共同父類別 `Param` 的子類別物件,而 `Param` 本身是 Pydantic 的 `FieldInfo` 類別的子類別。
+
+而 Pydantic 的 `Field` 也會回傳一個 `FieldInfo` 的實例。
+
+`Body` 也會直接回傳 `FieldInfo` 子類別的物件。稍後你會看到還有其他類別是 `Body` 類別的子類別。
+
+記得,當你從 `fastapi` 匯入 `Query`、`Path` 等時,它們其實是回傳特殊類別的函式。
+
+///
+
+/// tip
+
+注意,每個帶有型別、預設值與 `Field` 的模型屬性,其結構和「路徑操作函式」的參數相同,只是把 `Path`、`Query`、`Body` 換成了 `Field`。
+
+///
+
+## 加入額外資訊 { #add-extra-information }
+
+你可以在 `Field`、`Query`、`Body` 等中宣告額外資訊。這些資訊會被包含在產生的 JSON Schema 中。
+
+你會在後續文件中學到更多關於加入額外資訊的內容,特別是在宣告範例時。
+
+/// warning
+
+傳入 `Field` 的額外鍵也會出現在你的應用程式所產生的 OpenAPI schema 中。
+由於這些鍵不一定屬於 OpenAPI 規格的一部分,一些 OpenAPI 工具(例如 [OpenAPI 驗證器](https://validator.swagger.io/))可能無法處理你產生的 schema。
+
+///
+
+## 回顧 { #recap }
+
+你可以使用 Pydantic 的 `Field` 為模型屬性宣告額外的驗證與中繼資料。
+
+你也可以使用額外的關鍵字引數來傳遞額外的 JSON Schema 中繼資料。
diff --git a/docs/zh-hant/docs/tutorial/body-multiple-params.md b/docs/zh-hant/docs/tutorial/body-multiple-params.md
new file mode 100644
index 0000000000..1c334f51f5
--- /dev/null
+++ b/docs/zh-hant/docs/tutorial/body-multiple-params.md
@@ -0,0 +1,165 @@
+# Body - 多個參數 { #body-multiple-parameters }
+
+現在我們已經知道如何使用 `Path` 與 `Query`,接下來看看更進階的請求主體(request body)宣告用法。
+
+## 混用 `Path`、`Query` 與 Body 參數 { #mix-path-query-and-body-parameters }
+
+首先,當然你可以自由混用 `Path`、`Query` 與請求 Body 參數的宣告,**FastAPI** 會知道該怎麼做。
+
+你也可以將 Body 參數宣告為可選,方法是將預設值設為 `None`:
+
+{* ../../docs_src/body_multiple_params/tutorial001_an_py310.py hl[18:20] *}
+
+/// note | 注意
+
+請注意,在此情況下,從 body 取得的 `item` 是可選的,因為它的預設值是 `None`。
+
+///
+
+## 多個 Body 參數 { #multiple-body-parameters }
+
+在前一個範例中,路徑操作(path operation)會期望一個包含 `Item` 屬性的 JSON 主體,例如:
+
+```JSON
+{
+ "name": "Foo",
+ "description": "The pretender",
+ "price": 42.0,
+ "tax": 3.2
+}
+```
+
+但你也可以宣告多個 Body 參數,例如 `item` 與 `user`:
+
+{* ../../docs_src/body_multiple_params/tutorial002_py310.py hl[20] *}
+
+在此情況下,**FastAPI** 會注意到函式中有多個 Body 參數(有兩個參數是 Pydantic 模型)。
+
+因此,它會使用參數名稱作為 body 中的鍵(欄位名稱),並期望如下的主體:
+
+```JSON
+{
+ "item": {
+ "name": "Foo",
+ "description": "The pretender",
+ "price": 42.0,
+ "tax": 3.2
+ },
+ "user": {
+ "username": "dave",
+ "full_name": "Dave Grohl"
+ }
+}
+```
+
+/// note | 注意
+
+儘管 `item` 的宣告方式與先前相同,現在預期它會位於 body 內,且鍵為 `item`。
+
+///
+
+**FastAPI** 會自動從請求中進行轉換,讓參數 `item` 收到對應內容,`user` 亦同。
+
+它會對複合資料進行驗證,並在 OpenAPI 結構與自動文件中如此描述。
+
+## Body 中的單一值 { #singular-values-in-body }
+
+就像你可以用 `Query` 與 `Path` 為查詢與路徑參數定義額外資訊一樣,**FastAPI** 也提供對應的 `Body`。
+
+例如,延伸前述模型,你可以決定在相同的 Body 中,除了 `item` 與 `user` 外,還要有另一個鍵 `importance`。
+
+如果直接這樣宣告,因為它是單一值,**FastAPI** 會將其視為查詢參數。
+
+但你可以使用 `Body` 指示 **FastAPI** 將其視為另一個 Body 鍵:
+
+{* ../../docs_src/body_multiple_params/tutorial003_an_py310.py hl[23] *}
+
+在此情況下,**FastAPI** 會期望如下的主體:
+
+```JSON
+{
+ "item": {
+ "name": "Foo",
+ "description": "The pretender",
+ "price": 42.0,
+ "tax": 3.2
+ },
+ "user": {
+ "username": "dave",
+ "full_name": "Dave Grohl"
+ },
+ "importance": 5
+}
+```
+
+同樣地,它會進行型別轉換、驗證、文件化等。
+
+## 多個 Body 參數與 Query { #multiple-body-params-and-query }
+
+當然,你也可以在任何 Body 參數之外,視需要宣告額外的查詢參數。
+
+由於預設情況下,單一值會被解讀為查詢參數,你不必明確使用 `Query`,直接這樣寫即可:
+
+```Python
+q: str | None = None
+```
+
+例如:
+
+{* ../../docs_src/body_multiple_params/tutorial004_an_py310.py hl[28] *}
+
+/// info | 注意
+
+`Body` 也具有與 `Query`、`Path` 以及之後你會看到的其他工具相同的額外驗證與中繼資料參數。
+
+///
+
+## 嵌入單一 Body 參數 { #embed-a-single-body-parameter }
+
+假設你只有一個來自 Pydantic 模型 `Item` 的單一 `item` Body 參數。
+
+預設情況下,**FastAPI** 會直接期望該模型的內容作為請求主體。
+
+但如果你想讓它像宣告多個 Body 參數時那樣,期望一個帶有 `item` 鍵、其內含模型內容的 JSON,你可以使用 `Body` 的特殊參數 `embed`:
+
+```Python
+item: Item = Body(embed=True)
+```
+
+如下:
+
+{* ../../docs_src/body_multiple_params/tutorial005_an_py310.py hl[17] *}
+
+在此情況下 **FastAPI** 會期望如下的主體:
+
+```JSON hl_lines="2"
+{
+ "item": {
+ "name": "Foo",
+ "description": "The pretender",
+ "price": 42.0,
+ "tax": 3.2
+ }
+}
+```
+
+而不是:
+
+```JSON
+{
+ "name": "Foo",
+ "description": "The pretender",
+ "price": 42.0,
+ "tax": 3.2
+}
+```
+
+## 小結 { #recap }
+
+即便一個請求只能有單一主體,你仍可在你的路徑操作函式中宣告多個 Body 參數。
+
+但 **FastAPI** 會處理好這一切,在你的函式中提供正確的資料,並在路徑操作中驗證與文件化正確的結構。
+
+你也可以將單一值宣告為 Body 的一部分來接收。
+
+即使只宣告了一個參數,也可以指示 **FastAPI** 將 Body 以某個鍵進行嵌入。
diff --git a/docs/zh-hant/docs/tutorial/body-nested-models.md b/docs/zh-hant/docs/tutorial/body-nested-models.md
new file mode 100644
index 0000000000..df4aff6972
--- /dev/null
+++ b/docs/zh-hant/docs/tutorial/body-nested-models.md
@@ -0,0 +1,220 @@
+# Body - 巢狀模型 { #body-nested-models }
+
+使用 **FastAPI**,你可以定義、驗證、文件化,並使用任意深度的巢狀模型(感謝 Pydantic)。
+
+## 列表欄位 { #list-fields }
+
+你可以將屬性定義為某個子型別。例如,Python 的 `list`:
+
+{* ../../docs_src/body_nested_models/tutorial001_py310.py hl[12] *}
+
+這會讓 `tags` 成為一個列表,儘管尚未宣告列表元素的型別。
+
+## 具有型別參數的列表欄位 { #list-fields-with-type-parameter }
+
+不過,Python 有一種專門的方式來宣告具有內部型別(「型別參數」)的列表:
+
+### 宣告帶有型別參數的 `list` { #declare-a-list-with-a-type-parameter }
+
+要宣告具有型別參數(內部型別)的型別,例如 `list`、`dict`、`tuple`,使用方括號 `[` 與 `]` 傳入內部型別作為「型別參數」:
+
+```Python
+my_list: list[str]
+```
+
+以上都是標準的 Python 型別宣告語法。
+
+對於具有內部型別的模型屬性,也使用相同的標準語法。
+
+因此,在我們的範例中,可以讓 `tags` 明確成為「字串的列表」:
+
+{* ../../docs_src/body_nested_models/tutorial002_py310.py hl[12] *}
+
+## 集合型別 { #set-types }
+
+但進一步思考後,我們會意識到 `tags` 不應該重覆,應該是唯一的字串。
+
+而 Python 有一種用於唯一元素集合的特殊資料型別:`set`。
+
+因此我們可以將 `tags` 宣告為字串的 `set`:
+
+{* ../../docs_src/body_nested_models/tutorial003_py310.py hl[12] *}
+
+這樣一來,即使收到包含重覆資料的請求,也會被轉換為由唯一元素組成的 `set`。
+
+之後只要輸出該資料,即使來源有重覆,也會以唯一元素的 `set` 輸出。
+
+並且也會在註解/文件中相應標示。
+
+## 巢狀模型 { #nested-models }
+
+每個 Pydantic 模型的屬性都有型別。
+
+而該型別本身也可以是另一個 Pydantic 模型。
+
+因此,你可以宣告具有特定屬性名稱、型別與驗證的深度巢狀 JSON「物件」。
+
+而且可以任意深度巢狀。
+
+### 定義子模型 { #define-a-submodel }
+
+例如,我們可以定義一個 `Image` 模型:
+
+{* ../../docs_src/body_nested_models/tutorial004_py310.py hl[7:9] *}
+
+### 將子模型作為型別使用 { #use-the-submodel-as-a-type }
+
+然後把它作為某個屬性的型別使用:
+
+{* ../../docs_src/body_nested_models/tutorial004_py310.py hl[18] *}
+
+這表示 **FastAPI** 會期望一個類似如下的本文:
+
+```JSON
+{
+ "name": "Foo",
+ "description": "The pretender",
+ "price": 42.0,
+ "tax": 3.2,
+ "tags": ["rock", "metal", "bar"],
+ "image": {
+ "url": "http://example.com/baz.jpg",
+ "name": "The Foo live"
+ }
+}
+```
+
+只需進行上述宣告,使用 **FastAPI** 你就能獲得:
+
+- 編輯器支援(自動完成等),即使是巢狀模型
+- 資料轉換
+- 資料驗證
+- 自動產生文件
+
+## 特殊型別與驗證 { #special-types-and-validation }
+
+除了 `str`、`int`、`float` 等一般的單一型別外,你也可以使用繼承自 `str` 的更複雜單一型別。
+
+若要查看所有可用選項,請參閱 Pydantic 的型別總覽。你會在下一章看到一些範例。
+
+例如,在 `Image` 模型中有一個 `url` 欄位,我們可以將其宣告為 Pydantic 的 `HttpUrl`,而不是 `str`:
+
+{* ../../docs_src/body_nested_models/tutorial005_py310.py hl[2,8] *}
+
+該字串會被檢查是否為有效的 URL,並在 JSON Schema / OpenAPI 中相應註記。
+
+## 具有子模型列表的屬性 { #attributes-with-lists-of-submodels }
+
+你也可以將 Pydantic 模型作為 `list`、`set` 等的子型別使用:
+
+{* ../../docs_src/body_nested_models/tutorial006_py310.py hl[18] *}
+
+這會期望(並進行轉換、驗證、文件化等)如下的 JSON 本文:
+
+```JSON hl_lines="11"
+{
+ "name": "Foo",
+ "description": "The pretender",
+ "price": 42.0,
+ "tax": 3.2,
+ "tags": [
+ "rock",
+ "metal",
+ "bar"
+ ],
+ "images": [
+ {
+ "url": "http://example.com/baz.jpg",
+ "name": "The Foo live"
+ },
+ {
+ "url": "http://example.com/dave.jpg",
+ "name": "The Baz"
+ }
+ ]
+}
+```
+
+/// info
+
+注意 `images` 鍵現在是一個由 image 物件組成的列表。
+
+///
+
+## 深度巢狀模型 { #deeply-nested-models }
+
+你可以定義任意深度的巢狀模型:
+
+{* ../../docs_src/body_nested_models/tutorial007_py310.py hl[7,12,18,21,25] *}
+
+/// info
+
+請注意,`Offer` 具有一個 `Item` 的列表,而每個 `Item` 又有一個可選的 `Image` 列表。
+
+///
+
+## 純列表的本文 { #bodies-of-pure-lists }
+
+如果你期望的 JSON 本文頂層值是一個 JSON `array`(Python 的 `list`),可以像在 Pydantic 模型中那樣,直接在函式參數上宣告其型別:
+
+```Python
+images: list[Image]
+```
+
+如下所示:
+
+{* ../../docs_src/body_nested_models/tutorial008_py310.py hl[13] *}
+
+## 隨處可得的編輯器支援 { #editor-support-everywhere }
+
+你將在各處獲得編輯器支援。
+
+即使是列表中的項目也一樣:
+
+
+
+若直接操作 `dict` 而不是使用 Pydantic 模型,就無法獲得這種等級的編輯器支援。
+
+但你也不必擔心,傳入的 dict 會自動被轉換,而你的輸出也會自動轉換為 JSON。
+
+## 任意 `dict` 的本文 { #bodies-of-arbitrary-dicts }
+
+你也可以將本文宣告為一個 `dict`,其鍵為某種型別、值為另一種型別。
+
+如此一來,你無需事先知道有效的欄位/屬性名稱為何(不像使用 Pydantic 模型時需要)。
+
+這在你想接收尚未預知的鍵時很有用。
+
+---
+
+另一個實用情境是當你希望鍵是其他型別(例如,`int`)時。
+
+這正是我們在此要示範的。
+
+在此情況下,只要是擁有 `int` 鍵且對應 `float` 值的 `dict` 都會被接受:
+
+{* ../../docs_src/body_nested_models/tutorial009_py310.py hl[7] *}
+
+/// tip
+
+請記住,JSON 只支援 `str` 作為鍵。
+
+但 Pydantic 具有自動資料轉換。
+
+這表示即使你的 API 用戶端只能以字串作為鍵,只要這些字串是純整數,Pydantic 會自動轉換並驗證它們。
+
+而你作為 `weights` 所接收的 `dict`,實際上會擁有 `int` 鍵與 `float` 值。
+
+///
+
+## 總結 { #recap }
+
+使用 **FastAPI**,你在保持程式碼簡潔優雅的同時,亦可擁有 Pydantic 模型所提供的高度彈性。
+
+同時還具備以下優點:
+
+- 編輯器支援(到處都有自動完成!)
+- 資料轉換(亦即 parsing/serialization)
+- 資料驗證
+- 結構描述(Schema)文件
+- 自動產生文件
diff --git a/docs/zh-hant/docs/tutorial/body-updates.md b/docs/zh-hant/docs/tutorial/body-updates.md
new file mode 100644
index 0000000000..a309e3522c
--- /dev/null
+++ b/docs/zh-hant/docs/tutorial/body-updates.md
@@ -0,0 +1,100 @@
+# Body - 更新 { #body-updates }
+
+## 使用 `PUT` 取代式更新 { #update-replacing-with-put }
+
+要更新一個項目,你可以使用 HTTP `PUT` 操作。
+
+你可以使用 `jsonable_encoder` 將輸入資料轉換為可儲存為 JSON 的資料(例如用於 NoSQL 資料庫)。例如把 `datetime` 轉成 `str`。
+
+{* ../../docs_src/body_updates/tutorial001_py310.py hl[28:33] *}
+
+`PUT` 用於接收應該取代現有資料的資料。
+
+### 關於取代的警告 { #warning-about-replacing }
+
+這表示,如果你想用 `PUT` 並在 body 中包含以下內容來更新項目 `bar`:
+
+```Python
+{
+ "name": "Barz",
+ "price": 3,
+ "description": None,
+}
+```
+
+由於這裡沒有包含已儲存的屬性 `"tax": 20.2`,輸入的模型會採用預設值 `"tax": 10.5`。
+
+最終資料會以這個「新的」 `tax` 值 `10.5` 被儲存。
+
+## 使用 `PATCH` 進行部分更新 { #partial-updates-with-patch }
+
+你也可以使用 HTTP `PATCH` 操作來進行*部分*更新。
+
+這表示你只需傳送想要更新的資料,其餘保持不變。
+
+/// note | 注意
+
+`PATCH` 相較於 `PUT` 較少被使用、也較不為人知。
+
+許多團隊甚至在部分更新時也只用 `PUT`。
+
+你可以依需求自由選用,**FastAPI** 不會強制規範。
+
+但本指南會大致示範它們各自的設計用法。
+
+///
+
+### 使用 Pydantic 的 `exclude_unset` 參數 { #using-pydantics-exclude-unset-parameter }
+
+如果要接收部分更新,在 Pydantic 模型的 `.model_dump()` 中使用 `exclude_unset` 參數非常實用。
+
+例如 `item.model_dump(exclude_unset=True)`。
+
+這會產生一個只包含建立 `item` 模型時實際設定過之欄位的 `dict`,不含預設值。
+
+接著你可以用它來生成只包含實際設定(請求中傳來)的資料之 `dict`,省略預設值:
+
+{* ../../docs_src/body_updates/tutorial002_py310.py hl[32] *}
+
+### 使用 Pydantic 的 `update` 參數 { #using-pydantics-update-parameter }
+
+接著,你可以用 `.model_copy()` 建立現有模型的副本,並傳入含有要更新資料之 `dict` 到 `update` 參數。
+
+例如 `stored_item_model.model_copy(update=update_data)`:
+
+{* ../../docs_src/body_updates/tutorial002_py310.py hl[33] *}
+
+### 部分更新摘要 { #partial-updates-recap }
+
+總結一下,若要套用部分更新,你可以:
+
+*(可選)使用 `PATCH` 取代 `PUT`。
+* 取回已儲存的資料。
+* 將該資料放入一個 Pydantic 模型。
+* 從輸入模型產生一個不含預設值的 `dict`(使用 `exclude_unset`)。
+ * 如此即可只更新使用者實際設定的值,而不會以模型的預設值覆寫已儲存的值。
+* 建立已儲存模型的副本,並以收到的部分更新值更新其屬性(使用 `update` 參數)。
+* 將該副本模型轉成可儲存到資料庫的型別(例如使用 `jsonable_encoder`)。
+ * 這與再次使用模型的 `.model_dump()` 類似,但它會確保(並轉換)所有值為可轉為 JSON 的資料型別,例如把 `datetime` 轉為 `str`。
+* 將資料儲存到資料庫。
+* 回傳更新後的模型。
+
+{* ../../docs_src/body_updates/tutorial002_py310.py hl[28:35] *}
+
+/// tip | 提示
+
+其實你也可以在 HTTP `PUT` 操作中使用同一套技巧。
+
+但此處示例使用 `PATCH`,因為它正是為這類情境設計的。
+
+///
+
+/// note | 注意
+
+請注意,輸入的模型依然會被驗證。
+
+因此,如果你希望接收可以省略所有屬性的部分更新,你需要一個所有屬性皆為可選(具預設值或為 `None`)的模型。
+
+為了區分用於更新(全部可選)與用於建立(欄位為必填)的模型,你可以參考 [額外模型](extra-models.md){.internal-link target=_blank} 中的做法。
+
+///
diff --git a/docs/zh-hant/docs/tutorial/body.md b/docs/zh-hant/docs/tutorial/body.md
new file mode 100644
index 0000000000..bddcbbf434
--- /dev/null
+++ b/docs/zh-hant/docs/tutorial/body.md
@@ -0,0 +1,164 @@
+# 請求本文 { #request-body }
+
+當你需要從用戶端(例如瀏覽器)將資料傳送到你的 API 時,會把它作為**請求本文**送出。
+
+**請求**本文是用戶端傳給你的 API 的資料。**回應**本文是你的 API 傳回給用戶端的資料。
+
+你的 API 幾乎總是需要傳回**回應**本文。但用戶端不一定每次都要送出**請求本文**,有時只會請求某個路徑,可能帶一些查詢參數,但不會傳送本文。
+
+要宣告**請求**本文,你會使用 Pydantic 模型,享受其完整的功能與優點。
+
+/// info
+
+要傳送資料,應使用下列其中一種方法:`POST`(最常見)、`PUT`、`DELETE` 或 `PATCH`。
+
+在規範中,於 `GET` 請求中攜帶本文的行為是未定義的。不過,FastAPI 仍支援它,但僅適用於非常複雜/極端的情境。
+
+由於不建議這麼做,使用 Swagger UI 的互動式文件在使用 `GET` 時不會顯示本文的文件,而且中間的代理伺服器也可能不支援。
+
+///
+
+## 匯入 Pydantic 的 `BaseModel` { #import-pydantics-basemodel }
+
+首先,從 `pydantic` 匯入 `BaseModel`:
+
+{* ../../docs_src/body/tutorial001_py310.py hl[2] *}
+
+## 建立你的資料模型 { #create-your-data-model }
+
+接著,你將資料模型宣告為繼承自 `BaseModel` 的類別。
+
+對所有屬性使用標準的 Python 型別:
+
+{* ../../docs_src/body/tutorial001_py310.py hl[5:9] *}
+
+就和宣告查詢參數時一樣,當模型屬性有預設值時,它就不是必填;否則就是必填。使用 `None` 可使其成為選填。
+
+例如,上述模型對應的 JSON「`object`」(或 Python `dict`)如下:
+
+```JSON
+{
+ "name": "Foo",
+ "description": "An optional description",
+ "price": 45.2,
+ "tax": 3.5
+}
+```
+
+...由於 `description` 與 `tax` 是選填(預設為 `None`),以下這個 JSON「`object`」也有效:
+
+```JSON
+{
+ "name": "Foo",
+ "price": 45.2
+}
+```
+
+## 將它宣告為參數 { #declare-it-as-a-parameter }
+
+要把它加到你的*路徑操作(path operation)*中,宣告方式與路徑與查詢參數相同:
+
+{* ../../docs_src/body/tutorial001_py310.py hl[16] *}
+
+...並將其型別宣告為你建立的模型 `Item`。
+
+## 效果 { #results }
+
+只靠這樣的 Python 型別宣告,**FastAPI** 會:
+
+- 將請求本文讀取為 JSON。
+- (必要時)轉換為對應的型別。
+- 驗證資料。
+ - 若資料無效,會回傳清楚易懂的錯誤,指出哪裡、哪筆資料不正確。
+- 把接收到的資料放在參數 `item` 中提供給你。
+ - 由於你在函式中將其宣告為 `Item` 型別,你也會獲得完整的編輯器支援(自動完成等)以及所有屬性與其型別。
+- 為你的模型產生 JSON Schema 定義,如有需要,你也可以在專案中的其他地方使用。
+- 這些 schema 會成為產生的 OpenAPI schema 的一部分,並由自動文件 UIs 使用。
+
+## 自動文件 { #automatic-docs }
+
+你的模型的 JSON Schema 會納入產生的 OpenAPI schema,並顯示在互動式 API 文件中:
+
+
+
+也會用於每個需要它們的*路徑操作*內的 API 文件:
+
+
+
+## 編輯器支援 { #editor-support }
+
+在編輯器裡、於你的函式中,你會在各處獲得型別提示與自動完成(如果你接收的是 `dict` 而不是 Pydantic 模型,就不會有這些):
+
+
+
+你也會獲得對不正確型別操作的錯誤檢查:
+
+
+
+這不是偶然,整個框架就是圍繞這個設計而建。
+
+而且在實作之前的設計階段就已徹底測試,確保能在各種編輯器中運作良好。
+
+甚至為了支援這點,Pydantic 本身也做了些修改。
+
+前面的螢幕截圖是使用 Visual Studio Code 拍的。
+
+但你在 PyCharm 與大多數其它 Python 編輯器中也會得到相同的編輯器支援:
+
+
+
+/// tip
+
+如果你使用 PyCharm 作為編輯器,可以安裝 Pydantic PyCharm Plugin。
+
+它能增強 Pydantic 模型的編輯器支援,包含:
+
+- 自動完成
+- 型別檢查
+- 重構
+- 搜尋
+- 程式碼檢查
+
+///
+
+## 使用該模型 { #use-the-model }
+
+在函式內,你可以直接存取模型物件的所有屬性:
+
+{* ../../docs_src/body/tutorial002_py310.py *}
+
+## 請求本文 + 路徑參數 { #request-body-path-parameters }
+
+你可以同時宣告路徑參數與請求本文。
+
+**FastAPI** 會辨識出與路徑參數相符的函式參數應該從**路徑**取得,而宣告為 Pydantic 模型的函式參數應該從**請求本文**取得。
+
+{* ../../docs_src/body/tutorial003_py310.py hl[15:16] *}
+
+## 請求本文 + 路徑 + 查詢參數 { #request-body-path-query-parameters }
+
+你也可以同時宣告**本文**、**路徑**與**查詢**參數。
+
+**FastAPI** 會分別辨識並從正確的位置取得資料。
+
+{* ../../docs_src/body/tutorial004_py310.py hl[16] *}
+
+函式參數的辨識方式如下:
+
+- 如果參數同時在**路徑**中宣告,則作為路徑參數。
+- 如果參數是**單一型別**(像是 `int`、`float`、`str`、`bool` 等),會被視為**查詢**參數。
+- 如果參數宣告為 **Pydantic 模型** 型別,會被視為請求**本文**。
+
+/// note
+
+FastAPI 會因為預設值 `= None` 而知道 `q` 的值不是必填。
+
+`str | None` 並非 FastAPI 用來判斷是否必填的依據;它會因為有預設值 `= None` 而知道不是必填。
+
+但加入這些型別註解能讓你的編輯器提供更好的支援與錯誤偵測。
+
+///
+
+## 不使用 Pydantic { #without-pydantic }
+
+若你不想使用 Pydantic 模型,也可以使用 **Body** 參數。請參考[Body - 多個參數:本文中的單一值](body-multiple-params.md#singular-values-in-body){.internal-link target=_blank}。
diff --git a/docs/zh-hant/docs/tutorial/cookie-param-models.md b/docs/zh-hant/docs/tutorial/cookie-param-models.md
new file mode 100644
index 0000000000..8997903e38
--- /dev/null
+++ b/docs/zh-hant/docs/tutorial/cookie-param-models.md
@@ -0,0 +1,76 @@
+# Cookie 參數模型 { #cookie-parameter-models }
+
+如果你有一組彼此相關的「**Cookie**」,你可以建立一個「**Pydantic 模型**」來宣告它們。🍪
+
+這樣你就能在**多處**重複使用該模型,並且能一次性為所有參數宣告**驗證**與**中繼資料**。😎
+
+/// note | 注意
+
+自 FastAPI 版本 `0.115.0` 起支援。🤓
+
+///
+
+/// tip
+
+同樣的技巧也適用於 `Query`、`Cookie` 與 `Header`。😎
+
+///
+
+## 以 Pydantic 模型宣告 Cookie { #cookies-with-a-pydantic-model }
+
+在 **Pydantic 模型**中宣告所需的 **Cookie** 參數,接著將參數宣告為 `Cookie`:
+
+{* ../../docs_src/cookie_param_models/tutorial001_an_py310.py hl[9:12,16] *}
+
+**FastAPI** 會從請求收到的 **Cookie** 中擷取 **每個欄位** 的資料,並交給你定義的 Pydantic 模型。
+
+## 查看文件 { #check-the-docs }
+
+你可以在 `/docs` 的文件介面中看到已定義的 Cookie:
+
+
+

+
+
+/// info
+
+請注意,由於**瀏覽器會以特殊且在背景進行的方式處理 Cookie**,因此**不會**輕易允許 **JavaScript** 存取它們。
+
+當你前往位於 `/docs` 的 **API 文件介面**時,可以看到路徑操作的 Cookie 說明。
+
+但即使你**填入資料**並點擊「Execute」,因為該文件介面是以 **JavaScript** 運作,Cookie 不會被送出,你會看到**錯誤**訊息,就像完全沒有填任何值一樣。
+
+///
+
+## 禁止額外的 Cookie { #forbid-extra-cookies }
+
+在某些特殊情境(可能不太常見)下,你可能會想**限制**允許接收的 Cookie。
+
+你的 API 現在也能掌控自己的 Cookie 同意。🤪🍪
+
+你可以使用 Pydantic 的模型設定來 `forbid` 任何 `extra` 欄位:
+
+{* ../../docs_src/cookie_param_models/tutorial002_an_py310.py hl[10] *}
+
+如果客戶端嘗試送出**額外的 Cookie**,會收到**錯誤**回應。
+
+可憐的 Cookie 橫幅辛苦收集你的同意,最後卻是為了讓 API 拒絕它。🍪
+
+例如,若客戶端嘗試送出名為 `santa_tracker`、值為 `good-list-please` 的 Cookie,客戶端會收到**錯誤**回應,告知 `santa_tracker` 這個 Cookie 不被允許:
+
+```json
+{
+ "detail": [
+ {
+ "type": "extra_forbidden",
+ "loc": ["cookie", "santa_tracker"],
+ "msg": "Extra inputs are not permitted",
+ "input": "good-list-please",
+ }
+ ]
+}
+```
+
+## 摘要 { #summary }
+
+你可以在 **FastAPI** 中使用 **Pydantic 模型**來宣告 **Cookie**。😎
diff --git a/docs/zh-hant/docs/tutorial/cookie-params.md b/docs/zh-hant/docs/tutorial/cookie-params.md
new file mode 100644
index 0000000000..cc9d4b6828
--- /dev/null
+++ b/docs/zh-hant/docs/tutorial/cookie-params.md
@@ -0,0 +1,45 @@
+# Cookie 參數 { #cookie-parameters }
+
+你可以用與定義 `Query` 與 `Path` 參數相同的方式定義 Cookie 參數。
+
+## 匯入 `Cookie` { #import-cookie }
+
+先匯入 `Cookie`:
+
+{* ../../docs_src/cookie_params/tutorial001_an_py310.py hl[3] *}
+
+## 宣告 `Cookie` 參數 { #declare-cookie-parameters }
+
+然後用與 `Path`、`Query` 相同的結構宣告 `Cookie` 參數。
+
+你可以設定預設值,以及所有額外的驗證或註解參數:
+
+{* ../../docs_src/cookie_params/tutorial001_an_py310.py hl[9] *}
+
+/// note | 技術細節
+
+`Cookie` 是 `Path` 與 `Query` 的「姊妹」類別。它同樣繼承自共同的 `Param` 類別。
+
+但請記住,當你從 `fastapi` 匯入 `Query`、`Path`、`Cookie` 等時,它們實際上是回傳特殊類別的函式。
+
+///
+
+/// info
+
+要宣告 cookies,你需要使用 `Cookie`,否則參數會被當作查詢參數(query parameters)來解析。
+
+///
+
+/// info
+
+請注意,由於瀏覽器以特殊且在背後處理的方式管理 cookies,它們通常不允許 JavaScript 輕易存取它們。
+
+如果你前往位於 `/docs` 的 API 文件介面,你可以在你的路徑操作(path operations)的文件中看到 cookies 的說明。
+
+但即使你填入資料並點擊「Execute」,由於該文件介面是以 JavaScript 運作,cookies 不會被送出,你會看到一則錯誤訊息,就好像你沒有填任何值一樣。
+
+///
+
+## 總結 { #recap }
+
+使用 `Cookie` 來宣告 cookies,遵循與 `Query`、`Path` 相同的通用寫法。
diff --git a/docs/zh-hant/docs/tutorial/cors.md b/docs/zh-hant/docs/tutorial/cors.md
new file mode 100644
index 0000000000..5fa497c081
--- /dev/null
+++ b/docs/zh-hant/docs/tutorial/cors.md
@@ -0,0 +1,88 @@
+# CORS(跨來源資源共用) { #cors-cross-origin-resource-sharing }
+
+CORS 或「Cross-Origin Resource Sharing」指的是:當在瀏覽器中執行的前端以 JavaScript 與後端通訊,而後端與前端位於不同「來源(origin)」時的情境。
+
+## 來源(Origin) { #origin }
+
+一個來源是由通訊協定(`http`、`https`)、網域(`myapp.com`、`localhost`、`localhost.tiangolo.com`)與連接埠(`80`、`443`、`8080`)三者組合而成。
+
+因此,以下皆是不同的來源:
+
+* `http://localhost`
+* `https://localhost`
+* `http://localhost:8080`
+
+即使它們都在 `localhost`,但使用了不同的通訊協定或連接埠,所以它們是不同的「來源」。
+
+## 步驟 { #steps }
+
+假設你的前端在瀏覽器中執行於 `http://localhost:8080`,其 JavaScript 嘗試與執行在 `http://localhost` 的後端通訊(因為未指定連接埠,瀏覽器會假設預設連接埠為 `80`)。
+
+接著,瀏覽器會向 `:80` 的後端送出一個 HTTP `OPTIONS` 請求;若後端回傳適當的標頭,授權此不同來源(`http://localhost:8080`)的通訊,則在 `:8080` 的瀏覽器就會允許前端的 JavaScript 向 `:80` 的後端送出它的請求。
+
+為了達成這點,`:80` 的後端必須有一份「允許的來源」清單。
+
+在此情況下,該清單必須包含 `http://localhost:8080`,` :8080` 的前端才能正確運作。
+
+## 萬用字元 { #wildcards }
+
+也可以將清單宣告為 `"*"`(「wildcard」萬用字元),表示全部都允許。
+
+但那只會允許某些類型的通訊,凡是涉及憑證(credentials)的都會被排除:例如 Cookie、Authorization 標頭(像 Bearer Token 會用到的)等。
+
+因此,為了讓一切正常運作,最好明確指定被允許的來源。
+
+## 使用 `CORSMiddleware` { #use-corsmiddleware }
+
+你可以在 **FastAPI** 應用程式中使用 `CORSMiddleware` 來設定:
+
+* 匯入 `CORSMiddleware`。
+* 建立允許的來源清單(字串)。
+* 將它加入到你的 **FastAPI** 應用程式做為「中介軟體(middleware)」。
+
+你也可以指定你的後端是否允許:
+
+* 憑證(credentials,例如 Authorization 標頭、Cookie 等)。
+* 特定的 HTTP 方法(如 `POST`、`PUT`),或使用萬用字元 `"*"` 表示全部。
+* 特定的 HTTP 標頭,或使用萬用字元 `"*"` 表示全部。
+
+{* ../../docs_src/cors/tutorial001_py310.py hl[2,6:11,13:19] *}
+
+`CORSMiddleware` 的實作在預設參數上相當嚴格,因此你需要明確啟用特定的來源、方法或標頭,瀏覽器才會允許在跨網域情境中使用它們。
+
+支援以下參數:
+
+* `allow_origins` - 允許進行跨來源請求的來源清單。例如 `['https://example.org', 'https://www.example.org']`。你可以使用 `['*']` 來允許任何來源。
+* `allow_origin_regex` - 允許進行跨來源請求的來源,使用正規表示式字串比對。例如 `'https://.*\.example\.org'`。
+* `allow_methods` - 允許跨來源請求的 HTTP 方法清單。預設為 `['GET']`。你可以使用 `['*']` 來允許所有標準方法。
+* `allow_headers` - 允許跨來源請求所支援的 HTTP 請求標頭清單。預設為 `[]`。你可以使用 `['*']` 來允許所有標頭。對於簡單 CORS 請求,`Accept`、`Accept-Language`、`Content-Language` 與 `Content-Type` 標頭一律被允許。
+* `allow_credentials` - 指示是否支援跨來源請求的 Cookie。預設為 `False`。
+
+ 當 `allow_credentials` 設為 `True` 時,`allow_origins`、`allow_methods` 與 `allow_headers` 都不能設為 `['*']`。上述各項必須明確指定。
+
+* `expose_headers` - 指示哪些回應標頭應該讓瀏覽器可存取。預設為 `[]`。
+* `max_age` - 設定瀏覽器快取 CORS 回應的最長秒數。預設為 `600`。
+
+此中介軟體會回應兩種特定的 HTTP 請求類型...
+
+### CORS 預檢請求 { #cors-preflight-requests }
+
+任何帶有 `Origin` 與 `Access-Control-Request-Method` 標頭的 `OPTIONS` 請求。
+
+在這種情況下,中介軟體會攔截傳入的請求並回應適當的 CORS 標頭,並回傳 `200` 或 `400`(僅供資訊參考)。
+
+### 簡單請求 { #simple-requests }
+
+任何帶有 `Origin` 標頭的請求。在這種情況下,中介軟體會如常將請求往下傳遞,但會在回應上加入適當的 CORS 標頭。
+
+## 更多資訊 { #more-info }
+
+想進一步了解 CORS,請參考 Mozilla 的 CORS 文件。
+
+/// note | 技術細節
+
+你也可以使用 `from starlette.middleware.cors import CORSMiddleware`。
+
+**FastAPI** 在 `fastapi.middleware` 中提供了幾個中介軟體,做為開發者的便利性。但多數可用的中介軟體其實直接來自 Starlette。
+
+///
diff --git a/docs/zh-hant/docs/tutorial/debugging.md b/docs/zh-hant/docs/tutorial/debugging.md
new file mode 100644
index 0000000000..cb82ee417b
--- /dev/null
+++ b/docs/zh-hant/docs/tutorial/debugging.md
@@ -0,0 +1,113 @@
+# 偵錯 { #debugging }
+
+你可以在編輯器中連接偵錯器,例如 Visual Studio Code 或 PyCharm。
+
+## 呼叫 `uvicorn` { #call-uvicorn }
+
+在你的 FastAPI 應用程式中,直接匯入並執行 `uvicorn`:
+
+{* ../../docs_src/debugging/tutorial001_py310.py hl[1,15] *}
+
+### 關於 `__name__ == "__main__"` { #about-name-main }
+
+`__name__ == "__main__"` 的主要目的是,當你的檔案以以下方式呼叫時,執行某些程式碼:
+
+
+
+```console
+$ python myapp.py
+```
+
+
+
+但當其他檔案匯入它時不會執行,例如:
+
+```Python
+from myapp import app
+```
+
+#### 更多細節 { #more-details }
+
+假設你的檔名是 `myapp.py`。
+
+如果你用以下方式執行它:
+
+
+
+```console
+$ python myapp.py
+```
+
+
+
+那麼在你的檔案中,由 Python 自動建立的內部變數 `__name__`,其值會是字串 `"__main__"`。
+
+因此,這段:
+
+```Python
+ uvicorn.run(app, host="0.0.0.0", port=8000)
+```
+
+會被執行。
+
+---
+
+如果你是匯入該模組(檔案),就不會發生這件事。
+
+所以,如果你有另一個檔案 `importer.py`,內容如下:
+
+```Python
+from myapp import app
+
+# Some more code
+```
+
+在那種情況下,`myapp.py` 中自動建立的變數 `__name__` 就不會是 `"__main__"`。
+
+因此,這一行:
+
+```Python
+ uvicorn.run(app, host="0.0.0.0", port=8000)
+```
+
+就不會被執行。
+
+/// info | 說明
+
+想了解更多,參考 Python 官方文件。
+
+///
+
+## 用偵錯器執行你的程式碼 { #run-your-code-with-your-debugger }
+
+因為你是直接從程式碼中執行 Uvicorn 伺服器,所以你可以直接從偵錯器呼叫你的 Python 程式(你的 FastAPI 應用程式)。
+
+---
+
+例如,在 Visual Studio Code 中,你可以:
+
+* 前往 "Debug" 面板
+* 點選 "Add configuration..."
+* 選擇 "Python"
+* 使用選項 "`Python: Current File (Integrated Terminal)`" 啟動偵錯器
+
+接著它會用你的 **FastAPI** 程式碼啟動伺服器、在你的中斷點停下等。
+
+可能會長這樣:
+
+
+
+---
+
+如果你使用 PyCharm,你可以:
+
+* 開啟 "Run" 選單
+* 選擇 "Debug..."
+* 會出現一個情境選單
+* 選擇要偵錯的檔案(此例為 `main.py`)
+
+接著它會用你的 **FastAPI** 程式碼啟動伺服器、在你的中斷點停下等。
+
+可能會長這樣:
+
+
diff --git a/docs/zh-hant/docs/tutorial/dependencies/classes-as-dependencies.md b/docs/zh-hant/docs/tutorial/dependencies/classes-as-dependencies.md
new file mode 100644
index 0000000000..34b8732109
--- /dev/null
+++ b/docs/zh-hant/docs/tutorial/dependencies/classes-as-dependencies.md
@@ -0,0 +1,288 @@
+# 以類別作為相依性 { #classes-as-dependencies }
+
+在更深入了解 **相依性注入(Dependency Injection)** 系統之前,我們先把前一個範例升級一下。
+
+## 前一個範例中的 `dict` { #a-dict-from-the-previous-example }
+
+在前一個範例中,我們從相依項("dependable")回傳了一個 `dict`:
+
+{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[9] *}
+
+但接著我們在路徑操作函式(*path operation function*)的參數 `commons` 中取得的是一個 `dict`。
+
+而我們知道,編輯器對 `dict` 無法提供太多輔助(例如自動完成),因為它無法預先知道其中的鍵與值的型別。
+
+我們可以做得更好...
+
+## 什麼算是相依性 { #what-makes-a-dependency }
+
+到目前為止,你看到的相依性都是宣告成函式。
+
+但那不是宣告相依性的唯一方式(雖然那大概是最常見的)。
+
+關鍵在於,相依性應該要是「callable」。
+
+在 Python 中,「**callable**」指的是任何可以像函式一樣被 Python「呼叫」的東西。
+
+因此,如果你有一個物件 `something`(它可能不是函式),而你可以像這樣「呼叫」(執行)它:
+
+```Python
+something()
+```
+
+或是
+
+```Python
+something(some_argument, some_keyword_argument="foo")
+```
+
+那它就是一個「callable」。
+
+## 以類別作為相依性 { #classes-as-dependencies_1 }
+
+你可能已經注意到,建立一個 Python 類別的實例時,你用的語法也是一樣的。
+
+例如:
+
+```Python
+class Cat:
+ def __init__(self, name: str):
+ self.name = name
+
+
+fluffy = Cat(name="Mr Fluffy")
+```
+
+在這個例子中,`fluffy` 是 `Cat` 類別的一個實例。
+
+而要建立 `fluffy`,你其實是在「呼叫」`Cat`。
+
+所以,Python 類別本身也是一種 **callable**。
+
+因此,在 **FastAPI** 中,你可以將 Python 類別作為相依性。
+
+FastAPI 其實檢查的是它是否為「callable」(函式、類別或其他),以及它所定義的參數。
+
+如果你在 **FastAPI** 中傳入一個「callable」作為相依性,FastAPI 會分析該「callable」的參數,並以與路徑操作函式參數相同的方式來處理它們,包括子相依性。
+
+這也適用於完全沒有參數的 callable,就和沒有參數的路徑操作函式一樣。
+
+接著,我們可以把上面的相依項(dependable)`common_parameters` 改成類別 `CommonQueryParams`:
+
+{* ../../docs_src/dependencies/tutorial002_an_py310.py hl[11:15] *}
+
+注意用來建立該類別實例的 `__init__` 方法:
+
+{* ../../docs_src/dependencies/tutorial002_an_py310.py hl[12] *}
+
+...它的參數與我們之前的 `common_parameters` 相同:
+
+{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[8] *}
+
+**FastAPI** 會用這些參數來「解析」該相依性。
+
+兩種情況下都會有:
+
+- 一個可選的查詢參數 `q`,型別為 `str`。
+- 一個查詢參數 `skip`,型別為 `int`,預設為 `0`。
+- 一個查詢參數 `limit`,型別為 `int`,預設為 `100`。
+
+兩種情況下,資料都會被轉換、驗證,並記錄到 OpenAPI schema 中等。
+
+## 如何使用 { #use-it }
+
+現在你可以用這個類別來宣告你的相依性。
+
+{* ../../docs_src/dependencies/tutorial002_an_py310.py hl[19] *}
+
+**FastAPI** 會呼叫 `CommonQueryParams` 類別。這會建立該類別的一個「實例」,而該實例會以參數 `commons` 的形式傳給你的函式。
+
+## 型別註解與 `Depends` { #type-annotation-vs-depends }
+
+注意上面程式碼裡我們寫了兩次 `CommonQueryParams`:
+
+//// tab | Python 3.10+
+
+```Python
+commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]
+```
+
+////
+
+//// tab | Python 3.10+ 非 Annotated
+
+/// tip
+
+如有可能,優先使用 `Annotated` 版本。
+
+///
+
+```Python
+commons: CommonQueryParams = Depends(CommonQueryParams)
+```
+
+////
+
+最後面的 `CommonQueryParams`,在:
+
+```Python
+... Depends(CommonQueryParams)
+```
+
+...才是 **FastAPI** 實際用來知道相依性是什麼的依據。
+
+FastAPI 會從這個物件中提取宣告的參數,並且實際呼叫它。
+
+---
+
+在這個例子中,前面的 `CommonQueryParams`,於:
+
+//// tab | Python 3.10+
+
+```Python
+commons: Annotated[CommonQueryParams, ...
+```
+
+////
+
+//// tab | Python 3.10+ 非 Annotated
+
+/// tip
+
+如有可能,優先使用 `Annotated` 版本。
+
+///
+
+```Python
+commons: CommonQueryParams ...
+```
+
+////
+
+...對 **FastAPI** 來說沒有任何特殊意義。FastAPI 不會用它來做資料轉換、驗證等(因為這部分由 `Depends(CommonQueryParams)` 處理)。
+
+其實你可以只寫:
+
+//// tab | Python 3.10+
+
+```Python
+commons: Annotated[Any, Depends(CommonQueryParams)]
+```
+
+////
+
+//// tab | Python 3.10+ 非 Annotated
+
+/// tip
+
+如有可能,優先使用 `Annotated` 版本。
+
+///
+
+```Python
+commons = Depends(CommonQueryParams)
+```
+
+////
+
+...像是:
+
+{* ../../docs_src/dependencies/tutorial003_an_py310.py hl[19] *}
+
+但仍建議宣告型別,這樣你的編輯器就知道會以何種型別作為參數 `commons` 傳入,進而幫助你做自動完成、型別檢查等:
+
+
+
+## 捷徑 { #shortcut }
+
+不過你會發現這裡有些重複程式碼,我們寫了兩次 `CommonQueryParams`:
+
+//// tab | Python 3.10+
+
+```Python
+commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]
+```
+
+////
+
+//// tab | Python 3.10+ 非 Annotated
+
+/// tip
+
+如有可能,優先使用 `Annotated` 版本。
+
+///
+
+```Python
+commons: CommonQueryParams = Depends(CommonQueryParams)
+```
+
+////
+
+**FastAPI** 為這類情況提供了一個捷徑:當相依性「明確」是一個類別,且 **FastAPI** 會「呼叫」它來建立該類別的實例時。
+
+對這些特定情況,你可以這樣做:
+
+不要寫:
+
+//// tab | Python 3.10+
+
+```Python
+commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]
+```
+
+////
+
+//// tab | Python 3.10+ 非 Annotated
+
+/// tip
+
+如有可能,優先使用 `Annotated` 版本。
+
+///
+
+```Python
+commons: CommonQueryParams = Depends(CommonQueryParams)
+```
+
+////
+
+...而是改為:
+
+//// tab | Python 3.10+
+
+```Python
+commons: Annotated[CommonQueryParams, Depends()]
+```
+
+////
+
+//// tab | Python 3.10+ 非 Annotated
+
+/// tip
+
+如有可能,優先使用 `Annotated` 版本。
+
+///
+
+```Python
+commons: CommonQueryParams = Depends()
+```
+
+////
+
+你把相依性宣告為參數的型別,並使用不帶任何參數的 `Depends()`,而不用在 `Depends(CommonQueryParams)` 裡「再」寫一次整個類別。
+
+整個範例就會變成:
+
+{* ../../docs_src/dependencies/tutorial004_an_py310.py hl[19] *}
+
+...而 **FastAPI** 會知道該怎麼做。
+
+/// tip
+
+如果你覺得這樣比幫助更令人困惑,那就忽略它吧,你並不「需要」這個技巧。
+
+這只是個捷徑。因為 **FastAPI** 在意幫你減少重複的程式碼。
+
+///
diff --git a/docs/zh-hant/docs/tutorial/dependencies/dependencies-in-path-operation-decorators.md b/docs/zh-hant/docs/tutorial/dependencies/dependencies-in-path-operation-decorators.md
new file mode 100644
index 0000000000..e30c385375
--- /dev/null
+++ b/docs/zh-hant/docs/tutorial/dependencies/dependencies-in-path-operation-decorators.md
@@ -0,0 +1,69 @@
+# 路徑操作裝飾器中的依賴 { #dependencies-in-path-operation-decorators }
+
+有時在你的路徑操作函式中,其實不需要某個依賴的回傳值。
+
+或是該依賴根本沒有回傳值。
+
+但你仍需要它被執行/解析。
+
+這種情況下,你可以不在路徑操作函式的參數上使用 `Depends`,而是在路徑操作裝飾器加入一個 `dependencies` 的 `list`。
+
+## 在路徑操作裝飾器加入 `dependencies` { #add-dependencies-to-the-path-operation-decorator }
+
+路徑操作裝飾器可接受一個可選參數 `dependencies`。
+
+它應該是由 `Depends()` 組成的 `list`:
+
+{* ../../docs_src/dependencies/tutorial006_an_py310.py hl[19] *}
+
+這些依賴會以與一般依賴相同的方式被執行/解析。但它們的值(如果有回傳)不會傳遞給你的路徑操作函式。
+
+/// tip
+
+有些編輯器會檢查未使用的函式參數,並將其標示為錯誤。
+
+把這些依賴放在路徑操作裝飾器中,可以確保它們被執行,同時避免編輯器/工具報錯。
+
+這也有助於避免讓新加入的開發者看到未使用的參數時,以為它是不必要的而感到困惑。
+
+///
+
+/// info
+
+在這個範例中我們使用了自訂的(虛構的)標頭 `X-Key` 與 `X-Token`。
+
+但在實際情況下,當你實作安全機制時,使用整合的 [Security utilities(下一章)](../security/index.md){.internal-link target=_blank} 會獲得更多好處。
+
+///
+
+## 依賴的錯誤與回傳值 { #dependencies-errors-and-return-values }
+
+你可以使用與平常相同的依賴函式。
+
+### 依賴的需求 { #dependency-requirements }
+
+它們可以宣告請求需求(例如標頭(headers))或其他子依賴:
+
+{* ../../docs_src/dependencies/tutorial006_an_py310.py hl[8,13] *}
+
+### 拋出例外 { #raise-exceptions }
+
+這些依賴可以 `raise` 例外,與一般依賴相同:
+
+{* ../../docs_src/dependencies/tutorial006_an_py310.py hl[10,15] *}
+
+### 回傳值 { #return-values }
+
+它們可以回傳值,也可以不回傳;無論如何,回傳值都不會被使用。
+
+因此,你可以重複使用在其他地方已使用過的一般依賴(會回傳值),即使回傳值不會被使用,該依賴仍會被執行:
+
+{* ../../docs_src/dependencies/tutorial006_an_py310.py hl[11,16] *}
+
+## 一組路徑操作的依賴 { #dependencies-for-a-group-of-path-operations }
+
+之後在閱讀如何組織較大的應用程式([較大型應用程式——多個檔案](../../tutorial/bigger-applications.md){.internal-link target=_blank})時,你會學到如何為一組路徑操作宣告一個共同的 `dependencies` 參數。
+
+## 全域依賴 { #global-dependencies }
+
+接著我們會看看如何把依賴加到整個 `FastAPI` 應用程式,使其套用到每個路徑操作。
diff --git a/docs/zh-hant/docs/tutorial/dependencies/dependencies-with-yield.md b/docs/zh-hant/docs/tutorial/dependencies/dependencies-with-yield.md
new file mode 100644
index 0000000000..2339c6ef30
--- /dev/null
+++ b/docs/zh-hant/docs/tutorial/dependencies/dependencies-with-yield.md
@@ -0,0 +1,288 @@
+# 使用 yield 的相依 { #dependencies-with-yield }
+
+FastAPI 支援在完成後執行一些額外步驟的相依。
+
+要做到這點,使用 `yield` 取代 `return`,並把額外步驟(程式碼)寫在其後。
+
+/// tip
+
+請確保每個相依內只使用一次 `yield`。
+
+///
+
+/// note | 技術細節
+
+任何可用於下列裝飾器的函式:
+
+* `@contextlib.contextmanager` 或
+* `@contextlib.asynccontextmanager`
+
+都可以作為 **FastAPI** 的相依。
+
+事實上,FastAPI 內部就是使用這兩個裝飾器。
+
+///
+
+## 使用 `yield` 的資料庫相依 { #a-database-dependency-with-yield }
+
+例如,你可以用它建立一個資料庫 session,並在完成後關閉。
+
+只有 `yield` 之前(含 `yield` 本身)的程式碼會在產生回應之前執行:
+
+{* ../../docs_src/dependencies/tutorial007_py310.py hl[2:4] *}
+
+由 `yield` 產生的值會被注入到路徑操作(path operation)與其他相依中:
+
+{* ../../docs_src/dependencies/tutorial007_py310.py hl[4] *}
+
+位於 `yield` 之後的程式碼會在回應之後執行:
+
+{* ../../docs_src/dependencies/tutorial007_py310.py hl[5:6] *}
+
+/// tip
+
+你可以使用 `async` 或一般函式。
+
+**FastAPI** 都會正確處理,和一般相依相同。
+
+///
+
+## 同時使用 `yield` 與 `try` 的相依 { #a-dependency-with-yield-and-try }
+
+如果在含 `yield` 的相依中使用 `try` 區塊,你會接收到使用該相依時拋出的任何例外。
+
+例如,如果在中途的某段程式碼、其他相依,或某個路徑操作中,讓資料庫交易「rollback」或產生了任何例外,你都會在你的相依中接收到該例外。
+
+因此,你可以在相依內用 `except SomeException` 來攔截特定例外。
+
+同樣地,你可以使用 `finally` 來確保無論是否有例外都會執行結束步驟。
+
+{* ../../docs_src/dependencies/tutorial007_py310.py hl[3,5] *}
+
+## 含 `yield` 的子相依 { #sub-dependencies-with-yield }
+
+你可以擁有任何大小與形狀的子相依與相依樹,而它們都可以(或不)使用 `yield`。
+
+**FastAPI** 會確保每個使用 `yield` 的相依,其「結束程式碼」會以正確的順序執行。
+
+例如,`dependency_c` 可以相依於 `dependency_b`,而 `dependency_b` 相依於 `dependency_a`:
+
+{* ../../docs_src/dependencies/tutorial008_an_py310.py hl[6,14,22] *}
+
+而且它們都可以使用 `yield`。
+
+在這個例子中,`dependency_c` 為了執行它的結束程式碼,需要來自 `dependency_b`(此處命名為 `dep_b`)的值仍然可用。
+
+同理,`dependency_b` 為了執行它的結束程式碼,需要來自 `dependency_a`(此處命名為 `dep_a`)的值可用。
+
+{* ../../docs_src/dependencies/tutorial008_an_py310.py hl[18:19,26:27] *}
+
+同樣地,你可以同時擁有使用 `yield` 的相依與使用 `return` 的相依,並讓其中一些相依彼此相依。
+
+你也可以有一個相依同時需要多個使用 `yield` 的其他相依,等等。
+
+你可以擁有任何你需要的相依組合。
+
+**FastAPI** 會確保一切都以正確的順序執行。
+
+/// note | 技術細節
+
+這能運作,多虧了 Python 的 Context Managers。
+
+**FastAPI** 在內部使用它們來達成這點。
+
+///
+
+## 含 `yield` 與 `HTTPException` 的相依 { #dependencies-with-yield-and-httpexception }
+
+你已看到可以在含 `yield` 的相依中使用 `try` 區塊,嘗試執行一些程式碼,然後在 `finally` 後執行結束程式碼。
+
+你也可以用 `except` 來攔截被拋出的例外並加以處理。
+
+例如,你可以拋出不同的例外,如 `HTTPException`。
+
+/// tip
+
+這算是進階技巧;多數情況你並不需要,因為你可以在應用程式其他程式碼中(例如在路徑操作函式(path operation function)中)直接拋出例外(包含 `HTTPException`)。
+
+但如果你需要,它就在這裡。🤓
+
+///
+
+{* ../../docs_src/dependencies/tutorial008b_an_py310.py hl[18:22,31] *}
+
+如果你想攔截例外並據此回傳自訂回應,請建立一個[自訂例外處理器](../handling-errors.md#install-custom-exception-handlers){.internal-link target=_blank}。
+
+## 含 `yield` 與 `except` 的相依 { #dependencies-with-yield-and-except }
+
+如果你在含 `yield` 的相依中用 `except` 攔截了例外,且沒有再次拋出它(或拋出新的例外),FastAPI 將無法察覺有例外發生,就像在一般的 Python 中一樣:
+
+{* ../../docs_src/dependencies/tutorial008c_an_py310.py hl[15:16] *}
+
+在這種情況下,客戶端會如預期地看到一個 *HTTP 500 Internal Server Error* 回應(因為我們沒有拋出 `HTTPException` 或類似的東西),但伺服器將不會有任何日誌或其他錯誤線索。😱
+
+### 在含 `yield` 與 `except` 的相依中務必 `raise` { #always-raise-in-dependencies-with-yield-and-except }
+
+如果你在含 `yield` 的相依中攔截到了例外,除非你要拋出另一個 `HTTPException` 或類似的例外,否則**你應該重新拋出原本的例外**。
+
+你可以使用 `raise` 重新拋出同一個例外:
+
+{* ../../docs_src/dependencies/tutorial008d_an_py310.py hl[17] *}
+
+現在客戶端仍會獲得同樣的 *HTTP 500 Internal Server Error* 回應,但伺服器的日誌中會有我們自訂的 `InternalError`。😎
+
+## 含 `yield` 的相依執行順序 { #execution-of-dependencies-with-yield }
+
+執行順序大致如下圖。時間從上往下流動,每一欄代表一個互動或執行程式碼的部分。
+
+```mermaid
+sequenceDiagram
+
+participant client as Client
+participant handler as Exception handler
+participant dep as Dep with yield
+participant operation as Path Operation
+participant tasks as Background tasks
+
+ Note over client,operation: Can raise exceptions, including HTTPException
+ client ->> dep: Start request
+ Note over dep: Run code up to yield
+ opt raise Exception
+ dep -->> handler: Raise Exception
+ handler -->> client: HTTP error response
+ end
+ dep ->> operation: Run dependency, e.g. DB session
+ opt raise
+ operation -->> dep: Raise Exception (e.g. HTTPException)
+ opt handle
+ dep -->> dep: Can catch exception, raise a new HTTPException, raise other exception
+ end
+ handler -->> client: HTTP error response
+ end
+
+ operation ->> client: Return response to client
+ Note over client,operation: Response is already sent, can't change it anymore
+ opt Tasks
+ operation -->> tasks: Send background tasks
+ end
+ opt Raise other exception
+ tasks -->> tasks: Handle exceptions in the background task code
+ end
+```
+
+/// info
+
+只會向用戶端送出「一個回應」。可能是其中一個錯誤回應,或是來自該路徑操作的回應。
+
+一旦送出了其中一個回應,就不能再送出其他回應。
+
+///
+
+/// tip
+
+如果你在路徑操作函式的程式碼中拋出任何例外,它會被傳遞到使用 `yield` 的相依中(包含 `HTTPException`)。大多數情況你會想在該使用 `yield` 的相依中重新拋出相同的例外或一個新的例外,以確保它被正確處理。
+
+///
+
+## 提早關閉與 `scope` { #early-exit-and-scope }
+
+通常,含 `yield` 的相依之結束程式碼會在回應送出給用戶端之後才執行。
+
+但如果你確定在從路徑操作函式返回後就不會再使用該相依,你可以使用 `Depends(scope="function")`,告訴 FastAPI 應在路徑操作函式返回之後、但在回應送出之前關閉該相依。
+
+{* ../../docs_src/dependencies/tutorial008e_an_py310.py hl[12,16] *}
+
+`Depends()` 接受一個 `scope` 參數,可以是:
+
+* `"function"`:在處理請求的路徑操作函式之前啟動相依,在路徑操作函式結束之後結束相依,但在回應送回用戶端之前。所以,相依函式會在路徑操作**函式**的「周圍」執行。
+* `"request"`:在處理請求的路徑操作函式之前啟動相依(與使用 `"function"` 類似),但在回應送回用戶端之後才結束相依。所以,相依函式會在整個**請求**與回應循環的「周圍」執行。
+
+如果未指定且相依使用了 `yield`,則預設 `scope` 為 `"request"`。
+
+### 子相依的 `scope` { #scope-for-sub-dependencies }
+
+當你宣告一個 `scope="request"`(預設值)的相依時,任何子相依也需要有 `"request"` 的 `scope`。
+
+但一個 `scope` 為 `"function"` 的相依,可以擁有 `scope` 為 `"function"` 或 `"request"` 的子相依。
+
+這是因為任何相依都需要能在子相依之前執行其結束程式碼,因為它可能在結束程式碼中仍需要使用那些子相依。
+
+```mermaid
+sequenceDiagram
+
+participant client as Client
+participant dep_req as Dep scope="request"
+participant dep_func as Dep scope="function"
+participant operation as Path Operation
+
+ client ->> dep_req: Start request
+ Note over dep_req: Run code up to yield
+ dep_req ->> dep_func: Pass dependency
+ Note over dep_func: Run code up to yield
+ dep_func ->> operation: Run path operation with dependency
+ operation ->> dep_func: Return from path operation
+ Note over dep_func: Run code after yield
+ Note over dep_func: ✅ Dependency closed
+ dep_func ->> client: Send response to client
+ Note over client: Response sent
+ Note over dep_req: Run code after yield
+ Note over dep_req: ✅ Dependency closed
+```
+
+## 含 `yield`、`HTTPException`、`except` 與背景任務的相依 { #dependencies-with-yield-httpexception-except-and-background-tasks }
+
+含 `yield` 的相依隨時間演進,以涵蓋不同的使用情境並修正一些問題。
+
+如果你想了解在不同 FastAPI 版本中改了哪些內容,可以在進階指南中閱讀:[進階相依 — 含 `yield`、`HTTPException`、`except` 與背景任務的相依](../../advanced/advanced-dependencies.md#dependencies-with-yield-httpexception-except-and-background-tasks){.internal-link target=_blank}。
+## 情境管理器 { #context-managers }
+
+### 什麼是「情境管理器」 { #what-are-context-managers }
+
+「情境管理器」是那些你可以在 `with` 陳述式中使用的 Python 物件。
+
+例如,你可以用 `with` 來讀取檔案:
+
+```Python
+with open("./somefile.txt") as f:
+ contents = f.read()
+ print(contents)
+```
+
+在底層,`open("./somefile.txt")` 會建立一個稱為「情境管理器」的物件。
+
+當 `with` 區塊結束時,它會確保關閉檔案,即使發生了例外也一樣。
+
+當你建立一個含 `yield` 的相依時,**FastAPI** 會在內部為它建立一個情境管理器,並與其他相關工具結合。
+
+### 在含 `yield` 的相依中使用情境管理器 { #using-context-managers-in-dependencies-with-yield }
+
+/// warning
+
+這大致算是一個「進階」概念。
+
+如果你剛開始學習 **FastAPI**,此處可以先跳過。
+
+///
+
+在 Python 中,你可以透過建立一個擁有 `__enter__()` 與 `__exit__()` 兩個方法的類別來建立情境管理器。
+
+你也可以在 **FastAPI** 的含 `yield` 相依中,於相依函式內使用 `with` 或 `async with` 陳述式來使用它們:
+
+{* ../../docs_src/dependencies/tutorial010_py310.py hl[1:9,13] *}
+
+/// tip
+
+建立情境管理器的另一種方式是:
+
+* `@contextlib.contextmanager` 或
+* `@contextlib.asynccontextmanager`
+
+用它們裝飾一個只包含單一 `yield` 的函式。
+
+這正是 **FastAPI** 在內部為含 `yield` 的相依所使用的方法。
+
+但你不需要(而且也不該)在 FastAPI 的相依上使用這些裝飾器。
+
+FastAPI 會在內部替你處理好。
+
+///
diff --git a/docs/zh-hant/docs/tutorial/dependencies/global-dependencies.md b/docs/zh-hant/docs/tutorial/dependencies/global-dependencies.md
new file mode 100644
index 0000000000..3aac1a228b
--- /dev/null
+++ b/docs/zh-hant/docs/tutorial/dependencies/global-dependencies.md
@@ -0,0 +1,15 @@
+# 全域依賴 { #global-dependencies }
+
+在某些類型的應用程式中,你可能想為整個應用程式新增依賴。
+
+類似於你可以在[路徑操作(path operation)的裝飾器中新增 `dependencies`](dependencies-in-path-operation-decorators.md){.internal-link target=_blank} 的方式,你也可以把它們加到 `FastAPI` 應用程式上。
+
+在這種情況下,它們會套用到應用程式中的所有路徑操作:
+
+{* ../../docs_src/dependencies/tutorial012_an_py310.py hl[17] *}
+
+而且,在[將 `dependencies` 新增到路徑操作裝飾器](dependencies-in-path-operation-decorators.md){.internal-link target=_blank} 那一節中的所有概念依然適用,只是這裡是套用到整個應用中的所有路徑操作。
+
+## 路徑操作群組的依賴 { #dependencies-for-groups-of-path-operations }
+
+之後,在閱讀如何組織更大的應用程式([更大的應用程式 - 多個檔案](../../tutorial/bigger-applications.md){.internal-link target=_blank})時,可能會有多個檔案,你將會學到如何為一組路徑操作宣告單一的 `dependencies` 參數。
diff --git a/docs/zh-hant/docs/tutorial/dependencies/index.md b/docs/zh-hant/docs/tutorial/dependencies/index.md
new file mode 100644
index 0000000000..39c05ab056
--- /dev/null
+++ b/docs/zh-hant/docs/tutorial/dependencies/index.md
@@ -0,0 +1,248 @@
+# 依賴 { #dependencies }
+
+**FastAPI** 內建一套強大且直覺的 **依賴注入** 系統。
+
+它被設計為易於使用,使任何開發者都能輕鬆將其他元件與 **FastAPI** 整合。
+
+## 什麼是「依賴注入」 { #what-is-dependency-injection }
+
+在程式設計中,「依賴注入」的意思是:你的程式碼(此處指你的「路徑操作函式 (path operation functions)」)可以宣告它為了正常運作所需要的各種東西:也就是「依賴」。
+
+接著,這個系統(此處是 **FastAPI**)會負責做任何必要的事,將這些所需的依賴提供給你的程式碼(「注入」依賴)。
+
+當你需要以下情境時,這特別有用:
+
+* 共享邏輯(相同的邏輯一次又一次地使用)。
+* 共用資料庫連線。
+* 強制套用安全性、驗證、角色要求等。
+* 以及許多其他事情...
+
+同時把重複的程式碼降到最低。
+
+## 入門 { #first-steps }
+
+先看一個非常簡單的範例。它現在還不太實用,但夠簡單,讓我們能專注在 **依賴注入** 的運作方式。
+
+### 建立一個依賴,或稱「dependable」 { #create-a-dependency-or-dependable }
+
+先專注在依賴本身。
+
+它就是一個函式,可以接受與「路徑操作函式」相同的各種參數:
+
+{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[8:9] *}
+
+就這樣。
+
+僅僅兩行。
+
+而且它的外觀與結構和你的所有「路徑操作函式」一樣。
+
+你可以把它想成一個沒有「裝飾器」(沒有 `@app.get("/some-path")`)的「路徑操作函式」。
+
+它可以回傳你想要的任何東西。
+
+在這個例子中,這個依賴會期望:
+
+* 一個選用的查詢參數 `q`,型別為 `str`。
+* 一個選用的查詢參數 `skip`,型別為 `int`,預設為 `0`。
+* 一個選用的查詢參數 `limit`,型別為 `int`,預設為 `100`。
+
+然後它只會回傳一個包含這些值的 `dict`。
+
+/// info | 說明
+
+FastAPI 在 0.95.0 版新增了對 `Annotated` 的支援(並開始建議使用)。
+
+如果你使用較舊的版本,嘗試使用 `Annotated` 時會出現錯誤。
+
+在使用 `Annotated` 之前,請先[升級 FastAPI 版本](../../deployment/versions.md#upgrading-the-fastapi-versions){.internal-link target=_blank}到至少 0.95.1。
+
+///
+
+### 匯入 `Depends` { #import-depends }
+
+{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[3] *}
+
+### 在「被依賴者」(dependant)中宣告依賴 { #declare-the-dependency-in-the-dependant }
+
+和你在「路徑操作函式」參數上使用 `Body`、`Query` 等方式一樣,針對新參數使用 `Depends`:
+
+{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[13,18] *}
+
+雖然你在函式參數上使用 `Depends` 的方式和 `Body`、`Query` 等相同,但 `Depends` 的運作方式有點不同。
+
+你只需要傳給 `Depends` 一個參數。
+
+這個參數必須是類似函式的東西。
+
+你不需要直接呼叫它(不要在後面加上括號),只要把它作為參數傳給 `Depends()` 即可。
+
+而該函式的參數宣告方式與「路徑操作函式」相同。
+
+/// tip | 提示
+
+除了函式之外,還有其他「東西」也能當作依賴,會在下一章介紹。
+
+///
+
+當有新的請求到達時,**FastAPI** 會負責:
+
+* 以正確的參數呼叫你的依賴(dependable)函式。
+* 取得該函式的回傳結果。
+* 將結果指定給你的「路徑操作函式」中的對應參數。
+
+```mermaid
+graph TB
+
+common_parameters(["common_parameters"])
+read_items["/items/"]
+read_users["/users/"]
+
+common_parameters --> read_items
+common_parameters --> read_users
+```
+
+如此一來,你只需撰寫一次共用程式碼,**FastAPI** 會替你的各個「路徑操作」呼叫它。
+
+/// check | 檢查
+
+注意,你不必建立特殊的類別並把它傳到 **FastAPI** 去「註冊」或做類似的事。
+
+只要把它傳給 `Depends`,**FastAPI** 就知道該怎麼處理其餘的部分。
+
+///
+
+## 共用 `Annotated` 依賴 { #share-annotated-dependencies }
+
+在上面的範例中,可以看到有一點點的「重複程式碼」。
+
+當你要使用 `common_parameters()` 這個依賴時,你得寫出完整的型別註解搭配 `Depends()`:
+
+```Python
+commons: Annotated[dict, Depends(common_parameters)]
+```
+
+但因為我們在使用 `Annotated`,我們可以把這個 `Annotated` 的值存到一個變數中,並在多個地方重複使用:
+
+{* ../../docs_src/dependencies/tutorial001_02_an_py310.py hl[12,16,21] *}
+
+/// tip | 提示
+
+這只是標準的 Python,用的是所謂的「型別別名 (type alias)」,其實和 **FastAPI** 本身無關。
+
+但因為 **FastAPI** 是建立在 Python 標準之上(包含 `Annotated`),你就可以在程式碼中使用這個技巧。😎
+
+///
+
+這些依賴依然會如預期運作,而最棒的是「型別資訊會被保留」,代表你的編輯器仍能提供「自動完成」、「即時錯誤」等功能,像 `mypy` 等其他工具也一樣受益。
+
+當你在「大型程式碼庫」中,於許多「路徑操作」反覆使用「相同的依賴」時,這會特別有用。
+
+## 要不要使用 `async` { #to-async-or-not-to-async }
+
+因為依賴也會由 **FastAPI** 呼叫(就像你的「路徑操作函式」),所以在定義函式時套用相同的規則。
+
+你可以使用 `async def` 或一般的 `def`。
+
+而且你可以在一般 `def` 的「路徑操作函式」中宣告 `async def` 的依賴,或在 `async def` 的「路徑操作函式」中宣告 `def` 的依賴,等等。
+
+都沒關係。**FastAPI** 會知道該怎麼做。
+
+/// note | 注意
+
+如果你不熟悉,請參考文件中的 [Async: "In a hurry?"](../../async.md#in-a-hurry){.internal-link target=_blank} 一節,瞭解 `async` 與 `await`。
+
+///
+
+## 與 OpenAPI 整合 { #integrated-with-openapi }
+
+你的依賴(以及其子依賴)所宣告的所有請求參數、驗證與需求,都會整合進同一份 OpenAPI 結構中。
+
+因此,互動式文件也會包含來自這些依賴的所有資訊:
+
+
+
+## 簡單用法 { #simple-usage }
+
+想一想,「路徑操作函式」是宣告好讓框架在「路徑」與「操作」符合時使用的,然後 **FastAPI** 會負責帶入正確的參數、從請求中擷取資料,並呼叫該函式。
+
+其實,所有(或大多數)Web 框架都是這樣運作。
+
+你從不會直接呼叫這些函式。它們是由框架(此處是 **FastAPI**)呼叫的。
+
+透過依賴注入系統,你也可以告訴 **FastAPI**:你的「路徑操作函式」還「依賴」其他東西,應在你的「路徑操作函式」之前執行,**FastAPI** 會負責執行它並「注入」其結果。
+
+這個「依賴注入」概念的其他常見稱呼包括:
+
+* 資源
+* 提供者
+* 服務
+* 可注入項
+* 元件
+
+## **FastAPI** 外掛 { #fastapi-plug-ins }
+
+各種整合與「外掛」都能以 **依賴注入** 系統來構建。但事實上,並不需要真的去打造「外掛」,因為透過依賴,你可以宣告無數的整合與互動,並讓它們供你的「路徑操作函式」使用。
+
+而且依賴可以用非常簡單直覺的方式建立,你只需要匯入所需的 Python 套件,然後用幾行程式碼就能把它們與你的 API 函式整合,真的是「只要幾行」。
+
+在接下來的章節中你會看到這方面的例子,例如關聯式與 NoSQL 資料庫、安全性等。
+
+## **FastAPI** 相容性 { #fastapi-compatibility }
+
+依賴注入系統的簡潔,使 **FastAPI** 能與以下事物相容:
+
+* 所有關聯式資料庫
+* NoSQL 資料庫
+* 外部套件
+* 外部 API
+* 驗證與授權系統
+* API 使用監控系統
+* 回應資料注入系統
+* 等等
+
+## 簡單而強大 { #simple-and-powerful }
+
+雖然階層式的依賴注入系統相當容易定義與使用,但它依然非常強大。
+
+你可以定義會進一步依賴其他依賴的依賴。
+
+最終會形成一棵階層式的依賴樹,而 **依賴注入** 系統會負責為你解決所有這些依賴(以及它們的子依賴),並在每一步提供(注入)對應的結果。
+
+例如,假設你有 4 個 API 端點(「路徑操作」):
+
+* `/items/public/`
+* `/items/private/`
+* `/users/{user_id}/activate`
+* `/items/pro/`
+
+那麼你就能只透過依賴與子依賴,為每個端點加入不同的權限需求:
+
+```mermaid
+graph TB
+
+current_user(["current_user"])
+active_user(["active_user"])
+admin_user(["admin_user"])
+paying_user(["paying_user"])
+
+public["/items/public/"]
+private["/items/private/"]
+activate_user["/users/{user_id}/activate"]
+pro_items["/items/pro/"]
+
+current_user --> active_user
+active_user --> admin_user
+active_user --> paying_user
+
+current_user --> public
+active_user --> private
+admin_user --> activate_user
+paying_user --> pro_items
+```
+
+## 與 **OpenAPI** 整合 { #integrated-with-openapi_1 }
+
+所有這些依賴在宣告其需求的同時,也會為你的「路徑操作」新增參數、驗證等。
+
+**FastAPI** 會負責把這一切加入 OpenAPI 結構中,讓它們顯示在互動式文件系統裡。
diff --git a/docs/zh-hant/docs/tutorial/dependencies/sub-dependencies.md b/docs/zh-hant/docs/tutorial/dependencies/sub-dependencies.md
new file mode 100644
index 0000000000..50c4e17908
--- /dev/null
+++ b/docs/zh-hant/docs/tutorial/dependencies/sub-dependencies.md
@@ -0,0 +1,105 @@
+# 子相依 { #sub-dependencies }
+
+你可以建立具有「子相依」的相依項。
+
+它們可以按你的需要,層級任意加深。
+
+**FastAPI** 會負責解析它們。
+
+## 第一個相依項 "dependable" { #first-dependency-dependable }
+
+你可以建立第一個相依項("dependable")如下:
+
+{* ../../docs_src/dependencies/tutorial005_an_py310.py hl[8:9] *}
+
+它宣告了一個可選的查詢參數 `q`(型別為 `str`),然後直接回傳它。
+
+這很簡單(不太實用),但有助於我們專注於子相依如何運作。
+
+## 第二個相依,同時是 "dependable" 也是 "dependant" { #second-dependency-dependable-and-dependant }
+
+接著你可以建立另一個相依函式("dependable"),同時它也宣告了自己的相依(因此它同時也是 "dependant"):
+
+{* ../../docs_src/dependencies/tutorial005_an_py310.py hl[13] *}
+
+來看它所宣告的參數:
+
+- 即使這個函式本身是個相依項("dependable"),它也宣告了另一個相依(它「相依於」其他東西)。
+ - 它相依 `query_extractor`,並把其回傳值指定給參數 `q`。
+- 它還宣告了一個可選的 `last_query` cookie,型別為 `str`。
+ - 如果使用者沒有提供查詢 `q`,我們就使用先前儲存在 cookie 中的最後一次查詢值。
+
+## 使用相依項 { #use-the-dependency }
+
+然後我們可以這樣使用這個相依項:
+
+{* ../../docs_src/dependencies/tutorial005_an_py310.py hl[23] *}
+
+/// info
+
+注意,在路徑操作函式中我們只宣告了一個相依項 `query_or_cookie_extractor`。
+
+但 **FastAPI** 會知道它必須先解析 `query_extractor`,在呼叫 `query_or_cookie_extractor` 時把其結果傳入。
+
+///
+
+```mermaid
+graph TB
+
+query_extractor(["query_extractor"])
+query_or_cookie_extractor(["query_or_cookie_extractor"])
+
+read_query["/items/"]
+
+query_extractor --> query_or_cookie_extractor --> read_query
+```
+
+## 多次使用同一個相依項 { #using-the-same-dependency-multiple-times }
+
+如果你的某個相依項在同一個路徑操作中被宣告了多次,例如多個相依共用同一個子相依,**FastAPI** 會知道只需在每次請求中呼叫該子相依一次。
+
+它會把回傳值儲存在一個 「快取」 中,並在該次請求中傳遞給所有需要它的「相依者」,而不是為同一個請求多次呼叫相同的相依項。
+
+在進階情境下,如果你確定需要在同一次請求的每個步驟都呼叫該相依(可能呼叫多次),而不是使用「快取」的值,你可以在使用 `Depends` 時設定參數 `use_cache=False`:
+
+//// tab | Python 3.10+
+
+```Python hl_lines="1"
+async def needy_dependency(fresh_value: Annotated[str, Depends(get_value, use_cache=False)]):
+ return {"fresh_value": fresh_value}
+```
+
+////
+
+//// tab | Python 3.10+ 未使用 Annotated
+
+/// tip
+
+若可行,建議使用 `Annotated` 的版本。
+
+///
+
+```Python hl_lines="1"
+async def needy_dependency(fresh_value: str = Depends(get_value, use_cache=False)):
+ return {"fresh_value": fresh_value}
+```
+
+////
+
+## 回顧 { #recap }
+
+撇開這裡用到的術語不談,**相依性注入(Dependency Injection)** 系統其實很簡單。
+
+它只是一些與路徑操作函式外觀相同的函式。
+
+但它非常強大,允許你宣告任意深度巢狀的相依「圖」(樹)。
+
+/// tip
+
+用這些簡單的例子看起來可能不那麼有用。
+
+但在關於安全性的章節中,你會看到它有多實用。
+
+你也會看到它能為你省下多少程式碼。
+
+///
diff --git a/docs/zh-hant/docs/tutorial/encoder.md b/docs/zh-hant/docs/tutorial/encoder.md
new file mode 100644
index 0000000000..03b7db6394
--- /dev/null
+++ b/docs/zh-hant/docs/tutorial/encoder.md
@@ -0,0 +1,35 @@
+# JSON 相容編碼器 { #json-compatible-encoder }
+
+在某些情況下,你可能需要將某種資料型別(例如 Pydantic 模型)轉換為與 JSON 相容的類型(例如 `dict`、`list` 等)。
+
+例如,當你需要把它儲存在資料庫中。
+
+為此,**FastAPI** 提供了 `jsonable_encoder()` 函式。
+
+## 使用 `jsonable_encoder` { #using-the-jsonable-encoder }
+
+想像你有一個只接受與 JSON 相容資料的資料庫 `fake_db`。
+
+例如,它不接受 `datetime` 物件,因為那與 JSON 不相容。
+
+因此,必須將 `datetime` 物件轉為一個以 ISO 格式 表示資料的 `str`。
+
+同樣地,這個資料庫不會接受 Pydantic 模型(帶有屬性的物件),只接受 `dict`。
+
+你可以使用 `jsonable_encoder` 來處理。
+
+它接收一個物件(例如 Pydantic 模型),並回傳一個與 JSON 相容的版本:
+
+{* ../../docs_src/encoder/tutorial001_py310.py hl[4,21] *}
+
+在此範例中,它會把 Pydantic 模型轉成 `dict`,並將 `datetime` 轉成 `str`。
+
+呼叫後的結果可以用 Python 標準的 `json.dumps()` 進行編碼。
+
+它不會回傳一個包含 JSON 內容的大型 `str`(字串)。它會回傳 Python 標準的資料結構(例如 `dict`),其中的值與子值都與 JSON 相容。
+
+/// note
+
+事實上,`jsonable_encoder` 在 **FastAPI** 內部也被用來轉換資料。不過在許多其他情境中它同樣實用。
+
+///
diff --git a/docs/zh-hant/docs/tutorial/extra-data-types.md b/docs/zh-hant/docs/tutorial/extra-data-types.md
new file mode 100644
index 0000000000..f516d965a4
--- /dev/null
+++ b/docs/zh-hant/docs/tutorial/extra-data-types.md
@@ -0,0 +1,62 @@
+# 額外的資料型別 { #extra-data-types }
+
+到目前為止,你一直在使用常見的資料型別,例如:
+
+* `int`
+* `float`
+* `str`
+* `bool`
+
+但你也可以使用更複雜的資料型別。
+
+而且你仍然會擁有目前為止所見的同樣功能:
+
+* 極佳的編輯器支援。
+* 將傳入請求的資料轉換。
+* 回應資料的轉換。
+* 資料驗證。
+* 自動產生註解與文件。
+
+## 其他資料型別 { #other-data-types }
+
+以下是你可以使用的一些其他資料型別:
+
+* `UUID`:
+ * 一種標準的「通用唯一識別碼 (Universally Unique Identifier)」,常見於許多資料庫與系統的 ID。
+ * 在請求與回應中會以 `str` 表示。
+* `datetime.datetime`:
+ * Python 的 `datetime.datetime`。
+ * 在請求與回應中會以 ISO 8601 格式的 `str` 表示,例如:`2008-09-15T15:53:00+05:00`。
+* `datetime.date`:
+ * Python 的 `datetime.date`。
+ * 在請求與回應中會以 ISO 8601 格式的 `str` 表示,例如:`2008-09-15`。
+* `datetime.time`:
+ * Python 的 `datetime.time`。
+ * 在請求與回應中會以 ISO 8601 格式的 `str` 表示,例如:`14:23:55.003`。
+* `datetime.timedelta`:
+ * Python 的 `datetime.timedelta`。
+ * 在請求與回應中會以總秒數的 `float` 表示。
+ * Pydantic 也允許用「ISO 8601 time diff encoding」來表示,詳情見文件。
+* `frozenset`:
+ * 在請求與回應中與 `set` 相同處理:
+ * 在請求中,會讀取一個 list,去除重複並轉為 `set`。
+ * 在回應中,`set` 會被轉為 `list`。
+ * 生成的 schema 會指定 `set` 的值為唯一(使用 JSON Schema 的 `uniqueItems`)。
+* `bytes`:
+ * 標準的 Python `bytes`。
+ * 在請求與回應中會被當作 `str` 處理。
+ * 生成的 schema 會指定其為 `str`,且 "format" 為 `binary`。
+* `Decimal`:
+ * 標準的 Python `Decimal`。
+ * 在請求與回應中,與 `float` 的處理方式相同。
+* 你可以在此查閱所有可用的 Pydantic 資料型別:Pydantic 資料型別。
+
+## 範例 { #example }
+
+以下是一個帶有參數、使用上述部分型別的 *路徑操作 (path operation)* 範例。
+
+{* ../../docs_src/extra_data_types/tutorial001_an_py310.py hl[1,3,12:16] *}
+
+請注意,函式內的參數會是它們的自然資料型別,因此你可以進行一般的日期運算,例如:
+
+{* ../../docs_src/extra_data_types/tutorial001_an_py310.py hl[18:19] *}
diff --git a/docs/zh-hant/docs/tutorial/extra-models.md b/docs/zh-hant/docs/tutorial/extra-models.md
new file mode 100644
index 0000000000..8aae62f8e1
--- /dev/null
+++ b/docs/zh-hant/docs/tutorial/extra-models.md
@@ -0,0 +1,211 @@
+# 額外的模型 { #extra-models }
+
+延續前一個範例,通常會有不只一個彼此相關的模型。
+
+對使用者模型尤其如此,因為:
+
+* 「輸入模型」需要能包含密碼。
+* 「輸出模型」不應包含密碼。
+* 「資料庫模型」通常需要儲存雜湊後的密碼。
+
+/// danger
+
+切勿儲存使用者的明文密碼。務必只儲存可供驗證的「安全雜湊」。
+
+若你還不清楚,稍後會在[安全性章節](security/simple-oauth2.md#password-hashing){.internal-link target=_blank}學到什麼是「密碼雜湊」。
+
+///
+
+## 多個模型 { #multiple-models }
+
+以下是模型大致長相、與其密碼欄位以及它們被使用的位置:
+
+{* ../../docs_src/extra_models/tutorial001_py310.py hl[7,9,14,20,22,27:28,31:33,38:39] *}
+
+### 關於 `**user_in.model_dump()` { #about-user-in-model-dump }
+
+#### Pydantic 的 `.model_dump()` { #pydantics-model-dump }
+
+`user_in` 是一個 `UserIn` 類別的 Pydantic 模型。
+
+Pydantic 模型有 `.model_dump()` 方法,會回傳包含該模型資料的 `dict`。
+
+因此,若我們建立一個 Pydantic 物件 `user_in` 如:
+
+```Python
+user_in = UserIn(username="john", password="secret", email="john.doe@example.com")
+```
+
+接著呼叫:
+
+```Python
+user_dict = user_in.model_dump()
+```
+
+此時變數 `user_dict` 會是一個承載資料的 `dict`(也就是 `dict`,而非 Pydantic 模型物件)。
+
+若再呼叫:
+
+```Python
+print(user_dict)
+```
+
+我們會得到一個 Python `dict`:
+
+```Python
+{
+ 'username': 'john',
+ 'password': 'secret',
+ 'email': 'john.doe@example.com',
+ 'full_name': None,
+}
+```
+
+#### 解包 `dict` { #unpacking-a-dict }
+
+若將像 `user_dict` 這樣的 `dict` 以 `**user_dict` 傳給函式(或類別),Python 會將其「解包」,把 `user_dict` 的鍵和值直接當作具名引數傳入。
+
+因此,延續上面的 `user_dict`,寫成:
+
+```Python
+UserInDB(**user_dict)
+```
+
+效果等同於:
+
+```Python
+UserInDB(
+ username="john",
+ password="secret",
+ email="john.doe@example.com",
+ full_name=None,
+)
+```
+
+更精確地說,直接使用 `user_dict`(未來內容可能有所不同)則等同於:
+
+```Python
+UserInDB(
+ username = user_dict["username"],
+ password = user_dict["password"],
+ email = user_dict["email"],
+ full_name = user_dict["full_name"],
+)
+```
+
+#### 由另一個模型內容建立 Pydantic 模型 { #a-pydantic-model-from-the-contents-of-another }
+
+如上例我們從 `user_in.model_dump()` 得到 `user_dict`,以下程式碼:
+
+```Python
+user_dict = user_in.model_dump()
+UserInDB(**user_dict)
+```
+
+等同於:
+
+```Python
+UserInDB(**user_in.model_dump())
+```
+
+...因為 `user_in.model_dump()` 回傳的是 `dict`,接著在傳給 `UserInDB` 時以 `**` 前綴讓 Python 進行解包。
+
+因此,我們可以用一個 Pydantic 模型的資料建立另一個 Pydantic 模型。
+
+#### 解包 `dict` 並加入額外參數 { #unpacking-a-dict-and-extra-keywords }
+
+接著加入額外的具名引數 `hashed_password=hashed_password`,如下:
+
+```Python
+UserInDB(**user_in.model_dump(), hashed_password=hashed_password)
+```
+
+...結果等同於:
+
+```Python
+UserInDB(
+ username = user_dict["username"],
+ password = user_dict["password"],
+ email = user_dict["email"],
+ full_name = user_dict["full_name"],
+ hashed_password = hashed_password,
+)
+```
+
+/// warning
+
+輔助函式 `fake_password_hasher` 與 `fake_save_user` 只是用來示範資料流程,並不提供任何實際的安全性。
+
+///
+
+## 減少重複 { #reduce-duplication }
+
+減少程式碼重複是 FastAPI 的核心理念之一。
+
+因為重複的程式碼會提高發生錯誤、安全性問題、程式不同步(某處更新但其他處未更新)等風險。
+
+而這些模型共享大量資料,重複了屬性名稱與型別。
+
+我們可以做得更好。
+
+我們可以宣告一個作為基底的 `UserBase` 模型,其他模型繼承它成為子類別,沿用其屬性(型別宣告、驗證等)。
+
+所有資料轉換、驗證、文件產生等仍可正常運作。
+
+如此一來,我們只需要宣告模型之間的差異(含明文 `password`、含 `hashed_password`、或不含密碼):
+
+{* ../../docs_src/extra_models/tutorial002_py310.py hl[7,13:14,17:18,21:22] *}
+
+## `Union` 或 `anyOf` { #union-or-anyof }
+
+你可以將回應宣告為多個型別的 `Union`,表示回應可能是其中任一型別。
+
+在 OpenAPI 中會以 `anyOf` 定義。
+
+要達成這點,使用標準的 Python 型別提示 `typing.Union`:
+
+/// note
+
+在定義 `Union` 時,請先放置「更具體」的型別,再放「較不具體」的型別。以下範例中,較具體的 `PlaneItem` 置於 `CarItem` 之前:`Union[PlaneItem, CarItem]`。
+
+///
+
+{* ../../docs_src/extra_models/tutorial003_py310.py hl[1,14:15,18:20,33] *}
+
+### Python 3.10 中的 `Union` { #union-in-python-3-10 }
+
+此範例中,我們將 `Union[PlaneItem, CarItem]` 作為引數 `response_model` 的值。
+
+由於這裡是把它當作引數的「值」傳入,而非用於型別註記,因此即使在 Python 3.10 也必須使用 `Union`。
+
+若用於型別註記,則可以使用直線(|),如下:
+
+```Python
+some_variable: PlaneItem | CarItem
+```
+
+但若寫成指定值 `response_model=PlaneItem | CarItem` 會發生錯誤,因為 Python 會嘗試在 `PlaneItem` 與 `CarItem` 之間執行「無效運算」,而非將其視為型別註記。
+
+## 模型的清單 { #list-of-models }
+
+同樣地,你可以將回應宣告為物件的 `list`。
+
+為此,使用標準的 Python `list`:
+
+{* ../../docs_src/extra_models/tutorial004_py310.py hl[18] *}
+
+## 以任意 `dict` 作為回應 { #response-with-arbitrary-dict }
+
+你也可以用一般的任意 `dict` 宣告回應,只需指定鍵和值的型別,而不必使用 Pydantic 模型。
+
+當你事先不知道可用的欄位/屬性名稱(定義 Pydantic 模型所需)時,這很實用。
+
+此時可使用 `dict`:
+
+{* ../../docs_src/extra_models/tutorial005_py310.py hl[6] *}
+
+## 重點回顧 { #recap }
+
+依情境使用多個 Pydantic 模型並靈活繼承。
+
+當一個實體需要呈現不同「狀態」時,不必侷限於一個資料模型。例如使用者這個實體,可能有包含 `password`、包含 `password_hash`,或不含密碼等不同狀態。
diff --git a/docs/zh-hant/docs/tutorial/first-steps.md b/docs/zh-hant/docs/tutorial/first-steps.md
index 6bcb453bff..3aa2d39ae1 100644
--- a/docs/zh-hant/docs/tutorial/first-steps.md
+++ b/docs/zh-hant/docs/tutorial/first-steps.md
@@ -2,7 +2,7 @@
最簡單的 FastAPI 檔案可能看起來像這樣:
-{* ../../docs_src/first_steps/tutorial001_py39.py *}
+{* ../../docs_src/first_steps/tutorial001_py310.py *}
將其複製到一個名為 `main.py` 的文件中。
@@ -183,7 +183,7 @@ Deploying to FastAPI Cloud...
### 第一步:引入 `FastAPI` { #step-1-import-fastapi }
-{* ../../docs_src/first_steps/tutorial001_py39.py hl[1] *}
+{* ../../docs_src/first_steps/tutorial001_py310.py hl[1] *}
`FastAPI` 是一個 Python 類別,提供所有 API 的全部功能。
@@ -197,7 +197,7 @@ Deploying to FastAPI Cloud...
### 第二步:建立一個 `FastAPI`「實例」 { #step-2-create-a-fastapi-instance }
-{* ../../docs_src/first_steps/tutorial001_py39.py hl[3] *}
+{* ../../docs_src/first_steps/tutorial001_py310.py hl[3] *}
這裡的 `app` 變數將會是 `FastAPI` 類別的「實例」。
@@ -266,12 +266,12 @@ https://example.com/items/foo
#### 定義一個「路徑操作裝飾器」 { #define-a-path-operation-decorator }
-{* ../../docs_src/first_steps/tutorial001_py39.py hl[6] *}
+{* ../../docs_src/first_steps/tutorial001_py310.py hl[6] *}
`@app.get("/")` 告訴 **FastAPI** 那個函式負責處理請求:
* 路徑 `/`
-* 使用 get操作
+* 使用 get 操作
/// info | `@decorator` 說明
@@ -320,7 +320,7 @@ Python 中的 `@something` 語法被稱為「裝飾器」。
* **operation**:是 `get`。
* **function**:是裝飾器下面的函式(在 `@app.get("/")` 下面)。
-{* ../../docs_src/first_steps/tutorial001_py39.py hl[7] *}
+{* ../../docs_src/first_steps/tutorial001_py310.py hl[7] *}
這就是一個 Python 函式。
@@ -332,7 +332,7 @@ Python 中的 `@something` 語法被稱為「裝飾器」。
你也可以將它定義為一般函式,而不是 `async def`:
-{* ../../docs_src/first_steps/tutorial003_py39.py hl[7] *}
+{* ../../docs_src/first_steps/tutorial003_py310.py hl[7] *}
/// note
@@ -342,7 +342,7 @@ Python 中的 `@something` 語法被稱為「裝飾器」。
### 第五步:回傳內容 { #step-5-return-the-content }
-{* ../../docs_src/first_steps/tutorial001_py39.py hl[8] *}
+{* ../../docs_src/first_steps/tutorial001_py310.py hl[8] *}
你可以返回一個 `dict`、`list`、單個值作為 `str`、`int` 等。
diff --git a/docs/zh-hant/docs/tutorial/handling-errors.md b/docs/zh-hant/docs/tutorial/handling-errors.md
new file mode 100644
index 0000000000..f3a7573cd5
--- /dev/null
+++ b/docs/zh-hant/docs/tutorial/handling-errors.md
@@ -0,0 +1,244 @@
+# 錯誤處理 { #handling-errors }
+
+在許多情況下,你需要通知使用你 API 的用戶端發生錯誤。
+
+這個用戶端可能是帶有前端的瀏覽器、他人的程式碼、IoT 裝置等。
+
+你可能需要告訴用戶端:
+
+* 用戶端沒有足夠權限執行該操作。
+* 用戶端沒有權限存取該資源。
+* 用戶端嘗試存取的項目不存在。
+* 等等。
+
+在這些情況下,通常會回傳範圍為 400(400 到 499)的 HTTP 狀態碼。
+
+這類似於 200 範圍的 HTTP 狀態碼(200 到 299)。那些「200」狀態碼表示請求在某種程度上是「成功」的。
+
+400 範圍的狀態碼表示用戶端錯誤。
+
+還記得那些「404 Not Found」錯誤(和梗)嗎?
+
+## 使用 `HTTPException` { #use-httpexception }
+
+要向用戶端回傳帶有錯誤的 HTTP 回應,使用 `HTTPException`。
+
+### 匯入 `HTTPException` { #import-httpexception }
+
+{* ../../docs_src/handling_errors/tutorial001_py310.py hl[1] *}
+
+### 在程式中 raise 一個 `HTTPException` { #raise-an-httpexception-in-your-code }
+
+`HTTPException` 是一般的 Python 例外,但包含與 API 相關的附加資料。
+
+因為它是 Python 的例外,你不是 `return`,而是 `raise`。
+
+這也表示,如果你在某個工具函式中(該函式被你的「路徑操作函式」呼叫),並在該工具函式裡 raise `HTTPException`,那麼「路徑操作函式」剩下的程式碼將不會執行;該請求會立刻被終止,並將 `HTTPException` 的 HTTP 錯誤傳回給用戶端。
+
+為何選擇 raise 例外而非回傳值的好處,會在相依性與安全性章節更為明顯。
+
+在這個範例中,當用戶端以不存在的 ID 請求項目時,raise 一個狀態碼為 `404` 的例外:
+
+{* ../../docs_src/handling_errors/tutorial001_py310.py hl[11] *}
+
+### 回應結果 { #the-resulting-response }
+
+如果用戶端請求 `http://example.com/items/foo`(`item_id` 為 `"foo"`),會收到 200 的 HTTP 狀態碼,以及以下 JSON 回應:
+
+```JSON
+{
+ "item": "The Foo Wrestlers"
+}
+```
+
+但如果用戶端請求 `http://example.com/items/bar`(不存在的 `item_id` `"bar"`),會收到 404("not found")的 HTTP 狀態碼,以及以下 JSON 回應:
+
+```JSON
+{
+ "detail": "Item not found"
+}
+```
+
+/// tip
+
+在 raise 一個 `HTTPException` 時,你可以將任何可轉為 JSON 的值作為 `detail` 參數,不只限於 `str`。
+
+你可以傳入 `dict`、`list` 等。
+
+**FastAPI** 會自動處理並轉為 JSON。
+
+///
+
+## 新增自訂標頭 { #add-custom-headers }
+
+有些情況需要在 HTTP 錯誤回應中加入自訂標頭,例如某些安全性情境。
+
+你大概不需要在程式碼中直接使用。
+
+但若你在進階情境中需要,可以這樣加入自訂標頭:
+
+{* ../../docs_src/handling_errors/tutorial002_py310.py hl[14] *}
+
+## 安裝自訂例外處理器 { #install-custom-exception-handlers }
+
+你可以使用 Starlette 的相同例外工具 來加入自訂例外處理器。
+
+假設你有一個自訂例外 `UnicornException`,你(或你使用的函式庫)可能會 `raise` 它。
+
+而你想用 FastAPI 全域處理這個例外。
+
+你可以使用 `@app.exception_handler()` 加入自訂例外處理器:
+
+{* ../../docs_src/handling_errors/tutorial003_py310.py hl[5:7,13:18,24] *}
+
+在這裡,如果你請求 `/unicorns/yolo`,該「路徑操作」會 `raise` 一個 `UnicornException`。
+
+但它會被 `unicorn_exception_handler` 所處理。
+
+因此你會得到一個乾淨的錯誤回應,HTTP 狀態碼為 `418`,JSON 內容如下:
+
+```JSON
+{"message": "Oops! yolo did something. There goes a rainbow..."}
+```
+
+/// note | 技術細節
+
+你也可以使用 `from starlette.requests import Request` 與 `from starlette.responses import JSONResponse`。
+
+**FastAPI** 以便利性為由,提供和 `starlette.responses` 相同的介面於 `fastapi.responses`。但大多數可用的回應類型其實直接來自 Starlette。`Request` 也一樣。
+
+///
+
+## 覆寫預設例外處理器 { #override-the-default-exception-handlers }
+
+**FastAPI** 內建了一些預設例外處理器。
+
+這些處理器負責在你 `raise` 一個 `HTTPException` 或請求帶有無效資料時,回傳預設的 JSON 回應。
+
+你可以用自己的處理器來覆寫它們。
+
+### 覆寫請求驗證例外 { #override-request-validation-exceptions }
+
+當請求包含無效資料時,**FastAPI** 會在內部 raise 一個 `RequestValidationError`。
+
+它同時也包含了對應的預設例外處理器。
+
+要覆寫它,匯入 `RequestValidationError`,並用 `@app.exception_handler(RequestValidationError)` 來裝飾你的例外處理器。
+
+例外處理器會接收一個 `Request` 和該例外。
+
+{* ../../docs_src/handling_errors/tutorial004_py310.py hl[2,14:19] *}
+
+現在,如果你前往 `/items/foo`,預設的 JSON 錯誤本應為:
+
+```JSON
+{
+ "detail": [
+ {
+ "loc": [
+ "path",
+ "item_id"
+ ],
+ "msg": "value is not a valid integer",
+ "type": "type_error.integer"
+ }
+ ]
+}
+```
+
+你將會改而得到文字版:
+
+```
+Validation errors:
+Field: ('path', 'item_id'), Error: Input should be a valid integer, unable to parse string as an integer
+```
+
+### 覆寫 `HTTPException` 的錯誤處理器 { #override-the-httpexception-error-handler }
+
+同樣地,你也可以覆寫 `HTTPException` 的處理器。
+
+例如,你可能想在這些錯誤時回傳純文字而非 JSON:
+
+{* ../../docs_src/handling_errors/tutorial004_py310.py hl[3:4,9:11,25] *}
+
+/// note | 技術細節
+
+你也可以使用 `from starlette.responses import PlainTextResponse`。
+
+**FastAPI** 以便利性為由,提供和 `starlette.responses` 相同的介面於 `fastapi.responses`。但大多數可用的回應類型其實直接來自 Starlette。
+
+///
+
+/// warning
+
+請注意,`RequestValidationError` 內含驗證錯誤發生的檔名與行號,如果你願意,可以在日誌中顯示這些相關資訊。
+
+但這也代表如果你只是把它轉成字串並直接回傳,可能會洩漏一些關於你系統的資訊。因此這裡的程式碼會分別擷取並顯示每個錯誤。
+
+///
+
+### 使用 `RequestValidationError` 的 body { #use-the-requestvalidationerror-body }
+
+`RequestValidationError` 包含它收到的(但無效的)`body`。
+
+在開發應用時,你可以用它來記錄 body 並除錯、回傳給使用者等。
+
+{* ../../docs_src/handling_errors/tutorial005_py310.py hl[14] *}
+
+現在嘗試送出一個無效的項目,例如:
+
+```JSON
+{
+ "title": "towel",
+ "size": "XL"
+}
+```
+
+你會收到一個告知資料無效、且包含所收到 body 的回應:
+
+```JSON hl_lines="12-15"
+{
+ "detail": [
+ {
+ "loc": [
+ "body",
+ "size"
+ ],
+ "msg": "value is not a valid integer",
+ "type": "type_error.integer"
+ }
+ ],
+ "body": {
+ "title": "towel",
+ "size": "XL"
+ }
+}
+```
+
+#### FastAPI 的 `HTTPException` 與 Starlette 的 `HTTPException` { #fastapis-httpexception-vs-starlettes-httpexception }
+
+**FastAPI** 有自己定義的 `HTTPException`。
+
+而 **FastAPI** 的 `HTTPException` 錯誤類別是繼承自 Starlette 的 `HTTPException` 錯誤類別。
+
+唯一的差異是,**FastAPI** 的 `HTTPException` 在 `detail` 欄位接受任何可轉為 JSON 的資料,而 Starlette 的 `HTTPException` 只接受字串。
+
+因此,在你的程式碼中,你可以一如往常地 raise **FastAPI** 的 `HTTPException`。
+
+但當你註冊例外處理器時,應該針對 Starlette 的 `HTTPException` 來註冊。
+
+如此一來,如果 Starlette 的內部程式碼,或任何 Starlette 擴充/外掛 raise 了 Starlette 的 `HTTPException`,你的處理器就能攔截並處理它。
+
+在這個範例中,為了能在同一份程式碼中同時使用兩種 `HTTPException`,我們把 Starlette 的例外重新命名為 `StarletteHTTPException`:
+
+```Python
+from starlette.exceptions import HTTPException as StarletteHTTPException
+```
+
+### 重用 **FastAPI** 的例外處理器 { #reuse-fastapis-exception-handlers }
+
+如果你想在使用例外的同時,沿用 **FastAPI** 的預設例外處理器,你可以從 `fastapi.exception_handlers` 匯入並重用預設的處理器:
+
+{* ../../docs_src/handling_errors/tutorial006_py310.py hl[2:5,15,21] *}
+
+在這個範例中,你只是用一段很生動的訊息把錯誤印出來,不過重點是:你可以使用該例外,然後直接重用預設的例外處理器。
diff --git a/docs/zh-hant/docs/tutorial/header-param-models.md b/docs/zh-hant/docs/tutorial/header-param-models.md
new file mode 100644
index 0000000000..ca2b1f8dee
--- /dev/null
+++ b/docs/zh-hant/docs/tutorial/header-param-models.md
@@ -0,0 +1,72 @@
+# 標頭參數模型 { #header-parameter-models }
+
+如果你有一組相關的標頭參數,可以建立一個 Pydantic 模型來宣告它們。
+
+這能讓你在多處重複使用該模型,並一次性為所有參數宣告驗證與中繼資料。😎
+
+/// note | 注意
+
+自 FastAPI 版本 `0.115.0` 起支援。🤓
+
+///
+
+## 以 Pydantic 模型宣告標頭參數 { #header-parameters-with-a-pydantic-model }
+
+在 Pydantic 模型中宣告你需要的標頭參數,然後將參數宣告為 `Header`:
+
+{* ../../docs_src/header_param_models/tutorial001_an_py310.py hl[9:14,18] *}
+
+FastAPI 會從請求的標頭為每個欄位擷取資料,並交給你已定義的 Pydantic 模型實例。
+
+## 檢視文件 { #check-the-docs }
+
+你可以在 `/docs` 的文件介面看到所需的標頭:
+
+
+

+
+
+## 禁止額外標頭 { #forbid-extra-headers }
+
+在某些特殊情境(可能不常見)下,你可能想限制允許接收的標頭。
+
+你可以使用 Pydantic 的模型設定來 `forbid` 任何 `extra` 欄位:
+
+{* ../../docs_src/header_param_models/tutorial002_an_py310.py hl[10] *}
+
+如果用戶端嘗試傳送額外的標頭,會收到錯誤回應。
+
+例如,用戶端若傳送名為 `tool`、值為 `plumbus` 的標頭,會收到錯誤回應,指出不允許標頭參數 `tool`:
+
+```json
+{
+ "detail": [
+ {
+ "type": "extra_forbidden",
+ "loc": ["header", "tool"],
+ "msg": "Extra inputs are not permitted",
+ "input": "plumbus",
+ }
+ ]
+}
+```
+
+## 停用底線轉換 { #disable-convert-underscores }
+
+與一般標頭參數相同,當參數名稱包含底線字元時,會自動轉換為連字號。
+
+例如,若在程式碼中有標頭參數 `save_data`,實際期望的 HTTP 標頭為 `save-data`,在文件中也會如此顯示。
+
+如果因某些原因需要停用這個自動轉換,你也可以在標頭參數的 Pydantic 模型上設定。
+
+{* ../../docs_src/header_param_models/tutorial003_an_py310.py hl[19] *}
+
+/// warning | 警告
+
+在將 `convert_underscores` 設為 `False` 之前,請注意有些 HTTP 代理與伺服器不允許含有底線的標頭。
+
+///
+
+## 摘要 { #summary }
+
+你可以在 FastAPI 中使用 Pydantic 模型宣告標頭。😎
diff --git a/docs/zh-hant/docs/tutorial/header-params.md b/docs/zh-hant/docs/tutorial/header-params.md
new file mode 100644
index 0000000000..2d6aade4bb
--- /dev/null
+++ b/docs/zh-hant/docs/tutorial/header-params.md
@@ -0,0 +1,91 @@
+# Header 參數 { #header-parameters }
+
+你可以用與定義 `Query`、`Path`、`Cookie` 參數相同的方式來定義 Header 參數。
+
+## 匯入 `Header` { #import-header }
+
+先匯入 `Header`:
+
+{* ../../docs_src/header_params/tutorial001_an_py310.py hl[3] *}
+
+## 宣告 `Header` 參數 { #declare-header-parameters }
+
+接著使用與 `Path`、`Query`、`Cookie` 相同的結構來宣告標頭參數。
+
+你可以設定預設值,以及所有額外的驗證或註解參數:
+
+{* ../../docs_src/header_params/tutorial001_an_py310.py hl[9] *}
+
+/// note | 注意
+
+`Header` 與 `Path`、`Query`、`Cookie` 是「姊妹」類別,同樣繼承自共同的 `Param` 類別。
+
+但請記得,當你從 `fastapi` 匯入 `Query`、`Path`、`Header` 等時,它們其實是會回傳特殊類別的函式。
+
+///
+
+/// info | 說明
+
+要宣告標頭,必須使用 `Header`,否則參數會被解讀為查詢參數。
+
+///
+
+## 自動轉換 { #automatic-conversion }
+
+在 `Path`、`Query`、`Cookie` 提供的功能之上,`Header` 還有一些額外的小功能。
+
+大多數標準標頭的單字以連字號(減號,`-`)分隔。
+
+但像 `user-agent` 這樣的變數名稱在 Python 中是無效的。
+
+因此,`Header` 會在預設情況下把參數名稱中的底線(`_`)轉換為連字號(`-`),以便讀取並在文件中顯示該標頭。
+
+此外,HTTP 標頭不區分大小寫,所以你可以使用標準的 Python 命名風格(snake_case)來宣告。
+
+因此,你可以像在 Python 程式中一樣使用 `user_agent`,不需要把首字母大寫成 `User_Agent` 或類似寫法。
+
+若因某些原因需要停用底線自動轉連字號的行為,將 `Header` 的 `convert_underscores` 參數設為 `False`:
+
+{* ../../docs_src/header_params/tutorial002_an_py310.py hl[10] *}
+
+/// warning | 警告
+
+在將 `convert_underscores` 設為 `False` 之前,請注意有些 HTTP 代理與伺服器不允許使用帶有底線的標頭。
+
+///
+
+## 重複的標頭 { #duplicate-headers }
+
+有時可能會收到重複的標頭,也就是同一個標頭會有多個值。
+
+可以在型別宣告中使用 list 來定義這種情況。
+
+你會以 Python 的 `list` 形式收到該重複標頭的所有值。
+
+例如,要宣告可以出現多次的 `X-Token` 標頭,可以這樣寫:
+
+{* ../../docs_src/header_params/tutorial003_an_py310.py hl[9] *}
+
+如果你在與該*路徑操作 (path operation)* 溝通時送出兩個 HTTP 標頭如下:
+
+```
+X-Token: foo
+X-Token: bar
+```
+
+回應會像這樣:
+
+```JSON
+{
+ "X-Token values": [
+ "bar",
+ "foo"
+ ]
+}
+```
+
+## 小結 { #recap }
+
+使用 `Header` 宣告標頭,套用與 `Query`、`Path`、`Cookie` 相同的通用模式。
+
+而且別擔心變數名稱中的底線,**FastAPI** 會自動幫你轉換。
diff --git a/docs/zh-hant/docs/tutorial/metadata.md b/docs/zh-hant/docs/tutorial/metadata.md
new file mode 100644
index 0000000000..3243efa89c
--- /dev/null
+++ b/docs/zh-hant/docs/tutorial/metadata.md
@@ -0,0 +1,120 @@
+# 中繼資料與文件 URL { #metadata-and-docs-urls }
+
+你可以在你的 FastAPI 應用程式中自訂多項中繼資料設定。
+
+## API 的中繼資料 { #metadata-for-api }
+
+你可以設定下列欄位,這些欄位會用在 OpenAPI 規格與自動產生的 API 文件介面中:
+
+| 參數 | 型別 | 說明 |
+|------------|------|-------------|
+| `title` | `str` | API 的標題。 |
+| `summary` | `str` | API 的簡短摘要。自 OpenAPI 3.1.0、FastAPI 0.99.0 起可用。 |
+| `description` | `str` | API 的簡短說明。可使用 Markdown。 |
+| `version` | `string` | API 的版本號。這是你自己的應用程式版本,不是 OpenAPI 的版本,例如 `2.5.0`。 |
+| `terms_of_service` | `str` | 指向 API 服務條款的 URL。若提供,必須是 URL。 |
+| `contact` | `dict` | 對外公開的 API 聯絡資訊。可包含多個欄位。contact 欄位
| 參數 | 型別 | 說明 |
|---|
name | str | 聯絡人/組織的識別名稱。 |
url | str | 指向聯絡資訊的 URL。必須是 URL 格式。 |
email | str | 聯絡人/組織的電子郵件地址。必須是電子郵件格式。 |
|
+| `license_info` | `dict` | 對外公開的 API 授權資訊。可包含多個欄位。license_info 欄位
| 參數 | 型別 | 說明 |
|---|
name | str | 必填(若有設定 license_info)。API 使用的授權名稱。 |
identifier | str | API 的 SPDX 授權表示式。identifier 欄位與 url 欄位互斥。自 OpenAPI 3.1.0、FastAPI 0.99.0 起可用。 |
url | str | API 所採用授權的 URL。必須是 URL 格式。 |
|
+
+你可以這樣設定它們:
+
+{* ../../docs_src/metadata/tutorial001_py310.py hl[3:16, 19:32] *}
+
+/// tip | 提示
+
+你可以在 `description` 欄位中撰寫 Markdown,輸出時會被正確渲染。
+
+///
+
+使用這些設定後,自動產生的 API 文件會像這樣:
+
+
+
+## 授權識別碼 { #license-identifier }
+
+自 OpenAPI 3.1.0 與 FastAPI 0.99.0 起,你也可以在 `license_info` 中使用 `identifier` 來取代 `url`。
+
+例如:
+
+{* ../../docs_src/metadata/tutorial001_1_py310.py hl[31] *}
+
+## 標籤的中繼資料 { #metadata-for-tags }
+
+你也可以透過 `openapi_tags` 參數,為用來分組你的路徑操作(path operation)的各個標籤加入額外中繼資料。
+
+它接收一個 list,其中每個標籤對應一個 dictionary。
+
+每個 dictionary 可包含:
+
+* `name`(**必填**):一個 `str`,其值需與你在路徑操作與 `APIRouter`s 的 `tags` 參數中使用的標籤名稱相同。
+* `description`:一個 `str`,為該標籤的簡短描述。可使用 Markdown,並會顯示在文件介面中。
+* `externalDocs`:一個 `dict`,描述外部文件,包含:
+ * `description`:一個 `str`,外部文件的簡短描述。
+ * `url`(**必填**):一個 `str`,外部文件的 URL。
+
+### 建立標籤的中繼資料 { #create-metadata-for-tags }
+
+我們用 `users` 與 `items` 兩個標籤來示範。
+
+先為你的標籤建立中繼資料,然後將它傳給 `openapi_tags` 參數:
+
+{* ../../docs_src/metadata/tutorial004_py310.py hl[3:16,18] *}
+
+注意你可以在描述中使用 Markdown,例如「login」會以粗體(**login**)顯示,而「fancy」會以斜體(_fancy_)顯示。
+
+/// tip | 提示
+
+你不必為你使用到的每個標籤都加入中繼資料。
+
+///
+
+### 使用你的標籤 { #use-your-tags }
+
+在你的路徑操作(以及 `APIRouter`s)上使用 `tags` 參數,將它們歸類到不同標籤下:
+
+{* ../../docs_src/metadata/tutorial004_py310.py hl[21,26] *}
+
+/// info | 資訊
+
+在[路徑操作設定]中閱讀更多關於標籤的內容:[Path Operation Configuration](path-operation-configuration.md#tags){.internal-link target=_blank}。
+
+///
+
+### 檢視文件 { #check-the-docs }
+
+現在檢視文件時,會看到所有額外的中繼資料:
+
+
+
+### 標籤順序 { #order-of-tags }
+
+每個標籤中繼資料 dictionary 在清單中的順序,也會決定它們在文件介面中的顯示順序。
+
+例如,雖然按字母排序時 `users` 會排在 `items` 之後,但因為我們在清單中將它的中繼資料放在第一個,所以它會先顯示。
+
+## OpenAPI URL { #openapi-url }
+
+預設情況下,OpenAPI 綱要(schema)會提供在 `/openapi.json`。
+
+但你可以用 `openapi_url` 參數來調整。
+
+例如,將它設定為提供在 `/api/v1/openapi.json`:
+
+{* ../../docs_src/metadata/tutorial002_py310.py hl[3] *}
+
+如果你想完全停用 OpenAPI 綱要,可以設定 `openapi_url=None`,同時也會停用依賴它的文件使用者介面。
+
+## 文件 URL { #docs-urls }
+
+你可以設定內建的兩個文件使用者介面:
+
+* Swagger UI:提供於 `/docs`。
+ * 可用 `docs_url` 參數設定其 URL。
+ * 設定 `docs_url=None` 可停用。
+* ReDoc:提供於 `/redoc`。
+ * 可用 `redoc_url` 參數設定其 URL。
+ * 設定 `redoc_url=None` 可停用。
+
+例如,將 Swagger UI 提供於 `/documentation`,並停用 ReDoc:
+
+{* ../../docs_src/metadata/tutorial003_py310.py hl[3] *}
diff --git a/docs/zh-hant/docs/tutorial/middleware.md b/docs/zh-hant/docs/tutorial/middleware.md
new file mode 100644
index 0000000000..ac6f5367d0
--- /dev/null
+++ b/docs/zh-hant/docs/tutorial/middleware.md
@@ -0,0 +1,95 @@
+# 中介軟體 { #middleware }
+
+你可以在 **FastAPI** 應用程式中加入中介軟體。
+
+「中介軟體」是一個函式,在任何特定的*路徑操作*處理之前先處理每個**請求**;在回傳之前,也會處理每個**回應**。
+
+- 它會攔截進到應用程式的每個**請求**。
+- 然後可以對該**請求**做一些處理或執行所需的程式碼。
+- 接著把**請求**傳遞給應用程式的其餘部分(某個*路徑操作*)處理。
+- 之後再接收應用程式(某個*路徑操作*)所產生的**回應**。
+- 可以對該**回應**做一些處理或執行所需的程式碼。
+- 然後回傳**回應**。
+
+/// note | 技術細節
+
+如果你有使用帶有 `yield` 的相依性,其釋放階段的程式碼會在中介軟體之後執行。
+
+若有背景工作(在[背景工作](background-tasks.md){.internal-link target=_blank}一節會介紹,你稍後會看到),它們會在所有中介軟體之後執行。
+
+///
+
+## 建立中介軟體 { #create-a-middleware }
+
+要建立中介軟體,將裝飾器 `@app.middleware("http")` 加在函式上方。
+
+中介軟體函式會接收:
+
+- `request`。
+- 一個函式 `call_next`,會以 `request` 作為參數。
+ - 這個函式會把 `request` 傳給對應的*路徑操作*。
+ - 然後回傳對應*路徑操作*所產生的 `response`。
+- 然後你可以在回傳之前進一步修改 `response`。
+
+{* ../../docs_src/middleware/tutorial001_py310.py hl[8:9,11,14] *}
+
+/// tip
+
+請記得,自訂的非標準標頭可以使用 `X-` 前綴。
+
+但如果你有自訂標頭並希望瀏覽器端的用戶端能看到它們,你需要在 CORS 設定([CORS(Cross-Origin Resource Sharing)](cors.md){.internal-link target=_blank})中使用 Starlette 的 CORS 文件所記載的參數 `expose_headers` 將它們加入。
+
+///
+
+/// note | 技術細節
+
+你也可以使用 `from starlette.requests import Request`。
+
+**FastAPI** 為了方便開發者而提供了它,但實際上它直接來自 Starlette。
+
+///
+
+### 在 `response` 之前與之後 { #before-and-after-the-response }
+
+你可以在任何*路徑操作*接收 `request` 之前,加入要執行的程式碼。
+
+也可以在產生出 `response` 之後、回傳之前執行程式碼。
+
+例如,你可以新增一個自訂標頭 `X-Process-Time`,其內容為處理請求並產生回應所花費的秒數:
+
+{* ../../docs_src/middleware/tutorial001_py310.py hl[10,12:13] *}
+
+/// tip
+
+這裡我們使用 `time.perf_counter()` 而不是 `time.time()`,因為在這些用例中它可能更精確。🤓
+
+///
+
+## 多個中介軟體的執行順序 { #multiple-middleware-execution-order }
+
+當你使用 `@app.middleware()` 裝飾器或 `app.add_middleware()` 方法加入多個中介軟體時,每個新的中介軟體都會包裹應用程式,形成一個堆疊。最後加入的中介軟體位於最外層,最先加入的位於最內層。
+
+在請求路徑上,最外層的中介軟體最先執行。
+
+在回應路徑上,它最後執行。
+
+例如:
+
+```Python
+app.add_middleware(MiddlewareA)
+app.add_middleware(MiddlewareB)
+```
+
+執行順序如下:
+
+- **請求**:MiddlewareB → MiddlewareA → 路由
+
+- **回應**:路由 → MiddlewareA → MiddlewareB
+
+這種堆疊行為可確保中介軟體以可預期且可控制的順序執行。
+
+## 其他中介軟體 { #other-middlewares }
+
+你之後可以在[進階使用者指南:進階中介軟體](../advanced/middleware.md){.internal-link target=_blank}閱讀更多關於其他中介軟體的內容。
+
+下一節你將會讀到如何使用中介軟體處理 CORS。
diff --git a/docs/zh-hant/docs/tutorial/path-operation-configuration.md b/docs/zh-hant/docs/tutorial/path-operation-configuration.md
new file mode 100644
index 0000000000..45c101434d
--- /dev/null
+++ b/docs/zh-hant/docs/tutorial/path-operation-configuration.md
@@ -0,0 +1,107 @@
+# 路徑操作設定 { #path-operation-configuration }
+
+你可以在你的「路徑操作裝飾器」中傳入多個參數來進行設定。
+
+/// warning | 警告
+
+請注意,這些參數是直接傳給「路徑操作裝飾器」,而不是傳給你的「路徑操作函式」。
+
+///
+
+## 回應狀態碼 { #response-status-code }
+
+你可以為「路徑操作」的回應設定 (HTTP) `status_code`。
+
+你可以直接傳入整數代碼,例如 `404`。
+
+如果不記得每個數字代碼代表什麼,你可以使用 `status` 中的速記常數:
+
+{* ../../docs_src/path_operation_configuration/tutorial001_py310.py hl[1,15] *}
+
+該狀態碼會用於回應,並被加入至 OpenAPI 結構描述中。
+
+/// note | 技術細節
+
+你也可以使用 `from starlette import status`。
+
+**FastAPI** 提供與 `starlette.status` 相同的 `fastapi.status`,僅為了方便你這位開發者,但它其實直接來自 Starlette。
+
+///
+
+## 標籤 { #tags }
+
+你可以為「路徑操作」加入標籤,傳入參數 `tags`,其值為由 `str` 組成的 `list`(通常只是一個 `str`):
+
+{* ../../docs_src/path_operation_configuration/tutorial002_py310.py hl[15,20,25] *}
+
+這些標籤會被加入到 OpenAPI 結構描述,並由自動化文件介面使用:
+
+
+
+### 含 Enum 的標籤 { #tags-with-enums }
+
+如果你的應用很大,可能會累積數個標籤,你會希望對相關的「路徑操作」始終使用相同的標籤。
+
+在這種情況下,可以考慮把標籤存放在 `Enum` 中。
+
+**FastAPI** 對此的支援方式與使用普通字串相同:
+
+{* ../../docs_src/path_operation_configuration/tutorial002b_py310.py hl[1,8:10,13,18] *}
+
+## 摘要與描述 { #summary-and-description }
+
+你可以加入 `summary` 與 `description`:
+
+{* ../../docs_src/path_operation_configuration/tutorial003_py310.py hl[17:18] *}
+
+## 從 docstring 取得描述 { #description-from-docstring }
+
+由於描述常常較長、跨越多行,你可以在函式的 文件字串(docstring) 中宣告「路徑操作」的描述,**FastAPI** 會從那裡讀取。
+
+你可以在 docstring 中書寫 Markdown,它會被正確解析並顯示(會考慮 docstring 的縮排)。
+
+{* ../../docs_src/path_operation_configuration/tutorial004_py310.py hl[17:25] *}
+
+這會用於互動式文件:
+
+
+
+## 回應描述 { #response-description }
+
+你可以用參數 `response_description` 指定回應的描述:
+
+{* ../../docs_src/path_operation_configuration/tutorial005_py310.py hl[18] *}
+
+/// info | 資訊
+
+請注意,`response_description` 專指回應,而 `description` 則是針對整個「路徑操作」的一般描述。
+
+///
+
+/// check | 檢查
+
+OpenAPI 規範要求每個「路徑操作」都必須有一個回應描述。
+
+因此,如果你未提供,**FastAPI** 會自動產生 "Successful response"。
+
+///
+
+
+
+## 將「路徑操作」標記為已棄用 { #deprecate-a-path-operation }
+
+若需要將「路徑操作」標記為 已棄用,但不移除它,請傳入參數 `deprecated`:
+
+{* ../../docs_src/path_operation_configuration/tutorial006_py310.py hl[16] *}
+
+在互動式文件中,它會被清楚標示為已棄用:
+
+
+
+比較已棄用與未棄用的「路徑操作」在文件中的呈現:
+
+
+
+## 總結 { #recap }
+
+你可以透過將參數傳給「路徑操作裝飾器」,輕鬆地設定並為你的「路徑操作」加入中繼資料。
diff --git a/docs/zh-hant/docs/tutorial/path-params-numeric-validations.md b/docs/zh-hant/docs/tutorial/path-params-numeric-validations.md
new file mode 100644
index 0000000000..a07f825b05
--- /dev/null
+++ b/docs/zh-hant/docs/tutorial/path-params-numeric-validations.md
@@ -0,0 +1,154 @@
+# 路徑參數與數值驗證 { #path-parameters-and-numeric-validations }
+
+就像使用 `Query` 為查詢參數宣告更多驗證與中繼資料一樣,你也可以用 `Path` 為路徑參數宣告相同類型的驗證與中繼資料。
+
+## 匯入 `Path` { #import-path }
+
+首先,從 `fastapi` 匯入 `Path`,並匯入 `Annotated`:
+
+{* ../../docs_src/path_params_numeric_validations/tutorial001_an_py310.py hl[1,3] *}
+
+/// info
+
+FastAPI 在 0.95.0 版加入並開始推薦使用 `Annotated`。
+
+如果你使用更舊的版本,嘗試使用 `Annotated` 會出錯。
+
+請確保在使用 `Annotated` 前,先[升級 FastAPI 版本](../deployment/versions.md#upgrading-the-fastapi-versions){.internal-link target=_blank}到至少 0.95.1。
+
+///
+
+## 宣告中繼資料 { #declare-metadata }
+
+你可以宣告與 `Query` 相同的所有參數。
+
+例如,若要為路徑參數 `item_id` 宣告 `title` 中繼資料,可以這樣寫:
+
+{* ../../docs_src/path_params_numeric_validations/tutorial001_an_py310.py hl[10] *}
+
+/// note
+
+路徑參數一定是必填,因為它必須是路徑的一部分。即使你將其宣告為 `None` 或設定預設值,也不會有任何影響,它仍然是必填。
+
+///
+
+## 依需求調整參數順序 { #order-the-parameters-as-you-need }
+
+/// tip
+
+如果你使用 `Annotated`,這點大概沒那麼重要或必要。
+
+///
+
+假設你想把查詢參數 `q` 宣告為必要的 `str`。
+
+而你不需要為該參數宣告其他內容,所以其實不需要用 `Query`。
+
+但你仍需要為路徑參數 `item_id` 使用 `Path`,而且基於某些理由你不想用 `Annotated`。
+
+如果你把有「預設值」的參數放在沒有「預設值」的參數之前,Python 會抱怨。
+
+但你可以調整它們的順序,先放沒有預設值(查詢參數 `q`)的參數。
+
+對 **FastAPI** 來說沒差。它會依參數名稱、型別與預設宣告(`Query`、`Path` 等)來辨識參數,並不在意順序。
+
+因此,你可以這樣宣告你的函式:
+
+{* ../../docs_src/path_params_numeric_validations/tutorial002_py310.py hl[7] *}
+
+但請記住,若使用 `Annotated`,你就不會有這個問題,因為你不是用函式參數預設值來放 `Query()` 或 `Path()`。
+
+{* ../../docs_src/path_params_numeric_validations/tutorial002_an_py310.py *}
+
+## 依需求調整參數順序的技巧 { #order-the-parameters-as-you-need-tricks }
+
+/// tip
+
+如果你使用 `Annotated`,這點大概沒那麼重要或必要。
+
+///
+
+這裡有個小技巧偶爾很好用,不過你大概不常需要。
+
+如果你想要:
+
+* 不用 `Query`、也不給預設值就宣告查詢參數 `q`
+* 使用 `Path` 宣告路徑參數 `item_id`
+* 讓它們的順序不同
+* 不使用 `Annotated`
+
+…Python 有個小語法可以做到。
+
+在函式的參數列表最前面放一個 `*`。
+
+Python 不會對這個 `*` 做任何事,但它會知道後續的所有參數都必須以關鍵字引數(key-value pairs)方式呼叫,也就是所謂的 kwargs。即便它們沒有預設值也一樣。
+
+{* ../../docs_src/path_params_numeric_validations/tutorial003_py310.py hl[7] *}
+
+### 使用 `Annotated` 更好 { #better-with-annotated }
+
+記住,如果你使用 `Annotated`,因為不是用函式參數預設值,所以你不會遇到這個問題,也可能不需要使用 `*`。
+
+{* ../../docs_src/path_params_numeric_validations/tutorial003_an_py310.py hl[10] *}
+
+## 數值驗證:大於或等於 { #number-validations-greater-than-or-equal }
+
+使用 `Query` 和 `Path`(以及你之後會看到的其他類別)可以宣告數值限制。
+
+這裡用 `ge=1`,代表 `item_id` 必須是「大於(`g`reater)或等於(`e`qual)」`1` 的整數。
+
+{* ../../docs_src/path_params_numeric_validations/tutorial004_an_py310.py hl[10] *}
+
+## 數值驗證:大於與小於或等於 { #number-validations-greater-than-and-less-than-or-equal }
+
+同樣也適用於:
+
+* `gt`:大於(`g`reater `t`han)
+* `le`:小於或等於(`l`ess than or `e`qual)
+
+{* ../../docs_src/path_params_numeric_validations/tutorial005_an_py310.py hl[10] *}
+
+## 數值驗證:浮點數、大於與小於 { #number-validations-floats-greater-than-and-less-than }
+
+數值驗證也適用於 `float`。
+
+這時就能看出能宣告 gt(不只是 ge)的重要性。因為你可以要求數值必須大於 `0`,即便它小於 `1`。
+
+所以,`0.5` 是有效的值,但 `0.0` 或 `0` 則無效。
+
+lt 也是同樣的道理。
+
+{* ../../docs_src/path_params_numeric_validations/tutorial006_an_py310.py hl[13] *}
+
+## 小結 { #recap }
+
+使用 `Query`、`Path`(以及你尚未看到的其他類別)時,你可以像在[查詢參數與字串驗證](query-params-str-validations.md){.internal-link target=_blank}中一樣,宣告中繼資料與字串驗證。
+
+你也可以宣告數值驗證:
+
+* `gt`:大於(`g`reater `t`han)
+* `ge`:大於或等於(`g`reater than or `e`qual)
+* `lt`:小於(`l`ess `t`han)
+* `le`:小於或等於(`l`ess than or `e`qual)
+
+/// info
+
+你之後會看到的 `Query`、`Path` 與其他類別,都是共同父類別 `Param` 的子類別。
+
+它們共享你已經看到的那些用於額外驗證與中繼資料的參數。
+
+///
+
+/// note | 技術細節
+
+當你從 `fastapi` 匯入 `Query`、`Path` 等時,它們其實是函式。
+
+呼叫它們時,會回傳同名類別的實例。
+
+也就是說,你匯入的是名為 `Query` 的函式,而當你呼叫它時,它會回傳同名的 `Query` 類別實例。
+
+這些函式之所以存在(而不是直接使用類別),是為了避免編輯器標記它們的型別錯誤。
+
+如此一來,你就能使用一般的編輯器與開發工具,而不需要額外設定來忽略那些錯誤。
+
+///
diff --git a/docs/zh-hant/docs/tutorial/path-params.md b/docs/zh-hant/docs/tutorial/path-params.md
new file mode 100644
index 0000000000..373f430cde
--- /dev/null
+++ b/docs/zh-hant/docs/tutorial/path-params.md
@@ -0,0 +1,251 @@
+# 路徑參數 { #path-parameters }
+
+你可以用與 Python 格式化字串相同的語法來宣告路徑「參數」或「變數」:
+
+{* ../../docs_src/path_params/tutorial001_py310.py hl[6:7] *}
+
+路徑參數 `item_id` 的值會作為引數 `item_id` 傳入你的函式。
+
+所以,如果你執行這個範例並前往 http://127.0.0.1:8000/items/foo,你會看到這樣的回應:
+
+```JSON
+{"item_id":"foo"}
+```
+
+## 具型別的路徑參數 { #path-parameters-with-types }
+
+你可以在函式中使用標準的 Python 型別註記為路徑參數宣告型別:
+
+{* ../../docs_src/path_params/tutorial002_py310.py hl[7] *}
+
+在這個例子裡,`item_id` 被宣告為 `int`。
+
+/// check
+
+這會在你的函式中提供編輯器支援,包括錯誤檢查、自動完成等。
+
+///
+
+## 資料 轉換 { #data-conversion }
+
+如果你執行這個範例並在瀏覽器開啟 http://127.0.0.1:8000/items/3,你會看到這樣的回應:
+
+```JSON
+{"item_id":3}
+```
+
+/// check
+
+注意你的函式接收(並回傳)的值是 `3`,也就是 Python 的 `int`,而不是字串 `"3"`。
+
+因此,有了這個型別宣告,**FastAPI** 會自動為你處理請求的 「解析」。
+
+///
+
+## 資料驗證 { #data-validation }
+
+但如果你在瀏覽器前往 http://127.0.0.1:8000/items/foo,你會看到漂亮的 HTTP 錯誤:
+
+```JSON
+{
+ "detail": [
+ {
+ "type": "int_parsing",
+ "loc": [
+ "path",
+ "item_id"
+ ],
+ "msg": "Input should be a valid integer, unable to parse string as an integer",
+ "input": "foo"
+ }
+ ]
+}
+```
+
+因為路徑參數 `item_id` 的值是 `"foo"`,它不是 `int`。
+
+同樣的錯誤也會在你提供 `float` 而不是 `int` 時出現,例如:http://127.0.0.1:8000/items/4.2
+
+/// check
+
+因此,搭配相同的 Python 型別宣告,**FastAPI** 會為你進行資料驗證。
+
+注意錯誤也清楚指出驗證未通過的確切位置。
+
+這在開發與除錯與你的 API 互動的程式碼時非常有幫助。
+
+///
+
+## 文件 { #documentation }
+
+當你在瀏覽器開啟 http://127.0.0.1:8000/docs,你會看到自動產生、可互動的 API 文件,例如:
+
+
+
+/// check
+
+同樣地,只要使用那個 Python 型別宣告,**FastAPI** 就會提供自動、互動式的文件(整合 Swagger UI)。
+
+注意路徑參數被宣告為整數。
+
+///
+
+## 基於標準的優勢與替代文件 { #standards-based-benefits-alternative-documentation }
+
+而且因為產生的 schema 來自 OpenAPI 標準,有很多相容的工具可用。
+
+因此,**FastAPI** 本身也提供另一種 API 文件(使用 ReDoc),你可以在 http://127.0.0.1:8000/redoc 存取:
+
+
+
+同樣地,也有許多相容工具可用,包括支援多種語言的程式碼產生工具。
+
+## Pydantic { #pydantic }
+
+所有資料驗證都由 Pydantic 在底層處理,因此你能直接受惠。而且你可以放心使用。
+
+你可以用相同的型別宣告搭配 `str`、`float`、`bool` 與許多更複雜的資料型別。
+
+這些之中的好幾個會在接下來的教學章節中介紹。
+
+## 順序很重要 { #order-matters }
+
+在建立「路徑操作」時,你可能會遇到有固定路徑的情況。
+
+像是 `/users/me`,假設它用來取得目前使用者的資料。
+
+然後你也可能有一個路徑 `/users/{user_id}` 用來依使用者 ID 取得特定使用者的資料。
+
+因為「路徑操作」會依宣告順序來比對,你必須確保 `/users/me` 的路徑在 `/users/{user_id}` 之前宣告:
+
+{* ../../docs_src/path_params/tutorial003_py310.py hl[6,11] *}
+
+否則,`/users/{user_id}` 的路徑也會匹配 `/users/me`,並「認為」它收到一個值為 `"me"` 的 `user_id` 參數。
+
+同樣地,你不能重新定義同一路徑操作:
+
+{* ../../docs_src/path_params/tutorial003b_py310.py hl[6,11] *}
+
+因為第一個會被優先使用(路徑先匹配到)。
+
+## 預先定義的值 { #predefined-values }
+
+如果你有一個接收「路徑參數」的「路徑操作」,但你希望可用的「路徑參數」值是預先定義好的,你可以使用標準的 Python `Enum`。
+
+### 建立 `Enum` 類別 { #create-an-enum-class }
+
+匯入 `Enum` 並建立一個同時繼承自 `str` 與 `Enum` 的子類別。
+
+繼承自 `str` 之後,API 文件就能知道這些值的型別必須是 `string`,並能正確地呈現。
+
+然後建立具有固定值的類別屬性,這些就是可用的有效值:
+
+{* ../../docs_src/path_params/tutorial005_py310.py hl[1,6:9] *}
+
+/// tip
+
+如果你在想,「AlexNet」、「ResNet」和「LeNet」只是一些機器學習 模型 的名字。
+
+///
+
+### 宣告一個「路徑參數」 { #declare-a-path-parameter }
+
+接著使用你建立的列舉類別(`ModelName`)作為型別註記,建立一個「路徑參數」:
+
+{* ../../docs_src/path_params/tutorial005_py310.py hl[16] *}
+
+### 查看文件 { #check-the-docs }
+
+因為「路徑參數」的可用值是預先定義的,互動式文件可以很漂亮地顯示它們:
+
+
+
+### 使用 Python「列舉」 { #working-with-python-enumerations }
+
+「路徑參數」的值會是一個「列舉成員」。
+
+#### 比較「列舉成員」 { #compare-enumeration-members }
+
+你可以把它與你建立的列舉 `ModelName` 中的「列舉成員」比較:
+
+{* ../../docs_src/path_params/tutorial005_py310.py hl[17] *}
+
+#### 取得「列舉值」 { #get-the-enumeration-value }
+
+你可以用 `model_name.value` 取得實際的值(在這個例子中是 `str`),一般而言就是 `your_enum_member.value`:
+
+{* ../../docs_src/path_params/tutorial005_py310.py hl[20] *}
+
+/// tip
+
+你也可以用 `ModelName.lenet.value` 取得值 `"lenet"`。
+
+///
+
+#### 回傳「列舉成員」 { #return-enumeration-members }
+
+你可以從「路徑操作」回傳「列舉成員」,即使是巢狀在 JSON 主體(例如 `dict`)裡。
+
+在回傳給用戶端之前,它們會被轉成對應的值(此例為字串):
+
+{* ../../docs_src/path_params/tutorial005_py310.py hl[18,21,23] *}
+
+你的用戶端會收到像這樣的 JSON 回應:
+
+```JSON
+{
+ "model_name": "alexnet",
+ "message": "Deep Learning FTW!"
+}
+```
+
+## 包含路徑的路徑參數 { #path-parameters-containing-paths }
+
+假設你有一個路徑為 `/files/{file_path}` 的「路徑操作」。
+
+但你需要 `file_path` 本身就包含一個「路徑」,像是 `home/johndoe/myfile.txt`。
+
+所以,該檔案的 URL 會是:`/files/home/johndoe/myfile.txt`。
+
+### OpenAPI 支援 { #openapi-support }
+
+OpenAPI 並不支援直接宣告一個「路徑參數」內再包含一個「路徑」,因為那會導致難以測試與定義的情況。
+
+然而,你仍可在 **FastAPI** 中這樣做,方法是使用 Starlette 的其中一個內部工具。
+
+而文件依然能運作,只是它不會額外說明該參數應該包含一個路徑。
+
+### 路徑轉換器 { #path-convertor }
+
+使用 Starlette 提供的選項,你可以用像這樣的 URL 來宣告一個包含「路徑」的「路徑參數」:
+
+```
+/files/{file_path:path}
+```
+
+在這個例子裡,參數名稱是 `file_path`,而最後面的 `:path` 表示該參數應該匹配任意「路徑」。
+
+所以你可以這樣使用它:
+
+{* ../../docs_src/path_params/tutorial004_py310.py hl[6] *}
+
+/// tip
+
+你可能需要這個參數包含 `/home/johndoe/myfile.txt`,也就是前面帶有斜線(`/`)。
+
+在那種情況下,URL 會是:`/files//home/johndoe/myfile.txt`,在 `files` 與 `home` 之間有兩個斜線(`//`)。
+
+///
+
+## 回顧 { #recap }
+
+使用 **FastAPI**,只要撰寫簡短、直覺且標準的 Python 型別宣告,你就能獲得:
+
+* 編輯器支援:錯誤檢查、自動完成等
+* 資料 "解析"
+* 資料驗證
+* API 註解與自動產生文件
+
+而且你只要宣告一次就好。
+
+這大概是 **FastAPI** 相較於其他框架最明顯的優勢之一(除了原始效能之外)。
diff --git a/docs/zh-hant/docs/tutorial/query-params-str-validations.md b/docs/zh-hant/docs/tutorial/query-params-str-validations.md
new file mode 100644
index 0000000000..ea84234c0e
--- /dev/null
+++ b/docs/zh-hant/docs/tutorial/query-params-str-validations.md
@@ -0,0 +1,449 @@
+# 查詢參數與字串驗證 { #query-parameters-and-string-validations }
+
+FastAPI 允許你為參數宣告額外的資訊與驗證。
+
+以下面這個應用為例:
+
+{* ../../docs_src/query_params_str_validations/tutorial001_py310.py hl[7] *}
+
+查詢參數 `q` 的型別是 `str | None`,表示它是 `str` 但也可以是 `None`,而且預設值就是 `None`,因此 FastAPI 會知道它不是必填。
+
+/// note | 注意
+
+FastAPI 會因為預設值是 `= None` 而知道 `q` 不是必填。
+
+使用 `str | None` 也能讓你的編輯器提供更好的支援並偵測錯誤。
+
+///
+
+## 額外驗證 { #additional-validation }
+
+我們要強制:即使 `q` 是可選,只要提供了,長度就不能超過 50 個字元。
+
+### 匯入 `Query` 與 `Annotated` { #import-query-and-annotated }
+
+要達成這點,先匯入:
+
+- 從 `fastapi` 匯入 `Query`
+- 從 `typing` 匯入 `Annotated`
+
+{* ../../docs_src/query_params_str_validations/tutorial002_an_py310.py hl[1,3] *}
+
+/// info | 說明
+
+FastAPI 自 0.95.0 版起加入並開始推薦使用 `Annotated`。
+
+如果你的版本較舊,嘗試使用 `Annotated` 會出錯。
+
+請先至少 [升級 FastAPI 版本](../deployment/versions.md#upgrading-the-fastapi-versions){.internal-link target=_blank} 到 0.95.1 再使用 `Annotated`。
+
+///
+
+## 在 `q` 參數的型別中使用 `Annotated` { #use-annotated-in-the-type-for-the-q-parameter }
+
+還記得先前在 [Python 型別介紹](../python-types.md#type-hints-with-metadata-annotations){.internal-link target=_blank} 提到可以用 `Annotated` 為參數加入中繼資料嗎?
+
+現在就用在 FastAPI 上吧。🚀
+
+我們原本的型別註記是:
+
+```Python
+q: str | None = None
+```
+
+接著把它用 `Annotated` 包起來,變成:
+
+```Python
+q: Annotated[str | None] = None
+```
+
+這兩種寫法代表的意思相同:`q` 可以是 `str` 或 `None`,且預設是 `None`。
+
+現在來做有趣的部分。🎉
+
+## 在 `q` 參數的 `Annotated` 中加入 `Query` { #add-query-to-annotated-in-the-q-parameter }
+
+既然我們有可以放更多資訊的 `Annotated`(在此是額外驗證),就把 `Query` 放進 `Annotated`,並把參數 `max_length` 設為 `50`:
+
+{* ../../docs_src/query_params_str_validations/tutorial002_an_py310.py hl[9] *}
+
+注意預設值仍然是 `None`,所以這個參數仍是可選。
+
+不過,現在在 `Annotated` 裡有 `Query(max_length=50)`,我們就告訴 FastAPI 要對這個值做「額外驗證」,最多 50 個字元即可。😎
+
+/// tip | 提示
+
+這裡用的是 `Query()`,因為這是「查詢參數」。稍後你會看到 `Path()`、`Body()`、`Header()`、`Cookie()` 等,它們也接受與 `Query()` 相同的參數。
+
+///
+
+FastAPI 現在會:
+
+- 驗證資料,確保長度最多 50 個字元
+- 當資料不合法時,回給用戶端清楚的錯誤
+- 在 OpenAPI 的路徑操作中文件化該參數(因此會出現在自動文件 UI)
+
+## 替代方式(舊):將 `Query` 作為預設值 { #alternative-old-query-as-the-default-value }
+
+舊版 FastAPI(0.95.0 以前)需要把 `Query` 當成參數的預設值,而不是放在 `Annotated` 裡。你很可能會在各處看到這種寫法,所以我也會說明一下。
+
+/// tip | 提示
+
+新程式碼且在可能的情況下,請依上面說明使用 `Annotated`。它有多項優點(如下所述),而沒有缺點。🍰
+
+///
+
+這是把 `Query()` 作為函式參數預設值的寫法,並把參數 `max_length` 設為 50:
+
+{* ../../docs_src/query_params_str_validations/tutorial002_py310.py hl[7] *}
+
+在這種情況下(未使用 `Annotated`),我們必須用 `Query()` 取代函式中的預設值 `None`,因此需要用 `Query(default=None)` 來設定預設值;對 FastAPI 而言,這達到相同目的。
+
+所以:
+
+```Python
+q: str | None = Query(default=None)
+```
+
+…會讓參數變為可選、預設值是 `None`,等同於:
+
+```Python
+q: str | None = None
+```
+
+但用 `Query` 的版本會明確宣告它是查詢參數。
+
+接著,我們可以傳更多參數給 `Query`。此例中是用於字串的 `max_length` 參數:
+
+```Python
+q: str | None = Query(default=None, max_length=50)
+```
+
+這一樣會驗證資料、在資料不合法時顯示清楚錯誤,並在 OpenAPI 的路徑操作中文件化該參數。
+
+### 將 `Query` 作為預設值或放在 `Annotated` 中 { #query-as-the-default-value-or-in-annotated }
+
+注意,把 `Query` 放在 `Annotated` 內時,不能使用 `Query` 的 `default` 參數。
+
+請改用函式參數的實際預設值。否則會不一致。
+
+例如,這是不允許的:
+
+```Python
+q: Annotated[str, Query(default="rick")] = "morty"
+```
+
+…因為不清楚預設值到底該是 `"rick"` 還是 `"morty"`。
+
+因此,你可以(且更推薦)這樣寫:
+
+```Python
+q: Annotated[str, Query()] = "rick"
+```
+
+…或在較舊的程式碼中你會看到:
+
+```Python
+q: str = Query(default="rick")
+```
+
+### `Annotated` 的優點 { #advantages-of-annotated }
+
+建議使用 `Annotated`,而不是在函式參數上使用(舊式的)預設值寫法,理由很多,且更好。🤓
+
+函式參數的「預設值」就是「實際的預設值」,這在 Python 的直覺上更一致。😌
+
+你也可以在沒有 FastAPI 的其他地方「直接呼叫」同一個函式,而且能「如預期」運作。若有「必填」參數(沒有預設值),你的「編輯器」會提示錯誤,「Python」在執行時也會抱怨你未傳遞必填參數。
+
+若不使用 `Annotated`、改用「(舊式)預設值」寫法,你在沒有 FastAPI 的「其他地方」呼叫該函式時,就得「記得」傳入正確參數,否則值會和預期不同(例如會得到 `QueryInfo` 或類似的東西,而不是 `str`)。你的編輯器不會提示,Python 執行該函式時也不會抱怨,只有在內部操作失敗時才會出錯。
+
+因為 `Annotated` 可以有多個中繼資料註解,你甚至可以用同一個函式配合其他工具,例如 Typer。🚀
+
+## 加入更多驗證 { #add-more-validations }
+
+你也可以加入 `min_length` 參數:
+
+{* ../../docs_src/query_params_str_validations/tutorial003_an_py310.py hl[10] *}
+
+## 加入正規表示式 { #add-regular-expressions }
+
+你可以定義參數必須符合的 regular expression `pattern`:
+
+{* ../../docs_src/query_params_str_validations/tutorial004_an_py310.py hl[11] *}
+
+這個特定的正規表示式樣式會檢查收到的參數值是否:
+
+- `^`:以後續的字元開頭,前面不能有其他字元。
+- `fixedquery`:必須正好等於 `fixedquery`。
+- `$`:在此結束,`fixedquery` 後面不能再有其他字元。
+
+如果你對「正規表示式」感到困惑,別擔心。這對很多人來說都不容易。你仍然可以先不使用正規表示式就完成很多事情。
+
+現在你知道,當你需要它們時,可以在 FastAPI 中使用它們。
+
+## 預設值 { #default-values }
+
+當然,你可以使用 `None` 以外的預設值。
+
+假設你想宣告查詢參數 `q` 的 `min_length` 是 `3`,且預設值是 `"fixedquery"`:
+
+{* ../../docs_src/query_params_str_validations/tutorial005_an_py310.py hl[9] *}
+
+/// note | 注意
+
+只要有任何型別的預設值(包含 `None`),參數就是可選(非必填)。
+
+///
+
+## 必填參數 { #required-parameters }
+
+當我們不需要宣告更多的驗證或中繼資料時,只要不提供預設值,就能讓查詢參數 `q` 成為必填,例如:
+
+```Python
+q: str
+```
+
+而不是:
+
+```Python
+q: str | None = None
+```
+
+但現在我們要搭配 `Query` 來宣告,例如:
+
+```Python
+q: Annotated[str | None, Query(min_length=3)] = None
+```
+
+因此,在使用 `Query` 時若要宣告值為必填,只要不要宣告預設值即可:
+
+{* ../../docs_src/query_params_str_validations/tutorial006_an_py310.py hl[9] *}
+
+### 必填,但可為 `None` { #required-can-be-none }
+
+你可以宣告參數可以接受 `None`,但仍然是必填。這會強制用戶端一定要送出一個值,即使該值是 `None`。
+
+要做到這點,你可以宣告 `None` 是合法型別,但不要宣告預設值:
+
+{* ../../docs_src/query_params_str_validations/tutorial006c_an_py310.py hl[9] *}
+
+## 查詢參數清單/多個值 { #query-parameter-list-multiple-values }
+
+當你用 `Query` 明確定義查詢參數時,也可以讓它接收一個值的清單;換句話說,就是「多個值」。
+
+例如,要宣告查詢參數 `q` 可以在 URL 中出現多次,你可以這樣寫:
+
+{* ../../docs_src/query_params_str_validations/tutorial011_an_py310.py hl[9] *}
+
+若使用這樣的 URL:
+
+```
+http://localhost:8000/items/?q=foo&q=bar
+```
+
+你會在路徑操作函式的參數 `q` 中,收到多個 `q` 查詢參數的值(`foo` 與 `bar`),以 Python 的 `list` 形式。
+
+因此,對該 URL 的回應會是:
+
+```JSON
+{
+ "q": [
+ "foo",
+ "bar"
+ ]
+}
+```
+
+/// tip | 提示
+
+要宣告型別為 `list` 的查詢參數(如上例),需要明確使用 `Query`,否則它會被解讀為請求本文。
+
+///
+
+互動式 API 文件也會相應更新,以便支援多個值:
+
+
+
+### 查詢參數清單/多個值的預設值 { #query-parameter-list-multiple-values-with-defaults }
+
+也可以在未提供任何值時,定義 `list` 型別的預設值:
+
+{* ../../docs_src/query_params_str_validations/tutorial012_an_py310.py hl[9] *}
+
+如果你前往:
+
+```
+http://localhost:8000/items/
+```
+
+`q` 的預設值會是:`["foo", "bar"]`,而回應會是:
+
+```JSON
+{
+ "q": [
+ "foo",
+ "bar"
+ ]
+}
+```
+
+#### 只使用 `list` { #using-just-list }
+
+你也可以直接使用 `list`,而不是 `list[str]`:
+
+{* ../../docs_src/query_params_str_validations/tutorial013_an_py310.py hl[9] *}
+
+/// note | 注意
+
+注意,在這種情況下,FastAPI 不會檢查清單的內容。
+
+例如,`list[int]` 會檢查(並文件化)清單內容為整數;但單獨使用 `list` 則不會。
+
+///
+
+## 宣告更多中繼資料 { #declare-more-metadata }
+
+你可以為參數加入更多資訊。
+
+這些資訊會被包含在產生的 OpenAPI 中,供文件 UI 與外部工具使用。
+
+/// note | 注意
+
+請留意,不同工具對 OpenAPI 的支援程度可能不同。
+
+有些工具可能暫時還不會顯示所有額外資訊;不過多半這些缺漏功能已在開發規劃中。
+
+///
+
+你可以加入 `title`:
+
+{* ../../docs_src/query_params_str_validations/tutorial007_an_py310.py hl[10] *}
+
+以及 `description`:
+
+{* ../../docs_src/query_params_str_validations/tutorial008_an_py310.py hl[14] *}
+
+## 別名參數 { #alias-parameters }
+
+想像你希望參數名稱是 `item-query`。
+
+像這樣:
+
+```
+http://127.0.0.1:8000/items/?item-query=foobaritems
+```
+
+但 `item-query` 不是合法的 Python 變數名稱。
+
+最接近的大概是 `item_query`。
+
+但你仍然需要它就是 `item-query`...
+
+那你可以宣告一個 `alias`,實際上就會用這個別名來讀取參數值:
+
+{* ../../docs_src/query_params_str_validations/tutorial009_an_py310.py hl[9] *}
+
+## 棄用參數 { #deprecating-parameters }
+
+現在假設你不再喜歡這個參數了。
+
+你必須暫時保留它,因為還有用戶端在用,但你希望文件能清楚標示它是已棄用。
+
+接著把參數 `deprecated=True` 傳給 `Query`:
+
+{* ../../docs_src/query_params_str_validations/tutorial010_an_py310.py hl[19] *}
+
+文件會這樣顯示:
+
+
+
+## 從 OpenAPI 排除參數 { #exclude-parameters-from-openapi }
+
+若要把某個查詢參數從產生的 OpenAPI(以及自動文件系統)中排除,將 `Query` 的 `include_in_schema` 設為 `False`:
+
+{* ../../docs_src/query_params_str_validations/tutorial014_an_py310.py hl[10] *}
+
+## 自訂驗證 { #custom-validation }
+
+有時你需要做一些上述參數無法處理的「自訂驗證」。
+
+這種情況下,你可以使用「自訂驗證函式」,它會在一般驗證之後套用(例如先確認值是 `str` 之後)。
+
+你可以在 `Annotated` 中使用 Pydantic 的 `AfterValidator` 來達成。
+
+/// tip | 提示
+
+Pydantic 也有 `BeforeValidator` 等等。🤓
+
+///
+
+例如,以下自訂驗證器會檢查項目 ID 是否以 `isbn-` 開頭(ISBN 書籍編號),或以 `imdb-` 開頭(IMDB 電影 URL 的 ID):
+
+{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py hl[5,16:19,24] *}
+
+/// info | 說明
+
+這需搭配 Pydantic 2 或以上版本。😎
+
+///
+
+/// tip | 提示
+
+如果你需要做任何需要與「外部元件」溝通的驗證(例如資料庫或其他 API),應該改用「FastAPI 依賴」(FastAPI Dependencies),你稍後會學到。
+
+這些自訂驗證器適用於只需使用請求中「同一份資料」即可完成的檢查。
+
+///
+
+### 理解這段程式碼 { #understand-that-code }
+
+重點就是在 `Annotated` 中使用「`AfterValidator` 搭配函式」。如果你願意,可以略過這一節。🤸
+
+---
+
+但如果你對這個範例感到好奇且仍有興致,以下是一些額外細節。
+
+#### 使用 `value.startswith()` 的字串 { #string-with-value-startswith }
+
+你注意到了嗎?字串的 `value.startswith()` 可以接收一個 tuple,並逐一檢查 tuple 中的每個值:
+
+{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py ln[16:19] hl[17] *}
+
+#### 隨機項目 { #a-random-item }
+
+透過 `data.items()` 我們會得到一個包含每個字典項目鍵值對 tuple 的 iterable object。
+
+我們用 `list(data.items())` 把這個可疊代物件轉成正式的 `list`。
+
+接著用 `random.choice()` 從清單中取得一個「隨機值」,也就是一個 `(id, name)` 的 tuple。可能像是 `("imdb-tt0371724", "The Hitchhiker's Guide to the Galaxy")`。
+
+然後把這個 tuple 的兩個值分別指定給變數 `id` 和 `name`。
+
+因此,即使使用者沒有提供 item ID,仍然會收到一個隨機建議。
+
+……而這全部只用一行簡單的程式碼完成。🤯 你不愛 Python 嗎?🐍
+
+{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py ln[22:30] hl[29] *}
+
+## 重點回顧 { #recap }
+
+你可以為參數宣告額外的驗證與中繼資料。
+
+通用的驗證與中繼資料:
+
+- `alias`
+- `title`
+- `description`
+- `deprecated`
+
+字串專用的驗證:
+
+- `min_length`
+- `max_length`
+- `pattern`
+
+使用 `AfterValidator` 的自訂驗證。
+
+在這些範例中,你看到了如何為 `str` 值宣告驗證。
+
+接下來的章節會示範如何為其他型別(像是數字)宣告驗證。
diff --git a/docs/zh-hant/docs/tutorial/query-params.md b/docs/zh-hant/docs/tutorial/query-params.md
new file mode 100644
index 0000000000..f21bf40506
--- /dev/null
+++ b/docs/zh-hant/docs/tutorial/query-params.md
@@ -0,0 +1,187 @@
+# 查詢參數 { #query-parameters }
+
+當你宣告不是路徑參數的其他函式參數時,會自動被視為「查詢(query)」參數。
+
+{* ../../docs_src/query_params/tutorial001_py310.py hl[9] *}
+
+查詢是出現在 URL 中 `?` 之後的一組鍵值對,以 `&` 字元分隔。
+
+例如,URL:
+
+```
+http://127.0.0.1:8000/items/?skip=0&limit=10
+```
+
+...查詢參數為:
+
+* `skip`:值為 `0`
+* `limit`:值為 `10`
+
+因為它們是 URL 的一部分,天生是字串。
+
+但當你以 Python 型別宣告它們(如上例中的 `int`),它們會被轉換成該型別並據此驗證。
+
+對於查詢參數,會套用與路徑參數相同的處理流程:
+
+* 編輯器支援(當然)
+* 資料 「解析」
+* 資料驗證
+* 自動文件
+
+## 預設值 { #defaults }
+
+由於查詢參數不是路徑的固定部分,因此可以是選填並具有預設值。
+
+在上面的例子中,預設值為 `skip=0` 與 `limit=10`。
+
+因此,造訪下列 URL:
+
+```
+http://127.0.0.1:8000/items/
+```
+
+等同於造訪:
+
+```
+http://127.0.0.1:8000/items/?skip=0&limit=10
+```
+
+但如果你改為造訪:
+
+```
+http://127.0.0.1:8000/items/?skip=20
+```
+
+函式中的參數值會是:
+
+* `skip=20`:因為你在 URL 中設定了它
+* `limit=10`:因為那是預設值
+
+## 選用參數 { #optional-parameters }
+
+同樣地,你可以將預設值設為 `None` 來宣告選用的查詢參數:
+
+{* ../../docs_src/query_params/tutorial002_py310.py hl[7] *}
+
+在這種情況下,函式參數 `q` 為選用,且預設為 `None`。
+
+/// check | 注意
+
+另外請注意,FastAPI 能辨識出路徑參數 `item_id` 是路徑參數,而 `q` 不是,因此 `q` 會被當作查詢參數。
+
+///
+
+## 查詢參數型別轉換 { #query-parameter-type-conversion }
+
+你也可以宣告 `bool` 型別,值會被自動轉換:
+
+{* ../../docs_src/query_params/tutorial003_py310.py hl[7] *}
+
+在這種情況下,如果你造訪:
+
+```
+http://127.0.0.1:8000/items/foo?short=1
+```
+
+或
+
+```
+http://127.0.0.1:8000/items/foo?short=True
+```
+
+或
+
+```
+http://127.0.0.1:8000/items/foo?short=true
+```
+
+或
+
+```
+http://127.0.0.1:8000/items/foo?short=on
+```
+
+或
+
+```
+http://127.0.0.1:8000/items/foo?short=yes
+```
+
+或任何其他大小寫變化(全大寫、首字母大寫等),你的函式會將參數 `short` 視為 `bool` 值 `True`。否則為 `False`。
+
+## 多個路徑與查詢參數 { #multiple-path-and-query-parameters }
+
+你可以同時宣告多個路徑參數與查詢參數,FastAPI 會自動分辨。
+
+而且不必按特定順序宣告。
+
+會依名稱辨識:
+
+{* ../../docs_src/query_params/tutorial004_py310.py hl[6,8] *}
+
+## 必填查詢參數 { #required-query-parameters }
+
+當你為非路徑參數(目前我們只看到查詢參數)宣告了預設值時,它就不是必填。
+
+若你不想提供特定預設值、只想讓它為選填,將預設值設為 `None`。
+
+但若你要讓查詢參數成為必填,只要不要宣告任何預設值:
+
+{* ../../docs_src/query_params/tutorial005_py310.py hl[6:7] *}
+
+此處查詢參數 `needy` 是必填的 `str`。
+
+如果你在瀏覽器中開啟如下的 URL:
+
+```
+http://127.0.0.1:8000/items/foo-item
+```
+
+...沒有加上必填的 `needy` 參數,你會看到類似這樣的錯誤:
+
+```JSON
+{
+ "detail": [
+ {
+ "type": "missing",
+ "loc": [
+ "query",
+ "needy"
+ ],
+ "msg": "Field required",
+ "input": null
+ }
+ ]
+}
+```
+
+由於 `needy` 是必填參數,你需要在 URL 中設定它:
+
+```
+http://127.0.0.1:8000/items/foo-item?needy=sooooneedy
+```
+
+...這樣就會成功:
+
+```JSON
+{
+ "item_id": "foo-item",
+ "needy": "sooooneedy"
+}
+```
+
+當然,你可以同時定義部分參數為必填、部分有預設值、部分為選填:
+
+{* ../../docs_src/query_params/tutorial006_py310.py hl[8] *}
+
+在此例中,有 3 個查詢參數:
+
+* `needy`,必填的 `str`。
+* `skip`,具有預設值 `0` 的 `int`。
+* `limit`,選填的 `int`。
+
+/// tip | 提示
+
+你也可以像在[路徑參數](path-params.md#predefined-values){.internal-link target=_blank}中一樣使用 `Enum`。
+
+///
diff --git a/docs/zh-hant/docs/tutorial/request-files.md b/docs/zh-hant/docs/tutorial/request-files.md
new file mode 100644
index 0000000000..c8606a3f23
--- /dev/null
+++ b/docs/zh-hant/docs/tutorial/request-files.md
@@ -0,0 +1,176 @@
+# 請求中的檔案 { #request-files }
+
+你可以使用 `File` 定義由用戶端上傳的檔案。
+
+/// info
+
+若要接收上傳的檔案,請先安裝 `python-multipart`。
+
+請先建立並啟用一個[虛擬環境](../virtual-environments.md){.internal-link target=_blank},然後安裝,例如:
+
+```console
+$ pip install python-multipart
+```
+
+因為上傳的檔案是以「表單資料」送出的。
+
+///
+
+## 匯入 `File` { #import-file }
+
+從 `fastapi` 匯入 `File` 與 `UploadFile`:
+
+{* ../../docs_src/request_files/tutorial001_an_py310.py hl[3] *}
+
+## 定義 `File` 參數 { #define-file-parameters }
+
+和 `Body` 或 `Form` 一樣的方式建立檔案參數:
+
+{* ../../docs_src/request_files/tutorial001_an_py310.py hl[9] *}
+
+/// info
+
+`File` 是直接繼承自 `Form` 的類別。
+
+但請記住,當你從 `fastapi` 匯入 `Query`、`Path`、`File` 等時,它們其實是回傳特殊類別的函式。
+
+///
+
+/// tip
+
+要宣告檔案本文,必須使用 `File`,否則參數會被解讀為查詢參數或本文(JSON)參數。
+
+///
+
+檔案會以「表單資料」上傳。
+
+如果你將路徑操作函式(path operation function)的參數型別宣告為 `bytes`,**FastAPI** 會替你讀取檔案,你會以 `bytes` 取得內容。
+
+請注意,這表示整個內容會存放在記憶體中,適合小檔案。
+
+但在許多情況下,使用 `UploadFile` 會更好。
+
+## 使用 `UploadFile` 的檔案參數 { #file-parameters-with-uploadfile }
+
+將檔案參數型別設為 `UploadFile`:
+
+{* ../../docs_src/request_files/tutorial001_an_py310.py hl[14] *}
+
+使用 `UploadFile` 相較於 `bytes` 有數個優點:
+
+* 你不必在參數的預設值使用 `File()`。
+* 它使用「spooled」檔案:
+ * 檔案在記憶體中保存到某個大小上限,超過上限後會存到磁碟。
+* 因此適合處理大型檔案(例如圖片、影片、大型二進位檔等),而不會耗盡記憶體。
+* 你可以取得上傳檔案的中繼資料。
+* 它提供一個類檔案的 `async` 介面。
+* 它會提供實際的 Python `SpooledTemporaryFile` 物件,你可以直接傳給需要類檔案物件的其他函式或函式庫。
+
+### `UploadFile` { #uploadfile }
+
+`UploadFile` 具有以下屬性:
+
+* `filename`:一個 `str`,為上傳的原始檔名(例如 `myimage.jpg`)。
+* `content_type`:一個 `str`,為內容類型(MIME type / media type)(例如 `image/jpeg`)。
+* `file`:一個 `SpooledTemporaryFile`(類檔案物件)。這是真正的 Python 檔案物件,你可以直接傳給期待「類檔案」物件的其他函式或函式庫。
+
+`UploadFile` 有以下 `async` 方法。它們底層會呼叫對應的檔案方法(使用內部的 `SpooledTemporaryFile`)。
+
+* `write(data)`:將 `data`(`str` 或 `bytes`)寫入檔案。
+* `read(size)`:讀取檔案的 `size`(`int`)個位元組/字元。
+* `seek(offset)`:移動到檔案中的位元組位置 `offset`(`int`)。
+ * 例如,`await myfile.seek(0)` 會移到檔案開頭。
+ * 當你已經執行過 `await myfile.read()`,之後需要再次讀取內容時特別有用。
+* `close()`:關閉檔案。
+
+由於這些都是 `async` 方法,你需要以 await 呼叫它們。
+
+例如,在 `async` 的路徑操作函式中可這樣讀取內容:
+
+```Python
+contents = await myfile.read()
+```
+
+若是在一般的 `def` 路徑操作函式中,你可以直接存取 `UploadFile.file`,例如:
+
+```Python
+contents = myfile.file.read()
+```
+
+/// note | `async` 技術細節
+
+當你使用這些 `async` 方法時,**FastAPI** 會在執行緒池中執行對應的檔案方法並等待結果。
+
+///
+
+/// note | Starlette 技術細節
+
+**FastAPI** 的 `UploadFile` 直接繼承自 **Starlette** 的 `UploadFile`,但新增了一些必要部分,使其與 **Pydantic** 及 FastAPI 其他部分相容。
+
+///
+
+## 什麼是「表單資料」 { #what-is-form-data }
+
+HTML 表單(``)送到伺服器的資料通常使用一種「特殊」編碼,與 JSON 不同。
+
+**FastAPI** 會從正確的位置讀取該資料,而不是當作 JSON。
+
+/// note | 技術細節
+
+表單資料在不包含檔案時,通常使用媒體型別 `application/x-www-form-urlencoded` 編碼。
+
+但當表單包含檔案時,會使用 `multipart/form-data` 編碼。若你使用 `File`,**FastAPI** 會知道要從請求本文的正確部分取得檔案。
+
+若想進一步了解這些編碼與表單欄位,請參考 MDN Web Docs 的 POST。
+
+///
+
+/// warning
+
+你可以在一個路徑操作中宣告多個 `File` 與 `Form` 參數,但不能同時宣告預期以 JSON 接收的 `Body` 欄位,因為此請求的本文會使用 `multipart/form-data` 而不是 `application/json`。
+
+這不是 **FastAPI** 的限制,而是 HTTP 協定本身的規範。
+
+///
+
+## 可選的檔案上傳 { #optional-file-upload }
+
+可透過一般型別註解並將預設值設為 `None` 使檔案成為可選:
+
+{* ../../docs_src/request_files/tutorial001_02_an_py310.py hl[9,17] *}
+
+## `UploadFile` 搭配額外中繼資料 { #uploadfile-with-additional-metadata }
+
+你也可以在 `UploadFile` 上搭配 `File()`,例如用來設定額外的中繼資料:
+
+{* ../../docs_src/request_files/tutorial001_03_an_py310.py hl[9,15] *}
+
+## 多檔案上傳 { #multiple-file-uploads }
+
+可以同時上傳多個檔案。
+
+它們會同屬於以「表單資料」送出的同一個表單欄位。
+
+要這麼做,將型別宣告為 `bytes` 或 `UploadFile` 的 `list`:
+
+{* ../../docs_src/request_files/tutorial002_an_py310.py hl[10,15] *}
+
+你會如宣告所示,收到由 `bytes` 或 `UploadFile` 組成的 `list`。
+
+/// note | 技術細節
+
+你也可以使用 `from starlette.responses import HTMLResponse`。
+
+**FastAPI** 為了讓你(開發者)更方便,提供與 `starlette.responses` 相同的內容作為 `fastapi.responses`。但大多數可用的回應類型其實直接來自 Starlette。
+
+///
+
+### 多檔案上傳且包含額外中繼資料 { #multiple-file-uploads-with-additional-metadata }
+
+同樣地,即使對 `UploadFile`,你也可以用 `File()` 設定額外參數:
+
+{* ../../docs_src/request_files/tutorial003_an_py310.py hl[11,18:20] *}
+
+## 小結 { #recap }
+
+使用 `File`、`bytes` 與 `UploadFile` 來宣告請求中要上傳的檔案,這些檔案會以表單資料送出。
diff --git a/docs/zh-hant/docs/tutorial/request-form-models.md b/docs/zh-hant/docs/tutorial/request-form-models.md
new file mode 100644
index 0000000000..8cf4a7c5e8
--- /dev/null
+++ b/docs/zh-hant/docs/tutorial/request-form-models.md
@@ -0,0 +1,78 @@
+# 表單模型 { #form-models }
+
+你可以使用 **Pydantic 模型** 在 FastAPI 中宣告 **表單欄位**。
+
+/// info | 說明
+
+要使用表單,首先安裝 `python-multipart`。
+
+請先建立[虛擬環境](../virtual-environments.md){.internal-link target=_blank}、啟用後再安裝,例如:
+
+```console
+$ pip install python-multipart
+```
+
+///
+
+/// note | 注意
+
+此功能自 FastAPI 版本 `0.113.0` 起支援。🤓
+
+///
+
+## 針對表單的 Pydantic 模型 { #pydantic-models-for-forms }
+
+你只需要宣告一個 **Pydantic 模型**,包含你要接收為 **表單欄位** 的欄位,然後將參數宣告為 `Form`:
+
+{* ../../docs_src/request_form_models/tutorial001_an_py310.py hl[9:11,15] *}
+
+**FastAPI** 會從請求中的 **表單資料** 擷取 **各欄位** 的資料,並將這些資料組成你定義的 Pydantic 模型實例。
+
+## 檢視文件 { #check-the-docs }
+
+你可以在 `/docs` 的文件 UI 中驗證:
+
+
+

+
+
+## 禁止額外的表單欄位 { #forbid-extra-form-fields }
+
+在某些特殊情況(可能不常見)下,你可能希望僅允許 Pydantic 模型中宣告的表單欄位,並禁止任何額外欄位。
+
+/// note | 注意
+
+此功能自 FastAPI 版本 `0.114.0` 起支援。🤓
+
+///
+
+你可以使用 Pydantic 的模型設定來 `forbid` 任何 `extra` 欄位:
+
+{* ../../docs_src/request_form_models/tutorial002_an_py310.py hl[12] *}
+
+如果用戶端嘗試傳送額外資料,將會收到錯誤回應。
+
+例如,用戶端若送出以下表單欄位:
+
+* `username`: `Rick`
+* `password`: `Portal Gun`
+* `extra`: `Mr. Poopybutthole`
+
+他們會收到一個錯誤回應,告知欄位 `extra` 不被允許:
+
+```json
+{
+ "detail": [
+ {
+ "type": "extra_forbidden",
+ "loc": ["body", "extra"],
+ "msg": "Extra inputs are not permitted",
+ "input": "Mr. Poopybutthole"
+ }
+ ]
+}
+```
+
+## 摘要 { #summary }
+
+你可以使用 Pydantic 模型在 FastAPI 中宣告表單欄位。😎
diff --git a/docs/zh-hant/docs/tutorial/request-forms-and-files.md b/docs/zh-hant/docs/tutorial/request-forms-and-files.md
new file mode 100644
index 0000000000..6dcc1c260f
--- /dev/null
+++ b/docs/zh-hant/docs/tutorial/request-forms-and-files.md
@@ -0,0 +1,41 @@
+# 請求中的表單與檔案 { #request-forms-and-files }
+
+你可以使用 `File` 與 `Form` 同時定義檔案與表單欄位。
+
+/// info
+
+要接收上傳的檔案與/或表單資料,請先安裝 `python-multipart`。
+
+請先建立並啟用一個 [虛擬環境](../virtual-environments.md){.internal-link target=_blank},然後再安裝,例如:
+
+```console
+$ pip install python-multipart
+```
+
+///
+
+## 匯入 `File` 與 `Form` { #import-file-and-form }
+
+{* ../../docs_src/request_forms_and_files/tutorial001_an_py310.py hl[3] *}
+
+## 定義 `File` 與 `Form` 參數 { #define-file-and-form-parameters }
+
+以與 `Body` 或 `Query` 相同的方式建立檔案與表單參數:
+
+{* ../../docs_src/request_forms_and_files/tutorial001_an_py310.py hl[10:12] *}
+
+檔案與表單欄位會作為表單資料上傳,而你將能接收到這些檔案與欄位。
+
+你也可以將部分檔案宣告為 `bytes`,另一些宣告為 `UploadFile`。
+
+/// warning
+
+你可以在一個路徑操作 (path operation) 中宣告多個 `File` 與 `Form` 參數,但不能同時再宣告預期以 JSON 接收的 `Body` 欄位,因為該請求的本文會使用 `multipart/form-data` 而非 `application/json` 進行編碼。
+
+這不是 **FastAPI** 的限制,這是 HTTP 通訊協定本身的規範。
+
+///
+
+## 小結 { #recap }
+
+當你需要在同一個請求中同時接收資料與檔案時,請搭配使用 `File` 與 `Form`。
diff --git a/docs/zh-hant/docs/tutorial/request-forms.md b/docs/zh-hant/docs/tutorial/request-forms.md
new file mode 100644
index 0000000000..733a3e2869
--- /dev/null
+++ b/docs/zh-hant/docs/tutorial/request-forms.md
@@ -0,0 +1,73 @@
+# 表單資料 { #form-data }
+
+當你需要接收表單欄位而不是 JSON 時,可以使用 `Form`。
+
+/// info
+
+要使用表單,請先安裝 `python-multipart`。
+
+請先建立並啟用一個[虛擬環境](../virtual-environments.md){.internal-link target=_blank},然後再安裝,例如:
+
+```console
+$ pip install python-multipart
+```
+
+///
+
+## 匯入 `Form` { #import-form }
+
+從 `fastapi` 匯入 `Form`:
+
+{* ../../docs_src/request_forms/tutorial001_an_py310.py hl[3] *}
+
+## 定義 `Form` 參數 { #define-form-parameters }
+
+以與 `Body` 或 `Query` 相同的方式建立表單參數:
+
+{* ../../docs_src/request_forms/tutorial001_an_py310.py hl[9] *}
+
+例如,在 OAuth2 規範的一種用法(稱為「password flow」)中,必須以表單欄位傳送 `username` 與 `password`。
+
+該 規範 要求欄位名稱必須正好是 `username` 和 `password`,而且必須以表單欄位傳送,而不是 JSON。
+
+使用 `Form` 時,你可以宣告與 `Body`(以及 `Query`、`Path`、`Cookie`)相同的設定,包括驗證、範例、別名(例如用 `user-name` 取代 `username`)等。
+
+/// info
+
+`Form` 是一個直接繼承自 `Body` 的類別。
+
+///
+
+/// tip
+
+要宣告表單的請求本文,你需要明確使用 `Form`,否則這些參數會被解讀為查詢參數或請求本文(JSON)參數。
+
+///
+
+## 關於「表單欄位」 { #about-form-fields }
+
+HTML 表單(``)向伺服器傳送資料時,通常會使用一種「特殊」的編碼方式,與 JSON 不同。
+
+**FastAPI** 會從正確的位置讀取那些資料,而不是從 JSON。
+
+/// note | 技術細節
+
+表單資料通常會使用「媒體類型」`application/x-www-form-urlencoded` 進行編碼。
+
+但當表單包含檔案時,會使用 `multipart/form-data`。你會在下一章閱讀如何處理檔案。
+
+若想進一步了解這些編碼與表單欄位,請參考 MDN 的 POST 網頁文件。
+
+///
+
+/// warning
+
+你可以在一個 *路徑操作(path operation)* 中宣告多個 `Form` 參數,但不能同時再宣告期望以 JSON 接收的 `Body` 欄位,因為該請求的本文會使用 `application/x-www-form-urlencoded` 編碼,而不是 `application/json`。
+
+這不是 **FastAPI** 的限制,而是 HTTP 協定本身的規定。
+
+///
+
+## 回顧 { #recap }
+
+使用 `Form` 來宣告表單資料的輸入參數。
diff --git a/docs/zh-hant/docs/tutorial/response-model.md b/docs/zh-hant/docs/tutorial/response-model.md
new file mode 100644
index 0000000000..d22402e180
--- /dev/null
+++ b/docs/zh-hant/docs/tutorial/response-model.md
@@ -0,0 +1,343 @@
+# 回應模型 - 回傳型別 { #response-model-return-type }
+
+你可以在「路徑操作函式」的回傳型別上加上註解,宣告用於回應的型別。
+
+你可以像在函式「參數」的輸入資料那樣使用型別註解,你可以使用 Pydantic 模型、list、dictionary、整數、布林等純量值。
+
+{* ../../docs_src/response_model/tutorial001_01_py310.py hl[16,21] *}
+
+FastAPI 會使用這個回傳型別來:
+
+* 驗證回傳的資料。
+ * 如果資料無效(例如缺少欄位),代表你的應用程式程式碼有問題,沒有回傳應該回傳的內容,FastAPI 會回傳伺服器錯誤,而不是回傳不正確的資料。如此你和你的用戶端都能確定會收到預期的資料與資料結構。
+* 在 OpenAPI 的「路徑操作」中為回應新增 JSON Schema。
+ * 這會被自動文件使用。
+ * 也會被自動用戶端程式碼產生工具使用。
+
+但更重要的是:
+
+* 它會將輸出資料限制並過濾為回傳型別中定義的內容。
+ * 這對安全性特別重要,下面會再看到更多細節。
+
+## `response_model` 參數 { #response-model-parameter }
+
+有些情況下,你需要或想要回傳的資料與你宣告的型別不完全相同。
+
+例如,你可能想要回傳一個 dictionary 或資料庫物件,但把回應宣告為一個 Pydantic 模型。這樣 Pydantic 模型就會替你回傳的物件(例如 dictionary 或資料庫物件)處理所有的資料文件、驗證等。
+
+如果你加了回傳型別註解,工具與編輯器會(正確地)抱怨你的函式回傳的型別(例如 dict)與你宣告的(例如 Pydantic 模型)不同。
+
+在這些情況下,你可以使用「路徑操作裝飾器」參數 `response_model`,而不是函式的回傳型別。
+
+你可以在任何「路徑操作」上使用 `response_model` 參數:
+
+* `@app.get()`
+* `@app.post()`
+* `@app.put()`
+* `@app.delete()`
+* 等等。
+
+{* ../../docs_src/response_model/tutorial001_py310.py hl[17,22,24:27] *}
+
+/// note | 注意
+
+注意 `response_model` 是「裝飾器」方法(`get`、`post` 等)的參數。不是你的「路徑操作函式」的參數(像其他參數與請求主體那樣)。
+
+///
+
+`response_model` 接受的型別與你在 Pydantic 模型欄位中宣告的相同,所以它可以是一個 Pydantic 模型,也可以是例如由 Pydantic 模型組成的 `list`,像是 `List[Item]`。
+
+FastAPI 會使用這個 `response_model` 來做所有的資料文件、驗證等,並且也會將輸出資料轉換與過濾為其型別宣告。
+
+/// tip | 提示
+
+如果你在編輯器、mypy 等中有嚴格型別檢查,你可以把函式回傳型別宣告為 `Any`。
+
+這樣你是在告訴編輯器你是刻意回傳任意型別。但 FastAPI 仍會用 `response_model` 做資料文件、驗證、過濾等。
+
+///
+
+### `response_model` 優先權 { #response-model-priority }
+
+如果同時宣告了回傳型別與 `response_model`,`response_model` 會有優先權並由 FastAPI 使用。
+
+如此一來,即便你回傳的實際型別與回應模型不同,你仍可在函式上加上正確的型別註解,供編輯器與如 mypy 的工具使用。同時仍由 FastAPI 使用 `response_model` 做資料驗證、文件化等。
+
+你也可以使用 `response_model=None` 來停用該「路徑操作」的回應模型產生;當你為不是有效 Pydantic 欄位的東西加上型別註解時,可能需要這麼做,你會在下方某節看到範例。
+
+## 回傳與輸入相同的資料 { #return-the-same-input-data }
+
+這裡我們宣告一個 `UserIn` 模型,其中會包含明文密碼:
+
+{* ../../docs_src/response_model/tutorial002_py310.py hl[7,9] *}
+
+/// info | 說明
+
+要使用 `EmailStr`,請先安裝 `email-validator`。
+
+請先建立一個[虛擬環境](../virtual-environments.md){.internal-link target=_blank}、啟用它,然後安裝,例如:
+
+```console
+$ pip install email-validator
+```
+
+或:
+
+```console
+$ pip install "pydantic[email]"
+```
+
+///
+
+而我們使用這個模型同時宣告輸入與輸出:
+
+{* ../../docs_src/response_model/tutorial002_py310.py hl[16] *}
+
+現在,當瀏覽器建立一個帶有密碼的使用者時,API 會在回應中回傳相同的密碼。
+
+在這個例子中可能不是問題,因為是同一個使用者送出該密碼。
+
+但如果我們對其他「路徑操作」使用相同的模型,我們可能會把使用者密碼送給所有用戶端。
+
+/// danger | 警告
+
+除非你非常清楚所有影響並確定自己在做什麼,否則永遠不要儲存使用者的明文密碼,也不要像這樣在回應中傳送。
+
+///
+
+## 新增一個輸出模型 { #add-an-output-model }
+
+我們可以改為建立一個包含明文密碼的輸入模型,以及一個不含密碼的輸出模型:
+
+{* ../../docs_src/response_model/tutorial003_py310.py hl[9,11,16] *}
+
+在這裡,雖然「路徑操作函式」回傳的是同一個包含密碼的輸入使用者:
+
+{* ../../docs_src/response_model/tutorial003_py310.py hl[24] *}
+
+...我們把 `response_model` 宣告為不包含密碼的 `UserOut` 模型:
+
+{* ../../docs_src/response_model/tutorial003_py310.py hl[22] *}
+
+因此,FastAPI 會負責(透過 Pydantic)過濾掉輸出模型中未宣告的所有資料。
+
+### `response_model` 或回傳型別 { #response-model-or-return-type }
+
+在這種情況下,因為兩個模型不同,如果我們把函式回傳型別註解為 `UserOut`,編輯器和工具會抱怨我們回傳了無效的型別,因為它們是不同的類別。
+
+這就是為什麼在這個例子中我們必須在 `response_model` 參數中宣告它。
+
+...但繼續往下讀看看如何克服這個問題。
+
+## 回傳型別與資料過濾 { #return-type-and-data-filtering }
+
+讓我們延續前一個範例。我們想要用一種型別來註解函式,但實際上希望能夠從函式回傳包含更多資料的內容。
+
+我們希望 FastAPI 仍然用回應模型來過濾資料。這樣即使函式回傳更多資料,回應中也只會包含回應模型中宣告的欄位。
+
+在前一個例子中,因為類別不同,我們必須使用 `response_model` 參數。但這也代表我們失去了編輯器與工具對函式回傳型別的檢查支援。
+
+不過在大多數需要這樣做的情況下,我們只是想要像這個例子一樣,讓模型過濾/移除部分資料。
+
+在這些情況下,我們可以利用類別與繼承,搭配函式的型別註解,取得更好的編輯器與工具支援,同時仍能讓 FastAPI 做資料過濾。
+
+{* ../../docs_src/response_model/tutorial003_01_py310.py hl[7:10,13:14,18] *}
+
+這樣我們能得到工具支援,對於編輯器與 mypy 來說,這段程式碼在型別上是正確的,同時我們也能得到 FastAPI 的資料過濾。
+
+這是怎麼運作的?來看一下。🤓
+
+### 型別註解與工具支援 { #type-annotations-and-tooling }
+
+先看看編輯器、mypy 與其他工具會怎麼看這件事。
+
+`BaseUser` 有基礎欄位。然後 `UserIn` 繼承自 `BaseUser` 並新增 `password` 欄位,因此它會包含兩個模型的所有欄位。
+
+我們把函式回傳型別註解為 `BaseUser`,但實際上回傳的是 `UserIn` 實例。
+
+編輯器、mypy 與其他工具不會抱怨,因為就型別學而言,`UserIn` 是 `BaseUser` 的子類別,這代表當預期任何 `BaseUser` 時,`UserIn` 是一個有效的型別。
+
+### FastAPI 的資料過濾 { #fastapi-data-filtering }
+
+對 FastAPI 而言,它會查看回傳型別,並確保你回傳的內容只包含該型別中宣告的欄位。
+
+FastAPI 在內部會搭配 Pydantic 做一些事情,來確保不會把類別繼承的那些規則直接用在回傳資料的過濾上,否則你可能會回傳比預期更多的資料。
+
+如此,你就能同時擁有兩種好處:具備工具支援的型別註解,以及資料過濾。
+
+## 在文件中查看 { #see-it-in-the-docs }
+
+在自動文件中,你可以看到輸入模型與輸出模型各自都有自己的 JSON Schema:
+
+
+
+而且兩個模型都會用在互動式 API 文件中:
+
+
+
+## 其他回傳型別註解 { #other-return-type-annotations }
+
+有時你回傳的東西不是有效的 Pydantic 欄位,你仍會在函式上加上註解,只為了獲得工具(編輯器、mypy 等)提供的支援。
+
+### 直接回傳 Response { #return-a-response-directly }
+
+最常見的情況是[直接回傳 Response(在進階文件中稍後會解釋)](../advanced/response-directly.md){.internal-link target=_blank}。
+
+{* ../../docs_src/response_model/tutorial003_02_py310.py hl[8,10:11] *}
+
+這個簡單情境會由 FastAPI 自動處理,因為回傳型別註解是 `Response` 類別(或其子類別)。
+
+而工具也會滿意,因為 `RedirectResponse` 與 `JSONResponse` 都是 `Response` 的子類別,所以型別註解是正確的。
+
+### 註解為某個 Response 的子類別 { #annotate-a-response-subclass }
+
+你也可以在型別註解中使用 `Response` 的子類別:
+
+{* ../../docs_src/response_model/tutorial003_03_py310.py hl[8:9] *}
+
+這同樣可行,因為 `RedirectResponse` 是 `Response` 的子類別,而 FastAPI 會自動處理這種簡單情況。
+
+### 無效的回傳型別註解 { #invalid-return-type-annotations }
+
+但當你回傳其他任意物件(例如資料庫物件),它不是有效的 Pydantic 型別,並且你在函式上也這樣註解時,FastAPI 會嘗試從該型別註解建立一個 Pydantic 回應模型,因而失敗。
+
+如果你有像是多種型別的聯集,其中一個或多個不是有效的 Pydantic 型別,也會發生相同的事情,例如這個就會失敗 💥:
+
+{* ../../docs_src/response_model/tutorial003_04_py310.py hl[8] *}
+
+...這會失敗,因為該型別註解不是 Pydantic 型別,且它也不只是一個單一的 `Response` 類別或其子類別,而是 `Response` 與 `dict` 的聯集(兩者任一)。
+
+### 停用回應模型 { #disable-response-model }
+
+延續上面的例子,你可能不想要 FastAPI 執行預設的資料驗證、文件化、過濾等動作。
+
+但你可能仍想在函式上保留回傳型別註解,以獲得編輯器與型別檢查工具(例如 mypy)的支援。
+
+這種情況下,你可以設定 `response_model=None` 來停用回應模型的產生:
+
+{* ../../docs_src/response_model/tutorial003_05_py310.py hl[7] *}
+
+這會讓 FastAPI 略過回應模型的產生,如此你就能使用任何你需要的回傳型別註解,而不會影響你的 FastAPI 應用程式。🤓
+
+## 回應模型編碼參數 { #response-model-encoding-parameters }
+
+你的回應模型可能有預設值,例如:
+
+{* ../../docs_src/response_model/tutorial004_py310.py hl[9,11:12] *}
+
+* `description: Union[str, None] = None`(或在 Python 3.10 中的 `str | None = None`)預設為 `None`。
+* `tax: float = 10.5` 預設為 `10.5`。
+* `tags: List[str] = []` 預設為空的 list:`[]`。
+
+但如果這些值其實沒有被儲存,你可能想要在結果中省略它們。
+
+例如,如果你在 NoSQL 資料庫中有包含許多選擇性屬性的模型,但你不想傳送充滿預設值的冗長 JSON 回應。
+
+### 使用 `response_model_exclude_unset` 參數 { #use-the-response-model-exclude-unset-parameter }
+
+你可以在「路徑操作裝飾器」上設定 `response_model_exclude_unset=True`:
+
+{* ../../docs_src/response_model/tutorial004_py310.py hl[22] *}
+
+如此這些預設值就不會被包含在回應中,只有實際被設定的值才會包含。
+
+因此,如果你對該「路徑操作」發送針對 ID 為 `foo` 的項目的請求,回應(不包含預設值)會是:
+
+```JSON
+{
+ "name": "Foo",
+ "price": 50.2
+}
+```
+
+/// info | 說明
+
+你也可以使用:
+
+* `response_model_exclude_defaults=True`
+* `response_model_exclude_none=True`
+
+如 Pydantic 文件中對 `exclude_defaults` 與 `exclude_none` 的說明。
+
+///
+
+#### 對於有預設值欄位也有實際值的資料 { #data-with-values-for-fields-with-defaults }
+
+但如果你的資料在模型中對於有預設值的欄位也有實際值,例如 ID 為 `bar` 的項目:
+
+```Python hl_lines="3 5"
+{
+ "name": "Bar",
+ "description": "The bartenders",
+ "price": 62,
+ "tax": 20.2
+}
+```
+
+它們會被包含在回應中。
+
+#### 與預設值相同的資料 { #data-with-the-same-values-as-the-defaults }
+
+如果資料的值與預設值相同,例如 ID 為 `baz` 的項目:
+
+```Python hl_lines="3 5-6"
+{
+ "name": "Baz",
+ "description": None,
+ "price": 50.2,
+ "tax": 10.5,
+ "tags": []
+}
+```
+
+FastAPI 足夠聰明(其實是 Pydantic 足夠聰明)去判斷,儘管 `description`、`tax` 與 `tags` 的值與預設值相同,但它們是被明確設定的(而不是取自預設值)。
+
+因此,它們會被包含在 JSON 回應中。
+
+/// tip | 提示
+
+注意預設值可以是任何東西,不只有 `None`。
+
+它們可以是一個 list(`[]`)、一個 `float` 的 `10.5`,等等。
+
+///
+
+### `response_model_include` 與 `response_model_exclude` { #response-model-include-and-response-model-exclude }
+
+你也可以使用「路徑操作裝飾器」參數 `response_model_include` 與 `response_model_exclude`。
+
+它們接受一個由屬性名稱字串所組成的 `set`,分別用來包含(省略其他)或排除(包含其他)屬性。
+
+如果你只有一個 Pydantic 模型並且想從輸出移除部分資料,這可以作為一個快速捷徑。
+
+/// tip | 提示
+
+但仍建議使用上面提到的作法,使用多個類別,而不是這些參數。
+
+因為在你的應用程式 OpenAPI(與文件)中所產生的 JSON Schema 仍會是完整模型的,即便你使用 `response_model_include` 或 `response_model_exclude` 省略了一些屬性。
+
+`response_model_by_alias` 也有類似的情況。
+
+///
+
+{* ../../docs_src/response_model/tutorial005_py310.py hl[29,35] *}
+
+/// tip | 提示
+
+語法 `{"name", "description"}` 會建立一個包含這兩個值的 `set`。
+
+它等同於 `set(["name", "description"])`。
+
+///
+
+#### 使用 `list` 來代替 `set` { #using-lists-instead-of-sets }
+
+如果你忘了使用 `set` 而用了 `list` 或 `tuple`,FastAPI 仍會把它轉換成 `set`,並能正確運作:
+
+{* ../../docs_src/response_model/tutorial006_py310.py hl[29,35] *}
+
+## 重點回顧 { #recap }
+
+使用「路徑操作裝飾器」的 `response_model` 參數來定義回應模型,特別是為了確保私有資料被過濾掉。
+
+使用 `response_model_exclude_unset` 僅回傳被明確設定的值。
diff --git a/docs/zh-hant/docs/tutorial/response-status-code.md b/docs/zh-hant/docs/tutorial/response-status-code.md
new file mode 100644
index 0000000000..cbcc67ca55
--- /dev/null
+++ b/docs/zh-hant/docs/tutorial/response-status-code.md
@@ -0,0 +1,101 @@
+# 回應狀態碼 { #response-status-code }
+
+就像你可以指定回應模型一樣,你也可以在任一個「路徑操作(path operation)」的參數 `status_code` 中宣告回應所使用的 HTTP 狀態碼:
+
+* `@app.get()`
+* `@app.post()`
+* `@app.put()`
+* `@app.delete()`
+* 等等
+
+{* ../../docs_src/response_status_code/tutorial001_py310.py hl[6] *}
+
+/// note | 注意
+
+請注意,`status_code` 是「裝飾器(decorator)」方法(`get`、`post` 等等)的參數,而不是你的「路徑操作函式」的參數,就像所有的參數與 body 一樣。
+
+///
+
+參數 `status_code` 接受一個數字作為 HTTP 狀態碼。
+
+/// info | 資訊
+
+`status_code` 也可以接收一個 `IntEnum`,例如 Python 的 `http.HTTPStatus`。
+
+///
+
+它會:
+
+* 在回應中傳回該狀態碼。
+* 在 OpenAPI 結構中如此記錄(因此也會反映在使用者介面中):
+
+
+
+/// note | 注意
+
+有些回應碼(見下一節)表示回應不包含本文(body)。
+
+FastAPI 知道這點,並會產生聲明「無回應本文」的 OpenAPI 文件。
+
+///
+
+## 關於 HTTP 狀態碼 { #about-http-status-codes }
+
+/// note | 注意
+
+如果你已經知道什麼是 HTTP 狀態碼,可以直接跳到下一節。
+
+///
+
+在 HTTP 中,你會在回應的一部分傳回 3 位數的狀態碼。
+
+這些狀態碼有對應的名稱以便辨識,但重點是數字本身。
+
+簡而言之:
+
+* `100 - 199` 表示「資訊」。你很少會直接使用它們。這些狀態碼的回應不可包含本文。
+* **`200 - 299`** 表示「成功」。這是你最常使用的一組。
+ * `200` 是預設狀態碼,表示一切「OK」。
+ * 另一個例子是 `201`,代表「已建立」。常用於在資料庫中建立新紀錄之後。
+ * 一個特殊情況是 `204`,代表「無內容」。當沒有內容要回傳給用戶端時使用,因此回應不得有本文。
+* **`300 - 399`** 表示「重新導向」。這些狀態碼的回應可能有或沒有本文,唯獨 `304`(「未修改」)必須沒有本文。
+* **`400 - 499`** 表示「用戶端錯誤」。這大概是你第二常用的一組。
+ * 例如 `404`,代表「找不到」。
+ * 對於一般性的用戶端錯誤,你可以使用 `400`。
+* `500 - 599` 表示伺服器錯誤。你幾乎不會直接使用它們。當你的應用程式或伺服器某處出錯時,會自動回傳其中一個狀態碼。
+
+/// tip | 提示
+
+想深入瞭解各狀態碼與其用途,請參考 MDN 關於 HTTP 狀態碼的文件。
+
+///
+
+## 快速記住名稱 { #shortcut-to-remember-the-names }
+
+再看一次前面的範例:
+
+{* ../../docs_src/response_status_code/tutorial001_py310.py hl[6] *}
+
+`201` 是「已建立(Created)」的狀態碼。
+
+但你不需要背下每個代碼代表什麼。
+
+你可以使用 `fastapi.status` 提供的便利變數。
+
+{* ../../docs_src/response_status_code/tutorial002_py310.py hl[1,6] *}
+
+它們只是方便用的常數,值與數字相同,但這樣你可以用編輯器的自動完成來找到它們:
+
+
+
+/// note | 技術細節
+
+你也可以使用 `from starlette import status`。
+
+**FastAPI** 將同一個 `starlette.status` 以 `fastapi.status` 形式提供,純粹是為了讓你(開發者)方便。但它直接來自 Starlette。
+
+///
+
+## 變更預設值 { #changing-the-default }
+
+稍後在 [進階使用者指南](../advanced/response-change-status-code.md){.internal-link target=_blank} 中,你會看到如何回傳一個不同於此處所宣告預設值的狀態碼。
diff --git a/docs/zh-hant/docs/tutorial/schema-extra-example.md b/docs/zh-hant/docs/tutorial/schema-extra-example.md
new file mode 100644
index 0000000000..661938ac26
--- /dev/null
+++ b/docs/zh-hant/docs/tutorial/schema-extra-example.md
@@ -0,0 +1,202 @@
+# 宣告請求範例資料 { #declare-request-example-data }
+
+你可以宣告你的應用程式可接收資料的 examples。
+
+以下有數種方式可達成。
+
+## Pydantic 模型中的額外 JSON Schema 資料 { #extra-json-schema-data-in-pydantic-models }
+
+你可以為 Pydantic 模型宣告 `examples`,它們會加入到產生出的 JSON Schema 中。
+
+{* ../../docs_src/schema_extra_example/tutorial001_py310.py hl[13:24] *}
+
+這些額外資訊會原封不動加入該模型輸出的 JSON Schema,並且會用在 API 文件裡。
+
+你可以使用屬性 `model_config`(接收一個 `dict`),詳見 Pydantic 文件:Configuration。
+
+你可以將 `"json_schema_extra"` 設為一個 `dict`,其中包含你想在產生的 JSON Schema 中出現的任何額外資料,包括 `examples`。
+
+/// tip
+
+你可以用相同技巧擴充 JSON Schema,加入你自己的自訂額外資訊。
+
+例如,你可以用它為前端使用者介面新增中繼資料等。
+
+///
+
+/// info
+
+OpenAPI 3.1.0(自 FastAPI 0.99.0 起使用)新增了對 `examples` 的支援,這是 **JSON Schema** 標準的一部分。
+
+在那之前,只支援使用單一範例的關鍵字 `example`。OpenAPI 3.1.0 仍然支援 `example`,但它已被棄用,且不是 JSON Schema 標準的一部分。因此建議你將 `example` 遷移為 `examples`。🤓
+
+你可以在本頁結尾閱讀更多。
+
+///
+
+## `Field` 其他參數 { #field-additional-arguments }
+
+在 Pydantic 模型中使用 `Field()` 時,你也可以宣告額外的 `examples`:
+
+{* ../../docs_src/schema_extra_example/tutorial002_py310.py hl[2,8:11] *}
+
+## JSON Schema 的 `examples` - OpenAPI { #examples-in-json-schema-openapi }
+
+當使用下列任一項:
+
+* `Path()`
+* `Query()`
+* `Header()`
+* `Cookie()`
+* `Body()`
+* `Form()`
+* `File()`
+
+你也可以宣告一組 `examples`,包含會加入到 **OpenAPI** 中它們各自 **JSON Schemas** 的額外資訊。
+
+### `Body` 搭配 `examples` { #body-with-examples }
+
+這裡我們傳入 `examples`,其中包含 `Body()` 預期資料的一個範例:
+
+{* ../../docs_src/schema_extra_example/tutorial003_an_py310.py hl[22:29] *}
+
+### 文件 UI 中的範例 { #example-in-the-docs-ui }
+
+使用以上任一方法,在 `/docs` 中看起來會像這樣:
+
+
+
+### `Body` 搭配多個 `examples` { #body-with-multiple-examples }
+
+當然,你也可以傳入多個 `examples`:
+
+{* ../../docs_src/schema_extra_example/tutorial004_an_py310.py hl[23:38] *}
+
+這麼做時,這些範例會成為該 body 資料內部 **JSON Schema** 的一部分。
+
+然而,撰寫本文時,負責呈現文件 UI 的工具 Swagger UI 並不支援在 **JSON Schema** 中顯示多個範例。不過請繼續往下閱讀以取得變通方式。
+
+### OpenAPI 特定的 `examples` { #openapi-specific-examples }
+
+在 **JSON Schema** 支援 `examples` 之前,OpenAPI 就已支援另一個同名的欄位 `examples`。
+
+這個「OpenAPI 特定」的 `examples` 位於 OpenAPI 規範的另一個區塊:在每個「路徑操作」的詳細資訊中,而不是在各個 JSON Schema 內。
+
+而 Swagger UI 早已支援這個欄位,因此你可以用它在文件 UI 中顯示不同的範例。
+
+這個 OpenAPI 特定欄位 `examples` 的結構是一個包含「多個範例」的 `dict`(而非 `list`),每個範例都可包含會一併加入到 **OpenAPI** 的額外資訊。
+
+它不會出現在 OpenAPI 所含的各個 JSON Schema 內,而是直接放在對應的「路徑操作」上。
+
+### 使用 `openapi_examples` 參數 { #using-the-openapi-examples-parameter }
+
+你可以在 FastAPI 中透過參數 `openapi_examples` 為下列項目宣告 OpenAPI 特定的 `examples`:
+
+* `Path()`
+* `Query()`
+* `Header()`
+* `Cookie()`
+* `Body()`
+* `Form()`
+* `File()`
+
+該 `dict` 的鍵用來識別各個範例,而每個值則是另一個 `dict`。
+
+在 `examples` 中,每個範例的 `dict` 可以包含:
+
+* `summary`:範例的簡短描述。
+* `description`:較長的描述,可包含 Markdown 文字。
+* `value`:實際顯示的範例,例如一個 `dict`。
+* `externalValue`:`value` 的替代方案,為指向範例的 URL。儘管這可能不如 `value` 被工具廣泛支援。
+
+你可以這樣使用:
+
+{* ../../docs_src/schema_extra_example/tutorial005_an_py310.py hl[23:49] *}
+
+### 文件 UI 中的 OpenAPI 範例 { #openapi-examples-in-the-docs-ui }
+
+當在 `Body()` 加上 `openapi_examples`,`/docs` 會顯示為:
+
+
+
+## 技術細節 { #technical-details }
+
+/// tip
+
+如果你已經在使用 **FastAPI** **0.99.0 或以上**的版本,大概可以略過這些細節。
+
+這些內容比較與舊版(在 OpenAPI 3.1.0 可用之前)相關。
+
+你可以把這段當作一小堂 OpenAPI 與 JSON Schema 的歷史課。🤓
+
+///
+
+/// warning
+
+以下是關於 **JSON Schema** 與 **OpenAPI** 標準的技術細節。
+
+如果上面的做法對你已經足夠可用,就不需要這些細節,儘管直接跳過。
+
+///
+
+在 OpenAPI 3.1.0 之前,OpenAPI 使用的是較舊且經過修改的 **JSON Schema** 版本。
+
+當時 JSON Schema 沒有 `examples`,因此 OpenAPI 在它自訂修改的版本中新增了自己的 `example` 欄位。
+
+OpenAPI 也在規範的其他部分新增了 `example` 與 `examples` 欄位:
+
+* `Parameter Object`(規範),對應到 FastAPI 的:
+ * `Path()`
+ * `Query()`
+ * `Header()`
+ * `Cookie()`
+* `Request Body Object` 中的 `content` 欄位裡的 `Media Type Object`(規範),對應到 FastAPI 的:
+ * `Body()`
+ * `File()`
+ * `Form()`
+
+/// info
+
+這個舊的、OpenAPI 特定的 `examples` 參數,從 FastAPI `0.103.0` 起改名為 `openapi_examples`。
+
+///
+
+### JSON Schema 的 `examples` 欄位 { #json-schemas-examples-field }
+
+後來 JSON Schema 在新版本規範中新增了 `examples` 欄位。
+
+接著新的 OpenAPI 3.1.0 以最新版本(JSON Schema 2020-12)為基礎,該版本就包含這個新的 `examples` 欄位。
+
+現在這個新的 `examples` 欄位優先於舊的單一(且客製)`example` 欄位,後者已被棄用。
+
+JSON Schema 中新的 `examples` 欄位「就是一個 `list`」的範例集合,而不是像 OpenAPI 其他地方(如上所述)那樣附帶額外中繼資料的 `dict`。
+
+/// info
+
+即使 OpenAPI 3.1.0 已發佈並與 JSON Schema 有更簡潔的整合,一段時間內提供自動文件的 Swagger UI 並不支援 OpenAPI 3.1.0(自 5.0.0 版起支援 🎉)。
+
+因此,FastAPI 0.99.0 之前的版本仍使用 3.1.0 以下的 OpenAPI 版本。
+
+///
+
+### Pydantic 與 FastAPI 的 `examples` { #pydantic-and-fastapi-examples }
+
+當你在 Pydantic 模型中加入 `examples`,不論是用 `schema_extra` 或 `Field(examples=["something"])`,該範例都會被加入該 Pydantic 模型的 **JSON Schema**。
+
+而該 Pydantic 模型的 **JSON Schema** 會被包含到你的 API 的 **OpenAPI** 中,接著用於文件 UI。
+
+在 FastAPI 0.99.0 之前的版本(0.99.0 起使用較新的 OpenAPI 3.1.0)中,當你對其他工具(`Query()`、`Body()` 等)使用 `example` 或 `examples` 時,這些範例不會被加入描述該資料的 JSON Schema(甚至不會加入到 OpenAPI 自己版本的 JSON Schema 中),而是直接加入到 OpenAPI 中的「路徑操作」宣告(在 OpenAPI 使用 JSON Schema 的那些部分之外)。
+
+但現在 FastAPI 0.99.0 以上使用的 OpenAPI 3.1.0 搭配 JSON Schema 2020-12,以及 Swagger UI 5.0.0 以上版本,整體更加一致,範例會包含在 JSON Schema 中。
+
+### Swagger UI 與 OpenAPI 特定的 `examples` { #swagger-ui-and-openapi-specific-examples }
+
+由於在(2023-08-26 時)Swagger UI 不支援多個 JSON Schema 範例,使用者無法在文件中顯示多個範例。
+
+為了解決此問題,FastAPI `0.103.0` 透過新參數 `openapi_examples` **新增支援** 宣告舊的「OpenAPI 特定」`examples` 欄位。🤓
+
+### 總結 { #summary }
+
+我以前常說我不太喜歡歷史……結果現在在這裡講「科技史」。😅
+
+簡而言之,**升級到 FastAPI 0.99.0 或以上**,事情會更**簡單、一致又直覺**,而且你不需要了解這些歷史細節。😎
diff --git a/docs/zh-hant/docs/tutorial/security/first-steps.md b/docs/zh-hant/docs/tutorial/security/first-steps.md
new file mode 100644
index 0000000000..109f59a37a
--- /dev/null
+++ b/docs/zh-hant/docs/tutorial/security/first-steps.md
@@ -0,0 +1,203 @@
+# 安全性 - 入門 { #security-first-steps }
+
+想像你有一個部署在某個網域的後端 API。
+
+還有一個前端在另一個網域,或同一網域的不同路徑(或是行動應用程式)。
+
+你希望前端能用使用者名稱與密碼向後端進行身分驗證。
+
+我們可以用 OAuth2 搭配 FastAPI 來實作。
+
+但不必通讀整份冗長規格只為了找出你需要的幾個重點。
+
+就用 FastAPI 提供的工具處理安全性。
+
+## 看起來如何 { #how-it-looks }
+
+先直接跑範例看效果,再回頭理解其原理。
+
+## 建立 `main.py` { #create-main-py }
+
+將範例複製到檔案 `main.py`:
+
+{* ../../docs_src/security/tutorial001_an_py310.py *}
+
+## 執行 { #run-it }
+
+/// info
+
+當你使用 `pip install "fastapi[standard]"` 指令安裝時,`python-multipart` 套件會隨 FastAPI 自動安裝。
+
+不過若只執行 `pip install fastapi`,預設不會包含 `python-multipart`。
+
+若要手動安裝,請先建立並啟用一個[虛擬環境](../../virtual-environments.md){.internal-link target=_blank},接著執行:
+
+```console
+$ pip install python-multipart
+```
+
+因為 OAuth2 會以「form data」傳送 `username` 與 `password`。
+
+///
+
+用以下指令執行範例:
+
+
+
+```console
+$ fastapi dev main.py
+
+INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
+```
+
+
+
+## 檢查 { #check-it }
+
+開啟互動式文件:http://127.0.0.1:8000/docs。
+
+你會看到類似這樣:
+
+
+
+/// check | Authorize 按鈕!
+
+你會看到一個新的「Authorize」按鈕。
+
+而你的「路徑操作」右上角也會出現一個小鎖頭可以點擊。
+
+///
+
+點擊後會跳出一個小視窗,讓你輸入 `username` 與 `password`(以及其他可選欄位):
+
+
+
+/// note | 注意
+
+不管你在表單輸入什麼,現在都還不會成功;等等我們會把它完成。
+
+///
+
+這當然不是給最終使用者用的前端,但它是用來互動式文件化整個 API 的極佳自動化工具。
+
+前端團隊(也可能就是你)可以使用它。
+
+第三方應用或系統也能使用它。
+
+你也能用它來除錯、檢查與測試同一個應用。
+
+## `password` 流程 { #the-password-flow }
+
+現在回頭理解剛剛那些是什麼。
+
+在 OAuth2 中,`password` 是處理安全與身分驗證的其中一種「流程」(flow)。
+
+OAuth2 的設計讓後端或 API 可以獨立於執行使用者驗證的伺服器。
+
+但在這個例子中,同一個 FastAPI 應用會同時處理 API 與驗證。
+
+簡化來看流程如下:
+
+- 使用者在前端輸入 `username` 與 `password`,按下 `Enter`。
+- 前端(在使用者的瀏覽器中執行)把 `username` 與 `password` 傳到我們 API 的特定 URL(在程式中宣告為 `tokenUrl="token"`)。
+- API 檢查 `username` 與 `password`,並回傳一個「token(權杖)」(我們還沒實作這部分)。
+ - 「token(權杖)」就是一段字串,之後可用來識別並驗證此使用者。
+ - 通常 token 會設定一段時間後失效。
+ - 因此使用者之後需要重新登入。
+ - 若 token 被竊取,風險也較低;它不像永遠有效的萬用鑰匙(多數情況下)。
+- 前端會暫存這個 token。
+- 使用者在前端點擊前往其他頁面/區段。
+- 前端需要再向 API 取得資料。
+ - 但該端點需要驗證。
+ - 因此為了向 API 驗證,請求會帶上一個 `Authorization` 標頭,值為 `Bearer ` 加上 token。
+ - 例如 token 是 `foobar`,則 `Authorization` 標頭內容為:`Bearer foobar`。
+
+## FastAPI 的 `OAuth2PasswordBearer` { #fastapis-oauth2passwordbearer }
+
+FastAPI 提供多層抽象的工具來實作這些安全機制。
+
+本例將使用 OAuth2 的 Password 流程,並以 Bearer token 進行驗證;我們會用 `OAuth2PasswordBearer` 類別來完成。
+
+/// info
+
+「Bearer」token 不是唯一選項。
+
+但對本例最合適。
+
+通常對多數情境也足夠,除非你是 OAuth2 專家並確信有更適合你的選項。
+
+在那種情況下,FastAPI 也提供相應工具讓你自行組合。
+
+///
+
+當我們建立 `OAuth2PasswordBearer` 類別的實例時,會傳入 `tokenUrl` 參數。這個參數包含了客戶端(在使用者瀏覽器中執行的前端)用來送出 `username` 與 `password` 以取得 token 的 URL。
+
+{* ../../docs_src/security/tutorial001_an_py310.py hl[8] *}
+
+/// tip
+
+這裡的 `tokenUrl="token"` 指的是尚未建立的相對 URL `token`。因為是相對 URL,所以等同於 `./token`。
+
+由於使用了相對 URL,若你的 API 位於 `https://example.com/`,那它會指向 `https://example.com/token`;但若你的 API 位於 `https://example.com/api/v1/`,那它會指向 `https://example.com/api/v1/token`。
+
+使用相對 URL 很重要,能確保你的應用在像是[在 Proxy 後方](../../advanced/behind-a-proxy.md){.internal-link target=_blank}這類進階情境中仍能正常運作。
+
+///
+
+這個參數不會建立該端點/「路徑操作」,而是宣告 `/token` 將是客戶端用來取得 token 的 URL。這些資訊會出現在 OpenAPI,並被互動式 API 文件系統使用。
+
+我們很快也會建立實際的路徑操作。
+
+/// info
+
+如果你是非常嚴格的「Pythonista」,可能不喜歡參數名稱用 `tokenUrl` 而不是 `token_url`。
+
+那是因為它沿用了 OpenAPI 規格中的名稱。如此一來,若你要深入查閱這些安全方案,便能直接複製貼上去搜尋更多資訊。
+
+///
+
+變數 `oauth2_scheme` 是 `OAuth2PasswordBearer` 的實例,但同時它也是「可呼叫的」(callable)。
+
+它可以這樣被呼叫:
+
+```Python
+oauth2_scheme(some, parameters)
+```
+
+因此它可以配合 `Depends` 使用。
+
+### 如何使用 { #use-it }
+
+現在你可以在相依性中傳入 `oauth2_scheme` 與 `Depends` 搭配。
+
+{* ../../docs_src/security/tutorial001_an_py310.py hl[12] *}
+
+此相依性會提供一個 `str`,指派給「路徑操作函式」的參數 `token`。
+
+FastAPI 會知道可以使用這個相依性,在 OpenAPI(以及自動產生的 API 文件)中定義一個「安全性方案」。
+
+/// info | 技術細節
+
+FastAPI 之所以知道可以用(相依性中宣告的)`OAuth2PasswordBearer` 類別,在 OpenAPI 中定義安全性方案,是因為它繼承自 `fastapi.security.oauth2.OAuth2`,而後者又繼承自 `fastapi.security.base.SecurityBase`。
+
+所有能與 OpenAPI(以及自動 API 文件)整合的安全工具都繼承自 `SecurityBase`,FastAPI 才能知道如何把它們整合進 OpenAPI。
+
+///
+
+## 它做了什麼 { #what-it-does }
+
+它會從請求中尋找 `Authorization` 標頭,檢查其值是否為 `Bearer ` 加上一段 token,並將該 token 以 `str` 回傳。
+
+若未找到 `Authorization` 標頭,或其值不是 `Bearer ` token,則會直接回傳 401(`UNAUTHORIZED`)錯誤。
+
+你不必再自行檢查 token 是否存在;你可以確信只要你的函式被執行,該 token 參數就一定會是 `str`。
+
+你可以在互動式文件中試試看:
+
+
+
+我們還沒驗證 token 是否有效,但這已是個開始。
+
+## 小結 { #recap }
+
+只需多寫 3、4 行,就能有一個基本的安全機制。
diff --git a/docs/zh-hant/docs/tutorial/security/get-current-user.md b/docs/zh-hant/docs/tutorial/security/get-current-user.md
new file mode 100644
index 0000000000..b223d4823b
--- /dev/null
+++ b/docs/zh-hant/docs/tutorial/security/get-current-user.md
@@ -0,0 +1,105 @@
+# 取得目前使用者 { #get-current-user }
+
+在前一章,基於依賴注入系統的安全機制會把一個 `token`(作為 `str`)提供給*路徑操作函式*:
+
+{* ../../docs_src/security/tutorial001_an_py310.py hl[12] *}
+
+但這還不太有用。
+
+讓它改為回傳目前使用者吧。
+
+## 建立使用者模型 { #create-a-user-model }
+
+先建立一個 Pydantic 的使用者模型。
+
+就像用 Pydantic 宣告請求體一樣,我們也可以在其他地方使用它:
+
+{* ../../docs_src/security/tutorial002_an_py310.py hl[5,12:6] *}
+
+## 建立 `get_current_user` 依賴 { #create-a-get-current-user-dependency }
+
+讓我們建立一個依賴 `get_current_user`。
+
+記得依賴可以有子依賴嗎?
+
+`get_current_user` 會依賴我們先前建立的相同 `oauth2_scheme`。
+
+如同先前在*路徑操作*中直接做的一樣,新的依賴 `get_current_user` 會從子依賴 `oauth2_scheme` 接收一個作為 `str` 的 `token`:
+
+{* ../../docs_src/security/tutorial002_an_py310.py hl[25] *}
+
+## 取得使用者 { #get-the-user }
+
+`get_current_user` 會使用我們建立的(假的)工具函式,它接收一個作為 `str` 的 token,並回傳我們的 Pydantic `User` 模型:
+
+{* ../../docs_src/security/tutorial002_an_py310.py hl[19:22,26:27] *}
+
+## 注入目前使用者 { #inject-the-current-user }
+
+現在我們可以在*路徑操作*中用相同的 `Depends` 來使用 `get_current_user`:
+
+{* ../../docs_src/security/tutorial002_an_py310.py hl[31] *}
+
+注意我們把 `current_user` 的型別宣告為 Pydantic 的 `User` 模型。
+
+這能在函式內提供自動補全與型別檢查的協助。
+
+/// tip | 提示
+
+你可能記得,請求體也會用 Pydantic 模型宣告。
+
+這裡因為你使用了 `Depends`,**FastAPI** 不會混淆。
+
+///
+
+/// check | 檢查
+
+這個依賴系統的設計讓我們可以有不同的依賴(不同的 "dependables"),都回傳 `User` 模型。
+
+我們不受限於只能有一個能回傳該類型資料的依賴。
+
+///
+
+## 其他模型 { #other-models }
+
+現在你可以在*路徑操作函式*中直接取得目前使用者,並在**依賴注入**層處理安全機制,使用 `Depends`。
+
+而且你可以為安全需求使用任意模型或資料(本例中是 Pydantic 模型 `User`)。
+
+但你不受限於某個特定的資料模型、類別或型別。
+
+想在模型中只有 `id` 與 `email` 而沒有任何 `username`?當然可以。你可以用同樣的工具達成。
+
+想只用一個 `str`?或只用一個 `dict`?或直接使用資料庫類別的模型實例?都可以,一樣運作。
+
+你的應用其實沒有真人使用者登入,而是機器人、bot,或其他系統,只持有 access token?同樣沒有問題。
+
+只要用任何你的應用需要的模型、類別或資料庫即可。**FastAPI** 的依賴注入系統都支援。
+
+## 程式碼大小 { #code-size }
+
+這個範例看起來可能有點冗長。記住我們把安全、資料模型、工具函式與*路徑操作*混在同一個檔案中。
+
+但重點在這裡。
+
+安全與依賴注入相關的內容只需要寫一次。
+
+你可以把它設計得再複雜都沒問題,仍然只需在單一位置寫一次,依然具備完整的彈性。
+
+但你可以有成千上萬個端點(*路徑操作*)共用同一套安全系統。
+
+而且它們全部(或你想要的一部分)都可以重用這些依賴,或你建立的其他依賴。
+
+而所有這些上千個*路徑操作*都可以小到只要 3 行:
+
+{* ../../docs_src/security/tutorial002_an_py310.py hl[30:32] *}
+
+## 回顧 { #recap }
+
+現在你可以在*路徑操作函式*中直接取得目前使用者。
+
+我們已經完成一半了。
+
+我們只需要再新增一個*路徑操作*,讓使用者/用戶端實際送出 `username` 與 `password`。
+
+下一步就會做。
diff --git a/docs/zh-hant/docs/tutorial/security/index.md b/docs/zh-hant/docs/tutorial/security/index.md
new file mode 100644
index 0000000000..b5e3738bcd
--- /dev/null
+++ b/docs/zh-hant/docs/tutorial/security/index.md
@@ -0,0 +1,101 @@
+# 安全性 { #security }
+
+有許多方式可以處理安全性、身分驗證與授權。
+
+而且這通常是一個複雜且「困難」的主題。
+
+在許多框架與系統中,光是處理安全性與身分驗證就要花費大量心力與程式碼(很多情況下可能佔了全部程式碼的 50% 以上)。
+
+**FastAPI** 提供多種工具,讓你能以標準方式輕鬆、快速地處理「安全性」,而不必先研究並學會所有安全性規範。
+
+但在此之前,先釐清幾個小概念。
+
+## 急著上手? { #in-a-hurry }
+
+如果你不在意這些術語,只需要立刻加入以使用者名稱與密碼為基礎的身分驗證與安全性,就直接跳到後續章節。
+
+## OAuth2 { #oauth2 }
+
+OAuth2 是一套規範,定義了多種處理身分驗證與授權的方法。
+
+它相當龐大,涵蓋許多複雜的使用情境。
+
+它也包含使用「第三方」進行身分驗證的方式。
+
+這正是各種「使用 Facebook、Google、X(Twitter)、GitHub 登入」系統在底層採用的機制。
+
+### OAuth 1 { #oauth-1 }
+
+過去有 OAuth 1,和 OAuth2 非常不同,也更複雜,因為它直接規範了如何加密通訊。
+
+它現在並不流行,也很少被使用。
+
+OAuth2 不規範通訊如何加密,而是假設你的應用會透過 HTTPS 提供服務。
+
+/// tip | 提示
+在部署相關章節中,你會看到如何使用 Traefik 與 Let's Encrypt 免費設定 HTTPS。
+///
+
+## OpenID Connect { #openid-connect }
+
+OpenID Connect 是基於 **OAuth2** 的另一套規範。
+
+它只是擴充了 OAuth2,釐清了 OAuth2 中相對模糊的部份,以提升互通性。
+
+例如,Google 登入使用的是 OpenID Connect(其底層使用 OAuth2)。
+
+但 Facebook 登入不支援 OpenID Connect,它有自己風格的 OAuth2。
+
+### OpenID(不是「OpenID Connect」) { #openid-not-openid-connect }
+
+過去也有一個「OpenID」規範。它試圖解決與 **OpenID Connect** 相同的問題,但不是建立在 OAuth2 之上。
+
+因此,它是一套完全額外、獨立的系統。
+
+它現在並不流行,也很少被使用。
+
+## OpenAPI { #openapi }
+
+OpenAPI(先前稱為 Swagger)是一套用於構建 API 的開放規範(現為 Linux 基金會的一部分)。
+
+**FastAPI** 建立在 **OpenAPI** 之上。
+
+這使得它能提供多種自動化的互動式文件介面、程式碼產生等功能。
+
+OpenAPI 提供定義多種安全性「方案」。
+
+透過使用它們,你可以善用這些基於標準的工具,包括這些互動式文件系統。
+
+OpenAPI 定義了下列安全性方案:
+
+* `apiKey`:應用程式特定的金鑰,來源可以是:
+ * 查詢參數。
+ * 標頭(header)。
+ * Cookie。
+* `http`:標準的 HTTP 驗證系統,包括:
+ * `bearer`:使用 `Authorization` 標頭,值為 `Bearer ` 加上一個 token。這是從 OAuth2 延伸而來。
+ * HTTP Basic 驗證。
+ * HTTP Digest 等。
+* `oauth2`:所有 OAuth2 的安全性處理方式(稱為「flows」)。
+ * 其中數個 flow 適合用來建立 OAuth 2.0 身分驗證提供者(如 Google、Facebook、X(Twitter)、GitHub 等):
+ * `implicit`
+ * `clientCredentials`
+ * `authorizationCode`
+ * 但有一個特定的 flow 可直接在同一個應用中處理身分驗證:
+ * `password`:後續幾個章節會示範這個。
+* `openIdConnect`:提供一種方式來定義如何自動發現 OAuth2 的身分驗證資訊。
+ * 這種自動探索機制即由 OpenID Connect 規範定義。
+
+/// tip | 提示
+整合像 Google、Facebook、X(Twitter)、GitHub 等其他身分驗證/授權提供者也是可行而且相對容易。
+
+最複雜的部分其實是打造一個類似那樣的身分驗證/授權提供者,但 **FastAPI** 提供了工具,能替你處理繁重工作,讓你更輕鬆完成。
+///
+
+## **FastAPI** 工具 { #fastapi-utilities }
+
+FastAPI 在 `fastapi.security` 模組中為上述各種安全性方案提供了多種工具,讓這些機制更容易使用。
+
+接下來的章節會示範如何使用這些 **FastAPI** 提供的工具,為你的 API 加入安全性。
+
+你也會看到它如何自動整合到互動式文件系統中。
diff --git a/docs/zh-hant/docs/tutorial/security/oauth2-jwt.md b/docs/zh-hant/docs/tutorial/security/oauth2-jwt.md
new file mode 100644
index 0000000000..d6761a0051
--- /dev/null
+++ b/docs/zh-hant/docs/tutorial/security/oauth2-jwt.md
@@ -0,0 +1,277 @@
+# 使用密碼(與雜湊)的 OAuth2、以 Bearer 搭配 JWT 權杖 { #oauth2-with-password-and-hashing-bearer-with-jwt-tokens }
+
+現在我們已經有完整的安全流程了,接下來用 JWT 權杖與安全的密碼雜湊,讓應用真正安全。
+
+這份程式碼可以直接用在你的應用中,把密碼雜湊存進資料庫等等。
+
+我們會從上一章的內容繼續往下擴充。
+
+## 關於 JWT { #about-jwt }
+
+JWT 的意思是「JSON Web Tokens」。
+
+它是一種把 JSON 物件編碼成一段長且緊密(沒有空白)的字串的標準。看起來像這樣:
+
+```
+eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
+```
+
+它不是加密的,所以任何人都可以從內容還原出資訊。
+
+但它是簽名過的。因此當你收到一個你所簽發的權杖時,你可以驗證確實是你簽發的。
+
+如此一來,你可以建立一個(例如)有效期為 1 週的權杖。當使用者隔天帶著這個權杖回來時,你就知道該使用者仍然登入在你的系統中。
+
+一週後,權杖會過期,使用者就不再被授權,需要再次登入以取得新的權杖。而如果使用者(或第三方)試圖修改權杖來改變有效期,你也能發現,因為簽名不會相符。
+
+如果你想玩玩看 JWT 權杖並了解其運作,請參考 https://jwt.io。
+
+## 安裝 `PyJWT` { #install-pyjwt }
+
+我們需要安裝 `PyJWT` 才能在 Python 中產生與驗證 JWT 權杖。
+
+請先建立並啟用一個[虛擬環境](../../virtual-environments.md){.internal-link target=_blank},然後安裝 `pyjwt`:
+
+
+
+```console
+$ pip install pyjwt
+
+---> 100%
+```
+
+
+
+/// info | 說明
+
+如果你打算使用像 RSA 或 ECDSA 這類的數位簽章演算法,應該安裝帶有加密函式庫相依的 `pyjwt[crypto]`。
+
+更多內容可參考 PyJWT 安裝文件。
+
+///
+
+## 密碼雜湊 { #password-hashing }
+
+「雜湊」是指把某些內容(此處為密碼)轉換成一串看起來像亂碼的位元組序列(其實就是字串)。
+
+每當你輸入完全相同的內容(完全相同的密碼),就會得到完全相同的亂碼。
+
+但你無法從這串亂碼再反推回原本的密碼。
+
+### 為什麼要用密碼雜湊 { #why-use-password-hashing }
+
+如果你的資料庫被偷了,竊賊拿到的不是使用者的明文密碼,而只是雜湊值。
+
+因此,竊賊無法直接拿該密碼去嘗試登入其他系統(由於許多使用者在各處都用同一組密碼,這會很危險)。
+
+## 安裝 `pwdlib` { #install-pwdlib }
+
+pwdlib 是一個很棒的 Python 套件,用來處理密碼雜湊。
+
+它支援多種安全的雜湊演算法與相關工具。
+
+建議使用的演算法是「Argon2」。
+
+請先建立並啟用一個[虛擬環境](../../virtual-environments.md){.internal-link target=_blank},然後以 Argon2 支援安裝 pwdlib:
+
+
+
+```console
+$ pip install "pwdlib[argon2]"
+
+---> 100%
+```
+
+
+
+/// tip | 提示
+
+使用 `pwdlib`,你甚至可以把它設定為能讀取由 **Django**、**Flask** 的安全外掛或其他許多系統所建立的密碼。
+
+例如,你可以讓 Django 應用與 FastAPI 應用共用同一個資料庫中的資料。或者逐步遷移一個 Django 應用,同樣使用該資料庫。
+
+而你的使用者可以同時從 Django 應用或 **FastAPI** 應用登入。
+
+///
+
+## 雜湊與驗證密碼 { #hash-and-verify-the-passwords }
+
+從 `pwdlib` 匯入我們需要的工具。
+
+用建議設定建立一個 PasswordHash 執行個體——它會用於雜湊與驗證密碼。
+
+/// tip | 提示
+
+pwdlib 也支援 bcrypt 雜湊演算法,但不包含傳統(legacy)演算法——若需要處理過時的雜湊,建議使用 passlib 函式庫。
+
+例如,你可以用它讀取並驗證由其他系統(如 Django)產生的密碼,但針對任何新密碼則改用像 Argon2 或 Bcrypt 這類的不同演算法來雜湊。
+
+並同時與所有這些格式相容。
+
+///
+
+建立一個工具函式來雜湊使用者送來的密碼。
+
+再建立另一個工具來驗證收到的密碼是否符合已儲存的雜湊。
+
+以及另一個用於驗證並回傳使用者的工具。
+
+{* ../../docs_src/security/tutorial004_an_py310.py hl[8,49,51,58:59,62:63,72:79] *}
+
+當以不存在於資料庫的使用者名稱呼叫 `authenticate_user` 時,我們仍然會拿一個假的雜湊去跑一次 `verify_password`。
+
+這可確保無論使用者名稱是否有效,端點的回應時間都大致相同,避免可用來枚舉既有使用者名稱的「計時攻擊」(timing attacks)。
+
+/// note | 注意
+
+如果你查看新的(假)資料庫 `fake_users_db`,你會看到雜湊後的密碼現在長這樣:`"$argon2id$v=19$m=65536,t=3,p=4$wagCPXjifgvUFBzq4hqe3w$CYaIb8sB+wtD+Vu/P4uod1+Qof8h+1g7bbDlBID48Rc"`。
+
+///
+
+## 處理 JWT 權杖 { #handle-jwt-tokens }
+
+匯入剛安裝的模組。
+
+建立一把隨機的密鑰(secret key)用於簽署 JWT 權杖。
+
+要產生安全的隨機密鑰可使用以下指令:
+
+
+
+```console
+$ openssl rand -hex 32
+
+09d25e094faa6ca2556c818166b7a9563b93f7099f6f0f4caa6cf63b88e8d3e7
+```
+
+
+
+將輸出的值複製到變數 `SECRET_KEY`(不要使用範例中的那一組)。
+
+建立變數 `ALGORITHM` 指定用來簽署 JWT 權杖的演算法,設為 `"HS256"`。
+
+建立一個權杖有效期的變數。
+
+定義一個用於權杖端點回應的 Pydantic Model。
+
+建立一個工具函式來產生新的 access token。
+
+{* ../../docs_src/security/tutorial004_an_py310.py hl[4,7,13:15,29:31,82:90] *}
+
+## 更新相依項目 { #update-the-dependencies }
+
+更新 `get_current_user`,讓它仍接收相同的權杖,但這次改用 JWT 權杖。
+
+解碼收到的權杖、驗證它,並回傳目前的使用者。
+
+如果權杖無效,立即回傳一個 HTTP 錯誤。
+
+{* ../../docs_src/security/tutorial004_an_py310.py hl[93:110] *}
+
+## 更新 `/token` 路徑操作 { #update-the-token-path-operation }
+
+用權杖有效期建立一個 `timedelta`。
+
+建立真正的 JWT access token 並回傳它。
+
+{* ../../docs_src/security/tutorial004_an_py310.py hl[121:136] *}
+
+### 關於 JWT「主體」`sub` 的技術細節 { #technical-details-about-the-jwt-subject-sub }
+
+JWT 規範說有個鍵 `sub`,代表權杖的主體(subject)。
+
+使用它是可選的,但通常會把使用者的識別資訊放在這裡,所以我們在此採用。
+
+JWT 除了用來識別使用者並允許他直接對你的 API 執行操作外,也可用於其他用途。
+
+例如,你可以識別一台「車」或一篇「部落格文章」。
+
+接著可以替該實體加上權限,如「drive」(對車而言)或「edit」(對文章而言)。
+
+然後你可以把該 JWT 權杖交給某個使用者(或機器人),他們就能用它來執行那些動作(開車、或編輯文章),甚至不需要有帳號,只要使用你的 API 所產生的 JWT 權杖即可。
+
+基於這些概念,JWT 能用在更複雜的情境中。
+
+在那些情境裡,數個實體可能擁有相同的 ID,例如 `foo`(使用者 `foo`、車 `foo`、以及文章 `foo`)。
+
+為了避免 ID 衝突,在為使用者建立 JWT 權杖時,你可以替 `sub` 的值加上前綴,例如 `username:`。因此在這個例子中,`sub` 的值可以是:`username:johndoe`。
+
+要記住的重要點是:`sub` 必須是在整個應用中唯一的識別子,並且必須是字串。
+
+## 試試看 { #check-it }
+
+啟動伺服器並前往文件頁:http://127.0.0.1:8000/docs。
+
+你會看到這樣的介面:
+
+
+
+用和先前相同的方式授權應用。
+
+使用下列認證資訊:
+
+Username: `johndoe`
+Password: `secret`
+
+/// check | 檢查
+
+注意在程式碼中完全沒有明文密碼「`secret`」,我們只有雜湊後的版本。
+
+///
+
+
+
+呼叫端點 `/users/me/`,你會得到類似這樣的回應:
+
+```JSON
+{
+ "username": "johndoe",
+ "email": "johndoe@example.com",
+ "full_name": "John Doe",
+ "disabled": false
+}
+```
+
+
+
+如果你打開開發者工具,可以看到送出的資料只包含權杖;密碼只會在第一次請求(用來驗證使用者並取得 access token)時送出,之後就不會再送:
+
+
+
+/// note | 注意
+
+留意標頭 `Authorization`,其值是以 `Bearer ` 開頭。
+
+///
+
+## 進階用法:`scopes` { #advanced-usage-with-scopes }
+
+OAuth2 有「scopes」的概念。
+
+你可以用它們替 JWT 權杖加上一組特定的權限。
+
+接著你可以把這個權杖直接交給某個使用者或第三方,讓他們在一組受限條件下與你的 API 互動。
+
+你可以在之後的「進階使用者指南」學到如何使用它們,以及它們如何整合進 **FastAPI**。
+
+## 小結 { #recap }
+
+依照你目前學到的內容,你可以用 OAuth2 與 JWT 等標準,設定一個安全的 **FastAPI** 應用。
+
+在幾乎任何框架中,安全性處理都會很快變得相當複雜。
+
+許多能大幅簡化工作的套件,往往必須在資料模型、資料庫與可用功能上做出很多取捨。而有些過度簡化的套件底層其實存在安全弱點。
+
+---
+
+**FastAPI** 不會在任何資料庫、資料模型或工具上做妥協。
+
+它給你完全的彈性,讓你挑選最適合你專案的組合。
+
+而且你可以直接使用許多維護良好且被廣泛採用的套件,例如 `pwdlib` 與 `PyJWT`,因為 **FastAPI** 不需要任何複雜機制就能整合外部套件。
+
+同時它也提供工具來在不犧牲彈性、穩健或安全的前提下,盡可能地簡化流程。
+
+你可以用相對簡單的方式使用並實作像 OAuth2 這樣的安全標準協定。
+
+你可以在「進階使用者指南」進一步了解如何使用 OAuth2 的「scopes」,以實作更細緻的權限系統,並遵循相同的標準。帶有 scopes 的 OAuth2 是許多大型身份驗證供應商(如 Facebook、Google、GitHub、Microsoft、X(Twitter)等)用來授權第三方應用代表其使用者與其 API 互動的機制。
diff --git a/docs/zh-hant/docs/tutorial/security/simple-oauth2.md b/docs/zh-hant/docs/tutorial/security/simple-oauth2.md
new file mode 100644
index 0000000000..3b9aae3416
--- /dev/null
+++ b/docs/zh-hant/docs/tutorial/security/simple-oauth2.md
@@ -0,0 +1,289 @@
+# 簡易 OAuth2:Password 與 Bearer { #simple-oauth2-with-password-and-bearer }
+
+現在從上一章延伸,補上缺少的部分,完成整個安全流程。
+
+## 取得 `username` 與 `password` { #get-the-username-and-password }
+
+我們要使用 **FastAPI** 提供的安全性工具來取得 `username` 與 `password`。
+
+OAuth2 規範中,當使用「password flow」(我們現在使用的)時,用戶端/使用者必須以表單資料送出 `username` 與 `password` 欄位。
+
+而且規範要求欄位名稱必須就是這兩個,所以像是 `user-name` 或 `email` 都不行。
+
+但別擔心,你在前端要怎麼呈現給最終使用者都可以。
+
+而你的資料庫模型也可以使用任何你想要的欄位名稱。
+
+不過在登入的路徑操作(path operation)裡,我們需要使用這些名稱,才能符合規範(例如才能使用整合的 API 文件系統)。
+
+規範也說明 `username` 與 `password` 必須以表單資料傳送(也就是這裡不能用 JSON)。
+
+### `scope` { #scope }
+
+規範也說用戶端可以再送一個表單欄位「`scope`」。
+
+欄位名稱是單數的 `scope`,但實際上是由多個以空白分隔的「scopes」組成的一長串字串。
+
+每個「scope」就是一個(不含空白的)字串。
+
+它們通常用來宣告特定的權限,例如:
+
+- `users:read` 或 `users:write` 是常見的例子
+- `instagram_basic` 用在 Facebook / Instagram
+- `https://www.googleapis.com/auth/drive` 用在 Google
+
+/// info
+
+在 OAuth2 裡,「scope」只是用來宣告特定所需權限的一個字串。
+
+不論裡面是否包含像 `:` 之類的字元,或是否是一個 URL,都沒差。
+
+那些都是實作細節。
+
+對 OAuth2 而言,它們就是字串而已。
+
+///
+
+## 取得 `username` 與 `password` 的程式碼 { #code-to-get-the-username-and-password }
+
+現在用 **FastAPI** 提供的工具來處理。
+
+### `OAuth2PasswordRequestForm` { #oauth2passwordrequestform }
+
+先匯入 `OAuth2PasswordRequestForm`,並在 `/token` 的路徑操作中,搭配 `Depends` 當作依賴使用:
+
+{* ../../docs_src/security/tutorial003_an_py310.py hl[4,78] *}
+
+`OAuth2PasswordRequestForm` 是一個類別型依賴,它宣告了一個表單本文,包含:
+
+- `username`
+- `password`
+- 可選的 `scope` 欄位,內容是一個由空白分隔的長字串
+- 可選的 `grant_type`
+
+/// tip
+
+依規範,實際上需要一個 `grant_type` 欄位且固定值為 `password`,但 `OAuth2PasswordRequestForm` 並不會強制檢查。
+
+如果你需要強制檢查,請改用 `OAuth2PasswordRequestFormStrict` 取代 `OAuth2PasswordRequestForm`。
+
+///
+
+- 可選的 `client_id`(本例不需要)
+- 可選的 `client_secret`(本例不需要)
+
+/// info
+
+`OAuth2PasswordRequestForm` 並不是像 `OAuth2PasswordBearer` 那樣對 **FastAPI** 來說的特殊類別。
+
+`OAuth2PasswordBearer` 會讓 **FastAPI** 知道它是一個 security scheme,因此會以那種方式加入 OpenAPI。
+
+但 `OAuth2PasswordRequestForm` 只是你也可以自己撰寫的一個類別型依賴,或是你也可以直接宣告 `Form` 參數。
+
+只是因為這是很常見的用例,所以 **FastAPI** 直接內建提供,讓事情更簡單。
+
+///
+
+### 使用表單資料 { #use-the-form-data }
+
+/// tip
+
+`OAuth2PasswordRequestForm` 這個依賴類別的實例不會有以空白分隔長字串的 `scope` 屬性,而是會有一個 `scopes` 屬性,裡面是各個 scope 的實際字串清單。
+
+本示例沒有使用 `scopes`,但如果你需要,功能已經在那裡了。
+
+///
+
+現在,從(假的)資料庫裡用表單欄位的 `username` 取得使用者資料。
+
+如果沒有該使用者,就回傳「Incorrect username or password」的錯誤。
+
+我們用 `HTTPException` 這個例外來回傳錯誤:
+
+{* ../../docs_src/security/tutorial003_an_py310.py hl[3,79:81] *}
+
+### 檢查密碼 { #check-the-password }
+
+這時我們已經有來自資料庫的使用者資料,但還沒檢查密碼。
+
+先把那些資料放進 Pydantic 的 `UserInDB` 模型。
+
+你絕對不要以純文字儲存密碼,所以我們會使用(假的)密碼雜湊系統。
+
+如果密碼不匹配,我們回傳同樣的錯誤。
+
+#### 密碼雜湊(hashing) { #password-hashing }
+
+「雜湊」的意思是:把一些內容(這裡是密碼)轉換成一串看起來像亂碼的位元組序列(就是字串)。
+
+只要你輸入完全相同的內容(完全相同的密碼),就會得到完全相同的亂碼。
+
+但你無法從這串亂碼還原回原本的密碼。
+
+##### 為何要做密碼雜湊 { #why-use-password-hashing }
+
+如果你的資料庫被竊取,攻擊者拿到的不是使用者的純文字密碼,而只是雜湊值。
+
+因此攻擊者無法嘗試把那些密碼用在其他系統上(因為很多使用者在各處都用同一組密碼,這會很危險)。
+
+{* ../../docs_src/security/tutorial003_an_py310.py hl[82:85] *}
+
+#### 關於 `**user_dict**` { #about-user-dict }
+
+`UserInDB(**user_dict)` 的意思是:
+
+把 `user_dict` 的鍵和值直接當作具名參數傳入,等同於:
+
+```Python
+UserInDB(
+ username = user_dict["username"],
+ email = user_dict["email"],
+ full_name = user_dict["full_name"],
+ disabled = user_dict["disabled"],
+ hashed_password = user_dict["hashed_password"],
+)
+```
+
+/// info
+
+想更完整地了解 `**user_dict`,請回到[**額外模型** 的文件](../extra-models.md#about-user-in-dict){.internal-link target=_blank}。
+
+///
+
+## 回傳 token { #return-the-token }
+
+`token` 端點的回應必須是 JSON 物件。
+
+它應該有一個 `token_type`。在本例中,我們使用「Bearer」tokens,token 類型應該是「`bearer`」。
+
+而且它還應該有一個 `access_token`,其值為包含我們存取權杖的字串。
+
+在這個簡單示例中,我們會不安全地直接回傳相同的 `username` 當作 token。
+
+/// tip
+
+下一章你會看到真正安全的實作,包含密碼雜湊與 JWT tokens。
+
+但現在先把注意力放在我們需要的這些細節上。
+
+///
+
+{* ../../docs_src/security/tutorial003_an_py310.py hl[87] *}
+
+/// tip
+
+依照規範,你應該回傳一個包含 `access_token` 與 `token_type` 的 JSON,就像這個範例。
+
+這部分需要你自己在程式中完成,並確保使用這些 JSON key。
+
+這幾乎是你為了符合規範而必須自行記得正確處理的唯一事情。
+
+其餘的 **FastAPI** 都會幫你處理。
+
+///
+
+## 更新依賴項 { #update-the-dependencies }
+
+接著我們要更新依賴項。
+
+我們只想在使用者為啟用狀態時取得 `current_user`。
+
+所以,我們新增一個依賴 `get_current_active_user`,而它本身又依賴 `get_current_user`。
+
+這兩個依賴會在使用者不存在或未啟用時回傳 HTTP 錯誤。
+
+因此,在端點中,只有在使用者存在、已正確驗證且為啟用狀態時,我們才會取得使用者:
+
+{* ../../docs_src/security/tutorial003_an_py310.py hl[58:66,69:74,94] *}
+
+/// info
+
+這裡我們一併回傳值為 `Bearer` 的額外標頭 `WWW-Authenticate`,這也是規範的一部分。
+
+任何 HTTP(錯誤)狀態碼 401「UNAUTHORIZED」都應該同時回傳 `WWW-Authenticate` 標頭。
+
+在 bearer tokens(我們的情況)下,該標頭的值應該是 `Bearer`。
+
+其實你可以省略這個額外標頭,功能仍會正常。
+
+但此處加上它是為了遵循規範。
+
+同時也可能有工具會期待並使用它(現在或未來),而這可能對你或你的使用者有幫助,現在或未來皆然。
+
+這就是標準的好處...
+
+///
+
+## 實際操作看看 { #see-it-in-action }
+
+開啟互動式文件:http://127.0.0.1:8000/docs。
+
+### 驗證身分 { #authenticate }
+
+點選「Authorize」按鈕。
+
+使用下列帳密:
+
+User: `johndoe`
+
+Password: `secret`
+
+
+
+在系統中完成驗證後,你會看到如下畫面:
+
+
+
+### 取得自己的使用者資料 { #get-your-own-user-data }
+
+現在使用 `GET` 方法呼叫路徑 `/users/me`。
+
+你會取得自己的使用者資料,如:
+
+```JSON
+{
+ "username": "johndoe",
+ "email": "johndoe@example.com",
+ "full_name": "John Doe",
+ "disabled": false,
+ "hashed_password": "fakehashedsecret"
+}
+```
+
+
+
+如果你點擊鎖頭圖示登出,然後再次嘗試相同操作,你會得到 HTTP 401 錯誤:
+
+```JSON
+{
+ "detail": "Not authenticated"
+}
+```
+
+### 未啟用的使用者 { #inactive-user }
+
+現在改用一個未啟用的使用者,使用以下帳密驗證:
+
+User: `alice`
+
+Password: `secret2`
+
+然後再呼叫 `GET` 方法的 `/users/me`。
+
+你會得到「Inactive user」的錯誤,例如:
+
+```JSON
+{
+ "detail": "Inactive user"
+}
+```
+
+## 小結 { #recap }
+
+你現在已經有足夠的工具,能為你的 API 以 `username` 與 `password` 實作一個完整的安全性系統。
+
+使用這些工具,你可以讓安全性系統相容於任何資料庫,以及任何使用者或資料模型。
+
+唯一尚未補上的細節是:它現在其實還不「安全」。
+
+在下一章,你會看到如何使用安全的密碼雜湊函式庫與 JWT tokens。
diff --git a/docs/zh-hant/docs/tutorial/sql-databases.md b/docs/zh-hant/docs/tutorial/sql-databases.md
new file mode 100644
index 0000000000..930dc4e8a5
--- /dev/null
+++ b/docs/zh-hant/docs/tutorial/sql-databases.md
@@ -0,0 +1,357 @@
+# SQL(關聯式)資料庫 { #sql-relational-databases }
+
+FastAPI 不強制你使用 SQL(關聯式)資料庫。你可以使用任何你想要的資料庫。
+
+這裡我們會用 SQLModel 作為範例。
+
+SQLModel 建立在 SQLAlchemy 與 Pydantic 之上。它由 FastAPI 的作者開發,非常適合需要使用 SQL 資料庫的 FastAPI 應用。
+
+/// tip | 提示
+
+你可以使用任何你想用的 SQL 或 NoSQL 資料庫函式庫(有時稱為 "ORMs"),FastAPI 不會強迫你使用特定工具。😎
+
+///
+
+因為 SQLModel 建立在 SQLAlchemy 之上,你可以輕鬆使用 SQLAlchemy 所支援的任何資料庫(因此 SQLModel 也支援),例如:
+
+* PostgreSQL
+* MySQL
+* SQLite
+* Oracle
+* Microsoft SQL Server,等等。
+
+在這個範例中,我們會使用 SQLite,因為它只用到單一檔案,而且 Python 內建支援。你可以直接複製這個範例並原樣執行。
+
+之後,在你的正式環境應用中,你可能會想使用像 PostgreSQL 這類的資料庫伺服器。
+
+/// tip | 提示
+
+有一個包含 FastAPI 與 PostgreSQL 的官方專案腳手架,還有前端與更多工具:https://github.com/fastapi/full-stack-fastapi-template
+
+///
+
+這是一份非常簡短的教學,如果你想更全面學習資料庫、SQL,或更進階的功能,請參考 SQLModel 文件。
+
+## 安裝 `SQLModel` { #install-sqlmodel }
+
+首先,請先建立你的[虛擬環境](../virtual-environments.md){.internal-link target=_blank}、啟用它,然後安裝 `sqlmodel`:
+
+
+
+```console
+$ pip install sqlmodel
+---> 100%
+```
+
+
+
+## 建立只有單一模型的應用 { #create-the-app-with-a-single-model }
+
+我們先用單一 SQLModel 模型建立這個應用的最簡版。
+
+接著我們會在下方用多個模型來提升安全性與彈性。🤓
+
+### 建立模型 { #create-models }
+
+匯入 `SQLModel` 並建立一個資料庫模型:
+
+{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[1:11] hl[7:11] *}
+
+`Hero` 類別與 Pydantic 模型非常相似(事實上,在底層它就是一個 Pydantic 模型)。
+
+有幾點差異:
+
+* `table=True` 告訴 SQLModel 這是一個「資料表模型」(table model),它應該代表 SQL 資料庫中的一個資料表,而不僅僅是「資料模型」(就像一般的 Pydantic 類別)。
+
+* `Field(primary_key=True)` 告訴 SQLModel,`id` 是 SQL 資料庫中的「主鍵」。 (你可以在 SQLModel 文件中進一步了解 SQL 主鍵)
+
+ 注意:我們在主鍵欄位使用 `int | None`,這樣在 Python 程式碼中我們可以「在沒有 `id` 的情況下建立物件」(`id=None`),假設資料庫在儲存時會「自動產生」。SQLModel 瞭解資料庫會提供 `id`,並且在資料庫綱要中「將該欄位定義為非空的 `INTEGER`」。詳情請見 SQLModel 文件:主鍵。
+
+* `Field(index=True)` 告訴 SQLModel 應為此欄位建立「SQL 索引」,以便在用此欄位過濾讀取資料時更快查詢。
+
+ SQLModel 會知道宣告為 `str` 的欄位在 SQL 中會是 `TEXT`(或 `VARCHAR`,依資料庫而定)。
+
+### 建立引擎 { #create-an-engine }
+
+SQLModel 的 `engine`(底層實際上是 SQLAlchemy 的 `engine`)是用來「維護與資料庫連線」的東西。
+
+你的程式中應該只有「單一 `engine` 物件」來連到同一個資料庫。
+
+{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[14:18] hl[14:15,17:18] *}
+
+使用 `check_same_thread=False` 允許 FastAPI 在不同執行緒中使用同一個 SQLite 資料庫。這是必要的,因為「單一請求」可能會使用「多個執行緒」(例如在依賴項中)。
+
+別擔心,依照我們的程式結構,稍後我們會確保「每個請求只使用單一 SQLModel 的 session」,這其實就是 `check_same_thread` 想要達成的事。
+
+### 建立資料表 { #create-the-tables }
+
+接著我們新增一個函式,使用 `SQLModel.metadata.create_all(engine)` 為所有「資料表模型」建立資料表。
+
+{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[21:22] hl[21:22] *}
+
+### 建立 Session 依賴 { #create-a-session-dependency }
+
+「`Session`」會在記憶體中保存物件並追蹤資料需要的任何變更,然後透過「`engine`」與資料庫溝通。
+
+我們會用 `yield` 建立一個 FastAPI 的「依賴」,為每個請求提供一個新的 `Session`。這可確保每個請求只使用單一的 session。🤓
+
+接著我們建立一個 `Annotated` 的依賴 `SessionDep`,讓後續使用這個依賴的程式碼更簡潔。
+
+{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[25:30] hl[25:27,30] *}
+
+### 在啟動時建立資料表 { #create-database-tables-on-startup }
+
+我們會在應用啟動時建立資料庫的資料表。
+
+{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[32:37] hl[35:37] *}
+
+這裡我們在應用的啟動事件中建立資料表。
+
+在正式環境中,你大概會在啟動應用前使用遷移腳本來處理。🤓
+
+/// tip | 提示
+
+SQLModel 之後會提供包裝 Alembic 的遷移工具,但目前你可以直接使用 Alembic。
+
+///
+
+### 建立 Hero { #create-a-hero }
+
+因為每個 SQLModel 模型同時也是一個 Pydantic 模型,你可以在「型別標註」中像使用 Pydantic 模型一樣使用它。
+
+例如,如果你宣告一個參數型別為 `Hero`,它會從「JSON body」中讀取。
+
+同樣地,你也可以將它宣告為函式的「回傳型別」,然後在自動產生的 API 文件 UI 中就會顯示其資料結構。
+
+{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[40:45] hl[40:45] *}
+
+這裡我們使用 `SessionDep` 依賴(即一個 `Session`),把新的 `Hero` 加入 `Session` 實例,提交變更到資料庫,刷新 `hero` 的資料,然後回傳它。
+
+### 讀取多個 Hero { #read-heroes }
+
+我們可以用 `select()` 從資料庫「讀取」多個 `Hero`。可以加入 `limit` 與 `offset` 來分頁。
+
+{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[48:55] hl[51:52,54] *}
+
+### 讀取單一 Hero { #read-one-hero }
+
+我們可以「讀取」單一的 `Hero`。
+
+{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[58:63] hl[60] *}
+
+### 刪除 Hero { #delete-a-hero }
+
+我們也可以「刪除」一個 `Hero`。
+
+{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[66:73] hl[71] *}
+
+### 執行應用 { #run-the-app }
+
+你可以執行應用:
+
+
+
+```console
+$ fastapi dev main.py
+
+INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
+```
+
+
+
+然後前往 `/docs` 的 UI,你會看到 FastAPI 使用這些模型來「文件化」API,也會用它們來「序列化」與「驗證」資料。
+
+
+

+
+
+## 用多個模型更新應用 { #update-the-app-with-multiple-models }
+
+現在我們稍微「重構」一下這個應用,以提升「安全性」與「彈性」。
+
+如果你檢查前一版的應用,在 UI 中你會看到,到目前為止它讓用戶端自己決定要建立的 `Hero` 的 `id`。😱
+
+我們不該允許這樣,因為他們可能會覆蓋資料庫中我們已分配的 `id`。決定 `id` 應該由「後端」或「資料庫」來做,「不是用戶端」。
+
+另外,我們為 hero 建立了 `secret_name`,但目前我們在各處都把它回傳出去,這一點都不「保密」... 😅
+
+我們會透過加入一些「額外模型」來修正這些問題。這正是 SQLModel 大放異彩的地方。✨
+
+### 建立多個模型 { #create-multiple-models }
+
+在 SQLModel 中,任何設了 `table=True` 的模型類別都是「資料表模型」。
+
+而沒有設 `table=True` 的模型類別就是「資料模型」,這些其實就是 Pydantic 模型(只有一點小增強)。🤓
+
+使用 SQLModel,我們可以利用「繼承」來「避免重複」在各種情況下一再宣告所有欄位。
+
+#### `HeroBase` - 基底類別 { #herobase-the-base-class }
+
+先從 `HeroBase` 模型開始,它包含所有模型「共享」的欄位:
+
+* `name`
+* `age`
+
+{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:9] hl[7:9] *}
+
+#### `Hero` - 資料表模型 { #hero-the-table-model }
+
+接著建立 `Hero`,也就是實際的「資料表模型」,它包含不一定會出現在其他模型中的「額外欄位」:
+
+* `id`
+* `secret_name`
+
+因為 `Hero` 繼承自 `HeroBase`,它「也」擁有 `HeroBase` 中宣告的「欄位」,因此 `Hero` 的完整欄位為:
+
+* `id`
+* `name`
+* `age`
+* `secret_name`
+
+{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:14] hl[12:14] *}
+
+#### `HeroPublic` - 公開的資料模型 { #heropublic-the-public-data-model }
+
+接下來建立 `HeroPublic` 模型,它是要「回傳」給 API 用戶端的模型。
+
+它擁有與 `HeroBase` 相同的欄位,因此不會包含 `secret_name`。
+
+終於,我們英雄的真實身分受保護了!🥷
+
+它也重新宣告了 `id: int`。這麼做是與 API 用戶端訂立一個「契約」,讓他們可以確定 `id` 一定存在而且是 `int`(不會是 `None`)。
+
+/// tip | 提示
+
+讓回傳模型保證某個值一定存在、而且一定是 `int`(不是 `None`),對 API 用戶端非常有幫助。他們在有這個確信下可以寫出更簡單的程式碼。
+
+此外,透過「自動產生的客戶端」也會有更簡潔的介面,讓要使用你 API 的開發者能有更好的開發體驗。😎
+
+///
+
+`HeroPublic` 中的欄位與 `HeroBase` 相同,僅 `id` 宣告為 `int`(非 `None`):
+
+* `id`
+* `name`
+* `age`
+
+{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:18] hl[17:18] *}
+
+#### `HeroCreate` - 用於建立 Hero 的資料模型 { #herocreate-the-data-model-to-create-a-hero }
+
+現在我們建立 `HeroCreate` 模型,這是用來「驗證」用戶端送來資料的模型。
+
+它具有與 `HeroBase` 相同的欄位,並且還有 `secret_name`。
+
+接下來,當用戶端「建立新 hero」時,他們會送上 `secret_name`,它會被儲存在資料庫中,但這些祕密名稱不會在 API 中回傳給用戶端。
+
+/// tip | 提示
+
+這也就是你處理「密碼」的方式。接收它們,但不要在 API 中回傳。
+
+你也應該在儲存前先對密碼做「雜湊」,「永遠不要以明文儲存」。
+
+///
+
+`HeroCreate` 的欄位有:
+
+* `name`
+* `age`
+* `secret_name`
+
+{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:22] hl[21:22] *}
+
+#### `HeroUpdate` - 用於更新 Hero 的資料模型 { #heroupdate-the-data-model-to-update-a-hero }
+
+在前一版的應用中,我們沒有「更新 hero」的方式,但現在有了「多個模型」,我們就能做到。🎉
+
+`HeroUpdate` 這個資料模型有點特別,它包含「建立新 hero 所需的所有欄位」,但所有欄位都是「可選的」(都有預設值)。這樣在更新時,你只需要送出想要更新的欄位即可。
+
+因為所有欄位的「型別其實都改變了」(型別現在包含 `None`,而且預設值為 `None`),我們需要「重新宣告」它們。
+
+其實不一定要繼承 `HeroBase`,因為我們會重新宣告所有欄位。我這裡保留繼承只是為了一致性,並非必要。這主要是個人偏好的問題。🤷
+
+`HeroUpdate` 的欄位有:
+
+* `name`
+* `age`
+* `secret_name`
+
+{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:28] hl[25:28] *}
+
+### 用 `HeroCreate` 建立並回傳 `HeroPublic` { #create-with-herocreate-and-return-a-heropublic }
+
+現在我們有了「多個模型」,可以更新應用中使用它們的部分。
+
+我們在請求中接收 `HeroCreate`(資料模型),並由它建立一個 `Hero`(資料表模型)。
+
+這個新的資料表模型 `Hero` 會有用戶端傳來的欄位,並且會由資料庫產生一個 `id`。
+
+然後我們直接從函式回傳這個資料表模型 `Hero`。但因為我們用 `HeroPublic` 當作 `response_model`,FastAPI 會用 `HeroPublic` 來驗證與序列化資料。
+
+{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[56:62] hl[56:58] *}
+
+/// tip | 提示
+
+現在我們用 `response_model=HeroPublic`,而不是用回傳型別標註 `-> HeroPublic`,因為我們實際回傳的值其實「不是」`HeroPublic`。
+
+如果我們宣告 `-> HeroPublic`,你的編輯器與 linter 會(理所當然地)抱怨你回傳的是 `Hero` 而不是 `HeroPublic`。
+
+在 `response_model` 中宣告,就是要讓 FastAPI 去做它該做的事,而不影響型別標註,以及你的編輯器與其他工具提供的協助。
+
+///
+
+### 使用 `HeroPublic` 讀取多個 Hero { #read-heroes-with-heropublic }
+
+我們可以像先前一樣「讀取」多個 `Hero`。同樣地,我們使用 `response_model=list[HeroPublic]` 來確保資料被正確驗證與序列化。
+
+{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[65:72] hl[65] *}
+
+### 使用 `HeroPublic` 讀取單一 Hero { #read-one-hero-with-heropublic }
+
+我們可以「讀取」單一 hero:
+
+{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[75:80] hl[77] *}
+
+### 使用 `HeroUpdate` 更新 Hero { #update-a-hero-with-heroupdate }
+
+我們可以「更新 hero」。為此我們使用 HTTP 的 `PATCH` 操作。
+
+在程式碼中,我們會取得一個只包含用戶端有傳送的資料的 `dict`,不包含只是因為有預設值而存在的欄位。為了達成這點,我們使用 `exclude_unset=True`。這是關鍵。🪄
+
+然後我們使用 `hero_db.sqlmodel_update(hero_data)` 以 `hero_data` 的資料更新 `hero_db`。
+
+{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[83:93] hl[83:84,88:89] *}
+
+### 再次刪除 Hero { #delete-a-hero-again }
+
+「刪除」 hero 基本上維持不變。
+
+我們不會為了重構而重構一切。😅
+
+{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[96:103] hl[101] *}
+
+### 再次執行應用 { #run-the-app-again }
+
+你可以再次執行應用:
+
+
+
+```console
+$ fastapi dev main.py
+
+INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
+```
+
+
+
+如果你前往 `/docs` 的 API UI,你會看到它已更新,建立 hero 時不再期待從用戶端接收 `id`,等等。
+
+
+

+
+
+## 總結 { #recap }
+
+你可以使用 SQLModel 與 SQL 資料庫互動,並用「資料模型」與「資料表模型」讓程式碼更簡潔。
+
+你可以在 SQLModel 文件學到更多內容,這裡還有一份更長的 使用 SQLModel 與 FastAPI 的教學。🚀
diff --git a/docs/zh-hant/docs/tutorial/static-files.md b/docs/zh-hant/docs/tutorial/static-files.md
new file mode 100644
index 0000000000..06b6176760
--- /dev/null
+++ b/docs/zh-hant/docs/tutorial/static-files.md
@@ -0,0 +1,40 @@
+# 靜態檔案 { #static-files }
+
+你可以使用 `StaticFiles` 從某個目錄自動提供靜態檔案。
+
+## 使用 `StaticFiles` { #use-staticfiles }
+
+- 匯入 `StaticFiles`。
+- 在特定路徑上「掛載」一個 `StaticFiles()` 實例。
+
+{* ../../docs_src/static_files/tutorial001_py310.py hl[2,6] *}
+
+/// note | 技術細節
+
+你也可以使用 `from starlette.staticfiles import StaticFiles`。
+
+**FastAPI** 為了方便開發者,提供與 `starlette.staticfiles` 相同的介面作為 `fastapi.staticfiles`。但它其實是直接來自 Starlette。
+
+///
+
+### 什麼是「掛載」 { #what-is-mounting }
+
+「掛載(mounting)」是指在特定路徑下加入一個完整且「獨立」的應用,之後所有該路徑下的子路徑都由它處理。
+
+這與使用 `APIRouter` 不同,因為被掛載的應用是完全獨立的。主應用的 OpenAPI 與文件不會包含掛載應用的任何內容,等等。
+
+你可以在[進階使用者指南](../advanced/index.md){.internal-link target=_blank}中閱讀更多相關內容。
+
+## 細節 { #details }
+
+第一個 `"/static"` 指的是這個「子應用」要被「掛載」的子路徑。因此,任何以 `"/static"` 開頭的路徑都會由它處理。
+
+`directory="static"` 指向包含你靜態檔案的目錄名稱。
+
+`name="static"` 為它指定一個可供 **FastAPI** 內部使用的名稱。
+
+以上參數都不一定要是 "`static`",請依你的應用需求與細節調整。
+
+## 更多資訊 { #more-info }
+
+如需更多細節與選項,請參考 Starlette 關於靜態檔案的文件。
diff --git a/docs/zh-hant/docs/tutorial/testing.md b/docs/zh-hant/docs/tutorial/testing.md
new file mode 100644
index 0000000000..0d49fd5d7b
--- /dev/null
+++ b/docs/zh-hant/docs/tutorial/testing.md
@@ -0,0 +1,193 @@
+# 測試 { #testing }
+
+多虧了 Starlette,測試 **FastAPI** 應用既簡單又好用。
+
+它是基於 HTTPX 打造,而 HTTPX 的設計又參考了 Requests,所以用起來非常熟悉、直覺。
+
+借助它,你可以直接用 pytest 來測試 **FastAPI**。
+
+## 使用 `TestClient` { #using-testclient }
+
+/// info
+
+要使用 `TestClient`,請先安裝 `httpx`。
+
+請先建立並啟用一個[虛擬環境](../virtual-environments.md){.internal-link target=_blank},然後安裝,例如:
+
+```console
+$ pip install httpx
+```
+
+///
+
+匯入 `TestClient`。
+
+建立一個 `TestClient`,把你的 **FastAPI** 應用傳入其中。
+
+建立名稱以 `test_` 開頭的函式(這是 `pytest` 的慣例)。
+
+像使用 `httpx` 一樣使用 `TestClient` 物件。
+
+用簡單的 `assert` 敘述搭配標準的 Python 運算式來檢查(同樣是 `pytest` 的標準用法)。
+
+{* ../../docs_src/app_testing/tutorial001_py310.py hl[2,12,15:18] *}
+
+/// tip
+
+注意測試函式是一般的 `def`,不是 `async def`。
+
+而且對 client 的呼叫也都是一般呼叫,不需要使用 `await`。
+
+這讓你可以直接使用 `pytest`,不必費心處理非同步。
+
+///
+
+/// note | 技術細節
+
+你也可以使用 `from starlette.testclient import TestClient`。
+
+**FastAPI** 為了方便開發者,也提供與 `starlette.testclient` 相同的 `fastapi.testclient`。但它其實直接來自 Starlette。
+
+///
+
+/// tip
+
+如果你想在測試中呼叫其他 `async` 函式,而不只是對 FastAPI 應用發送請求(例如非同步的資料庫函式),請參考進階教學中的[非同步測試](../advanced/async-tests.md){.internal-link target=_blank}。
+
+///
+
+## 分離測試 { #separating-tests }
+
+在真實專案中,你大概會把測試放在不同的檔案中。
+
+你的 **FastAPI** 應用也可能由多個檔案/模組組成,等等。
+
+### **FastAPI** 應用檔案 { #fastapi-app-file }
+
+假設你的檔案結構如[更大型的應用](bigger-applications.md){.internal-link target=_blank}所述:
+
+```
+.
+├── app
+│ ├── __init__.py
+│ └── main.py
+```
+
+在 `main.py` 檔案中有你的 **FastAPI** 應用:
+
+
+{* ../../docs_src/app_testing/app_a_py310/main.py *}
+
+### 測試檔案 { #testing-file }
+
+然後你可以建立一個 `test_main.py` 放你的測試。它可以與應用位於同一個 Python 套件(同一個包含 `__init__.py` 的目錄):
+
+``` hl_lines="5"
+.
+├── app
+│ ├── __init__.py
+│ ├── main.py
+│ └── test_main.py
+```
+
+因為這個檔案在同一個套件中,你可以使用相對匯入,從 `main` 模組(`main.py`)匯入 `app` 這個物件:
+
+{* ../../docs_src/app_testing/app_a_py310/test_main.py hl[3] *}
+
+
+...然後測試的程式碼就和先前一樣。
+
+## 測試:進階範例 { #testing-extended-example }
+
+現在我們延伸這個範例並加入更多細節,看看如何測試不同部分。
+
+### 擴充的 **FastAPI** 應用檔案 { #extended-fastapi-app-file }
+
+沿用先前相同的檔案結構:
+
+```
+.
+├── app
+│ ├── __init__.py
+│ ├── main.py
+│ └── test_main.py
+```
+
+假設現在你的 **FastAPI** 應用所在的 `main.py` 有一些其他的路徑操作(path operations)。
+
+它有一個可能回傳錯誤的 `GET` 操作。
+
+它有一個可能回傳多種錯誤的 `POST` 操作。
+
+兩個路徑操作都需要一個 `X-Token` 標頭(header)。
+
+{* ../../docs_src/app_testing/app_b_an_py310/main.py *}
+
+### 擴充的測試檔案 { #extended-testing-file }
+
+接著你可以把 `test_main.py` 更新為擴充後的測試:
+
+{* ../../docs_src/app_testing/app_b_an_py310/test_main.py *}
+
+
+每當你需要在請求中讓 client 帶一些資料,但不確定該怎麼做時,你可以搜尋(Google)在 `httpx` 要如何傳遞,甚至用 Requests 怎麼做,因為 HTTPX 的設計是基於 Requests。
+
+然後在你的測試中做一樣的事即可。
+
+例如:
+
+* 要傳遞路徑或查詢參數,直接把它加在 URL 上。
+* 要傳遞 JSON 本文,將 Python 物件(例如 `dict`)傳給 `json` 參數。
+* 如果需要送出表單資料(Form Data)而不是 JSON,改用 `data` 參數。
+* 要傳遞標頭(headers),在 `headers` 參數中放一個 `dict`。
+* 對於 Cookie(cookies),在 `cookies` 參數中放一個 `dict`。
+
+關於如何把資料傳給後端(使用 `httpx` 或 `TestClient`),更多資訊請參考 HTTPX 文件。
+
+/// info
+
+請注意,`TestClient` 接收的是可轉為 JSON 的資料,而不是 Pydantic models。
+
+如果你的測試裡有一個 Pydantic model,並想在測試時把它的資料送給應用,你可以使用[JSON 相容編碼器](encoder.md){.internal-link target=_blank}中介紹的 `jsonable_encoder`。
+
+///
+
+## 執行 { #run-it }
+
+接下來,你只需要安裝 `pytest`。
+
+請先建立並啟用一個[虛擬環境](../virtual-environments.md){.internal-link target=_blank},然後安裝,例如:
+
+
+
+```console
+$ pip install pytest
+
+---> 100%
+```
+
+
+
+它會自動偵測檔案與測試、執行它們,並把結果回報給你。
+
+用以下指令執行測試:
+
+
+
+```console
+$ pytest
+
+================ test session starts ================
+platform linux -- Python 3.6.9, pytest-5.3.5, py-1.8.1, pluggy-0.13.1
+rootdir: /home/user/code/superawesome-cli/app
+plugins: forked-1.1.3, xdist-1.31.0, cov-2.8.1
+collected 6 items
+
+---> 100%
+
+test_main.py ...... [100%]
+
+================= 1 passed in 0.03s =================
+```
+
+
diff --git a/docs/zh-hant/docs/virtual-environments.md b/docs/zh-hant/docs/virtual-environments.md
index acd1d914ea..74b8b9f8c8 100644
--- a/docs/zh-hant/docs/virtual-environments.md
+++ b/docs/zh-hant/docs/virtual-environments.md
@@ -30,7 +30,7 @@
首先,為你的專案建立一個目錄。
-我(指原作者 —— 譯者注)通常會在我的主目錄下建立一個名為 `code` 的目錄。
+我通常會在我的主目錄下建立一個名為 `code` 的目錄。
在這個目錄下,我再為每個專案建立一個目錄。
@@ -53,7 +53,7 @@ $ cd awesome-project
## 建立一個虛擬環境 { #create-a-virtual-environment }
-在開始一個 Python 專案的**第一時間**,**在你的專案內部**建立一個虛擬環境。
+在開始一個 Python 專案的**第一時間**,**在你的專案內部**建立一個虛擬環境。
/// tip
@@ -412,7 +412,7 @@ Hello World
## 設定編輯器 { #configure-your-editor }
-你可能會用到編輯器,請確保設定它使用你建立的相同虛擬環境(它可能會自動偵測到),以便你可以獲得自動完成和内嵌錯誤提示。
+你可能會用到編輯器,請確保設定它使用你建立的相同虛擬環境(它可能會自動偵測到),以便你可以獲得自動完成和內嵌錯誤提示。
例如:
diff --git a/docs/zh/docs/_llm-test.md b/docs/zh/docs/_llm-test.md
new file mode 100644
index 0000000000..05c512e99b
--- /dev/null
+++ b/docs/zh/docs/_llm-test.md
@@ -0,0 +1,755 @@
+# LLM 测试文件 { #llm-test-file }
+
+本文用于测试用于翻译文档的 LLM 是否理解 `scripts/translate.py` 中的 `general_prompt` 以及 `docs/{language code}/llm-prompt.md` 中的语言特定提示。语言特定提示会追加到 `general_prompt` 之后。
+
+这里添加的测试会被所有语言特定提示的设计者看到。
+
+用法如下:
+
+* 准备语言特定提示——`docs/{language code}/llm-prompt.md`。
+* 将本文重新翻译为你的目标语言(例如使用 `translate.py` 的 `translate-page` 命令)。这会在 `docs/{language code}/docs/_llm-test.md` 下创建翻译。
+* 检查翻译是否正确。
+* 如有需要,改进你的语言特定提示、通用提示,或英文文档。
+* 然后手动修正翻译中剩余的问题,确保这是一个优秀的译文。
+* 重新翻译,在已有的优秀译文基础上进行。理想情况是 LLM 不再对译文做任何更改。这意味着通用提示和你的语言特定提示已经尽可能完善(有时它仍会做一些看似随机的改动,原因是LLM 不是确定性算法)。
+
+测试如下:
+
+## 代码片段 { #code-snippets }
+
+//// tab | 测试
+
+这是一个代码片段:`foo`。这是另一个代码片段:`bar`。还有一个:`baz quux`。
+
+////
+
+//// tab | 信息
+
+代码片段的内容应保持不变。
+
+参见 `scripts/translate.py` 中通用提示的 `### Content of code snippets` 部分。
+
+////
+
+## 引号 { #quotes }
+
+//// tab | 测试
+
+昨天,我的朋友写道:"如果你把 incorrectly 拼对了,你就把它拼错了"。我回答:"没错,但 'incorrectly' 错的不是 '"incorrectly"'"。
+
+/// note | 注意
+
+LLM 很可能会把这段翻错。我们只关心在重新翻译时它是否能保持修正后的译文。
+
+///
+
+////
+
+//// tab | 信息
+
+提示词设计者可以选择是否将中性引号转换为排版引号。也可以保持不变。
+
+例如参见 `docs/de/llm-prompt.md` 中的 `### Quotes` 部分。
+
+////
+
+## 代码片段中的引号 { #quotes-in-code-snippets }
+
+//// tab | 测试
+
+`pip install "foo[bar]"`
+
+代码片段中的字符串字面量示例:`"this"`,`'that'`。
+
+一个较难的字符串字面量示例:`f"I like {'oranges' if orange else "apples"}"`
+
+硬核:`Yesterday, my friend wrote: "If you spell incorrectly correctly, you have spelled it incorrectly". To which I answered: "Correct, but 'incorrectly' is incorrectly not '"incorrectly"'"`
+
+////
+
+//// tab | 信息
+
+... 但是,代码片段内的引号必须保持不变。
+
+////
+
+## 代码块 { #code-blocks }
+
+//// tab | 测试
+
+一个 Bash 代码示例...
+
+```bash
+# 向宇宙打印问候
+echo "Hello universe"
+```
+
+...以及一个控制台代码示例...
+
+```console
+$ fastapi run main.py
+ FastAPI Starting server
+ Searching for package file structure
+```
+
+...以及另一个控制台代码示例...
+
+```console
+// 创建目录 "code"
+$ mkdir code
+// 切换到该目录
+$ cd code
+```
+
+...以及一个 Python 代码示例...
+
+```Python
+wont_work() # 这不会起作用 😱
+works(foo="bar") # 这可行 🎉
+```
+
+...就这些。
+
+////
+
+//// tab | 信息
+
+代码块中的代码不应被修改,注释除外。
+
+参见 `scripts/translate.py` 中通用提示的 `### Content of code blocks` 部分。
+
+////
+
+## 选项卡与彩色提示框 { #tabs-and-colored-boxes }
+
+//// tab | 测试
+
+/// info | 信息
+Some text
+///
+
+/// note | 注意
+Some text
+///
+
+/// note | 技术细节
+Some text
+///
+
+/// check | 检查
+Some text
+///
+
+/// tip | 提示
+Some text
+///
+
+/// warning | 警告
+Some text
+///
+
+/// danger | 危险
+Some text
+///
+
+////
+
+//// tab | 信息
+
+选项卡以及 `Info`/`Note`/`Warning`/等提示块,应在竖线(`|`)后添加其标题的翻译。
+
+参见 `scripts/translate.py` 中通用提示的 `### Special blocks` 与 `### Tab blocks` 部分。
+
+////
+
+## Web 与内部链接 { #web-and-internal-links }
+
+//// tab | 测试
+
+链接文本应被翻译,链接地址应保持不变:
+
+* [链接到上面的标题](#code-snippets)
+* [内部链接](index.md#installation){.internal-link target=_blank}
+* 外部链接
+* 样式链接
+* 脚本链接
+* 图片链接
+
+链接文本应被翻译,且链接地址应指向对应的译文页面:
+
+* FastAPI 链接
+
+////
+
+//// tab | 信息
+
+链接的文本应被翻译,但地址保持不变。唯一的例外是指向 FastAPI 文档页面的绝对链接,此时应指向对应语言的译文。
+
+参见 `scripts/translate.py` 中通用提示的 `### Links` 部分。
+
+////
+
+## HTML "abbr" 元素 { #html-abbr-elements }
+
+//// tab | 测试
+
+这里有一些包裹在 HTML "abbr" 元素中的内容(有些是虚构的):
+
+### abbr 提供了完整短语 { #the-abbr-gives-a-full-phrase }
+
+* GTD
+* lt
+* XWT
+* PSGI
+
+### abbr 提供了完整短语与解释 { #the-abbr-gives-a-full-phrase-and-an-explanation }
+
+* MDN
+* I/O.
+
+////
+
+//// tab | 信息
+
+"abbr" 元素的 "title" 属性需要按照特定规则进行翻译。
+
+译文可以自行添加 "abbr" 元素以解释英语单词,LLM 不应删除这些元素。
+
+参见 `scripts/translate.py` 中通用提示的 `### HTML abbr elements` 部分。
+
+////
+
+## HTML "dfn" 元素 { #html-dfn-elements }
+
+* 集群
+* 深度学习
+
+## 标题 { #headings }
+
+//// tab | 测试
+
+### 开发 Web 应用——教程 { #develop-a-webapp-a-tutorial }
+
+Hello.
+
+### 类型提示与注解 { #type-hints-and-annotations }
+
+Hello again.
+
+### 超类与子类 { #super-and-subclasses }
+
+Hello again.
+
+////
+
+//// tab | 信息
+
+关于标题的唯一硬性规则是:LLM 必须保持花括号内的哈希部分不变,以确保链接不会失效。
+
+参见 `scripts/translate.py` 中通用提示的 `### Headings` 部分。
+
+语言特定的说明可参见例如 `docs/de/llm-prompt.md` 中的 `### Headings` 部分。
+
+////
+
+## 文档中使用的术语 { #terms-used-in-the-docs }
+
+//// tab | 测试
+
+* you
+* your
+
+* e.g.
+* etc.
+
+* `foo` as an `int`
+* `bar` as a `str`
+* `baz` as a `list`
+
+* the Tutorial - User guide
+* the Advanced User Guide
+* the SQLModel docs
+* the API docs
+* the automatic docs
+
+* Data Science
+* Deep Learning
+* Machine Learning
+* Dependency Injection
+* HTTP Basic authentication
+* HTTP Digest
+* ISO format
+* the JSON Schema standard
+* the JSON schema
+* the schema definition
+* Password Flow
+* Mobile
+
+* deprecated
+* designed
+* invalid
+* on the fly
+* standard
+* default
+* case-sensitive
+* case-insensitive
+
+* to serve the application
+* to serve the page
+
+* the app
+* the application
+
+* the request
+* the response
+* the error response
+
+* the path operation
+* the path operation decorator
+* the path operation function
+
+* the body
+* the request body
+* the response body
+* the JSON body
+* the form body
+* the file body
+* the function body
+
+* the parameter
+* the body parameter
+* the path parameter
+* the query parameter
+* the cookie parameter
+* the header parameter
+* the form parameter
+* the function parameter
+
+* the event
+* the startup event
+* the startup of the server
+* the shutdown event
+* the lifespan event
+
+* the handler
+* the event handler
+* the exception handler
+* to handle
+
+* the model
+* the Pydantic model
+* the data model
+* the database model
+* the form model
+* the model object
+
+* the class
+* the base class
+* the parent class
+* the subclass
+* the child class
+* the sibling class
+* the class method
+
+* the header
+* the headers
+* the authorization header
+* the `Authorization` header
+* the forwarded header
+
+* the dependency injection system
+* the dependency
+* the dependable
+* the dependant
+
+* I/O bound
+* CPU bound
+* concurrency
+* parallelism
+* multiprocessing
+
+* the env var
+* the environment variable
+* the `PATH`
+* the `PATH` variable
+
+* the authentication
+* the authentication provider
+* the authorization
+* the authorization form
+* the authorization provider
+* the user authenticates
+* the system authenticates the user
+
+* the CLI
+* the command line interface
+
+* the server
+* the client
+
+* the cloud provider
+* the cloud service
+
+* the development
+* the development stages
+
+* the dict
+* the dictionary
+* the enumeration
+* the enum
+* the enum member
+
+* the encoder
+* the decoder
+* to encode
+* to decode
+
+* the exception
+* to raise
+
+* the expression
+* the statement
+
+* the frontend
+* the backend
+
+* the GitHub discussion
+* the GitHub issue
+
+* the performance
+* the performance optimization
+
+* the return type
+* the return value
+
+* the security
+* the security scheme
+
+* the task
+* the background task
+* the task function
+
+* the template
+* the template engine
+
+* the type annotation
+* the type hint
+
+* the server worker
+* the Uvicorn worker
+* the Gunicorn Worker
+* the worker process
+* the worker class
+* the workload
+
+* the deployment
+* to deploy
+
+* the SDK
+* the software development kit
+
+* the `APIRouter`
+* the `requirements.txt`
+* the Bearer Token
+* the breaking change
+* the bug
+* the button
+* the callable
+* the code
+* the commit
+* the context manager
+* the coroutine
+* the database session
+* the disk
+* the domain
+* the engine
+* the fake X
+* the HTTP GET method
+* the item
+* the library
+* the lifespan
+* the lock
+* the middleware
+* the mobile application
+* the module
+* the mounting
+* the network
+* the origin
+* the override
+* the payload
+* the processor
+* the property
+* the proxy
+* the pull request
+* the query
+* the RAM
+* the remote machine
+* the status code
+* the string
+* the tag
+* the web framework
+* the wildcard
+* to return
+* to validate
+
+////
+
+//// tab | 信息
+
+这是一份不完整且非规范性的(主要是)技术术语清单,取自文档中常见的词汇。它可能有助于提示词设计者判断哪些术语需要对 LLM 提供额外指引。例如当它总是把一个好的译法改回次优译法,或在你的语言中对某个术语的词形变化有困难时。
+
+参见例如 `docs/de/llm-prompt.md` 中的 `### List of English terms and their preferred German translations` 部分。
+
+////
+
+////
+
+翻译(术语)对照:
+
+//// tab | 测试(译文)
+
+* 你
+* 你的
+
+* 例如
+* 等等
+
+* 将 `foo` 作为 `int`
+* 将 `bar` 作为 `str`
+* 将 `baz` 作为 `list`
+
+* 教程 - 用户指南
+* 高级用户指南
+* SQLModel 文档
+* API 文档
+* 自动文档
+
+* 数据科学
+* 深度学习
+* 机器学习
+* 依赖注入
+* HTTP 基本认证
+* HTTP 摘要认证
+* ISO 格式
+* JSON Schema 标准
+* JSON 模式
+* 模式定义
+* 密码流
+* 移动端
+
+* 已弃用
+* 设计的
+* 无效
+* 即时
+* 标准的
+* 默认的
+* 区分大小写
+* 不区分大小写
+
+* 为应用提供服务
+* 为页面提供服务
+
+* 应用
+* 应用程序
+
+* 请求
+* 响应
+* 错误响应
+
+* 路径操作
+* 路径操作装饰器
+* 路径操作函数
+
+* 主体
+* 请求体
+* 响应体
+* JSON 体
+* 表单体
+* 文件体
+* 函数体
+
+* 参数
+* 请求体参数
+* 路径参数
+* 查询参数
+* Cookie 参数
+* Header 参数
+* 表单参数
+* 函数参数
+
+* 事件
+* 启动事件
+* 服务器的启动
+* 关闭事件
+* 生命周期事件
+
+* 处理器
+* 事件处理器
+* 异常处理器
+* 处理
+
+* 模型
+* Pydantic 模型
+* 数据模型
+* 数据库模型
+* 表单模型
+* 模型对象
+
+* 类
+* 基类
+* 父类
+* 子类
+* 子类
+* 兄弟类
+* 类方法
+
+* 请求头
+* 请求头
+* 授权头
+* `Authorization` 头
+* 转发头
+
+* 依赖注入系统
+* 依赖
+* 可依赖对象
+* 依赖项
+
+* I/O 受限
+* CPU 受限
+* 并发
+* 并行
+* 多进程
+
+* 环境变量
+* 环境变量
+* `PATH`
+* `PATH` 变量
+
+* 认证
+* 认证提供方
+* 授权
+* 授权表单
+* 授权提供方
+* 用户进行认证
+* 系统对用户进行认证
+
+* CLI
+* 命令行界面
+
+* 服务器
+* 客户端
+
+* 云服务提供商
+* 云服务
+
+* 开发
+* 开发阶段
+
+* dict
+* 字典
+* 枚举
+* 枚举
+* 枚举成员
+
+* 编码器
+* 解码器
+* 编码
+* 解码
+
+* 异常
+* 抛出
+
+* 表达式
+* 语句
+
+* 前端
+* 后端
+
+* GitHub 讨论
+* GitHub Issue
+
+* 性能
+* 性能优化
+
+* 返回类型
+* 返回值
+
+* 安全
+* 安全方案
+
+* 任务
+* 后台任务
+* 任务函数
+
+* 模板
+* 模板引擎
+
+* 类型注解
+* 类型提示
+
+* 服务器 worker
+* Uvicorn worker
+* Gunicorn worker
+* worker 进程
+* worker 类
+* 工作负载
+
+* 部署
+* 部署
+
+* SDK
+* 软件开发工具包
+
+* `APIRouter`
+* `requirements.txt`
+* Bearer Token
+* 破坏性变更
+* Bug
+* 按钮
+* 可调用对象
+* 代码
+* 提交
+* 上下文管理器
+* 协程
+* 数据库会话
+* 磁盘
+* 域名
+* 引擎
+* 假 X
+* HTTP GET 方法
+* 项
+* 库
+* 生命周期
+* 锁
+* 中间件
+* 移动应用
+* 模块
+* 挂载
+* 网络
+* 源
+* 覆盖
+* 负载
+* 处理器
+* 属性
+* 代理
+* Pull Request
+* 查询
+* RAM
+* 远程机器
+* 状态码
+* 字符串
+* 标签
+* Web 框架
+* 通配符
+* 返回
+* 校验
+
+////
+
+//// tab | 信息(译文)
+
+此清单是不完整且非规范性的,列出(主要是)文档中出现的技术术语。它有助于提示词设计者确定哪些术语需要额外的指引。例如当 LLM 总是把更好的译法改回次优译法,或在你的语言中难以正确变形时。
+
+也可参见 `docs/de/llm-prompt.md` 中的 `### List of English terms and their preferred German translations` 部分。
+
+////
diff --git a/docs/zh/docs/about/index.md b/docs/zh/docs/about/index.md
new file mode 100644
index 0000000000..9b73533f7f
--- /dev/null
+++ b/docs/zh/docs/about/index.md
@@ -0,0 +1,3 @@
+# 关于 { #about }
+
+关于 FastAPI、其设计、灵感等。🤓
diff --git a/docs/zh/docs/advanced/additional-responses.md b/docs/zh/docs/advanced/additional-responses.md
index bc197280ab..aa3d22d1c7 100644
--- a/docs/zh/docs/advanced/additional-responses.md
+++ b/docs/zh/docs/advanced/additional-responses.md
@@ -26,7 +26,7 @@
例如,要声明另一个状态码为 `404` 且具有 Pydantic 模型 `Message` 的响应,你可以这样写:
-{* ../../docs_src/additional_responses/tutorial001_py39.py hl[18,22] *}
+{* ../../docs_src/additional_responses/tutorial001_py310.py hl[18,22] *}
/// note | 注意
@@ -203,7 +203,7 @@
以及一个状态码为 `200` 的响应,它使用你的 `response_model`,但包含自定义的 `example`:
-{* ../../docs_src/additional_responses/tutorial003_py39.py hl[20:31] *}
+{* ../../docs_src/additional_responses/tutorial003_py310.py hl[20:31] *}
所有这些都会被合并并包含到你的 OpenAPI 中,并显示在 API 文档里:
diff --git a/docs/zh/docs/advanced/additional-status-codes.md b/docs/zh/docs/advanced/additional-status-codes.md
index 23ceab4e87..7eeffaf532 100644
--- a/docs/zh/docs/advanced/additional-status-codes.md
+++ b/docs/zh/docs/advanced/additional-status-codes.md
@@ -16,7 +16,7 @@
{* ../../docs_src/additional_status_codes/tutorial001_an_py310.py hl[4,25] *}
-/// warning
+/// warning | 警告
当你直接返回一个像上面例子中的 `Response` 对象时,它会直接返回。
@@ -26,7 +26,7 @@
///
-/// note | 技术细节
+/// note | 注意
你也可以使用 `from starlette.responses import JSONResponse`。
diff --git a/docs/zh/docs/advanced/advanced-dependencies.md b/docs/zh/docs/advanced/advanced-dependencies.md
index 3efca89442..a547e88814 100644
--- a/docs/zh/docs/advanced/advanced-dependencies.md
+++ b/docs/zh/docs/advanced/advanced-dependencies.md
@@ -18,7 +18,7 @@
为此,声明一个 `__call__` 方法:
-{* ../../docs_src/dependencies/tutorial011_an_py39.py hl[12] *}
+{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[12] *}
在这种情况下,**FastAPI** 会使用这个 `__call__` 来检查附加参数和子依赖,并且稍后会调用它,把返回值传递给你的*路径操作函数*中的参数。
@@ -26,7 +26,7 @@
现在,我们可以用 `__init__` 声明实例的参数,用来“参数化”这个依赖项:
-{* ../../docs_src/dependencies/tutorial011_an_py39.py hl[9] *}
+{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[9] *}
在本例中,**FastAPI** 不会接触或关心 `__init__`,我们会在自己的代码中直接使用它。
@@ -34,7 +34,7 @@
我们可以这样创建该类的实例:
-{* ../../docs_src/dependencies/tutorial011_an_py39.py hl[18] *}
+{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[18] *}
这样就把依赖项“参数化”了,现在它内部带有属性 `checker.fixed_content` 的值 `"bar"`。
@@ -50,7 +50,7 @@ checker(q="somequery")
...并将其返回值作为依赖项的值,传给我们的*路径操作函数*中的参数 `fixed_content_included`:
-{* ../../docs_src/dependencies/tutorial011_an_py39.py hl[22] *}
+{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[22] *}
/// tip | 提示
diff --git a/docs/zh/docs/advanced/advanced-python-types.md b/docs/zh/docs/advanced/advanced-python-types.md
new file mode 100644
index 0000000000..bbc9302e86
--- /dev/null
+++ b/docs/zh/docs/advanced/advanced-python-types.md
@@ -0,0 +1,61 @@
+# 高级 Python 类型 { #advanced-python-types }
+
+这里有一些在使用 Python 类型时可能有用的额外想法。
+
+## 使用 `Union` 或 `Optional` { #using-union-or-optional }
+
+如果你的代码因为某些原因不能使用 `|`,例如它不是在类型注解里,而是在 `response_model=` 之类的参数中,那么你可以使用 `typing` 中的 `Union` 来代替竖线(`|`)。
+
+例如,你可以声明某个值可以是 `str` 或 `None`:
+
+```python
+from typing import Union
+
+
+def say_hi(name: Union[str, None]):
+ print(f"Hi {name}!")
+```
+
+`typing` 也提供了一个声明“可能为 `None`”的快捷方式:`Optional`。
+
+从我非常主观的角度给个小建议:
+
+- 🚨 避免使用 `Optional[SomeType]`
+- 改用 ✨`Union[SomeType, None]`✨。
+
+两者是等价的,底层其实也是一样的。但我更推荐使用 `Union` 而不是 `Optional`,因为单词“optional”(可选)看起来会暗示该值是可选的,而它真正的含义是“它可以是 `None`”,即使它并不是可选的,仍然是必填的。
+
+我认为 `Union[SomeType, None]` 更能明确表达其含义。
+
+这只是关于词语和命名的问题,但这些词语会影响你和你的队友如何看待代码。
+
+举个例子,看这段函数:
+
+```python
+from typing import Optional
+
+
+def say_hi(name: Optional[str]):
+ print(f"Hey {name}!")
+```
+
+参数 `name` 被定义为 `Optional[str]`,但它并不是“可选”的,你不能不传这个参数就调用函数:
+
+```Python
+say_hi() # 哎呀,这会报错!😱
+```
+
+参数 `name` 仍然是必填的(不是“可选”),因为它没有默认值。不过,`name` 接受 `None` 作为取值:
+
+```Python
+say_hi(name=None) # 这样可以,None 是有效的 🎉
+```
+
+好消息是,在大多数情况下,你可以直接使用 `|` 来定义类型联合:
+
+```python
+def say_hi(name: str | None):
+ print(f"Hey {name}!")
+```
+
+因此,通常你不必为像 `Optional` 和 `Union` 这样的名字而操心。😎
diff --git a/docs/zh/docs/advanced/async-tests.md b/docs/zh/docs/advanced/async-tests.md
index 6803358d25..16b8a8c813 100644
--- a/docs/zh/docs/advanced/async-tests.md
+++ b/docs/zh/docs/advanced/async-tests.md
@@ -32,11 +32,11 @@
文件 `main.py` 将包含:
-{* ../../docs_src/async_tests/app_a_py39/main.py *}
+{* ../../docs_src/async_tests/app_a_py310/main.py *}
文件 `test_main.py` 将包含针对 `main.py` 的测试,现在它可能看起来如下:
-{* ../../docs_src/async_tests/app_a_py39/test_main.py *}
+{* ../../docs_src/async_tests/app_a_py310/test_main.py *}
## 运行测试 { #run-it }
@@ -56,7 +56,7 @@ $ pytest
这个标记 `@pytest.mark.anyio` 会告诉 pytest 该测试函数应该被异步调用:
-{* ../../docs_src/async_tests/app_a_py39/test_main.py hl[7] *}
+{* ../../docs_src/async_tests/app_a_py310/test_main.py hl[7] *}
/// tip | 提示
@@ -66,7 +66,7 @@ $ pytest
我们现在可以使用应用程序创建一个 `AsyncClient` ,并使用 `await` 向其发送异步请求。
-{* ../../docs_src/async_tests/app_a_py39/test_main.py hl[9:12] *}
+{* ../../docs_src/async_tests/app_a_py310/test_main.py hl[9:12] *}
这相当于:
@@ -74,7 +74,7 @@ $ pytest
response = client.get('/')
```
-我们曾经通过它向 `TestClient` 发出请求。
+...我们曾经通过它向 `TestClient` 发出请求。
/// tip | 提示
diff --git a/docs/zh/docs/advanced/behind-a-proxy.md b/docs/zh/docs/advanced/behind-a-proxy.md
index b44b0b5ac5..3ccc65f292 100644
--- a/docs/zh/docs/advanced/behind-a-proxy.md
+++ b/docs/zh/docs/advanced/behind-a-proxy.md
@@ -44,7 +44,7 @@ $ fastapi run --forwarded-allow-ips="*"
例如,假设你定义了一个*路径操作* `/items/`:
-{* ../../docs_src/behind_a_proxy/tutorial001_01_py39.py hl[6] *}
+{* ../../docs_src/behind_a_proxy/tutorial001_01_py310.py hl[6] *}
如果客户端尝试访问 `/items`,默认会被重定向到 `/items/`。
@@ -115,7 +115,7 @@ sequenceDiagram
即使你的所有代码都假设只有 `/app`。
-{* ../../docs_src/behind_a_proxy/tutorial001_py39.py hl[6] *}
+{* ../../docs_src/behind_a_proxy/tutorial001_py310.py hl[6] *}
代理会在将请求传递给应用服务器(可能是通过 FastAPI CLI 运行的 Uvicorn)之前,实时**“移除”**这个**路径前缀**,让你的应用认为它是在 `/app` 被服务,这样你就不需要更新所有代码去包含 `/api/v1` 前缀。
@@ -193,7 +193,7 @@ ASGI 规范为这种用例定义了 `root_path`。
这里我们把它包含在响应消息中仅用于演示。
-{* ../../docs_src/behind_a_proxy/tutorial001_py39.py hl[8] *}
+{* ../../docs_src/behind_a_proxy/tutorial001_py310.py hl[8] *}
然后,如果你这样启动 Uvicorn:
@@ -220,7 +220,7 @@ $ fastapi run main.py --forwarded-allow-ips="*" --root-path /api/v1
或者,如果你无法提供类似 `--root-path` 的命令行选项,你可以在创建 FastAPI 应用时设置参数 `root_path`:
-{* ../../docs_src/behind_a_proxy/tutorial002_py39.py hl[3] *}
+{* ../../docs_src/behind_a_proxy/tutorial002_py310.py hl[3] *}
把 `root_path` 传给 `FastAPI` 等同于把命令行选项 `--root-path` 传给 Uvicorn 或 Hypercorn。
@@ -400,7 +400,7 @@ $ fastapi run main.py --forwarded-allow-ips="*" --root-path /api/v1
例如:
-{* ../../docs_src/behind_a_proxy/tutorial003_py39.py hl[4:7] *}
+{* ../../docs_src/behind_a_proxy/tutorial003_py310.py hl[4:7] *}
会生成如下的 OpenAPI 模式:
@@ -455,7 +455,7 @@ OpenAPI 规范中的 `servers` 属性是可选的。
如果你不希望 **FastAPI** 包含一个使用 `root_path` 的自动服务器,可以使用参数 `root_path_in_servers=False`:
-{* ../../docs_src/behind_a_proxy/tutorial004_py39.py hl[9] *}
+{* ../../docs_src/behind_a_proxy/tutorial004_py310.py hl[9] *}
这样它就不会被包含到 OpenAPI 模式中。
diff --git a/docs/zh/docs/advanced/custom-response.md b/docs/zh/docs/advanced/custom-response.md
index f5bec5fdcf..7c19b73fbc 100644
--- a/docs/zh/docs/advanced/custom-response.md
+++ b/docs/zh/docs/advanced/custom-response.md
@@ -30,7 +30,7 @@
但如果你确定你返回的内容是「可以用 JSON 序列化」的,你可以将它直接传给响应类,从而避免在传给响应类之前先通过 `jsonable_encoder` 带来的额外开销。
-{* ../../docs_src/custom_response/tutorial001b_py39.py hl[2,7] *}
+{* ../../docs_src/custom_response/tutorial001b_py310.py hl[2,7] *}
/// info | 信息
@@ -55,7 +55,7 @@
* 导入 `HTMLResponse`。
* 将 `HTMLResponse` 作为你的 *路径操作* 的 `response_class` 参数传入。
-{* ../../docs_src/custom_response/tutorial002_py39.py hl[2,7] *}
+{* ../../docs_src/custom_response/tutorial002_py310.py hl[2,7] *}
/// info | 信息
@@ -73,7 +73,7 @@
和上面一样的例子,返回一个 `HTMLResponse` 看起来可能是这样:
-{* ../../docs_src/custom_response/tutorial003_py39.py hl[2,7,19] *}
+{* ../../docs_src/custom_response/tutorial003_py310.py hl[2,7,19] *}
/// warning | 警告
@@ -97,7 +97,7 @@
比如像这样:
-{* ../../docs_src/custom_response/tutorial004_py39.py hl[7,21,23] *}
+{* ../../docs_src/custom_response/tutorial004_py310.py hl[7,21,23] *}
在这个例子中,函数 `generate_html_response()` 已经生成并返回 `Response` 对象而不是在 `str` 中返回 HTML。
@@ -136,7 +136,7 @@
FastAPI(实际上是 Starlette)将自动包含 Content-Length 的头。它还将包含一个基于 `media_type` 的 Content-Type 头,并为文本类型附加一个字符集。
-{* ../../docs_src/response_directly/tutorial002_py39.py hl[1,18] *}
+{* ../../docs_src/response_directly/tutorial002_py310.py hl[1,18] *}
### `HTMLResponse` { #htmlresponse }
@@ -146,7 +146,7 @@ FastAPI(实际上是 Starlette)将自动包含 Content-Length 的头。它
接受文本或字节并返回纯文本响应。
-{* ../../docs_src/custom_response/tutorial005_py39.py hl[2,7,9] *}
+{* ../../docs_src/custom_response/tutorial005_py310.py hl[2,7,9] *}
### `JSONResponse` { #jsonresponse }
@@ -180,7 +180,7 @@ FastAPI(实际上是 Starlette)将自动包含 Content-Length 的头。它
///
-{* ../../docs_src/custom_response/tutorial001_py39.py hl[2,7] *}
+{* ../../docs_src/custom_response/tutorial001_py310.py hl[2,7] *}
/// tip | 提示
@@ -194,13 +194,13 @@ FastAPI(实际上是 Starlette)将自动包含 Content-Length 的头。它
你可以直接返回一个 `RedirectResponse`:
-{* ../../docs_src/custom_response/tutorial006_py39.py hl[2,9] *}
+{* ../../docs_src/custom_response/tutorial006_py310.py hl[2,9] *}
---
或者你可以把它用于 `response_class` 参数:
-{* ../../docs_src/custom_response/tutorial006b_py39.py hl[2,7,9] *}
+{* ../../docs_src/custom_response/tutorial006b_py310.py hl[2,7,9] *}
如果你这么做,那么你可以在 *路径操作* 函数中直接返回 URL。
@@ -210,13 +210,13 @@ FastAPI(实际上是 Starlette)将自动包含 Content-Length 的头。它
你也可以将 `status_code` 参数和 `response_class` 参数结合使用:
-{* ../../docs_src/custom_response/tutorial006c_py39.py hl[2,7,9] *}
+{* ../../docs_src/custom_response/tutorial006c_py310.py hl[2,7,9] *}
### `StreamingResponse` { #streamingresponse }
采用异步生成器或普通生成器/迭代器,然后流式传输响应主体。
-{* ../../docs_src/custom_response/tutorial007_py39.py hl[2,14] *}
+{* ../../docs_src/custom_response/tutorial007_py310.py hl[2,14] *}
#### 对类似文件的对象使用 `StreamingResponse` { #using-streamingresponse-with-file-like-objects }
@@ -226,7 +226,7 @@ FastAPI(实际上是 Starlette)将自动包含 Content-Length 的头。它
这也包括许多与云存储、视频处理等交互的库。
-{* ../../docs_src/custom_response/tutorial008_py39.py hl[2,10:12,14] *}
+{* ../../docs_src/custom_response/tutorial008_py310.py hl[2,10:12,14] *}
1. 这是生成器函数。之所以是「生成器函数」,是因为它内部包含 `yield` 语句。
2. 通过使用 `with` 代码块,我们可以确保在生成器函数完成后关闭类文件对象。因此,在它完成发送响应之后会被关闭。
@@ -255,11 +255,11 @@ FastAPI(实际上是 Starlette)将自动包含 Content-Length 的头。它
文件响应将包含适当的 `Content-Length`、`Last-Modified` 和 `ETag` 响应头。
-{* ../../docs_src/custom_response/tutorial009_py39.py hl[2,10] *}
+{* ../../docs_src/custom_response/tutorial009_py310.py hl[2,10] *}
你也可以使用 `response_class` 参数:
-{* ../../docs_src/custom_response/tutorial009b_py39.py hl[2,8,10] *}
+{* ../../docs_src/custom_response/tutorial009b_py310.py hl[2,8,10] *}
在这种情况下,你可以在 *路径操作* 函数中直接返回文件路径。
@@ -273,7 +273,7 @@ FastAPI(实际上是 Starlette)将自动包含 Content-Length 的头。它
你可以创建一个 `CustomORJSONResponse`。你需要做的主要事情是实现一个返回 `bytes` 的 `Response.render(content)` 方法:
-{* ../../docs_src/custom_response/tutorial009c_py39.py hl[9:14,17] *}
+{* ../../docs_src/custom_response/tutorial009c_py310.py hl[9:14,17] *}
现在,不再是返回:
@@ -281,7 +281,7 @@ FastAPI(实际上是 Starlette)将自动包含 Content-Length 的头。它
{"message": "Hello World"}
```
-…这个响应将返回:
+...这个响应将返回:
```json
{
@@ -299,7 +299,7 @@ FastAPI(实际上是 Starlette)将自动包含 Content-Length 的头。它
在下面的示例中,**FastAPI** 会在所有 *路径操作* 中默认使用 `ORJSONResponse`,而不是 `JSONResponse`。
-{* ../../docs_src/custom_response/tutorial010_py39.py hl[2,4] *}
+{* ../../docs_src/custom_response/tutorial010_py310.py hl[2,4] *}
/// tip | 提示
diff --git a/docs/zh/docs/advanced/dataclasses.md b/docs/zh/docs/advanced/dataclasses.md
index d62aef8f39..f552d779fb 100644
--- a/docs/zh/docs/advanced/dataclasses.md
+++ b/docs/zh/docs/advanced/dataclasses.md
@@ -59,7 +59,7 @@ FastAPI 基于 **Pydantic** 构建,我已经向你展示过如何使用 Pydant
在本例中,它是一个 `Item` 数据类列表。
6. 这里我们返回一个字典,里面的 `items` 是一个数据类列表。
- FastAPI 仍然能够将数据序列化为 JSON。
+ FastAPI 仍然能够将数据序列化为 JSON。
7. 这里的 `response_model` 使用了 “`Author` 数据类列表” 的类型注解。
同样,你可以将 `dataclasses` 与标准类型注解组合使用。
diff --git a/docs/zh/docs/advanced/events.md b/docs/zh/docs/advanced/events.md
index 7b49931a4c..71ad1ae383 100644
--- a/docs/zh/docs/advanced/events.md
+++ b/docs/zh/docs/advanced/events.md
@@ -30,7 +30,7 @@
我们使用 `yield` 创建了一个异步函数 `lifespan()` 像这样:
-{* ../../docs_src/events/tutorial003_py39.py hl[16,19] *}
+{* ../../docs_src/events/tutorial003_py310.py hl[16,19] *}
在这里,我们在 `yield` 之前将(虚拟的)模型函数放入机器学习模型的字典中,以此模拟加载模型的耗时**启动**操作。这段代码将在应用程序**开始处理请求之前**执行,即**启动**期间。
@@ -48,7 +48,7 @@
首先要注意的是,我们定义了一个带有 `yield` 的异步函数。这与带有 `yield` 的依赖项非常相似。
-{* ../../docs_src/events/tutorial003_py39.py hl[14:19] *}
+{* ../../docs_src/events/tutorial003_py310.py hl[14:19] *}
这个函数在 `yield` 之前的部分,会在应用启动前执行。
@@ -60,7 +60,7 @@
它将函数转化为所谓的“**异步上下文管理器**”。
-{* ../../docs_src/events/tutorial003_py39.py hl[1,13] *}
+{* ../../docs_src/events/tutorial003_py310.py hl[1,13] *}
在 Python 中,**上下文管理器**是一个你可以在 `with` 语句中使用的东西,例如,`open()` 可以作为上下文管理器使用。
@@ -82,7 +82,7 @@ async with lifespan(app):
`FastAPI` 的 `lifespan` 参数接受一个**异步上下文管理器**,所以我们可以把我们新定义的异步上下文管理器 `lifespan` 传给它。
-{* ../../docs_src/events/tutorial003_py39.py hl[22] *}
+{* ../../docs_src/events/tutorial003_py310.py hl[22] *}
## 替代事件(弃用) { #alternative-events-deprecated }
@@ -104,7 +104,7 @@ async with lifespan(app):
使用事件 `"startup"` 声明一个在应用启动前运行的函数:
-{* ../../docs_src/events/tutorial001_py39.py hl[8] *}
+{* ../../docs_src/events/tutorial001_py310.py hl[8] *}
本例中,`startup` 事件处理器函数为项目“数据库”(只是一个 `dict`)提供了一些初始值。
@@ -116,7 +116,7 @@ async with lifespan(app):
使用事件 `"shutdown"` 声明一个在应用关闭时运行的函数:
-{* ../../docs_src/events/tutorial002_py39.py hl[6] *}
+{* ../../docs_src/events/tutorial002_py310.py hl[6] *}
此处,`shutdown` 事件处理器函数会向文件 `log.txt` 写入一行文本 `"Application shutdown"`。
diff --git a/docs/zh/docs/advanced/generate-clients.md b/docs/zh/docs/advanced/generate-clients.md
index 48a4ba07aa..e8a3b20558 100644
--- a/docs/zh/docs/advanced/generate-clients.md
+++ b/docs/zh/docs/advanced/generate-clients.md
@@ -40,7 +40,7 @@ FastAPI 会自动生成 **OpenAPI 3.1** 规范,因此你使用的任何工具
先从一个简单的 FastAPI 应用开始:
-{* ../../docs_src/generate_clients/tutorial001_py39.py hl[7:9,12:13,16:17,21] *}
+{* ../../docs_src/generate_clients/tutorial001_py310.py hl[7:9,12:13,16:17,21] *}
请注意,这些*路径操作*使用 `Item` 和 `ResponseMessage` 模型来定义它们的请求载荷和响应载荷。
@@ -98,7 +98,7 @@ npx @hey-api/openapi-ts -i http://localhost:8000/openapi.json -o src/client
例如,你可以有一个 **items** 相关的部分和另一个 **users** 相关的部分,它们可以用标签来分隔:
-{* ../../docs_src/generate_clients/tutorial002_py39.py hl[21,26,34] *}
+{* ../../docs_src/generate_clients/tutorial002_py310.py hl[21,26,34] *}
### 生成带标签的 TypeScript 客户端 { #generate-a-typescript-client-with-tags }
@@ -121,7 +121,7 @@ npx @hey-api/openapi-ts -i http://localhost:8000/openapi.json -o src/client
ItemsService.createItemItemsPost({name: "Plumbus", price: 5})
```
-……这是因为客户端生成器会把每个*路径操作*的 OpenAPI 内部**操作 ID(operation ID)**用作方法名的一部分。
+...这是因为客户端生成器会把每个*路径操作*的 OpenAPI 内部**操作 ID(operation ID)**用作方法名的一部分。
OpenAPI 要求每个操作 ID 在所有*路径操作*中都是唯一的,因此 FastAPI 会使用**函数名**、**路径**和**HTTP 方法/操作**来生成操作 ID,以确保其唯一性。
@@ -145,7 +145,7 @@ FastAPI 为每个*路径操作*使用一个**唯一 ID**,它既用于**操作
然后你可以把这个自定义函数通过 `generate_unique_id_function` 参数传给 **FastAPI**:
-{* ../../docs_src/generate_clients/tutorial003_py39.py hl[6:7,10] *}
+{* ../../docs_src/generate_clients/tutorial003_py310.py hl[6:7,10] *}
### 使用自定义操作 ID 生成 TypeScript 客户端 { #generate-a-typescript-client-with-custom-operation-ids }
@@ -167,7 +167,7 @@ FastAPI 为每个*路径操作*使用一个**唯一 ID**,它既用于**操作
我们可以把 OpenAPI JSON 下载到 `openapi.json` 文件中,然后用如下脚本**移除这个标签前缀**:
-{* ../../docs_src/generate_clients/tutorial004_py39.py *}
+{* ../../docs_src/generate_clients/tutorial004_py310.py *}
//// tab | Node.js
diff --git a/docs/zh/docs/advanced/middleware.md b/docs/zh/docs/advanced/middleware.md
index 108bbbb5c1..de4a3fcb13 100644
--- a/docs/zh/docs/advanced/middleware.md
+++ b/docs/zh/docs/advanced/middleware.md
@@ -43,7 +43,7 @@ app.add_middleware(UnicornMiddleware, some_config="rainbow")
**FastAPI** 为常见用例提供了一些中间件,下面介绍怎么使用这些中间件。
-/// note | 注意
+/// note | 技术细节
以下几个示例中也可以使用 `from starlette.middleware.something import SomethingMiddleware`。
@@ -57,13 +57,13 @@ app.add_middleware(UnicornMiddleware, some_config="rainbow")
任何传向 `http` 或 `ws` 的请求都会被重定向至安全方案。
-{* ../../docs_src/advanced_middleware/tutorial001_py39.py hl[2,6] *}
+{* ../../docs_src/advanced_middleware/tutorial001_py310.py hl[2,6] *}
## `TrustedHostMiddleware` { #trustedhostmiddleware }
强制所有传入请求都必须正确设置 `Host` 请求头,以防 HTTP 主机头攻击。
-{* ../../docs_src/advanced_middleware/tutorial002_py39.py hl[2,6:8] *}
+{* ../../docs_src/advanced_middleware/tutorial002_py310.py hl[2,6:8] *}
支持以下参数:
@@ -78,7 +78,7 @@ app.add_middleware(UnicornMiddleware, some_config="rainbow")
中间件会处理标准响应与流响应。
-{* ../../docs_src/advanced_middleware/tutorial003_py39.py hl[2,6] *}
+{* ../../docs_src/advanced_middleware/tutorial003_py310.py hl[2,6] *}
支持以下参数:
diff --git a/docs/zh/docs/advanced/openapi-callbacks.md b/docs/zh/docs/advanced/openapi-callbacks.md
index 6e8df68aef..cc9f5c28e1 100644
--- a/docs/zh/docs/advanced/openapi-callbacks.md
+++ b/docs/zh/docs/advanced/openapi-callbacks.md
@@ -179,7 +179,7 @@ JSON 请求体包含如下内容:
### 查看文档 { #check-the-docs }
-现在,使用 Uvicorn 启动应用,打开 http://127.0.0.1:8000/docs。
+现在,启动应用并打开 http://127.0.0.1:8000/docs。
就能看到文档的*路径操作*已经包含了**回调**的内容以及*外部 API*:
diff --git a/docs/zh/docs/advanced/openapi-webhooks.md b/docs/zh/docs/advanced/openapi-webhooks.md
index 9e64ed4e3c..d23fbcf888 100644
--- a/docs/zh/docs/advanced/openapi-webhooks.md
+++ b/docs/zh/docs/advanced/openapi-webhooks.md
@@ -32,7 +32,7 @@
当您创建一个 **FastAPI** 应用程序时,有一个 `webhooks` 属性可以用来定义网络钩子,方式与您定义*路径操作*的时候相同,例如使用 `@app.webhooks.post()` 。
-{* ../../docs_src/openapi_webhooks/tutorial001_py39.py hl[9:13,36:53] *}
+{* ../../docs_src/openapi_webhooks/tutorial001_py310.py hl[9:12,15:20] *}
您定义的网络钩子将被包含在 `OpenAPI` 的架构中,并出现在自动生成的**文档 UI** 中。
diff --git a/docs/zh/docs/advanced/path-operation-advanced-configuration.md b/docs/zh/docs/advanced/path-operation-advanced-configuration.md
index 6c9928ffce..588d4f09c5 100644
--- a/docs/zh/docs/advanced/path-operation-advanced-configuration.md
+++ b/docs/zh/docs/advanced/path-operation-advanced-configuration.md
@@ -12,7 +12,7 @@
务必确保每个操作的 `operation_id` 都是唯一的。
-{* ../../docs_src/path_operation_advanced_configuration/tutorial001_py39.py hl[6] *}
+{* ../../docs_src/path_operation_advanced_configuration/tutorial001_py310.py hl[6] *}
### 使用 *路径操作函数* 的函数名作为 operationId { #using-the-path-operation-function-name-as-the-operationid }
@@ -20,7 +20,7 @@
你应该在添加了所有 *路径操作* 之后执行此操作。
-{* ../../docs_src/path_operation_advanced_configuration/tutorial002_py39.py hl[2, 12:21, 24] *}
+{* ../../docs_src/path_operation_advanced_configuration/tutorial002_py310.py hl[2, 12:21, 24] *}
/// tip
@@ -40,7 +40,7 @@
使用参数 `include_in_schema` 并将其设置为 `False`,来从生成的 OpenAPI 方案中排除一个 *路径操作*(这样一来,就从自动化文档系统中排除掉了):
-{* ../../docs_src/path_operation_advanced_configuration/tutorial003_py39.py hl[6] *}
+{* ../../docs_src/path_operation_advanced_configuration/tutorial003_py310.py hl[6] *}
## 来自 docstring 的高级描述 { #advanced-description-from-docstring }
@@ -92,7 +92,7 @@
例如,这个 `openapi_extra` 可用于声明 [OpenAPI 扩展](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#specificationExtensions):
-{* ../../docs_src/path_operation_advanced_configuration/tutorial005_py39.py hl[6] *}
+{* ../../docs_src/path_operation_advanced_configuration/tutorial005_py310.py hl[6] *}
当你打开自动 API 文档时,你的扩展会显示在该 *路径操作* 的底部。
@@ -139,9 +139,9 @@
你可以用 `openapi_extra` 来做到:
-{* ../../docs_src/path_operation_advanced_configuration/tutorial006_py39.py hl[19:36, 39:40] *}
+{* ../../docs_src/path_operation_advanced_configuration/tutorial006_py310.py hl[19:36, 39:40] *}
-在这个示例中,我们没有声明任何 Pydantic 模型。事实上,请求体甚至没有被 解析 为 JSON,而是直接以 `bytes` 读取,并由函数 `magic_data_reader()` 以某种方式负责解析。
+在这个示例中,我们没有声明任何 Pydantic 模型。事实上,请求体甚至没有被 解析 为 JSON,而是直接以 `bytes` 读取,并由函数 `magic_data_reader()` 以某种方式负责解析。
尽管如此,我们仍然可以声明请求体的预期方案。
@@ -153,7 +153,7 @@
例如,在这个应用中我们不使用 FastAPI 集成的从 Pydantic 模型提取 JSON Schema 的功能,也不使用对 JSON 的自动校验。实际上,我们将请求的内容类型声明为 YAML,而不是 JSON:
-{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py39.py hl[15:20, 22] *}
+{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py310.py hl[15:20, 22] *}
尽管我们没有使用默认的集成功能,我们仍然使用 Pydantic 模型手动生成我们想以 YAML 接收的数据的 JSON Schema。
@@ -161,7 +161,7 @@
接着在我们的代码中,我们直接解析该 YAML 内容,然后再次使用同一个 Pydantic 模型来验证该 YAML 内容:
-{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py39.py hl[24:31] *}
+{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py310.py hl[24:31] *}
/// tip
diff --git a/docs/zh/docs/advanced/response-change-status-code.md b/docs/zh/docs/advanced/response-change-status-code.md
index cdcd39f50c..0b004bf4e5 100644
--- a/docs/zh/docs/advanced/response-change-status-code.md
+++ b/docs/zh/docs/advanced/response-change-status-code.md
@@ -20,9 +20,11 @@
然后你可以在这个*临时*响应对象中设置`status_code`。
-{* ../../docs_src/response_change_status_code/tutorial001_py39.py hl[1,9,12] *}
+{* ../../docs_src/response_change_status_code/tutorial001_py310.py hl[1,9,12] *}
-然后你可以像平常一样返回任何你需要的对象(例如一个`dict`或者一个数据库模型)。如果你声明了一个`response_model`,它仍然会被用来过滤和转换你返回的对象。
+然后你可以像平常一样返回任何你需要的对象(例如一个`dict`或者一个数据库模型)。
+
+如果你声明了一个`response_model`,它仍然会被用来过滤和转换你返回的对象。
**FastAPI**将使用这个*临时*响应来提取状态码(也包括cookies和头部),并将它们放入包含你返回的值的最终响应中,该响应由任何`response_model`过滤。
diff --git a/docs/zh/docs/advanced/response-cookies.md b/docs/zh/docs/advanced/response-cookies.md
index cc311a2708..c618cd0f0a 100644
--- a/docs/zh/docs/advanced/response-cookies.md
+++ b/docs/zh/docs/advanced/response-cookies.md
@@ -4,7 +4,7 @@
你可以在 *路径操作函数* 中定义一个类型为 `Response` 的参数,这样你就可以在这个临时响应对象中设置cookie了。
-{* ../../docs_src/response_cookies/tutorial002_py39.py hl[1, 8:9] *}
+{* ../../docs_src/response_cookies/tutorial002_py310.py hl[1, 8:9] *}
而且你还可以根据你的需要响应不同的对象,比如常用的 `dict`,数据库model等。
@@ -22,9 +22,9 @@
然后设置Cookies,并返回:
-{* ../../docs_src/response_cookies/tutorial001_py39.py hl[10:12] *}
+{* ../../docs_src/response_cookies/tutorial001_py310.py hl[10:12] *}
-/// tip
+/// tip | 提示
需要注意,如果你直接反馈一个response对象,而不是使用`Response`入参,FastAPI则会直接反馈你封装的response对象。
diff --git a/docs/zh/docs/advanced/response-directly.md b/docs/zh/docs/advanced/response-directly.md
index 8a9cf6ab89..a97992d249 100644
--- a/docs/zh/docs/advanced/response-directly.md
+++ b/docs/zh/docs/advanced/response-directly.md
@@ -36,7 +36,7 @@
{* ../../docs_src/response_directly/tutorial001_py310.py hl[5:6,20:21] *}
-/// note | 注意
+/// note | 技术细节
你也可以使用 `from starlette.responses import JSONResponse`。
@@ -54,7 +54,7 @@
你可以把你的 XML 内容放到一个字符串中,放到一个 `Response` 中,然后返回:
-{* ../../docs_src/response_directly/tutorial002_py39.py hl[1,18] *}
+{* ../../docs_src/response_directly/tutorial002_py310.py hl[1,18] *}
## 说明 { #notes }
diff --git a/docs/zh/docs/advanced/response-headers.md b/docs/zh/docs/advanced/response-headers.md
index fa02f53bea..01bde56d2a 100644
--- a/docs/zh/docs/advanced/response-headers.md
+++ b/docs/zh/docs/advanced/response-headers.md
@@ -6,13 +6,13 @@
然后你可以在这个*临时*响应对象中设置头部。
-{* ../../docs_src/response_headers/tutorial002_py39.py hl[1, 7:8] *}
+{* ../../docs_src/response_headers/tutorial002_py310.py hl[1, 7:8] *}
然后你可以像平常一样返回任何你需要的对象(例如一个 `dict` 或者一个数据库模型)。
如果你声明了一个 `response_model`,它仍然会被用来过滤和转换你返回的对象。
-**FastAPI** 将使用这个临时响应来提取头部(也包括 cookies 和状态码),并将它们放入包含你返回的值的最终响应中,该响应由任何 `response_model` 过滤。
+**FastAPI** 将使用这个*临时*响应来提取头部(也包括 cookies 和状态码),并将它们放入包含你返回的值的最终响应中,该响应由任何 `response_model` 过滤。
你也可以在依赖项中声明 `Response` 参数,并在其中设置头部(和 cookies)。
@@ -22,7 +22,7 @@
按照[直接返回响应](response-directly.md){.internal-link target=_blank}中所述创建响应,并将头部作为附加参数传递:
-{* ../../docs_src/response_headers/tutorial001_py39.py hl[10:12] *}
+{* ../../docs_src/response_headers/tutorial001_py310.py hl[10:12] *}
/// note | 技术细节
diff --git a/docs/zh/docs/advanced/security/http-basic-auth.md b/docs/zh/docs/advanced/security/http-basic-auth.md
index 55479d8e34..9128a49753 100644
--- a/docs/zh/docs/advanced/security/http-basic-auth.md
+++ b/docs/zh/docs/advanced/security/http-basic-auth.md
@@ -20,7 +20,7 @@ HTTP 基础授权让浏览器显示内置的用户名与密码提示。
* 返回类型为 `HTTPBasicCredentials` 的对象:
* 包含发送的 `username` 与 `password`
-{* ../../docs_src/security/tutorial006_an_py39.py hl[4,8,12] *}
+{* ../../docs_src/security/tutorial006_an_py310.py hl[4,8,12] *}
第一次打开 URL(或在 API 文档中点击 **Execute** 按钮)时,浏览器要求输入用户名与密码:
@@ -40,7 +40,7 @@ HTTP 基础授权让浏览器显示内置的用户名与密码提示。
然后我们可以使用 `secrets.compare_digest()` 来确保 `credentials.username` 是 `"stanleyjobson"`,且 `credentials.password` 是`"swordfish"`。
-{* ../../docs_src/security/tutorial007_an_py39.py hl[1,12:24] *}
+{* ../../docs_src/security/tutorial007_an_py310.py hl[1,12:24] *}
这类似于:
@@ -104,4 +104,4 @@ if "stanleyjobsox" == "stanleyjobson" and "love123" == "swordfish":
检测到凭证不正确后,返回 `HTTPException` 及状态码 401(与无凭证时返回的内容一样),并添加响应头 `WWW-Authenticate`,让浏览器再次显示登录提示:
-{* ../../docs_src/security/tutorial007_an_py39.py hl[26:30] *}
+{* ../../docs_src/security/tutorial007_an_py310.py hl[26:30] *}
diff --git a/docs/zh/docs/advanced/settings.md b/docs/zh/docs/advanced/settings.md
index adf2644915..b4def73eb5 100644
--- a/docs/zh/docs/advanced/settings.md
+++ b/docs/zh/docs/advanced/settings.md
@@ -54,7 +54,7 @@ $ pip install "fastapi[all]"
你可以使用与 Pydantic 模型相同的验证功能和工具,例如不同的数据类型,以及使用 `Field()` 进行附加验证。
-{* ../../docs_src/settings/tutorial001_py39.py hl[2,5:8,11] *}
+{* ../../docs_src/settings/tutorial001_py310.py hl[2,5:8,11] *}
/// tip | 提示
@@ -70,7 +70,7 @@ $ pip install "fastapi[all]"
然后你可以在应用中使用新的 `settings` 对象:
-{* ../../docs_src/settings/tutorial001_py39.py hl[18:20] *}
+{* ../../docs_src/settings/tutorial001_py310.py hl[18:20] *}
### 运行服务器 { #run-the-server }
@@ -100,19 +100,19 @@ $ ADMIN_EMAIL="deadpool@example.com" APP_NAME="ChimichangApp" fastapi run main.p
## 在另一个模块中放置设置 { #settings-in-another-module }
-你可以把这些设置放在另一个模块文件中,就像你在[Bigger Applications - Multiple Files](../tutorial/bigger-applications.md){.internal-link target=_blank}中看到的那样。
+你可以把这些设置放在另一个模块文件中,就像你在[更大的应用 - 多个文件](../tutorial/bigger-applications.md){.internal-link target=_blank}中看到的那样。
例如,可以有一个 `config.py` 文件:
-{* ../../docs_src/settings/app01_py39/config.py *}
+{* ../../docs_src/settings/app01_py310/config.py *}
然后在 `main.py` 文件中使用它:
-{* ../../docs_src/settings/app01_py39/main.py hl[3,11:13] *}
+{* ../../docs_src/settings/app01_py310/main.py hl[3,11:13] *}
/// tip | 提示
-你还需要一个 `__init__.py` 文件,就像你在[Bigger Applications - Multiple Files](../tutorial/bigger-applications.md){.internal-link target=_blank}中看到的那样。
+你还需要一个 `__init__.py` 文件,就像你在[更大的应用 - 多个文件](../tutorial/bigger-applications.md){.internal-link target=_blank}中看到的那样。
///
@@ -126,7 +126,7 @@ $ ADMIN_EMAIL="deadpool@example.com" APP_NAME="ChimichangApp" fastapi run main.p
延续上一个示例,你的 `config.py` 文件可能如下所示:
-{* ../../docs_src/settings/app02_an_py39/config.py hl[10] *}
+{* ../../docs_src/settings/app02_an_py310/config.py hl[10] *}
注意,现在我们不再创建默认实例 `settings = Settings()`。
@@ -134,7 +134,7 @@ $ ADMIN_EMAIL="deadpool@example.com" APP_NAME="ChimichangApp" fastapi run main.p
现在我们创建一个依赖项,返回一个新的 `config.Settings()`。
-{* ../../docs_src/settings/app02_an_py39/main.py hl[6,12:13] *}
+{* ../../docs_src/settings/app02_an_py310/main.py hl[6,12:13] *}
/// tip | 提示
@@ -144,15 +144,15 @@ $ ADMIN_EMAIL="deadpool@example.com" APP_NAME="ChimichangApp" fastapi run main.p
///
-然后我们可以在“路径操作函数”中将其作为依赖项引入,并在需要的任何地方使用它。
+然后我们可以在路径操作函数中将其作为依赖项引入,并在需要的任何地方使用它。
-{* ../../docs_src/settings/app02_an_py39/main.py hl[17,19:21] *}
+{* ../../docs_src/settings/app02_an_py310/main.py hl[17,19:21] *}
### 设置与测试 { #settings-and-testing }
接着,在测试期间,通过为 `get_settings` 创建依赖项覆盖,就可以很容易地提供一个不同的设置对象:
-{* ../../docs_src/settings/app02_an_py39/test_main.py hl[9:10,13,21] *}
+{* ../../docs_src/settings/app02_an_py310/test_main.py hl[9:10,13,21] *}
在依赖项覆盖中,我们在创建新的 `Settings` 对象时为 `admin_email` 设置了一个新值,然后返回该新对象。
@@ -193,7 +193,7 @@ APP_NAME="ChimichangApp"
然后更新 `config.py`:
-{* ../../docs_src/settings/app03_an_py39/config.py hl[9] *}
+{* ../../docs_src/settings/app03_an_py310/config.py hl[9] *}
/// tip | 提示
@@ -226,7 +226,7 @@ def get_settings():
但由于我们在顶部使用了 `@lru_cache` 装饰器,`Settings` 对象只会在第一次调用时创建一次。 ✔️
-{* ../../docs_src/settings/app03_an_py39/main.py hl[1,11] *}
+{* ../../docs_src/settings/app03_an_py310/main.py hl[1,11] *}
接着,对于后续请求中依赖项里对 `get_settings()` 的任何调用,它不会再次执行 `get_settings()` 的内部代码并创建新的 `Settings` 对象,而是会一遍又一遍地返回第一次调用时返回的那个相同对象。
diff --git a/docs/zh/docs/advanced/sub-applications.md b/docs/zh/docs/advanced/sub-applications.md
index fe1fcd1211..3e61610a37 100644
--- a/docs/zh/docs/advanced/sub-applications.md
+++ b/docs/zh/docs/advanced/sub-applications.md
@@ -10,7 +10,7 @@
首先,创建主(顶层)**FastAPI** 应用及其*路径操作*:
-{* ../../docs_src/sub_applications/tutorial001_py39.py hl[3, 6:8] *}
+{* ../../docs_src/sub_applications/tutorial001_py310.py hl[3, 6:8] *}
### 子应用 { #sub-application }
@@ -18,7 +18,7 @@
子应用只是另一个标准 FastAPI 应用,但这个应用是被**挂载**的应用:
-{* ../../docs_src/sub_applications/tutorial001_py39.py hl[11, 14:16] *}
+{* ../../docs_src/sub_applications/tutorial001_py310.py hl[11, 14:16] *}
### 挂载子应用 { #mount-the-sub-application }
@@ -26,7 +26,7 @@
本例的子应用挂载在 `/subapi` 路径下:
-{* ../../docs_src/sub_applications/tutorial001_py39.py hl[11, 19] *}
+{* ../../docs_src/sub_applications/tutorial001_py310.py hl[11, 19] *}
### 查看自动 API 文档 { #check-the-automatic-api-docs }
diff --git a/docs/zh/docs/advanced/templates.md b/docs/zh/docs/advanced/templates.md
index f2e5c21cf3..37575aff29 100644
--- a/docs/zh/docs/advanced/templates.md
+++ b/docs/zh/docs/advanced/templates.md
@@ -27,7 +27,7 @@ $ pip install jinja2
* 在返回模板的*路径操作*中声明 `Request` 参数
* 使用 `templates` 渲染并返回 `TemplateResponse`,传递模板的名称、request 对象以及一个包含多个键值对(用于 Jinja2 模板)的 "context" 字典。
-{* ../../docs_src/templates/tutorial001_py39.py hl[4,11,15:18] *}
+{* ../../docs_src/templates/tutorial001_py310.py hl[4,11,15:18] *}
/// note
diff --git a/docs/zh/docs/advanced/testing-dependencies.md b/docs/zh/docs/advanced/testing-dependencies.md
index db0b39483d..3291cfc256 100644
--- a/docs/zh/docs/advanced/testing-dependencies.md
+++ b/docs/zh/docs/advanced/testing-dependencies.md
@@ -46,7 +46,6 @@ FastAPI 可以覆盖这些位置的依赖项。
app.dependency_overrides = {}
```
-
/// tip | 提示
如果只在某些测试时覆盖依赖项,您可以在测试开始时(在测试函数内)设置覆盖依赖项,并在结束时(在测试函数结尾)重置覆盖依赖项。
diff --git a/docs/zh/docs/advanced/testing-events.md b/docs/zh/docs/advanced/testing-events.md
index 221984e906..90cbbda131 100644
--- a/docs/zh/docs/advanced/testing-events.md
+++ b/docs/zh/docs/advanced/testing-events.md
@@ -2,10 +2,10 @@
当你需要在测试中运行 `lifespan` 时,可以将 `TestClient` 与 `with` 语句一起使用:
-{* ../../docs_src/app_testing/tutorial004_py39.py hl[9:15,18,27:28,30:32,41:43] *}
+{* ../../docs_src/app_testing/tutorial004_py310.py hl[9:15,18,27:28,30:32,41:43] *}
你可以在[官方 Starlette 文档站点的“在测试中运行 lifespan”](https://www.starlette.dev/lifespan/#running-lifespan-in-tests)阅读更多细节。
对于已弃用的 `startup` 和 `shutdown` 事件,可以按如下方式使用 `TestClient`:
-{* ../../docs_src/app_testing/tutorial003_py39.py hl[9:12,20:24] *}
+{* ../../docs_src/app_testing/tutorial003_py310.py hl[9:12,20:24] *}
diff --git a/docs/zh/docs/advanced/testing-websockets.md b/docs/zh/docs/advanced/testing-websockets.md
index 64e1d3005f..e435e41e23 100644
--- a/docs/zh/docs/advanced/testing-websockets.md
+++ b/docs/zh/docs/advanced/testing-websockets.md
@@ -4,7 +4,7 @@
为此,在 `with` 语句中使用 `TestClient` 连接到 WebSocket:
-{* ../../docs_src/app_testing/tutorial002_py39.py hl[27:31] *}
+{* ../../docs_src/app_testing/tutorial002_py310.py hl[27:31] *}
/// note | 注意
diff --git a/docs/zh/docs/advanced/using-request-directly.md b/docs/zh/docs/advanced/using-request-directly.md
index 64ba8da1b4..8cfad4203a 100644
--- a/docs/zh/docs/advanced/using-request-directly.md
+++ b/docs/zh/docs/advanced/using-request-directly.md
@@ -29,7 +29,7 @@
此时,需要直接访问请求。
-{* ../../docs_src/using_request_directly/tutorial001_py39.py hl[1,7:8] *}
+{* ../../docs_src/using_request_directly/tutorial001_py310.py hl[1,7:8] *}
把*路径操作函数*的参数类型声明为 `Request`,**FastAPI** 就能把 `Request` 传递到参数里。
diff --git a/docs/zh/docs/advanced/websockets.md b/docs/zh/docs/advanced/websockets.md
index 4486a2e69f..513e1aaecd 100644
--- a/docs/zh/docs/advanced/websockets.md
+++ b/docs/zh/docs/advanced/websockets.md
@@ -38,13 +38,13 @@ $ pip install websockets
但这是一种专注于 WebSockets 的服务器端并提供一个工作示例的最简单方式:
-{* ../../docs_src/websockets/tutorial001_py39.py hl[2,6:38,41:43] *}
+{* ../../docs_src/websockets/tutorial001_py310.py hl[2,6:38,41:43] *}
## 创建 `websocket` { #create-a-websocket }
在您的 **FastAPI** 应用程序中,创建一个 `websocket`:
-{* ../../docs_src/websockets/tutorial001_py39.py hl[1,46:47] *}
+{* ../../docs_src/websockets/tutorial001_py310.py hl[1,46:47] *}
/// note | 技术细节
@@ -58,7 +58,7 @@ $ pip install websockets
在您的 WebSocket 路由中,您可以使用 `await` 等待消息并发送消息。
-{* ../../docs_src/websockets/tutorial001_py39.py hl[48:52] *}
+{* ../../docs_src/websockets/tutorial001_py310.py hl[48:52] *}
您可以接收和发送二进制、文本和 JSON 数据。
@@ -154,7 +154,7 @@ $ fastapi dev main.py
当 WebSocket 连接关闭时,`await websocket.receive_text()` 将引发 `WebSocketDisconnect` 异常,您可以捕获并处理该异常,就像本示例中的示例一样。
-{* ../../docs_src/websockets/tutorial003_py39.py hl[79:81] *}
+{* ../../docs_src/websockets/tutorial003_py310.py hl[79:81] *}
尝试以下操作:
diff --git a/docs/zh/docs/advanced/wsgi.md b/docs/zh/docs/advanced/wsgi.md
index 73fcb32196..487fbf8ddb 100644
--- a/docs/zh/docs/advanced/wsgi.md
+++ b/docs/zh/docs/advanced/wsgi.md
@@ -18,7 +18,7 @@
之后将其挂载到某一个路径下。
-{* ../../docs_src/wsgi/tutorial001_py39.py hl[1,3,23] *}
+{* ../../docs_src/wsgi/tutorial001_py310.py hl[1,3,23] *}
/// note | 注意
diff --git a/docs/zh/docs/alternatives.md b/docs/zh/docs/alternatives.md
new file mode 100644
index 0000000000..8a552c91d4
--- /dev/null
+++ b/docs/zh/docs/alternatives.md
@@ -0,0 +1,482 @@
+# 替代方案、灵感与对比 { #alternatives-inspiration-and-comparisons }
+
+是什么启发了 **FastAPI**,它与替代方案的比较,以及它从中学到的东西。
+
+## 介绍 { #intro }
+
+没有前人的工作,就不会有 **FastAPI**。
+
+在它诞生之前,已经有许多工具为其提供了灵感。
+
+我曾经多年避免创建一个新框架。起初,我尝试用许多不同的框架、插件和工具来解决 **FastAPI** 所覆盖的全部功能。
+
+但在某个时刻,除了创造一个能提供所有这些功能的东西之外,别无选择;它要吸收以往工具的最佳理念,并以尽可能好的方式组合起来,利用之前都不存在的语言特性(Python 3.6+ 类型提示)。
+
+## 先前的工具 { #previous-tools }
+
+### Django { #django }
+
+它是最流行且被广泛信任的 Python 框架。被用于构建 Instagram 等系统。
+
+它与关系型数据库(如 MySQL、PostgreSQL)耦合相对紧密,因此若要以 NoSQL 数据库(如 Couchbase、MongoDB、Cassandra 等)作为主要存储引擎并不容易。
+
+它最初用于在后端生成 HTML,而不是创建由现代前端(如 React、Vue.js、Angular)或与之通信的其他系统(如 IoT 设备)使用的 API。
+
+### Django REST Framework { #django-rest-framework }
+
+Django REST framework 作为一个灵活工具箱而创建,用于在底层使用 Django 构建 Web API,从而增强其 API 能力。
+
+它被包括 Mozilla、Red Hat、Eventbrite 在内的许多公司使用。
+
+它是最早的“自动 API 文档”的范例之一,这正是启发“寻找” **FastAPI** 的最初想法之一。
+
+/// note | 注意
+
+Django REST Framework 由 Tom Christie 创建。他也是 Starlette 和 Uvicorn 的作者,**FastAPI** 就是基于它们构建的。
+
+///
+
+/// check | 启发 **FastAPI**:
+
+提供自动化的 API 文档 Web 界面。
+
+///
+
+### Flask { #flask }
+
+Flask 是一个“微框架”,它不包含数据库集成,也没有像 Django 那样的许多默认内建功能。
+
+这种简单与灵活使得可以将 NoSQL 数据库作为主要的数据存储系统。
+
+由于非常简单,它相对直观易学,尽管文档在某些部分略显偏技术。
+
+它也常用于不一定需要数据库、用户管理,或任何 Django 预构建功能的应用;当然,许多这类功能可以通过插件添加。
+
+这种组件解耦、可按需扩展的“微框架”特性,是我想保留的关键点。
+
+鉴于 Flask 的简洁,它似乎非常适合构建 API。接下来要找的,就是 Flask 版的 “Django REST Framework”。
+
+/// check | 启发 **FastAPI**:
+
+- 成为微框架,便于按需组合所需的工具与组件。
+- 提供简单易用的路由系统。
+
+///
+
+### Requests { #requests }
+
+**FastAPI** 实际上不是 **Requests** 的替代品。它们的作用范围完全不同。
+
+在 FastAPI 应用程序内部使用 Requests 其实非常常见。
+
+尽管如此,FastAPI 依然从 Requests 中获得了不少灵感。
+
+**Requests** 是一个用于与 API 交互(作为客户端)的库,而 **FastAPI** 是一个用于构建 API(作为服务端)的库。
+
+它们处在某种意义上的“对立端”,彼此互补。
+
+Requests 设计非常简单直观,易于使用,且有合理的默认值。同时它也非常强大、可定制。
+
+这就是为什么,正如其官网所说:
+
+> Requests 是有史以来下载量最高的 Python 包之一
+
+它的用法非常简单。例如,进行一次 `GET` 请求,你会这样写:
+
+```Python
+response = requests.get("http://example.com/some/url")
+```
+
+对应地,FastAPI 的 API 路径操作可能看起来是这样的:
+
+```Python hl_lines="1"
+@app.get("/some/url")
+def read_url():
+ return {"message": "Hello World"}
+```
+
+可以看到 `requests.get(...)` 与 `@app.get(...)` 的相似之处。
+
+/// check | 启发 **FastAPI**:
+
+- 提供简单直观的 API。
+- 直接、自然地使用 HTTP 方法名(操作)。
+- 具备合理默认值,同时支持强大定制能力。
+
+///
+
+### Swagger / OpenAPI { #swagger-openapi }
+
+我想从 Django REST Framework 得到的主要特性之一是自动 API 文档。
+
+随后我发现有一个用于用 JSON(或 YAML,JSON 的扩展)来描述 API 的标准,称为 Swagger。
+
+并且已经有了用于 Swagger API 的 Web 用户界面。因此,只要能为 API 生成 Swagger 文档,就能自动使用这个 Web 界面。
+
+后来,Swagger 交由 Linux 基金会管理,并更名为 OpenAPI。
+
+因此,在谈到 2.0 版本时人们常说 “Swagger”,而 3+ 版本则称为 “OpenAPI”。
+
+/// check | 启发 **FastAPI**:
+
+采用并使用开放的 API 规范标准,而非自定义模式。
+
+并集成基于标准的用户界面工具:
+
+- Swagger UI
+- ReDoc
+
+选择这两者是因为它们相当流行且稳定;但稍作搜索,你就能找到数十种 OpenAPI 的替代用户界面(都可以与 **FastAPI** 搭配使用)。
+
+///
+
+### Flask REST 框架 { #flask-rest-frameworks }
+
+有若干基于 Flask 的 REST 框架,但在投入时间精力深入调研后,我发现许多已停止维护或被弃用,并存在多处未解决问题,不太适合采用。
+
+### Marshmallow { #marshmallow }
+
+API 系统所需的主要特性之一是数据“序列化”,即将代码(Python)中的数据转换为可通过网络发送的形式。例如,将包含数据库数据的对象转换为 JSON 对象、将 `datetime` 对象转换为字符串等。
+
+API 的另一个重要特性是数据校验,确保数据在给定约束下是有效的。例如,某个字段必须是 `int` 而不是任意字符串。这对传入数据尤其有用。
+
+没有数据校验系统的话,你就得在代码里手写所有检查。
+
+这些正是 Marshmallow 要提供的功能。它是个很棒的库,我之前大量使用过。
+
+但它诞生于 Python 类型提示出现之前。因此,定义每个模式都需要使用 Marshmallow 提供的特定工具和类。
+
+/// check | 启发 **FastAPI**:
+
+使用代码定义“模式”,自动提供数据类型与校验。
+
+///
+
+### Webargs { #webargs }
+
+API 的另一个重要需求是从传入请求中解析数据。
+
+Webargs 是一个在多个框架(包括 Flask)之上提供该功能的工具。
+
+它在底层使用 Marshmallow 进行数据校验,并且由相同的开发者创建。
+
+在拥有 **FastAPI** 之前,我也大量使用过它,这是个很棒的工具。
+
+/// info | 信息
+
+Webargs 由与 Marshmallow 相同的开发者创建。
+
+///
+
+/// check | 启发 **FastAPI**:
+
+对传入请求数据进行自动校验。
+
+///
+
+### APISpec { #apispec }
+
+Marshmallow 与 Webargs 通过插件提供了校验、解析与序列化。
+
+但文档仍然缺失,于是出现了 APISpec。
+
+它为许多框架提供插件(Starlette 也有插件)。
+
+它的工作方式是:你在处理路由的每个函数的文档字符串里,用 YAML 格式编写模式定义。
+
+然后它会生成 OpenAPI 模式。
+
+这正是它在 Flask、Starlette、Responder 等框架里的工作方式。
+
+但这样我们又回到了在 Python 字符串中维护一套“微语法”(一大段 YAML)的问题上。
+
+编辑器很难为此提供帮助;而且如果我们修改了参数或 Marshmallow 模式,却忘了同步更新那个 YAML 文档字符串,生成的模式就会过时。
+
+/// info | 信息
+
+APISpec 由与 Marshmallow 相同的开发者创建。
+
+///
+
+/// check | 启发 **FastAPI**:
+
+支持开放的 API 标准 OpenAPI。
+
+///
+
+### Flask-apispec { #flask-apispec }
+
+这是一个 Flask 插件,将 Webargs、Marshmallow 与 APISpec 结合在一起。
+
+它利用 Webargs 与 Marshmallow 的信息,通过 APISpec 自动生成 OpenAPI 模式。
+
+这是个很棒却被低估的工具;它理应比许多 Flask 插件更流行。或许是因为它的文档过于简洁与抽象。
+
+这解决了在 Python 文档字符串里书写 YAML(另一套语法)的问题。
+
+在构建 **FastAPI** 之前,Flask + Flask-apispec + Marshmallow + Webargs 的组合是我最喜欢的后端技术栈。
+
+使用它促成了若干 Flask 全栈脚手架的诞生。以下是我(以及若干外部团队)至今使用的主要技术栈:
+
+* https://github.com/tiangolo/full-stack
+* https://github.com/tiangolo/full-stack-flask-couchbase
+* https://github.com/tiangolo/full-stack-flask-couchdb
+
+这些全栈脚手架也成为了[**FastAPI** 项目脚手架](project-generation.md){.internal-link target=_blank}的基础。
+
+/// info | 信息
+
+Flask-apispec 由与 Marshmallow 相同的开发者创建。
+
+///
+
+/// check | 启发 **FastAPI**:
+
+从定义序列化与校验的同一份代码自动生成 OpenAPI 模式。
+
+///
+
+### NestJS(以及 Angular) { #nestjs-and-angular }
+
+这甚至不是 Python。NestJS 是一个 JavaScript(TypeScript)的 NodeJS 框架,受 Angular 启发。
+
+它实现了与 Flask-apispec 有些类似的效果。
+
+它集成了受 Angular 2 启发的依赖注入系统。与我所知的其他依赖注入系统一样,需要预先注册“可注入项”,因此会增加冗长与重复。
+
+由于参数用 TypeScript 类型描述(类似 Python 类型提示),编辑器支持相当好。
+
+但由于 TypeScript 的类型在编译为 JavaScript 后不会保留,无法只依赖这些类型同时定义校验、序列化与文档。受此以及一些设计决策影响,为了获得校验、序列化与自动 schema 生成,需要在许多位置添加装饰器,因此代码会相当冗长。
+
+它对嵌套模型的支持并不好。如果请求的 JSON 体是包含嵌套 JSON 对象的 JSON 对象,则无法被正确文档化和校验。
+
+/// check | 启发 **FastAPI**:
+
+使用 Python 类型以获得出色的编辑器支持。
+
+拥有强大的依赖注入系统,并设法尽量减少代码重复。
+
+///
+
+### Sanic { #sanic }
+
+它是最早的一批基于 `asyncio` 的极速 Python 框架之一,且做得与 Flask 很相似。
+
+/// note | 技术细节
+
+它使用了 `uvloop` 来替代 Python 默认的 `asyncio` 循环。这正是它如此之快的原因。
+
+它显然启发了 Uvicorn 和 Starlette;在公开的基准测试中,它们目前比 Sanic 更快。
+
+///
+
+/// check | 启发 **FastAPI**:
+
+找到实现疯狂性能的路径。
+
+这就是 **FastAPI** 基于 Starlette 的原因,因为它是目前可用的最快框架(由第三方基准测试验证)。
+
+///
+
+### Falcon { #falcon }
+
+Falcon 是另一个高性能 Python 框架,它被设计为精简且可作为 Hug 等其他框架的基础。
+
+它设计为接收两个参数的函数:一个“request”和一个“response”。然后从 request 中“读取”,向 response 中“写入”。由于这种设计,无法用标准的 Python 类型提示将请求参数和请求体声明为函数形参。
+
+因此,数据校验、序列化与文档要么需要手写完成,无法自动化;要么需要在 Falcon 之上实现一个框架,例如 Hug。其他受 Falcon 设计启发、采用“一个 request 对象 + 一个 response 对象作为参数”的框架也有同样的区别。
+
+/// check | 启发 **FastAPI**:
+
+寻找获得卓越性能的方法。
+
+与 Hug(Hug 基于 Falcon)一起,启发 **FastAPI** 在函数中声明一个 `response` 参数。尽管在 FastAPI 中它是可选的,主要用于设置 headers、cookies 和可选的状态码。
+
+///
+
+### Molten { #molten }
+
+我在构建 **FastAPI** 的早期阶段发现了 Molten。它有不少相似的想法:
+
+* 基于 Python 类型提示。
+* 从这些类型获得校验与文档。
+* 依赖注入系统。
+
+它没有使用像 Pydantic 这样的第三方数据校验、序列化与文档库,而是有自己的实现。因此这些数据类型定义不太容易在其他地方复用。
+
+它需要稍微冗长一些的配置。并且由于基于 WSGI(而非 ASGI),它并未设计为充分利用 Uvicorn、Starlette、Sanic 等工具所提供的高性能。
+
+其依赖注入系统需要预先注册依赖,且依赖根据声明的类型来解析。因此无法为同一类型声明多于一个“组件”。
+
+路由在一个地方集中声明,使用在其他地方声明的函数(而不是使用可以直接放在处理端点函数之上的装饰器)。这更接近 Django 的做法,而不是 Flask(和 Starlette)。它在代码中割裂了相对紧耦合的内容。
+
+/// check | 启发 **FastAPI**:
+
+通过模型属性的“默认值”为数据类型定义额外校验。这提升了编辑器支持,而这在当时的 Pydantic 中尚不可用。
+
+这实际上促成了对 Pydantic 的部分更新,以支持这种校验声明风格(这些功能现已在 Pydantic 中可用)。
+
+///
+
+### Hug { #hug }
+
+Hug 是最早使用 Python 类型提示来声明 API 参数类型的框架之一。这一绝妙想法也启发了其他工具。
+
+它在声明中使用自定义类型而不是标准的 Python 类型,但这依然是巨大的进步。
+
+它也是最早生成一个自定义 JSON 模式来声明整个 API 的框架之一。
+
+它并不基于 OpenAPI 与 JSON Schema 这类标准。因此与其他工具(如 Swagger UI)的集成并非一帆风顺。但它仍是非常有创新性的想法。
+
+它有一个有趣且少见的特性:使用同一框架,可以同时创建 API 与 CLI。
+
+由于基于同步 Python Web 框架的上一代标准(WSGI),它无法处理 WebSocket 等,尽管它的性能仍然很高。
+
+/// info | 信息
+
+Hug 由 Timothy Crosley 创建,他也是 `isort` 的作者,这是一个能自动排序 Python 文件中导入的优秀工具。
+
+///
+
+/// check | 启发 **FastAPI** 的想法:
+
+Hug 启发了 APIStar 的部分设计,也是我当时最看好的工具之一,与 APIStar 并列。
+
+Hug 促使 **FastAPI** 使用 Python 类型提示来声明参数,并自动生成定义整个 API 的模式。
+
+Hug 启发 **FastAPI** 在函数中声明 `response` 参数,用于设置 headers 与 cookies。
+
+///
+
+### APIStar (<= 0.5) { #apistar-0-5 }
+
+就在决定动手构建 **FastAPI** 之前,我找到了 **APIStar** 服务器。它几乎具备我想要的一切,设计也很出色。
+
+在我见过的框架中,它是最早使用 Python 类型提示来声明参数和请求的实现之一(早于 NestJS 与 Molten)。我与 Hug 几乎同时发现了它。但 APIStar 使用了 OpenAPI 标准。
+
+它基于相同的类型提示,在多处自动进行数据校验、序列化并生成 OpenAPI 模式。
+
+请求体模式定义并未使用与 Pydantic 相同的 Python 类型提示,它更接近 Marshmallow,因此编辑器支持不如 Pydantic 好,但即便如此,APIStar 仍是当时可用的最佳选择。
+
+它在当时拥有最好的性能基准(仅被 Starlette 超越)。
+
+起初它没有自动 API 文档 Web 界面,但我知道我可以把 Swagger UI 加进去。
+
+它有一个依赖注入系统。与上文提到的其他工具一样,需要预先注册组件。但这依然是很棒的特性。
+
+我从未在完整项目中使用过它,因为它没有安全集成,因此我无法用它替代基于 Flask-apispec 的全栈脚手架所具备的全部功能。我曾把“提交一个增加该功能的 PR”放在了待办里。
+
+但随后,项目的重心发生了变化。
+
+它不再是一个 API Web 框架,因为作者需要专注于 Starlette。
+
+现在 APIStar 是一组用于校验 OpenAPI 规范的工具,而不是 Web 框架。
+
+/// info | 信息
+
+APIStar 由 Tom Christie 创建。他还创建了:
+
+* Django REST Framework
+* Starlette(**FastAPI** 基于其之上)
+* Uvicorn(被 Starlette 与 **FastAPI** 使用)
+
+///
+
+/// check | 启发 **FastAPI**:
+
+诞生。
+
+用同一套 Python 类型同时声明多件事(数据校验、序列化与文档),并且还能提供出色的编辑器支持——我认为这是个极其巧妙的想法。
+
+在长时间寻找与测试多种替代之后,APIStar 是当时最好的选择。
+
+随后 APIStar 不再作为服务器存在,而 Starlette 出现,成为实现该体系的更佳基础。这成为构建 **FastAPI** 的最终灵感来源。
+
+我把 **FastAPI** 视为 APIStar 的“精神续作”,并在此基础上,结合前述工具的经验,改进并增强了功能、类型系统及其他各方面。
+
+///
+
+## **FastAPI** 所使用的组件 { #used-by-fastapi }
+
+### Pydantic { #pydantic }
+
+Pydantic 是一个基于 Python 类型提示来定义数据校验、序列化与文档(使用 JSON Schema)的库。
+
+这使得它极其直观。
+
+它可与 Marshmallow 类比。尽管在基准测试中它比 Marshmallow 更快。并且由于同样基于 Python 类型提示,编辑器支持优秀。
+
+/// check | **FastAPI** 用它来:
+
+处理所有数据校验、数据序列化与自动模型文档(基于 JSON Schema)。
+
+随后 **FastAPI** 会把这些 JSON Schema 数据纳入 OpenAPI(以及完成其他所有工作)。
+
+///
+
+### Starlette { #starlette }
+
+Starlette 是一个轻量级的 ASGI 框架/工具集,非常适合构建高性能的 asyncio 服务。
+
+它非常简单直观。被设计为易于扩展,且具有模块化组件。
+
+它具备:
+
+* 性能极其出色。
+* 支持 WebSocket。
+* 进程内后台任务。
+* 启动与停止事件。
+* 基于 HTTPX 的测试客户端。
+* CORS、GZip、静态文件、流式响应。
+* 会话与 Cookie 支持。
+* 100% 测试覆盖率。
+* 100% 类型注解的代码库。
+* 极少的强依赖。
+
+Starlette 目前是测试中最快的 Python 框架。仅次于 Uvicorn,它不是框架,而是服务器。
+
+Starlette 提供了 Web 微框架的全部基础能力。
+
+但它不提供自动的数据校验、序列化或文档。
+
+这正是 **FastAPI** 在其之上增加的主要内容之一,全部基于 Python 类型提示(通过 Pydantic)。此外还有依赖注入系统、安全工具、OpenAPI 模式生成等。
+
+/// note | 技术细节
+
+ASGI 是由 Django 核心团队成员推动的新“标准”。它尚不是正式的“Python 标准”(PEP),尽管正朝此方向推进。
+
+尽管如此,已有多种工具将其作为“标准”使用。这极大提升了互操作性:你可以把 Uvicorn 换成其他 ASGI 服务器(如 Daphne 或 Hypercorn),或添加 ASGI 兼容的工具,如 `python-socketio`。
+
+///
+
+/// check | **FastAPI** 用它来:
+
+处理所有核心 Web 部分,并在其之上扩展功能。
+
+`FastAPI` 类本身直接继承自 `Starlette`。
+
+因此,凡是你能用 Starlette 完成的事,也能直接用 **FastAPI** 完成;可以把它看作“加速版”的 Starlette。
+
+///
+
+### Uvicorn { #uvicorn }
+
+Uvicorn 是一个基于 uvloop 与 httptools 构建的极速 ASGI 服务器。
+
+它不是 Web 框架,而是服务器。例如它不提供按路径路由的工具——这是 Starlette(或 **FastAPI**)这类框架在其之上提供的功能。
+
+它是 Starlette 与 **FastAPI** 推荐的服务器。
+
+/// check | **FastAPI** 推荐将其作为:
+
+运行 **FastAPI** 应用的主要 Web 服务器。
+
+你也可以使用 `--workers` 命令行选项以获得异步的多进程服务器。
+
+更多细节见[部署](deployment/index.md){.internal-link target=_blank}一节。
+
+///
+
+## 基准与速度 { #benchmarks-and-speed }
+
+要理解、比较并查看 Uvicorn、Starlette 与 FastAPI 之间的差异,请查看[基准](benchmarks.md){.internal-link target=_blank}一节。
diff --git a/docs/zh/docs/async.md b/docs/zh/docs/async.md
index c94c907873..36d875f515 100644
--- a/docs/zh/docs/async.md
+++ b/docs/zh/docs/async.md
@@ -298,7 +298,7 @@ CPU 密集型操作的常见示例是需要复杂的数学处理。
这一点,再加上 Python 是**数据科学**、机器学习(尤其是深度学习)的主要语言这一简单事实,使得 **FastAPI** 与数据科学/机器学习 Web API 和应用程序(以及其他许多应用程序)非常匹配。
-了解如何在生产环境中实现这种并行性,可查看此文 [Deployment](deployment/index.md){.internal-link target=_blank}。
+了解如何在生产环境中实现这种并行性,可查看此文 [部署](deployment/index.md){.internal-link target=_blank}。
## `async` 和 `await` { #async-and-await }
@@ -369,7 +369,7 @@ Starlette (和 **FastAPI**) 是基于 AnyIO 编写自己的异步程序,使其拥有较高的兼容性并获得一些好处(例如, 结构化并发)。
-我(指原作者 —— 译者注)基于 AnyIO 新建了一个库,作为一个轻量级的封装层,用来优化类型注解,同时提供了更好的**自动补全**、**内联错误提示**等功能。这个库还附带了一个友好的入门指南和教程,能帮助你**理解**并编写**自己的异步代码**:Asyncer。如果你有**结合使用异步代码和常规**(阻塞/同步)代码的需求,这个库会特别有用。
+我基于 AnyIO 新建了一个库,作为一个轻量级的封装层,用来优化类型注解,同时提供了更好的**自动补全**、**内联错误提示**等功能。这个库还附带了一个友好的入门指南和教程,能帮助你**理解**并编写**自己的异步代码**:Asyncer。如果你有**结合使用异步代码和常规**(阻塞/同步)代码的需求,这个库会特别有用。
### 其他形式的异步代码 { #other-forms-of-asynchronous-code }
diff --git a/docs/zh/docs/benchmarks.md b/docs/zh/docs/benchmarks.md
index 1a4b4a3de8..a6e706dfaa 100644
--- a/docs/zh/docs/benchmarks.md
+++ b/docs/zh/docs/benchmarks.md
@@ -23,7 +23,7 @@
* 你不会直接在 Uvicorn 中编写应用程序。这意味着你的代码至少必须包含 Starlette(或 **FastAPI**)提供的代码。如果你这样做了(即直接在 Uvicorn 中编写应用程序),最终的应用程序会和使用了框架并且最小化了应用代码和 bug 的情况具有相同的性能损耗。
* 如果你要对比 Uvicorn,请将其与 Daphne,Hypercorn,uWSGI 等应用服务器进行比较。
* **Starlette**:
- * 在 Uvicorn 后使用 Starlette,性能会略有下降。实际上,Starlette 使用 Uvicorn 运行。因此,由于必须执行更多的代码,它只会比 Uvicorn 更慢。
+ * 性能仅次于 Uvicorn。实际上,Starlette 使用 Uvicorn 运行。因此,由于必须执行更多的代码,它只会比 Uvicorn 更慢。
* 但它为你提供了构建简单的网络程序的工具,并具有基于路径的路由等功能。
* 如果想对比与 Starlette 对标的开发框架,请将其与 Sanic,Flask,Django 等网络框架(或微框架)进行比较。
* **FastAPI**:
diff --git a/docs/zh/docs/deployment/concepts.md b/docs/zh/docs/deployment/concepts.md
index 66d32629cb..76e967d7de 100644
--- a/docs/zh/docs/deployment/concepts.md
+++ b/docs/zh/docs/deployment/concepts.md
@@ -190,7 +190,7 @@
### 工作进程和端口 { #worker-processes-and-ports }
-还记得文档 [About HTTPS](https.md){.internal-link target=_blank} 中只有一个进程可以侦听服务器中的端口和 IP 地址的一种组合吗?
+还记得文档 [关于 HTTPS](https.md){.internal-link target=_blank} 中只有一个进程可以侦听服务器中的端口和 IP 地址的一种组合吗?
现在仍然是对的。
diff --git a/docs/zh/docs/deployment/docker.md b/docs/zh/docs/deployment/docker.md
index 3d0c19903b..4e7410587e 100644
--- a/docs/zh/docs/deployment/docker.md
+++ b/docs/zh/docs/deployment/docker.md
@@ -14,7 +14,7 @@
Dockerfile 预览 👀
```Dockerfile
-FROM python:3.9
+FROM python:3.14
WORKDIR /code
@@ -166,7 +166,7 @@ def read_item(item_id: int, q: str | None = None):
```{ .dockerfile .annotate }
# (1)!
-FROM python:3.9
+FROM python:3.14
# (2)!
WORKDIR /code
@@ -390,7 +390,7 @@ $ docker run -d --name mycontainer -p 80:80 myimage
然后你只需要在 `Dockerfile` 中修改相应路径来复制该文件:
```{ .dockerfile .annotate hl_lines="10 13" }
-FROM python:3.9
+FROM python:3.14
WORKDIR /code
@@ -454,7 +454,7 @@ Traefik 与 Docker、Kubernetes 等都有集成,因此为容器设置和配置
## 复制 - 进程数 { #replication-number-of-processes }
-如果你有一个由 **Kubernetes**、Docker Swarm Mode、Nomad 或其他类似的复杂系统管理的、在多台机器上运行的分布式容器集群,那么你很可能会希望在**集群层面**来**处理复制**,而不是在每个容器中使用**进程管理**(比如让 Uvicorn 运行多个 workers)。
+如果你有一个由 **Kubernetes**、Docker Swarm Mode、Nomad 或其他类似的复杂系统管理的、在多台机器上运行的分布式容器集群,那么你很可能会希望在**集群层面**来**处理复制**,而不是在每个容器中使用**进程管理**(比如让 Uvicorn 运行多个 workers)。
像 Kubernetes 这样的分布式容器管理系统通常都有某种内置方式来处理**容器复制**,同时对传入请求进行**负载均衡**。这一切都在**集群层面**完成。
@@ -499,7 +499,7 @@ Traefik 与 Docker、Kubernetes 等都有集成,因此为容器设置和配置
在这些情况下,你可以使用 `--workers` 命令行选项来设置要运行的 worker 数量:
```{ .dockerfile .annotate }
-FROM python:3.9
+FROM python:3.14
WORKDIR /code
diff --git a/docs/zh/docs/deployment/fastapicloud.md b/docs/zh/docs/deployment/fastapicloud.md
new file mode 100644
index 0000000000..0239a15128
--- /dev/null
+++ b/docs/zh/docs/deployment/fastapicloud.md
@@ -0,0 +1,65 @@
+# FastAPI Cloud { #fastapi-cloud }
+
+你可以用**一条命令**将你的 FastAPI 应用部署到 FastAPI Cloud,如果还没有,去加入候补名单吧。🚀
+
+## 登录 { #login }
+
+请确保你已有 **FastAPI Cloud** 账号(我们已从候补名单向你发出邀请 😉)。
+
+然后登录:
+
+
+
+```console
+$ fastapi login
+
+You are logged in to FastAPI Cloud 🚀
+```
+
+
+
+## 部署 { #deploy }
+
+现在用**一条命令**部署你的应用:
+
+
+
+```console
+$ fastapi deploy
+
+Deploying to FastAPI Cloud...
+
+✅ Deployment successful!
+
+🐔 Ready the chicken! Your app is ready at https://myapp.fastapicloud.dev
+```
+
+
+
+就这样!现在你可以通过该 URL 访问你的应用。✨
+
+## 关于 FastAPI Cloud { #about-fastapi-cloud }
+
+**FastAPI Cloud** 由 **FastAPI** 背后的作者与团队打造。
+
+它让你以最小的投入完成 API 的**构建**、**部署**与**访问**。
+
+它把使用 FastAPI 构建应用时的**开发者体验**,同样带到将应用**部署**到云上的过程。🎉
+
+它还会替你处理部署应用时大多数需要的事项,例如:
+
+* HTTPS
+* 副本、基于请求的自动伸缩
+* 等等
+
+FastAPI Cloud 是 *FastAPI and friends* 开源项目的主要赞助方与资金提供者。✨
+
+## 部署到其他云服务商 { #deploy-to-other-cloud-providers }
+
+FastAPI 是开源的,并基于标准。你可以将 FastAPI 应用部署到你选择的任意云服务商。
+
+按照你所选云服务商的指南部署 FastAPI 应用即可。🤓
+
+## 部署到你自己的服务器 { #deploy-your-own-server }
+
+在后面的**部署**指南中,我也会讲解所有细节,帮助你理解幕后发生了什么、需要做什么,以及如何自行部署 FastAPI 应用,包括部署到你自己的服务器。🤓
diff --git a/docs/zh/docs/deployment/https.md b/docs/zh/docs/deployment/https.md
index 4f60b7bca7..591707f6dd 100644
--- a/docs/zh/docs/deployment/https.md
+++ b/docs/zh/docs/deployment/https.md
@@ -65,13 +65,13 @@
第一步我们要先**获取**一些**域名(Domain Name)**。 然后可以在 DNS 服务器(可能是你的同一家云服务商提供的)中配置它。
-你可能拥有一个云服务器(虚拟机)或类似的东西,并且它会有一个固定 **公共IP地址**。
+你可能拥有一个云服务器(虚拟机)或类似的东西,并且它会有一个固定 **公共IP地址**。
在 DNS 服务器中,你可以配置一条记录(“A 记录”)以将 **你的域名** 指向你服务器的公共 **IP 地址**。
这个操作一般只需要在最开始执行一次。
-/// tip
+/// tip | 提示
域名这部分发生在 HTTPS 之前,由于这一切都依赖于域名和 IP 地址,所以先在这里提一下。
@@ -121,7 +121,7 @@ TLS 终止代理可以访问一个或多个 **TLS 证书**(HTTPS 证书)。
这就是 **HTTPS**,它只是 **安全 TLS 连接** 内的普通 **HTTP**,而不是纯粹的(未加密的)TCP 连接。
-/// tip
+/// tip | 提示
请注意,通信加密发生在 **TCP 层**,而不是 HTTP 层。
@@ -217,7 +217,7 @@ TLS 终止代理将使用协商好的加密算法**解密请求**,并将**(
这在需要正确处理重定向等场景时很有用。
-/// tip
+/// tip | 提示
你可以在文档中了解更多:[在代理之后 - 启用代理转发请求头](../advanced/behind-a-proxy.md#enable-proxy-forwarded-headers){.internal-link target=_blank}
diff --git a/docs/zh/docs/deployment/manually.md b/docs/zh/docs/deployment/manually.md
index 6f2ad27b2f..f519c1e87a 100644
--- a/docs/zh/docs/deployment/manually.md
+++ b/docs/zh/docs/deployment/manually.md
@@ -90,7 +90,7 @@ $ pip install "uvicorn[standard]"
类似的流程也适用于任何其他 ASGI 服务器程序。
-/// tip
+/// tip | 提示
通过添加 `standard` 选项,Uvicorn 将安装并使用一些推荐的额外依赖项。
@@ -114,7 +114,7 @@ $ uvicorn main:app --host 0.0.0.0 --port 80
-/// note
+/// note | 注意
命令 `uvicorn main:app` 的含义如下:
@@ -131,7 +131,7 @@ from main import app
每种 ASGI 服务器程序通常都会有类似的命令,您可以在它们的官方文档中找到更多信息。
-/// warning
+/// warning | 警告
Uvicorn 和其他服务器支持 `--reload` 选项,该选项在开发过程中非常有用。
diff --git a/docs/zh/docs/features.md b/docs/zh/docs/features.md
index 7d7aa19c06..1414f7c6fc 100644
--- a/docs/zh/docs/features.md
+++ b/docs/zh/docs/features.md
@@ -6,7 +6,7 @@
### 基于开放标准 { #based-on-open-standards }
-* 用于创建 API 的
OpenAPI,包含对
路径 操作、参数、请求体、安全等的声明。
+* 用于创建 API 的
OpenAPI,包含对
路径 操作、参数、请求体、安全等的声明。
* 使用
JSON Schema 自动生成数据模型文档(因为 OpenAPI 本身就是基于 JSON Schema 的)。
* 经过了缜密的研究后围绕这些标准而设计。并非狗尾续貂。
* 这也允许了在很多语言中自动**生成客户端代码**。
@@ -137,7 +137,7 @@ OpenAPI 中定义的安全模式,包括:
### 依赖注入 { #dependency-injection }
-FastAPI 有一个使用非常简单,但是非常强大的
依赖注入系统。
+FastAPI 有一个使用非常简单,但是非常强大的
依赖注入系统。
* 甚至依赖也可以有依赖,创建一个层级或者**“图”依赖**。
* 所有**自动化处理**都由框架完成。
@@ -154,8 +154,8 @@ FastAPI 有一个使用非常简单,但是非常强大的
IDE/
linter/brain** 适配:
+* 和你 **
IDE/
linter/brain** 适配:
* 因为 pydantic 数据结构仅仅是你定义的类的实例;自动补全,linting,mypy 以及你的直觉应该可以和你验证的数据一起正常工作。
* 验证**复杂结构**:
* 使用分层的 Pydantic 模型,Python `typing` 的 `List` 和 `Dict` 等等。
diff --git a/docs/zh/docs/help-fastapi.md b/docs/zh/docs/help-fastapi.md
index 5a5157b5d3..1be60d9d55 100644
--- a/docs/zh/docs/help-fastapi.md
+++ b/docs/zh/docs/help-fastapi.md
@@ -59,7 +59,7 @@
## 发推谈谈 **FastAPI** { #tweet-about-fastapi }
-
Tweet about **FastAPI**,告诉我和大家你为什么喜欢它。🎉
+
发推谈谈 **FastAPI**,告诉我和大家你为什么喜欢它。🎉
我很高兴听到 **FastAPI** 的使用情况、你喜欢它的哪些点、你在哪个项目/公司使用它,等等。
diff --git a/docs/zh/docs/how-to/authentication-error-status-code.md b/docs/zh/docs/how-to/authentication-error-status-code.md
new file mode 100644
index 0000000000..466b90e15a
--- /dev/null
+++ b/docs/zh/docs/how-to/authentication-error-status-code.md
@@ -0,0 +1,17 @@
+# 使用旧的 403 认证错误状态码 { #use-old-403-authentication-error-status-codes }
+
+在 FastAPI `0.122.0` 版本之前,当内置的安全工具在认证失败后向客户端返回错误时,会使用 HTTP 状态码 `403 Forbidden`。
+
+从 FastAPI `0.122.0` 版本开始,它们改用更合适的 HTTP 状态码 `401 Unauthorized`,并在响应中返回合理的 `WWW-Authenticate` 头,遵循 HTTP 规范,
RFC 7235、
RFC 9110。
+
+但如果由于某些原因你的客户端依赖旧行为,你可以在你的安全类中重写方法 `make_not_authenticated_error` 来回退到旧行为。
+
+例如,你可以创建一个 `HTTPBearer` 的子类,使其返回 `403 Forbidden` 错误,而不是默认的 `401 Unauthorized` 错误:
+
+{* ../../docs_src/authentication_error_status_code/tutorial001_an_py310.py hl[9:13] *}
+
+/// tip | 提示
+
+注意该函数返回的是异常实例,而不是直接抛出它。抛出操作由其余的内部代码完成。
+
+///
diff --git a/docs/zh/docs/how-to/conditional-openapi.md b/docs/zh/docs/how-to/conditional-openapi.md
new file mode 100644
index 0000000000..d26b5f3bd0
--- /dev/null
+++ b/docs/zh/docs/how-to/conditional-openapi.md
@@ -0,0 +1,56 @@
+# 按条件配置 OpenAPI { #conditional-openapi }
+
+如果需要,你可以使用设置和环境变量,按环境有条件地配置 OpenAPI,甚至完全禁用它。
+
+## 关于安全、API 和文档 { #about-security-apis-and-docs }
+
+在生产环境隐藏文档界面并不应该成为保护 API 的方式。
+
+这并不会给你的 API 增加任何额外的安全性,*路径操作* 仍然会在原来的位置可用。
+
+如果你的代码里有安全漏洞,它仍然存在。
+
+隐藏文档只会让理解如何与 API 交互变得更困难,也可能让你在生产环境中调试更困难。这大体上可以被视为一种
通过隐藏实现安全 的做法。
+
+如果你想保护你的 API,有很多更好的措施,例如:
+
+- 确保为请求体和响应定义完善的 Pydantic 模型。
+- 使用依赖配置所需的权限和角色。
+- 绝不要存储明文密码,只存储密码哈希。
+- 实现并使用成熟的密码学工具,比如 pwdlib 和 JWT 令牌等。
+- 在需要的地方使用 OAuth2 作用域添加更细粒度的权限控制。
+- ...等。
+
+尽管如此,你可能确实有非常特定的用例,需要在某些环境(例如生产环境)禁用 API 文档,或根据环境变量的配置来决定。
+
+## 基于设置和环境变量的条件式 OpenAPI { #conditional-openapi-from-settings-and-env-vars }
+
+你可以很容易地使用相同的 Pydantic 设置来配置生成的 OpenAPI 和文档 UI。
+
+例如:
+
+{* ../../docs_src/conditional_openapi/tutorial001_py310.py hl[6,11] *}
+
+这里我们声明了设置项 `openapi_url`,其默认值同样是 `"/openapi.json"`。
+
+然后在创建 `FastAPI` 应用时使用它。
+
+接着,你可以通过把环境变量 `OPENAPI_URL` 设为空字符串来禁用 OpenAPI(包括文档 UI),例如:
+
+
+
+```console
+$ OPENAPI_URL= uvicorn main:app
+
+INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
+```
+
+
+
+然后如果你访问 `/openapi.json`、`/docs` 或 `/redoc`,就会得到一个 `404 Not Found` 错误,例如:
+
+```JSON
+{
+ "detail": "Not Found"
+}
+```
diff --git a/docs/zh/docs/how-to/configure-swagger-ui.md b/docs/zh/docs/how-to/configure-swagger-ui.md
index 104baff4bd..bf26246573 100644
--- a/docs/zh/docs/how-to/configure-swagger-ui.md
+++ b/docs/zh/docs/how-to/configure-swagger-ui.md
@@ -18,7 +18,7 @@ FastAPI会将这些配置转换为 **JSON**,使其与 JavaScript 兼容,因
但是你可以通过设置 `syntaxHighlight` 为 `False` 来禁用 Swagger UI 中的语法高亮:
-{* ../../docs_src/configure_swagger_ui/tutorial001_py39.py hl[3] *}
+{* ../../docs_src/configure_swagger_ui/tutorial001_py310.py hl[3] *}
...在此之后,Swagger UI 将不会高亮代码:
@@ -28,7 +28,7 @@ FastAPI会将这些配置转换为 **JSON**,使其与 JavaScript 兼容,因
同样地,你也可以通过设置键 `"syntaxHighlight.theme"` 来设置语法高亮主题(注意中间有一个点):
-{* ../../docs_src/configure_swagger_ui/tutorial002_py39.py hl[3] *}
+{* ../../docs_src/configure_swagger_ui/tutorial002_py310.py hl[3] *}
这个配置会改变语法高亮主题:
@@ -46,7 +46,7 @@ FastAPI 包含了一些默认配置参数,适用于大多数用例。
比如,如果要禁用 `deepLinking`,你可以像这样传递设置到 `swagger_ui_parameters` 中:
-{* ../../docs_src/configure_swagger_ui/tutorial003_py39.py hl[3] *}
+{* ../../docs_src/configure_swagger_ui/tutorial003_py310.py hl[3] *}
## 其他 Swagger UI 参数 { #other-swagger-ui-parameters }
diff --git a/docs/zh/docs/how-to/custom-docs-ui-assets.md b/docs/zh/docs/how-to/custom-docs-ui-assets.md
new file mode 100644
index 0000000000..9e6e5a66b8
--- /dev/null
+++ b/docs/zh/docs/how-to/custom-docs-ui-assets.md
@@ -0,0 +1,185 @@
+# 自托管自定义文档 UI 静态资源 { #custom-docs-ui-static-assets-self-hosting }
+
+API 文档使用 Swagger UI 和 ReDoc,它们各自需要一些 JavaScript 和 CSS 文件。
+
+默认情况下,这些文件从一个
CDN 提供。
+
+不过你可以自定义:可以指定特定的 CDN,或自行提供这些文件。
+
+## 为 JavaScript 和 CSS 自定义 CDN { #custom-cdn-for-javascript-and-css }
+
+假设你想使用不同的
CDN,例如使用 `https://unpkg.com/`。
+
+如果你所在的国家/地区屏蔽了某些 URL,这会很有用。
+
+### 关闭自动文档 { #disable-the-automatic-docs }
+
+第一步是关闭自动文档,因为默认它们会使用默认的 CDN。
+
+要关闭它们,在创建 `FastAPI` 应用时将其 URL 设为 `None`:
+
+{* ../../docs_src/custom_docs_ui/tutorial001_py310.py hl[8] *}
+
+### 包含自定义文档 { #include-the-custom-docs }
+
+现在你可以为自定义文档创建*路径操作*。
+
+你可以复用 FastAPI 的内部函数来创建文档的 HTML 页面,并传入所需参数:
+
+- `openapi_url`:文档 HTML 页面获取你的 API 的 OpenAPI 模式的 URL。这里可以使用 `app.openapi_url` 属性。
+- `title`:你的 API 标题。
+- `oauth2_redirect_url`:这里可以使用 `app.swagger_ui_oauth2_redirect_url` 来使用默认值。
+- `swagger_js_url`:你的 Swagger UI 文档 HTML 获取**JavaScript** 文件的 URL。这里是自定义的 CDN URL。
+- `swagger_css_url`:你的 Swagger UI 文档 HTML 获取**CSS** 文件的 URL。这里是自定义的 CDN URL。
+
+ReDoc 也类似...
+
+{* ../../docs_src/custom_docs_ui/tutorial001_py310.py hl[2:6,11:19,22:24,27:33] *}
+
+/// tip | 提示
+
+`swagger_ui_redirect` 的*路径操作*是在你使用 OAuth2 时的一个辅助。
+
+如果你把 API 与某个 OAuth2 提供方集成,你就可以完成认证并带着获取到的凭据回到 API 文档里。然后使用真实的 OAuth2 认证与之交互。
+
+Swagger UI 会在幕后为你处理这些,但它需要这个“重定向”辅助路径。
+
+///
+
+### 创建一个路径操作进行测试 { #create-a-path-operation-to-test-it }
+
+现在,为了测试一切是否正常,创建一个*路径操作*:
+
+{* ../../docs_src/custom_docs_ui/tutorial001_py310.py hl[36:38] *}
+
+### 测试 { #test-it }
+
+现在,你应该可以访问
http://127.0.0.1:8000/docs,并刷新页面,页面会从新的 CDN 加载这些资源。
+
+## 为文档自托管 JavaScript 和 CSS { #self-hosting-javascript-and-css-for-docs }
+
+如果你需要在离线、无法访问互联网或仅在局域网内时,应用仍能工作,那么自托管 JavaScript 和 CSS 会很有用。
+
+这里你将看到如何在同一个 FastAPI 应用中自行提供这些文件,并配置文档使用它们。
+
+### 项目文件结构 { #project-file-structure }
+
+假设你的项目文件结构如下:
+
+```
+.
+├── app
+│ ├── __init__.py
+│ ├── main.py
+```
+
+现在创建一个目录来存放这些静态文件。
+
+你的新文件结构可能如下:
+
+```
+.
+├── app
+│ ├── __init__.py
+│ ├── main.py
+└── static/
+```
+
+### 下载文件 { #download-the-files }
+
+下载文档需要的静态文件,并将它们放到 `static/` 目录中。
+
+你通常可以右键点击每个链接,选择类似“将链接另存为...”的选项。
+
+Swagger UI 使用以下文件:
+
+-
`swagger-ui-bundle.js`
+-
`swagger-ui.css`
+
+而 ReDoc 使用以下文件:
+
+-
`redoc.standalone.js`
+
+之后,你的文件结构可能如下:
+
+```
+.
+├── app
+│ ├── __init__.py
+│ ├── main.py
+└── static
+ ├── redoc.standalone.js
+ ├── swagger-ui-bundle.js
+ └── swagger-ui.css
+```
+
+### 提供静态文件 { #serve-the-static-files }
+
+- 导入 `StaticFiles`。
+- 在特定路径上“挂载”一个 `StaticFiles()` 实例。
+
+{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[7,11] *}
+
+### 测试静态文件 { #test-the-static-files }
+
+启动你的应用,并访问
http://127.0.0.1:8000/static/redoc.standalone.js。
+
+你应该会看到一个非常长的 **ReDoc** 的 JavaScript 文件。
+
+它可能以如下内容开头:
+
+```JavaScript
+/*! For license information please see redoc.standalone.js.LICENSE.txt */
+!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t(require("null")):
+...
+```
+
+这就确认了你的应用能够提供静态文件,并且你把文档所需的静态文件放在了正确的位置。
+
+现在我们可以配置应用,让文档使用这些静态文件。
+
+### 为静态文件关闭自动文档 { #disable-the-automatic-docs-for-static-files }
+
+和使用自定义 CDN 一样,第一步是关闭自动文档,因为默认情况下它们会使用 CDN。
+
+要关闭它们,在创建 `FastAPI` 应用时将其 URL 设为 `None`:
+
+{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[9] *}
+
+### 为静态文件包含自定义文档 { #include-the-custom-docs-for-static-files }
+
+同样地,现在你可以为自定义文档创建*路径操作*。
+
+你可以再次复用 FastAPI 的内部函数来创建文档的 HTML 页面,并传入所需参数:
+
+- `openapi_url`:文档 HTML 页面获取你的 API 的 OpenAPI 模式的 URL。这里可以使用 `app.openapi_url` 属性。
+- `title`:你的 API 标题。
+- `oauth2_redirect_url`:这里可以使用 `app.swagger_ui_oauth2_redirect_url` 来使用默认值。
+- `swagger_js_url`:你的 Swagger UI 文档 HTML 获取**JavaScript** 文件的 URL。**这是现在由你的应用自己提供的那个**。
+- `swagger_css_url`:你的 Swagger UI 文档 HTML 获取**CSS** 文件的 URL。**这是现在由你的应用自己提供的那个**。
+
+ReDoc 也类似...
+
+{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[2:6,14:22,25:27,30:36] *}
+
+/// tip | 提示
+
+`swagger_ui_redirect` 的*路径操作*是在你使用 OAuth2 时的一个辅助。
+
+如果你把 API 与某个 OAuth2 提供方集成,你就可以完成认证并带着获取到的凭据回到 API 文档里。然后使用真实的 OAuth2 认证与之交互。
+
+Swagger UI 会在幕后为你处理这些,但它需要这个“重定向”辅助路径。
+
+///
+
+### 创建一个路径操作测试静态文件 { #create-a-path-operation-to-test-static-files }
+
+现在,为了测试一切是否正常,创建一个*路径操作*:
+
+{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[39:41] *}
+
+### 测试静态文件 UI { #test-static-files-ui }
+
+现在,你可以断开 WiFi,访问
http://127.0.0.1:8000/docs,并刷新页面。
+
+即使没有互联网,你也能看到 API 的文档并与之交互。
diff --git a/docs/zh/docs/how-to/custom-request-and-route.md b/docs/zh/docs/how-to/custom-request-and-route.md
new file mode 100644
index 0000000000..8b365987ce
--- /dev/null
+++ b/docs/zh/docs/how-to/custom-request-and-route.md
@@ -0,0 +1,109 @@
+# 自定义 Request 和 APIRoute 类 { #custom-request-and-apiroute-class }
+
+在某些情况下,你可能想要重写 `Request` 和 `APIRoute` 类使用的逻辑。
+
+尤其是,当你本来会把这些逻辑放到中间件里时,这是一个不错的替代方案。
+
+例如,如果你想在应用处理之前读取或操作请求体。
+
+/// danger | 危险
+
+这是一个“高级”特性。
+
+如果你刚开始使用 **FastAPI**,可以先跳过本节。
+
+///
+
+## 使用场景 { #use-cases }
+
+一些使用场景包括:
+
+* 将非 JSON 的请求体转换为 JSON(例如
`msgpack`)。
+* 解压缩使用 gzip 压缩的请求体。
+* 自动记录所有请求体日志。
+
+## 处理自定义请求体编码 { #handling-custom-request-body-encodings }
+
+来看如何用自定义的 `Request` 子类来解压 gzip 请求。
+
+以及一个 `APIRoute` 子类来使用该自定义请求类。
+
+### 创建自定义 `GzipRequest` 类 { #create-a-custom-gziprequest-class }
+
+/// tip | 提示
+
+这是一个演示工作原理的示例。如果你需要 Gzip 支持,可以直接使用提供的 [`GzipMiddleware`](../advanced/middleware.md#gzipmiddleware){.internal-link target=_blank}。
+
+///
+
+首先,我们创建一个 `GzipRequest` 类,它会重写 `Request.body()` 方法:当请求头中存在相应标记时对请求体进行解压。
+
+如果请求头中没有 `gzip`,则不会尝试解压。
+
+这样,同一个路由类即可同时处理 gzip 压缩和未压缩的请求。
+
+{* ../../docs_src/custom_request_and_route/tutorial001_an_py310.py hl[9:16] *}
+
+### 创建自定义 `GzipRoute` 类 { #create-a-custom-gziproute-class }
+
+接着,我们创建 `fastapi.routing.APIRoute` 的自定义子类来使用 `GzipRequest`。
+
+这次,我们会重写 `APIRoute.get_route_handler()` 方法。
+
+该方法返回一个函数,这个函数负责接收请求并返回响应。
+
+这里我们用它把原始请求包装为 `GzipRequest`。
+
+{* ../../docs_src/custom_request_and_route/tutorial001_an_py310.py hl[19:27] *}
+
+/// note | 技术细节
+
+`Request` 拥有 `request.scope` 属性,它就是一个 Python `dict`,包含与请求相关的元数据。
+
+`Request` 还包含 `request.receive`,它是一个用于“接收”请求体的函数。
+
+`scope` 字典和 `receive` 函数都是 ASGI 规范的一部分。
+
+创建一个新的 `Request` 实例需要这两样:`scope` 和 `receive`。
+
+想了解更多关于 `Request` 的信息,请查看
Starlette 的 Request 文档。
+
+///
+
+由 `GzipRequest.get_route_handler` 返回的函数唯一不同之处是把 `Request` 转换为 `GzipRequest`。
+
+这样,在传给我们的路径操作之前,`GzipRequest` 会(在需要时)负责解压数据。
+
+之后,其余处理逻辑完全相同。
+
+但由于我们修改了 `GzipRequest.body`,在 **FastAPI** 需要读取时,请求体会被自动解压。
+
+## 在异常处理器中访问请求体 { #accessing-the-request-body-in-an-exception-handler }
+
+/// tip | 提示
+
+要解决类似问题,使用 `RequestValidationError` 的自定义处理器中的 `body` 往往更简单([处理错误](../tutorial/handling-errors.md#use-the-requestvalidationerror-body){.internal-link target=_blank})。
+
+但本示例同样有效,并展示了如何与内部组件交互。
+
+///
+
+我们也可以用相同的方法在异常处理器中访问请求体。
+
+所需仅是在 `try`/`except` 块中处理请求:
+
+{* ../../docs_src/custom_request_and_route/tutorial002_an_py310.py hl[14,16] *}
+
+如果发生异常,`Request` 实例仍在作用域内,因此我们可以在处理错误时读取并使用请求体:
+
+{* ../../docs_src/custom_request_and_route/tutorial002_an_py310.py hl[17:19] *}
+
+## 在路由器中自定义 `APIRoute` 类 { #custom-apiroute-class-in-a-router }
+
+你也可以设置 `APIRouter` 的 `route_class` 参数:
+
+{* ../../docs_src/custom_request_and_route/tutorial003_py310.py hl[26] *}
+
+在此示例中,`router` 下的路径操作将使用自定义的 `TimedRoute` 类,响应中会多一个 `X-Response-Time` 头,包含生成响应所用的时间:
+
+{* ../../docs_src/custom_request_and_route/tutorial003_py310.py hl[13:20] *}
diff --git a/docs/zh/docs/how-to/extending-openapi.md b/docs/zh/docs/how-to/extending-openapi.md
new file mode 100644
index 0000000000..ad8a1d6981
--- /dev/null
+++ b/docs/zh/docs/how-to/extending-openapi.md
@@ -0,0 +1,80 @@
+# 扩展 OpenAPI { #extending-openapi }
+
+在某些情况下,你可能需要修改生成的 OpenAPI 架构(schema)。
+
+本节将介绍如何实现。
+
+## 常规流程 { #the-normal-process }
+
+常规(默认)流程如下。
+
+`FastAPI` 应用(实例)有一个 `.openapi()` 方法,预期返回 OpenAPI 架构。
+
+在创建应用对象时,会注册一个用于 `/openapi.json`(或你在 `openapi_url` 中设置的路径)的路径操作。
+
+它只会返回一个 JSON 响应,内容是应用 `.openapi()` 方法的结果。
+
+默认情况下,`.openapi()` 方法会检查属性 `.openapi_schema` 是否已有内容,若有则直接返回。
+
+如果没有,则使用 `fastapi.openapi.utils.get_openapi` 工具函数生成。
+
+该 `get_openapi()` 函数接收以下参数:
+
+- `title`:OpenAPI 标题,显示在文档中。
+- `version`:你的 API 版本,例如 `2.5.0`。
+- `openapi_version`:使用的 OpenAPI 规范版本。默认是最新的 `3.1.0`。
+- `summary`:API 的简短摘要。
+- `description`:API 的描述,可包含 Markdown,并会展示在文档中。
+- `routes`:路由列表,即已注册的每个路径操作。来自 `app.routes`。
+
+/// info | 信息
+
+参数 `summary` 仅在 OpenAPI 3.1.0 及更高版本中可用,FastAPI 0.99.0 及以上版本支持。
+
+///
+
+## 覆盖默认值 { #overriding-the-defaults }
+
+基于以上信息,你可以用同一个工具函数生成 OpenAPI 架构,并按需覆盖其中的各个部分。
+
+例如,让我们添加
ReDoc 的 OpenAPI 扩展以包含自定义 Logo。
+
+### 常规 **FastAPI** { #normal-fastapi }
+
+首先,像平常一样编写你的 **FastAPI** 应用:
+
+{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[1,4,7:9] *}
+
+### 生成 OpenAPI 架构 { #generate-the-openapi-schema }
+
+然后,在一个 `custom_openapi()` 函数中使用同一个工具函数生成 OpenAPI 架构:
+
+{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[2,15:21] *}
+
+### 修改 OpenAPI 架构 { #modify-the-openapi-schema }
+
+现在你可以添加 ReDoc 扩展,在 OpenAPI 架构的 `info` “对象”中加入自定义 `x-logo`:
+
+{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[22:24] *}
+
+### 缓存 OpenAPI 架构 { #cache-the-openapi-schema }
+
+你可以把 `.openapi_schema` 属性当作“缓存”,用来存储已生成的架构。
+
+这样一来,用户每次打开 API 文档时,应用就不必重新生成架构。
+
+它只会生成一次,后续请求都会使用同一份缓存的架构。
+
+{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[13:14,25:26] *}
+
+### 覆盖方法 { #override-the-method }
+
+现在你可以用你的新函数替换 `.openapi()` 方法。
+
+{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[29] *}
+
+### 验证 { #check-it }
+
+当你访问
http://127.0.0.1:8000/redoc 时,你会看到已使用你的自定义 Logo(本例中为 **FastAPI** 的 Logo):
+
+

diff --git a/docs/zh/docs/how-to/general.md b/docs/zh/docs/how-to/general.md
index e75ad6c79d..2c9f781791 100644
--- a/docs/zh/docs/how-to/general.md
+++ b/docs/zh/docs/how-to/general.md
@@ -36,4 +36,4 @@
## OpenAPI 文档 URL { #openapi-docs-urls }
-要更改用于自动生成文档的 URL,请阅读 [教程 - 元数据和文档 URL](../tutorial/metadata.md#docs-urls){.internal-link target=_blank}。
+要更改自动生成的文档用户界面所使用的 URL,请阅读 [教程 - 元数据和文档 URL](../tutorial/metadata.md#docs-urls){.internal-link target=_blank}。
diff --git a/docs/zh/docs/how-to/graphql.md b/docs/zh/docs/how-to/graphql.md
new file mode 100644
index 0000000000..5384f15137
--- /dev/null
+++ b/docs/zh/docs/how-to/graphql.md
@@ -0,0 +1,60 @@
+# GraphQL { #graphql }
+
+由于 **FastAPI** 基于 **ASGI** 标准,因此很容易集成任何也兼容 ASGI 的 **GraphQL** 库。
+
+你可以在同一个应用中将常规的 FastAPI 路径操作与 GraphQL 结合使用。
+
+/// tip | 提示
+
+**GraphQL** 解决一些非常特定的用例。
+
+与常见的 **Web API** 相比,它有各自的**优点**和**缺点**。
+
+请确保评估在你的用例中,这些**好处**是否足以弥补这些**缺点**。 🤓
+
+///
+
+## GraphQL 库 { #graphql-libraries }
+
+以下是一些支持 **ASGI** 的 **GraphQL** 库。你可以将它们与 **FastAPI** 一起使用:
+
+*
Strawberry 🍓
+ * 提供
面向 FastAPI 的文档
+*
Ariadne
+ * 提供
面向 FastAPI 的文档
+*
Tartiflette
+ * 提供用于 ASGI 集成的
Tartiflette ASGI
+*
Graphene
+ * 可配合
starlette-graphene3 使用
+
+## 使用 Strawberry 的 GraphQL { #graphql-with-strawberry }
+
+如果你需要或想要使用 **GraphQL**,
**Strawberry** 是**推荐**的库,因为它的设计与 **FastAPI** 最为接近,全部基于**类型注解**。
+
+根据你的用例,你可能会更喜欢其他库,但如果你问我,我大概率会建议你先试试 **Strawberry**。
+
+下面是一个将 Strawberry 与 FastAPI 集成的小预览:
+
+{* ../../docs_src/graphql_/tutorial001_py310.py hl[3,22,25] *}
+
+你可以在
Strawberry 文档中了解更多信息。
+
+还有关于
将 Strawberry 与 FastAPI 结合使用的文档。
+
+## Starlette 中较早的 `GraphQLApp` { #older-graphqlapp-from-starlette }
+
+早期版本的 Starlette 包含一个 `GraphQLApp` 类,用于与
Graphene 集成。
+
+它已在 Starlette 中被弃用,但如果你的代码使用了它,你可以轻松**迁移**到
starlette-graphene3,它覆盖相同的用例,且接口**几乎完全一致**。
+
+/// tip | 提示
+
+如果你需要 GraphQL,我仍然建议看看
Strawberry,因为它基于类型注解而不是自定义类和类型。
+
+///
+
+## 了解更多 { #learn-more }
+
+你可以在
GraphQL 官方文档中了解更多关于 **GraphQL** 的内容。
+
+你也可以通过上面的链接阅读各个库的更多信息。
diff --git a/docs/zh/docs/how-to/migrate-from-pydantic-v1-to-pydantic-v2.md b/docs/zh/docs/how-to/migrate-from-pydantic-v1-to-pydantic-v2.md
new file mode 100644
index 0000000000..2e5445200a
--- /dev/null
+++ b/docs/zh/docs/how-to/migrate-from-pydantic-v1-to-pydantic-v2.md
@@ -0,0 +1,135 @@
+# 从 Pydantic v1 迁移到 Pydantic v2 { #migrate-from-pydantic-v1-to-pydantic-v2 }
+
+如果你有一个较旧的 FastAPI 应用,可能在使用 Pydantic v1。
+
+FastAPI 0.100.0 同时支持 Pydantic v1 和 v2,会使用你已安装的任一版本。
+
+FastAPI 0.119.0 引入了在 Pydantic v2 内部以 `pydantic.v1` 形式对 Pydantic v1 的部分支持,以便于迁移到 v2。
+
+FastAPI 0.126.0 移除了对 Pydantic v1 的支持,但在一段时间内仍支持 `pydantic.v1`。
+
+/// warning | 警告
+
+从 Python 3.14 开始,Pydantic 团队不再为最新的 Python 版本提供 Pydantic v1 的支持。
+
+这也包括 `pydantic.v1`,在 Python 3.14 及更高版本中不再受支持。
+
+如果你想使用 Python 的最新特性,需要确保使用 Pydantic v2。
+
+///
+
+如果你的旧 FastAPI 应用在用 Pydantic v1,这里将向你展示如何迁移到 Pydantic v2,以及 FastAPI 0.119.0 中可帮助你渐进式迁移的功能。
+
+## 官方指南 { #official-guide }
+
+Pydantic 有一份从 v1 迁移到 v2 的官方
迁移指南。
+
+其中包含变更内容、校验如何更准确更严格、可能的注意事项等。
+
+你可以阅读以更好地了解变更。
+
+## 测试 { #tests }
+
+请确保你的应用有[测试](../tutorial/testing.md){.internal-link target=_blank},并在持续集成(CI)中运行它们。
+
+这样你就可以升级并确保一切仍按预期工作。
+
+## `bump-pydantic` { #bump-pydantic }
+
+在很多情况下,如果你使用的是未做自定义的常规 Pydantic 模型,可以将从 Pydantic v1 迁移到 v2 的大部分过程自动化。
+
+你可以使用同一 Pydantic 团队提供的
`bump-pydantic`。
+
+该工具会帮助你自动修改大部分需要变更的代码。
+
+之后运行测试检查是否一切正常。如果正常,你就完成了。😎
+
+## v2 中的 Pydantic v1 { #pydantic-v1-in-v2 }
+
+Pydantic v2 以子模块 `pydantic.v1` 的形式包含了 Pydantic v1 的全部内容。但在 Python 3.13 以上的版本中不再受支持。
+
+这意味着你可以安装最新的 Pydantic v2,并从该子模块导入并使用旧的 Pydantic v1 组件,就像安装了旧版 Pydantic v1 一样。
+
+{* ../../docs_src/pydantic_v1_in_v2/tutorial001_an_py310.py hl[1,4] *}
+
+### FastAPI 对 v2 中 Pydantic v1 的支持 { #fastapi-support-for-pydantic-v1-in-v2 }
+
+自 FastAPI 0.119.0 起,FastAPI 也对 Pydantic v2 内的 Pydantic v1 提供了部分支持,以便迁移到 v2。
+
+因此,你可以将 Pydantic 升级到最新的 v2,并将导入改为使用 `pydantic.v1` 子模块,在很多情况下就能直接工作。
+
+{* ../../docs_src/pydantic_v1_in_v2/tutorial002_an_py310.py hl[2,5,15] *}
+
+/// warning | 警告
+
+请注意,由于 Pydantic 团队自 Python 3.14 起不再在较新的 Python 版本中支持 Pydantic v1,使用 `pydantic.v1` 在 Python 3.14 及更高版本中也不受支持。
+
+///
+
+### 同一应用中同时使用 Pydantic v1 与 v2 { #pydantic-v1-and-v2-on-the-same-app }
+
+Pydantic 不支持在一个 Pydantic v2 模型的字段中定义 Pydantic v1 模型,反之亦然。
+
+```mermaid
+graph TB
+ subgraph "❌ Not Supported"
+ direction TB
+ subgraph V2["Pydantic v2 Model"]
+ V1Field["Pydantic v1 Model"]
+ end
+ subgraph V1["Pydantic v1 Model"]
+ V2Field["Pydantic v2 Model"]
+ end
+ end
+
+ style V2 fill:#f9fff3
+ style V1 fill:#fff6f0
+ style V1Field fill:#fff6f0
+ style V2Field fill:#f9fff3
+```
+
+...但是,你可以在同一个应用中分别使用 Pydantic v1 和 v2 的独立模型。
+
+```mermaid
+graph TB
+ subgraph "✅ Supported"
+ direction TB
+ subgraph V2["Pydantic v2 Model"]
+ V2Field["Pydantic v2 Model"]
+ end
+ subgraph V1["Pydantic v1 Model"]
+ V1Field["Pydantic v1 Model"]
+ end
+ end
+
+ style V2 fill:#f9fff3
+ style V1 fill:#fff6f0
+ style V1Field fill:#fff6f0
+ style V2Field fill:#f9fff3
+```
+
+在某些情况下,甚至可以在 FastAPI 应用的同一个路径操作中同时使用 Pydantic v1 和 v2 模型:
+
+{* ../../docs_src/pydantic_v1_in_v2/tutorial003_an_py310.py hl[2:3,6,12,21:22] *}
+
+在上面的示例中,输入模型是 Pydantic v1 模型,输出模型(在 `response_model=ItemV2` 中定义)是 Pydantic v2 模型。
+
+### Pydantic v1 参数 { #pydantic-v1-parameters }
+
+如果你需要在 Pydantic v1 模型中使用 FastAPI 特有的参数工具,如 `Body`、`Query`、`Form` 等,在完成向 Pydantic v2 的迁移前,可以从 `fastapi.temp_pydantic_v1_params` 导入它们:
+
+{* ../../docs_src/pydantic_v1_in_v2/tutorial004_an_py310.py hl[4,18] *}
+
+### 分步迁移 { #migrate-in-steps }
+
+/// tip | 提示
+
+优先尝试 `bump-pydantic`,如果测试通过且可行,那么你就用一个命令完成了。✨
+
+///
+
+如果 `bump-pydantic` 不适用于你的场景,你可以在同一应用中同时支持 Pydantic v1 和 v2 模型,逐步迁移到 Pydantic v2。
+
+你可以首先将 Pydantic 升级到最新的 v2,并将所有模型的导入改为使用 `pydantic.v1`。
+
+然后按模块或分组,逐步把模型从 Pydantic v1 迁移到 v2。🚶
diff --git a/docs/zh/docs/how-to/separate-openapi-schemas.md b/docs/zh/docs/how-to/separate-openapi-schemas.md
new file mode 100644
index 0000000000..c3efe5f1a4
--- /dev/null
+++ b/docs/zh/docs/how-to/separate-openapi-schemas.md
@@ -0,0 +1,102 @@
+# 是否为输入和输出分别生成 OpenAPI JSON Schema { #separate-openapi-schemas-for-input-and-output-or-not }
+
+自从发布了 **Pydantic v2**,生成的 OpenAPI 比之前更精确、更**正确**了。😎
+
+事实上,在某些情况下,对于同一个 Pydantic 模型,OpenAPI 中会根据是否带有**默认值**,为输入和输出分别生成**两个 JSON Schema**。
+
+我们来看看它如何工作,以及在需要时如何修改。
+
+## 用于输入和输出的 Pydantic 模型 { #pydantic-models-for-input-and-output }
+
+假设你有一个带有默认值的 Pydantic 模型,例如:
+
+{* ../../docs_src/separate_openapi_schemas/tutorial001_py310.py ln[1:7] hl[7] *}
+
+### 输入用的模型 { #model-for-input }
+
+如果你像下面这样把该模型用作输入:
+
+{* ../../docs_src/separate_openapi_schemas/tutorial001_py310.py ln[1:15] hl[14] *}
+
+...那么 `description` 字段将**不是必填项**,因为它的默认值是 `None`。
+
+### 文档中的输入模型 { #input-model-in-docs }
+
+你可以在文档中确认,`description` 字段没有**红色星号**,也就是未被标记为必填:
+
+
+

+
+
+### 输出用的模型 { #model-for-output }
+
+但如果你把同一个模型用作输出,例如:
+
+{* ../../docs_src/separate_openapi_schemas/tutorial001_py310.py hl[19] *}
+
+...那么因为 `description` 有默认值,即使你**不返回该字段**,它仍然会有这个**默认值**。
+
+### 输出响应数据的模型 { #model-for-output-response-data }
+
+如果你在文档中交互并查看响应,即使代码没有给某个 `description` 字段赋值,JSON 响应中仍包含默认值(`null`):
+
+
+

+
+
+这意味着它**总会有值**,只是有时该值可能为 `None`(在 JSON 中是 `null`)。
+
+这也意味着,使用你的 API 的客户端无需检查该值是否存在,他们可以**假设该字段总会存在**,只是有时它会是默认值 `None`。
+
+在 OpenAPI 中描述这一点的方式,是把该字段标记为**必填**,因为它总会存在。
+
+因此,一个模型的 JSON Schema 会根据它用于**输入还是输出**而有所不同:
+
+- 用于**输入**时,`description` **不是必填**
+- 用于**输出**时,它是**必填**(并且可能为 `None`,在 JSON 中为 `null`)
+
+### 文档中的输出模型 { #model-for-output-in-docs }
+
+你也可以在文档中查看输出模型,`name` 和 `description` **都**被**红色星号**标记为**必填**:
+
+
+

+
+
+### 文档中的输入/输出模型 { #model-for-input-and-output-in-docs }
+
+如果你查看 OpenAPI 中可用的所有 Schema(JSON Schema),你会看到有两个,一个是 `Item-Input`,一个是 `Item-Output`。
+
+对于 `Item-Input`,`description` **不是必填**,没有红色星号。
+
+但对于 `Item-Output`,`description` 是**必填**,带有红色星号。
+
+
+

+
+
+借助 **Pydantic v2** 的这个特性,你的 API 文档会更**精确**,如果你有自动生成的客户端和 SDK,它们也会更精确,带来更好的**开发者体验**和一致性。🎉
+
+## 不要分离 Schema { #do-not-separate-schemas }
+
+当然,在某些情况下,你可能希望**输入和输出使用同一个 schema**。
+
+最常见的情形是:你已经有一些自动生成的客户端代码/SDK,你暂时不想更新所有这些自动生成的客户端代码/SDK(也许未来会,但不是现在)。
+
+这种情况下,你可以在 **FastAPI** 中通过参数 `separate_input_output_schemas=False` 禁用该特性。
+
+/// info | 信息
+
+对 `separate_input_output_schemas` 的支持是在 FastAPI `0.102.0` 中添加的。🤓
+
+///
+
+{* ../../docs_src/separate_openapi_schemas/tutorial002_py310.py hl[10] *}
+
+### 文档中输入/输出使用同一 Schema 的模型 { #same-schema-for-input-and-output-models-in-docs }
+
+现在该模型的输入和输出将只使用一个 schema,即 `Item`,并且其中的 `description` **不是必填**:
+
+
+

+
diff --git a/docs/zh/docs/how-to/testing-database.md b/docs/zh/docs/how-to/testing-database.md
new file mode 100644
index 0000000000..e4a20d8436
--- /dev/null
+++ b/docs/zh/docs/how-to/testing-database.md
@@ -0,0 +1,7 @@
+# 测试数据库 { #testing-a-database }
+
+你可以在
SQLModel 文档 中学习数据库、SQL 和 SQLModel。🤓
+
+这里有一个关于在 FastAPI 中使用 SQLModel 的小教程:
使用 SQLModel 搭配 FastAPI 的教程。✨
+
+该教程包含一个关于
测试 SQL 数据库 的章节。😎
diff --git a/docs/zh/docs/index.md b/docs/zh/docs/index.md
index 1c2aea3285..38e128bf14 100644
--- a/docs/zh/docs/index.md
+++ b/docs/zh/docs/index.md
@@ -40,7 +40,7 @@ FastAPI 是一个用于构建 API 的现代、快速(高性能)的 Web 框
* **快速**:极高性能,可与 **NodeJS** 和 **Go** 并肩(归功于 Starlette 和 Pydantic)。[最快的 Python 框架之一](#performance)。
* **高效编码**:功能开发速度提升约 200% ~ 300%。*
* **更少 bug**:人为(开发者)错误减少约 40%。*
-* **直观**:极佳的编辑器支持。处处皆可
自动补全。更少的调试时间。
+* **直观**:极佳的编辑器支持。处处皆可
自动补全。更少的调试时间。
* **易用**:为易用和易学而设计。更少的文档阅读时间。
* **简短**:最小化代码重复。一次参数声明即可获得多种功能。更少的 bug。
* **健壮**:生产可用级代码。并带有自动生成的交互式文档。
@@ -368,7 +368,7 @@ item: Item
* 数据校验:
* 当数据无效时自动生成清晰的错误信息。
* 即便是多层嵌套的 JSON 对象也会进行校验。
-* 输入数据的
转换:从网络读取到 Python 数据和类型。读取来源:
+*
转换输入数据:从网络读取到 Python 数据和类型。读取来源:
* JSON。
* 路径参数。
* 查询参数。
@@ -376,7 +376,7 @@ item: Item
* Headers。
* Forms。
* Files。
-* 输出数据的
转换:从 Python 数据和类型转换为网络数据(JSON):
+*
转换输出数据:从 Python 数据和类型转换为网络数据(JSON):
* 转换 Python 类型(`str`、`int`、`float`、`bool`、`list` 等)。
* `datetime` 对象。
* `UUID` 对象。
@@ -439,7 +439,7 @@ item: Item
* 来自不同位置的**参数**声明:**headers**、**cookies**、**form 字段**和**文件**。
* 如何设置**校验约束**,如 `maximum_length` 或 `regex`。
-* 功能强大且易用的 **
依赖注入** 系统。
+* 功能强大且易用的 **
依赖注入** 系统。
* 安全与认证,包括对 **OAuth2**、**JWT tokens** 和 **HTTP Basic** 认证的支持。
* 更高级(但同样简单)的 **多层嵌套 JSON 模型** 声明技巧(得益于 Pydantic)。
* 通过
Strawberry 等库进行 **GraphQL** 集成。
@@ -524,7 +524,7 @@ Starlette 使用:
*
httpx - 使用 `TestClient` 时需要。
*
jinja2 - 使用默认模板配置时需要。
-*
python-multipart - 使用 `request.form()` 支持表单
「解析」时需要。
+*
python-multipart - 使用 `request.form()` 支持表单
「解析」时需要。
FastAPI 使用:
diff --git a/docs/zh/docs/python-types.md b/docs/zh/docs/python-types.md
index 3e1c593c11..4824b7558d 100644
--- a/docs/zh/docs/python-types.md
+++ b/docs/zh/docs/python-types.md
@@ -2,11 +2,11 @@
Python 支持可选的“类型提示”(也叫“类型注解”)。
-这些“类型提示”或注解是一种特殊语法,用来声明变量的
类型。
+这些“类型提示”或注解是一种特殊语法,用来声明变量的
类型。
通过为变量声明类型,编辑器和工具可以为你提供更好的支持。
-这只是一个关于 Python 类型提示的快速入门/复习。它只涵盖与 **FastAPI** 一起使用所需的最少部分……实际上非常少。
+这只是一个关于 Python 类型提示的快速入门/复习。它只涵盖与 **FastAPI** 一起使用所需的最少部分...实际上非常少。
**FastAPI** 完全基于这些类型提示构建,它们带来了许多优势和好处。
@@ -22,7 +22,7 @@ Python 支持可选的“类型提示”(也叫“类型注解”)。
让我们从一个简单的例子开始:
-{* ../../docs_src/python_types/tutorial001_py39.py *}
+{* ../../docs_src/python_types/tutorial001_py310.py *}
运行这个程序会输出:
@@ -34,9 +34,9 @@ John Doe
* 接收 `first_name` 和 `last_name`。
* 通过 `title()` 将每个参数的第一个字母转换为大写。
-* 用一个空格将它们
拼接起来。
+* 用一个空格将它们
拼接起来。
-{* ../../docs_src/python_types/tutorial001_py39.py hl[2] *}
+{* ../../docs_src/python_types/tutorial001_py310.py hl[2] *}
### 修改它 { #edit-it }
@@ -78,7 +78,7 @@ John Doe
这些就是“类型提示”:
-{* ../../docs_src/python_types/tutorial002_py39.py hl[1] *}
+{* ../../docs_src/python_types/tutorial002_py310.py hl[1] *}
这和声明默认值不同,比如:
@@ -106,7 +106,7 @@ John Doe
看这个已经带有类型提示的函数:
-{* ../../docs_src/python_types/tutorial003_py39.py hl[1] *}
+{* ../../docs_src/python_types/tutorial003_py310.py hl[1] *}
因为编辑器知道变量的类型,你不仅能得到补全,还能获得错误检查:
@@ -114,7 +114,7 @@ John Doe
现在你知道需要修复它,用 `str(age)` 把 `age` 转成字符串:
-{* ../../docs_src/python_types/tutorial004_py39.py hl[2] *}
+{* ../../docs_src/python_types/tutorial004_py310.py hl[2] *}
## 声明类型 { #declaring-types }
@@ -133,29 +133,32 @@ John Doe
* `bool`
* `bytes`
-{* ../../docs_src/python_types/tutorial005_py39.py hl[1] *}
+{* ../../docs_src/python_types/tutorial005_py310.py hl[1] *}
-### 带类型参数的泛型类型 { #generic-types-with-type-parameters }
+### typing 模块 { #typing-module }
-有些数据结构可以包含其他值,比如 `dict`、`list`、`set` 和 `tuple`。而内部的值也会有自己的类型。
+在一些额外的用例中,你可能需要从标准库的 `typing` 模块导入内容。比如当你想声明“任意类型”时,可以使用 `typing` 中的 `Any`:
-这些带有内部类型的类型称为“泛型”(generic)类型。可以把它们连同内部类型一起声明出来。
+```python
+from typing import Any
-要声明这些类型以及内部类型,你可以使用 Python 标准库模块 `typing`。它就是为支持这些类型提示而存在的。
-#### 更新的 Python 版本 { #newer-versions-of-python }
-
-使用 `typing` 的语法与所有版本兼容,从 Python 3.6 到最新版本(包括 Python 3.9、Python 3.10 等)。
+def some_function(data: Any):
+ print(data)
+```
-随着 Python 的发展,更新的版本对这些类型注解的支持更好,在很多情况下你甚至不需要导入和使用 `typing` 模块来声明类型注解。
+### 泛型类型 { #generic-types }
-如果你可以为项目选择更高版本的 Python,你将能享受到这种额外的简化。
+有些类型可以在方括号中接收“类型参数”(type parameters),用于声明其内部值的类型。比如“字符串列表”可以写为 `list[str]`。
-在整个文档中,会根据不同 Python 版本提供相应的示例(当存在差异时)。
+这些能接收类型参数的类型称为“泛型类型”(Generic types)或“泛型”(Generics)。
-比如“Python 3.6+”表示兼容 Python 3.6 及以上(包括 3.7、3.8、3.9、3.10 等)。而“Python 3.9+”表示兼容 Python 3.9 及以上(包括 3.10 等)。
+你可以把相同的内建类型作为泛型使用(带方括号和内部类型):
-如果你可以使用最新的 Python 版本,请使用最新版本的示例,它们将拥有最简洁的语法,例如“Python 3.10+”。
+* `list`
+* `tuple`
+* `set`
+* `dict`
#### 列表 { #list }
@@ -167,7 +170,7 @@ John Doe
因为 list 是一种包含内部类型的类型,把内部类型写在方括号里:
-{* ../../docs_src/python_types/tutorial006_py39.py hl[1] *}
+{* ../../docs_src/python_types/tutorial006_py310.py hl[1] *}
/// info | 信息
@@ -193,7 +196,7 @@ John Doe
声明 `tuple` 和 `set` 的方式类似:
-{* ../../docs_src/python_types/tutorial007_py39.py hl[1] *}
+{* ../../docs_src/python_types/tutorial007_py310.py hl[1] *}
这表示:
@@ -208,7 +211,7 @@ John Doe
第二个类型参数用于字典的值:
-{* ../../docs_src/python_types/tutorial008_py39.py hl[1] *}
+{* ../../docs_src/python_types/tutorial008_py310.py hl[1] *}
这表示:
@@ -220,44 +223,20 @@ John Doe
你可以声明一个变量可以是若干种类型中的任意一种,比如既可以是 `int` 也可以是 `str`。
-在 Python 3.6 及以上(包括 Python 3.10),你可以使用 `typing` 中的 `Union`,把可能的类型放到方括号里。
-
-在 Python 3.10 中还有一种新的语法,可以用
竖线(`|`)把可能的类型分隔开。
+定义时使用
竖线(`|`)把两种类型分开。
-//// tab | Python 3.10+
+这称为“联合类型”(union),因为变量可以是这两类类型集合的并集中的任意一个。
```Python hl_lines="1"
{!> ../../docs_src/python_types/tutorial008b_py310.py!}
```
-////
-
-//// tab | Python 3.9+
-
-```Python hl_lines="1 4"
-{!> ../../docs_src/python_types/tutorial008b_py39.py!}
-```
-
-////
-
-两种方式的含义一致:`item` 可以是 `int` 或 `str`。
+这表示 `item` 可以是 `int` 或 `str`。
#### 可能为 `None` { #possibly-none }
你可以声明一个值的类型是某种类型(比如 `str`),但它也可能是 `None`。
-在 Python 3.6 及以上(包括 Python 3.10),你可以通过从 `typing` 模块导入并使用 `Optional` 来声明:
-
-```Python hl_lines="1 4"
-{!../../docs_src/python_types/tutorial009_py39.py!}
-```
-
-使用 `Optional[str]` 而不是仅仅 `str`,可以让编辑器帮助你发现把值当成总是 `str` 的错误(实际上它也可能是 `None`)。
-
-`Optional[Something]` 实际上是 `Union[Something, None]` 的简写,它们等价。
-
-这也意味着在 Python 3.10 中,你可以使用 `Something | None`:
-
//// tab | Python 3.10+
```Python hl_lines="1"
@@ -266,96 +245,7 @@ John Doe
////
-//// tab | Python 3.9+
-
-```Python hl_lines="1 4"
-{!> ../../docs_src/python_types/tutorial009_py39.py!}
-```
-
-////
-
-//// tab | Python 3.9+ 另一种写法
-
-```Python hl_lines="1 4"
-{!> ../../docs_src/python_types/tutorial009b_py39.py!}
-```
-
-////
-
-#### 使用 `Union` 或 `Optional` { #using-union-or-optional }
-
-如果你使用的是 3.10 以下的 Python 版本,这里有个来自我非常主观的建议:
-
-* 🚨 避免使用 `Optional[SomeType]`
-* 改用 ✨**`Union[SomeType, None]`**✨
-
-两者等价,底层相同,但我更推荐 `Union` 而不是 `Optional`,因为“optional(可选)”这个词看起来像是在说“参数可选”,而它实际上表示“它可以是 `None`”,即使它并不是可选的,仍然是必填的。
-
-我认为 `Union[SomeType, None]` 更明确地表达了它的意思。
-
-这只是关于词语和名字。但这些词会影响你和你的队友如何理解代码。
-
-例如,看下面这个函数:
-
-{* ../../docs_src/python_types/tutorial009c_py39.py hl[1,4] *}
-
-参数 `name` 被定义为 `Optional[str]`,但它并不是“可选”的,你不能不传这个参数就调用函数:
-
-```Python
-say_hi() # 哦不,这会抛错!😱
-```
-
-参数 `name` 仍然是必填的(不是“可选”),因为它没有默认值。不过,`name` 接受 `None` 作为值:
-
-```Python
-say_hi(name=None) # 这样可以,None 是有效值 🎉
-```
-
-好消息是,一旦你使用 Python 3.10,就无需再为此操心,因为你可以直接用 `|` 来定义类型联合:
-
-{* ../../docs_src/python_types/tutorial009c_py310.py hl[1,4] *}
-
-这样你就不必再考虑 `Optional` 和 `Union` 这些名字了。😎
-
-#### 泛型类型 { #generic-types }
-
-这些在方括号中接收类型参数的类型称为“泛型类型”(Generic types)或“泛型”(Generics),例如:
-
-//// tab | Python 3.10+
-
-你可以把同样的内建类型作为泛型使用(带方括号和内部类型):
-
-* `list`
-* `tuple`
-* `set`
-* `dict`
-
-以及与之前的 Python 版本一样,来自 `typing` 模块的:
-
-* `Union`
-* `Optional`
-* ……以及其他。
-
-在 Python 3.10 中,作为使用泛型 `Union` 和 `Optional` 的替代,你可以使用
竖线(`|`)来声明类型联合,这更好也更简单。
-
-////
-
-//// tab | Python 3.9+
-
-你可以把同样的内建类型作为泛型使用(带方括号和内部类型):
-
-* `list`
-* `tuple`
-* `set`
-* `dict`
-
-以及来自 `typing` 模块的泛型:
-
-* `Union`
-* `Optional`
-* ……以及其他。
-
-////
+使用 `str | None` 而不是仅仅 `str`,可以让编辑器帮助你发现把值当成总是 `str` 的错误(实际上它也可能是 `None`)。
### 类作为类型 { #classes-as-types }
@@ -363,11 +253,11 @@ say_hi(name=None) # 这样可以,None 是有效值 🎉
假设你有一个名为 `Person` 的类,带有 name:
-{* ../../docs_src/python_types/tutorial010_py39.py hl[1:3] *}
+{* ../../docs_src/python_types/tutorial010_py310.py hl[1:3] *}
然后你可以声明一个变量是 `Person` 类型:
-{* ../../docs_src/python_types/tutorial010_py39.py hl[6] *}
+{* ../../docs_src/python_types/tutorial010_py310.py hl[6] *}
接着,你会再次获得所有的编辑器支持:
@@ -403,19 +293,13 @@ say_hi(name=None) # 这样可以,None 是有效值 🎉
你会在[教程 - 用户指南](tutorial/index.md){.internal-link target=_blank}中看到更多的实战示例。
-/// tip | 提示
-
-当你在没有默认值的情况下使用 `Optional` 或 `Union[Something, None]` 时,Pydantic 有一个特殊行为,你可以在 Pydantic 文档的
必填的 Optional 字段 中了解更多。
-
-///
-
## 带元数据注解的类型提示 { #type-hints-with-metadata-annotations }
-Python 还提供了一个特性,可以使用 `Annotated` 在这些类型提示中放入额外的
元数据。
+Python 还提供了一个特性,可以使用 `Annotated` 在这些类型提示中放入额外的
元数据。
-从 Python 3.9 起,`Annotated` 是标准库的一部分,因此可以从 `typing` 导入。
+你可以从 `typing` 导入 `Annotated`。
-{* ../../docs_src/python_types/tutorial013_py39.py hl[1,4] *}
+{* ../../docs_src/python_types/tutorial013_py310.py hl[1,4] *}
Python 本身不会对这个 `Annotated` 做任何处理。对于编辑器和其他工具,类型仍然是 `str`。
diff --git a/docs/zh/docs/resources/index.md b/docs/zh/docs/resources/index.md
new file mode 100644
index 0000000000..2f55ac06f6
--- /dev/null
+++ b/docs/zh/docs/resources/index.md
@@ -0,0 +1,3 @@
+# 资源 { #resources }
+
+更多资源、外部链接等。✈️
diff --git a/docs/zh/docs/translation-banner.md b/docs/zh/docs/translation-banner.md
new file mode 100644
index 0000000000..76db203b0b
--- /dev/null
+++ b/docs/zh/docs/translation-banner.md
@@ -0,0 +1,11 @@
+/// details | 🌐 由 AI 与人类协作翻译
+
+本翻译由人类引导的 AI 生成。🤝
+
+可能存在误解原意或不够自然等问题。🤖
+
+你可以通过[帮助我们更好地引导 AI LLM](https://fastapi.tiangolo.com/zh/contributing/#translations)来改进此翻译。
+
+[英文版本](ENGLISH_VERSION_URL)
+
+///
diff --git a/docs/zh/docs/tutorial/background-tasks.md b/docs/zh/docs/tutorial/background-tasks.md
index 8398472c37..d73fee4299 100644
--- a/docs/zh/docs/tutorial/background-tasks.md
+++ b/docs/zh/docs/tutorial/background-tasks.md
@@ -15,7 +15,7 @@
首先导入 `BackgroundTasks` 并在 *路径操作函数* 中使用类型声明 `BackgroundTasks` 定义一个参数:
-{* ../../docs_src/background_tasks/tutorial001_py39.py hl[1,13] *}
+{* ../../docs_src/background_tasks/tutorial001_py310.py hl[1,13] *}
**FastAPI** 会创建一个 `BackgroundTasks` 类型的对象并作为该参数传入。
@@ -31,13 +31,13 @@
由于写操作不使用 `async` 和 `await`,我们用普通的 `def` 定义函数:
-{* ../../docs_src/background_tasks/tutorial001_py39.py hl[6:9] *}
+{* ../../docs_src/background_tasks/tutorial001_py310.py hl[6:9] *}
## 添加后台任务 { #add-the-background-task }
在你的 *路径操作函数* 里,用 `.add_task()` 方法将任务函数传到 *后台任务* 对象中:
-{* ../../docs_src/background_tasks/tutorial001_py39.py hl[14] *}
+{* ../../docs_src/background_tasks/tutorial001_py310.py hl[14] *}
`.add_task()` 接收以下参数:
@@ -69,7 +69,7 @@
在FastAPI中仍然可以单独使用 `BackgroundTask`,但您必须在代码中创建对象,并返回包含它的Starlette `Response`。
-更多细节查看
Starlette's official docs for Background Tasks.
+更多细节查看
Starlette 后台任务的官方文档.
## 告诫 { #caveat }
diff --git a/docs/zh/docs/tutorial/bigger-applications.md b/docs/zh/docs/tutorial/bigger-applications.md
index 1ced002dc3..a667d596f8 100644
--- a/docs/zh/docs/tutorial/bigger-applications.md
+++ b/docs/zh/docs/tutorial/bigger-applications.md
@@ -85,7 +85,7 @@ from app.routers import items
你可以导入它并通过与 `FastAPI` 类相同的方式创建一个「实例」:
-{* ../../docs_src/bigger_applications/app_an_py39/routers/users.py hl[1,3] title["app/routers/users.py"] *}
+{* ../../docs_src/bigger_applications/app_an_py310/routers/users.py hl[1,3] title["app/routers/users.py"] *}
### 使用 `APIRouter` 的*路径操作* { #path-operations-with-apirouter }
@@ -93,7 +93,7 @@ from app.routers import items
使用方式与 `FastAPI` 类相同:
-{* ../../docs_src/bigger_applications/app_an_py39/routers/users.py hl[6,11,16] title["app/routers/users.py"] *}
+{* ../../docs_src/bigger_applications/app_an_py310/routers/users.py hl[6,11,16] title["app/routers/users.py"] *}
你可以将 `APIRouter` 视为一个「迷你 `FastAPI`」类。
@@ -117,7 +117,7 @@ from app.routers import items
现在我们将使用一个简单的依赖项来读取一个自定义的 `X-Token` 请求首部:
-{* ../../docs_src/bigger_applications/app_an_py39/dependencies.py hl[3,6:8] title["app/dependencies.py"] *}
+{* ../../docs_src/bigger_applications/app_an_py310/dependencies.py hl[3,6:8] title["app/dependencies.py"] *}
/// tip | 提示
@@ -149,7 +149,7 @@ from app.routers import items
因此,我们可以将其添加到 `APIRouter` 中,而不是将其添加到每个路径操作中。
-{* ../../docs_src/bigger_applications/app_an_py39/routers/items.py hl[5:10,16,21] title["app/routers/items.py"] *}
+{* ../../docs_src/bigger_applications/app_an_py310/routers/items.py hl[5:10,16,21] title["app/routers/items.py"] *}
由于每个*路径操作*的路径都必须以 `/` 开头,例如:
@@ -208,7 +208,7 @@ async def read_item(item_id: str):
因此,我们通过 `..` 对依赖项使用了相对导入:
-{* ../../docs_src/bigger_applications/app_an_py39/routers/items.py hl[3] title["app/routers/items.py"] *}
+{* ../../docs_src/bigger_applications/app_an_py310/routers/items.py hl[3] title["app/routers/items.py"] *}
#### 相对导入如何工作 { #how-relative-imports-work }
@@ -279,11 +279,11 @@ from ...dependencies import get_token_header
但是我们仍然可以添加*更多*将会应用于特定的*路径操作*的 `tags`,以及一些特定于该*路径操作*的额外 `responses`:
-{* ../../docs_src/bigger_applications/app_an_py39/routers/items.py hl[30:31] title["app/routers/items.py"] *}
+{* ../../docs_src/bigger_applications/app_an_py310/routers/items.py hl[30:31] title["app/routers/items.py"] *}
/// tip | 提示
-最后的这个路径操作将包含标签的组合:`["items","custom"]`。
+最后的这个路径操作将包含标签的组合:`["items", "custom"]`。
并且在文档中也会有两个响应,一个用于 `404`,一个用于 `403`。
@@ -305,13 +305,13 @@ from ...dependencies import get_token_header
我们甚至可以声明[全局依赖项](dependencies/global-dependencies.md){.internal-link target=_blank},它会和每个 `APIRouter` 的依赖项组合在一起:
-{* ../../docs_src/bigger_applications/app_an_py39/main.py hl[1,3,7] title["app/main.py"] *}
+{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[1,3,7] title["app/main.py"] *}
### 导入 `APIRouter` { #import-the-apirouter }
现在,我们导入具有 `APIRouter` 的其他子模块:
-{* ../../docs_src/bigger_applications/app_an_py39/main.py hl[4:5] title["app/main.py"] *}
+{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[4:5] title["app/main.py"] *}
由于文件 `app/routers/users.py` 和 `app/routers/items.py` 是同一 Python 包 `app` 一个部分的子模块,因此我们可以使用单个点 ` .` 通过「相对导入」来导入它们。
@@ -374,13 +374,13 @@ from .routers.users import router
因此,为了能够在同一个文件中使用它们,我们直接导入子模块:
-{* ../../docs_src/bigger_applications/app_an_py39/main.py hl[5] title["app/main.py"] *}
+{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[5] title["app/main.py"] *}
### 包含 `users` 和 `items` 的 `APIRouter` { #include-the-apirouters-for-users-and-items }
现在,让我们来包含来自 `users` 和 `items` 子模块的 `router`。
-{* ../../docs_src/bigger_applications/app_an_py39/main.py hl[10:11] title["app/main.py"] *}
+{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[10:11] title["app/main.py"] *}
/// info | 信息
@@ -420,13 +420,13 @@ from .routers.users import router
对于此示例,它将非常简单。但是假设由于它是与组织中的其他项目所共享的,因此我们无法对其进行修改,以及直接在 `APIRouter` 中添加 `prefix`、`dependencies`、`tags` 等:
-{* ../../docs_src/bigger_applications/app_an_py39/internal/admin.py hl[3] title["app/internal/admin.py"] *}
+{* ../../docs_src/bigger_applications/app_an_py310/internal/admin.py hl[3] title["app/internal/admin.py"] *}
但是我们仍然希望在包含 `APIRouter` 时设置一个自定义的 `prefix`,以便其所有*路径操作*以 `/admin` 开头,我们希望使用本项目已经有的 `dependencies` 保护它,并且我们希望它包含自定义的 `tags` 和 `responses`。
我们可以通过将这些参数传递给 `app.include_router()` 来完成所有的声明,而不必修改原始的 `APIRouter`:
-{* ../../docs_src/bigger_applications/app_an_py39/main.py hl[14:17] title["app/main.py"] *}
+{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[14:17] title["app/main.py"] *}
这样,原始的 `APIRouter` 将保持不变,因此我们仍然可以与组织中的其他项目共享相同的 `app/internal/admin.py` 文件。
@@ -447,7 +447,7 @@ from .routers.users import router
这里我们这样做了...只是为了表明我们可以做到🤷:
-{* ../../docs_src/bigger_applications/app_an_py39/main.py hl[21:23] title["app/main.py"] *}
+{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[21:23] title["app/main.py"] *}
它将与通过 `app.include_router()` 添加的所有其他*路径操作*一起正常运行。
diff --git a/docs/zh/docs/tutorial/body-multiple-params.md b/docs/zh/docs/tutorial/body-multiple-params.md
index 7d0ddfc1ec..39b84904fc 100644
--- a/docs/zh/docs/tutorial/body-multiple-params.md
+++ b/docs/zh/docs/tutorial/body-multiple-params.md
@@ -104,12 +104,6 @@
q: str | None = None
```
-或者在 Python 3.9 中:
-
-```Python
-q: Union[str, None] = None
-```
-
比如:
{* ../../docs_src/body_multiple_params/tutorial004_an_py310.py hl[28] *}
diff --git a/docs/zh/docs/tutorial/body-nested-models.md b/docs/zh/docs/tutorial/body-nested-models.md
index 242aa5822c..fe6902e83f 100644
--- a/docs/zh/docs/tutorial/body-nested-models.md
+++ b/docs/zh/docs/tutorial/body-nested-models.md
@@ -163,7 +163,7 @@ images: list[Image]
例如:
-{* ../../docs_src/body_nested_models/tutorial008_py39.py hl[13] *}
+{* ../../docs_src/body_nested_models/tutorial008_py310.py hl[13] *}
## 无处不在的编辑器支持 { #editor-support-everywhere }
@@ -193,7 +193,7 @@ images: list[Image]
在下面的例子中,你将接受任意键为 `int` 类型并且值为 `float` 类型的 `dict`:
-{* ../../docs_src/body_nested_models/tutorial009_py39.py hl[7] *}
+{* ../../docs_src/body_nested_models/tutorial009_py310.py hl[7] *}
/// tip | 提示
diff --git a/docs/zh/docs/tutorial/body.md b/docs/zh/docs/tutorial/body.md
index 60088a0482..4a72ba17c5 100644
--- a/docs/zh/docs/tutorial/body.md
+++ b/docs/zh/docs/tutorial/body.md
@@ -153,7 +153,7 @@
FastAPI 会根据默认值 `= None` 知道 `q` 的值不是必填的。
-`str | None`(Python 3.10+)或 `Union[str, None]`(Python 3.9+ 中的 `Union`)并不是 FastAPI 用来判断是否必填的依据;是否必填由是否有默认值 `= None` 决定。
+`str | None` 并不是 FastAPI 用来判断是否必填的依据;是否必填由是否有默认值 `= None` 决定。
但添加这些类型注解可以让你的编辑器提供更好的支持并检测错误。
diff --git a/docs/zh/docs/tutorial/cookie-param-models.md b/docs/zh/docs/tutorial/cookie-param-models.md
index 707a6a9c79..8e094c7d3f 100644
--- a/docs/zh/docs/tutorial/cookie-param-models.md
+++ b/docs/zh/docs/tutorial/cookie-param-models.md
@@ -46,17 +46,17 @@
在某些特殊使用情况下(可能并不常见),您可能希望**限制**您想要接收的 cookie。
-您的 API 现在可以控制自己的
cookie 同意。🤪🍪
+您的 API 现在可以控制自己的
cookie 同意。🤪🍪
您可以使用 Pydantic 的模型配置来禁止( `forbid` )任何额外( `extra` )字段:
{* ../../docs_src/cookie_param_models/tutorial002_an_py310.py hl[10] *}
-如果客户尝试发送一些**额外的 cookie**,他们将收到**错误**响应。
+如果客户端尝试发送一些**额外的 cookie**,他们将收到**错误**响应。
-可怜的 cookie 通知条,费尽心思为了获得您的同意,却被
API 拒绝了。🍪
+可怜的 cookie 通知条,费尽心思为了获得您的同意,却被
API 拒绝了。🍪
-例如,如果客户端尝试发送一个值为 `good-list-please` 的 `santa_tracker` cookie,客户端将收到一个**错误**响应,告知他们 `santa_tracker`
cookie 是不允许的:
+例如,如果客户端尝试发送一个值为 `good-list-please` 的 `santa_tracker` cookie,客户端将收到一个**错误**响应,告知他们 `santa_tracker`
cookie 是不允许的:
```json
{
@@ -73,4 +73,4 @@
## 总结 { #summary }
-您可以使用 **Pydantic 模型**在 **FastAPI** 中声明
**cookie**。😎
+您可以使用 **Pydantic 模型**在 **FastAPI** 中声明
**cookie**。😎
diff --git a/docs/zh/docs/tutorial/cors.md b/docs/zh/docs/tutorial/cors.md
index 3a296ca723..2e271ec758 100644
--- a/docs/zh/docs/tutorial/cors.md
+++ b/docs/zh/docs/tutorial/cors.md
@@ -46,7 +46,7 @@
* 特定的 HTTP 方法(`POST`,`PUT`)或者使用通配符 `"*"` 允许所有方法。
* 特定的 HTTP 请求头或者使用通配符 `"*"` 允许所有请求头。
-{* ../../docs_src/cors/tutorial001_py39.py hl[2,6:11,13:19] *}
+{* ../../docs_src/cors/tutorial001_py310.py hl[2,6:11,13:19] *}
默认情况下,这个 `CORSMiddleware` 实现所使用的默认参数较为保守,所以你需要显式地启用特定的源、方法或者 headers,以便浏览器能够在跨域上下文中使用它们。
@@ -63,7 +63,7 @@
* `expose_headers` - 指示可以被浏览器访问的响应头。默认为 `[]`。
* `max_age` - 设定浏览器缓存 CORS 响应的最长时间,单位是秒。默认为 `600`。
-中间件响应两种特定类型的 HTTP 请求……
+中间件响应两种特定类型的 HTTP 请求...
### CORS 预检请求 { #cors-preflight-requests }
diff --git a/docs/zh/docs/tutorial/debugging.md b/docs/zh/docs/tutorial/debugging.md
index 6e0cefe5b5..1ff7d61275 100644
--- a/docs/zh/docs/tutorial/debugging.md
+++ b/docs/zh/docs/tutorial/debugging.md
@@ -6,7 +6,7 @@
在你的 FastAPI 应用中直接导入 `uvicorn` 并运行:
-{* ../../docs_src/debugging/tutorial001_py39.py hl[1,15] *}
+{* ../../docs_src/debugging/tutorial001_py310.py hl[1,15] *}
### 关于 `__name__ == "__main__"` { #about-name-main }
@@ -68,7 +68,7 @@ from myapp import app
uvicorn.run(app, host="0.0.0.0", port=8000)
```
-/// info
+/// info | 信息
更多信息请检查
Python 官方文档.
diff --git a/docs/zh/docs/tutorial/dependencies/classes-as-dependencies.md b/docs/zh/docs/tutorial/dependencies/classes-as-dependencies.md
index d83321ddd6..43bd7a6807 100644
--- a/docs/zh/docs/tutorial/dependencies/classes-as-dependencies.md
+++ b/docs/zh/docs/tutorial/dependencies/classes-as-dependencies.md
@@ -14,7 +14,7 @@
对此,我们可以做的更好...
-## 什么构成了依赖项? { #what-makes-a-dependency }
+## 什么构成了依赖项 { #what-makes-a-dependency }
到目前为止,你看到的依赖项都被声明为函数。
@@ -101,7 +101,7 @@ fluffy = Cat(name="Mr Fluffy")
注意,我们在上面的代码中编写了两次`CommonQueryParams`:
-//// tab | Python 3.9+
+//// tab | Python 3.10+
```Python
commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]
@@ -109,7 +109,7 @@ commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]
////
-//// tab | Python 3.9+ 未使用 Annotated
+//// tab | Python 3.10+ 未使用 Annotated
/// tip | 提示
@@ -129,7 +129,7 @@ commons: CommonQueryParams = Depends(CommonQueryParams)
... Depends(CommonQueryParams)
```
-...实际上是 **Fastapi** 用来知道依赖项是什么的。
+...实际上是 **FastAPI** 用来知道依赖项是什么的。
FastAPI 将从依赖项中提取声明的参数,这才是 FastAPI 实际调用的。
@@ -137,7 +137,7 @@ FastAPI 将从依赖项中提取声明的参数,这才是 FastAPI 实际调用
在本例中,第一个 `CommonQueryParams` :
-//// tab | Python 3.9+
+//// tab | Python 3.10+
```Python
commons: Annotated[CommonQueryParams, ...
@@ -145,7 +145,7 @@ commons: Annotated[CommonQueryParams, ...
////
-//// tab | Python 3.9+ 未使用 Annotated
+//// tab | Python 3.10+ 未使用 Annotated
/// tip | 提示
@@ -163,7 +163,7 @@ commons: CommonQueryParams ...
你实际上可以只这样编写:
-//// tab | Python 3.9+
+//// tab | Python 3.10+
```Python
commons: Annotated[Any, Depends(CommonQueryParams)]
@@ -171,7 +171,7 @@ commons: Annotated[Any, Depends(CommonQueryParams)]
////
-//// tab | Python 3.9+ 未使用 Annotated
+//// tab | Python 3.10+ 未使用 Annotated
/// tip | 提示
@@ -197,7 +197,7 @@ commons = Depends(CommonQueryParams)
但是你可以看到,我们在这里有一些代码重复了,编写了`CommonQueryParams`两次:
-//// tab | Python 3.9+
+//// tab | Python 3.10+
```Python
commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]
@@ -205,7 +205,7 @@ commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]
////
-//// tab | Python 3.9+ 未使用 Annotated
+//// tab | Python 3.10+ 未使用 Annotated
/// tip | 提示
@@ -225,7 +225,7 @@ commons: CommonQueryParams = Depends(CommonQueryParams)
不是写成这样:
-//// tab | Python 3.9+
+//// tab | Python 3.10+
```Python
commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]
@@ -233,7 +233,7 @@ commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]
////
-//// tab | Python 3.9+ 未使用 Annotated
+//// tab | Python 3.10+ 未使用 Annotated
/// tip | 提示
@@ -249,7 +249,7 @@ commons: CommonQueryParams = Depends(CommonQueryParams)
...而是这样写:
-//// tab | Python 3.9+
+//// tab | Python 3.10+
```Python
commons: Annotated[CommonQueryParams, Depends()]
@@ -257,7 +257,7 @@ commons: Annotated[CommonQueryParams, Depends()]
////
-//// tab | Python 3.9+ 未使用 Annotated
+//// tab | Python 3.10+ 未使用 Annotated
/// tip | 提示
diff --git a/docs/zh/docs/tutorial/dependencies/dependencies-in-path-operation-decorators.md b/docs/zh/docs/tutorial/dependencies/dependencies-in-path-operation-decorators.md
index 02fcf62a0a..23412e4650 100644
--- a/docs/zh/docs/tutorial/dependencies/dependencies-in-path-operation-decorators.md
+++ b/docs/zh/docs/tutorial/dependencies/dependencies-in-path-operation-decorators.md
@@ -14,7 +14,7 @@
该参数的值是由 `Depends()` 组成的 `list`:
-{* ../../docs_src/dependencies/tutorial006_an_py39.py hl[19] *}
+{* ../../docs_src/dependencies/tutorial006_an_py310.py hl[19] *}
路径操作装饰器依赖项的执行或解析方式和普通依赖项一样,但就算这些依赖项会返回值,它们的值也不会传递给*路径操作函数*。
@@ -22,13 +22,13 @@
有些编辑器会检查代码中没使用过的函数参数,并显示错误提示。
-在*路径操作装饰器*中使用 `dependencies` 参数,可以确保在执行依赖项的同时,避免编辑器显示错误提示。
+在*路径操作装饰器*中使用 `dependencies` 参数,可以确保在执行依赖项的同时,避免编辑器/工具报错。
使用路径装饰器依赖项还可以避免开发新人误会代码中包含无用的未使用参数。
///
-/// info | 说明
+/// info | 信息
本例中,使用的是自定义响应头 `X-Key` 和 `X-Token`。
@@ -44,13 +44,13 @@
路径装饰器依赖项可以声明请求的需求项(比如响应头)或其他子依赖项:
-{* ../../docs_src/dependencies/tutorial006_an_py39.py hl[8,13] *}
+{* ../../docs_src/dependencies/tutorial006_an_py310.py hl[8,13] *}
### 触发异常 { #raise-exceptions }
路径装饰器依赖项与正常的依赖项一样,可以 `raise` 异常:
-{* ../../docs_src/dependencies/tutorial006_an_py39.py hl[10,15] *}
+{* ../../docs_src/dependencies/tutorial006_an_py310.py hl[10,15] *}
### 返回值 { #return-values }
@@ -58,7 +58,7 @@
因此,可以复用在其他位置使用过的、(能返回值的)普通依赖项,即使没有使用这个值,也会执行该依赖项:
-{* ../../docs_src/dependencies/tutorial006_an_py39.py hl[11,16] *}
+{* ../../docs_src/dependencies/tutorial006_an_py310.py hl[11,16] *}
## 为一组路径操作定义依赖项 { #dependencies-for-a-group-of-path-operations }
diff --git a/docs/zh/docs/tutorial/dependencies/dependencies-with-yield.md b/docs/zh/docs/tutorial/dependencies/dependencies-with-yield.md
index bf495c9f39..413dedb96b 100644
--- a/docs/zh/docs/tutorial/dependencies/dependencies-with-yield.md
+++ b/docs/zh/docs/tutorial/dependencies/dependencies-with-yield.md
@@ -1,6 +1,6 @@
# 使用 yield 的依赖项 { #dependencies-with-yield }
-FastAPI 支持那些在完成后执行一些
额外步骤的依赖项。
+FastAPI 支持那些在完成后执行一些
额外步骤的依赖项。
为此,使用 `yield` 而不是 `return`,并把这些额外步骤(代码)写在后面。
@@ -29,15 +29,15 @@ FastAPI 支持那些在完成后执行一些
docstring 中声明*路径操作*的描述,**FastAPI** 会从中读取。
+描述内容比较长且占用多行时,可以在函数的
docstring 中声明*路径操作*的描述,**FastAPI** 会从中读取。
文档字符串支持
Markdown,能正确解析和显示 Markdown 的内容,但要注意文档字符串的缩进。
{* ../../docs_src/path_operation_configuration/tutorial004_py310.py hl[17:25] *}
-下图为 Markdown 文本在 API 文档中的显示效果:
+它会在交互式文档中使用:

@@ -72,7 +72,7 @@ OpenAPI 概图会自动添加标签,供 API 文档接口使用:
{* ../../docs_src/path_operation_configuration/tutorial005_py310.py hl[18] *}
-/// info | 说明
+/// info | 信息
注意,`response_description` 只用于描述响应,`description` 一般则用于描述*路径操作*。
@@ -90,9 +90,9 @@ OpenAPI 规定每个*路径操作*都要有响应描述。
## 弃用*路径操作* { #deprecate-a-path-operation }
-`deprecated` 参数可以把*路径操作*标记为
弃用,无需直接删除:
+如果需要把*路径操作*标记为
弃用,但不删除它,可以传入 `deprecated` 参数:
-{* ../../docs_src/path_operation_configuration/tutorial006_py39.py hl[16] *}
+{* ../../docs_src/path_operation_configuration/tutorial006_py310.py hl[16] *}
API 文档会把该路径操作标记为弃用:
diff --git a/docs/zh/docs/tutorial/path-params-numeric-validations.md b/docs/zh/docs/tutorial/path-params-numeric-validations.md
index ff8b1762cf..608aa69a1d 100644
--- a/docs/zh/docs/tutorial/path-params-numeric-validations.md
+++ b/docs/zh/docs/tutorial/path-params-numeric-validations.md
@@ -54,11 +54,11 @@ FastAPI 在 0.95.0 版本添加了对 `Annotated` 的支持(并开始推荐使
因此,你可以将函数声明为:
-{* ../../docs_src/path_params_numeric_validations/tutorial002_py39.py hl[7] *}
+{* ../../docs_src/path_params_numeric_validations/tutorial002_py310.py hl[7] *}
但请记住,如果你使用 `Annotated`,你就不会遇到这个问题,因为你没有使用 `Query()` 或 `Path()` 作为函数参数的默认值。
-{* ../../docs_src/path_params_numeric_validations/tutorial002_an_py39.py *}
+{* ../../docs_src/path_params_numeric_validations/tutorial002_an_py310.py *}
## 按需对参数排序的技巧 { #order-the-parameters-as-you-need-tricks }
@@ -83,13 +83,13 @@ FastAPI 在 0.95.0 版本添加了对 `Annotated` 的支持(并开始推荐使
Python 不会对这个 `*` 做任何事,但它会知道之后的所有参数都应该作为关键字参数(键值对)来调用,也被称为
kwargs。即使它们没有默认值。
-{* ../../docs_src/path_params_numeric_validations/tutorial003_py39.py hl[7] *}
+{* ../../docs_src/path_params_numeric_validations/tutorial003_py310.py hl[7] *}
### 使用 `Annotated` 更好 { #better-with-annotated }
请记住,如果你使用 `Annotated`,因为你没有使用函数参数的默认值,所以你不会有这个问题,你大概率也不需要使用 `*`。
-{* ../../docs_src/path_params_numeric_validations/tutorial003_an_py39.py hl[10] *}
+{* ../../docs_src/path_params_numeric_validations/tutorial003_an_py310.py hl[10] *}
## 数值校验:大于等于 { #number-validations-greater-than-or-equal }
@@ -97,7 +97,7 @@ Python 不会对这个 `*` 做任何事,但它会知道之后的所有参数
在这里,使用 `ge=1` 后,`item_id` 必须是一个整数,值要「`g`reater than or `e`qual」1。
-{* ../../docs_src/path_params_numeric_validations/tutorial004_an_py39.py hl[10] *}
+{* ../../docs_src/path_params_numeric_validations/tutorial004_an_py310.py hl[10] *}
## 数值校验:大于和小于等于 { #number-validations-greater-than-and-less-than-or-equal }
@@ -106,7 +106,7 @@ Python 不会对这个 `*` 做任何事,但它会知道之后的所有参数
* `gt`:大于(`g`reater `t`han)
* `le`:小于等于(`l`ess than or `e`qual)
-{* ../../docs_src/path_params_numeric_validations/tutorial005_an_py39.py hl[10] *}
+{* ../../docs_src/path_params_numeric_validations/tutorial005_an_py310.py hl[10] *}
## 数值校验:浮点数、大于和小于 { #number-validations-floats-greater-than-and-less-than }
@@ -118,7 +118,7 @@ Python 不会对这个 `*` 做任何事,但它会知道之后的所有参数
对于
lt 也是一样的。
-{* ../../docs_src/path_params_numeric_validations/tutorial006_an_py39.py hl[13] *}
+{* ../../docs_src/path_params_numeric_validations/tutorial006_an_py310.py hl[13] *}
## 总结 { #recap }
diff --git a/docs/zh/docs/tutorial/path-params.md b/docs/zh/docs/tutorial/path-params.md
index fa4c9514a9..06a9f1b442 100644
--- a/docs/zh/docs/tutorial/path-params.md
+++ b/docs/zh/docs/tutorial/path-params.md
@@ -2,7 +2,7 @@
你可以使用与 Python 字符串格式化相同的语法声明路径“参数”或“变量”:
-{* ../../docs_src/path_params/tutorial001_py39.py hl[6:7] *}
+{* ../../docs_src/path_params/tutorial001_py310.py hl[6:7] *}
路径参数 `item_id` 的值会作为参数 `item_id` 传递给你的函数。
@@ -16,7 +16,7 @@
使用 Python 标准类型注解,声明路径操作函数中路径参数的类型:
-{* ../../docs_src/path_params/tutorial002_py39.py hl[7] *}
+{* ../../docs_src/path_params/tutorial002_py310.py hl[7] *}
本例把 `item_id` 的类型声明为 `int`。
@@ -26,7 +26,7 @@
///
-## 数据
转换 { #data-conversion }
+## 数据
转换 { #data-conversion }
运行示例并访问
http://127.0.0.1:8000/items/3,返回的响应如下:
@@ -38,7 +38,7 @@
注意,函数接收并返回的值是 `3`( `int`),不是 `"3"`(`str`)。
-**FastAPI** 通过类型声明自动
**解析**请求中的数据。
+**FastAPI** 通过类型声明自动进行请求的
解析。
///
@@ -118,19 +118,19 @@ FastAPI 充分地利用了
`Enum` 类型接收预设的路径参数。
+路径操作使用 Python 的 `Enum` 类型接收预设的路径参数。
### 创建 `Enum` 类 { #create-an-enum-class }
@@ -140,11 +140,11 @@ FastAPI 充分地利用了 模型的名字。
+**AlexNet**、**ResNet**、**LeNet** 是机器学习模型的名字。
///
@@ -152,7 +152,7 @@ FastAPI 充分地利用了 解析"
+- 数据 "解析"
- 数据校验
- API 注解和自动文档
diff --git a/docs/zh/docs/tutorial/query-params-str-validations.md b/docs/zh/docs/tutorial/query-params-str-validations.md
index 62552e6d08..d41f302267 100644
--- a/docs/zh/docs/tutorial/query-params-str-validations.md
+++ b/docs/zh/docs/tutorial/query-params-str-validations.md
@@ -47,40 +47,16 @@ FastAPI 在 0.95.0 版本中添加了对 `Annotated` 的支持(并开始推荐
我们之前的类型标注是:
-//// tab | Python 3.10+
-
```Python
q: str | None = None
```
-////
-
-//// tab | Python 3.9+
-
-```Python
-q: Union[str, None] = None
-```
-
-////
-
我们要做的是用 `Annotated` 把它包起来,变成:
-//// tab | Python 3.10+
-
```Python
q: Annotated[str | None] = None
```
-////
-
-//// tab | Python 3.9+
-
-```Python
-q: Annotated[Union[str, None]] = None
-```
-
-////
-
这两种写法含义相同,`q` 是一个可以是 `str` 或 `None` 的参数,默认是 `None`。
现在进入更有趣的部分。🎉
@@ -109,7 +85,7 @@ FastAPI 现在会:
## 另一种(旧的)方式:把 `Query` 作为默认值 { #alternative-old-query-as-the-default-value }
-早期版本的 FastAPI(0.95.0 之前)要求你把 `Query` 作为参数的默认值,而不是放在 `Annotated` 里。你很可能会在别处看到这种写法,所以我也给你解释一下。
+早期版本的 FastAPI(0.95.0 之前)要求你把 `Query` 作为参数的默认值,而不是放在 `Annotated` 里。你很可能会在别处看到这种写法,所以我也给你解释一下。
/// tip | 提示
@@ -191,7 +167,7 @@ q: str = Query(default="rick")
## 添加正则表达式 { #add-regular-expressions }
-你可以定义一个参数必须匹配的 正则表达式 `pattern`:
+你可以定义一个参数必须匹配的 正则表达式 `pattern`:
{* ../../docs_src/query_params_str_validations/tutorial004_an_py310.py hl[11] *}
@@ -211,7 +187,7 @@ q: str = Query(default="rick")
假设你想要声明查询参数 `q` 的 `min_length` 为 `3`,并且默认值为 `"fixedquery"`:
-{* ../../docs_src/query_params_str_validations/tutorial005_an_py39.py hl[9] *}
+{* ../../docs_src/query_params_str_validations/tutorial005_an_py310.py hl[9] *}
/// note | 注意
@@ -241,7 +217,7 @@ q: Annotated[str | None, Query(min_length=3)] = None
因此,在使用 `Query` 的同时需要把某个值声明为必填时,只需不声明默认值:
-{* ../../docs_src/query_params_str_validations/tutorial006_an_py39.py hl[9] *}
+{* ../../docs_src/query_params_str_validations/tutorial006_an_py310.py hl[9] *}
### 必填,但可以为 `None` { #required-can-be-none }
@@ -292,7 +268,7 @@ http://localhost:8000/items/?q=foo&q=bar
你还可以定义在没有给定值时的默认 `list`:
-{* ../../docs_src/query_params_str_validations/tutorial012_an_py39.py hl[9] *}
+{* ../../docs_src/query_params_str_validations/tutorial012_an_py310.py hl[9] *}
如果你访问:
@@ -315,7 +291,7 @@ http://localhost:8000/items/
你也可以直接使用 `list`,而不是 `list[str]`:
-{* ../../docs_src/query_params_str_validations/tutorial013_an_py39.py hl[9] *}
+{* ../../docs_src/query_params_str_validations/tutorial013_an_py310.py hl[9] *}
/// note | 注意
@@ -371,7 +347,7 @@ http://127.0.0.1:8000/items/?item-query=foobaritems
现在假设你不再喜欢这个参数了。
-由于还有客户端在使用它,你不得不保留一段时间,但你希望文档清楚地将其展示为已弃用。
+由于还有客户端在使用它,你不得不保留一段时间,但你希望文档清楚地将其展示为已弃用。
那么将参数 `deprecated=True` 传给 `Query`:
@@ -401,7 +377,7 @@ Pydantic 还有 ISBN 书号)或 `imdb-`(用于 IMDB 电影 URL 的 ID)开头:
+例如,这个自定义校验器会检查条目 ID 是否以 `isbn-`(用于 ISBN 书号)或 `imdb-`(用于 IMDB 电影 URL 的 ID)开头:
{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py hl[5,16:19,24] *}
@@ -435,7 +411,7 @@ Pydantic 还有 可迭代对象。
+使用 `data.items()` 我们会得到一个包含每个字典项键和值的元组的 可迭代对象。
我们用 `list(data.items())` 把这个可迭代对象转换成一个真正的 `list`。
diff --git a/docs/zh/docs/tutorial/query-params.md b/docs/zh/docs/tutorial/query-params.md
index 9ef998731a..4ea37d7e0c 100644
--- a/docs/zh/docs/tutorial/query-params.md
+++ b/docs/zh/docs/tutorial/query-params.md
@@ -2,7 +2,7 @@
声明的参数不是路径参数时,路径操作函数会把该参数自动解释为**查询**参数。
-{* ../../docs_src/query_params/tutorial001_py39.py hl[9] *}
+{* ../../docs_src/query_params/tutorial001_py310.py hl[9] *}
查询字符串是键值对的集合,这些键值对位于 URL 的 `?` 之后,以 `&` 分隔。
@@ -12,7 +12,7 @@
http://127.0.0.1:8000/items/?skip=0&limit=10
```
-……查询参数为:
+...查询参数为:
* `skip`:值为 `0`
* `limit`:值为 `10`
@@ -24,7 +24,7 @@ http://127.0.0.1:8000/items/?skip=0&limit=10
所有应用于路径参数的流程也适用于查询参数:
* (显而易见的)编辑器支持
-* 数据**解析**
+* 数据"解析"
* 数据校验
* 自动文档
@@ -75,7 +75,6 @@ http://127.0.0.1:8000/items/?skip=20
参数还可以声明为 `bool` 类型,FastAPI 会自动转换参数类型:
-
{* ../../docs_src/query_params/tutorial003_py310.py hl[7] *}
本例中,访问:
@@ -129,7 +128,7 @@ FastAPI 通过参数名进行检测:
如果要把查询参数设置为**必选**,就不要声明默认值:
-{* ../../docs_src/query_params/tutorial005_py39.py hl[6:7] *}
+{* ../../docs_src/query_params/tutorial005_py310.py hl[6:7] *}
这里的查询参数 `needy` 是类型为 `str` 的必选查询参数。
@@ -139,7 +138,7 @@ FastAPI 通过参数名进行检测:
http://127.0.0.1:8000/items/foo-item
```
-……因为路径中没有必选参数 `needy`,返回的响应中会显示如下错误信息:
+...因为路径中没有必选参数 `needy`,返回的响应中会显示如下错误信息:
```JSON
{
@@ -163,7 +162,7 @@ http://127.0.0.1:8000/items/foo-item
http://127.0.0.1:8000/items/foo-item?needy=sooooneedy
```
-……这样就正常了:
+...这样就正常了:
```JSON
{
diff --git a/docs/zh/docs/tutorial/request-files.md b/docs/zh/docs/tutorial/request-files.md
index 927bd093b0..e3b5435392 100644
--- a/docs/zh/docs/tutorial/request-files.md
+++ b/docs/zh/docs/tutorial/request-files.md
@@ -20,13 +20,13 @@ $ pip install python-multipart
从 `fastapi` 导入 `File` 和 `UploadFile`:
-{* ../../docs_src/request_files/tutorial001_an_py39.py hl[3] *}
+{* ../../docs_src/request_files/tutorial001_an_py310.py hl[3] *}
## 定义 `File` 参数 { #define-file-parameters }
像为 `Body` 或 `Form` 一样创建文件参数:
-{* ../../docs_src/request_files/tutorial001_an_py39.py hl[9] *}
+{* ../../docs_src/request_files/tutorial001_an_py310.py hl[9] *}
/// info | 信息
@@ -54,7 +54,7 @@ $ pip install python-multipart
将文件参数的类型声明为 `UploadFile`:
-{* ../../docs_src/request_files/tutorial001_an_py39.py hl[14] *}
+{* ../../docs_src/request_files/tutorial001_an_py310.py hl[14] *}
与 `bytes` 相比,使用 `UploadFile` 有多项优势:
@@ -76,9 +76,9 @@ $ pip install python-multipart
`UploadFile` 具有以下 `async` 方法。它们都会在底层调用对应的文件方法(使用内部的 `SpooledTemporaryFile`)。
-* `write(data)`:将 `data`(`str` 或 `bytes`)写入文件。
-* `read(size)`:读取文件中 `size`(`int`)个字节/字符。
-* `seek(offset)`:移动到文件中字节位置 `offset`(`int`)。
+* `write(data)`:将 `data` (`str` 或 `bytes`) 写入文件。
+* `read(size)`:读取文件中 `size` (`int`) 个字节/字符。
+* `seek(offset)`:移动到文件中字节位置 `offset` (`int`)。
* 例如,`await myfile.seek(0)` 会移动到文件开头。
* 如果你先运行过 `await myfile.read()`,然后需要再次读取内容时,这尤其有用。
* `close()`:关闭文件。
@@ -121,7 +121,7 @@ HTML 表单(``)向服务器发送数据的方式通常会对数
但当表单包含文件时,会编码为 `multipart/form-data`。如果你使用 `File`,**FastAPI** 会知道需要从请求体的正确位置获取文件。
-如果你想进一步了解这些编码和表单字段,请参阅 MDN web docs for POST。
+如果你想进一步了解这些编码和表单字段,请参阅
MDN 关于 POST 的 Web 文档。
///
@@ -135,7 +135,7 @@ HTML 表单(`
`)向服务器发送数据的方式通常会对数
## 可选文件上传 { #optional-file-upload }
-您可以通过使用标准类型注解并将 None 作为默认值的方式将一个文件参数设为可选:
+您可以通过使用标准类型注解并将 `None` 作为默认值的方式将一个文件参数设为可选:
{* ../../docs_src/request_files/tutorial001_02_an_py310.py hl[9,17] *}
@@ -143,7 +143,7 @@ HTML 表单(`
`)向服务器发送数据的方式通常会对数
您也可以将 `File()` 与 `UploadFile` 一起使用,例如,设置额外的元数据:
-{* ../../docs_src/request_files/tutorial001_03_an_py39.py hl[9,15] *}
+{* ../../docs_src/request_files/tutorial001_03_an_py310.py hl[9,15] *}
## 多文件上传 { #multiple-file-uploads }
@@ -153,7 +153,7 @@ FastAPI 支持同时上传多个文件。
要实现这一点,声明一个由 `bytes` 或 `UploadFile` 组成的列表(`List`):
-{* ../../docs_src/request_files/tutorial002_an_py39.py hl[10,15] *}
+{* ../../docs_src/request_files/tutorial002_an_py310.py hl[10,15] *}
接收的也是含 `bytes` 或 `UploadFile` 的列表(`list`)。
@@ -169,7 +169,7 @@ FastAPI 支持同时上传多个文件。
和之前的方式一样,你可以为 `File()` 设置额外参数,即使是 `UploadFile`:
-{* ../../docs_src/request_files/tutorial003_an_py39.py hl[11,18:20] *}
+{* ../../docs_src/request_files/tutorial003_an_py310.py hl[11,18:20] *}
## 小结 { #recap }
diff --git a/docs/zh/docs/tutorial/request-form-models.md b/docs/zh/docs/tutorial/request-form-models.md
index 4eb98ea225..63759df086 100644
--- a/docs/zh/docs/tutorial/request-form-models.md
+++ b/docs/zh/docs/tutorial/request-form-models.md
@@ -24,7 +24,7 @@ $ pip install python-multipart
你只需声明一个 **Pydantic 模型**,其中包含你希望接收的**表单字段**,然后将参数声明为 `Form`:
-{* ../../docs_src/request_form_models/tutorial001_an_py39.py hl[9:11,15] *}
+{* ../../docs_src/request_form_models/tutorial001_an_py310.py hl[9:11,15] *}
**FastAPI** 将从请求中的**表单数据**中**提取**出**每个字段**的数据,并提供你定义的 Pydantic 模型。
@@ -48,7 +48,7 @@ $ pip install python-multipart
你可以使用 Pydantic 的模型配置来 `forbid` 任何 `extra` 字段:
-{* ../../docs_src/request_form_models/tutorial002_an_py39.py hl[12] *}
+{* ../../docs_src/request_form_models/tutorial002_an_py310.py hl[12] *}
如果客户端尝试发送一些额外的数据,他们将收到**错误**响应。
diff --git a/docs/zh/docs/tutorial/request-forms-and-files.md b/docs/zh/docs/tutorial/request-forms-and-files.md
index 3c809868b2..484fcd5d6d 100644
--- a/docs/zh/docs/tutorial/request-forms-and-files.md
+++ b/docs/zh/docs/tutorial/request-forms-and-files.md
@@ -16,17 +16,17 @@ $ pip install python-multipart
## 导入 `File` 与 `Form` { #import-file-and-form }
-{* ../../docs_src/request_forms_and_files/tutorial001_an_py39.py hl[3] *}
+{* ../../docs_src/request_forms_and_files/tutorial001_an_py310.py hl[3] *}
## 定义 `File` 与 `Form` 参数 { #define-file-and-form-parameters }
创建文件和表单参数的方式与 `Body` 和 `Query` 一样:
-{* ../../docs_src/request_forms_and_files/tutorial001_an_py39.py hl[10:12] *}
+{* ../../docs_src/request_forms_and_files/tutorial001_an_py310.py hl[10:12] *}
文件和表单字段作为表单数据上传与接收。
-声明文件可以使用 `bytes` 或 `UploadFile` 。
+并且你可以将部分文件声明为 `bytes`,将部分文件声明为 `UploadFile`。
/// warning | 警告
diff --git a/docs/zh/docs/tutorial/request-forms.md b/docs/zh/docs/tutorial/request-forms.md
index 70eb93a260..1fc305a69c 100644
--- a/docs/zh/docs/tutorial/request-forms.md
+++ b/docs/zh/docs/tutorial/request-forms.md
@@ -18,17 +18,17 @@ $ pip install python-multipart
从 `fastapi` 导入 `Form`:
-{* ../../docs_src/request_forms/tutorial001_an_py39.py hl[3] *}
+{* ../../docs_src/request_forms/tutorial001_an_py310.py hl[3] *}
## 定义 `Form` 参数 { #define-form-parameters }
创建表单参数的方式与 `Body` 或 `Query` 相同:
-{* ../../docs_src/request_forms/tutorial001_an_py39.py hl[9] *}
+{* ../../docs_src/request_forms/tutorial001_an_py310.py hl[9] *}
例如,在 OAuth2 规范的一种使用方式(称为“密码流”)中,要求将 `username` 和 `password` 作为表单字段发送。
-
spec 要求这些字段必须精确命名为 `username` 和 `password`,并且作为表单字段发送,而不是 JSON。
+
规范 要求这些字段必须精确命名为 `username` 和 `password`,并且作为表单字段发送,而不是 JSON。
使用 `Form` 可以像使用 `Body`(以及 `Query`、`Path`、`Cookie`)一样声明相同的配置,包括校验、示例、别名(例如将 `username` 写成 `user-name`)等。
diff --git a/docs/zh/docs/tutorial/response-model.md b/docs/zh/docs/tutorial/response-model.md
index 791eb66fb7..df0afa66f8 100644
--- a/docs/zh/docs/tutorial/response-model.md
+++ b/docs/zh/docs/tutorial/response-model.md
@@ -183,7 +183,7 @@ FastAPI 在内部配合 Pydantic 做了多项处理,确保不会把类继承
最常见的情况是[直接返回 Response,详见进阶文档](../advanced/response-directly.md){.internal-link target=_blank}。
-{* ../../docs_src/response_model/tutorial003_02_py39.py hl[8,10:11] *}
+{* ../../docs_src/response_model/tutorial003_02_py310.py hl[8,10:11] *}
这个简单场景 FastAPI 会自动处理,因为返回类型注解是 `Response`(或其子类)。
@@ -193,7 +193,7 @@ FastAPI 在内部配合 Pydantic 做了多项处理,确保不会把类继承
你也可以在类型注解中使用 `Response` 的子类:
-{* ../../docs_src/response_model/tutorial003_03_py39.py hl[8:9] *}
+{* ../../docs_src/response_model/tutorial003_03_py310.py hl[8:9] *}
这同样可行,因为 `RedirectResponse` 是 `Response` 的子类,FastAPI 会自动处理这个简单场景。
@@ -201,7 +201,7 @@ FastAPI 在内部配合 Pydantic 做了多项处理,确保不会把类继承
但当你返回其他任意对象(如数据库对象)而它不是有效的 Pydantic 类型,并在函数中按此进行了注解时,FastAPI 会尝试基于该类型注解创建一个 Pydantic 响应模型,但会失败。
-如果你有一个在多个类型之间的
联合类型,其中一个或多个不是有效的 Pydantic 类型,也会发生同样的情况,例如这个会失败 💥:
+如果你有一个在多个类型之间的
联合类型,其中一个或多个不是有效的 Pydantic 类型,也会发生同样的情况,例如这个会失败 💥:
{* ../../docs_src/response_model/tutorial003_04_py310.py hl[8] *}
diff --git a/docs/zh/docs/tutorial/response-status-code.md b/docs/zh/docs/tutorial/response-status-code.md
index 3630de2803..266f919ba1 100644
--- a/docs/zh/docs/tutorial/response-status-code.md
+++ b/docs/zh/docs/tutorial/response-status-code.md
@@ -8,7 +8,7 @@
* `@app.delete()`
* 等...
-{* ../../docs_src/response_status_code/tutorial001_py39.py hl[6] *}
+{* ../../docs_src/response_status_code/tutorial001_py310.py hl[6] *}
/// note | 注意
@@ -74,7 +74,7 @@ FastAPI 可以进行识别,并生成表明无响应体的 OpenAPI 文档。
再看下之前的例子:
-{* ../../docs_src/response_status_code/tutorial001_py39.py hl[6] *}
+{* ../../docs_src/response_status_code/tutorial001_py310.py hl[6] *}
`201` 表示“已创建”的状态码。
@@ -82,7 +82,7 @@ FastAPI 可以进行识别,并生成表明无响应体的 OpenAPI 文档。
可以使用 `fastapi.status` 中的快捷变量。
-{* ../../docs_src/response_status_code/tutorial002_py39.py hl[1,6] *}
+{* ../../docs_src/response_status_code/tutorial002_py310.py hl[1,6] *}
这只是一种快捷方式,具有相同的数字代码,但它可以使用编辑器的自动补全功能:
diff --git a/docs/zh/docs/tutorial/schema-extra-example.md b/docs/zh/docs/tutorial/schema-extra-example.md
index 818ff5087b..ec1fc29e55 100644
--- a/docs/zh/docs/tutorial/schema-extra-example.md
+++ b/docs/zh/docs/tutorial/schema-extra-example.md
@@ -74,7 +74,7 @@ OpenAPI 3.1.0(自 FastAPI 0.99.0 起使用)增加了对 `examples` 的支持
这样做时,这些示例会成为该请求体数据内部 JSON Schema 的一部分。
-不过,在
撰写本文时,用于展示文档 UI 的 Swagger UI 并不支持显示 JSON Schema 中数据的多个示例。但请继续阅读,下面有一种变通方法。
+不过,在
撰写本文时,用于展示文档 UI 的 Swagger UI 并不支持显示 JSON Schema 中数据的多个示例。但请继续阅读,下面有一种变通方法。
### OpenAPI 特定的 `examples` { #openapi-specific-examples }
diff --git a/docs/zh/docs/tutorial/security/first-steps.md b/docs/zh/docs/tutorial/security/first-steps.md
index 43b7c66579..8b1aeb70b3 100644
--- a/docs/zh/docs/tutorial/security/first-steps.md
+++ b/docs/zh/docs/tutorial/security/first-steps.md
@@ -20,7 +20,7 @@
把下面的示例代码复制到 `main.py`:
-{* ../../docs_src/security/tutorial001_an_py39.py *}
+{* ../../docs_src/security/tutorial001_an_py310.py *}
## 运行 { #run-it }
@@ -132,7 +132,7 @@ OAuth2 的设计目标是让后端或 API 与负责用户认证的服务器解
创建 `OAuth2PasswordBearer` 类实例时,需要传入 `tokenUrl` 参数。该参数包含客户端(运行在用户浏览器中的前端)用来发送 `username` 和 `password` 以获取令牌的 URL。
-{* ../../docs_src/security/tutorial001_an_py39.py hl[8] *}
+{* ../../docs_src/security/tutorial001_an_py310.py hl[8] *}
/// tip | 提示
@@ -170,7 +170,7 @@ oauth2_scheme(some, parameters)
现在你可以通过 `Depends` 将 `oauth2_scheme` 作为依赖传入。
-{* ../../docs_src/security/tutorial001_an_py39.py hl[12] *}
+{* ../../docs_src/security/tutorial001_an_py310.py hl[12] *}
该依赖会提供一个 `str`,赋值给*路径操作函数*的参数 `token`。
diff --git a/docs/zh/docs/tutorial/security/get-current-user.md b/docs/zh/docs/tutorial/security/get-current-user.md
index c14bba28af..814ff2c822 100644
--- a/docs/zh/docs/tutorial/security/get-current-user.md
+++ b/docs/zh/docs/tutorial/security/get-current-user.md
@@ -2,7 +2,7 @@
上一章中,(基于依赖注入系统的)安全系统向*路径操作函数*传递了 `str` 类型的 `token`:
-{* ../../docs_src/security/tutorial001_an_py39.py hl[12] *}
+{* ../../docs_src/security/tutorial001_an_py310.py hl[12] *}
但这并不实用。
diff --git a/docs/zh/docs/tutorial/security/index.md b/docs/zh/docs/tutorial/security/index.md
index 589f93c3e9..a4c3521105 100644
--- a/docs/zh/docs/tutorial/security/index.md
+++ b/docs/zh/docs/tutorial/security/index.md
@@ -10,7 +10,7 @@
但首先,让我们来看一些小的概念。
-## 没有时间? { #in-a-hurry }
+## 赶时间 { #in-a-hurry }
如果你不关心这些术语,而只需要*立即*通过基于用户名和密码的身份认证来增加安全性,请跳转到接下来的章节。
diff --git a/docs/zh/docs/tutorial/security/oauth2-jwt.md b/docs/zh/docs/tutorial/security/oauth2-jwt.md
index c7eb9bd907..b5ccfd3e3f 100644
--- a/docs/zh/docs/tutorial/security/oauth2-jwt.md
+++ b/docs/zh/docs/tutorial/security/oauth2-jwt.md
@@ -116,7 +116,11 @@ pwdlib 也支持 bcrypt 哈希算法,但不包含遗留算法——如果需
再创建一个工具函数来进行身份验证并返回用户。
-{* ../../docs_src/security/tutorial004_an_py310.py hl[8,49,56:57,60:61,70:76] *}
+{* ../../docs_src/security/tutorial004_an_py310.py hl[8,49,51,58:59,62:63,72:79] *}
+
+当使用一个在数据库中不存在的用户名调用 `authenticate_user` 时,我们仍然会针对一个虚拟哈希运行 `verify_password`。
+
+这可以确保无论用户名是否有效,端点的响应时间大致相同,从而防止可用于枚举已存在用户名的“时间攻击”(timing attacks)。
/// note | 注意
@@ -152,7 +156,7 @@ $ openssl rand -hex 32
创建一个生成新访问令牌的工具函数。
-{* ../../docs_src/security/tutorial004_an_py310.py hl[4,7,13:15,29:31,79:87] *}
+{* ../../docs_src/security/tutorial004_an_py310.py hl[4,7,13:15,29:31,82:90] *}
## 更新依赖项 { #update-the-dependencies }
@@ -162,7 +166,7 @@ $ openssl rand -hex 32
如果令牌无效,立即返回一个 HTTP 错误。
-{* ../../docs_src/security/tutorial004_an_py310.py hl[90:107] *}
+{* ../../docs_src/security/tutorial004_an_py310.py hl[93:110] *}
## 更新 `/token` 路径操作 { #update-the-token-path-operation }
@@ -170,7 +174,7 @@ $ openssl rand -hex 32
创建一个真正的 JWT 访问令牌并返回它。
-{* ../../docs_src/security/tutorial004_an_py310.py hl[118:133] *}
+{* ../../docs_src/security/tutorial004_an_py310.py hl[121:136] *}
### 关于 JWT “主题” `sub` 的技术细节 { #technical-details-about-the-jwt-subject-sub }
diff --git a/docs/zh/docs/tutorial/security/simple-oauth2.md b/docs/zh/docs/tutorial/security/simple-oauth2.md
index 3037a983b3..95f708ae6a 100644
--- a/docs/zh/docs/tutorial/security/simple-oauth2.md
+++ b/docs/zh/docs/tutorial/security/simple-oauth2.md
@@ -6,9 +6,9 @@
首先,使用 **FastAPI** 安全工具获取 `username` 和 `password`。
-OAuth2 规范要求使用**密码流**时,客户端或用户必须以表单数据形式发送 `username` 和 `password` 字段。
+OAuth2 规范要求使用“密码流”时,客户端或用户必须以表单数据形式发送 `username` 和 `password` 字段。
-并且,这两个字段必须命名为 `username` 和 `password` ,不能使用 `user-name` 或 `email` 等其它名称。
+并且,这两个字段必须命名为 `username` 和 `password`,不能使用 `user-name` 或 `email` 等其它名称。
不过也不用担心,前端仍可以显示终端用户所需的名称。
@@ -74,7 +74,7 @@ OAuth2 中,**作用域**只是声明指定权限的字符串。
/// info | 信息
-`OAuth2PasswordRequestForm` 与 `OAuth2PasswordBearer` 一样,都不是 FastAPI 的特殊类。
+`OAuth2PasswordRequestForm` 并不像 `OAuth2PasswordBearer` 那样是 **FastAPI** 的特殊类。
**FastAPI** 把 `OAuth2PasswordBearer` 识别为安全方案。因此,可以通过这种方式把它添加至 OpenAPI。
@@ -200,7 +200,7 @@ UserInDB(
此处返回值为 `Bearer` 的响应头 `WWW-Authenticate` 也是规范的一部分。
-任何 401**UNAUTHORIZED**HTTP(错误)状态码都应返回 `WWW-Authenticate` 响应头。
+任何 401“UNAUTHORIZED”HTTP(错误)状态码都应返回 `WWW-Authenticate` 响应头。
本例中,因为使用的是 Bearer Token,该响应头的值应为 `Bearer`。
@@ -220,7 +220,7 @@ UserInDB(
### 身份验证 { #authenticate }
-点击**Authorize**按钮。
+点击“Authorize”按钮。
使用以下凭证:
@@ -286,4 +286,4 @@ UserInDB(
唯一欠缺的是,它仍然不是真的**安全**。
-下一章,介绍使用密码哈希支持库与
JWT 令牌实现真正的安全机制。
+下一章你将看到如何使用安全的密码哈希库和
JWT 令牌。
diff --git a/docs/zh/docs/tutorial/sql-databases.md b/docs/zh/docs/tutorial/sql-databases.md
index 944e960a76..ef0b7c4601 100644
--- a/docs/zh/docs/tutorial/sql-databases.md
+++ b/docs/zh/docs/tutorial/sql-databases.md
@@ -216,7 +216,7 @@ $ fastapi dev main.py
它包含与 `HeroBase` 相同的字段,因此不会包括 `secret_name`。
-终于,我们英雄(hero)的身份得到了保护!🥷
+终于,我们英雄的身份得到了保护!🥷
它还重新声明了 `id: int`。这样我们便与 API 客户端建立了一种**约定**,使他们始终可以期待 `id` 存在并且是一个整数 `int`(永远不会是 `None`)。
diff --git a/docs/zh/docs/tutorial/static-files.md b/docs/zh/docs/tutorial/static-files.md
index 5b2f920b2c..1f4ebae9ab 100644
--- a/docs/zh/docs/tutorial/static-files.md
+++ b/docs/zh/docs/tutorial/static-files.md
@@ -7,9 +7,9 @@
* 导入 `StaticFiles`。
* 将一个 `StaticFiles()` 实例“挂载”(Mount)到指定路径。
-{* ../../docs_src/static_files/tutorial001_py39.py hl[2,6] *}
+{* ../../docs_src/static_files/tutorial001_py310.py hl[2,6] *}
-/// note | 注意
+/// note | 技术细节
你也可以用 `from starlette.staticfiles import StaticFiles`。
diff --git a/docs/zh/docs/tutorial/testing.md b/docs/zh/docs/tutorial/testing.md
index 1aff9f799c..7eb32f19e6 100644
--- a/docs/zh/docs/tutorial/testing.md
+++ b/docs/zh/docs/tutorial/testing.md
@@ -30,7 +30,7 @@ $ pip install httpx
为你需要检查的地方用标准的Python表达式写个简单的 `assert` 语句(重申,标准的`pytest`)。
-{* ../../docs_src/app_testing/tutorial001_py39.py hl[2,12,15:18] *}
+{* ../../docs_src/app_testing/tutorial001_py310.py hl[2,12,15:18] *}
/// tip | 提示
@@ -76,7 +76,7 @@ $ pip install httpx
在 `main.py` 文件中你有一个 **FastAPI** app:
-{* ../../docs_src/app_testing/app_a_py39/main.py *}
+{* ../../docs_src/app_testing/app_a_py310/main.py *}
### 测试文件 { #testing-file }
@@ -92,7 +92,7 @@ $ pip install httpx
因为这文件在同一个包中,所以你可以通过相对导入从 `main` 模块(`main.py`)导入`app`对象:
-{* ../../docs_src/app_testing/app_a_py39/test_main.py hl[3] *}
+{* ../../docs_src/app_testing/app_a_py310/test_main.py hl[3] *}
...然后测试代码和之前一样的。
diff --git a/docs/zh/docs/virtual-environments.md b/docs/zh/docs/virtual-environments.md
index 29e272b59a..60fb9e23f6 100644
--- a/docs/zh/docs/virtual-environments.md
+++ b/docs/zh/docs/virtual-environments.md
@@ -30,7 +30,7 @@
首先,为你的工程创建一个目录。
-我 (指原作者 —— 译者注) 通常会在我的主目录下创建一个名为 `code` 的目录。
+我通常会在我的主目录下创建一个名为 `code` 的目录。
在这个目录下,我再为每个工程创建一个目录。
@@ -53,7 +53,7 @@ $ cd awesome-project
## 创建一个虚拟环境 { #create-a-virtual-environment }
-在开始一个 Python 工程的**第一时间**,**
在你的工程内部**创建一个虚拟环境。
+在开始一个 Python 工程的**第一时间**,**
在你的工程内部**创建一个虚拟环境。
/// tip | 提示
@@ -316,7 +316,7 @@ $ echo "*" > .venv/.gitignore
### 直接安装包 { #install-packages-directly }
-如果你急于安装,不想使用文件来声明工程的软件包依赖,您可以直接安装它们。
+如果你急于安装,不想使用文件来声明工程的软件包依赖,你可以直接安装它们。
/// tip | 提示
@@ -412,7 +412,7 @@ Hello World
## 配置编辑器 { #configure-your-editor }
-你可能会用到编辑器(即 IDE —— 译者注),请确保配置它使用与你创建的相同的虚拟环境(它可能会自动检测到),以便你可以获得自动补全和内联错误提示。
+你可能会用到编辑器,请确保配置它使用与你创建的相同的虚拟环境(它可能会自动检测到),以便你可以获得自动补全和内联错误提示。
例如:
@@ -437,7 +437,7 @@ $ deactivate
-这样,当你运行 `python` 时,它不会尝试从安装了软件包的虚拟环境中运行。(即,它将不再会尝试从虚拟环境中运行,也不会使用其中安装的软件包。—— 译者注)
+这样,当你运行 `python` 时,它不会尝试从那个虚拟环境及其已安装的软件包中运行。
## 开始工作 { #ready-to-work }
diff --git a/docs_src/additional_responses/tutorial001_py39.py b/docs_src/additional_responses/tutorial001_py310.py
similarity index 100%
rename from docs_src/additional_responses/tutorial001_py39.py
rename to docs_src/additional_responses/tutorial001_py310.py
diff --git a/docs_src/additional_responses/tutorial002_py39.py b/docs_src/additional_responses/tutorial002_py39.py
deleted file mode 100644
index bd0c957049..0000000000
--- a/docs_src/additional_responses/tutorial002_py39.py
+++ /dev/null
@@ -1,30 +0,0 @@
-from typing import Union
-
-from fastapi import FastAPI
-from fastapi.responses import FileResponse
-from pydantic import BaseModel
-
-
-class Item(BaseModel):
- id: str
- value: str
-
-
-app = FastAPI()
-
-
-@app.get(
- "/items/{item_id}",
- response_model=Item,
- responses={
- 200: {
- "content": {"image/png": {}},
- "description": "Return the JSON item or an image.",
- }
- },
-)
-async def read_item(item_id: str, img: Union[bool, None] = None):
- if img:
- return FileResponse("image.png", media_type="image/png")
- else:
- return {"id": "foo", "value": "there goes my hero"}
diff --git a/docs_src/additional_responses/tutorial003_py39.py b/docs_src/additional_responses/tutorial003_py310.py
similarity index 100%
rename from docs_src/additional_responses/tutorial003_py39.py
rename to docs_src/additional_responses/tutorial003_py310.py
diff --git a/docs_src/additional_responses/tutorial004_py39.py b/docs_src/additional_responses/tutorial004_py39.py
deleted file mode 100644
index 978bc18c13..0000000000
--- a/docs_src/additional_responses/tutorial004_py39.py
+++ /dev/null
@@ -1,32 +0,0 @@
-from typing import Union
-
-from fastapi import FastAPI
-from fastapi.responses import FileResponse
-from pydantic import BaseModel
-
-
-class Item(BaseModel):
- id: str
- value: str
-
-
-responses = {
- 404: {"description": "Item not found"},
- 302: {"description": "The item was moved"},
- 403: {"description": "Not enough privileges"},
-}
-
-
-app = FastAPI()
-
-
-@app.get(
- "/items/{item_id}",
- response_model=Item,
- responses={**responses, 200: {"content": {"image/png": {}}}},
-)
-async def read_item(item_id: str, img: Union[bool, None] = None):
- if img:
- return FileResponse("image.png", media_type="image/png")
- else:
- return {"id": "foo", "value": "there goes my hero"}
diff --git a/docs_src/additional_status_codes/tutorial001_an_py39.py b/docs_src/additional_status_codes/tutorial001_an_py39.py
deleted file mode 100644
index 89653dd8a0..0000000000
--- a/docs_src/additional_status_codes/tutorial001_an_py39.py
+++ /dev/null
@@ -1,25 +0,0 @@
-from typing import Annotated, Union
-
-from fastapi import Body, FastAPI, status
-from fastapi.responses import JSONResponse
-
-app = FastAPI()
-
-items = {"foo": {"name": "Fighters", "size": 6}, "bar": {"name": "Tenders", "size": 3}}
-
-
-@app.put("/items/{item_id}")
-async def upsert_item(
- item_id: str,
- name: Annotated[Union[str, None], Body()] = None,
- size: Annotated[Union[int, None], Body()] = None,
-):
- if item_id in items:
- item = items[item_id]
- item["name"] = name
- item["size"] = size
- return item
- else:
- item = {"name": name, "size": size}
- items[item_id] = item
- return JSONResponse(status_code=status.HTTP_201_CREATED, content=item)
diff --git a/docs_src/additional_status_codes/tutorial001_py39.py b/docs_src/additional_status_codes/tutorial001_py39.py
deleted file mode 100644
index 74a986a6a9..0000000000
--- a/docs_src/additional_status_codes/tutorial001_py39.py
+++ /dev/null
@@ -1,25 +0,0 @@
-from typing import Union
-
-from fastapi import Body, FastAPI, status
-from fastapi.responses import JSONResponse
-
-app = FastAPI()
-
-items = {"foo": {"name": "Fighters", "size": 6}, "bar": {"name": "Tenders", "size": 3}}
-
-
-@app.put("/items/{item_id}")
-async def upsert_item(
- item_id: str,
- name: Union[str, None] = Body(default=None),
- size: Union[int, None] = Body(default=None),
-):
- if item_id in items:
- item = items[item_id]
- item["name"] = name
- item["size"] = size
- return item
- else:
- item = {"name": name, "size": size}
- items[item_id] = item
- return JSONResponse(status_code=status.HTTP_201_CREATED, content=item)
diff --git a/docs_src/advanced_middleware/tutorial001_py39.py b/docs_src/advanced_middleware/tutorial001_py310.py
similarity index 100%
rename from docs_src/advanced_middleware/tutorial001_py39.py
rename to docs_src/advanced_middleware/tutorial001_py310.py
diff --git a/docs_src/advanced_middleware/tutorial002_py39.py b/docs_src/advanced_middleware/tutorial002_py310.py
similarity index 100%
rename from docs_src/advanced_middleware/tutorial002_py39.py
rename to docs_src/advanced_middleware/tutorial002_py310.py
diff --git a/docs_src/advanced_middleware/tutorial003_py39.py b/docs_src/advanced_middleware/tutorial003_py310.py
similarity index 100%
rename from docs_src/advanced_middleware/tutorial003_py39.py
rename to docs_src/advanced_middleware/tutorial003_py310.py
diff --git a/docs_src/app_testing/app_a_py39/__init__.py b/docs_src/app_testing/app_a_py310/__init__.py
similarity index 100%
rename from docs_src/app_testing/app_a_py39/__init__.py
rename to docs_src/app_testing/app_a_py310/__init__.py
diff --git a/docs_src/app_testing/app_a_py39/main.py b/docs_src/app_testing/app_a_py310/main.py
similarity index 100%
rename from docs_src/app_testing/app_a_py39/main.py
rename to docs_src/app_testing/app_a_py310/main.py
diff --git a/docs_src/app_testing/app_a_py39/test_main.py b/docs_src/app_testing/app_a_py310/test_main.py
similarity index 100%
rename from docs_src/app_testing/app_a_py39/test_main.py
rename to docs_src/app_testing/app_a_py310/test_main.py
diff --git a/docs_src/app_testing/app_b_an_py39/main.py b/docs_src/app_testing/app_b_an_py39/main.py
deleted file mode 100644
index 42026a81a0..0000000000
--- a/docs_src/app_testing/app_b_an_py39/main.py
+++ /dev/null
@@ -1,38 +0,0 @@
-from typing import Annotated, Union
-
-from fastapi import FastAPI, Header, HTTPException
-from pydantic import BaseModel
-
-fake_secret_token = "coneofsilence"
-
-fake_db = {
- "foo": {"id": "foo", "title": "Foo", "description": "There goes my hero"},
- "bar": {"id": "bar", "title": "Bar", "description": "The bartenders"},
-}
-
-app = FastAPI()
-
-
-class Item(BaseModel):
- id: str
- title: str
- description: Union[str, None] = None
-
-
-@app.get("/items/{item_id}", response_model=Item)
-async def read_main(item_id: str, x_token: Annotated[str, Header()]):
- if x_token != fake_secret_token:
- raise HTTPException(status_code=400, detail="Invalid X-Token header")
- if item_id not in fake_db:
- raise HTTPException(status_code=404, detail="Item not found")
- return fake_db[item_id]
-
-
-@app.post("/items/")
-async def create_item(item: Item, x_token: Annotated[str, Header()]) -> Item:
- if x_token != fake_secret_token:
- raise HTTPException(status_code=400, detail="Invalid X-Token header")
- if item.id in fake_db:
- raise HTTPException(status_code=409, detail="Item already exists")
- fake_db[item.id] = item.model_dump()
- return item
diff --git a/docs_src/app_testing/app_b_an_py39/test_main.py b/docs_src/app_testing/app_b_an_py39/test_main.py
deleted file mode 100644
index 4e1c51ecc8..0000000000
--- a/docs_src/app_testing/app_b_an_py39/test_main.py
+++ /dev/null
@@ -1,65 +0,0 @@
-from fastapi.testclient import TestClient
-
-from .main import app
-
-client = TestClient(app)
-
-
-def test_read_item():
- response = client.get("/items/foo", headers={"X-Token": "coneofsilence"})
- assert response.status_code == 200
- assert response.json() == {
- "id": "foo",
- "title": "Foo",
- "description": "There goes my hero",
- }
-
-
-def test_read_item_bad_token():
- response = client.get("/items/foo", headers={"X-Token": "hailhydra"})
- assert response.status_code == 400
- assert response.json() == {"detail": "Invalid X-Token header"}
-
-
-def test_read_nonexistent_item():
- response = client.get("/items/baz", headers={"X-Token": "coneofsilence"})
- assert response.status_code == 404
- assert response.json() == {"detail": "Item not found"}
-
-
-def test_create_item():
- response = client.post(
- "/items/",
- headers={"X-Token": "coneofsilence"},
- json={"id": "foobar", "title": "Foo Bar", "description": "The Foo Barters"},
- )
- assert response.status_code == 200
- assert response.json() == {
- "id": "foobar",
- "title": "Foo Bar",
- "description": "The Foo Barters",
- }
-
-
-def test_create_item_bad_token():
- response = client.post(
- "/items/",
- headers={"X-Token": "hailhydra"},
- json={"id": "bazz", "title": "Bazz", "description": "Drop the bazz"},
- )
- assert response.status_code == 400
- assert response.json() == {"detail": "Invalid X-Token header"}
-
-
-def test_create_existing_item():
- response = client.post(
- "/items/",
- headers={"X-Token": "coneofsilence"},
- json={
- "id": "foo",
- "title": "The Foo ID Stealers",
- "description": "There goes my stealer",
- },
- )
- assert response.status_code == 409
- assert response.json() == {"detail": "Item already exists"}
diff --git a/docs_src/app_testing/app_b_py39/main.py b/docs_src/app_testing/app_b_py39/main.py
deleted file mode 100644
index ed38f4721c..0000000000
--- a/docs_src/app_testing/app_b_py39/main.py
+++ /dev/null
@@ -1,38 +0,0 @@
-from typing import Union
-
-from fastapi import FastAPI, Header, HTTPException
-from pydantic import BaseModel
-
-fake_secret_token = "coneofsilence"
-
-fake_db = {
- "foo": {"id": "foo", "title": "Foo", "description": "There goes my hero"},
- "bar": {"id": "bar", "title": "Bar", "description": "The bartenders"},
-}
-
-app = FastAPI()
-
-
-class Item(BaseModel):
- id: str
- title: str
- description: Union[str, None] = None
-
-
-@app.get("/items/{item_id}", response_model=Item)
-async def read_main(item_id: str, x_token: str = Header()):
- if x_token != fake_secret_token:
- raise HTTPException(status_code=400, detail="Invalid X-Token header")
- if item_id not in fake_db:
- raise HTTPException(status_code=404, detail="Item not found")
- return fake_db[item_id]
-
-
-@app.post("/items/")
-async def create_item(item: Item, x_token: str = Header()) -> Item:
- if x_token != fake_secret_token:
- raise HTTPException(status_code=400, detail="Invalid X-Token header")
- if item.id in fake_db:
- raise HTTPException(status_code=409, detail="Item already exists")
- fake_db[item.id] = item.model_dump()
- return item
diff --git a/docs_src/app_testing/app_b_py39/test_main.py b/docs_src/app_testing/app_b_py39/test_main.py
deleted file mode 100644
index 4e1c51ecc8..0000000000
--- a/docs_src/app_testing/app_b_py39/test_main.py
+++ /dev/null
@@ -1,65 +0,0 @@
-from fastapi.testclient import TestClient
-
-from .main import app
-
-client = TestClient(app)
-
-
-def test_read_item():
- response = client.get("/items/foo", headers={"X-Token": "coneofsilence"})
- assert response.status_code == 200
- assert response.json() == {
- "id": "foo",
- "title": "Foo",
- "description": "There goes my hero",
- }
-
-
-def test_read_item_bad_token():
- response = client.get("/items/foo", headers={"X-Token": "hailhydra"})
- assert response.status_code == 400
- assert response.json() == {"detail": "Invalid X-Token header"}
-
-
-def test_read_nonexistent_item():
- response = client.get("/items/baz", headers={"X-Token": "coneofsilence"})
- assert response.status_code == 404
- assert response.json() == {"detail": "Item not found"}
-
-
-def test_create_item():
- response = client.post(
- "/items/",
- headers={"X-Token": "coneofsilence"},
- json={"id": "foobar", "title": "Foo Bar", "description": "The Foo Barters"},
- )
- assert response.status_code == 200
- assert response.json() == {
- "id": "foobar",
- "title": "Foo Bar",
- "description": "The Foo Barters",
- }
-
-
-def test_create_item_bad_token():
- response = client.post(
- "/items/",
- headers={"X-Token": "hailhydra"},
- json={"id": "bazz", "title": "Bazz", "description": "Drop the bazz"},
- )
- assert response.status_code == 400
- assert response.json() == {"detail": "Invalid X-Token header"}
-
-
-def test_create_existing_item():
- response = client.post(
- "/items/",
- headers={"X-Token": "coneofsilence"},
- json={
- "id": "foo",
- "title": "The Foo ID Stealers",
- "description": "There goes my stealer",
- },
- )
- assert response.status_code == 409
- assert response.json() == {"detail": "Item already exists"}
diff --git a/docs_src/app_testing/tutorial001_py39.py b/docs_src/app_testing/tutorial001_py310.py
similarity index 100%
rename from docs_src/app_testing/tutorial001_py39.py
rename to docs_src/app_testing/tutorial001_py310.py
diff --git a/docs_src/app_testing/tutorial002_py39.py b/docs_src/app_testing/tutorial002_py310.py
similarity index 100%
rename from docs_src/app_testing/tutorial002_py39.py
rename to docs_src/app_testing/tutorial002_py310.py
diff --git a/docs_src/app_testing/tutorial003_py39.py b/docs_src/app_testing/tutorial003_py310.py
similarity index 100%
rename from docs_src/app_testing/tutorial003_py39.py
rename to docs_src/app_testing/tutorial003_py310.py
diff --git a/docs_src/app_testing/tutorial004_py39.py b/docs_src/app_testing/tutorial004_py310.py
similarity index 100%
rename from docs_src/app_testing/tutorial004_py39.py
rename to docs_src/app_testing/tutorial004_py310.py
diff --git a/docs_src/app_testing/app_b_an_py39/__init__.py b/docs_src/async_tests/app_a_py310/__init__.py
similarity index 100%
rename from docs_src/app_testing/app_b_an_py39/__init__.py
rename to docs_src/async_tests/app_a_py310/__init__.py
diff --git a/docs_src/async_tests/app_a_py39/main.py b/docs_src/async_tests/app_a_py310/main.py
similarity index 100%
rename from docs_src/async_tests/app_a_py39/main.py
rename to docs_src/async_tests/app_a_py310/main.py
diff --git a/docs_src/async_tests/app_a_py39/test_main.py b/docs_src/async_tests/app_a_py310/test_main.py
similarity index 100%
rename from docs_src/async_tests/app_a_py39/test_main.py
rename to docs_src/async_tests/app_a_py310/test_main.py
diff --git a/docs_src/authentication_error_status_code/tutorial001_an_py39.py b/docs_src/authentication_error_status_code/tutorial001_an_py310.py
similarity index 100%
rename from docs_src/authentication_error_status_code/tutorial001_an_py39.py
rename to docs_src/authentication_error_status_code/tutorial001_an_py310.py
diff --git a/docs_src/background_tasks/tutorial001_py39.py b/docs_src/background_tasks/tutorial001_py310.py
similarity index 100%
rename from docs_src/background_tasks/tutorial001_py39.py
rename to docs_src/background_tasks/tutorial001_py310.py
diff --git a/docs_src/background_tasks/tutorial002_an_py39.py b/docs_src/background_tasks/tutorial002_an_py39.py
deleted file mode 100644
index bfdd148753..0000000000
--- a/docs_src/background_tasks/tutorial002_an_py39.py
+++ /dev/null
@@ -1,26 +0,0 @@
-from typing import Annotated, Union
-
-from fastapi import BackgroundTasks, Depends, FastAPI
-
-app = FastAPI()
-
-
-def write_log(message: str):
- with open("log.txt", mode="a") as log:
- log.write(message)
-
-
-def get_query(background_tasks: BackgroundTasks, q: Union[str, None] = None):
- if q:
- message = f"found query: {q}\n"
- background_tasks.add_task(write_log, message)
- return q
-
-
-@app.post("/send-notification/{email}")
-async def send_notification(
- email: str, background_tasks: BackgroundTasks, q: Annotated[str, Depends(get_query)]
-):
- message = f"message to {email}\n"
- background_tasks.add_task(write_log, message)
- return {"message": "Message sent"}
diff --git a/docs_src/background_tasks/tutorial002_py39.py b/docs_src/background_tasks/tutorial002_py39.py
deleted file mode 100644
index 2e1b2f6c6c..0000000000
--- a/docs_src/background_tasks/tutorial002_py39.py
+++ /dev/null
@@ -1,26 +0,0 @@
-from typing import Union
-
-from fastapi import BackgroundTasks, Depends, FastAPI
-
-app = FastAPI()
-
-
-def write_log(message: str):
- with open("log.txt", mode="a") as log:
- log.write(message)
-
-
-def get_query(background_tasks: BackgroundTasks, q: Union[str, None] = None):
- if q:
- message = f"found query: {q}\n"
- background_tasks.add_task(write_log, message)
- return q
-
-
-@app.post("/send-notification/{email}")
-async def send_notification(
- email: str, background_tasks: BackgroundTasks, q: str = Depends(get_query)
-):
- message = f"message to {email}\n"
- background_tasks.add_task(write_log, message)
- return {"message": "Message sent"}
diff --git a/docs_src/behind_a_proxy/tutorial001_01_py39.py b/docs_src/behind_a_proxy/tutorial001_01_py310.py
similarity index 100%
rename from docs_src/behind_a_proxy/tutorial001_01_py39.py
rename to docs_src/behind_a_proxy/tutorial001_01_py310.py
diff --git a/docs_src/behind_a_proxy/tutorial001_py39.py b/docs_src/behind_a_proxy/tutorial001_py310.py
similarity index 100%
rename from docs_src/behind_a_proxy/tutorial001_py39.py
rename to docs_src/behind_a_proxy/tutorial001_py310.py
diff --git a/docs_src/behind_a_proxy/tutorial002_py39.py b/docs_src/behind_a_proxy/tutorial002_py310.py
similarity index 100%
rename from docs_src/behind_a_proxy/tutorial002_py39.py
rename to docs_src/behind_a_proxy/tutorial002_py310.py
diff --git a/docs_src/behind_a_proxy/tutorial003_py39.py b/docs_src/behind_a_proxy/tutorial003_py310.py
similarity index 100%
rename from docs_src/behind_a_proxy/tutorial003_py39.py
rename to docs_src/behind_a_proxy/tutorial003_py310.py
diff --git a/docs_src/behind_a_proxy/tutorial004_py39.py b/docs_src/behind_a_proxy/tutorial004_py310.py
similarity index 100%
rename from docs_src/behind_a_proxy/tutorial004_py39.py
rename to docs_src/behind_a_proxy/tutorial004_py310.py
diff --git a/docs_src/app_testing/app_b_py39/__init__.py b/docs_src/bigger_applications/app_an_py310/__init__.py
similarity index 100%
rename from docs_src/app_testing/app_b_py39/__init__.py
rename to docs_src/bigger_applications/app_an_py310/__init__.py
diff --git a/docs_src/bigger_applications/app_an_py39/dependencies.py b/docs_src/bigger_applications/app_an_py310/dependencies.py
similarity index 100%
rename from docs_src/bigger_applications/app_an_py39/dependencies.py
rename to docs_src/bigger_applications/app_an_py310/dependencies.py
diff --git a/docs_src/async_tests/app_a_py39/__init__.py b/docs_src/bigger_applications/app_an_py310/internal/__init__.py
similarity index 100%
rename from docs_src/async_tests/app_a_py39/__init__.py
rename to docs_src/bigger_applications/app_an_py310/internal/__init__.py
diff --git a/docs_src/bigger_applications/app_an_py39/internal/admin.py b/docs_src/bigger_applications/app_an_py310/internal/admin.py
similarity index 100%
rename from docs_src/bigger_applications/app_an_py39/internal/admin.py
rename to docs_src/bigger_applications/app_an_py310/internal/admin.py
diff --git a/docs_src/bigger_applications/app_an_py39/main.py b/docs_src/bigger_applications/app_an_py310/main.py
similarity index 100%
rename from docs_src/bigger_applications/app_an_py39/main.py
rename to docs_src/bigger_applications/app_an_py310/main.py
diff --git a/docs_src/bigger_applications/app_an_py39/__init__.py b/docs_src/bigger_applications/app_an_py310/routers/__init__.py
similarity index 100%
rename from docs_src/bigger_applications/app_an_py39/__init__.py
rename to docs_src/bigger_applications/app_an_py310/routers/__init__.py
diff --git a/docs_src/bigger_applications/app_an_py39/routers/items.py b/docs_src/bigger_applications/app_an_py310/routers/items.py
similarity index 100%
rename from docs_src/bigger_applications/app_an_py39/routers/items.py
rename to docs_src/bigger_applications/app_an_py310/routers/items.py
diff --git a/docs_src/bigger_applications/app_an_py39/routers/users.py b/docs_src/bigger_applications/app_an_py310/routers/users.py
similarity index 100%
rename from docs_src/bigger_applications/app_an_py39/routers/users.py
rename to docs_src/bigger_applications/app_an_py310/routers/users.py
diff --git a/docs_src/bigger_applications/app_py39/dependencies.py b/docs_src/bigger_applications/app_py39/dependencies.py
deleted file mode 100644
index 8e45f004b4..0000000000
--- a/docs_src/bigger_applications/app_py39/dependencies.py
+++ /dev/null
@@ -1,11 +0,0 @@
-from fastapi import Header, HTTPException
-
-
-async def get_token_header(x_token: str = Header()):
- if x_token != "fake-super-secret-token":
- raise HTTPException(status_code=400, detail="X-Token header invalid")
-
-
-async def get_query_token(token: str):
- if token != "jessica":
- raise HTTPException(status_code=400, detail="No Jessica token provided")
diff --git a/docs_src/bigger_applications/app_py39/internal/admin.py b/docs_src/bigger_applications/app_py39/internal/admin.py
deleted file mode 100644
index 99d3da86b9..0000000000
--- a/docs_src/bigger_applications/app_py39/internal/admin.py
+++ /dev/null
@@ -1,8 +0,0 @@
-from fastapi import APIRouter
-
-router = APIRouter()
-
-
-@router.post("/")
-async def update_admin():
- return {"message": "Admin getting schwifty"}
diff --git a/docs_src/bigger_applications/app_py39/main.py b/docs_src/bigger_applications/app_py39/main.py
deleted file mode 100644
index ae544a3aac..0000000000
--- a/docs_src/bigger_applications/app_py39/main.py
+++ /dev/null
@@ -1,23 +0,0 @@
-from fastapi import Depends, FastAPI
-
-from .dependencies import get_query_token, get_token_header
-from .internal import admin
-from .routers import items, users
-
-app = FastAPI(dependencies=[Depends(get_query_token)])
-
-
-app.include_router(users.router)
-app.include_router(items.router)
-app.include_router(
- admin.router,
- prefix="/admin",
- tags=["admin"],
- dependencies=[Depends(get_token_header)],
- responses={418: {"description": "I'm a teapot"}},
-)
-
-
-@app.get("/")
-async def root():
- return {"message": "Hello Bigger Applications!"}
diff --git a/docs_src/bigger_applications/app_py39/routers/items.py b/docs_src/bigger_applications/app_py39/routers/items.py
deleted file mode 100644
index bde9ff4d55..0000000000
--- a/docs_src/bigger_applications/app_py39/routers/items.py
+++ /dev/null
@@ -1,38 +0,0 @@
-from fastapi import APIRouter, Depends, HTTPException
-
-from ..dependencies import get_token_header
-
-router = APIRouter(
- prefix="/items",
- tags=["items"],
- dependencies=[Depends(get_token_header)],
- responses={404: {"description": "Not found"}},
-)
-
-
-fake_items_db = {"plumbus": {"name": "Plumbus"}, "gun": {"name": "Portal Gun"}}
-
-
-@router.get("/")
-async def read_items():
- return fake_items_db
-
-
-@router.get("/{item_id}")
-async def read_item(item_id: str):
- if item_id not in fake_items_db:
- raise HTTPException(status_code=404, detail="Item not found")
- return {"name": fake_items_db[item_id]["name"], "item_id": item_id}
-
-
-@router.put(
- "/{item_id}",
- tags=["custom"],
- responses={403: {"description": "Operation forbidden"}},
-)
-async def update_item(item_id: str):
- if item_id != "plumbus":
- raise HTTPException(
- status_code=403, detail="You can only update the item: plumbus"
- )
- return {"item_id": item_id, "name": "The great Plumbus"}
diff --git a/docs_src/bigger_applications/app_py39/routers/users.py b/docs_src/bigger_applications/app_py39/routers/users.py
deleted file mode 100644
index 39b3d7e7cf..0000000000
--- a/docs_src/bigger_applications/app_py39/routers/users.py
+++ /dev/null
@@ -1,18 +0,0 @@
-from fastapi import APIRouter
-
-router = APIRouter()
-
-
-@router.get("/users/", tags=["users"])
-async def read_users():
- return [{"username": "Rick"}, {"username": "Morty"}]
-
-
-@router.get("/users/me", tags=["users"])
-async def read_user_me():
- return {"username": "fakecurrentuser"}
-
-
-@router.get("/users/{username}", tags=["users"])
-async def read_user(username: str):
- return {"username": username}
diff --git a/docs_src/body/tutorial001_py39.py b/docs_src/body/tutorial001_py39.py
deleted file mode 100644
index f933172746..0000000000
--- a/docs_src/body/tutorial001_py39.py
+++ /dev/null
@@ -1,19 +0,0 @@
-from typing import Union
-
-from fastapi import FastAPI
-from pydantic import BaseModel
-
-
-class Item(BaseModel):
- name: str
- description: Union[str, None] = None
- price: float
- tax: Union[float, None] = None
-
-
-app = FastAPI()
-
-
-@app.post("/items/")
-async def create_item(item: Item):
- return item
diff --git a/docs_src/body/tutorial002_py39.py b/docs_src/body/tutorial002_py39.py
deleted file mode 100644
index fb212e8e79..0000000000
--- a/docs_src/body/tutorial002_py39.py
+++ /dev/null
@@ -1,23 +0,0 @@
-from typing import Union
-
-from fastapi import FastAPI
-from pydantic import BaseModel
-
-
-class Item(BaseModel):
- name: str
- description: Union[str, None] = None
- price: float
- tax: Union[float, None] = None
-
-
-app = FastAPI()
-
-
-@app.post("/items/")
-async def create_item(item: Item):
- item_dict = item.model_dump()
- if item.tax is not None:
- price_with_tax = item.price + item.tax
- item_dict.update({"price_with_tax": price_with_tax})
- return item_dict
diff --git a/docs_src/body/tutorial003_py39.py b/docs_src/body/tutorial003_py39.py
deleted file mode 100644
index 636ba2275a..0000000000
--- a/docs_src/body/tutorial003_py39.py
+++ /dev/null
@@ -1,19 +0,0 @@
-from typing import Union
-
-from fastapi import FastAPI
-from pydantic import BaseModel
-
-
-class Item(BaseModel):
- name: str
- description: Union[str, None] = None
- price: float
- tax: Union[float, None] = None
-
-
-app = FastAPI()
-
-
-@app.put("/items/{item_id}")
-async def update_item(item_id: int, item: Item):
- return {"item_id": item_id, **item.model_dump()}
diff --git a/docs_src/body/tutorial004_py39.py b/docs_src/body/tutorial004_py39.py
deleted file mode 100644
index 2c157abfa1..0000000000
--- a/docs_src/body/tutorial004_py39.py
+++ /dev/null
@@ -1,22 +0,0 @@
-from typing import Union
-
-from fastapi import FastAPI
-from pydantic import BaseModel
-
-
-class Item(BaseModel):
- name: str
- description: Union[str, None] = None
- price: float
- tax: Union[float, None] = None
-
-
-app = FastAPI()
-
-
-@app.put("/items/{item_id}")
-async def update_item(item_id: int, item: Item, q: Union[str, None] = None):
- result = {"item_id": item_id, **item.model_dump()}
- if q:
- result.update({"q": q})
- return result
diff --git a/docs_src/body_fields/tutorial001_an_py39.py b/docs_src/body_fields/tutorial001_an_py39.py
deleted file mode 100644
index 6ef14470cd..0000000000
--- a/docs_src/body_fields/tutorial001_an_py39.py
+++ /dev/null
@@ -1,21 +0,0 @@
-from typing import Annotated, Union
-
-from fastapi import Body, FastAPI
-from pydantic import BaseModel, Field
-
-app = FastAPI()
-
-
-class Item(BaseModel):
- name: str
- description: Union[str, None] = Field(
- default=None, title="The description of the item", max_length=300
- )
- price: float = Field(gt=0, description="The price must be greater than zero")
- tax: Union[float, None] = None
-
-
-@app.put("/items/{item_id}")
-async def update_item(item_id: int, item: Annotated[Item, Body(embed=True)]):
- results = {"item_id": item_id, "item": item}
- return results
diff --git a/docs_src/body_fields/tutorial001_py39.py b/docs_src/body_fields/tutorial001_py39.py
deleted file mode 100644
index cbeebd614a..0000000000
--- a/docs_src/body_fields/tutorial001_py39.py
+++ /dev/null
@@ -1,21 +0,0 @@
-from typing import Union
-
-from fastapi import Body, FastAPI
-from pydantic import BaseModel, Field
-
-app = FastAPI()
-
-
-class Item(BaseModel):
- name: str
- description: Union[str, None] = Field(
- default=None, title="The description of the item", max_length=300
- )
- price: float = Field(gt=0, description="The price must be greater than zero")
- tax: Union[float, None] = None
-
-
-@app.put("/items/{item_id}")
-async def update_item(item_id: int, item: Item = Body(embed=True)):
- results = {"item_id": item_id, "item": item}
- return results
diff --git a/docs_src/body_multiple_params/tutorial001_an_py39.py b/docs_src/body_multiple_params/tutorial001_an_py39.py
deleted file mode 100644
index 1c0ac3a7b3..0000000000
--- a/docs_src/body_multiple_params/tutorial001_an_py39.py
+++ /dev/null
@@ -1,27 +0,0 @@
-from typing import Annotated, Union
-
-from fastapi import FastAPI, Path
-from pydantic import BaseModel
-
-app = FastAPI()
-
-
-class Item(BaseModel):
- name: str
- description: Union[str, None] = None
- price: float
- tax: Union[float, None] = None
-
-
-@app.put("/items/{item_id}")
-async def update_item(
- item_id: Annotated[int, Path(title="The ID of the item to get", ge=0, le=1000)],
- q: Union[str, None] = None,
- item: Union[Item, None] = None,
-):
- results = {"item_id": item_id}
- if q:
- results.update({"q": q})
- if item:
- results.update({"item": item})
- return results
diff --git a/docs_src/body_multiple_params/tutorial001_py39.py b/docs_src/body_multiple_params/tutorial001_py39.py
deleted file mode 100644
index a73975b3a2..0000000000
--- a/docs_src/body_multiple_params/tutorial001_py39.py
+++ /dev/null
@@ -1,28 +0,0 @@
-from typing import Union
-
-from fastapi import FastAPI, Path
-from pydantic import BaseModel
-
-app = FastAPI()
-
-
-class Item(BaseModel):
- name: str
- description: Union[str, None] = None
- price: float
- tax: Union[float, None] = None
-
-
-@app.put("/items/{item_id}")
-async def update_item(
- *,
- item_id: int = Path(title="The ID of the item to get", ge=0, le=1000),
- q: Union[str, None] = None,
- item: Union[Item, None] = None,
-):
- results = {"item_id": item_id}
- if q:
- results.update({"q": q})
- if item:
- results.update({"item": item})
- return results
diff --git a/docs_src/body_multiple_params/tutorial002_py39.py b/docs_src/body_multiple_params/tutorial002_py39.py
deleted file mode 100644
index 2d7160ae8e..0000000000
--- a/docs_src/body_multiple_params/tutorial002_py39.py
+++ /dev/null
@@ -1,24 +0,0 @@
-from typing import Union
-
-from fastapi import FastAPI
-from pydantic import BaseModel
-
-app = FastAPI()
-
-
-class Item(BaseModel):
- name: str
- description: Union[str, None] = None
- price: float
- tax: Union[float, None] = None
-
-
-class User(BaseModel):
- username: str
- full_name: Union[str, None] = None
-
-
-@app.put("/items/{item_id}")
-async def update_item(item_id: int, item: Item, user: User):
- results = {"item_id": item_id, "item": item, "user": user}
- return results
diff --git a/docs_src/body_multiple_params/tutorial003_an_py39.py b/docs_src/body_multiple_params/tutorial003_an_py39.py
deleted file mode 100644
index 042351e0b7..0000000000
--- a/docs_src/body_multiple_params/tutorial003_an_py39.py
+++ /dev/null
@@ -1,26 +0,0 @@
-from typing import Annotated, Union
-
-from fastapi import Body, FastAPI
-from pydantic import BaseModel
-
-app = FastAPI()
-
-
-class Item(BaseModel):
- name: str
- description: Union[str, None] = None
- price: float
- tax: Union[float, None] = None
-
-
-class User(BaseModel):
- username: str
- full_name: Union[str, None] = None
-
-
-@app.put("/items/{item_id}")
-async def update_item(
- item_id: int, item: Item, user: User, importance: Annotated[int, Body()]
-):
- results = {"item_id": item_id, "item": item, "user": user, "importance": importance}
- return results
diff --git a/docs_src/body_multiple_params/tutorial003_py39.py b/docs_src/body_multiple_params/tutorial003_py39.py
deleted file mode 100644
index cf344e6c5d..0000000000
--- a/docs_src/body_multiple_params/tutorial003_py39.py
+++ /dev/null
@@ -1,24 +0,0 @@
-from typing import Union
-
-from fastapi import Body, FastAPI
-from pydantic import BaseModel
-
-app = FastAPI()
-
-
-class Item(BaseModel):
- name: str
- description: Union[str, None] = None
- price: float
- tax: Union[float, None] = None
-
-
-class User(BaseModel):
- username: str
- full_name: Union[str, None] = None
-
-
-@app.put("/items/{item_id}")
-async def update_item(item_id: int, item: Item, user: User, importance: int = Body()):
- results = {"item_id": item_id, "item": item, "user": user, "importance": importance}
- return results
diff --git a/docs_src/body_multiple_params/tutorial004_an_py39.py b/docs_src/body_multiple_params/tutorial004_an_py39.py
deleted file mode 100644
index 567427c03e..0000000000
--- a/docs_src/body_multiple_params/tutorial004_an_py39.py
+++ /dev/null
@@ -1,33 +0,0 @@
-from typing import Annotated, Union
-
-from fastapi import Body, FastAPI
-from pydantic import BaseModel
-
-app = FastAPI()
-
-
-class Item(BaseModel):
- name: str
- description: Union[str, None] = None
- price: float
- tax: Union[float, None] = None
-
-
-class User(BaseModel):
- username: str
- full_name: Union[str, None] = None
-
-
-@app.put("/items/{item_id}")
-async def update_item(
- *,
- item_id: int,
- item: Item,
- user: User,
- importance: Annotated[int, Body(gt=0)],
- q: Union[str, None] = None,
-):
- results = {"item_id": item_id, "item": item, "user": user, "importance": importance}
- if q:
- results.update({"q": q})
- return results
diff --git a/docs_src/body_multiple_params/tutorial004_py39.py b/docs_src/body_multiple_params/tutorial004_py39.py
deleted file mode 100644
index 8ce4c7a976..0000000000
--- a/docs_src/body_multiple_params/tutorial004_py39.py
+++ /dev/null
@@ -1,33 +0,0 @@
-from typing import Union
-
-from fastapi import Body, FastAPI
-from pydantic import BaseModel
-
-app = FastAPI()
-
-
-class Item(BaseModel):
- name: str
- description: Union[str, None] = None
- price: float
- tax: Union[float, None] = None
-
-
-class User(BaseModel):
- username: str
- full_name: Union[str, None] = None
-
-
-@app.put("/items/{item_id}")
-async def update_item(
- *,
- item_id: int,
- item: Item,
- user: User,
- importance: int = Body(gt=0),
- q: Union[str, None] = None,
-):
- results = {"item_id": item_id, "item": item, "user": user, "importance": importance}
- if q:
- results.update({"q": q})
- return results
diff --git a/docs_src/body_multiple_params/tutorial005_an_py39.py b/docs_src/body_multiple_params/tutorial005_an_py39.py
deleted file mode 100644
index 9a52425c16..0000000000
--- a/docs_src/body_multiple_params/tutorial005_an_py39.py
+++ /dev/null
@@ -1,19 +0,0 @@
-from typing import Annotated, Union
-
-from fastapi import Body, FastAPI
-from pydantic import BaseModel
-
-app = FastAPI()
-
-
-class Item(BaseModel):
- name: str
- description: Union[str, None] = None
- price: float
- tax: Union[float, None] = None
-
-
-@app.put("/items/{item_id}")
-async def update_item(item_id: int, item: Annotated[Item, Body(embed=True)]):
- results = {"item_id": item_id, "item": item}
- return results
diff --git a/docs_src/body_multiple_params/tutorial005_py39.py b/docs_src/body_multiple_params/tutorial005_py39.py
deleted file mode 100644
index 29e6e14b7e..0000000000
--- a/docs_src/body_multiple_params/tutorial005_py39.py
+++ /dev/null
@@ -1,19 +0,0 @@
-from typing import Union
-
-from fastapi import Body, FastAPI
-from pydantic import BaseModel
-
-app = FastAPI()
-
-
-class Item(BaseModel):
- name: str
- description: Union[str, None] = None
- price: float
- tax: Union[float, None] = None
-
-
-@app.put("/items/{item_id}")
-async def update_item(item_id: int, item: Item = Body(embed=True)):
- results = {"item_id": item_id, "item": item}
- return results
diff --git a/docs_src/body_nested_models/tutorial001_py39.py b/docs_src/body_nested_models/tutorial001_py39.py
deleted file mode 100644
index 37ef6dda58..0000000000
--- a/docs_src/body_nested_models/tutorial001_py39.py
+++ /dev/null
@@ -1,20 +0,0 @@
-from typing import Union
-
-from fastapi import FastAPI
-from pydantic import BaseModel
-
-app = FastAPI()
-
-
-class Item(BaseModel):
- name: str
- description: Union[str, None] = None
- price: float
- tax: Union[float, None] = None
- tags: list = []
-
-
-@app.put("/items/{item_id}")
-async def update_item(item_id: int, item: Item):
- results = {"item_id": item_id, "item": item}
- return results
diff --git a/docs_src/body_nested_models/tutorial002_py39.py b/docs_src/body_nested_models/tutorial002_py39.py
deleted file mode 100644
index 8a93a7233f..0000000000
--- a/docs_src/body_nested_models/tutorial002_py39.py
+++ /dev/null
@@ -1,20 +0,0 @@
-from typing import Union
-
-from fastapi import FastAPI
-from pydantic import BaseModel
-
-app = FastAPI()
-
-
-class Item(BaseModel):
- name: str
- description: Union[str, None] = None
- price: float
- tax: Union[float, None] = None
- tags: list[str] = []
-
-
-@app.put("/items/{item_id}")
-async def update_item(item_id: int, item: Item):
- results = {"item_id": item_id, "item": item}
- return results
diff --git a/docs_src/body_nested_models/tutorial003_py39.py b/docs_src/body_nested_models/tutorial003_py39.py
deleted file mode 100644
index b590ece369..0000000000
--- a/docs_src/body_nested_models/tutorial003_py39.py
+++ /dev/null
@@ -1,20 +0,0 @@
-from typing import Union
-
-from fastapi import FastAPI
-from pydantic import BaseModel
-
-app = FastAPI()
-
-
-class Item(BaseModel):
- name: str
- description: Union[str, None] = None
- price: float
- tax: Union[float, None] = None
- tags: set[str] = set()
-
-
-@app.put("/items/{item_id}")
-async def update_item(item_id: int, item: Item):
- results = {"item_id": item_id, "item": item}
- return results
diff --git a/docs_src/body_nested_models/tutorial004_py39.py b/docs_src/body_nested_models/tutorial004_py39.py
deleted file mode 100644
index dc2b175fb2..0000000000
--- a/docs_src/body_nested_models/tutorial004_py39.py
+++ /dev/null
@@ -1,26 +0,0 @@
-from typing import Union
-
-from fastapi import FastAPI
-from pydantic import BaseModel
-
-app = FastAPI()
-
-
-class Image(BaseModel):
- url: str
- name: str
-
-
-class Item(BaseModel):
- name: str
- description: Union[str, None] = None
- price: float
- tax: Union[float, None] = None
- tags: set[str] = set()
- image: Union[Image, None] = None
-
-
-@app.put("/items/{item_id}")
-async def update_item(item_id: int, item: Item):
- results = {"item_id": item_id, "item": item}
- return results
diff --git a/docs_src/body_nested_models/tutorial005_py39.py b/docs_src/body_nested_models/tutorial005_py39.py
deleted file mode 100644
index 47db90008a..0000000000
--- a/docs_src/body_nested_models/tutorial005_py39.py
+++ /dev/null
@@ -1,26 +0,0 @@
-from typing import Union
-
-from fastapi import FastAPI
-from pydantic import BaseModel, HttpUrl
-
-app = FastAPI()
-
-
-class Image(BaseModel):
- url: HttpUrl
- name: str
-
-
-class Item(BaseModel):
- name: str
- description: Union[str, None] = None
- price: float
- tax: Union[float, None] = None
- tags: set[str] = set()
- image: Union[Image, None] = None
-
-
-@app.put("/items/{item_id}")
-async def update_item(item_id: int, item: Item):
- results = {"item_id": item_id, "item": item}
- return results
diff --git a/docs_src/body_nested_models/tutorial006_py39.py b/docs_src/body_nested_models/tutorial006_py39.py
deleted file mode 100644
index b14409703a..0000000000
--- a/docs_src/body_nested_models/tutorial006_py39.py
+++ /dev/null
@@ -1,26 +0,0 @@
-from typing import Union
-
-from fastapi import FastAPI
-from pydantic import BaseModel, HttpUrl
-
-app = FastAPI()
-
-
-class Image(BaseModel):
- url: HttpUrl
- name: str
-
-
-class Item(BaseModel):
- name: str
- description: Union[str, None] = None
- price: float
- tax: Union[float, None] = None
- tags: set[str] = set()
- images: Union[list[Image], None] = None
-
-
-@app.put("/items/{item_id}")
-async def update_item(item_id: int, item: Item):
- results = {"item_id": item_id, "item": item}
- return results
diff --git a/docs_src/body_nested_models/tutorial007_py39.py b/docs_src/body_nested_models/tutorial007_py39.py
deleted file mode 100644
index 59cf01e236..0000000000
--- a/docs_src/body_nested_models/tutorial007_py39.py
+++ /dev/null
@@ -1,32 +0,0 @@
-from typing import Union
-
-from fastapi import FastAPI
-from pydantic import BaseModel, HttpUrl
-
-app = FastAPI()
-
-
-class Image(BaseModel):
- url: HttpUrl
- name: str
-
-
-class Item(BaseModel):
- name: str
- description: Union[str, None] = None
- price: float
- tax: Union[float, None] = None
- tags: set[str] = set()
- images: Union[list[Image], None] = None
-
-
-class Offer(BaseModel):
- name: str
- description: Union[str, None] = None
- price: float
- items: list[Item]
-
-
-@app.post("/offers/")
-async def create_offer(offer: Offer):
- return offer
diff --git a/docs_src/body_nested_models/tutorial008_py39.py b/docs_src/body_nested_models/tutorial008_py310.py
similarity index 100%
rename from docs_src/body_nested_models/tutorial008_py39.py
rename to docs_src/body_nested_models/tutorial008_py310.py
diff --git a/docs_src/body_nested_models/tutorial009_py39.py b/docs_src/body_nested_models/tutorial009_py310.py
similarity index 100%
rename from docs_src/body_nested_models/tutorial009_py39.py
rename to docs_src/body_nested_models/tutorial009_py310.py
diff --git a/docs_src/body_updates/tutorial001_py39.py b/docs_src/body_updates/tutorial001_py39.py
deleted file mode 100644
index 999bcdb82d..0000000000
--- a/docs_src/body_updates/tutorial001_py39.py
+++ /dev/null
@@ -1,34 +0,0 @@
-from typing import Union
-
-from fastapi import FastAPI
-from fastapi.encoders import jsonable_encoder
-from pydantic import BaseModel
-
-app = FastAPI()
-
-
-class Item(BaseModel):
- name: Union[str, None] = None
- description: Union[str, None] = None
- price: Union[float, None] = None
- tax: float = 10.5
- tags: list[str] = []
-
-
-items = {
- "foo": {"name": "Foo", "price": 50.2},
- "bar": {"name": "Bar", "description": "The bartenders", "price": 62, "tax": 20.2},
- "baz": {"name": "Baz", "description": None, "price": 50.2, "tax": 10.5, "tags": []},
-}
-
-
-@app.get("/items/{item_id}", response_model=Item)
-async def read_item(item_id: str):
- return items[item_id]
-
-
-@app.put("/items/{item_id}", response_model=Item)
-async def update_item(item_id: str, item: Item):
- update_item_encoded = jsonable_encoder(item)
- items[item_id] = update_item_encoded
- return update_item_encoded
diff --git a/docs_src/body_updates/tutorial002_py39.py b/docs_src/body_updates/tutorial002_py39.py
deleted file mode 100644
index 3714b5a55d..0000000000
--- a/docs_src/body_updates/tutorial002_py39.py
+++ /dev/null
@@ -1,37 +0,0 @@
-from typing import Union
-
-from fastapi import FastAPI
-from fastapi.encoders import jsonable_encoder
-from pydantic import BaseModel
-
-app = FastAPI()
-
-
-class Item(BaseModel):
- name: Union[str, None] = None
- description: Union[str, None] = None
- price: Union[float, None] = None
- tax: float = 10.5
- tags: list[str] = []
-
-
-items = {
- "foo": {"name": "Foo", "price": 50.2},
- "bar": {"name": "Bar", "description": "The bartenders", "price": 62, "tax": 20.2},
- "baz": {"name": "Baz", "description": None, "price": 50.2, "tax": 10.5, "tags": []},
-}
-
-
-@app.get("/items/{item_id}", response_model=Item)
-async def read_item(item_id: str):
- return items[item_id]
-
-
-@app.patch("/items/{item_id}")
-async def update_item(item_id: str, item: Item) -> Item:
- stored_item_data = items[item_id]
- stored_item_model = Item(**stored_item_data)
- update_data = item.model_dump(exclude_unset=True)
- updated_item = stored_item_model.model_copy(update=update_data)
- items[item_id] = jsonable_encoder(updated_item)
- return updated_item
diff --git a/docs_src/conditional_openapi/tutorial001_py39.py b/docs_src/conditional_openapi/tutorial001_py310.py
similarity index 100%
rename from docs_src/conditional_openapi/tutorial001_py39.py
rename to docs_src/conditional_openapi/tutorial001_py310.py
diff --git a/docs_src/configure_swagger_ui/tutorial001_py39.py b/docs_src/configure_swagger_ui/tutorial001_py310.py
similarity index 100%
rename from docs_src/configure_swagger_ui/tutorial001_py39.py
rename to docs_src/configure_swagger_ui/tutorial001_py310.py
diff --git a/docs_src/configure_swagger_ui/tutorial002_py39.py b/docs_src/configure_swagger_ui/tutorial002_py310.py
similarity index 100%
rename from docs_src/configure_swagger_ui/tutorial002_py39.py
rename to docs_src/configure_swagger_ui/tutorial002_py310.py
diff --git a/docs_src/configure_swagger_ui/tutorial003_py39.py b/docs_src/configure_swagger_ui/tutorial003_py310.py
similarity index 100%
rename from docs_src/configure_swagger_ui/tutorial003_py39.py
rename to docs_src/configure_swagger_ui/tutorial003_py310.py
diff --git a/docs_src/cookie_param_models/tutorial001_an_py39.py b/docs_src/cookie_param_models/tutorial001_an_py39.py
deleted file mode 100644
index 3d90c2007b..0000000000
--- a/docs_src/cookie_param_models/tutorial001_an_py39.py
+++ /dev/null
@@ -1,17 +0,0 @@
-from typing import Annotated, Union
-
-from fastapi import Cookie, FastAPI
-from pydantic import BaseModel
-
-app = FastAPI()
-
-
-class Cookies(BaseModel):
- session_id: str
- fatebook_tracker: Union[str, None] = None
- googall_tracker: Union[str, None] = None
-
-
-@app.get("/items/")
-async def read_items(cookies: Annotated[Cookies, Cookie()]):
- return cookies
diff --git a/docs_src/cookie_param_models/tutorial001_py39.py b/docs_src/cookie_param_models/tutorial001_py39.py
deleted file mode 100644
index cc65c43e1a..0000000000
--- a/docs_src/cookie_param_models/tutorial001_py39.py
+++ /dev/null
@@ -1,17 +0,0 @@
-from typing import Union
-
-from fastapi import Cookie, FastAPI
-from pydantic import BaseModel
-
-app = FastAPI()
-
-
-class Cookies(BaseModel):
- session_id: str
- fatebook_tracker: Union[str, None] = None
- googall_tracker: Union[str, None] = None
-
-
-@app.get("/items/")
-async def read_items(cookies: Cookies = Cookie()):
- return cookies
diff --git a/docs_src/cookie_param_models/tutorial002_an_py39.py b/docs_src/cookie_param_models/tutorial002_an_py39.py
deleted file mode 100644
index a906ce6a1c..0000000000
--- a/docs_src/cookie_param_models/tutorial002_an_py39.py
+++ /dev/null
@@ -1,19 +0,0 @@
-from typing import Annotated, Union
-
-from fastapi import Cookie, FastAPI
-from pydantic import BaseModel
-
-app = FastAPI()
-
-
-class Cookies(BaseModel):
- model_config = {"extra": "forbid"}
-
- session_id: str
- fatebook_tracker: Union[str, None] = None
- googall_tracker: Union[str, None] = None
-
-
-@app.get("/items/")
-async def read_items(cookies: Annotated[Cookies, Cookie()]):
- return cookies
diff --git a/docs_src/cookie_param_models/tutorial002_py39.py b/docs_src/cookie_param_models/tutorial002_py39.py
deleted file mode 100644
index 9679e890f6..0000000000
--- a/docs_src/cookie_param_models/tutorial002_py39.py
+++ /dev/null
@@ -1,19 +0,0 @@
-from typing import Union
-
-from fastapi import Cookie, FastAPI
-from pydantic import BaseModel
-
-app = FastAPI()
-
-
-class Cookies(BaseModel):
- model_config = {"extra": "forbid"}
-
- session_id: str
- fatebook_tracker: Union[str, None] = None
- googall_tracker: Union[str, None] = None
-
-
-@app.get("/items/")
-async def read_items(cookies: Cookies = Cookie()):
- return cookies
diff --git a/docs_src/cookie_params/tutorial001_an_py39.py b/docs_src/cookie_params/tutorial001_an_py39.py
deleted file mode 100644
index e18d0a332e..0000000000
--- a/docs_src/cookie_params/tutorial001_an_py39.py
+++ /dev/null
@@ -1,10 +0,0 @@
-from typing import Annotated, Union
-
-from fastapi import Cookie, FastAPI
-
-app = FastAPI()
-
-
-@app.get("/items/")
-async def read_items(ads_id: Annotated[Union[str, None], Cookie()] = None):
- return {"ads_id": ads_id}
diff --git a/docs_src/cookie_params/tutorial001_py39.py b/docs_src/cookie_params/tutorial001_py39.py
deleted file mode 100644
index c4a497fda5..0000000000
--- a/docs_src/cookie_params/tutorial001_py39.py
+++ /dev/null
@@ -1,10 +0,0 @@
-from typing import Union
-
-from fastapi import Cookie, FastAPI
-
-app = FastAPI()
-
-
-@app.get("/items/")
-async def read_items(ads_id: Union[str, None] = Cookie(default=None)):
- return {"ads_id": ads_id}
diff --git a/docs_src/cors/tutorial001_py39.py b/docs_src/cors/tutorial001_py310.py
similarity index 100%
rename from docs_src/cors/tutorial001_py39.py
rename to docs_src/cors/tutorial001_py310.py
diff --git a/docs_src/custom_docs_ui/tutorial001_py39.py b/docs_src/custom_docs_ui/tutorial001_py310.py
similarity index 100%
rename from docs_src/custom_docs_ui/tutorial001_py39.py
rename to docs_src/custom_docs_ui/tutorial001_py310.py
diff --git a/docs_src/custom_docs_ui/tutorial002_py39.py b/docs_src/custom_docs_ui/tutorial002_py310.py
similarity index 100%
rename from docs_src/custom_docs_ui/tutorial002_py39.py
rename to docs_src/custom_docs_ui/tutorial002_py310.py
diff --git a/docs_src/custom_request_and_route/tutorial001_an_py39.py b/docs_src/custom_request_and_route/tutorial001_an_py39.py
deleted file mode 100644
index 076727e643..0000000000
--- a/docs_src/custom_request_and_route/tutorial001_an_py39.py
+++ /dev/null
@@ -1,35 +0,0 @@
-import gzip
-from typing import Annotated, Callable
-
-from fastapi import Body, FastAPI, Request, Response
-from fastapi.routing import APIRoute
-
-
-class GzipRequest(Request):
- async def body(self) -> bytes:
- if not hasattr(self, "_body"):
- body = await super().body()
- if "gzip" in self.headers.getlist("Content-Encoding"):
- body = gzip.decompress(body)
- self._body = body
- return self._body
-
-
-class GzipRoute(APIRoute):
- def get_route_handler(self) -> Callable:
- original_route_handler = super().get_route_handler()
-
- async def custom_route_handler(request: Request) -> Response:
- request = GzipRequest(request.scope, request.receive)
- return await original_route_handler(request)
-
- return custom_route_handler
-
-
-app = FastAPI()
-app.router.route_class = GzipRoute
-
-
-@app.post("/sum")
-async def sum_numbers(numbers: Annotated[list[int], Body()]):
- return {"sum": sum(numbers)}
diff --git a/docs_src/custom_request_and_route/tutorial001_py39.py b/docs_src/custom_request_and_route/tutorial001_py39.py
deleted file mode 100644
index 54b20b9425..0000000000
--- a/docs_src/custom_request_and_route/tutorial001_py39.py
+++ /dev/null
@@ -1,35 +0,0 @@
-import gzip
-from typing import Callable
-
-from fastapi import Body, FastAPI, Request, Response
-from fastapi.routing import APIRoute
-
-
-class GzipRequest(Request):
- async def body(self) -> bytes:
- if not hasattr(self, "_body"):
- body = await super().body()
- if "gzip" in self.headers.getlist("Content-Encoding"):
- body = gzip.decompress(body)
- self._body = body
- return self._body
-
-
-class GzipRoute(APIRoute):
- def get_route_handler(self) -> Callable:
- original_route_handler = super().get_route_handler()
-
- async def custom_route_handler(request: Request) -> Response:
- request = GzipRequest(request.scope, request.receive)
- return await original_route_handler(request)
-
- return custom_route_handler
-
-
-app = FastAPI()
-app.router.route_class = GzipRoute
-
-
-@app.post("/sum")
-async def sum_numbers(numbers: list[int] = Body()):
- return {"sum": sum(numbers)}
diff --git a/docs_src/custom_request_and_route/tutorial002_an_py39.py b/docs_src/custom_request_and_route/tutorial002_an_py39.py
deleted file mode 100644
index e7de09de44..0000000000
--- a/docs_src/custom_request_and_route/tutorial002_an_py39.py
+++ /dev/null
@@ -1,29 +0,0 @@
-from typing import Annotated, Callable
-
-from fastapi import Body, FastAPI, HTTPException, Request, Response
-from fastapi.exceptions import RequestValidationError
-from fastapi.routing import APIRoute
-
-
-class ValidationErrorLoggingRoute(APIRoute):
- def get_route_handler(self) -> Callable:
- original_route_handler = super().get_route_handler()
-
- async def custom_route_handler(request: Request) -> Response:
- try:
- return await original_route_handler(request)
- except RequestValidationError as exc:
- body = await request.body()
- detail = {"errors": exc.errors(), "body": body.decode()}
- raise HTTPException(status_code=422, detail=detail)
-
- return custom_route_handler
-
-
-app = FastAPI()
-app.router.route_class = ValidationErrorLoggingRoute
-
-
-@app.post("/")
-async def sum_numbers(numbers: Annotated[list[int], Body()]):
- return sum(numbers)
diff --git a/docs_src/custom_request_and_route/tutorial002_py39.py b/docs_src/custom_request_and_route/tutorial002_py39.py
deleted file mode 100644
index c4e4748281..0000000000
--- a/docs_src/custom_request_and_route/tutorial002_py39.py
+++ /dev/null
@@ -1,29 +0,0 @@
-from typing import Callable
-
-from fastapi import Body, FastAPI, HTTPException, Request, Response
-from fastapi.exceptions import RequestValidationError
-from fastapi.routing import APIRoute
-
-
-class ValidationErrorLoggingRoute(APIRoute):
- def get_route_handler(self) -> Callable:
- original_route_handler = super().get_route_handler()
-
- async def custom_route_handler(request: Request) -> Response:
- try:
- return await original_route_handler(request)
- except RequestValidationError as exc:
- body = await request.body()
- detail = {"errors": exc.errors(), "body": body.decode()}
- raise HTTPException(status_code=422, detail=detail)
-
- return custom_route_handler
-
-
-app = FastAPI()
-app.router.route_class = ValidationErrorLoggingRoute
-
-
-@app.post("/")
-async def sum_numbers(numbers: list[int] = Body()):
- return sum(numbers)
diff --git a/docs_src/custom_request_and_route/tutorial003_py39.py b/docs_src/custom_request_and_route/tutorial003_py39.py
deleted file mode 100644
index aabe760685..0000000000
--- a/docs_src/custom_request_and_route/tutorial003_py39.py
+++ /dev/null
@@ -1,39 +0,0 @@
-import time
-from typing import Callable
-
-from fastapi import APIRouter, FastAPI, Request, Response
-from fastapi.routing import APIRoute
-
-
-class TimedRoute(APIRoute):
- def get_route_handler(self) -> Callable:
- original_route_handler = super().get_route_handler()
-
- async def custom_route_handler(request: Request) -> Response:
- before = time.time()
- response: Response = await original_route_handler(request)
- duration = time.time() - before
- response.headers["X-Response-Time"] = str(duration)
- print(f"route duration: {duration}")
- print(f"route response: {response}")
- print(f"route response headers: {response.headers}")
- return response
-
- return custom_route_handler
-
-
-app = FastAPI()
-router = APIRouter(route_class=TimedRoute)
-
-
-@app.get("/")
-async def not_timed():
- return {"message": "Not timed"}
-
-
-@router.get("/timed")
-async def timed():
- return {"message": "It's the time of my life"}
-
-
-app.include_router(router)
diff --git a/docs_src/custom_response/tutorial001_py39.py b/docs_src/custom_response/tutorial001_py310.py
similarity index 100%
rename from docs_src/custom_response/tutorial001_py39.py
rename to docs_src/custom_response/tutorial001_py310.py
diff --git a/docs_src/custom_response/tutorial001b_py39.py b/docs_src/custom_response/tutorial001b_py310.py
similarity index 100%
rename from docs_src/custom_response/tutorial001b_py39.py
rename to docs_src/custom_response/tutorial001b_py310.py
diff --git a/docs_src/custom_response/tutorial002_py39.py b/docs_src/custom_response/tutorial002_py310.py
similarity index 100%
rename from docs_src/custom_response/tutorial002_py39.py
rename to docs_src/custom_response/tutorial002_py310.py
diff --git a/docs_src/custom_response/tutorial003_py39.py b/docs_src/custom_response/tutorial003_py310.py
similarity index 100%
rename from docs_src/custom_response/tutorial003_py39.py
rename to docs_src/custom_response/tutorial003_py310.py
diff --git a/docs_src/custom_response/tutorial004_py39.py b/docs_src/custom_response/tutorial004_py310.py
similarity index 100%
rename from docs_src/custom_response/tutorial004_py39.py
rename to docs_src/custom_response/tutorial004_py310.py
diff --git a/docs_src/custom_response/tutorial005_py39.py b/docs_src/custom_response/tutorial005_py310.py
similarity index 100%
rename from docs_src/custom_response/tutorial005_py39.py
rename to docs_src/custom_response/tutorial005_py310.py
diff --git a/docs_src/custom_response/tutorial006_py39.py b/docs_src/custom_response/tutorial006_py310.py
similarity index 100%
rename from docs_src/custom_response/tutorial006_py39.py
rename to docs_src/custom_response/tutorial006_py310.py
diff --git a/docs_src/custom_response/tutorial006b_py39.py b/docs_src/custom_response/tutorial006b_py310.py
similarity index 100%
rename from docs_src/custom_response/tutorial006b_py39.py
rename to docs_src/custom_response/tutorial006b_py310.py
diff --git a/docs_src/custom_response/tutorial006c_py39.py b/docs_src/custom_response/tutorial006c_py310.py
similarity index 100%
rename from docs_src/custom_response/tutorial006c_py39.py
rename to docs_src/custom_response/tutorial006c_py310.py
diff --git a/docs_src/custom_response/tutorial007_py39.py b/docs_src/custom_response/tutorial007_py310.py
similarity index 100%
rename from docs_src/custom_response/tutorial007_py39.py
rename to docs_src/custom_response/tutorial007_py310.py
diff --git a/docs_src/custom_response/tutorial008_py39.py b/docs_src/custom_response/tutorial008_py310.py
similarity index 100%
rename from docs_src/custom_response/tutorial008_py39.py
rename to docs_src/custom_response/tutorial008_py310.py
diff --git a/docs_src/custom_response/tutorial009_py39.py b/docs_src/custom_response/tutorial009_py310.py
similarity index 100%
rename from docs_src/custom_response/tutorial009_py39.py
rename to docs_src/custom_response/tutorial009_py310.py
diff --git a/docs_src/custom_response/tutorial009b_py39.py b/docs_src/custom_response/tutorial009b_py310.py
similarity index 100%
rename from docs_src/custom_response/tutorial009b_py39.py
rename to docs_src/custom_response/tutorial009b_py310.py
diff --git a/docs_src/custom_response/tutorial009c_py39.py b/docs_src/custom_response/tutorial009c_py310.py
similarity index 100%
rename from docs_src/custom_response/tutorial009c_py39.py
rename to docs_src/custom_response/tutorial009c_py310.py
diff --git a/docs_src/custom_response/tutorial010_py39.py b/docs_src/custom_response/tutorial010_py310.py
similarity index 100%
rename from docs_src/custom_response/tutorial010_py39.py
rename to docs_src/custom_response/tutorial010_py310.py
diff --git a/docs_src/dataclasses_/tutorial001_py39.py b/docs_src/dataclasses_/tutorial001_py39.py
deleted file mode 100644
index 2954c391f1..0000000000
--- a/docs_src/dataclasses_/tutorial001_py39.py
+++ /dev/null
@@ -1,20 +0,0 @@
-from dataclasses import dataclass
-from typing import Union
-
-from fastapi import FastAPI
-
-
-@dataclass
-class Item:
- name: str
- price: float
- description: Union[str, None] = None
- tax: Union[float, None] = None
-
-
-app = FastAPI()
-
-
-@app.post("/items/")
-async def create_item(item: Item):
- return item
diff --git a/docs_src/dataclasses_/tutorial002_py39.py b/docs_src/dataclasses_/tutorial002_py39.py
deleted file mode 100644
index 0c23765d84..0000000000
--- a/docs_src/dataclasses_/tutorial002_py39.py
+++ /dev/null
@@ -1,26 +0,0 @@
-from dataclasses import dataclass, field
-from typing import Union
-
-from fastapi import FastAPI
-
-
-@dataclass
-class Item:
- name: str
- price: float
- tags: list[str] = field(default_factory=list)
- description: Union[str, None] = None
- tax: Union[float, None] = None
-
-
-app = FastAPI()
-
-
-@app.get("/items/next", response_model=Item)
-async def read_next_item():
- return {
- "name": "Island In The Moon",
- "price": 12.99,
- "description": "A place to be playin' and havin' fun",
- "tags": ["breater"],
- }
diff --git a/docs_src/dataclasses_/tutorial003_py39.py b/docs_src/dataclasses_/tutorial003_py39.py
deleted file mode 100644
index 991708c009..0000000000
--- a/docs_src/dataclasses_/tutorial003_py39.py
+++ /dev/null
@@ -1,55 +0,0 @@
-from dataclasses import field # (1)
-from typing import Union
-
-from fastapi import FastAPI
-from pydantic.dataclasses import dataclass # (2)
-
-
-@dataclass
-class Item:
- name: str
- description: Union[str, None] = None
-
-
-@dataclass
-class Author:
- name: str
- items: list[Item] = field(default_factory=list) # (3)
-
-
-app = FastAPI()
-
-
-@app.post("/authors/{author_id}/items/", response_model=Author) # (4)
-async def create_author_items(author_id: str, items: list[Item]): # (5)
- return {"name": author_id, "items": items} # (6)
-
-
-@app.get("/authors/", response_model=list[Author]) # (7)
-def get_authors(): # (8)
- return [ # (9)
- {
- "name": "Breaters",
- "items": [
- {
- "name": "Island In The Moon",
- "description": "A place to be playin' and havin' fun",
- },
- {"name": "Holy Buddies"},
- ],
- },
- {
- "name": "System of an Up",
- "items": [
- {
- "name": "Salt",
- "description": "The kombucha mushroom people's favorite",
- },
- {"name": "Pad Thai"},
- {
- "name": "Lonely Night",
- "description": "The mostests lonliest nightiest of allest",
- },
- ],
- },
- ]
diff --git a/docs_src/debugging/tutorial001_py39.py b/docs_src/debugging/tutorial001_py310.py
similarity index 100%
rename from docs_src/debugging/tutorial001_py39.py
rename to docs_src/debugging/tutorial001_py310.py
diff --git a/docs_src/dependencies/tutorial001_02_an_py39.py b/docs_src/dependencies/tutorial001_02_an_py39.py
deleted file mode 100644
index df969ae9c8..0000000000
--- a/docs_src/dependencies/tutorial001_02_an_py39.py
+++ /dev/null
@@ -1,24 +0,0 @@
-from typing import Annotated, Union
-
-from fastapi import Depends, FastAPI
-
-app = FastAPI()
-
-
-async def common_parameters(
- q: Union[str, None] = None, skip: int = 0, limit: int = 100
-):
- return {"q": q, "skip": skip, "limit": limit}
-
-
-CommonsDep = Annotated[dict, Depends(common_parameters)]
-
-
-@app.get("/items/")
-async def read_items(commons: CommonsDep):
- return commons
-
-
-@app.get("/users/")
-async def read_users(commons: CommonsDep):
- return commons
diff --git a/docs_src/dependencies/tutorial001_an_py39.py b/docs_src/dependencies/tutorial001_an_py39.py
deleted file mode 100644
index 5d9fe6ddfd..0000000000
--- a/docs_src/dependencies/tutorial001_an_py39.py
+++ /dev/null
@@ -1,21 +0,0 @@
-from typing import Annotated, Union
-
-from fastapi import Depends, FastAPI
-
-app = FastAPI()
-
-
-async def common_parameters(
- q: Union[str, None] = None, skip: int = 0, limit: int = 100
-):
- return {"q": q, "skip": skip, "limit": limit}
-
-
-@app.get("/items/")
-async def read_items(commons: Annotated[dict, Depends(common_parameters)]):
- return commons
-
-
-@app.get("/users/")
-async def read_users(commons: Annotated[dict, Depends(common_parameters)]):
- return commons
diff --git a/docs_src/dependencies/tutorial001_py39.py b/docs_src/dependencies/tutorial001_py39.py
deleted file mode 100644
index b1275103a0..0000000000
--- a/docs_src/dependencies/tutorial001_py39.py
+++ /dev/null
@@ -1,21 +0,0 @@
-from typing import Union
-
-from fastapi import Depends, FastAPI
-
-app = FastAPI()
-
-
-async def common_parameters(
- q: Union[str, None] = None, skip: int = 0, limit: int = 100
-):
- return {"q": q, "skip": skip, "limit": limit}
-
-
-@app.get("/items/")
-async def read_items(commons: dict = Depends(common_parameters)):
- return commons
-
-
-@app.get("/users/")
-async def read_users(commons: dict = Depends(common_parameters)):
- return commons
diff --git a/docs_src/dependencies/tutorial002_an_py39.py b/docs_src/dependencies/tutorial002_an_py39.py
deleted file mode 100644
index 844a23c5a7..0000000000
--- a/docs_src/dependencies/tutorial002_an_py39.py
+++ /dev/null
@@ -1,25 +0,0 @@
-from typing import Annotated, Union
-
-from fastapi import Depends, FastAPI
-
-app = FastAPI()
-
-
-fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}]
-
-
-class CommonQueryParams:
- def __init__(self, q: Union[str, None] = None, skip: int = 0, limit: int = 100):
- self.q = q
- self.skip = skip
- self.limit = limit
-
-
-@app.get("/items/")
-async def read_items(commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]):
- response = {}
- if commons.q:
- response.update({"q": commons.q})
- items = fake_items_db[commons.skip : commons.skip + commons.limit]
- response.update({"items": items})
- return response
diff --git a/docs_src/dependencies/tutorial002_py39.py b/docs_src/dependencies/tutorial002_py39.py
deleted file mode 100644
index 8e863e4fab..0000000000
--- a/docs_src/dependencies/tutorial002_py39.py
+++ /dev/null
@@ -1,25 +0,0 @@
-from typing import Union
-
-from fastapi import Depends, FastAPI
-
-app = FastAPI()
-
-
-fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}]
-
-
-class CommonQueryParams:
- def __init__(self, q: Union[str, None] = None, skip: int = 0, limit: int = 100):
- self.q = q
- self.skip = skip
- self.limit = limit
-
-
-@app.get("/items/")
-async def read_items(commons: CommonQueryParams = Depends(CommonQueryParams)):
- response = {}
- if commons.q:
- response.update({"q": commons.q})
- items = fake_items_db[commons.skip : commons.skip + commons.limit]
- response.update({"items": items})
- return response
diff --git a/docs_src/dependencies/tutorial003_an_py39.py b/docs_src/dependencies/tutorial003_an_py39.py
deleted file mode 100644
index 9e9123ad2f..0000000000
--- a/docs_src/dependencies/tutorial003_an_py39.py
+++ /dev/null
@@ -1,25 +0,0 @@
-from typing import Annotated, Any, Union
-
-from fastapi import Depends, FastAPI
-
-app = FastAPI()
-
-
-fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}]
-
-
-class CommonQueryParams:
- def __init__(self, q: Union[str, None] = None, skip: int = 0, limit: int = 100):
- self.q = q
- self.skip = skip
- self.limit = limit
-
-
-@app.get("/items/")
-async def read_items(commons: Annotated[Any, Depends(CommonQueryParams)]):
- response = {}
- if commons.q:
- response.update({"q": commons.q})
- items = fake_items_db[commons.skip : commons.skip + commons.limit]
- response.update({"items": items})
- return response
diff --git a/docs_src/dependencies/tutorial003_py39.py b/docs_src/dependencies/tutorial003_py39.py
deleted file mode 100644
index 34614e5397..0000000000
--- a/docs_src/dependencies/tutorial003_py39.py
+++ /dev/null
@@ -1,25 +0,0 @@
-from typing import Union
-
-from fastapi import Depends, FastAPI
-
-app = FastAPI()
-
-
-fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}]
-
-
-class CommonQueryParams:
- def __init__(self, q: Union[str, None] = None, skip: int = 0, limit: int = 100):
- self.q = q
- self.skip = skip
- self.limit = limit
-
-
-@app.get("/items/")
-async def read_items(commons=Depends(CommonQueryParams)):
- response = {}
- if commons.q:
- response.update({"q": commons.q})
- items = fake_items_db[commons.skip : commons.skip + commons.limit]
- response.update({"items": items})
- return response
diff --git a/docs_src/dependencies/tutorial004_an_py39.py b/docs_src/dependencies/tutorial004_an_py39.py
deleted file mode 100644
index 74268626b4..0000000000
--- a/docs_src/dependencies/tutorial004_an_py39.py
+++ /dev/null
@@ -1,25 +0,0 @@
-from typing import Annotated, Union
-
-from fastapi import Depends, FastAPI
-
-app = FastAPI()
-
-
-fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}]
-
-
-class CommonQueryParams:
- def __init__(self, q: Union[str, None] = None, skip: int = 0, limit: int = 100):
- self.q = q
- self.skip = skip
- self.limit = limit
-
-
-@app.get("/items/")
-async def read_items(commons: Annotated[CommonQueryParams, Depends()]):
- response = {}
- if commons.q:
- response.update({"q": commons.q})
- items = fake_items_db[commons.skip : commons.skip + commons.limit]
- response.update({"items": items})
- return response
diff --git a/docs_src/dependencies/tutorial004_py39.py b/docs_src/dependencies/tutorial004_py39.py
deleted file mode 100644
index d9fe881488..0000000000
--- a/docs_src/dependencies/tutorial004_py39.py
+++ /dev/null
@@ -1,25 +0,0 @@
-from typing import Union
-
-from fastapi import Depends, FastAPI
-
-app = FastAPI()
-
-
-fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}]
-
-
-class CommonQueryParams:
- def __init__(self, q: Union[str, None] = None, skip: int = 0, limit: int = 100):
- self.q = q
- self.skip = skip
- self.limit = limit
-
-
-@app.get("/items/")
-async def read_items(commons: CommonQueryParams = Depends()):
- response = {}
- if commons.q:
- response.update({"q": commons.q})
- items = fake_items_db[commons.skip : commons.skip + commons.limit]
- response.update({"items": items})
- return response
diff --git a/docs_src/dependencies/tutorial005_an_py39.py b/docs_src/dependencies/tutorial005_an_py39.py
deleted file mode 100644
index d5dd8dca9a..0000000000
--- a/docs_src/dependencies/tutorial005_an_py39.py
+++ /dev/null
@@ -1,25 +0,0 @@
-from typing import Annotated, Union
-
-from fastapi import Cookie, Depends, FastAPI
-
-app = FastAPI()
-
-
-def query_extractor(q: Union[str, None] = None):
- return q
-
-
-def query_or_cookie_extractor(
- q: Annotated[str, Depends(query_extractor)],
- last_query: Annotated[Union[str, None], Cookie()] = None,
-):
- if not q:
- return last_query
- return q
-
-
-@app.get("/items/")
-async def read_query(
- query_or_default: Annotated[str, Depends(query_or_cookie_extractor)],
-):
- return {"q_or_cookie": query_or_default}
diff --git a/docs_src/dependencies/tutorial005_py39.py b/docs_src/dependencies/tutorial005_py39.py
deleted file mode 100644
index 697332b5ba..0000000000
--- a/docs_src/dependencies/tutorial005_py39.py
+++ /dev/null
@@ -1,23 +0,0 @@
-from typing import Union
-
-from fastapi import Cookie, Depends, FastAPI
-
-app = FastAPI()
-
-
-def query_extractor(q: Union[str, None] = None):
- return q
-
-
-def query_or_cookie_extractor(
- q: str = Depends(query_extractor),
- last_query: Union[str, None] = Cookie(default=None),
-):
- if not q:
- return last_query
- return q
-
-
-@app.get("/items/")
-async def read_query(query_or_default: str = Depends(query_or_cookie_extractor)):
- return {"q_or_cookie": query_or_default}
diff --git a/docs_src/dependencies/tutorial006_an_py39.py b/docs_src/dependencies/tutorial006_an_py310.py
similarity index 100%
rename from docs_src/dependencies/tutorial006_an_py39.py
rename to docs_src/dependencies/tutorial006_an_py310.py
diff --git a/docs_src/dependencies/tutorial006_py39.py b/docs_src/dependencies/tutorial006_py310.py
similarity index 100%
rename from docs_src/dependencies/tutorial006_py39.py
rename to docs_src/dependencies/tutorial006_py310.py
diff --git a/docs_src/dependencies/tutorial007_py39.py b/docs_src/dependencies/tutorial007_py310.py
similarity index 100%
rename from docs_src/dependencies/tutorial007_py39.py
rename to docs_src/dependencies/tutorial007_py310.py
diff --git a/docs_src/dependencies/tutorial008_an_py39.py b/docs_src/dependencies/tutorial008_an_py310.py
similarity index 100%
rename from docs_src/dependencies/tutorial008_an_py39.py
rename to docs_src/dependencies/tutorial008_an_py310.py
diff --git a/docs_src/dependencies/tutorial008_py39.py b/docs_src/dependencies/tutorial008_py310.py
similarity index 100%
rename from docs_src/dependencies/tutorial008_py39.py
rename to docs_src/dependencies/tutorial008_py310.py
diff --git a/docs_src/dependencies/tutorial008b_an_py39.py b/docs_src/dependencies/tutorial008b_an_py310.py
similarity index 100%
rename from docs_src/dependencies/tutorial008b_an_py39.py
rename to docs_src/dependencies/tutorial008b_an_py310.py
diff --git a/docs_src/dependencies/tutorial008b_py39.py b/docs_src/dependencies/tutorial008b_py310.py
similarity index 100%
rename from docs_src/dependencies/tutorial008b_py39.py
rename to docs_src/dependencies/tutorial008b_py310.py
diff --git a/docs_src/dependencies/tutorial008c_an_py39.py b/docs_src/dependencies/tutorial008c_an_py310.py
similarity index 100%
rename from docs_src/dependencies/tutorial008c_an_py39.py
rename to docs_src/dependencies/tutorial008c_an_py310.py
diff --git a/docs_src/dependencies/tutorial008c_py39.py b/docs_src/dependencies/tutorial008c_py310.py
similarity index 100%
rename from docs_src/dependencies/tutorial008c_py39.py
rename to docs_src/dependencies/tutorial008c_py310.py
diff --git a/docs_src/dependencies/tutorial008d_an_py39.py b/docs_src/dependencies/tutorial008d_an_py310.py
similarity index 100%
rename from docs_src/dependencies/tutorial008d_an_py39.py
rename to docs_src/dependencies/tutorial008d_an_py310.py
diff --git a/docs_src/dependencies/tutorial008d_py39.py b/docs_src/dependencies/tutorial008d_py310.py
similarity index 100%
rename from docs_src/dependencies/tutorial008d_py39.py
rename to docs_src/dependencies/tutorial008d_py310.py
diff --git a/docs_src/dependencies/tutorial008e_an_py39.py b/docs_src/dependencies/tutorial008e_an_py310.py
similarity index 100%
rename from docs_src/dependencies/tutorial008e_an_py39.py
rename to docs_src/dependencies/tutorial008e_an_py310.py
diff --git a/docs_src/dependencies/tutorial008e_py39.py b/docs_src/dependencies/tutorial008e_py310.py
similarity index 100%
rename from docs_src/dependencies/tutorial008e_py39.py
rename to docs_src/dependencies/tutorial008e_py310.py
diff --git a/docs_src/dependencies/tutorial010_py39.py b/docs_src/dependencies/tutorial010_py310.py
similarity index 100%
rename from docs_src/dependencies/tutorial010_py39.py
rename to docs_src/dependencies/tutorial010_py310.py
diff --git a/docs_src/dependencies/tutorial011_an_py39.py b/docs_src/dependencies/tutorial011_an_py310.py
similarity index 100%
rename from docs_src/dependencies/tutorial011_an_py39.py
rename to docs_src/dependencies/tutorial011_an_py310.py
diff --git a/docs_src/dependencies/tutorial011_py39.py b/docs_src/dependencies/tutorial011_py310.py
similarity index 100%
rename from docs_src/dependencies/tutorial011_py39.py
rename to docs_src/dependencies/tutorial011_py310.py
diff --git a/docs_src/dependencies/tutorial012_an_py39.py b/docs_src/dependencies/tutorial012_an_py310.py
similarity index 100%
rename from docs_src/dependencies/tutorial012_an_py39.py
rename to docs_src/dependencies/tutorial012_an_py310.py
diff --git a/docs_src/dependencies/tutorial012_py39.py b/docs_src/dependencies/tutorial012_py310.py
similarity index 100%
rename from docs_src/dependencies/tutorial012_py39.py
rename to docs_src/dependencies/tutorial012_py310.py
diff --git a/docs_src/dependency_testing/tutorial001_an_py39.py b/docs_src/dependency_testing/tutorial001_an_py39.py
deleted file mode 100644
index bccb0cdb1f..0000000000
--- a/docs_src/dependency_testing/tutorial001_an_py39.py
+++ /dev/null
@@ -1,59 +0,0 @@
-from typing import Annotated, Union
-
-from fastapi import Depends, FastAPI
-from fastapi.testclient import TestClient
-
-app = FastAPI()
-
-
-async def common_parameters(
- q: Union[str, None] = None, skip: int = 0, limit: int = 100
-):
- return {"q": q, "skip": skip, "limit": limit}
-
-
-@app.get("/items/")
-async def read_items(commons: Annotated[dict, Depends(common_parameters)]):
- return {"message": "Hello Items!", "params": commons}
-
-
-@app.get("/users/")
-async def read_users(commons: Annotated[dict, Depends(common_parameters)]):
- return {"message": "Hello Users!", "params": commons}
-
-
-client = TestClient(app)
-
-
-async def override_dependency(q: Union[str, None] = None):
- return {"q": q, "skip": 5, "limit": 10}
-
-
-app.dependency_overrides[common_parameters] = override_dependency
-
-
-def test_override_in_items():
- response = client.get("/items/")
- assert response.status_code == 200
- assert response.json() == {
- "message": "Hello Items!",
- "params": {"q": None, "skip": 5, "limit": 10},
- }
-
-
-def test_override_in_items_with_q():
- response = client.get("/items/?q=foo")
- assert response.status_code == 200
- assert response.json() == {
- "message": "Hello Items!",
- "params": {"q": "foo", "skip": 5, "limit": 10},
- }
-
-
-def test_override_in_items_with_params():
- response = client.get("/items/?q=foo&skip=100&limit=200")
- assert response.status_code == 200
- assert response.json() == {
- "message": "Hello Items!",
- "params": {"q": "foo", "skip": 5, "limit": 10},
- }
diff --git a/docs_src/dependency_testing/tutorial001_py39.py b/docs_src/dependency_testing/tutorial001_py39.py
deleted file mode 100644
index a5fe1d9bff..0000000000
--- a/docs_src/dependency_testing/tutorial001_py39.py
+++ /dev/null
@@ -1,59 +0,0 @@
-from typing import Union
-
-from fastapi import Depends, FastAPI
-from fastapi.testclient import TestClient
-
-app = FastAPI()
-
-
-async def common_parameters(
- q: Union[str, None] = None, skip: int = 0, limit: int = 100
-):
- return {"q": q, "skip": skip, "limit": limit}
-
-
-@app.get("/items/")
-async def read_items(commons: dict = Depends(common_parameters)):
- return {"message": "Hello Items!", "params": commons}
-
-
-@app.get("/users/")
-async def read_users(commons: dict = Depends(common_parameters)):
- return {"message": "Hello Users!", "params": commons}
-
-
-client = TestClient(app)
-
-
-async def override_dependency(q: Union[str, None] = None):
- return {"q": q, "skip": 5, "limit": 10}
-
-
-app.dependency_overrides[common_parameters] = override_dependency
-
-
-def test_override_in_items():
- response = client.get("/items/")
- assert response.status_code == 200
- assert response.json() == {
- "message": "Hello Items!",
- "params": {"q": None, "skip": 5, "limit": 10},
- }
-
-
-def test_override_in_items_with_q():
- response = client.get("/items/?q=foo")
- assert response.status_code == 200
- assert response.json() == {
- "message": "Hello Items!",
- "params": {"q": "foo", "skip": 5, "limit": 10},
- }
-
-
-def test_override_in_items_with_params():
- response = client.get("/items/?q=foo&skip=100&limit=200")
- assert response.status_code == 200
- assert response.json() == {
- "message": "Hello Items!",
- "params": {"q": "foo", "skip": 5, "limit": 10},
- }
diff --git a/docs_src/encoder/tutorial001_py39.py b/docs_src/encoder/tutorial001_py39.py
deleted file mode 100644
index 5f7e7061e4..0000000000
--- a/docs_src/encoder/tutorial001_py39.py
+++ /dev/null
@@ -1,23 +0,0 @@
-from datetime import datetime
-from typing import Union
-
-from fastapi import FastAPI
-from fastapi.encoders import jsonable_encoder
-from pydantic import BaseModel
-
-fake_db = {}
-
-
-class Item(BaseModel):
- title: str
- timestamp: datetime
- description: Union[str, None] = None
-
-
-app = FastAPI()
-
-
-@app.put("/items/{id}")
-def update_item(id: str, item: Item):
- json_compatible_item_data = jsonable_encoder(item)
- fake_db[id] = json_compatible_item_data
diff --git a/docs_src/events/tutorial001_py39.py b/docs_src/events/tutorial001_py310.py
similarity index 100%
rename from docs_src/events/tutorial001_py39.py
rename to docs_src/events/tutorial001_py310.py
diff --git a/docs_src/events/tutorial002_py39.py b/docs_src/events/tutorial002_py310.py
similarity index 100%
rename from docs_src/events/tutorial002_py39.py
rename to docs_src/events/tutorial002_py310.py
diff --git a/docs_src/events/tutorial003_py39.py b/docs_src/events/tutorial003_py310.py
similarity index 100%
rename from docs_src/events/tutorial003_py39.py
rename to docs_src/events/tutorial003_py310.py
diff --git a/docs_src/extending_openapi/tutorial001_py39.py b/docs_src/extending_openapi/tutorial001_py310.py
similarity index 100%
rename from docs_src/extending_openapi/tutorial001_py39.py
rename to docs_src/extending_openapi/tutorial001_py310.py
diff --git a/docs_src/extra_data_types/tutorial001_an_py39.py b/docs_src/extra_data_types/tutorial001_an_py39.py
deleted file mode 100644
index fa3551d665..0000000000
--- a/docs_src/extra_data_types/tutorial001_an_py39.py
+++ /dev/null
@@ -1,28 +0,0 @@
-from datetime import datetime, time, timedelta
-from typing import Annotated, Union
-from uuid import UUID
-
-from fastapi import Body, FastAPI
-
-app = FastAPI()
-
-
-@app.put("/items/{item_id}")
-async def read_items(
- item_id: UUID,
- start_datetime: Annotated[datetime, Body()],
- end_datetime: Annotated[datetime, Body()],
- process_after: Annotated[timedelta, Body()],
- repeat_at: Annotated[Union[time, None], Body()] = None,
-):
- start_process = start_datetime + process_after
- duration = end_datetime - start_process
- return {
- "item_id": item_id,
- "start_datetime": start_datetime,
- "end_datetime": end_datetime,
- "process_after": process_after,
- "repeat_at": repeat_at,
- "start_process": start_process,
- "duration": duration,
- }
diff --git a/docs_src/extra_data_types/tutorial001_py39.py b/docs_src/extra_data_types/tutorial001_py39.py
deleted file mode 100644
index 71de958ff5..0000000000
--- a/docs_src/extra_data_types/tutorial001_py39.py
+++ /dev/null
@@ -1,28 +0,0 @@
-from datetime import datetime, time, timedelta
-from typing import Union
-from uuid import UUID
-
-from fastapi import Body, FastAPI
-
-app = FastAPI()
-
-
-@app.put("/items/{item_id}")
-async def read_items(
- item_id: UUID,
- start_datetime: datetime = Body(),
- end_datetime: datetime = Body(),
- process_after: timedelta = Body(),
- repeat_at: Union[time, None] = Body(default=None),
-):
- start_process = start_datetime + process_after
- duration = end_datetime - start_process
- return {
- "item_id": item_id,
- "start_datetime": start_datetime,
- "end_datetime": end_datetime,
- "process_after": process_after,
- "repeat_at": repeat_at,
- "start_process": start_process,
- "duration": duration,
- }
diff --git a/docs_src/extra_models/tutorial001_py39.py b/docs_src/extra_models/tutorial001_py39.py
deleted file mode 100644
index 327ffcdf09..0000000000
--- a/docs_src/extra_models/tutorial001_py39.py
+++ /dev/null
@@ -1,43 +0,0 @@
-from typing import Union
-
-from fastapi import FastAPI
-from pydantic import BaseModel, EmailStr
-
-app = FastAPI()
-
-
-class UserIn(BaseModel):
- username: str
- password: str
- email: EmailStr
- full_name: Union[str, None] = None
-
-
-class UserOut(BaseModel):
- username: str
- email: EmailStr
- full_name: Union[str, None] = None
-
-
-class UserInDB(BaseModel):
- username: str
- hashed_password: str
- email: EmailStr
- full_name: Union[str, None] = None
-
-
-def fake_password_hasher(raw_password: str):
- return "supersecret" + raw_password
-
-
-def fake_save_user(user_in: UserIn):
- hashed_password = fake_password_hasher(user_in.password)
- user_in_db = UserInDB(**user_in.model_dump(), hashed_password=hashed_password)
- print("User saved! ..not really")
- return user_in_db
-
-
-@app.post("/user/", response_model=UserOut)
-async def create_user(user_in: UserIn):
- user_saved = fake_save_user(user_in)
- return user_saved
diff --git a/docs_src/extra_models/tutorial002_py39.py b/docs_src/extra_models/tutorial002_py39.py
deleted file mode 100644
index 6543796015..0000000000
--- a/docs_src/extra_models/tutorial002_py39.py
+++ /dev/null
@@ -1,41 +0,0 @@
-from typing import Union
-
-from fastapi import FastAPI
-from pydantic import BaseModel, EmailStr
-
-app = FastAPI()
-
-
-class UserBase(BaseModel):
- username: str
- email: EmailStr
- full_name: Union[str, None] = None
-
-
-class UserIn(UserBase):
- password: str
-
-
-class UserOut(UserBase):
- pass
-
-
-class UserInDB(UserBase):
- hashed_password: str
-
-
-def fake_password_hasher(raw_password: str):
- return "supersecret" + raw_password
-
-
-def fake_save_user(user_in: UserIn):
- hashed_password = fake_password_hasher(user_in.password)
- user_in_db = UserInDB(**user_in.model_dump(), hashed_password=hashed_password)
- print("User saved! ..not really")
- return user_in_db
-
-
-@app.post("/user/", response_model=UserOut)
-async def create_user(user_in: UserIn):
- user_saved = fake_save_user(user_in)
- return user_saved
diff --git a/docs_src/extra_models/tutorial003_py310.py b/docs_src/extra_models/tutorial003_py310.py
index 06675cbc09..8fe6f7136e 100644
--- a/docs_src/extra_models/tutorial003_py310.py
+++ b/docs_src/extra_models/tutorial003_py310.py
@@ -1,5 +1,3 @@
-from typing import Union
-
from fastapi import FastAPI
from pydantic import BaseModel
@@ -30,6 +28,6 @@ items = {
}
-@app.get("/items/{item_id}", response_model=Union[PlaneItem, CarItem])
+@app.get("/items/{item_id}", response_model=PlaneItem | CarItem)
async def read_item(item_id: str):
return items[item_id]
diff --git a/docs_src/extra_models/tutorial003_py39.py b/docs_src/extra_models/tutorial003_py39.py
deleted file mode 100644
index 06675cbc09..0000000000
--- a/docs_src/extra_models/tutorial003_py39.py
+++ /dev/null
@@ -1,35 +0,0 @@
-from typing import Union
-
-from fastapi import FastAPI
-from pydantic import BaseModel
-
-app = FastAPI()
-
-
-class BaseItem(BaseModel):
- description: str
- type: str
-
-
-class CarItem(BaseItem):
- type: str = "car"
-
-
-class PlaneItem(BaseItem):
- type: str = "plane"
- size: int
-
-
-items = {
- "item1": {"description": "All my friends drive a low rider", "type": "car"},
- "item2": {
- "description": "Music is my aeroplane, it's my aeroplane",
- "type": "plane",
- "size": 5,
- },
-}
-
-
-@app.get("/items/{item_id}", response_model=Union[PlaneItem, CarItem])
-async def read_item(item_id: str):
- return items[item_id]
diff --git a/docs_src/extra_models/tutorial004_py39.py b/docs_src/extra_models/tutorial004_py310.py
similarity index 100%
rename from docs_src/extra_models/tutorial004_py39.py
rename to docs_src/extra_models/tutorial004_py310.py
diff --git a/docs_src/extra_models/tutorial005_py39.py b/docs_src/extra_models/tutorial005_py310.py
similarity index 100%
rename from docs_src/extra_models/tutorial005_py39.py
rename to docs_src/extra_models/tutorial005_py310.py
diff --git a/docs_src/first_steps/tutorial001_py39.py b/docs_src/first_steps/tutorial001_py310.py
similarity index 100%
rename from docs_src/first_steps/tutorial001_py39.py
rename to docs_src/first_steps/tutorial001_py310.py
diff --git a/docs_src/first_steps/tutorial003_py39.py b/docs_src/first_steps/tutorial003_py310.py
similarity index 100%
rename from docs_src/first_steps/tutorial003_py39.py
rename to docs_src/first_steps/tutorial003_py310.py
diff --git a/docs_src/generate_clients/tutorial001_py39.py b/docs_src/generate_clients/tutorial001_py310.py
similarity index 100%
rename from docs_src/generate_clients/tutorial001_py39.py
rename to docs_src/generate_clients/tutorial001_py310.py
diff --git a/docs_src/generate_clients/tutorial002_py39.py b/docs_src/generate_clients/tutorial002_py310.py
similarity index 100%
rename from docs_src/generate_clients/tutorial002_py39.py
rename to docs_src/generate_clients/tutorial002_py310.py
diff --git a/docs_src/generate_clients/tutorial003_py39.py b/docs_src/generate_clients/tutorial003_py310.py
similarity index 100%
rename from docs_src/generate_clients/tutorial003_py39.py
rename to docs_src/generate_clients/tutorial003_py310.py
diff --git a/docs_src/generate_clients/tutorial004_py39.py b/docs_src/generate_clients/tutorial004_py310.py
similarity index 100%
rename from docs_src/generate_clients/tutorial004_py39.py
rename to docs_src/generate_clients/tutorial004_py310.py
diff --git a/docs_src/graphql_/tutorial001_py39.py b/docs_src/graphql_/tutorial001_py310.py
similarity index 100%
rename from docs_src/graphql_/tutorial001_py39.py
rename to docs_src/graphql_/tutorial001_py310.py
diff --git a/docs_src/handling_errors/tutorial001_py39.py b/docs_src/handling_errors/tutorial001_py310.py
similarity index 100%
rename from docs_src/handling_errors/tutorial001_py39.py
rename to docs_src/handling_errors/tutorial001_py310.py
diff --git a/docs_src/handling_errors/tutorial002_py39.py b/docs_src/handling_errors/tutorial002_py310.py
similarity index 100%
rename from docs_src/handling_errors/tutorial002_py39.py
rename to docs_src/handling_errors/tutorial002_py310.py
diff --git a/docs_src/handling_errors/tutorial003_py39.py b/docs_src/handling_errors/tutorial003_py310.py
similarity index 100%
rename from docs_src/handling_errors/tutorial003_py39.py
rename to docs_src/handling_errors/tutorial003_py310.py
diff --git a/docs_src/handling_errors/tutorial004_py39.py b/docs_src/handling_errors/tutorial004_py310.py
similarity index 100%
rename from docs_src/handling_errors/tutorial004_py39.py
rename to docs_src/handling_errors/tutorial004_py310.py
diff --git a/docs_src/handling_errors/tutorial005_py39.py b/docs_src/handling_errors/tutorial005_py310.py
similarity index 100%
rename from docs_src/handling_errors/tutorial005_py39.py
rename to docs_src/handling_errors/tutorial005_py310.py
diff --git a/docs_src/handling_errors/tutorial006_py39.py b/docs_src/handling_errors/tutorial006_py310.py
similarity index 100%
rename from docs_src/handling_errors/tutorial006_py39.py
rename to docs_src/handling_errors/tutorial006_py310.py
diff --git a/docs_src/header_param_models/tutorial001_an_py39.py b/docs_src/header_param_models/tutorial001_an_py39.py
deleted file mode 100644
index 51a5f94fc8..0000000000
--- a/docs_src/header_param_models/tutorial001_an_py39.py
+++ /dev/null
@@ -1,19 +0,0 @@
-from typing import Annotated, Union
-
-from fastapi import FastAPI, Header
-from pydantic import BaseModel
-
-app = FastAPI()
-
-
-class CommonHeaders(BaseModel):
- host: str
- save_data: bool
- if_modified_since: Union[str, None] = None
- traceparent: Union[str, None] = None
- x_tag: list[str] = []
-
-
-@app.get("/items/")
-async def read_items(headers: Annotated[CommonHeaders, Header()]):
- return headers
diff --git a/docs_src/header_param_models/tutorial001_py39.py b/docs_src/header_param_models/tutorial001_py39.py
deleted file mode 100644
index 4c1137813a..0000000000
--- a/docs_src/header_param_models/tutorial001_py39.py
+++ /dev/null
@@ -1,19 +0,0 @@
-from typing import Union
-
-from fastapi import FastAPI, Header
-from pydantic import BaseModel
-
-app = FastAPI()
-
-
-class CommonHeaders(BaseModel):
- host: str
- save_data: bool
- if_modified_since: Union[str, None] = None
- traceparent: Union[str, None] = None
- x_tag: list[str] = []
-
-
-@app.get("/items/")
-async def read_items(headers: CommonHeaders = Header()):
- return headers
diff --git a/docs_src/header_param_models/tutorial002_an_py39.py b/docs_src/header_param_models/tutorial002_an_py39.py
deleted file mode 100644
index ca5208c9d0..0000000000
--- a/docs_src/header_param_models/tutorial002_an_py39.py
+++ /dev/null
@@ -1,21 +0,0 @@
-from typing import Annotated, Union
-
-from fastapi import FastAPI, Header
-from pydantic import BaseModel
-
-app = FastAPI()
-
-
-class CommonHeaders(BaseModel):
- model_config = {"extra": "forbid"}
-
- host: str
- save_data: bool
- if_modified_since: Union[str, None] = None
- traceparent: Union[str, None] = None
- x_tag: list[str] = []
-
-
-@app.get("/items/")
-async def read_items(headers: Annotated[CommonHeaders, Header()]):
- return headers
diff --git a/docs_src/header_param_models/tutorial002_py39.py b/docs_src/header_param_models/tutorial002_py39.py
deleted file mode 100644
index f8ce559a74..0000000000
--- a/docs_src/header_param_models/tutorial002_py39.py
+++ /dev/null
@@ -1,21 +0,0 @@
-from typing import Union
-
-from fastapi import FastAPI, Header
-from pydantic import BaseModel
-
-app = FastAPI()
-
-
-class CommonHeaders(BaseModel):
- model_config = {"extra": "forbid"}
-
- host: str
- save_data: bool
- if_modified_since: Union[str, None] = None
- traceparent: Union[str, None] = None
- x_tag: list[str] = []
-
-
-@app.get("/items/")
-async def read_items(headers: CommonHeaders = Header()):
- return headers
diff --git a/docs_src/header_param_models/tutorial003_an_py39.py b/docs_src/header_param_models/tutorial003_an_py39.py
deleted file mode 100644
index 8be6b01d0e..0000000000
--- a/docs_src/header_param_models/tutorial003_an_py39.py
+++ /dev/null
@@ -1,21 +0,0 @@
-from typing import Annotated, Union
-
-from fastapi import FastAPI, Header
-from pydantic import BaseModel
-
-app = FastAPI()
-
-
-class CommonHeaders(BaseModel):
- host: str
- save_data: bool
- if_modified_since: Union[str, None] = None
- traceparent: Union[str, None] = None
- x_tag: list[str] = []
-
-
-@app.get("/items/")
-async def read_items(
- headers: Annotated[CommonHeaders, Header(convert_underscores=False)],
-):
- return headers
diff --git a/docs_src/header_param_models/tutorial003_py39.py b/docs_src/header_param_models/tutorial003_py39.py
deleted file mode 100644
index 848c341119..0000000000
--- a/docs_src/header_param_models/tutorial003_py39.py
+++ /dev/null
@@ -1,19 +0,0 @@
-from typing import Union
-
-from fastapi import FastAPI, Header
-from pydantic import BaseModel
-
-app = FastAPI()
-
-
-class CommonHeaders(BaseModel):
- host: str
- save_data: bool
- if_modified_since: Union[str, None] = None
- traceparent: Union[str, None] = None
- x_tag: list[str] = []
-
-
-@app.get("/items/")
-async def read_items(headers: CommonHeaders = Header(convert_underscores=False)):
- return headers
diff --git a/docs_src/header_params/tutorial001_an_py39.py b/docs_src/header_params/tutorial001_an_py39.py
deleted file mode 100644
index 1fbe3bb99a..0000000000
--- a/docs_src/header_params/tutorial001_an_py39.py
+++ /dev/null
@@ -1,10 +0,0 @@
-from typing import Annotated, Union
-
-from fastapi import FastAPI, Header
-
-app = FastAPI()
-
-
-@app.get("/items/")
-async def read_items(user_agent: Annotated[Union[str, None], Header()] = None):
- return {"User-Agent": user_agent}
diff --git a/docs_src/header_params/tutorial001_py39.py b/docs_src/header_params/tutorial001_py39.py
deleted file mode 100644
index 74429c8e2d..0000000000
--- a/docs_src/header_params/tutorial001_py39.py
+++ /dev/null
@@ -1,10 +0,0 @@
-from typing import Union
-
-from fastapi import FastAPI, Header
-
-app = FastAPI()
-
-
-@app.get("/items/")
-async def read_items(user_agent: Union[str, None] = Header(default=None)):
- return {"User-Agent": user_agent}
diff --git a/docs_src/header_params/tutorial002_an_py39.py b/docs_src/header_params/tutorial002_an_py39.py
deleted file mode 100644
index 008e4b6e1a..0000000000
--- a/docs_src/header_params/tutorial002_an_py39.py
+++ /dev/null
@@ -1,14 +0,0 @@
-from typing import Annotated, Union
-
-from fastapi import FastAPI, Header
-
-app = FastAPI()
-
-
-@app.get("/items/")
-async def read_items(
- strange_header: Annotated[
- Union[str, None], Header(convert_underscores=False)
- ] = None,
-):
- return {"strange_header": strange_header}
diff --git a/docs_src/header_params/tutorial002_py39.py b/docs_src/header_params/tutorial002_py39.py
deleted file mode 100644
index 0a34f17cc4..0000000000
--- a/docs_src/header_params/tutorial002_py39.py
+++ /dev/null
@@ -1,12 +0,0 @@
-from typing import Union
-
-from fastapi import FastAPI, Header
-
-app = FastAPI()
-
-
-@app.get("/items/")
-async def read_items(
- strange_header: Union[str, None] = Header(default=None, convert_underscores=False),
-):
- return {"strange_header": strange_header}
diff --git a/docs_src/header_params/tutorial003_an_py39.py b/docs_src/header_params/tutorial003_an_py39.py
deleted file mode 100644
index 5aad89407e..0000000000
--- a/docs_src/header_params/tutorial003_an_py39.py
+++ /dev/null
@@ -1,10 +0,0 @@
-from typing import Annotated, Union
-
-from fastapi import FastAPI, Header
-
-app = FastAPI()
-
-
-@app.get("/items/")
-async def read_items(x_token: Annotated[Union[list[str], None], Header()] = None):
- return {"X-Token values": x_token}
diff --git a/docs_src/header_params/tutorial003_py39.py b/docs_src/header_params/tutorial003_py39.py
deleted file mode 100644
index 34437db161..0000000000
--- a/docs_src/header_params/tutorial003_py39.py
+++ /dev/null
@@ -1,10 +0,0 @@
-from typing import Union
-
-from fastapi import FastAPI, Header
-
-app = FastAPI()
-
-
-@app.get("/items/")
-async def read_items(x_token: Union[list[str], None] = Header(default=None)):
- return {"X-Token values": x_token}
diff --git a/docs_src/metadata/tutorial001_1_py39.py b/docs_src/metadata/tutorial001_1_py310.py
similarity index 100%
rename from docs_src/metadata/tutorial001_1_py39.py
rename to docs_src/metadata/tutorial001_1_py310.py
diff --git a/docs_src/metadata/tutorial001_py39.py b/docs_src/metadata/tutorial001_py310.py
similarity index 100%
rename from docs_src/metadata/tutorial001_py39.py
rename to docs_src/metadata/tutorial001_py310.py
diff --git a/docs_src/metadata/tutorial002_py39.py b/docs_src/metadata/tutorial002_py310.py
similarity index 100%
rename from docs_src/metadata/tutorial002_py39.py
rename to docs_src/metadata/tutorial002_py310.py
diff --git a/docs_src/metadata/tutorial003_py39.py b/docs_src/metadata/tutorial003_py310.py
similarity index 100%
rename from docs_src/metadata/tutorial003_py39.py
rename to docs_src/metadata/tutorial003_py310.py
diff --git a/docs_src/metadata/tutorial004_py39.py b/docs_src/metadata/tutorial004_py310.py
similarity index 100%
rename from docs_src/metadata/tutorial004_py39.py
rename to docs_src/metadata/tutorial004_py310.py
diff --git a/docs_src/middleware/tutorial001_py39.py b/docs_src/middleware/tutorial001_py310.py
similarity index 100%
rename from docs_src/middleware/tutorial001_py39.py
rename to docs_src/middleware/tutorial001_py310.py
diff --git a/docs_src/openapi_callbacks/tutorial001_py39.py b/docs_src/openapi_callbacks/tutorial001_py39.py
deleted file mode 100644
index 3f1bac6e29..0000000000
--- a/docs_src/openapi_callbacks/tutorial001_py39.py
+++ /dev/null
@@ -1,53 +0,0 @@
-from typing import Union
-
-from fastapi import APIRouter, FastAPI
-from pydantic import BaseModel, HttpUrl
-
-app = FastAPI()
-
-
-class Invoice(BaseModel):
- id: str
- title: Union[str, None] = None
- customer: str
- total: float
-
-
-class InvoiceEvent(BaseModel):
- description: str
- paid: bool
-
-
-class InvoiceEventReceived(BaseModel):
- ok: bool
-
-
-invoices_callback_router = APIRouter()
-
-
-@invoices_callback_router.post(
- "{$callback_url}/invoices/{$request.body.id}", response_model=InvoiceEventReceived
-)
-def invoice_notification(body: InvoiceEvent):
- pass
-
-
-@app.post("/invoices/", callbacks=invoices_callback_router.routes)
-def create_invoice(invoice: Invoice, callback_url: Union[HttpUrl, None] = None):
- """
- Create an invoice.
-
- This will (let's imagine) let the API user (some external developer) create an
- invoice.
-
- And this path operation will:
-
- * Send the invoice to the client.
- * Collect the money from the client.
- * Send a notification back to the API user (the external developer), as a callback.
- * At this point is that the API will somehow send a POST request to the
- external API with the notification of the invoice event
- (e.g. "payment successful").
- """
- # Send the invoice, collect the money, send the notification (the callback)
- return {"msg": "Invoice received"}
diff --git a/docs_src/openapi_webhooks/tutorial001_py39.py b/docs_src/openapi_webhooks/tutorial001_py310.py
similarity index 100%
rename from docs_src/openapi_webhooks/tutorial001_py39.py
rename to docs_src/openapi_webhooks/tutorial001_py310.py
diff --git a/docs_src/path_operation_advanced_configuration/tutorial001_py39.py b/docs_src/path_operation_advanced_configuration/tutorial001_py310.py
similarity index 100%
rename from docs_src/path_operation_advanced_configuration/tutorial001_py39.py
rename to docs_src/path_operation_advanced_configuration/tutorial001_py310.py
diff --git a/docs_src/path_operation_advanced_configuration/tutorial002_py39.py b/docs_src/path_operation_advanced_configuration/tutorial002_py310.py
similarity index 100%
rename from docs_src/path_operation_advanced_configuration/tutorial002_py39.py
rename to docs_src/path_operation_advanced_configuration/tutorial002_py310.py
diff --git a/docs_src/path_operation_advanced_configuration/tutorial003_py39.py b/docs_src/path_operation_advanced_configuration/tutorial003_py310.py
similarity index 100%
rename from docs_src/path_operation_advanced_configuration/tutorial003_py39.py
rename to docs_src/path_operation_advanced_configuration/tutorial003_py310.py
diff --git a/docs_src/path_operation_advanced_configuration/tutorial004_py39.py b/docs_src/path_operation_advanced_configuration/tutorial004_py39.py
deleted file mode 100644
index 8fabe7cb80..0000000000
--- a/docs_src/path_operation_advanced_configuration/tutorial004_py39.py
+++ /dev/null
@@ -1,30 +0,0 @@
-from typing import Union
-
-from fastapi import FastAPI
-from pydantic import BaseModel
-
-app = FastAPI()
-
-
-class Item(BaseModel):
- name: str
- description: Union[str, None] = None
- price: float
- tax: Union[float, None] = None
- tags: set[str] = set()
-
-
-@app.post("/items/", summary="Create an item")
-async def create_item(item: Item) -> Item:
- """
- Create an item with all the information:
-
- - **name**: each item must have a name
- - **description**: a long description
- - **price**: required
- - **tax**: if the item doesn't have tax, you can omit this
- - **tags**: a set of unique tag strings for this item
- \f
- :param item: User input.
- """
- return item
diff --git a/docs_src/path_operation_advanced_configuration/tutorial005_py39.py b/docs_src/path_operation_advanced_configuration/tutorial005_py310.py
similarity index 100%
rename from docs_src/path_operation_advanced_configuration/tutorial005_py39.py
rename to docs_src/path_operation_advanced_configuration/tutorial005_py310.py
diff --git a/docs_src/path_operation_advanced_configuration/tutorial006_py39.py b/docs_src/path_operation_advanced_configuration/tutorial006_py310.py
similarity index 100%
rename from docs_src/path_operation_advanced_configuration/tutorial006_py39.py
rename to docs_src/path_operation_advanced_configuration/tutorial006_py310.py
diff --git a/docs_src/path_operation_advanced_configuration/tutorial007_pv1_py39.py b/docs_src/path_operation_advanced_configuration/tutorial007_pv1_py39.py
deleted file mode 100644
index 849f648e12..0000000000
--- a/docs_src/path_operation_advanced_configuration/tutorial007_pv1_py39.py
+++ /dev/null
@@ -1,32 +0,0 @@
-import yaml
-from fastapi import FastAPI, HTTPException, Request
-from pydantic.v1 import BaseModel, ValidationError
-
-app = FastAPI()
-
-
-class Item(BaseModel):
- name: str
- tags: list[str]
-
-
-@app.post(
- "/items/",
- openapi_extra={
- "requestBody": {
- "content": {"application/x-yaml": {"schema": Item.schema()}},
- "required": True,
- },
- },
-)
-async def create_item(request: Request):
- raw_body = await request.body()
- try:
- data = yaml.safe_load(raw_body)
- except yaml.YAMLError:
- raise HTTPException(status_code=422, detail="Invalid YAML")
- try:
- item = Item.parse_obj(data)
- except ValidationError as e:
- raise HTTPException(status_code=422, detail=e.errors())
- return item
diff --git a/docs_src/path_operation_advanced_configuration/tutorial007_py39.py b/docs_src/path_operation_advanced_configuration/tutorial007_py310.py
similarity index 100%
rename from docs_src/path_operation_advanced_configuration/tutorial007_py39.py
rename to docs_src/path_operation_advanced_configuration/tutorial007_py310.py
diff --git a/docs_src/path_operation_configuration/tutorial001_py39.py b/docs_src/path_operation_configuration/tutorial001_py39.py
deleted file mode 100644
index 09b3182821..0000000000
--- a/docs_src/path_operation_configuration/tutorial001_py39.py
+++ /dev/null
@@ -1,19 +0,0 @@
-from typing import Union
-
-from fastapi import FastAPI, status
-from pydantic import BaseModel
-
-app = FastAPI()
-
-
-class Item(BaseModel):
- name: str
- description: Union[str, None] = None
- price: float
- tax: Union[float, None] = None
- tags: set[str] = set()
-
-
-@app.post("/items/", status_code=status.HTTP_201_CREATED)
-async def create_item(item: Item) -> Item:
- return item
diff --git a/docs_src/path_operation_configuration/tutorial002_py39.py b/docs_src/path_operation_configuration/tutorial002_py39.py
deleted file mode 100644
index fca3b0de9e..0000000000
--- a/docs_src/path_operation_configuration/tutorial002_py39.py
+++ /dev/null
@@ -1,29 +0,0 @@
-from typing import Union
-
-from fastapi import FastAPI
-from pydantic import BaseModel
-
-app = FastAPI()
-
-
-class Item(BaseModel):
- name: str
- description: Union[str, None] = None
- price: float
- tax: Union[float, None] = None
- tags: set[str] = set()
-
-
-@app.post("/items/", tags=["items"])
-async def create_item(item: Item) -> Item:
- return item
-
-
-@app.get("/items/", tags=["items"])
-async def read_items():
- return [{"name": "Foo", "price": 42}]
-
-
-@app.get("/users/", tags=["users"])
-async def read_users():
- return [{"username": "johndoe"}]
diff --git a/docs_src/path_operation_configuration/tutorial002b_py39.py b/docs_src/path_operation_configuration/tutorial002b_py310.py
similarity index 100%
rename from docs_src/path_operation_configuration/tutorial002b_py39.py
rename to docs_src/path_operation_configuration/tutorial002b_py310.py
diff --git a/docs_src/path_operation_configuration/tutorial003_py39.py b/docs_src/path_operation_configuration/tutorial003_py39.py
deleted file mode 100644
index a77fb34d89..0000000000
--- a/docs_src/path_operation_configuration/tutorial003_py39.py
+++ /dev/null
@@ -1,23 +0,0 @@
-from typing import Union
-
-from fastapi import FastAPI
-from pydantic import BaseModel
-
-app = FastAPI()
-
-
-class Item(BaseModel):
- name: str
- description: Union[str, None] = None
- price: float
- tax: Union[float, None] = None
- tags: set[str] = set()
-
-
-@app.post(
- "/items/",
- summary="Create an item",
- description="Create an item with all the information, name, description, price, tax and a set of unique tags",
-)
-async def create_item(item: Item) -> Item:
- return item
diff --git a/docs_src/path_operation_configuration/tutorial004_py39.py b/docs_src/path_operation_configuration/tutorial004_py39.py
deleted file mode 100644
index 31dfbff1d2..0000000000
--- a/docs_src/path_operation_configuration/tutorial004_py39.py
+++ /dev/null
@@ -1,28 +0,0 @@
-from typing import Union
-
-from fastapi import FastAPI
-from pydantic import BaseModel
-
-app = FastAPI()
-
-
-class Item(BaseModel):
- name: str
- description: Union[str, None] = None
- price: float
- tax: Union[float, None] = None
- tags: set[str] = set()
-
-
-@app.post("/items/", summary="Create an item")
-async def create_item(item: Item) -> Item:
- """
- Create an item with all the information:
-
- - **name**: each item must have a name
- - **description**: a long description
- - **price**: required
- - **tax**: if the item doesn't have tax, you can omit this
- - **tags**: a set of unique tag strings for this item
- """
- return item
diff --git a/docs_src/path_operation_configuration/tutorial005_py39.py b/docs_src/path_operation_configuration/tutorial005_py39.py
deleted file mode 100644
index 0a53a8f2dd..0000000000
--- a/docs_src/path_operation_configuration/tutorial005_py39.py
+++ /dev/null
@@ -1,32 +0,0 @@
-from typing import Union
-
-from fastapi import FastAPI
-from pydantic import BaseModel
-
-app = FastAPI()
-
-
-class Item(BaseModel):
- name: str
- description: Union[str, None] = None
- price: float
- tax: Union[float, None] = None
- tags: set[str] = set()
-
-
-@app.post(
- "/items/",
- summary="Create an item",
- response_description="The created item",
-)
-async def create_item(item: Item) -> Item:
- """
- Create an item with all the information:
-
- - **name**: each item must have a name
- - **description**: a long description
- - **price**: required
- - **tax**: if the item doesn't have tax, you can omit this
- - **tags**: a set of unique tag strings for this item
- """
- return item
diff --git a/docs_src/path_operation_configuration/tutorial006_py39.py b/docs_src/path_operation_configuration/tutorial006_py310.py
similarity index 100%
rename from docs_src/path_operation_configuration/tutorial006_py39.py
rename to docs_src/path_operation_configuration/tutorial006_py310.py
diff --git a/docs_src/path_params/tutorial001_py39.py b/docs_src/path_params/tutorial001_py310.py
similarity index 100%
rename from docs_src/path_params/tutorial001_py39.py
rename to docs_src/path_params/tutorial001_py310.py
diff --git a/docs_src/path_params/tutorial002_py39.py b/docs_src/path_params/tutorial002_py310.py
similarity index 100%
rename from docs_src/path_params/tutorial002_py39.py
rename to docs_src/path_params/tutorial002_py310.py
diff --git a/docs_src/path_params/tutorial003_py39.py b/docs_src/path_params/tutorial003_py310.py
similarity index 100%
rename from docs_src/path_params/tutorial003_py39.py
rename to docs_src/path_params/tutorial003_py310.py
diff --git a/docs_src/path_params/tutorial003b_py39.py b/docs_src/path_params/tutorial003b_py310.py
similarity index 100%
rename from docs_src/path_params/tutorial003b_py39.py
rename to docs_src/path_params/tutorial003b_py310.py
diff --git a/docs_src/path_params/tutorial004_py39.py b/docs_src/path_params/tutorial004_py310.py
similarity index 100%
rename from docs_src/path_params/tutorial004_py39.py
rename to docs_src/path_params/tutorial004_py310.py
diff --git a/docs_src/path_params/tutorial005_py39.py b/docs_src/path_params/tutorial005_py310.py
similarity index 100%
rename from docs_src/path_params/tutorial005_py39.py
rename to docs_src/path_params/tutorial005_py310.py
diff --git a/docs_src/path_params_numeric_validations/tutorial001_an_py39.py b/docs_src/path_params_numeric_validations/tutorial001_an_py39.py
deleted file mode 100644
index b36315a46d..0000000000
--- a/docs_src/path_params_numeric_validations/tutorial001_an_py39.py
+++ /dev/null
@@ -1,16 +0,0 @@
-from typing import Annotated, Union
-
-from fastapi import FastAPI, Path, Query
-
-app = FastAPI()
-
-
-@app.get("/items/{item_id}")
-async def read_items(
- item_id: Annotated[int, Path(title="The ID of the item to get")],
- q: Annotated[Union[str, None], Query(alias="item-query")] = None,
-):
- results = {"item_id": item_id}
- if q:
- results.update({"q": q})
- return results
diff --git a/docs_src/path_params_numeric_validations/tutorial001_py39.py b/docs_src/path_params_numeric_validations/tutorial001_py39.py
deleted file mode 100644
index 5301470282..0000000000
--- a/docs_src/path_params_numeric_validations/tutorial001_py39.py
+++ /dev/null
@@ -1,16 +0,0 @@
-from typing import Union
-
-from fastapi import FastAPI, Path, Query
-
-app = FastAPI()
-
-
-@app.get("/items/{item_id}")
-async def read_items(
- item_id: int = Path(title="The ID of the item to get"),
- q: Union[str, None] = Query(default=None, alias="item-query"),
-):
- results = {"item_id": item_id}
- if q:
- results.update({"q": q})
- return results
diff --git a/docs_src/path_params_numeric_validations/tutorial002_an_py39.py b/docs_src/path_params_numeric_validations/tutorial002_an_py310.py
similarity index 100%
rename from docs_src/path_params_numeric_validations/tutorial002_an_py39.py
rename to docs_src/path_params_numeric_validations/tutorial002_an_py310.py
diff --git a/docs_src/path_params_numeric_validations/tutorial002_py39.py b/docs_src/path_params_numeric_validations/tutorial002_py310.py
similarity index 100%
rename from docs_src/path_params_numeric_validations/tutorial002_py39.py
rename to docs_src/path_params_numeric_validations/tutorial002_py310.py
diff --git a/docs_src/path_params_numeric_validations/tutorial003_an_py39.py b/docs_src/path_params_numeric_validations/tutorial003_an_py310.py
similarity index 100%
rename from docs_src/path_params_numeric_validations/tutorial003_an_py39.py
rename to docs_src/path_params_numeric_validations/tutorial003_an_py310.py
diff --git a/docs_src/path_params_numeric_validations/tutorial003_py39.py b/docs_src/path_params_numeric_validations/tutorial003_py310.py
similarity index 100%
rename from docs_src/path_params_numeric_validations/tutorial003_py39.py
rename to docs_src/path_params_numeric_validations/tutorial003_py310.py
diff --git a/docs_src/path_params_numeric_validations/tutorial004_an_py39.py b/docs_src/path_params_numeric_validations/tutorial004_an_py310.py
similarity index 100%
rename from docs_src/path_params_numeric_validations/tutorial004_an_py39.py
rename to docs_src/path_params_numeric_validations/tutorial004_an_py310.py
diff --git a/docs_src/path_params_numeric_validations/tutorial004_py39.py b/docs_src/path_params_numeric_validations/tutorial004_py310.py
similarity index 100%
rename from docs_src/path_params_numeric_validations/tutorial004_py39.py
rename to docs_src/path_params_numeric_validations/tutorial004_py310.py
diff --git a/docs_src/path_params_numeric_validations/tutorial005_an_py39.py b/docs_src/path_params_numeric_validations/tutorial005_an_py310.py
similarity index 100%
rename from docs_src/path_params_numeric_validations/tutorial005_an_py39.py
rename to docs_src/path_params_numeric_validations/tutorial005_an_py310.py
diff --git a/docs_src/path_params_numeric_validations/tutorial005_py39.py b/docs_src/path_params_numeric_validations/tutorial005_py310.py
similarity index 100%
rename from docs_src/path_params_numeric_validations/tutorial005_py39.py
rename to docs_src/path_params_numeric_validations/tutorial005_py310.py
diff --git a/docs_src/path_params_numeric_validations/tutorial006_an_py39.py b/docs_src/path_params_numeric_validations/tutorial006_an_py310.py
similarity index 100%
rename from docs_src/path_params_numeric_validations/tutorial006_an_py39.py
rename to docs_src/path_params_numeric_validations/tutorial006_an_py310.py
diff --git a/docs_src/path_params_numeric_validations/tutorial006_py39.py b/docs_src/path_params_numeric_validations/tutorial006_py310.py
similarity index 100%
rename from docs_src/path_params_numeric_validations/tutorial006_py39.py
rename to docs_src/path_params_numeric_validations/tutorial006_py310.py
diff --git a/docs_src/pydantic_v1_in_v2/tutorial001_an_py39.py b/docs_src/pydantic_v1_in_v2/tutorial001_an_py39.py
deleted file mode 100644
index 62a4b2c210..0000000000
--- a/docs_src/pydantic_v1_in_v2/tutorial001_an_py39.py
+++ /dev/null
@@ -1,9 +0,0 @@
-from typing import Union
-
-from pydantic.v1 import BaseModel
-
-
-class Item(BaseModel):
- name: str
- description: Union[str, None] = None
- size: float
diff --git a/docs_src/pydantic_v1_in_v2/tutorial002_an_py39.py b/docs_src/pydantic_v1_in_v2/tutorial002_an_py39.py
deleted file mode 100644
index 3c6a060807..0000000000
--- a/docs_src/pydantic_v1_in_v2/tutorial002_an_py39.py
+++ /dev/null
@@ -1,18 +0,0 @@
-from typing import Union
-
-from fastapi import FastAPI
-from pydantic.v1 import BaseModel
-
-
-class Item(BaseModel):
- name: str
- description: Union[str, None] = None
- size: float
-
-
-app = FastAPI()
-
-
-@app.post("/items/")
-async def create_item(item: Item) -> Item:
- return item
diff --git a/docs_src/pydantic_v1_in_v2/tutorial003_an_py39.py b/docs_src/pydantic_v1_in_v2/tutorial003_an_py39.py
deleted file mode 100644
index 117d6f7a4c..0000000000
--- a/docs_src/pydantic_v1_in_v2/tutorial003_an_py39.py
+++ /dev/null
@@ -1,25 +0,0 @@
-from typing import Union
-
-from fastapi import FastAPI
-from pydantic import BaseModel as BaseModelV2
-from pydantic.v1 import BaseModel
-
-
-class Item(BaseModel):
- name: str
- description: Union[str, None] = None
- size: float
-
-
-class ItemV2(BaseModelV2):
- name: str
- description: Union[str, None] = None
- size: float
-
-
-app = FastAPI()
-
-
-@app.post("/items/", response_model=ItemV2)
-async def create_item(item: Item):
- return item
diff --git a/docs_src/pydantic_v1_in_v2/tutorial004_an_py39.py b/docs_src/pydantic_v1_in_v2/tutorial004_an_py39.py
deleted file mode 100644
index 150ab20ae5..0000000000
--- a/docs_src/pydantic_v1_in_v2/tutorial004_an_py39.py
+++ /dev/null
@@ -1,19 +0,0 @@
-from typing import Annotated, Union
-
-from fastapi import FastAPI
-from fastapi.temp_pydantic_v1_params import Body
-from pydantic.v1 import BaseModel
-
-
-class Item(BaseModel):
- name: str
- description: Union[str, None] = None
- size: float
-
-
-app = FastAPI()
-
-
-@app.post("/items/")
-async def create_item(item: Annotated[Item, Body(embed=True)]) -> Item:
- return item
diff --git a/docs_src/python_types/tutorial001_py39.py b/docs_src/python_types/tutorial001_py310.py
similarity index 100%
rename from docs_src/python_types/tutorial001_py39.py
rename to docs_src/python_types/tutorial001_py310.py
diff --git a/docs_src/python_types/tutorial002_py39.py b/docs_src/python_types/tutorial002_py310.py
similarity index 100%
rename from docs_src/python_types/tutorial002_py39.py
rename to docs_src/python_types/tutorial002_py310.py
diff --git a/docs_src/python_types/tutorial003_py39.py b/docs_src/python_types/tutorial003_py310.py
similarity index 100%
rename from docs_src/python_types/tutorial003_py39.py
rename to docs_src/python_types/tutorial003_py310.py
diff --git a/docs_src/python_types/tutorial004_py39.py b/docs_src/python_types/tutorial004_py310.py
similarity index 100%
rename from docs_src/python_types/tutorial004_py39.py
rename to docs_src/python_types/tutorial004_py310.py
diff --git a/docs_src/python_types/tutorial005_py310.py b/docs_src/python_types/tutorial005_py310.py
new file mode 100644
index 0000000000..6c8edb0ec4
--- /dev/null
+++ b/docs_src/python_types/tutorial005_py310.py
@@ -0,0 +1,2 @@
+def get_items(item_a: str, item_b: int, item_c: float, item_d: bool, item_e: bytes):
+ return item_a, item_b, item_c, item_d, item_e
diff --git a/docs_src/python_types/tutorial006_py39.py b/docs_src/python_types/tutorial006_py310.py
similarity index 100%
rename from docs_src/python_types/tutorial006_py39.py
rename to docs_src/python_types/tutorial006_py310.py
diff --git a/docs_src/python_types/tutorial007_py39.py b/docs_src/python_types/tutorial007_py310.py
similarity index 100%
rename from docs_src/python_types/tutorial007_py39.py
rename to docs_src/python_types/tutorial007_py310.py
diff --git a/docs_src/python_types/tutorial008_py39.py b/docs_src/python_types/tutorial008_py310.py
similarity index 100%
rename from docs_src/python_types/tutorial008_py39.py
rename to docs_src/python_types/tutorial008_py310.py
diff --git a/docs_src/python_types/tutorial008b_py39.py b/docs_src/python_types/tutorial008b_py39.py
deleted file mode 100644
index e52539ead0..0000000000
--- a/docs_src/python_types/tutorial008b_py39.py
+++ /dev/null
@@ -1,5 +0,0 @@
-from typing import Union
-
-
-def process_item(item: Union[int, str]):
- print(item)
diff --git a/docs_src/python_types/tutorial009_py39.py b/docs_src/python_types/tutorial009_py39.py
deleted file mode 100644
index 6328a1495c..0000000000
--- a/docs_src/python_types/tutorial009_py39.py
+++ /dev/null
@@ -1,8 +0,0 @@
-from typing import Optional
-
-
-def say_hi(name: Optional[str] = None):
- if name is not None:
- print(f"Hey {name}!")
- else:
- print("Hello World")
diff --git a/docs_src/python_types/tutorial009b_py39.py b/docs_src/python_types/tutorial009b_py39.py
deleted file mode 100644
index 9f1a05bc0f..0000000000
--- a/docs_src/python_types/tutorial009b_py39.py
+++ /dev/null
@@ -1,8 +0,0 @@
-from typing import Union
-
-
-def say_hi(name: Union[str, None] = None):
- if name is not None:
- print(f"Hey {name}!")
- else:
- print("Hello World")
diff --git a/docs_src/python_types/tutorial009c_py310.py b/docs_src/python_types/tutorial009c_py310.py
deleted file mode 100644
index 96b1220fcc..0000000000
--- a/docs_src/python_types/tutorial009c_py310.py
+++ /dev/null
@@ -1,2 +0,0 @@
-def say_hi(name: str | None):
- print(f"Hey {name}!")
diff --git a/docs_src/python_types/tutorial009c_py39.py b/docs_src/python_types/tutorial009c_py39.py
deleted file mode 100644
index 2f539a34b1..0000000000
--- a/docs_src/python_types/tutorial009c_py39.py
+++ /dev/null
@@ -1,5 +0,0 @@
-from typing import Optional
-
-
-def say_hi(name: Optional[str]):
- print(f"Hey {name}!")
diff --git a/docs_src/python_types/tutorial010_py39.py b/docs_src/python_types/tutorial010_py310.py
similarity index 100%
rename from docs_src/python_types/tutorial010_py39.py
rename to docs_src/python_types/tutorial010_py310.py
diff --git a/docs_src/python_types/tutorial011_py39.py b/docs_src/python_types/tutorial011_py39.py
deleted file mode 100644
index 4eb40b405f..0000000000
--- a/docs_src/python_types/tutorial011_py39.py
+++ /dev/null
@@ -1,23 +0,0 @@
-from datetime import datetime
-from typing import Union
-
-from pydantic import BaseModel
-
-
-class User(BaseModel):
- id: int
- name: str = "John Doe"
- signup_ts: Union[datetime, None] = None
- friends: list[int] = []
-
-
-external_data = {
- "id": "123",
- "signup_ts": "2017-06-01 12:22",
- "friends": [1, "2", b"3"],
-}
-user = User(**external_data)
-print(user)
-# > User id=123 name='John Doe' signup_ts=datetime.datetime(2017, 6, 1, 12, 22) friends=[1, 2, 3]
-print(user.id)
-# > 123
diff --git a/docs_src/python_types/tutorial012_py39.py b/docs_src/python_types/tutorial012_py39.py
deleted file mode 100644
index 74fa94c432..0000000000
--- a/docs_src/python_types/tutorial012_py39.py
+++ /dev/null
@@ -1,8 +0,0 @@
-from typing import Optional
-
-from pydantic import BaseModel
-
-
-class User(BaseModel):
- name: str
- age: Optional[int]
diff --git a/docs_src/python_types/tutorial013_py39.py b/docs_src/python_types/tutorial013_py310.py
similarity index 100%
rename from docs_src/python_types/tutorial013_py39.py
rename to docs_src/python_types/tutorial013_py310.py
diff --git a/docs_src/query_param_models/tutorial001_an_py39.py b/docs_src/query_param_models/tutorial001_an_py39.py
deleted file mode 100644
index 71427acae1..0000000000
--- a/docs_src/query_param_models/tutorial001_an_py39.py
+++ /dev/null
@@ -1,18 +0,0 @@
-from typing import Annotated, Literal
-
-from fastapi import FastAPI, Query
-from pydantic import BaseModel, Field
-
-app = FastAPI()
-
-
-class FilterParams(BaseModel):
- limit: int = Field(100, gt=0, le=100)
- offset: int = Field(0, ge=0)
- order_by: Literal["created_at", "updated_at"] = "created_at"
- tags: list[str] = []
-
-
-@app.get("/items/")
-async def read_items(filter_query: Annotated[FilterParams, Query()]):
- return filter_query
diff --git a/docs_src/query_param_models/tutorial001_py39.py b/docs_src/query_param_models/tutorial001_py39.py
deleted file mode 100644
index 3ebf9f4d70..0000000000
--- a/docs_src/query_param_models/tutorial001_py39.py
+++ /dev/null
@@ -1,18 +0,0 @@
-from typing import Literal
-
-from fastapi import FastAPI, Query
-from pydantic import BaseModel, Field
-
-app = FastAPI()
-
-
-class FilterParams(BaseModel):
- limit: int = Field(100, gt=0, le=100)
- offset: int = Field(0, ge=0)
- order_by: Literal["created_at", "updated_at"] = "created_at"
- tags: list[str] = []
-
-
-@app.get("/items/")
-async def read_items(filter_query: FilterParams = Query()):
- return filter_query
diff --git a/docs_src/query_param_models/tutorial002_an_py39.py b/docs_src/query_param_models/tutorial002_an_py39.py
deleted file mode 100644
index 9759565023..0000000000
--- a/docs_src/query_param_models/tutorial002_an_py39.py
+++ /dev/null
@@ -1,20 +0,0 @@
-from typing import Annotated, Literal
-
-from fastapi import FastAPI, Query
-from pydantic import BaseModel, Field
-
-app = FastAPI()
-
-
-class FilterParams(BaseModel):
- model_config = {"extra": "forbid"}
-
- limit: int = Field(100, gt=0, le=100)
- offset: int = Field(0, ge=0)
- order_by: Literal["created_at", "updated_at"] = "created_at"
- tags: list[str] = []
-
-
-@app.get("/items/")
-async def read_items(filter_query: Annotated[FilterParams, Query()]):
- return filter_query
diff --git a/docs_src/query_param_models/tutorial002_py39.py b/docs_src/query_param_models/tutorial002_py39.py
deleted file mode 100644
index 6ec4184991..0000000000
--- a/docs_src/query_param_models/tutorial002_py39.py
+++ /dev/null
@@ -1,20 +0,0 @@
-from typing import Literal
-
-from fastapi import FastAPI, Query
-from pydantic import BaseModel, Field
-
-app = FastAPI()
-
-
-class FilterParams(BaseModel):
- model_config = {"extra": "forbid"}
-
- limit: int = Field(100, gt=0, le=100)
- offset: int = Field(0, ge=0)
- order_by: Literal["created_at", "updated_at"] = "created_at"
- tags: list[str] = []
-
-
-@app.get("/items/")
-async def read_items(filter_query: FilterParams = Query()):
- return filter_query
diff --git a/docs_src/query_params/tutorial001_py39.py b/docs_src/query_params/tutorial001_py310.py
similarity index 100%
rename from docs_src/query_params/tutorial001_py39.py
rename to docs_src/query_params/tutorial001_py310.py
diff --git a/docs_src/query_params/tutorial002_py39.py b/docs_src/query_params/tutorial002_py39.py
deleted file mode 100644
index 8465f45eed..0000000000
--- a/docs_src/query_params/tutorial002_py39.py
+++ /dev/null
@@ -1,12 +0,0 @@
-from typing import Union
-
-from fastapi import FastAPI
-
-app = FastAPI()
-
-
-@app.get("/items/{item_id}")
-async def read_item(item_id: str, q: Union[str, None] = None):
- if q:
- return {"item_id": item_id, "q": q}
- return {"item_id": item_id}
diff --git a/docs_src/query_params/tutorial003_py39.py b/docs_src/query_params/tutorial003_py39.py
deleted file mode 100644
index 3362715b39..0000000000
--- a/docs_src/query_params/tutorial003_py39.py
+++ /dev/null
@@ -1,17 +0,0 @@
-from typing import Union
-
-from fastapi import FastAPI
-
-app = FastAPI()
-
-
-@app.get("/items/{item_id}")
-async def read_item(item_id: str, q: Union[str, None] = None, short: bool = False):
- item = {"item_id": item_id}
- if q:
- item.update({"q": q})
- if not short:
- item.update(
- {"description": "This is an amazing item that has a long description"}
- )
- return item
diff --git a/docs_src/query_params/tutorial004_py39.py b/docs_src/query_params/tutorial004_py39.py
deleted file mode 100644
index 049c3ae934..0000000000
--- a/docs_src/query_params/tutorial004_py39.py
+++ /dev/null
@@ -1,19 +0,0 @@
-from typing import Union
-
-from fastapi import FastAPI
-
-app = FastAPI()
-
-
-@app.get("/users/{user_id}/items/{item_id}")
-async def read_user_item(
- user_id: int, item_id: str, q: Union[str, None] = None, short: bool = False
-):
- item = {"item_id": item_id, "owner_id": user_id}
- if q:
- item.update({"q": q})
- if not short:
- item.update(
- {"description": "This is an amazing item that has a long description"}
- )
- return item
diff --git a/docs_src/query_params/tutorial005_py39.py b/docs_src/query_params/tutorial005_py310.py
similarity index 100%
rename from docs_src/query_params/tutorial005_py39.py
rename to docs_src/query_params/tutorial005_py310.py
diff --git a/docs_src/query_params/tutorial006_py39.py b/docs_src/query_params/tutorial006_py39.py
deleted file mode 100644
index f0dbfe08fe..0000000000
--- a/docs_src/query_params/tutorial006_py39.py
+++ /dev/null
@@ -1,13 +0,0 @@
-from typing import Union
-
-from fastapi import FastAPI
-
-app = FastAPI()
-
-
-@app.get("/items/{item_id}")
-async def read_user_item(
- item_id: str, needy: str, skip: int = 0, limit: Union[int, None] = None
-):
- item = {"item_id": item_id, "needy": needy, "skip": skip, "limit": limit}
- return item
diff --git a/docs_src/query_params_str_validations/tutorial001_py39.py b/docs_src/query_params_str_validations/tutorial001_py39.py
deleted file mode 100644
index e38326b18c..0000000000
--- a/docs_src/query_params_str_validations/tutorial001_py39.py
+++ /dev/null
@@ -1,13 +0,0 @@
-from typing import Union
-
-from fastapi import FastAPI
-
-app = FastAPI()
-
-
-@app.get("/items/")
-async def read_items(q: Union[str, None] = None):
- results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
- if q:
- results.update({"q": q})
- return results
diff --git a/docs_src/query_params_str_validations/tutorial002_an_py39.py b/docs_src/query_params_str_validations/tutorial002_an_py39.py
deleted file mode 100644
index 2d8fc97985..0000000000
--- a/docs_src/query_params_str_validations/tutorial002_an_py39.py
+++ /dev/null
@@ -1,13 +0,0 @@
-from typing import Annotated, Union
-
-from fastapi import FastAPI, Query
-
-app = FastAPI()
-
-
-@app.get("/items/")
-async def read_items(q: Annotated[Union[str, None], Query(max_length=50)] = None):
- results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
- if q:
- results.update({"q": q})
- return results
diff --git a/docs_src/query_params_str_validations/tutorial002_py39.py b/docs_src/query_params_str_validations/tutorial002_py39.py
deleted file mode 100644
index 17e017b7e7..0000000000
--- a/docs_src/query_params_str_validations/tutorial002_py39.py
+++ /dev/null
@@ -1,13 +0,0 @@
-from typing import Union
-
-from fastapi import FastAPI, Query
-
-app = FastAPI()
-
-
-@app.get("/items/")
-async def read_items(q: Union[str, None] = Query(default=None, max_length=50)):
- results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
- if q:
- results.update({"q": q})
- return results
diff --git a/docs_src/query_params_str_validations/tutorial003_an_py39.py b/docs_src/query_params_str_validations/tutorial003_an_py39.py
deleted file mode 100644
index 3d6697793f..0000000000
--- a/docs_src/query_params_str_validations/tutorial003_an_py39.py
+++ /dev/null
@@ -1,15 +0,0 @@
-from typing import Annotated, Union
-
-from fastapi import FastAPI, Query
-
-app = FastAPI()
-
-
-@app.get("/items/")
-async def read_items(
- q: Annotated[Union[str, None], Query(min_length=3, max_length=50)] = None,
-):
- results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
- if q:
- results.update({"q": q})
- return results
diff --git a/docs_src/query_params_str_validations/tutorial003_py39.py b/docs_src/query_params_str_validations/tutorial003_py39.py
deleted file mode 100644
index 7d4917373a..0000000000
--- a/docs_src/query_params_str_validations/tutorial003_py39.py
+++ /dev/null
@@ -1,15 +0,0 @@
-from typing import Union
-
-from fastapi import FastAPI, Query
-
-app = FastAPI()
-
-
-@app.get("/items/")
-async def read_items(
- q: Union[str, None] = Query(default=None, min_length=3, max_length=50),
-):
- results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
- if q:
- results.update({"q": q})
- return results
diff --git a/docs_src/query_params_str_validations/tutorial004_an_py39.py b/docs_src/query_params_str_validations/tutorial004_an_py39.py
deleted file mode 100644
index de27097b38..0000000000
--- a/docs_src/query_params_str_validations/tutorial004_an_py39.py
+++ /dev/null
@@ -1,17 +0,0 @@
-from typing import Annotated, Union
-
-from fastapi import FastAPI, Query
-
-app = FastAPI()
-
-
-@app.get("/items/")
-async def read_items(
- q: Annotated[
- Union[str, None], Query(min_length=3, max_length=50, pattern="^fixedquery$")
- ] = None,
-):
- results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
- if q:
- results.update({"q": q})
- return results
diff --git a/docs_src/query_params_str_validations/tutorial004_py39.py b/docs_src/query_params_str_validations/tutorial004_py39.py
deleted file mode 100644
index 64a647a16a..0000000000
--- a/docs_src/query_params_str_validations/tutorial004_py39.py
+++ /dev/null
@@ -1,17 +0,0 @@
-from typing import Union
-
-from fastapi import FastAPI, Query
-
-app = FastAPI()
-
-
-@app.get("/items/")
-async def read_items(
- q: Union[str, None] = Query(
- default=None, min_length=3, max_length=50, pattern="^fixedquery$"
- ),
-):
- results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
- if q:
- results.update({"q": q})
- return results
diff --git a/docs_src/query_params_str_validations/tutorial004_regex_an_py310.py b/docs_src/query_params_str_validations/tutorial004_regex_an_py310.py
deleted file mode 100644
index 21e0d3eb85..0000000000
--- a/docs_src/query_params_str_validations/tutorial004_regex_an_py310.py
+++ /dev/null
@@ -1,17 +0,0 @@
-from typing import Annotated
-
-from fastapi import FastAPI, Query
-
-app = FastAPI()
-
-
-@app.get("/items/")
-async def read_items(
- q: Annotated[
- str | None, Query(min_length=3, max_length=50, regex="^fixedquery$")
- ] = None,
-):
- results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
- if q:
- results.update({"q": q})
- return results
diff --git a/docs_src/query_params_str_validations/tutorial005_an_py39.py b/docs_src/query_params_str_validations/tutorial005_an_py310.py
similarity index 100%
rename from docs_src/query_params_str_validations/tutorial005_an_py39.py
rename to docs_src/query_params_str_validations/tutorial005_an_py310.py
diff --git a/docs_src/query_params_str_validations/tutorial005_py39.py b/docs_src/query_params_str_validations/tutorial005_py310.py
similarity index 100%
rename from docs_src/query_params_str_validations/tutorial005_py39.py
rename to docs_src/query_params_str_validations/tutorial005_py310.py
diff --git a/docs_src/query_params_str_validations/tutorial006_an_py39.py b/docs_src/query_params_str_validations/tutorial006_an_py310.py
similarity index 100%
rename from docs_src/query_params_str_validations/tutorial006_an_py39.py
rename to docs_src/query_params_str_validations/tutorial006_an_py310.py
diff --git a/docs_src/query_params_str_validations/tutorial006_py39.py b/docs_src/query_params_str_validations/tutorial006_py310.py
similarity index 100%
rename from docs_src/query_params_str_validations/tutorial006_py39.py
rename to docs_src/query_params_str_validations/tutorial006_py310.py
diff --git a/docs_src/query_params_str_validations/tutorial006c_an_py39.py b/docs_src/query_params_str_validations/tutorial006c_an_py39.py
deleted file mode 100644
index 76a1cd49ac..0000000000
--- a/docs_src/query_params_str_validations/tutorial006c_an_py39.py
+++ /dev/null
@@ -1,13 +0,0 @@
-from typing import Annotated, Union
-
-from fastapi import FastAPI, Query
-
-app = FastAPI()
-
-
-@app.get("/items/")
-async def read_items(q: Annotated[Union[str, None], Query(min_length=3)]):
- results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
- if q:
- results.update({"q": q})
- return results
diff --git a/docs_src/query_params_str_validations/tutorial006c_py39.py b/docs_src/query_params_str_validations/tutorial006c_py39.py
deleted file mode 100644
index 0a0e820da3..0000000000
--- a/docs_src/query_params_str_validations/tutorial006c_py39.py
+++ /dev/null
@@ -1,13 +0,0 @@
-from typing import Union
-
-from fastapi import FastAPI, Query
-
-app = FastAPI()
-
-
-@app.get("/items/")
-async def read_items(q: Union[str, None] = Query(min_length=3)):
- results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
- if q:
- results.update({"q": q})
- return results
diff --git a/docs_src/query_params_str_validations/tutorial007_an_py39.py b/docs_src/query_params_str_validations/tutorial007_an_py39.py
deleted file mode 100644
index 8d7a82c465..0000000000
--- a/docs_src/query_params_str_validations/tutorial007_an_py39.py
+++ /dev/null
@@ -1,15 +0,0 @@
-from typing import Annotated, Union
-
-from fastapi import FastAPI, Query
-
-app = FastAPI()
-
-
-@app.get("/items/")
-async def read_items(
- q: Annotated[Union[str, None], Query(title="Query string", min_length=3)] = None,
-):
- results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
- if q:
- results.update({"q": q})
- return results
diff --git a/docs_src/query_params_str_validations/tutorial007_py39.py b/docs_src/query_params_str_validations/tutorial007_py39.py
deleted file mode 100644
index 27b649e145..0000000000
--- a/docs_src/query_params_str_validations/tutorial007_py39.py
+++ /dev/null
@@ -1,15 +0,0 @@
-from typing import Union
-
-from fastapi import FastAPI, Query
-
-app = FastAPI()
-
-
-@app.get("/items/")
-async def read_items(
- q: Union[str, None] = Query(default=None, title="Query string", min_length=3),
-):
- results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
- if q:
- results.update({"q": q})
- return results
diff --git a/docs_src/query_params_str_validations/tutorial008_an_py39.py b/docs_src/query_params_str_validations/tutorial008_an_py39.py
deleted file mode 100644
index f3f2f2c0e7..0000000000
--- a/docs_src/query_params_str_validations/tutorial008_an_py39.py
+++ /dev/null
@@ -1,22 +0,0 @@
-from typing import Annotated, Union
-
-from fastapi import FastAPI, Query
-
-app = FastAPI()
-
-
-@app.get("/items/")
-async def read_items(
- q: Annotated[
- Union[str, None],
- Query(
- title="Query string",
- description="Query string for the items to search in the database that have a good match",
- min_length=3,
- ),
- ] = None,
-):
- results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
- if q:
- results.update({"q": q})
- return results
diff --git a/docs_src/query_params_str_validations/tutorial008_py39.py b/docs_src/query_params_str_validations/tutorial008_py39.py
deleted file mode 100644
index e3e0b50aa1..0000000000
--- a/docs_src/query_params_str_validations/tutorial008_py39.py
+++ /dev/null
@@ -1,20 +0,0 @@
-from typing import Union
-
-from fastapi import FastAPI, Query
-
-app = FastAPI()
-
-
-@app.get("/items/")
-async def read_items(
- q: Union[str, None] = Query(
- default=None,
- title="Query string",
- description="Query string for the items to search in the database that have a good match",
- min_length=3,
- ),
-):
- results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
- if q:
- results.update({"q": q})
- return results
diff --git a/docs_src/query_params_str_validations/tutorial009_an_py39.py b/docs_src/query_params_str_validations/tutorial009_an_py39.py
deleted file mode 100644
index 70a89e6137..0000000000
--- a/docs_src/query_params_str_validations/tutorial009_an_py39.py
+++ /dev/null
@@ -1,13 +0,0 @@
-from typing import Annotated, Union
-
-from fastapi import FastAPI, Query
-
-app = FastAPI()
-
-
-@app.get("/items/")
-async def read_items(q: Annotated[Union[str, None], Query(alias="item-query")] = None):
- results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
- if q:
- results.update({"q": q})
- return results
diff --git a/docs_src/query_params_str_validations/tutorial009_py39.py b/docs_src/query_params_str_validations/tutorial009_py39.py
deleted file mode 100644
index 8a6bfe2d93..0000000000
--- a/docs_src/query_params_str_validations/tutorial009_py39.py
+++ /dev/null
@@ -1,13 +0,0 @@
-from typing import Union
-
-from fastapi import FastAPI, Query
-
-app = FastAPI()
-
-
-@app.get("/items/")
-async def read_items(q: Union[str, None] = Query(default=None, alias="item-query")):
- results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
- if q:
- results.update({"q": q})
- return results
diff --git a/docs_src/query_params_str_validations/tutorial010_an_py39.py b/docs_src/query_params_str_validations/tutorial010_an_py39.py
deleted file mode 100644
index b126c116f0..0000000000
--- a/docs_src/query_params_str_validations/tutorial010_an_py39.py
+++ /dev/null
@@ -1,26 +0,0 @@
-from typing import Annotated, Union
-
-from fastapi import FastAPI, Query
-
-app = FastAPI()
-
-
-@app.get("/items/")
-async def read_items(
- q: Annotated[
- Union[str, None],
- Query(
- alias="item-query",
- title="Query string",
- description="Query string for the items to search in the database that have a good match",
- min_length=3,
- max_length=50,
- pattern="^fixedquery$",
- deprecated=True,
- ),
- ] = None,
-):
- results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
- if q:
- results.update({"q": q})
- return results
diff --git a/docs_src/query_params_str_validations/tutorial010_py39.py b/docs_src/query_params_str_validations/tutorial010_py39.py
deleted file mode 100644
index ff29176fe5..0000000000
--- a/docs_src/query_params_str_validations/tutorial010_py39.py
+++ /dev/null
@@ -1,24 +0,0 @@
-from typing import Union
-
-from fastapi import FastAPI, Query
-
-app = FastAPI()
-
-
-@app.get("/items/")
-async def read_items(
- q: Union[str, None] = Query(
- default=None,
- alias="item-query",
- title="Query string",
- description="Query string for the items to search in the database that have a good match",
- min_length=3,
- max_length=50,
- pattern="^fixedquery$",
- deprecated=True,
- ),
-):
- results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
- if q:
- results.update({"q": q})
- return results
diff --git a/docs_src/query_params_str_validations/tutorial011_an_py39.py b/docs_src/query_params_str_validations/tutorial011_an_py39.py
deleted file mode 100644
index 416e3990dc..0000000000
--- a/docs_src/query_params_str_validations/tutorial011_an_py39.py
+++ /dev/null
@@ -1,11 +0,0 @@
-from typing import Annotated, Union
-
-from fastapi import FastAPI, Query
-
-app = FastAPI()
-
-
-@app.get("/items/")
-async def read_items(q: Annotated[Union[list[str], None], Query()] = None):
- query_items = {"q": q}
- return query_items
diff --git a/docs_src/query_params_str_validations/tutorial011_py39.py b/docs_src/query_params_str_validations/tutorial011_py39.py
deleted file mode 100644
index 878f95c798..0000000000
--- a/docs_src/query_params_str_validations/tutorial011_py39.py
+++ /dev/null
@@ -1,11 +0,0 @@
-from typing import Union
-
-from fastapi import FastAPI, Query
-
-app = FastAPI()
-
-
-@app.get("/items/")
-async def read_items(q: Union[list[str], None] = Query(default=None)):
- query_items = {"q": q}
- return query_items
diff --git a/docs_src/query_params_str_validations/tutorial012_an_py39.py b/docs_src/query_params_str_validations/tutorial012_an_py310.py
similarity index 100%
rename from docs_src/query_params_str_validations/tutorial012_an_py39.py
rename to docs_src/query_params_str_validations/tutorial012_an_py310.py
diff --git a/docs_src/query_params_str_validations/tutorial012_py39.py b/docs_src/query_params_str_validations/tutorial012_py310.py
similarity index 100%
rename from docs_src/query_params_str_validations/tutorial012_py39.py
rename to docs_src/query_params_str_validations/tutorial012_py310.py
diff --git a/docs_src/query_params_str_validations/tutorial013_an_py39.py b/docs_src/query_params_str_validations/tutorial013_an_py310.py
similarity index 100%
rename from docs_src/query_params_str_validations/tutorial013_an_py39.py
rename to docs_src/query_params_str_validations/tutorial013_an_py310.py
diff --git a/docs_src/query_params_str_validations/tutorial013_py39.py b/docs_src/query_params_str_validations/tutorial013_py310.py
similarity index 100%
rename from docs_src/query_params_str_validations/tutorial013_py39.py
rename to docs_src/query_params_str_validations/tutorial013_py310.py
diff --git a/docs_src/query_params_str_validations/tutorial014_an_py39.py b/docs_src/query_params_str_validations/tutorial014_an_py39.py
deleted file mode 100644
index aaf7703a57..0000000000
--- a/docs_src/query_params_str_validations/tutorial014_an_py39.py
+++ /dev/null
@@ -1,15 +0,0 @@
-from typing import Annotated, Union
-
-from fastapi import FastAPI, Query
-
-app = FastAPI()
-
-
-@app.get("/items/")
-async def read_items(
- hidden_query: Annotated[Union[str, None], Query(include_in_schema=False)] = None,
-):
- if hidden_query:
- return {"hidden_query": hidden_query}
- else:
- return {"hidden_query": "Not found"}
diff --git a/docs_src/query_params_str_validations/tutorial014_py39.py b/docs_src/query_params_str_validations/tutorial014_py39.py
deleted file mode 100644
index 779db1c80e..0000000000
--- a/docs_src/query_params_str_validations/tutorial014_py39.py
+++ /dev/null
@@ -1,15 +0,0 @@
-from typing import Union
-
-from fastapi import FastAPI, Query
-
-app = FastAPI()
-
-
-@app.get("/items/")
-async def read_items(
- hidden_query: Union[str, None] = Query(default=None, include_in_schema=False),
-):
- if hidden_query:
- return {"hidden_query": hidden_query}
- else:
- return {"hidden_query": "Not found"}
diff --git a/docs_src/query_params_str_validations/tutorial015_an_py39.py b/docs_src/query_params_str_validations/tutorial015_an_py39.py
deleted file mode 100644
index 989b6d2c25..0000000000
--- a/docs_src/query_params_str_validations/tutorial015_an_py39.py
+++ /dev/null
@@ -1,30 +0,0 @@
-import random
-from typing import Annotated, Union
-
-from fastapi import FastAPI
-from pydantic import AfterValidator
-
-app = FastAPI()
-
-data = {
- "isbn-9781529046137": "The Hitchhiker's Guide to the Galaxy",
- "imdb-tt0371724": "The Hitchhiker's Guide to the Galaxy",
- "isbn-9781439512982": "Isaac Asimov: The Complete Stories, Vol. 2",
-}
-
-
-def check_valid_id(id: str):
- if not id.startswith(("isbn-", "imdb-")):
- raise ValueError('Invalid ID format, it must start with "isbn-" or "imdb-"')
- return id
-
-
-@app.get("/items/")
-async def read_items(
- id: Annotated[Union[str, None], AfterValidator(check_valid_id)] = None,
-):
- if id:
- item = data.get(id)
- else:
- id, item = random.choice(list(data.items()))
- return {"id": id, "name": item}
diff --git a/docs_src/request_files/tutorial001_02_an_py39.py b/docs_src/request_files/tutorial001_02_an_py39.py
deleted file mode 100644
index bb090ff6ca..0000000000
--- a/docs_src/request_files/tutorial001_02_an_py39.py
+++ /dev/null
@@ -1,21 +0,0 @@
-from typing import Annotated, Union
-
-from fastapi import FastAPI, File, UploadFile
-
-app = FastAPI()
-
-
-@app.post("/files/")
-async def create_file(file: Annotated[Union[bytes, None], File()] = None):
- if not file:
- return {"message": "No file sent"}
- else:
- return {"file_size": len(file)}
-
-
-@app.post("/uploadfile/")
-async def create_upload_file(file: Union[UploadFile, None] = None):
- if not file:
- return {"message": "No upload file sent"}
- else:
- return {"filename": file.filename}
diff --git a/docs_src/request_files/tutorial001_02_py39.py b/docs_src/request_files/tutorial001_02_py39.py
deleted file mode 100644
index ac30be2d30..0000000000
--- a/docs_src/request_files/tutorial001_02_py39.py
+++ /dev/null
@@ -1,21 +0,0 @@
-from typing import Union
-
-from fastapi import FastAPI, File, UploadFile
-
-app = FastAPI()
-
-
-@app.post("/files/")
-async def create_file(file: Union[bytes, None] = File(default=None)):
- if not file:
- return {"message": "No file sent"}
- else:
- return {"file_size": len(file)}
-
-
-@app.post("/uploadfile/")
-async def create_upload_file(file: Union[UploadFile, None] = None):
- if not file:
- return {"message": "No upload file sent"}
- else:
- return {"filename": file.filename}
diff --git a/docs_src/request_files/tutorial001_03_an_py39.py b/docs_src/request_files/tutorial001_03_an_py310.py
similarity index 100%
rename from docs_src/request_files/tutorial001_03_an_py39.py
rename to docs_src/request_files/tutorial001_03_an_py310.py
diff --git a/docs_src/request_files/tutorial001_03_py39.py b/docs_src/request_files/tutorial001_03_py310.py
similarity index 100%
rename from docs_src/request_files/tutorial001_03_py39.py
rename to docs_src/request_files/tutorial001_03_py310.py
diff --git a/docs_src/request_files/tutorial001_an_py39.py b/docs_src/request_files/tutorial001_an_py310.py
similarity index 100%
rename from docs_src/request_files/tutorial001_an_py39.py
rename to docs_src/request_files/tutorial001_an_py310.py
diff --git a/docs_src/request_files/tutorial001_py39.py b/docs_src/request_files/tutorial001_py310.py
similarity index 100%
rename from docs_src/request_files/tutorial001_py39.py
rename to docs_src/request_files/tutorial001_py310.py
diff --git a/docs_src/request_files/tutorial002_an_py39.py b/docs_src/request_files/tutorial002_an_py310.py
similarity index 100%
rename from docs_src/request_files/tutorial002_an_py39.py
rename to docs_src/request_files/tutorial002_an_py310.py
diff --git a/docs_src/request_files/tutorial002_py39.py b/docs_src/request_files/tutorial002_py310.py
similarity index 100%
rename from docs_src/request_files/tutorial002_py39.py
rename to docs_src/request_files/tutorial002_py310.py
diff --git a/docs_src/request_files/tutorial003_an_py39.py b/docs_src/request_files/tutorial003_an_py310.py
similarity index 100%
rename from docs_src/request_files/tutorial003_an_py39.py
rename to docs_src/request_files/tutorial003_an_py310.py
diff --git a/docs_src/request_files/tutorial003_py39.py b/docs_src/request_files/tutorial003_py310.py
similarity index 100%
rename from docs_src/request_files/tutorial003_py39.py
rename to docs_src/request_files/tutorial003_py310.py
diff --git a/docs_src/request_form_models/tutorial001_an_py39.py b/docs_src/request_form_models/tutorial001_an_py310.py
similarity index 100%
rename from docs_src/request_form_models/tutorial001_an_py39.py
rename to docs_src/request_form_models/tutorial001_an_py310.py
diff --git a/docs_src/request_form_models/tutorial001_py39.py b/docs_src/request_form_models/tutorial001_py310.py
similarity index 100%
rename from docs_src/request_form_models/tutorial001_py39.py
rename to docs_src/request_form_models/tutorial001_py310.py
diff --git a/docs_src/request_form_models/tutorial002_an_py39.py b/docs_src/request_form_models/tutorial002_an_py310.py
similarity index 100%
rename from docs_src/request_form_models/tutorial002_an_py39.py
rename to docs_src/request_form_models/tutorial002_an_py310.py
diff --git a/docs_src/request_form_models/tutorial002_py39.py b/docs_src/request_form_models/tutorial002_py310.py
similarity index 100%
rename from docs_src/request_form_models/tutorial002_py39.py
rename to docs_src/request_form_models/tutorial002_py310.py
diff --git a/docs_src/request_forms/tutorial001_an_py39.py b/docs_src/request_forms/tutorial001_an_py310.py
similarity index 100%
rename from docs_src/request_forms/tutorial001_an_py39.py
rename to docs_src/request_forms/tutorial001_an_py310.py
diff --git a/docs_src/request_forms/tutorial001_py39.py b/docs_src/request_forms/tutorial001_py310.py
similarity index 100%
rename from docs_src/request_forms/tutorial001_py39.py
rename to docs_src/request_forms/tutorial001_py310.py
diff --git a/docs_src/request_forms_and_files/tutorial001_an_py39.py b/docs_src/request_forms_and_files/tutorial001_an_py310.py
similarity index 100%
rename from docs_src/request_forms_and_files/tutorial001_an_py39.py
rename to docs_src/request_forms_and_files/tutorial001_an_py310.py
diff --git a/docs_src/request_forms_and_files/tutorial001_py39.py b/docs_src/request_forms_and_files/tutorial001_py310.py
similarity index 100%
rename from docs_src/request_forms_and_files/tutorial001_py39.py
rename to docs_src/request_forms_and_files/tutorial001_py310.py
diff --git a/docs_src/response_change_status_code/tutorial001_py39.py b/docs_src/response_change_status_code/tutorial001_py310.py
similarity index 100%
rename from docs_src/response_change_status_code/tutorial001_py39.py
rename to docs_src/response_change_status_code/tutorial001_py310.py
diff --git a/docs_src/response_cookies/tutorial001_py39.py b/docs_src/response_cookies/tutorial001_py310.py
similarity index 100%
rename from docs_src/response_cookies/tutorial001_py39.py
rename to docs_src/response_cookies/tutorial001_py310.py
diff --git a/docs_src/response_cookies/tutorial002_py39.py b/docs_src/response_cookies/tutorial002_py310.py
similarity index 100%
rename from docs_src/response_cookies/tutorial002_py39.py
rename to docs_src/response_cookies/tutorial002_py310.py
diff --git a/docs_src/response_directly/tutorial001_py39.py b/docs_src/response_directly/tutorial001_py39.py
deleted file mode 100644
index 5ab655a8a7..0000000000
--- a/docs_src/response_directly/tutorial001_py39.py
+++ /dev/null
@@ -1,22 +0,0 @@
-from datetime import datetime
-from typing import Union
-
-from fastapi import FastAPI
-from fastapi.encoders import jsonable_encoder
-from fastapi.responses import JSONResponse
-from pydantic import BaseModel
-
-
-class Item(BaseModel):
- title: str
- timestamp: datetime
- description: Union[str, None] = None
-
-
-app = FastAPI()
-
-
-@app.put("/items/{id}")
-def update_item(id: str, item: Item):
- json_compatible_item_data = jsonable_encoder(item)
- return JSONResponse(content=json_compatible_item_data)
diff --git a/docs_src/response_directly/tutorial002_py39.py b/docs_src/response_directly/tutorial002_py310.py
similarity index 100%
rename from docs_src/response_directly/tutorial002_py39.py
rename to docs_src/response_directly/tutorial002_py310.py
diff --git a/docs_src/response_headers/tutorial001_py39.py b/docs_src/response_headers/tutorial001_py310.py
similarity index 100%
rename from docs_src/response_headers/tutorial001_py39.py
rename to docs_src/response_headers/tutorial001_py310.py
diff --git a/docs_src/response_headers/tutorial002_py39.py b/docs_src/response_headers/tutorial002_py310.py
similarity index 100%
rename from docs_src/response_headers/tutorial002_py39.py
rename to docs_src/response_headers/tutorial002_py310.py
diff --git a/docs_src/response_model/tutorial001_01_py39.py b/docs_src/response_model/tutorial001_01_py39.py
deleted file mode 100644
index 16c78aa3fd..0000000000
--- a/docs_src/response_model/tutorial001_01_py39.py
+++ /dev/null
@@ -1,27 +0,0 @@
-from typing import Union
-
-from fastapi import FastAPI
-from pydantic import BaseModel
-
-app = FastAPI()
-
-
-class Item(BaseModel):
- name: str
- description: Union[str, None] = None
- price: float
- tax: Union[float, None] = None
- tags: list[str] = []
-
-
-@app.post("/items/")
-async def create_item(item: Item) -> Item:
- return item
-
-
-@app.get("/items/")
-async def read_items() -> list[Item]:
- return [
- Item(name="Portal Gun", price=42.0),
- Item(name="Plumbus", price=32.0),
- ]
diff --git a/docs_src/response_model/tutorial001_py39.py b/docs_src/response_model/tutorial001_py39.py
deleted file mode 100644
index 261e252d00..0000000000
--- a/docs_src/response_model/tutorial001_py39.py
+++ /dev/null
@@ -1,27 +0,0 @@
-from typing import Any, Union
-
-from fastapi import FastAPI
-from pydantic import BaseModel
-
-app = FastAPI()
-
-
-class Item(BaseModel):
- name: str
- description: Union[str, None] = None
- price: float
- tax: Union[float, None] = None
- tags: list[str] = []
-
-
-@app.post("/items/", response_model=Item)
-async def create_item(item: Item) -> Any:
- return item
-
-
-@app.get("/items/", response_model=list[Item])
-async def read_items() -> Any:
- return [
- {"name": "Portal Gun", "price": 42.0},
- {"name": "Plumbus", "price": 32.0},
- ]
diff --git a/docs_src/response_model/tutorial002_py39.py b/docs_src/response_model/tutorial002_py39.py
deleted file mode 100644
index a58668f9ef..0000000000
--- a/docs_src/response_model/tutorial002_py39.py
+++ /dev/null
@@ -1,19 +0,0 @@
-from typing import Union
-
-from fastapi import FastAPI
-from pydantic import BaseModel, EmailStr
-
-app = FastAPI()
-
-
-class UserIn(BaseModel):
- username: str
- password: str
- email: EmailStr
- full_name: Union[str, None] = None
-
-
-# Don't do this in production!
-@app.post("/user/")
-async def create_user(user: UserIn) -> UserIn:
- return user
diff --git a/docs_src/response_model/tutorial003_01_py39.py b/docs_src/response_model/tutorial003_01_py39.py
deleted file mode 100644
index 52694b5510..0000000000
--- a/docs_src/response_model/tutorial003_01_py39.py
+++ /dev/null
@@ -1,21 +0,0 @@
-from typing import Union
-
-from fastapi import FastAPI
-from pydantic import BaseModel, EmailStr
-
-app = FastAPI()
-
-
-class BaseUser(BaseModel):
- username: str
- email: EmailStr
- full_name: Union[str, None] = None
-
-
-class UserIn(BaseUser):
- password: str
-
-
-@app.post("/user/")
-async def create_user(user: UserIn) -> BaseUser:
- return user
diff --git a/docs_src/response_model/tutorial003_02_py39.py b/docs_src/response_model/tutorial003_02_py310.py
similarity index 100%
rename from docs_src/response_model/tutorial003_02_py39.py
rename to docs_src/response_model/tutorial003_02_py310.py
diff --git a/docs_src/response_model/tutorial003_03_py39.py b/docs_src/response_model/tutorial003_03_py310.py
similarity index 100%
rename from docs_src/response_model/tutorial003_03_py39.py
rename to docs_src/response_model/tutorial003_03_py310.py
diff --git a/docs_src/response_model/tutorial003_04_py39.py b/docs_src/response_model/tutorial003_04_py39.py
deleted file mode 100644
index b13a926929..0000000000
--- a/docs_src/response_model/tutorial003_04_py39.py
+++ /dev/null
@@ -1,13 +0,0 @@
-from typing import Union
-
-from fastapi import FastAPI, Response
-from fastapi.responses import RedirectResponse
-
-app = FastAPI()
-
-
-@app.get("/portal")
-async def get_portal(teleport: bool = False) -> Union[Response, dict]:
- if teleport:
- return RedirectResponse(url="https://www.youtube.com/watch?v=dQw4w9WgXcQ")
- return {"message": "Here's your interdimensional portal."}
diff --git a/docs_src/response_model/tutorial003_05_py39.py b/docs_src/response_model/tutorial003_05_py39.py
deleted file mode 100644
index 0962061a60..0000000000
--- a/docs_src/response_model/tutorial003_05_py39.py
+++ /dev/null
@@ -1,13 +0,0 @@
-from typing import Union
-
-from fastapi import FastAPI, Response
-from fastapi.responses import RedirectResponse
-
-app = FastAPI()
-
-
-@app.get("/portal", response_model=None)
-async def get_portal(teleport: bool = False) -> Union[Response, dict]:
- if teleport:
- return RedirectResponse(url="https://www.youtube.com/watch?v=dQw4w9WgXcQ")
- return {"message": "Here's your interdimensional portal."}
diff --git a/docs_src/response_model/tutorial003_py39.py b/docs_src/response_model/tutorial003_py39.py
deleted file mode 100644
index c42dbc7077..0000000000
--- a/docs_src/response_model/tutorial003_py39.py
+++ /dev/null
@@ -1,24 +0,0 @@
-from typing import Any, Union
-
-from fastapi import FastAPI
-from pydantic import BaseModel, EmailStr
-
-app = FastAPI()
-
-
-class UserIn(BaseModel):
- username: str
- password: str
- email: EmailStr
- full_name: Union[str, None] = None
-
-
-class UserOut(BaseModel):
- username: str
- email: EmailStr
- full_name: Union[str, None] = None
-
-
-@app.post("/user/", response_model=UserOut)
-async def create_user(user: UserIn) -> Any:
- return user
diff --git a/docs_src/response_model/tutorial004_py39.py b/docs_src/response_model/tutorial004_py39.py
deleted file mode 100644
index 9463b45ec1..0000000000
--- a/docs_src/response_model/tutorial004_py39.py
+++ /dev/null
@@ -1,26 +0,0 @@
-from typing import Union
-
-from fastapi import FastAPI
-from pydantic import BaseModel
-
-app = FastAPI()
-
-
-class Item(BaseModel):
- name: str
- description: Union[str, None] = None
- price: float
- tax: float = 10.5
- tags: list[str] = []
-
-
-items = {
- "foo": {"name": "Foo", "price": 50.2},
- "bar": {"name": "Bar", "description": "The bartenders", "price": 62, "tax": 20.2},
- "baz": {"name": "Baz", "description": None, "price": 50.2, "tax": 10.5, "tags": []},
-}
-
-
-@app.get("/items/{item_id}", response_model=Item, response_model_exclude_unset=True)
-async def read_item(item_id: str):
- return items[item_id]
diff --git a/docs_src/response_model/tutorial005_py39.py b/docs_src/response_model/tutorial005_py39.py
deleted file mode 100644
index 30eb9f8e3f..0000000000
--- a/docs_src/response_model/tutorial005_py39.py
+++ /dev/null
@@ -1,39 +0,0 @@
-from typing import Union
-
-from fastapi import FastAPI
-from pydantic import BaseModel
-
-app = FastAPI()
-
-
-class Item(BaseModel):
- name: str
- description: Union[str, None] = None
- price: float
- tax: float = 10.5
-
-
-items = {
- "foo": {"name": "Foo", "price": 50.2},
- "bar": {"name": "Bar", "description": "The Bar fighters", "price": 62, "tax": 20.2},
- "baz": {
- "name": "Baz",
- "description": "There goes my baz",
- "price": 50.2,
- "tax": 10.5,
- },
-}
-
-
-@app.get(
- "/items/{item_id}/name",
- response_model=Item,
- response_model_include={"name", "description"},
-)
-async def read_item_name(item_id: str):
- return items[item_id]
-
-
-@app.get("/items/{item_id}/public", response_model=Item, response_model_exclude={"tax"})
-async def read_item_public_data(item_id: str):
- return items[item_id]
diff --git a/docs_src/response_model/tutorial006_py39.py b/docs_src/response_model/tutorial006_py39.py
deleted file mode 100644
index 3ffdb512bc..0000000000
--- a/docs_src/response_model/tutorial006_py39.py
+++ /dev/null
@@ -1,39 +0,0 @@
-from typing import Union
-
-from fastapi import FastAPI
-from pydantic import BaseModel
-
-app = FastAPI()
-
-
-class Item(BaseModel):
- name: str
- description: Union[str, None] = None
- price: float
- tax: float = 10.5
-
-
-items = {
- "foo": {"name": "Foo", "price": 50.2},
- "bar": {"name": "Bar", "description": "The Bar fighters", "price": 62, "tax": 20.2},
- "baz": {
- "name": "Baz",
- "description": "There goes my baz",
- "price": 50.2,
- "tax": 10.5,
- },
-}
-
-
-@app.get(
- "/items/{item_id}/name",
- response_model=Item,
- response_model_include=["name", "description"],
-)
-async def read_item_name(item_id: str):
- return items[item_id]
-
-
-@app.get("/items/{item_id}/public", response_model=Item, response_model_exclude=["tax"])
-async def read_item_public_data(item_id: str):
- return items[item_id]
diff --git a/docs_src/response_status_code/tutorial001_py39.py b/docs_src/response_status_code/tutorial001_py310.py
similarity index 100%
rename from docs_src/response_status_code/tutorial001_py39.py
rename to docs_src/response_status_code/tutorial001_py310.py
diff --git a/docs_src/response_status_code/tutorial002_py39.py b/docs_src/response_status_code/tutorial002_py310.py
similarity index 100%
rename from docs_src/response_status_code/tutorial002_py39.py
rename to docs_src/response_status_code/tutorial002_py310.py
diff --git a/docs_src/schema_extra_example/tutorial001_pv1_py310.py b/docs_src/schema_extra_example/tutorial001_pv1_py310.py
deleted file mode 100644
index b13b8a8c2c..0000000000
--- a/docs_src/schema_extra_example/tutorial001_pv1_py310.py
+++ /dev/null
@@ -1,29 +0,0 @@
-from fastapi import FastAPI
-from pydantic.v1 import BaseModel
-
-app = FastAPI()
-
-
-class Item(BaseModel):
- name: str
- description: str | None = None
- price: float
- tax: float | None = None
-
- class Config:
- schema_extra = {
- "examples": [
- {
- "name": "Foo",
- "description": "A very nice Item",
- "price": 35.4,
- "tax": 3.2,
- }
- ]
- }
-
-
-@app.put("/items/{item_id}")
-async def update_item(item_id: int, item: Item):
- results = {"item_id": item_id, "item": item}
- return results
diff --git a/docs_src/schema_extra_example/tutorial001_pv1_py39.py b/docs_src/schema_extra_example/tutorial001_pv1_py39.py
deleted file mode 100644
index 3240b35d6d..0000000000
--- a/docs_src/schema_extra_example/tutorial001_pv1_py39.py
+++ /dev/null
@@ -1,31 +0,0 @@
-from typing import Union
-
-from fastapi import FastAPI
-from pydantic.v1 import BaseModel
-
-app = FastAPI()
-
-
-class Item(BaseModel):
- name: str
- description: Union[str, None] = None
- price: float
- tax: Union[float, None] = None
-
- class Config:
- schema_extra = {
- "examples": [
- {
- "name": "Foo",
- "description": "A very nice Item",
- "price": 35.4,
- "tax": 3.2,
- }
- ]
- }
-
-
-@app.put("/items/{item_id}")
-async def update_item(item_id: int, item: Item):
- results = {"item_id": item_id, "item": item}
- return results
diff --git a/docs_src/schema_extra_example/tutorial001_py39.py b/docs_src/schema_extra_example/tutorial001_py39.py
deleted file mode 100644
index 32a66db3a9..0000000000
--- a/docs_src/schema_extra_example/tutorial001_py39.py
+++ /dev/null
@@ -1,32 +0,0 @@
-from typing import Union
-
-from fastapi import FastAPI
-from pydantic import BaseModel
-
-app = FastAPI()
-
-
-class Item(BaseModel):
- name: str
- description: Union[str, None] = None
- price: float
- tax: Union[float, None] = None
-
- model_config = {
- "json_schema_extra": {
- "examples": [
- {
- "name": "Foo",
- "description": "A very nice Item",
- "price": 35.4,
- "tax": 3.2,
- }
- ]
- }
- }
-
-
-@app.put("/items/{item_id}")
-async def update_item(item_id: int, item: Item):
- results = {"item_id": item_id, "item": item}
- return results
diff --git a/docs_src/schema_extra_example/tutorial002_py39.py b/docs_src/schema_extra_example/tutorial002_py39.py
deleted file mode 100644
index 70f06567c3..0000000000
--- a/docs_src/schema_extra_example/tutorial002_py39.py
+++ /dev/null
@@ -1,19 +0,0 @@
-from typing import Union
-
-from fastapi import FastAPI
-from pydantic import BaseModel, Field
-
-app = FastAPI()
-
-
-class Item(BaseModel):
- name: str = Field(examples=["Foo"])
- description: Union[str, None] = Field(default=None, examples=["A very nice Item"])
- price: float = Field(examples=[35.4])
- tax: Union[float, None] = Field(default=None, examples=[3.2])
-
-
-@app.put("/items/{item_id}")
-async def update_item(item_id: int, item: Item):
- results = {"item_id": item_id, "item": item}
- return results
diff --git a/docs_src/schema_extra_example/tutorial003_an_py39.py b/docs_src/schema_extra_example/tutorial003_an_py39.py
deleted file mode 100644
index 4728085617..0000000000
--- a/docs_src/schema_extra_example/tutorial003_an_py39.py
+++ /dev/null
@@ -1,34 +0,0 @@
-from typing import Annotated, Union
-
-from fastapi import Body, FastAPI
-from pydantic import BaseModel
-
-app = FastAPI()
-
-
-class Item(BaseModel):
- name: str
- description: Union[str, None] = None
- price: float
- tax: Union[float, None] = None
-
-
-@app.put("/items/{item_id}")
-async def update_item(
- item_id: int,
- item: Annotated[
- Item,
- Body(
- examples=[
- {
- "name": "Foo",
- "description": "A very nice Item",
- "price": 35.4,
- "tax": 3.2,
- }
- ],
- ),
- ],
-):
- results = {"item_id": item_id, "item": item}
- return results
diff --git a/docs_src/schema_extra_example/tutorial003_py39.py b/docs_src/schema_extra_example/tutorial003_py39.py
deleted file mode 100644
index 385f3de8a1..0000000000
--- a/docs_src/schema_extra_example/tutorial003_py39.py
+++ /dev/null
@@ -1,31 +0,0 @@
-from typing import Union
-
-from fastapi import Body, FastAPI
-from pydantic import BaseModel
-
-app = FastAPI()
-
-
-class Item(BaseModel):
- name: str
- description: Union[str, None] = None
- price: float
- tax: Union[float, None] = None
-
-
-@app.put("/items/{item_id}")
-async def update_item(
- item_id: int,
- item: Item = Body(
- examples=[
- {
- "name": "Foo",
- "description": "A very nice Item",
- "price": 35.4,
- "tax": 3.2,
- }
- ],
- ),
-):
- results = {"item_id": item_id, "item": item}
- return results
diff --git a/docs_src/schema_extra_example/tutorial004_an_py39.py b/docs_src/schema_extra_example/tutorial004_an_py39.py
deleted file mode 100644
index dc5a8fe49c..0000000000
--- a/docs_src/schema_extra_example/tutorial004_an_py39.py
+++ /dev/null
@@ -1,43 +0,0 @@
-from typing import Annotated, Union
-
-from fastapi import Body, FastAPI
-from pydantic import BaseModel
-
-app = FastAPI()
-
-
-class Item(BaseModel):
- name: str
- description: Union[str, None] = None
- price: float
- tax: Union[float, None] = None
-
-
-@app.put("/items/{item_id}")
-async def update_item(
- *,
- item_id: int,
- item: Annotated[
- Item,
- Body(
- examples=[
- {
- "name": "Foo",
- "description": "A very nice Item",
- "price": 35.4,
- "tax": 3.2,
- },
- {
- "name": "Bar",
- "price": "35.4",
- },
- {
- "name": "Baz",
- "price": "thirty five point four",
- },
- ],
- ),
- ],
-):
- results = {"item_id": item_id, "item": item}
- return results
diff --git a/docs_src/schema_extra_example/tutorial004_py39.py b/docs_src/schema_extra_example/tutorial004_py39.py
deleted file mode 100644
index 75514a3e91..0000000000
--- a/docs_src/schema_extra_example/tutorial004_py39.py
+++ /dev/null
@@ -1,40 +0,0 @@
-from typing import Union
-
-from fastapi import Body, FastAPI
-from pydantic import BaseModel
-
-app = FastAPI()
-
-
-class Item(BaseModel):
- name: str
- description: Union[str, None] = None
- price: float
- tax: Union[float, None] = None
-
-
-@app.put("/items/{item_id}")
-async def update_item(
- *,
- item_id: int,
- item: Item = Body(
- examples=[
- {
- "name": "Foo",
- "description": "A very nice Item",
- "price": 35.4,
- "tax": 3.2,
- },
- {
- "name": "Bar",
- "price": "35.4",
- },
- {
- "name": "Baz",
- "price": "thirty five point four",
- },
- ],
- ),
-):
- results = {"item_id": item_id, "item": item}
- return results
diff --git a/docs_src/schema_extra_example/tutorial005_an_py39.py b/docs_src/schema_extra_example/tutorial005_an_py39.py
deleted file mode 100644
index edeb1affce..0000000000
--- a/docs_src/schema_extra_example/tutorial005_an_py39.py
+++ /dev/null
@@ -1,54 +0,0 @@
-from typing import Annotated, Union
-
-from fastapi import Body, FastAPI
-from pydantic import BaseModel
-
-app = FastAPI()
-
-
-class Item(BaseModel):
- name: str
- description: Union[str, None] = None
- price: float
- tax: Union[float, None] = None
-
-
-@app.put("/items/{item_id}")
-async def update_item(
- *,
- item_id: int,
- item: Annotated[
- Item,
- Body(
- openapi_examples={
- "normal": {
- "summary": "A normal example",
- "description": "A **normal** item works correctly.",
- "value": {
- "name": "Foo",
- "description": "A very nice Item",
- "price": 35.4,
- "tax": 3.2,
- },
- },
- "converted": {
- "summary": "An example with converted data",
- "description": "FastAPI can convert price `strings` to actual `numbers` automatically",
- "value": {
- "name": "Bar",
- "price": "35.4",
- },
- },
- "invalid": {
- "summary": "Invalid data is rejected with an error",
- "value": {
- "name": "Baz",
- "price": "thirty five point four",
- },
- },
- },
- ),
- ],
-):
- results = {"item_id": item_id, "item": item}
- return results
diff --git a/docs_src/schema_extra_example/tutorial005_py39.py b/docs_src/schema_extra_example/tutorial005_py39.py
deleted file mode 100644
index b8217c27e9..0000000000
--- a/docs_src/schema_extra_example/tutorial005_py39.py
+++ /dev/null
@@ -1,51 +0,0 @@
-from typing import Union
-
-from fastapi import Body, FastAPI
-from pydantic import BaseModel
-
-app = FastAPI()
-
-
-class Item(BaseModel):
- name: str
- description: Union[str, None] = None
- price: float
- tax: Union[float, None] = None
-
-
-@app.put("/items/{item_id}")
-async def update_item(
- *,
- item_id: int,
- item: Item = Body(
- openapi_examples={
- "normal": {
- "summary": "A normal example",
- "description": "A **normal** item works correctly.",
- "value": {
- "name": "Foo",
- "description": "A very nice Item",
- "price": 35.4,
- "tax": 3.2,
- },
- },
- "converted": {
- "summary": "An example with converted data",
- "description": "FastAPI can convert price `strings` to actual `numbers` automatically",
- "value": {
- "name": "Bar",
- "price": "35.4",
- },
- },
- "invalid": {
- "summary": "Invalid data is rejected with an error",
- "value": {
- "name": "Baz",
- "price": "thirty five point four",
- },
- },
- },
- ),
-):
- results = {"item_id": item_id, "item": item}
- return results
diff --git a/docs_src/security/tutorial001_an_py39.py b/docs_src/security/tutorial001_an_py310.py
similarity index 100%
rename from docs_src/security/tutorial001_an_py39.py
rename to docs_src/security/tutorial001_an_py310.py
diff --git a/docs_src/security/tutorial001_py39.py b/docs_src/security/tutorial001_py310.py
similarity index 100%
rename from docs_src/security/tutorial001_py39.py
rename to docs_src/security/tutorial001_py310.py
diff --git a/docs_src/security/tutorial002_an_py39.py b/docs_src/security/tutorial002_an_py39.py
deleted file mode 100644
index 7ff1c470bb..0000000000
--- a/docs_src/security/tutorial002_an_py39.py
+++ /dev/null
@@ -1,32 +0,0 @@
-from typing import Annotated, Union
-
-from fastapi import Depends, FastAPI
-from fastapi.security import OAuth2PasswordBearer
-from pydantic import BaseModel
-
-app = FastAPI()
-
-oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
-
-
-class User(BaseModel):
- username: str
- email: Union[str, None] = None
- full_name: Union[str, None] = None
- disabled: Union[bool, None] = None
-
-
-def fake_decode_token(token):
- return User(
- username=token + "fakedecoded", email="john@example.com", full_name="John Doe"
- )
-
-
-async def get_current_user(token: Annotated[str, Depends(oauth2_scheme)]):
- user = fake_decode_token(token)
- return user
-
-
-@app.get("/users/me")
-async def read_users_me(current_user: Annotated[User, Depends(get_current_user)]):
- return current_user
diff --git a/docs_src/security/tutorial002_py39.py b/docs_src/security/tutorial002_py39.py
deleted file mode 100644
index bfd035221c..0000000000
--- a/docs_src/security/tutorial002_py39.py
+++ /dev/null
@@ -1,32 +0,0 @@
-from typing import Union
-
-from fastapi import Depends, FastAPI
-from fastapi.security import OAuth2PasswordBearer
-from pydantic import BaseModel
-
-app = FastAPI()
-
-oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
-
-
-class User(BaseModel):
- username: str
- email: Union[str, None] = None
- full_name: Union[str, None] = None
- disabled: Union[bool, None] = None
-
-
-def fake_decode_token(token):
- return User(
- username=token + "fakedecoded", email="john@example.com", full_name="John Doe"
- )
-
-
-async def get_current_user(token: str = Depends(oauth2_scheme)):
- user = fake_decode_token(token)
- return user
-
-
-@app.get("/users/me")
-async def read_users_me(current_user: User = Depends(get_current_user)):
- return current_user
diff --git a/docs_src/security/tutorial003_an_py39.py b/docs_src/security/tutorial003_an_py39.py
deleted file mode 100644
index b396210c82..0000000000
--- a/docs_src/security/tutorial003_an_py39.py
+++ /dev/null
@@ -1,94 +0,0 @@
-from typing import Annotated, Union
-
-from fastapi import Depends, FastAPI, HTTPException, status
-from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
-from pydantic import BaseModel
-
-fake_users_db = {
- "johndoe": {
- "username": "johndoe",
- "full_name": "John Doe",
- "email": "johndoe@example.com",
- "hashed_password": "fakehashedsecret",
- "disabled": False,
- },
- "alice": {
- "username": "alice",
- "full_name": "Alice Wonderson",
- "email": "alice@example.com",
- "hashed_password": "fakehashedsecret2",
- "disabled": True,
- },
-}
-
-app = FastAPI()
-
-
-def fake_hash_password(password: str):
- return "fakehashed" + password
-
-
-oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
-
-
-class User(BaseModel):
- username: str
- email: Union[str, None] = None
- full_name: Union[str, None] = None
- disabled: Union[bool, None] = None
-
-
-class UserInDB(User):
- hashed_password: str
-
-
-def get_user(db, username: str):
- if username in db:
- user_dict = db[username]
- return UserInDB(**user_dict)
-
-
-def fake_decode_token(token):
- # This doesn't provide any security at all
- # Check the next version
- user = get_user(fake_users_db, token)
- return user
-
-
-async def get_current_user(token: Annotated[str, Depends(oauth2_scheme)]):
- user = fake_decode_token(token)
- if not user:
- raise HTTPException(
- status_code=status.HTTP_401_UNAUTHORIZED,
- detail="Not authenticated",
- headers={"WWW-Authenticate": "Bearer"},
- )
- return user
-
-
-async def get_current_active_user(
- current_user: Annotated[User, Depends(get_current_user)],
-):
- if current_user.disabled:
- raise HTTPException(status_code=400, detail="Inactive user")
- return current_user
-
-
-@app.post("/token")
-async def login(form_data: Annotated[OAuth2PasswordRequestForm, Depends()]):
- user_dict = fake_users_db.get(form_data.username)
- if not user_dict:
- raise HTTPException(status_code=400, detail="Incorrect username or password")
- user = UserInDB(**user_dict)
- hashed_password = fake_hash_password(form_data.password)
- if not hashed_password == user.hashed_password:
- raise HTTPException(status_code=400, detail="Incorrect username or password")
-
- return {"access_token": user.username, "token_type": "bearer"}
-
-
-@app.get("/users/me")
-async def read_users_me(
- current_user: Annotated[User, Depends(get_current_active_user)],
-):
- return current_user
diff --git a/docs_src/security/tutorial003_py39.py b/docs_src/security/tutorial003_py39.py
deleted file mode 100644
index ce7a71b68b..0000000000
--- a/docs_src/security/tutorial003_py39.py
+++ /dev/null
@@ -1,90 +0,0 @@
-from typing import Union
-
-from fastapi import Depends, FastAPI, HTTPException, status
-from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
-from pydantic import BaseModel
-
-fake_users_db = {
- "johndoe": {
- "username": "johndoe",
- "full_name": "John Doe",
- "email": "johndoe@example.com",
- "hashed_password": "fakehashedsecret",
- "disabled": False,
- },
- "alice": {
- "username": "alice",
- "full_name": "Alice Wonderson",
- "email": "alice@example.com",
- "hashed_password": "fakehashedsecret2",
- "disabled": True,
- },
-}
-
-app = FastAPI()
-
-
-def fake_hash_password(password: str):
- return "fakehashed" + password
-
-
-oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
-
-
-class User(BaseModel):
- username: str
- email: Union[str, None] = None
- full_name: Union[str, None] = None
- disabled: Union[bool, None] = None
-
-
-class UserInDB(User):
- hashed_password: str
-
-
-def get_user(db, username: str):
- if username in db:
- user_dict = db[username]
- return UserInDB(**user_dict)
-
-
-def fake_decode_token(token):
- # This doesn't provide any security at all
- # Check the next version
- user = get_user(fake_users_db, token)
- return user
-
-
-async def get_current_user(token: str = Depends(oauth2_scheme)):
- user = fake_decode_token(token)
- if not user:
- raise HTTPException(
- status_code=status.HTTP_401_UNAUTHORIZED,
- detail="Not authenticated",
- headers={"WWW-Authenticate": "Bearer"},
- )
- return user
-
-
-async def get_current_active_user(current_user: User = Depends(get_current_user)):
- if current_user.disabled:
- raise HTTPException(status_code=400, detail="Inactive user")
- return current_user
-
-
-@app.post("/token")
-async def login(form_data: OAuth2PasswordRequestForm = Depends()):
- user_dict = fake_users_db.get(form_data.username)
- if not user_dict:
- raise HTTPException(status_code=400, detail="Incorrect username or password")
- user = UserInDB(**user_dict)
- hashed_password = fake_hash_password(form_data.password)
- if not hashed_password == user.hashed_password:
- raise HTTPException(status_code=400, detail="Incorrect username or password")
-
- return {"access_token": user.username, "token_type": "bearer"}
-
-
-@app.get("/users/me")
-async def read_users_me(current_user: User = Depends(get_current_active_user)):
- return current_user
diff --git a/docs_src/security/tutorial004_an_py310.py b/docs_src/security/tutorial004_an_py310.py
index 368c743bf9..685cb034ee 100644
--- a/docs_src/security/tutorial004_an_py310.py
+++ b/docs_src/security/tutorial004_an_py310.py
@@ -48,6 +48,8 @@ class UserInDB(User):
password_hash = PasswordHash.recommended()
+DUMMY_HASH = password_hash.hash("dummypassword")
+
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
app = FastAPI()
@@ -70,6 +72,7 @@ def get_user(db, username: str):
def authenticate_user(fake_db, username: str, password: str):
user = get_user(fake_db, username)
if not user:
+ verify_password(password, DUMMY_HASH)
return False
if not verify_password(password, user.hashed_password):
return False
diff --git a/docs_src/security/tutorial004_an_py39.py b/docs_src/security/tutorial004_an_py39.py
deleted file mode 100644
index 73b3d456d1..0000000000
--- a/docs_src/security/tutorial004_an_py39.py
+++ /dev/null
@@ -1,147 +0,0 @@
-from datetime import datetime, timedelta, timezone
-from typing import Annotated, Union
-
-import jwt
-from fastapi import Depends, FastAPI, HTTPException, status
-from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
-from jwt.exceptions import InvalidTokenError
-from pwdlib import PasswordHash
-from pydantic import BaseModel
-
-# to get a string like this run:
-# openssl rand -hex 32
-SECRET_KEY = "09d25e094faa6ca2556c818166b7a9563b93f7099f6f0f4caa6cf63b88e8d3e7"
-ALGORITHM = "HS256"
-ACCESS_TOKEN_EXPIRE_MINUTES = 30
-
-
-fake_users_db = {
- "johndoe": {
- "username": "johndoe",
- "full_name": "John Doe",
- "email": "johndoe@example.com",
- "hashed_password": "$argon2id$v=19$m=65536,t=3,p=4$wagCPXjifgvUFBzq4hqe3w$CYaIb8sB+wtD+Vu/P4uod1+Qof8h+1g7bbDlBID48Rc",
- "disabled": False,
- }
-}
-
-
-class Token(BaseModel):
- access_token: str
- token_type: str
-
-
-class TokenData(BaseModel):
- username: Union[str, None] = None
-
-
-class User(BaseModel):
- username: str
- email: Union[str, None] = None
- full_name: Union[str, None] = None
- disabled: Union[bool, None] = None
-
-
-class UserInDB(User):
- hashed_password: str
-
-
-password_hash = PasswordHash.recommended()
-
-oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
-
-app = FastAPI()
-
-
-def verify_password(plain_password, hashed_password):
- return password_hash.verify(plain_password, hashed_password)
-
-
-def get_password_hash(password):
- return password_hash.hash(password)
-
-
-def get_user(db, username: str):
- if username in db:
- user_dict = db[username]
- return UserInDB(**user_dict)
-
-
-def authenticate_user(fake_db, username: str, password: str):
- user = get_user(fake_db, username)
- if not user:
- return False
- if not verify_password(password, user.hashed_password):
- return False
- return user
-
-
-def create_access_token(data: dict, expires_delta: Union[timedelta, None] = None):
- to_encode = data.copy()
- if expires_delta:
- expire = datetime.now(timezone.utc) + expires_delta
- else:
- expire = datetime.now(timezone.utc) + timedelta(minutes=15)
- to_encode.update({"exp": expire})
- encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
- return encoded_jwt
-
-
-async def get_current_user(token: Annotated[str, Depends(oauth2_scheme)]):
- credentials_exception = HTTPException(
- status_code=status.HTTP_401_UNAUTHORIZED,
- detail="Could not validate credentials",
- headers={"WWW-Authenticate": "Bearer"},
- )
- try:
- payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
- username = payload.get("sub")
- if username is None:
- raise credentials_exception
- token_data = TokenData(username=username)
- except InvalidTokenError:
- raise credentials_exception
- user = get_user(fake_users_db, username=token_data.username)
- if user is None:
- raise credentials_exception
- return user
-
-
-async def get_current_active_user(
- current_user: Annotated[User, Depends(get_current_user)],
-):
- if current_user.disabled:
- raise HTTPException(status_code=400, detail="Inactive user")
- return current_user
-
-
-@app.post("/token")
-async def login_for_access_token(
- form_data: Annotated[OAuth2PasswordRequestForm, Depends()],
-) -> Token:
- user = authenticate_user(fake_users_db, form_data.username, form_data.password)
- if not user:
- raise HTTPException(
- status_code=status.HTTP_401_UNAUTHORIZED,
- detail="Incorrect username or password",
- headers={"WWW-Authenticate": "Bearer"},
- )
- access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
- access_token = create_access_token(
- data={"sub": user.username}, expires_delta=access_token_expires
- )
- return Token(access_token=access_token, token_type="bearer")
-
-
-@app.get("/users/me/")
-async def read_users_me(
- current_user: Annotated[User, Depends(get_current_active_user)],
-) -> User:
- return current_user
-
-
-@app.get("/users/me/items/")
-async def read_own_items(
- current_user: Annotated[User, Depends(get_current_active_user)],
-):
- return [{"item_id": "Foo", "owner": current_user.username}]
diff --git a/docs_src/security/tutorial004_py310.py b/docs_src/security/tutorial004_py310.py
index 8d0785b404..dc7f1c9e29 100644
--- a/docs_src/security/tutorial004_py310.py
+++ b/docs_src/security/tutorial004_py310.py
@@ -47,6 +47,8 @@ class UserInDB(User):
password_hash = PasswordHash.recommended()
+DUMMY_HASH = password_hash.hash("dummypassword")
+
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
app = FastAPI()
@@ -69,6 +71,7 @@ def get_user(db, username: str):
def authenticate_user(fake_db, username: str, password: str):
user = get_user(fake_db, username)
if not user:
+ verify_password(password, DUMMY_HASH)
return False
if not verify_password(password, user.hashed_password):
return False
diff --git a/docs_src/security/tutorial004_py39.py b/docs_src/security/tutorial004_py39.py
deleted file mode 100644
index e67403d5d7..0000000000
--- a/docs_src/security/tutorial004_py39.py
+++ /dev/null
@@ -1,141 +0,0 @@
-from datetime import datetime, timedelta, timezone
-from typing import Union
-
-import jwt
-from fastapi import Depends, FastAPI, HTTPException, status
-from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
-from jwt.exceptions import InvalidTokenError
-from pwdlib import PasswordHash
-from pydantic import BaseModel
-
-# to get a string like this run:
-# openssl rand -hex 32
-SECRET_KEY = "09d25e094faa6ca2556c818166b7a9563b93f7099f6f0f4caa6cf63b88e8d3e7"
-ALGORITHM = "HS256"
-ACCESS_TOKEN_EXPIRE_MINUTES = 30
-
-
-fake_users_db = {
- "johndoe": {
- "username": "johndoe",
- "full_name": "John Doe",
- "email": "johndoe@example.com",
- "hashed_password": "$argon2id$v=19$m=65536,t=3,p=4$wagCPXjifgvUFBzq4hqe3w$CYaIb8sB+wtD+Vu/P4uod1+Qof8h+1g7bbDlBID48Rc",
- "disabled": False,
- }
-}
-
-
-class Token(BaseModel):
- access_token: str
- token_type: str
-
-
-class TokenData(BaseModel):
- username: Union[str, None] = None
-
-
-class User(BaseModel):
- username: str
- email: Union[str, None] = None
- full_name: Union[str, None] = None
- disabled: Union[bool, None] = None
-
-
-class UserInDB(User):
- hashed_password: str
-
-
-password_hash = PasswordHash.recommended()
-
-oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
-
-app = FastAPI()
-
-
-def verify_password(plain_password, hashed_password):
- return password_hash.verify(plain_password, hashed_password)
-
-
-def get_password_hash(password):
- return password_hash.hash(password)
-
-
-def get_user(db, username: str):
- if username in db:
- user_dict = db[username]
- return UserInDB(**user_dict)
-
-
-def authenticate_user(fake_db, username: str, password: str):
- user = get_user(fake_db, username)
- if not user:
- return False
- if not verify_password(password, user.hashed_password):
- return False
- return user
-
-
-def create_access_token(data: dict, expires_delta: Union[timedelta, None] = None):
- to_encode = data.copy()
- if expires_delta:
- expire = datetime.now(timezone.utc) + expires_delta
- else:
- expire = datetime.now(timezone.utc) + timedelta(minutes=15)
- to_encode.update({"exp": expire})
- encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
- return encoded_jwt
-
-
-async def get_current_user(token: str = Depends(oauth2_scheme)):
- credentials_exception = HTTPException(
- status_code=status.HTTP_401_UNAUTHORIZED,
- detail="Could not validate credentials",
- headers={"WWW-Authenticate": "Bearer"},
- )
- try:
- payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
- username = payload.get("sub")
- if username is None:
- raise credentials_exception
- token_data = TokenData(username=username)
- except InvalidTokenError:
- raise credentials_exception
- user = get_user(fake_users_db, username=token_data.username)
- if user is None:
- raise credentials_exception
- return user
-
-
-async def get_current_active_user(current_user: User = Depends(get_current_user)):
- if current_user.disabled:
- raise HTTPException(status_code=400, detail="Inactive user")
- return current_user
-
-
-@app.post("/token")
-async def login_for_access_token(
- form_data: OAuth2PasswordRequestForm = Depends(),
-) -> Token:
- user = authenticate_user(fake_users_db, form_data.username, form_data.password)
- if not user:
- raise HTTPException(
- status_code=status.HTTP_401_UNAUTHORIZED,
- detail="Incorrect username or password",
- headers={"WWW-Authenticate": "Bearer"},
- )
- access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
- access_token = create_access_token(
- data={"sub": user.username}, expires_delta=access_token_expires
- )
- return Token(access_token=access_token, token_type="bearer")
-
-
-@app.get("/users/me/")
-async def read_users_me(current_user: User = Depends(get_current_active_user)) -> User:
- return current_user
-
-
-@app.get("/users/me/items/")
-async def read_own_items(current_user: User = Depends(get_current_active_user)):
- return [{"item_id": "Foo", "owner": current_user.username}]
diff --git a/docs_src/security/tutorial005_an_py310.py b/docs_src/security/tutorial005_an_py310.py
index fef0ab71ca..9911723db7 100644
--- a/docs_src/security/tutorial005_an_py310.py
+++ b/docs_src/security/tutorial005_an_py310.py
@@ -60,6 +60,8 @@ class UserInDB(User):
password_hash = PasswordHash.recommended()
+DUMMY_HASH = password_hash.hash("dummypassword")
+
oauth2_scheme = OAuth2PasswordBearer(
tokenUrl="token",
scopes={"me": "Read information about the current user.", "items": "Read items."},
@@ -85,6 +87,7 @@ def get_user(db, username: str):
def authenticate_user(fake_db, username: str, password: str):
user = get_user(fake_db, username)
if not user:
+ verify_password(password, DUMMY_HASH)
return False
if not verify_password(password, user.hashed_password):
return False
diff --git a/docs_src/security/tutorial005_an_py39.py b/docs_src/security/tutorial005_an_py39.py
deleted file mode 100644
index 1aeba688a6..0000000000
--- a/docs_src/security/tutorial005_an_py39.py
+++ /dev/null
@@ -1,179 +0,0 @@
-from datetime import datetime, timedelta, timezone
-from typing import Annotated, Union
-
-import jwt
-from fastapi import Depends, FastAPI, HTTPException, Security, status
-from fastapi.security import (
- OAuth2PasswordBearer,
- OAuth2PasswordRequestForm,
- SecurityScopes,
-)
-from jwt.exceptions import InvalidTokenError
-from pwdlib import PasswordHash
-from pydantic import BaseModel, ValidationError
-
-# to get a string like this run:
-# openssl rand -hex 32
-SECRET_KEY = "09d25e094faa6ca2556c818166b7a9563b93f7099f6f0f4caa6cf63b88e8d3e7"
-ALGORITHM = "HS256"
-ACCESS_TOKEN_EXPIRE_MINUTES = 30
-
-
-fake_users_db = {
- "johndoe": {
- "username": "johndoe",
- "full_name": "John Doe",
- "email": "johndoe@example.com",
- "hashed_password": "$argon2id$v=19$m=65536,t=3,p=4$wagCPXjifgvUFBzq4hqe3w$CYaIb8sB+wtD+Vu/P4uod1+Qof8h+1g7bbDlBID48Rc",
- "disabled": False,
- },
- "alice": {
- "username": "alice",
- "full_name": "Alice Chains",
- "email": "alicechains@example.com",
- "hashed_password": "$argon2id$v=19$m=65536,t=3,p=4$g2/AV1zwopqUntPKJavBFw$BwpRGDCyUHLvHICnwijyX8ROGoiUPwNKZ7915MeYfCE",
- "disabled": True,
- },
-}
-
-
-class Token(BaseModel):
- access_token: str
- token_type: str
-
-
-class TokenData(BaseModel):
- username: Union[str, None] = None
- scopes: list[str] = []
-
-
-class User(BaseModel):
- username: str
- email: Union[str, None] = None
- full_name: Union[str, None] = None
- disabled: Union[bool, None] = None
-
-
-class UserInDB(User):
- hashed_password: str
-
-
-password_hash = PasswordHash.recommended()
-
-oauth2_scheme = OAuth2PasswordBearer(
- tokenUrl="token",
- scopes={"me": "Read information about the current user.", "items": "Read items."},
-)
-
-app = FastAPI()
-
-
-def verify_password(plain_password, hashed_password):
- return password_hash.verify(plain_password, hashed_password)
-
-
-def get_password_hash(password):
- return password_hash.hash(password)
-
-
-def get_user(db, username: str):
- if username in db:
- user_dict = db[username]
- return UserInDB(**user_dict)
-
-
-def authenticate_user(fake_db, username: str, password: str):
- user = get_user(fake_db, username)
- if not user:
- return False
- if not verify_password(password, user.hashed_password):
- return False
- return user
-
-
-def create_access_token(data: dict, expires_delta: Union[timedelta, None] = None):
- to_encode = data.copy()
- if expires_delta:
- expire = datetime.now(timezone.utc) + expires_delta
- else:
- expire = datetime.now(timezone.utc) + timedelta(minutes=15)
- to_encode.update({"exp": expire})
- encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
- return encoded_jwt
-
-
-async def get_current_user(
- security_scopes: SecurityScopes, token: Annotated[str, Depends(oauth2_scheme)]
-):
- if security_scopes.scopes:
- authenticate_value = f'Bearer scope="{security_scopes.scope_str}"'
- else:
- authenticate_value = "Bearer"
- credentials_exception = HTTPException(
- status_code=status.HTTP_401_UNAUTHORIZED,
- detail="Could not validate credentials",
- headers={"WWW-Authenticate": authenticate_value},
- )
- try:
- payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
- username = payload.get("sub")
- if username is None:
- raise credentials_exception
- scope: str = payload.get("scope", "")
- token_scopes = scope.split(" ")
- token_data = TokenData(scopes=token_scopes, username=username)
- except (InvalidTokenError, ValidationError):
- raise credentials_exception
- user = get_user(fake_users_db, username=token_data.username)
- if user is None:
- raise credentials_exception
- for scope in security_scopes.scopes:
- if scope not in token_data.scopes:
- raise HTTPException(
- status_code=status.HTTP_401_UNAUTHORIZED,
- detail="Not enough permissions",
- headers={"WWW-Authenticate": authenticate_value},
- )
- return user
-
-
-async def get_current_active_user(
- current_user: Annotated[User, Security(get_current_user, scopes=["me"])],
-):
- if current_user.disabled:
- raise HTTPException(status_code=400, detail="Inactive user")
- return current_user
-
-
-@app.post("/token")
-async def login_for_access_token(
- form_data: Annotated[OAuth2PasswordRequestForm, Depends()],
-) -> Token:
- user = authenticate_user(fake_users_db, form_data.username, form_data.password)
- if not user:
- raise HTTPException(status_code=400, detail="Incorrect username or password")
- access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
- access_token = create_access_token(
- data={"sub": user.username, "scope": " ".join(form_data.scopes)},
- expires_delta=access_token_expires,
- )
- return Token(access_token=access_token, token_type="bearer")
-
-
-@app.get("/users/me/")
-async def read_users_me(
- current_user: Annotated[User, Depends(get_current_active_user)],
-) -> User:
- return current_user
-
-
-@app.get("/users/me/items/")
-async def read_own_items(
- current_user: Annotated[User, Security(get_current_active_user, scopes=["items"])],
-):
- return [{"item_id": "Foo", "owner": current_user.username}]
-
-
-@app.get("/status/")
-async def read_system_status(current_user: Annotated[User, Depends(get_current_user)]):
- return {"status": "ok"}
diff --git a/docs_src/security/tutorial005_py310.py b/docs_src/security/tutorial005_py310.py
index 412fbf7984..710cdac329 100644
--- a/docs_src/security/tutorial005_py310.py
+++ b/docs_src/security/tutorial005_py310.py
@@ -59,6 +59,8 @@ class UserInDB(User):
password_hash = PasswordHash.recommended()
+DUMMY_HASH = password_hash.hash("dummypassword")
+
oauth2_scheme = OAuth2PasswordBearer(
tokenUrl="token",
scopes={"me": "Read information about the current user.", "items": "Read items."},
@@ -84,6 +86,7 @@ def get_user(db, username: str):
def authenticate_user(fake_db, username: str, password: str):
user = get_user(fake_db, username)
if not user:
+ verify_password(password, DUMMY_HASH)
return False
if not verify_password(password, user.hashed_password):
return False
diff --git a/docs_src/security/tutorial005_py39.py b/docs_src/security/tutorial005_py39.py
deleted file mode 100644
index 32280aa48b..0000000000
--- a/docs_src/security/tutorial005_py39.py
+++ /dev/null
@@ -1,177 +0,0 @@
-from datetime import datetime, timedelta, timezone
-from typing import Union
-
-import jwt
-from fastapi import Depends, FastAPI, HTTPException, Security, status
-from fastapi.security import (
- OAuth2PasswordBearer,
- OAuth2PasswordRequestForm,
- SecurityScopes,
-)
-from jwt.exceptions import InvalidTokenError
-from pwdlib import PasswordHash
-from pydantic import BaseModel, ValidationError
-
-# to get a string like this run:
-# openssl rand -hex 32
-SECRET_KEY = "09d25e094faa6ca2556c818166b7a9563b93f7099f6f0f4caa6cf63b88e8d3e7"
-ALGORITHM = "HS256"
-ACCESS_TOKEN_EXPIRE_MINUTES = 30
-
-
-fake_users_db = {
- "johndoe": {
- "username": "johndoe",
- "full_name": "John Doe",
- "email": "johndoe@example.com",
- "hashed_password": "$argon2id$v=19$m=65536,t=3,p=4$wagCPXjifgvUFBzq4hqe3w$CYaIb8sB+wtD+Vu/P4uod1+Qof8h+1g7bbDlBID48Rc",
- "disabled": False,
- },
- "alice": {
- "username": "alice",
- "full_name": "Alice Chains",
- "email": "alicechains@example.com",
- "hashed_password": "$argon2id$v=19$m=65536,t=3,p=4$g2/AV1zwopqUntPKJavBFw$BwpRGDCyUHLvHICnwijyX8ROGoiUPwNKZ7915MeYfCE",
- "disabled": True,
- },
-}
-
-
-class Token(BaseModel):
- access_token: str
- token_type: str
-
-
-class TokenData(BaseModel):
- username: Union[str, None] = None
- scopes: list[str] = []
-
-
-class User(BaseModel):
- username: str
- email: Union[str, None] = None
- full_name: Union[str, None] = None
- disabled: Union[bool, None] = None
-
-
-class UserInDB(User):
- hashed_password: str
-
-
-password_hash = PasswordHash.recommended()
-
-oauth2_scheme = OAuth2PasswordBearer(
- tokenUrl="token",
- scopes={"me": "Read information about the current user.", "items": "Read items."},
-)
-
-app = FastAPI()
-
-
-def verify_password(plain_password, hashed_password):
- return password_hash.verify(plain_password, hashed_password)
-
-
-def get_password_hash(password):
- return password_hash.hash(password)
-
-
-def get_user(db, username: str):
- if username in db:
- user_dict = db[username]
- return UserInDB(**user_dict)
-
-
-def authenticate_user(fake_db, username: str, password: str):
- user = get_user(fake_db, username)
- if not user:
- return False
- if not verify_password(password, user.hashed_password):
- return False
- return user
-
-
-def create_access_token(data: dict, expires_delta: Union[timedelta, None] = None):
- to_encode = data.copy()
- if expires_delta:
- expire = datetime.now(timezone.utc) + expires_delta
- else:
- expire = datetime.now(timezone.utc) + timedelta(minutes=15)
- to_encode.update({"exp": expire})
- encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
- return encoded_jwt
-
-
-async def get_current_user(
- security_scopes: SecurityScopes, token: str = Depends(oauth2_scheme)
-):
- if security_scopes.scopes:
- authenticate_value = f'Bearer scope="{security_scopes.scope_str}"'
- else:
- authenticate_value = "Bearer"
- credentials_exception = HTTPException(
- status_code=status.HTTP_401_UNAUTHORIZED,
- detail="Could not validate credentials",
- headers={"WWW-Authenticate": authenticate_value},
- )
- try:
- payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
- username: str = payload.get("sub")
- if username is None:
- raise credentials_exception
- scope: str = payload.get("scope", "")
- token_scopes = scope.split(" ")
- token_data = TokenData(scopes=token_scopes, username=username)
- except (InvalidTokenError, ValidationError):
- raise credentials_exception
- user = get_user(fake_users_db, username=token_data.username)
- if user is None:
- raise credentials_exception
- for scope in security_scopes.scopes:
- if scope not in token_data.scopes:
- raise HTTPException(
- status_code=status.HTTP_401_UNAUTHORIZED,
- detail="Not enough permissions",
- headers={"WWW-Authenticate": authenticate_value},
- )
- return user
-
-
-async def get_current_active_user(
- current_user: User = Security(get_current_user, scopes=["me"]),
-):
- if current_user.disabled:
- raise HTTPException(status_code=400, detail="Inactive user")
- return current_user
-
-
-@app.post("/token")
-async def login_for_access_token(
- form_data: OAuth2PasswordRequestForm = Depends(),
-) -> Token:
- user = authenticate_user(fake_users_db, form_data.username, form_data.password)
- if not user:
- raise HTTPException(status_code=400, detail="Incorrect username or password")
- access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
- access_token = create_access_token(
- data={"sub": user.username, "scope": " ".join(form_data.scopes)},
- expires_delta=access_token_expires,
- )
- return Token(access_token=access_token, token_type="bearer")
-
-
-@app.get("/users/me/")
-async def read_users_me(current_user: User = Depends(get_current_active_user)) -> User:
- return current_user
-
-
-@app.get("/users/me/items/")
-async def read_own_items(
- current_user: User = Security(get_current_active_user, scopes=["items"]),
-):
- return [{"item_id": "Foo", "owner": current_user.username}]
-
-
-@app.get("/status/")
-async def read_system_status(current_user: User = Depends(get_current_user)):
- return {"status": "ok"}
diff --git a/docs_src/security/tutorial006_an_py39.py b/docs_src/security/tutorial006_an_py310.py
similarity index 100%
rename from docs_src/security/tutorial006_an_py39.py
rename to docs_src/security/tutorial006_an_py310.py
diff --git a/docs_src/security/tutorial006_py39.py b/docs_src/security/tutorial006_py310.py
similarity index 100%
rename from docs_src/security/tutorial006_py39.py
rename to docs_src/security/tutorial006_py310.py
diff --git a/docs_src/security/tutorial007_an_py39.py b/docs_src/security/tutorial007_an_py310.py
similarity index 100%
rename from docs_src/security/tutorial007_an_py39.py
rename to docs_src/security/tutorial007_an_py310.py
diff --git a/docs_src/security/tutorial007_py39.py b/docs_src/security/tutorial007_py310.py
similarity index 100%
rename from docs_src/security/tutorial007_py39.py
rename to docs_src/security/tutorial007_py310.py
diff --git a/docs_src/separate_openapi_schemas/tutorial001_py39.py b/docs_src/separate_openapi_schemas/tutorial001_py39.py
deleted file mode 100644
index 63cffd1e30..0000000000
--- a/docs_src/separate_openapi_schemas/tutorial001_py39.py
+++ /dev/null
@@ -1,28 +0,0 @@
-from typing import Optional
-
-from fastapi import FastAPI
-from pydantic import BaseModel
-
-
-class Item(BaseModel):
- name: str
- description: Optional[str] = None
-
-
-app = FastAPI()
-
-
-@app.post("/items/")
-def create_item(item: Item):
- return item
-
-
-@app.get("/items/")
-def read_items() -> list[Item]:
- return [
- Item(
- name="Portal Gun",
- description="Device to travel through the multi-rick-verse",
- ),
- Item(name="Plumbus"),
- ]
diff --git a/docs_src/separate_openapi_schemas/tutorial002_py39.py b/docs_src/separate_openapi_schemas/tutorial002_py39.py
deleted file mode 100644
index 50d997d92a..0000000000
--- a/docs_src/separate_openapi_schemas/tutorial002_py39.py
+++ /dev/null
@@ -1,28 +0,0 @@
-from typing import Optional
-
-from fastapi import FastAPI
-from pydantic import BaseModel
-
-
-class Item(BaseModel):
- name: str
- description: Optional[str] = None
-
-
-app = FastAPI(separate_input_output_schemas=False)
-
-
-@app.post("/items/")
-def create_item(item: Item):
- return item
-
-
-@app.get("/items/")
-def read_items() -> list[Item]:
- return [
- Item(
- name="Portal Gun",
- description="Device to travel through the multi-rick-verse",
- ),
- Item(name="Plumbus"),
- ]
diff --git a/docs_src/bigger_applications/app_an_py39/internal/__init__.py b/docs_src/settings/app01_py310/__init__.py
similarity index 100%
rename from docs_src/bigger_applications/app_an_py39/internal/__init__.py
rename to docs_src/settings/app01_py310/__init__.py
diff --git a/docs_src/settings/app01_py39/config.py b/docs_src/settings/app01_py310/config.py
similarity index 100%
rename from docs_src/settings/app01_py39/config.py
rename to docs_src/settings/app01_py310/config.py
diff --git a/docs_src/settings/app01_py39/main.py b/docs_src/settings/app01_py310/main.py
similarity index 100%
rename from docs_src/settings/app01_py39/main.py
rename to docs_src/settings/app01_py310/main.py
diff --git a/docs_src/settings/app01_py39/__init__.py b/docs_src/settings/app01_py39/__init__.py
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/docs_src/bigger_applications/app_an_py39/routers/__init__.py b/docs_src/settings/app02_an_py310/__init__.py
similarity index 100%
rename from docs_src/bigger_applications/app_an_py39/routers/__init__.py
rename to docs_src/settings/app02_an_py310/__init__.py
diff --git a/docs_src/settings/app02_an_py39/config.py b/docs_src/settings/app02_an_py310/config.py
similarity index 100%
rename from docs_src/settings/app02_an_py39/config.py
rename to docs_src/settings/app02_an_py310/config.py
diff --git a/docs_src/settings/app02_an_py39/main.py b/docs_src/settings/app02_an_py310/main.py
similarity index 100%
rename from docs_src/settings/app02_an_py39/main.py
rename to docs_src/settings/app02_an_py310/main.py
diff --git a/docs_src/settings/app02_an_py39/test_main.py b/docs_src/settings/app02_an_py310/test_main.py
similarity index 100%
rename from docs_src/settings/app02_an_py39/test_main.py
rename to docs_src/settings/app02_an_py310/test_main.py
diff --git a/docs_src/settings/app02_an_py39/__init__.py b/docs_src/settings/app02_an_py39/__init__.py
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/docs_src/bigger_applications/app_py39/__init__.py b/docs_src/settings/app02_py310/__init__.py
similarity index 100%
rename from docs_src/bigger_applications/app_py39/__init__.py
rename to docs_src/settings/app02_py310/__init__.py
diff --git a/docs_src/settings/app02_py39/config.py b/docs_src/settings/app02_py310/config.py
similarity index 100%
rename from docs_src/settings/app02_py39/config.py
rename to docs_src/settings/app02_py310/config.py
diff --git a/docs_src/settings/app02_py39/main.py b/docs_src/settings/app02_py310/main.py
similarity index 100%
rename from docs_src/settings/app02_py39/main.py
rename to docs_src/settings/app02_py310/main.py
diff --git a/docs_src/settings/app02_py39/test_main.py b/docs_src/settings/app02_py310/test_main.py
similarity index 100%
rename from docs_src/settings/app02_py39/test_main.py
rename to docs_src/settings/app02_py310/test_main.py
diff --git a/docs_src/settings/app02_py39/__init__.py b/docs_src/settings/app02_py39/__init__.py
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/docs_src/bigger_applications/app_py39/internal/__init__.py b/docs_src/settings/app03_an_py310/__init__.py
similarity index 100%
rename from docs_src/bigger_applications/app_py39/internal/__init__.py
rename to docs_src/settings/app03_an_py310/__init__.py
diff --git a/docs_src/settings/app03_an_py39/config.py b/docs_src/settings/app03_an_py310/config.py
similarity index 100%
rename from docs_src/settings/app03_an_py39/config.py
rename to docs_src/settings/app03_an_py310/config.py
diff --git a/docs_src/settings/app03_an_py39/main.py b/docs_src/settings/app03_an_py310/main.py
similarity index 100%
rename from docs_src/settings/app03_an_py39/main.py
rename to docs_src/settings/app03_an_py310/main.py
diff --git a/docs_src/settings/app03_an_py39/__init__.py b/docs_src/settings/app03_an_py39/__init__.py
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/docs_src/settings/app03_an_py39/config_pv1.py b/docs_src/settings/app03_an_py39/config_pv1.py
deleted file mode 100644
index 7ae66ef77c..0000000000
--- a/docs_src/settings/app03_an_py39/config_pv1.py
+++ /dev/null
@@ -1,10 +0,0 @@
-from pydantic.v1 import BaseSettings
-
-
-class Settings(BaseSettings):
- app_name: str = "Awesome API"
- admin_email: str
- items_per_user: int = 50
-
- class Config:
- env_file = ".env"
diff --git a/docs_src/bigger_applications/app_py39/routers/__init__.py b/docs_src/settings/app03_py310/__init__.py
similarity index 100%
rename from docs_src/bigger_applications/app_py39/routers/__init__.py
rename to docs_src/settings/app03_py310/__init__.py
diff --git a/docs_src/settings/app03_py39/config.py b/docs_src/settings/app03_py310/config.py
similarity index 100%
rename from docs_src/settings/app03_py39/config.py
rename to docs_src/settings/app03_py310/config.py
diff --git a/docs_src/settings/app03_py39/main.py b/docs_src/settings/app03_py310/main.py
similarity index 100%
rename from docs_src/settings/app03_py39/main.py
rename to docs_src/settings/app03_py310/main.py
diff --git a/docs_src/settings/app03_py39/__init__.py b/docs_src/settings/app03_py39/__init__.py
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/docs_src/settings/app03_py39/config_pv1.py b/docs_src/settings/app03_py39/config_pv1.py
deleted file mode 100644
index 7ae66ef77c..0000000000
--- a/docs_src/settings/app03_py39/config_pv1.py
+++ /dev/null
@@ -1,10 +0,0 @@
-from pydantic.v1 import BaseSettings
-
-
-class Settings(BaseSettings):
- app_name: str = "Awesome API"
- admin_email: str
- items_per_user: int = 50
-
- class Config:
- env_file = ".env"
diff --git a/docs_src/settings/tutorial001_pv1_py39.py b/docs_src/settings/tutorial001_pv1_py39.py
deleted file mode 100644
index 20ad2bbf62..0000000000
--- a/docs_src/settings/tutorial001_pv1_py39.py
+++ /dev/null
@@ -1,21 +0,0 @@
-from fastapi import FastAPI
-from pydantic.v1 import BaseSettings
-
-
-class Settings(BaseSettings):
- app_name: str = "Awesome API"
- admin_email: str
- items_per_user: int = 50
-
-
-settings = Settings()
-app = FastAPI()
-
-
-@app.get("/info")
-async def info():
- return {
- "app_name": settings.app_name,
- "admin_email": settings.admin_email,
- "items_per_user": settings.items_per_user,
- }
diff --git a/docs_src/settings/tutorial001_py39.py b/docs_src/settings/tutorial001_py310.py
similarity index 100%
rename from docs_src/settings/tutorial001_py39.py
rename to docs_src/settings/tutorial001_py310.py
diff --git a/docs_src/sql_databases/tutorial001_an_py39.py b/docs_src/sql_databases/tutorial001_an_py39.py
deleted file mode 100644
index 5958927461..0000000000
--- a/docs_src/sql_databases/tutorial001_an_py39.py
+++ /dev/null
@@ -1,73 +0,0 @@
-from typing import Annotated, Union
-
-from fastapi import Depends, FastAPI, HTTPException, Query
-from sqlmodel import Field, Session, SQLModel, create_engine, select
-
-
-class Hero(SQLModel, table=True):
- id: Union[int, None] = Field(default=None, primary_key=True)
- name: str = Field(index=True)
- age: Union[int, None] = Field(default=None, index=True)
- secret_name: str
-
-
-sqlite_file_name = "database.db"
-sqlite_url = f"sqlite:///{sqlite_file_name}"
-
-connect_args = {"check_same_thread": False}
-engine = create_engine(sqlite_url, connect_args=connect_args)
-
-
-def create_db_and_tables():
- SQLModel.metadata.create_all(engine)
-
-
-def get_session():
- with Session(engine) as session:
- yield session
-
-
-SessionDep = Annotated[Session, Depends(get_session)]
-
-app = FastAPI()
-
-
-@app.on_event("startup")
-def on_startup():
- create_db_and_tables()
-
-
-@app.post("/heroes/")
-def create_hero(hero: Hero, session: SessionDep) -> Hero:
- session.add(hero)
- session.commit()
- session.refresh(hero)
- return hero
-
-
-@app.get("/heroes/")
-def read_heroes(
- session: SessionDep,
- offset: int = 0,
- limit: Annotated[int, Query(le=100)] = 100,
-) -> list[Hero]:
- heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
- return heroes
-
-
-@app.get("/heroes/{hero_id}")
-def read_hero(hero_id: int, session: SessionDep) -> Hero:
- hero = session.get(Hero, hero_id)
- if not hero:
- raise HTTPException(status_code=404, detail="Hero not found")
- return hero
-
-
-@app.delete("/heroes/{hero_id}")
-def delete_hero(hero_id: int, session: SessionDep):
- hero = session.get(Hero, hero_id)
- if not hero:
- raise HTTPException(status_code=404, detail="Hero not found")
- session.delete(hero)
- session.commit()
- return {"ok": True}
diff --git a/docs_src/sql_databases/tutorial001_py39.py b/docs_src/sql_databases/tutorial001_py39.py
deleted file mode 100644
index 410a52d0c0..0000000000
--- a/docs_src/sql_databases/tutorial001_py39.py
+++ /dev/null
@@ -1,71 +0,0 @@
-from typing import Union
-
-from fastapi import Depends, FastAPI, HTTPException, Query
-from sqlmodel import Field, Session, SQLModel, create_engine, select
-
-
-class Hero(SQLModel, table=True):
- id: Union[int, None] = Field(default=None, primary_key=True)
- name: str = Field(index=True)
- age: Union[int, None] = Field(default=None, index=True)
- secret_name: str
-
-
-sqlite_file_name = "database.db"
-sqlite_url = f"sqlite:///{sqlite_file_name}"
-
-connect_args = {"check_same_thread": False}
-engine = create_engine(sqlite_url, connect_args=connect_args)
-
-
-def create_db_and_tables():
- SQLModel.metadata.create_all(engine)
-
-
-def get_session():
- with Session(engine) as session:
- yield session
-
-
-app = FastAPI()
-
-
-@app.on_event("startup")
-def on_startup():
- create_db_and_tables()
-
-
-@app.post("/heroes/")
-def create_hero(hero: Hero, session: Session = Depends(get_session)) -> Hero:
- session.add(hero)
- session.commit()
- session.refresh(hero)
- return hero
-
-
-@app.get("/heroes/")
-def read_heroes(
- session: Session = Depends(get_session),
- offset: int = 0,
- limit: int = Query(default=100, le=100),
-) -> list[Hero]:
- heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
- return heroes
-
-
-@app.get("/heroes/{hero_id}")
-def read_hero(hero_id: int, session: Session = Depends(get_session)) -> Hero:
- hero = session.get(Hero, hero_id)
- if not hero:
- raise HTTPException(status_code=404, detail="Hero not found")
- return hero
-
-
-@app.delete("/heroes/{hero_id}")
-def delete_hero(hero_id: int, session: Session = Depends(get_session)):
- hero = session.get(Hero, hero_id)
- if not hero:
- raise HTTPException(status_code=404, detail="Hero not found")
- session.delete(hero)
- session.commit()
- return {"ok": True}
diff --git a/docs_src/sql_databases/tutorial002_an_py39.py b/docs_src/sql_databases/tutorial002_an_py39.py
deleted file mode 100644
index a8a0721ff6..0000000000
--- a/docs_src/sql_databases/tutorial002_an_py39.py
+++ /dev/null
@@ -1,103 +0,0 @@
-from typing import Annotated, Union
-
-from fastapi import Depends, FastAPI, HTTPException, Query
-from sqlmodel import Field, Session, SQLModel, create_engine, select
-
-
-class HeroBase(SQLModel):
- name: str = Field(index=True)
- age: Union[int, None] = Field(default=None, index=True)
-
-
-class Hero(HeroBase, table=True):
- id: Union[int, None] = Field(default=None, primary_key=True)
- secret_name: str
-
-
-class HeroPublic(HeroBase):
- id: int
-
-
-class HeroCreate(HeroBase):
- secret_name: str
-
-
-class HeroUpdate(HeroBase):
- name: Union[str, None] = None
- age: Union[int, None] = None
- secret_name: Union[str, None] = None
-
-
-sqlite_file_name = "database.db"
-sqlite_url = f"sqlite:///{sqlite_file_name}"
-
-connect_args = {"check_same_thread": False}
-engine = create_engine(sqlite_url, connect_args=connect_args)
-
-
-def create_db_and_tables():
- SQLModel.metadata.create_all(engine)
-
-
-def get_session():
- with Session(engine) as session:
- yield session
-
-
-SessionDep = Annotated[Session, Depends(get_session)]
-app = FastAPI()
-
-
-@app.on_event("startup")
-def on_startup():
- create_db_and_tables()
-
-
-@app.post("/heroes/", response_model=HeroPublic)
-def create_hero(hero: HeroCreate, session: SessionDep):
- db_hero = Hero.model_validate(hero)
- session.add(db_hero)
- session.commit()
- session.refresh(db_hero)
- return db_hero
-
-
-@app.get("/heroes/", response_model=list[HeroPublic])
-def read_heroes(
- session: SessionDep,
- offset: int = 0,
- limit: Annotated[int, Query(le=100)] = 100,
-):
- heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
- return heroes
-
-
-@app.get("/heroes/{hero_id}", response_model=HeroPublic)
-def read_hero(hero_id: int, session: SessionDep):
- hero = session.get(Hero, hero_id)
- if not hero:
- raise HTTPException(status_code=404, detail="Hero not found")
- return hero
-
-
-@app.patch("/heroes/{hero_id}", response_model=HeroPublic)
-def update_hero(hero_id: int, hero: HeroUpdate, session: SessionDep):
- hero_db = session.get(Hero, hero_id)
- if not hero_db:
- raise HTTPException(status_code=404, detail="Hero not found")
- hero_data = hero.model_dump(exclude_unset=True)
- hero_db.sqlmodel_update(hero_data)
- session.add(hero_db)
- session.commit()
- session.refresh(hero_db)
- return hero_db
-
-
-@app.delete("/heroes/{hero_id}")
-def delete_hero(hero_id: int, session: SessionDep):
- hero = session.get(Hero, hero_id)
- if not hero:
- raise HTTPException(status_code=404, detail="Hero not found")
- session.delete(hero)
- session.commit()
- return {"ok": True}
diff --git a/docs_src/sql_databases/tutorial002_py39.py b/docs_src/sql_databases/tutorial002_py39.py
deleted file mode 100644
index d8f5dd0901..0000000000
--- a/docs_src/sql_databases/tutorial002_py39.py
+++ /dev/null
@@ -1,104 +0,0 @@
-from typing import Union
-
-from fastapi import Depends, FastAPI, HTTPException, Query
-from sqlmodel import Field, Session, SQLModel, create_engine, select
-
-
-class HeroBase(SQLModel):
- name: str = Field(index=True)
- age: Union[int, None] = Field(default=None, index=True)
-
-
-class Hero(HeroBase, table=True):
- id: Union[int, None] = Field(default=None, primary_key=True)
- secret_name: str
-
-
-class HeroPublic(HeroBase):
- id: int
-
-
-class HeroCreate(HeroBase):
- secret_name: str
-
-
-class HeroUpdate(HeroBase):
- name: Union[str, None] = None
- age: Union[int, None] = None
- secret_name: Union[str, None] = None
-
-
-sqlite_file_name = "database.db"
-sqlite_url = f"sqlite:///{sqlite_file_name}"
-
-connect_args = {"check_same_thread": False}
-engine = create_engine(sqlite_url, connect_args=connect_args)
-
-
-def create_db_and_tables():
- SQLModel.metadata.create_all(engine)
-
-
-def get_session():
- with Session(engine) as session:
- yield session
-
-
-app = FastAPI()
-
-
-@app.on_event("startup")
-def on_startup():
- create_db_and_tables()
-
-
-@app.post("/heroes/", response_model=HeroPublic)
-def create_hero(hero: HeroCreate, session: Session = Depends(get_session)):
- db_hero = Hero.model_validate(hero)
- session.add(db_hero)
- session.commit()
- session.refresh(db_hero)
- return db_hero
-
-
-@app.get("/heroes/", response_model=list[HeroPublic])
-def read_heroes(
- session: Session = Depends(get_session),
- offset: int = 0,
- limit: int = Query(default=100, le=100),
-):
- heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
- return heroes
-
-
-@app.get("/heroes/{hero_id}", response_model=HeroPublic)
-def read_hero(hero_id: int, session: Session = Depends(get_session)):
- hero = session.get(Hero, hero_id)
- if not hero:
- raise HTTPException(status_code=404, detail="Hero not found")
- return hero
-
-
-@app.patch("/heroes/{hero_id}", response_model=HeroPublic)
-def update_hero(
- hero_id: int, hero: HeroUpdate, session: Session = Depends(get_session)
-):
- hero_db = session.get(Hero, hero_id)
- if not hero_db:
- raise HTTPException(status_code=404, detail="Hero not found")
- hero_data = hero.model_dump(exclude_unset=True)
- hero_db.sqlmodel_update(hero_data)
- session.add(hero_db)
- session.commit()
- session.refresh(hero_db)
- return hero_db
-
-
-@app.delete("/heroes/{hero_id}")
-def delete_hero(hero_id: int, session: Session = Depends(get_session)):
- hero = session.get(Hero, hero_id)
- if not hero:
- raise HTTPException(status_code=404, detail="Hero not found")
- session.delete(hero)
- session.commit()
- return {"ok": True}
diff --git a/docs_src/static_files/tutorial001_py39.py b/docs_src/static_files/tutorial001_py310.py
similarity index 100%
rename from docs_src/static_files/tutorial001_py39.py
rename to docs_src/static_files/tutorial001_py310.py
diff --git a/docs_src/sub_applications/tutorial001_py39.py b/docs_src/sub_applications/tutorial001_py310.py
similarity index 100%
rename from docs_src/sub_applications/tutorial001_py39.py
rename to docs_src/sub_applications/tutorial001_py310.py
diff --git a/docs_src/templates/tutorial001_py39.py b/docs_src/templates/tutorial001_py310.py
similarity index 100%
rename from docs_src/templates/tutorial001_py39.py
rename to docs_src/templates/tutorial001_py310.py
diff --git a/docs_src/using_request_directly/tutorial001_py39.py b/docs_src/using_request_directly/tutorial001_py310.py
similarity index 100%
rename from docs_src/using_request_directly/tutorial001_py39.py
rename to docs_src/using_request_directly/tutorial001_py310.py
diff --git a/docs_src/websockets/tutorial001_py39.py b/docs_src/websockets/tutorial001_py310.py
similarity index 100%
rename from docs_src/websockets/tutorial001_py39.py
rename to docs_src/websockets/tutorial001_py310.py
diff --git a/docs_src/websockets/tutorial002_an_py39.py b/docs_src/websockets/tutorial002_an_py39.py
deleted file mode 100644
index 606d355fe1..0000000000
--- a/docs_src/websockets/tutorial002_an_py39.py
+++ /dev/null
@@ -1,92 +0,0 @@
-from typing import Annotated, Union
-
-from fastapi import (
- Cookie,
- Depends,
- FastAPI,
- Query,
- WebSocket,
- WebSocketException,
- status,
-)
-from fastapi.responses import HTMLResponse
-
-app = FastAPI()
-
-html = """
-
-
-
-
Chat
-
-
-
WebSocket Chat
-
-
-
-
-
-"""
-
-
-@app.get("/")
-async def get():
- return HTMLResponse(html)
-
-
-async def get_cookie_or_token(
- websocket: WebSocket,
- session: Annotated[Union[str, None], Cookie()] = None,
- token: Annotated[Union[str, None], Query()] = None,
-):
- if session is None and token is None:
- raise WebSocketException(code=status.WS_1008_POLICY_VIOLATION)
- return session or token
-
-
-@app.websocket("/items/{item_id}/ws")
-async def websocket_endpoint(
- *,
- websocket: WebSocket,
- item_id: str,
- q: Union[int, None] = None,
- cookie_or_token: Annotated[str, Depends(get_cookie_or_token)],
-):
- await websocket.accept()
- while True:
- data = await websocket.receive_text()
- await websocket.send_text(
- f"Session cookie or query token value is: {cookie_or_token}"
- )
- if q is not None:
- await websocket.send_text(f"Query parameter q is: {q}")
- await websocket.send_text(f"Message text was: {data}, for item ID: {item_id}")
diff --git a/docs_src/websockets/tutorial002_py39.py b/docs_src/websockets/tutorial002_py39.py
deleted file mode 100644
index cab749e4db..0000000000
--- a/docs_src/websockets/tutorial002_py39.py
+++ /dev/null
@@ -1,91 +0,0 @@
-from typing import Union
-
-from fastapi import (
- Cookie,
- Depends,
- FastAPI,
- Query,
- WebSocket,
- WebSocketException,
- status,
-)
-from fastapi.responses import HTMLResponse
-
-app = FastAPI()
-
-html = """
-
-
-
-
Chat
-
-
-
WebSocket Chat
-
-
-
-
-
-"""
-
-
-@app.get("/")
-async def get():
- return HTMLResponse(html)
-
-
-async def get_cookie_or_token(
- websocket: WebSocket,
- session: Union[str, None] = Cookie(default=None),
- token: Union[str, None] = Query(default=None),
-):
- if session is None and token is None:
- raise WebSocketException(code=status.WS_1008_POLICY_VIOLATION)
- return session or token
-
-
-@app.websocket("/items/{item_id}/ws")
-async def websocket_endpoint(
- websocket: WebSocket,
- item_id: str,
- q: Union[int, None] = None,
- cookie_or_token: str = Depends(get_cookie_or_token),
-):
- await websocket.accept()
- while True:
- data = await websocket.receive_text()
- await websocket.send_text(
- f"Session cookie or query token value is: {cookie_or_token}"
- )
- if q is not None:
- await websocket.send_text(f"Query parameter q is: {q}")
- await websocket.send_text(f"Message text was: {data}, for item ID: {item_id}")
diff --git a/docs_src/websockets/tutorial003_py39.py b/docs_src/websockets/tutorial003_py310.py
similarity index 100%
rename from docs_src/websockets/tutorial003_py39.py
rename to docs_src/websockets/tutorial003_py310.py
diff --git a/docs_src/wsgi/tutorial001_py39.py b/docs_src/wsgi/tutorial001_py310.py
similarity index 100%
rename from docs_src/wsgi/tutorial001_py39.py
rename to docs_src/wsgi/tutorial001_py310.py
diff --git a/fastapi-slim/README.md b/fastapi-slim/README.md
new file mode 100644
index 0000000000..e378a9c8c2
--- /dev/null
+++ b/fastapi-slim/README.md
@@ -0,0 +1,54 @@
+
+
+
+
+ FastAPI framework, high performance, easy to learn, fast to code, ready for production
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+---
+
+**Documentation**:
https://fastapi.tiangolo.com
+
+**Source Code**:
https://github.com/fastapi/fastapi
+
+---
+
+FastAPI is a modern, fast (high-performance), web framework for building APIs with Python based on standard Python type hints.
+
+## `fastapi-slim`
+
+⚠️ Do not install this package. ⚠️
+
+This package, `fastapi-slim`, does nothing other than depend on `fastapi`.
+
+All the functionality has been integrated into `fastapi`.
+
+The only reason this package exists is as a migration path for old projects that used to depend on `fastapi-slim`, so that they can get the latest version of `fastapi`.
+
+You **should not** install this package.
+
+Install instead:
+
+```bash
+pip install fastapi
+```
+
+This package is deprecated and will stop receiving any updates and published versions.
+
+## License
+
+This project is licensed under the terms of the MIT license.
diff --git a/fastapi/__init__.py b/fastapi/__init__.py
index 95e57e2eba..de5a0be382 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.128.6"
+__version__ = "0.129.0"
from starlette import status as status
diff --git a/fastapi/_compat/shared.py b/fastapi/_compat/shared.py
index c009da8fdc..9d76dabe69 100644
--- a/fastapi/_compat/shared.py
+++ b/fastapi/_compat/shared.py
@@ -1,4 +1,3 @@
-import sys
import types
import typing
import warnings
@@ -8,27 +7,26 @@ from dataclasses import is_dataclass
from typing import (
Annotated,
Any,
+ TypeGuard,
TypeVar,
Union,
+ get_args,
+ get_origin,
)
from fastapi.types import UnionType
from pydantic import BaseModel
from pydantic.version import VERSION as PYDANTIC_VERSION
from starlette.datastructures import UploadFile
-from typing_extensions import TypeGuard, get_args, get_origin
_T = TypeVar("_T")
# Copy from Pydantic: pydantic/_internal/_typing_extra.py
-if sys.version_info < (3, 10):
- WithArgsTypes: tuple[Any, ...] = (typing._GenericAlias, types.GenericAlias) # type: ignore[attr-defined]
-else:
- WithArgsTypes: tuple[Any, ...] = (
- typing._GenericAlias, # type: ignore[attr-defined]
- types.GenericAlias,
- types.UnionType,
- ) # pyright: ignore[reportAttributeAccessIssue]
+WithArgsTypes: tuple[Any, ...] = (
+ typing._GenericAlias, # type: ignore[attr-defined]
+ types.GenericAlias,
+ types.UnionType,
+) # pyright: ignore[reportAttributeAccessIssue]
PYDANTIC_VERSION_MINOR_TUPLE = tuple(int(x) for x in PYDANTIC_VERSION.split(".")[:2])
@@ -47,7 +45,7 @@ sequence_types: tuple[type[Any], ...] = tuple(sequence_annotation_to_type.keys()
# Copy of Pydantic: pydantic/_internal/_utils.py with added TypeGuard
def lenient_issubclass(
- cls: Any, class_or_tuple: Union[type[_T], tuple[type[_T], ...], None]
+ cls: Any, class_or_tuple: type[_T] | tuple[type[_T], ...] | None
) -> TypeGuard[type[_T]]:
try:
return isinstance(cls, type) and issubclass(cls, class_or_tuple) # type: ignore[arg-type]
@@ -57,13 +55,13 @@ def lenient_issubclass(
raise # pragma: no cover
-def _annotation_is_sequence(annotation: Union[type[Any], None]) -> bool:
+def _annotation_is_sequence(annotation: type[Any] | None) -> bool:
if lenient_issubclass(annotation, (str, bytes)):
return False
return lenient_issubclass(annotation, sequence_types)
-def field_annotation_is_sequence(annotation: Union[type[Any], None]) -> bool:
+def field_annotation_is_sequence(annotation: type[Any] | None) -> bool:
origin = get_origin(annotation)
if origin is Union or origin is UnionType:
for arg in get_args(annotation):
@@ -79,7 +77,7 @@ def value_is_sequence(value: Any) -> bool:
return isinstance(value, sequence_types) and not isinstance(value, (str, bytes))
-def _annotation_is_complex(annotation: Union[type[Any], None]) -> bool:
+def _annotation_is_complex(annotation: type[Any] | None) -> bool:
return (
lenient_issubclass(annotation, (BaseModel, Mapping, UploadFile))
or _annotation_is_sequence(annotation)
@@ -87,7 +85,7 @@ def _annotation_is_complex(annotation: Union[type[Any], None]) -> bool:
)
-def field_annotation_is_complex(annotation: Union[type[Any], None]) -> bool:
+def field_annotation_is_complex(annotation: type[Any] | None) -> bool:
origin = get_origin(annotation)
if origin is Union or origin is UnionType:
return any(field_annotation_is_complex(arg) for arg in get_args(annotation))
@@ -108,7 +106,7 @@ def field_annotation_is_scalar(annotation: Any) -> bool:
return annotation is Ellipsis or not field_annotation_is_complex(annotation)
-def field_annotation_is_scalar_sequence(annotation: Union[type[Any], None]) -> bool:
+def field_annotation_is_scalar_sequence(annotation: type[Any] | None) -> bool:
origin = get_origin(annotation)
if origin is Union or origin is UnionType:
at_least_one_scalar_sequence = False
diff --git a/fastapi/_compat/v2.py b/fastapi/_compat/v2.py
index 87b9fb47fa..b83bc1b55b 100644
--- a/fastapi/_compat/v2.py
+++ b/fastapi/_compat/v2.py
@@ -8,8 +8,11 @@ from functools import lru_cache
from typing import (
Annotated,
Any,
+ Literal,
Union,
cast,
+ get_args,
+ get_origin,
)
from fastapi._compat import lenient_issubclass, shared
@@ -32,7 +35,6 @@ from pydantic_core import Url as Url
from pydantic_core.core_schema import (
with_info_plain_validator_function as with_info_plain_validator_function,
)
-from typing_extensions import Literal, get_args, get_origin
RequiredParam = PydanticUndefined
Undefined = PydanticUndefined
@@ -83,7 +85,7 @@ class ModelField:
field_info: FieldInfo
name: str
mode: Literal["validation", "serialization"] = "validation"
- config: Union[ConfigDict, None] = None
+ config: ConfigDict | None = None
@property
def alias(self) -> str:
@@ -91,14 +93,14 @@ class ModelField:
return a if a is not None else self.name
@property
- def validation_alias(self) -> Union[str, None]:
+ def validation_alias(self) -> str | None:
va = self.field_info.validation_alias
if isinstance(va, str) and va:
return va
return None
@property
- def serialization_alias(self) -> Union[str, None]:
+ def serialization_alias(self) -> str | None:
sa = self.field_info.serialization_alias
return sa or None
@@ -143,7 +145,7 @@ class ModelField:
value: Any,
values: dict[str, Any] = {}, # noqa: B006
*,
- loc: tuple[Union[int, str], ...] = (),
+ loc: tuple[int | str, ...] = (),
) -> tuple[Any, list[dict[str, Any]]]:
try:
return (
@@ -160,8 +162,8 @@ class ModelField:
value: Any,
*,
mode: Literal["json", "python"] = "json",
- include: Union[IncEx, None] = None,
- exclude: Union[IncEx, None] = None,
+ include: IncEx | None = None,
+ exclude: IncEx | None = None,
by_alias: bool = True,
exclude_unset: bool = False,
exclude_defaults: bool = False,
@@ -202,7 +204,7 @@ def get_schema_from_model_field(
],
separate_input_output_schemas: bool = True,
) -> dict[str, Any]:
- override_mode: Union[Literal["validation"], None] = (
+ override_mode: Literal["validation"] | None = (
None
if (separate_input_output_schemas or _has_computed_fields(field))
else "validation"
@@ -318,7 +320,7 @@ def serialize_sequence_value(*, field: ModelField, value: Any) -> Sequence[Any]:
return shared.sequence_annotation_to_type[origin_type](value) # type: ignore[no-any-return,index]
-def get_missing_field_error(loc: tuple[Union[int, str], ...]) -> dict[str, Any]:
+def get_missing_field_error(loc: tuple[int | str, ...]) -> dict[str, Any]:
error = ValidationError.from_exception_data(
"Field required", [{"type": "missing", "loc": loc, "input": {}}]
).errors(include_url=False)[0]
@@ -360,7 +362,7 @@ def get_cached_model_fields(model: type[BaseModel]) -> list[ModelField]:
# Duplicate of several schema functions from Pydantic v1 to make them compatible with
# Pydantic v2 and allow mixing the models
-TypeModelOrEnum = Union[type["BaseModel"], type[Enum]]
+TypeModelOrEnum = type["BaseModel"] | type[Enum]
TypeModelSet = set[TypeModelOrEnum]
@@ -377,7 +379,7 @@ def get_model_name_map(unique_models: TypeModelSet) -> dict[TypeModelOrEnum, str
def get_flat_models_from_model(
- model: type["BaseModel"], known_models: Union[TypeModelSet, None] = None
+ model: type["BaseModel"], known_models: TypeModelSet | None = None
) -> TypeModelSet:
known_models = known_models or set()
fields = get_model_fields(model)
@@ -426,7 +428,7 @@ def get_flat_models_from_fields(
def _regenerate_error_with_loc(
- *, errors: Sequence[Any], loc_prefix: tuple[Union[str, int], ...]
+ *, errors: Sequence[Any], loc_prefix: tuple[str | int, ...]
) -> list[dict[str, Any]]:
updated_loc_errors: list[Any] = [
{**err, "loc": loc_prefix + err.get("loc", ())} for err in errors
diff --git a/fastapi/applications.py b/fastapi/applications.py
index 340cabfc29..41d86143ec 100644
--- a/fastapi/applications.py
+++ b/fastapi/applications.py
@@ -1,12 +1,9 @@
-from collections.abc import Awaitable, Coroutine, Sequence
+from collections.abc import Awaitable, Callable, Coroutine, Sequence
from enum import Enum
from typing import (
Annotated,
Any,
- Callable,
- Optional,
TypeVar,
- Union,
)
from annotated_doc import Doc
@@ -77,7 +74,7 @@ class FastAPI(Starlette):
),
] = False,
routes: Annotated[
- Optional[list[BaseRoute]],
+ list[BaseRoute] | None,
Doc(
"""
**Note**: you probably shouldn't use this parameter, it is inherited
@@ -120,7 +117,7 @@ class FastAPI(Starlette):
),
] = "FastAPI",
summary: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
A short summary of the API.
@@ -203,7 +200,7 @@ class FastAPI(Starlette):
),
] = "0.1.0",
openapi_url: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
The URL where the OpenAPI schema will be served from.
@@ -226,7 +223,7 @@ class FastAPI(Starlette):
),
] = "/openapi.json",
openapi_tags: Annotated[
- Optional[list[dict[str, Any]]],
+ list[dict[str, Any]] | None,
Doc(
"""
A list of tags used by OpenAPI, these are the same `tags` you can set
@@ -286,7 +283,7 @@ class FastAPI(Starlette):
),
] = None,
servers: Annotated[
- Optional[list[dict[str, Union[str, Any]]]],
+ list[dict[str, str | Any]] | None,
Doc(
"""
A `list` of `dict`s with connectivity information to a target server.
@@ -335,7 +332,7 @@ class FastAPI(Starlette):
),
] = None,
dependencies: Annotated[
- Optional[Sequence[Depends]],
+ Sequence[Depends] | None,
Doc(
"""
A list of global dependencies, they will be applied to each
@@ -402,7 +399,7 @@ class FastAPI(Starlette):
),
] = True,
docs_url: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
The path to the automatic interactive API documentation.
@@ -426,7 +423,7 @@ class FastAPI(Starlette):
),
] = "/docs",
redoc_url: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
The path to the alternative automatic interactive API documentation
@@ -450,7 +447,7 @@ class FastAPI(Starlette):
),
] = "/redoc",
swagger_ui_oauth2_redirect_url: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
The OAuth2 redirect endpoint for the Swagger UI.
@@ -463,7 +460,7 @@ class FastAPI(Starlette):
),
] = "/docs/oauth2-redirect",
swagger_ui_init_oauth: Annotated[
- Optional[dict[str, Any]],
+ dict[str, Any] | None,
Doc(
"""
OAuth2 configuration for the Swagger UI, by default shown at `/docs`.
@@ -474,7 +471,7 @@ class FastAPI(Starlette):
),
] = None,
middleware: Annotated[
- Optional[Sequence[Middleware]],
+ Sequence[Middleware] | None,
Doc(
"""
List of middleware to be added when creating the application.
@@ -488,12 +485,11 @@ class FastAPI(Starlette):
),
] = None,
exception_handlers: Annotated[
- Optional[
- dict[
- Union[int, type[Exception]],
- Callable[[Request, Any], Coroutine[Any, Any, Response]],
- ]
- ],
+ dict[
+ int | type[Exception],
+ Callable[[Request, Any], Coroutine[Any, Any, Response]],
+ ]
+ | None,
Doc(
"""
A dictionary with handlers for exceptions.
@@ -507,7 +503,7 @@ class FastAPI(Starlette):
),
] = None,
on_startup: Annotated[
- Optional[Sequence[Callable[[], Any]]],
+ Sequence[Callable[[], Any]] | None,
Doc(
"""
A list of startup event handler functions.
@@ -519,7 +515,7 @@ class FastAPI(Starlette):
),
] = None,
on_shutdown: Annotated[
- Optional[Sequence[Callable[[], Any]]],
+ Sequence[Callable[[], Any]] | None,
Doc(
"""
A list of shutdown event handler functions.
@@ -532,7 +528,7 @@ class FastAPI(Starlette):
),
] = None,
lifespan: Annotated[
- Optional[Lifespan[AppType]],
+ Lifespan[AppType] | None,
Doc(
"""
A `Lifespan` context manager handler. This replaces `startup` and
@@ -544,7 +540,7 @@ class FastAPI(Starlette):
),
] = None,
terms_of_service: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
A URL to the Terms of Service for your API.
@@ -563,7 +559,7 @@ class FastAPI(Starlette):
),
] = None,
contact: Annotated[
- Optional[dict[str, Union[str, Any]]],
+ dict[str, str | Any] | None,
Doc(
"""
A dictionary with the contact information for the exposed API.
@@ -596,7 +592,7 @@ class FastAPI(Starlette):
),
] = None,
license_info: Annotated[
- Optional[dict[str, Union[str, Any]]],
+ dict[str, str | Any] | None,
Doc(
"""
A dictionary with the license information for the exposed API.
@@ -685,7 +681,7 @@ class FastAPI(Starlette):
),
] = True,
responses: Annotated[
- Optional[dict[Union[int, str], dict[str, Any]]],
+ dict[int | str, dict[str, Any]] | None,
Doc(
"""
Additional responses to be shown in OpenAPI.
@@ -701,7 +697,7 @@ class FastAPI(Starlette):
),
] = None,
callbacks: Annotated[
- Optional[list[BaseRoute]],
+ list[BaseRoute] | None,
Doc(
"""
OpenAPI callbacks that should apply to all *path operations*.
@@ -714,7 +710,7 @@ class FastAPI(Starlette):
),
] = None,
webhooks: Annotated[
- Optional[routing.APIRouter],
+ routing.APIRouter | None,
Doc(
"""
Add OpenAPI webhooks. This is similar to `callbacks` but it doesn't
@@ -730,7 +726,7 @@ class FastAPI(Starlette):
),
] = None,
deprecated: Annotated[
- Optional[bool],
+ bool | None,
Doc(
"""
Mark all *path operations* as deprecated. You probably don't need it,
@@ -758,7 +754,7 @@ class FastAPI(Starlette):
),
] = True,
swagger_ui_parameters: Annotated[
- Optional[dict[str, Any]],
+ dict[str, Any] | None,
Doc(
"""
Parameters to configure Swagger UI, the autogenerated interactive API
@@ -819,7 +815,7 @@ class FastAPI(Starlette):
),
] = True,
openapi_external_docs: Annotated[
- Optional[dict[str, Any]],
+ dict[str, Any] | None,
Doc(
"""
This field allows you to provide additional external documentation links.
@@ -905,7 +901,7 @@ class FastAPI(Starlette):
"""
),
] = "3.1.0"
- self.openapi_schema: Optional[dict[str, Any]] = None
+ self.openapi_schema: dict[str, Any] | None = None
if self.openapi_url:
assert self.title, "A title must be provided for OpenAPI, e.g.: 'My API'"
assert self.version, "A version must be provided for OpenAPI, e.g.: '2.1.0'"
@@ -980,7 +976,7 @@ class FastAPI(Starlette):
generate_unique_id_function=generate_unique_id_function,
)
self.exception_handlers: dict[
- Any, Callable[[Request, Any], Union[Response, Awaitable[Response]]]
+ Any, Callable[[Request, Any], Response | Awaitable[Response]]
] = {} if exception_handlers is None else dict(exception_handlers)
self.exception_handlers.setdefault(HTTPException, http_exception_handler)
self.exception_handlers.setdefault(
@@ -995,7 +991,7 @@ class FastAPI(Starlette):
self.user_middleware: list[Middleware] = (
[] if middleware is None else list(middleware)
)
- self.middleware_stack: Union[ASGIApp, None] = None
+ self.middleware_stack: ASGIApp | None = None
self.setup()
def build_middleware_stack(self) -> ASGIApp:
@@ -1143,28 +1139,26 @@ class FastAPI(Starlette):
endpoint: Callable[..., Any],
*,
response_model: Any = Default(None),
- status_code: Optional[int] = None,
- tags: Optional[list[Union[str, Enum]]] = None,
- dependencies: Optional[Sequence[Depends]] = None,
- summary: Optional[str] = None,
- description: Optional[str] = None,
+ status_code: int | None = None,
+ tags: list[str | Enum] | None = None,
+ dependencies: Sequence[Depends] | None = None,
+ summary: str | None = None,
+ description: str | None = None,
response_description: str = "Successful Response",
- responses: Optional[dict[Union[int, str], dict[str, Any]]] = None,
- deprecated: Optional[bool] = None,
- methods: Optional[list[str]] = None,
- operation_id: Optional[str] = None,
- response_model_include: Optional[IncEx] = None,
- response_model_exclude: Optional[IncEx] = None,
+ responses: dict[int | str, dict[str, Any]] | None = None,
+ deprecated: bool | None = None,
+ methods: list[str] | None = None,
+ operation_id: str | None = None,
+ response_model_include: IncEx | None = None,
+ response_model_exclude: IncEx | None = None,
response_model_by_alias: bool = True,
response_model_exclude_unset: bool = False,
response_model_exclude_defaults: bool = False,
response_model_exclude_none: bool = False,
include_in_schema: bool = True,
- response_class: Union[type[Response], DefaultPlaceholder] = Default(
- JSONResponse
- ),
- name: Optional[str] = None,
- openapi_extra: Optional[dict[str, Any]] = None,
+ response_class: type[Response] | DefaultPlaceholder = Default(JSONResponse),
+ name: str | None = None,
+ openapi_extra: dict[str, Any] | None = None,
generate_unique_id_function: Callable[[routing.APIRoute], str] = Default(
generate_unique_id
),
@@ -1201,26 +1195,26 @@ class FastAPI(Starlette):
path: str,
*,
response_model: Any = Default(None),
- status_code: Optional[int] = None,
- tags: Optional[list[Union[str, Enum]]] = None,
- dependencies: Optional[Sequence[Depends]] = None,
- summary: Optional[str] = None,
- description: Optional[str] = None,
+ status_code: int | None = None,
+ tags: list[str | Enum] | None = None,
+ dependencies: Sequence[Depends] | None = None,
+ summary: str | None = None,
+ description: str | None = None,
response_description: str = "Successful Response",
- responses: Optional[dict[Union[int, str], dict[str, Any]]] = None,
- deprecated: Optional[bool] = None,
- methods: Optional[list[str]] = None,
- operation_id: Optional[str] = None,
- response_model_include: Optional[IncEx] = None,
- response_model_exclude: Optional[IncEx] = None,
+ responses: dict[int | str, dict[str, Any]] | None = None,
+ deprecated: bool | None = None,
+ methods: list[str] | None = None,
+ operation_id: str | None = None,
+ response_model_include: IncEx | None = None,
+ response_model_exclude: IncEx | None = None,
response_model_by_alias: bool = True,
response_model_exclude_unset: bool = False,
response_model_exclude_defaults: bool = False,
response_model_exclude_none: bool = False,
include_in_schema: bool = True,
response_class: type[Response] = Default(JSONResponse),
- name: Optional[str] = None,
- openapi_extra: Optional[dict[str, Any]] = None,
+ name: str | None = None,
+ openapi_extra: dict[str, Any] | None = None,
generate_unique_id_function: Callable[[routing.APIRoute], str] = Default(
generate_unique_id
),
@@ -1260,9 +1254,9 @@ class FastAPI(Starlette):
self,
path: str,
endpoint: Callable[..., Any],
- name: Optional[str] = None,
+ name: str | None = None,
*,
- dependencies: Optional[Sequence[Depends]] = None,
+ dependencies: Sequence[Depends] | None = None,
) -> None:
self.router.add_api_websocket_route(
path,
@@ -1282,7 +1276,7 @@ class FastAPI(Starlette):
),
],
name: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
A name for the WebSocket. Only used internally.
@@ -1291,7 +1285,7 @@ class FastAPI(Starlette):
] = None,
*,
dependencies: Annotated[
- Optional[Sequence[Depends]],
+ Sequence[Depends] | None,
Doc(
"""
A list of dependencies (using `Depends()`) to be used for this
@@ -1342,7 +1336,7 @@ class FastAPI(Starlette):
*,
prefix: Annotated[str, Doc("An optional path prefix for the router.")] = "",
tags: Annotated[
- Optional[list[Union[str, Enum]]],
+ list[str | Enum] | None,
Doc(
"""
A list of tags to be applied to all the *path operations* in this
@@ -1356,7 +1350,7 @@ class FastAPI(Starlette):
),
] = None,
dependencies: Annotated[
- Optional[Sequence[Depends]],
+ Sequence[Depends] | None,
Doc(
"""
A list of dependencies (using `Depends()`) to be applied to all the
@@ -1384,7 +1378,7 @@ class FastAPI(Starlette):
),
] = None,
responses: Annotated[
- Optional[dict[Union[int, str], dict[str, Any]]],
+ dict[int | str, dict[str, Any]] | None,
Doc(
"""
Additional responses to be shown in OpenAPI.
@@ -1400,7 +1394,7 @@ class FastAPI(Starlette):
),
] = None,
deprecated: Annotated[
- Optional[bool],
+ bool | None,
Doc(
"""
Mark all the *path operations* in this router as deprecated.
@@ -1479,7 +1473,7 @@ class FastAPI(Starlette):
),
] = Default(JSONResponse),
callbacks: Annotated[
- Optional[list[BaseRoute]],
+ list[BaseRoute] | None,
Doc(
"""
List of *path operations* that will be used as OpenAPI callbacks.
@@ -1589,7 +1583,7 @@ class FastAPI(Starlette):
),
] = Default(None),
status_code: Annotated[
- Optional[int],
+ int | None,
Doc(
"""
The default status code to be used for the response.
@@ -1602,7 +1596,7 @@ class FastAPI(Starlette):
),
] = None,
tags: Annotated[
- Optional[list[Union[str, Enum]]],
+ list[str | Enum] | None,
Doc(
"""
A list of tags to be applied to the *path operation*.
@@ -1615,7 +1609,7 @@ class FastAPI(Starlette):
),
] = None,
dependencies: Annotated[
- Optional[Sequence[Depends]],
+ Sequence[Depends] | None,
Doc(
"""
A list of dependencies (using `Depends()`) to be applied to the
@@ -1627,7 +1621,7 @@ class FastAPI(Starlette):
),
] = None,
summary: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
A summary for the *path operation*.
@@ -1640,7 +1634,7 @@ class FastAPI(Starlette):
),
] = None,
description: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
A description for the *path operation*.
@@ -1668,7 +1662,7 @@ class FastAPI(Starlette):
),
] = "Successful Response",
responses: Annotated[
- Optional[dict[Union[int, str], dict[str, Any]]],
+ dict[int | str, dict[str, Any]] | None,
Doc(
"""
Additional responses that could be returned by this *path operation*.
@@ -1678,7 +1672,7 @@ class FastAPI(Starlette):
),
] = None,
deprecated: Annotated[
- Optional[bool],
+ bool | None,
Doc(
"""
Mark this *path operation* as deprecated.
@@ -1688,7 +1682,7 @@ class FastAPI(Starlette):
),
] = None,
operation_id: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
Custom operation ID to be used by this *path operation*.
@@ -1708,7 +1702,7 @@ class FastAPI(Starlette):
),
] = None,
response_model_include: Annotated[
- Optional[IncEx],
+ IncEx | None,
Doc(
"""
Configuration passed to Pydantic to include only certain fields in the
@@ -1720,7 +1714,7 @@ class FastAPI(Starlette):
),
] = None,
response_model_exclude: Annotated[
- Optional[IncEx],
+ IncEx | None,
Doc(
"""
Configuration passed to Pydantic to exclude certain fields in the
@@ -1822,7 +1816,7 @@ class FastAPI(Starlette):
),
] = Default(JSONResponse),
name: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
Name for this *path operation*. Only used internally.
@@ -1830,7 +1824,7 @@ class FastAPI(Starlette):
),
] = None,
callbacks: Annotated[
- Optional[list[BaseRoute]],
+ list[BaseRoute] | None,
Doc(
"""
List of *path operations* that will be used as OpenAPI callbacks.
@@ -1846,7 +1840,7 @@ class FastAPI(Starlette):
),
] = None,
openapi_extra: Annotated[
- Optional[dict[str, Any]],
+ dict[str, Any] | None,
Doc(
"""
Extra metadata to be included in the OpenAPI schema for this *path
@@ -1962,7 +1956,7 @@ class FastAPI(Starlette):
),
] = Default(None),
status_code: Annotated[
- Optional[int],
+ int | None,
Doc(
"""
The default status code to be used for the response.
@@ -1975,7 +1969,7 @@ class FastAPI(Starlette):
),
] = None,
tags: Annotated[
- Optional[list[Union[str, Enum]]],
+ list[str | Enum] | None,
Doc(
"""
A list of tags to be applied to the *path operation*.
@@ -1988,7 +1982,7 @@ class FastAPI(Starlette):
),
] = None,
dependencies: Annotated[
- Optional[Sequence[Depends]],
+ Sequence[Depends] | None,
Doc(
"""
A list of dependencies (using `Depends()`) to be applied to the
@@ -2000,7 +1994,7 @@ class FastAPI(Starlette):
),
] = None,
summary: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
A summary for the *path operation*.
@@ -2013,7 +2007,7 @@ class FastAPI(Starlette):
),
] = None,
description: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
A description for the *path operation*.
@@ -2041,7 +2035,7 @@ class FastAPI(Starlette):
),
] = "Successful Response",
responses: Annotated[
- Optional[dict[Union[int, str], dict[str, Any]]],
+ dict[int | str, dict[str, Any]] | None,
Doc(
"""
Additional responses that could be returned by this *path operation*.
@@ -2051,7 +2045,7 @@ class FastAPI(Starlette):
),
] = None,
deprecated: Annotated[
- Optional[bool],
+ bool | None,
Doc(
"""
Mark this *path operation* as deprecated.
@@ -2061,7 +2055,7 @@ class FastAPI(Starlette):
),
] = None,
operation_id: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
Custom operation ID to be used by this *path operation*.
@@ -2081,7 +2075,7 @@ class FastAPI(Starlette):
),
] = None,
response_model_include: Annotated[
- Optional[IncEx],
+ IncEx | None,
Doc(
"""
Configuration passed to Pydantic to include only certain fields in the
@@ -2093,7 +2087,7 @@ class FastAPI(Starlette):
),
] = None,
response_model_exclude: Annotated[
- Optional[IncEx],
+ IncEx | None,
Doc(
"""
Configuration passed to Pydantic to exclude certain fields in the
@@ -2195,7 +2189,7 @@ class FastAPI(Starlette):
),
] = Default(JSONResponse),
name: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
Name for this *path operation*. Only used internally.
@@ -2203,7 +2197,7 @@ class FastAPI(Starlette):
),
] = None,
callbacks: Annotated[
- Optional[list[BaseRoute]],
+ list[BaseRoute] | None,
Doc(
"""
List of *path operations* that will be used as OpenAPI callbacks.
@@ -2219,7 +2213,7 @@ class FastAPI(Starlette):
),
] = None,
openapi_extra: Annotated[
- Optional[dict[str, Any]],
+ dict[str, Any] | None,
Doc(
"""
Extra metadata to be included in the OpenAPI schema for this *path
@@ -2340,7 +2334,7 @@ class FastAPI(Starlette):
),
] = Default(None),
status_code: Annotated[
- Optional[int],
+ int | None,
Doc(
"""
The default status code to be used for the response.
@@ -2353,7 +2347,7 @@ class FastAPI(Starlette):
),
] = None,
tags: Annotated[
- Optional[list[Union[str, Enum]]],
+ list[str | Enum] | None,
Doc(
"""
A list of tags to be applied to the *path operation*.
@@ -2366,7 +2360,7 @@ class FastAPI(Starlette):
),
] = None,
dependencies: Annotated[
- Optional[Sequence[Depends]],
+ Sequence[Depends] | None,
Doc(
"""
A list of dependencies (using `Depends()`) to be applied to the
@@ -2378,7 +2372,7 @@ class FastAPI(Starlette):
),
] = None,
summary: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
A summary for the *path operation*.
@@ -2391,7 +2385,7 @@ class FastAPI(Starlette):
),
] = None,
description: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
A description for the *path operation*.
@@ -2419,7 +2413,7 @@ class FastAPI(Starlette):
),
] = "Successful Response",
responses: Annotated[
- Optional[dict[Union[int, str], dict[str, Any]]],
+ dict[int | str, dict[str, Any]] | None,
Doc(
"""
Additional responses that could be returned by this *path operation*.
@@ -2429,7 +2423,7 @@ class FastAPI(Starlette):
),
] = None,
deprecated: Annotated[
- Optional[bool],
+ bool | None,
Doc(
"""
Mark this *path operation* as deprecated.
@@ -2439,7 +2433,7 @@ class FastAPI(Starlette):
),
] = None,
operation_id: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
Custom operation ID to be used by this *path operation*.
@@ -2459,7 +2453,7 @@ class FastAPI(Starlette):
),
] = None,
response_model_include: Annotated[
- Optional[IncEx],
+ IncEx | None,
Doc(
"""
Configuration passed to Pydantic to include only certain fields in the
@@ -2471,7 +2465,7 @@ class FastAPI(Starlette):
),
] = None,
response_model_exclude: Annotated[
- Optional[IncEx],
+ IncEx | None,
Doc(
"""
Configuration passed to Pydantic to exclude certain fields in the
@@ -2573,7 +2567,7 @@ class FastAPI(Starlette):
),
] = Default(JSONResponse),
name: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
Name for this *path operation*. Only used internally.
@@ -2581,7 +2575,7 @@ class FastAPI(Starlette):
),
] = None,
callbacks: Annotated[
- Optional[list[BaseRoute]],
+ list[BaseRoute] | None,
Doc(
"""
List of *path operations* that will be used as OpenAPI callbacks.
@@ -2597,7 +2591,7 @@ class FastAPI(Starlette):
),
] = None,
openapi_extra: Annotated[
- Optional[dict[str, Any]],
+ dict[str, Any] | None,
Doc(
"""
Extra metadata to be included in the OpenAPI schema for this *path
@@ -2718,7 +2712,7 @@ class FastAPI(Starlette):
),
] = Default(None),
status_code: Annotated[
- Optional[int],
+ int | None,
Doc(
"""
The default status code to be used for the response.
@@ -2731,7 +2725,7 @@ class FastAPI(Starlette):
),
] = None,
tags: Annotated[
- Optional[list[Union[str, Enum]]],
+ list[str | Enum] | None,
Doc(
"""
A list of tags to be applied to the *path operation*.
@@ -2744,7 +2738,7 @@ class FastAPI(Starlette):
),
] = None,
dependencies: Annotated[
- Optional[Sequence[Depends]],
+ Sequence[Depends] | None,
Doc(
"""
A list of dependencies (using `Depends()`) to be applied to the
@@ -2756,7 +2750,7 @@ class FastAPI(Starlette):
),
] = None,
summary: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
A summary for the *path operation*.
@@ -2769,7 +2763,7 @@ class FastAPI(Starlette):
),
] = None,
description: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
A description for the *path operation*.
@@ -2797,7 +2791,7 @@ class FastAPI(Starlette):
),
] = "Successful Response",
responses: Annotated[
- Optional[dict[Union[int, str], dict[str, Any]]],
+ dict[int | str, dict[str, Any]] | None,
Doc(
"""
Additional responses that could be returned by this *path operation*.
@@ -2807,7 +2801,7 @@ class FastAPI(Starlette):
),
] = None,
deprecated: Annotated[
- Optional[bool],
+ bool | None,
Doc(
"""
Mark this *path operation* as deprecated.
@@ -2817,7 +2811,7 @@ class FastAPI(Starlette):
),
] = None,
operation_id: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
Custom operation ID to be used by this *path operation*.
@@ -2837,7 +2831,7 @@ class FastAPI(Starlette):
),
] = None,
response_model_include: Annotated[
- Optional[IncEx],
+ IncEx | None,
Doc(
"""
Configuration passed to Pydantic to include only certain fields in the
@@ -2849,7 +2843,7 @@ class FastAPI(Starlette):
),
] = None,
response_model_exclude: Annotated[
- Optional[IncEx],
+ IncEx | None,
Doc(
"""
Configuration passed to Pydantic to exclude certain fields in the
@@ -2951,7 +2945,7 @@ class FastAPI(Starlette):
),
] = Default(JSONResponse),
name: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
Name for this *path operation*. Only used internally.
@@ -2959,7 +2953,7 @@ class FastAPI(Starlette):
),
] = None,
callbacks: Annotated[
- Optional[list[BaseRoute]],
+ list[BaseRoute] | None,
Doc(
"""
List of *path operations* that will be used as OpenAPI callbacks.
@@ -2975,7 +2969,7 @@ class FastAPI(Starlette):
),
] = None,
openapi_extra: Annotated[
- Optional[dict[str, Any]],
+ dict[str, Any] | None,
Doc(
"""
Extra metadata to be included in the OpenAPI schema for this *path
@@ -3091,7 +3085,7 @@ class FastAPI(Starlette):
),
] = Default(None),
status_code: Annotated[
- Optional[int],
+ int | None,
Doc(
"""
The default status code to be used for the response.
@@ -3104,7 +3098,7 @@ class FastAPI(Starlette):
),
] = None,
tags: Annotated[
- Optional[list[Union[str, Enum]]],
+ list[str | Enum] | None,
Doc(
"""
A list of tags to be applied to the *path operation*.
@@ -3117,7 +3111,7 @@ class FastAPI(Starlette):
),
] = None,
dependencies: Annotated[
- Optional[Sequence[Depends]],
+ Sequence[Depends] | None,
Doc(
"""
A list of dependencies (using `Depends()`) to be applied to the
@@ -3129,7 +3123,7 @@ class FastAPI(Starlette):
),
] = None,
summary: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
A summary for the *path operation*.
@@ -3142,7 +3136,7 @@ class FastAPI(Starlette):
),
] = None,
description: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
A description for the *path operation*.
@@ -3170,7 +3164,7 @@ class FastAPI(Starlette):
),
] = "Successful Response",
responses: Annotated[
- Optional[dict[Union[int, str], dict[str, Any]]],
+ dict[int | str, dict[str, Any]] | None,
Doc(
"""
Additional responses that could be returned by this *path operation*.
@@ -3180,7 +3174,7 @@ class FastAPI(Starlette):
),
] = None,
deprecated: Annotated[
- Optional[bool],
+ bool | None,
Doc(
"""
Mark this *path operation* as deprecated.
@@ -3190,7 +3184,7 @@ class FastAPI(Starlette):
),
] = None,
operation_id: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
Custom operation ID to be used by this *path operation*.
@@ -3210,7 +3204,7 @@ class FastAPI(Starlette):
),
] = None,
response_model_include: Annotated[
- Optional[IncEx],
+ IncEx | None,
Doc(
"""
Configuration passed to Pydantic to include only certain fields in the
@@ -3222,7 +3216,7 @@ class FastAPI(Starlette):
),
] = None,
response_model_exclude: Annotated[
- Optional[IncEx],
+ IncEx | None,
Doc(
"""
Configuration passed to Pydantic to exclude certain fields in the
@@ -3324,7 +3318,7 @@ class FastAPI(Starlette):
),
] = Default(JSONResponse),
name: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
Name for this *path operation*. Only used internally.
@@ -3332,7 +3326,7 @@ class FastAPI(Starlette):
),
] = None,
callbacks: Annotated[
- Optional[list[BaseRoute]],
+ list[BaseRoute] | None,
Doc(
"""
List of *path operations* that will be used as OpenAPI callbacks.
@@ -3348,7 +3342,7 @@ class FastAPI(Starlette):
),
] = None,
openapi_extra: Annotated[
- Optional[dict[str, Any]],
+ dict[str, Any] | None,
Doc(
"""
Extra metadata to be included in the OpenAPI schema for this *path
@@ -3464,7 +3458,7 @@ class FastAPI(Starlette):
),
] = Default(None),
status_code: Annotated[
- Optional[int],
+ int | None,
Doc(
"""
The default status code to be used for the response.
@@ -3477,7 +3471,7 @@ class FastAPI(Starlette):
),
] = None,
tags: Annotated[
- Optional[list[Union[str, Enum]]],
+ list[str | Enum] | None,
Doc(
"""
A list of tags to be applied to the *path operation*.
@@ -3490,7 +3484,7 @@ class FastAPI(Starlette):
),
] = None,
dependencies: Annotated[
- Optional[Sequence[Depends]],
+ Sequence[Depends] | None,
Doc(
"""
A list of dependencies (using `Depends()`) to be applied to the
@@ -3502,7 +3496,7 @@ class FastAPI(Starlette):
),
] = None,
summary: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
A summary for the *path operation*.
@@ -3515,7 +3509,7 @@ class FastAPI(Starlette):
),
] = None,
description: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
A description for the *path operation*.
@@ -3543,7 +3537,7 @@ class FastAPI(Starlette):
),
] = "Successful Response",
responses: Annotated[
- Optional[dict[Union[int, str], dict[str, Any]]],
+ dict[int | str, dict[str, Any]] | None,
Doc(
"""
Additional responses that could be returned by this *path operation*.
@@ -3553,7 +3547,7 @@ class FastAPI(Starlette):
),
] = None,
deprecated: Annotated[
- Optional[bool],
+ bool | None,
Doc(
"""
Mark this *path operation* as deprecated.
@@ -3563,7 +3557,7 @@ class FastAPI(Starlette):
),
] = None,
operation_id: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
Custom operation ID to be used by this *path operation*.
@@ -3583,7 +3577,7 @@ class FastAPI(Starlette):
),
] = None,
response_model_include: Annotated[
- Optional[IncEx],
+ IncEx | None,
Doc(
"""
Configuration passed to Pydantic to include only certain fields in the
@@ -3595,7 +3589,7 @@ class FastAPI(Starlette):
),
] = None,
response_model_exclude: Annotated[
- Optional[IncEx],
+ IncEx | None,
Doc(
"""
Configuration passed to Pydantic to exclude certain fields in the
@@ -3697,7 +3691,7 @@ class FastAPI(Starlette):
),
] = Default(JSONResponse),
name: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
Name for this *path operation*. Only used internally.
@@ -3705,7 +3699,7 @@ class FastAPI(Starlette):
),
] = None,
callbacks: Annotated[
- Optional[list[BaseRoute]],
+ list[BaseRoute] | None,
Doc(
"""
List of *path operations* that will be used as OpenAPI callbacks.
@@ -3721,7 +3715,7 @@ class FastAPI(Starlette):
),
] = None,
openapi_extra: Annotated[
- Optional[dict[str, Any]],
+ dict[str, Any] | None,
Doc(
"""
Extra metadata to be included in the OpenAPI schema for this *path
@@ -3837,7 +3831,7 @@ class FastAPI(Starlette):
),
] = Default(None),
status_code: Annotated[
- Optional[int],
+ int | None,
Doc(
"""
The default status code to be used for the response.
@@ -3850,7 +3844,7 @@ class FastAPI(Starlette):
),
] = None,
tags: Annotated[
- Optional[list[Union[str, Enum]]],
+ list[str | Enum] | None,
Doc(
"""
A list of tags to be applied to the *path operation*.
@@ -3863,7 +3857,7 @@ class FastAPI(Starlette):
),
] = None,
dependencies: Annotated[
- Optional[Sequence[Depends]],
+ Sequence[Depends] | None,
Doc(
"""
A list of dependencies (using `Depends()`) to be applied to the
@@ -3875,7 +3869,7 @@ class FastAPI(Starlette):
),
] = None,
summary: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
A summary for the *path operation*.
@@ -3888,7 +3882,7 @@ class FastAPI(Starlette):
),
] = None,
description: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
A description for the *path operation*.
@@ -3916,7 +3910,7 @@ class FastAPI(Starlette):
),
] = "Successful Response",
responses: Annotated[
- Optional[dict[Union[int, str], dict[str, Any]]],
+ dict[int | str, dict[str, Any]] | None,
Doc(
"""
Additional responses that could be returned by this *path operation*.
@@ -3926,7 +3920,7 @@ class FastAPI(Starlette):
),
] = None,
deprecated: Annotated[
- Optional[bool],
+ bool | None,
Doc(
"""
Mark this *path operation* as deprecated.
@@ -3936,7 +3930,7 @@ class FastAPI(Starlette):
),
] = None,
operation_id: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
Custom operation ID to be used by this *path operation*.
@@ -3956,7 +3950,7 @@ class FastAPI(Starlette):
),
] = None,
response_model_include: Annotated[
- Optional[IncEx],
+ IncEx | None,
Doc(
"""
Configuration passed to Pydantic to include only certain fields in the
@@ -3968,7 +3962,7 @@ class FastAPI(Starlette):
),
] = None,
response_model_exclude: Annotated[
- Optional[IncEx],
+ IncEx | None,
Doc(
"""
Configuration passed to Pydantic to exclude certain fields in the
@@ -4070,7 +4064,7 @@ class FastAPI(Starlette):
),
] = Default(JSONResponse),
name: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
Name for this *path operation*. Only used internally.
@@ -4078,7 +4072,7 @@ class FastAPI(Starlette):
),
] = None,
callbacks: Annotated[
- Optional[list[BaseRoute]],
+ list[BaseRoute] | None,
Doc(
"""
List of *path operations* that will be used as OpenAPI callbacks.
@@ -4094,7 +4088,7 @@ class FastAPI(Starlette):
),
] = None,
openapi_extra: Annotated[
- Optional[dict[str, Any]],
+ dict[str, Any] | None,
Doc(
"""
Extra metadata to be included in the OpenAPI schema for this *path
@@ -4215,7 +4209,7 @@ class FastAPI(Starlette):
),
] = Default(None),
status_code: Annotated[
- Optional[int],
+ int | None,
Doc(
"""
The default status code to be used for the response.
@@ -4228,7 +4222,7 @@ class FastAPI(Starlette):
),
] = None,
tags: Annotated[
- Optional[list[Union[str, Enum]]],
+ list[str | Enum] | None,
Doc(
"""
A list of tags to be applied to the *path operation*.
@@ -4241,7 +4235,7 @@ class FastAPI(Starlette):
),
] = None,
dependencies: Annotated[
- Optional[Sequence[Depends]],
+ Sequence[Depends] | None,
Doc(
"""
A list of dependencies (using `Depends()`) to be applied to the
@@ -4253,7 +4247,7 @@ class FastAPI(Starlette):
),
] = None,
summary: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
A summary for the *path operation*.
@@ -4266,7 +4260,7 @@ class FastAPI(Starlette):
),
] = None,
description: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
A description for the *path operation*.
@@ -4294,7 +4288,7 @@ class FastAPI(Starlette):
),
] = "Successful Response",
responses: Annotated[
- Optional[dict[Union[int, str], dict[str, Any]]],
+ dict[int | str, dict[str, Any]] | None,
Doc(
"""
Additional responses that could be returned by this *path operation*.
@@ -4304,7 +4298,7 @@ class FastAPI(Starlette):
),
] = None,
deprecated: Annotated[
- Optional[bool],
+ bool | None,
Doc(
"""
Mark this *path operation* as deprecated.
@@ -4314,7 +4308,7 @@ class FastAPI(Starlette):
),
] = None,
operation_id: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
Custom operation ID to be used by this *path operation*.
@@ -4334,7 +4328,7 @@ class FastAPI(Starlette):
),
] = None,
response_model_include: Annotated[
- Optional[IncEx],
+ IncEx | None,
Doc(
"""
Configuration passed to Pydantic to include only certain fields in the
@@ -4346,7 +4340,7 @@ class FastAPI(Starlette):
),
] = None,
response_model_exclude: Annotated[
- Optional[IncEx],
+ IncEx | None,
Doc(
"""
Configuration passed to Pydantic to exclude certain fields in the
@@ -4448,7 +4442,7 @@ class FastAPI(Starlette):
),
] = Default(JSONResponse),
name: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
Name for this *path operation*. Only used internally.
@@ -4456,7 +4450,7 @@ class FastAPI(Starlette):
),
] = None,
callbacks: Annotated[
- Optional[list[BaseRoute]],
+ list[BaseRoute] | None,
Doc(
"""
List of *path operations* that will be used as OpenAPI callbacks.
@@ -4472,7 +4466,7 @@ class FastAPI(Starlette):
),
] = None,
openapi_extra: Annotated[
- Optional[dict[str, Any]],
+ dict[str, Any] | None,
Doc(
"""
Extra metadata to be included in the OpenAPI schema for this *path
@@ -4541,7 +4535,7 @@ class FastAPI(Starlette):
)
def websocket_route(
- self, path: str, name: Union[str, None] = None
+ self, path: str, name: str | None = None
) -> Callable[[DecoratedCallable], DecoratedCallable]:
def decorator(func: DecoratedCallable) -> DecoratedCallable:
self.router.add_websocket_route(path, func, name=name)
@@ -4627,7 +4621,7 @@ class FastAPI(Starlette):
def exception_handler(
self,
exc_class_or_status_code: Annotated[
- Union[int, type[Exception]],
+ int | type[Exception],
Doc(
"""
The Exception class this would handle, or a status code.
diff --git a/fastapi/background.py b/fastapi/background.py
index 20803ba670..7677058c43 100644
--- a/fastapi/background.py
+++ b/fastapi/background.py
@@ -1,4 +1,5 @@
-from typing import Annotated, Any, Callable
+from collections.abc import Callable
+from typing import Annotated, Any
from annotated_doc import Doc
from starlette.background import BackgroundTasks as StarletteBackgroundTasks
diff --git a/fastapi/datastructures.py b/fastapi/datastructures.py
index 2bf5fdb262..c04b5f0f39 100644
--- a/fastapi/datastructures.py
+++ b/fastapi/datastructures.py
@@ -1,10 +1,8 @@
-from collections.abc import Mapping
+from collections.abc import Callable, Mapping
from typing import (
Annotated,
Any,
BinaryIO,
- Callable,
- Optional,
TypeVar,
cast,
)
@@ -58,11 +56,11 @@ class UploadFile(StarletteUploadFile):
BinaryIO,
Doc("The standard Python file object (non-async)."),
]
- filename: Annotated[Optional[str], Doc("The original file name.")]
- size: Annotated[Optional[int], Doc("The size of the file in bytes.")]
+ filename: Annotated[str | None, Doc("The original file name.")]
+ size: Annotated[int | None, Doc("The size of the file in bytes.")]
headers: Annotated[Headers, Doc("The headers of the request.")]
content_type: Annotated[
- Optional[str], Doc("The content type of the request, from the headers.")
+ str | None, Doc("The content type of the request, from the headers.")
]
async def write(
diff --git a/fastapi/dependencies/models.py b/fastapi/dependencies/models.py
index 58392326d6..25ffb0d2da 100644
--- a/fastapi/dependencies/models.py
+++ b/fastapi/dependencies/models.py
@@ -1,13 +1,13 @@
import inspect
import sys
+from collections.abc import Callable
from dataclasses import dataclass, field
from functools import cached_property, partial
-from typing import Any, Callable, Optional, Union
+from typing import Any, Literal
from fastapi._compat import ModelField
from fastapi.security.base import SecurityBase
from fastapi.types import DependencyCacheKey
-from typing_extensions import Literal
if sys.version_info >= (3, 13): # pragma: no cover
from inspect import iscoroutinefunction
@@ -15,7 +15,7 @@ else: # pragma: no cover
from asyncio import iscoroutinefunction
-def _unwrapped_call(call: Optional[Callable[..., Any]]) -> Any:
+def _unwrapped_call(call: Callable[..., Any] | None) -> Any:
if call is None:
return call # pragma: no cover
unwrapped = inspect.unwrap(_impartial(call))
@@ -36,19 +36,19 @@ class Dependant:
cookie_params: list[ModelField] = field(default_factory=list)
body_params: list[ModelField] = field(default_factory=list)
dependencies: list["Dependant"] = field(default_factory=list)
- name: Optional[str] = None
- call: Optional[Callable[..., Any]] = None
- request_param_name: Optional[str] = None
- websocket_param_name: Optional[str] = None
- http_connection_param_name: Optional[str] = None
- response_param_name: Optional[str] = None
- background_tasks_param_name: Optional[str] = None
- security_scopes_param_name: Optional[str] = None
- own_oauth_scopes: Optional[list[str]] = None
- parent_oauth_scopes: Optional[list[str]] = None
+ name: str | None = None
+ call: Callable[..., Any] | None = None
+ request_param_name: str | None = None
+ websocket_param_name: str | None = None
+ http_connection_param_name: str | None = None
+ response_param_name: str | None = None
+ background_tasks_param_name: str | None = None
+ security_scopes_param_name: str | None = None
+ own_oauth_scopes: list[str] | None = None
+ parent_oauth_scopes: list[str] | None = None
use_cache: bool = True
- path: Optional[str] = None
- scope: Union[Literal["function", "request"], None] = None
+ path: str | None = None
+ scope: Literal["function", "request"] | None = None
@cached_property
def oauth_scopes(self) -> list[str]:
@@ -185,7 +185,7 @@ class Dependant:
return False
@cached_property
- def computed_scope(self) -> Union[str, None]:
+ def computed_scope(self) -> str | None:
if self.scope:
return self.scope
if self.is_gen_callable or self.is_async_gen_callable:
diff --git a/fastapi/dependencies/utils.py b/fastapi/dependencies/utils.py
index 80f9c76e90..ab18ec2db6 100644
--- a/fastapi/dependencies/utils.py
+++ b/fastapi/dependencies/utils.py
@@ -1,21 +1,21 @@
import dataclasses
import inspect
import sys
-from collections.abc import Coroutine, Mapping, Sequence
+from collections.abc import Callable, Mapping, Sequence
from contextlib import AsyncExitStack, contextmanager
from copy import copy, deepcopy
from dataclasses import dataclass
from typing import (
Annotated,
Any,
- Callable,
ForwardRef,
- Optional,
+ Literal,
Union,
cast,
+ get_args,
+ get_origin,
)
-import anyio
from fastapi import params
from fastapi._compat import (
ModelField,
@@ -64,7 +64,6 @@ from starlette.datastructures import (
from starlette.requests import HTTPConnection, Request
from starlette.responses import Response
from starlette.websockets import WebSocket
-from typing_extensions import Literal, get_args, get_origin
from typing_inspection.typing_objects import is_typealiastype
multipart_not_installed_error = (
@@ -128,8 +127,8 @@ def get_flat_dependant(
dependant: Dependant,
*,
skip_repeats: bool = False,
- visited: Optional[list[DependencyCacheKey]] = None,
- parent_oauth_scopes: Optional[list[str]] = None,
+ visited: list[DependencyCacheKey] | None = None,
+ parent_oauth_scopes: list[str] | None = None,
) -> Dependant:
if visited is None:
visited = []
@@ -200,20 +199,17 @@ def get_flat_params(dependant: Dependant) -> list[ModelField]:
def _get_signature(call: Callable[..., Any]) -> inspect.Signature:
- if sys.version_info >= (3, 10):
- try:
- signature = inspect.signature(call, eval_str=True)
- except NameError:
- # Handle type annotations with if TYPE_CHECKING, not used by FastAPI
- # e.g. dependency return types
- if sys.version_info >= (3, 14):
- from annotationlib import Format
-
- signature = inspect.signature(call, annotation_format=Format.FORWARDREF)
- else:
- signature = inspect.signature(call)
- else:
- signature = inspect.signature(call)
+ try:
+ signature = inspect.signature(call, eval_str=True)
+ except NameError:
+ # Handle type annotations with if TYPE_CHECKING, not used by FastAPI
+ # e.g. dependency return types
+ if sys.version_info >= (3, 14):
+ from annotationlib import Format
+
+ signature = inspect.signature(call, annotation_format=Format.FORWARDREF)
+ else:
+ signature = inspect.signature(call)
return signature
@@ -259,11 +255,11 @@ def get_dependant(
*,
path: str,
call: Callable[..., Any],
- name: Optional[str] = None,
- own_oauth_scopes: Optional[list[str]] = None,
- parent_oauth_scopes: Optional[list[str]] = None,
+ name: str | None = None,
+ own_oauth_scopes: list[str] | None = None,
+ parent_oauth_scopes: list[str] | None = None,
use_cache: bool = True,
- scope: Union[Literal["function", "request"], None] = None,
+ scope: Literal["function", "request"] | None = None,
) -> Dependant:
dependant = Dependant(
call=call,
@@ -332,7 +328,7 @@ def get_dependant(
def add_non_field_param_to_dependency(
*, param_name: str, type_annotation: Any, dependant: Dependant
-) -> Optional[bool]:
+) -> bool | None:
if lenient_issubclass(type_annotation, Request):
dependant.request_param_name = param_name
return True
@@ -357,8 +353,8 @@ def add_non_field_param_to_dependency(
@dataclass
class ParamDetails:
type_annotation: Any
- depends: Optional[params.Depends]
- field: Optional[ModelField]
+ depends: params.Depends | None
+ field: ModelField | None
def analyze_param(
@@ -400,7 +396,7 @@ def analyze_param(
)
]
if fastapi_specific_annotations:
- fastapi_annotation: Union[FieldInfo, params.Depends, None] = (
+ fastapi_annotation: FieldInfo | params.Depends | None = (
fastapi_specific_annotations[-1]
)
else:
@@ -561,20 +557,20 @@ async def _solve_generator(
class SolvedDependency:
values: dict[str, Any]
errors: list[Any]
- background_tasks: Optional[StarletteBackgroundTasks]
+ background_tasks: StarletteBackgroundTasks | None
response: Response
dependency_cache: dict[DependencyCacheKey, Any]
async def solve_dependencies(
*,
- request: Union[Request, WebSocket],
+ request: Request | WebSocket,
dependant: Dependant,
- body: Optional[Union[dict[str, Any], FormData]] = None,
- background_tasks: Optional[StarletteBackgroundTasks] = None,
- response: Optional[Response] = None,
- dependency_overrides_provider: Optional[Any] = None,
- dependency_cache: Optional[dict[DependencyCacheKey, Any]] = None,
+ body: dict[str, Any] | FormData | None = None,
+ background_tasks: StarletteBackgroundTasks | None = None,
+ response: Response | None = None,
+ dependency_overrides_provider: Any | None = None,
+ dependency_cache: dict[DependencyCacheKey, Any] | None = None,
# TODO: remove this parameter later, no longer used, not removing it yet as some
# people might be monkey patching this function (although that's not supported)
async_exit_stack: AsyncExitStack,
@@ -722,7 +718,7 @@ def _is_json_field(field: ModelField) -> bool:
def _get_multidict_value(
- field: ModelField, values: Mapping[str, Any], alias: Union[str, None] = None
+ field: ModelField, values: Mapping[str, Any], alias: str | None = None
) -> Any:
alias = alias or get_validation_alias(field)
if (
@@ -754,7 +750,7 @@ def _get_multidict_value(
def request_params_to_args(
fields: Sequence[ModelField],
- received_params: Union[Mapping[str, Any], QueryParams, Headers],
+ received_params: Mapping[str, Any] | QueryParams | Headers,
) -> tuple[dict[str, Any], list[Any]]:
values: dict[str, Any] = {}
errors: list[dict[str, Any]] = []
@@ -902,17 +898,9 @@ async def _extract_form_body(
):
# For types
assert isinstance(value, sequence_types)
- results: list[Union[bytes, str]] = []
-
- async def process_fn(
- fn: Callable[[], Coroutine[Any, Any, Any]],
- ) -> None:
- result = await fn()
- results.append(result) # noqa: B023
-
- async with anyio.create_task_group() as tg:
- for sub_value in value:
- tg.start_soon(process_fn, sub_value.read)
+ results: list[bytes | str] = []
+ for sub_value in value:
+ results.append(await sub_value.read())
value = serialize_sequence_value(field=field, value=results)
if value is not None:
values[get_validation_alias(field)] = value
@@ -929,7 +917,7 @@ async def _extract_form_body(
async def request_body_to_args(
body_fields: list[ModelField],
- received_body: Optional[Union[dict[str, Any], FormData]],
+ received_body: dict[str, Any] | FormData | None,
embed_body_fields: bool,
) -> tuple[dict[str, Any], list[dict[str, Any]]]:
values: dict[str, Any] = {}
@@ -959,7 +947,7 @@ async def request_body_to_args(
return {first_field.name: v_}, errors_
for field in body_fields:
loc = ("body", get_validation_alias(field))
- value: Optional[Any] = None
+ value: Any | None = None
if body_to_process is not None:
try:
value = body_to_process.get(get_validation_alias(field))
@@ -979,7 +967,7 @@ async def request_body_to_args(
def get_body_field(
*, flat_dependant: Dependant, name: str, embed_body_fields: bool
-) -> Optional[ModelField]:
+) -> ModelField | None:
"""
Get a ModelField representing the request body for a path operation, combining
all body parameters into a single field if necessary.
diff --git a/fastapi/encoders.py b/fastapi/encoders.py
index b4661be4fa..e20255c110 100644
--- a/fastapi/encoders.py
+++ b/fastapi/encoders.py
@@ -1,6 +1,7 @@
import dataclasses
import datetime
from collections import defaultdict, deque
+from collections.abc import Callable
from decimal import Decimal
from enum import Enum
from ipaddress import (
@@ -14,7 +15,7 @@ from ipaddress import (
from pathlib import Path, PurePath
from re import Pattern
from types import GeneratorType
-from typing import Annotated, Any, Callable, Optional, Union
+from typing import Annotated, Any
from uuid import UUID
from annotated_doc import Doc
@@ -33,13 +34,13 @@ from ._compat import (
# Taken from Pydantic v1 as is
-def isoformat(o: Union[datetime.date, datetime.time]) -> str:
+def isoformat(o: datetime.date | datetime.time) -> str:
return o.isoformat()
# Adapted from Pydantic v1
# TODO: pv2 should this return strings instead?
-def decimal_encoder(dec_value: Decimal) -> Union[int, float]:
+def decimal_encoder(dec_value: Decimal) -> int | float:
"""
Encodes a Decimal as int if there's no exponent, otherwise float
@@ -118,7 +119,7 @@ def jsonable_encoder(
),
],
include: Annotated[
- Optional[IncEx],
+ IncEx | None,
Doc(
"""
Pydantic's `include` parameter, passed to Pydantic models to set the
@@ -127,7 +128,7 @@ def jsonable_encoder(
),
] = None,
exclude: Annotated[
- Optional[IncEx],
+ IncEx | None,
Doc(
"""
Pydantic's `exclude` parameter, passed to Pydantic models to set the
@@ -177,7 +178,7 @@ def jsonable_encoder(
),
] = False,
custom_encoder: Annotated[
- Optional[dict[Any, Callable[[Any], Any]]],
+ dict[Any, Callable[[Any], Any]] | None,
Doc(
"""
Pydantic's `custom_encoder` parameter, passed to Pydantic models to define
diff --git a/fastapi/exceptions.py b/fastapi/exceptions.py
index 62b4674de3..d7065c52fe 100644
--- a/fastapi/exceptions.py
+++ b/fastapi/exceptions.py
@@ -1,5 +1,5 @@
-from collections.abc import Sequence
-from typing import Annotated, Any, Optional, TypedDict, Union
+from collections.abc import Mapping, Sequence
+from typing import Annotated, Any, TypedDict
from annotated_doc import Doc
from pydantic import BaseModel, create_model
@@ -68,7 +68,7 @@ class HTTPException(StarletteHTTPException):
),
] = None,
headers: Annotated[
- Optional[dict[str, str]],
+ Mapping[str, str] | None,
Doc(
"""
Any headers to send to the client in the response.
@@ -137,7 +137,7 @@ class WebSocketException(StarletteWebSocketException):
),
],
reason: Annotated[
- Union[str, None],
+ str | None,
Doc(
"""
The reason to close the WebSocket connection.
@@ -176,7 +176,7 @@ class ValidationException(Exception):
self,
errors: Sequence[Any],
*,
- endpoint_ctx: Optional[EndpointContext] = None,
+ endpoint_ctx: EndpointContext | None = None,
) -> None:
self._errors = errors
self.endpoint_ctx = endpoint_ctx
@@ -215,7 +215,7 @@ class RequestValidationError(ValidationException):
errors: Sequence[Any],
*,
body: Any = None,
- endpoint_ctx: Optional[EndpointContext] = None,
+ endpoint_ctx: EndpointContext | None = None,
) -> None:
super().__init__(errors, endpoint_ctx=endpoint_ctx)
self.body = body
@@ -226,7 +226,7 @@ class WebSocketRequestValidationError(ValidationException):
self,
errors: Sequence[Any],
*,
- endpoint_ctx: Optional[EndpointContext] = None,
+ endpoint_ctx: EndpointContext | None = None,
) -> None:
super().__init__(errors, endpoint_ctx=endpoint_ctx)
@@ -237,7 +237,7 @@ class ResponseValidationError(ValidationException):
errors: Sequence[Any],
*,
body: Any = None,
- endpoint_ctx: Optional[EndpointContext] = None,
+ endpoint_ctx: EndpointContext | None = None,
) -> None:
super().__init__(errors, endpoint_ctx=endpoint_ctx)
self.body = body
diff --git a/fastapi/openapi/docs.py b/fastapi/openapi/docs.py
index bb387c609a..b845f87c1c 100644
--- a/fastapi/openapi/docs.py
+++ b/fastapi/openapi/docs.py
@@ -1,5 +1,5 @@
import json
-from typing import Annotated, Any, Optional
+from typing import Annotated, Any
from annotated_doc import Doc
from fastapi.encoders import jsonable_encoder
@@ -85,7 +85,7 @@ def get_swagger_ui_html(
),
] = "https://fastapi.tiangolo.com/img/favicon.png",
oauth2_redirect_url: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
The OAuth2 redirect URL, it is normally automatically handled by FastAPI.
@@ -96,7 +96,7 @@ def get_swagger_ui_html(
),
] = None,
init_oauth: Annotated[
- Optional[dict[str, Any]],
+ dict[str, Any] | None,
Doc(
"""
A dictionary with Swagger UI OAuth2 initialization configurations.
@@ -107,7 +107,7 @@ def get_swagger_ui_html(
),
] = None,
swagger_ui_parameters: Annotated[
- Optional[dict[str, Any]],
+ dict[str, Any] | None,
Doc(
"""
Configuration parameters for Swagger UI.
diff --git a/fastapi/openapi/models.py b/fastapi/openapi/models.py
index 0959906390..d7950241fc 100644
--- a/fastapi/openapi/models.py
+++ b/fastapi/openapi/models.py
@@ -1,6 +1,6 @@
-from collections.abc import Iterable, Mapping
+from collections.abc import Callable, Iterable, Mapping
from enum import Enum
-from typing import Annotated, Any, Callable, Optional, Union
+from typing import Annotated, Any, Literal, Optional, Union
from fastapi._compat import with_info_plain_validator_function
from fastapi.logger import logger
@@ -10,7 +10,7 @@ from pydantic import (
Field,
GetJsonSchemaHandler,
)
-from typing_extensions import Literal, TypedDict
+from typing_extensions import TypedDict
from typing_extensions import deprecated as typing_deprecated
try:
@@ -59,37 +59,37 @@ class BaseModelWithConfig(BaseModel):
class Contact(BaseModelWithConfig):
- name: Optional[str] = None
- url: Optional[AnyUrl] = None
- email: Optional[EmailStr] = None
+ name: str | None = None
+ url: AnyUrl | None = None
+ email: EmailStr | None = None
class License(BaseModelWithConfig):
name: str
- identifier: Optional[str] = None
- url: Optional[AnyUrl] = None
+ identifier: str | None = None
+ url: AnyUrl | None = None
class Info(BaseModelWithConfig):
title: str
- summary: Optional[str] = None
- description: Optional[str] = None
- termsOfService: Optional[str] = None
- contact: Optional[Contact] = None
- license: Optional[License] = None
+ summary: str | None = None
+ description: str | None = None
+ termsOfService: str | None = None
+ contact: Contact | None = None
+ license: License | None = None
version: str
class ServerVariable(BaseModelWithConfig):
- enum: Annotated[Optional[list[str]], Field(min_length=1)] = None
+ enum: Annotated[list[str] | None, Field(min_length=1)] = None
default: str
- description: Optional[str] = None
+ description: str | None = None
class Server(BaseModelWithConfig):
- url: Union[AnyUrl, str]
- description: Optional[str] = None
- variables: Optional[dict[str, ServerVariable]] = None
+ url: AnyUrl | str
+ description: str | None = None
+ variables: dict[str, ServerVariable] | None = None
class Reference(BaseModel):
@@ -98,19 +98,19 @@ class Reference(BaseModel):
class Discriminator(BaseModel):
propertyName: str
- mapping: Optional[dict[str, str]] = None
+ mapping: dict[str, str] | None = None
class XML(BaseModelWithConfig):
- name: Optional[str] = None
- namespace: Optional[str] = None
- prefix: Optional[str] = None
- attribute: Optional[bool] = None
- wrapped: Optional[bool] = None
+ name: str | None = None
+ namespace: str | None = None
+ prefix: str | None = None
+ attribute: bool | None = None
+ wrapped: bool | None = None
class ExternalDocumentation(BaseModelWithConfig):
- description: Optional[str] = None
+ description: str | None = None
url: AnyUrl
@@ -123,80 +123,80 @@ SchemaType = Literal[
class Schema(BaseModelWithConfig):
# Ref: JSON Schema 2020-12: https://json-schema.org/draft/2020-12/json-schema-core.html#name-the-json-schema-core-vocabu
# Core Vocabulary
- schema_: Optional[str] = Field(default=None, alias="$schema")
- vocabulary: Optional[str] = Field(default=None, alias="$vocabulary")
- id: Optional[str] = Field(default=None, alias="$id")
- anchor: Optional[str] = Field(default=None, alias="$anchor")
- dynamicAnchor: Optional[str] = Field(default=None, alias="$dynamicAnchor")
- ref: Optional[str] = Field(default=None, alias="$ref")
- dynamicRef: Optional[str] = Field(default=None, alias="$dynamicRef")
- defs: Optional[dict[str, "SchemaOrBool"]] = Field(default=None, alias="$defs")
- comment: Optional[str] = Field(default=None, alias="$comment")
+ schema_: str | None = Field(default=None, alias="$schema")
+ vocabulary: str | None = Field(default=None, alias="$vocabulary")
+ id: str | None = Field(default=None, alias="$id")
+ anchor: str | None = Field(default=None, alias="$anchor")
+ dynamicAnchor: str | None = Field(default=None, alias="$dynamicAnchor")
+ ref: str | None = Field(default=None, alias="$ref")
+ dynamicRef: str | None = Field(default=None, alias="$dynamicRef")
+ defs: dict[str, "SchemaOrBool"] | None = Field(default=None, alias="$defs")
+ comment: str | None = Field(default=None, alias="$comment")
# Ref: JSON Schema 2020-12: https://json-schema.org/draft/2020-12/json-schema-core.html#name-a-vocabulary-for-applying-s
# A Vocabulary for Applying Subschemas
- allOf: Optional[list["SchemaOrBool"]] = None
- anyOf: Optional[list["SchemaOrBool"]] = None
- oneOf: Optional[list["SchemaOrBool"]] = None
+ allOf: list["SchemaOrBool"] | None = None
+ anyOf: list["SchemaOrBool"] | None = None
+ oneOf: list["SchemaOrBool"] | None = None
not_: Optional["SchemaOrBool"] = Field(default=None, alias="not")
if_: Optional["SchemaOrBool"] = Field(default=None, alias="if")
then: Optional["SchemaOrBool"] = None
else_: Optional["SchemaOrBool"] = Field(default=None, alias="else")
- dependentSchemas: Optional[dict[str, "SchemaOrBool"]] = None
- prefixItems: Optional[list["SchemaOrBool"]] = None
+ dependentSchemas: dict[str, "SchemaOrBool"] | None = None
+ prefixItems: list["SchemaOrBool"] | None = None
items: Optional["SchemaOrBool"] = None
contains: Optional["SchemaOrBool"] = None
- properties: Optional[dict[str, "SchemaOrBool"]] = None
- patternProperties: Optional[dict[str, "SchemaOrBool"]] = None
+ properties: dict[str, "SchemaOrBool"] | None = None
+ patternProperties: dict[str, "SchemaOrBool"] | None = None
additionalProperties: Optional["SchemaOrBool"] = None
propertyNames: Optional["SchemaOrBool"] = None
unevaluatedItems: Optional["SchemaOrBool"] = None
unevaluatedProperties: Optional["SchemaOrBool"] = None
# Ref: JSON Schema Validation 2020-12: https://json-schema.org/draft/2020-12/json-schema-validation.html#name-a-vocabulary-for-structural
# A Vocabulary for Structural Validation
- type: Optional[Union[SchemaType, list[SchemaType]]] = None
- enum: Optional[list[Any]] = None
- const: Optional[Any] = None
- multipleOf: Optional[float] = Field(default=None, gt=0)
- maximum: Optional[float] = None
- exclusiveMaximum: Optional[float] = None
- minimum: Optional[float] = None
- exclusiveMinimum: Optional[float] = None
- maxLength: Optional[int] = Field(default=None, ge=0)
- minLength: Optional[int] = Field(default=None, ge=0)
- pattern: Optional[str] = None
- maxItems: Optional[int] = Field(default=None, ge=0)
- minItems: Optional[int] = Field(default=None, ge=0)
- uniqueItems: Optional[bool] = None
- maxContains: Optional[int] = Field(default=None, ge=0)
- minContains: Optional[int] = Field(default=None, ge=0)
- maxProperties: Optional[int] = Field(default=None, ge=0)
- minProperties: Optional[int] = Field(default=None, ge=0)
- required: Optional[list[str]] = None
- dependentRequired: Optional[dict[str, set[str]]] = None
+ type: SchemaType | list[SchemaType] | None = None
+ enum: list[Any] | None = None
+ const: Any | None = None
+ multipleOf: float | None = Field(default=None, gt=0)
+ maximum: float | None = None
+ exclusiveMaximum: float | None = None
+ minimum: float | None = None
+ exclusiveMinimum: float | None = None
+ maxLength: int | None = Field(default=None, ge=0)
+ minLength: int | None = Field(default=None, ge=0)
+ pattern: str | None = None
+ maxItems: int | None = Field(default=None, ge=0)
+ minItems: int | None = Field(default=None, ge=0)
+ uniqueItems: bool | None = None
+ maxContains: int | None = Field(default=None, ge=0)
+ minContains: int | None = Field(default=None, ge=0)
+ maxProperties: int | None = Field(default=None, ge=0)
+ minProperties: int | None = Field(default=None, ge=0)
+ required: list[str] | None = None
+ dependentRequired: dict[str, set[str]] | None = None
# Ref: JSON Schema Validation 2020-12: https://json-schema.org/draft/2020-12/json-schema-validation.html#name-vocabularies-for-semantic-c
# Vocabularies for Semantic Content With "format"
- format: Optional[str] = None
+ format: str | None = None
# Ref: JSON Schema Validation 2020-12: https://json-schema.org/draft/2020-12/json-schema-validation.html#name-a-vocabulary-for-the-conten
# A Vocabulary for the Contents of String-Encoded Data
- contentEncoding: Optional[str] = None
- contentMediaType: Optional[str] = None
+ contentEncoding: str | None = None
+ contentMediaType: str | None = None
contentSchema: Optional["SchemaOrBool"] = None
# Ref: JSON Schema Validation 2020-12: https://json-schema.org/draft/2020-12/json-schema-validation.html#name-a-vocabulary-for-basic-meta
# A Vocabulary for Basic Meta-Data Annotations
- title: Optional[str] = None
- description: Optional[str] = None
- default: Optional[Any] = None
- deprecated: Optional[bool] = None
- readOnly: Optional[bool] = None
- writeOnly: Optional[bool] = None
- examples: Optional[list[Any]] = None
+ title: str | None = None
+ description: str | None = None
+ default: Any | None = None
+ deprecated: bool | None = None
+ readOnly: bool | None = None
+ writeOnly: bool | None = None
+ examples: list[Any] | None = None
# Ref: OpenAPI 3.1.0: https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#schema-object
# Schema Object
- discriminator: Optional[Discriminator] = None
- xml: Optional[XML] = None
- externalDocs: Optional[ExternalDocumentation] = None
+ discriminator: Discriminator | None = None
+ xml: XML | None = None
+ externalDocs: ExternalDocumentation | None = None
example: Annotated[
- Optional[Any],
+ Any | None,
typing_deprecated(
"Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, "
"although still supported. Use examples instead."
@@ -206,14 +206,14 @@ class Schema(BaseModelWithConfig):
# Ref: https://json-schema.org/draft/2020-12/json-schema-core.html#name-json-schema-documents
# A JSON Schema MUST be an object or a boolean.
-SchemaOrBool = Union[Schema, bool]
+SchemaOrBool = Schema | bool
class Example(TypedDict, total=False):
- summary: Optional[str]
- description: Optional[str]
- value: Optional[Any]
- externalValue: Optional[AnyUrl]
+ summary: str | None
+ description: str | None
+ value: Any | None
+ externalValue: AnyUrl | None
__pydantic_config__ = {"extra": "allow"} # type: ignore[misc]
@@ -226,33 +226,33 @@ class ParameterInType(Enum):
class Encoding(BaseModelWithConfig):
- contentType: Optional[str] = None
- headers: Optional[dict[str, Union["Header", Reference]]] = None
- style: Optional[str] = None
- explode: Optional[bool] = None
- allowReserved: Optional[bool] = None
+ contentType: str | None = None
+ headers: dict[str, Union["Header", Reference]] | None = None
+ style: str | None = None
+ explode: bool | None = None
+ allowReserved: bool | None = None
class MediaType(BaseModelWithConfig):
- schema_: Optional[Union[Schema, Reference]] = Field(default=None, alias="schema")
- example: Optional[Any] = None
- examples: Optional[dict[str, Union[Example, Reference]]] = None
- encoding: Optional[dict[str, Encoding]] = None
+ schema_: Schema | Reference | None = Field(default=None, alias="schema")
+ example: Any | None = None
+ examples: dict[str, Example | Reference] | None = None
+ encoding: dict[str, Encoding] | None = None
class ParameterBase(BaseModelWithConfig):
- description: Optional[str] = None
- required: Optional[bool] = None
- deprecated: Optional[bool] = None
+ description: str | None = None
+ required: bool | None = None
+ deprecated: bool | None = None
# Serialization rules for simple scenarios
- style: Optional[str] = None
- explode: Optional[bool] = None
- allowReserved: Optional[bool] = None
- schema_: Optional[Union[Schema, Reference]] = Field(default=None, alias="schema")
- example: Optional[Any] = None
- examples: Optional[dict[str, Union[Example, Reference]]] = None
+ style: str | None = None
+ explode: bool | None = None
+ allowReserved: bool | None = None
+ schema_: Schema | Reference | None = Field(default=None, alias="schema")
+ example: Any | None = None
+ examples: dict[str, Example | Reference] | None = None
# Serialization rules for more complex scenarios
- content: Optional[dict[str, MediaType]] = None
+ content: dict[str, MediaType] | None = None
class Parameter(ParameterBase):
@@ -265,57 +265,57 @@ class Header(ParameterBase):
class RequestBody(BaseModelWithConfig):
- description: Optional[str] = None
+ description: str | None = None
content: dict[str, MediaType]
- required: Optional[bool] = None
+ required: bool | None = None
class Link(BaseModelWithConfig):
- operationRef: Optional[str] = None
- operationId: Optional[str] = None
- parameters: Optional[dict[str, Union[Any, str]]] = None
- requestBody: Optional[Union[Any, str]] = None
- description: Optional[str] = None
- server: Optional[Server] = None
+ operationRef: str | None = None
+ operationId: str | None = None
+ parameters: dict[str, Any | str] | None = None
+ requestBody: Any | str | None = None
+ description: str | None = None
+ server: Server | None = None
class Response(BaseModelWithConfig):
description: str
- headers: Optional[dict[str, Union[Header, Reference]]] = None
- content: Optional[dict[str, MediaType]] = None
- links: Optional[dict[str, Union[Link, Reference]]] = None
+ headers: dict[str, Header | Reference] | None = None
+ content: dict[str, MediaType] | None = None
+ links: dict[str, Link | Reference] | None = None
class Operation(BaseModelWithConfig):
- tags: Optional[list[str]] = None
- summary: Optional[str] = None
- description: Optional[str] = None
- externalDocs: Optional[ExternalDocumentation] = None
- operationId: Optional[str] = None
- parameters: Optional[list[Union[Parameter, Reference]]] = None
- requestBody: Optional[Union[RequestBody, Reference]] = None
+ tags: list[str] | None = None
+ summary: str | None = None
+ description: str | None = None
+ externalDocs: ExternalDocumentation | None = None
+ operationId: str | None = None
+ parameters: list[Parameter | Reference] | None = None
+ requestBody: RequestBody | Reference | None = None
# Using Any for Specification Extensions
- responses: Optional[dict[str, Union[Response, Any]]] = None
- callbacks: Optional[dict[str, Union[dict[str, "PathItem"], Reference]]] = None
- deprecated: Optional[bool] = None
- security: Optional[list[dict[str, list[str]]]] = None
- servers: Optional[list[Server]] = None
+ responses: dict[str, Response | Any] | None = None
+ callbacks: dict[str, dict[str, "PathItem"] | Reference] | None = None
+ deprecated: bool | None = None
+ security: list[dict[str, list[str]]] | None = None
+ servers: list[Server] | None = None
class PathItem(BaseModelWithConfig):
- ref: Optional[str] = Field(default=None, alias="$ref")
- summary: Optional[str] = None
- description: Optional[str] = None
- get: Optional[Operation] = None
- put: Optional[Operation] = None
- post: Optional[Operation] = None
- delete: Optional[Operation] = None
- options: Optional[Operation] = None
- head: Optional[Operation] = None
- patch: Optional[Operation] = None
- trace: Optional[Operation] = None
- servers: Optional[list[Server]] = None
- parameters: Optional[list[Union[Parameter, Reference]]] = None
+ ref: str | None = Field(default=None, alias="$ref")
+ summary: str | None = None
+ description: str | None = None
+ get: Operation | None = None
+ put: Operation | None = None
+ post: Operation | None = None
+ delete: Operation | None = None
+ options: Operation | None = None
+ head: Operation | None = None
+ patch: Operation | None = None
+ trace: Operation | None = None
+ servers: list[Server] | None = None
+ parameters: list[Parameter | Reference] | None = None
class SecuritySchemeType(Enum):
@@ -327,7 +327,7 @@ class SecuritySchemeType(Enum):
class SecurityBase(BaseModelWithConfig):
type_: SecuritySchemeType = Field(alias="type")
- description: Optional[str] = None
+ description: str | None = None
class APIKeyIn(Enum):
@@ -349,11 +349,11 @@ class HTTPBase(SecurityBase):
class HTTPBearer(HTTPBase):
scheme: Literal["bearer"] = "bearer"
- bearerFormat: Optional[str] = None
+ bearerFormat: str | None = None
class OAuthFlow(BaseModelWithConfig):
- refreshUrl: Optional[str] = None
+ refreshUrl: str | None = None
scopes: dict[str, str] = {}
@@ -375,10 +375,10 @@ class OAuthFlowAuthorizationCode(OAuthFlow):
class OAuthFlows(BaseModelWithConfig):
- implicit: Optional[OAuthFlowImplicit] = None
- password: Optional[OAuthFlowPassword] = None
- clientCredentials: Optional[OAuthFlowClientCredentials] = None
- authorizationCode: Optional[OAuthFlowAuthorizationCode] = None
+ implicit: OAuthFlowImplicit | None = None
+ password: OAuthFlowPassword | None = None
+ clientCredentials: OAuthFlowClientCredentials | None = None
+ authorizationCode: OAuthFlowAuthorizationCode | None = None
class OAuth2(SecurityBase):
@@ -393,41 +393,41 @@ class OpenIdConnect(SecurityBase):
openIdConnectUrl: str
-SecurityScheme = Union[APIKey, HTTPBase, OAuth2, OpenIdConnect, HTTPBearer]
+SecurityScheme = APIKey | HTTPBase | OAuth2 | OpenIdConnect | HTTPBearer
class Components(BaseModelWithConfig):
- schemas: Optional[dict[str, Union[Schema, Reference]]] = None
- responses: Optional[dict[str, Union[Response, Reference]]] = None
- parameters: Optional[dict[str, Union[Parameter, Reference]]] = None
- examples: Optional[dict[str, Union[Example, Reference]]] = None
- requestBodies: Optional[dict[str, Union[RequestBody, Reference]]] = None
- headers: Optional[dict[str, Union[Header, Reference]]] = None
- securitySchemes: Optional[dict[str, Union[SecurityScheme, Reference]]] = None
- links: Optional[dict[str, Union[Link, Reference]]] = None
+ schemas: dict[str, Schema | Reference] | None = None
+ responses: dict[str, Response | Reference] | None = None
+ parameters: dict[str, Parameter | Reference] | None = None
+ examples: dict[str, Example | Reference] | None = None
+ requestBodies: dict[str, RequestBody | Reference] | None = None
+ headers: dict[str, Header | Reference] | None = None
+ securitySchemes: dict[str, SecurityScheme | Reference] | None = None
+ links: dict[str, Link | Reference] | None = None
# Using Any for Specification Extensions
- callbacks: Optional[dict[str, Union[dict[str, PathItem], Reference, Any]]] = None
- pathItems: Optional[dict[str, Union[PathItem, Reference]]] = None
+ callbacks: dict[str, dict[str, PathItem] | Reference | Any] | None = None
+ pathItems: dict[str, PathItem | Reference] | None = None
class Tag(BaseModelWithConfig):
name: str
- description: Optional[str] = None
- externalDocs: Optional[ExternalDocumentation] = None
+ description: str | None = None
+ externalDocs: ExternalDocumentation | None = None
class OpenAPI(BaseModelWithConfig):
openapi: str
info: Info
- jsonSchemaDialect: Optional[str] = None
- servers: Optional[list[Server]] = None
+ jsonSchemaDialect: str | None = None
+ servers: list[Server] | None = None
# Using Any for Specification Extensions
- paths: Optional[dict[str, Union[PathItem, Any]]] = None
- webhooks: Optional[dict[str, Union[PathItem, Reference]]] = None
- components: Optional[Components] = None
- security: Optional[list[dict[str, list[str]]]] = None
- tags: Optional[list[Tag]] = None
- externalDocs: Optional[ExternalDocumentation] = None
+ paths: dict[str, PathItem | Any] | None = None
+ webhooks: dict[str, PathItem | Reference] | None = None
+ components: Components | None = None
+ security: list[dict[str, list[str]]] | None = None
+ tags: list[Tag] | None = None
+ externalDocs: ExternalDocumentation | None = None
Schema.model_rebuild()
diff --git a/fastapi/openapi/utils.py b/fastapi/openapi/utils.py
index bcad0be75d..812003aee3 100644
--- a/fastapi/openapi/utils.py
+++ b/fastapi/openapi/utils.py
@@ -3,7 +3,7 @@ import http.client
import inspect
import warnings
from collections.abc import Sequence
-from typing import Any, Optional, Union, cast
+from typing import Any, Literal, cast
from fastapi import routing
from fastapi._compat import (
@@ -38,7 +38,6 @@ from fastapi.utils import (
from pydantic import BaseModel
from starlette.responses import JSONResponse
from starlette.routing import BaseRoute
-from typing_extensions import Literal
validation_error_definition = {
"title": "ValidationError",
@@ -180,13 +179,13 @@ def _get_openapi_operation_parameters(
def get_openapi_operation_request_body(
*,
- body_field: Optional[ModelField],
+ body_field: ModelField | None,
model_name_map: ModelNameMap,
field_mapping: dict[
tuple[ModelField, Literal["validation", "serialization"]], dict[str, Any]
],
separate_input_output_schemas: bool = True,
-) -> Optional[dict[str, Any]]:
+) -> dict[str, Any] | None:
if not body_field:
return None
assert isinstance(body_field, ModelField)
@@ -279,7 +278,7 @@ def get_openapi_path(
else:
current_response_class = route.response_class
assert current_response_class, "A response class is needed to generate OpenAPI"
- route_response_media_type: Optional[str] = current_response_class.media_type
+ route_response_media_type: str | None = current_response_class.media_type
if route.include_in_schema:
for method in route.methods:
operation = get_openapi_operation_metadata(
@@ -393,7 +392,7 @@ def get_openapi_path(
"An additional response must be a dict"
)
field = route.response_fields.get(additional_status_code)
- additional_field_schema: Optional[dict[str, Any]] = None
+ additional_field_schema: dict[str, Any] | None = None
if field:
additional_field_schema = get_schema_from_model_field(
field=field,
@@ -408,7 +407,7 @@ def get_openapi_path(
.setdefault("schema", {})
)
deep_dict_update(additional_schema, additional_field_schema)
- status_text: Optional[str] = status_code_ranges.get(
+ status_text: str | None = status_code_ranges.get(
str(additional_status_code).upper()
) or http.client.responses.get(int(additional_status_code))
description = (
@@ -482,17 +481,17 @@ def get_openapi(
title: str,
version: str,
openapi_version: str = "3.1.0",
- summary: Optional[str] = None,
- description: Optional[str] = None,
+ summary: str | None = None,
+ description: str | None = None,
routes: Sequence[BaseRoute],
- webhooks: Optional[Sequence[BaseRoute]] = None,
- tags: Optional[list[dict[str, Any]]] = None,
- servers: Optional[list[dict[str, Union[str, Any]]]] = None,
- terms_of_service: Optional[str] = None,
- contact: Optional[dict[str, Union[str, Any]]] = None,
- license_info: Optional[dict[str, Union[str, Any]]] = None,
+ webhooks: Sequence[BaseRoute] | None = None,
+ tags: list[dict[str, Any]] | None = None,
+ servers: list[dict[str, str | Any]] | None = None,
+ terms_of_service: str | None = None,
+ contact: dict[str, str | Any] | None = None,
+ license_info: dict[str, str | Any] | None = None,
separate_input_output_schemas: bool = True,
- external_docs: Optional[dict[str, Any]] = None,
+ external_docs: dict[str, Any] | None = None,
) -> dict[str, Any]:
info: dict[str, Any] = {"title": title, "version": version}
if summary:
diff --git a/fastapi/param_functions.py b/fastapi/param_functions.py
index 9bd92be4c7..4be504f435 100644
--- a/fastapi/param_functions.py
+++ b/fastapi/param_functions.py
@@ -1,12 +1,12 @@
-from collections.abc import Sequence
-from typing import Annotated, Any, Callable, Optional, Union
+from collections.abc import Callable, Sequence
+from typing import Annotated, Any, Literal
from annotated_doc import Doc
from fastapi import params
from fastapi._compat import Undefined
from fastapi.openapi.models import Example
from pydantic import AliasChoices, AliasPath
-from typing_extensions import Literal, deprecated
+from typing_extensions import deprecated
_Unset: Any = Undefined
@@ -25,7 +25,7 @@ def Path( # noqa: N802
] = ...,
*,
default_factory: Annotated[
- Union[Callable[[], Any], None],
+ Callable[[], Any] | None,
Doc(
"""
A callable to generate the default value.
@@ -36,7 +36,7 @@ def Path( # noqa: N802
),
] = _Unset,
alias: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
An alternative name for the parameter field.
@@ -48,7 +48,7 @@ def Path( # noqa: N802
),
] = None,
alias_priority: Annotated[
- Union[int, None],
+ int | None,
Doc(
"""
Priority of the alias. This affects whether an alias generator is used.
@@ -56,7 +56,7 @@ def Path( # noqa: N802
),
] = _Unset,
validation_alias: Annotated[
- Union[str, AliasPath, AliasChoices, None],
+ str | AliasPath | AliasChoices | None,
Doc(
"""
'Whitelist' validation step. The parameter field will be the single one
@@ -65,7 +65,7 @@ def Path( # noqa: N802
),
] = None,
serialization_alias: Annotated[
- Union[str, None],
+ str | None,
Doc(
"""
'Blacklist' validation step. The vanilla parameter field will be the
@@ -75,7 +75,7 @@ def Path( # noqa: N802
),
] = None,
title: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
Human-readable title.
@@ -86,7 +86,7 @@ def Path( # noqa: N802
),
] = None,
description: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
Human-readable description.
@@ -94,7 +94,7 @@ def Path( # noqa: N802
),
] = None,
gt: Annotated[
- Optional[float],
+ float | None,
Doc(
"""
Greater than. If set, value must be greater than this. Only applicable to
@@ -106,7 +106,7 @@ def Path( # noqa: N802
),
] = None,
ge: Annotated[
- Optional[float],
+ float | None,
Doc(
"""
Greater than or equal. If set, value must be greater than or equal to
@@ -118,7 +118,7 @@ def Path( # noqa: N802
),
] = None,
lt: Annotated[
- Optional[float],
+ float | None,
Doc(
"""
Less than. If set, value must be less than this. Only applicable to numbers.
@@ -129,7 +129,7 @@ def Path( # noqa: N802
),
] = None,
le: Annotated[
- Optional[float],
+ float | None,
Doc(
"""
Less than or equal. If set, value must be less than or equal to this.
@@ -141,7 +141,7 @@ def Path( # noqa: N802
),
] = None,
min_length: Annotated[
- Optional[int],
+ int | None,
Doc(
"""
Minimum length for strings.
@@ -149,7 +149,7 @@ def Path( # noqa: N802
),
] = None,
max_length: Annotated[
- Optional[int],
+ int | None,
Doc(
"""
Maximum length for strings.
@@ -157,7 +157,7 @@ def Path( # noqa: N802
),
] = None,
pattern: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
RegEx pattern for strings.
@@ -165,7 +165,7 @@ def Path( # noqa: N802
),
] = None,
regex: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
RegEx pattern for strings.
@@ -176,7 +176,7 @@ def Path( # noqa: N802
),
] = None,
discriminator: Annotated[
- Union[str, None],
+ str | None,
Doc(
"""
Parameter field name for discriminating the type in a tagged union.
@@ -184,7 +184,7 @@ def Path( # noqa: N802
),
] = None,
strict: Annotated[
- Union[bool, None],
+ bool | None,
Doc(
"""
If `True`, strict validation is applied to the field.
@@ -192,7 +192,7 @@ def Path( # noqa: N802
),
] = _Unset,
multiple_of: Annotated[
- Union[float, None],
+ float | None,
Doc(
"""
Value must be a multiple of this. Only applicable to numbers.
@@ -200,7 +200,7 @@ def Path( # noqa: N802
),
] = _Unset,
allow_inf_nan: Annotated[
- Union[bool, None],
+ bool | None,
Doc(
"""
Allow `inf`, `-inf`, `nan`. Only applicable to numbers.
@@ -208,7 +208,7 @@ def Path( # noqa: N802
),
] = _Unset,
max_digits: Annotated[
- Union[int, None],
+ int | None,
Doc(
"""
Maximum number of allow digits for strings.
@@ -216,7 +216,7 @@ def Path( # noqa: N802
),
] = _Unset,
decimal_places: Annotated[
- Union[int, None],
+ int | None,
Doc(
"""
Maximum number of decimal places allowed for numbers.
@@ -224,7 +224,7 @@ def Path( # noqa: N802
),
] = _Unset,
examples: Annotated[
- Optional[list[Any]],
+ list[Any] | None,
Doc(
"""
Example values for this field.
@@ -235,14 +235,14 @@ def Path( # noqa: N802
),
] = None,
example: Annotated[
- Optional[Any],
+ Any | None,
deprecated(
"Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, "
"although still supported. Use examples instead."
),
] = _Unset,
openapi_examples: Annotated[
- Optional[dict[str, Example]],
+ dict[str, Example] | None,
Doc(
"""
OpenAPI-specific examples.
@@ -259,7 +259,7 @@ def Path( # noqa: N802
),
] = None,
deprecated: Annotated[
- Union[deprecated, str, bool, None],
+ deprecated | str | bool | None,
Doc(
"""
Mark this parameter field as deprecated.
@@ -280,7 +280,7 @@ def Path( # noqa: N802
),
] = True,
json_schema_extra: Annotated[
- Union[dict[str, Any], None],
+ dict[str, Any] | None,
Doc(
"""
Any additional JSON schema data.
@@ -369,7 +369,7 @@ def Query( # noqa: N802
] = Undefined,
*,
default_factory: Annotated[
- Union[Callable[[], Any], None],
+ Callable[[], Any] | None,
Doc(
"""
A callable to generate the default value.
@@ -380,7 +380,7 @@ def Query( # noqa: N802
),
] = _Unset,
alias: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
An alternative name for the parameter field.
@@ -395,7 +395,7 @@ def Query( # noqa: N802
),
] = None,
alias_priority: Annotated[
- Union[int, None],
+ int | None,
Doc(
"""
Priority of the alias. This affects whether an alias generator is used.
@@ -403,7 +403,7 @@ def Query( # noqa: N802
),
] = _Unset,
validation_alias: Annotated[
- Union[str, AliasPath, AliasChoices, None],
+ str | AliasPath | AliasChoices | None,
Doc(
"""
'Whitelist' validation step. The parameter field will be the single one
@@ -412,7 +412,7 @@ def Query( # noqa: N802
),
] = None,
serialization_alias: Annotated[
- Union[str, None],
+ str | None,
Doc(
"""
'Blacklist' validation step. The vanilla parameter field will be the
@@ -422,7 +422,7 @@ def Query( # noqa: N802
),
] = None,
title: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
Human-readable title.
@@ -433,7 +433,7 @@ def Query( # noqa: N802
),
] = None,
description: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
Human-readable description.
@@ -444,7 +444,7 @@ def Query( # noqa: N802
),
] = None,
gt: Annotated[
- Optional[float],
+ float | None,
Doc(
"""
Greater than. If set, value must be greater than this. Only applicable to
@@ -456,7 +456,7 @@ def Query( # noqa: N802
),
] = None,
ge: Annotated[
- Optional[float],
+ float | None,
Doc(
"""
Greater than or equal. If set, value must be greater than or equal to
@@ -468,7 +468,7 @@ def Query( # noqa: N802
),
] = None,
lt: Annotated[
- Optional[float],
+ float | None,
Doc(
"""
Less than. If set, value must be less than this. Only applicable to numbers.
@@ -479,7 +479,7 @@ def Query( # noqa: N802
),
] = None,
le: Annotated[
- Optional[float],
+ float | None,
Doc(
"""
Less than or equal. If set, value must be less than or equal to this.
@@ -491,7 +491,7 @@ def Query( # noqa: N802
),
] = None,
min_length: Annotated[
- Optional[int],
+ int | None,
Doc(
"""
Minimum length for strings.
@@ -502,7 +502,7 @@ def Query( # noqa: N802
),
] = None,
max_length: Annotated[
- Optional[int],
+ int | None,
Doc(
"""
Maximum length for strings.
@@ -513,7 +513,7 @@ def Query( # noqa: N802
),
] = None,
pattern: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
RegEx pattern for strings.
@@ -524,7 +524,7 @@ def Query( # noqa: N802
),
] = None,
regex: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
RegEx pattern for strings.
@@ -535,7 +535,7 @@ def Query( # noqa: N802
),
] = None,
discriminator: Annotated[
- Union[str, None],
+ str | None,
Doc(
"""
Parameter field name for discriminating the type in a tagged union.
@@ -543,7 +543,7 @@ def Query( # noqa: N802
),
] = None,
strict: Annotated[
- Union[bool, None],
+ bool | None,
Doc(
"""
If `True`, strict validation is applied to the field.
@@ -551,7 +551,7 @@ def Query( # noqa: N802
),
] = _Unset,
multiple_of: Annotated[
- Union[float, None],
+ float | None,
Doc(
"""
Value must be a multiple of this. Only applicable to numbers.
@@ -559,7 +559,7 @@ def Query( # noqa: N802
),
] = _Unset,
allow_inf_nan: Annotated[
- Union[bool, None],
+ bool | None,
Doc(
"""
Allow `inf`, `-inf`, `nan`. Only applicable to numbers.
@@ -567,7 +567,7 @@ def Query( # noqa: N802
),
] = _Unset,
max_digits: Annotated[
- Union[int, None],
+ int | None,
Doc(
"""
Maximum number of allow digits for strings.
@@ -575,7 +575,7 @@ def Query( # noqa: N802
),
] = _Unset,
decimal_places: Annotated[
- Union[int, None],
+ int | None,
Doc(
"""
Maximum number of decimal places allowed for numbers.
@@ -583,7 +583,7 @@ def Query( # noqa: N802
),
] = _Unset,
examples: Annotated[
- Optional[list[Any]],
+ list[Any] | None,
Doc(
"""
Example values for this field.
@@ -594,14 +594,14 @@ def Query( # noqa: N802
),
] = None,
example: Annotated[
- Optional[Any],
+ Any | None,
deprecated(
"Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, "
"although still supported. Use examples instead."
),
] = _Unset,
openapi_examples: Annotated[
- Optional[dict[str, Example]],
+ dict[str, Example] | None,
Doc(
"""
OpenAPI-specific examples.
@@ -618,7 +618,7 @@ def Query( # noqa: N802
),
] = None,
deprecated: Annotated[
- Union[deprecated, str, bool, None],
+ deprecated | str | bool | None,
Doc(
"""
Mark this parameter field as deprecated.
@@ -645,7 +645,7 @@ def Query( # noqa: N802
),
] = True,
json_schema_extra: Annotated[
- Union[dict[str, Any], None],
+ dict[str, Any] | None,
Doc(
"""
Any additional JSON schema data.
@@ -710,7 +710,7 @@ def Header( # noqa: N802
] = Undefined,
*,
default_factory: Annotated[
- Union[Callable[[], Any], None],
+ Callable[[], Any] | None,
Doc(
"""
A callable to generate the default value.
@@ -721,7 +721,7 @@ def Header( # noqa: N802
),
] = _Unset,
alias: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
An alternative name for the parameter field.
@@ -733,7 +733,7 @@ def Header( # noqa: N802
),
] = None,
alias_priority: Annotated[
- Union[int, None],
+ int | None,
Doc(
"""
Priority of the alias. This affects whether an alias generator is used.
@@ -741,7 +741,7 @@ def Header( # noqa: N802
),
] = _Unset,
validation_alias: Annotated[
- Union[str, AliasPath, AliasChoices, None],
+ str | AliasPath | AliasChoices | None,
Doc(
"""
'Whitelist' validation step. The parameter field will be the single one
@@ -750,7 +750,7 @@ def Header( # noqa: N802
),
] = None,
serialization_alias: Annotated[
- Union[str, None],
+ str | None,
Doc(
"""
'Blacklist' validation step. The vanilla parameter field will be the
@@ -771,7 +771,7 @@ def Header( # noqa: N802
),
] = True,
title: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
Human-readable title.
@@ -779,7 +779,7 @@ def Header( # noqa: N802
),
] = None,
description: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
Human-readable description.
@@ -787,7 +787,7 @@ def Header( # noqa: N802
),
] = None,
gt: Annotated[
- Optional[float],
+ float | None,
Doc(
"""
Greater than. If set, value must be greater than this. Only applicable to
@@ -796,7 +796,7 @@ def Header( # noqa: N802
),
] = None,
ge: Annotated[
- Optional[float],
+ float | None,
Doc(
"""
Greater than or equal. If set, value must be greater than or equal to
@@ -805,7 +805,7 @@ def Header( # noqa: N802
),
] = None,
lt: Annotated[
- Optional[float],
+ float | None,
Doc(
"""
Less than. If set, value must be less than this. Only applicable to numbers.
@@ -813,7 +813,7 @@ def Header( # noqa: N802
),
] = None,
le: Annotated[
- Optional[float],
+ float | None,
Doc(
"""
Less than or equal. If set, value must be less than or equal to this.
@@ -822,7 +822,7 @@ def Header( # noqa: N802
),
] = None,
min_length: Annotated[
- Optional[int],
+ int | None,
Doc(
"""
Minimum length for strings.
@@ -830,7 +830,7 @@ def Header( # noqa: N802
),
] = None,
max_length: Annotated[
- Optional[int],
+ int | None,
Doc(
"""
Maximum length for strings.
@@ -838,7 +838,7 @@ def Header( # noqa: N802
),
] = None,
pattern: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
RegEx pattern for strings.
@@ -846,7 +846,7 @@ def Header( # noqa: N802
),
] = None,
regex: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
RegEx pattern for strings.
@@ -857,7 +857,7 @@ def Header( # noqa: N802
),
] = None,
discriminator: Annotated[
- Union[str, None],
+ str | None,
Doc(
"""
Parameter field name for discriminating the type in a tagged union.
@@ -865,7 +865,7 @@ def Header( # noqa: N802
),
] = None,
strict: Annotated[
- Union[bool, None],
+ bool | None,
Doc(
"""
If `True`, strict validation is applied to the field.
@@ -873,7 +873,7 @@ def Header( # noqa: N802
),
] = _Unset,
multiple_of: Annotated[
- Union[float, None],
+ float | None,
Doc(
"""
Value must be a multiple of this. Only applicable to numbers.
@@ -881,7 +881,7 @@ def Header( # noqa: N802
),
] = _Unset,
allow_inf_nan: Annotated[
- Union[bool, None],
+ bool | None,
Doc(
"""
Allow `inf`, `-inf`, `nan`. Only applicable to numbers.
@@ -889,7 +889,7 @@ def Header( # noqa: N802
),
] = _Unset,
max_digits: Annotated[
- Union[int, None],
+ int | None,
Doc(
"""
Maximum number of allow digits for strings.
@@ -897,7 +897,7 @@ def Header( # noqa: N802
),
] = _Unset,
decimal_places: Annotated[
- Union[int, None],
+ int | None,
Doc(
"""
Maximum number of decimal places allowed for numbers.
@@ -905,7 +905,7 @@ def Header( # noqa: N802
),
] = _Unset,
examples: Annotated[
- Optional[list[Any]],
+ list[Any] | None,
Doc(
"""
Example values for this field.
@@ -916,14 +916,14 @@ def Header( # noqa: N802
),
] = None,
example: Annotated[
- Optional[Any],
+ Any | None,
deprecated(
"Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, "
"although still supported. Use examples instead."
),
] = _Unset,
openapi_examples: Annotated[
- Optional[dict[str, Example]],
+ dict[str, Example] | None,
Doc(
"""
OpenAPI-specific examples.
@@ -940,7 +940,7 @@ def Header( # noqa: N802
),
] = None,
deprecated: Annotated[
- Union[deprecated, str, bool, None],
+ deprecated | str | bool | None,
Doc(
"""
Mark this parameter field as deprecated.
@@ -961,7 +961,7 @@ def Header( # noqa: N802
),
] = True,
json_schema_extra: Annotated[
- Union[dict[str, Any], None],
+ dict[str, Any] | None,
Doc(
"""
Any additional JSON schema data.
@@ -1027,7 +1027,7 @@ def Cookie( # noqa: N802
] = Undefined,
*,
default_factory: Annotated[
- Union[Callable[[], Any], None],
+ Callable[[], Any] | None,
Doc(
"""
A callable to generate the default value.
@@ -1038,7 +1038,7 @@ def Cookie( # noqa: N802
),
] = _Unset,
alias: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
An alternative name for the parameter field.
@@ -1050,7 +1050,7 @@ def Cookie( # noqa: N802
),
] = None,
alias_priority: Annotated[
- Union[int, None],
+ int | None,
Doc(
"""
Priority of the alias. This affects whether an alias generator is used.
@@ -1058,7 +1058,7 @@ def Cookie( # noqa: N802
),
] = _Unset,
validation_alias: Annotated[
- Union[str, AliasPath, AliasChoices, None],
+ str | AliasPath | AliasChoices | None,
Doc(
"""
'Whitelist' validation step. The parameter field will be the single one
@@ -1067,7 +1067,7 @@ def Cookie( # noqa: N802
),
] = None,
serialization_alias: Annotated[
- Union[str, None],
+ str | None,
Doc(
"""
'Blacklist' validation step. The vanilla parameter field will be the
@@ -1077,7 +1077,7 @@ def Cookie( # noqa: N802
),
] = None,
title: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
Human-readable title.
@@ -1085,7 +1085,7 @@ def Cookie( # noqa: N802
),
] = None,
description: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
Human-readable description.
@@ -1093,7 +1093,7 @@ def Cookie( # noqa: N802
),
] = None,
gt: Annotated[
- Optional[float],
+ float | None,
Doc(
"""
Greater than. If set, value must be greater than this. Only applicable to
@@ -1102,7 +1102,7 @@ def Cookie( # noqa: N802
),
] = None,
ge: Annotated[
- Optional[float],
+ float | None,
Doc(
"""
Greater than or equal. If set, value must be greater than or equal to
@@ -1111,7 +1111,7 @@ def Cookie( # noqa: N802
),
] = None,
lt: Annotated[
- Optional[float],
+ float | None,
Doc(
"""
Less than. If set, value must be less than this. Only applicable to numbers.
@@ -1119,7 +1119,7 @@ def Cookie( # noqa: N802
),
] = None,
le: Annotated[
- Optional[float],
+ float | None,
Doc(
"""
Less than or equal. If set, value must be less than or equal to this.
@@ -1128,7 +1128,7 @@ def Cookie( # noqa: N802
),
] = None,
min_length: Annotated[
- Optional[int],
+ int | None,
Doc(
"""
Minimum length for strings.
@@ -1136,7 +1136,7 @@ def Cookie( # noqa: N802
),
] = None,
max_length: Annotated[
- Optional[int],
+ int | None,
Doc(
"""
Maximum length for strings.
@@ -1144,7 +1144,7 @@ def Cookie( # noqa: N802
),
] = None,
pattern: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
RegEx pattern for strings.
@@ -1152,7 +1152,7 @@ def Cookie( # noqa: N802
),
] = None,
regex: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
RegEx pattern for strings.
@@ -1163,7 +1163,7 @@ def Cookie( # noqa: N802
),
] = None,
discriminator: Annotated[
- Union[str, None],
+ str | None,
Doc(
"""
Parameter field name for discriminating the type in a tagged union.
@@ -1171,7 +1171,7 @@ def Cookie( # noqa: N802
),
] = None,
strict: Annotated[
- Union[bool, None],
+ bool | None,
Doc(
"""
If `True`, strict validation is applied to the field.
@@ -1179,7 +1179,7 @@ def Cookie( # noqa: N802
),
] = _Unset,
multiple_of: Annotated[
- Union[float, None],
+ float | None,
Doc(
"""
Value must be a multiple of this. Only applicable to numbers.
@@ -1187,7 +1187,7 @@ def Cookie( # noqa: N802
),
] = _Unset,
allow_inf_nan: Annotated[
- Union[bool, None],
+ bool | None,
Doc(
"""
Allow `inf`, `-inf`, `nan`. Only applicable to numbers.
@@ -1195,7 +1195,7 @@ def Cookie( # noqa: N802
),
] = _Unset,
max_digits: Annotated[
- Union[int, None],
+ int | None,
Doc(
"""
Maximum number of allow digits for strings.
@@ -1203,7 +1203,7 @@ def Cookie( # noqa: N802
),
] = _Unset,
decimal_places: Annotated[
- Union[int, None],
+ int | None,
Doc(
"""
Maximum number of decimal places allowed for numbers.
@@ -1211,7 +1211,7 @@ def Cookie( # noqa: N802
),
] = _Unset,
examples: Annotated[
- Optional[list[Any]],
+ list[Any] | None,
Doc(
"""
Example values for this field.
@@ -1222,14 +1222,14 @@ def Cookie( # noqa: N802
),
] = None,
example: Annotated[
- Optional[Any],
+ Any | None,
deprecated(
"Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, "
"although still supported. Use examples instead."
),
] = _Unset,
openapi_examples: Annotated[
- Optional[dict[str, Example]],
+ dict[str, Example] | None,
Doc(
"""
OpenAPI-specific examples.
@@ -1246,7 +1246,7 @@ def Cookie( # noqa: N802
),
] = None,
deprecated: Annotated[
- Union[deprecated, str, bool, None],
+ deprecated | str | bool | None,
Doc(
"""
Mark this parameter field as deprecated.
@@ -1267,7 +1267,7 @@ def Cookie( # noqa: N802
),
] = True,
json_schema_extra: Annotated[
- Union[dict[str, Any], None],
+ dict[str, Any] | None,
Doc(
"""
Any additional JSON schema data.
@@ -1332,7 +1332,7 @@ def Body( # noqa: N802
] = Undefined,
*,
default_factory: Annotated[
- Union[Callable[[], Any], None],
+ Callable[[], Any] | None,
Doc(
"""
A callable to generate the default value.
@@ -1343,7 +1343,7 @@ def Body( # noqa: N802
),
] = _Unset,
embed: Annotated[
- Union[bool, None],
+ bool | None,
Doc(
"""
When `embed` is `True`, the parameter will be expected in a JSON body as a
@@ -1366,7 +1366,7 @@ def Body( # noqa: N802
),
] = "application/json",
alias: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
An alternative name for the parameter field.
@@ -1378,7 +1378,7 @@ def Body( # noqa: N802
),
] = None,
alias_priority: Annotated[
- Union[int, None],
+ int | None,
Doc(
"""
Priority of the alias. This affects whether an alias generator is used.
@@ -1386,7 +1386,7 @@ def Body( # noqa: N802
),
] = _Unset,
validation_alias: Annotated[
- Union[str, AliasPath, AliasChoices, None],
+ str | AliasPath | AliasChoices | None,
Doc(
"""
'Whitelist' validation step. The parameter field will be the single one
@@ -1395,7 +1395,7 @@ def Body( # noqa: N802
),
] = None,
serialization_alias: Annotated[
- Union[str, None],
+ str | None,
Doc(
"""
'Blacklist' validation step. The vanilla parameter field will be the
@@ -1405,7 +1405,7 @@ def Body( # noqa: N802
),
] = None,
title: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
Human-readable title.
@@ -1413,7 +1413,7 @@ def Body( # noqa: N802
),
] = None,
description: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
Human-readable description.
@@ -1421,7 +1421,7 @@ def Body( # noqa: N802
),
] = None,
gt: Annotated[
- Optional[float],
+ float | None,
Doc(
"""
Greater than. If set, value must be greater than this. Only applicable to
@@ -1430,7 +1430,7 @@ def Body( # noqa: N802
),
] = None,
ge: Annotated[
- Optional[float],
+ float | None,
Doc(
"""
Greater than or equal. If set, value must be greater than or equal to
@@ -1439,7 +1439,7 @@ def Body( # noqa: N802
),
] = None,
lt: Annotated[
- Optional[float],
+ float | None,
Doc(
"""
Less than. If set, value must be less than this. Only applicable to numbers.
@@ -1447,7 +1447,7 @@ def Body( # noqa: N802
),
] = None,
le: Annotated[
- Optional[float],
+ float | None,
Doc(
"""
Less than or equal. If set, value must be less than or equal to this.
@@ -1456,7 +1456,7 @@ def Body( # noqa: N802
),
] = None,
min_length: Annotated[
- Optional[int],
+ int | None,
Doc(
"""
Minimum length for strings.
@@ -1464,7 +1464,7 @@ def Body( # noqa: N802
),
] = None,
max_length: Annotated[
- Optional[int],
+ int | None,
Doc(
"""
Maximum length for strings.
@@ -1472,7 +1472,7 @@ def Body( # noqa: N802
),
] = None,
pattern: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
RegEx pattern for strings.
@@ -1480,7 +1480,7 @@ def Body( # noqa: N802
),
] = None,
regex: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
RegEx pattern for strings.
@@ -1491,7 +1491,7 @@ def Body( # noqa: N802
),
] = None,
discriminator: Annotated[
- Union[str, None],
+ str | None,
Doc(
"""
Parameter field name for discriminating the type in a tagged union.
@@ -1499,7 +1499,7 @@ def Body( # noqa: N802
),
] = None,
strict: Annotated[
- Union[bool, None],
+ bool | None,
Doc(
"""
If `True`, strict validation is applied to the field.
@@ -1507,7 +1507,7 @@ def Body( # noqa: N802
),
] = _Unset,
multiple_of: Annotated[
- Union[float, None],
+ float | None,
Doc(
"""
Value must be a multiple of this. Only applicable to numbers.
@@ -1515,7 +1515,7 @@ def Body( # noqa: N802
),
] = _Unset,
allow_inf_nan: Annotated[
- Union[bool, None],
+ bool | None,
Doc(
"""
Allow `inf`, `-inf`, `nan`. Only applicable to numbers.
@@ -1523,7 +1523,7 @@ def Body( # noqa: N802
),
] = _Unset,
max_digits: Annotated[
- Union[int, None],
+ int | None,
Doc(
"""
Maximum number of allow digits for strings.
@@ -1531,7 +1531,7 @@ def Body( # noqa: N802
),
] = _Unset,
decimal_places: Annotated[
- Union[int, None],
+ int | None,
Doc(
"""
Maximum number of decimal places allowed for numbers.
@@ -1539,7 +1539,7 @@ def Body( # noqa: N802
),
] = _Unset,
examples: Annotated[
- Optional[list[Any]],
+ list[Any] | None,
Doc(
"""
Example values for this field.
@@ -1550,14 +1550,14 @@ def Body( # noqa: N802
),
] = None,
example: Annotated[
- Optional[Any],
+ Any | None,
deprecated(
"Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, "
"although still supported. Use examples instead."
),
] = _Unset,
openapi_examples: Annotated[
- Optional[dict[str, Example]],
+ dict[str, Example] | None,
Doc(
"""
OpenAPI-specific examples.
@@ -1574,7 +1574,7 @@ def Body( # noqa: N802
),
] = None,
deprecated: Annotated[
- Union[deprecated, str, bool, None],
+ deprecated | str | bool | None,
Doc(
"""
Mark this parameter field as deprecated.
@@ -1595,7 +1595,7 @@ def Body( # noqa: N802
),
] = True,
json_schema_extra: Annotated[
- Union[dict[str, Any], None],
+ dict[str, Any] | None,
Doc(
"""
Any additional JSON schema data.
@@ -1662,7 +1662,7 @@ def Form( # noqa: N802
] = Undefined,
*,
default_factory: Annotated[
- Union[Callable[[], Any], None],
+ Callable[[], Any] | None,
Doc(
"""
A callable to generate the default value.
@@ -1682,7 +1682,7 @@ def Form( # noqa: N802
),
] = "application/x-www-form-urlencoded",
alias: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
An alternative name for the parameter field.
@@ -1694,7 +1694,7 @@ def Form( # noqa: N802
),
] = None,
alias_priority: Annotated[
- Union[int, None],
+ int | None,
Doc(
"""
Priority of the alias. This affects whether an alias generator is used.
@@ -1702,7 +1702,7 @@ def Form( # noqa: N802
),
] = _Unset,
validation_alias: Annotated[
- Union[str, AliasPath, AliasChoices, None],
+ str | AliasPath | AliasChoices | None,
Doc(
"""
'Whitelist' validation step. The parameter field will be the single one
@@ -1711,7 +1711,7 @@ def Form( # noqa: N802
),
] = None,
serialization_alias: Annotated[
- Union[str, None],
+ str | None,
Doc(
"""
'Blacklist' validation step. The vanilla parameter field will be the
@@ -1721,7 +1721,7 @@ def Form( # noqa: N802
),
] = None,
title: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
Human-readable title.
@@ -1729,7 +1729,7 @@ def Form( # noqa: N802
),
] = None,
description: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
Human-readable description.
@@ -1737,7 +1737,7 @@ def Form( # noqa: N802
),
] = None,
gt: Annotated[
- Optional[float],
+ float | None,
Doc(
"""
Greater than. If set, value must be greater than this. Only applicable to
@@ -1746,7 +1746,7 @@ def Form( # noqa: N802
),
] = None,
ge: Annotated[
- Optional[float],
+ float | None,
Doc(
"""
Greater than or equal. If set, value must be greater than or equal to
@@ -1755,7 +1755,7 @@ def Form( # noqa: N802
),
] = None,
lt: Annotated[
- Optional[float],
+ float | None,
Doc(
"""
Less than. If set, value must be less than this. Only applicable to numbers.
@@ -1763,7 +1763,7 @@ def Form( # noqa: N802
),
] = None,
le: Annotated[
- Optional[float],
+ float | None,
Doc(
"""
Less than or equal. If set, value must be less than or equal to this.
@@ -1772,7 +1772,7 @@ def Form( # noqa: N802
),
] = None,
min_length: Annotated[
- Optional[int],
+ int | None,
Doc(
"""
Minimum length for strings.
@@ -1780,7 +1780,7 @@ def Form( # noqa: N802
),
] = None,
max_length: Annotated[
- Optional[int],
+ int | None,
Doc(
"""
Maximum length for strings.
@@ -1788,7 +1788,7 @@ def Form( # noqa: N802
),
] = None,
pattern: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
RegEx pattern for strings.
@@ -1796,7 +1796,7 @@ def Form( # noqa: N802
),
] = None,
regex: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
RegEx pattern for strings.
@@ -1807,7 +1807,7 @@ def Form( # noqa: N802
),
] = None,
discriminator: Annotated[
- Union[str, None],
+ str | None,
Doc(
"""
Parameter field name for discriminating the type in a tagged union.
@@ -1815,7 +1815,7 @@ def Form( # noqa: N802
),
] = None,
strict: Annotated[
- Union[bool, None],
+ bool | None,
Doc(
"""
If `True`, strict validation is applied to the field.
@@ -1823,7 +1823,7 @@ def Form( # noqa: N802
),
] = _Unset,
multiple_of: Annotated[
- Union[float, None],
+ float | None,
Doc(
"""
Value must be a multiple of this. Only applicable to numbers.
@@ -1831,7 +1831,7 @@ def Form( # noqa: N802
),
] = _Unset,
allow_inf_nan: Annotated[
- Union[bool, None],
+ bool | None,
Doc(
"""
Allow `inf`, `-inf`, `nan`. Only applicable to numbers.
@@ -1839,7 +1839,7 @@ def Form( # noqa: N802
),
] = _Unset,
max_digits: Annotated[
- Union[int, None],
+ int | None,
Doc(
"""
Maximum number of allow digits for strings.
@@ -1847,7 +1847,7 @@ def Form( # noqa: N802
),
] = _Unset,
decimal_places: Annotated[
- Union[int, None],
+ int | None,
Doc(
"""
Maximum number of decimal places allowed for numbers.
@@ -1855,7 +1855,7 @@ def Form( # noqa: N802
),
] = _Unset,
examples: Annotated[
- Optional[list[Any]],
+ list[Any] | None,
Doc(
"""
Example values for this field.
@@ -1866,14 +1866,14 @@ def Form( # noqa: N802
),
] = None,
example: Annotated[
- Optional[Any],
+ Any | None,
deprecated(
"Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, "
"although still supported. Use examples instead."
),
] = _Unset,
openapi_examples: Annotated[
- Optional[dict[str, Example]],
+ dict[str, Example] | None,
Doc(
"""
OpenAPI-specific examples.
@@ -1890,7 +1890,7 @@ def Form( # noqa: N802
),
] = None,
deprecated: Annotated[
- Union[deprecated, str, bool, None],
+ deprecated | str | bool | None,
Doc(
"""
Mark this parameter field as deprecated.
@@ -1911,7 +1911,7 @@ def Form( # noqa: N802
),
] = True,
json_schema_extra: Annotated[
- Union[dict[str, Any], None],
+ dict[str, Any] | None,
Doc(
"""
Any additional JSON schema data.
@@ -1977,7 +1977,7 @@ def File( # noqa: N802
] = Undefined,
*,
default_factory: Annotated[
- Union[Callable[[], Any], None],
+ Callable[[], Any] | None,
Doc(
"""
A callable to generate the default value.
@@ -1997,7 +1997,7 @@ def File( # noqa: N802
),
] = "multipart/form-data",
alias: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
An alternative name for the parameter field.
@@ -2009,7 +2009,7 @@ def File( # noqa: N802
),
] = None,
alias_priority: Annotated[
- Union[int, None],
+ int | None,
Doc(
"""
Priority of the alias. This affects whether an alias generator is used.
@@ -2017,7 +2017,7 @@ def File( # noqa: N802
),
] = _Unset,
validation_alias: Annotated[
- Union[str, AliasPath, AliasChoices, None],
+ str | AliasPath | AliasChoices | None,
Doc(
"""
'Whitelist' validation step. The parameter field will be the single one
@@ -2026,7 +2026,7 @@ def File( # noqa: N802
),
] = None,
serialization_alias: Annotated[
- Union[str, None],
+ str | None,
Doc(
"""
'Blacklist' validation step. The vanilla parameter field will be the
@@ -2036,7 +2036,7 @@ def File( # noqa: N802
),
] = None,
title: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
Human-readable title.
@@ -2044,7 +2044,7 @@ def File( # noqa: N802
),
] = None,
description: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
Human-readable description.
@@ -2052,7 +2052,7 @@ def File( # noqa: N802
),
] = None,
gt: Annotated[
- Optional[float],
+ float | None,
Doc(
"""
Greater than. If set, value must be greater than this. Only applicable to
@@ -2061,7 +2061,7 @@ def File( # noqa: N802
),
] = None,
ge: Annotated[
- Optional[float],
+ float | None,
Doc(
"""
Greater than or equal. If set, value must be greater than or equal to
@@ -2070,7 +2070,7 @@ def File( # noqa: N802
),
] = None,
lt: Annotated[
- Optional[float],
+ float | None,
Doc(
"""
Less than. If set, value must be less than this. Only applicable to numbers.
@@ -2078,7 +2078,7 @@ def File( # noqa: N802
),
] = None,
le: Annotated[
- Optional[float],
+ float | None,
Doc(
"""
Less than or equal. If set, value must be less than or equal to this.
@@ -2087,7 +2087,7 @@ def File( # noqa: N802
),
] = None,
min_length: Annotated[
- Optional[int],
+ int | None,
Doc(
"""
Minimum length for strings.
@@ -2095,7 +2095,7 @@ def File( # noqa: N802
),
] = None,
max_length: Annotated[
- Optional[int],
+ int | None,
Doc(
"""
Maximum length for strings.
@@ -2103,7 +2103,7 @@ def File( # noqa: N802
),
] = None,
pattern: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
RegEx pattern for strings.
@@ -2111,7 +2111,7 @@ def File( # noqa: N802
),
] = None,
regex: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
RegEx pattern for strings.
@@ -2122,7 +2122,7 @@ def File( # noqa: N802
),
] = None,
discriminator: Annotated[
- Union[str, None],
+ str | None,
Doc(
"""
Parameter field name for discriminating the type in a tagged union.
@@ -2130,7 +2130,7 @@ def File( # noqa: N802
),
] = None,
strict: Annotated[
- Union[bool, None],
+ bool | None,
Doc(
"""
If `True`, strict validation is applied to the field.
@@ -2138,7 +2138,7 @@ def File( # noqa: N802
),
] = _Unset,
multiple_of: Annotated[
- Union[float, None],
+ float | None,
Doc(
"""
Value must be a multiple of this. Only applicable to numbers.
@@ -2146,7 +2146,7 @@ def File( # noqa: N802
),
] = _Unset,
allow_inf_nan: Annotated[
- Union[bool, None],
+ bool | None,
Doc(
"""
Allow `inf`, `-inf`, `nan`. Only applicable to numbers.
@@ -2154,7 +2154,7 @@ def File( # noqa: N802
),
] = _Unset,
max_digits: Annotated[
- Union[int, None],
+ int | None,
Doc(
"""
Maximum number of allow digits for strings.
@@ -2162,7 +2162,7 @@ def File( # noqa: N802
),
] = _Unset,
decimal_places: Annotated[
- Union[int, None],
+ int | None,
Doc(
"""
Maximum number of decimal places allowed for numbers.
@@ -2170,7 +2170,7 @@ def File( # noqa: N802
),
] = _Unset,
examples: Annotated[
- Optional[list[Any]],
+ list[Any] | None,
Doc(
"""
Example values for this field.
@@ -2181,14 +2181,14 @@ def File( # noqa: N802
),
] = None,
example: Annotated[
- Optional[Any],
+ Any | None,
deprecated(
"Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, "
"although still supported. Use examples instead."
),
] = _Unset,
openapi_examples: Annotated[
- Optional[dict[str, Example]],
+ dict[str, Example] | None,
Doc(
"""
OpenAPI-specific examples.
@@ -2205,7 +2205,7 @@ def File( # noqa: N802
),
] = None,
deprecated: Annotated[
- Union[deprecated, str, bool, None],
+ deprecated | str | bool | None,
Doc(
"""
Mark this parameter field as deprecated.
@@ -2226,7 +2226,7 @@ def File( # noqa: N802
),
] = True,
json_schema_extra: Annotated[
- Union[dict[str, Any], None],
+ dict[str, Any] | None,
Doc(
"""
Any additional JSON schema data.
@@ -2283,7 +2283,7 @@ def File( # noqa: N802
def Depends( # noqa: N802
dependency: Annotated[
- Optional[Callable[..., Any]],
+ Callable[..., Any] | None,
Doc(
"""
A "dependable" callable (like a function).
@@ -2315,7 +2315,7 @@ def Depends( # noqa: N802
),
] = True,
scope: Annotated[
- Union[Literal["function", "request"], None],
+ Literal["function", "request"] | None,
Doc(
"""
Mainly for dependencies with `yield`, define when the dependency function
@@ -2372,7 +2372,7 @@ def Depends( # noqa: N802
def Security( # noqa: N802
dependency: Annotated[
- Optional[Callable[..., Any]],
+ Callable[..., Any] | None,
Doc(
"""
A "dependable" callable (like a function).
@@ -2387,7 +2387,7 @@ def Security( # noqa: N802
] = None,
*,
scopes: Annotated[
- Optional[Sequence[str]],
+ Sequence[str] | None,
Doc(
"""
OAuth2 scopes required for the *path operation* that uses this Security
diff --git a/fastapi/params.py b/fastapi/params.py
index 72e797f833..68f9870810 100644
--- a/fastapi/params.py
+++ b/fastapi/params.py
@@ -1,14 +1,14 @@
import warnings
-from collections.abc import Sequence
+from collections.abc import Callable, Sequence
from dataclasses import dataclass
from enum import Enum
-from typing import Annotated, Any, Callable, Optional, Union
+from typing import Annotated, Any, Literal
from fastapi.exceptions import FastAPIDeprecationWarning
from fastapi.openapi.models import Example
from pydantic import AliasChoices, AliasPath
from pydantic.fields import FieldInfo
-from typing_extensions import Literal, deprecated
+from typing_extensions import deprecated
from ._compat import (
Undefined,
@@ -31,45 +31,45 @@ class Param(FieldInfo): # type: ignore[misc]
self,
default: Any = Undefined,
*,
- default_factory: Union[Callable[[], Any], None] = _Unset,
- annotation: Optional[Any] = None,
- alias: Optional[str] = None,
- alias_priority: Union[int, None] = _Unset,
- validation_alias: Union[str, AliasPath, AliasChoices, None] = None,
- serialization_alias: Union[str, None] = None,
- title: Optional[str] = None,
- description: Optional[str] = None,
- gt: Optional[float] = None,
- ge: Optional[float] = None,
- lt: Optional[float] = None,
- le: Optional[float] = None,
- min_length: Optional[int] = None,
- max_length: Optional[int] = None,
- pattern: Optional[str] = None,
+ default_factory: Callable[[], Any] | None = _Unset,
+ annotation: Any | None = None,
+ alias: str | None = None,
+ alias_priority: int | None = _Unset,
+ validation_alias: str | AliasPath | AliasChoices | None = None,
+ serialization_alias: str | None = None,
+ title: str | None = None,
+ description: str | None = None,
+ gt: float | None = None,
+ ge: float | None = None,
+ lt: float | None = None,
+ le: float | None = None,
+ min_length: int | None = None,
+ max_length: int | None = None,
+ pattern: str | None = None,
regex: Annotated[
- Optional[str],
+ str | None,
deprecated(
"Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead."
),
] = None,
- discriminator: Union[str, None] = None,
- strict: Union[bool, None] = _Unset,
- multiple_of: Union[float, None] = _Unset,
- allow_inf_nan: Union[bool, None] = _Unset,
- max_digits: Union[int, None] = _Unset,
- decimal_places: Union[int, None] = _Unset,
- examples: Optional[list[Any]] = None,
+ discriminator: str | None = None,
+ strict: bool | None = _Unset,
+ multiple_of: float | None = _Unset,
+ allow_inf_nan: bool | None = _Unset,
+ max_digits: int | None = _Unset,
+ decimal_places: int | None = _Unset,
+ examples: list[Any] | None = None,
example: Annotated[
- Optional[Any],
+ Any | None,
deprecated(
"Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, "
"although still supported. Use examples instead."
),
] = _Unset,
- openapi_examples: Optional[dict[str, Example]] = None,
- deprecated: Union[deprecated, str, bool, None] = None,
+ openapi_examples: dict[str, Example] | None = None,
+ deprecated: deprecated | str | bool | None = None,
include_in_schema: bool = True,
- json_schema_extra: Union[dict[str, Any], None] = None,
+ json_schema_extra: dict[str, Any] | None = None,
**extra: Any,
):
if example is not _Unset:
@@ -142,45 +142,45 @@ class Path(Param): # type: ignore[misc]
self,
default: Any = ...,
*,
- default_factory: Union[Callable[[], Any], None] = _Unset,
- annotation: Optional[Any] = None,
- alias: Optional[str] = None,
- alias_priority: Union[int, None] = _Unset,
- validation_alias: Union[str, AliasPath, AliasChoices, None] = None,
- serialization_alias: Union[str, None] = None,
- title: Optional[str] = None,
- description: Optional[str] = None,
- gt: Optional[float] = None,
- ge: Optional[float] = None,
- lt: Optional[float] = None,
- le: Optional[float] = None,
- min_length: Optional[int] = None,
- max_length: Optional[int] = None,
- pattern: Optional[str] = None,
+ default_factory: Callable[[], Any] | None = _Unset,
+ annotation: Any | None = None,
+ alias: str | None = None,
+ alias_priority: int | None = _Unset,
+ validation_alias: str | AliasPath | AliasChoices | None = None,
+ serialization_alias: str | None = None,
+ title: str | None = None,
+ description: str | None = None,
+ gt: float | None = None,
+ ge: float | None = None,
+ lt: float | None = None,
+ le: float | None = None,
+ min_length: int | None = None,
+ max_length: int | None = None,
+ pattern: str | None = None,
regex: Annotated[
- Optional[str],
+ str | None,
deprecated(
"Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead."
),
] = None,
- discriminator: Union[str, None] = None,
- strict: Union[bool, None] = _Unset,
- multiple_of: Union[float, None] = _Unset,
- allow_inf_nan: Union[bool, None] = _Unset,
- max_digits: Union[int, None] = _Unset,
- decimal_places: Union[int, None] = _Unset,
- examples: Optional[list[Any]] = None,
+ discriminator: str | None = None,
+ strict: bool | None = _Unset,
+ multiple_of: float | None = _Unset,
+ allow_inf_nan: bool | None = _Unset,
+ max_digits: int | None = _Unset,
+ decimal_places: int | None = _Unset,
+ examples: list[Any] | None = None,
example: Annotated[
- Optional[Any],
+ Any | None,
deprecated(
"Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, "
"although still supported. Use examples instead."
),
] = _Unset,
- openapi_examples: Optional[dict[str, Example]] = None,
- deprecated: Union[deprecated, str, bool, None] = None,
+ openapi_examples: dict[str, Example] | None = None,
+ deprecated: deprecated | str | bool | None = None,
include_in_schema: bool = True,
- json_schema_extra: Union[dict[str, Any], None] = None,
+ json_schema_extra: dict[str, Any] | None = None,
**extra: Any,
):
assert default is ..., "Path parameters cannot have a default value"
@@ -226,45 +226,45 @@ class Query(Param): # type: ignore[misc]
self,
default: Any = Undefined,
*,
- default_factory: Union[Callable[[], Any], None] = _Unset,
- annotation: Optional[Any] = None,
- alias: Optional[str] = None,
- alias_priority: Union[int, None] = _Unset,
- validation_alias: Union[str, AliasPath, AliasChoices, None] = None,
- serialization_alias: Union[str, None] = None,
- title: Optional[str] = None,
- description: Optional[str] = None,
- gt: Optional[float] = None,
- ge: Optional[float] = None,
- lt: Optional[float] = None,
- le: Optional[float] = None,
- min_length: Optional[int] = None,
- max_length: Optional[int] = None,
- pattern: Optional[str] = None,
+ default_factory: Callable[[], Any] | None = _Unset,
+ annotation: Any | None = None,
+ alias: str | None = None,
+ alias_priority: int | None = _Unset,
+ validation_alias: str | AliasPath | AliasChoices | None = None,
+ serialization_alias: str | None = None,
+ title: str | None = None,
+ description: str | None = None,
+ gt: float | None = None,
+ ge: float | None = None,
+ lt: float | None = None,
+ le: float | None = None,
+ min_length: int | None = None,
+ max_length: int | None = None,
+ pattern: str | None = None,
regex: Annotated[
- Optional[str],
+ str | None,
deprecated(
"Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead."
),
] = None,
- discriminator: Union[str, None] = None,
- strict: Union[bool, None] = _Unset,
- multiple_of: Union[float, None] = _Unset,
- allow_inf_nan: Union[bool, None] = _Unset,
- max_digits: Union[int, None] = _Unset,
- decimal_places: Union[int, None] = _Unset,
- examples: Optional[list[Any]] = None,
+ discriminator: str | None = None,
+ strict: bool | None = _Unset,
+ multiple_of: float | None = _Unset,
+ allow_inf_nan: bool | None = _Unset,
+ max_digits: int | None = _Unset,
+ decimal_places: int | None = _Unset,
+ examples: list[Any] | None = None,
example: Annotated[
- Optional[Any],
+ Any | None,
deprecated(
"Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, "
"although still supported. Use examples instead."
),
] = _Unset,
- openapi_examples: Optional[dict[str, Example]] = None,
- deprecated: Union[deprecated, str, bool, None] = None,
+ openapi_examples: dict[str, Example] | None = None,
+ deprecated: deprecated | str | bool | None = None,
include_in_schema: bool = True,
- json_schema_extra: Union[dict[str, Any], None] = None,
+ json_schema_extra: dict[str, Any] | None = None,
**extra: Any,
):
super().__init__(
@@ -308,46 +308,46 @@ class Header(Param): # type: ignore[misc]
self,
default: Any = Undefined,
*,
- default_factory: Union[Callable[[], Any], None] = _Unset,
- annotation: Optional[Any] = None,
- alias: Optional[str] = None,
- alias_priority: Union[int, None] = _Unset,
- validation_alias: Union[str, AliasPath, AliasChoices, None] = None,
- serialization_alias: Union[str, None] = None,
+ default_factory: Callable[[], Any] | None = _Unset,
+ annotation: Any | None = None,
+ alias: str | None = None,
+ alias_priority: int | None = _Unset,
+ validation_alias: str | AliasPath | AliasChoices | None = None,
+ serialization_alias: str | None = None,
convert_underscores: bool = True,
- title: Optional[str] = None,
- description: Optional[str] = None,
- gt: Optional[float] = None,
- ge: Optional[float] = None,
- lt: Optional[float] = None,
- le: Optional[float] = None,
- min_length: Optional[int] = None,
- max_length: Optional[int] = None,
- pattern: Optional[str] = None,
+ title: str | None = None,
+ description: str | None = None,
+ gt: float | None = None,
+ ge: float | None = None,
+ lt: float | None = None,
+ le: float | None = None,
+ min_length: int | None = None,
+ max_length: int | None = None,
+ pattern: str | None = None,
regex: Annotated[
- Optional[str],
+ str | None,
deprecated(
"Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead."
),
] = None,
- discriminator: Union[str, None] = None,
- strict: Union[bool, None] = _Unset,
- multiple_of: Union[float, None] = _Unset,
- allow_inf_nan: Union[bool, None] = _Unset,
- max_digits: Union[int, None] = _Unset,
- decimal_places: Union[int, None] = _Unset,
- examples: Optional[list[Any]] = None,
+ discriminator: str | None = None,
+ strict: bool | None = _Unset,
+ multiple_of: float | None = _Unset,
+ allow_inf_nan: bool | None = _Unset,
+ max_digits: int | None = _Unset,
+ decimal_places: int | None = _Unset,
+ examples: list[Any] | None = None,
example: Annotated[
- Optional[Any],
+ Any | None,
deprecated(
"Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, "
"although still supported. Use examples instead."
),
] = _Unset,
- openapi_examples: Optional[dict[str, Example]] = None,
- deprecated: Union[deprecated, str, bool, None] = None,
+ openapi_examples: dict[str, Example] | None = None,
+ deprecated: deprecated | str | bool | None = None,
include_in_schema: bool = True,
- json_schema_extra: Union[dict[str, Any], None] = None,
+ json_schema_extra: dict[str, Any] | None = None,
**extra: Any,
):
self.convert_underscores = convert_underscores
@@ -392,45 +392,45 @@ class Cookie(Param): # type: ignore[misc]
self,
default: Any = Undefined,
*,
- default_factory: Union[Callable[[], Any], None] = _Unset,
- annotation: Optional[Any] = None,
- alias: Optional[str] = None,
- alias_priority: Union[int, None] = _Unset,
- validation_alias: Union[str, AliasPath, AliasChoices, None] = None,
- serialization_alias: Union[str, None] = None,
- title: Optional[str] = None,
- description: Optional[str] = None,
- gt: Optional[float] = None,
- ge: Optional[float] = None,
- lt: Optional[float] = None,
- le: Optional[float] = None,
- min_length: Optional[int] = None,
- max_length: Optional[int] = None,
- pattern: Optional[str] = None,
+ default_factory: Callable[[], Any] | None = _Unset,
+ annotation: Any | None = None,
+ alias: str | None = None,
+ alias_priority: int | None = _Unset,
+ validation_alias: str | AliasPath | AliasChoices | None = None,
+ serialization_alias: str | None = None,
+ title: str | None = None,
+ description: str | None = None,
+ gt: float | None = None,
+ ge: float | None = None,
+ lt: float | None = None,
+ le: float | None = None,
+ min_length: int | None = None,
+ max_length: int | None = None,
+ pattern: str | None = None,
regex: Annotated[
- Optional[str],
+ str | None,
deprecated(
"Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead."
),
] = None,
- discriminator: Union[str, None] = None,
- strict: Union[bool, None] = _Unset,
- multiple_of: Union[float, None] = _Unset,
- allow_inf_nan: Union[bool, None] = _Unset,
- max_digits: Union[int, None] = _Unset,
- decimal_places: Union[int, None] = _Unset,
- examples: Optional[list[Any]] = None,
+ discriminator: str | None = None,
+ strict: bool | None = _Unset,
+ multiple_of: float | None = _Unset,
+ allow_inf_nan: bool | None = _Unset,
+ max_digits: int | None = _Unset,
+ decimal_places: int | None = _Unset,
+ examples: list[Any] | None = None,
example: Annotated[
- Optional[Any],
+ Any | None,
deprecated(
"Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, "
"although still supported. Use examples instead."
),
] = _Unset,
- openapi_examples: Optional[dict[str, Example]] = None,
- deprecated: Union[deprecated, str, bool, None] = None,
+ openapi_examples: dict[str, Example] | None = None,
+ deprecated: deprecated | str | bool | None = None,
include_in_schema: bool = True,
- json_schema_extra: Union[dict[str, Any], None] = None,
+ json_schema_extra: dict[str, Any] | None = None,
**extra: Any,
):
super().__init__(
@@ -472,47 +472,47 @@ class Body(FieldInfo): # type: ignore[misc]
self,
default: Any = Undefined,
*,
- default_factory: Union[Callable[[], Any], None] = _Unset,
- annotation: Optional[Any] = None,
- embed: Union[bool, None] = None,
+ default_factory: Callable[[], Any] | None = _Unset,
+ annotation: Any | None = None,
+ embed: bool | None = None,
media_type: str = "application/json",
- alias: Optional[str] = None,
- alias_priority: Union[int, None] = _Unset,
- validation_alias: Union[str, AliasPath, AliasChoices, None] = None,
- serialization_alias: Union[str, None] = None,
- title: Optional[str] = None,
- description: Optional[str] = None,
- gt: Optional[float] = None,
- ge: Optional[float] = None,
- lt: Optional[float] = None,
- le: Optional[float] = None,
- min_length: Optional[int] = None,
- max_length: Optional[int] = None,
- pattern: Optional[str] = None,
+ alias: str | None = None,
+ alias_priority: int | None = _Unset,
+ validation_alias: str | AliasPath | AliasChoices | None = None,
+ serialization_alias: str | None = None,
+ title: str | None = None,
+ description: str | None = None,
+ gt: float | None = None,
+ ge: float | None = None,
+ lt: float | None = None,
+ le: float | None = None,
+ min_length: int | None = None,
+ max_length: int | None = None,
+ pattern: str | None = None,
regex: Annotated[
- Optional[str],
+ str | None,
deprecated(
"Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead."
),
] = None,
- discriminator: Union[str, None] = None,
- strict: Union[bool, None] = _Unset,
- multiple_of: Union[float, None] = _Unset,
- allow_inf_nan: Union[bool, None] = _Unset,
- max_digits: Union[int, None] = _Unset,
- decimal_places: Union[int, None] = _Unset,
- examples: Optional[list[Any]] = None,
+ discriminator: str | None = None,
+ strict: bool | None = _Unset,
+ multiple_of: float | None = _Unset,
+ allow_inf_nan: bool | None = _Unset,
+ max_digits: int | None = _Unset,
+ decimal_places: int | None = _Unset,
+ examples: list[Any] | None = None,
example: Annotated[
- Optional[Any],
+ Any | None,
deprecated(
"Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, "
"although still supported. Use examples instead."
),
] = _Unset,
- openapi_examples: Optional[dict[str, Example]] = None,
- deprecated: Union[deprecated, str, bool, None] = None,
+ openapi_examples: dict[str, Example] | None = None,
+ deprecated: deprecated | str | bool | None = None,
include_in_schema: bool = True,
- json_schema_extra: Union[dict[str, Any], None] = None,
+ json_schema_extra: dict[str, Any] | None = None,
**extra: Any,
):
self.embed = embed
@@ -584,46 +584,46 @@ class Form(Body): # type: ignore[misc]
self,
default: Any = Undefined,
*,
- default_factory: Union[Callable[[], Any], None] = _Unset,
- annotation: Optional[Any] = None,
+ default_factory: Callable[[], Any] | None = _Unset,
+ annotation: Any | None = None,
media_type: str = "application/x-www-form-urlencoded",
- alias: Optional[str] = None,
- alias_priority: Union[int, None] = _Unset,
- validation_alias: Union[str, AliasPath, AliasChoices, None] = None,
- serialization_alias: Union[str, None] = None,
- title: Optional[str] = None,
- description: Optional[str] = None,
- gt: Optional[float] = None,
- ge: Optional[float] = None,
- lt: Optional[float] = None,
- le: Optional[float] = None,
- min_length: Optional[int] = None,
- max_length: Optional[int] = None,
- pattern: Optional[str] = None,
+ alias: str | None = None,
+ alias_priority: int | None = _Unset,
+ validation_alias: str | AliasPath | AliasChoices | None = None,
+ serialization_alias: str | None = None,
+ title: str | None = None,
+ description: str | None = None,
+ gt: float | None = None,
+ ge: float | None = None,
+ lt: float | None = None,
+ le: float | None = None,
+ min_length: int | None = None,
+ max_length: int | None = None,
+ pattern: str | None = None,
regex: Annotated[
- Optional[str],
+ str | None,
deprecated(
"Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead."
),
] = None,
- discriminator: Union[str, None] = None,
- strict: Union[bool, None] = _Unset,
- multiple_of: Union[float, None] = _Unset,
- allow_inf_nan: Union[bool, None] = _Unset,
- max_digits: Union[int, None] = _Unset,
- decimal_places: Union[int, None] = _Unset,
- examples: Optional[list[Any]] = None,
+ discriminator: str | None = None,
+ strict: bool | None = _Unset,
+ multiple_of: float | None = _Unset,
+ allow_inf_nan: bool | None = _Unset,
+ max_digits: int | None = _Unset,
+ decimal_places: int | None = _Unset,
+ examples: list[Any] | None = None,
example: Annotated[
- Optional[Any],
+ Any | None,
deprecated(
"Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, "
"although still supported. Use examples instead."
),
] = _Unset,
- openapi_examples: Optional[dict[str, Example]] = None,
- deprecated: Union[deprecated, str, bool, None] = None,
+ openapi_examples: dict[str, Example] | None = None,
+ deprecated: deprecated | str | bool | None = None,
include_in_schema: bool = True,
- json_schema_extra: Union[dict[str, Any], None] = None,
+ json_schema_extra: dict[str, Any] | None = None,
**extra: Any,
):
super().__init__(
@@ -666,46 +666,46 @@ class File(Form): # type: ignore[misc]
self,
default: Any = Undefined,
*,
- default_factory: Union[Callable[[], Any], None] = _Unset,
- annotation: Optional[Any] = None,
+ default_factory: Callable[[], Any] | None = _Unset,
+ annotation: Any | None = None,
media_type: str = "multipart/form-data",
- alias: Optional[str] = None,
- alias_priority: Union[int, None] = _Unset,
- validation_alias: Union[str, AliasPath, AliasChoices, None] = None,
- serialization_alias: Union[str, None] = None,
- title: Optional[str] = None,
- description: Optional[str] = None,
- gt: Optional[float] = None,
- ge: Optional[float] = None,
- lt: Optional[float] = None,
- le: Optional[float] = None,
- min_length: Optional[int] = None,
- max_length: Optional[int] = None,
- pattern: Optional[str] = None,
+ alias: str | None = None,
+ alias_priority: int | None = _Unset,
+ validation_alias: str | AliasPath | AliasChoices | None = None,
+ serialization_alias: str | None = None,
+ title: str | None = None,
+ description: str | None = None,
+ gt: float | None = None,
+ ge: float | None = None,
+ lt: float | None = None,
+ le: float | None = None,
+ min_length: int | None = None,
+ max_length: int | None = None,
+ pattern: str | None = None,
regex: Annotated[
- Optional[str],
+ str | None,
deprecated(
"Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead."
),
] = None,
- discriminator: Union[str, None] = None,
- strict: Union[bool, None] = _Unset,
- multiple_of: Union[float, None] = _Unset,
- allow_inf_nan: Union[bool, None] = _Unset,
- max_digits: Union[int, None] = _Unset,
- decimal_places: Union[int, None] = _Unset,
- examples: Optional[list[Any]] = None,
+ discriminator: str | None = None,
+ strict: bool | None = _Unset,
+ multiple_of: float | None = _Unset,
+ allow_inf_nan: bool | None = _Unset,
+ max_digits: int | None = _Unset,
+ decimal_places: int | None = _Unset,
+ examples: list[Any] | None = None,
example: Annotated[
- Optional[Any],
+ Any | None,
deprecated(
"Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, "
"although still supported. Use examples instead."
),
] = _Unset,
- openapi_examples: Optional[dict[str, Example]] = None,
- deprecated: Union[deprecated, str, bool, None] = None,
+ openapi_examples: dict[str, Example] | None = None,
+ deprecated: deprecated | str | bool | None = None,
include_in_schema: bool = True,
- json_schema_extra: Union[dict[str, Any], None] = None,
+ json_schema_extra: dict[str, Any] | None = None,
**extra: Any,
):
super().__init__(
@@ -745,11 +745,11 @@ class File(Form): # type: ignore[misc]
@dataclass(frozen=True)
class Depends:
- dependency: Optional[Callable[..., Any]] = None
+ dependency: Callable[..., Any] | None = None
use_cache: bool = True
- scope: Union[Literal["function", "request"], None] = None
+ scope: Literal["function", "request"] | None = None
@dataclass(frozen=True)
class Security(Depends):
- scopes: Optional[Sequence[str]] = None
+ scopes: Sequence[str] | None = None
diff --git a/fastapi/routing.py b/fastapi/routing.py
index ed873fda8c..ea82ab14a3 100644
--- a/fastapi/routing.py
+++ b/fastapi/routing.py
@@ -7,6 +7,7 @@ import types
from collections.abc import (
AsyncIterator,
Awaitable,
+ Callable,
Collection,
Coroutine,
Generator,
@@ -23,10 +24,7 @@ from enum import Enum, IntEnum
from typing import (
Annotated,
Any,
- Callable,
- Optional,
TypeVar,
- Union,
)
from annotated_doc import Doc
@@ -84,7 +82,7 @@ from typing_extensions import deprecated
# Copy of starlette.routing.request_response modified to include the
# dependencies' AsyncExitStack
def request_response(
- func: Callable[[Request], Union[Awaitable[Response], Response]],
+ func: Callable[[Request], Awaitable[Response] | Response],
) -> ASGIApp:
"""
Takes a function or coroutine `func(request) -> response`,
@@ -168,10 +166,10 @@ class _AsyncLiftContextManager(AbstractAsyncContextManager[_T]):
async def __aexit__(
self,
- exc_type: Optional[type[BaseException]],
- exc_value: Optional[BaseException],
- traceback: Optional[types.TracebackType],
- ) -> Optional[bool]:
+ exc_type: type[BaseException] | None,
+ exc_value: BaseException | None,
+ traceback: types.TracebackType | None,
+ ) -> bool | None:
return self._cm.__exit__(exc_type, exc_value, traceback)
@@ -199,7 +197,7 @@ def _merge_lifespan_context(
@asynccontextmanager
async def merged_lifespan(
app: AppType,
- ) -> AsyncIterator[Optional[Mapping[str, Any]]]:
+ ) -> AsyncIterator[Mapping[str, Any] | None]:
async with original_context(app) as maybe_original_state:
async with nested_context(app) as maybe_nested_state:
if maybe_nested_state is None and maybe_original_state is None:
@@ -263,16 +261,16 @@ def _extract_endpoint_context(func: Any) -> EndpointContext:
async def serialize_response(
*,
- field: Optional[ModelField] = None,
+ field: ModelField | None = None,
response_content: Any,
- include: Optional[IncEx] = None,
- exclude: Optional[IncEx] = None,
+ include: IncEx | None = None,
+ exclude: IncEx | None = None,
by_alias: bool = True,
exclude_unset: bool = False,
exclude_defaults: bool = False,
exclude_none: bool = False,
is_coroutine: bool = True,
- endpoint_ctx: Optional[EndpointContext] = None,
+ endpoint_ctx: EndpointContext | None = None,
) -> Any:
if field:
if is_coroutine:
@@ -318,17 +316,17 @@ async def run_endpoint_function(
def get_request_handler(
dependant: Dependant,
- body_field: Optional[ModelField] = None,
- status_code: Optional[int] = None,
- response_class: Union[type[Response], DefaultPlaceholder] = Default(JSONResponse),
- response_field: Optional[ModelField] = None,
- response_model_include: Optional[IncEx] = None,
- response_model_exclude: Optional[IncEx] = None,
+ body_field: ModelField | None = None,
+ status_code: int | None = None,
+ response_class: type[Response] | DefaultPlaceholder = Default(JSONResponse),
+ response_field: ModelField | None = None,
+ response_model_include: IncEx | None = None,
+ response_model_exclude: IncEx | None = None,
response_model_by_alias: bool = True,
response_model_exclude_unset: bool = False,
response_model_exclude_defaults: bool = False,
response_model_exclude_none: bool = False,
- dependency_overrides_provider: Optional[Any] = None,
+ dependency_overrides_provider: Any | None = None,
embed_body_fields: bool = False,
) -> Callable[[Request], Coroutine[Any, Any, Response]]:
assert dependant.call is not None, "dependant.call must be a function"
@@ -340,7 +338,7 @@ def get_request_handler(
actual_response_class = response_class
async def app(request: Request) -> Response:
- response: Union[Response, None] = None
+ response: Response | None = None
file_stack = request.scope.get("fastapi_middleware_astack")
assert isinstance(file_stack, AsyncExitStack), (
"fastapi_middleware_astack not found in request scope"
@@ -476,7 +474,7 @@ def get_request_handler(
def get_websocket_app(
dependant: Dependant,
- dependency_overrides_provider: Optional[Any] = None,
+ dependency_overrides_provider: Any | None = None,
embed_body_fields: bool = False,
) -> Callable[[WebSocket], Coroutine[Any, Any, Any]]:
async def app(websocket: WebSocket) -> None:
@@ -517,9 +515,9 @@ class APIWebSocketRoute(routing.WebSocketRoute):
path: str,
endpoint: Callable[..., Any],
*,
- name: Optional[str] = None,
- dependencies: Optional[Sequence[params.Depends]] = None,
- dependency_overrides_provider: Optional[Any] = None,
+ name: str | None = None,
+ dependencies: Sequence[params.Depends] | None = None,
+ dependency_overrides_provider: Any | None = None,
) -> None:
self.path = path
self.endpoint = endpoint
@@ -560,33 +558,30 @@ class APIRoute(routing.Route):
endpoint: Callable[..., Any],
*,
response_model: Any = Default(None),
- status_code: Optional[int] = None,
- tags: Optional[list[Union[str, Enum]]] = None,
- dependencies: Optional[Sequence[params.Depends]] = None,
- summary: Optional[str] = None,
- description: Optional[str] = None,
+ status_code: int | None = None,
+ tags: list[str | Enum] | None = None,
+ dependencies: Sequence[params.Depends] | None = None,
+ summary: str | None = None,
+ description: str | None = None,
response_description: str = "Successful Response",
- responses: Optional[dict[Union[int, str], dict[str, Any]]] = None,
- deprecated: Optional[bool] = None,
- name: Optional[str] = None,
- methods: Optional[Union[set[str], list[str]]] = None,
- operation_id: Optional[str] = None,
- response_model_include: Optional[IncEx] = None,
- response_model_exclude: Optional[IncEx] = None,
+ responses: dict[int | str, dict[str, Any]] | None = None,
+ deprecated: bool | None = None,
+ name: str | None = None,
+ methods: set[str] | list[str] | None = None,
+ operation_id: str | None = None,
+ response_model_include: IncEx | None = None,
+ response_model_exclude: IncEx | None = None,
response_model_by_alias: bool = True,
response_model_exclude_unset: bool = False,
response_model_exclude_defaults: bool = False,
response_model_exclude_none: bool = False,
include_in_schema: bool = True,
- response_class: Union[type[Response], DefaultPlaceholder] = Default(
- JSONResponse
- ),
- dependency_overrides_provider: Optional[Any] = None,
- callbacks: Optional[list[BaseRoute]] = None,
- openapi_extra: Optional[dict[str, Any]] = None,
- generate_unique_id_function: Union[
- Callable[["APIRoute"], str], DefaultPlaceholder
- ] = Default(generate_unique_id),
+ response_class: type[Response] | DefaultPlaceholder = Default(JSONResponse),
+ dependency_overrides_provider: Any | None = None,
+ callbacks: list[BaseRoute] | None = None,
+ openapi_extra: dict[str, Any] | None = None,
+ generate_unique_id_function: Callable[["APIRoute"], str]
+ | DefaultPlaceholder = Default(generate_unique_id),
) -> None:
self.path = path
self.endpoint = endpoint
@@ -662,7 +657,7 @@ class APIRoute(routing.Route):
)
response_fields[additional_status_code] = response_field
if response_fields:
- self.response_fields: dict[Union[int, str], ModelField] = response_fields
+ self.response_fields: dict[int | str, ModelField] = response_fields
else:
self.response_fields = {}
@@ -742,7 +737,7 @@ class APIRouter(routing.Router):
*,
prefix: Annotated[str, Doc("An optional path prefix for the router.")] = "",
tags: Annotated[
- Optional[list[Union[str, Enum]]],
+ list[str | Enum] | None,
Doc(
"""
A list of tags to be applied to all the *path operations* in this
@@ -756,7 +751,7 @@ class APIRouter(routing.Router):
),
] = None,
dependencies: Annotated[
- Optional[Sequence[params.Depends]],
+ Sequence[params.Depends] | None,
Doc(
"""
A list of dependencies (using `Depends()`) to be applied to all the
@@ -779,7 +774,7 @@ class APIRouter(routing.Router):
),
] = Default(JSONResponse),
responses: Annotated[
- Optional[dict[Union[int, str], dict[str, Any]]],
+ dict[int | str, dict[str, Any]] | None,
Doc(
"""
Additional responses to be shown in OpenAPI.
@@ -795,7 +790,7 @@ class APIRouter(routing.Router):
),
] = None,
callbacks: Annotated[
- Optional[list[BaseRoute]],
+ list[BaseRoute] | None,
Doc(
"""
OpenAPI callbacks that should apply to all *path operations* in this
@@ -809,7 +804,7 @@ class APIRouter(routing.Router):
),
] = None,
routes: Annotated[
- Optional[list[BaseRoute]],
+ list[BaseRoute] | None,
Doc(
"""
**Note**: you probably shouldn't use this parameter, it is inherited
@@ -840,7 +835,7 @@ class APIRouter(routing.Router):
),
] = True,
default: Annotated[
- Optional[ASGIApp],
+ ASGIApp | None,
Doc(
"""
Default function handler for this router. Used to handle
@@ -849,7 +844,7 @@ class APIRouter(routing.Router):
),
] = None,
dependency_overrides_provider: Annotated[
- Optional[Any],
+ Any | None,
Doc(
"""
Only used internally by FastAPI to handle dependency overrides.
@@ -871,7 +866,7 @@ class APIRouter(routing.Router):
),
] = APIRoute,
on_startup: Annotated[
- Optional[Sequence[Callable[[], Any]]],
+ Sequence[Callable[[], Any]] | None,
Doc(
"""
A list of startup event handler functions.
@@ -883,7 +878,7 @@ class APIRouter(routing.Router):
),
] = None,
on_shutdown: Annotated[
- Optional[Sequence[Callable[[], Any]]],
+ Sequence[Callable[[], Any]] | None,
Doc(
"""
A list of shutdown event handler functions.
@@ -898,7 +893,7 @@ class APIRouter(routing.Router):
# the generic to Lifespan[AppType] is the type of the top level application
# which the router cannot know statically, so we use typing.Any
lifespan: Annotated[
- Optional[Lifespan[Any]],
+ Lifespan[Any] | None,
Doc(
"""
A `Lifespan` context manager handler. This replaces `startup` and
@@ -910,7 +905,7 @@ class APIRouter(routing.Router):
),
] = None,
deprecated: Annotated[
- Optional[bool],
+ bool | None,
Doc(
"""
Mark all *path operations* in this router as deprecated.
@@ -987,7 +982,7 @@ class APIRouter(routing.Router):
)
self.prefix = prefix
- self.tags: list[Union[str, Enum]] = tags or []
+ self.tags: list[str | Enum] = tags or []
self.dependencies = list(dependencies or [])
self.deprecated = deprecated
self.include_in_schema = include_in_schema
@@ -1001,8 +996,8 @@ class APIRouter(routing.Router):
def route(
self,
path: str,
- methods: Optional[Collection[str]] = None,
- name: Optional[str] = None,
+ methods: Collection[str] | None = None,
+ name: str | None = None,
include_in_schema: bool = True,
) -> Callable[[DecoratedCallable], DecoratedCallable]:
def decorator(func: DecoratedCallable) -> DecoratedCallable:
@@ -1023,33 +1018,30 @@ class APIRouter(routing.Router):
endpoint: Callable[..., Any],
*,
response_model: Any = Default(None),
- status_code: Optional[int] = None,
- tags: Optional[list[Union[str, Enum]]] = None,
- dependencies: Optional[Sequence[params.Depends]] = None,
- summary: Optional[str] = None,
- description: Optional[str] = None,
+ status_code: int | None = None,
+ tags: list[str | Enum] | None = None,
+ dependencies: Sequence[params.Depends] | None = None,
+ summary: str | None = None,
+ description: str | None = None,
response_description: str = "Successful Response",
- responses: Optional[dict[Union[int, str], dict[str, Any]]] = None,
- deprecated: Optional[bool] = None,
- methods: Optional[Union[set[str], list[str]]] = None,
- operation_id: Optional[str] = None,
- response_model_include: Optional[IncEx] = None,
- response_model_exclude: Optional[IncEx] = None,
+ responses: dict[int | str, dict[str, Any]] | None = None,
+ deprecated: bool | None = None,
+ methods: set[str] | list[str] | None = None,
+ operation_id: str | None = None,
+ response_model_include: IncEx | None = None,
+ response_model_exclude: IncEx | None = None,
response_model_by_alias: bool = True,
response_model_exclude_unset: bool = False,
response_model_exclude_defaults: bool = False,
response_model_exclude_none: bool = False,
include_in_schema: bool = True,
- response_class: Union[type[Response], DefaultPlaceholder] = Default(
- JSONResponse
- ),
- name: Optional[str] = None,
- route_class_override: Optional[type[APIRoute]] = None,
- callbacks: Optional[list[BaseRoute]] = None,
- openapi_extra: Optional[dict[str, Any]] = None,
- generate_unique_id_function: Union[
- Callable[[APIRoute], str], DefaultPlaceholder
- ] = Default(generate_unique_id),
+ response_class: type[Response] | DefaultPlaceholder = Default(JSONResponse),
+ name: str | None = None,
+ route_class_override: type[APIRoute] | None = None,
+ callbacks: list[BaseRoute] | None = None,
+ openapi_extra: dict[str, Any] | None = None,
+ generate_unique_id_function: Callable[[APIRoute], str]
+ | DefaultPlaceholder = Default(generate_unique_id),
) -> None:
route_class = route_class_override or self.route_class
responses = responses or {}
@@ -1104,27 +1096,27 @@ class APIRouter(routing.Router):
path: str,
*,
response_model: Any = Default(None),
- status_code: Optional[int] = None,
- tags: Optional[list[Union[str, Enum]]] = None,
- dependencies: Optional[Sequence[params.Depends]] = None,
- summary: Optional[str] = None,
- description: Optional[str] = None,
+ status_code: int | None = None,
+ tags: list[str | Enum] | None = None,
+ dependencies: Sequence[params.Depends] | None = None,
+ summary: str | None = None,
+ description: str | None = None,
response_description: str = "Successful Response",
- responses: Optional[dict[Union[int, str], dict[str, Any]]] = None,
- deprecated: Optional[bool] = None,
- methods: Optional[list[str]] = None,
- operation_id: Optional[str] = None,
- response_model_include: Optional[IncEx] = None,
- response_model_exclude: Optional[IncEx] = None,
+ responses: dict[int | str, dict[str, Any]] | None = None,
+ deprecated: bool | None = None,
+ methods: list[str] | None = None,
+ operation_id: str | None = None,
+ response_model_include: IncEx | None = None,
+ response_model_exclude: IncEx | None = None,
response_model_by_alias: bool = True,
response_model_exclude_unset: bool = False,
response_model_exclude_defaults: bool = False,
response_model_exclude_none: bool = False,
include_in_schema: bool = True,
response_class: type[Response] = Default(JSONResponse),
- name: Optional[str] = None,
- callbacks: Optional[list[BaseRoute]] = None,
- openapi_extra: Optional[dict[str, Any]] = None,
+ name: str | None = None,
+ callbacks: list[BaseRoute] | None = None,
+ openapi_extra: dict[str, Any] | None = None,
generate_unique_id_function: Callable[[APIRoute], str] = Default(
generate_unique_id
),
@@ -1165,9 +1157,9 @@ class APIRouter(routing.Router):
self,
path: str,
endpoint: Callable[..., Any],
- name: Optional[str] = None,
+ name: str | None = None,
*,
- dependencies: Optional[Sequence[params.Depends]] = None,
+ dependencies: Sequence[params.Depends] | None = None,
) -> None:
current_dependencies = self.dependencies.copy()
if dependencies:
@@ -1193,7 +1185,7 @@ class APIRouter(routing.Router):
),
],
name: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
A name for the WebSocket. Only used internally.
@@ -1202,7 +1194,7 @@ class APIRouter(routing.Router):
] = None,
*,
dependencies: Annotated[
- Optional[Sequence[params.Depends]],
+ Sequence[params.Depends] | None,
Doc(
"""
A list of dependencies (using `Depends()`) to be used for this
@@ -1250,7 +1242,7 @@ class APIRouter(routing.Router):
return decorator
def websocket_route(
- self, path: str, name: Union[str, None] = None
+ self, path: str, name: str | None = None
) -> Callable[[DecoratedCallable], DecoratedCallable]:
def decorator(func: DecoratedCallable) -> DecoratedCallable:
self.add_websocket_route(path, func, name=name)
@@ -1264,7 +1256,7 @@ class APIRouter(routing.Router):
*,
prefix: Annotated[str, Doc("An optional path prefix for the router.")] = "",
tags: Annotated[
- Optional[list[Union[str, Enum]]],
+ list[str | Enum] | None,
Doc(
"""
A list of tags to be applied to all the *path operations* in this
@@ -1278,7 +1270,7 @@ class APIRouter(routing.Router):
),
] = None,
dependencies: Annotated[
- Optional[Sequence[params.Depends]],
+ Sequence[params.Depends] | None,
Doc(
"""
A list of dependencies (using `Depends()`) to be applied to all the
@@ -1301,7 +1293,7 @@ class APIRouter(routing.Router):
),
] = Default(JSONResponse),
responses: Annotated[
- Optional[dict[Union[int, str], dict[str, Any]]],
+ dict[int | str, dict[str, Any]] | None,
Doc(
"""
Additional responses to be shown in OpenAPI.
@@ -1317,7 +1309,7 @@ class APIRouter(routing.Router):
),
] = None,
callbacks: Annotated[
- Optional[list[BaseRoute]],
+ list[BaseRoute] | None,
Doc(
"""
OpenAPI callbacks that should apply to all *path operations* in this
@@ -1331,7 +1323,7 @@ class APIRouter(routing.Router):
),
] = None,
deprecated: Annotated[
- Optional[bool],
+ bool | None,
Doc(
"""
Mark all *path operations* in this router as deprecated.
@@ -1554,7 +1546,7 @@ class APIRouter(routing.Router):
),
] = Default(None),
status_code: Annotated[
- Optional[int],
+ int | None,
Doc(
"""
The default status code to be used for the response.
@@ -1567,7 +1559,7 @@ class APIRouter(routing.Router):
),
] = None,
tags: Annotated[
- Optional[list[Union[str, Enum]]],
+ list[str | Enum] | None,
Doc(
"""
A list of tags to be applied to the *path operation*.
@@ -1580,7 +1572,7 @@ class APIRouter(routing.Router):
),
] = None,
dependencies: Annotated[
- Optional[Sequence[params.Depends]],
+ Sequence[params.Depends] | None,
Doc(
"""
A list of dependencies (using `Depends()`) to be applied to the
@@ -1592,7 +1584,7 @@ class APIRouter(routing.Router):
),
] = None,
summary: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
A summary for the *path operation*.
@@ -1605,7 +1597,7 @@ class APIRouter(routing.Router):
),
] = None,
description: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
A description for the *path operation*.
@@ -1633,7 +1625,7 @@ class APIRouter(routing.Router):
),
] = "Successful Response",
responses: Annotated[
- Optional[dict[Union[int, str], dict[str, Any]]],
+ dict[int | str, dict[str, Any]] | None,
Doc(
"""
Additional responses that could be returned by this *path operation*.
@@ -1643,7 +1635,7 @@ class APIRouter(routing.Router):
),
] = None,
deprecated: Annotated[
- Optional[bool],
+ bool | None,
Doc(
"""
Mark this *path operation* as deprecated.
@@ -1653,7 +1645,7 @@ class APIRouter(routing.Router):
),
] = None,
operation_id: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
Custom operation ID to be used by this *path operation*.
@@ -1673,7 +1665,7 @@ class APIRouter(routing.Router):
),
] = None,
response_model_include: Annotated[
- Optional[IncEx],
+ IncEx | None,
Doc(
"""
Configuration passed to Pydantic to include only certain fields in the
@@ -1685,7 +1677,7 @@ class APIRouter(routing.Router):
),
] = None,
response_model_exclude: Annotated[
- Optional[IncEx],
+ IncEx | None,
Doc(
"""
Configuration passed to Pydantic to exclude certain fields in the
@@ -1787,7 +1779,7 @@ class APIRouter(routing.Router):
),
] = Default(JSONResponse),
name: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
Name for this *path operation*. Only used internally.
@@ -1795,7 +1787,7 @@ class APIRouter(routing.Router):
),
] = None,
callbacks: Annotated[
- Optional[list[BaseRoute]],
+ list[BaseRoute] | None,
Doc(
"""
List of *path operations* that will be used as OpenAPI callbacks.
@@ -1811,7 +1803,7 @@ class APIRouter(routing.Router):
),
] = None,
openapi_extra: Annotated[
- Optional[dict[str, Any]],
+ dict[str, Any] | None,
Doc(
"""
Extra metadata to be included in the OpenAPI schema for this *path
@@ -1931,7 +1923,7 @@ class APIRouter(routing.Router):
),
] = Default(None),
status_code: Annotated[
- Optional[int],
+ int | None,
Doc(
"""
The default status code to be used for the response.
@@ -1944,7 +1936,7 @@ class APIRouter(routing.Router):
),
] = None,
tags: Annotated[
- Optional[list[Union[str, Enum]]],
+ list[str | Enum] | None,
Doc(
"""
A list of tags to be applied to the *path operation*.
@@ -1957,7 +1949,7 @@ class APIRouter(routing.Router):
),
] = None,
dependencies: Annotated[
- Optional[Sequence[params.Depends]],
+ Sequence[params.Depends] | None,
Doc(
"""
A list of dependencies (using `Depends()`) to be applied to the
@@ -1969,7 +1961,7 @@ class APIRouter(routing.Router):
),
] = None,
summary: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
A summary for the *path operation*.
@@ -1982,7 +1974,7 @@ class APIRouter(routing.Router):
),
] = None,
description: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
A description for the *path operation*.
@@ -2010,7 +2002,7 @@ class APIRouter(routing.Router):
),
] = "Successful Response",
responses: Annotated[
- Optional[dict[Union[int, str], dict[str, Any]]],
+ dict[int | str, dict[str, Any]] | None,
Doc(
"""
Additional responses that could be returned by this *path operation*.
@@ -2020,7 +2012,7 @@ class APIRouter(routing.Router):
),
] = None,
deprecated: Annotated[
- Optional[bool],
+ bool | None,
Doc(
"""
Mark this *path operation* as deprecated.
@@ -2030,7 +2022,7 @@ class APIRouter(routing.Router):
),
] = None,
operation_id: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
Custom operation ID to be used by this *path operation*.
@@ -2050,7 +2042,7 @@ class APIRouter(routing.Router):
),
] = None,
response_model_include: Annotated[
- Optional[IncEx],
+ IncEx | None,
Doc(
"""
Configuration passed to Pydantic to include only certain fields in the
@@ -2062,7 +2054,7 @@ class APIRouter(routing.Router):
),
] = None,
response_model_exclude: Annotated[
- Optional[IncEx],
+ IncEx | None,
Doc(
"""
Configuration passed to Pydantic to exclude certain fields in the
@@ -2164,7 +2156,7 @@ class APIRouter(routing.Router):
),
] = Default(JSONResponse),
name: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
Name for this *path operation*. Only used internally.
@@ -2172,7 +2164,7 @@ class APIRouter(routing.Router):
),
] = None,
callbacks: Annotated[
- Optional[list[BaseRoute]],
+ list[BaseRoute] | None,
Doc(
"""
List of *path operations* that will be used as OpenAPI callbacks.
@@ -2188,7 +2180,7 @@ class APIRouter(routing.Router):
),
] = None,
openapi_extra: Annotated[
- Optional[dict[str, Any]],
+ dict[str, Any] | None,
Doc(
"""
Extra metadata to be included in the OpenAPI schema for this *path
@@ -2313,7 +2305,7 @@ class APIRouter(routing.Router):
),
] = Default(None),
status_code: Annotated[
- Optional[int],
+ int | None,
Doc(
"""
The default status code to be used for the response.
@@ -2326,7 +2318,7 @@ class APIRouter(routing.Router):
),
] = None,
tags: Annotated[
- Optional[list[Union[str, Enum]]],
+ list[str | Enum] | None,
Doc(
"""
A list of tags to be applied to the *path operation*.
@@ -2339,7 +2331,7 @@ class APIRouter(routing.Router):
),
] = None,
dependencies: Annotated[
- Optional[Sequence[params.Depends]],
+ Sequence[params.Depends] | None,
Doc(
"""
A list of dependencies (using `Depends()`) to be applied to the
@@ -2351,7 +2343,7 @@ class APIRouter(routing.Router):
),
] = None,
summary: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
A summary for the *path operation*.
@@ -2364,7 +2356,7 @@ class APIRouter(routing.Router):
),
] = None,
description: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
A description for the *path operation*.
@@ -2392,7 +2384,7 @@ class APIRouter(routing.Router):
),
] = "Successful Response",
responses: Annotated[
- Optional[dict[Union[int, str], dict[str, Any]]],
+ dict[int | str, dict[str, Any]] | None,
Doc(
"""
Additional responses that could be returned by this *path operation*.
@@ -2402,7 +2394,7 @@ class APIRouter(routing.Router):
),
] = None,
deprecated: Annotated[
- Optional[bool],
+ bool | None,
Doc(
"""
Mark this *path operation* as deprecated.
@@ -2412,7 +2404,7 @@ class APIRouter(routing.Router):
),
] = None,
operation_id: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
Custom operation ID to be used by this *path operation*.
@@ -2432,7 +2424,7 @@ class APIRouter(routing.Router):
),
] = None,
response_model_include: Annotated[
- Optional[IncEx],
+ IncEx | None,
Doc(
"""
Configuration passed to Pydantic to include only certain fields in the
@@ -2444,7 +2436,7 @@ class APIRouter(routing.Router):
),
] = None,
response_model_exclude: Annotated[
- Optional[IncEx],
+ IncEx | None,
Doc(
"""
Configuration passed to Pydantic to exclude certain fields in the
@@ -2546,7 +2538,7 @@ class APIRouter(routing.Router):
),
] = Default(JSONResponse),
name: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
Name for this *path operation*. Only used internally.
@@ -2554,7 +2546,7 @@ class APIRouter(routing.Router):
),
] = None,
callbacks: Annotated[
- Optional[list[BaseRoute]],
+ list[BaseRoute] | None,
Doc(
"""
List of *path operations* that will be used as OpenAPI callbacks.
@@ -2570,7 +2562,7 @@ class APIRouter(routing.Router):
),
] = None,
openapi_extra: Annotated[
- Optional[dict[str, Any]],
+ dict[str, Any] | None,
Doc(
"""
Extra metadata to be included in the OpenAPI schema for this *path
@@ -2695,7 +2687,7 @@ class APIRouter(routing.Router):
),
] = Default(None),
status_code: Annotated[
- Optional[int],
+ int | None,
Doc(
"""
The default status code to be used for the response.
@@ -2708,7 +2700,7 @@ class APIRouter(routing.Router):
),
] = None,
tags: Annotated[
- Optional[list[Union[str, Enum]]],
+ list[str | Enum] | None,
Doc(
"""
A list of tags to be applied to the *path operation*.
@@ -2721,7 +2713,7 @@ class APIRouter(routing.Router):
),
] = None,
dependencies: Annotated[
- Optional[Sequence[params.Depends]],
+ Sequence[params.Depends] | None,
Doc(
"""
A list of dependencies (using `Depends()`) to be applied to the
@@ -2733,7 +2725,7 @@ class APIRouter(routing.Router):
),
] = None,
summary: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
A summary for the *path operation*.
@@ -2746,7 +2738,7 @@ class APIRouter(routing.Router):
),
] = None,
description: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
A description for the *path operation*.
@@ -2774,7 +2766,7 @@ class APIRouter(routing.Router):
),
] = "Successful Response",
responses: Annotated[
- Optional[dict[Union[int, str], dict[str, Any]]],
+ dict[int | str, dict[str, Any]] | None,
Doc(
"""
Additional responses that could be returned by this *path operation*.
@@ -2784,7 +2776,7 @@ class APIRouter(routing.Router):
),
] = None,
deprecated: Annotated[
- Optional[bool],
+ bool | None,
Doc(
"""
Mark this *path operation* as deprecated.
@@ -2794,7 +2786,7 @@ class APIRouter(routing.Router):
),
] = None,
operation_id: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
Custom operation ID to be used by this *path operation*.
@@ -2814,7 +2806,7 @@ class APIRouter(routing.Router):
),
] = None,
response_model_include: Annotated[
- Optional[IncEx],
+ IncEx | None,
Doc(
"""
Configuration passed to Pydantic to include only certain fields in the
@@ -2826,7 +2818,7 @@ class APIRouter(routing.Router):
),
] = None,
response_model_exclude: Annotated[
- Optional[IncEx],
+ IncEx | None,
Doc(
"""
Configuration passed to Pydantic to exclude certain fields in the
@@ -2928,7 +2920,7 @@ class APIRouter(routing.Router):
),
] = Default(JSONResponse),
name: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
Name for this *path operation*. Only used internally.
@@ -2936,7 +2928,7 @@ class APIRouter(routing.Router):
),
] = None,
callbacks: Annotated[
- Optional[list[BaseRoute]],
+ list[BaseRoute] | None,
Doc(
"""
List of *path operations* that will be used as OpenAPI callbacks.
@@ -2952,7 +2944,7 @@ class APIRouter(routing.Router):
),
] = None,
openapi_extra: Annotated[
- Optional[dict[str, Any]],
+ dict[str, Any] | None,
Doc(
"""
Extra metadata to be included in the OpenAPI schema for this *path
@@ -3072,7 +3064,7 @@ class APIRouter(routing.Router):
),
] = Default(None),
status_code: Annotated[
- Optional[int],
+ int | None,
Doc(
"""
The default status code to be used for the response.
@@ -3085,7 +3077,7 @@ class APIRouter(routing.Router):
),
] = None,
tags: Annotated[
- Optional[list[Union[str, Enum]]],
+ list[str | Enum] | None,
Doc(
"""
A list of tags to be applied to the *path operation*.
@@ -3098,7 +3090,7 @@ class APIRouter(routing.Router):
),
] = None,
dependencies: Annotated[
- Optional[Sequence[params.Depends]],
+ Sequence[params.Depends] | None,
Doc(
"""
A list of dependencies (using `Depends()`) to be applied to the
@@ -3110,7 +3102,7 @@ class APIRouter(routing.Router):
),
] = None,
summary: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
A summary for the *path operation*.
@@ -3123,7 +3115,7 @@ class APIRouter(routing.Router):
),
] = None,
description: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
A description for the *path operation*.
@@ -3151,7 +3143,7 @@ class APIRouter(routing.Router):
),
] = "Successful Response",
responses: Annotated[
- Optional[dict[Union[int, str], dict[str, Any]]],
+ dict[int | str, dict[str, Any]] | None,
Doc(
"""
Additional responses that could be returned by this *path operation*.
@@ -3161,7 +3153,7 @@ class APIRouter(routing.Router):
),
] = None,
deprecated: Annotated[
- Optional[bool],
+ bool | None,
Doc(
"""
Mark this *path operation* as deprecated.
@@ -3171,7 +3163,7 @@ class APIRouter(routing.Router):
),
] = None,
operation_id: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
Custom operation ID to be used by this *path operation*.
@@ -3191,7 +3183,7 @@ class APIRouter(routing.Router):
),
] = None,
response_model_include: Annotated[
- Optional[IncEx],
+ IncEx | None,
Doc(
"""
Configuration passed to Pydantic to include only certain fields in the
@@ -3203,7 +3195,7 @@ class APIRouter(routing.Router):
),
] = None,
response_model_exclude: Annotated[
- Optional[IncEx],
+ IncEx | None,
Doc(
"""
Configuration passed to Pydantic to exclude certain fields in the
@@ -3305,7 +3297,7 @@ class APIRouter(routing.Router):
),
] = Default(JSONResponse),
name: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
Name for this *path operation*. Only used internally.
@@ -3313,7 +3305,7 @@ class APIRouter(routing.Router):
),
] = None,
callbacks: Annotated[
- Optional[list[BaseRoute]],
+ list[BaseRoute] | None,
Doc(
"""
List of *path operations* that will be used as OpenAPI callbacks.
@@ -3329,7 +3321,7 @@ class APIRouter(routing.Router):
),
] = None,
openapi_extra: Annotated[
- Optional[dict[str, Any]],
+ dict[str, Any] | None,
Doc(
"""
Extra metadata to be included in the OpenAPI schema for this *path
@@ -3449,7 +3441,7 @@ class APIRouter(routing.Router):
),
] = Default(None),
status_code: Annotated[
- Optional[int],
+ int | None,
Doc(
"""
The default status code to be used for the response.
@@ -3462,7 +3454,7 @@ class APIRouter(routing.Router):
),
] = None,
tags: Annotated[
- Optional[list[Union[str, Enum]]],
+ list[str | Enum] | None,
Doc(
"""
A list of tags to be applied to the *path operation*.
@@ -3475,7 +3467,7 @@ class APIRouter(routing.Router):
),
] = None,
dependencies: Annotated[
- Optional[Sequence[params.Depends]],
+ Sequence[params.Depends] | None,
Doc(
"""
A list of dependencies (using `Depends()`) to be applied to the
@@ -3487,7 +3479,7 @@ class APIRouter(routing.Router):
),
] = None,
summary: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
A summary for the *path operation*.
@@ -3500,7 +3492,7 @@ class APIRouter(routing.Router):
),
] = None,
description: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
A description for the *path operation*.
@@ -3528,7 +3520,7 @@ class APIRouter(routing.Router):
),
] = "Successful Response",
responses: Annotated[
- Optional[dict[Union[int, str], dict[str, Any]]],
+ dict[int | str, dict[str, Any]] | None,
Doc(
"""
Additional responses that could be returned by this *path operation*.
@@ -3538,7 +3530,7 @@ class APIRouter(routing.Router):
),
] = None,
deprecated: Annotated[
- Optional[bool],
+ bool | None,
Doc(
"""
Mark this *path operation* as deprecated.
@@ -3548,7 +3540,7 @@ class APIRouter(routing.Router):
),
] = None,
operation_id: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
Custom operation ID to be used by this *path operation*.
@@ -3568,7 +3560,7 @@ class APIRouter(routing.Router):
),
] = None,
response_model_include: Annotated[
- Optional[IncEx],
+ IncEx | None,
Doc(
"""
Configuration passed to Pydantic to include only certain fields in the
@@ -3580,7 +3572,7 @@ class APIRouter(routing.Router):
),
] = None,
response_model_exclude: Annotated[
- Optional[IncEx],
+ IncEx | None,
Doc(
"""
Configuration passed to Pydantic to exclude certain fields in the
@@ -3682,7 +3674,7 @@ class APIRouter(routing.Router):
),
] = Default(JSONResponse),
name: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
Name for this *path operation*. Only used internally.
@@ -3690,7 +3682,7 @@ class APIRouter(routing.Router):
),
] = None,
callbacks: Annotated[
- Optional[list[BaseRoute]],
+ list[BaseRoute] | None,
Doc(
"""
List of *path operations* that will be used as OpenAPI callbacks.
@@ -3706,7 +3698,7 @@ class APIRouter(routing.Router):
),
] = None,
openapi_extra: Annotated[
- Optional[dict[str, Any]],
+ dict[str, Any] | None,
Doc(
"""
Extra metadata to be included in the OpenAPI schema for this *path
@@ -3831,7 +3823,7 @@ class APIRouter(routing.Router):
),
] = Default(None),
status_code: Annotated[
- Optional[int],
+ int | None,
Doc(
"""
The default status code to be used for the response.
@@ -3844,7 +3836,7 @@ class APIRouter(routing.Router):
),
] = None,
tags: Annotated[
- Optional[list[Union[str, Enum]]],
+ list[str | Enum] | None,
Doc(
"""
A list of tags to be applied to the *path operation*.
@@ -3857,7 +3849,7 @@ class APIRouter(routing.Router):
),
] = None,
dependencies: Annotated[
- Optional[Sequence[params.Depends]],
+ Sequence[params.Depends] | None,
Doc(
"""
A list of dependencies (using `Depends()`) to be applied to the
@@ -3869,7 +3861,7 @@ class APIRouter(routing.Router):
),
] = None,
summary: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
A summary for the *path operation*.
@@ -3882,7 +3874,7 @@ class APIRouter(routing.Router):
),
] = None,
description: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
A description for the *path operation*.
@@ -3910,7 +3902,7 @@ class APIRouter(routing.Router):
),
] = "Successful Response",
responses: Annotated[
- Optional[dict[Union[int, str], dict[str, Any]]],
+ dict[int | str, dict[str, Any]] | None,
Doc(
"""
Additional responses that could be returned by this *path operation*.
@@ -3920,7 +3912,7 @@ class APIRouter(routing.Router):
),
] = None,
deprecated: Annotated[
- Optional[bool],
+ bool | None,
Doc(
"""
Mark this *path operation* as deprecated.
@@ -3930,7 +3922,7 @@ class APIRouter(routing.Router):
),
] = None,
operation_id: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
Custom operation ID to be used by this *path operation*.
@@ -3950,7 +3942,7 @@ class APIRouter(routing.Router):
),
] = None,
response_model_include: Annotated[
- Optional[IncEx],
+ IncEx | None,
Doc(
"""
Configuration passed to Pydantic to include only certain fields in the
@@ -3962,7 +3954,7 @@ class APIRouter(routing.Router):
),
] = None,
response_model_exclude: Annotated[
- Optional[IncEx],
+ IncEx | None,
Doc(
"""
Configuration passed to Pydantic to exclude certain fields in the
@@ -4064,7 +4056,7 @@ class APIRouter(routing.Router):
),
] = Default(JSONResponse),
name: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
Name for this *path operation*. Only used internally.
@@ -4072,7 +4064,7 @@ class APIRouter(routing.Router):
),
] = None,
callbacks: Annotated[
- Optional[list[BaseRoute]],
+ list[BaseRoute] | None,
Doc(
"""
List of *path operations* that will be used as OpenAPI callbacks.
@@ -4088,7 +4080,7 @@ class APIRouter(routing.Router):
),
] = None,
openapi_extra: Annotated[
- Optional[dict[str, Any]],
+ dict[str, Any] | None,
Doc(
"""
Extra metadata to be included in the OpenAPI schema for this *path
@@ -4213,7 +4205,7 @@ class APIRouter(routing.Router):
),
] = Default(None),
status_code: Annotated[
- Optional[int],
+ int | None,
Doc(
"""
The default status code to be used for the response.
@@ -4226,7 +4218,7 @@ class APIRouter(routing.Router):
),
] = None,
tags: Annotated[
- Optional[list[Union[str, Enum]]],
+ list[str | Enum] | None,
Doc(
"""
A list of tags to be applied to the *path operation*.
@@ -4239,7 +4231,7 @@ class APIRouter(routing.Router):
),
] = None,
dependencies: Annotated[
- Optional[Sequence[params.Depends]],
+ Sequence[params.Depends] | None,
Doc(
"""
A list of dependencies (using `Depends()`) to be applied to the
@@ -4251,7 +4243,7 @@ class APIRouter(routing.Router):
),
] = None,
summary: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
A summary for the *path operation*.
@@ -4264,7 +4256,7 @@ class APIRouter(routing.Router):
),
] = None,
description: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
A description for the *path operation*.
@@ -4292,7 +4284,7 @@ class APIRouter(routing.Router):
),
] = "Successful Response",
responses: Annotated[
- Optional[dict[Union[int, str], dict[str, Any]]],
+ dict[int | str, dict[str, Any]] | None,
Doc(
"""
Additional responses that could be returned by this *path operation*.
@@ -4302,7 +4294,7 @@ class APIRouter(routing.Router):
),
] = None,
deprecated: Annotated[
- Optional[bool],
+ bool | None,
Doc(
"""
Mark this *path operation* as deprecated.
@@ -4312,7 +4304,7 @@ class APIRouter(routing.Router):
),
] = None,
operation_id: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
Custom operation ID to be used by this *path operation*.
@@ -4332,7 +4324,7 @@ class APIRouter(routing.Router):
),
] = None,
response_model_include: Annotated[
- Optional[IncEx],
+ IncEx | None,
Doc(
"""
Configuration passed to Pydantic to include only certain fields in the
@@ -4344,7 +4336,7 @@ class APIRouter(routing.Router):
),
] = None,
response_model_exclude: Annotated[
- Optional[IncEx],
+ IncEx | None,
Doc(
"""
Configuration passed to Pydantic to exclude certain fields in the
@@ -4446,7 +4438,7 @@ class APIRouter(routing.Router):
),
] = Default(JSONResponse),
name: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
Name for this *path operation*. Only used internally.
@@ -4454,7 +4446,7 @@ class APIRouter(routing.Router):
),
] = None,
callbacks: Annotated[
- Optional[list[BaseRoute]],
+ list[BaseRoute] | None,
Doc(
"""
List of *path operations* that will be used as OpenAPI callbacks.
@@ -4470,7 +4462,7 @@ class APIRouter(routing.Router):
),
] = None,
openapi_extra: Annotated[
- Optional[dict[str, Any]],
+ dict[str, Any] | None,
Doc(
"""
Extra metadata to be included in the OpenAPI schema for this *path
diff --git a/fastapi/security/api_key.py b/fastapi/security/api_key.py
index 18dfb8e618..89358a9136 100644
--- a/fastapi/security/api_key.py
+++ b/fastapi/security/api_key.py
@@ -1,4 +1,4 @@
-from typing import Annotated, Optional, Union
+from typing import Annotated
from annotated_doc import Doc
from fastapi.openapi.models import APIKey, APIKeyIn
@@ -13,8 +13,8 @@ class APIKeyBase(SecurityBase):
self,
location: APIKeyIn,
name: str,
- description: Union[str, None],
- scheme_name: Union[str, None],
+ description: str | None,
+ scheme_name: str | None,
auto_error: bool,
):
self.auto_error = auto_error
@@ -42,7 +42,7 @@ class APIKeyBase(SecurityBase):
headers={"WWW-Authenticate": "APIKey"},
)
- def check_api_key(self, api_key: Optional[str]) -> Optional[str]:
+ def check_api_key(self, api_key: str | None) -> str | None:
if not api_key:
if self.auto_error:
raise self.make_not_authenticated_error()
@@ -90,7 +90,7 @@ class APIKeyQuery(APIKeyBase):
Doc("Query parameter name."),
],
scheme_name: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
Security scheme name.
@@ -100,7 +100,7 @@ class APIKeyQuery(APIKeyBase):
),
] = None,
description: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
Security scheme description.
@@ -137,7 +137,7 @@ class APIKeyQuery(APIKeyBase):
auto_error=auto_error,
)
- async def __call__(self, request: Request) -> Optional[str]:
+ async def __call__(self, request: Request) -> str | None:
api_key = request.query_params.get(self.model.name)
return self.check_api_key(api_key)
@@ -179,7 +179,7 @@ class APIKeyHeader(APIKeyBase):
*,
name: Annotated[str, Doc("Header name.")],
scheme_name: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
Security scheme name.
@@ -189,7 +189,7 @@ class APIKeyHeader(APIKeyBase):
),
] = None,
description: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
Security scheme description.
@@ -225,7 +225,7 @@ class APIKeyHeader(APIKeyBase):
auto_error=auto_error,
)
- async def __call__(self, request: Request) -> Optional[str]:
+ async def __call__(self, request: Request) -> str | None:
api_key = request.headers.get(self.model.name)
return self.check_api_key(api_key)
@@ -267,7 +267,7 @@ class APIKeyCookie(APIKeyBase):
*,
name: Annotated[str, Doc("Cookie name.")],
scheme_name: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
Security scheme name.
@@ -277,7 +277,7 @@ class APIKeyCookie(APIKeyBase):
),
] = None,
description: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
Security scheme description.
@@ -313,6 +313,6 @@ class APIKeyCookie(APIKeyBase):
auto_error=auto_error,
)
- async def __call__(self, request: Request) -> Optional[str]:
+ async def __call__(self, request: Request) -> str | None:
api_key = request.cookies.get(self.model.name)
return self.check_api_key(api_key)
diff --git a/fastapi/security/http.py b/fastapi/security/http.py
index b4c3bc6d85..05299323cb 100644
--- a/fastapi/security/http.py
+++ b/fastapi/security/http.py
@@ -1,6 +1,6 @@
import binascii
from base64 import b64decode
-from typing import Annotated, Optional
+from typing import Annotated
from annotated_doc import Doc
from fastapi.exceptions import HTTPException
@@ -71,8 +71,8 @@ class HTTPBase(SecurityBase):
self,
*,
scheme: str,
- scheme_name: Optional[str] = None,
- description: Optional[str] = None,
+ scheme_name: str | None = None,
+ description: str | None = None,
auto_error: bool = True,
):
self.model: HTTPBaseModel = HTTPBaseModel(
@@ -91,9 +91,7 @@ class HTTPBase(SecurityBase):
headers=self.make_authenticate_headers(),
)
- async def __call__(
- self, request: Request
- ) -> Optional[HTTPAuthorizationCredentials]:
+ async def __call__(self, request: Request) -> HTTPAuthorizationCredentials | None:
authorization = request.headers.get("Authorization")
scheme, credentials = get_authorization_scheme_param(authorization)
if not (authorization and scheme and credentials):
@@ -143,7 +141,7 @@ class HTTPBasic(HTTPBase):
self,
*,
scheme_name: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
Security scheme name.
@@ -153,7 +151,7 @@ class HTTPBasic(HTTPBase):
),
] = None,
realm: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
HTTP Basic authentication realm.
@@ -161,7 +159,7 @@ class HTTPBasic(HTTPBase):
),
] = None,
description: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
Security scheme description.
@@ -203,7 +201,7 @@ class HTTPBasic(HTTPBase):
async def __call__( # type: ignore
self, request: Request
- ) -> Optional[HTTPBasicCredentials]:
+ ) -> HTTPBasicCredentials | None:
authorization = request.headers.get("Authorization")
scheme, param = get_authorization_scheme_param(authorization)
if not authorization or scheme.lower() != "basic":
@@ -256,9 +254,9 @@ class HTTPBearer(HTTPBase):
def __init__(
self,
*,
- bearerFormat: Annotated[Optional[str], Doc("Bearer token format.")] = None,
+ bearerFormat: Annotated[str | None, Doc("Bearer token format.")] = None,
scheme_name: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
Security scheme name.
@@ -268,7 +266,7 @@ class HTTPBearer(HTTPBase):
),
] = None,
description: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
Security scheme description.
@@ -302,9 +300,7 @@ class HTTPBearer(HTTPBase):
self.scheme_name = scheme_name or self.__class__.__name__
self.auto_error = auto_error
- async def __call__(
- self, request: Request
- ) -> Optional[HTTPAuthorizationCredentials]:
+ async def __call__(self, request: Request) -> HTTPAuthorizationCredentials | None:
authorization = request.headers.get("Authorization")
scheme, credentials = get_authorization_scheme_param(authorization)
if not (authorization and scheme and credentials):
@@ -362,7 +358,7 @@ class HTTPDigest(HTTPBase):
self,
*,
scheme_name: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
Security scheme name.
@@ -372,7 +368,7 @@ class HTTPDigest(HTTPBase):
),
] = None,
description: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
Security scheme description.
@@ -405,9 +401,7 @@ class HTTPDigest(HTTPBase):
self.scheme_name = scheme_name or self.__class__.__name__
self.auto_error = auto_error
- async def __call__(
- self, request: Request
- ) -> Optional[HTTPAuthorizationCredentials]:
+ async def __call__(self, request: Request) -> HTTPAuthorizationCredentials | None:
authorization = request.headers.get("Authorization")
scheme, credentials = get_authorization_scheme_param(authorization)
if not (authorization and scheme and credentials):
diff --git a/fastapi/security/oauth2.py b/fastapi/security/oauth2.py
index 58ffc5c762..661043ce7b 100644
--- a/fastapi/security/oauth2.py
+++ b/fastapi/security/oauth2.py
@@ -1,4 +1,4 @@
-from typing import Annotated, Any, Optional, Union, cast
+from typing import Annotated, Any, cast
from annotated_doc import Doc
from fastapi.exceptions import HTTPException
@@ -60,7 +60,7 @@ class OAuth2PasswordRequestForm:
self,
*,
grant_type: Annotated[
- Union[str, None],
+ str | None,
Form(pattern="^password$"),
Doc(
"""
@@ -128,7 +128,7 @@ class OAuth2PasswordRequestForm:
),
] = "",
client_id: Annotated[
- Union[str, None],
+ str | None,
Form(),
Doc(
"""
@@ -139,7 +139,7 @@ class OAuth2PasswordRequestForm:
),
] = None,
client_secret: Annotated[
- Union[str, None],
+ str | None,
Form(json_schema_extra={"format": "password"}),
Doc(
"""
@@ -294,7 +294,7 @@ class OAuth2PasswordRequestFormStrict(OAuth2PasswordRequestForm):
),
] = "",
client_id: Annotated[
- Union[str, None],
+ str | None,
Form(),
Doc(
"""
@@ -305,7 +305,7 @@ class OAuth2PasswordRequestFormStrict(OAuth2PasswordRequestForm):
),
] = None,
client_secret: Annotated[
- Union[str, None],
+ str | None,
Form(),
Doc(
"""
@@ -344,7 +344,7 @@ class OAuth2(SecurityBase):
self,
*,
flows: Annotated[
- Union[OAuthFlowsModel, dict[str, dict[str, Any]]],
+ OAuthFlowsModel | dict[str, dict[str, Any]],
Doc(
"""
The dictionary of OAuth2 flows.
@@ -352,7 +352,7 @@ class OAuth2(SecurityBase):
),
] = OAuthFlowsModel(),
scheme_name: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
Security scheme name.
@@ -362,7 +362,7 @@ class OAuth2(SecurityBase):
),
] = None,
description: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
Security scheme description.
@@ -420,7 +420,7 @@ class OAuth2(SecurityBase):
headers={"WWW-Authenticate": "Bearer"},
)
- async def __call__(self, request: Request) -> Optional[str]:
+ async def __call__(self, request: Request) -> str | None:
authorization = request.headers.get("Authorization")
if not authorization:
if self.auto_error:
@@ -454,7 +454,7 @@ class OAuth2PasswordBearer(OAuth2):
),
],
scheme_name: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
Security scheme name.
@@ -464,7 +464,7 @@ class OAuth2PasswordBearer(OAuth2):
),
] = None,
scopes: Annotated[
- Optional[dict[str, str]],
+ dict[str, str] | None,
Doc(
"""
The OAuth2 scopes that would be required by the *path operations* that
@@ -476,7 +476,7 @@ class OAuth2PasswordBearer(OAuth2):
),
] = None,
description: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
Security scheme description.
@@ -506,7 +506,7 @@ class OAuth2PasswordBearer(OAuth2):
),
] = True,
refreshUrl: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
The URL to refresh the token and obtain a new one.
@@ -533,7 +533,7 @@ class OAuth2PasswordBearer(OAuth2):
auto_error=auto_error,
)
- async def __call__(self, request: Request) -> Optional[str]:
+ async def __call__(self, request: Request) -> str | None:
authorization = request.headers.get("Authorization")
scheme, param = get_authorization_scheme_param(authorization)
if not authorization or scheme.lower() != "bearer":
@@ -562,7 +562,7 @@ class OAuth2AuthorizationCodeBearer(OAuth2):
),
],
refreshUrl: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
The URL to refresh the token and obtain a new one.
@@ -570,7 +570,7 @@ class OAuth2AuthorizationCodeBearer(OAuth2):
),
] = None,
scheme_name: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
Security scheme name.
@@ -580,7 +580,7 @@ class OAuth2AuthorizationCodeBearer(OAuth2):
),
] = None,
scopes: Annotated[
- Optional[dict[str, str]],
+ dict[str, str] | None,
Doc(
"""
The OAuth2 scopes that would be required by the *path operations* that
@@ -589,7 +589,7 @@ class OAuth2AuthorizationCodeBearer(OAuth2):
),
] = None,
description: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
Security scheme description.
@@ -639,7 +639,7 @@ class OAuth2AuthorizationCodeBearer(OAuth2):
auto_error=auto_error,
)
- async def __call__(self, request: Request) -> Optional[str]:
+ async def __call__(self, request: Request) -> str | None:
authorization = request.headers.get("Authorization")
scheme, param = get_authorization_scheme_param(authorization)
if not authorization or scheme.lower() != "bearer":
@@ -666,7 +666,7 @@ class SecurityScopes:
def __init__(
self,
scopes: Annotated[
- Optional[list[str]],
+ list[str] | None,
Doc(
"""
This will be filled by FastAPI.
diff --git a/fastapi/security/open_id_connect_url.py b/fastapi/security/open_id_connect_url.py
index f4d953351e..1c6fcc7440 100644
--- a/fastapi/security/open_id_connect_url.py
+++ b/fastapi/security/open_id_connect_url.py
@@ -1,4 +1,4 @@
-from typing import Annotated, Optional
+from typing import Annotated
from annotated_doc import Doc
from fastapi.openapi.models import OpenIdConnect as OpenIdConnectModel
@@ -31,7 +31,7 @@ class OpenIdConnect(SecurityBase):
),
],
scheme_name: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
Security scheme name.
@@ -41,7 +41,7 @@ class OpenIdConnect(SecurityBase):
),
] = None,
description: Annotated[
- Optional[str],
+ str | None,
Doc(
"""
Security scheme description.
@@ -84,7 +84,7 @@ class OpenIdConnect(SecurityBase):
headers={"WWW-Authenticate": "Bearer"},
)
- async def __call__(self, request: Request) -> Optional[str]:
+ async def __call__(self, request: Request) -> str | None:
authorization = request.headers.get("Authorization")
if not authorization:
if self.auto_error:
diff --git a/fastapi/security/utils.py b/fastapi/security/utils.py
index fd349aec74..8ee66fd381 100644
--- a/fastapi/security/utils.py
+++ b/fastapi/security/utils.py
@@ -1,8 +1,5 @@
-from typing import Optional
-
-
def get_authorization_scheme_param(
- authorization_header_value: Optional[str],
+ authorization_header_value: str | None,
) -> tuple[str, str]:
if not authorization_header_value:
return "", ""
diff --git a/fastapi/types.py b/fastapi/types.py
index 1c3a6de749..1fb86e13b1 100644
--- a/fastapi/types.py
+++ b/fastapi/types.py
@@ -1,11 +1,12 @@
import types
+from collections.abc import Callable
from enum import Enum
-from typing import Any, Callable, Optional, TypeVar, Union
+from typing import Any, TypeVar, Union
from pydantic import BaseModel
from pydantic.main import IncEx as IncEx
DecoratedCallable = TypeVar("DecoratedCallable", bound=Callable[..., Any])
UnionType = getattr(types, "UnionType", Union)
-ModelNameMap = dict[Union[type[BaseModel], type[Enum]], str]
-DependencyCacheKey = tuple[Optional[Callable[..., Any]], tuple[str, ...], str]
+ModelNameMap = dict[type[BaseModel] | type[Enum], str]
+DependencyCacheKey = tuple[Callable[..., Any] | None, tuple[str, ...], str]
diff --git a/fastapi/utils.py b/fastapi/utils.py
index 28c7cdfccb..12eaa2bf08 100644
--- a/fastapi/utils.py
+++ b/fastapi/utils.py
@@ -3,8 +3,7 @@ import warnings
from typing import (
TYPE_CHECKING,
Any,
- Optional,
- Union,
+ Literal,
)
import fastapi
@@ -17,7 +16,6 @@ from fastapi._compat import (
from fastapi.datastructures import DefaultPlaceholder, DefaultType
from fastapi.exceptions import FastAPIDeprecationWarning, PydanticV1NotSupportedError
from pydantic.fields import FieldInfo
-from typing_extensions import Literal
from ._compat import v2
@@ -25,7 +23,7 @@ if TYPE_CHECKING: # pragma: nocover
from .routing import APIRoute
-def is_body_allowed_for_status_code(status_code: Union[int, str, None]) -> bool:
+def is_body_allowed_for_status_code(status_code: int | str | None) -> bool:
if status_code is None:
return True
# Ref: https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#patterned-fields-1
@@ -60,9 +58,9 @@ _invalid_args_message = (
def create_model_field(
name: str,
type_: Any,
- default: Optional[Any] = Undefined,
- field_info: Optional[FieldInfo] = None,
- alias: Optional[str] = None,
+ default: Any | None = Undefined,
+ field_info: FieldInfo | None = None,
+ alias: str | None = None,
mode: Literal["validation", "serialization"] = "validation",
) -> ModelField:
if annotation_is_pydantic_v1(type_):
@@ -121,9 +119,9 @@ def deep_dict_update(main_dict: dict[Any, Any], update_dict: dict[Any, Any]) ->
def get_value_or_default(
- first_item: Union[DefaultPlaceholder, DefaultType],
- *extra_items: Union[DefaultPlaceholder, DefaultType],
-) -> Union[DefaultPlaceholder, DefaultType]:
+ first_item: DefaultPlaceholder | DefaultType,
+ *extra_items: DefaultPlaceholder | DefaultType,
+) -> DefaultPlaceholder | DefaultType:
"""
Pass items or `DefaultPlaceholder`s by descending priority.
diff --git a/pdm_build.py b/pdm_build.py
index a0eb88eebb..b1b662bd39 100644
--- a/pdm_build.py
+++ b/pdm_build.py
@@ -3,18 +3,38 @@ from typing import Any
from pdm.backend.hooks import Context
-TIANGOLO_BUILD_PACKAGE = os.getenv("TIANGOLO_BUILD_PACKAGE", "fastapi")
+TIANGOLO_BUILD_PACKAGE = os.getenv("TIANGOLO_BUILD_PACKAGE")
def pdm_build_initialize(context: Context) -> None:
metadata = context.config.metadata
+ # Get main version
+ version = metadata["version"]
# Get custom config for the current package, from the env var
- config: dict[str, Any] = context.config.data["tool"]["tiangolo"][
+ all_configs_config: dict[str, Any] = context.config.data["tool"]["tiangolo"][
"_internal-slim-build"
- ]["packages"].get(TIANGOLO_BUILD_PACKAGE)
- if not config:
+ ]["packages"]
+
+ if TIANGOLO_BUILD_PACKAGE not in all_configs_config:
return
+
+ config = all_configs_config[TIANGOLO_BUILD_PACKAGE]
project_config: dict[str, Any] = config["project"]
# Override main [project] configs with custom configs for this package
for key, value in project_config.items():
metadata[key] = value
+ # Get custom build config for the current package
+ build_config: dict[str, Any] = (
+ config.get("tool", {}).get("pdm", {}).get("build", {})
+ )
+ # Override PDM build config with custom build config for this package
+ for key, value in build_config.items():
+ context.config.build_config[key] = value
+ # Get main dependencies
+ dependencies: list[str] = metadata.get("dependencies", [])
+ # Sync versions in dependencies
+ new_dependencies = []
+ for dep in dependencies:
+ new_dep = f"{dep}>={version}"
+ new_dependencies.append(new_dep)
+ metadata["dependencies"] = new_dependencies
diff --git a/pyproject.toml b/pyproject.toml
index 4895c2d34e..1e6fda3b1c 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -9,7 +9,7 @@ description = "FastAPI framework, high performance, easy to learn, fast to code,
readme = "README.md"
license = "MIT"
license-files = ["LICENSE"]
-requires-python = ">=3.9"
+requires-python = ">=3.10"
authors = [
{ name = "Sebastián Ramírez", email = "tiangolo@gmail.com" },
]
@@ -33,7 +33,6 @@ classifiers = [
"Framework :: Pydantic :: 2",
"Intended Audience :: Developers",
"Programming Language :: Python :: 3 :: Only",
- "Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
@@ -202,6 +201,29 @@ source-includes = [
[tool.tiangolo._internal-slim-build.packages.fastapi-slim.project]
name = "fastapi-slim"
+readme = "fastapi-slim/README.md"
+dependencies = [
+ "fastapi",
+]
+optional-dependencies = {}
+scripts = {}
+
+[tool.tiangolo._internal-slim-build.packages.fastapi-slim.tool.pdm.build]
+# excludes needs to explicitly exclude the top level python packages,
+# otherwise PDM includes them by default
+# A "*" glob pattern can't be used here because in PDM internals, the patterns are put
+# in a set (unordered, order varies) and each excluded file is assigned one of the
+# glob patterns that matches, as the set is unordered, the matched pattern could be "*"
+# independent of the order here. And then the internal code would give it a lower score
+# than the one for a default included file.
+# By not using "*" and explicitly excluding the top level packages, they get a higher
+# score than the default inclusion
+excludes = ["fastapi", "tests", "pdm_build.py"]
+# source-includes needs to explicitly define some value because PDM will check the
+# truthy value of the list, and if empty, will include some defaults, including "tests",
+# an empty string doesn't match anything, but makes the list truthy, so that PDM
+# doesn't override it during the build.
+source-includes = [""]
[tool.mypy]
plugins = ["pydantic.mypy"]
@@ -263,20 +285,205 @@ omit = [
"docs_src/dependencies/tutorial014_an_py310.py", # temporary code example?
# Pydantic v1 migration, no longer tested
"docs_src/pydantic_v1_in_v2/tutorial001_an_py310.py",
- "docs_src/pydantic_v1_in_v2/tutorial001_an_py39.py",
"docs_src/pydantic_v1_in_v2/tutorial002_an_py310.py",
- "docs_src/pydantic_v1_in_v2/tutorial002_an_py39.py",
"docs_src/pydantic_v1_in_v2/tutorial003_an_py310.py",
- "docs_src/pydantic_v1_in_v2/tutorial003_an_py39.py",
"docs_src/pydantic_v1_in_v2/tutorial004_an_py310.py",
- "docs_src/pydantic_v1_in_v2/tutorial004_an_py39.py",
- # TODO: remove when removing this file, after updating translations, Pydantic v1
- "docs_src/schema_extra_example/tutorial001_pv1_py310.py",
- "docs_src/schema_extra_example/tutorial001_pv1_py39.py",
- "docs_src/path_operation_advanced_configuration/tutorial007_pv1_py39.py",
- "docs_src/settings/app03_py39/config_pv1.py",
- "docs_src/settings/app03_an_py39/config_pv1.py",
- "docs_src/settings/tutorial001_pv1_py39.py",
+ # TODO: remove all the ignores below when all translations use the new Python 3.10 files
+ "docs_src/additional_responses/tutorial001_py39.py",
+ "docs_src/additional_responses/tutorial003_py39.py",
+ "docs_src/advanced_middleware/tutorial001_py39.py",
+ "docs_src/advanced_middleware/tutorial002_py39.py",
+ "docs_src/advanced_middleware/tutorial003_py39.py",
+ "docs_src/app_testing/app_a_py39/main.py",
+ "docs_src/app_testing/app_a_py39/test_main.py",
+ "docs_src/app_testing/tutorial001_py39.py",
+ "docs_src/app_testing/tutorial002_py39.py",
+ "docs_src/app_testing/tutorial003_py39.py",
+ "docs_src/app_testing/tutorial004_py39.py",
+ "docs_src/async_tests/app_a_py39/main.py",
+ "docs_src/async_tests/app_a_py39/test_main.py",
+ "docs_src/authentication_error_status_code/tutorial001_an_py39.py",
+ "docs_src/background_tasks/tutorial001_py39.py",
+ "docs_src/behind_a_proxy/tutorial001_01_py39.py",
+ "docs_src/behind_a_proxy/tutorial001_py39.py",
+ "docs_src/behind_a_proxy/tutorial002_py39.py",
+ "docs_src/behind_a_proxy/tutorial003_py39.py",
+ "docs_src/behind_a_proxy/tutorial004_py39.py",
+ "docs_src/bigger_applications/app_an_py39/dependencies.py",
+ "docs_src/bigger_applications/app_an_py39/internal/admin.py",
+ "docs_src/bigger_applications/app_an_py39/main.py",
+ "docs_src/bigger_applications/app_an_py39/routers/items.py",
+ "docs_src/bigger_applications/app_an_py39/routers/users.py",
+ "docs_src/bigger_applications/app_py39/dependencies.py",
+ "docs_src/bigger_applications/app_py39/main.py",
+ "docs_src/body_nested_models/tutorial008_py39.py",
+ "docs_src/body_nested_models/tutorial009_py39.py",
+ "docs_src/conditional_openapi/tutorial001_py39.py",
+ "docs_src/configure_swagger_ui/tutorial001_py39.py",
+ "docs_src/configure_swagger_ui/tutorial002_py39.py",
+ "docs_src/configure_swagger_ui/tutorial003_py39.py",
+ "docs_src/cors/tutorial001_py39.py",
+ "docs_src/custom_docs_ui/tutorial001_py39.py",
+ "docs_src/custom_docs_ui/tutorial002_py39.py",
+ "docs_src/custom_response/tutorial001_py39.py",
+ "docs_src/custom_response/tutorial001b_py39.py",
+ "docs_src/custom_response/tutorial002_py39.py",
+ "docs_src/custom_response/tutorial003_py39.py",
+ "docs_src/custom_response/tutorial004_py39.py",
+ "docs_src/custom_response/tutorial005_py39.py",
+ "docs_src/custom_response/tutorial006_py39.py",
+ "docs_src/custom_response/tutorial006b_py39.py",
+ "docs_src/custom_response/tutorial006c_py39.py",
+ "docs_src/custom_response/tutorial007_py39.py",
+ "docs_src/custom_response/tutorial008_py39.py",
+ "docs_src/custom_response/tutorial009_py39.py",
+ "docs_src/custom_response/tutorial009b_py39.py",
+ "docs_src/custom_response/tutorial009c_py39.py",
+ "docs_src/custom_response/tutorial010_py39.py",
+ "docs_src/debugging/tutorial001_py39.py",
+ "docs_src/dependencies/tutorial006_an_py39.py",
+ "docs_src/dependencies/tutorial006_py39.py",
+ "docs_src/dependencies/tutorial007_py39.py",
+ "docs_src/dependencies/tutorial008_py39.py",
+ "docs_src/dependencies/tutorial008b_an_py39.py",
+ "docs_src/dependencies/tutorial008b_py39.py",
+ "docs_src/dependencies/tutorial008c_an_py39.py",
+ "docs_src/dependencies/tutorial008c_py39.py",
+ "docs_src/dependencies/tutorial008d_an_py39.py",
+ "docs_src/dependencies/tutorial008d_py39.py",
+ "docs_src/dependencies/tutorial008e_an_py39.py",
+ "docs_src/dependencies/tutorial008e_py39.py",
+ "docs_src/dependencies/tutorial010_py39.py",
+ "docs_src/dependencies/tutorial011_an_py39.py",
+ "docs_src/dependencies/tutorial011_py39.py",
+ "docs_src/dependencies/tutorial012_an_py39.py",
+ "docs_src/dependencies/tutorial012_py39.py",
+ "docs_src/events/tutorial001_py39.py",
+ "docs_src/events/tutorial002_py39.py",
+ "docs_src/events/tutorial003_py39.py",
+ "docs_src/extending_openapi/tutorial001_py39.py",
+ "docs_src/extra_models/tutorial004_py39.py",
+ "docs_src/extra_models/tutorial005_py39.py",
+ "docs_src/first_steps/tutorial001_py39.py",
+ "docs_src/first_steps/tutorial003_py39.py",
+ "docs_src/generate_clients/tutorial001_py39.py",
+ "docs_src/generate_clients/tutorial002_py39.py",
+ "docs_src/generate_clients/tutorial003_py39.py",
+ "docs_src/generate_clients/tutorial004_py39.py",
+ "docs_src/graphql_/tutorial001_py39.py",
+ "docs_src/handling_errors/tutorial001_py39.py",
+ "docs_src/handling_errors/tutorial002_py39.py",
+ "docs_src/handling_errors/tutorial003_py39.py",
+ "docs_src/handling_errors/tutorial004_py39.py",
+ "docs_src/handling_errors/tutorial005_py39.py",
+ "docs_src/handling_errors/tutorial006_py39.py",
+ "docs_src/metadata/tutorial001_1_py39.py",
+ "docs_src/metadata/tutorial001_py39.py",
+ "docs_src/metadata/tutorial002_py39.py",
+ "docs_src/metadata/tutorial003_py39.py",
+ "docs_src/metadata/tutorial004_py39.py",
+ "docs_src/middleware/tutorial001_py39.py",
+ "docs_src/openapi_webhooks/tutorial001_py39.py",
+ "docs_src/path_operation_advanced_configuration/tutorial001_py39.py",
+ "docs_src/path_operation_advanced_configuration/tutorial002_py39.py",
+ "docs_src/path_operation_advanced_configuration/tutorial003_py39.py",
+ "docs_src/path_operation_advanced_configuration/tutorial005_py39.py",
+ "docs_src/path_operation_advanced_configuration/tutorial006_py39.py",
+ "docs_src/path_operation_advanced_configuration/tutorial007_py39.py",
+ "docs_src/path_operation_configuration/tutorial002b_py39.py",
+ "docs_src/path_operation_configuration/tutorial006_py39.py",
+ "docs_src/path_params/tutorial001_py39.py",
+ "docs_src/path_params/tutorial002_py39.py",
+ "docs_src/path_params/tutorial003_py39.py",
+ "docs_src/path_params/tutorial003b_py39.py",
+ "docs_src/path_params/tutorial004_py39.py",
+ "docs_src/path_params/tutorial005_py39.py",
+ "docs_src/path_params_numeric_validations/tutorial002_an_py39.py",
+ "docs_src/path_params_numeric_validations/tutorial002_py39.py",
+ "docs_src/path_params_numeric_validations/tutorial003_an_py39.py",
+ "docs_src/path_params_numeric_validations/tutorial003_py39.py",
+ "docs_src/path_params_numeric_validations/tutorial004_an_py39.py",
+ "docs_src/path_params_numeric_validations/tutorial004_py39.py",
+ "docs_src/path_params_numeric_validations/tutorial005_an_py39.py",
+ "docs_src/path_params_numeric_validations/tutorial005_py39.py",
+ "docs_src/path_params_numeric_validations/tutorial006_an_py39.py",
+ "docs_src/path_params_numeric_validations/tutorial006_py39.py",
+ "docs_src/python_types/tutorial001_py39.py",
+ "docs_src/python_types/tutorial002_py39.py",
+ "docs_src/python_types/tutorial003_py39.py",
+ "docs_src/python_types/tutorial004_py39.py",
+ "docs_src/python_types/tutorial005_py39.py",
+ "docs_src/python_types/tutorial006_py39.py",
+ "docs_src/python_types/tutorial007_py39.py",
+ "docs_src/python_types/tutorial008_py39.py",
+ "docs_src/python_types/tutorial008b_py39.py",
+ "docs_src/python_types/tutorial009_py39.py",
+ "docs_src/python_types/tutorial009b_py39.py",
+ "docs_src/python_types/tutorial009c_py39.py",
+ "docs_src/python_types/tutorial010_py39.py",
+ "docs_src/python_types/tutorial013_py39.py",
+ "docs_src/query_params/tutorial001_py39.py",
+ "docs_src/query_params/tutorial005_py39.py",
+ "docs_src/query_params_str_validations/tutorial005_an_py39.py",
+ "docs_src/query_params_str_validations/tutorial005_py39.py",
+ "docs_src/query_params_str_validations/tutorial006_an_py39.py",
+ "docs_src/query_params_str_validations/tutorial006_py39.py",
+ "docs_src/query_params_str_validations/tutorial012_an_py39.py",
+ "docs_src/query_params_str_validations/tutorial012_py39.py",
+ "docs_src/query_params_str_validations/tutorial013_an_py39.py",
+ "docs_src/query_params_str_validations/tutorial013_py39.py",
+ "docs_src/request_files/tutorial001_03_an_py39.py",
+ "docs_src/request_files/tutorial001_03_py39.py",
+ "docs_src/request_files/tutorial001_an_py39.py",
+ "docs_src/request_files/tutorial001_py39.py",
+ "docs_src/request_files/tutorial002_an_py39.py",
+ "docs_src/request_files/tutorial002_py39.py",
+ "docs_src/request_files/tutorial003_an_py39.py",
+ "docs_src/request_files/tutorial003_py39.py",
+ "docs_src/request_form_models/tutorial001_an_py39.py",
+ "docs_src/request_form_models/tutorial001_py39.py",
+ "docs_src/request_form_models/tutorial002_an_py39.py",
+ "docs_src/request_form_models/tutorial002_py39.py",
+ "docs_src/request_forms/tutorial001_an_py39.py",
+ "docs_src/request_forms/tutorial001_py39.py",
+ "docs_src/request_forms_and_files/tutorial001_an_py39.py",
+ "docs_src/request_forms_and_files/tutorial001_py39.py",
+ "docs_src/response_change_status_code/tutorial001_py39.py",
+ "docs_src/response_cookies/tutorial001_py39.py",
+ "docs_src/response_cookies/tutorial002_py39.py",
+ "docs_src/response_directly/tutorial002_py39.py",
+ "docs_src/response_headers/tutorial001_py39.py",
+ "docs_src/response_headers/tutorial002_py39.py",
+ "docs_src/response_model/tutorial003_02_py39.py",
+ "docs_src/response_model/tutorial003_03_py39.py",
+ "docs_src/response_status_code/tutorial001_py39.py",
+ "docs_src/response_status_code/tutorial002_py39.py",
+ "docs_src/security/tutorial001_an_py39.py",
+ "docs_src/security/tutorial001_py39.py",
+ "docs_src/security/tutorial006_an_py39.py",
+ "docs_src/security/tutorial006_py39.py",
+ "docs_src/security/tutorial007_an_py39.py",
+ "docs_src/security/tutorial007_py39.py",
+ "docs_src/settings/app01_py39/config.py",
+ "docs_src/settings/app01_py39/main.py",
+ "docs_src/settings/app02_an_py39/config.py",
+ "docs_src/settings/app02_an_py39/main.py",
+ "docs_src/settings/app02_an_py39/test_main.py",
+ "docs_src/settings/app02_py39/config.py",
+ "docs_src/settings/app02_py39/main.py",
+ "docs_src/settings/app02_py39/test_main.py",
+ "docs_src/settings/app03_an_py39/config.py",
+ "docs_src/settings/app03_an_py39/main.py",
+ "docs_src/settings/app03_py39/config.py",
+ "docs_src/settings/app03_py39/main.py",
+ "docs_src/settings/tutorial001_py39.py",
+ "docs_src/static_files/tutorial001_py39.py",
+ "docs_src/sub_applications/tutorial001_py39.py",
+ "docs_src/templates/tutorial001_py39.py",
+ "docs_src/using_request_directly/tutorial001_py39.py",
+ "docs_src/websockets/tutorial001_py39.py",
+ "docs_src/websockets/tutorial003_py39.py",
+ "docs_src/wsgi/tutorial001_py39.py",
]
[tool.coverage.report]
@@ -305,32 +512,42 @@ ignore = [
[tool.ruff.lint.per-file-ignores]
"__init__.py" = ["F401"]
+"docs_src/custom_request_and_route/tutorial002_an_py310.py" = ["B904"]
+"docs_src/custom_request_and_route/tutorial002_an_py39.py" = ["B904"]
+"docs_src/custom_request_and_route/tutorial002_py310.py" = ["B904"]
+"docs_src/custom_request_and_route/tutorial002_py39.py" = ["B904"]
+"docs_src/custom_response/tutorial007_py310.py" = ["B007"]
+"docs_src/custom_response/tutorial007_py39.py" = ["B007"]
+"docs_src/dataclasses/tutorial003_py39.py" = ["I001"]
+"docs_src/dependencies/tutorial007_py310.py" = ["F821"]
"docs_src/dependencies/tutorial007_py39.py" = ["F821"]
+"docs_src/dependencies/tutorial008_an_py310.py" = ["F821"]
+"docs_src/dependencies/tutorial008_an_py39.py" = ["F821"]
+"docs_src/dependencies/tutorial008_py310.py" = ["F821"]
"docs_src/dependencies/tutorial008_py39.py" = ["F821"]
+"docs_src/dependencies/tutorial008b_an_py310.py" = ["B904"]
+"docs_src/dependencies/tutorial008b_an_py39.py" = ["B904"]
+"docs_src/dependencies/tutorial008b_py310.py" = ["B904"]
+"docs_src/dependencies/tutorial008b_py39.py" = ["B904"]
+"docs_src/dependencies/tutorial009_py310.py" = ["F821"]
"docs_src/dependencies/tutorial009_py39.py" = ["F821"]
+"docs_src/dependencies/tutorial010_py310.py" = ["F821"]
"docs_src/dependencies/tutorial010_py39.py" = ["F821"]
-"docs_src/custom_response/tutorial007_py39.py" = ["B007"]
-"docs_src/dataclasses/tutorial003_py39.py" = ["I001"]
-"docs_src/path_operation_advanced_configuration/tutorial007_py39.py" = ["B904"]
"docs_src/path_operation_advanced_configuration/tutorial007_pv1_py39.py" = ["B904"]
-"docs_src/custom_request_and_route/tutorial002_py39.py" = ["B904"]
-"docs_src/custom_request_and_route/tutorial002_py310.py" = ["B904"]
-"docs_src/custom_request_and_route/tutorial002_an_py39.py" = ["B904"]
-"docs_src/custom_request_and_route/tutorial002_an_py310.py" = ["B904"]
-"docs_src/dependencies/tutorial008_an_py39.py" = ["F821"]
+"docs_src/path_operation_advanced_configuration/tutorial007_py310.py" = ["B904"]
+"docs_src/path_operation_advanced_configuration/tutorial007_py39.py" = ["B904"]
+"docs_src/query_params_str_validations/tutorial012_an_py310.py" = ["B006"]
"docs_src/query_params_str_validations/tutorial012_an_py39.py" = ["B006"]
+"docs_src/query_params_str_validations/tutorial013_an_py310.py" = ["B006"]
"docs_src/query_params_str_validations/tutorial013_an_py39.py" = ["B006"]
-"docs_src/security/tutorial004_py39.py" = ["B904"]
-"docs_src/security/tutorial004_an_py39.py" = ["B904"]
"docs_src/security/tutorial004_an_py310.py" = ["B904"]
+"docs_src/security/tutorial004_an_py39.py" = ["B904"]
"docs_src/security/tutorial004_py310.py" = ["B904"]
+"docs_src/security/tutorial004_py39.py" = ["B904"]
"docs_src/security/tutorial005_an_py310.py" = ["B904"]
"docs_src/security/tutorial005_an_py39.py" = ["B904"]
"docs_src/security/tutorial005_py310.py" = ["B904"]
"docs_src/security/tutorial005_py39.py" = ["B904"]
-"docs_src/dependencies/tutorial008b_py39.py" = ["B904"]
-"docs_src/dependencies/tutorial008b_an_py39.py" = ["B904"]
-
[tool.ruff.lint.isort]
known-third-party = ["fastapi", "pydantic", "starlette"]
diff --git a/scripts/doc_parsing_utils.py b/scripts/doc_parsing_utils.py
index 79f2e9ec0a..1cd2299e66 100644
--- a/scripts/doc_parsing_utils.py
+++ b/scripts/doc_parsing_utils.py
@@ -1,5 +1,5 @@
import re
-from typing import TypedDict, Union
+from typing import TypedDict
CODE_INCLUDE_RE = re.compile(r"^\{\*\s*(\S+)\s*(.*)\*\}$")
CODE_INCLUDE_PLACEHOLDER = "
"
@@ -50,8 +50,8 @@ class MarkdownLinkInfo(TypedDict):
line_no: int
url: str
text: str
- title: Union[str, None]
- attributes: Union[str, None]
+ title: str | None
+ attributes: str | None
full_match: str
@@ -287,8 +287,8 @@ def _add_lang_code_to_url(url: str, lang_code: str) -> str:
def _construct_markdown_link(
url: str,
text: str,
- title: Union[str, None],
- attributes: Union[str, None],
+ title: str | None,
+ attributes: str | None,
lang_code: str,
) -> str:
"""
@@ -549,7 +549,7 @@ def extract_multiline_code_blocks(text: list[str]) -> list[MultilineCodeBlockInf
return blocks
-def _split_hash_comment(line: str) -> tuple[str, Union[str, None]]:
+def _split_hash_comment(line: str) -> tuple[str, str | None]:
match = HASH_COMMENT_RE.match(line)
if match:
code = match.group("code").rstrip()
@@ -558,7 +558,7 @@ def _split_hash_comment(line: str) -> tuple[str, Union[str, None]]:
return line.rstrip(), None
-def _split_slashes_comment(line: str) -> tuple[str, Union[str, None]]:
+def _split_slashes_comment(line: str) -> tuple[str, str | None]:
match = SLASHES_COMMENT_RE.match(line)
if match:
code = match.group("code").rstrip()
@@ -603,9 +603,9 @@ def replace_multiline_code_block(
return block_a["content"].copy() # We don't handle mermaid code blocks for now
code_block: list[str] = []
- for line_a, line_b in zip(block_a["content"], block_b["content"]):
- line_a_comment: Union[str, None] = None
- line_b_comment: Union[str, None] = None
+ for line_a, line_b in zip(block_a["content"], block_b["content"], strict=False):
+ line_a_comment: str | None = None
+ line_b_comment: str | None = None
# Handle comments based on language
if block_language in {
@@ -659,7 +659,7 @@ def replace_multiline_code_blocks_in_text(
)
modified_text = text.copy()
- for block, original_block in zip(code_blocks, original_code_blocks):
+ for block, original_block in zip(code_blocks, original_code_blocks, strict=True):
updated_content = replace_multiline_code_block(block, original_block)
start_line_index = block["start_line_no"] - 1
diff --git a/scripts/docs.py b/scripts/docs.py
index 3cf62f084c..23d74aaf4a 100644
--- a/scripts/docs.py
+++ b/scripts/docs.py
@@ -8,7 +8,7 @@ from html.parser import HTMLParser
from http.server import HTTPServer, SimpleHTTPRequestHandler
from multiprocessing import Pool
from pathlib import Path
-from typing import Any, Optional, Union
+from typing import Any
import mkdocs.utils
import typer
@@ -103,7 +103,7 @@ def get_lang_paths() -> list[Path]:
return sorted(docs_path.iterdir())
-def lang_callback(lang: Optional[str]) -> Union[str, None]:
+def lang_callback(lang: str | None) -> str | None:
if lang is None:
return None
lang = lang.lower()
@@ -412,6 +412,13 @@ def langs_json():
@app.command()
def generate_docs_src_versions_for_file(file_path: Path) -> None:
target_versions = ["py39", "py310"]
+ full_path_str = str(file_path)
+ for target_version in target_versions:
+ if f"_{target_version}" in full_path_str:
+ logging.info(
+ f"Skipping {file_path}, already a version file for {target_version}"
+ )
+ return
base_content = file_path.read_text(encoding="utf-8")
previous_content = {base_content}
for target_version in target_versions:
@@ -438,13 +445,207 @@ def generate_docs_src_versions_for_file(file_path: Path) -> None:
if content_format in previous_content:
continue
previous_content.add(content_format)
- version_file = file_path.with_name(
- file_path.name.replace(".py", f"_{target_version}.py")
- )
+ # Determine where the version label should go: in the parent directory
+ # name or in the file name, matching the source structure.
+ label_in_parent = False
+ for v in target_versions:
+ if f"_{v}" in file_path.parent.name:
+ label_in_parent = True
+ break
+ if label_in_parent:
+ parent_name = file_path.parent.name
+ for v in target_versions:
+ parent_name = parent_name.replace(f"_{v}", "")
+ new_parent = file_path.parent.parent / f"{parent_name}_{target_version}"
+ new_parent.mkdir(parents=True, exist_ok=True)
+ version_file = new_parent / file_path.name
+ else:
+ base_name = file_path.stem
+ for v in target_versions:
+ if base_name.endswith(f"_{v}"):
+ base_name = base_name[: -len(f"_{v}")]
+ break
+ version_file = file_path.with_name(f"{base_name}_{target_version}.py")
logging.info(f"Writing to {version_file}")
version_file.write_text(content_format, encoding="utf-8")
+@app.command()
+def generate_docs_src_versions() -> None:
+ """
+ Generate Python version-specific files for all .py files in docs_src.
+ """
+ docs_src_path = Path("docs_src")
+ for py_file in sorted(docs_src_path.rglob("*.py")):
+ generate_docs_src_versions_for_file(py_file)
+
+
+@app.command()
+def copy_py39_to_py310() -> None:
+ """
+ For each docs_src file/directory with a _py39 label that has no _py310
+ counterpart, copy it with the _py310 label.
+ """
+ docs_src_path = Path("docs_src")
+ # Handle directory-level labels (e.g. app_b_an_py39/)
+ for dir_path in sorted(docs_src_path.rglob("*_py39")):
+ if not dir_path.is_dir():
+ continue
+ py310_dir = dir_path.parent / dir_path.name.replace("_py39", "_py310")
+ if py310_dir.exists():
+ continue
+ logging.info(f"Copying directory {dir_path} -> {py310_dir}")
+ shutil.copytree(dir_path, py310_dir)
+ # Handle file-level labels (e.g. tutorial001_py39.py)
+ for file_path in sorted(docs_src_path.rglob("*_py39.py")):
+ if not file_path.is_file():
+ continue
+ # Skip files inside _py39 directories (already handled above)
+ if "_py39" in file_path.parent.name:
+ continue
+ py310_file = file_path.with_name(
+ file_path.name.replace("_py39.py", "_py310.py")
+ )
+ if py310_file.exists():
+ continue
+ logging.info(f"Copying file {file_path} -> {py310_file}")
+ shutil.copy2(file_path, py310_file)
+
+
+@app.command()
+def update_docs_includes_py39_to_py310() -> None:
+ """
+ Update .md files in docs/en/ to replace _py39 includes with _py310 versions.
+
+ For each include line referencing a _py39 file or directory in docs_src, replace
+ the _py39 label with _py310.
+ """
+ include_pattern = re.compile(r"\{[^}]*docs_src/[^}]*_py39[^}]*\.py[^}]*\}")
+ count = 0
+ for md_file in sorted(en_docs_path.rglob("*.md")):
+ content = md_file.read_text(encoding="utf-8")
+ if "_py39" not in content:
+ continue
+ new_content = include_pattern.sub(
+ lambda m: m.group(0).replace("_py39", "_py310"), content
+ )
+ if new_content != content:
+ md_file.write_text(new_content, encoding="utf-8")
+ count += 1
+ logging.info(f"Updated includes in {md_file}")
+ print(f"Updated {count} file(s) ✅")
+
+
+@app.command()
+def remove_unused_docs_src() -> None:
+ """
+ Delete .py files in docs_src that are not included in any .md file under docs/.
+ """
+ docs_src_path = Path("docs_src")
+ # Collect all docs .md content referencing docs_src
+ all_docs_content = ""
+ for md_file in docs_path.rglob("*.md"):
+ all_docs_content += md_file.read_text(encoding="utf-8")
+ # Build a set of directory-based package roots (e.g. docs_src/bigger_applications/app_py39)
+ # where at least one file is referenced in docs. All files in these directories
+ # should be kept since they may be internally imported by the referenced files.
+ used_package_dirs: set[Path] = set()
+ for py_file in docs_src_path.rglob("*.py"):
+ if py_file.name == "__init__.py":
+ continue
+ rel_path = str(py_file)
+ if rel_path in all_docs_content:
+ # Walk up from the file's parent to find the package root
+ # (a subdirectory under docs_src//)
+ parts = py_file.relative_to(docs_src_path).parts
+ if len(parts) > 2:
+ # File is inside a sub-package like docs_src/topic/app_xxx/...
+ package_root = docs_src_path / parts[0] / parts[1]
+ used_package_dirs.add(package_root)
+ removed = 0
+ for py_file in sorted(docs_src_path.rglob("*.py")):
+ if py_file.name == "__init__.py":
+ continue
+ # Build the relative path as it appears in includes (e.g. docs_src/first_steps/tutorial001.py)
+ rel_path = str(py_file)
+ if rel_path in all_docs_content:
+ continue
+ # If this file is inside a directory-based package where any sibling is
+ # referenced, keep it (it's likely imported internally).
+ parts = py_file.relative_to(docs_src_path).parts
+ if len(parts) > 2:
+ package_root = docs_src_path / parts[0] / parts[1]
+ if package_root in used_package_dirs:
+ continue
+ # Check if the _an counterpart (or non-_an counterpart) is referenced.
+ # If either variant is included, keep both.
+ # Handle both file-level _an (tutorial001_an.py) and directory-level _an
+ # (app_an/main.py)
+ counterpart_found = False
+ full_path_str = str(py_file)
+ if "_an" in py_file.stem:
+ # This is an _an file, check if the non-_an version is referenced
+ counterpart = full_path_str.replace(
+ f"/{py_file.stem}", f"/{py_file.stem.replace('_an', '', 1)}"
+ )
+ if counterpart in all_docs_content:
+ counterpart_found = True
+ else:
+ # This is a non-_an file, check if there's an _an version referenced
+ # Insert _an before any version suffix or at the end of the stem
+ stem = py_file.stem
+ for suffix in ("_py39", "_py310"):
+ if suffix in stem:
+ an_stem = stem.replace(suffix, f"_an{suffix}", 1)
+ break
+ else:
+ an_stem = f"{stem}_an"
+ counterpart = full_path_str.replace(f"/{stem}.", f"/{an_stem}.")
+ if counterpart in all_docs_content:
+ counterpart_found = True
+ # Also check directory-level _an counterparts
+ if not counterpart_found:
+ parent_name = py_file.parent.name
+ if "_an" in parent_name:
+ counterpart_parent = parent_name.replace("_an", "", 1)
+ counterpart_dir = str(py_file).replace(
+ f"/{parent_name}/", f"/{counterpart_parent}/"
+ )
+ if counterpart_dir in all_docs_content:
+ counterpart_found = True
+ else:
+ # Try inserting _an into parent directory name
+ for suffix in ("_py39", "_py310"):
+ if suffix in parent_name:
+ an_parent = parent_name.replace(suffix, f"_an{suffix}", 1)
+ break
+ else:
+ an_parent = f"{parent_name}_an"
+ counterpart_dir = str(py_file).replace(
+ f"/{parent_name}/", f"/{an_parent}/"
+ )
+ if counterpart_dir in all_docs_content:
+ counterpart_found = True
+ if counterpart_found:
+ continue
+ logging.info(f"Removing unused file: {py_file}")
+ py_file.unlink()
+ removed += 1
+ # Clean up directories that are empty or only contain __init__.py / __pycache__
+ for dir_path in sorted(docs_src_path.rglob("*"), reverse=True):
+ if not dir_path.is_dir():
+ continue
+ remaining = [
+ f
+ for f in dir_path.iterdir()
+ if f.name != "__pycache__" and f.name != "__init__.py"
+ ]
+ if not remaining:
+ logging.info(f"Removing empty/init-only directory: {dir_path}")
+ shutil.rmtree(dir_path)
+ print(f"Removed {removed} unused file(s) ✅")
+
+
@app.command()
def add_permalinks_page(path: Path, update_existing: bool = False):
"""
diff --git a/scripts/general-llm-prompt.md b/scripts/general-llm-prompt.md
index d45ab8eb07..23926bd8e9 100644
--- a/scripts/general-llm-prompt.md
+++ b/scripts/general-llm-prompt.md
@@ -353,7 +353,9 @@ Erstelle eine [Virtuelle Umgebung](../virtual-environments.md){.internal-link ta
Translate HTML abbr elements (`text`) as follows:
-- If the text surrounded by the abbr element is an abbreviation (the text may be surrounded by further HTML or Markdown markup or quotes, for example text or `text` or "text", ignore that further markup when deciding if the text is an abbreviation), and if the description (the text inside the title attribute) contains the full phrase for this abbreviation, then append a dash (-) to the full phrase, followed by the translation of the full phrase.
+- The text inside abbr tag may be surrounded by further HTML or Markdown markup or quotes, for example text or `text` or "text". Preserve markup and only translate visible text inside the abbr element.
+
+- If the description (the text inside the title attribute) contains the full phrase for this abbreviation, then append a dash (-) to the full phrase, followed by the translation of the full phrase.
Conversion scheme:
@@ -421,45 +423,7 @@ Result (German):
ASGI
```
-- If the description is not a full phrase for an abbreviation which the abbr element surrounds, but some other information, then just translate the description.
-
-Conversion scheme:
-
-Source (English):
-
-```
-{text}
-```
-
-Result:
-
-```
-{translation of text}
-```
-
-Examples:
-
- Source (English):
-
-```
-path
-linter
-parsing
-0.95.0
-at the time of writing this
-```
-
-Result (German):
-
-```
-Pfad
-Linter
-Parsen
-0.95.0
-zum Zeitpunkt als das hier geschrieben wurde
-```
-
-- If the text surrounded by the abbr element is an abbreviation and the description contains both the full phrase for that abbreviation, and other information, separated by a colon (`:`), then append a dash (`-`) and the translation of the full phrase to the original full phrase and translate the other information.
+- If the title of abbr element contains a full phrase for that abbreviation, and other information, separated by a colon (`:`), then append a dash (`-`) and the translation of the full phrase to the original full phrase and translate the other information.
Conversion scheme:
@@ -526,3 +490,23 @@ Result (German):
- If there is an existing translation, and it has ADDITIONAL abbr elements in a sentence, and these additional abbr elements do not exist in the related sentence in the English text, then KEEP those additional abbr elements in the translation. Do not remove them. Except when you remove the whole sentence from the translation, because the whole sentence was removed from the English text, then also remove the abbr element. The reasoning for this rule is, that such additional abbr elements are manually added by the human editor of the translation, in order to translate or explain an English word to the human readers of the translation. These additional abbr elements would not make sense in the English text, but they do make sense in the translation. So keep them in the translation, even though they are not part of the English text. This rule only applies to abbr elements.
- Apply above rules also when there is an existing translation! Make sure that all title attributes in abbr elements get properly translated or updated, using the schemes given above. However, leave the ADDITIONAL abbr's described above alone. Do not change their formatting or content.
+
+### HTML dfn elements
+
+For HTML dfn elements (`text`), translate the text inside the dfn element and the title attribute. Do not include the original English text in the title attribute.
+
+Examples:
+
+Source (English):
+
+```
+path
+linter
+```
+
+Result (German):
+
+```
+Pfad
+Linter
+```
diff --git a/scripts/mkdocs_hooks.py b/scripts/mkdocs_hooks.py
index 567c0111dc..97006953d6 100644
--- a/scripts/mkdocs_hooks.py
+++ b/scripts/mkdocs_hooks.py
@@ -1,6 +1,6 @@
from functools import lru_cache
from pathlib import Path
-from typing import Any, Union
+from typing import Any
import material
from mkdocs.config.defaults import MkDocsConfig
@@ -105,9 +105,9 @@ def on_files(files: Files, *, config: MkDocsConfig) -> Files:
def generate_renamed_section_items(
- items: list[Union[Page, Section, Link]], *, config: MkDocsConfig
-) -> list[Union[Page, Section, Link]]:
- new_items: list[Union[Page, Section, Link]] = []
+ items: list[Page | Section | Link], *, config: MkDocsConfig
+) -> list[Page | Section | Link]:
+ new_items: list[Page | Section | Link] = []
for item in items:
if isinstance(item, Section):
new_title = item.title
diff --git a/scripts/notify_translations.py b/scripts/notify_translations.py
index 74cdf0dffe..3484b69c70 100644
--- a/scripts/notify_translations.py
+++ b/scripts/notify_translations.py
@@ -3,7 +3,7 @@ import random
import sys
import time
from pathlib import Path
-from typing import Any, Union, cast
+from typing import Any, cast
import httpx
from github import Github
@@ -181,9 +181,9 @@ class Settings(BaseSettings):
github_repository: str
github_token: SecretStr
github_event_path: Path
- github_event_name: Union[str, None] = None
+ github_event_name: str | None = None
httpx_timeout: int = 30
- debug: Union[bool, None] = False
+ debug: bool | None = False
number: int | None = None
@@ -199,12 +199,12 @@ def get_graphql_response(
*,
settings: Settings,
query: str,
- after: Union[str, None] = None,
- category_id: Union[str, None] = None,
- discussion_number: Union[int, None] = None,
- discussion_id: Union[str, None] = None,
- comment_id: Union[str, None] = None,
- body: Union[str, None] = None,
+ after: str | None = None,
+ category_id: str | None = None,
+ discussion_number: int | None = None,
+ discussion_id: str | None = None,
+ comment_id: str | None = None,
+ body: str | None = None,
) -> dict[str, Any]:
headers = {"Authorization": f"token {settings.github_token.get_secret_value()}"}
variables = {
@@ -249,7 +249,7 @@ def get_graphql_translation_discussions(
def get_graphql_translation_discussion_comments_edges(
- *, settings: Settings, discussion_number: int, after: Union[str, None] = None
+ *, settings: Settings, discussion_number: int, after: str | None = None
) -> list[CommentsEdge]:
data = get_graphql_response(
settings=settings,
@@ -372,8 +372,8 @@ def main() -> None:
f"Found a translation discussion for language: {lang} in discussion: #{discussion.number}"
)
- already_notified_comment: Union[Comment, None] = None
- already_done_comment: Union[Comment, None] = None
+ already_notified_comment: Comment | None = None
+ already_done_comment: Comment | None = None
logging.info(
f"Checking current comments in discussion: #{discussion.number} to see if already notified about this PR: #{pr.number}"
diff --git a/scripts/people.py b/scripts/people.py
index 207ab46493..f3254ab606 100644
--- a/scripts/people.py
+++ b/scripts/people.py
@@ -6,7 +6,7 @@ from collections import Counter
from collections.abc import Container
from datetime import datetime, timedelta, timezone
from pathlib import Path
-from typing import Any, Union
+from typing import Any
import httpx
import yaml
@@ -70,7 +70,7 @@ class Author(BaseModel):
class CommentsNode(BaseModel):
createdAt: datetime
- author: Union[Author, None] = None
+ author: Author | None = None
class Replies(BaseModel):
@@ -89,7 +89,7 @@ class DiscussionsComments(BaseModel):
class DiscussionsNode(BaseModel):
number: int
- author: Union[Author, None] = None
+ author: Author | None = None
title: str | None = None
createdAt: datetime
comments: DiscussionsComments
@@ -127,8 +127,8 @@ def get_graphql_response(
*,
settings: Settings,
query: str,
- after: Union[str, None] = None,
- category_id: Union[str, None] = None,
+ after: str | None = None,
+ category_id: str | None = None,
) -> dict[str, Any]:
headers = {"Authorization": f"token {settings.github_token.get_secret_value()}"}
variables = {"after": after, "category_id": category_id}
@@ -156,7 +156,7 @@ def get_graphql_response(
def get_graphql_question_discussion_edges(
*,
settings: Settings,
- after: Union[str, None] = None,
+ after: str | None = None,
) -> list[DiscussionsEdge]:
data = get_graphql_response(
settings=settings,
diff --git a/scripts/tests/test_translation_fixer/test_code_includes/data/en_doc.md b/scripts/tests/test_translation_fixer/test_code_includes/data/en_doc.md
index 593da0b327..0e021dadea 100644
--- a/scripts/tests/test_translation_fixer/test_code_includes/data/en_doc.md
+++ b/scripts/tests/test_translation_fixer/test_code_includes/data/en_doc.md
@@ -4,7 +4,7 @@
Some text
-{* ../../docs_src/bigger_applications/app_an_py39/internal/admin.py hl[3] title["app/internal/admin.py"] *}
+{* ../../docs_src/bigger_applications/app_an_py310/internal/admin.py hl[3] title["app/internal/admin.py"] *}
Some more text
diff --git a/scripts/tests/test_translation_fixer/test_code_includes/data/translated_doc_number_gt.md b/scripts/tests/test_translation_fixer/test_code_includes/data/translated_doc_number_gt.md
index c1ad94d276..aca1464ff2 100644
--- a/scripts/tests/test_translation_fixer/test_code_includes/data/translated_doc_number_gt.md
+++ b/scripts/tests/test_translation_fixer/test_code_includes/data/translated_doc_number_gt.md
@@ -4,7 +4,7 @@
Some text
-{* ../../docs_src/bigger_applications/app_an_py39/internal/admin.py hl[3] title["app/internal/admin.py"] *}
+{* ../../docs_src/bigger_applications/app_an_py310/internal/admin.py hl[3] title["app/internal/admin.py"] *}
Some more text
@@ -12,4 +12,4 @@ Some more text
And even more text
-{* ../../docs_src/python_types/tutorial001_py39.py *}
+{* ../../docs_src/python_types/tutorial001_py310.py *}
diff --git a/scripts/tests/test_translation_fixer/test_code_includes/data/translated_doc_number_lt.md b/scripts/tests/test_translation_fixer/test_code_includes/data/translated_doc_number_lt.md
index 07eaf2c23d..12573aa196 100644
--- a/scripts/tests/test_translation_fixer/test_code_includes/data/translated_doc_number_lt.md
+++ b/scripts/tests/test_translation_fixer/test_code_includes/data/translated_doc_number_lt.md
@@ -4,7 +4,7 @@
Some text
-{* ../../docs_src/bigger_applications/app_an_py39/internal/admin.py hl[3] title["app/internal/admin.py"] *}
+{* ../../docs_src/bigger_applications/app_an_py310/internal/admin.py hl[3] title["app/internal/admin.py"] *}
Some more text
diff --git a/scripts/tests/test_translation_fixer/test_complex_doc/data/en_doc.md b/scripts/tests/test_translation_fixer/test_complex_doc/data/en_doc.md
index 69cd3f3fd7..d6c1e3d2fe 100644
--- a/scripts/tests/test_translation_fixer/test_complex_doc/data/en_doc.md
+++ b/scripts/tests/test_translation_fixer/test_complex_doc/data/en_doc.md
@@ -141,16 +141,16 @@ def hello_world():
## Simple code includes { #simple-code-includes }
-{* ../../docs_src/python_types/tutorial001_py39.py *}
+{* ../../docs_src/python_types/tutorial001_py310.py *}
-{* ../../docs_src/python_types/tutorial002_py39.py *}
+{* ../../docs_src/python_types/tutorial002_py310.py *}
## Code includes with highlighting { #code-includes-with-highlighting }
-{* ../../docs_src/python_types/tutorial002_py39.py hl[1] *}
+{* ../../docs_src/python_types/tutorial002_py310.py hl[1] *}
-{* ../../docs_src/python_types/tutorial006_py39.py hl[10] *}
+{* ../../docs_src/python_types/tutorial006_py310.py hl[10] *}
## Code includes with line ranges { #code-includes-with-line-ranges }
@@ -169,19 +169,19 @@ def hello_world():
## Code includes qith title { #code-includes-with-title }
-{* ../../docs_src/bigger_applications/app_an_py39/routers/users.py hl[1,3] title["app/routers/users.py"] *}
+{* ../../docs_src/bigger_applications/app_an_py310/routers/users.py hl[1,3] title["app/routers/users.py"] *}
-{* ../../docs_src/bigger_applications/app_an_py39/internal/admin.py hl[3] title["app/internal/admin.py"] *}
+{* ../../docs_src/bigger_applications/app_an_py310/internal/admin.py hl[3] title["app/internal/admin.py"] *}
## Code includes with unknown attributes { #code-includes-with-unknown-attributes }
-{* ../../docs_src/python_types/tutorial001_py39.py unknown[123] *}
+{* ../../docs_src/python_types/tutorial001_py310.py unknown[123] *}
## Some more code includes to test fixing { #some-more-code-includes-to-test-fixing }
{* ../../docs_src/dependencies/tutorial013_an_py310.py ln[19:21] *}
-{* ../../docs_src/bigger_applications/app_an_py39/internal/admin.py hl[3] title["app/internal/admin.py"] *}
+{* ../../docs_src/bigger_applications/app_an_py310/internal/admin.py hl[3] title["app/internal/admin.py"] *}
{* ../../docs_src/dependencies/tutorial013_an_py310.py ln[30:38] hl[31:33] *}
diff --git a/scripts/tests/test_translation_fixer/test_complex_doc/data/translated_doc.md b/scripts/tests/test_translation_fixer/test_complex_doc/data/translated_doc.md
index c922d7b133..b27eef202c 100644
--- a/scripts/tests/test_translation_fixer/test_complex_doc/data/translated_doc.md
+++ b/scripts/tests/test_translation_fixer/test_complex_doc/data/translated_doc.md
@@ -139,16 +139,16 @@ def hello_world():
## Простые включения кода { #simple-code-includes }
-{* ../../docs_src/python_types/tutorial001_py39.py *}
+{* ../../docs_src/python_types/tutorial001_py310.py *}
-{* ../../docs_src/python_types/tutorial002_py39.py *}
+{* ../../docs_src/python_types/tutorial002_py310.py *}
## Включения кода с подсветкой { #code-includes-with-highlighting }
-{* ../../docs_src/python_types/tutorial002_py39.py hl[1] *}
+{* ../../docs_src/python_types/tutorial002_py310.py hl[1] *}
-{* ../../docs_src/python_types/tutorial006_py39.py hl[10] *}
+{* ../../docs_src/python_types/tutorial006_py310.py hl[10] *}
## Включения кода с диапазонами строк { #code-includes-with-line-ranges }
@@ -167,19 +167,19 @@ def hello_world():
## Включения кода с заголовком { #code-includes-with-title }
-{* ../../docs_src/bigger_applications/app_an_py39/routers/users.py hl[1,3] title["app/routers/users.py"] *}
+{* ../../docs_src/bigger_applications/app_an_py310/routers/users.py hl[1,3] title["app/routers/users.py"] *}
-{* ../../docs_src/bigger_applications/app_an_py39/internal/admin.py hl[3] title["app/internal/admin.py"] *}
+{* ../../docs_src/bigger_applications/app_an_py310/internal/admin.py hl[3] title["app/internal/admin.py"] *}
## Включения кода с неизвестными атрибутами { #code-includes-with-unknown-attributes }
-{* ../../docs_src/python_types/tutorial001_py39.py unknown[123] *}
+{* ../../docs_src/python_types/tutorial001_py310.py unknown[123] *}
## Ещё включения кода для тестирования исправления { #some-more-code-includes-to-test-fixing }
{* ../../docs_src/dependencies/tutorial013_an_py310.py ln[19 : 21] *}
-{* ../../docs_src/bigger_applications/app_an_py39/wrong.py hl[3] title["app/internal/admin.py"] *}
+{* ../../docs_src/bigger_applications/app_an_py310/wrong.py hl[3] title["app/internal/admin.py"] *}
{* ../../docs_src/dependencies/tutorial013_an_py310.py ln[1:30] hl[1:10] *}
diff --git a/scripts/tests/test_translation_fixer/test_complex_doc/data/translated_doc_expected.md b/scripts/tests/test_translation_fixer/test_complex_doc/data/translated_doc_expected.md
index b33f36e772..8e2394f14f 100644
--- a/scripts/tests/test_translation_fixer/test_complex_doc/data/translated_doc_expected.md
+++ b/scripts/tests/test_translation_fixer/test_complex_doc/data/translated_doc_expected.md
@@ -139,16 +139,16 @@ def hello_world():
## Простые включения кода { #simple-code-includes }
-{* ../../docs_src/python_types/tutorial001_py39.py *}
+{* ../../docs_src/python_types/tutorial001_py310.py *}
-{* ../../docs_src/python_types/tutorial002_py39.py *}
+{* ../../docs_src/python_types/tutorial002_py310.py *}
## Включения кода с подсветкой { #code-includes-with-highlighting }
-{* ../../docs_src/python_types/tutorial002_py39.py hl[1] *}
+{* ../../docs_src/python_types/tutorial002_py310.py hl[1] *}
-{* ../../docs_src/python_types/tutorial006_py39.py hl[10] *}
+{* ../../docs_src/python_types/tutorial006_py310.py hl[10] *}
## Включения кода с диапазонами строк { #code-includes-with-line-ranges }
@@ -167,19 +167,19 @@ def hello_world():
## Включения кода с заголовком { #code-includes-with-title }
-{* ../../docs_src/bigger_applications/app_an_py39/routers/users.py hl[1,3] title["app/routers/users.py"] *}
+{* ../../docs_src/bigger_applications/app_an_py310/routers/users.py hl[1,3] title["app/routers/users.py"] *}
-{* ../../docs_src/bigger_applications/app_an_py39/internal/admin.py hl[3] title["app/internal/admin.py"] *}
+{* ../../docs_src/bigger_applications/app_an_py310/internal/admin.py hl[3] title["app/internal/admin.py"] *}
## Включения кода с неизвестными атрибутами { #code-includes-with-unknown-attributes }
-{* ../../docs_src/python_types/tutorial001_py39.py unknown[123] *}
+{* ../../docs_src/python_types/tutorial001_py310.py unknown[123] *}
## Ещё включения кода для тестирования исправления { #some-more-code-includes-to-test-fixing }
{* ../../docs_src/dependencies/tutorial013_an_py310.py ln[19:21] *}
-{* ../../docs_src/bigger_applications/app_an_py39/internal/admin.py hl[3] title["app/internal/admin.py"] *}
+{* ../../docs_src/bigger_applications/app_an_py310/internal/admin.py hl[3] title["app/internal/admin.py"] *}
{* ../../docs_src/dependencies/tutorial013_an_py310.py ln[30:38] hl[31:33] *}
diff --git a/tests/main.py b/tests/main.py
index 7edb16c615..d2fbbe6153 100644
--- a/tests/main.py
+++ b/tests/main.py
@@ -1,5 +1,4 @@
import http
-from typing import Optional
from fastapi import FastAPI, Path, Query
@@ -54,7 +53,7 @@ def get_bool_id(item_id: bool):
@app.get("/path/param/{item_id}")
-def get_path_param_id(item_id: Optional[str] = Path()):
+def get_path_param_id(item_id: str | None = Path()):
return item_id
@@ -161,7 +160,7 @@ def get_query_type(query: int):
@app.get("/query/int/optional")
-def get_query_type_optional(query: Optional[int] = None):
+def get_query_type_optional(query: int | None = None):
if query is None:
return "foo bar"
return f"foo bar {query}"
diff --git a/tests/test_additional_properties_bool.py b/tests/test_additional_properties_bool.py
index c02841cde1..9a1e139eaa 100644
--- a/tests/test_additional_properties_bool.py
+++ b/tests/test_additional_properties_bool.py
@@ -1,5 +1,3 @@
-from typing import Union
-
from fastapi import FastAPI
from fastapi.testclient import TestClient
from inline_snapshot import snapshot
@@ -19,7 +17,7 @@ app = FastAPI()
@app.post("/")
async def post(
- foo: Union[Foo, None] = None,
+ foo: Foo | None = None,
):
return foo
diff --git a/tests/test_additional_responses_union_duplicate_anyof.py b/tests/test_additional_responses_union_duplicate_anyof.py
index 5d833fce4a..401bc0a744 100644
--- a/tests/test_additional_responses_union_duplicate_anyof.py
+++ b/tests/test_additional_responses_union_duplicate_anyof.py
@@ -4,8 +4,6 @@ don't accumulate duplicate $ref entries in anyOf arrays.
See https://github.com/fastapi/fastapi/pull/14463
"""
-from typing import Union
-
from fastapi import FastAPI
from fastapi.testclient import TestClient
from inline_snapshot import snapshot
@@ -23,7 +21,7 @@ class ModelB(BaseModel):
app = FastAPI(
responses={
500: {
- "model": Union[ModelA, ModelB],
+ "model": ModelA | ModelB,
"content": {"application/json": {"examples": {"Case A": {"value": "a"}}}},
}
}
diff --git a/tests/test_callable_endpoint.py b/tests/test_callable_endpoint.py
index 1882e9053a..28999d3833 100644
--- a/tests/test_callable_endpoint.py
+++ b/tests/test_callable_endpoint.py
@@ -1,11 +1,10 @@
from functools import partial
-from typing import Optional
from fastapi import FastAPI
from fastapi.testclient import TestClient
-def main(some_arg, q: Optional[str] = None):
+def main(some_arg, q: str | None = None):
return {"some_arg": some_arg, "q": q}
diff --git a/tests/test_compat.py b/tests/test_compat.py
index 0b5600f8f5..772bd305eb 100644
--- a/tests/test_compat.py
+++ b/tests/test_compat.py
@@ -1,5 +1,3 @@
-from typing import Union
-
from fastapi import FastAPI, UploadFile
from fastapi._compat import (
Undefined,
@@ -10,8 +8,6 @@ from fastapi.testclient import TestClient
from pydantic import BaseModel, ConfigDict
from pydantic.fields import FieldInfo
-from .utils import needs_py310
-
def test_model_field_default_required():
from fastapi._compat import v2
@@ -26,7 +22,7 @@ def test_complex():
app = FastAPI()
@app.post("/")
- def foo(foo: Union[str, list[int]]):
+ def foo(foo: str | list[int]):
return foo
client = TestClient(app)
@@ -49,17 +45,17 @@ def test_propagates_pydantic2_model_config():
class EmbeddedModel(BaseModel):
model_config = ConfigDict(arbitrary_types_allowed=True)
- value: Union[str, Missing] = Missing()
+ value: str | Missing = Missing()
class Model(BaseModel):
model_config = ConfigDict(
arbitrary_types_allowed=True,
)
- value: Union[str, Missing] = Missing()
+ value: str | Missing = Missing()
embedded_model: EmbeddedModel = EmbeddedModel()
@app.post("/")
- def foo(req: Model) -> dict[str, Union[str, None]]:
+ def foo(req: Model) -> dict[str, str | None]:
return {
"value": req.value or None,
"embedded_value": req.embedded_model.value or None,
@@ -89,7 +85,7 @@ def test_is_bytes_sequence_annotation_union():
# TODO: in theory this would allow declaring types that could be lists of bytes
# to be read from files and other types, but I'm not even sure it's a good idea
# to support it as a first class "feature"
- assert is_bytes_sequence_annotation(Union[list[str], list[bytes]])
+ assert is_bytes_sequence_annotation(list[str] | list[bytes])
def test_is_uploadfile_sequence_annotation():
@@ -97,21 +93,20 @@ def test_is_uploadfile_sequence_annotation():
# TODO: in theory this would allow declaring types that could be lists of UploadFile
# and other types, but I'm not even sure it's a good idea to support it as a first
# class "feature"
- assert is_uploadfile_sequence_annotation(Union[list[str], list[UploadFile]])
+ assert is_uploadfile_sequence_annotation(list[str] | list[UploadFile])
def test_serialize_sequence_value_with_optional_list():
"""Test that serialize_sequence_value handles optional lists correctly."""
from fastapi._compat import v2
- field_info = FieldInfo(annotation=Union[list[str], None])
+ field_info = FieldInfo(annotation=list[str] | None)
field = v2.ModelField(name="items", field_info=field_info)
result = v2.serialize_sequence_value(field=field, value=["a", "b", "c"])
assert result == ["a", "b", "c"]
assert isinstance(result, list)
-@needs_py310
def test_serialize_sequence_value_with_optional_list_pipe_union():
"""Test that serialize_sequence_value handles optional lists correctly (with new syntax)."""
from fastapi._compat import v2
@@ -125,9 +120,12 @@ def test_serialize_sequence_value_with_optional_list_pipe_union():
def test_serialize_sequence_value_with_none_first_in_union():
"""Test that serialize_sequence_value handles Union[None, List[...]] correctly."""
+ from typing import Union
+
from fastapi._compat import v2
- field_info = FieldInfo(annotation=Union[None, list[str]])
+ # Use Union[None, list[str]] to ensure None comes first in the union args
+ field_info = FieldInfo(annotation=Union[None, list[str]]) # noqa: UP007
field = v2.ModelField(name="items", field_info=field_info)
result = v2.serialize_sequence_value(field=field, value=["x", "y"])
assert result == ["x", "y"]
diff --git a/tests/test_custom_middleware_exception.py b/tests/test_custom_middleware_exception.py
index d9b81e7c2e..cf548f4aed 100644
--- a/tests/test_custom_middleware_exception.py
+++ b/tests/test_custom_middleware_exception.py
@@ -1,5 +1,4 @@
from pathlib import Path
-from typing import Optional
from fastapi import APIRouter, FastAPI, File, UploadFile
from fastapi.exceptions import HTTPException
@@ -17,7 +16,7 @@ class ContentSizeLimitMiddleware:
max_content_size (optional): the maximum content size allowed in bytes, None for no limit
"""
- def __init__(self, app: APIRouter, max_content_size: Optional[int] = None):
+ def __init__(self, app: APIRouter, max_content_size: int | None = None):
self.app = app
self.max_content_size = max_content_size
diff --git a/tests/test_custom_schema_fields.py b/tests/test_custom_schema_fields.py
index 60b795e9ba..c907c54242 100644
--- a/tests/test_custom_schema_fields.py
+++ b/tests/test_custom_schema_fields.py
@@ -1,4 +1,4 @@
-from typing import Annotated, Optional
+from typing import Annotated
from fastapi import FastAPI
from fastapi.testclient import TestClient
@@ -10,9 +10,9 @@ app = FastAPI()
class Item(BaseModel):
name: str
- description: Annotated[
- Optional[str], WithJsonSchema({"type": ["string", "null"]})
- ] = None
+ description: Annotated[str | None, WithJsonSchema({"type": ["string", "null"]})] = (
+ None
+ )
model_config = {
"json_schema_extra": {
diff --git a/tests/test_dependencies_utils.py b/tests/test_dependencies_utils.py
new file mode 100644
index 0000000000..9257d1c9ee
--- /dev/null
+++ b/tests/test_dependencies_utils.py
@@ -0,0 +1,8 @@
+from fastapi.dependencies.utils import get_typed_annotation
+
+
+def test_get_typed_annotation():
+ # For coverage
+ annotation = "None"
+ typed_annotation = get_typed_annotation(annotation, globals())
+ assert typed_annotation is None
diff --git a/tests/test_dependency_contextvars.py b/tests/test_dependency_contextvars.py
index 0c2e5594b6..eba135785b 100644
--- a/tests/test_dependency_contextvars.py
+++ b/tests/test_dependency_contextvars.py
@@ -1,11 +1,11 @@
-from collections.abc import Awaitable
+from collections.abc import Awaitable, Callable
from contextvars import ContextVar
-from typing import Any, Callable, Optional
+from typing import Any
from fastapi import Depends, FastAPI, Request, Response
from fastapi.testclient import TestClient
-legacy_request_state_context_var: ContextVar[Optional[dict[str, Any]]] = ContextVar(
+legacy_request_state_context_var: ContextVar[dict[str, Any] | None] = ContextVar(
"legacy_request_state_context_var", default=None
)
diff --git a/tests/test_dependency_overrides.py b/tests/test_dependency_overrides.py
index e25db624d8..7c99d9d9d3 100644
--- a/tests/test_dependency_overrides.py
+++ b/tests/test_dependency_overrides.py
@@ -1,5 +1,3 @@
-from typing import Optional
-
import pytest
from fastapi import APIRouter, Depends, FastAPI
from fastapi.testclient import TestClient
@@ -38,7 +36,7 @@ app.include_router(router)
client = TestClient(app)
-async def overrider_dependency_simple(q: Optional[str] = None):
+async def overrider_dependency_simple(q: str | None = None):
return {"q": q, "skip": 5, "limit": 10}
diff --git a/tests/test_dependency_paramless.py b/tests/test_dependency_paramless.py
index 1774196fe4..62c977b825 100644
--- a/tests/test_dependency_paramless.py
+++ b/tests/test_dependency_paramless.py
@@ -1,4 +1,4 @@
-from typing import Annotated, Union
+from typing import Annotated
from fastapi import FastAPI, HTTPException, Security
from fastapi.security import (
@@ -13,7 +13,7 @@ oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
def process_auth(
- credentials: Annotated[Union[str, None], Security(oauth2_scheme)],
+ credentials: Annotated[str | None, Security(oauth2_scheme)],
security_scopes: SecurityScopes,
):
# This is an incorrect way of using it, this is not checking if the scopes are
diff --git a/tests/test_enforce_once_required_parameter.py b/tests/test_enforce_once_required_parameter.py
index 0dee15c25d..9f8a964543 100644
--- a/tests/test_enforce_once_required_parameter.py
+++ b/tests/test_enforce_once_required_parameter.py
@@ -1,5 +1,3 @@
-from typing import Optional
-
from fastapi import Depends, FastAPI, Query
from fastapi.testclient import TestClient
from inline_snapshot import snapshot
@@ -11,7 +9,7 @@ def _get_client_key(client_id: str = Query(...)) -> str:
return f"{client_id}_key"
-def _get_client_tag(client_id: Optional[str] = Query(None)) -> Optional[str]:
+def _get_client_tag(client_id: str | None = Query(None)) -> str | None:
if client_id is None:
return None
return f"{client_id}_tag"
@@ -20,7 +18,7 @@ def _get_client_tag(client_id: Optional[str] = Query(None)) -> Optional[str]:
@app.get("/foo")
def foo_handler(
client_key: str = Depends(_get_client_key),
- client_tag: Optional[str] = Depends(_get_client_tag),
+ client_tag: str | None = Depends(_get_client_tag),
):
return {"client_id": client_key, "client_tag": client_tag}
diff --git a/tests/test_extra_routes.py b/tests/test_extra_routes.py
index 96f85b4465..985adb9439 100644
--- a/tests/test_extra_routes.py
+++ b/tests/test_extra_routes.py
@@ -1,5 +1,3 @@
-from typing import Optional
-
from fastapi import FastAPI
from fastapi.responses import JSONResponse
from fastapi.testclient import TestClient
@@ -11,7 +9,7 @@ app = FastAPI()
class Item(BaseModel):
name: str
- price: Optional[float] = None
+ price: float | None = None
@app.api_route("/items/{item_id}", methods=["GET"])
diff --git a/tests/test_filter_pydantic_sub_model_pv2.py b/tests/test_filter_pydantic_sub_model_pv2.py
index 1de2b50f7f..1f39581c23 100644
--- a/tests/test_filter_pydantic_sub_model_pv2.py
+++ b/tests/test_filter_pydantic_sub_model_pv2.py
@@ -1,5 +1,3 @@
-from typing import Optional
-
import pytest
from dirty_equals import HasRepr
from fastapi import Depends, FastAPI
@@ -22,7 +20,7 @@ def get_client():
class ModelA(BaseModel):
name: str
- description: Optional[str] = None
+ description: str | None = None
foo: ModelB
tags: dict[str, str] = {}
diff --git a/tests/test_form_default.py b/tests/test_form_default.py
index 0b3eb8f2e2..c4d33e3fb6 100644
--- a/tests/test_form_default.py
+++ b/tests/test_form_default.py
@@ -1,4 +1,4 @@
-from typing import Annotated, Optional
+from typing import Annotated
from fastapi import FastAPI, File, Form
from starlette.testclient import TestClient
@@ -7,14 +7,14 @@ app = FastAPI()
@app.post("/urlencoded")
-async def post_url_encoded(age: Annotated[Optional[int], Form()] = None):
+async def post_url_encoded(age: Annotated[int | None, Form()] = None):
return age
@app.post("/multipart")
async def post_multi_part(
- age: Annotated[Optional[int], Form()] = None,
- file: Annotated[Optional[bytes], File()] = None,
+ age: Annotated[int | None, Form()] = None,
+ file: Annotated[bytes | None, File()] = None,
):
return {"file": file, "age": age}
diff --git a/tests/test_forms_single_model.py b/tests/test_forms_single_model.py
index 7d03d29572..4575e3335e 100644
--- a/tests/test_forms_single_model.py
+++ b/tests/test_forms_single_model.py
@@ -1,4 +1,4 @@
-from typing import Annotated, Optional
+from typing import Annotated
from fastapi import FastAPI, Form
from fastapi.testclient import TestClient
@@ -10,7 +10,7 @@ app = FastAPI()
class FormModel(BaseModel):
username: str
lastname: str
- age: Optional[int] = None
+ age: int | None = None
tags: list[str] = ["foo", "bar"]
alias_with: str = Field(alias="with", default="nothing")
diff --git a/tests/test_infer_param_optionality.py b/tests/test_infer_param_optionality.py
index bb20a4a1aa..2cf74e187a 100644
--- a/tests/test_infer_param_optionality.py
+++ b/tests/test_infer_param_optionality.py
@@ -1,5 +1,3 @@
-from typing import Optional
-
from fastapi import APIRouter, FastAPI
from fastapi.testclient import TestClient
from inline_snapshot import snapshot
@@ -22,7 +20,7 @@ def get_user(user_id: str):
@item_router.get("/")
-def get_items(user_id: Optional[str] = None):
+def get_items(user_id: str | None = None):
if user_id is None:
return [{"item_id": "i1", "user_id": "u1"}, {"item_id": "i2", "user_id": "u2"}]
else:
@@ -30,7 +28,7 @@ def get_items(user_id: Optional[str] = None):
@item_router.get("/{item_id}")
-def get_item(item_id: str, user_id: Optional[str] = None):
+def get_item(item_id: str, user_id: str | None = None):
if user_id is None:
return {"item_id": item_id}
else:
diff --git a/tests/test_invalid_sequence_param.py b/tests/test_invalid_sequence_param.py
index 3695344f7a..d137f6805e 100644
--- a/tests/test_invalid_sequence_param.py
+++ b/tests/test_invalid_sequence_param.py
@@ -1,5 +1,3 @@
-from typing import Optional
-
import pytest
from fastapi import FastAPI, Query
from pydantic import BaseModel
@@ -61,5 +59,5 @@ def test_invalid_simple_dict():
title: str
@app.get("/items/")
- def read_items(q: Optional[dict] = Query(default=None)):
+ def read_items(q: dict | None = Query(default=None)):
pass # pragma: no cover
diff --git a/tests/test_jsonable_encoder.py b/tests/test_jsonable_encoder.py
index 4528dff440..595202beaf 100644
--- a/tests/test_jsonable_encoder.py
+++ b/tests/test_jsonable_encoder.py
@@ -6,7 +6,7 @@ from decimal import Decimal
from enum import Enum
from math import isinf, isnan
from pathlib import PurePath, PurePosixPath, PureWindowsPath
-from typing import Optional, TypedDict
+from typing import TypedDict
import pytest
from fastapi._compat import Undefined
@@ -57,7 +57,7 @@ class RoleEnum(Enum):
class ModelWithConfig(BaseModel):
- role: Optional[RoleEnum] = None
+ role: RoleEnum | None = None
model_config = {"use_enum_values": True}
diff --git a/tests/test_list_bytes_file_order_preserved_issue_14811.py b/tests/test_list_bytes_file_order_preserved_issue_14811.py
new file mode 100644
index 0000000000..dbf0a78186
--- /dev/null
+++ b/tests/test_list_bytes_file_order_preserved_issue_14811.py
@@ -0,0 +1,46 @@
+"""
+Regression test: preserve order when using list[bytes] + File()
+See https://github.com/fastapi/fastapi/discussions/14811
+Fixed in PR: https://github.com/fastapi/fastapi/pull/14884
+"""
+
+from typing import Annotated
+
+import anyio
+import pytest
+from fastapi import FastAPI, File
+from fastapi.testclient import TestClient
+from starlette.datastructures import UploadFile as StarletteUploadFile
+
+
+def test_list_bytes_file_preserves_order(
+ monkeypatch: pytest.MonkeyPatch,
+) -> None:
+ app = FastAPI()
+
+ @app.post("/upload")
+ async def upload(files: Annotated[list[bytes], File()]):
+ # return something that makes order obvious
+ return [b[0] for b in files]
+
+ original_read = StarletteUploadFile.read
+
+ async def patched_read(self: StarletteUploadFile, size: int = -1) -> bytes:
+ # Make the FIRST file slower *deterministically*
+ if self.filename == "slow.txt":
+ await anyio.sleep(0.05)
+ return await original_read(self, size)
+
+ monkeypatch.setattr(StarletteUploadFile, "read", patched_read)
+
+ client = TestClient(app)
+
+ files = [
+ ("files", ("slow.txt", b"A" * 10, "text/plain")),
+ ("files", ("fast.txt", b"B" * 10, "text/plain")),
+ ]
+ r = client.post("/upload", files=files)
+ assert r.status_code == 200, r.text
+
+ # Must preserve request order: slow first, fast second
+ assert r.json() == [ord("A"), ord("B")]
diff --git a/tests/test_openapi_examples.py b/tests/test_openapi_examples.py
index deb74d8a0f..e27dd2be08 100644
--- a/tests/test_openapi_examples.py
+++ b/tests/test_openapi_examples.py
@@ -1,5 +1,3 @@
-from typing import Union
-
from fastapi import Body, Cookie, FastAPI, Header, Path, Query
from fastapi.testclient import TestClient
from inline_snapshot import snapshot
@@ -57,7 +55,7 @@ def path_examples(
@app.get("/query_examples/")
def query_examples(
- data: Union[str, None] = Query(
+ data: str | None = Query(
default=None,
examples=[
"json_schema_query1",
@@ -80,7 +78,7 @@ def query_examples(
@app.get("/header_examples/")
def header_examples(
- data: Union[str, None] = Header(
+ data: str | None = Header(
default=None,
examples=[
"json_schema_header1",
@@ -103,7 +101,7 @@ def header_examples(
@app.get("/cookie_examples/")
def cookie_examples(
- data: Union[str, None] = Cookie(
+ data: str | None = Cookie(
default=None,
examples=["json_schema_cookie1", "json_schema_cookie2"],
openapi_examples={
diff --git a/tests/test_openapi_query_parameter_extension.py b/tests/test_openapi_query_parameter_extension.py
index 836a0a7ee5..118d518149 100644
--- a/tests/test_openapi_query_parameter_extension.py
+++ b/tests/test_openapi_query_parameter_extension.py
@@ -1,5 +1,3 @@
-from typing import Optional
-
from fastapi import FastAPI
from fastapi.testclient import TestClient
from inline_snapshot import snapshot
@@ -26,7 +24,7 @@ app = FastAPI()
]
},
)
-def route_with_extra_query_parameters(standard_query_param: Optional[int] = 50):
+def route_with_extra_query_parameters(standard_query_param: int | None = 50):
return {}
diff --git a/tests/test_openapi_schema_type.py b/tests/test_openapi_schema_type.py
index 98d9787455..e8166d2fb9 100644
--- a/tests/test_openapi_schema_type.py
+++ b/tests/test_openapi_schema_type.py
@@ -1,5 +1,3 @@
-from typing import Optional, Union
-
import pytest
from fastapi.openapi.models import Schema, SchemaType
@@ -13,7 +11,7 @@ from fastapi.openapi.models import Schema, SchemaType
],
)
def test_allowed_schema_type(
- type_value: Optional[Union[SchemaType, list[SchemaType]]],
+ type_value: SchemaType | list[SchemaType] | None,
) -> None:
"""Test that Schema accepts SchemaType, List[SchemaType] and None for type field."""
schema = Schema(type=type_value)
diff --git a/tests/test_openapi_separate_input_output_schemas.py b/tests/test_openapi_separate_input_output_schemas.py
index 0efeece017..50255ed09a 100644
--- a/tests/test_openapi_separate_input_output_schemas.py
+++ b/tests/test_openapi_separate_input_output_schemas.py
@@ -1,5 +1,3 @@
-from typing import Optional
-
from fastapi import FastAPI
from fastapi.testclient import TestClient
from inline_snapshot import snapshot
@@ -8,15 +6,15 @@ from pydantic import BaseModel, computed_field
class SubItem(BaseModel):
subname: str
- sub_description: Optional[str] = None
+ sub_description: str | None = None
tags: list[str] = []
model_config = {"json_schema_serialization_defaults_required": True}
class Item(BaseModel):
name: str
- description: Optional[str] = None
- sub: Optional[SubItem] = None
+ description: str | None = None
+ sub: SubItem | None = None
model_config = {"json_schema_serialization_defaults_required": True}
diff --git a/tests/test_optional_file_list.py b/tests/test_optional_file_list.py
index 6860258643..a57e6358fd 100644
--- a/tests/test_optional_file_list.py
+++ b/tests/test_optional_file_list.py
@@ -1,5 +1,3 @@
-from typing import Optional
-
from fastapi import FastAPI, File
from fastapi.testclient import TestClient
@@ -7,7 +5,7 @@ app = FastAPI()
@app.post("/files")
-async def upload_files(files: Optional[list[bytes]] = File(None)):
+async def upload_files(files: list[bytes] | None = File(None)):
if files is None:
return {"files_count": 0}
return {"files_count": len(files), "sizes": [len(f) for f in files]}
diff --git a/tests/test_param_class.py b/tests/test_param_class.py
index 1fd40dcd21..e6642daeac 100644
--- a/tests/test_param_class.py
+++ b/tests/test_param_class.py
@@ -1,5 +1,3 @@
-from typing import Optional
-
from fastapi import FastAPI
from fastapi.params import Param
from fastapi.testclient import TestClient
@@ -8,7 +6,7 @@ app = FastAPI()
@app.get("/items/")
-def read_items(q: Optional[str] = Param(default=None)): # type: ignore
+def read_items(q: str | None = Param(default=None)): # type: ignore
return {"q": q}
diff --git a/tests/test_param_include_in_schema.py b/tests/test_param_include_in_schema.py
index 463fb51b10..727552b466 100644
--- a/tests/test_param_include_in_schema.py
+++ b/tests/test_param_include_in_schema.py
@@ -1,5 +1,3 @@
-from typing import Optional
-
import pytest
from fastapi import Cookie, FastAPI, Header, Path, Query
from fastapi.testclient import TestClient
@@ -10,14 +8,14 @@ app = FastAPI()
@app.get("/hidden_cookie")
async def hidden_cookie(
- hidden_cookie: Optional[str] = Cookie(default=None, include_in_schema=False),
+ hidden_cookie: str | None = Cookie(default=None, include_in_schema=False),
):
return {"hidden_cookie": hidden_cookie}
@app.get("/hidden_header")
async def hidden_header(
- hidden_header: Optional[str] = Header(default=None, include_in_schema=False),
+ hidden_header: str | None = Header(default=None, include_in_schema=False),
):
return {"hidden_header": hidden_header}
@@ -29,7 +27,7 @@ async def hidden_path(hidden_path: str = Path(include_in_schema=False)):
@app.get("/hidden_query")
async def hidden_query(
- hidden_query: Optional[str] = Query(default=None, include_in_schema=False),
+ hidden_query: str | None = Query(default=None, include_in_schema=False),
):
return {"hidden_query": hidden_query}
diff --git a/tests/test_pydantic_v1_error.py b/tests/test_pydantic_v1_error.py
index 13229a3137..044fdf0d65 100644
--- a/tests/test_pydantic_v1_error.py
+++ b/tests/test_pydantic_v1_error.py
@@ -1,6 +1,5 @@
import sys
import warnings
-from typing import Union
import pytest
@@ -80,7 +79,7 @@ def test_raises_pydantic_v1_model_in_union() -> None:
with pytest.raises(PydanticV1NotSupportedError):
@app.post("/union")
- def endpoint(data: Union[dict, ModelV1A]): # pragma: no cover
+ def endpoint(data: dict | ModelV1A): # pragma: no cover
return data
diff --git a/tests/test_pydanticv2_dataclasses_uuid_stringified_annotations.py b/tests/test_pydanticv2_dataclasses_uuid_stringified_annotations.py
index b72b0518a1..4f7b0b2a0a 100644
--- a/tests/test_pydanticv2_dataclasses_uuid_stringified_annotations.py
+++ b/tests/test_pydanticv2_dataclasses_uuid_stringified_annotations.py
@@ -2,7 +2,6 @@ from __future__ import annotations
import uuid
from dataclasses import dataclass, field
-from typing import Union
from dirty_equals import IsUUID
from fastapi import FastAPI
@@ -16,8 +15,8 @@ class Item:
name: str
price: float
tags: list[str] = field(default_factory=list)
- description: Union[str, None] = None
- tax: Union[float, None] = None
+ description: str | None = None
+ tax: float | None = None
app = FastAPI()
diff --git a/tests/test_request_params/test_body/test_list.py b/tests/test_request_params/test_body/test_list.py
index 970e6a6607..aa9745f84f 100644
--- a/tests/test_request_params/test_body/test_list.py
+++ b/tests/test_request_params/test_body/test_list.py
@@ -1,4 +1,4 @@
-from typing import Annotated, Union
+from typing import Annotated
import pytest
from dirty_equals import IsOneOf, IsPartialDict
@@ -55,7 +55,7 @@ def test_required_list_str_schema(path: str):
"path",
["/required-list-str", "/model-required-list-str"],
)
-def test_required_list_str_missing(path: str, json: Union[dict, None]):
+def test_required_list_str_missing(path: str, json: dict | None):
client = TestClient(app)
response = client.post(path, json=json)
assert response.status_code == 422
@@ -132,7 +132,7 @@ def test_required_list_str_alias_schema(path: str):
"path",
["/required-list-alias", "/model-required-list-alias"],
)
-def test_required_list_alias_missing(path: str, json: Union[dict, None]):
+def test_required_list_alias_missing(path: str, json: dict | None):
client = TestClient(app)
response = client.post(path, json=json)
assert response.status_code == 422
@@ -236,7 +236,7 @@ def test_required_list_validation_alias_schema(path: str):
"/model-required-list-validation-alias",
],
)
-def test_required_list_validation_alias_missing(path: str, json: Union[dict, None]):
+def test_required_list_validation_alias_missing(path: str, json: dict | None):
client = TestClient(app)
response = client.post(path, json=json)
assert response.status_code == 422
diff --git a/tests/test_request_params/test_body/test_optional_list.py b/tests/test_request_params/test_body/test_optional_list.py
index ba8ba9092e..2c5c5d61b6 100644
--- a/tests/test_request_params/test_body/test_optional_list.py
+++ b/tests/test_request_params/test_body/test_optional_list.py
@@ -1,4 +1,4 @@
-from typing import Annotated, Optional
+from typing import Annotated
import pytest
from fastapi import Body, FastAPI
@@ -15,13 +15,13 @@ app = FastAPI()
@app.post("/optional-list-str", operation_id="optional_list_str")
async def read_optional_list_str(
- p: Annotated[Optional[list[str]], Body(embed=True)] = None,
+ p: Annotated[list[str] | None, Body(embed=True)] = None,
):
return {"p": p}
class BodyModelOptionalListStr(BaseModel):
- p: Optional[list[str]] = None
+ p: list[str] | None = None
@app.post("/model-optional-list-str", operation_id="model_optional_list_str")
@@ -103,13 +103,13 @@ def test_optional_list_str(path: str):
@app.post("/optional-list-alias", operation_id="optional_list_alias")
async def read_optional_list_alias(
- p: Annotated[Optional[list[str]], Body(embed=True, alias="p_alias")] = None,
+ p: Annotated[list[str] | None, Body(embed=True, alias="p_alias")] = None,
):
return {"p": p}
class BodyModelOptionalListAlias(BaseModel):
- p: Optional[list[str]] = Field(None, alias="p_alias")
+ p: list[str] | None = Field(None, alias="p_alias")
@app.post("/model-optional-list-alias", operation_id="model_optional_list_alias")
@@ -208,14 +208,14 @@ def test_optional_list_alias_by_alias(path: str):
)
def read_optional_list_validation_alias(
p: Annotated[
- Optional[list[str]], Body(embed=True, validation_alias="p_val_alias")
+ list[str] | None, Body(embed=True, validation_alias="p_val_alias")
] = None,
):
return {"p": p}
class BodyModelOptionalListValidationAlias(BaseModel):
- p: Optional[list[str]] = Field(None, validation_alias="p_val_alias")
+ p: list[str] | None = Field(None, validation_alias="p_val_alias")
@app.post(
@@ -323,7 +323,7 @@ def test_optional_list_validation_alias_by_validation_alias(path: str):
)
def read_optional_list_alias_and_validation_alias(
p: Annotated[
- Optional[list[str]],
+ list[str] | None,
Body(embed=True, alias="p_alias", validation_alias="p_val_alias"),
] = None,
):
@@ -331,9 +331,7 @@ def read_optional_list_alias_and_validation_alias(
class BodyModelOptionalListAliasAndValidationAlias(BaseModel):
- p: Optional[list[str]] = Field(
- None, alias="p_alias", validation_alias="p_val_alias"
- )
+ p: list[str] | None = Field(None, alias="p_alias", validation_alias="p_val_alias")
@app.post(
diff --git a/tests/test_request_params/test_body/test_optional_str.py b/tests/test_request_params/test_body/test_optional_str.py
index b9c18034da..184fc94cb2 100644
--- a/tests/test_request_params/test_body/test_optional_str.py
+++ b/tests/test_request_params/test_body/test_optional_str.py
@@ -1,4 +1,4 @@
-from typing import Annotated, Optional
+from typing import Annotated
import pytest
from fastapi import Body, FastAPI
@@ -14,12 +14,12 @@ app = FastAPI()
@app.post("/optional-str", operation_id="optional_str")
-async def read_optional_str(p: Annotated[Optional[str], Body(embed=True)] = None):
+async def read_optional_str(p: Annotated[str | None, Body(embed=True)] = None):
return {"p": p}
class BodyModelOptionalStr(BaseModel):
- p: Optional[str] = None
+ p: str | None = None
@app.post("/model-optional-str", operation_id="model_optional_str")
@@ -98,13 +98,13 @@ def test_optional_str(path: str):
@app.post("/optional-alias", operation_id="optional_alias")
async def read_optional_alias(
- p: Annotated[Optional[str], Body(embed=True, alias="p_alias")] = None,
+ p: Annotated[str | None, Body(embed=True, alias="p_alias")] = None,
):
return {"p": p}
class BodyModelOptionalAlias(BaseModel):
- p: Optional[str] = Field(None, alias="p_alias")
+ p: str | None = Field(None, alias="p_alias")
@app.post("/model-optional-alias", operation_id="model_optional_alias")
@@ -197,15 +197,13 @@ def test_optional_alias_by_alias(path: str):
@app.post("/optional-validation-alias", operation_id="optional_validation_alias")
def read_optional_validation_alias(
- p: Annotated[
- Optional[str], Body(embed=True, validation_alias="p_val_alias")
- ] = None,
+ p: Annotated[str | None, Body(embed=True, validation_alias="p_val_alias")] = None,
):
return {"p": p}
class BodyModelOptionalValidationAlias(BaseModel):
- p: Optional[str] = Field(None, validation_alias="p_val_alias")
+ p: str | None = Field(None, validation_alias="p_val_alias")
@app.post(
@@ -309,14 +307,14 @@ def test_optional_validation_alias_by_validation_alias(path: str):
)
def read_optional_alias_and_validation_alias(
p: Annotated[
- Optional[str], Body(embed=True, alias="p_alias", validation_alias="p_val_alias")
+ str | None, Body(embed=True, alias="p_alias", validation_alias="p_val_alias")
] = None,
):
return {"p": p}
class BodyModelOptionalAliasAndValidationAlias(BaseModel):
- p: Optional[str] = Field(None, alias="p_alias", validation_alias="p_val_alias")
+ p: str | None = Field(None, alias="p_alias", validation_alias="p_val_alias")
@app.post(
diff --git a/tests/test_request_params/test_body/test_required_str.py b/tests/test_request_params/test_body/test_required_str.py
index 5b434fa1db..2e02f8d203 100644
--- a/tests/test_request_params/test_body/test_required_str.py
+++ b/tests/test_request_params/test_body/test_required_str.py
@@ -1,4 +1,4 @@
-from typing import Annotated, Any, Union
+from typing import Annotated, Any
import pytest
from dirty_equals import IsOneOf
@@ -51,7 +51,7 @@ def test_required_str_schema(path: str):
"path",
["/required-str", "/model-required-str"],
)
-def test_required_str_missing(path: str, json: Union[dict[str, Any], None]):
+def test_required_str_missing(path: str, json: dict[str, Any] | None):
client = TestClient(app)
response = client.post(path, json=json)
assert response.status_code == 422
@@ -124,7 +124,7 @@ def test_required_str_alias_schema(path: str):
"path",
["/required-alias", "/model-required-alias"],
)
-def test_required_alias_missing(path: str, json: Union[dict[str, Any], None]):
+def test_required_alias_missing(path: str, json: dict[str, Any] | None):
client = TestClient(app)
response = client.post(path, json=json)
assert response.status_code == 422
@@ -221,9 +221,7 @@ def test_required_validation_alias_schema(path: str):
"/model-required-validation-alias",
],
)
-def test_required_validation_alias_missing(
- path: str, json: Union[dict[str, Any], None]
-):
+def test_required_validation_alias_missing(path: str, json: dict[str, Any] | None):
client = TestClient(app)
response = client.post(path, json=json)
assert response.status_code == 422
@@ -338,7 +336,7 @@ def test_required_alias_and_validation_alias_schema(path: str):
],
)
def test_required_alias_and_validation_alias_missing(
- path: str, json: Union[dict[str, Any], None]
+ path: str, json: dict[str, Any] | None
):
client = TestClient(app)
response = client.post(path, json=json)
diff --git a/tests/test_request_params/test_cookie/test_optional_str.py b/tests/test_request_params/test_cookie/test_optional_str.py
index 1b2a18b072..227d2bccc2 100644
--- a/tests/test_request_params/test_cookie/test_optional_str.py
+++ b/tests/test_request_params/test_cookie/test_optional_str.py
@@ -1,4 +1,4 @@
-from typing import Annotated, Optional
+from typing import Annotated
import pytest
from fastapi import Cookie, FastAPI
@@ -13,12 +13,12 @@ app = FastAPI()
@app.get("/optional-str")
-async def read_optional_str(p: Annotated[Optional[str], Cookie()] = None):
+async def read_optional_str(p: Annotated[str | None, Cookie()] = None):
return {"p": p}
class CookieModelOptionalStr(BaseModel):
- p: Optional[str] = None
+ p: str | None = None
@app.get("/model-optional-str")
@@ -75,13 +75,13 @@ def test_optional_str(path: str):
@app.get("/optional-alias")
async def read_optional_alias(
- p: Annotated[Optional[str], Cookie(alias="p_alias")] = None,
+ p: Annotated[str | None, Cookie(alias="p_alias")] = None,
):
return {"p": p}
class CookieModelOptionalAlias(BaseModel):
- p: Optional[str] = Field(None, alias="p_alias")
+ p: str | None = Field(None, alias="p_alias")
@app.get("/model-optional-alias")
@@ -153,13 +153,13 @@ def test_optional_alias_by_alias(path: str):
@app.get("/optional-validation-alias")
def read_optional_validation_alias(
- p: Annotated[Optional[str], Cookie(validation_alias="p_val_alias")] = None,
+ p: Annotated[str | None, Cookie(validation_alias="p_val_alias")] = None,
):
return {"p": p}
class CookieModelOptionalValidationAlias(BaseModel):
- p: Optional[str] = Field(None, validation_alias="p_val_alias")
+ p: str | None = Field(None, validation_alias="p_val_alias")
@app.get("/model-optional-validation-alias")
@@ -237,14 +237,14 @@ def test_optional_validation_alias_by_validation_alias(path: str):
@app.get("/optional-alias-and-validation-alias")
def read_optional_alias_and_validation_alias(
p: Annotated[
- Optional[str], Cookie(alias="p_alias", validation_alias="p_val_alias")
+ str | None, Cookie(alias="p_alias", validation_alias="p_val_alias")
] = None,
):
return {"p": p}
class CookieModelOptionalAliasAndValidationAlias(BaseModel):
- p: Optional[str] = Field(None, alias="p_alias", validation_alias="p_val_alias")
+ p: str | None = Field(None, alias="p_alias", validation_alias="p_val_alias")
@app.get("/model-optional-alias-and-validation-alias")
diff --git a/tests/test_request_params/test_file/test_optional.py b/tests/test_request_params/test_file/test_optional.py
index 45ef7bdec4..b4dc11a06a 100644
--- a/tests/test_request_params/test_file/test_optional.py
+++ b/tests/test_request_params/test_file/test_optional.py
@@ -1,4 +1,4 @@
-from typing import Annotated, Optional
+from typing import Annotated
import pytest
from fastapi import FastAPI, File, UploadFile
@@ -13,12 +13,12 @@ app = FastAPI()
@app.post("/optional-bytes", operation_id="optional_bytes")
-async def read_optional_bytes(p: Annotated[Optional[bytes], File()] = None):
+async def read_optional_bytes(p: Annotated[bytes | None, File()] = None):
return {"file_size": len(p) if p else None}
@app.post("/optional-uploadfile", operation_id="optional_uploadfile")
-async def read_optional_uploadfile(p: Annotated[Optional[UploadFile], File()] = None):
+async def read_optional_uploadfile(p: Annotated[UploadFile | None, File()] = None):
return {"file_size": p.size if p else None}
@@ -82,14 +82,14 @@ def test_optional(path: str):
@app.post("/optional-bytes-alias", operation_id="optional_bytes_alias")
async def read_optional_bytes_alias(
- p: Annotated[Optional[bytes], File(alias="p_alias")] = None,
+ p: Annotated[bytes | None, File(alias="p_alias")] = None,
):
return {"file_size": len(p) if p else None}
@app.post("/optional-uploadfile-alias", operation_id="optional_uploadfile_alias")
async def read_optional_uploadfile_alias(
- p: Annotated[Optional[UploadFile], File(alias="p_alias")] = None,
+ p: Annotated[UploadFile | None, File(alias="p_alias")] = None,
):
return {"file_size": p.size if p else None}
@@ -170,7 +170,7 @@ def test_optional_alias_by_alias(path: str):
"/optional-bytes-validation-alias", operation_id="optional_bytes_validation_alias"
)
def read_optional_bytes_validation_alias(
- p: Annotated[Optional[bytes], File(validation_alias="p_val_alias")] = None,
+ p: Annotated[bytes | None, File(validation_alias="p_val_alias")] = None,
):
return {"file_size": len(p) if p else None}
@@ -180,7 +180,7 @@ def read_optional_bytes_validation_alias(
operation_id="optional_uploadfile_validation_alias",
)
def read_optional_uploadfile_validation_alias(
- p: Annotated[Optional[UploadFile], File(validation_alias="p_val_alias")] = None,
+ p: Annotated[UploadFile | None, File(validation_alias="p_val_alias")] = None,
):
return {"file_size": p.size if p else None}
@@ -263,7 +263,7 @@ def test_optional_validation_alias_by_validation_alias(path: str):
)
def read_optional_bytes_alias_and_validation_alias(
p: Annotated[
- Optional[bytes], File(alias="p_alias", validation_alias="p_val_alias")
+ bytes | None, File(alias="p_alias", validation_alias="p_val_alias")
] = None,
):
return {"file_size": len(p) if p else None}
@@ -275,7 +275,7 @@ def read_optional_bytes_alias_and_validation_alias(
)
def read_optional_uploadfile_alias_and_validation_alias(
p: Annotated[
- Optional[UploadFile], File(alias="p_alias", validation_alias="p_val_alias")
+ UploadFile | None, File(alias="p_alias", validation_alias="p_val_alias")
] = None,
):
return {"file_size": p.size if p else None}
diff --git a/tests/test_request_params/test_file/test_optional_list.py b/tests/test_request_params/test_file/test_optional_list.py
index 162fbe08ae..a506ec991f 100644
--- a/tests/test_request_params/test_file/test_optional_list.py
+++ b/tests/test_request_params/test_file/test_optional_list.py
@@ -1,4 +1,4 @@
-from typing import Annotated, Optional
+from typing import Annotated
import pytest
from fastapi import FastAPI, File, UploadFile
@@ -13,13 +13,13 @@ app = FastAPI()
@app.post("/optional-list-bytes")
-async def read_optional_list_bytes(p: Annotated[Optional[list[bytes]], File()] = None):
+async def read_optional_list_bytes(p: Annotated[list[bytes] | None, File()] = None):
return {"file_size": [len(file) for file in p] if p else None}
@app.post("/optional-list-uploadfile")
async def read_optional_list_uploadfile(
- p: Annotated[Optional[list[UploadFile]], File()] = None,
+ p: Annotated[list[UploadFile] | None, File()] = None,
):
return {"file_size": [file.size for file in p] if p else None}
@@ -87,14 +87,14 @@ def test_optional_list(path: str):
@app.post("/optional-list-bytes-alias")
async def read_optional_list_bytes_alias(
- p: Annotated[Optional[list[bytes]], File(alias="p_alias")] = None,
+ p: Annotated[list[bytes] | None, File(alias="p_alias")] = None,
):
return {"file_size": [len(file) for file in p] if p else None}
@app.post("/optional-list-uploadfile-alias")
async def read_optional_list_uploadfile_alias(
- p: Annotated[Optional[list[UploadFile]], File(alias="p_alias")] = None,
+ p: Annotated[list[UploadFile] | None, File(alias="p_alias")] = None,
):
return {"file_size": [file.size for file in p] if p else None}
@@ -176,16 +176,14 @@ def test_optional_list_alias_by_alias(path: str):
@app.post("/optional-list-bytes-validation-alias")
def read_optional_list_bytes_validation_alias(
- p: Annotated[Optional[list[bytes]], File(validation_alias="p_val_alias")] = None,
+ p: Annotated[list[bytes] | None, File(validation_alias="p_val_alias")] = None,
):
return {"file_size": [len(file) for file in p] if p else None}
@app.post("/optional-list-uploadfile-validation-alias")
def read_optional_list_uploadfile_validation_alias(
- p: Annotated[
- Optional[list[UploadFile]], File(validation_alias="p_val_alias")
- ] = None,
+ p: Annotated[list[UploadFile] | None, File(validation_alias="p_val_alias")] = None,
):
return {"file_size": [file.size for file in p] if p else None}
@@ -270,7 +268,7 @@ def test_optional_validation_alias_by_validation_alias(path: str):
@app.post("/optional-list-bytes-alias-and-validation-alias")
def read_optional_list_bytes_alias_and_validation_alias(
p: Annotated[
- Optional[list[bytes]], File(alias="p_alias", validation_alias="p_val_alias")
+ list[bytes] | None, File(alias="p_alias", validation_alias="p_val_alias")
] = None,
):
return {"file_size": [len(file) for file in p] if p else None}
@@ -279,7 +277,7 @@ def read_optional_list_bytes_alias_and_validation_alias(
@app.post("/optional-list-uploadfile-alias-and-validation-alias")
def read_optional_list_uploadfile_alias_and_validation_alias(
p: Annotated[
- Optional[list[UploadFile]],
+ list[UploadFile] | None,
File(alias="p_alias", validation_alias="p_val_alias"),
] = None,
):
diff --git a/tests/test_request_params/test_form/test_optional_list.py b/tests/test_request_params/test_form/test_optional_list.py
index 6d1957a18c..7ecf9c9bfc 100644
--- a/tests/test_request_params/test_form/test_optional_list.py
+++ b/tests/test_request_params/test_form/test_optional_list.py
@@ -1,4 +1,4 @@
-from typing import Annotated, Optional
+from typing import Annotated
import pytest
from fastapi import FastAPI, Form
@@ -15,13 +15,13 @@ app = FastAPI()
@app.post("/optional-list-str", operation_id="optional_list_str")
async def read_optional_list_str(
- p: Annotated[Optional[list[str]], Form()] = None,
+ p: Annotated[list[str] | None, Form()] = None,
):
return {"p": p}
class FormModelOptionalListStr(BaseModel):
- p: Optional[list[str]] = None
+ p: list[str] | None = None
@app.post("/model-optional-list-str", operation_id="model_optional_list_str")
@@ -80,13 +80,13 @@ def test_optional_list_str(path: str):
@app.post("/optional-list-alias", operation_id="optional_list_alias")
async def read_optional_list_alias(
- p: Annotated[Optional[list[str]], Form(alias="p_alias")] = None,
+ p: Annotated[list[str] | None, Form(alias="p_alias")] = None,
):
return {"p": p}
class FormModelOptionalListAlias(BaseModel):
- p: Optional[list[str]] = Field(None, alias="p_alias")
+ p: list[str] | None = Field(None, alias="p_alias")
@app.post("/model-optional-list-alias", operation_id="model_optional_list_alias")
@@ -163,13 +163,13 @@ def test_optional_list_alias_by_alias(path: str):
"/optional-list-validation-alias", operation_id="optional_list_validation_alias"
)
def read_optional_list_validation_alias(
- p: Annotated[Optional[list[str]], Form(validation_alias="p_val_alias")] = None,
+ p: Annotated[list[str] | None, Form(validation_alias="p_val_alias")] = None,
):
return {"p": p}
class FormModelOptionalListValidationAlias(BaseModel):
- p: Optional[list[str]] = Field(None, validation_alias="p_val_alias")
+ p: list[str] | None = Field(None, validation_alias="p_val_alias")
@app.post(
@@ -251,16 +251,14 @@ def test_optional_list_validation_alias_by_validation_alias(path: str):
)
def read_optional_list_alias_and_validation_alias(
p: Annotated[
- Optional[list[str]], Form(alias="p_alias", validation_alias="p_val_alias")
+ list[str] | None, Form(alias="p_alias", validation_alias="p_val_alias")
] = None,
):
return {"p": p}
class FormModelOptionalListAliasAndValidationAlias(BaseModel):
- p: Optional[list[str]] = Field(
- None, alias="p_alias", validation_alias="p_val_alias"
- )
+ p: list[str] | None = Field(None, alias="p_alias", validation_alias="p_val_alias")
@app.post(
diff --git a/tests/test_request_params/test_form/test_optional_str.py b/tests/test_request_params/test_form/test_optional_str.py
index 810e83caa3..4ef16756ef 100644
--- a/tests/test_request_params/test_form/test_optional_str.py
+++ b/tests/test_request_params/test_form/test_optional_str.py
@@ -1,4 +1,4 @@
-from typing import Annotated, Optional
+from typing import Annotated
import pytest
from fastapi import FastAPI, Form
@@ -14,12 +14,12 @@ app = FastAPI()
@app.post("/optional-str", operation_id="optional_str")
-async def read_optional_str(p: Annotated[Optional[str], Form()] = None):
+async def read_optional_str(p: Annotated[str | None, Form()] = None):
return {"p": p}
class FormModelOptionalStr(BaseModel):
- p: Optional[str] = None
+ p: str | None = None
@app.post("/model-optional-str", operation_id="model_optional_str")
@@ -75,13 +75,13 @@ def test_optional_str(path: str):
@app.post("/optional-alias", operation_id="optional_alias")
async def read_optional_alias(
- p: Annotated[Optional[str], Form(alias="p_alias")] = None,
+ p: Annotated[str | None, Form(alias="p_alias")] = None,
):
return {"p": p}
class FormModelOptionalAlias(BaseModel):
- p: Optional[str] = Field(None, alias="p_alias")
+ p: str | None = Field(None, alias="p_alias")
@app.post("/model-optional-alias", operation_id="model_optional_alias")
@@ -151,13 +151,13 @@ def test_optional_alias_by_alias(path: str):
@app.post("/optional-validation-alias", operation_id="optional_validation_alias")
def read_optional_validation_alias(
- p: Annotated[Optional[str], Form(validation_alias="p_val_alias")] = None,
+ p: Annotated[str | None, Form(validation_alias="p_val_alias")] = None,
):
return {"p": p}
class FormModelOptionalValidationAlias(BaseModel):
- p: Optional[str] = Field(None, validation_alias="p_val_alias")
+ p: str | None = Field(None, validation_alias="p_val_alias")
@app.post(
@@ -238,14 +238,14 @@ def test_optional_validation_alias_by_validation_alias(path: str):
)
def read_optional_alias_and_validation_alias(
p: Annotated[
- Optional[str], Form(alias="p_alias", validation_alias="p_val_alias")
+ str | None, Form(alias="p_alias", validation_alias="p_val_alias")
] = None,
):
return {"p": p}
class FormModelOptionalAliasAndValidationAlias(BaseModel):
- p: Optional[str] = Field(None, alias="p_alias", validation_alias="p_val_alias")
+ p: str | None = Field(None, alias="p_alias", validation_alias="p_val_alias")
@app.post(
diff --git a/tests/test_request_params/test_header/test_optional_list.py b/tests/test_request_params/test_header/test_optional_list.py
index 3bbb73d544..9f4eacc235 100644
--- a/tests/test_request_params/test_header/test_optional_list.py
+++ b/tests/test_request_params/test_header/test_optional_list.py
@@ -1,4 +1,4 @@
-from typing import Annotated, Optional
+from typing import Annotated
import pytest
from fastapi import FastAPI, Header
@@ -14,13 +14,13 @@ app = FastAPI()
@app.get("/optional-list-str")
async def read_optional_list_str(
- p: Annotated[Optional[list[str]], Header()] = None,
+ p: Annotated[list[str] | None, Header()] = None,
):
return {"p": p}
class HeaderModelOptionalListStr(BaseModel):
- p: Optional[list[str]] = None
+ p: list[str] | None = None
@app.get("/model-optional-list-str")
@@ -81,13 +81,13 @@ def test_optional_list_str(path: str):
@app.get("/optional-list-alias")
async def read_optional_list_alias(
- p: Annotated[Optional[list[str]], Header(alias="p_alias")] = None,
+ p: Annotated[list[str] | None, Header(alias="p_alias")] = None,
):
return {"p": p}
class HeaderModelOptionalListAlias(BaseModel):
- p: Optional[list[str]] = Field(None, alias="p_alias")
+ p: list[str] | None = Field(None, alias="p_alias")
@app.get("/model-optional-list-alias")
@@ -162,13 +162,13 @@ def test_optional_list_alias_by_alias(path: str):
@app.get("/optional-list-validation-alias")
def read_optional_list_validation_alias(
- p: Annotated[Optional[list[str]], Header(validation_alias="p_val_alias")] = None,
+ p: Annotated[list[str] | None, Header(validation_alias="p_val_alias")] = None,
):
return {"p": p}
class HeaderModelOptionalListValidationAlias(BaseModel):
- p: Optional[list[str]] = Field(None, validation_alias="p_val_alias")
+ p: list[str] | None = Field(None, validation_alias="p_val_alias")
@app.get("/model-optional-list-validation-alias")
@@ -246,16 +246,14 @@ def test_optional_list_validation_alias_by_validation_alias(path: str):
@app.get("/optional-list-alias-and-validation-alias")
def read_optional_list_alias_and_validation_alias(
p: Annotated[
- Optional[list[str]], Header(alias="p_alias", validation_alias="p_val_alias")
+ list[str] | None, Header(alias="p_alias", validation_alias="p_val_alias")
] = None,
):
return {"p": p}
class HeaderModelOptionalListAliasAndValidationAlias(BaseModel):
- p: Optional[list[str]] = Field(
- None, alias="p_alias", validation_alias="p_val_alias"
- )
+ p: list[str] | None = Field(None, alias="p_alias", validation_alias="p_val_alias")
@app.get("/model-optional-list-alias-and-validation-alias")
diff --git a/tests/test_request_params/test_header/test_optional_str.py b/tests/test_request_params/test_header/test_optional_str.py
index a5174e59af..04773c83f9 100644
--- a/tests/test_request_params/test_header/test_optional_str.py
+++ b/tests/test_request_params/test_header/test_optional_str.py
@@ -1,4 +1,4 @@
-from typing import Annotated, Optional
+from typing import Annotated
import pytest
from fastapi import FastAPI, Header
@@ -13,12 +13,12 @@ app = FastAPI()
@app.get("/optional-str")
-async def read_optional_str(p: Annotated[Optional[str], Header()] = None):
+async def read_optional_str(p: Annotated[str | None, Header()] = None):
return {"p": p}
class HeaderModelOptionalStr(BaseModel):
- p: Optional[str] = None
+ p: str | None = None
@app.get("/model-optional-str")
@@ -74,13 +74,13 @@ def test_optional_str(path: str):
@app.get("/optional-alias")
async def read_optional_alias(
- p: Annotated[Optional[str], Header(alias="p_alias")] = None,
+ p: Annotated[str | None, Header(alias="p_alias")] = None,
):
return {"p": p}
class HeaderModelOptionalAlias(BaseModel):
- p: Optional[str] = Field(None, alias="p_alias")
+ p: str | None = Field(None, alias="p_alias")
@app.get("/model-optional-alias")
@@ -150,13 +150,13 @@ def test_optional_alias_by_alias(path: str):
@app.get("/optional-validation-alias")
def read_optional_validation_alias(
- p: Annotated[Optional[str], Header(validation_alias="p_val_alias")] = None,
+ p: Annotated[str | None, Header(validation_alias="p_val_alias")] = None,
):
return {"p": p}
class HeaderModelOptionalValidationAlias(BaseModel):
- p: Optional[str] = Field(None, validation_alias="p_val_alias")
+ p: str | None = Field(None, validation_alias="p_val_alias")
@app.get("/model-optional-validation-alias")
@@ -232,14 +232,14 @@ def test_optional_validation_alias_by_validation_alias(path: str):
@app.get("/optional-alias-and-validation-alias")
def read_optional_alias_and_validation_alias(
p: Annotated[
- Optional[str], Header(alias="p_alias", validation_alias="p_val_alias")
+ str | None, Header(alias="p_alias", validation_alias="p_val_alias")
] = None,
):
return {"p": p}
class HeaderModelOptionalAliasAndValidationAlias(BaseModel):
- p: Optional[str] = Field(None, alias="p_alias", validation_alias="p_val_alias")
+ p: str | None = Field(None, alias="p_alias", validation_alias="p_val_alias")
@app.get("/model-optional-alias-and-validation-alias")
diff --git a/tests/test_request_params/test_query/test_optional_list.py b/tests/test_request_params/test_query/test_optional_list.py
index 5608c6499b..6b70b75a4f 100644
--- a/tests/test_request_params/test_query/test_optional_list.py
+++ b/tests/test_request_params/test_query/test_optional_list.py
@@ -1,4 +1,4 @@
-from typing import Annotated, Optional
+from typing import Annotated
import pytest
from fastapi import FastAPI, Query
@@ -14,13 +14,13 @@ app = FastAPI()
@app.get("/optional-list-str")
async def read_optional_list_str(
- p: Annotated[Optional[list[str]], Query()] = None,
+ p: Annotated[list[str] | None, Query()] = None,
):
return {"p": p}
class QueryModelOptionalListStr(BaseModel):
- p: Optional[list[str]] = None
+ p: list[str] | None = None
@app.get("/model-optional-list-str")
@@ -81,13 +81,13 @@ def test_optional_list_str(path: str):
@app.get("/optional-list-alias")
async def read_optional_list_alias(
- p: Annotated[Optional[list[str]], Query(alias="p_alias")] = None,
+ p: Annotated[list[str] | None, Query(alias="p_alias")] = None,
):
return {"p": p}
class QueryModelOptionalListAlias(BaseModel):
- p: Optional[list[str]] = Field(None, alias="p_alias")
+ p: list[str] | None = Field(None, alias="p_alias")
@app.get("/model-optional-list-alias")
@@ -162,13 +162,13 @@ def test_optional_list_alias_by_alias(path: str):
@app.get("/optional-list-validation-alias")
def read_optional_list_validation_alias(
- p: Annotated[Optional[list[str]], Query(validation_alias="p_val_alias")] = None,
+ p: Annotated[list[str] | None, Query(validation_alias="p_val_alias")] = None,
):
return {"p": p}
class QueryModelOptionalListValidationAlias(BaseModel):
- p: Optional[list[str]] = Field(None, validation_alias="p_val_alias")
+ p: list[str] | None = Field(None, validation_alias="p_val_alias")
@app.get("/model-optional-list-validation-alias")
@@ -244,16 +244,14 @@ def test_optional_list_validation_alias_by_validation_alias(path: str):
@app.get("/optional-list-alias-and-validation-alias")
def read_optional_list_alias_and_validation_alias(
p: Annotated[
- Optional[list[str]], Query(alias="p_alias", validation_alias="p_val_alias")
+ list[str] | None, Query(alias="p_alias", validation_alias="p_val_alias")
] = None,
):
return {"p": p}
class QueryModelOptionalListAliasAndValidationAlias(BaseModel):
- p: Optional[list[str]] = Field(
- None, alias="p_alias", validation_alias="p_val_alias"
- )
+ p: list[str] | None = Field(None, alias="p_alias", validation_alias="p_val_alias")
@app.get("/model-optional-list-alias-and-validation-alias")
diff --git a/tests/test_request_params/test_query/test_optional_str.py b/tests/test_request_params/test_query/test_optional_str.py
index b181686b05..f7f35860b6 100644
--- a/tests/test_request_params/test_query/test_optional_str.py
+++ b/tests/test_request_params/test_query/test_optional_str.py
@@ -1,4 +1,4 @@
-from typing import Annotated, Optional
+from typing import Annotated
import pytest
from fastapi import FastAPI, Query
@@ -13,12 +13,12 @@ app = FastAPI()
@app.get("/optional-str")
-async def read_optional_str(p: Optional[str] = None):
+async def read_optional_str(p: str | None = None):
return {"p": p}
class QueryModelOptionalStr(BaseModel):
- p: Optional[str] = None
+ p: str | None = None
@app.get("/model-optional-str")
@@ -74,13 +74,13 @@ def test_optional_str(path: str):
@app.get("/optional-alias")
async def read_optional_alias(
- p: Annotated[Optional[str], Query(alias="p_alias")] = None,
+ p: Annotated[str | None, Query(alias="p_alias")] = None,
):
return {"p": p}
class QueryModelOptionalAlias(BaseModel):
- p: Optional[str] = Field(None, alias="p_alias")
+ p: str | None = Field(None, alias="p_alias")
@app.get("/model-optional-alias")
@@ -150,13 +150,13 @@ def test_optional_alias_by_alias(path: str):
@app.get("/optional-validation-alias")
def read_optional_validation_alias(
- p: Annotated[Optional[str], Query(validation_alias="p_val_alias")] = None,
+ p: Annotated[str | None, Query(validation_alias="p_val_alias")] = None,
):
return {"p": p}
class QueryModelOptionalValidationAlias(BaseModel):
- p: Optional[str] = Field(None, validation_alias="p_val_alias")
+ p: str | None = Field(None, validation_alias="p_val_alias")
@app.get("/model-optional-validation-alias")
@@ -232,14 +232,14 @@ def test_optional_validation_alias_by_validation_alias(path: str):
@app.get("/optional-alias-and-validation-alias")
def read_optional_alias_and_validation_alias(
p: Annotated[
- Optional[str], Query(alias="p_alias", validation_alias="p_val_alias")
+ str | None, Query(alias="p_alias", validation_alias="p_val_alias")
] = None,
):
return {"p": p}
class QueryModelOptionalAliasAndValidationAlias(BaseModel):
- p: Optional[str] = Field(None, alias="p_alias", validation_alias="p_val_alias")
+ p: str | None = Field(None, alias="p_alias", validation_alias="p_val_alias")
@app.get("/model-optional-alias-and-validation-alias")
diff --git a/tests/test_required_noneable.py b/tests/test_required_noneable.py
index 5da8cd4d09..c99f20212f 100644
--- a/tests/test_required_noneable.py
+++ b/tests/test_required_noneable.py
@@ -1,5 +1,3 @@
-from typing import Union
-
from fastapi import Body, FastAPI, Query
from fastapi.testclient import TestClient
@@ -7,17 +5,17 @@ app = FastAPI()
@app.get("/query")
-def read_query(q: Union[str, None]):
+def read_query(q: str | None):
return q
@app.get("/explicit-query")
-def read_explicit_query(q: Union[str, None] = Query()):
+def read_explicit_query(q: str | None = Query()):
return q
@app.post("/body-embed")
-def send_body_embed(b: Union[str, None] = Body(embed=True)):
+def send_body_embed(b: str | None = Body(embed=True)):
return b
diff --git a/tests/test_response_model_as_return_annotation.py b/tests/test_response_model_as_return_annotation.py
index ded5971027..7be7902ada 100644
--- a/tests/test_response_model_as_return_annotation.py
+++ b/tests/test_response_model_as_return_annotation.py
@@ -1,5 +1,3 @@
-from typing import Union
-
import pytest
from fastapi import FastAPI
from fastapi.exceptions import FastAPIError, ResponseValidationError
@@ -216,7 +214,7 @@ def no_response_model_annotation_forward_ref_list_of_model() -> "list[User]":
@app.get(
"/response_model_union-no_annotation-return_model1",
- response_model=Union[User, Item],
+ response_model=User | Item,
)
def response_model_union_no_annotation_return_model1():
return DBUser(name="John", surname="Doe", password_hash="secret")
@@ -224,19 +222,19 @@ def response_model_union_no_annotation_return_model1():
@app.get(
"/response_model_union-no_annotation-return_model2",
- response_model=Union[User, Item],
+ response_model=User | Item,
)
def response_model_union_no_annotation_return_model2():
return Item(name="Foo", price=42.0)
@app.get("/no_response_model-annotation_union-return_model1")
-def no_response_model_annotation_union_return_model1() -> Union[User, Item]:
+def no_response_model_annotation_union_return_model1() -> User | Item:
return DBUser(name="John", surname="Doe", password_hash="secret")
@app.get("/no_response_model-annotation_union-return_model2")
-def no_response_model_annotation_union_return_model2() -> Union[User, Item]:
+def no_response_model_annotation_union_return_model2() -> User | Item:
return Item(name="Foo", price=42.0)
@@ -503,7 +501,7 @@ def test_invalid_response_model_field():
with pytest.raises(FastAPIError) as e:
@app.get("/")
- def read_root() -> Union[Response, None]:
+ def read_root() -> Response | None:
return Response(content="Foo") # pragma: no cover
assert "valid Pydantic field type" in e.value.args[0]
diff --git a/tests/test_router_events.py b/tests/test_router_events.py
index a47d119139..7869a7afcd 100644
--- a/tests/test_router_events.py
+++ b/tests/test_router_events.py
@@ -1,6 +1,5 @@
from collections.abc import AsyncGenerator
from contextlib import asynccontextmanager
-from typing import Union
import pytest
from fastapi import APIRouter, FastAPI, Request
@@ -176,7 +175,7 @@ def test_router_nested_lifespan_state_overriding_by_parent() -> None:
@asynccontextmanager
async def lifespan(
app: FastAPI,
- ) -> AsyncGenerator[dict[str, Union[str, bool]], None]:
+ ) -> AsyncGenerator[dict[str, str | bool], None]:
yield {
"app_specific": True,
"overridden": "app",
@@ -185,7 +184,7 @@ def test_router_nested_lifespan_state_overriding_by_parent() -> None:
@asynccontextmanager
async def router_lifespan(
app: FastAPI,
- ) -> AsyncGenerator[dict[str, Union[str, bool]], None]:
+ ) -> AsyncGenerator[dict[str, str | bool], None]:
yield {
"router_specific": True,
"overridden": "router", # should override parent
diff --git a/tests/test_schema_extra_examples.py b/tests/test_schema_extra_examples.py
index 9ec41e7e84..32f5cea476 100644
--- a/tests/test_schema_extra_examples.py
+++ b/tests/test_schema_extra_examples.py
@@ -1,5 +1,3 @@
-from typing import Union
-
import pytest
from fastapi import Body, Cookie, FastAPI, Header, Path, Query
from fastapi.exceptions import FastAPIDeprecationWarning
@@ -117,7 +115,7 @@ def create_app():
@app.get("/query_example/")
def query_example(
- data: Union[str, None] = Query(
+ data: str | None = Query(
default=None,
example="query1",
),
@@ -126,7 +124,7 @@ def create_app():
@app.get("/query_examples/")
def query_examples(
- data: Union[str, None] = Query(
+ data: str | None = Query(
default=None,
examples=["query1", "query2"],
),
@@ -137,7 +135,7 @@ def create_app():
@app.get("/query_example_examples/")
def query_example_examples(
- data: Union[str, None] = Query(
+ data: str | None = Query(
default=None,
example="query_overridden",
examples=["query1", "query2"],
@@ -149,7 +147,7 @@ def create_app():
@app.get("/header_example/")
def header_example(
- data: Union[str, None] = Header(
+ data: str | None = Header(
default=None,
example="header1",
),
@@ -158,7 +156,7 @@ def create_app():
@app.get("/header_examples/")
def header_examples(
- data: Union[str, None] = Header(
+ data: str | None = Header(
default=None,
examples=[
"header1",
@@ -172,7 +170,7 @@ def create_app():
@app.get("/header_example_examples/")
def header_example_examples(
- data: Union[str, None] = Header(
+ data: str | None = Header(
default=None,
example="header_overridden",
examples=["header1", "header2"],
@@ -184,7 +182,7 @@ def create_app():
@app.get("/cookie_example/")
def cookie_example(
- data: Union[str, None] = Cookie(
+ data: str | None = Cookie(
default=None,
example="cookie1",
),
@@ -193,7 +191,7 @@ def create_app():
@app.get("/cookie_examples/")
def cookie_examples(
- data: Union[str, None] = Cookie(
+ data: str | None = Cookie(
default=None,
examples=["cookie1", "cookie2"],
),
@@ -204,7 +202,7 @@ def create_app():
@app.get("/cookie_example_examples/")
def cookie_example_examples(
- data: Union[str, None] = Cookie(
+ data: str | None = Cookie(
default=None,
example="cookie_overridden",
examples=["cookie1", "cookie2"],
diff --git a/tests/test_security_api_key_cookie_optional.py b/tests/test_security_api_key_cookie_optional.py
index 7988d80443..e911654fac 100644
--- a/tests/test_security_api_key_cookie_optional.py
+++ b/tests/test_security_api_key_cookie_optional.py
@@ -1,5 +1,3 @@
-from typing import Optional
-
from fastapi import Depends, FastAPI, Security
from fastapi.security import APIKeyCookie
from fastapi.testclient import TestClient
@@ -15,7 +13,7 @@ class User(BaseModel):
username: str
-def get_current_user(oauth_header: Optional[str] = Security(api_key)):
+def get_current_user(oauth_header: str | None = Security(api_key)):
if oauth_header is None:
return None
user = User(username=oauth_header)
diff --git a/tests/test_security_api_key_header_optional.py b/tests/test_security_api_key_header_optional.py
index 51abd0bb96..0a8cf420ed 100644
--- a/tests/test_security_api_key_header_optional.py
+++ b/tests/test_security_api_key_header_optional.py
@@ -1,5 +1,3 @@
-from typing import Optional
-
from fastapi import Depends, FastAPI, Security
from fastapi.security import APIKeyHeader
from fastapi.testclient import TestClient
@@ -15,7 +13,7 @@ class User(BaseModel):
username: str
-def get_current_user(oauth_header: Optional[str] = Security(api_key)):
+def get_current_user(oauth_header: str | None = Security(api_key)):
if oauth_header is None:
return None
user = User(username=oauth_header)
@@ -23,7 +21,7 @@ def get_current_user(oauth_header: Optional[str] = Security(api_key)):
@app.get("/users/me")
-def read_current_user(current_user: Optional[User] = Depends(get_current_user)):
+def read_current_user(current_user: User | None = Depends(get_current_user)):
if current_user is None:
return {"msg": "Create an account first"}
return current_user
diff --git a/tests/test_security_api_key_query_optional.py b/tests/test_security_api_key_query_optional.py
index 26fbb9ee4f..e9fba30435 100644
--- a/tests/test_security_api_key_query_optional.py
+++ b/tests/test_security_api_key_query_optional.py
@@ -1,5 +1,3 @@
-from typing import Optional
-
from fastapi import Depends, FastAPI, Security
from fastapi.security import APIKeyQuery
from fastapi.testclient import TestClient
@@ -15,7 +13,7 @@ class User(BaseModel):
username: str
-def get_current_user(oauth_header: Optional[str] = Security(api_key)):
+def get_current_user(oauth_header: str | None = Security(api_key)):
if oauth_header is None:
return None
user = User(username=oauth_header)
@@ -23,7 +21,7 @@ def get_current_user(oauth_header: Optional[str] = Security(api_key)):
@app.get("/users/me")
-def read_current_user(current_user: Optional[User] = Depends(get_current_user)):
+def read_current_user(current_user: User | None = Depends(get_current_user)):
if current_user is None:
return {"msg": "Create an account first"}
return current_user
diff --git a/tests/test_security_http_base_optional.py b/tests/test_security_http_base_optional.py
index 612a7909fe..1d1944ab0a 100644
--- a/tests/test_security_http_base_optional.py
+++ b/tests/test_security_http_base_optional.py
@@ -1,5 +1,3 @@
-from typing import Optional
-
from fastapi import FastAPI, Security
from fastapi.security.http import HTTPAuthorizationCredentials, HTTPBase
from fastapi.testclient import TestClient
@@ -12,7 +10,7 @@ security = HTTPBase(scheme="Other", auto_error=False)
@app.get("/users/me")
def read_current_user(
- credentials: Optional[HTTPAuthorizationCredentials] = Security(security),
+ credentials: HTTPAuthorizationCredentials | None = Security(security),
):
if credentials is None:
return {"msg": "Create an account first"}
diff --git a/tests/test_security_http_basic_optional.py b/tests/test_security_http_basic_optional.py
index e94565c7bb..78abf2b680 100644
--- a/tests/test_security_http_basic_optional.py
+++ b/tests/test_security_http_basic_optional.py
@@ -1,5 +1,4 @@
from base64 import b64encode
-from typing import Optional
from fastapi import FastAPI, Security
from fastapi.security import HTTPBasic, HTTPBasicCredentials
@@ -12,7 +11,7 @@ security = HTTPBasic(auto_error=False)
@app.get("/users/me")
-def read_current_user(credentials: Optional[HTTPBasicCredentials] = Security(security)):
+def read_current_user(credentials: HTTPBasicCredentials | None = Security(security)):
if credentials is None:
return {"msg": "Create an account first"}
return {"username": credentials.username, "password": credentials.password}
diff --git a/tests/test_security_http_bearer_optional.py b/tests/test_security_http_bearer_optional.py
index b49a6593ec..06d9d03db4 100644
--- a/tests/test_security_http_bearer_optional.py
+++ b/tests/test_security_http_bearer_optional.py
@@ -1,5 +1,3 @@
-from typing import Optional
-
from fastapi import FastAPI, Security
from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
from fastapi.testclient import TestClient
@@ -12,7 +10,7 @@ security = HTTPBearer(auto_error=False)
@app.get("/users/me")
def read_current_user(
- credentials: Optional[HTTPAuthorizationCredentials] = Security(security),
+ credentials: HTTPAuthorizationCredentials | None = Security(security),
):
if credentials is None:
return {"msg": "Create an account first"}
diff --git a/tests/test_security_http_digest_optional.py b/tests/test_security_http_digest_optional.py
index 97e62634d8..d1056b1918 100644
--- a/tests/test_security_http_digest_optional.py
+++ b/tests/test_security_http_digest_optional.py
@@ -1,5 +1,3 @@
-from typing import Optional
-
from fastapi import FastAPI, Security
from fastapi.security import HTTPAuthorizationCredentials, HTTPDigest
from fastapi.testclient import TestClient
@@ -12,7 +10,7 @@ security = HTTPDigest(auto_error=False)
@app.get("/users/me")
def read_current_user(
- credentials: Optional[HTTPAuthorizationCredentials] = Security(security),
+ credentials: HTTPAuthorizationCredentials | None = Security(security),
):
if credentials is None:
return {"msg": "Create an account first"}
diff --git a/tests/test_security_oauth2_authorization_code_bearer.py b/tests/test_security_oauth2_authorization_code_bearer.py
index 1ba577e9ff..587486c76b 100644
--- a/tests/test_security_oauth2_authorization_code_bearer.py
+++ b/tests/test_security_oauth2_authorization_code_bearer.py
@@ -1,5 +1,3 @@
-from typing import Optional
-
from fastapi import FastAPI, Security
from fastapi.security import OAuth2AuthorizationCodeBearer
from fastapi.testclient import TestClient
@@ -13,7 +11,7 @@ oauth2_scheme = OAuth2AuthorizationCodeBearer(
@app.get("/items/")
-async def read_items(token: Optional[str] = Security(oauth2_scheme)):
+async def read_items(token: str | None = Security(oauth2_scheme)):
return {"token": token}
diff --git a/tests/test_security_oauth2_authorization_code_bearer_description.py b/tests/test_security_oauth2_authorization_code_bearer_description.py
index 73807c31a3..f878ede643 100644
--- a/tests/test_security_oauth2_authorization_code_bearer_description.py
+++ b/tests/test_security_oauth2_authorization_code_bearer_description.py
@@ -1,5 +1,3 @@
-from typing import Optional
-
from fastapi import FastAPI, Security
from fastapi.security import OAuth2AuthorizationCodeBearer
from fastapi.testclient import TestClient
@@ -16,7 +14,7 @@ oauth2_scheme = OAuth2AuthorizationCodeBearer(
@app.get("/items/")
-async def read_items(token: Optional[str] = Security(oauth2_scheme)):
+async def read_items(token: str | None = Security(oauth2_scheme)):
return {"token": token}
diff --git a/tests/test_security_oauth2_authorization_code_bearer_scopes_openapi.py b/tests/test_security_oauth2_authorization_code_bearer_scopes_openapi.py
index 583007c8b7..6fcce6fed7 100644
--- a/tests/test_security_oauth2_authorization_code_bearer_scopes_openapi.py
+++ b/tests/test_security_oauth2_authorization_code_bearer_scopes_openapi.py
@@ -1,6 +1,6 @@
# Ref: https://github.com/fastapi/fastapi/issues/14454
-from typing import Annotated, Optional
+from typing import Annotated
from fastapi import APIRouter, Depends, FastAPI, Security
from fastapi.security import OAuth2AuthorizationCodeBearer
@@ -46,13 +46,13 @@ router = APIRouter(dependencies=[Security(oauth2_scheme, scopes=["read"])])
@router.get("/items/")
-async def read_items(token: Optional[str] = Depends(oauth2_scheme)):
+async def read_items(token: str | None = Depends(oauth2_scheme)):
return {"token": token}
@router.post("/items/")
async def create_item(
- token: Optional[str] = Security(oauth2_scheme, scopes=["read", "write"]),
+ token: str | None = Security(oauth2_scheme, scopes=["read", "write"]),
):
return {"token": token}
diff --git a/tests/test_security_oauth2_optional.py b/tests/test_security_oauth2_optional.py
index cb79afdb86..a7eaf59443 100644
--- a/tests/test_security_oauth2_optional.py
+++ b/tests/test_security_oauth2_optional.py
@@ -1,5 +1,3 @@
-from typing import Optional
-
import pytest
from fastapi import Depends, FastAPI, Security
from fastapi.security import OAuth2, OAuth2PasswordRequestFormStrict
@@ -24,7 +22,7 @@ class User(BaseModel):
username: str
-def get_current_user(oauth_header: Optional[str] = Security(reusable_oauth2)):
+def get_current_user(oauth_header: str | None = Security(reusable_oauth2)):
if oauth_header is None:
return None
user = User(username=oauth_header)
@@ -37,7 +35,7 @@ def login(form_data: OAuth2PasswordRequestFormStrict = Depends()):
@app.get("/users/me")
-def read_users_me(current_user: Optional[User] = Depends(get_current_user)):
+def read_users_me(current_user: User | None = Depends(get_current_user)):
if current_user is None:
return {"msg": "Create an account first"}
return current_user
diff --git a/tests/test_security_oauth2_optional_description.py b/tests/test_security_oauth2_optional_description.py
index b3fae37a17..0918d352ea 100644
--- a/tests/test_security_oauth2_optional_description.py
+++ b/tests/test_security_oauth2_optional_description.py
@@ -1,5 +1,3 @@
-from typing import Optional
-
import pytest
from fastapi import Depends, FastAPI, Security
from fastapi.security import OAuth2, OAuth2PasswordRequestFormStrict
@@ -25,7 +23,7 @@ class User(BaseModel):
username: str
-def get_current_user(oauth_header: Optional[str] = Security(reusable_oauth2)):
+def get_current_user(oauth_header: str | None = Security(reusable_oauth2)):
if oauth_header is None:
return None
user = User(username=oauth_header)
@@ -38,7 +36,7 @@ def login(form_data: OAuth2PasswordRequestFormStrict = Depends()):
@app.get("/users/me")
-def read_users_me(current_user: Optional[User] = Depends(get_current_user)):
+def read_users_me(current_user: User | None = Depends(get_current_user)):
if current_user is None:
return {"msg": "Create an account first"}
return current_user
diff --git a/tests/test_security_oauth2_password_bearer_optional.py b/tests/test_security_oauth2_password_bearer_optional.py
index 01e2f65ed9..263359c950 100644
--- a/tests/test_security_oauth2_password_bearer_optional.py
+++ b/tests/test_security_oauth2_password_bearer_optional.py
@@ -1,5 +1,3 @@
-from typing import Optional
-
from fastapi import FastAPI, Security
from fastapi.security import OAuth2PasswordBearer
from fastapi.testclient import TestClient
@@ -11,7 +9,7 @@ oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/token", auto_error=False)
@app.get("/items/")
-async def read_items(token: Optional[str] = Security(oauth2_scheme)):
+async def read_items(token: str | None = Security(oauth2_scheme)):
if token is None:
return {"msg": "Create an account first"}
return {"token": token}
diff --git a/tests/test_security_oauth2_password_bearer_optional_description.py b/tests/test_security_oauth2_password_bearer_optional_description.py
index fec8d03a7a..0deb7e48ff 100644
--- a/tests/test_security_oauth2_password_bearer_optional_description.py
+++ b/tests/test_security_oauth2_password_bearer_optional_description.py
@@ -1,5 +1,3 @@
-from typing import Optional
-
from fastapi import FastAPI, Security
from fastapi.security import OAuth2PasswordBearer
from fastapi.testclient import TestClient
@@ -15,7 +13,7 @@ oauth2_scheme = OAuth2PasswordBearer(
@app.get("/items/")
-async def read_items(token: Optional[str] = Security(oauth2_scheme)):
+async def read_items(token: str | None = Security(oauth2_scheme)):
if token is None:
return {"msg": "Create an account first"}
return {"token": token}
diff --git a/tests/test_security_openid_connect_optional.py b/tests/test_security_openid_connect_optional.py
index ebaf394dc9..44e1a4866e 100644
--- a/tests/test_security_openid_connect_optional.py
+++ b/tests/test_security_openid_connect_optional.py
@@ -1,5 +1,3 @@
-from typing import Optional
-
from fastapi import Depends, FastAPI, Security
from fastapi.security.open_id_connect_url import OpenIdConnect
from fastapi.testclient import TestClient
@@ -15,7 +13,7 @@ class User(BaseModel):
username: str
-def get_current_user(oauth_header: Optional[str] = Security(oid)):
+def get_current_user(oauth_header: str | None = Security(oid)):
if oauth_header is None:
return None
user = User(username=oauth_header)
@@ -23,7 +21,7 @@ def get_current_user(oauth_header: Optional[str] = Security(oid)):
@app.get("/users/me")
-def read_current_user(current_user: Optional[User] = Depends(get_current_user)):
+def read_current_user(current_user: User | None = Depends(get_current_user)):
if current_user is None:
return {"msg": "Create an account first"}
return current_user
diff --git a/tests/test_serialize_response.py b/tests/test_serialize_response.py
index 14f88dd931..114c3c6cb2 100644
--- a/tests/test_serialize_response.py
+++ b/tests/test_serialize_response.py
@@ -1,5 +1,3 @@
-from typing import Optional
-
from fastapi import FastAPI
from fastapi.testclient import TestClient
from pydantic import BaseModel
@@ -9,8 +7,8 @@ app = FastAPI()
class Item(BaseModel):
name: str
- price: Optional[float] = None
- owner_ids: Optional[list[int]] = None
+ price: float | None = None
+ owner_ids: list[int] | None = None
@app.get("/items/valid", response_model=Item)
diff --git a/tests/test_serialize_response_dataclass.py b/tests/test_serialize_response_dataclass.py
index ee695368b8..ae05f14d1a 100644
--- a/tests/test_serialize_response_dataclass.py
+++ b/tests/test_serialize_response_dataclass.py
@@ -1,6 +1,5 @@
from dataclasses import dataclass
from datetime import datetime
-from typing import Optional
from fastapi import FastAPI
from fastapi.testclient import TestClient
@@ -12,8 +11,8 @@ app = FastAPI()
class Item:
name: str
date: datetime
- price: Optional[float] = None
- owner_ids: Optional[list[int]] = None
+ price: float | None = None
+ owner_ids: list[int] | None = None
@app.get("/items/valid", response_model=Item)
diff --git a/tests/test_serialize_response_model.py b/tests/test_serialize_response_model.py
index 79c90c9c29..bb05f7bc40 100644
--- a/tests/test_serialize_response_model.py
+++ b/tests/test_serialize_response_model.py
@@ -1,5 +1,3 @@
-from typing import Optional
-
from fastapi import FastAPI
from pydantic import BaseModel, Field
from starlette.testclient import TestClient
@@ -9,8 +7,8 @@ app = FastAPI()
class Item(BaseModel):
name: str = Field(alias="aliased_name")
- price: Optional[float] = None
- owner_ids: Optional[list[int]] = None
+ price: float | None = None
+ owner_ids: list[int] | None = None
@app.get("/items/valid", response_model=Item)
diff --git a/tests/test_skip_defaults.py b/tests/test_skip_defaults.py
index 02765291cb..238da7392f 100644
--- a/tests/test_skip_defaults.py
+++ b/tests/test_skip_defaults.py
@@ -1,5 +1,3 @@
-from typing import Optional
-
from fastapi import FastAPI
from fastapi.testclient import TestClient
from pydantic import BaseModel
@@ -8,23 +6,23 @@ app = FastAPI()
class SubModel(BaseModel):
- a: Optional[str] = "foo"
+ a: str | None = "foo"
class Model(BaseModel):
- x: Optional[int] = None
+ x: int | None = None
sub: SubModel
class ModelSubclass(Model):
y: int
z: int = 0
- w: Optional[int] = None
+ w: int | None = None
class ModelDefaults(BaseModel):
- w: Optional[str] = None
- x: Optional[str] = None
+ w: str | None = None
+ x: str | None = None
y: str = "y"
z: str = "z"
diff --git a/tests/test_sub_callbacks.py b/tests/test_sub_callbacks.py
index 86dc4d00e2..b8a9dd2921 100644
--- a/tests/test_sub_callbacks.py
+++ b/tests/test_sub_callbacks.py
@@ -1,5 +1,3 @@
-from typing import Optional
-
from fastapi import APIRouter, FastAPI
from fastapi.testclient import TestClient
from inline_snapshot import snapshot
@@ -10,7 +8,7 @@ app = FastAPI()
class Invoice(BaseModel):
id: str
- title: Optional[str] = None
+ title: str | None = None
customer: str
total: float
@@ -51,7 +49,7 @@ subrouter = APIRouter()
@subrouter.post("/invoices/", callbacks=invoices_callback_router.routes)
-def create_invoice(invoice: Invoice, callback_url: Optional[HttpUrl] = None):
+def create_invoice(invoice: Invoice, callback_url: HttpUrl | None = None):
"""
Create an invoice.
diff --git a/tests/test_tutorial/test_additional_responses/test_tutorial001.py b/tests/test_tutorial/test_additional_responses/test_tutorial001.py
index d8d9d4130b..456070c9c3 100644
--- a/tests/test_tutorial/test_additional_responses/test_tutorial001.py
+++ b/tests/test_tutorial/test_additional_responses/test_tutorial001.py
@@ -1,7 +1,7 @@
from fastapi.testclient import TestClient
from inline_snapshot import snapshot
-from docs_src.additional_responses.tutorial001_py39 import app
+from docs_src.additional_responses.tutorial001_py310 import app
client = TestClient(app)
diff --git a/tests/test_tutorial/test_additional_responses/test_tutorial002.py b/tests/test_tutorial/test_additional_responses/test_tutorial002.py
index 4fae59d222..586779e44f 100644
--- a/tests/test_tutorial/test_additional_responses/test_tutorial002.py
+++ b/tests/test_tutorial/test_additional_responses/test_tutorial002.py
@@ -12,7 +12,6 @@ from tests.utils import needs_py310
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial002_py39"),
pytest.param("tutorial002_py310", marks=needs_py310),
],
)
diff --git a/tests/test_tutorial/test_additional_responses/test_tutorial003.py b/tests/test_tutorial/test_additional_responses/test_tutorial003.py
index e888819dfe..56eeacb605 100644
--- a/tests/test_tutorial/test_additional_responses/test_tutorial003.py
+++ b/tests/test_tutorial/test_additional_responses/test_tutorial003.py
@@ -1,7 +1,7 @@
from fastapi.testclient import TestClient
from inline_snapshot import snapshot
-from docs_src.additional_responses.tutorial003_py39 import app
+from docs_src.additional_responses.tutorial003_py310 import app
client = TestClient(app)
diff --git a/tests/test_tutorial/test_additional_responses/test_tutorial004.py b/tests/test_tutorial/test_additional_responses/test_tutorial004.py
index 9df326a5ce..fe56fbb8b5 100644
--- a/tests/test_tutorial/test_additional_responses/test_tutorial004.py
+++ b/tests/test_tutorial/test_additional_responses/test_tutorial004.py
@@ -12,7 +12,6 @@ from tests.utils import needs_py310
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial004_py39"),
pytest.param("tutorial004_py310", marks=needs_py310),
],
)
diff --git a/tests/test_tutorial/test_additional_status_codes/test_tutorial001.py b/tests/test_tutorial/test_additional_status_codes/test_tutorial001.py
index bced1f6dfe..f57ea2bcf2 100644
--- a/tests/test_tutorial/test_additional_status_codes/test_tutorial001.py
+++ b/tests/test_tutorial/test_additional_status_codes/test_tutorial001.py
@@ -9,9 +9,7 @@ from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
- "tutorial001_py39",
pytest.param("tutorial001_py310", marks=needs_py310),
- "tutorial001_an_py39",
pytest.param("tutorial001_an_py310", marks=needs_py310),
],
)
diff --git a/tests/test_tutorial/test_advanced_middleware/test_tutorial001.py b/tests/test_tutorial/test_advanced_middleware/test_tutorial001.py
index f17391956e..6231cf4cb1 100644
--- a/tests/test_tutorial/test_advanced_middleware/test_tutorial001.py
+++ b/tests/test_tutorial/test_advanced_middleware/test_tutorial001.py
@@ -1,6 +1,6 @@
from fastapi.testclient import TestClient
-from docs_src.advanced_middleware.tutorial001_py39 import app
+from docs_src.advanced_middleware.tutorial001_py310 import app
def test_middleware():
diff --git a/tests/test_tutorial/test_advanced_middleware/test_tutorial002.py b/tests/test_tutorial/test_advanced_middleware/test_tutorial002.py
index bae915406e..fa8ac41d79 100644
--- a/tests/test_tutorial/test_advanced_middleware/test_tutorial002.py
+++ b/tests/test_tutorial/test_advanced_middleware/test_tutorial002.py
@@ -1,6 +1,6 @@
from fastapi.testclient import TestClient
-from docs_src.advanced_middleware.tutorial002_py39 import app
+from docs_src.advanced_middleware.tutorial002_py310 import app
def test_middleware():
diff --git a/tests/test_tutorial/test_advanced_middleware/test_tutorial003.py b/tests/test_tutorial/test_advanced_middleware/test_tutorial003.py
index 66697997c8..8602e15697 100644
--- a/tests/test_tutorial/test_advanced_middleware/test_tutorial003.py
+++ b/tests/test_tutorial/test_advanced_middleware/test_tutorial003.py
@@ -1,7 +1,7 @@
from fastapi.responses import PlainTextResponse
from fastapi.testclient import TestClient
-from docs_src.advanced_middleware.tutorial003_py39 import app
+from docs_src.advanced_middleware.tutorial003_py310 import app
@app.get("/large")
diff --git a/tests/test_tutorial/test_async_tests/test_main_a.py b/tests/test_tutorial/test_async_tests/test_main_a.py
index f29acaa9a0..4e33692d0c 100644
--- a/tests/test_tutorial/test_async_tests/test_main_a.py
+++ b/tests/test_tutorial/test_async_tests/test_main_a.py
@@ -1,6 +1,6 @@
import pytest
-from docs_src.async_tests.app_a_py39.test_main import test_root
+from docs_src.async_tests.app_a_py310.test_main import test_root
@pytest.mark.anyio
diff --git a/tests/test_tutorial/test_authentication_error_status_code/test_tutorial001.py b/tests/test_tutorial/test_authentication_error_status_code/test_tutorial001.py
index 6f58116313..7e1588d676 100644
--- a/tests/test_tutorial/test_authentication_error_status_code/test_tutorial001.py
+++ b/tests/test_tutorial/test_authentication_error_status_code/test_tutorial001.py
@@ -8,7 +8,7 @@ from inline_snapshot import snapshot
@pytest.fixture(
name="client",
params=[
- "tutorial001_an_py39",
+ "tutorial001_an_py310",
],
)
def get_client(request: pytest.FixtureRequest):
diff --git a/tests/test_tutorial/test_background_tasks/test_tutorial001.py b/tests/test_tutorial/test_background_tasks/test_tutorial001.py
index c0ad27a6f5..100583f77a 100644
--- a/tests/test_tutorial/test_background_tasks/test_tutorial001.py
+++ b/tests/test_tutorial/test_background_tasks/test_tutorial001.py
@@ -3,7 +3,7 @@ from pathlib import Path
from fastapi.testclient import TestClient
-from docs_src.background_tasks.tutorial001_py39 import app
+from docs_src.background_tasks.tutorial001_py310 import app
client = TestClient(app)
diff --git a/tests/test_tutorial/test_background_tasks/test_tutorial002.py b/tests/test_tutorial/test_background_tasks/test_tutorial002.py
index 288a1c244e..f29402c833 100644
--- a/tests/test_tutorial/test_background_tasks/test_tutorial002.py
+++ b/tests/test_tutorial/test_background_tasks/test_tutorial002.py
@@ -11,9 +11,7 @@ from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
- "tutorial002_py39",
pytest.param("tutorial002_py310", marks=needs_py310),
- "tutorial002_an_py39",
pytest.param("tutorial002_an_py310", marks=needs_py310),
],
)
diff --git a/tests/test_tutorial/test_behind_a_proxy/test_tutorial001.py b/tests/test_tutorial/test_behind_a_proxy/test_tutorial001.py
index 31adaa56a6..38ae460fbe 100644
--- a/tests/test_tutorial/test_behind_a_proxy/test_tutorial001.py
+++ b/tests/test_tutorial/test_behind_a_proxy/test_tutorial001.py
@@ -1,7 +1,7 @@
from fastapi.testclient import TestClient
from inline_snapshot import snapshot
-from docs_src.behind_a_proxy.tutorial001_py39 import app
+from docs_src.behind_a_proxy.tutorial001_py310 import app
client = TestClient(app, root_path="/api/v1")
diff --git a/tests/test_tutorial/test_behind_a_proxy/test_tutorial001_01.py b/tests/test_tutorial/test_behind_a_proxy/test_tutorial001_01.py
index da4acb28cc..190b33c50f 100644
--- a/tests/test_tutorial/test_behind_a_proxy/test_tutorial001_01.py
+++ b/tests/test_tutorial/test_behind_a_proxy/test_tutorial001_01.py
@@ -1,6 +1,6 @@
from fastapi.testclient import TestClient
-from docs_src.behind_a_proxy.tutorial001_01_py39 import app
+from docs_src.behind_a_proxy.tutorial001_01_py310 import app
client = TestClient(
app,
diff --git a/tests/test_tutorial/test_behind_a_proxy/test_tutorial002.py b/tests/test_tutorial/test_behind_a_proxy/test_tutorial002.py
index 56e6f2f9d2..c9356a5130 100644
--- a/tests/test_tutorial/test_behind_a_proxy/test_tutorial002.py
+++ b/tests/test_tutorial/test_behind_a_proxy/test_tutorial002.py
@@ -1,7 +1,7 @@
from fastapi.testclient import TestClient
from inline_snapshot import snapshot
-from docs_src.behind_a_proxy.tutorial002_py39 import app
+from docs_src.behind_a_proxy.tutorial002_py310 import app
client = TestClient(app)
diff --git a/tests/test_tutorial/test_behind_a_proxy/test_tutorial003.py b/tests/test_tutorial/test_behind_a_proxy/test_tutorial003.py
index a164bb80b5..d74da5b73e 100644
--- a/tests/test_tutorial/test_behind_a_proxy/test_tutorial003.py
+++ b/tests/test_tutorial/test_behind_a_proxy/test_tutorial003.py
@@ -1,7 +1,7 @@
from fastapi.testclient import TestClient
from inline_snapshot import snapshot
-from docs_src.behind_a_proxy.tutorial003_py39 import app
+from docs_src.behind_a_proxy.tutorial003_py310 import app
client = TestClient(app)
diff --git a/tests/test_tutorial/test_behind_a_proxy/test_tutorial004.py b/tests/test_tutorial/test_behind_a_proxy/test_tutorial004.py
index 01bba9fedd..f5e27c1183 100644
--- a/tests/test_tutorial/test_behind_a_proxy/test_tutorial004.py
+++ b/tests/test_tutorial/test_behind_a_proxy/test_tutorial004.py
@@ -1,7 +1,7 @@
from fastapi.testclient import TestClient
from inline_snapshot import snapshot
-from docs_src.behind_a_proxy.tutorial004_py39 import app
+from docs_src.behind_a_proxy.tutorial004_py310 import app
client = TestClient(app)
diff --git a/tests/test_tutorial/test_bigger_applications/test_main.py b/tests/test_tutorial/test_bigger_applications/test_main.py
index 18845e4702..abe008d9e2 100644
--- a/tests/test_tutorial/test_bigger_applications/test_main.py
+++ b/tests/test_tutorial/test_bigger_applications/test_main.py
@@ -8,8 +8,7 @@ from inline_snapshot import snapshot
@pytest.fixture(
name="client",
params=[
- "app_py39.main",
- "app_an_py39.main",
+ "app_an_py310.main",
],
)
def get_client(request: pytest.FixtureRequest):
diff --git a/tests/test_tutorial/test_body/test_tutorial001.py b/tests/test_tutorial/test_body/test_tutorial001.py
index c1877a72ef..bdabf8d68b 100644
--- a/tests/test_tutorial/test_body/test_tutorial001.py
+++ b/tests/test_tutorial/test_body/test_tutorial001.py
@@ -11,7 +11,6 @@ from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
- "tutorial001_py39",
pytest.param("tutorial001_py310", marks=needs_py310),
],
)
diff --git a/tests/test_tutorial/test_body/test_tutorial002.py b/tests/test_tutorial/test_body/test_tutorial002.py
index 94bf213e3f..f1e1236c99 100644
--- a/tests/test_tutorial/test_body/test_tutorial002.py
+++ b/tests/test_tutorial/test_body/test_tutorial002.py
@@ -1,5 +1,4 @@
import importlib
-from typing import Union
import pytest
from fastapi.testclient import TestClient
@@ -11,7 +10,6 @@ from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial002_py39"),
pytest.param("tutorial002_py310", marks=needs_py310),
],
)
@@ -23,7 +21,7 @@ def get_client(request: pytest.FixtureRequest):
@pytest.mark.parametrize("price", ["50.5", 50.5])
-def test_post_with_tax(client: TestClient, price: Union[str, float]):
+def test_post_with_tax(client: TestClient, price: str | float):
response = client.post(
"/items/",
json={"name": "Foo", "price": price, "description": "Some Foo", "tax": 0.3},
@@ -39,7 +37,7 @@ def test_post_with_tax(client: TestClient, price: Union[str, float]):
@pytest.mark.parametrize("price", ["50.5", 50.5])
-def test_post_without_tax(client: TestClient, price: Union[str, float]):
+def test_post_without_tax(client: TestClient, price: str | float):
response = client.post(
"/items/", json={"name": "Foo", "price": price, "description": "Some Foo"}
)
diff --git a/tests/test_tutorial/test_body/test_tutorial003.py b/tests/test_tutorial/test_body/test_tutorial003.py
index 832c211f66..b4767cf285 100644
--- a/tests/test_tutorial/test_body/test_tutorial003.py
+++ b/tests/test_tutorial/test_body/test_tutorial003.py
@@ -10,7 +10,6 @@ from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial003_py39"),
pytest.param("tutorial003_py310", marks=needs_py310),
],
)
diff --git a/tests/test_tutorial/test_body/test_tutorial004.py b/tests/test_tutorial/test_body/test_tutorial004.py
index 1019a168cf..f0a50a64c6 100644
--- a/tests/test_tutorial/test_body/test_tutorial004.py
+++ b/tests/test_tutorial/test_body/test_tutorial004.py
@@ -10,7 +10,6 @@ from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial004_py39"),
pytest.param("tutorial004_py310", marks=needs_py310),
],
)
diff --git a/tests/test_tutorial/test_body_fields/test_tutorial001.py b/tests/test_tutorial/test_body_fields/test_tutorial001.py
index 0116dcb09c..eb94d24cda 100644
--- a/tests/test_tutorial/test_body_fields/test_tutorial001.py
+++ b/tests/test_tutorial/test_body_fields/test_tutorial001.py
@@ -10,9 +10,7 @@ from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
- "tutorial001_py39",
pytest.param("tutorial001_py310", marks=needs_py310),
- "tutorial001_an_py39",
pytest.param("tutorial001_an_py310", marks=needs_py310),
],
)
diff --git a/tests/test_tutorial/test_body_multiple_params/test_tutorial001.py b/tests/test_tutorial/test_body_multiple_params/test_tutorial001.py
index 2e8ba457be..f510f1c156 100644
--- a/tests/test_tutorial/test_body_multiple_params/test_tutorial001.py
+++ b/tests/test_tutorial/test_body_multiple_params/test_tutorial001.py
@@ -10,9 +10,7 @@ from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
- "tutorial001_py39",
pytest.param("tutorial001_py310", marks=needs_py310),
- "tutorial001_an_py39",
pytest.param("tutorial001_an_py310", marks=needs_py310),
],
)
diff --git a/tests/test_tutorial/test_body_multiple_params/test_tutorial002.py b/tests/test_tutorial/test_body_multiple_params/test_tutorial002.py
index 0c94e9dd1e..b23402c3cb 100644
--- a/tests/test_tutorial/test_body_multiple_params/test_tutorial002.py
+++ b/tests/test_tutorial/test_body_multiple_params/test_tutorial002.py
@@ -10,7 +10,6 @@ from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial002_py39"),
pytest.param("tutorial002_py310", marks=needs_py310),
],
)
diff --git a/tests/test_tutorial/test_body_multiple_params/test_tutorial003.py b/tests/test_tutorial/test_body_multiple_params/test_tutorial003.py
index c27f3d5ba8..89fabd3ba2 100644
--- a/tests/test_tutorial/test_body_multiple_params/test_tutorial003.py
+++ b/tests/test_tutorial/test_body_multiple_params/test_tutorial003.py
@@ -10,9 +10,7 @@ from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
- "tutorial003_py39",
pytest.param("tutorial003_py310", marks=needs_py310),
- "tutorial003_an_py39",
pytest.param("tutorial003_an_py310", marks=needs_py310),
],
)
diff --git a/tests/test_tutorial/test_body_multiple_params/test_tutorial004.py b/tests/test_tutorial/test_body_multiple_params/test_tutorial004.py
index 2a39f3d713..c5b4b452d5 100644
--- a/tests/test_tutorial/test_body_multiple_params/test_tutorial004.py
+++ b/tests/test_tutorial/test_body_multiple_params/test_tutorial004.py
@@ -10,9 +10,7 @@ from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial004_py39"),
pytest.param("tutorial004_py310", marks=needs_py310),
- pytest.param("tutorial004_an_py39"),
pytest.param("tutorial004_an_py310", marks=needs_py310),
],
)
diff --git a/tests/test_tutorial/test_body_multiple_params/test_tutorial005.py b/tests/test_tutorial/test_body_multiple_params/test_tutorial005.py
index d600e0767d..b8fc98cd7e 100644
--- a/tests/test_tutorial/test_body_multiple_params/test_tutorial005.py
+++ b/tests/test_tutorial/test_body_multiple_params/test_tutorial005.py
@@ -10,9 +10,7 @@ from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial005_py39"),
pytest.param("tutorial005_py310", marks=needs_py310),
- pytest.param("tutorial005_an_py39"),
pytest.param("tutorial005_an_py310", marks=needs_py310),
],
)
diff --git a/tests/test_tutorial/test_body_nested_models/test_tutorial001_tutorial002_tutorial003.py b/tests/test_tutorial/test_body_nested_models/test_tutorial001_tutorial002_tutorial003.py
index 18bce279b9..2e2f329f79 100644
--- a/tests/test_tutorial/test_body_nested_models/test_tutorial001_tutorial002_tutorial003.py
+++ b/tests/test_tutorial/test_body_nested_models/test_tutorial001_tutorial002_tutorial003.py
@@ -17,11 +17,8 @@ SET_OF_STR_SCHEMA = {"type": "array", "items": {"type": "string"}, "uniqueItems"
@pytest.fixture(
name="mod_name",
params=[
- pytest.param("tutorial001_py39"),
pytest.param("tutorial001_py310", marks=needs_py310),
- pytest.param("tutorial002_py39"),
pytest.param("tutorial002_py310", marks=needs_py310),
- pytest.param("tutorial003_py39"),
pytest.param("tutorial003_py310", marks=needs_py310),
],
)
diff --git a/tests/test_tutorial/test_body_nested_models/test_tutorial004.py b/tests/test_tutorial/test_body_nested_models/test_tutorial004.py
index 6a70779b68..4605a757d4 100644
--- a/tests/test_tutorial/test_body_nested_models/test_tutorial004.py
+++ b/tests/test_tutorial/test_body_nested_models/test_tutorial004.py
@@ -11,7 +11,6 @@ from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial004_py39"),
pytest.param("tutorial004_py310", marks=needs_py310),
],
)
diff --git a/tests/test_tutorial/test_body_nested_models/test_tutorial005.py b/tests/test_tutorial/test_body_nested_models/test_tutorial005.py
index 2ff3d4f220..ffa02cd65f 100644
--- a/tests/test_tutorial/test_body_nested_models/test_tutorial005.py
+++ b/tests/test_tutorial/test_body_nested_models/test_tutorial005.py
@@ -11,7 +11,6 @@ from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial005_py39"),
pytest.param("tutorial005_py310", marks=needs_py310),
],
)
diff --git a/tests/test_tutorial/test_body_nested_models/test_tutorial006.py b/tests/test_tutorial/test_body_nested_models/test_tutorial006.py
index 229216fc58..4551a72b31 100644
--- a/tests/test_tutorial/test_body_nested_models/test_tutorial006.py
+++ b/tests/test_tutorial/test_body_nested_models/test_tutorial006.py
@@ -11,7 +11,6 @@ from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial006_py39"),
pytest.param("tutorial006_py310", marks=needs_py310),
],
)
diff --git a/tests/test_tutorial/test_body_nested_models/test_tutorial007.py b/tests/test_tutorial/test_body_nested_models/test_tutorial007.py
index 5a7763f598..5b99b41b6a 100644
--- a/tests/test_tutorial/test_body_nested_models/test_tutorial007.py
+++ b/tests/test_tutorial/test_body_nested_models/test_tutorial007.py
@@ -10,7 +10,6 @@ from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial007_py39"),
pytest.param("tutorial007_py310", marks=needs_py310),
],
)
diff --git a/tests/test_tutorial/test_body_nested_models/test_tutorial008.py b/tests/test_tutorial/test_body_nested_models/test_tutorial008.py
index 26f48f1d5f..d038805bd7 100644
--- a/tests/test_tutorial/test_body_nested_models/test_tutorial008.py
+++ b/tests/test_tutorial/test_body_nested_models/test_tutorial008.py
@@ -8,7 +8,7 @@ from inline_snapshot import snapshot
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial008_py39"),
+ pytest.param("tutorial008_py310"),
],
)
def get_client(request: pytest.FixtureRequest):
diff --git a/tests/test_tutorial/test_body_nested_models/test_tutorial009.py b/tests/test_tutorial/test_body_nested_models/test_tutorial009.py
index 492dcecd2b..a747e2a64c 100644
--- a/tests/test_tutorial/test_body_nested_models/test_tutorial009.py
+++ b/tests/test_tutorial/test_body_nested_models/test_tutorial009.py
@@ -8,7 +8,7 @@ from inline_snapshot import snapshot
@pytest.fixture(
name="client",
params=[
- "tutorial009_py39",
+ "tutorial009_py310",
],
)
def get_client(request: pytest.FixtureRequest):
diff --git a/tests/test_tutorial/test_body_updates/test_tutorial001.py b/tests/test_tutorial/test_body_updates/test_tutorial001.py
index feb07b8595..ba8d7baf33 100644
--- a/tests/test_tutorial/test_body_updates/test_tutorial001.py
+++ b/tests/test_tutorial/test_body_updates/test_tutorial001.py
@@ -10,7 +10,6 @@ from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
- "tutorial001_py39",
pytest.param("tutorial001_py310", marks=needs_py310),
],
)
diff --git a/tests/test_tutorial/test_body_updates/test_tutorial002.py b/tests/test_tutorial/test_body_updates/test_tutorial002.py
index a34d08b52b..cf0ee7ada4 100644
--- a/tests/test_tutorial/test_body_updates/test_tutorial002.py
+++ b/tests/test_tutorial/test_body_updates/test_tutorial002.py
@@ -10,7 +10,6 @@ from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial002_py39"),
pytest.param("tutorial002_py310", marks=needs_py310),
],
)
diff --git a/tests/test_tutorial/test_conditional_openapi/test_tutorial001.py b/tests/test_tutorial/test_conditional_openapi/test_tutorial001.py
index 644b82ad9a..a7aa9dbe27 100644
--- a/tests/test_tutorial/test_conditional_openapi/test_tutorial001.py
+++ b/tests/test_tutorial/test_conditional_openapi/test_tutorial001.py
@@ -5,11 +5,11 @@ from inline_snapshot import snapshot
def get_client() -> TestClient:
- from docs_src.conditional_openapi import tutorial001_py39
+ from docs_src.conditional_openapi import tutorial001_py310
- importlib.reload(tutorial001_py39)
+ importlib.reload(tutorial001_py310)
- client = TestClient(tutorial001_py39.app)
+ client = TestClient(tutorial001_py310.app)
return client
diff --git a/tests/test_tutorial/test_configure_swagger_ui/test_tutorial001.py b/tests/test_tutorial/test_configure_swagger_ui/test_tutorial001.py
index 1fa9419a76..e2f1fbf907 100644
--- a/tests/test_tutorial/test_configure_swagger_ui/test_tutorial001.py
+++ b/tests/test_tutorial/test_configure_swagger_ui/test_tutorial001.py
@@ -1,6 +1,6 @@
from fastapi.testclient import TestClient
-from docs_src.configure_swagger_ui.tutorial001_py39 import app
+from docs_src.configure_swagger_ui.tutorial001_py310 import app
client = TestClient(app)
diff --git a/tests/test_tutorial/test_configure_swagger_ui/test_tutorial002.py b/tests/test_tutorial/test_configure_swagger_ui/test_tutorial002.py
index c218cc858c..ce1cb4bace 100644
--- a/tests/test_tutorial/test_configure_swagger_ui/test_tutorial002.py
+++ b/tests/test_tutorial/test_configure_swagger_ui/test_tutorial002.py
@@ -1,6 +1,6 @@
from fastapi.testclient import TestClient
-from docs_src.configure_swagger_ui.tutorial002_py39 import app
+from docs_src.configure_swagger_ui.tutorial002_py310 import app
client = TestClient(app)
diff --git a/tests/test_tutorial/test_configure_swagger_ui/test_tutorial003.py b/tests/test_tutorial/test_configure_swagger_ui/test_tutorial003.py
index 8b73685499..6f28e77341 100644
--- a/tests/test_tutorial/test_configure_swagger_ui/test_tutorial003.py
+++ b/tests/test_tutorial/test_configure_swagger_ui/test_tutorial003.py
@@ -1,6 +1,6 @@
from fastapi.testclient import TestClient
-from docs_src.configure_swagger_ui.tutorial003_py39 import app
+from docs_src.configure_swagger_ui.tutorial003_py310 import app
client = TestClient(app)
diff --git a/tests/test_tutorial/test_cookie_param_models/test_tutorial001.py b/tests/test_tutorial/test_cookie_param_models/test_tutorial001.py
index f391c569a8..c4de7ad450 100644
--- a/tests/test_tutorial/test_cookie_param_models/test_tutorial001.py
+++ b/tests/test_tutorial/test_cookie_param_models/test_tutorial001.py
@@ -10,9 +10,7 @@ from tests.utils import needs_py310
@pytest.fixture(
name="client",
params=[
- "tutorial001_py39",
pytest.param("tutorial001_py310", marks=needs_py310),
- "tutorial001_an_py39",
pytest.param("tutorial001_an_py310", marks=needs_py310),
],
)
diff --git a/tests/test_tutorial/test_cookie_param_models/test_tutorial002.py b/tests/test_tutorial/test_cookie_param_models/test_tutorial002.py
index 6583045dc8..37be0f1ddb 100644
--- a/tests/test_tutorial/test_cookie_param_models/test_tutorial002.py
+++ b/tests/test_tutorial/test_cookie_param_models/test_tutorial002.py
@@ -10,9 +10,7 @@ from tests.utils import needs_py310
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial002_py39"),
pytest.param("tutorial002_py310", marks=[needs_py310]),
- pytest.param("tutorial002_an_py39"),
pytest.param("tutorial002_an_py310", marks=[needs_py310]),
],
)
diff --git a/tests/test_tutorial/test_cookie_params/test_tutorial001.py b/tests/test_tutorial/test_cookie_params/test_tutorial001.py
index 4d7adf0d60..db0765ea51 100644
--- a/tests/test_tutorial/test_cookie_params/test_tutorial001.py
+++ b/tests/test_tutorial/test_cookie_params/test_tutorial001.py
@@ -11,9 +11,7 @@ from ...utils import needs_py310
@pytest.fixture(
name="mod",
params=[
- "tutorial001_py39",
pytest.param("tutorial001_py310", marks=needs_py310),
- "tutorial001_an_py39",
pytest.param("tutorial001_an_py310", marks=needs_py310),
],
)
diff --git a/tests/test_tutorial/test_cors/test_tutorial001.py b/tests/test_tutorial/test_cors/test_tutorial001.py
index 6a733693ae..428378cd44 100644
--- a/tests/test_tutorial/test_cors/test_tutorial001.py
+++ b/tests/test_tutorial/test_cors/test_tutorial001.py
@@ -1,6 +1,6 @@
from fastapi.testclient import TestClient
-from docs_src.cors.tutorial001_py39 import app
+from docs_src.cors.tutorial001_py310 import app
def test_cors():
diff --git a/tests/test_tutorial/test_custom_docs_ui/test_tutorial001.py b/tests/test_tutorial/test_custom_docs_ui/test_tutorial001.py
index 1816e5d975..f7eb7fd97d 100644
--- a/tests/test_tutorial/test_custom_docs_ui/test_tutorial001.py
+++ b/tests/test_tutorial/test_custom_docs_ui/test_tutorial001.py
@@ -10,7 +10,7 @@ def client():
static_dir: Path = Path(os.getcwd()) / "static"
print(static_dir)
static_dir.mkdir(exist_ok=True)
- from docs_src.custom_docs_ui.tutorial001_py39 import app
+ from docs_src.custom_docs_ui.tutorial001_py310 import app
with TestClient(app) as client:
yield client
diff --git a/tests/test_tutorial/test_custom_docs_ui/test_tutorial002.py b/tests/test_tutorial/test_custom_docs_ui/test_tutorial002.py
index e8b7eb7aa3..28945d8387 100644
--- a/tests/test_tutorial/test_custom_docs_ui/test_tutorial002.py
+++ b/tests/test_tutorial/test_custom_docs_ui/test_tutorial002.py
@@ -10,7 +10,7 @@ def client():
static_dir: Path = Path(os.getcwd()) / "static"
print(static_dir)
static_dir.mkdir(exist_ok=True)
- from docs_src.custom_docs_ui.tutorial002_py39 import app
+ from docs_src.custom_docs_ui.tutorial002_py310 import app
with TestClient(app) as client:
yield client
diff --git a/tests/test_tutorial/test_custom_request_and_route/test_tutorial001.py b/tests/test_tutorial/test_custom_request_and_route/test_tutorial001.py
index b4ea537846..39d3bd4065 100644
--- a/tests/test_tutorial/test_custom_request_and_route/test_tutorial001.py
+++ b/tests/test_tutorial/test_custom_request_and_route/test_tutorial001.py
@@ -12,9 +12,7 @@ from tests.utils import needs_py310
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial001_py39"),
pytest.param("tutorial001_py310", marks=needs_py310),
- pytest.param("tutorial001_an_py39"),
pytest.param("tutorial001_an_py310", marks=needs_py310),
],
)
diff --git a/tests/test_tutorial/test_custom_request_and_route/test_tutorial002.py b/tests/test_tutorial/test_custom_request_and_route/test_tutorial002.py
index a9c7ae638b..746d6c9d2f 100644
--- a/tests/test_tutorial/test_custom_request_and_route/test_tutorial002.py
+++ b/tests/test_tutorial/test_custom_request_and_route/test_tutorial002.py
@@ -10,9 +10,7 @@ from tests.utils import needs_py310
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial002_py39"),
pytest.param("tutorial002_py310", marks=needs_py310),
- pytest.param("tutorial002_an_py39"),
pytest.param("tutorial002_an_py310", marks=needs_py310),
],
)
diff --git a/tests/test_tutorial/test_custom_request_and_route/test_tutorial003.py b/tests/test_tutorial/test_custom_request_and_route/test_tutorial003.py
index 6cad7bd3f0..c11ea12590 100644
--- a/tests/test_tutorial/test_custom_request_and_route/test_tutorial003.py
+++ b/tests/test_tutorial/test_custom_request_and_route/test_tutorial003.py
@@ -9,7 +9,6 @@ from tests.utils import needs_py310
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial003_py39"),
pytest.param("tutorial003_py310", marks=needs_py310),
],
)
diff --git a/tests/test_tutorial/test_custom_response/test_tutorial001.py b/tests/test_tutorial/test_custom_response/test_tutorial001.py
index 20244bef45..a5fe4c8f4c 100644
--- a/tests/test_tutorial/test_custom_response/test_tutorial001.py
+++ b/tests/test_tutorial/test_custom_response/test_tutorial001.py
@@ -8,8 +8,8 @@ from inline_snapshot import snapshot
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial001_py39"),
- pytest.param("tutorial010_py39"),
+ pytest.param("tutorial001_py310"),
+ pytest.param("tutorial010_py310"),
],
)
def get_client(request: pytest.FixtureRequest):
diff --git a/tests/test_tutorial/test_custom_response/test_tutorial001b.py b/tests/test_tutorial/test_custom_response/test_tutorial001b.py
index 746801df16..32437db86b 100644
--- a/tests/test_tutorial/test_custom_response/test_tutorial001b.py
+++ b/tests/test_tutorial/test_custom_response/test_tutorial001b.py
@@ -1,7 +1,7 @@
from fastapi.testclient import TestClient
from inline_snapshot import snapshot
-from docs_src.custom_response.tutorial001b_py39 import app
+from docs_src.custom_response.tutorial001b_py310 import app
client = TestClient(app)
diff --git a/tests/test_tutorial/test_custom_response/test_tutorial002_tutorial003_tutorial004.py b/tests/test_tutorial/test_custom_response/test_tutorial002_tutorial003_tutorial004.py
index 68e046ac5a..42fd85583c 100644
--- a/tests/test_tutorial/test_custom_response/test_tutorial002_tutorial003_tutorial004.py
+++ b/tests/test_tutorial/test_custom_response/test_tutorial002_tutorial003_tutorial004.py
@@ -8,9 +8,9 @@ from inline_snapshot import Is, snapshot
@pytest.fixture(
name="mod_name",
params=[
- pytest.param("tutorial002_py39"),
- pytest.param("tutorial003_py39"),
- pytest.param("tutorial004_py39"),
+ pytest.param("tutorial002_py310"),
+ pytest.param("tutorial003_py310"),
+ pytest.param("tutorial004_py310"),
],
)
def get_mod_name(request: pytest.FixtureRequest) -> str:
diff --git a/tests/test_tutorial/test_custom_response/test_tutorial005.py b/tests/test_tutorial/test_custom_response/test_tutorial005.py
index b4919af6c3..297e488225 100644
--- a/tests/test_tutorial/test_custom_response/test_tutorial005.py
+++ b/tests/test_tutorial/test_custom_response/test_tutorial005.py
@@ -1,7 +1,7 @@
from fastapi.testclient import TestClient
from inline_snapshot import snapshot
-from docs_src.custom_response.tutorial005_py39 import app
+from docs_src.custom_response.tutorial005_py310 import app
client = TestClient(app)
diff --git a/tests/test_tutorial/test_custom_response/test_tutorial006.py b/tests/test_tutorial/test_custom_response/test_tutorial006.py
index ea2d366aa0..4365090c27 100644
--- a/tests/test_tutorial/test_custom_response/test_tutorial006.py
+++ b/tests/test_tutorial/test_custom_response/test_tutorial006.py
@@ -1,7 +1,7 @@
from fastapi.testclient import TestClient
from inline_snapshot import snapshot
-from docs_src.custom_response.tutorial006_py39 import app
+from docs_src.custom_response.tutorial006_py310 import app
client = TestClient(app)
diff --git a/tests/test_tutorial/test_custom_response/test_tutorial006b.py b/tests/test_tutorial/test_custom_response/test_tutorial006b.py
index 133a591b16..a776188471 100644
--- a/tests/test_tutorial/test_custom_response/test_tutorial006b.py
+++ b/tests/test_tutorial/test_custom_response/test_tutorial006b.py
@@ -1,7 +1,7 @@
from fastapi.testclient import TestClient
from inline_snapshot import snapshot
-from docs_src.custom_response.tutorial006b_py39 import app
+from docs_src.custom_response.tutorial006b_py310 import app
client = TestClient(app)
diff --git a/tests/test_tutorial/test_custom_response/test_tutorial006c.py b/tests/test_tutorial/test_custom_response/test_tutorial006c.py
index 5b17d815d0..f29bda2c29 100644
--- a/tests/test_tutorial/test_custom_response/test_tutorial006c.py
+++ b/tests/test_tutorial/test_custom_response/test_tutorial006c.py
@@ -1,7 +1,7 @@
from fastapi.testclient import TestClient
from inline_snapshot import snapshot
-from docs_src.custom_response.tutorial006c_py39 import app
+from docs_src.custom_response.tutorial006c_py310 import app
client = TestClient(app)
diff --git a/tests/test_tutorial/test_custom_response/test_tutorial007.py b/tests/test_tutorial/test_custom_response/test_tutorial007.py
index a62476ec14..5f2e233f8b 100644
--- a/tests/test_tutorial/test_custom_response/test_tutorial007.py
+++ b/tests/test_tutorial/test_custom_response/test_tutorial007.py
@@ -1,6 +1,6 @@
from fastapi.testclient import TestClient
-from docs_src.custom_response.tutorial007_py39 import app
+from docs_src.custom_response.tutorial007_py310 import app
client = TestClient(app)
diff --git a/tests/test_tutorial/test_custom_response/test_tutorial008.py b/tests/test_tutorial/test_custom_response/test_tutorial008.py
index d9fe61f539..1be7c1a622 100644
--- a/tests/test_tutorial/test_custom_response/test_tutorial008.py
+++ b/tests/test_tutorial/test_custom_response/test_tutorial008.py
@@ -2,15 +2,15 @@ from pathlib import Path
from fastapi.testclient import TestClient
-from docs_src.custom_response import tutorial008_py39
-from docs_src.custom_response.tutorial008_py39 import app
+from docs_src.custom_response import tutorial008_py310
+from docs_src.custom_response.tutorial008_py310 import app
client = TestClient(app)
def test_get(tmp_path: Path):
file_path: Path = tmp_path / "large-video-file.mp4"
- tutorial008_py39.some_file_path = str(file_path)
+ tutorial008_py310.some_file_path = str(file_path)
test_content = b"Fake video bytes"
file_path.write_bytes(test_content)
response = client.get("/")
diff --git a/tests/test_tutorial/test_custom_response/test_tutorial009.py b/tests/test_tutorial/test_custom_response/test_tutorial009.py
index cb6a514be6..a6564d5516 100644
--- a/tests/test_tutorial/test_custom_response/test_tutorial009.py
+++ b/tests/test_tutorial/test_custom_response/test_tutorial009.py
@@ -2,15 +2,15 @@ from pathlib import Path
from fastapi.testclient import TestClient
-from docs_src.custom_response import tutorial009_py39
-from docs_src.custom_response.tutorial009_py39 import app
+from docs_src.custom_response import tutorial009_py310
+from docs_src.custom_response.tutorial009_py310 import app
client = TestClient(app)
def test_get(tmp_path: Path):
file_path: Path = tmp_path / "large-video-file.mp4"
- tutorial009_py39.some_file_path = str(file_path)
+ tutorial009_py310.some_file_path = str(file_path)
test_content = b"Fake video bytes"
file_path.write_bytes(test_content)
response = client.get("/")
diff --git a/tests/test_tutorial/test_custom_response/test_tutorial009b.py b/tests/test_tutorial/test_custom_response/test_tutorial009b.py
index 9918bdb1ac..05ac62f3d0 100644
--- a/tests/test_tutorial/test_custom_response/test_tutorial009b.py
+++ b/tests/test_tutorial/test_custom_response/test_tutorial009b.py
@@ -2,15 +2,15 @@ from pathlib import Path
from fastapi.testclient import TestClient
-from docs_src.custom_response import tutorial009b_py39
-from docs_src.custom_response.tutorial009b_py39 import app
+from docs_src.custom_response import tutorial009b_py310
+from docs_src.custom_response.tutorial009b_py310 import app
client = TestClient(app)
def test_get(tmp_path: Path):
file_path: Path = tmp_path / "large-video-file.mp4"
- tutorial009b_py39.some_file_path = str(file_path)
+ tutorial009b_py310.some_file_path = str(file_path)
test_content = b"Fake video bytes"
file_path.write_bytes(test_content)
response = client.get("/")
diff --git a/tests/test_tutorial/test_custom_response/test_tutorial009c.py b/tests/test_tutorial/test_custom_response/test_tutorial009c.py
index efc3a6b4a0..7a1b713079 100644
--- a/tests/test_tutorial/test_custom_response/test_tutorial009c.py
+++ b/tests/test_tutorial/test_custom_response/test_tutorial009c.py
@@ -1,6 +1,6 @@
from fastapi.testclient import TestClient
-from docs_src.custom_response.tutorial009c_py39 import app
+from docs_src.custom_response.tutorial009c_py310 import app
client = TestClient(app)
diff --git a/tests/test_tutorial/test_dataclasses/test_tutorial001.py b/tests/test_tutorial/test_dataclasses/test_tutorial001.py
index a3d2cf5152..62de135dcd 100644
--- a/tests/test_tutorial/test_dataclasses/test_tutorial001.py
+++ b/tests/test_tutorial/test_dataclasses/test_tutorial001.py
@@ -10,7 +10,6 @@ from tests.utils import needs_py310
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial001_py39"),
pytest.param("tutorial001_py310", marks=needs_py310),
],
)
diff --git a/tests/test_tutorial/test_dataclasses/test_tutorial002.py b/tests/test_tutorial/test_dataclasses/test_tutorial002.py
index 210d743bb8..f6607c8e02 100644
--- a/tests/test_tutorial/test_dataclasses/test_tutorial002.py
+++ b/tests/test_tutorial/test_dataclasses/test_tutorial002.py
@@ -10,7 +10,6 @@ from tests.utils import needs_py310
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial002_py39"),
pytest.param("tutorial002_py310", marks=needs_py310),
],
)
diff --git a/tests/test_tutorial/test_dataclasses/test_tutorial003.py b/tests/test_tutorial/test_dataclasses/test_tutorial003.py
index e023271bc3..5a35e5c4a8 100644
--- a/tests/test_tutorial/test_dataclasses/test_tutorial003.py
+++ b/tests/test_tutorial/test_dataclasses/test_tutorial003.py
@@ -10,7 +10,6 @@ from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial003_py39"),
pytest.param("tutorial003_py310", marks=needs_py310),
],
)
diff --git a/tests/test_tutorial/test_debugging/test_tutorial001.py b/tests/test_tutorial/test_debugging/test_tutorial001.py
index 1a0ca6cad7..fbf2bfa025 100644
--- a/tests/test_tutorial/test_debugging/test_tutorial001.py
+++ b/tests/test_tutorial/test_debugging/test_tutorial001.py
@@ -7,7 +7,7 @@ import pytest
from fastapi.testclient import TestClient
from inline_snapshot import snapshot
-MOD_NAME = "docs_src.debugging.tutorial001_py39"
+MOD_NAME = "docs_src.debugging.tutorial001_py310"
@pytest.fixture(name="client")
diff --git a/tests/test_tutorial/test_dependencies/test_tutorial001_tutorial001_02.py b/tests/test_tutorial/test_dependencies/test_tutorial001_tutorial001_02.py
index 74f4a8f3a2..11e732e6de 100644
--- a/tests/test_tutorial/test_dependencies/test_tutorial001_tutorial001_02.py
+++ b/tests/test_tutorial/test_dependencies/test_tutorial001_tutorial001_02.py
@@ -10,11 +10,8 @@ from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial001_py39"),
pytest.param("tutorial001_py310", marks=needs_py310),
- pytest.param("tutorial001_an_py39"),
pytest.param("tutorial001_an_py310", marks=needs_py310),
- pytest.param("tutorial001_02_an_py39"),
pytest.param("tutorial001_02_an_py310", marks=needs_py310),
],
)
diff --git a/tests/test_tutorial/test_dependencies/test_tutorial002_tutorial003_tutorial004.py b/tests/test_tutorial/test_dependencies/test_tutorial002_tutorial003_tutorial004.py
index 6e1cea5a08..a9ddf8a521 100644
--- a/tests/test_tutorial/test_dependencies/test_tutorial002_tutorial003_tutorial004.py
+++ b/tests/test_tutorial/test_dependencies/test_tutorial002_tutorial003_tutorial004.py
@@ -10,17 +10,11 @@ from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial002_py39"),
pytest.param("tutorial002_py310", marks=needs_py310),
- pytest.param("tutorial002_an_py39"),
pytest.param("tutorial002_an_py310", marks=needs_py310),
- pytest.param("tutorial003_py39"),
pytest.param("tutorial003_py310", marks=needs_py310),
- pytest.param("tutorial003_an_py39"),
pytest.param("tutorial003_an_py310", marks=needs_py310),
- pytest.param("tutorial004_py39"),
pytest.param("tutorial004_py310", marks=needs_py310),
- pytest.param("tutorial004_an_py39"),
pytest.param("tutorial004_an_py310", marks=needs_py310),
],
)
diff --git a/tests/test_tutorial/test_dependencies/test_tutorial005.py b/tests/test_tutorial/test_dependencies/test_tutorial005.py
index 31054744a1..3cd083b351 100644
--- a/tests/test_tutorial/test_dependencies/test_tutorial005.py
+++ b/tests/test_tutorial/test_dependencies/test_tutorial005.py
@@ -10,9 +10,7 @@ from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial005_py39"),
pytest.param("tutorial005_py310", marks=needs_py310),
- pytest.param("tutorial005_an_py39"),
pytest.param("tutorial005_an_py310", marks=needs_py310),
],
)
diff --git a/tests/test_tutorial/test_dependencies/test_tutorial006.py b/tests/test_tutorial/test_dependencies/test_tutorial006.py
index 8d6cfa2d65..f6e6f83685 100644
--- a/tests/test_tutorial/test_dependencies/test_tutorial006.py
+++ b/tests/test_tutorial/test_dependencies/test_tutorial006.py
@@ -8,8 +8,8 @@ from inline_snapshot import snapshot
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial006_py39"),
- pytest.param("tutorial006_an_py39"),
+ pytest.param("tutorial006_py310"),
+ pytest.param("tutorial006_an_py310"),
],
)
def get_client(request: pytest.FixtureRequest):
diff --git a/tests/test_tutorial/test_dependencies/test_tutorial007.py b/tests/test_tutorial/test_dependencies/test_tutorial007.py
index 3e188abcf6..c984856117 100644
--- a/tests/test_tutorial/test_dependencies/test_tutorial007.py
+++ b/tests/test_tutorial/test_dependencies/test_tutorial007.py
@@ -2,7 +2,7 @@ import asyncio
from contextlib import asynccontextmanager
from unittest.mock import Mock, patch
-from docs_src.dependencies.tutorial007_py39 import get_db
+from docs_src.dependencies.tutorial007_py310 import get_db
def test_get_db(): # Just for coverage
@@ -14,7 +14,7 @@ def test_get_db(): # Just for coverage
dbsession_moock = Mock()
with patch(
- "docs_src.dependencies.tutorial007_py39.DBSession",
+ "docs_src.dependencies.tutorial007_py310.DBSession",
return_value=dbsession_moock,
create=True,
):
diff --git a/tests/test_tutorial/test_dependencies/test_tutorial008.py b/tests/test_tutorial/test_dependencies/test_tutorial008.py
index 5a2d226bff..e23ac0ac51 100644
--- a/tests/test_tutorial/test_dependencies/test_tutorial008.py
+++ b/tests/test_tutorial/test_dependencies/test_tutorial008.py
@@ -12,9 +12,9 @@ from fastapi.testclient import TestClient
@pytest.fixture(
name="module",
params=[
- "tutorial008_py39",
+ "tutorial008_py310",
pytest.param(
- "tutorial008_an_py39",
+ "tutorial008_an_py310",
marks=pytest.mark.xfail(
sys.version_info < (3, 14),
reason="Fails with `NameError: name 'DepA' is not defined`",
diff --git a/tests/test_tutorial/test_dependencies/test_tutorial008b.py b/tests/test_tutorial/test_dependencies/test_tutorial008b.py
index 91e00b3705..d2493d0cce 100644
--- a/tests/test_tutorial/test_dependencies/test_tutorial008b.py
+++ b/tests/test_tutorial/test_dependencies/test_tutorial008b.py
@@ -7,8 +7,8 @@ from fastapi.testclient import TestClient
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial008b_py39"),
- pytest.param("tutorial008b_an_py39"),
+ pytest.param("tutorial008b_py310"),
+ pytest.param("tutorial008b_an_py310"),
],
)
def get_client(request: pytest.FixtureRequest):
diff --git a/tests/test_tutorial/test_dependencies/test_tutorial008c.py b/tests/test_tutorial/test_dependencies/test_tutorial008c.py
index aede6f8d25..b7713c73b5 100644
--- a/tests/test_tutorial/test_dependencies/test_tutorial008c.py
+++ b/tests/test_tutorial/test_dependencies/test_tutorial008c.py
@@ -9,8 +9,8 @@ from fastapi.testclient import TestClient
@pytest.fixture(
name="mod",
params=[
- pytest.param("tutorial008c_py39"),
- pytest.param("tutorial008c_an_py39"),
+ pytest.param("tutorial008c_py310"),
+ pytest.param("tutorial008c_an_py310"),
],
)
def get_mod(request: pytest.FixtureRequest):
diff --git a/tests/test_tutorial/test_dependencies/test_tutorial008d.py b/tests/test_tutorial/test_dependencies/test_tutorial008d.py
index 5477f8b953..e831c055ec 100644
--- a/tests/test_tutorial/test_dependencies/test_tutorial008d.py
+++ b/tests/test_tutorial/test_dependencies/test_tutorial008d.py
@@ -8,8 +8,8 @@ from fastapi.testclient import TestClient
@pytest.fixture(
name="mod",
params=[
- pytest.param("tutorial008d_py39"),
- pytest.param("tutorial008d_an_py39"),
+ pytest.param("tutorial008d_py310"),
+ pytest.param("tutorial008d_an_py310"),
],
)
def get_mod(request: pytest.FixtureRequest):
diff --git a/tests/test_tutorial/test_dependencies/test_tutorial008e.py b/tests/test_tutorial/test_dependencies/test_tutorial008e.py
index c433157ea1..18eba9f775 100644
--- a/tests/test_tutorial/test_dependencies/test_tutorial008e.py
+++ b/tests/test_tutorial/test_dependencies/test_tutorial008e.py
@@ -7,8 +7,8 @@ from fastapi.testclient import TestClient
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial008e_py39"),
- pytest.param("tutorial008e_an_py39"),
+ pytest.param("tutorial008e_py310"),
+ pytest.param("tutorial008e_an_py310"),
],
)
def get_client(request: pytest.FixtureRequest):
diff --git a/tests/test_tutorial/test_dependencies/test_tutorial010.py b/tests/test_tutorial/test_dependencies/test_tutorial010.py
index 6d3815ada2..954d09f20d 100644
--- a/tests/test_tutorial/test_dependencies/test_tutorial010.py
+++ b/tests/test_tutorial/test_dependencies/test_tutorial010.py
@@ -4,7 +4,7 @@ from unittest.mock import Mock, patch
from fastapi import Depends, FastAPI
from fastapi.testclient import TestClient
-from docs_src.dependencies.tutorial010_py39 import get_db
+from docs_src.dependencies.tutorial010_py310 import get_db
def test_get_db():
@@ -19,7 +19,7 @@ def test_get_db():
dbsession_mock = Mock()
with patch(
- "docs_src.dependencies.tutorial010_py39.DBSession",
+ "docs_src.dependencies.tutorial010_py310.DBSession",
return_value=dbsession_mock,
create=True,
):
diff --git a/tests/test_tutorial/test_dependencies/test_tutorial011.py b/tests/test_tutorial/test_dependencies/test_tutorial011.py
index 383422a7e6..16167fd2e0 100644
--- a/tests/test_tutorial/test_dependencies/test_tutorial011.py
+++ b/tests/test_tutorial/test_dependencies/test_tutorial011.py
@@ -8,8 +8,8 @@ from inline_snapshot import snapshot
@pytest.fixture(
name="client",
params=[
- "tutorial011_py39",
- pytest.param("tutorial011_an_py39"),
+ "tutorial011_py310",
+ pytest.param("tutorial011_an_py310"),
],
)
def get_client(request: pytest.FixtureRequest):
diff --git a/tests/test_tutorial/test_dependencies/test_tutorial012.py b/tests/test_tutorial/test_dependencies/test_tutorial012.py
index a156889245..e0148e0521 100644
--- a/tests/test_tutorial/test_dependencies/test_tutorial012.py
+++ b/tests/test_tutorial/test_dependencies/test_tutorial012.py
@@ -8,8 +8,8 @@ from inline_snapshot import snapshot
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial012_py39"),
- pytest.param("tutorial012_an_py39"),
+ pytest.param("tutorial012_py310"),
+ pytest.param("tutorial012_an_py310"),
],
)
def get_client(request: pytest.FixtureRequest):
diff --git a/tests/test_tutorial/test_encoder/test_tutorial001.py b/tests/test_tutorial/test_encoder/test_tutorial001.py
index a3d6723336..e8c1f3c73f 100644
--- a/tests/test_tutorial/test_encoder/test_tutorial001.py
+++ b/tests/test_tutorial/test_encoder/test_tutorial001.py
@@ -11,7 +11,6 @@ from ...utils import needs_py310
@pytest.fixture(
name="mod",
params=[
- pytest.param("tutorial001_py39"),
pytest.param("tutorial001_py310", marks=needs_py310),
],
)
diff --git a/tests/test_tutorial/test_events/test_tutorial001.py b/tests/test_tutorial/test_events/test_tutorial001.py
index 63215c00db..e392cdcc90 100644
--- a/tests/test_tutorial/test_events/test_tutorial001.py
+++ b/tests/test_tutorial/test_events/test_tutorial001.py
@@ -7,7 +7,7 @@ from inline_snapshot import snapshot
@pytest.fixture(name="app", scope="module")
def get_app():
with pytest.warns(DeprecationWarning):
- from docs_src.events.tutorial001_py39 import app
+ from docs_src.events.tutorial001_py310 import app
yield app
diff --git a/tests/test_tutorial/test_events/test_tutorial002.py b/tests/test_tutorial/test_events/test_tutorial002.py
index f98d8921f7..47af7a9527 100644
--- a/tests/test_tutorial/test_events/test_tutorial002.py
+++ b/tests/test_tutorial/test_events/test_tutorial002.py
@@ -7,7 +7,7 @@ from inline_snapshot import snapshot
@pytest.fixture(name="app", scope="module")
def get_app():
with pytest.warns(DeprecationWarning):
- from docs_src.events.tutorial002_py39 import app
+ from docs_src.events.tutorial002_py310 import app
yield app
diff --git a/tests/test_tutorial/test_events/test_tutorial003.py b/tests/test_tutorial/test_events/test_tutorial003.py
index 4fc848e116..3da0b2ca52 100644
--- a/tests/test_tutorial/test_events/test_tutorial003.py
+++ b/tests/test_tutorial/test_events/test_tutorial003.py
@@ -1,7 +1,7 @@
from fastapi.testclient import TestClient
from inline_snapshot import snapshot
-from docs_src.events.tutorial003_py39 import (
+from docs_src.events.tutorial003_py310 import (
app,
fake_answer_to_everything_ml_model,
ml_models,
diff --git a/tests/test_tutorial/test_extending_openapi/test_tutorial001.py b/tests/test_tutorial/test_extending_openapi/test_tutorial001.py
index bc10c888c1..06c56565f6 100644
--- a/tests/test_tutorial/test_extending_openapi/test_tutorial001.py
+++ b/tests/test_tutorial/test_extending_openapi/test_tutorial001.py
@@ -1,7 +1,7 @@
from fastapi.testclient import TestClient
from inline_snapshot import snapshot
-from docs_src.extending_openapi.tutorial001_py39 import app
+from docs_src.extending_openapi.tutorial001_py310 import app
client = TestClient(app)
diff --git a/tests/test_tutorial/test_extra_data_types/test_tutorial001.py b/tests/test_tutorial/test_extra_data_types/test_tutorial001.py
index 28fe68f285..2e7f0e522e 100644
--- a/tests/test_tutorial/test_extra_data_types/test_tutorial001.py
+++ b/tests/test_tutorial/test_extra_data_types/test_tutorial001.py
@@ -10,9 +10,7 @@ from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial001_py39"),
pytest.param("tutorial001_py310", marks=needs_py310),
- pytest.param("tutorial001_an_py39"),
pytest.param("tutorial001_an_py310", marks=needs_py310),
],
)
diff --git a/tests/test_tutorial/test_extra_models/test_tutorial001_tutorial002.py b/tests/test_tutorial/test_extra_models/test_tutorial001_tutorial002.py
index 4248878b5a..4fcb7ff78b 100644
--- a/tests/test_tutorial/test_extra_models/test_tutorial001_tutorial002.py
+++ b/tests/test_tutorial/test_extra_models/test_tutorial001_tutorial002.py
@@ -11,9 +11,7 @@ from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial001_py39"),
pytest.param("tutorial001_py310", marks=needs_py310),
- pytest.param("tutorial002_py39"),
pytest.param("tutorial002_py310", marks=needs_py310),
],
)
diff --git a/tests/test_tutorial/test_extra_models/test_tutorial003.py b/tests/test_tutorial/test_extra_models/test_tutorial003.py
index 38e8741582..2a2cf8afae 100644
--- a/tests/test_tutorial/test_extra_models/test_tutorial003.py
+++ b/tests/test_tutorial/test_extra_models/test_tutorial003.py
@@ -10,7 +10,6 @@ from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial003_py39"),
pytest.param("tutorial003_py310", marks=needs_py310),
],
)
diff --git a/tests/test_tutorial/test_extra_models/test_tutorial004.py b/tests/test_tutorial/test_extra_models/test_tutorial004.py
index c64371e3be..3ded20959a 100644
--- a/tests/test_tutorial/test_extra_models/test_tutorial004.py
+++ b/tests/test_tutorial/test_extra_models/test_tutorial004.py
@@ -8,7 +8,7 @@ from inline_snapshot import snapshot
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial004_py39"),
+ pytest.param("tutorial004_py310"),
],
)
def get_client(request: pytest.FixtureRequest):
diff --git a/tests/test_tutorial/test_extra_models/test_tutorial005.py b/tests/test_tutorial/test_extra_models/test_tutorial005.py
index 43b8bae8e5..265b768326 100644
--- a/tests/test_tutorial/test_extra_models/test_tutorial005.py
+++ b/tests/test_tutorial/test_extra_models/test_tutorial005.py
@@ -8,7 +8,7 @@ from inline_snapshot import snapshot
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial005_py39"),
+ pytest.param("tutorial005_py310"),
],
)
def get_client(request: pytest.FixtureRequest):
diff --git a/tests/test_tutorial/test_first_steps/test_tutorial001_tutorial002_tutorial003.py b/tests/test_tutorial/test_first_steps/test_tutorial001_tutorial002_tutorial003.py
index 5457ad132a..30eab21e93 100644
--- a/tests/test_tutorial/test_first_steps/test_tutorial001_tutorial002_tutorial003.py
+++ b/tests/test_tutorial/test_first_steps/test_tutorial001_tutorial002_tutorial003.py
@@ -8,8 +8,8 @@ from inline_snapshot import snapshot
@pytest.fixture(
name="client",
params=[
- "tutorial001_py39",
- "tutorial003_py39",
+ "tutorial001_py310",
+ "tutorial003_py310",
],
)
def get_client(request: pytest.FixtureRequest):
diff --git a/tests/test_tutorial/test_generate_clients/test_tutorial001.py b/tests/test_tutorial/test_generate_clients/test_tutorial001.py
index 62799d259b..40ed3eeea2 100644
--- a/tests/test_tutorial/test_generate_clients/test_tutorial001.py
+++ b/tests/test_tutorial/test_generate_clients/test_tutorial001.py
@@ -8,7 +8,7 @@ from inline_snapshot import snapshot
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial001_py39"),
+ pytest.param("tutorial001_py310"),
],
)
def get_client(request: pytest.FixtureRequest):
diff --git a/tests/test_tutorial/test_generate_clients/test_tutorial002.py b/tests/test_tutorial/test_generate_clients/test_tutorial002.py
index f64f5f8666..6557b8c275 100644
--- a/tests/test_tutorial/test_generate_clients/test_tutorial002.py
+++ b/tests/test_tutorial/test_generate_clients/test_tutorial002.py
@@ -1,7 +1,7 @@
from fastapi.testclient import TestClient
from inline_snapshot import snapshot
-from docs_src.generate_clients.tutorial002_py39 import app
+from docs_src.generate_clients.tutorial002_py310 import app
client = TestClient(app)
diff --git a/tests/test_tutorial/test_generate_clients/test_tutorial003.py b/tests/test_tutorial/test_generate_clients/test_tutorial003.py
index 34ede61946..cded241ae1 100644
--- a/tests/test_tutorial/test_generate_clients/test_tutorial003.py
+++ b/tests/test_tutorial/test_generate_clients/test_tutorial003.py
@@ -1,7 +1,7 @@
from fastapi.testclient import TestClient
from inline_snapshot import snapshot
-from docs_src.generate_clients.tutorial003_py39 import app
+from docs_src.generate_clients.tutorial003_py310 import app
client = TestClient(app)
diff --git a/tests/test_tutorial/test_generate_clients/test_tutorial004.py b/tests/test_tutorial/test_generate_clients/test_tutorial004.py
index d04bfbfe87..1d71de869f 100644
--- a/tests/test_tutorial/test_generate_clients/test_tutorial004.py
+++ b/tests/test_tutorial/test_generate_clients/test_tutorial004.py
@@ -5,16 +5,16 @@ from unittest.mock import patch
from inline_snapshot import snapshot
-from docs_src.generate_clients import tutorial003_py39
+from docs_src.generate_clients import tutorial003_py310
def test_remove_tags(tmp_path: pathlib.Path):
tmp_file = tmp_path / "openapi.json"
- openapi_json = tutorial003_py39.app.openapi()
+ openapi_json = tutorial003_py310.app.openapi()
tmp_file.write_text(json.dumps(openapi_json))
with patch("pathlib.Path", return_value=tmp_file):
- importlib.import_module("docs_src.generate_clients.tutorial004_py39")
+ importlib.import_module("docs_src.generate_clients.tutorial004_py310")
modified_openapi = json.loads(tmp_file.read_text())
assert modified_openapi == snapshot(
diff --git a/tests/test_tutorial/test_graphql/test_tutorial001.py b/tests/test_tutorial/test_graphql/test_tutorial001.py
index cc3be6a190..c933470814 100644
--- a/tests/test_tutorial/test_graphql/test_tutorial001.py
+++ b/tests/test_tutorial/test_graphql/test_tutorial001.py
@@ -10,7 +10,7 @@ warnings.filterwarnings(
category=DeprecationWarning,
)
-from docs_src.graphql_.tutorial001_py39 import app # noqa: E402
+from docs_src.graphql_.tutorial001_py310 import app # noqa: E402
@pytest.fixture(name="client")
diff --git a/tests/test_tutorial/test_handling_errors/test_tutorial001.py b/tests/test_tutorial/test_handling_errors/test_tutorial001.py
index 8283cdc73e..001a02a0fd 100644
--- a/tests/test_tutorial/test_handling_errors/test_tutorial001.py
+++ b/tests/test_tutorial/test_handling_errors/test_tutorial001.py
@@ -1,7 +1,7 @@
from fastapi.testclient import TestClient
from inline_snapshot import snapshot
-from docs_src.handling_errors.tutorial001_py39 import app
+from docs_src.handling_errors.tutorial001_py310 import app
client = TestClient(app)
diff --git a/tests/test_tutorial/test_handling_errors/test_tutorial002.py b/tests/test_tutorial/test_handling_errors/test_tutorial002.py
index c437693d3d..0e7321ee7c 100644
--- a/tests/test_tutorial/test_handling_errors/test_tutorial002.py
+++ b/tests/test_tutorial/test_handling_errors/test_tutorial002.py
@@ -1,7 +1,7 @@
from fastapi.testclient import TestClient
from inline_snapshot import snapshot
-from docs_src.handling_errors.tutorial002_py39 import app
+from docs_src.handling_errors.tutorial002_py310 import app
client = TestClient(app)
diff --git a/tests/test_tutorial/test_handling_errors/test_tutorial003.py b/tests/test_tutorial/test_handling_errors/test_tutorial003.py
index 959729e53f..cc11985be1 100644
--- a/tests/test_tutorial/test_handling_errors/test_tutorial003.py
+++ b/tests/test_tutorial/test_handling_errors/test_tutorial003.py
@@ -1,7 +1,7 @@
from fastapi.testclient import TestClient
from inline_snapshot import snapshot
-from docs_src.handling_errors.tutorial003_py39 import app
+from docs_src.handling_errors.tutorial003_py310 import app
client = TestClient(app)
diff --git a/tests/test_tutorial/test_handling_errors/test_tutorial004.py b/tests/test_tutorial/test_handling_errors/test_tutorial004.py
index 16165bb3d3..5471cb0d82 100644
--- a/tests/test_tutorial/test_handling_errors/test_tutorial004.py
+++ b/tests/test_tutorial/test_handling_errors/test_tutorial004.py
@@ -1,7 +1,7 @@
from fastapi.testclient import TestClient
from inline_snapshot import snapshot
-from docs_src.handling_errors.tutorial004_py39 import app
+from docs_src.handling_errors.tutorial004_py310 import app
client = TestClient(app)
diff --git a/tests/test_tutorial/test_handling_errors/test_tutorial005.py b/tests/test_tutorial/test_handling_errors/test_tutorial005.py
index af924a9f76..c04b510c39 100644
--- a/tests/test_tutorial/test_handling_errors/test_tutorial005.py
+++ b/tests/test_tutorial/test_handling_errors/test_tutorial005.py
@@ -1,7 +1,7 @@
from fastapi.testclient import TestClient
from inline_snapshot import snapshot
-from docs_src.handling_errors.tutorial005_py39 import app
+from docs_src.handling_errors.tutorial005_py310 import app
client = TestClient(app)
diff --git a/tests/test_tutorial/test_handling_errors/test_tutorial006.py b/tests/test_tutorial/test_handling_errors/test_tutorial006.py
index 4c069d81e2..666e44f3a8 100644
--- a/tests/test_tutorial/test_handling_errors/test_tutorial006.py
+++ b/tests/test_tutorial/test_handling_errors/test_tutorial006.py
@@ -1,7 +1,7 @@
from fastapi.testclient import TestClient
from inline_snapshot import snapshot
-from docs_src.handling_errors.tutorial006_py39 import app
+from docs_src.handling_errors.tutorial006_py310 import app
client = TestClient(app)
diff --git a/tests/test_tutorial/test_header_param_models/test_tutorial001.py b/tests/test_tutorial/test_header_param_models/test_tutorial001.py
index 2d14c698e0..8391bd1197 100644
--- a/tests/test_tutorial/test_header_param_models/test_tutorial001.py
+++ b/tests/test_tutorial/test_header_param_models/test_tutorial001.py
@@ -10,9 +10,7 @@ from tests.utils import needs_py310
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial001_py39"),
pytest.param("tutorial001_py310", marks=needs_py310),
- pytest.param("tutorial001_an_py39"),
pytest.param("tutorial001_an_py310", marks=needs_py310),
],
)
diff --git a/tests/test_tutorial/test_header_param_models/test_tutorial002.py b/tests/test_tutorial/test_header_param_models/test_tutorial002.py
index 478ac84087..3d66dca08d 100644
--- a/tests/test_tutorial/test_header_param_models/test_tutorial002.py
+++ b/tests/test_tutorial/test_header_param_models/test_tutorial002.py
@@ -10,9 +10,7 @@ from tests.utils import needs_py310
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial002_py39"),
pytest.param("tutorial002_py310", marks=[needs_py310]),
- pytest.param("tutorial002_an_py39"),
pytest.param("tutorial002_an_py310", marks=[needs_py310]),
],
)
diff --git a/tests/test_tutorial/test_header_param_models/test_tutorial003.py b/tests/test_tutorial/test_header_param_models/test_tutorial003.py
index 00636c2b53..7d0da24fd5 100644
--- a/tests/test_tutorial/test_header_param_models/test_tutorial003.py
+++ b/tests/test_tutorial/test_header_param_models/test_tutorial003.py
@@ -10,9 +10,7 @@ from tests.utils import needs_py310
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial003_py39"),
pytest.param("tutorial003_py310", marks=needs_py310),
- pytest.param("tutorial003_an_py39"),
pytest.param("tutorial003_an_py310", marks=needs_py310),
],
)
diff --git a/tests/test_tutorial/test_header_params/test_tutorial001.py b/tests/test_tutorial/test_header_params/test_tutorial001.py
index 2e97a83221..900d35adc5 100644
--- a/tests/test_tutorial/test_header_params/test_tutorial001.py
+++ b/tests/test_tutorial/test_header_params/test_tutorial001.py
@@ -10,9 +10,7 @@ from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial001_py39"),
pytest.param("tutorial001_py310", marks=needs_py310),
- pytest.param("tutorial001_an_py39"),
pytest.param("tutorial001_an_py310", marks=needs_py310),
],
)
diff --git a/tests/test_tutorial/test_header_params/test_tutorial002.py b/tests/test_tutorial/test_header_params/test_tutorial002.py
index ba86c55bf6..c756eae71f 100644
--- a/tests/test_tutorial/test_header_params/test_tutorial002.py
+++ b/tests/test_tutorial/test_header_params/test_tutorial002.py
@@ -10,9 +10,7 @@ from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial002_py39"),
pytest.param("tutorial002_py310", marks=needs_py310),
- pytest.param("tutorial002_an_py39"),
pytest.param("tutorial002_an_py310", marks=needs_py310),
],
)
diff --git a/tests/test_tutorial/test_header_params/test_tutorial003.py b/tests/test_tutorial/test_header_params/test_tutorial003.py
index 30e5133c01..1f71322b69 100644
--- a/tests/test_tutorial/test_header_params/test_tutorial003.py
+++ b/tests/test_tutorial/test_header_params/test_tutorial003.py
@@ -10,9 +10,7 @@ from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial003_py39"),
pytest.param("tutorial003_py310", marks=needs_py310),
- pytest.param("tutorial003_an_py39"),
pytest.param("tutorial003_an_py310", marks=needs_py310),
],
)
diff --git a/tests/test_tutorial/test_metadata/test_tutorial001.py b/tests/test_tutorial/test_metadata/test_tutorial001.py
index ba3c09ce4c..ce0c1643a9 100644
--- a/tests/test_tutorial/test_metadata/test_tutorial001.py
+++ b/tests/test_tutorial/test_metadata/test_tutorial001.py
@@ -1,7 +1,7 @@
from fastapi.testclient import TestClient
from inline_snapshot import snapshot
-from docs_src.metadata.tutorial001_py39 import app
+from docs_src.metadata.tutorial001_py310 import app
client = TestClient(app)
diff --git a/tests/test_tutorial/test_metadata/test_tutorial001_1.py b/tests/test_tutorial/test_metadata/test_tutorial001_1.py
index 9339549731..ba9ba9dcbc 100644
--- a/tests/test_tutorial/test_metadata/test_tutorial001_1.py
+++ b/tests/test_tutorial/test_metadata/test_tutorial001_1.py
@@ -1,7 +1,7 @@
from fastapi.testclient import TestClient
from inline_snapshot import snapshot
-from docs_src.metadata.tutorial001_1_py39 import app
+from docs_src.metadata.tutorial001_1_py310 import app
client = TestClient(app)
diff --git a/tests/test_tutorial/test_metadata/test_tutorial002.py b/tests/test_tutorial/test_metadata/test_tutorial002.py
index 5a252475eb..979a6a7b84 100644
--- a/tests/test_tutorial/test_metadata/test_tutorial002.py
+++ b/tests/test_tutorial/test_metadata/test_tutorial002.py
@@ -1,7 +1,7 @@
from fastapi.testclient import TestClient
from inline_snapshot import snapshot
-from docs_src.metadata.tutorial002_py39 import app
+from docs_src.metadata.tutorial002_py310 import app
client = TestClient(app)
diff --git a/tests/test_tutorial/test_metadata/test_tutorial003.py b/tests/test_tutorial/test_metadata/test_tutorial003.py
index 778781e665..ee29780288 100644
--- a/tests/test_tutorial/test_metadata/test_tutorial003.py
+++ b/tests/test_tutorial/test_metadata/test_tutorial003.py
@@ -1,7 +1,7 @@
from fastapi.testclient import TestClient
from inline_snapshot import snapshot
-from docs_src.metadata.tutorial003_py39 import app
+from docs_src.metadata.tutorial003_py310 import app
client = TestClient(app)
diff --git a/tests/test_tutorial/test_metadata/test_tutorial004.py b/tests/test_tutorial/test_metadata/test_tutorial004.py
index 5c309a830e..ef0533d506 100644
--- a/tests/test_tutorial/test_metadata/test_tutorial004.py
+++ b/tests/test_tutorial/test_metadata/test_tutorial004.py
@@ -1,7 +1,7 @@
from fastapi.testclient import TestClient
from inline_snapshot import snapshot
-from docs_src.metadata.tutorial004_py39 import app
+from docs_src.metadata.tutorial004_py310 import app
client = TestClient(app)
diff --git a/tests/test_tutorial/test_middleware/test_tutorial001.py b/tests/test_tutorial/test_middleware/test_tutorial001.py
index 18047f3430..1fa1e5a507 100644
--- a/tests/test_tutorial/test_middleware/test_tutorial001.py
+++ b/tests/test_tutorial/test_middleware/test_tutorial001.py
@@ -1,7 +1,7 @@
from fastapi.testclient import TestClient
from inline_snapshot import snapshot
-from docs_src.middleware.tutorial001_py39 import app
+from docs_src.middleware.tutorial001_py310 import app
client = TestClient(app)
diff --git a/tests/test_tutorial/test_openapi_callbacks/test_tutorial001.py b/tests/test_tutorial/test_openapi_callbacks/test_tutorial001.py
index 1e937d0c90..62374ef270 100644
--- a/tests/test_tutorial/test_openapi_callbacks/test_tutorial001.py
+++ b/tests/test_tutorial/test_openapi_callbacks/test_tutorial001.py
@@ -11,7 +11,6 @@ from tests.utils import needs_py310
@pytest.fixture(
name="mod",
params=[
- pytest.param("tutorial001_py39"),
pytest.param("tutorial001_py310", marks=needs_py310),
],
)
diff --git a/tests/test_tutorial/test_openapi_webhooks/test_tutorial001.py b/tests/test_tutorial/test_openapi_webhooks/test_tutorial001.py
index 0482c94bf9..696a2bed53 100644
--- a/tests/test_tutorial/test_openapi_webhooks/test_tutorial001.py
+++ b/tests/test_tutorial/test_openapi_webhooks/test_tutorial001.py
@@ -1,7 +1,7 @@
from fastapi.testclient import TestClient
from inline_snapshot import snapshot
-from docs_src.openapi_webhooks.tutorial001_py39 import app
+from docs_src.openapi_webhooks.tutorial001_py310 import app
client = TestClient(app)
diff --git a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial001.py b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial001.py
index 3a4f648241..ecda8a3153 100644
--- a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial001.py
+++ b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial001.py
@@ -1,7 +1,7 @@
from fastapi.testclient import TestClient
from inline_snapshot import snapshot
-from docs_src.path_operation_advanced_configuration.tutorial001_py39 import app
+from docs_src.path_operation_advanced_configuration.tutorial001_py310 import app
client = TestClient(app)
diff --git a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial002.py b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial002.py
index c26c36030b..c5067e233a 100644
--- a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial002.py
+++ b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial002.py
@@ -1,7 +1,7 @@
from fastapi.testclient import TestClient
from inline_snapshot import snapshot
-from docs_src.path_operation_advanced_configuration.tutorial002_py39 import app
+from docs_src.path_operation_advanced_configuration.tutorial002_py310 import app
client = TestClient(app)
diff --git a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial003.py b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial003.py
index f060647b29..36fe21678f 100644
--- a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial003.py
+++ b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial003.py
@@ -1,7 +1,7 @@
from fastapi.testclient import TestClient
from inline_snapshot import snapshot
-from docs_src.path_operation_advanced_configuration.tutorial003_py39 import app
+from docs_src.path_operation_advanced_configuration.tutorial003_py310 import app
client = TestClient(app)
diff --git a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial004.py b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial004.py
index bf79345449..894cd9749b 100644
--- a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial004.py
+++ b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial004.py
@@ -10,7 +10,6 @@ from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial004_py39"),
pytest.param("tutorial004_py310", marks=needs_py310),
],
)
diff --git a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial005.py b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial005.py
index 779e54f9e7..f129ec6f4a 100644
--- a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial005.py
+++ b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial005.py
@@ -1,7 +1,7 @@
from fastapi.testclient import TestClient
from inline_snapshot import snapshot
-from docs_src.path_operation_advanced_configuration.tutorial005_py39 import app
+from docs_src.path_operation_advanced_configuration.tutorial005_py310 import app
client = TestClient(app)
diff --git a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial006.py b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial006.py
index d63b5f912d..f3bf2b5bfd 100644
--- a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial006.py
+++ b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial006.py
@@ -1,7 +1,7 @@
from fastapi.testclient import TestClient
from inline_snapshot import snapshot
-from docs_src.path_operation_advanced_configuration.tutorial006_py39 import app
+from docs_src.path_operation_advanced_configuration.tutorial006_py310 import app
client = TestClient(app)
diff --git a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial007.py b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial007.py
index ec0c91bdad..ad06e6c05f 100644
--- a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial007.py
+++ b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial007.py
@@ -8,7 +8,7 @@ from inline_snapshot import snapshot
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial007_py39"),
+ pytest.param("tutorial007_py310"),
],
)
def get_client(request: pytest.FixtureRequest):
diff --git a/tests/test_tutorial/test_path_operation_configurations/test_tutorial001.py b/tests/test_tutorial/test_path_operation_configurations/test_tutorial001.py
index 500cb057c5..1b81b6f863 100644
--- a/tests/test_tutorial/test_path_operation_configurations/test_tutorial001.py
+++ b/tests/test_tutorial/test_path_operation_configurations/test_tutorial001.py
@@ -11,7 +11,6 @@ from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial001_py39"),
pytest.param("tutorial001_py310", marks=needs_py310),
],
)
diff --git a/tests/test_tutorial/test_path_operation_configurations/test_tutorial002.py b/tests/test_tutorial/test_path_operation_configurations/test_tutorial002.py
index 1cc560cb9a..675f3b1aea 100644
--- a/tests/test_tutorial/test_path_operation_configurations/test_tutorial002.py
+++ b/tests/test_tutorial/test_path_operation_configurations/test_tutorial002.py
@@ -11,7 +11,6 @@ from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial002_py39"),
pytest.param("tutorial002_py310", marks=needs_py310),
],
)
diff --git a/tests/test_tutorial/test_path_operation_configurations/test_tutorial002b.py b/tests/test_tutorial/test_path_operation_configurations/test_tutorial002b.py
index 98319645c2..f9a5ff7601 100644
--- a/tests/test_tutorial/test_path_operation_configurations/test_tutorial002b.py
+++ b/tests/test_tutorial/test_path_operation_configurations/test_tutorial002b.py
@@ -1,7 +1,7 @@
from fastapi.testclient import TestClient
from inline_snapshot import snapshot
-from docs_src.path_operation_configuration.tutorial002b_py39 import app
+from docs_src.path_operation_configuration.tutorial002b_py310 import app
client = TestClient(app)
diff --git a/tests/test_tutorial/test_path_operation_configurations/test_tutorial003_tutorial004.py b/tests/test_tutorial/test_path_operation_configurations/test_tutorial003_tutorial004.py
index c13a3c38c8..6d1afecc80 100644
--- a/tests/test_tutorial/test_path_operation_configurations/test_tutorial003_tutorial004.py
+++ b/tests/test_tutorial/test_path_operation_configurations/test_tutorial003_tutorial004.py
@@ -25,9 +25,7 @@ DESCRIPTIONS = {
@pytest.fixture(
name="mod_name",
params=[
- pytest.param("tutorial003_py39"),
pytest.param("tutorial003_py310", marks=needs_py310),
- pytest.param("tutorial004_py39"),
pytest.param("tutorial004_py310", marks=needs_py310),
],
)
diff --git a/tests/test_tutorial/test_path_operation_configurations/test_tutorial005.py b/tests/test_tutorial/test_path_operation_configurations/test_tutorial005.py
index 07152755f5..b186c0a684 100644
--- a/tests/test_tutorial/test_path_operation_configurations/test_tutorial005.py
+++ b/tests/test_tutorial/test_path_operation_configurations/test_tutorial005.py
@@ -10,7 +10,6 @@ from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial005_py39"),
pytest.param("tutorial005_py310", marks=needs_py310),
],
)
diff --git a/tests/test_tutorial/test_path_operation_configurations/test_tutorial006.py b/tests/test_tutorial/test_path_operation_configurations/test_tutorial006.py
index 5f56ab929e..27a93f563f 100644
--- a/tests/test_tutorial/test_path_operation_configurations/test_tutorial006.py
+++ b/tests/test_tutorial/test_path_operation_configurations/test_tutorial006.py
@@ -2,7 +2,7 @@ import pytest
from fastapi.testclient import TestClient
from inline_snapshot import snapshot
-from docs_src.path_operation_configuration.tutorial006_py39 import app
+from docs_src.path_operation_configuration.tutorial006_py310 import app
client = TestClient(app)
diff --git a/tests/test_tutorial/test_path_params/test_tutorial001.py b/tests/test_tutorial/test_path_params/test_tutorial001.py
index ec598832b0..75c47c8553 100644
--- a/tests/test_tutorial/test_path_params/test_tutorial001.py
+++ b/tests/test_tutorial/test_path_params/test_tutorial001.py
@@ -2,7 +2,7 @@ import pytest
from fastapi.testclient import TestClient
from inline_snapshot import snapshot
-from docs_src.path_params.tutorial001_py39 import app
+from docs_src.path_params.tutorial001_py310 import app
client = TestClient(app)
diff --git a/tests/test_tutorial/test_path_params/test_tutorial002.py b/tests/test_tutorial/test_path_params/test_tutorial002.py
index 8384ec8eff..416c705585 100644
--- a/tests/test_tutorial/test_path_params/test_tutorial002.py
+++ b/tests/test_tutorial/test_path_params/test_tutorial002.py
@@ -1,7 +1,7 @@
from fastapi.testclient import TestClient
from inline_snapshot import snapshot
-from docs_src.path_params.tutorial002_py39 import app
+from docs_src.path_params.tutorial002_py310 import app
client = TestClient(app)
diff --git a/tests/test_tutorial/test_path_params/test_tutorial003.py b/tests/test_tutorial/test_path_params/test_tutorial003.py
index 432ccde49d..2c07ebbc83 100644
--- a/tests/test_tutorial/test_path_params/test_tutorial003.py
+++ b/tests/test_tutorial/test_path_params/test_tutorial003.py
@@ -2,7 +2,7 @@ import pytest
from fastapi.testclient import TestClient
from inline_snapshot import snapshot
-from docs_src.path_params.tutorial003_py39 import app
+from docs_src.path_params.tutorial003_py310 import app
client = TestClient(app)
diff --git a/tests/test_tutorial/test_path_params/test_tutorial003b.py b/tests/test_tutorial/test_path_params/test_tutorial003b.py
index 1cf39eca9a..debf985033 100644
--- a/tests/test_tutorial/test_path_params/test_tutorial003b.py
+++ b/tests/test_tutorial/test_path_params/test_tutorial003b.py
@@ -3,7 +3,7 @@ import asyncio
from fastapi.testclient import TestClient
from inline_snapshot import snapshot
-from docs_src.path_params.tutorial003b_py39 import app, read_users2
+from docs_src.path_params.tutorial003b_py310 import app, read_users2
client = TestClient(app)
diff --git a/tests/test_tutorial/test_path_params/test_tutorial004.py b/tests/test_tutorial/test_path_params/test_tutorial004.py
index b691e821df..2f2a72e64e 100644
--- a/tests/test_tutorial/test_path_params/test_tutorial004.py
+++ b/tests/test_tutorial/test_path_params/test_tutorial004.py
@@ -1,7 +1,7 @@
from fastapi.testclient import TestClient
from inline_snapshot import snapshot
-from docs_src.path_params.tutorial004_py39 import app
+from docs_src.path_params.tutorial004_py310 import app
client = TestClient(app)
diff --git a/tests/test_tutorial/test_path_params/test_tutorial005.py b/tests/test_tutorial/test_path_params/test_tutorial005.py
index c60fee3f0c..bf54b59a91 100644
--- a/tests/test_tutorial/test_path_params/test_tutorial005.py
+++ b/tests/test_tutorial/test_path_params/test_tutorial005.py
@@ -1,7 +1,7 @@
from fastapi.testclient import TestClient
from inline_snapshot import snapshot
-from docs_src.path_params.tutorial005_py39 import app
+from docs_src.path_params.tutorial005_py310 import app
client = TestClient(app)
diff --git a/tests/test_tutorial/test_path_params_numeric_validations/test_tutorial001.py b/tests/test_tutorial/test_path_params_numeric_validations/test_tutorial001.py
index b43de70325..868b0ea786 100644
--- a/tests/test_tutorial/test_path_params_numeric_validations/test_tutorial001.py
+++ b/tests/test_tutorial/test_path_params_numeric_validations/test_tutorial001.py
@@ -10,9 +10,7 @@ from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial001_py39"),
pytest.param("tutorial001_py310", marks=needs_py310),
- pytest.param("tutorial001_an_py39"),
pytest.param("tutorial001_an_py310", marks=needs_py310),
],
)
diff --git a/tests/test_tutorial/test_path_params_numeric_validations/test_tutorial002_tutorial003.py b/tests/test_tutorial/test_path_params_numeric_validations/test_tutorial002_tutorial003.py
index 1bb2a3ea8e..55d5b418cd 100644
--- a/tests/test_tutorial/test_path_params_numeric_validations/test_tutorial002_tutorial003.py
+++ b/tests/test_tutorial/test_path_params_numeric_validations/test_tutorial002_tutorial003.py
@@ -8,10 +8,10 @@ from inline_snapshot import snapshot
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial002_py39"),
- pytest.param("tutorial002_an_py39"),
- pytest.param("tutorial003_py39"),
- pytest.param("tutorial003_an_py39"),
+ pytest.param("tutorial002_py310"),
+ pytest.param("tutorial002_an_py310"),
+ pytest.param("tutorial003_py310"),
+ pytest.param("tutorial003_an_py310"),
],
)
def get_client(request: pytest.FixtureRequest) -> TestClient:
diff --git a/tests/test_tutorial/test_path_params_numeric_validations/test_tutorial004.py b/tests/test_tutorial/test_path_params_numeric_validations/test_tutorial004.py
index 37c16d2954..7b1272fa10 100644
--- a/tests/test_tutorial/test_path_params_numeric_validations/test_tutorial004.py
+++ b/tests/test_tutorial/test_path_params_numeric_validations/test_tutorial004.py
@@ -8,8 +8,8 @@ from inline_snapshot import snapshot
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial004_py39"),
- pytest.param("tutorial004_an_py39"),
+ pytest.param("tutorial004_py310"),
+ pytest.param("tutorial004_an_py310"),
],
)
def get_client(request: pytest.FixtureRequest) -> TestClient:
diff --git a/tests/test_tutorial/test_path_params_numeric_validations/test_tutorial005.py b/tests/test_tutorial/test_path_params_numeric_validations/test_tutorial005.py
index 0afc9dcbc9..d2c9b6077d 100644
--- a/tests/test_tutorial/test_path_params_numeric_validations/test_tutorial005.py
+++ b/tests/test_tutorial/test_path_params_numeric_validations/test_tutorial005.py
@@ -8,8 +8,8 @@ from inline_snapshot import snapshot
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial005_py39"),
- pytest.param("tutorial005_an_py39"),
+ pytest.param("tutorial005_py310"),
+ pytest.param("tutorial005_an_py310"),
],
)
def get_client(request: pytest.FixtureRequest) -> TestClient:
diff --git a/tests/test_tutorial/test_path_params_numeric_validations/test_tutorial006.py b/tests/test_tutorial/test_path_params_numeric_validations/test_tutorial006.py
index e0a9694c12..9fb1f8b3b5 100644
--- a/tests/test_tutorial/test_path_params_numeric_validations/test_tutorial006.py
+++ b/tests/test_tutorial/test_path_params_numeric_validations/test_tutorial006.py
@@ -8,8 +8,8 @@ from inline_snapshot import snapshot
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial006_py39"),
- pytest.param("tutorial006_an_py39"),
+ pytest.param("tutorial006_py310"),
+ pytest.param("tutorial006_an_py310"),
],
)
def get_client(request: pytest.FixtureRequest) -> TestClient:
diff --git a/tests/test_tutorial/test_python_types/test_tutorial001_tutorial002.py b/tests/test_tutorial/test_python_types/test_tutorial001_tutorial002.py
index ccb0968576..d7bf599fe5 100644
--- a/tests/test_tutorial/test_python_types/test_tutorial001_tutorial002.py
+++ b/tests/test_tutorial/test_python_types/test_tutorial001_tutorial002.py
@@ -7,8 +7,8 @@ import pytest
@pytest.mark.parametrize(
"module_name",
[
- "tutorial001_py39",
- "tutorial002_py39",
+ "tutorial001_py310",
+ "tutorial002_py310",
],
)
def test_run_module(module_name: str):
diff --git a/tests/test_tutorial/test_python_types/test_tutorial003.py b/tests/test_tutorial/test_python_types/test_tutorial003.py
index 34d2649171..20b1e7101d 100644
--- a/tests/test_tutorial/test_python_types/test_tutorial003.py
+++ b/tests/test_tutorial/test_python_types/test_tutorial003.py
@@ -1,6 +1,6 @@
import pytest
-from docs_src.python_types.tutorial003_py39 import get_name_with_age
+from docs_src.python_types.tutorial003_py310 import get_name_with_age
def test_get_name_with_age_pass_int():
diff --git a/tests/test_tutorial/test_python_types/test_tutorial004.py b/tests/test_tutorial/test_python_types/test_tutorial004.py
index 24af32883e..0b16c0cb45 100644
--- a/tests/test_tutorial/test_python_types/test_tutorial004.py
+++ b/tests/test_tutorial/test_python_types/test_tutorial004.py
@@ -1,4 +1,4 @@
-from docs_src.python_types.tutorial004_py39 import get_name_with_age
+from docs_src.python_types.tutorial004_py310 import get_name_with_age
def test_get_name_with_age_pass_int():
diff --git a/tests/test_tutorial/test_python_types/test_tutorial005.py b/tests/test_tutorial/test_python_types/test_tutorial005.py
index 6d67ec4716..b5c847523d 100644
--- a/tests/test_tutorial/test_python_types/test_tutorial005.py
+++ b/tests/test_tutorial/test_python_types/test_tutorial005.py
@@ -1,4 +1,4 @@
-from docs_src.python_types.tutorial005_py39 import get_items
+from docs_src.python_types.tutorial005_py310 import get_items
def test_get_items():
diff --git a/tests/test_tutorial/test_python_types/test_tutorial006.py b/tests/test_tutorial/test_python_types/test_tutorial006.py
index 50976926e7..fbe929a766 100644
--- a/tests/test_tutorial/test_python_types/test_tutorial006.py
+++ b/tests/test_tutorial/test_python_types/test_tutorial006.py
@@ -1,6 +1,6 @@
from unittest.mock import patch
-from docs_src.python_types.tutorial006_py39 import process_items
+from docs_src.python_types.tutorial006_py310 import process_items
def test_process_items():
diff --git a/tests/test_tutorial/test_python_types/test_tutorial007.py b/tests/test_tutorial/test_python_types/test_tutorial007.py
index c045294652..b664d2784c 100644
--- a/tests/test_tutorial/test_python_types/test_tutorial007.py
+++ b/tests/test_tutorial/test_python_types/test_tutorial007.py
@@ -1,4 +1,4 @@
-from docs_src.python_types.tutorial007_py39 import process_items
+from docs_src.python_types.tutorial007_py310 import process_items
def test_process_items():
diff --git a/tests/test_tutorial/test_python_types/test_tutorial008.py b/tests/test_tutorial/test_python_types/test_tutorial008.py
index 33cf6cbfbc..74a4e9cace 100644
--- a/tests/test_tutorial/test_python_types/test_tutorial008.py
+++ b/tests/test_tutorial/test_python_types/test_tutorial008.py
@@ -1,6 +1,6 @@
from unittest.mock import patch
-from docs_src.python_types.tutorial008_py39 import process_items
+from docs_src.python_types.tutorial008_py310 import process_items
def test_process_items():
diff --git a/tests/test_tutorial/test_python_types/test_tutorial008b.py b/tests/test_tutorial/test_python_types/test_tutorial008b.py
index 1ef0d4ea16..60d7e51c12 100644
--- a/tests/test_tutorial/test_python_types/test_tutorial008b.py
+++ b/tests/test_tutorial/test_python_types/test_tutorial008b.py
@@ -10,7 +10,7 @@ from ...utils import needs_py310
@pytest.fixture(
name="module",
params=[
- pytest.param("tutorial008b_py39"),
+ pytest.param("tutorial008b_py310"),
pytest.param("tutorial008b_py310", marks=needs_py310),
],
)
diff --git a/tests/test_tutorial/test_python_types/test_tutorial009_tutorial009b.py b/tests/test_tutorial/test_python_types/test_tutorial009_tutorial009b.py
index 34046c5c48..eec51b1bec 100644
--- a/tests/test_tutorial/test_python_types/test_tutorial009_tutorial009b.py
+++ b/tests/test_tutorial/test_python_types/test_tutorial009_tutorial009b.py
@@ -10,9 +10,8 @@ from ...utils import needs_py310
@pytest.fixture(
name="module",
params=[
- pytest.param("tutorial009_py39"),
+ pytest.param("tutorial009_py310"),
pytest.param("tutorial009_py310", marks=needs_py310),
- pytest.param("tutorial009b_py39"),
],
)
def get_module(request: pytest.FixtureRequest):
diff --git a/tests/test_tutorial/test_python_types/test_tutorial009c.py b/tests/test_tutorial/test_python_types/test_tutorial009c.py
deleted file mode 100644
index 7bd4049113..0000000000
--- a/tests/test_tutorial/test_python_types/test_tutorial009c.py
+++ /dev/null
@@ -1,33 +0,0 @@
-import importlib
-import re
-from types import ModuleType
-from unittest.mock import patch
-
-import pytest
-
-from ...utils import needs_py310
-
-
-@pytest.fixture(
- name="module",
- params=[
- pytest.param("tutorial009c_py39"),
- pytest.param("tutorial009c_py310", marks=needs_py310),
- ],
-)
-def get_module(request: pytest.FixtureRequest):
- mod = importlib.import_module(f"docs_src.python_types.{request.param}")
- return mod
-
-
-def test_say_hi(module: ModuleType):
- with patch("builtins.print") as mock_print:
- module.say_hi("FastAPI")
-
- mock_print.assert_called_once_with("Hey FastAPI!")
-
- with pytest.raises(
- TypeError,
- match=re.escape("say_hi() missing 1 required positional argument: 'name'"),
- ):
- module.say_hi()
diff --git a/tests/test_tutorial/test_python_types/test_tutorial010.py b/tests/test_tutorial/test_python_types/test_tutorial010.py
index 9e4d2e36bf..8525e6d843 100644
--- a/tests/test_tutorial/test_python_types/test_tutorial010.py
+++ b/tests/test_tutorial/test_python_types/test_tutorial010.py
@@ -1,4 +1,4 @@
-from docs_src.python_types.tutorial010_py39 import Person, get_person_name
+from docs_src.python_types.tutorial010_py310 import Person, get_person_name
def test_get_person_name():
diff --git a/tests/test_tutorial/test_python_types/test_tutorial011.py b/tests/test_tutorial/test_python_types/test_tutorial011.py
index a05751b974..3761eb9243 100644
--- a/tests/test_tutorial/test_python_types/test_tutorial011.py
+++ b/tests/test_tutorial/test_python_types/test_tutorial011.py
@@ -9,7 +9,6 @@ from ...utils import needs_py310
@pytest.mark.parametrize(
"module_name",
[
- pytest.param("tutorial011_py39"),
pytest.param("tutorial011_py310", marks=needs_py310),
],
)
diff --git a/tests/test_tutorial/test_python_types/test_tutorial012.py b/tests/test_tutorial/test_python_types/test_tutorial012.py
deleted file mode 100644
index e578048204..0000000000
--- a/tests/test_tutorial/test_python_types/test_tutorial012.py
+++ /dev/null
@@ -1,7 +0,0 @@
-from docs_src.python_types.tutorial012_py39 import User
-
-
-def test_user():
- user = User(name="John Doe", age=30)
- assert user.name == "John Doe"
- assert user.age == 30
diff --git a/tests/test_tutorial/test_python_types/test_tutorial013.py b/tests/test_tutorial/test_python_types/test_tutorial013.py
index 5602ef76f8..d8669b485c 100644
--- a/tests/test_tutorial/test_python_types/test_tutorial013.py
+++ b/tests/test_tutorial/test_python_types/test_tutorial013.py
@@ -1,4 +1,4 @@
-from docs_src.python_types.tutorial013_py39 import say_hello
+from docs_src.python_types.tutorial013_py310 import say_hello
def test_say_hello():
diff --git a/tests/test_tutorial/test_query_param_models/test_tutorial001.py b/tests/test_tutorial/test_query_param_models/test_tutorial001.py
index 38b767154a..75d1b97622 100644
--- a/tests/test_tutorial/test_query_param_models/test_tutorial001.py
+++ b/tests/test_tutorial/test_query_param_models/test_tutorial001.py
@@ -10,9 +10,7 @@ from tests.utils import needs_py310
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial001_py39"),
pytest.param("tutorial001_py310", marks=needs_py310),
- pytest.param("tutorial001_an_py39"),
pytest.param("tutorial001_an_py310", marks=needs_py310),
],
)
diff --git a/tests/test_tutorial/test_query_param_models/test_tutorial002.py b/tests/test_tutorial/test_query_param_models/test_tutorial002.py
index b173a2df45..da2b6608ab 100644
--- a/tests/test_tutorial/test_query_param_models/test_tutorial002.py
+++ b/tests/test_tutorial/test_query_param_models/test_tutorial002.py
@@ -10,9 +10,7 @@ from tests.utils import needs_py310
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial002_py39"),
pytest.param("tutorial002_py310", marks=[needs_py310]),
- pytest.param("tutorial002_an_py39"),
pytest.param("tutorial002_an_py310", marks=[needs_py310]),
],
)
diff --git a/tests/test_tutorial/test_query_params/test_tutorial001.py b/tests/test_tutorial/test_query_params/test_tutorial001.py
index 40ada0e8e4..d687025871 100644
--- a/tests/test_tutorial/test_query_params/test_tutorial001.py
+++ b/tests/test_tutorial/test_query_params/test_tutorial001.py
@@ -8,7 +8,7 @@ from inline_snapshot import snapshot
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial001_py39"),
+ pytest.param("tutorial001_py310"),
],
)
def get_client(request: pytest.FixtureRequest):
diff --git a/tests/test_tutorial/test_query_params/test_tutorial002.py b/tests/test_tutorial/test_query_params/test_tutorial002.py
index 1da308a7e2..9be507fba7 100644
--- a/tests/test_tutorial/test_query_params/test_tutorial002.py
+++ b/tests/test_tutorial/test_query_params/test_tutorial002.py
@@ -10,7 +10,6 @@ from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial002_py39"),
pytest.param("tutorial002_py310", marks=needs_py310),
],
)
diff --git a/tests/test_tutorial/test_query_params/test_tutorial003.py b/tests/test_tutorial/test_query_params/test_tutorial003.py
index 9bb58ff9fe..2951f1adf9 100644
--- a/tests/test_tutorial/test_query_params/test_tutorial003.py
+++ b/tests/test_tutorial/test_query_params/test_tutorial003.py
@@ -10,7 +10,6 @@ from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial003_py39"),
pytest.param("tutorial003_py310", marks=needs_py310),
],
)
diff --git a/tests/test_tutorial/test_query_params/test_tutorial004.py b/tests/test_tutorial/test_query_params/test_tutorial004.py
index 20aadb3acd..9786f861f1 100644
--- a/tests/test_tutorial/test_query_params/test_tutorial004.py
+++ b/tests/test_tutorial/test_query_params/test_tutorial004.py
@@ -10,7 +10,6 @@ from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial004_py39"),
pytest.param("tutorial004_py310", marks=needs_py310),
],
)
diff --git a/tests/test_tutorial/test_query_params/test_tutorial005.py b/tests/test_tutorial/test_query_params/test_tutorial005.py
index e023fe6d80..b21e97f0b3 100644
--- a/tests/test_tutorial/test_query_params/test_tutorial005.py
+++ b/tests/test_tutorial/test_query_params/test_tutorial005.py
@@ -1,7 +1,7 @@
from fastapi.testclient import TestClient
from inline_snapshot import snapshot
-from docs_src.query_params.tutorial005_py39 import app
+from docs_src.query_params.tutorial005_py310 import app
client = TestClient(app)
diff --git a/tests/test_tutorial/test_query_params/test_tutorial006.py b/tests/test_tutorial/test_query_params/test_tutorial006.py
index b28e126556..a27f2bbb01 100644
--- a/tests/test_tutorial/test_query_params/test_tutorial006.py
+++ b/tests/test_tutorial/test_query_params/test_tutorial006.py
@@ -10,7 +10,6 @@ from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial006_py39"),
pytest.param("tutorial006_py310", marks=needs_py310),
],
)
diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial001.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial001.py
index ed73b7329e..1eb424e4fe 100644
--- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial001.py
+++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial001.py
@@ -10,7 +10,6 @@ from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial001_py39"),
pytest.param("tutorial001_py310", marks=needs_py310),
],
)
diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial002.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial002.py
index 3eac1f2b36..feb59f1690 100644
--- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial002.py
+++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial002.py
@@ -10,9 +10,7 @@ from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial002_py39"),
pytest.param("tutorial002_py310", marks=needs_py310),
- pytest.param("tutorial002_an_py39"),
pytest.param("tutorial002_an_py310", marks=needs_py310),
],
)
diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial003.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial003.py
index 59d5160acb..4e1ef1da7f 100644
--- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial003.py
+++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial003.py
@@ -10,9 +10,7 @@ from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial003_py39"),
pytest.param("tutorial003_py310", marks=needs_py310),
- pytest.param("tutorial003_an_py39"),
pytest.param("tutorial003_an_py310", marks=needs_py310),
],
)
diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial004.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial004.py
index abf08c9328..9c2d442c8c 100644
--- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial004.py
+++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial004.py
@@ -10,19 +10,8 @@ from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial004_py39"),
pytest.param("tutorial004_py310", marks=needs_py310),
- pytest.param("tutorial004_an_py39"),
pytest.param("tutorial004_an_py310", marks=needs_py310),
- pytest.param(
- "tutorial004_regex_an_py310",
- marks=(
- needs_py310,
- pytest.mark.filterwarnings(
- "ignore:`regex` has been deprecated, please use `pattern` instead:fastapi.exceptions.FastAPIDeprecationWarning"
- ),
- ),
- ),
],
)
def get_client(request: pytest.FixtureRequest):
diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial005.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial005.py
index 7b5368abc4..61f07631b3 100644
--- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial005.py
+++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial005.py
@@ -8,8 +8,8 @@ from inline_snapshot import snapshot
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial005_py39"),
- pytest.param("tutorial005_an_py39"),
+ pytest.param("tutorial005_py310"),
+ pytest.param("tutorial005_an_py310"),
],
)
def get_client(request: pytest.FixtureRequest):
diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial006.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial006.py
index 2c1df2c08f..18ee8dbdcf 100644
--- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial006.py
+++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial006.py
@@ -8,8 +8,8 @@ from inline_snapshot import snapshot
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial006_py39"),
- pytest.param("tutorial006_an_py39"),
+ pytest.param("tutorial006_py310"),
+ pytest.param("tutorial006_an_py310"),
],
)
def get_client(request: pytest.FixtureRequest):
diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial006c.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial006c.py
index 3df9efa839..74c10b885d 100644
--- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial006c.py
+++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial006c.py
@@ -10,9 +10,7 @@ from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial006c_py39"),
pytest.param("tutorial006c_py310", marks=needs_py310),
- pytest.param("tutorial006c_an_py39"),
pytest.param("tutorial006c_an_py310", marks=needs_py310),
],
)
diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial007.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial007.py
index 874002b173..3a23ce4a43 100644
--- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial007.py
+++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial007.py
@@ -10,9 +10,7 @@ from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial007_py39"),
pytest.param("tutorial007_py310", marks=needs_py310),
- pytest.param("tutorial007_an_py39"),
pytest.param("tutorial007_an_py310", marks=needs_py310),
],
)
diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial008.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial008.py
index b9613a17b8..430d1bc188 100644
--- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial008.py
+++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial008.py
@@ -10,9 +10,7 @@ from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial008_py39"),
pytest.param("tutorial008_py310", marks=needs_py310),
- pytest.param("tutorial008_an_py39"),
pytest.param("tutorial008_an_py310", marks=needs_py310),
],
)
diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial009.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial009.py
index d749d85f7a..a81e1c40e3 100644
--- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial009.py
+++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial009.py
@@ -10,9 +10,7 @@ from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial009_py39"),
pytest.param("tutorial009_py310", marks=needs_py310),
- pytest.param("tutorial009_an_py39"),
pytest.param("tutorial009_an_py310", marks=needs_py310),
],
)
diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial010.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial010.py
index efe9f1fa6b..bb8fbfceec 100644
--- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial010.py
+++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial010.py
@@ -11,9 +11,7 @@ from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial010_py39"),
pytest.param("tutorial010_py310", marks=needs_py310),
- pytest.param("tutorial010_an_py39"),
pytest.param("tutorial010_an_py310", marks=needs_py310),
],
)
diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial011.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial011.py
index c25357fdd1..8d558efec9 100644
--- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial011.py
+++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial011.py
@@ -10,9 +10,7 @@ from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial011_py39"),
pytest.param("tutorial011_py310", marks=needs_py310),
- pytest.param("tutorial011_an_py39"),
pytest.param("tutorial011_an_py310", marks=needs_py310),
],
)
diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial012.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial012.py
index c3d01e90ea..5aae7fcc69 100644
--- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial012.py
+++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial012.py
@@ -8,8 +8,8 @@ from inline_snapshot import snapshot
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial012_py39"),
- pytest.param("tutorial012_an_py39"),
+ pytest.param("tutorial012_py310"),
+ pytest.param("tutorial012_an_py310"),
],
)
def get_client(request: pytest.FixtureRequest):
diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial013.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial013.py
index 74efa46958..29d49a5b77 100644
--- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial013.py
+++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial013.py
@@ -8,8 +8,8 @@ from inline_snapshot import snapshot
@pytest.fixture(
name="client",
params=[
- "tutorial013_py39",
- "tutorial013_an_py39",
+ "tutorial013_py310",
+ "tutorial013_an_py310",
],
)
def get_client(request: pytest.FixtureRequest):
diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial014.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial014.py
index 6dff18b787..683e39795a 100644
--- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial014.py
+++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial014.py
@@ -10,9 +10,7 @@ from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial014_py39"),
pytest.param("tutorial014_py310", marks=needs_py310),
- pytest.param("tutorial014_an_py39"),
pytest.param("tutorial014_an_py310", marks=needs_py310),
],
)
diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial015.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial015.py
index 32a990e748..01d7c983a6 100644
--- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial015.py
+++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial015.py
@@ -11,7 +11,6 @@ from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial015_an_py39"),
pytest.param("tutorial015_an_py310", marks=[needs_py310]),
],
)
diff --git a/tests/test_tutorial/test_request_files/test_tutorial001.py b/tests/test_tutorial/test_request_files/test_tutorial001.py
index fd5c3b0559..4d3c35d65d 100644
--- a/tests/test_tutorial/test_request_files/test_tutorial001.py
+++ b/tests/test_tutorial/test_request_files/test_tutorial001.py
@@ -8,8 +8,8 @@ from inline_snapshot import snapshot
@pytest.fixture(
name="client",
params=[
- "tutorial001_py39",
- "tutorial001_an_py39",
+ "tutorial001_py310",
+ "tutorial001_an_py310",
],
)
def get_client(request: pytest.FixtureRequest):
diff --git a/tests/test_tutorial/test_request_files/test_tutorial001_02.py b/tests/test_tutorial/test_request_files/test_tutorial001_02.py
index feeb5363ed..f199b992ae 100644
--- a/tests/test_tutorial/test_request_files/test_tutorial001_02.py
+++ b/tests/test_tutorial/test_request_files/test_tutorial001_02.py
@@ -11,9 +11,7 @@ from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial001_02_py39"),
pytest.param("tutorial001_02_py310", marks=needs_py310),
- pytest.param("tutorial001_02_an_py39"),
pytest.param("tutorial001_02_an_py310", marks=needs_py310),
],
)
diff --git a/tests/test_tutorial/test_request_files/test_tutorial001_03.py b/tests/test_tutorial/test_request_files/test_tutorial001_03.py
index 5ef8df178c..ce22c1b5c4 100644
--- a/tests/test_tutorial/test_request_files/test_tutorial001_03.py
+++ b/tests/test_tutorial/test_request_files/test_tutorial001_03.py
@@ -8,8 +8,8 @@ from inline_snapshot import snapshot
@pytest.fixture(
name="client",
params=[
- "tutorial001_03_py39",
- "tutorial001_03_an_py39",
+ "tutorial001_03_py310",
+ "tutorial001_03_an_py310",
],
)
def get_client(request: pytest.FixtureRequest):
diff --git a/tests/test_tutorial/test_request_files/test_tutorial002.py b/tests/test_tutorial/test_request_files/test_tutorial002.py
index 52655fd63b..ebf76b3a07 100644
--- a/tests/test_tutorial/test_request_files/test_tutorial002.py
+++ b/tests/test_tutorial/test_request_files/test_tutorial002.py
@@ -9,8 +9,8 @@ from inline_snapshot import snapshot
@pytest.fixture(
name="app",
params=[
- "tutorial002_py39",
- "tutorial002_an_py39",
+ "tutorial002_py310",
+ "tutorial002_an_py310",
],
)
def get_app(request: pytest.FixtureRequest):
diff --git a/tests/test_tutorial/test_request_files/test_tutorial003.py b/tests/test_tutorial/test_request_files/test_tutorial003.py
index a1425ba330..f11658d27c 100644
--- a/tests/test_tutorial/test_request_files/test_tutorial003.py
+++ b/tests/test_tutorial/test_request_files/test_tutorial003.py
@@ -9,8 +9,8 @@ from inline_snapshot import snapshot
@pytest.fixture(
name="app",
params=[
- "tutorial003_py39",
- "tutorial003_an_py39",
+ "tutorial003_py310",
+ "tutorial003_an_py310",
],
)
def get_app(request: pytest.FixtureRequest):
diff --git a/tests/test_tutorial/test_request_form_models/test_tutorial001.py b/tests/test_tutorial/test_request_form_models/test_tutorial001.py
index 68fa074dc3..3122e97e81 100644
--- a/tests/test_tutorial/test_request_form_models/test_tutorial001.py
+++ b/tests/test_tutorial/test_request_form_models/test_tutorial001.py
@@ -8,8 +8,8 @@ from inline_snapshot import snapshot
@pytest.fixture(
name="client",
params=[
- "tutorial001_py39",
- "tutorial001_an_py39",
+ "tutorial001_py310",
+ "tutorial001_an_py310",
],
)
def get_client(request: pytest.FixtureRequest):
diff --git a/tests/test_tutorial/test_request_form_models/test_tutorial002.py b/tests/test_tutorial/test_request_form_models/test_tutorial002.py
index ed5ae109a0..e5dc6e486b 100644
--- a/tests/test_tutorial/test_request_form_models/test_tutorial002.py
+++ b/tests/test_tutorial/test_request_form_models/test_tutorial002.py
@@ -8,8 +8,8 @@ from inline_snapshot import snapshot
@pytest.fixture(
name="client",
params=[
- "tutorial002_py39",
- "tutorial002_an_py39",
+ "tutorial002_py310",
+ "tutorial002_an_py310",
],
)
def get_client(request: pytest.FixtureRequest):
diff --git a/tests/test_tutorial/test_request_forms/test_tutorial001.py b/tests/test_tutorial/test_request_forms/test_tutorial001.py
index d1596f137e..ff3421aac0 100644
--- a/tests/test_tutorial/test_request_forms/test_tutorial001.py
+++ b/tests/test_tutorial/test_request_forms/test_tutorial001.py
@@ -8,8 +8,8 @@ from inline_snapshot import snapshot
@pytest.fixture(
name="client",
params=[
- "tutorial001_py39",
- "tutorial001_an_py39",
+ "tutorial001_py310",
+ "tutorial001_an_py310",
],
)
def get_client(request: pytest.FixtureRequest):
diff --git a/tests/test_tutorial/test_request_forms_and_files/test_tutorial001.py b/tests/test_tutorial/test_request_forms_and_files/test_tutorial001.py
index 6e9165c425..e2462e040b 100644
--- a/tests/test_tutorial/test_request_forms_and_files/test_tutorial001.py
+++ b/tests/test_tutorial/test_request_forms_and_files/test_tutorial001.py
@@ -9,8 +9,8 @@ from inline_snapshot import snapshot
@pytest.fixture(
name="app",
params=[
- "tutorial001_py39",
- "tutorial001_an_py39",
+ "tutorial001_py310",
+ "tutorial001_an_py310",
],
)
def get_app(request: pytest.FixtureRequest):
diff --git a/tests/test_tutorial/test_response_change_status_code/test_tutorial001.py b/tests/test_tutorial/test_response_change_status_code/test_tutorial001.py
index 05d5ca619f..d046bd266f 100644
--- a/tests/test_tutorial/test_response_change_status_code/test_tutorial001.py
+++ b/tests/test_tutorial/test_response_change_status_code/test_tutorial001.py
@@ -1,6 +1,6 @@
from fastapi.testclient import TestClient
-from docs_src.response_change_status_code.tutorial001_py39 import app
+from docs_src.response_change_status_code.tutorial001_py310 import app
client = TestClient(app)
diff --git a/tests/test_tutorial/test_response_cookies/test_tutorial001.py b/tests/test_tutorial/test_response_cookies/test_tutorial001.py
index 6b931c8bda..1068983395 100644
--- a/tests/test_tutorial/test_response_cookies/test_tutorial001.py
+++ b/tests/test_tutorial/test_response_cookies/test_tutorial001.py
@@ -1,6 +1,6 @@
from fastapi.testclient import TestClient
-from docs_src.response_cookies.tutorial001_py39 import app
+from docs_src.response_cookies.tutorial001_py310 import app
client = TestClient(app)
diff --git a/tests/test_tutorial/test_response_cookies/test_tutorial002.py b/tests/test_tutorial/test_response_cookies/test_tutorial002.py
index 3ee5f500c5..66812e4807 100644
--- a/tests/test_tutorial/test_response_cookies/test_tutorial002.py
+++ b/tests/test_tutorial/test_response_cookies/test_tutorial002.py
@@ -1,6 +1,6 @@
from fastapi.testclient import TestClient
-from docs_src.response_cookies.tutorial002_py39 import app
+from docs_src.response_cookies.tutorial002_py310 import app
client = TestClient(app)
diff --git a/tests/test_tutorial/test_response_directly/test_tutorial001.py b/tests/test_tutorial/test_response_directly/test_tutorial001.py
index 2b034f1c98..54406684d8 100644
--- a/tests/test_tutorial/test_response_directly/test_tutorial001.py
+++ b/tests/test_tutorial/test_response_directly/test_tutorial001.py
@@ -10,7 +10,6 @@ from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial001_py39"),
pytest.param("tutorial001_py310", marks=needs_py310),
],
)
diff --git a/tests/test_tutorial/test_response_directly/test_tutorial002.py b/tests/test_tutorial/test_response_directly/test_tutorial002.py
index 047e82c148..7dcb8d2926 100644
--- a/tests/test_tutorial/test_response_directly/test_tutorial002.py
+++ b/tests/test_tutorial/test_response_directly/test_tutorial002.py
@@ -8,7 +8,7 @@ from inline_snapshot import snapshot
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial002_py39"),
+ pytest.param("tutorial002_py310"),
],
)
def get_client(request: pytest.FixtureRequest):
diff --git a/tests/test_tutorial/test_response_headers/test_tutorial001.py b/tests/test_tutorial/test_response_headers/test_tutorial001.py
index 6232aad23e..ea182246f6 100644
--- a/tests/test_tutorial/test_response_headers/test_tutorial001.py
+++ b/tests/test_tutorial/test_response_headers/test_tutorial001.py
@@ -1,6 +1,6 @@
from fastapi.testclient import TestClient
-from docs_src.response_headers.tutorial001_py39 import app
+from docs_src.response_headers.tutorial001_py310 import app
client = TestClient(app)
diff --git a/tests/test_tutorial/test_response_headers/test_tutorial002.py b/tests/test_tutorial/test_response_headers/test_tutorial002.py
index 2ac2226cb1..9b90459cb7 100644
--- a/tests/test_tutorial/test_response_headers/test_tutorial002.py
+++ b/tests/test_tutorial/test_response_headers/test_tutorial002.py
@@ -1,6 +1,6 @@
from fastapi.testclient import TestClient
-from docs_src.response_headers.tutorial002_py39 import app
+from docs_src.response_headers.tutorial002_py310 import app
client = TestClient(app)
diff --git a/tests/test_tutorial/test_response_model/test_tutorial001_tutorial001_01.py b/tests/test_tutorial/test_response_model/test_tutorial001_tutorial001_01.py
index 914f53783c..bbdcc68202 100644
--- a/tests/test_tutorial/test_response_model/test_tutorial001_tutorial001_01.py
+++ b/tests/test_tutorial/test_response_model/test_tutorial001_tutorial001_01.py
@@ -10,9 +10,7 @@ from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial001_py39"),
pytest.param("tutorial001_py310", marks=needs_py310),
- pytest.param("tutorial001_01_py39"),
pytest.param("tutorial001_01_py310", marks=needs_py310),
],
)
diff --git a/tests/test_tutorial/test_response_model/test_tutorial002.py b/tests/test_tutorial/test_response_model/test_tutorial002.py
index 10a4e37cd3..31b4659905 100644
--- a/tests/test_tutorial/test_response_model/test_tutorial002.py
+++ b/tests/test_tutorial/test_response_model/test_tutorial002.py
@@ -10,7 +10,6 @@ from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial002_py39"),
pytest.param("tutorial002_py310", marks=needs_py310),
],
)
diff --git a/tests/test_tutorial/test_response_model/test_tutorial003.py b/tests/test_tutorial/test_response_model/test_tutorial003.py
index a1477b7dfd..8178c81963 100644
--- a/tests/test_tutorial/test_response_model/test_tutorial003.py
+++ b/tests/test_tutorial/test_response_model/test_tutorial003.py
@@ -10,7 +10,6 @@ from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial003_py39"),
pytest.param("tutorial003_py310", marks=needs_py310),
],
)
diff --git a/tests/test_tutorial/test_response_model/test_tutorial003_01.py b/tests/test_tutorial/test_response_model/test_tutorial003_01.py
index a60a14ae8d..1a0c4f2603 100644
--- a/tests/test_tutorial/test_response_model/test_tutorial003_01.py
+++ b/tests/test_tutorial/test_response_model/test_tutorial003_01.py
@@ -10,7 +10,6 @@ from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial003_01_py39"),
pytest.param("tutorial003_01_py310", marks=needs_py310),
],
)
diff --git a/tests/test_tutorial/test_response_model/test_tutorial003_02.py b/tests/test_tutorial/test_response_model/test_tutorial003_02.py
index 460c882516..a28c56be92 100644
--- a/tests/test_tutorial/test_response_model/test_tutorial003_02.py
+++ b/tests/test_tutorial/test_response_model/test_tutorial003_02.py
@@ -1,7 +1,7 @@
from fastapi.testclient import TestClient
from inline_snapshot import snapshot
-from docs_src.response_model.tutorial003_02_py39 import app
+from docs_src.response_model.tutorial003_02_py310 import app
client = TestClient(app)
diff --git a/tests/test_tutorial/test_response_model/test_tutorial003_03.py b/tests/test_tutorial/test_response_model/test_tutorial003_03.py
index c83d78c4fa..65e7470222 100644
--- a/tests/test_tutorial/test_response_model/test_tutorial003_03.py
+++ b/tests/test_tutorial/test_response_model/test_tutorial003_03.py
@@ -1,7 +1,7 @@
from fastapi.testclient import TestClient
from inline_snapshot import snapshot
-from docs_src.response_model.tutorial003_03_py39 import app
+from docs_src.response_model.tutorial003_03_py310 import app
client = TestClient(app)
diff --git a/tests/test_tutorial/test_response_model/test_tutorial003_04.py b/tests/test_tutorial/test_response_model/test_tutorial003_04.py
index 145af126fd..44f2e504ea 100644
--- a/tests/test_tutorial/test_response_model/test_tutorial003_04.py
+++ b/tests/test_tutorial/test_response_model/test_tutorial003_04.py
@@ -9,7 +9,6 @@ from ...utils import needs_py310
@pytest.mark.parametrize(
"module_name",
[
- pytest.param("tutorial003_04_py39"),
pytest.param("tutorial003_04_py310", marks=needs_py310),
],
)
diff --git a/tests/test_tutorial/test_response_model/test_tutorial003_05.py b/tests/test_tutorial/test_response_model/test_tutorial003_05.py
index 187b6491fc..0f0e94fdaa 100644
--- a/tests/test_tutorial/test_response_model/test_tutorial003_05.py
+++ b/tests/test_tutorial/test_response_model/test_tutorial003_05.py
@@ -10,7 +10,6 @@ from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial003_05_py39"),
pytest.param("tutorial003_05_py310", marks=needs_py310),
],
)
diff --git a/tests/test_tutorial/test_response_model/test_tutorial004.py b/tests/test_tutorial/test_response_model/test_tutorial004.py
index d40bce261b..e7c0e79f21 100644
--- a/tests/test_tutorial/test_response_model/test_tutorial004.py
+++ b/tests/test_tutorial/test_response_model/test_tutorial004.py
@@ -10,7 +10,6 @@ from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial004_py39"),
pytest.param("tutorial004_py310", marks=needs_py310),
],
)
diff --git a/tests/test_tutorial/test_response_model/test_tutorial005.py b/tests/test_tutorial/test_response_model/test_tutorial005.py
index 55b2334d46..75c8fc0aca 100644
--- a/tests/test_tutorial/test_response_model/test_tutorial005.py
+++ b/tests/test_tutorial/test_response_model/test_tutorial005.py
@@ -10,7 +10,6 @@ from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial005_py39"),
pytest.param("tutorial005_py310", marks=needs_py310),
],
)
diff --git a/tests/test_tutorial/test_response_model/test_tutorial006.py b/tests/test_tutorial/test_response_model/test_tutorial006.py
index 5d6f542b5d..f80ce1b28b 100644
--- a/tests/test_tutorial/test_response_model/test_tutorial006.py
+++ b/tests/test_tutorial/test_response_model/test_tutorial006.py
@@ -10,7 +10,6 @@ from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial006_py39"),
pytest.param("tutorial006_py310", marks=needs_py310),
],
)
diff --git a/tests/test_tutorial/test_response_status_code/test_tutorial001_tutorial002.py b/tests/test_tutorial/test_response_status_code/test_tutorial001_tutorial002.py
index 7199ceed65..69c32f92e2 100644
--- a/tests/test_tutorial/test_response_status_code/test_tutorial001_tutorial002.py
+++ b/tests/test_tutorial/test_response_status_code/test_tutorial001_tutorial002.py
@@ -8,8 +8,8 @@ from inline_snapshot import snapshot
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial001_py39"),
- pytest.param("tutorial002_py39"),
+ pytest.param("tutorial001_py310"),
+ pytest.param("tutorial002_py310"),
],
)
def get_client(request: pytest.FixtureRequest):
diff --git a/tests/test_tutorial/test_schema_extra_example/test_tutorial001.py b/tests/test_tutorial/test_schema_extra_example/test_tutorial001.py
index f19346a3a4..126dfbe7d3 100644
--- a/tests/test_tutorial/test_schema_extra_example/test_tutorial001.py
+++ b/tests/test_tutorial/test_schema_extra_example/test_tutorial001.py
@@ -10,7 +10,6 @@ from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial001_py39"),
pytest.param("tutorial001_py310", marks=needs_py310),
],
)
diff --git a/tests/test_tutorial/test_schema_extra_example/test_tutorial002.py b/tests/test_tutorial/test_schema_extra_example/test_tutorial002.py
index 8313cb14f6..cac3337a24 100644
--- a/tests/test_tutorial/test_schema_extra_example/test_tutorial002.py
+++ b/tests/test_tutorial/test_schema_extra_example/test_tutorial002.py
@@ -10,7 +10,6 @@ from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial002_py39"),
pytest.param("tutorial002_py310", marks=needs_py310),
],
)
diff --git a/tests/test_tutorial/test_schema_extra_example/test_tutorial003.py b/tests/test_tutorial/test_schema_extra_example/test_tutorial003.py
index 3c45a64bcf..1ccca4da85 100644
--- a/tests/test_tutorial/test_schema_extra_example/test_tutorial003.py
+++ b/tests/test_tutorial/test_schema_extra_example/test_tutorial003.py
@@ -10,9 +10,7 @@ from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial003_py39"),
pytest.param("tutorial003_py310", marks=needs_py310),
- pytest.param("tutorial003_an_py39"),
pytest.param("tutorial003_an_py310", marks=needs_py310),
],
)
diff --git a/tests/test_tutorial/test_schema_extra_example/test_tutorial004.py b/tests/test_tutorial/test_schema_extra_example/test_tutorial004.py
index 4b8e15fa19..cffd270665 100644
--- a/tests/test_tutorial/test_schema_extra_example/test_tutorial004.py
+++ b/tests/test_tutorial/test_schema_extra_example/test_tutorial004.py
@@ -10,9 +10,7 @@ from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial004_py39"),
pytest.param("tutorial004_py310", marks=needs_py310),
- pytest.param("tutorial004_an_py39"),
pytest.param("tutorial004_an_py310", marks=needs_py310),
],
)
diff --git a/tests/test_tutorial/test_schema_extra_example/test_tutorial005.py b/tests/test_tutorial/test_schema_extra_example/test_tutorial005.py
index 7f8e36df21..0bc17a00e1 100644
--- a/tests/test_tutorial/test_schema_extra_example/test_tutorial005.py
+++ b/tests/test_tutorial/test_schema_extra_example/test_tutorial005.py
@@ -10,9 +10,7 @@ from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial005_py39"),
pytest.param("tutorial005_py310", marks=needs_py310),
- pytest.param("tutorial005_an_py39"),
pytest.param("tutorial005_an_py310", marks=needs_py310),
],
)
diff --git a/tests/test_tutorial/test_security/test_tutorial001.py b/tests/test_tutorial/test_security/test_tutorial001.py
index 5742b51bf0..c1a15ae009 100644
--- a/tests/test_tutorial/test_security/test_tutorial001.py
+++ b/tests/test_tutorial/test_security/test_tutorial001.py
@@ -8,8 +8,8 @@ from inline_snapshot import snapshot
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial001_py39"),
- pytest.param("tutorial001_an_py39"),
+ pytest.param("tutorial001_py310"),
+ pytest.param("tutorial001_an_py310"),
],
)
def get_client(request: pytest.FixtureRequest):
diff --git a/tests/test_tutorial/test_security/test_tutorial002.py b/tests/test_tutorial/test_security/test_tutorial002.py
index 1e8c6e0180..4d1202c325 100644
--- a/tests/test_tutorial/test_security/test_tutorial002.py
+++ b/tests/test_tutorial/test_security/test_tutorial002.py
@@ -10,9 +10,7 @@ from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial002_py39"),
pytest.param("tutorial002_py310", marks=needs_py310),
- pytest.param("tutorial002_an_py39"),
pytest.param("tutorial002_an_py310", marks=needs_py310),
],
)
diff --git a/tests/test_tutorial/test_security/test_tutorial003.py b/tests/test_tutorial/test_security/test_tutorial003.py
index acd910c71f..45f4e57bba 100644
--- a/tests/test_tutorial/test_security/test_tutorial003.py
+++ b/tests/test_tutorial/test_security/test_tutorial003.py
@@ -10,9 +10,7 @@ from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial003_py39"),
pytest.param("tutorial003_py310", marks=needs_py310),
- pytest.param("tutorial003_an_py39"),
pytest.param("tutorial003_an_py310", marks=needs_py310),
],
)
diff --git a/tests/test_tutorial/test_security/test_tutorial004.py b/tests/test_tutorial/test_security/test_tutorial004.py
index e842c92a13..e52a029bd4 100644
--- a/tests/test_tutorial/test_security/test_tutorial004.py
+++ b/tests/test_tutorial/test_security/test_tutorial004.py
@@ -12,9 +12,7 @@ from ...utils import needs_py310
@pytest.fixture(
name="mod",
params=[
- pytest.param("tutorial004_py39"),
pytest.param("tutorial004_py310", marks=needs_py310),
- pytest.param("tutorial004_an_py39"),
pytest.param("tutorial004_an_py310", marks=needs_py310),
],
)
diff --git a/tests/test_tutorial/test_security/test_tutorial005.py b/tests/test_tutorial/test_security/test_tutorial005.py
index 76b08860f5..c6e0e78e09 100644
--- a/tests/test_tutorial/test_security/test_tutorial005.py
+++ b/tests/test_tutorial/test_security/test_tutorial005.py
@@ -11,9 +11,7 @@ from ...utils import needs_py310
@pytest.fixture(
name="mod",
params=[
- pytest.param("tutorial005_py39"),
pytest.param("tutorial005_py310", marks=needs_py310),
- pytest.param("tutorial005_an_py39"),
pytest.param("tutorial005_an_py310", marks=needs_py310),
],
)
diff --git a/tests/test_tutorial/test_security/test_tutorial006.py b/tests/test_tutorial/test_security/test_tutorial006.py
index 1c96f62ae3..671946d97e 100644
--- a/tests/test_tutorial/test_security/test_tutorial006.py
+++ b/tests/test_tutorial/test_security/test_tutorial006.py
@@ -9,8 +9,8 @@ from inline_snapshot import snapshot
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial006_py39"),
- pytest.param("tutorial006_an_py39"),
+ pytest.param("tutorial006_py310"),
+ pytest.param("tutorial006_an_py310"),
],
)
def get_client(request: pytest.FixtureRequest):
diff --git a/tests/test_tutorial/test_security/test_tutorial007.py b/tests/test_tutorial/test_security/test_tutorial007.py
index 24667422fe..e735457536 100644
--- a/tests/test_tutorial/test_security/test_tutorial007.py
+++ b/tests/test_tutorial/test_security/test_tutorial007.py
@@ -9,8 +9,8 @@ from inline_snapshot import snapshot
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial007_py39"),
- pytest.param("tutorial007_an_py39"),
+ pytest.param("tutorial007_py310"),
+ pytest.param("tutorial007_an_py310"),
],
)
def get_client(request: pytest.FixtureRequest):
diff --git a/tests/test_tutorial/test_separate_openapi_schemas/test_tutorial001.py b/tests/test_tutorial/test_separate_openapi_schemas/test_tutorial001.py
index 0be3b59f99..653b20c7d2 100644
--- a/tests/test_tutorial/test_separate_openapi_schemas/test_tutorial001.py
+++ b/tests/test_tutorial/test_separate_openapi_schemas/test_tutorial001.py
@@ -10,7 +10,6 @@ from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial001_py39"),
pytest.param("tutorial001_py310", marks=needs_py310),
],
)
diff --git a/tests/test_tutorial/test_separate_openapi_schemas/test_tutorial002.py b/tests/test_tutorial/test_separate_openapi_schemas/test_tutorial002.py
index 87c63f69e0..0ef706a4d1 100644
--- a/tests/test_tutorial/test_separate_openapi_schemas/test_tutorial002.py
+++ b/tests/test_tutorial/test_separate_openapi_schemas/test_tutorial002.py
@@ -10,7 +10,6 @@ from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial002_py39"),
pytest.param("tutorial002_py310", marks=needs_py310),
],
)
diff --git a/tests/test_tutorial/test_settings/test_app01.py b/tests/test_tutorial/test_settings/test_app01.py
index 52b9b1e629..da27308e80 100644
--- a/tests/test_tutorial/test_settings/test_app01.py
+++ b/tests/test_tutorial/test_settings/test_app01.py
@@ -12,7 +12,7 @@ from pytest import MonkeyPatch
@pytest.fixture(
name="mod_name",
params=[
- pytest.param("app01_py39"),
+ pytest.param("app01_py310"),
],
)
def get_mod_name(request: pytest.FixtureRequest):
diff --git a/tests/test_tutorial/test_settings/test_app02.py b/tests/test_tutorial/test_settings/test_app02.py
index 9cbed4fd1b..20594ebb74 100644
--- a/tests/test_tutorial/test_settings/test_app02.py
+++ b/tests/test_tutorial/test_settings/test_app02.py
@@ -8,8 +8,8 @@ from pytest import MonkeyPatch
@pytest.fixture(
name="mod_path",
params=[
- pytest.param("app02_py39"),
- pytest.param("app02_an_py39"),
+ pytest.param("app02_py310"),
+ pytest.param("app02_an_py310"),
],
)
def get_mod_path(request: pytest.FixtureRequest):
diff --git a/tests/test_tutorial/test_settings/test_app03.py b/tests/test_tutorial/test_settings/test_app03.py
index 72de497967..f4539c96d7 100644
--- a/tests/test_tutorial/test_settings/test_app03.py
+++ b/tests/test_tutorial/test_settings/test_app03.py
@@ -9,8 +9,8 @@ from pytest import MonkeyPatch
@pytest.fixture(
name="mod_path",
params=[
- pytest.param("app03_py39"),
- pytest.param("app03_an_py39"),
+ pytest.param("app03_py310"),
+ pytest.param("app03_an_py310"),
],
)
def get_mod_path(request: pytest.FixtureRequest):
diff --git a/tests/test_tutorial/test_settings/test_tutorial001.py b/tests/test_tutorial/test_settings/test_tutorial001.py
index f4576a0d21..8857c35df3 100644
--- a/tests/test_tutorial/test_settings/test_tutorial001.py
+++ b/tests/test_tutorial/test_settings/test_tutorial001.py
@@ -5,7 +5,7 @@ from fastapi.testclient import TestClient
from pytest import MonkeyPatch
-@pytest.fixture(name="app", params=[pytest.param("tutorial001_py39")])
+@pytest.fixture(name="app", params=[pytest.param("tutorial001_py310")])
def get_app(request: pytest.FixtureRequest, monkeypatch: MonkeyPatch):
monkeypatch.setenv("ADMIN_EMAIL", "admin@example.com")
mod = importlib.import_module(f"docs_src.settings.{request.param}")
diff --git a/tests/test_tutorial/test_sql_databases/test_tutorial001.py b/tests/test_tutorial/test_sql_databases/test_tutorial001.py
index aec20e42e1..3407ec7588 100644
--- a/tests/test_tutorial/test_sql_databases/test_tutorial001.py
+++ b/tests/test_tutorial/test_sql_databases/test_tutorial001.py
@@ -22,9 +22,7 @@ def clear_sqlmodel():
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial001_py39"),
pytest.param("tutorial001_py310", marks=needs_py310),
- pytest.param("tutorial001_an_py39"),
pytest.param("tutorial001_an_py310", marks=needs_py310),
],
)
diff --git a/tests/test_tutorial/test_sql_databases/test_tutorial002.py b/tests/test_tutorial/test_sql_databases/test_tutorial002.py
index 4ea7d5f647..51a36b6c79 100644
--- a/tests/test_tutorial/test_sql_databases/test_tutorial002.py
+++ b/tests/test_tutorial/test_sql_databases/test_tutorial002.py
@@ -22,9 +22,7 @@ def clear_sqlmodel():
@pytest.fixture(
name="client",
params=[
- pytest.param("tutorial002_py39"),
pytest.param("tutorial002_py310", marks=needs_py310),
- pytest.param("tutorial002_an_py39"),
pytest.param("tutorial002_an_py310", marks=needs_py310),
],
)
diff --git a/tests/test_tutorial/test_static_files/test_tutorial001.py b/tests/test_tutorial/test_static_files/test_tutorial001.py
index dd93fee790..1d57310f30 100644
--- a/tests/test_tutorial/test_static_files/test_tutorial001.py
+++ b/tests/test_tutorial/test_static_files/test_tutorial001.py
@@ -12,7 +12,7 @@ def client():
static_dir.mkdir(exist_ok=True)
sample_file = static_dir / "sample.txt"
sample_file.write_text("This is a sample static file.")
- from docs_src.static_files.tutorial001_py39 import app
+ from docs_src.static_files.tutorial001_py310 import app
with TestClient(app) as client:
yield client
diff --git a/tests/test_tutorial/test_sub_applications/test_tutorial001.py b/tests/test_tutorial/test_sub_applications/test_tutorial001.py
index a8fb3dc36f..63fb68fb27 100644
--- a/tests/test_tutorial/test_sub_applications/test_tutorial001.py
+++ b/tests/test_tutorial/test_sub_applications/test_tutorial001.py
@@ -1,7 +1,7 @@
from fastapi.testclient import TestClient
from inline_snapshot import snapshot
-from docs_src.sub_applications.tutorial001_py39 import app
+from docs_src.sub_applications.tutorial001_py310 import app
client = TestClient(app)
diff --git a/tests/test_tutorial/test_templates/test_tutorial001.py b/tests/test_tutorial/test_templates/test_tutorial001.py
index 818508037d..04bc3fce86 100644
--- a/tests/test_tutorial/test_templates/test_tutorial001.py
+++ b/tests/test_tutorial/test_templates/test_tutorial001.py
@@ -11,7 +11,7 @@ def test_main():
shutil.rmtree("./templates")
shutil.copytree("./docs_src/templates/templates/", "./templates")
shutil.copytree("./docs_src/templates/static/", "./static")
- from docs_src.templates.tutorial001_py39 import app
+ from docs_src.templates.tutorial001_py310 import app
client = TestClient(app)
response = client.get("/items/foo")
diff --git a/tests/test_tutorial/test_testing/test_main_a.py b/tests/test_tutorial/test_testing/test_main_a.py
index 5284888053..d071d53095 100644
--- a/tests/test_tutorial/test_testing/test_main_a.py
+++ b/tests/test_tutorial/test_testing/test_main_a.py
@@ -1,6 +1,6 @@
from inline_snapshot import snapshot
-from docs_src.app_testing.app_a_py39.test_main import client, test_read_main
+from docs_src.app_testing.app_a_py310.test_main import client, test_read_main
def test_main():
diff --git a/tests/test_tutorial/test_testing/test_main_b.py b/tests/test_tutorial/test_testing/test_main_b.py
index 3d679cd5a6..2d042fd690 100644
--- a/tests/test_tutorial/test_testing/test_main_b.py
+++ b/tests/test_tutorial/test_testing/test_main_b.py
@@ -9,9 +9,7 @@ from ...utils import needs_py310
@pytest.fixture(
name="test_module",
params=[
- "app_b_py39.test_main",
pytest.param("app_b_py310.test_main", marks=needs_py310),
- "app_b_an_py39.test_main",
pytest.param("app_b_an_py310.test_main", marks=needs_py310),
],
)
diff --git a/tests/test_tutorial/test_testing/test_tutorial001.py b/tests/test_tutorial/test_testing/test_tutorial001.py
index 2b501d36a7..b9bb182b77 100644
--- a/tests/test_tutorial/test_testing/test_tutorial001.py
+++ b/tests/test_tutorial/test_testing/test_tutorial001.py
@@ -1,6 +1,6 @@
from inline_snapshot import snapshot
-from docs_src.app_testing.tutorial001_py39 import client, test_read_main
+from docs_src.app_testing.tutorial001_py310 import client, test_read_main
def test_main():
diff --git a/tests/test_tutorial/test_testing/test_tutorial002.py b/tests/test_tutorial/test_testing/test_tutorial002.py
index cc9b5ba27c..840248dc30 100644
--- a/tests/test_tutorial/test_testing/test_tutorial002.py
+++ b/tests/test_tutorial/test_testing/test_tutorial002.py
@@ -1,4 +1,4 @@
-from docs_src.app_testing.tutorial002_py39 import test_read_main, test_websocket
+from docs_src.app_testing.tutorial002_py310 import test_read_main, test_websocket
def test_main():
diff --git a/tests/test_tutorial/test_testing/test_tutorial003.py b/tests/test_tutorial/test_testing/test_tutorial003.py
index 4faa820e98..196fc45559 100644
--- a/tests/test_tutorial/test_testing/test_tutorial003.py
+++ b/tests/test_tutorial/test_testing/test_tutorial003.py
@@ -3,5 +3,5 @@ import pytest
def test_main():
with pytest.warns(DeprecationWarning):
- from docs_src.app_testing.tutorial003_py39 import test_read_items
+ from docs_src.app_testing.tutorial003_py310 import test_read_items
test_read_items()
diff --git a/tests/test_tutorial/test_testing/test_tutorial004.py b/tests/test_tutorial/test_testing/test_tutorial004.py
index c95214ffe3..d5de1bb603 100644
--- a/tests/test_tutorial/test_testing/test_tutorial004.py
+++ b/tests/test_tutorial/test_testing/test_tutorial004.py
@@ -1,4 +1,4 @@
-from docs_src.app_testing.tutorial004_py39 import test_read_items
+from docs_src.app_testing.tutorial004_py310 import test_read_items
def test_main():
diff --git a/tests/test_tutorial/test_testing_dependencies/test_tutorial001.py b/tests/test_tutorial/test_testing_dependencies/test_tutorial001.py
index 6e9656bf55..81491276eb 100644
--- a/tests/test_tutorial/test_testing_dependencies/test_tutorial001.py
+++ b/tests/test_tutorial/test_testing_dependencies/test_tutorial001.py
@@ -9,9 +9,7 @@ from ...utils import needs_py310
@pytest.fixture(
name="test_module",
params=[
- pytest.param("tutorial001_py39"),
pytest.param("tutorial001_py310", marks=needs_py310),
- pytest.param("tutorial001_an_py39"),
pytest.param("tutorial001_an_py310", marks=needs_py310),
],
)
diff --git a/tests/test_tutorial/test_using_request_directly/test_tutorial001.py b/tests/test_tutorial/test_using_request_directly/test_tutorial001.py
index cb8ae8b050..4145177e4a 100644
--- a/tests/test_tutorial/test_using_request_directly/test_tutorial001.py
+++ b/tests/test_tutorial/test_using_request_directly/test_tutorial001.py
@@ -1,7 +1,7 @@
from fastapi.testclient import TestClient
from inline_snapshot import snapshot
-from docs_src.using_request_directly.tutorial001_py39 import app
+from docs_src.using_request_directly.tutorial001_py310 import app
client = TestClient(app)
diff --git a/tests/test_tutorial/test_websockets/test_tutorial001.py b/tests/test_tutorial/test_websockets/test_tutorial001.py
index 4f8368db28..6f3bf1429a 100644
--- a/tests/test_tutorial/test_websockets/test_tutorial001.py
+++ b/tests/test_tutorial/test_websockets/test_tutorial001.py
@@ -2,7 +2,7 @@ import pytest
from fastapi.testclient import TestClient
from fastapi.websockets import WebSocketDisconnect
-from docs_src.websockets.tutorial001_py39 import app
+from docs_src.websockets.tutorial001_py310 import app
client = TestClient(app)
diff --git a/tests/test_tutorial/test_websockets/test_tutorial002.py b/tests/test_tutorial/test_websockets/test_tutorial002.py
index ebf1fc8e81..0509b0d0d6 100644
--- a/tests/test_tutorial/test_websockets/test_tutorial002.py
+++ b/tests/test_tutorial/test_websockets/test_tutorial002.py
@@ -11,9 +11,7 @@ from ...utils import needs_py310
@pytest.fixture(
name="app",
params=[
- pytest.param("tutorial002_py39"),
pytest.param("tutorial002_py310", marks=needs_py310),
- pytest.param("tutorial002_an_py39"),
pytest.param("tutorial002_an_py310", marks=needs_py310),
],
)
diff --git a/tests/test_tutorial/test_websockets/test_tutorial003.py b/tests/test_tutorial/test_websockets/test_tutorial003.py
index 0be1fc81d6..781146371d 100644
--- a/tests/test_tutorial/test_websockets/test_tutorial003.py
+++ b/tests/test_tutorial/test_websockets/test_tutorial003.py
@@ -8,7 +8,7 @@ from fastapi.testclient import TestClient
@pytest.fixture(
name="mod",
params=[
- pytest.param("tutorial003_py39"),
+ pytest.param("tutorial003_py310"),
],
)
def get_mod(request: pytest.FixtureRequest):
diff --git a/tests/test_tutorial/test_wsgi/test_tutorial001.py b/tests/test_tutorial/test_wsgi/test_tutorial001.py
index 9fe8c2a4b8..9bcd56dfc2 100644
--- a/tests/test_tutorial/test_wsgi/test_tutorial001.py
+++ b/tests/test_tutorial/test_wsgi/test_tutorial001.py
@@ -1,6 +1,6 @@
from fastapi.testclient import TestClient
-from docs_src.wsgi.tutorial001_py39 import app
+from docs_src.wsgi.tutorial001_py310 import app
client = TestClient(app)
diff --git a/tests/test_union_body.py b/tests/test_union_body.py
index e333e2499f..88f9e06cc8 100644
--- a/tests/test_union_body.py
+++ b/tests/test_union_body.py
@@ -1,5 +1,3 @@
-from typing import Optional, Union
-
from fastapi import FastAPI
from fastapi.testclient import TestClient
from inline_snapshot import snapshot
@@ -9,7 +7,7 @@ app = FastAPI()
class Item(BaseModel):
- name: Optional[str] = None
+ name: str | None = None
class OtherItem(BaseModel):
@@ -17,7 +15,7 @@ class OtherItem(BaseModel):
@app.post("/items/")
-def save_union_body(item: Union[OtherItem, Item]):
+def save_union_body(item: OtherItem | Item):
return {"item": item}
diff --git a/tests/test_union_body_discriminator.py b/tests/test_union_body_discriminator.py
index 4afe7be4b4..1b682c7751 100644
--- a/tests/test_union_body_discriminator.py
+++ b/tests/test_union_body_discriminator.py
@@ -1,10 +1,9 @@
-from typing import Annotated, Any, Union
+from typing import Annotated, Any, Literal
from fastapi import FastAPI
from fastapi.testclient import TestClient
from inline_snapshot import snapshot
from pydantic import BaseModel, Field
-from typing_extensions import Literal
def test_discriminator_pydantic_v2() -> None:
@@ -21,7 +20,7 @@ def test_discriminator_pydantic_v2() -> None:
price: float
Item = Annotated[
- Union[Annotated[FirstItem, Tag("first")], Annotated[OtherItem, Tag("other")]],
+ Annotated[FirstItem, Tag("first")] | Annotated[OtherItem, Tag("other")],
Field(discriminator="value"),
]
diff --git a/tests/test_union_body_discriminator_annotated.py b/tests/test_union_body_discriminator_annotated.py
index 6644d106c8..7e64ea75b4 100644
--- a/tests/test_union_body_discriminator_annotated.py
+++ b/tests/test_union_body_discriminator_annotated.py
@@ -1,6 +1,6 @@
# Ref: https://github.com/fastapi/fastapi/discussions/14495
-from typing import Annotated, Union
+from typing import Annotated
import pytest
from fastapi import FastAPI
@@ -27,7 +27,7 @@ def client_fixture() -> TestClient:
return v.get("pet_type", "")
Pet = Annotated[
- Union[Annotated[Cat, Tag("cat")], Annotated[Dog, Tag("dog")]],
+ Annotated[Cat, Tag("cat")] | Annotated[Dog, Tag("dog")],
Discriminator(get_pet_type),
]
diff --git a/tests/test_union_forms.py b/tests/test_union_forms.py
index f6c2658f96..8cd7b4f017 100644
--- a/tests/test_union_forms.py
+++ b/tests/test_union_forms.py
@@ -1,4 +1,4 @@
-from typing import Annotated, Union
+from typing import Annotated
from fastapi import FastAPI, Form
from fastapi.testclient import TestClient
@@ -19,7 +19,7 @@ class CompanyForm(BaseModel):
@app.post("/form-union/")
-def post_union_form(data: Annotated[Union[UserForm, CompanyForm], Form()]):
+def post_union_form(data: Annotated[UserForm | CompanyForm, Form()]):
return {"received": data}
diff --git a/tests/test_union_inherited_body.py b/tests/test_union_inherited_body.py
index 5378880a47..c997a87a35 100644
--- a/tests/test_union_inherited_body.py
+++ b/tests/test_union_inherited_body.py
@@ -1,5 +1,3 @@
-from typing import Optional, Union
-
from fastapi import FastAPI
from fastapi.testclient import TestClient
from inline_snapshot import snapshot
@@ -9,7 +7,7 @@ app = FastAPI()
class Item(BaseModel):
- name: Optional[str] = None
+ name: str | None = None
class ExtendedItem(Item):
@@ -17,7 +15,7 @@ class ExtendedItem(Item):
@app.post("/items/")
-def save_union_different_body(item: Union[ExtendedItem, Item]):
+def save_union_different_body(item: ExtendedItem | Item):
return {"item": item}
diff --git a/tests/test_validate_response.py b/tests/test_validate_response.py
index 938d419566..7288220eab 100644
--- a/tests/test_validate_response.py
+++ b/tests/test_validate_response.py
@@ -1,5 +1,3 @@
-from typing import Optional, Union
-
import pytest
from fastapi import FastAPI
from fastapi.exceptions import ResponseValidationError
@@ -11,8 +9,8 @@ app = FastAPI()
class Item(BaseModel):
name: str
- price: Optional[float] = None
- owner_ids: Optional[list[int]] = None
+ price: float | None = None
+ owner_ids: list[int] | None = None
@app.get("/items/invalid", response_model=Item)
@@ -25,7 +23,7 @@ def get_invalid_none():
return None
-@app.get("/items/validnone", response_model=Union[Item, None])
+@app.get("/items/validnone", response_model=Item | None)
def get_valid_none(send_none: bool = False):
if send_none:
return None
diff --git a/tests/test_validate_response_dataclass.py b/tests/test_validate_response_dataclass.py
index 67282bcde1..03b7d5f338 100644
--- a/tests/test_validate_response_dataclass.py
+++ b/tests/test_validate_response_dataclass.py
@@ -1,5 +1,3 @@
-from typing import Optional
-
import pytest
from fastapi import FastAPI
from fastapi.exceptions import ResponseValidationError
@@ -12,8 +10,8 @@ app = FastAPI()
@dataclass
class Item:
name: str
- price: Optional[float] = None
- owner_ids: Optional[list[int]] = None
+ price: float | None = None
+ owner_ids: list[int] | None = None
@app.get("/items/invalid", response_model=Item)
diff --git a/tests/utils.py b/tests/utils.py
index 4cbfee79f5..09c4e13b00 100644
--- a/tests/utils.py
+++ b/tests/utils.py
@@ -2,7 +2,6 @@ import sys
import pytest
-needs_py39 = pytest.mark.skipif(sys.version_info < (3, 9), reason="requires python3.9+")
needs_py310 = pytest.mark.skipif(
sys.version_info < (3, 10), reason="requires python3.10+"
)
diff --git a/uv.lock b/uv.lock
index 9a807f8b4d..aa8c558c7d 100644
--- a/uv.lock
+++ b/uv.lock
@@ -1,10 +1,9 @@
version = 1
revision = 3
-requires-python = ">=3.9"
+requires-python = ">=3.10"
resolution-markers = [
"python_full_version >= '3.14'",
- "python_full_version >= '3.10' and python_full_version < '3.14'",
- "python_full_version < '3.10'",
+ "python_full_version < '3.14'",
]
[[package]]
@@ -158,23 +157,6 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/3c/5f/24155e30ba7f8c96918af1350eb0663e2430aad9e001c0489d89cd708ab1/aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:fc353029f176fd2b3ec6cfc71be166aba1936fe5d73dd1992ce289ca6647a9aa", size = 1769801, upload-time = "2026-01-03T17:32:20.25Z" },
{ url = "https://files.pythonhosted.org/packages/eb/f8/7314031ff5c10e6ece114da79b338ec17eeff3a079e53151f7e9f43c4723/aiohttp-3.13.3-cp314-cp314t-win32.whl", hash = "sha256:2e41b18a58da1e474a057b3d35248d8320029f61d70a37629535b16a0c8f3767", size = 466523, upload-time = "2026-01-03T17:32:22.215Z" },
{ url = "https://files.pythonhosted.org/packages/b4/63/278a98c715ae467624eafe375542d8ba9b4383a016df8fdefe0ae28382a7/aiohttp-3.13.3-cp314-cp314t-win_amd64.whl", hash = "sha256:44531a36aa2264a1860089ffd4dce7baf875ee5a6079d5fb42e261c704ef7344", size = 499694, upload-time = "2026-01-03T17:32:24.546Z" },
- { url = "https://files.pythonhosted.org/packages/bf/79/446655656861d3e7e2c32bfcf160c7aa9e9dc63776a691b124dba65cdd77/aiohttp-3.13.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:31a83ea4aead760dfcb6962efb1d861db48c34379f2ff72db9ddddd4cda9ea2e", size = 741433, upload-time = "2026-01-03T17:32:26.453Z" },
- { url = "https://files.pythonhosted.org/packages/cb/49/773c4b310b5140d2fb5e79bb0bf40b7b41dad80a288ca1a8759f5f72bda9/aiohttp-3.13.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:988a8c5e317544fdf0d39871559e67b6341065b87fceac641108c2096d5506b7", size = 497332, upload-time = "2026-01-03T17:32:28.37Z" },
- { url = "https://files.pythonhosted.org/packages/bc/31/1dcbc4b83a4e6f76a0ad883f07f21ffbfe29750c89db97381701508c9f45/aiohttp-3.13.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9b174f267b5cfb9a7dba9ee6859cecd234e9a681841eb85068059bc867fb8f02", size = 492365, upload-time = "2026-01-03T17:32:30.234Z" },
- { url = "https://files.pythonhosted.org/packages/5a/b5/b50657496c8754482cd7964e50aaf3aa84b3db61ed45daec4c1aec5b94b4/aiohttp-3.13.3-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:947c26539750deeaee933b000fb6517cc770bbd064bad6033f1cff4803881e43", size = 1660440, upload-time = "2026-01-03T17:32:32.586Z" },
- { url = "https://files.pythonhosted.org/packages/2a/73/9b69e5139d89d75127569298931444ad78ea86a5befd5599780b1e9a6880/aiohttp-3.13.3-cp39-cp39-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:9ebf57d09e131f5323464bd347135a88622d1c0976e88ce15b670e7ad57e4bd6", size = 1632740, upload-time = "2026-01-03T17:32:34.793Z" },
- { url = "https://files.pythonhosted.org/packages/ef/fe/3ea9b5af694b4e3aec0d0613a806132ca744747146fca68e96bf056f61a7/aiohttp-3.13.3-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4ae5b5a0e1926e504c81c5b84353e7a5516d8778fbbff00429fe7b05bb25cbce", size = 1719782, upload-time = "2026-01-03T17:32:37.737Z" },
- { url = "https://files.pythonhosted.org/packages/fb/c2/46b3b06e60851cbb71efb0f79a3267279cbef7b12c58e68a1e897f269cca/aiohttp-3.13.3-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2ba0eea45eb5cc3172dbfc497c066f19c41bac70963ea1a67d51fc92e4cf9a80", size = 1813527, upload-time = "2026-01-03T17:32:39.973Z" },
- { url = "https://files.pythonhosted.org/packages/36/23/71ceb78c769ed65fe4c697692de232b63dab399210678d2b00961ccb0619/aiohttp-3.13.3-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bae5c2ed2eae26cc382020edad80d01f36cb8e746da40b292e68fec40421dc6a", size = 1661268, upload-time = "2026-01-03T17:32:42.082Z" },
- { url = "https://files.pythonhosted.org/packages/c4/8d/86e929523d955e85ebab7c0e2b9e0cb63604cfc27dc3280e10d0063cf682/aiohttp-3.13.3-cp39-cp39-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:8a60e60746623925eab7d25823329941aee7242d559baa119ca2b253c88a7bd6", size = 1552742, upload-time = "2026-01-03T17:32:44.622Z" },
- { url = "https://files.pythonhosted.org/packages/3a/ea/3f5987cba1bab6bd151f0d97aa60f0ce04d3c83316692a6bb6ba2fb69f92/aiohttp-3.13.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:e50a2e1404f063427c9d027378472316201a2290959a295169bcf25992d04558", size = 1632918, upload-time = "2026-01-03T17:32:46.749Z" },
- { url = "https://files.pythonhosted.org/packages/be/2c/7e1e85121f2e31ee938cb83a8f32dfafd4908530c10fabd6d46761c12ac7/aiohttp-3.13.3-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:9a9dc347e5a3dc7dfdbc1f82da0ef29e388ddb2ed281bfce9dd8248a313e62b7", size = 1644446, upload-time = "2026-01-03T17:32:49.063Z" },
- { url = "https://files.pythonhosted.org/packages/5d/35/ce6133d423ad0e8ca976a7c848f7146bca3520eea4ccf6b95e2d077c9d20/aiohttp-3.13.3-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:b46020d11d23fe16551466c77823df9cc2f2c1e63cc965daf67fa5eec6ca1877", size = 1689487, upload-time = "2026-01-03T17:32:51.113Z" },
- { url = "https://files.pythonhosted.org/packages/50/f7/ff7a27c15603d460fd1366b3c22054f7ae4fa9310aca40b43bde35867fcd/aiohttp-3.13.3-cp39-cp39-musllinux_1_2_riscv64.whl", hash = "sha256:69c56fbc1993fa17043e24a546959c0178fe2b5782405ad4559e6c13975c15e3", size = 1540715, upload-time = "2026-01-03T17:32:53.38Z" },
- { url = "https://files.pythonhosted.org/packages/17/02/053f11346e5b962e6d8a1c4f8c70c29d5970a1b4b8e7894c68e12c27a57f/aiohttp-3.13.3-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:b99281b0704c103d4e11e72a76f1b543d4946fea7dd10767e7e1b5f00d4e5704", size = 1711835, upload-time = "2026-01-03T17:32:56.088Z" },
- { url = "https://files.pythonhosted.org/packages/fb/71/9b9761ddf276fd6708d13720197cbac19b8d67ecfa9116777924056cfcaa/aiohttp-3.13.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:40c5e40ecc29ba010656c18052b877a1c28f84344825efa106705e835c28530f", size = 1649593, upload-time = "2026-01-03T17:32:58.181Z" },
- { url = "https://files.pythonhosted.org/packages/ae/72/5d817e9ea218acae12a5e3b9ad1178cf0c12fc3570c0b47eea2daf95f9ea/aiohttp-3.13.3-cp39-cp39-win32.whl", hash = "sha256:56339a36b9f1fc708260c76c87e593e2afb30d26de9ae1eb445b5e051b98a7a1", size = 434831, upload-time = "2026-01-03T17:33:00.577Z" },
- { url = "https://files.pythonhosted.org/packages/39/cb/22659d9bf3149b7a2927bc2769cc9c8f8f5a80eba098398e03c199a43a85/aiohttp-3.13.3-cp39-cp39-win_amd64.whl", hash = "sha256:c6b8568a3bb5819a0ad087f16d40e5a3fb6099f39ea1d5625a3edc1e923fc538", size = 457697, upload-time = "2026-01-03T17:33:03.167Z" },
]
[[package]]
@@ -243,8 +225,7 @@ wheels = [
[package.optional-dependencies]
trio = [
- { name = "trio", version = "0.31.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
- { name = "trio", version = "0.32.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
+ { name = "trio" },
]
[[package]]
@@ -256,31 +237,12 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/74/f5/9373290775639cb67a2fce7f629a1c240dce9f12fe927bc32b2736e16dfc/argcomplete-3.6.3-py3-none-any.whl", hash = "sha256:f5007b3a600ccac5d25bbce33089211dfd49eab4a7718da3f10e3082525a92ce", size = 43846, upload-time = "2025-10-20T03:33:33.021Z" },
]
-[[package]]
-name = "argon2-cffi"
-version = "23.1.0"
-source = { registry = "https://pypi.org/simple" }
-resolution-markers = [
- "python_full_version < '3.10'",
-]
-dependencies = [
- { name = "argon2-cffi-bindings", marker = "python_full_version < '3.10'" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/31/fa/57ec2c6d16ecd2ba0cf15f3c7d1c3c2e7b5fcb83555ff56d7ab10888ec8f/argon2_cffi-23.1.0.tar.gz", hash = "sha256:879c3e79a2729ce768ebb7d36d4609e3a78a4ca2ec3a9f12286ca057e3d0db08", size = 42798, upload-time = "2023-08-15T14:13:12.711Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/a4/6a/e8a041599e78b6b3752da48000b14c8d1e8a04ded09c88c714ba047f34f5/argon2_cffi-23.1.0-py3-none-any.whl", hash = "sha256:c670642b78ba29641818ab2e68bd4e6a78ba53b7eff7b4c3815ae16abf91c7ea", size = 15124, upload-time = "2023-08-15T14:13:10.752Z" },
-]
-
[[package]]
name = "argon2-cffi"
version = "25.1.0"
source = { registry = "https://pypi.org/simple" }
-resolution-markers = [
- "python_full_version >= '3.14'",
- "python_full_version >= '3.10' and python_full_version < '3.14'",
-]
dependencies = [
- { name = "argon2-cffi-bindings", marker = "python_full_version >= '3.10'" },
+ { name = "argon2-cffi-bindings" },
]
sdist = { url = "https://files.pythonhosted.org/packages/0e/89/ce5af8a7d472a67cc819d5d998aa8c82c5d860608c4db9f46f1162d7dab9/argon2_cffi-25.1.0.tar.gz", hash = "sha256:694ae5cc8a42f4c4e2bf2ca0e64e51e23a040c6a517a85074683d3959e1346c1", size = 45706, upload-time = "2025-06-03T06:55:32.073Z" }
wheels = [
@@ -355,7 +317,7 @@ name = "authlib"
version = "1.6.7"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "cryptography", marker = "python_full_version >= '3.10'" },
+ { name = "cryptography" },
]
sdist = { url = "https://files.pythonhosted.org/packages/49/dc/ed1681bf1339dd6ea1ce56136bad4baabc6f7ad466e375810702b0237047/authlib-1.6.7.tar.gz", hash = "sha256:dbf10100011d1e1b34048c9d120e83f13b35d69a826ae762b93d2fb5aafc337b", size = 164950, upload-time = "2026-02-06T14:04:14.171Z" }
wheels = [
@@ -403,69 +365,19 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/71/cc/18245721fa7747065ab478316c7fea7c74777d07f37ae60db2e84f8172e8/beartype-0.22.9-py3-none-any.whl", hash = "sha256:d16c9bbc61ea14637596c5f6fbff2ee99cbe3573e46a716401734ef50c3060c2", size = 1333658, upload-time = "2025-12-13T06:50:28.266Z" },
]
-[[package]]
-name = "black"
-version = "25.11.0"
-source = { registry = "https://pypi.org/simple" }
-resolution-markers = [
- "python_full_version < '3.10'",
-]
-dependencies = [
- { name = "click", version = "8.1.8", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
- { name = "mypy-extensions", marker = "python_full_version < '3.10'" },
- { name = "packaging", marker = "python_full_version < '3.10'" },
- { name = "pathspec", marker = "python_full_version < '3.10'" },
- { name = "platformdirs", version = "4.4.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
- { name = "pytokens", marker = "python_full_version < '3.10'" },
- { name = "tomli", marker = "python_full_version < '3.10'" },
- { name = "typing-extensions", marker = "python_full_version < '3.10'" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/8c/ad/33adf4708633d047950ff2dfdea2e215d84ac50ef95aff14a614e4b6e9b2/black-25.11.0.tar.gz", hash = "sha256:9a323ac32f5dc75ce7470501b887250be5005a01602e931a15e45593f70f6e08", size = 655669, upload-time = "2025-11-10T01:53:50.558Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/b3/d2/6caccbc96f9311e8ec3378c296d4f4809429c43a6cd2394e3c390e86816d/black-25.11.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ec311e22458eec32a807f029b2646f661e6859c3f61bc6d9ffb67958779f392e", size = 1743501, upload-time = "2025-11-10T01:59:06.202Z" },
- { url = "https://files.pythonhosted.org/packages/69/35/b986d57828b3f3dccbf922e2864223197ba32e74c5004264b1c62bc9f04d/black-25.11.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1032639c90208c15711334d681de2e24821af0575573db2810b0763bcd62e0f0", size = 1597308, upload-time = "2025-11-10T01:57:58.633Z" },
- { url = "https://files.pythonhosted.org/packages/39/8e/8b58ef4b37073f52b64a7b2dd8c9a96c84f45d6f47d878d0aa557e9a2d35/black-25.11.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0c0f7c461df55cf32929b002335883946a4893d759f2df343389c4396f3b6b37", size = 1656194, upload-time = "2025-11-10T01:57:10.909Z" },
- { url = "https://files.pythonhosted.org/packages/8d/30/9c2267a7955ecc545306534ab88923769a979ac20a27cf618d370091e5dd/black-25.11.0-cp310-cp310-win_amd64.whl", hash = "sha256:f9786c24d8e9bd5f20dc7a7f0cdd742644656987f6ea6947629306f937726c03", size = 1347996, upload-time = "2025-11-10T01:57:22.391Z" },
- { url = "https://files.pythonhosted.org/packages/c4/62/d304786b75ab0c530b833a89ce7d997924579fb7484ecd9266394903e394/black-25.11.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:895571922a35434a9d8ca67ef926da6bc9ad464522a5fe0db99b394ef1c0675a", size = 1727891, upload-time = "2025-11-10T02:01:40.507Z" },
- { url = "https://files.pythonhosted.org/packages/82/5d/ffe8a006aa522c9e3f430e7b93568a7b2163f4b3f16e8feb6d8c3552761a/black-25.11.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:cb4f4b65d717062191bdec8e4a442539a8ea065e6af1c4f4d36f0cdb5f71e170", size = 1581875, upload-time = "2025-11-10T01:57:51.192Z" },
- { url = "https://files.pythonhosted.org/packages/cb/c8/7c8bda3108d0bb57387ac41b4abb5c08782b26da9f9c4421ef6694dac01a/black-25.11.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d81a44cbc7e4f73a9d6ae449ec2317ad81512d1e7dce7d57f6333fd6259737bc", size = 1642716, upload-time = "2025-11-10T01:56:51.589Z" },
- { url = "https://files.pythonhosted.org/packages/34/b9/f17dea34eecb7cc2609a89627d480fb6caea7b86190708eaa7eb15ed25e7/black-25.11.0-cp311-cp311-win_amd64.whl", hash = "sha256:7eebd4744dfe92ef1ee349dc532defbf012a88b087bb7ddd688ff59a447b080e", size = 1352904, upload-time = "2025-11-10T01:59:26.252Z" },
- { url = "https://files.pythonhosted.org/packages/7f/12/5c35e600b515f35ffd737da7febdb2ab66bb8c24d88560d5e3ef3d28c3fd/black-25.11.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:80e7486ad3535636657aa180ad32a7d67d7c273a80e12f1b4bfa0823d54e8fac", size = 1772831, upload-time = "2025-11-10T02:03:47Z" },
- { url = "https://files.pythonhosted.org/packages/1a/75/b3896bec5a2bb9ed2f989a970ea40e7062f8936f95425879bbe162746fe5/black-25.11.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6cced12b747c4c76bc09b4db057c319d8545307266f41aaee665540bc0e04e96", size = 1608520, upload-time = "2025-11-10T01:58:46.895Z" },
- { url = "https://files.pythonhosted.org/packages/f3/b5/2bfc18330eddbcfb5aab8d2d720663cd410f51b2ed01375f5be3751595b0/black-25.11.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6cb2d54a39e0ef021d6c5eef442e10fd71fcb491be6413d083a320ee768329dd", size = 1682719, upload-time = "2025-11-10T01:56:55.24Z" },
- { url = "https://files.pythonhosted.org/packages/96/fb/f7dc2793a22cdf74a72114b5ed77fe3349a2e09ef34565857a2f917abdf2/black-25.11.0-cp312-cp312-win_amd64.whl", hash = "sha256:ae263af2f496940438e5be1a0c1020e13b09154f3af4df0835ea7f9fe7bfa409", size = 1362684, upload-time = "2025-11-10T01:57:07.639Z" },
- { url = "https://files.pythonhosted.org/packages/ad/47/3378d6a2ddefe18553d1115e36aea98f4a90de53b6a3017ed861ba1bd3bc/black-25.11.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0a1d40348b6621cc20d3d7530a5b8d67e9714906dfd7346338249ad9c6cedf2b", size = 1772446, upload-time = "2025-11-10T02:02:16.181Z" },
- { url = "https://files.pythonhosted.org/packages/ba/4b/0f00bfb3d1f7e05e25bfc7c363f54dc523bb6ba502f98f4ad3acf01ab2e4/black-25.11.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:51c65d7d60bb25429ea2bf0731c32b2a2442eb4bd3b2afcb47830f0b13e58bfd", size = 1607983, upload-time = "2025-11-10T02:02:52.502Z" },
- { url = "https://files.pythonhosted.org/packages/99/fe/49b0768f8c9ae57eb74cc10a1f87b4c70453551d8ad498959721cc345cb7/black-25.11.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:936c4dd07669269f40b497440159a221ee435e3fddcf668e0c05244a9be71993", size = 1682481, upload-time = "2025-11-10T01:57:12.35Z" },
- { url = "https://files.pythonhosted.org/packages/55/17/7e10ff1267bfa950cc16f0a411d457cdff79678fbb77a6c73b73a5317904/black-25.11.0-cp313-cp313-win_amd64.whl", hash = "sha256:f42c0ea7f59994490f4dccd64e6b2dd49ac57c7c84f38b8faab50f8759db245c", size = 1363869, upload-time = "2025-11-10T01:58:24.608Z" },
- { url = "https://files.pythonhosted.org/packages/67/c0/cc865ce594d09e4cd4dfca5e11994ebb51604328489f3ca3ae7bb38a7db5/black-25.11.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:35690a383f22dd3e468c85dc4b915217f87667ad9cce781d7b42678ce63c4170", size = 1771358, upload-time = "2025-11-10T02:03:33.331Z" },
- { url = "https://files.pythonhosted.org/packages/37/77/4297114d9e2fd2fc8ab0ab87192643cd49409eb059e2940391e7d2340e57/black-25.11.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:dae49ef7369c6caa1a1833fd5efb7c3024bb7e4499bf64833f65ad27791b1545", size = 1612902, upload-time = "2025-11-10T01:59:33.382Z" },
- { url = "https://files.pythonhosted.org/packages/de/63/d45ef97ada84111e330b2b2d45e1dd163e90bd116f00ac55927fb6bf8adb/black-25.11.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5bd4a22a0b37401c8e492e994bce79e614f91b14d9ea911f44f36e262195fdda", size = 1680571, upload-time = "2025-11-10T01:57:04.239Z" },
- { url = "https://files.pythonhosted.org/packages/ff/4b/5604710d61cdff613584028b4cb4607e56e148801ed9b38ee7970799dab6/black-25.11.0-cp314-cp314-win_amd64.whl", hash = "sha256:aa211411e94fdf86519996b7f5f05e71ba34835d8f0c0f03c00a26271da02664", size = 1382599, upload-time = "2025-11-10T01:57:57.427Z" },
- { url = "https://files.pythonhosted.org/packages/d5/9a/5b2c0e3215fe748fcf515c2dd34658973a1210bf610e24de5ba887e4f1c8/black-25.11.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a3bb5ce32daa9ff0605d73b6f19da0b0e6c1f8f2d75594db539fdfed722f2b06", size = 1743063, upload-time = "2025-11-10T02:02:43.175Z" },
- { url = "https://files.pythonhosted.org/packages/a1/20/245164c6efc27333409c62ba54dcbfbe866c6d1957c9a6c0647786e950da/black-25.11.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9815ccee1e55717fe9a4b924cae1646ef7f54e0f990da39a34fc7b264fcf80a2", size = 1596867, upload-time = "2025-11-10T02:00:17.157Z" },
- { url = "https://files.pythonhosted.org/packages/ca/6f/1a3859a7da205f3d50cf3a8bec6bdc551a91c33ae77a045bb24c1f46ab54/black-25.11.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:92285c37b93a1698dcbc34581867b480f1ba3a7b92acf1fe0467b04d7a4da0dc", size = 1655678, upload-time = "2025-11-10T01:57:09.028Z" },
- { url = "https://files.pythonhosted.org/packages/56/1a/6dec1aeb7be90753d4fcc273e69bc18bfd34b353223ed191da33f7519410/black-25.11.0-cp39-cp39-win_amd64.whl", hash = "sha256:43945853a31099c7c0ff8dface53b4de56c41294fa6783c0441a8b1d9bf668bc", size = 1347452, upload-time = "2025-11-10T01:57:01.871Z" },
- { url = "https://files.pythonhosted.org/packages/00/5d/aed32636ed30a6e7f9efd6ad14e2a0b0d687ae7c8c7ec4e4a557174b895c/black-25.11.0-py3-none-any.whl", hash = "sha256:e3f562da087791e96cefcd9dda058380a442ab322a02e222add53736451f604b", size = 204918, upload-time = "2025-11-10T01:53:48.917Z" },
-]
-
[[package]]
name = "black"
version = "26.1.0"
source = { registry = "https://pypi.org/simple" }
-resolution-markers = [
- "python_full_version >= '3.14'",
- "python_full_version >= '3.10' and python_full_version < '3.14'",
-]
dependencies = [
- { name = "click", version = "8.3.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
- { name = "mypy-extensions", marker = "python_full_version >= '3.10'" },
- { name = "packaging", marker = "python_full_version >= '3.10'" },
- { name = "pathspec", marker = "python_full_version >= '3.10'" },
- { name = "platformdirs", version = "4.5.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
- { name = "pytokens", marker = "python_full_version >= '3.10'" },
- { name = "tomli", marker = "python_full_version == '3.10.*'" },
- { name = "typing-extensions", marker = "python_full_version == '3.10.*'" },
+ { name = "click" },
+ { name = "mypy-extensions" },
+ { name = "packaging" },
+ { name = "pathspec" },
+ { name = "platformdirs" },
+ { name = "pytokens" },
+ { name = "tomli", marker = "python_full_version < '3.11'" },
+ { name = "typing-extensions", marker = "python_full_version < '3.11'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/13/88/560b11e521c522440af991d46848a2bde64b5f7202ec14e1f46f9509d328/black-26.1.0.tar.gz", hash = "sha256:d294ac3340eef9c9eb5d29288e96dc719ff269a88e27b396340459dd85da4c58", size = 658785, upload-time = "2026-01-18T04:50:11.993Z" }
wheels = [
@@ -527,8 +439,7 @@ source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "jmespath" },
{ name = "python-dateutil" },
- { name = "urllib3", version = "1.26.20", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
- { name = "urllib3", version = "2.6.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
+ { name = "urllib3" },
]
sdist = { url = "https://files.pythonhosted.org/packages/af/d6/def916ad1d13de5d511074afcde538a958e2e8a7c7020fb698d1f392f63b/botocore-1.42.43.tar.gz", hash = "sha256:41d04ead0b0862eec21f841811fb5764fe370a2df9b319e0d5297325c50fba1b", size = 14934077, upload-time = "2026-02-05T20:31:35.15Z" }
wheels = [
@@ -564,10 +475,8 @@ dependencies = [
{ name = "cairocffi" },
{ name = "cssselect2" },
{ name = "defusedxml" },
- { name = "pillow", version = "11.3.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
- { name = "pillow", version = "12.1.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
- { name = "tinycss2", version = "1.4.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
- { name = "tinycss2", version = "1.5.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
+ { name = "pillow" },
+ { name = "tinycss2" },
]
sdist = { url = "https://files.pythonhosted.org/packages/ab/b9/5106168bd43d7cd8b7cc2a2ee465b385f14b63f4c092bb89eee2d48c8e67/cairosvg-2.8.2.tar.gz", hash = "sha256:07cbf4e86317b27a92318a4cac2a4bb37a5e9c1b8a27355d06874b22f85bef9f", size = 8398590, upload-time = "2025-05-15T06:56:32.653Z" }
wheels = [
@@ -588,8 +497,7 @@ name = "cffi"
version = "2.0.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pycparser", version = "2.23", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10' and implementation_name != 'PyPy'" },
- { name = "pycparser", version = "3.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10' and implementation_name != 'PyPy'" },
+ { name = "pycparser", marker = "implementation_name != 'PyPy'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/eb/56/b1ba7935a17738ae8453301356628e8147c79dbb825bcbc73dc7401f9846/cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529", size = 523588, upload-time = "2025-09-08T23:24:04.541Z" }
wheels = [
@@ -664,18 +572,6 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/a0/1d/ec1a60bd1a10daa292d3cd6bb0b359a81607154fb8165f3ec95fe003b85c/cffi-2.0.0-cp314-cp314t-win32.whl", hash = "sha256:1fc9ea04857caf665289b7a75923f2c6ed559b8298a1b8c49e59f7dd95c8481e", size = 180487, upload-time = "2025-09-08T23:23:40.423Z" },
{ url = "https://files.pythonhosted.org/packages/bf/41/4c1168c74fac325c0c8156f04b6749c8b6a8f405bbf91413ba088359f60d/cffi-2.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:d68b6cef7827e8641e8ef16f4494edda8b36104d79773a334beaa1e3521430f6", size = 191726, upload-time = "2025-09-08T23:23:41.742Z" },
{ url = "https://files.pythonhosted.org/packages/ae/3a/dbeec9d1ee0844c679f6bb5d6ad4e9f198b1224f4e7a32825f47f6192b0c/cffi-2.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:0a1527a803f0a659de1af2e1fd700213caba79377e27e4693648c2923da066f9", size = 184195, upload-time = "2025-09-08T23:23:43.004Z" },
- { url = "https://files.pythonhosted.org/packages/c0/cc/08ed5a43f2996a16b462f64a7055c6e962803534924b9b2f1371d8c00b7b/cffi-2.0.0-cp39-cp39-macosx_10_13_x86_64.whl", hash = "sha256:fe562eb1a64e67dd297ccc4f5addea2501664954f2692b69a76449ec7913ecbf", size = 184288, upload-time = "2025-09-08T23:23:48.404Z" },
- { url = "https://files.pythonhosted.org/packages/3d/de/38d9726324e127f727b4ecc376bc85e505bfe61ef130eaf3f290c6847dd4/cffi-2.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:de8dad4425a6ca6e4e5e297b27b5c824ecc7581910bf9aee86cb6835e6812aa7", size = 180509, upload-time = "2025-09-08T23:23:49.73Z" },
- { url = "https://files.pythonhosted.org/packages/9b/13/c92e36358fbcc39cf0962e83223c9522154ee8630e1df7c0b3a39a8124e2/cffi-2.0.0-cp39-cp39-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:4647afc2f90d1ddd33441e5b0e85b16b12ddec4fca55f0d9671fef036ecca27c", size = 208813, upload-time = "2025-09-08T23:23:51.263Z" },
- { url = "https://files.pythonhosted.org/packages/15/12/a7a79bd0df4c3bff744b2d7e52cc1b68d5e7e427b384252c42366dc1ecbc/cffi-2.0.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3f4d46d8b35698056ec29bca21546e1551a205058ae1a181d871e278b0b28165", size = 216498, upload-time = "2025-09-08T23:23:52.494Z" },
- { url = "https://files.pythonhosted.org/packages/a3/ad/5c51c1c7600bdd7ed9a24a203ec255dccdd0ebf4527f7b922a0bde2fb6ed/cffi-2.0.0-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:e6e73b9e02893c764e7e8d5bb5ce277f1a009cd5243f8228f75f842bf937c534", size = 203243, upload-time = "2025-09-08T23:23:53.836Z" },
- { url = "https://files.pythonhosted.org/packages/32/f2/81b63e288295928739d715d00952c8c6034cb6c6a516b17d37e0c8be5600/cffi-2.0.0-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:cb527a79772e5ef98fb1d700678fe031e353e765d1ca2d409c92263c6d43e09f", size = 203158, upload-time = "2025-09-08T23:23:55.169Z" },
- { url = "https://files.pythonhosted.org/packages/1f/74/cc4096ce66f5939042ae094e2e96f53426a979864aa1f96a621ad128be27/cffi-2.0.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:61d028e90346df14fedc3d1e5441df818d095f3b87d286825dfcbd6459b7ef63", size = 216548, upload-time = "2025-09-08T23:23:56.506Z" },
- { url = "https://files.pythonhosted.org/packages/e8/be/f6424d1dc46b1091ffcc8964fa7c0ab0cd36839dd2761b49c90481a6ba1b/cffi-2.0.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:0f6084a0ea23d05d20c3edcda20c3d006f9b6f3fefeac38f59262e10cef47ee2", size = 218897, upload-time = "2025-09-08T23:23:57.825Z" },
- { url = "https://files.pythonhosted.org/packages/f7/e0/dda537c2309817edf60109e39265f24f24aa7f050767e22c98c53fe7f48b/cffi-2.0.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:1cd13c99ce269b3ed80b417dcd591415d3372bcac067009b6e0f59c7d4015e65", size = 211249, upload-time = "2025-09-08T23:23:59.139Z" },
- { url = "https://files.pythonhosted.org/packages/2b/e7/7c769804eb75e4c4b35e658dba01de1640a351a9653c3d49ca89d16ccc91/cffi-2.0.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:89472c9762729b5ae1ad974b777416bfda4ac5642423fa93bd57a09204712322", size = 218041, upload-time = "2025-09-08T23:24:00.496Z" },
- { url = "https://files.pythonhosted.org/packages/aa/d9/6218d78f920dcd7507fc16a766b5ef8f3b913cc7aa938e7fc80b9978d089/cffi-2.0.0-cp39-cp39-win32.whl", hash = "sha256:2081580ebb843f759b9f617314a24ed5738c51d2aee65d31e02f6f7a2b97707a", size = 172138, upload-time = "2025-09-08T23:24:01.7Z" },
- { url = "https://files.pythonhosted.org/packages/54/8f/a1e836f82d8e32a97e6b29cc8f641779181ac7363734f12df27db803ebda/cffi-2.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:b882b3df248017dba09d6b16defe9b5c407fe32fc7c65a9c69798e6175601be9", size = 182794, upload-time = "2025-09-08T23:24:02.943Z" },
]
[[package]]
@@ -764,50 +660,15 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/b0/6f/8f7af07237c34a1defe7defc565a9bc1807762f672c0fde711a4b22bf9c0/charset_normalizer-3.4.4-cp314-cp314-win32.whl", hash = "sha256:f9d332f8c2a2fcbffe1378594431458ddbef721c1769d78e2cbc06280d8155f9", size = 99940, upload-time = "2025-10-14T04:41:49.946Z" },
{ url = "https://files.pythonhosted.org/packages/4b/51/8ade005e5ca5b0d80fb4aff72a3775b325bdc3d27408c8113811a7cbe640/charset_normalizer-3.4.4-cp314-cp314-win_amd64.whl", hash = "sha256:8a6562c3700cce886c5be75ade4a5db4214fda19fede41d9792d100288d8f94c", size = 107104, upload-time = "2025-10-14T04:41:51.051Z" },
{ url = "https://files.pythonhosted.org/packages/da/5f/6b8f83a55bb8278772c5ae54a577f3099025f9ade59d0136ac24a0df4bde/charset_normalizer-3.4.4-cp314-cp314-win_arm64.whl", hash = "sha256:de00632ca48df9daf77a2c65a484531649261ec9f25489917f09e455cb09ddb2", size = 100743, upload-time = "2025-10-14T04:41:52.122Z" },
- { url = "https://files.pythonhosted.org/packages/46/7c/0c4760bccf082737ca7ab84a4c2034fcc06b1f21cf3032ea98bd6feb1725/charset_normalizer-3.4.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:a9768c477b9d7bd54bc0c86dbaebdec6f03306675526c9927c0e8a04e8f94af9", size = 209609, upload-time = "2025-10-14T04:42:10.922Z" },
- { url = "https://files.pythonhosted.org/packages/bb/a4/69719daef2f3d7f1819de60c9a6be981b8eeead7542d5ec4440f3c80e111/charset_normalizer-3.4.4-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1bee1e43c28aa63cb16e5c14e582580546b08e535299b8b6158a7c9c768a1f3d", size = 149029, upload-time = "2025-10-14T04:42:12.38Z" },
- { url = "https://files.pythonhosted.org/packages/e6/21/8d4e1d6c1e6070d3672908b8e4533a71b5b53e71d16828cc24d0efec564c/charset_normalizer-3.4.4-cp39-cp39-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:fd44c878ea55ba351104cb93cc85e74916eb8fa440ca7903e57575e97394f608", size = 144580, upload-time = "2025-10-14T04:42:13.549Z" },
- { url = "https://files.pythonhosted.org/packages/a7/0a/a616d001b3f25647a9068e0b9199f697ce507ec898cacb06a0d5a1617c99/charset_normalizer-3.4.4-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:0f04b14ffe5fdc8c4933862d8306109a2c51e0704acfa35d51598eb45a1e89fc", size = 162340, upload-time = "2025-10-14T04:42:14.892Z" },
- { url = "https://files.pythonhosted.org/packages/85/93/060b52deb249a5450460e0585c88a904a83aec474ab8e7aba787f45e79f2/charset_normalizer-3.4.4-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:cd09d08005f958f370f539f186d10aec3377d55b9eeb0d796025d4886119d76e", size = 159619, upload-time = "2025-10-14T04:42:16.676Z" },
- { url = "https://files.pythonhosted.org/packages/dd/21/0274deb1cc0632cd587a9a0ec6b4674d9108e461cb4cd40d457adaeb0564/charset_normalizer-3.4.4-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4fe7859a4e3e8457458e2ff592f15ccb02f3da787fcd31e0183879c3ad4692a1", size = 153980, upload-time = "2025-10-14T04:42:17.917Z" },
- { url = "https://files.pythonhosted.org/packages/28/2b/e3d7d982858dccc11b31906976323d790dded2017a0572f093ff982d692f/charset_normalizer-3.4.4-cp39-cp39-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:fa09f53c465e532f4d3db095e0c55b615f010ad81803d383195b6b5ca6cbf5f3", size = 152174, upload-time = "2025-10-14T04:42:19.018Z" },
- { url = "https://files.pythonhosted.org/packages/6e/ff/4a269f8e35f1e58b2df52c131a1fa019acb7ef3f8697b7d464b07e9b492d/charset_normalizer-3.4.4-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:7fa17817dc5625de8a027cb8b26d9fefa3ea28c8253929b8d6649e705d2835b6", size = 151666, upload-time = "2025-10-14T04:42:20.171Z" },
- { url = "https://files.pythonhosted.org/packages/da/c9/ec39870f0b330d58486001dd8e532c6b9a905f5765f58a6f8204926b4a93/charset_normalizer-3.4.4-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:5947809c8a2417be3267efc979c47d76a079758166f7d43ef5ae8e9f92751f88", size = 145550, upload-time = "2025-10-14T04:42:21.324Z" },
- { url = "https://files.pythonhosted.org/packages/75/8f/d186ab99e40e0ed9f82f033d6e49001701c81244d01905dd4a6924191a30/charset_normalizer-3.4.4-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:4902828217069c3c5c71094537a8e623f5d097858ac6ca8252f7b4d10b7560f1", size = 163721, upload-time = "2025-10-14T04:42:22.46Z" },
- { url = "https://files.pythonhosted.org/packages/96/b1/6047663b9744df26a7e479ac1e77af7134b1fcf9026243bb48ee2d18810f/charset_normalizer-3.4.4-cp39-cp39-musllinux_1_2_riscv64.whl", hash = "sha256:7c308f7e26e4363d79df40ca5b2be1c6ba9f02bdbccfed5abddb7859a6ce72cf", size = 152127, upload-time = "2025-10-14T04:42:23.712Z" },
- { url = "https://files.pythonhosted.org/packages/59/78/e5a6eac9179f24f704d1be67d08704c3c6ab9f00963963524be27c18ed87/charset_normalizer-3.4.4-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:2c9d3c380143a1fedbff95a312aa798578371eb29da42106a29019368a475318", size = 161175, upload-time = "2025-10-14T04:42:24.87Z" },
- { url = "https://files.pythonhosted.org/packages/e5/43/0e626e42d54dd2f8dd6fc5e1c5ff00f05fbca17cb699bedead2cae69c62f/charset_normalizer-3.4.4-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:cb01158d8b88ee68f15949894ccc6712278243d95f344770fa7593fa2d94410c", size = 155375, upload-time = "2025-10-14T04:42:27.246Z" },
- { url = "https://files.pythonhosted.org/packages/e9/91/d9615bf2e06f35e4997616ff31248c3657ed649c5ab9d35ea12fce54e380/charset_normalizer-3.4.4-cp39-cp39-win32.whl", hash = "sha256:2677acec1a2f8ef614c6888b5b4ae4060cc184174a938ed4e8ef690e15d3e505", size = 99692, upload-time = "2025-10-14T04:42:28.425Z" },
- { url = "https://files.pythonhosted.org/packages/d1/a9/6c040053909d9d1ef4fcab45fddec083aedc9052c10078339b47c8573ea8/charset_normalizer-3.4.4-cp39-cp39-win_amd64.whl", hash = "sha256:f8e160feb2aed042cd657a72acc0b481212ed28b1b9a95c0cee1621b524e1966", size = 107192, upload-time = "2025-10-14T04:42:29.482Z" },
- { url = "https://files.pythonhosted.org/packages/f0/c6/4fa536b2c0cd3edfb7ccf8469fa0f363ea67b7213a842b90909ca33dd851/charset_normalizer-3.4.4-cp39-cp39-win_arm64.whl", hash = "sha256:b5d84d37db046c5ca74ee7bb47dd6cbc13f80665fdde3e8040bdd3fb015ecb50", size = 100220, upload-time = "2025-10-14T04:42:30.632Z" },
{ url = "https://files.pythonhosted.org/packages/0a/4c/925909008ed5a988ccbb72dcc897407e5d6d3bd72410d69e051fc0c14647/charset_normalizer-3.4.4-py3-none-any.whl", hash = "sha256:7a32c560861a02ff789ad905a2fe94e3f840803362c84fecf1851cb4cf3dc37f", size = 53402, upload-time = "2025-10-14T04:42:31.76Z" },
]
-[[package]]
-name = "click"
-version = "8.1.8"
-source = { registry = "https://pypi.org/simple" }
-resolution-markers = [
- "python_full_version < '3.10'",
-]
-dependencies = [
- { name = "colorama", marker = "python_full_version < '3.10' and sys_platform == 'win32'" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/b9/2e/0090cbf739cee7d23781ad4b89a9894a41538e4fcf4c31dcdd705b78eb8b/click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a", size = 226593, upload-time = "2024-12-21T18:38:44.339Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2", size = 98188, upload-time = "2024-12-21T18:38:41.666Z" },
-]
-
[[package]]
name = "click"
version = "8.3.1"
source = { registry = "https://pypi.org/simple" }
-resolution-markers = [
- "python_full_version >= '3.14'",
- "python_full_version >= '3.10' and python_full_version < '3.14'",
-]
dependencies = [
- { name = "colorama", marker = "python_full_version >= '3.10' and sys_platform == 'win32'" },
+ { name = "colorama", marker = "sys_platform == 'win32'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/3d/fa/656b739db8587d7b5dfa22e22ed02566950fbfbcdc20311993483657a5c0/click-8.3.1.tar.gz", hash = "sha256:12ff4785d337a1bb490bb7e9c2b1ee5da3112e94a8622f26a6c77f5d2fc6842a", size = 295065, upload-time = "2025-11-15T20:45:42.706Z" }
wheels = [
@@ -834,8 +695,7 @@ dependencies = [
{ name = "pydantic-core" },
{ name = "requests" },
{ name = "tokenizers" },
- { name = "types-requests", version = "2.31.0.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
- { name = "types-requests", version = "2.32.4.20260107", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
+ { name = "types-requests" },
{ name = "typing-extensions" },
]
sdist = { url = "https://files.pythonhosted.org/packages/35/37/65af9c50b5d5772a5528c6a949799f98ae286b8ebb924e0fac0619b3ae88/cohere-5.20.4.tar.gz", hash = "sha256:3b3017048ff5d5b4f113180947d538ca3d0f274de5875f0345be4c8cb3d5119a", size = 180737, upload-time = "2026-02-05T14:47:54.639Z" }
@@ -852,133 +712,10 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" },
]
-[[package]]
-name = "coverage"
-version = "7.10.7"
-source = { registry = "https://pypi.org/simple" }
-resolution-markers = [
- "python_full_version < '3.10'",
-]
-sdist = { url = "https://files.pythonhosted.org/packages/51/26/d22c300112504f5f9a9fd2297ce33c35f3d353e4aeb987c8419453b2a7c2/coverage-7.10.7.tar.gz", hash = "sha256:f4ab143ab113be368a3e9b795f9cd7906c5ef407d6173fe9675a902e1fffc239", size = 827704, upload-time = "2025-09-21T20:03:56.815Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/e5/6c/3a3f7a46888e69d18abe3ccc6fe4cb16cccb1e6a2f99698931dafca489e6/coverage-7.10.7-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:fc04cc7a3db33664e0c2d10eb8990ff6b3536f6842c9590ae8da4c614b9ed05a", size = 217987, upload-time = "2025-09-21T20:00:57.218Z" },
- { url = "https://files.pythonhosted.org/packages/03/94/952d30f180b1a916c11a56f5c22d3535e943aa22430e9e3322447e520e1c/coverage-7.10.7-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e201e015644e207139f7e2351980feb7040e6f4b2c2978892f3e3789d1c125e5", size = 218388, upload-time = "2025-09-21T20:01:00.081Z" },
- { url = "https://files.pythonhosted.org/packages/50/2b/9e0cf8ded1e114bcd8b2fd42792b57f1c4e9e4ea1824cde2af93a67305be/coverage-7.10.7-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:240af60539987ced2c399809bd34f7c78e8abe0736af91c3d7d0e795df633d17", size = 245148, upload-time = "2025-09-21T20:01:01.768Z" },
- { url = "https://files.pythonhosted.org/packages/19/20/d0384ac06a6f908783d9b6aa6135e41b093971499ec488e47279f5b846e6/coverage-7.10.7-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:8421e088bc051361b01c4b3a50fd39a4b9133079a2229978d9d30511fd05231b", size = 246958, upload-time = "2025-09-21T20:01:03.355Z" },
- { url = "https://files.pythonhosted.org/packages/60/83/5c283cff3d41285f8eab897651585db908a909c572bdc014bcfaf8a8b6ae/coverage-7.10.7-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6be8ed3039ae7f7ac5ce058c308484787c86e8437e72b30bf5e88b8ea10f3c87", size = 248819, upload-time = "2025-09-21T20:01:04.968Z" },
- { url = "https://files.pythonhosted.org/packages/60/22/02eb98fdc5ff79f423e990d877693e5310ae1eab6cb20ae0b0b9ac45b23b/coverage-7.10.7-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e28299d9f2e889e6d51b1f043f58d5f997c373cc12e6403b90df95b8b047c13e", size = 245754, upload-time = "2025-09-21T20:01:06.321Z" },
- { url = "https://files.pythonhosted.org/packages/b4/bc/25c83bcf3ad141b32cd7dc45485ef3c01a776ca3aa8ef0a93e77e8b5bc43/coverage-7.10.7-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:c4e16bd7761c5e454f4efd36f345286d6f7c5fa111623c355691e2755cae3b9e", size = 246860, upload-time = "2025-09-21T20:01:07.605Z" },
- { url = "https://files.pythonhosted.org/packages/3c/b7/95574702888b58c0928a6e982038c596f9c34d52c5e5107f1eef729399b5/coverage-7.10.7-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:b1c81d0e5e160651879755c9c675b974276f135558cf4ba79fee7b8413a515df", size = 244877, upload-time = "2025-09-21T20:01:08.829Z" },
- { url = "https://files.pythonhosted.org/packages/47/b6/40095c185f235e085df0e0b158f6bd68cc6e1d80ba6c7721dc81d97ec318/coverage-7.10.7-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:606cc265adc9aaedcc84f1f064f0e8736bc45814f15a357e30fca7ecc01504e0", size = 245108, upload-time = "2025-09-21T20:01:10.527Z" },
- { url = "https://files.pythonhosted.org/packages/c8/50/4aea0556da7a4b93ec9168420d170b55e2eb50ae21b25062513d020c6861/coverage-7.10.7-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:10b24412692df990dbc34f8fb1b6b13d236ace9dfdd68df5b28c2e39cafbba13", size = 245752, upload-time = "2025-09-21T20:01:11.857Z" },
- { url = "https://files.pythonhosted.org/packages/6a/28/ea1a84a60828177ae3b100cb6723838523369a44ec5742313ed7db3da160/coverage-7.10.7-cp310-cp310-win32.whl", hash = "sha256:b51dcd060f18c19290d9b8a9dd1e0181538df2ce0717f562fff6cf74d9fc0b5b", size = 220497, upload-time = "2025-09-21T20:01:13.459Z" },
- { url = "https://files.pythonhosted.org/packages/fc/1a/a81d46bbeb3c3fd97b9602ebaa411e076219a150489bcc2c025f151bd52d/coverage-7.10.7-cp310-cp310-win_amd64.whl", hash = "sha256:3a622ac801b17198020f09af3eaf45666b344a0d69fc2a6ffe2ea83aeef1d807", size = 221392, upload-time = "2025-09-21T20:01:14.722Z" },
- { url = "https://files.pythonhosted.org/packages/d2/5d/c1a17867b0456f2e9ce2d8d4708a4c3a089947d0bec9c66cdf60c9e7739f/coverage-7.10.7-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a609f9c93113be646f44c2a0256d6ea375ad047005d7f57a5c15f614dc1b2f59", size = 218102, upload-time = "2025-09-21T20:01:16.089Z" },
- { url = "https://files.pythonhosted.org/packages/54/f0/514dcf4b4e3698b9a9077f084429681bf3aad2b4a72578f89d7f643eb506/coverage-7.10.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:65646bb0359386e07639c367a22cf9b5bf6304e8630b565d0626e2bdf329227a", size = 218505, upload-time = "2025-09-21T20:01:17.788Z" },
- { url = "https://files.pythonhosted.org/packages/20/f6/9626b81d17e2a4b25c63ac1b425ff307ecdeef03d67c9a147673ae40dc36/coverage-7.10.7-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:5f33166f0dfcce728191f520bd2692914ec70fac2713f6bf3ce59c3deacb4699", size = 248898, upload-time = "2025-09-21T20:01:19.488Z" },
- { url = "https://files.pythonhosted.org/packages/b0/ef/bd8e719c2f7417ba03239052e099b76ea1130ac0cbb183ee1fcaa58aaff3/coverage-7.10.7-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:35f5e3f9e455bb17831876048355dca0f758b6df22f49258cb5a91da23ef437d", size = 250831, upload-time = "2025-09-21T20:01:20.817Z" },
- { url = "https://files.pythonhosted.org/packages/a5/b6/bf054de41ec948b151ae2b79a55c107f5760979538f5fb80c195f2517718/coverage-7.10.7-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4da86b6d62a496e908ac2898243920c7992499c1712ff7c2b6d837cc69d9467e", size = 252937, upload-time = "2025-09-21T20:01:22.171Z" },
- { url = "https://files.pythonhosted.org/packages/0f/e5/3860756aa6f9318227443c6ce4ed7bf9e70bb7f1447a0353f45ac5c7974b/coverage-7.10.7-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:6b8b09c1fad947c84bbbc95eca841350fad9cbfa5a2d7ca88ac9f8d836c92e23", size = 249021, upload-time = "2025-09-21T20:01:23.907Z" },
- { url = "https://files.pythonhosted.org/packages/26/0f/bd08bd042854f7fd07b45808927ebcce99a7ed0f2f412d11629883517ac2/coverage-7.10.7-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:4376538f36b533b46f8971d3a3e63464f2c7905c9800db97361c43a2b14792ab", size = 250626, upload-time = "2025-09-21T20:01:25.721Z" },
- { url = "https://files.pythonhosted.org/packages/8e/a7/4777b14de4abcc2e80c6b1d430f5d51eb18ed1d75fca56cbce5f2db9b36e/coverage-7.10.7-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:121da30abb574f6ce6ae09840dae322bef734480ceafe410117627aa54f76d82", size = 248682, upload-time = "2025-09-21T20:01:27.105Z" },
- { url = "https://files.pythonhosted.org/packages/34/72/17d082b00b53cd45679bad682fac058b87f011fd8b9fe31d77f5f8d3a4e4/coverage-7.10.7-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:88127d40df529336a9836870436fc2751c339fbaed3a836d42c93f3e4bd1d0a2", size = 248402, upload-time = "2025-09-21T20:01:28.629Z" },
- { url = "https://files.pythonhosted.org/packages/81/7a/92367572eb5bdd6a84bfa278cc7e97db192f9f45b28c94a9ca1a921c3577/coverage-7.10.7-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ba58bbcd1b72f136080c0bccc2400d66cc6115f3f906c499013d065ac33a4b61", size = 249320, upload-time = "2025-09-21T20:01:30.004Z" },
- { url = "https://files.pythonhosted.org/packages/2f/88/a23cc185f6a805dfc4fdf14a94016835eeb85e22ac3a0e66d5e89acd6462/coverage-7.10.7-cp311-cp311-win32.whl", hash = "sha256:972b9e3a4094b053a4e46832b4bc829fc8a8d347160eb39d03f1690316a99c14", size = 220536, upload-time = "2025-09-21T20:01:32.184Z" },
- { url = "https://files.pythonhosted.org/packages/fe/ef/0b510a399dfca17cec7bc2f05ad8bd78cf55f15c8bc9a73ab20c5c913c2e/coverage-7.10.7-cp311-cp311-win_amd64.whl", hash = "sha256:a7b55a944a7f43892e28ad4bc0561dfd5f0d73e605d1aa5c3c976b52aea121d2", size = 221425, upload-time = "2025-09-21T20:01:33.557Z" },
- { url = "https://files.pythonhosted.org/packages/51/7f/023657f301a276e4ba1850f82749bc136f5a7e8768060c2e5d9744a22951/coverage-7.10.7-cp311-cp311-win_arm64.whl", hash = "sha256:736f227fb490f03c6488f9b6d45855f8e0fd749c007f9303ad30efab0e73c05a", size = 220103, upload-time = "2025-09-21T20:01:34.929Z" },
- { url = "https://files.pythonhosted.org/packages/13/e4/eb12450f71b542a53972d19117ea5a5cea1cab3ac9e31b0b5d498df1bd5a/coverage-7.10.7-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7bb3b9ddb87ef7725056572368040c32775036472d5a033679d1fa6c8dc08417", size = 218290, upload-time = "2025-09-21T20:01:36.455Z" },
- { url = "https://files.pythonhosted.org/packages/37/66/593f9be12fc19fb36711f19a5371af79a718537204d16ea1d36f16bd78d2/coverage-7.10.7-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:18afb24843cbc175687225cab1138c95d262337f5473512010e46831aa0c2973", size = 218515, upload-time = "2025-09-21T20:01:37.982Z" },
- { url = "https://files.pythonhosted.org/packages/66/80/4c49f7ae09cafdacc73fbc30949ffe77359635c168f4e9ff33c9ebb07838/coverage-7.10.7-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:399a0b6347bcd3822be369392932884b8216d0944049ae22925631a9b3d4ba4c", size = 250020, upload-time = "2025-09-21T20:01:39.617Z" },
- { url = "https://files.pythonhosted.org/packages/a6/90/a64aaacab3b37a17aaedd83e8000142561a29eb262cede42d94a67f7556b/coverage-7.10.7-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:314f2c326ded3f4b09be11bc282eb2fc861184bc95748ae67b360ac962770be7", size = 252769, upload-time = "2025-09-21T20:01:41.341Z" },
- { url = "https://files.pythonhosted.org/packages/98/2e/2dda59afd6103b342e096f246ebc5f87a3363b5412609946c120f4e7750d/coverage-7.10.7-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c41e71c9cfb854789dee6fc51e46743a6d138b1803fab6cb860af43265b42ea6", size = 253901, upload-time = "2025-09-21T20:01:43.042Z" },
- { url = "https://files.pythonhosted.org/packages/53/dc/8d8119c9051d50f3119bb4a75f29f1e4a6ab9415cd1fa8bf22fcc3fb3b5f/coverage-7.10.7-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc01f57ca26269c2c706e838f6422e2a8788e41b3e3c65e2f41148212e57cd59", size = 250413, upload-time = "2025-09-21T20:01:44.469Z" },
- { url = "https://files.pythonhosted.org/packages/98/b3/edaff9c5d79ee4d4b6d3fe046f2b1d799850425695b789d491a64225d493/coverage-7.10.7-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a6442c59a8ac8b85812ce33bc4d05bde3fb22321fa8294e2a5b487c3505f611b", size = 251820, upload-time = "2025-09-21T20:01:45.915Z" },
- { url = "https://files.pythonhosted.org/packages/11/25/9a0728564bb05863f7e513e5a594fe5ffef091b325437f5430e8cfb0d530/coverage-7.10.7-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:78a384e49f46b80fb4c901d52d92abe098e78768ed829c673fbb53c498bef73a", size = 249941, upload-time = "2025-09-21T20:01:47.296Z" },
- { url = "https://files.pythonhosted.org/packages/e0/fd/ca2650443bfbef5b0e74373aac4df67b08180d2f184b482c41499668e258/coverage-7.10.7-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:5e1e9802121405ede4b0133aa4340ad8186a1d2526de5b7c3eca519db7bb89fb", size = 249519, upload-time = "2025-09-21T20:01:48.73Z" },
- { url = "https://files.pythonhosted.org/packages/24/79/f692f125fb4299b6f963b0745124998ebb8e73ecdfce4ceceb06a8c6bec5/coverage-7.10.7-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:d41213ea25a86f69efd1575073d34ea11aabe075604ddf3d148ecfec9e1e96a1", size = 251375, upload-time = "2025-09-21T20:01:50.529Z" },
- { url = "https://files.pythonhosted.org/packages/5e/75/61b9bbd6c7d24d896bfeec57acba78e0f8deac68e6baf2d4804f7aae1f88/coverage-7.10.7-cp312-cp312-win32.whl", hash = "sha256:77eb4c747061a6af8d0f7bdb31f1e108d172762ef579166ec84542f711d90256", size = 220699, upload-time = "2025-09-21T20:01:51.941Z" },
- { url = "https://files.pythonhosted.org/packages/ca/f3/3bf7905288b45b075918d372498f1cf845b5b579b723c8fd17168018d5f5/coverage-7.10.7-cp312-cp312-win_amd64.whl", hash = "sha256:f51328ffe987aecf6d09f3cd9d979face89a617eacdaea43e7b3080777f647ba", size = 221512, upload-time = "2025-09-21T20:01:53.481Z" },
- { url = "https://files.pythonhosted.org/packages/5c/44/3e32dbe933979d05cf2dac5e697c8599cfe038aaf51223ab901e208d5a62/coverage-7.10.7-cp312-cp312-win_arm64.whl", hash = "sha256:bda5e34f8a75721c96085903c6f2197dc398c20ffd98df33f866a9c8fd95f4bf", size = 220147, upload-time = "2025-09-21T20:01:55.2Z" },
- { url = "https://files.pythonhosted.org/packages/9a/94/b765c1abcb613d103b64fcf10395f54d69b0ef8be6a0dd9c524384892cc7/coverage-7.10.7-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:981a651f543f2854abd3b5fcb3263aac581b18209be49863ba575de6edf4c14d", size = 218320, upload-time = "2025-09-21T20:01:56.629Z" },
- { url = "https://files.pythonhosted.org/packages/72/4f/732fff31c119bb73b35236dd333030f32c4bfe909f445b423e6c7594f9a2/coverage-7.10.7-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:73ab1601f84dc804f7812dc297e93cd99381162da39c47040a827d4e8dafe63b", size = 218575, upload-time = "2025-09-21T20:01:58.203Z" },
- { url = "https://files.pythonhosted.org/packages/87/02/ae7e0af4b674be47566707777db1aa375474f02a1d64b9323e5813a6cdd5/coverage-7.10.7-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:a8b6f03672aa6734e700bbcd65ff050fd19cddfec4b031cc8cf1c6967de5a68e", size = 249568, upload-time = "2025-09-21T20:01:59.748Z" },
- { url = "https://files.pythonhosted.org/packages/a2/77/8c6d22bf61921a59bce5471c2f1f7ac30cd4ac50aadde72b8c48d5727902/coverage-7.10.7-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:10b6ba00ab1132a0ce4428ff68cf50a25efd6840a42cdf4239c9b99aad83be8b", size = 252174, upload-time = "2025-09-21T20:02:01.192Z" },
- { url = "https://files.pythonhosted.org/packages/b1/20/b6ea4f69bbb52dac0aebd62157ba6a9dddbfe664f5af8122dac296c3ee15/coverage-7.10.7-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c79124f70465a150e89340de5963f936ee97097d2ef76c869708c4248c63ca49", size = 253447, upload-time = "2025-09-21T20:02:02.701Z" },
- { url = "https://files.pythonhosted.org/packages/f9/28/4831523ba483a7f90f7b259d2018fef02cb4d5b90bc7c1505d6e5a84883c/coverage-7.10.7-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:69212fbccdbd5b0e39eac4067e20a4a5256609e209547d86f740d68ad4f04911", size = 249779, upload-time = "2025-09-21T20:02:04.185Z" },
- { url = "https://files.pythonhosted.org/packages/a7/9f/4331142bc98c10ca6436d2d620c3e165f31e6c58d43479985afce6f3191c/coverage-7.10.7-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:7ea7c6c9d0d286d04ed3541747e6597cbe4971f22648b68248f7ddcd329207f0", size = 251604, upload-time = "2025-09-21T20:02:06.034Z" },
- { url = "https://files.pythonhosted.org/packages/ce/60/bda83b96602036b77ecf34e6393a3836365481b69f7ed7079ab85048202b/coverage-7.10.7-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b9be91986841a75042b3e3243d0b3cb0b2434252b977baaf0cd56e960fe1e46f", size = 249497, upload-time = "2025-09-21T20:02:07.619Z" },
- { url = "https://files.pythonhosted.org/packages/5f/af/152633ff35b2af63977edd835d8e6430f0caef27d171edf2fc76c270ef31/coverage-7.10.7-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:b281d5eca50189325cfe1f365fafade89b14b4a78d9b40b05ddd1fc7d2a10a9c", size = 249350, upload-time = "2025-09-21T20:02:10.34Z" },
- { url = "https://files.pythonhosted.org/packages/9d/71/d92105d122bd21cebba877228990e1646d862e34a98bb3374d3fece5a794/coverage-7.10.7-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:99e4aa63097ab1118e75a848a28e40d68b08a5e19ce587891ab7fd04475e780f", size = 251111, upload-time = "2025-09-21T20:02:12.122Z" },
- { url = "https://files.pythonhosted.org/packages/a2/9e/9fdb08f4bf476c912f0c3ca292e019aab6712c93c9344a1653986c3fd305/coverage-7.10.7-cp313-cp313-win32.whl", hash = "sha256:dc7c389dce432500273eaf48f410b37886be9208b2dd5710aaf7c57fd442c698", size = 220746, upload-time = "2025-09-21T20:02:13.919Z" },
- { url = "https://files.pythonhosted.org/packages/b1/b1/a75fd25df44eab52d1931e89980d1ada46824c7a3210be0d3c88a44aaa99/coverage-7.10.7-cp313-cp313-win_amd64.whl", hash = "sha256:cac0fdca17b036af3881a9d2729a850b76553f3f716ccb0360ad4dbc06b3b843", size = 221541, upload-time = "2025-09-21T20:02:15.57Z" },
- { url = "https://files.pythonhosted.org/packages/14/3a/d720d7c989562a6e9a14b2c9f5f2876bdb38e9367126d118495b89c99c37/coverage-7.10.7-cp313-cp313-win_arm64.whl", hash = "sha256:4b6f236edf6e2f9ae8fcd1332da4e791c1b6ba0dc16a2dc94590ceccb482e546", size = 220170, upload-time = "2025-09-21T20:02:17.395Z" },
- { url = "https://files.pythonhosted.org/packages/bb/22/e04514bf2a735d8b0add31d2b4ab636fc02370730787c576bb995390d2d5/coverage-7.10.7-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:a0ec07fd264d0745ee396b666d47cef20875f4ff2375d7c4f58235886cc1ef0c", size = 219029, upload-time = "2025-09-21T20:02:18.936Z" },
- { url = "https://files.pythonhosted.org/packages/11/0b/91128e099035ece15da3445d9015e4b4153a6059403452d324cbb0a575fa/coverage-7.10.7-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:dd5e856ebb7bfb7672b0086846db5afb4567a7b9714b8a0ebafd211ec7ce6a15", size = 219259, upload-time = "2025-09-21T20:02:20.44Z" },
- { url = "https://files.pythonhosted.org/packages/8b/51/66420081e72801536a091a0c8f8c1f88a5c4bf7b9b1bdc6222c7afe6dc9b/coverage-7.10.7-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:f57b2a3c8353d3e04acf75b3fed57ba41f5c0646bbf1d10c7c282291c97936b4", size = 260592, upload-time = "2025-09-21T20:02:22.313Z" },
- { url = "https://files.pythonhosted.org/packages/5d/22/9b8d458c2881b22df3db5bb3e7369e63d527d986decb6c11a591ba2364f7/coverage-7.10.7-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:1ef2319dd15a0b009667301a3f84452a4dc6fddfd06b0c5c53ea472d3989fbf0", size = 262768, upload-time = "2025-09-21T20:02:24.287Z" },
- { url = "https://files.pythonhosted.org/packages/f7/08/16bee2c433e60913c610ea200b276e8eeef084b0d200bdcff69920bd5828/coverage-7.10.7-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:83082a57783239717ceb0ad584de3c69cf581b2a95ed6bf81ea66034f00401c0", size = 264995, upload-time = "2025-09-21T20:02:26.133Z" },
- { url = "https://files.pythonhosted.org/packages/20/9d/e53eb9771d154859b084b90201e5221bca7674ba449a17c101a5031d4054/coverage-7.10.7-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:50aa94fb1fb9a397eaa19c0d5ec15a5edd03a47bf1a3a6111a16b36e190cff65", size = 259546, upload-time = "2025-09-21T20:02:27.716Z" },
- { url = "https://files.pythonhosted.org/packages/ad/b0/69bc7050f8d4e56a89fb550a1577d5d0d1db2278106f6f626464067b3817/coverage-7.10.7-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:2120043f147bebb41c85b97ac45dd173595ff14f2a584f2963891cbcc3091541", size = 262544, upload-time = "2025-09-21T20:02:29.216Z" },
- { url = "https://files.pythonhosted.org/packages/ef/4b/2514b060dbd1bc0aaf23b852c14bb5818f244c664cb16517feff6bb3a5ab/coverage-7.10.7-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:2fafd773231dd0378fdba66d339f84904a8e57a262f583530f4f156ab83863e6", size = 260308, upload-time = "2025-09-21T20:02:31.226Z" },
- { url = "https://files.pythonhosted.org/packages/54/78/7ba2175007c246d75e496f64c06e94122bdb914790a1285d627a918bd271/coverage-7.10.7-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:0b944ee8459f515f28b851728ad224fa2d068f1513ef6b7ff1efafeb2185f999", size = 258920, upload-time = "2025-09-21T20:02:32.823Z" },
- { url = "https://files.pythonhosted.org/packages/c0/b3/fac9f7abbc841409b9a410309d73bfa6cfb2e51c3fada738cb607ce174f8/coverage-7.10.7-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:4b583b97ab2e3efe1b3e75248a9b333bd3f8b0b1b8e5b45578e05e5850dfb2c2", size = 261434, upload-time = "2025-09-21T20:02:34.86Z" },
- { url = "https://files.pythonhosted.org/packages/ee/51/a03bec00d37faaa891b3ff7387192cef20f01604e5283a5fabc95346befa/coverage-7.10.7-cp313-cp313t-win32.whl", hash = "sha256:2a78cd46550081a7909b3329e2266204d584866e8d97b898cd7fb5ac8d888b1a", size = 221403, upload-time = "2025-09-21T20:02:37.034Z" },
- { url = "https://files.pythonhosted.org/packages/53/22/3cf25d614e64bf6d8e59c7c669b20d6d940bb337bdee5900b9ca41c820bb/coverage-7.10.7-cp313-cp313t-win_amd64.whl", hash = "sha256:33a5e6396ab684cb43dc7befa386258acb2d7fae7f67330ebb85ba4ea27938eb", size = 222469, upload-time = "2025-09-21T20:02:39.011Z" },
- { url = "https://files.pythonhosted.org/packages/49/a1/00164f6d30d8a01c3c9c48418a7a5be394de5349b421b9ee019f380df2a0/coverage-7.10.7-cp313-cp313t-win_arm64.whl", hash = "sha256:86b0e7308289ddde73d863b7683f596d8d21c7d8664ce1dee061d0bcf3fbb4bb", size = 220731, upload-time = "2025-09-21T20:02:40.939Z" },
- { url = "https://files.pythonhosted.org/packages/23/9c/5844ab4ca6a4dd97a1850e030a15ec7d292b5c5cb93082979225126e35dd/coverage-7.10.7-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:b06f260b16ead11643a5a9f955bd4b5fd76c1a4c6796aeade8520095b75de520", size = 218302, upload-time = "2025-09-21T20:02:42.527Z" },
- { url = "https://files.pythonhosted.org/packages/f0/89/673f6514b0961d1f0e20ddc242e9342f6da21eaba3489901b565c0689f34/coverage-7.10.7-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:212f8f2e0612778f09c55dd4872cb1f64a1f2b074393d139278ce902064d5b32", size = 218578, upload-time = "2025-09-21T20:02:44.468Z" },
- { url = "https://files.pythonhosted.org/packages/05/e8/261cae479e85232828fb17ad536765c88dd818c8470aca690b0ac6feeaa3/coverage-7.10.7-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:3445258bcded7d4aa630ab8296dea4d3f15a255588dd535f980c193ab6b95f3f", size = 249629, upload-time = "2025-09-21T20:02:46.503Z" },
- { url = "https://files.pythonhosted.org/packages/82/62/14ed6546d0207e6eda876434e3e8475a3e9adbe32110ce896c9e0c06bb9a/coverage-7.10.7-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:bb45474711ba385c46a0bfe696c695a929ae69ac636cda8f532be9e8c93d720a", size = 252162, upload-time = "2025-09-21T20:02:48.689Z" },
- { url = "https://files.pythonhosted.org/packages/ff/49/07f00db9ac6478e4358165a08fb41b469a1b053212e8a00cb02f0d27a05f/coverage-7.10.7-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:813922f35bd800dca9994c5971883cbc0d291128a5de6b167c7aa697fcf59360", size = 253517, upload-time = "2025-09-21T20:02:50.31Z" },
- { url = "https://files.pythonhosted.org/packages/a2/59/c5201c62dbf165dfbc91460f6dbbaa85a8b82cfa6131ac45d6c1bfb52deb/coverage-7.10.7-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:93c1b03552081b2a4423091d6fb3787265b8f86af404cff98d1b5342713bdd69", size = 249632, upload-time = "2025-09-21T20:02:51.971Z" },
- { url = "https://files.pythonhosted.org/packages/07/ae/5920097195291a51fb00b3a70b9bbd2edbfe3c84876a1762bd1ef1565ebc/coverage-7.10.7-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:cc87dd1b6eaf0b848eebb1c86469b9f72a1891cb42ac7adcfbce75eadb13dd14", size = 251520, upload-time = "2025-09-21T20:02:53.858Z" },
- { url = "https://files.pythonhosted.org/packages/b9/3c/a815dde77a2981f5743a60b63df31cb322c944843e57dbd579326625a413/coverage-7.10.7-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:39508ffda4f343c35f3236fe8d1a6634a51f4581226a1262769d7f970e73bffe", size = 249455, upload-time = "2025-09-21T20:02:55.807Z" },
- { url = "https://files.pythonhosted.org/packages/aa/99/f5cdd8421ea656abefb6c0ce92556709db2265c41e8f9fc6c8ae0f7824c9/coverage-7.10.7-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:925a1edf3d810537c5a3abe78ec5530160c5f9a26b1f4270b40e62cc79304a1e", size = 249287, upload-time = "2025-09-21T20:02:57.784Z" },
- { url = "https://files.pythonhosted.org/packages/c3/7a/e9a2da6a1fc5d007dd51fca083a663ab930a8c4d149c087732a5dbaa0029/coverage-7.10.7-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2c8b9a0636f94c43cd3576811e05b89aa9bc2d0a85137affc544ae5cb0e4bfbd", size = 250946, upload-time = "2025-09-21T20:02:59.431Z" },
- { url = "https://files.pythonhosted.org/packages/ef/5b/0b5799aa30380a949005a353715095d6d1da81927d6dbed5def2200a4e25/coverage-7.10.7-cp314-cp314-win32.whl", hash = "sha256:b7b8288eb7cdd268b0304632da8cb0bb93fadcfec2fe5712f7b9cc8f4d487be2", size = 221009, upload-time = "2025-09-21T20:03:01.324Z" },
- { url = "https://files.pythonhosted.org/packages/da/b0/e802fbb6eb746de006490abc9bb554b708918b6774b722bb3a0e6aa1b7de/coverage-7.10.7-cp314-cp314-win_amd64.whl", hash = "sha256:1ca6db7c8807fb9e755d0379ccc39017ce0a84dcd26d14b5a03b78563776f681", size = 221804, upload-time = "2025-09-21T20:03:03.4Z" },
- { url = "https://files.pythonhosted.org/packages/9e/e8/71d0c8e374e31f39e3389bb0bd19e527d46f00ea8571ec7ec8fd261d8b44/coverage-7.10.7-cp314-cp314-win_arm64.whl", hash = "sha256:097c1591f5af4496226d5783d036bf6fd6cd0cbc132e071b33861de756efb880", size = 220384, upload-time = "2025-09-21T20:03:05.111Z" },
- { url = "https://files.pythonhosted.org/packages/62/09/9a5608d319fa3eba7a2019addeacb8c746fb50872b57a724c9f79f146969/coverage-7.10.7-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:a62c6ef0d50e6de320c270ff91d9dd0a05e7250cac2a800b7784bae474506e63", size = 219047, upload-time = "2025-09-21T20:03:06.795Z" },
- { url = "https://files.pythonhosted.org/packages/f5/6f/f58d46f33db9f2e3647b2d0764704548c184e6f5e014bef528b7f979ef84/coverage-7.10.7-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:9fa6e4dd51fe15d8738708a973470f67a855ca50002294852e9571cdbd9433f2", size = 219266, upload-time = "2025-09-21T20:03:08.495Z" },
- { url = "https://files.pythonhosted.org/packages/74/5c/183ffc817ba68e0b443b8c934c8795553eb0c14573813415bd59941ee165/coverage-7.10.7-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:8fb190658865565c549b6b4706856d6a7b09302c797eb2cf8e7fe9dabb043f0d", size = 260767, upload-time = "2025-09-21T20:03:10.172Z" },
- { url = "https://files.pythonhosted.org/packages/0f/48/71a8abe9c1ad7e97548835e3cc1adbf361e743e9d60310c5f75c9e7bf847/coverage-7.10.7-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:affef7c76a9ef259187ef31599a9260330e0335a3011732c4b9effa01e1cd6e0", size = 262931, upload-time = "2025-09-21T20:03:11.861Z" },
- { url = "https://files.pythonhosted.org/packages/84/fd/193a8fb132acfc0a901f72020e54be5e48021e1575bb327d8ee1097a28fd/coverage-7.10.7-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6e16e07d85ca0cf8bafe5f5d23a0b850064e8e945d5677492b06bbe6f09cc699", size = 265186, upload-time = "2025-09-21T20:03:13.539Z" },
- { url = "https://files.pythonhosted.org/packages/b1/8f/74ecc30607dd95ad50e3034221113ccb1c6d4e8085cc761134782995daae/coverage-7.10.7-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:03ffc58aacdf65d2a82bbeb1ffe4d01ead4017a21bfd0454983b88ca73af94b9", size = 259470, upload-time = "2025-09-21T20:03:15.584Z" },
- { url = "https://files.pythonhosted.org/packages/0f/55/79ff53a769f20d71b07023ea115c9167c0bb56f281320520cf64c5298a96/coverage-7.10.7-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:1b4fd784344d4e52647fd7857b2af5b3fbe6c239b0b5fa63e94eb67320770e0f", size = 262626, upload-time = "2025-09-21T20:03:17.673Z" },
- { url = "https://files.pythonhosted.org/packages/88/e2/dac66c140009b61ac3fc13af673a574b00c16efdf04f9b5c740703e953c0/coverage-7.10.7-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:0ebbaddb2c19b71912c6f2518e791aa8b9f054985a0769bdb3a53ebbc765c6a1", size = 260386, upload-time = "2025-09-21T20:03:19.36Z" },
- { url = "https://files.pythonhosted.org/packages/a2/f1/f48f645e3f33bb9ca8a496bc4a9671b52f2f353146233ebd7c1df6160440/coverage-7.10.7-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:a2d9a3b260cc1d1dbdb1c582e63ddcf5363426a1a68faa0f5da28d8ee3c722a0", size = 258852, upload-time = "2025-09-21T20:03:21.007Z" },
- { url = "https://files.pythonhosted.org/packages/bb/3b/8442618972c51a7affeead957995cfa8323c0c9bcf8fa5a027421f720ff4/coverage-7.10.7-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:a3cc8638b2480865eaa3926d192e64ce6c51e3d29c849e09d5b4ad95efae5399", size = 261534, upload-time = "2025-09-21T20:03:23.12Z" },
- { url = "https://files.pythonhosted.org/packages/b2/dc/101f3fa3a45146db0cb03f5b4376e24c0aac818309da23e2de0c75295a91/coverage-7.10.7-cp314-cp314t-win32.whl", hash = "sha256:67f8c5cbcd3deb7a60b3345dffc89a961a484ed0af1f6f73de91705cc6e31235", size = 221784, upload-time = "2025-09-21T20:03:24.769Z" },
- { url = "https://files.pythonhosted.org/packages/4c/a1/74c51803fc70a8a40d7346660379e144be772bab4ac7bb6e6b905152345c/coverage-7.10.7-cp314-cp314t-win_amd64.whl", hash = "sha256:e1ed71194ef6dea7ed2d5cb5f7243d4bcd334bfb63e59878519be558078f848d", size = 222905, upload-time = "2025-09-21T20:03:26.93Z" },
- { url = "https://files.pythonhosted.org/packages/12/65/f116a6d2127df30bcafbceef0302d8a64ba87488bf6f73a6d8eebf060873/coverage-7.10.7-cp314-cp314t-win_arm64.whl", hash = "sha256:7fe650342addd8524ca63d77b2362b02345e5f1a093266787d210c70a50b471a", size = 220922, upload-time = "2025-09-21T20:03:28.672Z" },
- { url = "https://files.pythonhosted.org/packages/a3/ad/d1c25053764b4c42eb294aae92ab617d2e4f803397f9c7c8295caa77a260/coverage-7.10.7-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:fff7b9c3f19957020cac546c70025331113d2e61537f6e2441bc7657913de7d3", size = 217978, upload-time = "2025-09-21T20:03:30.362Z" },
- { url = "https://files.pythonhosted.org/packages/52/2f/b9f9daa39b80ece0b9548bbb723381e29bc664822d9a12c2135f8922c22b/coverage-7.10.7-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:bc91b314cef27742da486d6839b677b3f2793dfe52b51bbbb7cf736d5c29281c", size = 218370, upload-time = "2025-09-21T20:03:32.147Z" },
- { url = "https://files.pythonhosted.org/packages/dd/6e/30d006c3b469e58449650642383dddf1c8fb63d44fdf92994bfd46570695/coverage-7.10.7-cp39-cp39-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:567f5c155eda8df1d3d439d40a45a6a5f029b429b06648235f1e7e51b522b396", size = 244802, upload-time = "2025-09-21T20:03:33.919Z" },
- { url = "https://files.pythonhosted.org/packages/b0/49/8a070782ce7e6b94ff6a0b6d7c65ba6bc3091d92a92cef4cd4eb0767965c/coverage-7.10.7-cp39-cp39-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:2af88deffcc8a4d5974cf2d502251bc3b2db8461f0b66d80a449c33757aa9f40", size = 246625, upload-time = "2025-09-21T20:03:36.09Z" },
- { url = "https://files.pythonhosted.org/packages/6a/92/1c1c5a9e8677ce56d42b97bdaca337b2d4d9ebe703d8c174ede52dbabd5f/coverage-7.10.7-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c7315339eae3b24c2d2fa1ed7d7a38654cba34a13ef19fbcb9425da46d3dc594", size = 248399, upload-time = "2025-09-21T20:03:38.342Z" },
- { url = "https://files.pythonhosted.org/packages/c0/54/b140edee7257e815de7426d5d9846b58505dffc29795fff2dfb7f8a1c5a0/coverage-7.10.7-cp39-cp39-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:912e6ebc7a6e4adfdbb1aec371ad04c68854cd3bf3608b3514e7ff9062931d8a", size = 245142, upload-time = "2025-09-21T20:03:40.591Z" },
- { url = "https://files.pythonhosted.org/packages/e4/9e/6d6b8295940b118e8b7083b29226c71f6154f7ff41e9ca431f03de2eac0d/coverage-7.10.7-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:f49a05acd3dfe1ce9715b657e28d138578bc40126760efb962322c56e9ca344b", size = 246284, upload-time = "2025-09-21T20:03:42.355Z" },
- { url = "https://files.pythonhosted.org/packages/db/e5/5e957ca747d43dbe4d9714358375c7546cb3cb533007b6813fc20fce37ad/coverage-7.10.7-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:cce2109b6219f22ece99db7644b9622f54a4e915dad65660ec435e89a3ea7cc3", size = 244353, upload-time = "2025-09-21T20:03:44.218Z" },
- { url = "https://files.pythonhosted.org/packages/9a/45/540fc5cc92536a1b783b7ef99450bd55a4b3af234aae35a18a339973ce30/coverage-7.10.7-cp39-cp39-musllinux_1_2_riscv64.whl", hash = "sha256:f3c887f96407cea3916294046fc7dab611c2552beadbed4ea901cbc6a40cc7a0", size = 244430, upload-time = "2025-09-21T20:03:46.065Z" },
- { url = "https://files.pythonhosted.org/packages/75/0b/8287b2e5b38c8fe15d7e3398849bb58d382aedc0864ea0fa1820e8630491/coverage-7.10.7-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:635adb9a4507c9fd2ed65f39693fa31c9a3ee3a8e6dc64df033e8fdf52a7003f", size = 245311, upload-time = "2025-09-21T20:03:48.19Z" },
- { url = "https://files.pythonhosted.org/packages/0c/1d/29724999984740f0c86d03e6420b942439bf5bd7f54d4382cae386a9d1e9/coverage-7.10.7-cp39-cp39-win32.whl", hash = "sha256:5a02d5a850e2979b0a014c412573953995174743a3f7fa4ea5a6e9a3c5617431", size = 220500, upload-time = "2025-09-21T20:03:50.024Z" },
- { url = "https://files.pythonhosted.org/packages/43/11/4b1e6b129943f905ca54c339f343877b55b365ae2558806c1be4f7476ed5/coverage-7.10.7-cp39-cp39-win_amd64.whl", hash = "sha256:c134869d5ffe34547d14e174c866fd8fe2254918cc0a95e99052903bc1543e07", size = 221408, upload-time = "2025-09-21T20:03:51.803Z" },
- { url = "https://files.pythonhosted.org/packages/ec/16/114df1c291c22cac3b0c127a73e0af5c12ed7bbb6558d310429a0ae24023/coverage-7.10.7-py3-none-any.whl", hash = "sha256:f7941f6f2fe6dd6807a1208737b8a0cbcf1cc6d7b07d24998ad2d63590868260", size = 209952, upload-time = "2025-09-21T20:03:53.918Z" },
-]
-
-[package.optional-dependencies]
-toml = [
- { name = "tomli", marker = "python_full_version < '3.10'" },
-]
-
[[package]]
name = "coverage"
version = "7.13.3"
source = { registry = "https://pypi.org/simple" }
-resolution-markers = [
- "python_full_version >= '3.14'",
- "python_full_version >= '3.10' and python_full_version < '3.14'",
-]
sdist = { url = "https://files.pythonhosted.org/packages/11/43/3e4ac666cc35f231fa70c94e9f38459299de1a152813f9d2f60fc5f3ecaf/coverage-7.13.3.tar.gz", hash = "sha256:f7f6182d3dfb8802c1747eacbfe611b669455b69b7c037484bb1efbbb56711ac", size = 826832, upload-time = "2026-02-03T14:02:30.944Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/ab/07/1c8099563a8a6c389a31c2d0aa1497cee86d6248bb4b9ba5e779215db9f9/coverage-7.13.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0b4f345f7265cdbdb5ec2521ffff15fa49de6d6c39abf89fc7ad68aa9e3a55f0", size = 219143, upload-time = "2026-02-03T13:59:40.459Z" },
@@ -1076,7 +813,7 @@ wheels = [
[package.optional-dependencies]
toml = [
- { name = "tomli", marker = "python_full_version >= '3.10' and python_full_version <= '3.11'" },
+ { name = "tomli", marker = "python_full_version <= '3.11'" },
]
[[package]]
@@ -1084,8 +821,8 @@ name = "croniter"
version = "6.0.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "python-dateutil", marker = "python_full_version >= '3.10'" },
- { name = "pytz", marker = "python_full_version >= '3.10'" },
+ { name = "python-dateutil" },
+ { name = "pytz" },
]
sdist = { url = "https://files.pythonhosted.org/packages/ad/2f/44d1ae153a0e27be56be43465e5cb39b9650c781e001e7864389deb25090/croniter-6.0.0.tar.gz", hash = "sha256:37c504b313956114a983ece2c2b07790b1f1094fe9d81cc94739214748255577", size = 64481, upload-time = "2024-12-17T17:17:47.32Z" }
wheels = [
@@ -1106,62 +843,62 @@ wheels = [
[[package]]
name = "cryptography"
-version = "46.0.4"
+version = "46.0.5"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "cffi", marker = "platform_python_implementation != 'PyPy'" },
{ name = "typing-extensions", marker = "python_full_version < '3.11'" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/78/19/f748958276519adf6a0c1e79e7b8860b4830dda55ccdf29f2719b5fc499c/cryptography-46.0.4.tar.gz", hash = "sha256:bfd019f60f8abc2ed1b9be4ddc21cfef059c841d86d710bb69909a688cbb8f59", size = 749301, upload-time = "2026-01-28T00:24:37.379Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/8d/99/157aae7949a5f30d51fcb1a9851e8ebd5c74bf99b5285d8bb4b8b9ee641e/cryptography-46.0.4-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:281526e865ed4166009e235afadf3a4c4cba6056f99336a99efba65336fd5485", size = 7173686, upload-time = "2026-01-28T00:23:07.515Z" },
- { url = "https://files.pythonhosted.org/packages/87/91/874b8910903159043b5c6a123b7e79c4559ddd1896e38967567942635778/cryptography-46.0.4-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:5f14fba5bf6f4390d7ff8f086c566454bff0411f6d8aa7af79c88b6f9267aecc", size = 4275871, upload-time = "2026-01-28T00:23:09.439Z" },
- { url = "https://files.pythonhosted.org/packages/c0/35/690e809be77896111f5b195ede56e4b4ed0435b428c2f2b6d35046fbb5e8/cryptography-46.0.4-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:47bcd19517e6389132f76e2d5303ded6cf3f78903da2158a671be8de024f4cd0", size = 4423124, upload-time = "2026-01-28T00:23:11.529Z" },
- { url = "https://files.pythonhosted.org/packages/1a/5b/a26407d4f79d61ca4bebaa9213feafdd8806dc69d3d290ce24996d3cfe43/cryptography-46.0.4-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:01df4f50f314fbe7009f54046e908d1754f19d0c6d3070df1e6268c5a4af09fa", size = 4277090, upload-time = "2026-01-28T00:23:13.123Z" },
- { url = "https://files.pythonhosted.org/packages/0c/d8/4bb7aec442a9049827aa34cee1aa83803e528fa55da9a9d45d01d1bb933e/cryptography-46.0.4-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:5aa3e463596b0087b3da0dbe2b2487e9fc261d25da85754e30e3b40637d61f81", size = 4947652, upload-time = "2026-01-28T00:23:14.554Z" },
- { url = "https://files.pythonhosted.org/packages/2b/08/f83e2e0814248b844265802d081f2fac2f1cbe6cd258e72ba14ff006823a/cryptography-46.0.4-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:0a9ad24359fee86f131836a9ac3bffc9329e956624a2d379b613f8f8abaf5255", size = 4455157, upload-time = "2026-01-28T00:23:16.443Z" },
- { url = "https://files.pythonhosted.org/packages/0a/05/19d849cf4096448779d2dcc9bb27d097457dac36f7273ffa875a93b5884c/cryptography-46.0.4-cp311-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:dc1272e25ef673efe72f2096e92ae39dea1a1a450dd44918b15351f72c5a168e", size = 3981078, upload-time = "2026-01-28T00:23:17.838Z" },
- { url = "https://files.pythonhosted.org/packages/e6/89/f7bac81d66ba7cde867a743ea5b37537b32b5c633c473002b26a226f703f/cryptography-46.0.4-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:de0f5f4ec8711ebc555f54735d4c673fc34b65c44283895f1a08c2b49d2fd99c", size = 4276213, upload-time = "2026-01-28T00:23:19.257Z" },
- { url = "https://files.pythonhosted.org/packages/da/9f/7133e41f24edd827020ad21b068736e792bc68eecf66d93c924ad4719fb3/cryptography-46.0.4-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:eeeb2e33d8dbcccc34d64651f00a98cb41b2dc69cef866771a5717e6734dfa32", size = 4912190, upload-time = "2026-01-28T00:23:21.244Z" },
- { url = "https://files.pythonhosted.org/packages/a6/f7/6d43cbaddf6f65b24816e4af187d211f0bc536a29961f69faedc48501d8e/cryptography-46.0.4-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:3d425eacbc9aceafd2cb429e42f4e5d5633c6f873f5e567077043ef1b9bbf616", size = 4454641, upload-time = "2026-01-28T00:23:22.866Z" },
- { url = "https://files.pythonhosted.org/packages/9e/4f/ebd0473ad656a0ac912a16bd07db0f5d85184924e14fc88feecae2492834/cryptography-46.0.4-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:91627ebf691d1ea3976a031b61fb7bac1ccd745afa03602275dda443e11c8de0", size = 4405159, upload-time = "2026-01-28T00:23:25.278Z" },
- { url = "https://files.pythonhosted.org/packages/d1/f7/7923886f32dc47e27adeff8246e976d77258fd2aa3efdd1754e4e323bf49/cryptography-46.0.4-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:2d08bc22efd73e8854b0b7caff402d735b354862f1145d7be3b9c0f740fef6a0", size = 4666059, upload-time = "2026-01-28T00:23:26.766Z" },
- { url = "https://files.pythonhosted.org/packages/eb/a7/0fca0fd3591dffc297278a61813d7f661a14243dd60f499a7a5b48acb52a/cryptography-46.0.4-cp311-abi3-win32.whl", hash = "sha256:82a62483daf20b8134f6e92898da70d04d0ef9a75829d732ea1018678185f4f5", size = 3026378, upload-time = "2026-01-28T00:23:28.317Z" },
- { url = "https://files.pythonhosted.org/packages/2d/12/652c84b6f9873f0909374864a57b003686c642ea48c84d6c7e2c515e6da5/cryptography-46.0.4-cp311-abi3-win_amd64.whl", hash = "sha256:6225d3ebe26a55dbc8ead5ad1265c0403552a63336499564675b29eb3184c09b", size = 3478614, upload-time = "2026-01-28T00:23:30.275Z" },
- { url = "https://files.pythonhosted.org/packages/b9/27/542b029f293a5cce59349d799d4d8484b3b1654a7b9a0585c266e974a488/cryptography-46.0.4-cp314-cp314t-macosx_10_9_universal2.whl", hash = "sha256:485e2b65d25ec0d901bca7bcae0f53b00133bf3173916d8e421f6fddde103908", size = 7116417, upload-time = "2026-01-28T00:23:31.958Z" },
- { url = "https://files.pythonhosted.org/packages/f8/f5/559c25b77f40b6bf828eabaf988efb8b0e17b573545edb503368ca0a2a03/cryptography-46.0.4-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:078e5f06bd2fa5aea5a324f2a09f914b1484f1d0c2a4d6a8a28c74e72f65f2da", size = 4264508, upload-time = "2026-01-28T00:23:34.264Z" },
- { url = "https://files.pythonhosted.org/packages/49/a1/551fa162d33074b660dc35c9bc3616fefa21a0e8c1edd27b92559902e408/cryptography-46.0.4-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:dce1e4f068f03008da7fa51cc7abc6ddc5e5de3e3d1550334eaf8393982a5829", size = 4409080, upload-time = "2026-01-28T00:23:35.793Z" },
- { url = "https://files.pythonhosted.org/packages/b0/6a/4d8d129a755f5d6df1bbee69ea2f35ebfa954fa1847690d1db2e8bca46a5/cryptography-46.0.4-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:2067461c80271f422ee7bdbe79b9b4be54a5162e90345f86a23445a0cf3fd8a2", size = 4270039, upload-time = "2026-01-28T00:23:37.263Z" },
- { url = "https://files.pythonhosted.org/packages/4c/f5/ed3fcddd0a5e39321e595e144615399e47e7c153a1fb8c4862aec3151ff9/cryptography-46.0.4-cp314-cp314t-manylinux_2_28_ppc64le.whl", hash = "sha256:c92010b58a51196a5f41c3795190203ac52edfd5dc3ff99149b4659eba9d2085", size = 4926748, upload-time = "2026-01-28T00:23:38.884Z" },
- { url = "https://files.pythonhosted.org/packages/43/ae/9f03d5f0c0c00e85ecb34f06d3b79599f20630e4db91b8a6e56e8f83d410/cryptography-46.0.4-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:829c2b12bbc5428ab02d6b7f7e9bbfd53e33efd6672d21341f2177470171ad8b", size = 4442307, upload-time = "2026-01-28T00:23:40.56Z" },
- { url = "https://files.pythonhosted.org/packages/8b/22/e0f9f2dae8040695103369cf2283ef9ac8abe4d51f68710bec2afd232609/cryptography-46.0.4-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:62217ba44bf81b30abaeda1488686a04a702a261e26f87db51ff61d9d3510abd", size = 3959253, upload-time = "2026-01-28T00:23:42.827Z" },
- { url = "https://files.pythonhosted.org/packages/01/5b/6a43fcccc51dae4d101ac7d378a8724d1ba3de628a24e11bf2f4f43cba4d/cryptography-46.0.4-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:9c2da296c8d3415b93e6053f5a728649a87a48ce084a9aaf51d6e46c87c7f2d2", size = 4269372, upload-time = "2026-01-28T00:23:44.655Z" },
- { url = "https://files.pythonhosted.org/packages/17/b7/0f6b8c1dd0779df2b526e78978ff00462355e31c0a6f6cff8a3e99889c90/cryptography-46.0.4-cp314-cp314t-manylinux_2_34_ppc64le.whl", hash = "sha256:9b34d8ba84454641a6bf4d6762d15847ecbd85c1316c0a7984e6e4e9f748ec2e", size = 4891908, upload-time = "2026-01-28T00:23:46.48Z" },
- { url = "https://files.pythonhosted.org/packages/83/17/259409b8349aa10535358807a472c6a695cf84f106022268d31cea2b6c97/cryptography-46.0.4-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:df4a817fa7138dd0c96c8c8c20f04b8aaa1fac3bbf610913dcad8ea82e1bfd3f", size = 4441254, upload-time = "2026-01-28T00:23:48.403Z" },
- { url = "https://files.pythonhosted.org/packages/9c/fe/e4a1b0c989b00cee5ffa0764401767e2d1cf59f45530963b894129fd5dce/cryptography-46.0.4-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:b1de0ebf7587f28f9190b9cb526e901bf448c9e6a99655d2b07fff60e8212a82", size = 4396520, upload-time = "2026-01-28T00:23:50.26Z" },
- { url = "https://files.pythonhosted.org/packages/b3/81/ba8fd9657d27076eb40d6a2f941b23429a3c3d2f56f5a921d6b936a27bc9/cryptography-46.0.4-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:9b4d17bc7bd7cdd98e3af40b441feaea4c68225e2eb2341026c84511ad246c0c", size = 4651479, upload-time = "2026-01-28T00:23:51.674Z" },
- { url = "https://files.pythonhosted.org/packages/00/03/0de4ed43c71c31e4fe954edd50b9d28d658fef56555eba7641696370a8e2/cryptography-46.0.4-cp314-cp314t-win32.whl", hash = "sha256:c411f16275b0dea722d76544a61d6421e2cc829ad76eec79280dbdc9ddf50061", size = 3001986, upload-time = "2026-01-28T00:23:53.485Z" },
- { url = "https://files.pythonhosted.org/packages/5c/70/81830b59df7682917d7a10f833c4dab2a5574cd664e86d18139f2b421329/cryptography-46.0.4-cp314-cp314t-win_amd64.whl", hash = "sha256:728fedc529efc1439eb6107b677f7f7558adab4553ef8669f0d02d42d7b959a7", size = 3468288, upload-time = "2026-01-28T00:23:55.09Z" },
- { url = "https://files.pythonhosted.org/packages/56/f7/f648fdbb61d0d45902d3f374217451385edc7e7768d1b03ff1d0e5ffc17b/cryptography-46.0.4-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:a9556ba711f7c23f77b151d5798f3ac44a13455cc68db7697a1096e6d0563cab", size = 7169583, upload-time = "2026-01-28T00:23:56.558Z" },
- { url = "https://files.pythonhosted.org/packages/d8/cc/8f3224cbb2a928de7298d6ed4790f5ebc48114e02bdc9559196bfb12435d/cryptography-46.0.4-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8bf75b0259e87fa70bddc0b8b4078b76e7fd512fd9afae6c1193bcf440a4dbef", size = 4275419, upload-time = "2026-01-28T00:23:58.364Z" },
- { url = "https://files.pythonhosted.org/packages/17/43/4a18faa7a872d00e4264855134ba82d23546c850a70ff209e04ee200e76f/cryptography-46.0.4-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3c268a3490df22270955966ba236d6bc4a8f9b6e4ffddb78aac535f1a5ea471d", size = 4419058, upload-time = "2026-01-28T00:23:59.867Z" },
- { url = "https://files.pythonhosted.org/packages/ee/64/6651969409821d791ba12346a124f55e1b76f66a819254ae840a965d4b9c/cryptography-46.0.4-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:812815182f6a0c1d49a37893a303b44eaac827d7f0d582cecfc81b6427f22973", size = 4278151, upload-time = "2026-01-28T00:24:01.731Z" },
- { url = "https://files.pythonhosted.org/packages/20/0b/a7fce65ee08c3c02f7a8310cc090a732344066b990ac63a9dfd0a655d321/cryptography-46.0.4-cp38-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:a90e43e3ef65e6dcf969dfe3bb40cbf5aef0d523dff95bfa24256be172a845f4", size = 4939441, upload-time = "2026-01-28T00:24:03.175Z" },
- { url = "https://files.pythonhosted.org/packages/db/a7/20c5701e2cd3e1dfd7a19d2290c522a5f435dd30957d431dcb531d0f1413/cryptography-46.0.4-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:a05177ff6296644ef2876fce50518dffb5bcdf903c85250974fc8bc85d54c0af", size = 4451617, upload-time = "2026-01-28T00:24:05.403Z" },
- { url = "https://files.pythonhosted.org/packages/00/dc/3e16030ea9aa47b63af6524c354933b4fb0e352257c792c4deeb0edae367/cryptography-46.0.4-cp38-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:daa392191f626d50f1b136c9b4cf08af69ca8279d110ea24f5c2700054d2e263", size = 3977774, upload-time = "2026-01-28T00:24:06.851Z" },
- { url = "https://files.pythonhosted.org/packages/42/c8/ad93f14118252717b465880368721c963975ac4b941b7ef88f3c56bf2897/cryptography-46.0.4-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:e07ea39c5b048e085f15923511d8121e4a9dc45cee4e3b970ca4f0d338f23095", size = 4277008, upload-time = "2026-01-28T00:24:08.926Z" },
- { url = "https://files.pythonhosted.org/packages/00/cf/89c99698151c00a4631fbfcfcf459d308213ac29e321b0ff44ceeeac82f1/cryptography-46.0.4-cp38-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:d5a45ddc256f492ce42a4e35879c5e5528c09cd9ad12420828c972951d8e016b", size = 4903339, upload-time = "2026-01-28T00:24:12.009Z" },
- { url = "https://files.pythonhosted.org/packages/03/c3/c90a2cb358de4ac9309b26acf49b2a100957e1ff5cc1e98e6c4996576710/cryptography-46.0.4-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:6bb5157bf6a350e5b28aee23beb2d84ae6f5be390b2f8ee7ea179cda077e1019", size = 4451216, upload-time = "2026-01-28T00:24:13.975Z" },
- { url = "https://files.pythonhosted.org/packages/96/2c/8d7f4171388a10208671e181ca43cdc0e596d8259ebacbbcfbd16de593da/cryptography-46.0.4-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:dd5aba870a2c40f87a3af043e0dee7d9eb02d4aff88a797b48f2b43eff8c3ab4", size = 4404299, upload-time = "2026-01-28T00:24:16.169Z" },
- { url = "https://files.pythonhosted.org/packages/e9/23/cbb2036e450980f65c6e0a173b73a56ff3bccd8998965dea5cc9ddd424a5/cryptography-46.0.4-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:93d8291da8d71024379ab2cb0b5c57915300155ad42e07f76bea6ad838d7e59b", size = 4664837, upload-time = "2026-01-28T00:24:17.629Z" },
- { url = "https://files.pythonhosted.org/packages/0a/21/f7433d18fe6d5845329cbdc597e30caf983229c7a245bcf54afecc555938/cryptography-46.0.4-cp38-abi3-win32.whl", hash = "sha256:0563655cb3c6d05fb2afe693340bc050c30f9f34e15763361cf08e94749401fc", size = 3009779, upload-time = "2026-01-28T00:24:20.198Z" },
- { url = "https://files.pythonhosted.org/packages/3a/6a/bd2e7caa2facffedf172a45c1a02e551e6d7d4828658c9a245516a598d94/cryptography-46.0.4-cp38-abi3-win_amd64.whl", hash = "sha256:fa0900b9ef9c49728887d1576fd8d9e7e3ea872fa9b25ef9b64888adc434e976", size = 3466633, upload-time = "2026-01-28T00:24:21.851Z" },
- { url = "https://files.pythonhosted.org/packages/59/e0/f9c6c53e1f2a1c2507f00f2faba00f01d2f334b35b0fbfe5286715da2184/cryptography-46.0.4-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:766330cce7416c92b5e90c3bb71b1b79521760cdcfc3a6a1a182d4c9fab23d2b", size = 3476316, upload-time = "2026-01-28T00:24:24.144Z" },
- { url = "https://files.pythonhosted.org/packages/27/7a/f8d2d13227a9a1a9fe9c7442b057efecffa41f1e3c51d8622f26b9edbe8f/cryptography-46.0.4-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:c236a44acfb610e70f6b3e1c3ca20ff24459659231ef2f8c48e879e2d32b73da", size = 4216693, upload-time = "2026-01-28T00:24:25.758Z" },
- { url = "https://files.pythonhosted.org/packages/c5/de/3787054e8f7972658370198753835d9d680f6cd4a39df9f877b57f0dd69c/cryptography-46.0.4-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:8a15fb869670efa8f83cbffbc8753c1abf236883225aed74cd179b720ac9ec80", size = 4382765, upload-time = "2026-01-28T00:24:27.577Z" },
- { url = "https://files.pythonhosted.org/packages/8a/5f/60e0afb019973ba6a0b322e86b3d61edf487a4f5597618a430a2a15f2d22/cryptography-46.0.4-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:fdc3daab53b212472f1524d070735b2f0c214239df131903bae1d598016fa822", size = 4216066, upload-time = "2026-01-28T00:24:29.056Z" },
- { url = "https://files.pythonhosted.org/packages/81/8e/bf4a0de294f147fee66f879d9bae6f8e8d61515558e3d12785dd90eca0be/cryptography-46.0.4-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:44cc0675b27cadb71bdbb96099cca1fa051cd11d2ade09e5cd3a2edb929ed947", size = 4382025, upload-time = "2026-01-28T00:24:30.681Z" },
- { url = "https://files.pythonhosted.org/packages/79/f4/9ceb90cfd6a3847069b0b0b353fd3075dc69b49defc70182d8af0c4ca390/cryptography-46.0.4-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:be8c01a7d5a55f9a47d1888162b76c8f49d62b234d88f0ff91a9fbebe32ffbc3", size = 3406043, upload-time = "2026-01-28T00:24:32.236Z" },
+sdist = { url = "https://files.pythonhosted.org/packages/60/04/ee2a9e8542e4fa2773b81771ff8349ff19cdd56b7258a0cc442639052edb/cryptography-46.0.5.tar.gz", hash = "sha256:abace499247268e3757271b2f1e244b36b06f8515cf27c4d49468fc9eb16e93d", size = 750064, upload-time = "2026-02-10T19:18:38.255Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/f7/81/b0bb27f2ba931a65409c6b8a8b358a7f03c0e46eceacddff55f7c84b1f3b/cryptography-46.0.5-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:351695ada9ea9618b3500b490ad54c739860883df6c1f555e088eaf25b1bbaad", size = 7176289, upload-time = "2026-02-10T19:17:08.274Z" },
+ { url = "https://files.pythonhosted.org/packages/ff/9e/6b4397a3e3d15123de3b1806ef342522393d50736c13b20ec4c9ea6693a6/cryptography-46.0.5-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:c18ff11e86df2e28854939acde2d003f7984f721eba450b56a200ad90eeb0e6b", size = 4275637, upload-time = "2026-02-10T19:17:10.53Z" },
+ { url = "https://files.pythonhosted.org/packages/63/e7/471ab61099a3920b0c77852ea3f0ea611c9702f651600397ac567848b897/cryptography-46.0.5-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4d7e3d356b8cd4ea5aff04f129d5f66ebdc7b6f8eae802b93739ed520c47c79b", size = 4424742, upload-time = "2026-02-10T19:17:12.388Z" },
+ { url = "https://files.pythonhosted.org/packages/37/53/a18500f270342d66bf7e4d9f091114e31e5ee9e7375a5aba2e85a91e0044/cryptography-46.0.5-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:50bfb6925eff619c9c023b967d5b77a54e04256c4281b0e21336a130cd7fc263", size = 4277528, upload-time = "2026-02-10T19:17:13.853Z" },
+ { url = "https://files.pythonhosted.org/packages/22/29/c2e812ebc38c57b40e7c583895e73c8c5adb4d1e4a0cc4c5a4fdab2b1acc/cryptography-46.0.5-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:803812e111e75d1aa73690d2facc295eaefd4439be1023fefc4995eaea2af90d", size = 4947993, upload-time = "2026-02-10T19:17:15.618Z" },
+ { url = "https://files.pythonhosted.org/packages/6b/e7/237155ae19a9023de7e30ec64e5d99a9431a567407ac21170a046d22a5a3/cryptography-46.0.5-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:3ee190460e2fbe447175cda91b88b84ae8322a104fc27766ad09428754a618ed", size = 4456855, upload-time = "2026-02-10T19:17:17.221Z" },
+ { url = "https://files.pythonhosted.org/packages/2d/87/fc628a7ad85b81206738abbd213b07702bcbdada1dd43f72236ef3cffbb5/cryptography-46.0.5-cp311-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:f145bba11b878005c496e93e257c1e88f154d278d2638e6450d17e0f31e558d2", size = 3984635, upload-time = "2026-02-10T19:17:18.792Z" },
+ { url = "https://files.pythonhosted.org/packages/84/29/65b55622bde135aedf4565dc509d99b560ee4095e56989e815f8fd2aa910/cryptography-46.0.5-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:e9251e3be159d1020c4030bd2e5f84d6a43fe54b6c19c12f51cde9542a2817b2", size = 4277038, upload-time = "2026-02-10T19:17:20.256Z" },
+ { url = "https://files.pythonhosted.org/packages/bc/36/45e76c68d7311432741faf1fbf7fac8a196a0a735ca21f504c75d37e2558/cryptography-46.0.5-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:47fb8a66058b80e509c47118ef8a75d14c455e81ac369050f20ba0d23e77fee0", size = 4912181, upload-time = "2026-02-10T19:17:21.825Z" },
+ { url = "https://files.pythonhosted.org/packages/6d/1a/c1ba8fead184d6e3d5afcf03d569acac5ad063f3ac9fb7258af158f7e378/cryptography-46.0.5-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:4c3341037c136030cb46e4b1e17b7418ea4cbd9dd207e4a6f3b2b24e0d4ac731", size = 4456482, upload-time = "2026-02-10T19:17:25.133Z" },
+ { url = "https://files.pythonhosted.org/packages/f9/e5/3fb22e37f66827ced3b902cf895e6a6bc1d095b5b26be26bd13c441fdf19/cryptography-46.0.5-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:890bcb4abd5a2d3f852196437129eb3667d62630333aacc13dfd470fad3aaa82", size = 4405497, upload-time = "2026-02-10T19:17:26.66Z" },
+ { url = "https://files.pythonhosted.org/packages/1a/df/9d58bb32b1121a8a2f27383fabae4d63080c7ca60b9b5c88be742be04ee7/cryptography-46.0.5-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:80a8d7bfdf38f87ca30a5391c0c9ce4ed2926918e017c29ddf643d0ed2778ea1", size = 4667819, upload-time = "2026-02-10T19:17:28.569Z" },
+ { url = "https://files.pythonhosted.org/packages/ea/ed/325d2a490c5e94038cdb0117da9397ece1f11201f425c4e9c57fe5b9f08b/cryptography-46.0.5-cp311-abi3-win32.whl", hash = "sha256:60ee7e19e95104d4c03871d7d7dfb3d22ef8a9b9c6778c94e1c8fcc8365afd48", size = 3028230, upload-time = "2026-02-10T19:17:30.518Z" },
+ { url = "https://files.pythonhosted.org/packages/e9/5a/ac0f49e48063ab4255d9e3b79f5def51697fce1a95ea1370f03dc9db76f6/cryptography-46.0.5-cp311-abi3-win_amd64.whl", hash = "sha256:38946c54b16c885c72c4f59846be9743d699eee2b69b6988e0a00a01f46a61a4", size = 3480909, upload-time = "2026-02-10T19:17:32.083Z" },
+ { url = "https://files.pythonhosted.org/packages/00/13/3d278bfa7a15a96b9dc22db5a12ad1e48a9eb3d40e1827ef66a5df75d0d0/cryptography-46.0.5-cp314-cp314t-macosx_10_9_universal2.whl", hash = "sha256:94a76daa32eb78d61339aff7952ea819b1734b46f73646a07decb40e5b3448e2", size = 7119287, upload-time = "2026-02-10T19:17:33.801Z" },
+ { url = "https://files.pythonhosted.org/packages/67/c8/581a6702e14f0898a0848105cbefd20c058099e2c2d22ef4e476dfec75d7/cryptography-46.0.5-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:5be7bf2fb40769e05739dd0046e7b26f9d4670badc7b032d6ce4db64dddc0678", size = 4265728, upload-time = "2026-02-10T19:17:35.569Z" },
+ { url = "https://files.pythonhosted.org/packages/dd/4a/ba1a65ce8fc65435e5a849558379896c957870dd64fecea97b1ad5f46a37/cryptography-46.0.5-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fe346b143ff9685e40192a4960938545c699054ba11d4f9029f94751e3f71d87", size = 4408287, upload-time = "2026-02-10T19:17:36.938Z" },
+ { url = "https://files.pythonhosted.org/packages/f8/67/8ffdbf7b65ed1ac224d1c2df3943553766914a8ca718747ee3871da6107e/cryptography-46.0.5-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:c69fd885df7d089548a42d5ec05be26050ebcd2283d89b3d30676eb32ff87dee", size = 4270291, upload-time = "2026-02-10T19:17:38.748Z" },
+ { url = "https://files.pythonhosted.org/packages/f8/e5/f52377ee93bc2f2bba55a41a886fd208c15276ffbd2569f2ddc89d50e2c5/cryptography-46.0.5-cp314-cp314t-manylinux_2_28_ppc64le.whl", hash = "sha256:8293f3dea7fc929ef7240796ba231413afa7b68ce38fd21da2995549f5961981", size = 4927539, upload-time = "2026-02-10T19:17:40.241Z" },
+ { url = "https://files.pythonhosted.org/packages/3b/02/cfe39181b02419bbbbcf3abdd16c1c5c8541f03ca8bda240debc467d5a12/cryptography-46.0.5-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:1abfdb89b41c3be0365328a410baa9df3ff8a9110fb75e7b52e66803ddabc9a9", size = 4442199, upload-time = "2026-02-10T19:17:41.789Z" },
+ { url = "https://files.pythonhosted.org/packages/c0/96/2fcaeb4873e536cf71421a388a6c11b5bc846e986b2b069c79363dc1648e/cryptography-46.0.5-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:d66e421495fdb797610a08f43b05269e0a5ea7f5e652a89bfd5a7d3c1dee3648", size = 3960131, upload-time = "2026-02-10T19:17:43.379Z" },
+ { url = "https://files.pythonhosted.org/packages/d8/d2/b27631f401ddd644e94c5cf33c9a4069f72011821cf3dc7309546b0642a0/cryptography-46.0.5-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:4e817a8920bfbcff8940ecfd60f23d01836408242b30f1a708d93198393a80b4", size = 4270072, upload-time = "2026-02-10T19:17:45.481Z" },
+ { url = "https://files.pythonhosted.org/packages/f4/a7/60d32b0370dae0b4ebe55ffa10e8599a2a59935b5ece1b9f06edb73abdeb/cryptography-46.0.5-cp314-cp314t-manylinux_2_34_ppc64le.whl", hash = "sha256:68f68d13f2e1cb95163fa3b4db4bf9a159a418f5f6e7242564fc75fcae667fd0", size = 4892170, upload-time = "2026-02-10T19:17:46.997Z" },
+ { url = "https://files.pythonhosted.org/packages/d2/b9/cf73ddf8ef1164330eb0b199a589103c363afa0cf794218c24d524a58eab/cryptography-46.0.5-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:a3d1fae9863299076f05cb8a778c467578262fae09f9dc0ee9b12eb4268ce663", size = 4441741, upload-time = "2026-02-10T19:17:48.661Z" },
+ { url = "https://files.pythonhosted.org/packages/5f/eb/eee00b28c84c726fe8fa0158c65afe312d9c3b78d9d01daf700f1f6e37ff/cryptography-46.0.5-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:c4143987a42a2397f2fc3b4d7e3a7d313fbe684f67ff443999e803dd75a76826", size = 4396728, upload-time = "2026-02-10T19:17:50.058Z" },
+ { url = "https://files.pythonhosted.org/packages/65/f4/6bc1a9ed5aef7145045114b75b77c2a8261b4d38717bd8dea111a63c3442/cryptography-46.0.5-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:7d731d4b107030987fd61a7f8ab512b25b53cef8f233a97379ede116f30eb67d", size = 4652001, upload-time = "2026-02-10T19:17:51.54Z" },
+ { url = "https://files.pythonhosted.org/packages/86/ef/5d00ef966ddd71ac2e6951d278884a84a40ffbd88948ef0e294b214ae9e4/cryptography-46.0.5-cp314-cp314t-win32.whl", hash = "sha256:c3bcce8521d785d510b2aad26ae2c966092b7daa8f45dd8f44734a104dc0bc1a", size = 3003637, upload-time = "2026-02-10T19:17:52.997Z" },
+ { url = "https://files.pythonhosted.org/packages/b7/57/f3f4160123da6d098db78350fdfd9705057aad21de7388eacb2401dceab9/cryptography-46.0.5-cp314-cp314t-win_amd64.whl", hash = "sha256:4d8ae8659ab18c65ced284993c2265910f6c9e650189d4e3f68445ef82a810e4", size = 3469487, upload-time = "2026-02-10T19:17:54.549Z" },
+ { url = "https://files.pythonhosted.org/packages/e2/fa/a66aa722105ad6a458bebd64086ca2b72cdd361fed31763d20390f6f1389/cryptography-46.0.5-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:4108d4c09fbbf2789d0c926eb4152ae1760d5a2d97612b92d508d96c861e4d31", size = 7170514, upload-time = "2026-02-10T19:17:56.267Z" },
+ { url = "https://files.pythonhosted.org/packages/0f/04/c85bdeab78c8bc77b701bf0d9bdcf514c044e18a46dcff330df5448631b0/cryptography-46.0.5-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7d1f30a86d2757199cb2d56e48cce14deddf1f9c95f1ef1b64ee91ea43fe2e18", size = 4275349, upload-time = "2026-02-10T19:17:58.419Z" },
+ { url = "https://files.pythonhosted.org/packages/5c/32/9b87132a2f91ee7f5223b091dc963055503e9b442c98fc0b8a5ca765fab0/cryptography-46.0.5-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:039917b0dc418bb9f6edce8a906572d69e74bd330b0b3fea4f79dab7f8ddd235", size = 4420667, upload-time = "2026-02-10T19:18:00.619Z" },
+ { url = "https://files.pythonhosted.org/packages/a1/a6/a7cb7010bec4b7c5692ca6f024150371b295ee1c108bdc1c400e4c44562b/cryptography-46.0.5-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:ba2a27ff02f48193fc4daeadf8ad2590516fa3d0adeeb34336b96f7fa64c1e3a", size = 4276980, upload-time = "2026-02-10T19:18:02.379Z" },
+ { url = "https://files.pythonhosted.org/packages/8e/7c/c4f45e0eeff9b91e3f12dbd0e165fcf2a38847288fcfd889deea99fb7b6d/cryptography-46.0.5-cp38-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:61aa400dce22cb001a98014f647dc21cda08f7915ceb95df0c9eaf84b4b6af76", size = 4939143, upload-time = "2026-02-10T19:18:03.964Z" },
+ { url = "https://files.pythonhosted.org/packages/37/19/e1b8f964a834eddb44fa1b9a9976f4e414cbb7aa62809b6760c8803d22d1/cryptography-46.0.5-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:3ce58ba46e1bc2aac4f7d9290223cead56743fa6ab94a5d53292ffaac6a91614", size = 4453674, upload-time = "2026-02-10T19:18:05.588Z" },
+ { url = "https://files.pythonhosted.org/packages/db/ed/db15d3956f65264ca204625597c410d420e26530c4e2943e05a0d2f24d51/cryptography-46.0.5-cp38-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:420d0e909050490d04359e7fdb5ed7e667ca5c3c402b809ae2563d7e66a92229", size = 3978801, upload-time = "2026-02-10T19:18:07.167Z" },
+ { url = "https://files.pythonhosted.org/packages/41/e2/df40a31d82df0a70a0daf69791f91dbb70e47644c58581d654879b382d11/cryptography-46.0.5-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:582f5fcd2afa31622f317f80426a027f30dc792e9c80ffee87b993200ea115f1", size = 4276755, upload-time = "2026-02-10T19:18:09.813Z" },
+ { url = "https://files.pythonhosted.org/packages/33/45/726809d1176959f4a896b86907b98ff4391a8aa29c0aaaf9450a8a10630e/cryptography-46.0.5-cp38-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:bfd56bb4b37ed4f330b82402f6f435845a5f5648edf1ad497da51a8452d5d62d", size = 4901539, upload-time = "2026-02-10T19:18:11.263Z" },
+ { url = "https://files.pythonhosted.org/packages/99/0f/a3076874e9c88ecb2ecc31382f6e7c21b428ede6f55aafa1aa272613e3cd/cryptography-46.0.5-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:a3d507bb6a513ca96ba84443226af944b0f7f47dcc9a399d110cd6146481d24c", size = 4452794, upload-time = "2026-02-10T19:18:12.914Z" },
+ { url = "https://files.pythonhosted.org/packages/02/ef/ffeb542d3683d24194a38f66ca17c0a4b8bf10631feef44a7ef64e631b1a/cryptography-46.0.5-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:9f16fbdf4da055efb21c22d81b89f155f02ba420558db21288b3d0035bafd5f4", size = 4404160, upload-time = "2026-02-10T19:18:14.375Z" },
+ { url = "https://files.pythonhosted.org/packages/96/93/682d2b43c1d5f1406ed048f377c0fc9fc8f7b0447a478d5c65ab3d3a66eb/cryptography-46.0.5-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:ced80795227d70549a411a4ab66e8ce307899fad2220ce5ab2f296e687eacde9", size = 4667123, upload-time = "2026-02-10T19:18:15.886Z" },
+ { url = "https://files.pythonhosted.org/packages/45/2d/9c5f2926cb5300a8eefc3f4f0b3f3df39db7f7ce40c8365444c49363cbda/cryptography-46.0.5-cp38-abi3-win32.whl", hash = "sha256:02f547fce831f5096c9a567fd41bc12ca8f11df260959ecc7c3202555cc47a72", size = 3010220, upload-time = "2026-02-10T19:18:17.361Z" },
+ { url = "https://files.pythonhosted.org/packages/48/ef/0c2f4a8e31018a986949d34a01115dd057bf536905dca38897bacd21fac3/cryptography-46.0.5-cp38-abi3-win_amd64.whl", hash = "sha256:556e106ee01aa13484ce9b0239bca667be5004efb0aabbed28d353df86445595", size = 3467050, upload-time = "2026-02-10T19:18:18.899Z" },
+ { url = "https://files.pythonhosted.org/packages/eb/dd/2d9fdb07cebdf3d51179730afb7d5e576153c6744c3ff8fded23030c204e/cryptography-46.0.5-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:3b4995dc971c9fb83c25aa44cf45f02ba86f71ee600d81091c2f0cbae116b06c", size = 3476964, upload-time = "2026-02-10T19:18:20.687Z" },
+ { url = "https://files.pythonhosted.org/packages/e9/6f/6cc6cc9955caa6eaf83660b0da2b077c7fe8ff9950a3c5e45d605038d439/cryptography-46.0.5-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:bc84e875994c3b445871ea7181d424588171efec3e185dced958dad9e001950a", size = 4218321, upload-time = "2026-02-10T19:18:22.349Z" },
+ { url = "https://files.pythonhosted.org/packages/3e/5d/c4da701939eeee699566a6c1367427ab91a8b7088cc2328c09dbee940415/cryptography-46.0.5-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:2ae6971afd6246710480e3f15824ed3029a60fc16991db250034efd0b9fb4356", size = 4381786, upload-time = "2026-02-10T19:18:24.529Z" },
+ { url = "https://files.pythonhosted.org/packages/ac/97/a538654732974a94ff96c1db621fa464f455c02d4bb7d2652f4edc21d600/cryptography-46.0.5-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:d861ee9e76ace6cf36a6a89b959ec08e7bc2493ee39d07ffe5acb23ef46d27da", size = 4217990, upload-time = "2026-02-10T19:18:25.957Z" },
+ { url = "https://files.pythonhosted.org/packages/ae/11/7e500d2dd3ba891197b9efd2da5454b74336d64a7cc419aa7327ab74e5f6/cryptography-46.0.5-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:2b7a67c9cd56372f3249b39699f2ad479f6991e62ea15800973b956f4b73e257", size = 4381252, upload-time = "2026-02-10T19:18:27.496Z" },
+ { url = "https://files.pythonhosted.org/packages/bc/58/6b3d24e6b9bc474a2dcdee65dfd1f008867015408a271562e4b690561a4d/cryptography-46.0.5-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:8456928655f856c6e1533ff59d5be76578a7157224dbd9ce6872f25055ab9ab7", size = 3407605, upload-time = "2026-02-10T19:18:29.233Z" },
]
[[package]]
@@ -1169,8 +906,7 @@ name = "cssselect2"
version = "0.8.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "tinycss2", version = "1.4.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
- { name = "tinycss2", version = "1.5.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
+ { name = "tinycss2" },
{ name = "webencodings" },
]
sdist = { url = "https://files.pythonhosted.org/packages/9f/86/fd7f58fc498b3166f3a7e8e0cddb6e620fe1da35b02248b1bd59e95dbaaa/cssselect2-0.8.0.tar.gz", hash = "sha256:7674ffb954a3b46162392aee2a3a0aedb2e14ecf99fcc28644900f4e6e3e9d3a", size = 35716, upload-time = "2025-03-05T14:46:07.988Z" }
@@ -1192,12 +928,12 @@ name = "cyclopts"
version = "4.5.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "attrs", marker = "python_full_version >= '3.10'" },
- { name = "docstring-parser", marker = "python_full_version >= '3.10'" },
- { name = "rich", marker = "python_full_version >= '3.10'" },
- { name = "rich-rst", marker = "python_full_version >= '3.10'" },
- { name = "tomli", marker = "python_full_version == '3.10.*'" },
- { name = "typing-extensions", marker = "python_full_version == '3.10.*'" },
+ { name = "attrs" },
+ { name = "docstring-parser" },
+ { name = "rich" },
+ { name = "rich-rst" },
+ { name = "tomli", marker = "python_full_version < '3.11'" },
+ { name = "typing-extensions", marker = "python_full_version < '3.11'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/d4/93/6085aa89c3fff78a5180987354538d72e43b0db27e66a959302d0c07821a/cyclopts-4.5.1.tar.gz", hash = "sha256:fadc45304763fd9f5d6033727f176898d17a1778e194436964661a005078a3dd", size = 162075, upload-time = "2026-01-25T15:23:54.07Z" }
wheels = [
@@ -1240,26 +976,10 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl", hash = "sha256:7bffd925d65168f85027d8da9af6bddab658135b840670a223589bc0c8ef02b2", size = 20277, upload-time = "2023-12-24T09:54:30.421Z" },
]
-[[package]]
-name = "dnspython"
-version = "2.7.0"
-source = { registry = "https://pypi.org/simple" }
-resolution-markers = [
- "python_full_version < '3.10'",
-]
-sdist = { url = "https://files.pythonhosted.org/packages/b5/4a/263763cb2ba3816dd94b08ad3a33d5fdae34ecb856678773cc40a3605829/dnspython-2.7.0.tar.gz", hash = "sha256:ce9c432eda0dc91cf618a5cedf1a4e142651196bbcd2c80e89ed5a907e5cfaf1", size = 345197, upload-time = "2024-10-05T20:14:59.362Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/68/1b/e0a87d256e40e8c888847551b20a017a6b98139178505dc7ffb96f04e954/dnspython-2.7.0-py3-none-any.whl", hash = "sha256:b4c34b7d10b51bcc3a5071e7b8dee77939f1e878477eeecc965e9835f63c6c86", size = 313632, upload-time = "2024-10-05T20:14:57.687Z" },
-]
-
[[package]]
name = "dnspython"
version = "2.8.0"
source = { registry = "https://pypi.org/simple" }
-resolution-markers = [
- "python_full_version >= '3.14'",
- "python_full_version >= '3.10' and python_full_version < '3.14'",
-]
sdist = { url = "https://files.pythonhosted.org/packages/8c/8b/57666417c0f90f08bcafa776861060426765fdb422eb10212086fb811d26/dnspython-2.8.0.tar.gz", hash = "sha256:181d3c6996452cb1189c4046c61599b84a5a86e099562ffde77d26984ff26d0f", size = 368251, upload-time = "2025-09-07T18:58:00.022Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl", hash = "sha256:01d9bbc4a2d76bf0db7c1f729812ded6d912bd318d3b1cf81d30c0f845dbf3af", size = 331094, upload-time = "2025-09-07T18:57:58.071Z" },
@@ -1288,8 +1008,7 @@ name = "email-validator"
version = "2.3.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "dnspython", version = "2.7.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
- { name = "dnspython", version = "2.8.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
+ { name = "dnspython" },
{ name = "idna" },
]
sdist = { url = "https://files.pythonhosted.org/packages/f5/22/900cb125c76b7aaa450ce02fd727f452243f2e91a61af068b40adba60ea9/email_validator-2.3.0.tar.gz", hash = "sha256:9fc05c37f2f6cf439ff414f8fc46d917929974a82244c20eb10231ba60c54426", size = 51238, upload-time = "2025-08-26T13:09:06.831Z" }
@@ -1332,9 +1051,9 @@ name = "fakeredis"
version = "2.33.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "redis", marker = "python_full_version >= '3.10'" },
- { name = "sortedcontainers", marker = "python_full_version >= '3.10'" },
- { name = "typing-extensions", marker = "python_full_version == '3.10.*'" },
+ { name = "redis" },
+ { name = "sortedcontainers" },
+ { name = "typing-extensions", marker = "python_full_version < '3.11'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/5f/f9/57464119936414d60697fcbd32f38909bb5688b616ae13de6e98384433e0/fakeredis-2.33.0.tar.gz", hash = "sha256:d7bc9a69d21df108a6451bbffee23b3eba432c21a654afc7ff2d295428ec5770", size = 175187, upload-time = "2025-12-16T19:45:52.269Z" }
wheels = [
@@ -1343,7 +1062,7 @@ wheels = [
[package.optional-dependencies]
lua = [
- { name = "lupa", marker = "python_full_version >= '3.10'" },
+ { name = "lupa" },
]
[[package]]
@@ -1352,8 +1071,7 @@ source = { editable = "." }
dependencies = [
{ name = "annotated-doc" },
{ name = "pydantic" },
- { name = "starlette", version = "0.49.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
- { name = "starlette", version = "0.52.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
+ { name = "starlette" },
{ name = "typing-extensions" },
{ name = "typing-inspection" },
]
@@ -1365,17 +1083,13 @@ all = [
{ name = "httpx" },
{ name = "itsdangerous" },
{ name = "jinja2" },
- { name = "orjson", version = "3.11.5", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
- { name = "orjson", version = "3.11.7", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
+ { name = "orjson" },
{ name = "pydantic-extra-types" },
- { name = "pydantic-settings", version = "2.11.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
- { name = "pydantic-settings", version = "2.12.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
- { name = "python-multipart", version = "0.0.20", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
- { name = "python-multipart", version = "0.0.22", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
+ { name = "pydantic-settings" },
+ { name = "python-multipart" },
{ name = "pyyaml" },
{ name = "ujson" },
- { name = "uvicorn", version = "0.39.0", source = { registry = "https://pypi.org/simple" }, extra = ["standard"], marker = "python_full_version < '3.10'" },
- { name = "uvicorn", version = "0.40.0", source = { registry = "https://pypi.org/simple" }, extra = ["standard"], marker = "python_full_version >= '3.10'" },
+ { name = "uvicorn", extra = ["standard"] },
]
standard = [
{ name = "email-validator" },
@@ -1383,12 +1097,9 @@ standard = [
{ name = "httpx" },
{ name = "jinja2" },
{ name = "pydantic-extra-types" },
- { name = "pydantic-settings", version = "2.11.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
- { name = "pydantic-settings", version = "2.12.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
- { name = "python-multipart", version = "0.0.20", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
- { name = "python-multipart", version = "0.0.22", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
- { name = "uvicorn", version = "0.39.0", source = { registry = "https://pypi.org/simple" }, extra = ["standard"], marker = "python_full_version < '3.10'" },
- { name = "uvicorn", version = "0.40.0", source = { registry = "https://pypi.org/simple" }, extra = ["standard"], marker = "python_full_version >= '3.10'" },
+ { name = "pydantic-settings" },
+ { name = "python-multipart" },
+ { name = "uvicorn", extra = ["standard"] },
]
standard-no-fastapi-cloud-cli = [
{ name = "email-validator" },
@@ -1396,23 +1107,18 @@ standard-no-fastapi-cloud-cli = [
{ name = "httpx" },
{ name = "jinja2" },
{ name = "pydantic-extra-types" },
- { name = "pydantic-settings", version = "2.11.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
- { name = "pydantic-settings", version = "2.12.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
- { name = "python-multipart", version = "0.0.20", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
- { name = "python-multipart", version = "0.0.22", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
- { name = "uvicorn", version = "0.39.0", source = { registry = "https://pypi.org/simple" }, extra = ["standard"], marker = "python_full_version < '3.10'" },
- { name = "uvicorn", version = "0.40.0", source = { registry = "https://pypi.org/simple" }, extra = ["standard"], marker = "python_full_version >= '3.10'" },
+ { name = "pydantic-settings" },
+ { name = "python-multipart" },
+ { name = "uvicorn", extra = ["standard"] },
]
[package.dev-dependencies]
dev = [
{ name = "a2wsgi" },
{ name = "anyio", extra = ["trio"] },
- { name = "black", version = "25.11.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
- { name = "black", version = "26.1.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
+ { name = "black" },
{ name = "cairosvg" },
- { name = "coverage", version = "7.10.7", source = { registry = "https://pypi.org/simple" }, extra = ["toml"], marker = "python_full_version < '3.10'" },
- { name = "coverage", version = "7.13.3", source = { registry = "https://pypi.org/simple" }, extra = ["toml"], marker = "python_full_version >= '3.10'" },
+ { name = "coverage", extra = ["toml"] },
{ name = "dirty-equals" },
{ name = "flask" },
{ name = "gitpython" },
@@ -1426,17 +1132,13 @@ dev = [
{ name = "mkdocs-macros-plugin" },
{ name = "mkdocs-material" },
{ name = "mkdocs-redirects" },
- { name = "mkdocstrings", version = "0.30.1", source = { registry = "https://pypi.org/simple" }, extra = ["python"], marker = "python_full_version < '3.10'" },
- { name = "mkdocstrings", version = "1.0.2", source = { registry = "https://pypi.org/simple" }, extra = ["python"], marker = "python_full_version >= '3.10'" },
+ { name = "mkdocstrings", extra = ["python"] },
{ name = "mypy" },
- { name = "pillow", version = "11.3.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
- { name = "pillow", version = "12.1.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
+ { name = "pillow" },
{ name = "playwright" },
{ name = "prek" },
- { name = "pwdlib", version = "0.2.1", source = { registry = "https://pypi.org/simple" }, extra = ["argon2"], marker = "python_full_version < '3.10'" },
- { name = "pwdlib", version = "0.3.0", source = { registry = "https://pypi.org/simple" }, extra = ["argon2"], marker = "python_full_version >= '3.10'" },
- { name = "pydantic-ai", version = "0.8.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
- { name = "pydantic-ai", version = "1.56.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
+ { name = "pwdlib", extra = ["argon2"] },
+ { name = "pydantic-ai" },
{ name = "pygithub" },
{ name = "pyjwt" },
{ name = "pytest" },
@@ -1445,15 +1147,13 @@ dev = [
{ name = "pyyaml" },
{ name = "ruff" },
{ name = "sqlmodel" },
- { name = "strawberry-graphql", version = "0.283.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
- { name = "strawberry-graphql", version = "0.291.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
+ { name = "strawberry-graphql" },
{ name = "typer" },
{ name = "types-orjson" },
{ name = "types-ujson" },
]
docs = [
- { name = "black", version = "25.11.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
- { name = "black", version = "26.1.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
+ { name = "black" },
{ name = "cairosvg" },
{ name = "griffe-typingdoc" },
{ name = "griffe-warnings-deprecated" },
@@ -1464,10 +1164,8 @@ docs = [
{ name = "mkdocs-macros-plugin" },
{ name = "mkdocs-material" },
{ name = "mkdocs-redirects" },
- { name = "mkdocstrings", version = "0.30.1", source = { registry = "https://pypi.org/simple" }, extra = ["python"], marker = "python_full_version < '3.10'" },
- { name = "mkdocstrings", version = "1.0.2", source = { registry = "https://pypi.org/simple" }, extra = ["python"], marker = "python_full_version >= '3.10'" },
- { name = "pillow", version = "11.3.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
- { name = "pillow", version = "12.1.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
+ { name = "mkdocstrings", extra = ["python"] },
+ { name = "pillow" },
{ name = "python-slugify" },
{ name = "pyyaml" },
{ name = "ruff" },
@@ -1480,8 +1178,7 @@ docs-tests = [
github-actions = [
{ name = "httpx" },
{ name = "pydantic" },
- { name = "pydantic-settings", version = "2.11.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
- { name = "pydantic-settings", version = "2.12.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
+ { name = "pydantic-settings" },
{ name = "pygithub" },
{ name = "pyyaml" },
{ name = "smokeshow" },
@@ -1489,30 +1186,26 @@ github-actions = [
tests = [
{ name = "a2wsgi" },
{ name = "anyio", extra = ["trio"] },
- { name = "coverage", version = "7.10.7", source = { registry = "https://pypi.org/simple" }, extra = ["toml"], marker = "python_full_version < '3.10'" },
- { name = "coverage", version = "7.13.3", source = { registry = "https://pypi.org/simple" }, extra = ["toml"], marker = "python_full_version >= '3.10'" },
+ { name = "coverage", extra = ["toml"] },
{ name = "dirty-equals" },
{ name = "flask" },
{ name = "httpx" },
{ name = "inline-snapshot" },
{ name = "mypy" },
- { name = "pwdlib", version = "0.2.1", source = { registry = "https://pypi.org/simple" }, extra = ["argon2"], marker = "python_full_version < '3.10'" },
- { name = "pwdlib", version = "0.3.0", source = { registry = "https://pypi.org/simple" }, extra = ["argon2"], marker = "python_full_version >= '3.10'" },
+ { name = "pwdlib", extra = ["argon2"] },
{ name = "pyjwt" },
{ name = "pytest" },
{ name = "pytest-codspeed" },
{ name = "pyyaml" },
{ name = "ruff" },
{ name = "sqlmodel" },
- { name = "strawberry-graphql", version = "0.283.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
- { name = "strawberry-graphql", version = "0.291.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
+ { name = "strawberry-graphql" },
{ name = "types-orjson" },
{ name = "types-ujson" },
]
translations = [
{ name = "gitpython" },
- { name = "pydantic-ai", version = "0.8.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
- { name = "pydantic-ai", version = "1.56.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
+ { name = "pydantic-ai" },
{ name = "pygithub" },
]
@@ -1659,8 +1352,7 @@ dependencies = [
{ name = "rich-toolkit" },
{ name = "tomli", marker = "python_full_version < '3.11'" },
{ name = "typer" },
- { name = "uvicorn", version = "0.39.0", source = { registry = "https://pypi.org/simple" }, extra = ["standard"], marker = "python_full_version < '3.10'" },
- { name = "uvicorn", version = "0.40.0", source = { registry = "https://pypi.org/simple" }, extra = ["standard"], marker = "python_full_version >= '3.10'" },
+ { name = "uvicorn", extra = ["standard"] },
]
sdist = { url = "https://files.pythonhosted.org/packages/d3/ca/d90fb3bfbcbd6e56c77afd9d114dd6ce8955d8bb90094399d1c70e659e40/fastapi_cli-0.0.20.tar.gz", hash = "sha256:d17c2634f7b96b6b560bc16b0035ed047d523c912011395f49f00a421692bc3a", size = 19786, upload-time = "2025-12-22T17:13:33.794Z" }
wheels = [
@@ -1670,12 +1362,10 @@ wheels = [
[package.optional-dependencies]
standard = [
{ name = "fastapi-cloud-cli" },
- { name = "uvicorn", version = "0.39.0", source = { registry = "https://pypi.org/simple" }, extra = ["standard"], marker = "python_full_version < '3.10'" },
- { name = "uvicorn", version = "0.40.0", source = { registry = "https://pypi.org/simple" }, extra = ["standard"], marker = "python_full_version >= '3.10'" },
+ { name = "uvicorn", extra = ["standard"] },
]
standard-no-fastapi-cloud-cli = [
- { name = "uvicorn", version = "0.39.0", source = { registry = "https://pypi.org/simple" }, extra = ["standard"], marker = "python_full_version < '3.10'" },
- { name = "uvicorn", version = "0.40.0", source = { registry = "https://pypi.org/simple" }, extra = ["standard"], marker = "python_full_version >= '3.10'" },
+ { name = "uvicorn", extra = ["standard"] },
]
[[package]]
@@ -1690,8 +1380,7 @@ dependencies = [
{ name = "rignore" },
{ name = "sentry-sdk" },
{ name = "typer" },
- { name = "uvicorn", version = "0.39.0", source = { registry = "https://pypi.org/simple" }, extra = ["standard"], marker = "python_full_version < '3.10'" },
- { name = "uvicorn", version = "0.40.0", source = { registry = "https://pypi.org/simple" }, extra = ["standard"], marker = "python_full_version >= '3.10'" },
+ { name = "uvicorn", extra = ["standard"] },
]
sdist = { url = "https://files.pythonhosted.org/packages/11/15/6c3d85d63964340fde6f36cc80f3f365d35f371e6a918d68ff3a3d588ef2/fastapi_cloud_cli-0.11.0.tar.gz", hash = "sha256:ecc83a5db106be35af528eccb01aa9bced1d29783efd48c8c1c831cf111eea99", size = 36170, upload-time = "2026-01-15T09:51:33.681Z" }
wheels = [
@@ -1793,20 +1482,6 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/c9/e2/dfa19a4b260b8ab3581b7484dcb80c09b25324f4daa6b6ae1c7640d1607a/fastar-0.8.0-cp314-cp314t-win32.whl", hash = "sha256:187f61dc739afe45ac8e47ed7fd1adc45d52eac110cf27d579155720507d6fbe", size = 455767, upload-time = "2025-11-26T02:36:34.758Z" },
{ url = "https://files.pythonhosted.org/packages/51/47/df65c72afc1297797b255f90c4778b5d6f1f0f80282a134d5ab610310ed9/fastar-0.8.0-cp314-cp314t-win_amd64.whl", hash = "sha256:40e9d763cf8bf85ce2fa256e010aa795c0fe3d3bd1326d5c3084e6ce7857127e", size = 489971, upload-time = "2025-11-26T02:36:22.081Z" },
{ url = "https://files.pythonhosted.org/packages/85/11/0aa8455af26f0ae89e42be67f3a874255ee5d7f0f026fc86e8d56f76b428/fastar-0.8.0-cp314-cp314t-win_arm64.whl", hash = "sha256:e59673307b6a08210987059a2bdea2614fe26e3335d0e5d1a3d95f49a05b1418", size = 460467, upload-time = "2025-11-26T02:36:07.978Z" },
- { url = "https://files.pythonhosted.org/packages/fd/0d/462ce073b1f87cc6bf33b656c340c103eeb67487d118b761a697f1ee454f/fastar-0.8.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:923afc2db5192e56e71952a88e3fe5965c7c9c910d385d2db7573136f064f2fa", size = 709519, upload-time = "2025-11-26T02:34:44.783Z" },
- { url = "https://files.pythonhosted.org/packages/0d/f1/ceca1e04fd3266f866efdbb5d343fee1d8ff8fe94c64c8d1aab68b483ad0/fastar-0.8.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4fbe775356930f3aab0ce709fdf8ecf90c10882f5bbdcea215c89a3b14090c50", size = 632509, upload-time = "2025-11-26T02:34:29.428Z" },
- { url = "https://files.pythonhosted.org/packages/4f/db/fdb07e9dce80ebb38138f166a30dc482c82cc8dfcfda1024e8b100a53d1c/fastar-0.8.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:2ff516154e77f4bf78c31a0c11aa78a8a80e11b6964ec6f28982e42ffcbb543c", size = 871400, upload-time = "2025-11-26T02:33:58.461Z" },
- { url = "https://files.pythonhosted.org/packages/54/6d/d0a342528002cf7527339fd275bdee5e5cc90c2f193e8418d3510ffedcd7/fastar-0.8.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0d2fdd1c987ff2300bdf39baed556f8e155f8577018775e794a268ecf1707610", size = 765781, upload-time = "2025-11-26T02:32:53.929Z" },
- { url = "https://files.pythonhosted.org/packages/bc/96/dd2721e7160eed7bc9c3b695e942868c7ba2fab41947278fa380c18569be/fastar-0.8.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d80e4dad8ee2362a71870b1e735800bb5e97f12ebbee4bd0cf15a81ad2428b5a", size = 766126, upload-time = "2025-11-26T02:33:10.075Z" },
- { url = "https://files.pythonhosted.org/packages/9c/ac/6533d2608254def722cd8c852f4ac8fb413fc43ad3251b7fb99863ffaa83/fastar-0.8.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a17abee1febf5363ed2633f5e13de4be481ba1ab5f77860d39470eccdc4b65af", size = 932549, upload-time = "2025-11-26T02:33:25.866Z" },
- { url = "https://files.pythonhosted.org/packages/97/dc/aac042d0d0017b8d75ff34381cc28b482ace0d78a26d4eef9a8674f850c2/fastar-0.8.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:64cbde8e0ece3d799090a4727f936f66c5990d3ac59416f3de76a2c676e8e568", size = 821860, upload-time = "2025-11-26T02:33:41.423Z" },
- { url = "https://files.pythonhosted.org/packages/b2/ef/c31057572e3a5a2c90da4986d8594d0ff33097b4a44058f9f52103c33677/fastar-0.8.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:63d98b26590d293a9d9a379bae88367a8f3a6137c28819ed6dd6e11aca4a5c6e", size = 821660, upload-time = "2025-11-26T02:34:13.84Z" },
- { url = "https://files.pythonhosted.org/packages/39/00/d42fc84e8ce8587eb746406aa74ec231f97ce659a48bc064d5ff5cd78889/fastar-0.8.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:bf440983d4d64582bddf2f0bd3c43ea1db93a8c31cf7c20e473bffaf6d9c0b6d", size = 987026, upload-time = "2025-11-26T02:35:01.181Z" },
- { url = "https://files.pythonhosted.org/packages/aa/d9/5e4d37faca6f2df6a0bf1efc340192a871356162a7cc53626dc117645ad6/fastar-0.8.0-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:1d90cbf984a39afda27afe08e40c2d8eddc49c5e80590af641610c7b6dc20161", size = 1042165, upload-time = "2025-11-26T02:35:18.729Z" },
- { url = "https://files.pythonhosted.org/packages/77/fd/bb4731243e42f385e8db9da824971f5d0380e6b31466c36eb089d631c589/fastar-0.8.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:ca0db5e563d84b639fe15385eeca940777b6d2f0a1f3bb7cd5b55ab7124f0554", size = 1046990, upload-time = "2025-11-26T02:35:36.158Z" },
- { url = "https://files.pythonhosted.org/packages/c4/50/2ac066f771858ea45d885cfde7262b286a223af9538d3f85d29d5159b4fb/fastar-0.8.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:42ff3052d74684a636423d4f040db88eebd4caf20842fa5f06020e0130c01f69", size = 995637, upload-time = "2025-11-26T02:35:54.714Z" },
- { url = "https://files.pythonhosted.org/packages/d3/04/c884ea3fa7c154ac0e89219a337c9d6e0d52d0eb5547b3f99b896eca417e/fastar-0.8.0-cp39-cp39-win32.whl", hash = "sha256:15e3dfaa769d2117ef707e5f47c62126d1b63f8e9c85133112f33f1fbdf8942f", size = 456817, upload-time = "2025-11-26T02:36:33.198Z" },
- { url = "https://files.pythonhosted.org/packages/aa/0f/3a5758cca852bb221e78950fbfece0b932c6de6981ee36fb0ac57cf66c13/fastar-0.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:5153aa1c194316d0f67b6884a62d122d51fce4196263e92e4bca2a6c47cd44c0", size = 490633, upload-time = "2025-11-26T02:36:19.976Z" },
{ url = "https://files.pythonhosted.org/packages/25/9f/6eaa810c240236eff2edf736cd50a17c97dbab1693cda4f7bcea09d13418/fastar-0.8.0-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:2127cf2e80ffd49744a160201e0e2f55198af6c028a7b3f750026e0b1f1caa4e", size = 710544, upload-time = "2025-11-26T02:34:46.195Z" },
{ url = "https://files.pythonhosted.org/packages/1d/a5/58ff9e49a1cd5fbfc8f1238226cbf83b905376a391a6622cdd396b2cfa29/fastar-0.8.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:ff85094f10003801339ac4fa9b20a3410c2d8f284d4cba2dc99de6e98c877812", size = 634020, upload-time = "2025-11-26T02:34:31.085Z" },
{ url = "https://files.pythonhosted.org/packages/80/94/f839257c6600a83fbdb5a7fcc06319599086137b25ba38ca3d2c0fe14562/fastar-0.8.0-pp310-pypy310_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:3dbca235f0bd804cca6602fe055d3892bebf95fb802e6c6c7d872fb10f7abc6c", size = 871735, upload-time = "2025-11-26T02:34:00.088Z" },
@@ -1831,18 +1506,6 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/a4/b9/9a8c3fd59958c1c8027bc075af11722cdc62c4968bb277e841d131232289/fastar-0.8.0-pp311-pypy311_pp73-musllinux_1_2_armv7l.whl", hash = "sha256:382bfe82c026086487cb17fee12f4c1e2b4e67ce230f2e04487d3e7ddfd69031", size = 1042911, upload-time = "2025-11-26T02:35:21.857Z" },
{ url = "https://files.pythonhosted.org/packages/e2/2f/c3f30963b47022134b8a231c12845f4d7cfba520f59bbc1a82468aea77c7/fastar-0.8.0-pp311-pypy311_pp73-musllinux_1_2_i686.whl", hash = "sha256:908d2b9a1ff3d549cc304b32f95706a536da8f0bcb0bc0f9e4c1cce39b80e218", size = 1047464, upload-time = "2025-11-26T02:35:39.376Z" },
{ url = "https://files.pythonhosted.org/packages/9e/8a/218ab6d9a2bab3b07718e6cd8405529600edc1e9c266320e8524c8f63251/fastar-0.8.0-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:1aa7dbde2d2d73eb5b6203d0f74875cb66350f0f1b4325b4839fc8fbbf5d074e", size = 997309, upload-time = "2025-11-26T02:35:57.722Z" },
- { url = "https://files.pythonhosted.org/packages/4e/ef/da0cbac6da78b22ddb6ec0bbf3ad1813f8dd991a911342fc20e5feabaa15/fastar-0.8.0-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:284036bae786a520456ad3f58e72aaf1bd5d74e309132e568343564daa4ae383", size = 710367, upload-time = "2025-11-26T02:34:48.853Z" },
- { url = "https://files.pythonhosted.org/packages/c4/f0/951d368b4538477fe44651aaa7436318c22bf89e8e18086a68bd89e14a82/fastar-0.8.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:5aba0942b4f56acdb8fa8aa7cb506f70c1a17bf13dcab318a17ffb467cb2e7ec", size = 633744, upload-time = "2025-11-26T02:34:33.723Z" },
- { url = "https://files.pythonhosted.org/packages/1e/d2/5f37b634aff1e27191874b7f0fb7306e60566d984df06ff5c2f901ef123b/fastar-0.8.0-pp39-pypy39_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:52eda6230799db7bbd44461c622161e9bcd43603399da19b0daab2782e0030b0", size = 871412, upload-time = "2025-11-26T02:34:02.738Z" },
- { url = "https://files.pythonhosted.org/packages/b4/cd/41148c74cc164aacb8b5e7cb938a7ecc5a4e595f95e312aafcc8dbe36e48/fastar-0.8.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f860566b9f3cb1900980f46a4c3f003990c0009c11730f988f758542c17a2364", size = 766470, upload-time = "2025-11-26T02:32:58.503Z" },
- { url = "https://files.pythonhosted.org/packages/5f/89/b5715d4f969f15fe78b184ae42295e71f0ad2e0e083f0625212271cbda55/fastar-0.8.0-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:78f3fe5f45437c66d1dbece5f31aa487e48ef46d76b2082b873d5fa18013ebe1", size = 765285, upload-time = "2025-11-26T02:33:14.148Z" },
- { url = "https://files.pythonhosted.org/packages/39/4a/88223721278a663684c4fa6cb95ca296e0ba385362de4809a5e85cacfb36/fastar-0.8.0-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:82bc445202bbc53f067bb15e3b8639f01fd54d3096a0f9601240690cfd7c9684", size = 933881, upload-time = "2025-11-26T02:33:29.637Z" },
- { url = "https://files.pythonhosted.org/packages/ac/73/a13d6d57029378477c4d9232eddfb81bb2f74e0e91bdbca864c74223d877/fastar-0.8.0-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3b1208b5453cfe7192e54765f73844b80d684bd8dc6d6acbbb60ead42590b13e", size = 822511, upload-time = "2025-11-26T02:33:45.882Z" },
- { url = "https://files.pythonhosted.org/packages/a4/96/79000571a10d93e2110e72b5e7155e6bf138c8cb896117cfb768c74d01ff/fastar-0.8.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8922754c66699e27d4f1ce07c9c256228054cdc9bb36363e8bb5b503453a6da", size = 822204, upload-time = "2025-11-26T02:34:18.164Z" },
- { url = "https://files.pythonhosted.org/packages/35/e4/c2066024f336349ce36f85b0df9d082981d453cfdb5c139af2c5eebcc49a/fastar-0.8.0-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:92cad46dfbb9969359823c9f61165ec32d5d675d86e863889416e9b64efea95c", size = 987454, upload-time = "2025-11-26T02:35:05.827Z" },
- { url = "https://files.pythonhosted.org/packages/4a/b7/e3a062534af02610dea226d2c14e70beb90b91a23562fed8f76bfa35e6cd/fastar-0.8.0-pp39-pypy39_pp73-musllinux_1_2_armv7l.whl", hash = "sha256:f4eb9560a447ff6a4b377f08b6e5d3a31909a612b028f2c57810ffaf570eceb8", size = 1041310, upload-time = "2025-11-26T02:35:23.305Z" },
- { url = "https://files.pythonhosted.org/packages/91/73/1640476553705ee29ff9350a3b6c707ac150be53094d326e0d81d62a65ec/fastar-0.8.0-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:52455794e6cc2b6a6dbf141a1c4312a1a1215d75e8849a35fcff694454da880f", size = 1047020, upload-time = "2025-11-26T02:35:40.95Z" },
- { url = "https://files.pythonhosted.org/packages/b7/79/9b492c4da885a6699bc76032dbc285c565429ca1b6dc6b5aa5c908111d22/fastar-0.8.0-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:8de5decfa18a03807ae26ba5af095c2c04ac31ae915e9a849363a4495463171f", size = 996379, upload-time = "2025-11-26T02:35:59.297Z" },
]
[[package]]
@@ -1890,12 +1553,6 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/a7/1c/6dfd082a205be4510543221b734b1191299e6a1810c452b6bc76dfa6968e/fastavro-1.12.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b6a3462934b20a74f9ece1daa49c2e4e749bd9a35fa2657b53bf62898fba80f5", size = 3433972, upload-time = "2025-10-10T15:42:14.485Z" },
{ url = "https://files.pythonhosted.org/packages/24/90/9de694625a1a4b727b1ad0958d220cab25a9b6cf7f16a5c7faa9ea7b2261/fastavro-1.12.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:1f81011d54dd47b12437b51dd93a70a9aa17b61307abf26542fc3c13efbc6c51", size = 3368752, upload-time = "2025-10-10T15:42:16.618Z" },
{ url = "https://files.pythonhosted.org/packages/fa/93/b44f67589e4d439913dab6720f7e3507b0fa8b8e56d06f6fc875ced26afb/fastavro-1.12.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:43ded16b3f4a9f1a42f5970c2aa618acb23ea59c4fcaa06680bdf470b255e5a8", size = 3386636, upload-time = "2025-10-10T15:42:18.974Z" },
- { url = "https://files.pythonhosted.org/packages/8f/b8/67f5682cd59cb59ec6eecb5479b132caaf69709d1e1ceda4f92d8c69d7f1/fastavro-1.12.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:02281432dcb11c78b3280da996eff61ee0eff39c5de06c6e0fbf19275093e6d4", size = 1002311, upload-time = "2025-10-10T15:42:20.415Z" },
- { url = "https://files.pythonhosted.org/packages/93/38/2f15a7ad24e4b6e0239016c068f142358732bf8ead0315ee926b88634bec/fastavro-1.12.1-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4128978b930aaf930332db4b3acc290783183f3be06a241ae4a482f3ed8ce892", size = 3195871, upload-time = "2025-10-10T15:42:22.675Z" },
- { url = "https://files.pythonhosted.org/packages/c1/e5/6fc0250b3006b1b42c1ab9f0511ccd44e1aeb15a63a77fc780ee97f58797/fastavro-1.12.1-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:546ffffda6610fca672f0ed41149808e106d8272bb246aa7539fa8bb6f117f17", size = 3204127, upload-time = "2025-10-10T15:42:24.855Z" },
- { url = "https://files.pythonhosted.org/packages/c6/43/1f3909eb096eb1066e416f0875abe783b73fabe823ad616f6956b3e80e84/fastavro-1.12.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:a7d840ccd9aacada3ddc80fbcc4ea079b658107fe62e9d289a0de9d54e95d366", size = 3135604, upload-time = "2025-10-10T15:42:28.899Z" },
- { url = "https://files.pythonhosted.org/packages/e6/61/ec083a3a5d7c2b97d0e2c9e137a6e667583afe884af0e49318f7ee7eaa5a/fastavro-1.12.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:3100ad643e7fa658469a2a2db229981c1a000ff16b8037c0b58ce3ec4d2107e8", size = 3210932, upload-time = "2025-10-10T15:42:30.891Z" },
- { url = "https://files.pythonhosted.org/packages/9e/ba/b814fb09b32c8f3059451c33bb11d55eb23188e6a499f5dde628d13bc076/fastavro-1.12.1-cp39-cp39-win_amd64.whl", hash = "sha256:a38607444281619eda3a9c1be9f5397634012d1b237142eee1540e810b30ac8b", size = 510328, upload-time = "2025-10-10T15:42:32.415Z" },
]
[[package]]
@@ -1903,50 +1560,34 @@ name = "fastmcp"
version = "2.14.5"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "authlib", marker = "python_full_version >= '3.10'" },
- { name = "cyclopts", marker = "python_full_version >= '3.10'" },
- { name = "exceptiongroup", marker = "python_full_version >= '3.10'" },
- { name = "httpx", marker = "python_full_version >= '3.10'" },
- { name = "jsonref", marker = "python_full_version >= '3.10'" },
- { name = "jsonschema-path", marker = "python_full_version >= '3.10'" },
- { name = "mcp", marker = "python_full_version >= '3.10'" },
- { name = "openapi-pydantic", marker = "python_full_version >= '3.10'" },
- { name = "packaging", marker = "python_full_version >= '3.10'" },
- { name = "platformdirs", version = "4.5.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
- { name = "py-key-value-aio", extra = ["disk", "keyring", "memory"], marker = "python_full_version >= '3.10'" },
- { name = "pydantic", extra = ["email"], marker = "python_full_version >= '3.10'" },
- { name = "pydocket", marker = "python_full_version >= '3.10'" },
- { name = "pyperclip", marker = "python_full_version >= '3.10'" },
- { name = "python-dotenv", marker = "python_full_version >= '3.10'" },
- { name = "rich", marker = "python_full_version >= '3.10'" },
- { name = "uvicorn", version = "0.40.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
- { name = "websockets", marker = "python_full_version >= '3.10'" },
+ { name = "authlib" },
+ { name = "cyclopts" },
+ { name = "exceptiongroup" },
+ { name = "httpx" },
+ { name = "jsonref" },
+ { name = "jsonschema-path" },
+ { name = "mcp" },
+ { name = "openapi-pydantic" },
+ { name = "packaging" },
+ { name = "platformdirs" },
+ { name = "py-key-value-aio", extra = ["disk", "keyring", "memory"] },
+ { name = "pydantic", extra = ["email"] },
+ { name = "pydocket" },
+ { name = "pyperclip" },
+ { name = "python-dotenv" },
+ { name = "rich" },
+ { name = "uvicorn" },
+ { name = "websockets" },
]
sdist = { url = "https://files.pythonhosted.org/packages/3b/32/982678d44f13849530a74ab101ed80e060c2ee6cf87471f062dcf61705fd/fastmcp-2.14.5.tar.gz", hash = "sha256:38944dc582c541d55357082bda2241cedb42cd3a78faea8a9d6a2662c62a42d7", size = 8296329, upload-time = "2026-02-03T15:35:21.005Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/e5/c1/1a35ec68ff76ea8443aa115b18bcdee748a4ada2124537ee90522899ff9f/fastmcp-2.14.5-py3-none-any.whl", hash = "sha256:d81e8ec813f5089d3624bec93944beaefa86c0c3a4ef1111cbef676a761ebccf", size = 417784, upload-time = "2026-02-03T15:35:18.489Z" },
]
-[[package]]
-name = "filelock"
-version = "3.19.1"
-source = { registry = "https://pypi.org/simple" }
-resolution-markers = [
- "python_full_version < '3.10'",
-]
-sdist = { url = "https://files.pythonhosted.org/packages/40/bb/0ab3e58d22305b6f5440629d20683af28959bf793d98d11950e305c1c326/filelock-3.19.1.tar.gz", hash = "sha256:66eda1888b0171c998b35be2bcc0f6d75c388a7ce20c3f3f37aa8e96c2dddf58", size = 17687, upload-time = "2025-08-14T16:56:03.016Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/42/14/42b2651a2f46b022ccd948bca9f2d5af0fd8929c4eec235b8d6d844fbe67/filelock-3.19.1-py3-none-any.whl", hash = "sha256:d38e30481def20772f5baf097c122c3babc4fcdb7e14e57049eb9d88c6dc017d", size = 15988, upload-time = "2025-08-14T16:56:01.633Z" },
-]
-
[[package]]
name = "filelock"
version = "3.20.3"
source = { registry = "https://pypi.org/simple" }
-resolution-markers = [
- "python_full_version >= '3.14'",
- "python_full_version >= '3.10' and python_full_version < '3.14'",
-]
sdist = { url = "https://files.pythonhosted.org/packages/1d/65/ce7f1b70157833bf3cb851b556a37d4547ceafc158aa9b34b36782f23696/filelock-3.20.3.tar.gz", hash = "sha256:18c57ee915c7ec61cff0ecf7f0f869936c7c30191bb0cf406f1341778d0834e1", size = 19485, upload-time = "2026-01-09T17:55:05.421Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/b5/36/7fb70f04bf00bc646cd5bb45aa9eddb15e19437a28b8fb2b4a5249fac770/filelock-3.20.3-py3-none-any.whl", hash = "sha256:4b0dda527ee31078689fc205ec4f1c1bf7d56cf88b6dc9426c4f230e46c2dce1", size = 16701, upload-time = "2026-01-09T17:55:04.334Z" },
@@ -1958,9 +1599,7 @@ version = "3.1.2"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "blinker" },
- { name = "click", version = "8.1.8", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
- { name = "click", version = "8.3.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
- { name = "importlib-metadata", marker = "python_full_version < '3.10'" },
+ { name = "click" },
{ name = "itsdangerous" },
{ name = "jinja2" },
{ name = "markupsafe" },
@@ -2089,45 +1728,13 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/af/d3/76bd4ed4317e7119c2b7f57c3f6934aba26d277acc6309f873341640e21f/frozenlist-1.8.0-cp314-cp314t-win32.whl", hash = "sha256:342c97bf697ac5480c0a7ec73cd700ecfa5a8a40ac923bd035484616efecc2df", size = 44676, upload-time = "2025-10-06T05:37:52.222Z" },
{ url = "https://files.pythonhosted.org/packages/89/76/c615883b7b521ead2944bb3480398cbb07e12b7b4e4d073d3752eb721558/frozenlist-1.8.0-cp314-cp314t-win_amd64.whl", hash = "sha256:06be8f67f39c8b1dc671f5d83aaefd3358ae5cdcf8314552c57e7ed3e6475bdd", size = 49451, upload-time = "2025-10-06T05:37:53.425Z" },
{ url = "https://files.pythonhosted.org/packages/e0/a3/5982da14e113d07b325230f95060e2169f5311b1017ea8af2a29b374c289/frozenlist-1.8.0-cp314-cp314t-win_arm64.whl", hash = "sha256:102e6314ca4da683dca92e3b1355490fed5f313b768500084fbe6371fddfdb79", size = 42507, upload-time = "2025-10-06T05:37:54.513Z" },
- { url = "https://files.pythonhosted.org/packages/c2/59/ae5cdac87a00962122ea37bb346d41b66aec05f9ce328fa2b9e216f8967b/frozenlist-1.8.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:d8b7138e5cd0647e4523d6685b0eac5d4be9a184ae9634492f25c6eb38c12a47", size = 86967, upload-time = "2025-10-06T05:37:55.607Z" },
- { url = "https://files.pythonhosted.org/packages/8a/10/17059b2db5a032fd9323c41c39e9d1f5f9d0c8f04d1e4e3e788573086e61/frozenlist-1.8.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a6483e309ca809f1efd154b4d37dc6d9f61037d6c6a81c2dc7a15cb22c8c5dca", size = 49984, upload-time = "2025-10-06T05:37:57.049Z" },
- { url = "https://files.pythonhosted.org/packages/4b/de/ad9d82ca8e5fa8f0c636e64606553c79e2b859ad253030b62a21fe9986f5/frozenlist-1.8.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1b9290cf81e95e93fdf90548ce9d3c1211cf574b8e3f4b3b7cb0537cf2227068", size = 50240, upload-time = "2025-10-06T05:37:58.145Z" },
- { url = "https://files.pythonhosted.org/packages/4e/45/3dfb7767c2a67d123650122b62ce13c731b6c745bc14424eea67678b508c/frozenlist-1.8.0-cp39-cp39-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:59a6a5876ca59d1b63af8cd5e7ffffb024c3dc1e9cf9301b21a2e76286505c95", size = 219472, upload-time = "2025-10-06T05:37:59.239Z" },
- { url = "https://files.pythonhosted.org/packages/0b/bf/5bf23d913a741b960d5c1dac7c1985d8a2a1d015772b2d18ea168b08e7ff/frozenlist-1.8.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6dc4126390929823e2d2d9dc79ab4046ed74680360fc5f38b585c12c66cdf459", size = 221531, upload-time = "2025-10-06T05:38:00.521Z" },
- { url = "https://files.pythonhosted.org/packages/d0/03/27ec393f3b55860859f4b74cdc8c2a4af3dbf3533305e8eacf48a4fd9a54/frozenlist-1.8.0-cp39-cp39-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:332db6b2563333c5671fecacd085141b5800cb866be16d5e3eb15a2086476675", size = 219211, upload-time = "2025-10-06T05:38:01.842Z" },
- { url = "https://files.pythonhosted.org/packages/3a/ad/0fd00c404fa73fe9b169429e9a972d5ed807973c40ab6b3cf9365a33d360/frozenlist-1.8.0-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9ff15928d62a0b80bb875655c39bf517938c7d589554cbd2669be42d97c2cb61", size = 231775, upload-time = "2025-10-06T05:38:03.384Z" },
- { url = "https://files.pythonhosted.org/packages/8a/c3/86962566154cb4d2995358bc8331bfc4ea19d07db1a96f64935a1607f2b6/frozenlist-1.8.0-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:7bf6cdf8e07c8151fba6fe85735441240ec7f619f935a5205953d58009aef8c6", size = 236631, upload-time = "2025-10-06T05:38:04.609Z" },
- { url = "https://files.pythonhosted.org/packages/ea/9e/6ffad161dbd83782d2c66dc4d378a9103b31770cb1e67febf43aea42d202/frozenlist-1.8.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:48e6d3f4ec5c7273dfe83ff27c91083c6c9065af655dc2684d2c200c94308bb5", size = 218632, upload-time = "2025-10-06T05:38:05.917Z" },
- { url = "https://files.pythonhosted.org/packages/58/b2/4677eee46e0a97f9b30735e6ad0bf6aba3e497986066eb68807ac85cf60f/frozenlist-1.8.0-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:1a7607e17ad33361677adcd1443edf6f5da0ce5e5377b798fba20fae194825f3", size = 235967, upload-time = "2025-10-06T05:38:07.614Z" },
- { url = "https://files.pythonhosted.org/packages/05/f3/86e75f8639c5a93745ca7addbbc9de6af56aebb930d233512b17e46f6493/frozenlist-1.8.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:5a3a935c3a4e89c733303a2d5a7c257ea44af3a56c8202df486b7f5de40f37e1", size = 228799, upload-time = "2025-10-06T05:38:08.845Z" },
- { url = "https://files.pythonhosted.org/packages/30/00/39aad3a7f0d98f5eb1d99a3c311215674ed87061aecee7851974b335c050/frozenlist-1.8.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:940d4a017dbfed9daf46a3b086e1d2167e7012ee297fef9e1c545c4d022f5178", size = 230566, upload-time = "2025-10-06T05:38:10.52Z" },
- { url = "https://files.pythonhosted.org/packages/0d/4d/aa144cac44568d137846ddc4d5210fb5d9719eb1d7ec6fa2728a54b5b94a/frozenlist-1.8.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:b9be22a69a014bc47e78072d0ecae716f5eb56c15238acca0f43d6eb8e4a5bda", size = 217715, upload-time = "2025-10-06T05:38:11.832Z" },
- { url = "https://files.pythonhosted.org/packages/64/4c/8f665921667509d25a0dd72540513bc86b356c95541686f6442a3283019f/frozenlist-1.8.0-cp39-cp39-win32.whl", hash = "sha256:1aa77cb5697069af47472e39612976ed05343ff2e84a3dcf15437b232cbfd087", size = 39933, upload-time = "2025-10-06T05:38:13.061Z" },
- { url = "https://files.pythonhosted.org/packages/79/bd/bcc926f87027fad5e59926ff12d136e1082a115025d33c032d1cd69ab377/frozenlist-1.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:7398c222d1d405e796970320036b1b563892b65809d9e5261487bb2c7f7b5c6a", size = 44121, upload-time = "2025-10-06T05:38:14.572Z" },
- { url = "https://files.pythonhosted.org/packages/4c/07/9c2e4eb7584af4b705237b971b89a4155a8e57599c4483a131a39256a9a0/frozenlist-1.8.0-cp39-cp39-win_arm64.whl", hash = "sha256:b4f3b365f31c6cd4af24545ca0a244a53688cad8834e32f56831c4923b50a103", size = 40312, upload-time = "2025-10-06T05:38:15.699Z" },
{ url = "https://files.pythonhosted.org/packages/9a/9a/e35b4a917281c0b8419d4207f4334c8e8c5dbf4f3f5f9ada73958d937dcc/frozenlist-1.8.0-py3-none-any.whl", hash = "sha256:0c18a16eab41e82c295618a77502e17b195883241c563b00f0aa5106fc4eaa0d", size = 13409, upload-time = "2025-10-06T05:38:16.721Z" },
]
-[[package]]
-name = "fsspec"
-version = "2025.10.0"
-source = { registry = "https://pypi.org/simple" }
-resolution-markers = [
- "python_full_version < '3.10'",
-]
-sdist = { url = "https://files.pythonhosted.org/packages/24/7f/2747c0d332b9acfa75dc84447a066fdf812b5a6b8d30472b74d309bfe8cb/fsspec-2025.10.0.tar.gz", hash = "sha256:b6789427626f068f9a83ca4e8a3cc050850b6c0f71f99ddb4f542b8266a26a59", size = 309285, upload-time = "2025-10-30T14:58:44.036Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/eb/02/a6b21098b1d5d6249b7c5ab69dde30108a71e4e819d4a9778f1de1d5b70d/fsspec-2025.10.0-py3-none-any.whl", hash = "sha256:7c7712353ae7d875407f97715f0e1ffcc21e33d5b24556cb1e090ae9409ec61d", size = 200966, upload-time = "2025-10-30T14:58:42.53Z" },
-]
-
[[package]]
name = "fsspec"
version = "2026.2.0"
source = { registry = "https://pypi.org/simple" }
-resolution-markers = [
- "python_full_version >= '3.14'",
- "python_full_version >= '3.10' and python_full_version < '3.14'",
-]
sdist = { url = "https://files.pythonhosted.org/packages/51/7c/f60c259dcbf4f0c47cc4ddb8f7720d2dcdc8888c8e5ad84c73ea4531cc5b/fsspec-2026.2.0.tar.gz", hash = "sha256:6544e34b16869f5aacd5b90bdf1a71acb37792ea3ddf6125ee69a22a53fb8bff", size = 313441, upload-time = "2026-02-05T21:50:53.743Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/e6/ab/fb21f4c939bb440104cc2b396d3be1d9b7a9fd3c6c2a53d98c45b3d7c954/fsspec-2026.2.0-py3-none-any.whl", hash = "sha256:98de475b5cb3bd66bedd5c4679e87b4fdfe1a3bf4d707b151b3c07e58c9a2437", size = 202505, upload-time = "2026-02-05T21:50:51.819Z" },
@@ -2138,7 +1745,6 @@ name = "genai-prices"
version = "0.0.52"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "eval-type-backport", marker = "python_full_version < '3.10'" },
{ name = "httpx" },
{ name = "pydantic" },
]
@@ -2177,7 +1783,6 @@ version = "3.1.46"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "gitdb" },
- { name = "typing-extensions", marker = "python_full_version < '3.10'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/df/b5/59d16470a1f0dfe8c793f9ef56fd3826093fc52b3bd96d6b9d6c26c7e27b/gitpython-3.1.46.tar.gz", hash = "sha256:400124c7d0ef4ea03f7310ac2fbf7151e09ff97f2a3288d64a440c584a29c37f", size = 215371, upload-time = "2026-01-01T15:37:32.073Z" }
wheels = [
@@ -2200,50 +1805,24 @@ wheels = [
[package.optional-dependencies]
requests = [
- { name = "requests", marker = "python_full_version >= '3.10'" },
-]
-
-[[package]]
-name = "google-genai"
-version = "1.47.0"
-source = { registry = "https://pypi.org/simple" }
-resolution-markers = [
- "python_full_version < '3.10'",
-]
-dependencies = [
- { name = "anyio", marker = "python_full_version < '3.10'" },
- { name = "google-auth", marker = "python_full_version < '3.10'" },
- { name = "httpx", marker = "python_full_version < '3.10'" },
- { name = "pydantic", marker = "python_full_version < '3.10'" },
- { name = "requests", marker = "python_full_version < '3.10'" },
- { name = "tenacity", version = "9.1.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
- { name = "typing-extensions", marker = "python_full_version < '3.10'" },
- { name = "websockets", marker = "python_full_version < '3.10'" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/9f/97/784fba9bc6c41263ff90cb9063eadfdd755dde79cfa5a8d0e397b067dcf9/google_genai-1.47.0.tar.gz", hash = "sha256:ecece00d0a04e6739ea76cc8dad82ec9593d9380aaabef078990e60574e5bf59", size = 241471, upload-time = "2025-10-29T22:01:02.88Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/89/ef/e080e8d67c270ea320956bb911a9359664fc46d3b87d1f029decd33e5c4c/google_genai-1.47.0-py3-none-any.whl", hash = "sha256:e3851237556cbdec96007d8028b4b1f2425cdc5c099a8dc36b72a57e42821b60", size = 241506, upload-time = "2025-10-29T22:01:00.982Z" },
+ { name = "requests" },
]
[[package]]
name = "google-genai"
version = "1.62.0"
source = { registry = "https://pypi.org/simple" }
-resolution-markers = [
- "python_full_version >= '3.14'",
- "python_full_version >= '3.10' and python_full_version < '3.14'",
-]
dependencies = [
- { name = "anyio", marker = "python_full_version >= '3.10'" },
- { name = "distro", marker = "python_full_version >= '3.10'" },
- { name = "google-auth", extra = ["requests"], marker = "python_full_version >= '3.10'" },
- { name = "httpx", marker = "python_full_version >= '3.10'" },
- { name = "pydantic", marker = "python_full_version >= '3.10'" },
- { name = "requests", marker = "python_full_version >= '3.10'" },
- { name = "sniffio", marker = "python_full_version >= '3.10'" },
- { name = "tenacity", version = "9.1.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
- { name = "typing-extensions", marker = "python_full_version >= '3.10'" },
- { name = "websockets", marker = "python_full_version >= '3.10'" },
+ { name = "anyio" },
+ { name = "distro" },
+ { name = "google-auth", extra = ["requests"] },
+ { name = "httpx" },
+ { name = "pydantic" },
+ { name = "requests" },
+ { name = "sniffio" },
+ { name = "tenacity" },
+ { name = "typing-extensions" },
+ { name = "websockets" },
]
sdist = { url = "https://files.pythonhosted.org/packages/94/4c/71b32b5c8db420cf2fd0d5ef8a672adbde97d85e5d44a0b4fca712264ef1/google_genai-1.62.0.tar.gz", hash = "sha256:709468a14c739a080bc240a4f3191df597bf64485b1ca3728e0fb67517774c18", size = 490888, upload-time = "2026-02-04T22:48:41.989Z" }
wheels = [
@@ -2255,7 +1834,7 @@ name = "googleapis-common-protos"
version = "1.72.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "protobuf", version = "6.33.5", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
+ { name = "protobuf" },
]
sdist = { url = "https://files.pythonhosted.org/packages/e5/7b/adfd75544c415c487b33061fe7ae526165241c1ea133f9a9125a56b39fd8/googleapis_common_protos-1.72.0.tar.gz", hash = "sha256:e55a601c1b32b52d7a3e65f43563e2aa61bcd737998ee672ac9b951cd49319f5", size = 147433, upload-time = "2025-11-06T18:29:24.087Z" }
wheels = [
@@ -2266,98 +1845,15 @@ wheels = [
name = "graphql-core"
version = "3.2.7"
source = { registry = "https://pypi.org/simple" }
-dependencies = [
- { name = "typing-extensions", marker = "python_full_version < '3.10'" },
-]
sdist = { url = "https://files.pythonhosted.org/packages/ac/9b/037a640a2983b09aed4a823f9cf1729e6d780b0671f854efa4727a7affbe/graphql_core-3.2.7.tar.gz", hash = "sha256:27b6904bdd3b43f2a0556dad5d579bdfdeab1f38e8e8788e555bdcb586a6f62c", size = 513484, upload-time = "2025-11-01T22:30:40.436Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/0a/14/933037032608787fb92e365883ad6a741c235e0ff992865ec5d904a38f1e/graphql_core-3.2.7-py3-none-any.whl", hash = "sha256:17fc8f3ca4a42913d8e24d9ac9f08deddf0a0b2483076575757f6c412ead2ec0", size = 207262, upload-time = "2025-11-01T22:30:38.912Z" },
]
-[[package]]
-name = "greenlet"
-version = "3.2.4"
-source = { registry = "https://pypi.org/simple" }
-resolution-markers = [
- "python_full_version < '3.10'",
-]
-sdist = { url = "https://files.pythonhosted.org/packages/03/b8/704d753a5a45507a7aab61f18db9509302ed3d0a27ac7e0359ec2905b1a6/greenlet-3.2.4.tar.gz", hash = "sha256:0dca0d95ff849f9a364385f36ab49f50065d76964944638be9691e1832e9f86d", size = 188260, upload-time = "2025-08-07T13:24:33.51Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/7d/ed/6bfa4109fcb23a58819600392564fea69cdc6551ffd5e69ccf1d52a40cbc/greenlet-3.2.4-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:8c68325b0d0acf8d91dde4e6f930967dd52a5302cd4062932a6b2e7c2969f47c", size = 271061, upload-time = "2025-08-07T13:17:15.373Z" },
- { url = "https://files.pythonhosted.org/packages/2a/fc/102ec1a2fc015b3a7652abab7acf3541d58c04d3d17a8d3d6a44adae1eb1/greenlet-3.2.4-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:94385f101946790ae13da500603491f04a76b6e4c059dab271b3ce2e283b2590", size = 629475, upload-time = "2025-08-07T13:42:54.009Z" },
- { url = "https://files.pythonhosted.org/packages/c5/26/80383131d55a4ac0fb08d71660fd77e7660b9db6bdb4e8884f46d9f2cc04/greenlet-3.2.4-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f10fd42b5ee276335863712fa3da6608e93f70629c631bf77145021600abc23c", size = 640802, upload-time = "2025-08-07T13:45:25.52Z" },
- { url = "https://files.pythonhosted.org/packages/9f/7c/e7833dbcd8f376f3326bd728c845d31dcde4c84268d3921afcae77d90d08/greenlet-3.2.4-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:c8c9e331e58180d0d83c5b7999255721b725913ff6bc6cf39fa2a45841a4fd4b", size = 636703, upload-time = "2025-08-07T13:53:12.622Z" },
- { url = "https://files.pythonhosted.org/packages/e9/49/547b93b7c0428ede7b3f309bc965986874759f7d89e4e04aeddbc9699acb/greenlet-3.2.4-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:58b97143c9cc7b86fc458f215bd0932f1757ce649e05b640fea2e79b54cedb31", size = 635417, upload-time = "2025-08-07T13:18:25.189Z" },
- { url = "https://files.pythonhosted.org/packages/7f/91/ae2eb6b7979e2f9b035a9f612cf70f1bf54aad4e1d125129bef1eae96f19/greenlet-3.2.4-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c2ca18a03a8cfb5b25bc1cbe20f3d9a4c80d8c3b13ba3df49ac3961af0b1018d", size = 584358, upload-time = "2025-08-07T13:18:23.708Z" },
- { url = "https://files.pythonhosted.org/packages/f7/85/433de0c9c0252b22b16d413c9407e6cb3b41df7389afc366ca204dbc1393/greenlet-3.2.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:9fe0a28a7b952a21e2c062cd5756d34354117796c6d9215a87f55e38d15402c5", size = 1113550, upload-time = "2025-08-07T13:42:37.467Z" },
- { url = "https://files.pythonhosted.org/packages/a1/8d/88f3ebd2bc96bf7747093696f4335a0a8a4c5acfcf1b757717c0d2474ba3/greenlet-3.2.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8854167e06950ca75b898b104b63cc646573aa5fef1353d4508ecdd1ee76254f", size = 1137126, upload-time = "2025-08-07T13:18:20.239Z" },
- { url = "https://files.pythonhosted.org/packages/f1/29/74242b7d72385e29bcc5563fba67dad94943d7cd03552bac320d597f29b2/greenlet-3.2.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f47617f698838ba98f4ff4189aef02e7343952df3a615f847bb575c3feb177a7", size = 1544904, upload-time = "2025-11-04T12:42:04.763Z" },
- { url = "https://files.pythonhosted.org/packages/c8/e2/1572b8eeab0f77df5f6729d6ab6b141e4a84ee8eb9bc8c1e7918f94eda6d/greenlet-3.2.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:af41be48a4f60429d5cad9d22175217805098a9ef7c40bfef44f7669fb9d74d8", size = 1611228, upload-time = "2025-11-04T12:42:08.423Z" },
- { url = "https://files.pythonhosted.org/packages/d6/6f/b60b0291d9623c496638c582297ead61f43c4b72eef5e9c926ef4565ec13/greenlet-3.2.4-cp310-cp310-win_amd64.whl", hash = "sha256:73f49b5368b5359d04e18d15828eecc1806033db5233397748f4ca813ff1056c", size = 298654, upload-time = "2025-08-07T13:50:00.469Z" },
- { url = "https://files.pythonhosted.org/packages/a4/de/f28ced0a67749cac23fecb02b694f6473f47686dff6afaa211d186e2ef9c/greenlet-3.2.4-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:96378df1de302bc38e99c3a9aa311967b7dc80ced1dcc6f171e99842987882a2", size = 272305, upload-time = "2025-08-07T13:15:41.288Z" },
- { url = "https://files.pythonhosted.org/packages/09/16/2c3792cba130000bf2a31c5272999113f4764fd9d874fb257ff588ac779a/greenlet-3.2.4-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:1ee8fae0519a337f2329cb78bd7a8e128ec0f881073d43f023c7b8d4831d5246", size = 632472, upload-time = "2025-08-07T13:42:55.044Z" },
- { url = "https://files.pythonhosted.org/packages/ae/8f/95d48d7e3d433e6dae5b1682e4292242a53f22df82e6d3dda81b1701a960/greenlet-3.2.4-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:94abf90142c2a18151632371140b3dba4dee031633fe614cb592dbb6c9e17bc3", size = 644646, upload-time = "2025-08-07T13:45:26.523Z" },
- { url = "https://files.pythonhosted.org/packages/d5/5e/405965351aef8c76b8ef7ad370e5da58d57ef6068df197548b015464001a/greenlet-3.2.4-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:4d1378601b85e2e5171b99be8d2dc85f594c79967599328f95c1dc1a40f1c633", size = 640519, upload-time = "2025-08-07T13:53:13.928Z" },
- { url = "https://files.pythonhosted.org/packages/25/5d/382753b52006ce0218297ec1b628e048c4e64b155379331f25a7316eb749/greenlet-3.2.4-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0db5594dce18db94f7d1650d7489909b57afde4c580806b8d9203b6e79cdc079", size = 639707, upload-time = "2025-08-07T13:18:27.146Z" },
- { url = "https://files.pythonhosted.org/packages/1f/8e/abdd3f14d735b2929290a018ecf133c901be4874b858dd1c604b9319f064/greenlet-3.2.4-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2523e5246274f54fdadbce8494458a2ebdcdbc7b802318466ac5606d3cded1f8", size = 587684, upload-time = "2025-08-07T13:18:25.164Z" },
- { url = "https://files.pythonhosted.org/packages/5d/65/deb2a69c3e5996439b0176f6651e0052542bb6c8f8ec2e3fba97c9768805/greenlet-3.2.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:1987de92fec508535687fb807a5cea1560f6196285a4cde35c100b8cd632cc52", size = 1116647, upload-time = "2025-08-07T13:42:38.655Z" },
- { url = "https://files.pythonhosted.org/packages/3f/cc/b07000438a29ac5cfb2194bfc128151d52f333cee74dd7dfe3fb733fc16c/greenlet-3.2.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:55e9c5affaa6775e2c6b67659f3a71684de4c549b3dd9afca3bc773533d284fa", size = 1142073, upload-time = "2025-08-07T13:18:21.737Z" },
- { url = "https://files.pythonhosted.org/packages/67/24/28a5b2fa42d12b3d7e5614145f0bd89714c34c08be6aabe39c14dd52db34/greenlet-3.2.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c9c6de1940a7d828635fbd254d69db79e54619f165ee7ce32fda763a9cb6a58c", size = 1548385, upload-time = "2025-11-04T12:42:11.067Z" },
- { url = "https://files.pythonhosted.org/packages/6a/05/03f2f0bdd0b0ff9a4f7b99333d57b53a7709c27723ec8123056b084e69cd/greenlet-3.2.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:03c5136e7be905045160b1b9fdca93dd6727b180feeafda6818e6496434ed8c5", size = 1613329, upload-time = "2025-11-04T12:42:12.928Z" },
- { url = "https://files.pythonhosted.org/packages/d8/0f/30aef242fcab550b0b3520b8e3561156857c94288f0332a79928c31a52cf/greenlet-3.2.4-cp311-cp311-win_amd64.whl", hash = "sha256:9c40adce87eaa9ddb593ccb0fa6a07caf34015a29bf8d344811665b573138db9", size = 299100, upload-time = "2025-08-07T13:44:12.287Z" },
- { url = "https://files.pythonhosted.org/packages/44/69/9b804adb5fd0671f367781560eb5eb586c4d495277c93bde4307b9e28068/greenlet-3.2.4-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:3b67ca49f54cede0186854a008109d6ee71f66bd57bb36abd6d0a0267b540cdd", size = 274079, upload-time = "2025-08-07T13:15:45.033Z" },
- { url = "https://files.pythonhosted.org/packages/46/e9/d2a80c99f19a153eff70bc451ab78615583b8dac0754cfb942223d2c1a0d/greenlet-3.2.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ddf9164e7a5b08e9d22511526865780a576f19ddd00d62f8a665949327fde8bb", size = 640997, upload-time = "2025-08-07T13:42:56.234Z" },
- { url = "https://files.pythonhosted.org/packages/3b/16/035dcfcc48715ccd345f3a93183267167cdd162ad123cd93067d86f27ce4/greenlet-3.2.4-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f28588772bb5fb869a8eb331374ec06f24a83a9c25bfa1f38b6993afe9c1e968", size = 655185, upload-time = "2025-08-07T13:45:27.624Z" },
- { url = "https://files.pythonhosted.org/packages/31/da/0386695eef69ffae1ad726881571dfe28b41970173947e7c558d9998de0f/greenlet-3.2.4-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:5c9320971821a7cb77cfab8d956fa8e39cd07ca44b6070db358ceb7f8797c8c9", size = 649926, upload-time = "2025-08-07T13:53:15.251Z" },
- { url = "https://files.pythonhosted.org/packages/68/88/69bf19fd4dc19981928ceacbc5fd4bb6bc2215d53199e367832e98d1d8fe/greenlet-3.2.4-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c60a6d84229b271d44b70fb6e5fa23781abb5d742af7b808ae3f6efd7c9c60f6", size = 651839, upload-time = "2025-08-07T13:18:30.281Z" },
- { url = "https://files.pythonhosted.org/packages/19/0d/6660d55f7373b2ff8152401a83e02084956da23ae58cddbfb0b330978fe9/greenlet-3.2.4-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3b3812d8d0c9579967815af437d96623f45c0f2ae5f04e366de62a12d83a8fb0", size = 607586, upload-time = "2025-08-07T13:18:28.544Z" },
- { url = "https://files.pythonhosted.org/packages/8e/1a/c953fdedd22d81ee4629afbb38d2f9d71e37d23caace44775a3a969147d4/greenlet-3.2.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:abbf57b5a870d30c4675928c37278493044d7c14378350b3aa5d484fa65575f0", size = 1123281, upload-time = "2025-08-07T13:42:39.858Z" },
- { url = "https://files.pythonhosted.org/packages/3f/c7/12381b18e21aef2c6bd3a636da1088b888b97b7a0362fac2e4de92405f97/greenlet-3.2.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:20fb936b4652b6e307b8f347665e2c615540d4b42b3b4c8a321d8286da7e520f", size = 1151142, upload-time = "2025-08-07T13:18:22.981Z" },
- { url = "https://files.pythonhosted.org/packages/27/45/80935968b53cfd3f33cf99ea5f08227f2646e044568c9b1555b58ffd61c2/greenlet-3.2.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ee7a6ec486883397d70eec05059353b8e83eca9168b9f3f9a361971e77e0bcd0", size = 1564846, upload-time = "2025-11-04T12:42:15.191Z" },
- { url = "https://files.pythonhosted.org/packages/69/02/b7c30e5e04752cb4db6202a3858b149c0710e5453b71a3b2aec5d78a1aab/greenlet-3.2.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:326d234cbf337c9c3def0676412eb7040a35a768efc92504b947b3e9cfc7543d", size = 1633814, upload-time = "2025-11-04T12:42:17.175Z" },
- { url = "https://files.pythonhosted.org/packages/e9/08/b0814846b79399e585f974bbeebf5580fbe59e258ea7be64d9dfb253c84f/greenlet-3.2.4-cp312-cp312-win_amd64.whl", hash = "sha256:a7d4e128405eea3814a12cc2605e0e6aedb4035bf32697f72deca74de4105e02", size = 299899, upload-time = "2025-08-07T13:38:53.448Z" },
- { url = "https://files.pythonhosted.org/packages/49/e8/58c7f85958bda41dafea50497cbd59738c5c43dbbea5ee83d651234398f4/greenlet-3.2.4-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:1a921e542453fe531144e91e1feedf12e07351b1cf6c9e8a3325ea600a715a31", size = 272814, upload-time = "2025-08-07T13:15:50.011Z" },
- { url = "https://files.pythonhosted.org/packages/62/dd/b9f59862e9e257a16e4e610480cfffd29e3fae018a68c2332090b53aac3d/greenlet-3.2.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:cd3c8e693bff0fff6ba55f140bf390fa92c994083f838fece0f63be121334945", size = 641073, upload-time = "2025-08-07T13:42:57.23Z" },
- { url = "https://files.pythonhosted.org/packages/f7/0b/bc13f787394920b23073ca3b6c4a7a21396301ed75a655bcb47196b50e6e/greenlet-3.2.4-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:710638eb93b1fa52823aa91bf75326f9ecdfd5e0466f00789246a5280f4ba0fc", size = 655191, upload-time = "2025-08-07T13:45:29.752Z" },
- { url = "https://files.pythonhosted.org/packages/f2/d6/6adde57d1345a8d0f14d31e4ab9c23cfe8e2cd39c3baf7674b4b0338d266/greenlet-3.2.4-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:c5111ccdc9c88f423426df3fd1811bfc40ed66264d35aa373420a34377efc98a", size = 649516, upload-time = "2025-08-07T13:53:16.314Z" },
- { url = "https://files.pythonhosted.org/packages/7f/3b/3a3328a788d4a473889a2d403199932be55b1b0060f4ddd96ee7cdfcad10/greenlet-3.2.4-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d76383238584e9711e20ebe14db6c88ddcedc1829a9ad31a584389463b5aa504", size = 652169, upload-time = "2025-08-07T13:18:32.861Z" },
- { url = "https://files.pythonhosted.org/packages/ee/43/3cecdc0349359e1a527cbf2e3e28e5f8f06d3343aaf82ca13437a9aa290f/greenlet-3.2.4-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:23768528f2911bcd7e475210822ffb5254ed10d71f4028387e5a99b4c6699671", size = 610497, upload-time = "2025-08-07T13:18:31.636Z" },
- { url = "https://files.pythonhosted.org/packages/b8/19/06b6cf5d604e2c382a6f31cafafd6f33d5dea706f4db7bdab184bad2b21d/greenlet-3.2.4-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:00fadb3fedccc447f517ee0d3fd8fe49eae949e1cd0f6a611818f4f6fb7dc83b", size = 1121662, upload-time = "2025-08-07T13:42:41.117Z" },
- { url = "https://files.pythonhosted.org/packages/a2/15/0d5e4e1a66fab130d98168fe984c509249c833c1a3c16806b90f253ce7b9/greenlet-3.2.4-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:d25c5091190f2dc0eaa3f950252122edbbadbb682aa7b1ef2f8af0f8c0afefae", size = 1149210, upload-time = "2025-08-07T13:18:24.072Z" },
- { url = "https://files.pythonhosted.org/packages/1c/53/f9c440463b3057485b8594d7a638bed53ba531165ef0ca0e6c364b5cc807/greenlet-3.2.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:6e343822feb58ac4d0a1211bd9399de2b3a04963ddeec21530fc426cc121f19b", size = 1564759, upload-time = "2025-11-04T12:42:19.395Z" },
- { url = "https://files.pythonhosted.org/packages/47/e4/3bb4240abdd0a8d23f4f88adec746a3099f0d86bfedb623f063b2e3b4df0/greenlet-3.2.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ca7f6f1f2649b89ce02f6f229d7c19f680a6238af656f61e0115b24857917929", size = 1634288, upload-time = "2025-11-04T12:42:21.174Z" },
- { url = "https://files.pythonhosted.org/packages/0b/55/2321e43595e6801e105fcfdee02b34c0f996eb71e6ddffca6b10b7e1d771/greenlet-3.2.4-cp313-cp313-win_amd64.whl", hash = "sha256:554b03b6e73aaabec3745364d6239e9e012d64c68ccd0b8430c64ccc14939a8b", size = 299685, upload-time = "2025-08-07T13:24:38.824Z" },
- { url = "https://files.pythonhosted.org/packages/22/5c/85273fd7cc388285632b0498dbbab97596e04b154933dfe0f3e68156c68c/greenlet-3.2.4-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:49a30d5fda2507ae77be16479bdb62a660fa51b1eb4928b524975b3bde77b3c0", size = 273586, upload-time = "2025-08-07T13:16:08.004Z" },
- { url = "https://files.pythonhosted.org/packages/d1/75/10aeeaa3da9332c2e761e4c50d4c3556c21113ee3f0afa2cf5769946f7a3/greenlet-3.2.4-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:299fd615cd8fc86267b47597123e3f43ad79c9d8a22bebdce535e53550763e2f", size = 686346, upload-time = "2025-08-07T13:42:59.944Z" },
- { url = "https://files.pythonhosted.org/packages/c0/aa/687d6b12ffb505a4447567d1f3abea23bd20e73a5bed63871178e0831b7a/greenlet-3.2.4-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:c17b6b34111ea72fc5a4e4beec9711d2226285f0386ea83477cbb97c30a3f3a5", size = 699218, upload-time = "2025-08-07T13:45:30.969Z" },
- { url = "https://files.pythonhosted.org/packages/dc/8b/29aae55436521f1d6f8ff4e12fb676f3400de7fcf27fccd1d4d17fd8fecd/greenlet-3.2.4-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b4a1870c51720687af7fa3e7cda6d08d801dae660f75a76f3845b642b4da6ee1", size = 694659, upload-time = "2025-08-07T13:53:17.759Z" },
- { url = "https://files.pythonhosted.org/packages/92/2e/ea25914b1ebfde93b6fc4ff46d6864564fba59024e928bdc7de475affc25/greenlet-3.2.4-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:061dc4cf2c34852b052a8620d40f36324554bc192be474b9e9770e8c042fd735", size = 695355, upload-time = "2025-08-07T13:18:34.517Z" },
- { url = "https://files.pythonhosted.org/packages/72/60/fc56c62046ec17f6b0d3060564562c64c862948c9d4bc8aa807cf5bd74f4/greenlet-3.2.4-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:44358b9bf66c8576a9f57a590d5f5d6e72fa4228b763d0e43fee6d3b06d3a337", size = 657512, upload-time = "2025-08-07T13:18:33.969Z" },
- { url = "https://files.pythonhosted.org/packages/23/6e/74407aed965a4ab6ddd93a7ded3180b730d281c77b765788419484cdfeef/greenlet-3.2.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:2917bdf657f5859fbf3386b12d68ede4cf1f04c90c3a6bc1f013dd68a22e2269", size = 1612508, upload-time = "2025-11-04T12:42:23.427Z" },
- { url = "https://files.pythonhosted.org/packages/0d/da/343cd760ab2f92bac1845ca07ee3faea9fe52bee65f7bcb19f16ad7de08b/greenlet-3.2.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:015d48959d4add5d6c9f6c5210ee3803a830dce46356e3bc326d6776bde54681", size = 1680760, upload-time = "2025-11-04T12:42:25.341Z" },
- { url = "https://files.pythonhosted.org/packages/e3/a5/6ddab2b4c112be95601c13428db1d8b6608a8b6039816f2ba09c346c08fc/greenlet-3.2.4-cp314-cp314-win_amd64.whl", hash = "sha256:e37ab26028f12dbb0ff65f29a8d3d44a765c61e729647bf2ddfbbed621726f01", size = 303425, upload-time = "2025-08-07T13:32:27.59Z" },
- { url = "https://files.pythonhosted.org/packages/f7/c0/93885c4106d2626bf51fdec377d6aef740dfa5c4877461889a7cf8e565cc/greenlet-3.2.4-cp39-cp39-macosx_11_0_universal2.whl", hash = "sha256:b6a7c19cf0d2742d0809a4c05975db036fdff50cd294a93632d6a310bf9ac02c", size = 269859, upload-time = "2025-08-07T13:16:16.003Z" },
- { url = "https://files.pythonhosted.org/packages/4d/f5/33f05dc3ba10a02dedb1485870cf81c109227d3d3aa280f0e48486cac248/greenlet-3.2.4-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:27890167f55d2387576d1f41d9487ef171849ea0359ce1510ca6e06c8bece11d", size = 627610, upload-time = "2025-08-07T13:43:01.345Z" },
- { url = "https://files.pythonhosted.org/packages/b2/a7/9476decef51a0844195f99ed5dc611d212e9b3515512ecdf7321543a7225/greenlet-3.2.4-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:18d9260df2b5fbf41ae5139e1be4e796d99655f023a636cd0e11e6406cca7d58", size = 639417, upload-time = "2025-08-07T13:45:32.094Z" },
- { url = "https://files.pythonhosted.org/packages/bd/e0/849b9159cbb176f8c0af5caaff1faffdece7a8417fcc6fe1869770e33e21/greenlet-3.2.4-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:671df96c1f23c4a0d4077a325483c1503c96a1b7d9db26592ae770daa41233d4", size = 634751, upload-time = "2025-08-07T13:53:18.848Z" },
- { url = "https://files.pythonhosted.org/packages/5f/d3/844e714a9bbd39034144dca8b658dcd01839b72bb0ec7d8014e33e3705f0/greenlet-3.2.4-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:16458c245a38991aa19676900d48bd1a6f2ce3e16595051a4db9d012154e8433", size = 634020, upload-time = "2025-08-07T13:18:36.841Z" },
- { url = "https://files.pythonhosted.org/packages/6b/4c/f3de2a8de0e840ecb0253ad0dc7e2bb3747348e798ec7e397d783a3cb380/greenlet-3.2.4-cp39-cp39-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c9913f1a30e4526f432991f89ae263459b1c64d1608c0d22a5c79c287b3c70df", size = 582817, upload-time = "2025-08-07T13:18:35.48Z" },
- { url = "https://files.pythonhosted.org/packages/89/80/7332915adc766035c8980b161c2e5d50b2f941f453af232c164cff5e0aeb/greenlet-3.2.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b90654e092f928f110e0007f572007c9727b5265f7632c2fa7415b4689351594", size = 1111985, upload-time = "2025-08-07T13:42:42.425Z" },
- { url = "https://files.pythonhosted.org/packages/66/71/1928e2c80197353bcb9b50aa19c4d8e26ee6d7a900c564907665cf4b9a41/greenlet-3.2.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:81701fd84f26330f0d5f4944d4e92e61afe6319dcd9775e39396e39d7c3e5f98", size = 1136137, upload-time = "2025-08-07T13:18:26.168Z" },
- { url = "https://files.pythonhosted.org/packages/4b/bf/7bd33643e48ed45dcc0e22572f650767832bd4e1287f97434943cc402148/greenlet-3.2.4-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:28a3c6b7cd72a96f61b0e4b2a36f681025b60ae4779cc73c1535eb5f29560b10", size = 1542941, upload-time = "2025-11-04T12:42:27.427Z" },
- { url = "https://files.pythonhosted.org/packages/9b/74/4bc433f91d0d09a1c22954a371f9df928cb85e72640870158853a83415e5/greenlet-3.2.4-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:52206cd642670b0b320a1fd1cbfd95bca0e043179c1d8a045f2c6109dfe973be", size = 1609685, upload-time = "2025-11-04T12:42:29.242Z" },
- { url = "https://files.pythonhosted.org/packages/89/48/a5dc74dde38aeb2b15d418cec76ed50e1dd3d620ccda84d8199703248968/greenlet-3.2.4-cp39-cp39-win32.whl", hash = "sha256:65458b409c1ed459ea899e939f0e1cdb14f58dbc803f2f93c5eab5694d32671b", size = 281400, upload-time = "2025-08-07T14:02:20.263Z" },
- { url = "https://files.pythonhosted.org/packages/e5/44/342c4591db50db1076b8bda86ed0ad59240e3e1da17806a4cf10a6d0e447/greenlet-3.2.4-cp39-cp39-win_amd64.whl", hash = "sha256:d2e685ade4dafd447ede19c31277a224a239a0a1a4eca4e6390efedf20260cfb", size = 298533, upload-time = "2025-08-07T13:56:34.168Z" },
-]
-
[[package]]
name = "greenlet"
version = "3.3.1"
source = { registry = "https://pypi.org/simple" }
-resolution-markers = [
- "python_full_version >= '3.14'",
- "python_full_version >= '3.10' and python_full_version < '3.14'",
-]
sdist = { url = "https://files.pythonhosted.org/packages/8a/99/1cd3411c56a410994669062bd73dd58270c00cc074cac15f385a1fd91f8a/greenlet-3.3.1.tar.gz", hash = "sha256:41848f3230b58c08bb43dee542e74a2a2e34d3c59dc3076cec9151aeeedcae98", size = 184690, upload-time = "2026-01-23T15:31:02.076Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/fe/65/5b235b40581ad75ab97dcd8b4218022ae8e3ab77c13c919f1a1dfe9171fd/greenlet-3.3.1-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:04bee4775f40ecefcdaa9d115ab44736cd4b9c5fba733575bfe9379419582e13", size = 273723, upload-time = "2026-01-23T15:30:37.521Z" },
@@ -2414,31 +1910,12 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/e1/2b/98c7f93e6db9977aaee07eb1e51ca63bd5f779b900d362791d3252e60558/greenlet-3.3.1-cp314-cp314t-win_amd64.whl", hash = "sha256:301860987846c24cb8964bdec0e31a96ad4a2a801b41b4ef40963c1b44f33451", size = 233181, upload-time = "2026-01-23T15:33:00.29Z" },
]
-[[package]]
-name = "griffe"
-version = "1.14.0"
-source = { registry = "https://pypi.org/simple" }
-resolution-markers = [
- "python_full_version < '3.10'",
-]
-dependencies = [
- { name = "colorama", marker = "python_full_version < '3.10'" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/ec/d7/6c09dd7ce4c7837e4cdb11dce980cb45ae3cd87677298dc3b781b6bce7d3/griffe-1.14.0.tar.gz", hash = "sha256:9d2a15c1eca966d68e00517de5d69dd1bc5c9f2335ef6c1775362ba5b8651a13", size = 424684, upload-time = "2025-09-05T15:02:29.167Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/2a/b1/9ff6578d789a89812ff21e4e0f80ffae20a65d5dd84e7a17873fe3b365be/griffe-1.14.0-py3-none-any.whl", hash = "sha256:0e9d52832cccf0f7188cfe585ba962d2674b241c01916d780925df34873bceb0", size = 144439, upload-time = "2025-09-05T15:02:27.511Z" },
-]
-
[[package]]
name = "griffe"
version = "1.15.0"
source = { registry = "https://pypi.org/simple" }
-resolution-markers = [
- "python_full_version >= '3.14'",
- "python_full_version >= '3.10' and python_full_version < '3.14'",
-]
dependencies = [
- { name = "colorama", marker = "python_full_version >= '3.10'" },
+ { name = "colorama" },
]
sdist = { url = "https://files.pythonhosted.org/packages/0d/0c/3a471b6e31951dce2360477420d0a8d1e00dea6cf33b70f3e8c3ab6e28e1/griffe-1.15.0.tar.gz", hash = "sha256:7726e3afd6f298fbc3696e67958803e7ac843c1cfe59734b6251a40cdbfb5eea", size = 424112, upload-time = "2025-11-10T15:03:15.52Z" }
wheels = [
@@ -2450,8 +1927,7 @@ name = "griffe-typingdoc"
version = "0.3.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "griffe", version = "1.14.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
- { name = "griffe", version = "1.15.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
+ { name = "griffe" },
{ name = "typing-extensions" },
]
sdist = { url = "https://files.pythonhosted.org/packages/be/77/d5e5fa0a8391bc2890ae45255847197299739833108dd76ee3c9b2ff0bba/griffe_typingdoc-0.3.0.tar.gz", hash = "sha256:59d9ef98d02caa7aed88d8df1119c9e48c02ed049ea50ce4018ace9331d20f8b", size = 33169, upload-time = "2025-10-23T12:01:39.037Z" }
@@ -2464,8 +1940,7 @@ name = "griffe-warnings-deprecated"
version = "1.1.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "griffe", version = "1.14.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
- { name = "griffe", version = "1.15.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
+ { name = "griffe" },
]
sdist = { url = "https://files.pythonhosted.org/packages/7e/0e/f034e1714eb2c694d6196c75f77a02f9c69d19f9961c4804a016397bf3e5/griffe_warnings_deprecated-1.1.0.tar.gz", hash = "sha256:7bf21de327d59c66c7ce08d0166aa4292ce0577ff113de5878f428d102b6f7c5", size = 33260, upload-time = "2024-12-10T21:02:18.395Z" }
wheels = [
@@ -2494,7 +1969,7 @@ name = "grpcio"
version = "1.78.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "typing-extensions", marker = "python_full_version >= '3.10'" },
+ { name = "typing-extensions" },
]
sdist = { url = "https://files.pythonhosted.org/packages/06/8a/3d098f35c143a89520e568e6539cc098fcd294495910e359889ce8741c84/grpcio-1.78.0.tar.gz", hash = "sha256:7382b95189546f375c174f53a5fa873cef91c4b8005faa05cc5b3beea9c4f1c5", size = 12852416, upload-time = "2026-02-06T09:57:18.093Z" }
wheels = [
@@ -2548,16 +2023,6 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/3c/05/33a7a4985586f27e1de4803887c417ec7ced145ebd069bc38a9607059e2b/grpcio-1.78.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:207db540302c884b8848036b80db352a832b99dfdf41db1eb554c2c2c7800f65", size = 7696837, upload-time = "2026-02-06T09:56:40.173Z" },
{ url = "https://files.pythonhosted.org/packages/73/77/7382241caf88729b106e49e7d18e3116216c778e6a7e833826eb96de22f7/grpcio-1.78.0-cp314-cp314-win32.whl", hash = "sha256:57bab6deef2f4f1ca76cc04565df38dc5713ae6c17de690721bdf30cb1e0545c", size = 4142439, upload-time = "2026-02-06T09:56:43.258Z" },
{ url = "https://files.pythonhosted.org/packages/48/b2/b096ccce418882fbfda4f7496f9357aaa9a5af1896a9a7f60d9f2b275a06/grpcio-1.78.0-cp314-cp314-win_amd64.whl", hash = "sha256:dce09d6116df20a96acfdbf85e4866258c3758180e8c49845d6ba8248b6d0bbb", size = 4929852, upload-time = "2026-02-06T09:56:45.885Z" },
- { url = "https://files.pythonhosted.org/packages/58/6c/40a4bba2c753ea8eeb8d776a31e9c54f4e506edf36db93a3db5456725294/grpcio-1.78.0-cp39-cp39-linux_armv7l.whl", hash = "sha256:86f85dd7c947baa707078a236288a289044836d4b640962018ceb9cd1f899af5", size = 5947902, upload-time = "2026-02-06T09:56:48.469Z" },
- { url = "https://files.pythonhosted.org/packages/c0/4c/ed7664a37a7008be41204c77e0d88bbc4ac531bcf0c27668cd066f9ff6e2/grpcio-1.78.0-cp39-cp39-macosx_11_0_universal2.whl", hash = "sha256:de8cb00d1483a412a06394b8303feec5dcb3b55f81d83aa216dbb6a0b86a94f5", size = 11824772, upload-time = "2026-02-06T09:56:51.264Z" },
- { url = "https://files.pythonhosted.org/packages/9a/5b/45a5c23ba3c4a0f51352366d9b25369a2a51163ab1c93482cb8408726617/grpcio-1.78.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:e888474dee2f59ff68130f8a397792d8cb8e17e6b3434339657ba4ee90845a8c", size = 6521579, upload-time = "2026-02-06T09:56:54.967Z" },
- { url = "https://files.pythonhosted.org/packages/9a/e3/392e647d918004231e3d1c780ed125c48939bfc8f845adb8b5820410da3e/grpcio-1.78.0-cp39-cp39-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:86ce2371bfd7f212cf60d8517e5e854475c2c43ce14aa910e136ace72c6db6c1", size = 7199330, upload-time = "2026-02-06T09:56:57.611Z" },
- { url = "https://files.pythonhosted.org/packages/68/2f/42a52d78bdbdb3f1310ed690a3511cd004740281ca75d300b7bd6d9d3de3/grpcio-1.78.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:b0c689c02947d636bc7fab3e30cc3a3445cca99c834dfb77cd4a6cabfc1c5597", size = 6726696, upload-time = "2026-02-06T09:57:00.357Z" },
- { url = "https://files.pythonhosted.org/packages/0f/83/b3d932a4fbb2dce3056f6df2926fc2d3ddc5d5acbafbec32c84033cf3f23/grpcio-1.78.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:ce7599575eeb25c0f4dc1be59cada6219f3b56176f799627f44088b21381a28a", size = 7299076, upload-time = "2026-02-06T09:57:04.124Z" },
- { url = "https://files.pythonhosted.org/packages/ba/d9/70ea1be55efaf91fd19f7258b1292772a8226cf1b0e237717fba671073cb/grpcio-1.78.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:684083fd383e9dc04c794adb838d4faea08b291ce81f64ecd08e4577c7398adf", size = 8284493, upload-time = "2026-02-06T09:57:06.746Z" },
- { url = "https://files.pythonhosted.org/packages/d0/2f/3dddccf49e3e75564655b84175fca092d3efd81d2979fc89c4b1c1d879dc/grpcio-1.78.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:ab399ef5e3cd2a721b1038a0f3021001f19c5ab279f145e1146bb0b9f1b2b12c", size = 7724340, upload-time = "2026-02-06T09:57:09.453Z" },
- { url = "https://files.pythonhosted.org/packages/79/ae/dfdb3183141db787a9363078a98764675996a7c2448883153091fd7c8527/grpcio-1.78.0-cp39-cp39-win32.whl", hash = "sha256:f3d6379493e18ad4d39537a82371c5281e153e963cecb13f953ebac155756525", size = 4077641, upload-time = "2026-02-06T09:57:11.881Z" },
- { url = "https://files.pythonhosted.org/packages/aa/aa/694b2f505345cfdd234cffb2525aa379a81695e6c02fd40d7e9193e871c6/grpcio-1.78.0-cp39-cp39-win_amd64.whl", hash = "sha256:5361a0630a7fdb58a6a97638ab70e1dae2893c4d08d7aba64ded28bb9e7a29df", size = 4799428, upload-time = "2026-02-06T09:57:14.493Z" },
]
[[package]]
@@ -2661,13 +2126,6 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/4d/31/14df99e1c43bd132eec921c2e7e11cda7852f65619bc0fc5bdc2d0cb126c/httptools-0.7.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:f084813239e1eb403ddacd06a30de3d3e09a9b76e7894dcda2b22f8a726e9c60", size = 452631, upload-time = "2025-10-10T03:54:58.219Z" },
{ url = "https://files.pythonhosted.org/packages/22/d2/b7e131f7be8d854d48cb6d048113c30f9a46dca0c9a8b08fcb3fcd588cdc/httptools-0.7.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:7347714368fb2b335e9063bc2b96f2f87a9ceffcd9758ac295f8bbcd3ffbc0ca", size = 452910, upload-time = "2025-10-10T03:54:59.366Z" },
{ url = "https://files.pythonhosted.org/packages/53/cf/878f3b91e4e6e011eff6d1fa9ca39f7eb17d19c9d7971b04873734112f30/httptools-0.7.1-cp314-cp314-win_amd64.whl", hash = "sha256:cfabda2a5bb85aa2a904ce06d974a3f30fb36cc63d7feaddec05d2050acede96", size = 88205, upload-time = "2025-10-10T03:55:00.389Z" },
- { url = "https://files.pythonhosted.org/packages/90/de/b1fe0e8890f0292c266117d4cd268186758a9c34e576fbd573fdf3beacff/httptools-0.7.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:ac50afa68945df63ec7a2707c506bd02239272288add34539a2ef527254626a4", size = 206454, upload-time = "2025-10-10T03:55:01.528Z" },
- { url = "https://files.pythonhosted.org/packages/57/a7/a675c90b49e550c7635ce209c01bc61daa5b08aef17da27ef4e0e78fcf3f/httptools-0.7.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:de987bb4e7ac95b99b805b99e0aae0ad51ae61df4263459d36e07cf4052d8b3a", size = 110260, upload-time = "2025-10-10T03:55:02.418Z" },
- { url = "https://files.pythonhosted.org/packages/03/44/fb5ef8136e6e97f7b020e97e40c03a999f97e68574d4998fa52b0a62b01b/httptools-0.7.1-cp39-cp39-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:d169162803a24425eb5e4d51d79cbf429fd7a491b9e570a55f495ea55b26f0bf", size = 441524, upload-time = "2025-10-10T03:55:03.292Z" },
- { url = "https://files.pythonhosted.org/packages/b4/62/8496a5425341867796d7e2419695f74a74607054e227bbaeabec8323e87f/httptools-0.7.1-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:49794f9250188a57fa73c706b46cb21a313edb00d337ca4ce1a011fe3c760b28", size = 440877, upload-time = "2025-10-10T03:55:04.282Z" },
- { url = "https://files.pythonhosted.org/packages/e8/f1/26c2e5214106bf6ed04d03e518ff28ca0c6b5390c5da7b12bbf94b40ae43/httptools-0.7.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:aeefa0648362bb97a7d6b5ff770bfb774930a327d7f65f8208394856862de517", size = 425775, upload-time = "2025-10-10T03:55:05.341Z" },
- { url = "https://files.pythonhosted.org/packages/3a/34/7500a19257139725281f7939a7d1aa3701cf1ac4601a1690f9ab6f510e15/httptools-0.7.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:0d92b10dbf0b3da4823cde6a96d18e6ae358a9daa741c71448975f6a2c339cad", size = 425001, upload-time = "2025-10-10T03:55:06.389Z" },
- { url = "https://files.pythonhosted.org/packages/71/04/31a7949d645ebf33a67f56a0024109444a52a271735e0647a210264f3e61/httptools-0.7.1-cp39-cp39-win_amd64.whl", hash = "sha256:5ddbd045cfcb073db2449563dd479057f2c2b681ebc232380e63ef15edc9c023", size = 86818, upload-time = "2025-10-10T03:55:07.316Z" },
]
[[package]]
@@ -2699,10 +2157,8 @@ name = "huggingface-hub"
version = "0.36.2"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "filelock", version = "3.19.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
- { name = "filelock", version = "3.20.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
- { name = "fsspec", version = "2025.10.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
- { name = "fsspec", version = "2026.2.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
+ { name = "filelock" },
+ { name = "fsspec" },
{ name = "hf-xet", marker = "platform_machine == 'aarch64' or platform_machine == 'amd64' or platform_machine == 'arm64' or platform_machine == 'x86_64'" },
{ name = "packaging" },
{ name = "pyyaml" },
@@ -2741,26 +2197,10 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/fa/5e/f8e9a1d23b9c20a551a8a02ea3637b4642e22c2626e3a13a9a29cdea99eb/importlib_metadata-8.7.1-py3-none-any.whl", hash = "sha256:5a1f80bf1daa489495071efbb095d75a634cf28a8bc299581244063b53176151", size = 27865, upload-time = "2025-12-21T10:00:18.329Z" },
]
-[[package]]
-name = "iniconfig"
-version = "2.1.0"
-source = { registry = "https://pypi.org/simple" }
-resolution-markers = [
- "python_full_version < '3.10'",
-]
-sdist = { url = "https://files.pythonhosted.org/packages/f2/97/ebf4da567aa6827c909642694d71c9fcf53e5b504f2d96afea02718862f3/iniconfig-2.1.0.tar.gz", hash = "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7", size = 4793, upload-time = "2025-03-19T20:09:59.721Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl", hash = "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760", size = 6050, upload-time = "2025-03-19T20:10:01.071Z" },
-]
-
[[package]]
name = "iniconfig"
version = "2.3.0"
source = { registry = "https://pypi.org/simple" }
-resolution-markers = [
- "python_full_version >= '3.14'",
- "python_full_version >= '3.10' and python_full_version < '3.14'",
-]
sdist = { url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", size = 20503, upload-time = "2025-10-18T21:55:43.219Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" },
@@ -2805,7 +2245,7 @@ name = "jaraco-classes"
version = "3.4.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "more-itertools", marker = "python_full_version >= '3.10'" },
+ { name = "more-itertools" },
]
sdist = { url = "https://files.pythonhosted.org/packages/06/c0/ed4a27bc5571b99e3cff68f8a9fa5b56ff7df1c2251cc715a652ddd26402/jaraco.classes-3.4.0.tar.gz", hash = "sha256:47a024b51d0239c0dd8c8540c6c7f484be3b8fcf0b2d85c13825780d3b3f3acd", size = 11780, upload-time = "2024-03-31T07:27:36.643Z" }
wheels = [
@@ -2817,7 +2257,7 @@ name = "jaraco-context"
version = "6.1.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "backports-tarfile", marker = "python_full_version >= '3.10' and python_full_version < '3.12'" },
+ { name = "backports-tarfile", marker = "python_full_version < '3.12'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/cb/9c/a788f5bb29c61e456b8ee52ce76dbdd32fd72cd73dd67bc95f42c7a8d13c/jaraco_context-6.1.0.tar.gz", hash = "sha256:129a341b0a85a7db7879e22acd66902fda67882db771754574338898b2d5d86f", size = 15850, upload-time = "2026-01-13T02:53:53.847Z" }
wheels = [
@@ -2829,7 +2269,7 @@ name = "jaraco-functools"
version = "4.4.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "more-itertools", marker = "python_full_version >= '3.10'" },
+ { name = "more-itertools" },
]
sdist = { url = "https://files.pythonhosted.org/packages/0f/27/056e0638a86749374d6f57d0b0db39f29509cce9313cf91bdc0ac4d91084/jaraco_functools-4.4.0.tar.gz", hash = "sha256:da21933b0417b89515562656547a77b4931f98176eb173644c0d35032a33d6bb", size = 19943, upload-time = "2025-12-21T09:29:43.6Z" }
wheels = [
@@ -2950,18 +2390,6 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/47/66/eea81dfff765ed66c68fd2ed8c96245109e13c896c2a5015c7839c92367e/jiter-0.13.0-cp314-cp314t-win32.whl", hash = "sha256:24dc96eca9f84da4131cdf87a95e6ce36765c3b156fc9ae33280873b1c32d5f6", size = 201196, upload-time = "2026-02-02T12:37:19.101Z" },
{ url = "https://files.pythonhosted.org/packages/ff/32/4ac9c7a76402f8f00d00842a7f6b83b284d0cf7c1e9d4227bc95aa6d17fa/jiter-0.13.0-cp314-cp314t-win_amd64.whl", hash = "sha256:0a8d76c7524087272c8ae913f5d9d608bd839154b62c4322ef65723d2e5bb0b8", size = 204215, upload-time = "2026-02-02T12:37:20.495Z" },
{ url = "https://files.pythonhosted.org/packages/f9/8e/7def204fea9f9be8b3c21a6f2dd6c020cf56c7d5ff753e0e23ed7f9ea57e/jiter-0.13.0-cp314-cp314t-win_arm64.whl", hash = "sha256:2c26cf47e2cad140fa23b6d58d435a7c0161f5c514284802f25e87fddfe11024", size = 187152, upload-time = "2026-02-02T12:37:22.124Z" },
- { url = "https://files.pythonhosted.org/packages/41/95/8e6611379c9ce8534ff94dd800c50d6d0061b2c9ae6386fbcd86c7386f0a/jiter-0.13.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:4397ee562b9f69d283e5674445551b47a5e8076fdde75e71bfac5891113dc543", size = 313635, upload-time = "2026-02-02T12:37:23.545Z" },
- { url = "https://files.pythonhosted.org/packages/70/ea/17db64dcaf84bbb187874232222030ea4d689e6008f93bda6e7c691bc4c7/jiter-0.13.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:7f90023f8f672e13ea1819507d2d21b9d2d1c18920a3b3a5f1541955a85b5504", size = 309761, upload-time = "2026-02-02T12:37:25.075Z" },
- { url = "https://files.pythonhosted.org/packages/a3/36/b2e2a7b12b94ecc7248acf2a8fe6288be893d1ebb9728655ceada22f00ad/jiter-0.13.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ed0240dd1536a98c3ab55e929c60dfff7c899fecafcb7d01161b21a99fc8c363", size = 355245, upload-time = "2026-02-02T12:37:26.646Z" },
- { url = "https://files.pythonhosted.org/packages/77/3f/5b159663c5be622daec20074c997bb66bc1fac63c167c02aef3df476fb32/jiter-0.13.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6207fc61c395b26fffdcf637a0b06b4326f35bfa93c6e92fe1a166a21aeb6731", size = 365842, upload-time = "2026-02-02T12:37:28.207Z" },
- { url = "https://files.pythonhosted.org/packages/98/30/76a68fa2c9c815c6b7802a92fc354080d66ffba9acc4690fd85622f77ad4/jiter-0.13.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:00203f47c214156df427b5989de74cb340c65c8180d09be1bf9de81d0abad599", size = 489223, upload-time = "2026-02-02T12:37:29.571Z" },
- { url = "https://files.pythonhosted.org/packages/a3/39/7c5cb85ccd71241513c878054c26a55828ccded6567d931a23ea4be73787/jiter-0.13.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c26ad6967c9dcedf10c995a21539c3aa57d4abad7001b7a84f621a263a6b605", size = 375762, upload-time = "2026-02-02T12:37:31.186Z" },
- { url = "https://files.pythonhosted.org/packages/a8/6a/381cd18d050b0102e60324e8d3f51f37ef02c56e9f4e5f0b7d26ba18958d/jiter-0.13.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a576f5dce9ac7de5d350b8e2f552cf364f32975ed84717c35379a51c7cb198bd", size = 364996, upload-time = "2026-02-02T12:37:32.931Z" },
- { url = "https://files.pythonhosted.org/packages/37/1e/d66310f1f7085c13ea6f1119c9566ec5d2cfd1dc90df963118a6869247bb/jiter-0.13.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b22945be8425d161f2e536cdae66da300b6b000f1c0ba3ddf237d1bfd45d21b8", size = 395463, upload-time = "2026-02-02T12:37:34.446Z" },
- { url = "https://files.pythonhosted.org/packages/c0/ab/06ae77cb293f860b152c356c635c15aaa800ce48772865a41704d9fac80d/jiter-0.13.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:6eeb7db8bc77dc20476bc2f7407a23dbe3d46d9cc664b166e3d474e1c1de4baa", size = 520944, upload-time = "2026-02-02T12:37:35.987Z" },
- { url = "https://files.pythonhosted.org/packages/f1/8e/57b49b20361c42a80d455a6d83cb38626204508cab4298d6a22880205319/jiter-0.13.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:19cd6f85e1dc090277c3ce90a5b7d96f32127681d825e71c9dce28788e39fc0c", size = 554955, upload-time = "2026-02-02T12:37:37.656Z" },
- { url = "https://files.pythonhosted.org/packages/79/dd/113489973c3b4256e383321aea11bd57389e401912fa48eb145a99b38767/jiter-0.13.0-cp39-cp39-win32.whl", hash = "sha256:dc3ce84cfd4fa9628fe62c4f85d0d597a4627d4242cfafac32a12cc1455d00f7", size = 206876, upload-time = "2026-02-02T12:37:39.225Z" },
- { url = "https://files.pythonhosted.org/packages/6e/73/2bdfc7133c5ee0c8f18cfe4a7582f3cfbbf3ff672cec1b5f4ca67ff9d041/jiter-0.13.0-cp39-cp39-win_amd64.whl", hash = "sha256:9ffda299e417dc83362963966c50cb76d42da673ee140de8a8ac762d4bb2378b", size = 206404, upload-time = "2026-02-02T12:37:40.632Z" },
{ url = "https://files.pythonhosted.org/packages/79/b3/3c29819a27178d0e461a8571fb63c6ae38be6dc36b78b3ec2876bbd6a910/jiter-0.13.0-graalpy311-graalpy242_311_native-macosx_10_12_x86_64.whl", hash = "sha256:b1cbfa133241d0e6bdab48dcdc2604e8ba81512f6bbd68ec3e8e1357dd3c316c", size = 307016, upload-time = "2026-02-02T12:37:42.755Z" },
{ url = "https://files.pythonhosted.org/packages/eb/ae/60993e4b07b1ac5ebe46da7aa99fdbb802eb986c38d26e3883ac0125c4e0/jiter-0.13.0-graalpy311-graalpy242_311_native-macosx_11_0_arm64.whl", hash = "sha256:db367d8be9fad6e8ebbac4a7578b7af562e506211036cba2c06c3b998603c3d2", size = 305024, upload-time = "2026-02-02T12:37:44.774Z" },
{ url = "https://files.pythonhosted.org/packages/77/fa/2227e590e9cf98803db2811f172b2d6460a21539ab73006f251c66f44b14/jiter-0.13.0-graalpy311-graalpy242_311_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45f6f8efb2f3b0603092401dc2df79fa89ccbc027aaba4174d2d4133ed661434", size = 339337, upload-time = "2026-02-02T12:37:46.668Z" },
@@ -2995,10 +2423,10 @@ name = "jsonschema"
version = "4.26.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "attrs", marker = "python_full_version >= '3.10'" },
- { name = "jsonschema-specifications", marker = "python_full_version >= '3.10'" },
- { name = "referencing", marker = "python_full_version >= '3.10'" },
- { name = "rpds-py", marker = "python_full_version >= '3.10'" },
+ { name = "attrs" },
+ { name = "jsonschema-specifications" },
+ { name = "referencing" },
+ { name = "rpds-py" },
]
sdist = { url = "https://files.pythonhosted.org/packages/b3/fc/e067678238fa451312d4c62bf6e6cf5ec56375422aee02f9cb5f909b3047/jsonschema-4.26.0.tar.gz", hash = "sha256:0c26707e2efad8aa1bfc5b7ce170f3fccc2e4918ff85989ba9ffa9facb2be326", size = 366583, upload-time = "2026-01-07T13:41:07.246Z" }
wheels = [
@@ -3010,10 +2438,10 @@ name = "jsonschema-path"
version = "0.3.4"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pathable", marker = "python_full_version >= '3.10'" },
- { name = "pyyaml", marker = "python_full_version >= '3.10'" },
- { name = "referencing", marker = "python_full_version >= '3.10'" },
- { name = "requests", marker = "python_full_version >= '3.10'" },
+ { name = "pathable" },
+ { name = "pyyaml" },
+ { name = "referencing" },
+ { name = "requests" },
]
sdist = { url = "https://files.pythonhosted.org/packages/6e/45/41ebc679c2a4fced6a722f624c18d658dee42612b83ea24c1caf7c0eb3a8/jsonschema_path-0.3.4.tar.gz", hash = "sha256:8365356039f16cc65fddffafda5f58766e34bebab7d6d105616ab52bc4297001", size = 11159, upload-time = "2025-01-24T14:33:16.547Z" }
wheels = [
@@ -3025,7 +2453,7 @@ name = "jsonschema-specifications"
version = "2025.9.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "referencing", marker = "python_full_version >= '3.10'" },
+ { name = "referencing" },
]
sdist = { url = "https://files.pythonhosted.org/packages/19/74/a633ee74eb36c44aa6d1095e7cc5569bebf04342ee146178e2d36600708b/jsonschema_specifications-2025.9.1.tar.gz", hash = "sha256:b540987f239e745613c7a9176f3edb72b832a4ac465cf02712288397832b5e8d", size = 32855, upload-time = "2025-09-08T01:34:59.186Z" }
wheels = [
@@ -3037,31 +2465,19 @@ name = "keyring"
version = "25.7.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "importlib-metadata", marker = "python_full_version >= '3.10' and python_full_version < '3.12'" },
- { name = "jaraco-classes", marker = "python_full_version >= '3.10'" },
- { name = "jaraco-context", marker = "python_full_version >= '3.10'" },
- { name = "jaraco-functools", marker = "python_full_version >= '3.10'" },
- { name = "jeepney", marker = "python_full_version >= '3.10' and sys_platform == 'linux'" },
- { name = "pywin32-ctypes", marker = "python_full_version >= '3.10' and sys_platform == 'win32'" },
- { name = "secretstorage", marker = "python_full_version >= '3.10' and sys_platform == 'linux'" },
+ { name = "importlib-metadata", marker = "python_full_version < '3.12'" },
+ { name = "jaraco-classes" },
+ { name = "jaraco-context" },
+ { name = "jaraco-functools" },
+ { name = "jeepney", marker = "sys_platform == 'linux'" },
+ { name = "pywin32-ctypes", marker = "sys_platform == 'win32'" },
+ { name = "secretstorage", marker = "sys_platform == 'linux'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/43/4b/674af6ef2f97d56f0ab5153bf0bfa28ccb6c3ed4d1babf4305449668807b/keyring-25.7.0.tar.gz", hash = "sha256:fe01bd85eb3f8fb3dd0405defdeac9a5b4f6f0439edbb3149577f244a2e8245b", size = 63516, upload-time = "2025-11-16T16:26:09.482Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/81/db/e655086b7f3a705df045bf0933bdd9c2f79bb3c97bfef1384598bb79a217/keyring-25.7.0-py3-none-any.whl", hash = "sha256:be4a0b195f149690c166e850609a477c532ddbfbaed96a404d4e43f8d5e2689f", size = 39160, upload-time = "2025-11-16T16:26:08.402Z" },
]
-[[package]]
-name = "lia-web"
-version = "0.3.1"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
- { name = "cross-web", marker = "python_full_version < '3.10'" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/05/3d/7d574a7a5cf5fbc5fc09c07ea3696dd400353b7702bc009cf596b8c12035/lia_web-0.3.1.tar.gz", hash = "sha256:7f551269eddd729f1437e9341ad21622a849eb0c0975d9232ccbbaadbdc74c06", size = 2021, upload-time = "2025-12-25T20:41:51.195Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/a1/8b/b628fc18658f94b3d094708a18b71083cf47628e85cbc6b9edba54d5b2d7/lia_web-0.3.1-py3-none-any.whl", hash = "sha256:e4e6e7a9381e228aca60a6f3d67dbae9a5f4638eced242d931f95797ddba3f8b", size = 5933, upload-time = "2025-12-25T20:41:52.289Z" },
-]
-
[[package]]
name = "librt"
version = "0.7.8"
@@ -3133,16 +2549,6 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/22/f0/07fb6ab5c39a4ca9af3e37554f9d42f25c464829254d72e4ebbd81da351c/librt-0.7.8-cp314-cp314t-win32.whl", hash = "sha256:171ca3a0a06c643bd0a2f62a8944e1902c94aa8e5da4db1ea9a8daf872685365", size = 41173, upload-time = "2026-01-14T12:55:59.315Z" },
{ url = "https://files.pythonhosted.org/packages/24/d4/7e4be20993dc6a782639625bd2f97f3c66125c7aa80c82426956811cfccf/librt-0.7.8-cp314-cp314t-win_amd64.whl", hash = "sha256:445b7304145e24c60288a2f172b5ce2ca35c0f81605f5299f3fa567e189d2e32", size = 47668, upload-time = "2026-01-14T12:56:00.261Z" },
{ url = "https://files.pythonhosted.org/packages/fc/85/69f92b2a7b3c0f88ffe107c86b952b397004b5b8ea5a81da3d9c04c04422/librt-0.7.8-cp314-cp314t-win_arm64.whl", hash = "sha256:8766ece9de08527deabcd7cb1b4f1a967a385d26e33e536d6d8913db6ef74f06", size = 40550, upload-time = "2026-01-14T12:56:01.542Z" },
- { url = "https://files.pythonhosted.org/packages/3b/9b/2668bb01f568bc89ace53736df950845f8adfcacdf6da087d5cef12110cb/librt-0.7.8-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c7e8f88f79308d86d8f39c491773cbb533d6cb7fa6476f35d711076ee04fceb6", size = 56680, upload-time = "2026-01-14T12:56:02.602Z" },
- { url = "https://files.pythonhosted.org/packages/b3/d4/dbb3edf2d0ec4ba08dcaf1865833d32737ad208962d4463c022cea6e9d3c/librt-0.7.8-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:389bd25a0db916e1d6bcb014f11aa9676cedaa485e9ec3752dfe19f196fd377b", size = 58612, upload-time = "2026-01-14T12:56:03.616Z" },
- { url = "https://files.pythonhosted.org/packages/0f/c9/64b029de4ac9901fcd47832c650a0fd050555a452bd455ce8deddddfbb9f/librt-0.7.8-cp39-cp39-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:73fd300f501a052f2ba52ede721232212f3b06503fa12665408ecfc9d8fd149c", size = 163654, upload-time = "2026-01-14T12:56:04.975Z" },
- { url = "https://files.pythonhosted.org/packages/81/5c/95e2abb1b48eb8f8c7fc2ae945321a6b82777947eb544cc785c3f37165b2/librt-0.7.8-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6d772edc6a5f7835635c7562f6688e031f0b97e31d538412a852c49c9a6c92d5", size = 172477, upload-time = "2026-01-14T12:56:06.103Z" },
- { url = "https://files.pythonhosted.org/packages/7e/27/9bdf12e05b0eb089dd008d9c8aabc05748aad9d40458ade5e627c9538158/librt-0.7.8-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bfde8a130bd0f239e45503ab39fab239ace094d63ee1d6b67c25a63d741c0f71", size = 186220, upload-time = "2026-01-14T12:56:09.958Z" },
- { url = "https://files.pythonhosted.org/packages/53/6a/c3774f4cc95e68ed444a39f2c8bd383fd18673db7d6b98cfa709f6634b93/librt-0.7.8-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:fdec6e2368ae4f796fc72fad7fd4bd1753715187e6d870932b0904609e7c878e", size = 183841, upload-time = "2026-01-14T12:56:11.109Z" },
- { url = "https://files.pythonhosted.org/packages/58/6b/48702c61cf83e9c04ad5cec8cad7e5e22a2cde23a13db8ef341598897ddd/librt-0.7.8-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:00105e7d541a8f2ee5be52caacea98a005e0478cfe78c8080fbb7b5d2b340c63", size = 179751, upload-time = "2026-01-14T12:56:12.278Z" },
- { url = "https://files.pythonhosted.org/packages/35/87/5f607fc73a131d4753f4db948833063c6aad18e18a4e6fbf64316c37ae65/librt-0.7.8-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:c6f8947d3dfd7f91066c5b4385812c18be26c9d5a99ca56667547f2c39149d94", size = 199319, upload-time = "2026-01-14T12:56:13.425Z" },
- { url = "https://files.pythonhosted.org/packages/6e/cc/b7c5ac28ae0f0645a9681248bae4ede665bba15d6f761c291853c5c5b78e/librt-0.7.8-cp39-cp39-win32.whl", hash = "sha256:41d7bb1e07916aeb12ae4a44e3025db3691c4149ab788d0315781b4d29b86afb", size = 43434, upload-time = "2026-01-14T12:56:14.781Z" },
- { url = "https://files.pythonhosted.org/packages/e4/5d/dce0c92f786495adf2c1e6784d9c50a52fb7feb1cfb17af97a08281a6e82/librt-0.7.8-cp39-cp39-win_amd64.whl", hash = "sha256:e90a8e237753c83b8e484d478d9a996dc5e39fd5bd4c6ce32563bc8123f132be", size = 49801, upload-time = "2026-01-14T12:56:15.827Z" },
]
[[package]]
@@ -3150,14 +2556,14 @@ name = "logfire"
version = "4.22.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "executing", marker = "python_full_version >= '3.10'" },
- { name = "opentelemetry-exporter-otlp-proto-http", marker = "python_full_version >= '3.10'" },
- { name = "opentelemetry-instrumentation", marker = "python_full_version >= '3.10'" },
- { name = "opentelemetry-sdk", marker = "python_full_version >= '3.10'" },
- { name = "protobuf", version = "6.33.5", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
- { name = "rich", marker = "python_full_version >= '3.10'" },
- { name = "tomli", marker = "python_full_version == '3.10.*'" },
- { name = "typing-extensions", marker = "python_full_version >= '3.10'" },
+ { name = "executing" },
+ { name = "opentelemetry-exporter-otlp-proto-http" },
+ { name = "opentelemetry-instrumentation" },
+ { name = "opentelemetry-sdk" },
+ { name = "protobuf" },
+ { name = "rich" },
+ { name = "tomli", marker = "python_full_version < '3.11'" },
+ { name = "typing-extensions" },
]
sdist = { url = "https://files.pythonhosted.org/packages/b1/29/4386b331b8aecad429c043bbd1b7684cdb56ff9e11a5bd96845483dc0968/logfire-4.22.0.tar.gz", hash = "sha256:284b3b955c7515d4428dbc1e04784c3e652e62acf7597bd64a0aa9ecb6a7dedd", size = 654771, upload-time = "2026-02-04T12:17:57.635Z" }
wheels = [
@@ -3166,7 +2572,7 @@ wheels = [
[package.optional-dependencies]
httpx = [
- { name = "opentelemetry-instrumentation-httpx", marker = "python_full_version >= '3.10'" },
+ { name = "opentelemetry-instrumentation-httpx" },
]
[[package]]
@@ -3250,42 +2656,12 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/b4/a0/89e6a024c3b4485b89ef86881c9d55e097e7cb0bdb74efb746f2fa6a9a76/lupa-2.6-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:9abb98d5a8fd27c8285302e82199f0e56e463066f88f619d6594a450bf269d80", size = 2153693, upload-time = "2025-10-24T07:19:31.379Z" },
{ url = "https://files.pythonhosted.org/packages/b6/36/a0f007dc58fc1bbf51fb85dcc82fcb1f21b8c4261361de7dab0e3d8521ef/lupa-2.6-cp314-cp314t-win32.whl", hash = "sha256:1849efeba7a8f6fb8aa2c13790bee988fd242ae404bd459509640eeea3d1e291", size = 1590104, upload-time = "2025-10-24T07:19:33.514Z" },
{ url = "https://files.pythonhosted.org/packages/7d/5e/db903ce9cf82c48d6b91bf6d63ae4c8d0d17958939a4e04ba6b9f38b8643/lupa-2.6-cp314-cp314t-win_amd64.whl", hash = "sha256:fc1498d1a4fc028bc521c26d0fad4ca00ed63b952e32fb95949bda76a04bad52", size = 1913818, upload-time = "2025-10-24T07:19:36.039Z" },
- { url = "https://files.pythonhosted.org/packages/fb/c5/918ed6c3af793764bae155d68df47bab2635ab7c94dee3dbb5d9c6d5ba38/lupa-2.6-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8897dc6c3249786b2cdf2f83324febb436193d4581b6a71dea49f77bf8b19bb0", size = 956718, upload-time = "2025-10-24T07:20:03.086Z" },
- { url = "https://files.pythonhosted.org/packages/da/91/0ca797da854478225c0f6a8fc3c500a2f5c11826d732735beb5dffff9e85/lupa-2.6-cp39-cp39-macosx_11_0_universal2.whl", hash = "sha256:4446396ca3830be0c106c70db4b4f622c37b2d447874c07952cafb9c57949a4a", size = 1923934, upload-time = "2025-10-24T07:20:05.428Z" },
- { url = "https://files.pythonhosted.org/packages/f5/7f/98a6a2535285d43457eb665822ab08447e2196b614db3152772d457ca426/lupa-2.6-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:5826e687c89995a6eaafeae242071ba16448eec1a9ee8e17ed48551b5d1e21c2", size = 987286, upload-time = "2025-10-24T07:20:07.338Z" },
- { url = "https://files.pythonhosted.org/packages/5f/50/edad7c180ab28aa543e6c3895e56a2c7a6ff92140a283316e6086f118552/lupa-2.6-cp39-cp39-manylinux2010_i686.manylinux_2_12_i686.manylinux_2_28_i686.whl", hash = "sha256:5871935cb36d1d22f9c04ac0db75c06751bd95edcfa0d9309f732de908e297a9", size = 1176541, upload-time = "2025-10-24T07:20:09.305Z" },
- { url = "https://files.pythonhosted.org/packages/24/b3/27a0ec4c73011e86f9bd2eada010062308a4ed32921898d066ae54e064e1/lupa-2.6-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:43eb6e43ea8512d0d65b995d36dd9d77aa02598035e25b84c23a1b58700c9fb2", size = 1058981, upload-time = "2025-10-24T07:20:11.7Z" },
- { url = "https://files.pythonhosted.org/packages/a4/12/d55d45a8c253e7981f59ae920bac49dbd49888954b25fd1eb3a7be1321db/lupa-2.6-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:559714053018d9885cc8c36a33c5b7eb9aad30fb6357719cac3ce4dc6b39157e", size = 2103336, upload-time = "2025-10-24T07:20:13.71Z" },
- { url = "https://files.pythonhosted.org/packages/ab/17/058cc212c22d6a25990226afd02c741b2813b5f325396a9180b4accb70ac/lupa-2.6-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:57ac88a00ce59bd9d4ddcd4fca8e02564765725f5068786b011c9d1be3de20c5", size = 1083209, upload-time = "2025-10-24T07:20:15.587Z" },
- { url = "https://files.pythonhosted.org/packages/e6/01/8ca3a56a4e127784a15f0c7ec1f67e9894c2e9d4bf402389ddda4ea8081b/lupa-2.6-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:b683fbd867c2e54c44a686361b75eee7e7a790da55afdbe89f1f23b106de0274", size = 1193077, upload-time = "2025-10-24T07:20:17.857Z" },
- { url = "https://files.pythonhosted.org/packages/07/1b/c7fe79bcda6d489306bb7c1a9b4d545b7f0930b9ce80080643fc39b3fdc9/lupa-2.6-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:d2f656903a2ed2e074bf2b7d300968028dfa327a45b055be8e3b51ef0b82f9bf", size = 2198584, upload-time = "2025-10-24T07:20:20.468Z" },
- { url = "https://files.pythonhosted.org/packages/9e/df/3f7631eea3478ac3868cbcb2763c1a4e2f7b875fcb2683f956bf7aabf65f/lupa-2.6-cp39-cp39-win32.whl", hash = "sha256:bf28f68ae231b72008523ab5ac23835ba0f76e0e99ec38b59766080a84eb596a", size = 1414693, upload-time = "2025-10-24T07:20:23.477Z" },
- { url = "https://files.pythonhosted.org/packages/08/e0/3fd9617814663129fa4a9b33a980c3fe344297337cb550c738f87f730f6b/lupa-2.6-cp39-cp39-win_amd64.whl", hash = "sha256:b4b2e9b3795a9897cf6cfcc58d08210fdc0d13ab47c9a0e13858c68932d8353c", size = 1658877, upload-time = "2025-10-24T07:20:27.086Z" },
-]
-
-[[package]]
-name = "markdown"
-version = "3.9"
-source = { registry = "https://pypi.org/simple" }
-resolution-markers = [
- "python_full_version < '3.10'",
-]
-dependencies = [
- { name = "importlib-metadata", marker = "python_full_version < '3.10'" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/8d/37/02347f6d6d8279247a5837082ebc26fc0d5aaeaf75aa013fcbb433c777ab/markdown-3.9.tar.gz", hash = "sha256:d2900fe1782bd33bdbbd56859defef70c2e78fc46668f8eb9df3128138f2cb6a", size = 364585, upload-time = "2025-09-04T20:25:22.885Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/70/ae/44c4a6a4cbb496d93c6257954260fe3a6e91b7bed2240e5dad2a717f5111/markdown-3.9-py3-none-any.whl", hash = "sha256:9f4d91ed810864ea88a6f32c07ba8bee1346c0cc1f6b1f9f6c822f2a9667d280", size = 107441, upload-time = "2025-09-04T20:25:21.784Z" },
]
[[package]]
name = "markdown"
version = "3.10.1"
source = { registry = "https://pypi.org/simple" }
-resolution-markers = [
- "python_full_version >= '3.14'",
- "python_full_version >= '3.10' and python_full_version < '3.14'",
-]
sdist = { url = "https://files.pythonhosted.org/packages/b7/b1/af95bcae8549f1f3fd70faacb29075826a0d689a27f232e8cee315efa053/markdown-3.10.1.tar.gz", hash = "sha256:1c19c10bd5c14ac948c53d0d762a04e2fa35a6d58a6b7b1e6bfcbe6fefc0001a", size = 365402, upload-time = "2026-01-21T18:09:28.206Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/59/1b/6ef961f543593969d25b2afe57a3564200280528caa9bd1082eecdd7b3bc/markdown-3.10.1-py3-none-any.whl", hash = "sha256:867d788939fe33e4b736426f5b9f651ad0c0ae0ecf89df0ca5d1176c70812fe3", size = 107684, upload-time = "2026-01-21T18:09:27.203Z" },
@@ -3296,39 +2672,19 @@ name = "markdown-include-variants"
version = "0.0.8"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "markdown", version = "3.9", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
- { name = "markdown", version = "3.10.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
+ { name = "markdown" },
]
sdist = { url = "https://files.pythonhosted.org/packages/c5/47/ec9eae4a6d2f336d95681df43720e2b25b045dc3ed44ae6d30a5ce2f5dff/markdown_include_variants-0.0.8.tar.gz", hash = "sha256:46d812340c64dcd3646b1eaa356bafb31626dd7b4955d15c44ff8c48c6357227", size = 46882, upload-time = "2025-12-12T16:11:04.254Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/4e/0e/130958e7ec50d13f2ee7b6c142df5c352520a9251baf1652e41262703857/markdown_include_variants-0.0.8-py3-none-any.whl", hash = "sha256:425a300ae25fbcd598506cba67859a9dfa047333e869e0ff2e11a5e354b326dc", size = 8120, upload-time = "2025-12-12T16:11:02.881Z" },
]
-[[package]]
-name = "markdown-it-py"
-version = "3.0.0"
-source = { registry = "https://pypi.org/simple" }
-resolution-markers = [
- "python_full_version < '3.10'",
-]
-dependencies = [
- { name = "mdurl", marker = "python_full_version < '3.10'" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/38/71/3b932df36c1a044d397a1f92d1cf91ee0a503d91e470cbd670aa66b07ed0/markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb", size = 74596, upload-time = "2023-06-03T06:41:14.443Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1", size = 87528, upload-time = "2023-06-03T06:41:11.019Z" },
-]
-
[[package]]
name = "markdown-it-py"
version = "4.0.0"
source = { registry = "https://pypi.org/simple" }
-resolution-markers = [
- "python_full_version >= '3.14'",
- "python_full_version >= '3.10' and python_full_version < '3.14'",
-]
dependencies = [
- { name = "mdurl", marker = "python_full_version >= '3.10'" },
+ { name = "mdurl" },
]
sdist = { url = "https://files.pythonhosted.org/packages/5b/f5/4ec618ed16cc4f8fb3b701563655a69816155e79e24a17b651541804721d/markdown_it_py-4.0.0.tar.gz", hash = "sha256:cb0a2b4aa34f932c007117b194e945bd74e0ec24133ceb5bac59009cda1cb9f3", size = 73070, upload-time = "2025-08-11T12:57:52.854Z" }
wheels = [
@@ -3418,17 +2774,6 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/fb/df/5bd7a48c256faecd1d36edc13133e51397e41b73bb77e1a69deab746ebac/markupsafe-3.0.3-cp314-cp314t-win32.whl", hash = "sha256:915c04ba3851909ce68ccc2b8e2cd691618c4dc4c4232fb7982bca3f41fd8c3d", size = 14819, upload-time = "2025-09-27T18:37:26.285Z" },
{ url = "https://files.pythonhosted.org/packages/1a/8a/0402ba61a2f16038b48b39bccca271134be00c5c9f0f623208399333c448/markupsafe-3.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4faffd047e07c38848ce017e8725090413cd80cbc23d86e55c587bf979e579c9", size = 15426, upload-time = "2025-09-27T18:37:27.316Z" },
{ url = "https://files.pythonhosted.org/packages/70/bc/6f1c2f612465f5fa89b95bead1f44dcb607670fd42891d8fdcd5d039f4f4/markupsafe-3.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:32001d6a8fc98c8cb5c947787c5d08b0a50663d139f1305bac5885d98d9b40fa", size = 14146, upload-time = "2025-09-27T18:37:28.327Z" },
- { url = "https://files.pythonhosted.org/packages/56/23/0d8c13a44bde9154821586520840643467aee574d8ce79a17da539ee7fed/markupsafe-3.0.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:15d939a21d546304880945ca1ecb8a039db6b4dc49b2c5a400387cdae6a62e26", size = 11623, upload-time = "2025-09-27T18:37:29.296Z" },
- { url = "https://files.pythonhosted.org/packages/fd/23/07a2cb9a8045d5f3f0890a8c3bc0859d7a47bfd9a560b563899bec7b72ed/markupsafe-3.0.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f71a396b3bf33ecaa1626c255855702aca4d3d9fea5e051b41ac59a9c1c41edc", size = 12049, upload-time = "2025-09-27T18:37:30.234Z" },
- { url = "https://files.pythonhosted.org/packages/bc/e4/6be85eb81503f8e11b61c0b6369b6e077dcf0a74adbd9ebf6b349937b4e9/markupsafe-3.0.3-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0f4b68347f8c5eab4a13419215bdfd7f8c9b19f2b25520968adfad23eb0ce60c", size = 21923, upload-time = "2025-09-27T18:37:31.177Z" },
- { url = "https://files.pythonhosted.org/packages/6f/bc/4dc914ead3fe6ddaef035341fee0fc956949bbd27335b611829292b89ee2/markupsafe-3.0.3-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e8fc20152abba6b83724d7ff268c249fa196d8259ff481f3b1476383f8f24e42", size = 20543, upload-time = "2025-09-27T18:37:32.168Z" },
- { url = "https://files.pythonhosted.org/packages/89/6e/5fe81fbcfba4aef4093d5f856e5c774ec2057946052d18d168219b7bd9f9/markupsafe-3.0.3-cp39-cp39-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:949b8d66bc381ee8b007cd945914c721d9aba8e27f71959d750a46f7c282b20b", size = 20585, upload-time = "2025-09-27T18:37:33.166Z" },
- { url = "https://files.pythonhosted.org/packages/f6/f6/e0e5a3d3ae9c4020f696cd055f940ef86b64fe88de26f3a0308b9d3d048c/markupsafe-3.0.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:3537e01efc9d4dccdf77221fb1cb3b8e1a38d5428920e0657ce299b20324d758", size = 21387, upload-time = "2025-09-27T18:37:34.185Z" },
- { url = "https://files.pythonhosted.org/packages/c8/25/651753ef4dea08ea790f4fbb65146a9a44a014986996ca40102e237aa49a/markupsafe-3.0.3-cp39-cp39-musllinux_1_2_riscv64.whl", hash = "sha256:591ae9f2a647529ca990bc681daebdd52c8791ff06c2bfa05b65163e28102ef2", size = 20133, upload-time = "2025-09-27T18:37:35.138Z" },
- { url = "https://files.pythonhosted.org/packages/dc/0a/c3cf2b4fef5f0426e8a6d7fce3cb966a17817c568ce59d76b92a233fdbec/markupsafe-3.0.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:a320721ab5a1aba0a233739394eb907f8c8da5c98c9181d1161e77a0c8e36f2d", size = 20588, upload-time = "2025-09-27T18:37:36.096Z" },
- { url = "https://files.pythonhosted.org/packages/cd/1b/a7782984844bd519ad4ffdbebbba2671ec5d0ebbeac34736c15fb86399e8/markupsafe-3.0.3-cp39-cp39-win32.whl", hash = "sha256:df2449253ef108a379b8b5d6b43f4b1a8e81a061d6537becd5582fba5f9196d7", size = 14566, upload-time = "2025-09-27T18:37:37.09Z" },
- { url = "https://files.pythonhosted.org/packages/18/1f/8d9c20e1c9440e215a44be5ab64359e207fcb4f675543f1cf9a2a7f648d0/markupsafe-3.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:7c3fb7d25180895632e5d3148dbdc29ea38ccb7fd210aa27acbd1201a1902c6e", size = 15053, upload-time = "2025-09-27T18:37:38.054Z" },
- { url = "https://files.pythonhosted.org/packages/4e/d3/fe08482b5cd995033556d45041a4f4e76e7f0521112a9c9991d40d39825f/markupsafe-3.0.3-cp39-cp39-win_arm64.whl", hash = "sha256:38664109c14ffc9e7437e86b4dceb442b0096dfe3541d7864d9cbe1da4cf36c8", size = 13928, upload-time = "2025-09-27T18:37:39.037Z" },
]
[[package]]
@@ -3436,20 +2781,20 @@ name = "mcp"
version = "1.26.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "anyio", marker = "python_full_version >= '3.10'" },
- { name = "httpx", marker = "python_full_version >= '3.10'" },
- { name = "httpx-sse", marker = "python_full_version >= '3.10'" },
- { name = "jsonschema", marker = "python_full_version >= '3.10'" },
- { name = "pydantic", marker = "python_full_version >= '3.10'" },
- { name = "pydantic-settings", version = "2.12.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
- { name = "pyjwt", extra = ["crypto"], marker = "python_full_version >= '3.10'" },
- { name = "python-multipart", version = "0.0.22", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
- { name = "pywin32", marker = "python_full_version >= '3.10' and sys_platform == 'win32'" },
- { name = "sse-starlette", marker = "python_full_version >= '3.10'" },
- { name = "starlette", version = "0.52.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
- { name = "typing-extensions", marker = "python_full_version >= '3.10'" },
- { name = "typing-inspection", marker = "python_full_version >= '3.10'" },
- { name = "uvicorn", version = "0.40.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10' and sys_platform != 'emscripten'" },
+ { name = "anyio" },
+ { name = "httpx" },
+ { name = "httpx-sse" },
+ { name = "jsonschema" },
+ { name = "pydantic" },
+ { name = "pydantic-settings" },
+ { name = "pyjwt", extra = ["crypto"] },
+ { name = "python-multipart" },
+ { name = "pywin32", marker = "sys_platform == 'win32'" },
+ { name = "sse-starlette" },
+ { name = "starlette" },
+ { name = "typing-extensions" },
+ { name = "typing-inspection" },
+ { name = "uvicorn", marker = "sys_platform != 'emscripten'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/fc/6d/62e76bbb8144d6ed86e202b5edd8a4cb631e7c8130f3f4893c3f90262b10/mcp-1.26.0.tar.gz", hash = "sha256:db6e2ef491eecc1a0d93711a76f28dec2e05999f93afd48795da1c1137142c66", size = 608005, upload-time = "2026-01-24T19:40:32.468Z" }
wheels = [
@@ -3471,8 +2816,7 @@ version = "1.4.2"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "cyclic" },
- { name = "markdown", version = "3.9", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
- { name = "markdown", version = "3.10.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
+ { name = "markdown" },
{ name = "rcslice" },
]
sdist = { url = "https://files.pythonhosted.org/packages/bf/f0/f395a9cf164471d3c7bbe58cbd64d74289575a8b85a962b49a804ab7ed34/mdx_include-1.4.2.tar.gz", hash = "sha256:992f9fbc492b5cf43f7d8cb4b90b52a4e4c5fdd7fd04570290a83eea5c84f297", size = 15051, upload-time = "2022-07-26T05:46:14.129Z" }
@@ -3512,14 +2856,11 @@ name = "mkdocs"
version = "1.6.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "click", version = "8.1.8", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
- { name = "click", version = "8.3.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
+ { name = "click" },
{ name = "colorama", marker = "sys_platform == 'win32'" },
{ name = "ghp-import" },
- { name = "importlib-metadata", marker = "python_full_version < '3.10'" },
{ name = "jinja2" },
- { name = "markdown", version = "3.9", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
- { name = "markdown", version = "3.10.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
+ { name = "markdown" },
{ name = "markupsafe" },
{ name = "mergedeep" },
{ name = "mkdocs-get-deps" },
@@ -3539,8 +2880,7 @@ name = "mkdocs-autorefs"
version = "1.4.3"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "markdown", version = "3.9", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
- { name = "markdown", version = "3.10.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
+ { name = "markdown" },
{ name = "markupsafe" },
{ name = "mkdocs" },
]
@@ -3554,10 +2894,8 @@ name = "mkdocs-get-deps"
version = "0.2.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "importlib-metadata", marker = "python_full_version < '3.10'" },
{ name = "mergedeep" },
- { name = "platformdirs", version = "4.4.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
- { name = "platformdirs", version = "4.5.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
+ { name = "platformdirs" },
{ name = "pyyaml" },
]
sdist = { url = "https://files.pythonhosted.org/packages/98/f5/ed29cd50067784976f25ed0ed6fcd3c2ce9eb90650aa3b2796ddf7b6870b/mkdocs_get_deps-0.2.0.tar.gz", hash = "sha256:162b3d129c7fad9b19abfdcb9c1458a651628e4b1dea628ac68790fb3061c60c", size = 10239, upload-time = "2023-11-20T17:51:09.981Z" }
@@ -3579,8 +2917,7 @@ dependencies = [
{ name = "pyyaml" },
{ name = "requests" },
{ name = "super-collections" },
- { name = "termcolor", version = "3.1.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
- { name = "termcolor", version = "3.3.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
+ { name = "termcolor" },
]
sdist = { url = "https://files.pythonhosted.org/packages/92/15/e6a44839841ebc9c5872fa0e6fad1c3757424e4fe026093b68e9f386d136/mkdocs_macros_plugin-1.5.0.tar.gz", hash = "sha256:12aa45ce7ecb7a445c66b9f649f3dd05e9b92e8af6bc65e4acd91d26f878c01f", size = 37730, upload-time = "2025-11-13T08:08:55.545Z" }
wheels = [
@@ -3596,8 +2933,7 @@ dependencies = [
{ name = "backrefs" },
{ name = "colorama" },
{ name = "jinja2" },
- { name = "markdown", version = "3.9", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
- { name = "markdown", version = "3.10.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
+ { name = "markdown" },
{ name = "mkdocs" },
{ name = "mkdocs-material-extensions" },
{ name = "paginate" },
@@ -3631,47 +2967,17 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/c4/ec/38443b1f2a3821bbcb24e46cd8ba979154417794d54baf949fefde1c2146/mkdocs_redirects-1.2.2-py3-none-any.whl", hash = "sha256:7dbfa5647b79a3589da4401403d69494bd1f4ad03b9c15136720367e1f340ed5", size = 6142, upload-time = "2024-11-07T14:57:19.143Z" },
]
-[[package]]
-name = "mkdocstrings"
-version = "0.30.1"
-source = { registry = "https://pypi.org/simple" }
-resolution-markers = [
- "python_full_version < '3.10'",
-]
-dependencies = [
- { name = "importlib-metadata", marker = "python_full_version < '3.10'" },
- { name = "jinja2", marker = "python_full_version < '3.10'" },
- { name = "markdown", version = "3.9", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
- { name = "markupsafe", marker = "python_full_version < '3.10'" },
- { name = "mkdocs", marker = "python_full_version < '3.10'" },
- { name = "mkdocs-autorefs", marker = "python_full_version < '3.10'" },
- { name = "pymdown-extensions", marker = "python_full_version < '3.10'" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/c5/33/2fa3243439f794e685d3e694590d28469a9b8ea733af4b48c250a3ffc9a0/mkdocstrings-0.30.1.tar.gz", hash = "sha256:84a007aae9b707fb0aebfc9da23db4b26fc9ab562eb56e335e9ec480cb19744f", size = 106350, upload-time = "2025-09-19T10:49:26.446Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/7b/2c/f0dc4e1ee7f618f5bff7e05898d20bf8b6e7fa612038f768bfa295f136a4/mkdocstrings-0.30.1-py3-none-any.whl", hash = "sha256:41bd71f284ca4d44a668816193e4025c950b002252081e387433656ae9a70a82", size = 36704, upload-time = "2025-09-19T10:49:24.805Z" },
-]
-
-[package.optional-dependencies]
-python = [
- { name = "mkdocstrings-python", version = "1.18.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
-]
-
[[package]]
name = "mkdocstrings"
version = "1.0.2"
source = { registry = "https://pypi.org/simple" }
-resolution-markers = [
- "python_full_version >= '3.14'",
- "python_full_version >= '3.10' and python_full_version < '3.14'",
-]
dependencies = [
- { name = "jinja2", marker = "python_full_version >= '3.10'" },
- { name = "markdown", version = "3.10.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
- { name = "markupsafe", marker = "python_full_version >= '3.10'" },
- { name = "mkdocs", marker = "python_full_version >= '3.10'" },
- { name = "mkdocs-autorefs", marker = "python_full_version >= '3.10'" },
- { name = "pymdown-extensions", marker = "python_full_version >= '3.10'" },
+ { name = "jinja2" },
+ { name = "markdown" },
+ { name = "markupsafe" },
+ { name = "mkdocs" },
+ { name = "mkdocs-autorefs" },
+ { name = "pymdown-extensions" },
]
sdist = { url = "https://files.pythonhosted.org/packages/63/4d/1ca8a9432579184599714aaeb36591414cc3d3bfd9d494f6db540c995ae4/mkdocstrings-1.0.2.tar.gz", hash = "sha256:48edd0ccbcb9e30a3121684e165261a9d6af4d63385fc4f39a54a49ac3b32ea8", size = 101048, upload-time = "2026-01-24T15:57:25.735Z" }
wheels = [
@@ -3680,40 +2986,18 @@ wheels = [
[package.optional-dependencies]
python = [
- { name = "mkdocstrings-python", version = "2.0.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
-]
-
-[[package]]
-name = "mkdocstrings-python"
-version = "1.18.2"
-source = { registry = "https://pypi.org/simple" }
-resolution-markers = [
- "python_full_version < '3.10'",
-]
-dependencies = [
- { name = "griffe", version = "1.14.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
- { name = "mkdocs-autorefs", marker = "python_full_version < '3.10'" },
- { name = "mkdocstrings", version = "0.30.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
- { name = "typing-extensions", marker = "python_full_version < '3.10'" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/95/ae/58ab2bfbee2792e92a98b97e872f7c003deb903071f75d8d83aa55db28fa/mkdocstrings_python-1.18.2.tar.gz", hash = "sha256:4ad536920a07b6336f50d4c6d5603316fafb1172c5c882370cbbc954770ad323", size = 207972, upload-time = "2025-08-28T16:11:19.847Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/d5/8f/ce008599d9adebf33ed144e7736914385e8537f5fc686fdb7cceb8c22431/mkdocstrings_python-1.18.2-py3-none-any.whl", hash = "sha256:944fe6deb8f08f33fa936d538233c4036e9f53e840994f6146e8e94eb71b600d", size = 138215, upload-time = "2025-08-28T16:11:18.176Z" },
+ { name = "mkdocstrings-python" },
]
[[package]]
name = "mkdocstrings-python"
version = "2.0.1"
source = { registry = "https://pypi.org/simple" }
-resolution-markers = [
- "python_full_version >= '3.14'",
- "python_full_version >= '3.10' and python_full_version < '3.14'",
-]
dependencies = [
- { name = "griffe", version = "1.15.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
- { name = "mkdocs-autorefs", marker = "python_full_version >= '3.10'" },
- { name = "mkdocstrings", version = "1.0.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
- { name = "typing-extensions", marker = "python_full_version == '3.10.*'" },
+ { name = "griffe" },
+ { name = "mkdocs-autorefs" },
+ { name = "mkdocstrings" },
+ { name = "typing-extensions", marker = "python_full_version < '3.11'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/24/75/d30af27a2906f00eb90143470272376d728521997800f5dce5b340ba35bc/mkdocstrings_python-2.0.1.tar.gz", hash = "sha256:843a562221e6a471fefdd4b45cc6c22d2607ccbad632879234fa9692e9cf7732", size = 199345, upload-time = "2025-12-03T14:26:11.755Z" }
wheels = [
@@ -3864,24 +3148,6 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/5f/60/c3a5187bf66f6fb546ff4ab8fb5a077cbdd832d7b1908d4365c7f74a1917/multidict-6.7.1-cp314-cp314t-win32.whl", hash = "sha256:98655c737850c064a65e006a3df7c997cd3b220be4ec8fe26215760b9697d4d7", size = 48008, upload-time = "2026-01-26T02:46:07.468Z" },
{ url = "https://files.pythonhosted.org/packages/0c/f7/addf1087b860ac60e6f382240f64fb99f8bfb532bb06f7c542b83c29ca61/multidict-6.7.1-cp314-cp314t-win_amd64.whl", hash = "sha256:497bde6223c212ba11d462853cfa4f0ae6ef97465033e7dc9940cdb3ab5b48e5", size = 53542, upload-time = "2026-01-26T02:46:08.809Z" },
{ url = "https://files.pythonhosted.org/packages/4c/81/4629d0aa32302ef7b2ec65c75a728cc5ff4fa410c50096174c1632e70b3e/multidict-6.7.1-cp314-cp314t-win_arm64.whl", hash = "sha256:2bbd113e0d4af5db41d5ebfe9ccaff89de2120578164f86a5d17d5a576d1e5b2", size = 44719, upload-time = "2026-01-26T02:46:11.146Z" },
- { url = "https://files.pythonhosted.org/packages/9e/ee/74525ebe3eb5fddcd6735fc03cbea3feeed4122b53bc798ac32d297ac9ae/multidict-6.7.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:65573858d27cdeaca41893185677dc82395159aa28875a8867af66532d413a8f", size = 77107, upload-time = "2026-01-26T02:46:12.608Z" },
- { url = "https://files.pythonhosted.org/packages/f0/9a/ce8744e777a74b3050b1bf56be3eed1053b3457302ea055f1ea437200a23/multidict-6.7.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c524c6fb8fc342793708ab111c4dbc90ff9abd568de220432500e47e990c0358", size = 44943, upload-time = "2026-01-26T02:46:14.016Z" },
- { url = "https://files.pythonhosted.org/packages/83/9c/1d2a283d9c6f31e260cb6c2fccadc3edcf6c4c14ee0929cd2af4d2606dd7/multidict-6.7.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:aa23b001d968faef416ff70dc0f1ab045517b9b42a90edd3e9bcdb06479e31d5", size = 44603, upload-time = "2026-01-26T02:46:15.391Z" },
- { url = "https://files.pythonhosted.org/packages/87/9d/3b186201671583d8e8d6d79c07481a5aafd0ba7575e3d8566baec80c1e82/multidict-6.7.1-cp39-cp39-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:6704fa2b7453b2fb121740555fa1ee20cd98c4d011120caf4d2b8d4e7c76eec0", size = 240573, upload-time = "2026-01-26T02:46:16.783Z" },
- { url = "https://files.pythonhosted.org/packages/42/7d/a52f5d4d0754311d1ac78478e34dff88de71259a8585e05ee14e5f877caf/multidict-6.7.1-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:121a34e5bfa410cdf2c8c49716de160de3b1dbcd86b49656f5681e4543bcd1a8", size = 240106, upload-time = "2026-01-26T02:46:18.432Z" },
- { url = "https://files.pythonhosted.org/packages/84/9f/d80118e6c30ff55b7d171bdc5520aad4b9626e657520b8d7c8ca8c2fad12/multidict-6.7.1-cp39-cp39-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:026d264228bcd637d4e060844e39cdc60f86c479e463d49075dedc21b18fbbe0", size = 219418, upload-time = "2026-01-26T02:46:20.526Z" },
- { url = "https://files.pythonhosted.org/packages/c7/bd/896e60b3457f194de77c7de64f9acce9f75da0518a5230ce1df534f6747b/multidict-6.7.1-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:0e697826df7eb63418ee190fd06ce9f1803593bb4b9517d08c60d9b9a7f69d8f", size = 252124, upload-time = "2026-01-26T02:46:22.157Z" },
- { url = "https://files.pythonhosted.org/packages/f4/de/ba6b30447c36a37078d0ba604aa12c1a52887af0c355236ca6e0a9d5286f/multidict-6.7.1-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:bb08271280173720e9fea9ede98e5231defcbad90f1624bea26f32ec8a956e2f", size = 249402, upload-time = "2026-01-26T02:46:23.718Z" },
- { url = "https://files.pythonhosted.org/packages/c2/b2/50a383c96230e432895a2fd3bcfe1b65785899598259d871d5de6b93180c/multidict-6.7.1-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c6b3228e1d80af737b72925ce5fb4daf5a335e49cd7ab77ed7b9fdfbf58c526e", size = 240346, upload-time = "2026-01-26T02:46:25.393Z" },
- { url = "https://files.pythonhosted.org/packages/89/37/16d391fd8da544b1489306e38a46785fa41dd0f0ef766837ed7d4676dde0/multidict-6.7.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:3943debf0fbb57bdde5901695c11094a9a36723e5c03875f87718ee15ca2f4d2", size = 237010, upload-time = "2026-01-26T02:46:27.408Z" },
- { url = "https://files.pythonhosted.org/packages/b0/24/3152ee026eda86d5d3e3685182911e6951af7a016579da931080ce6ac9ad/multidict-6.7.1-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:98c5787b0a0d9a41d9311eae44c3b76e6753def8d8870ab501320efe75a6a5f8", size = 232018, upload-time = "2026-01-26T02:46:29.941Z" },
- { url = "https://files.pythonhosted.org/packages/9c/1f/48d3c27a72be7fd23a55d8847193c459959bf35a5bb5844530dab00b739b/multidict-6.7.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:08ccb2a6dc72009093ebe7f3f073e5ec5964cba9a706fa94b1a1484039b87941", size = 241498, upload-time = "2026-01-26T02:46:32.052Z" },
- { url = "https://files.pythonhosted.org/packages/1a/45/413643ae2952d0decdf6c1250f86d08a43e143271441e81027e38d598bd7/multidict-6.7.1-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:eb351f72c26dc9abe338ca7294661aa22969ad8ffe7ef7d5541d19f368dc854a", size = 247957, upload-time = "2026-01-26T02:46:33.666Z" },
- { url = "https://files.pythonhosted.org/packages/50/f8/f1d0ac23df15e0470776388bdb261506f63af1f81d28bacb5e262d6e12b6/multidict-6.7.1-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:ac1c665bad8b5d762f5f85ebe4d94130c26965f11de70c708c75671297c776de", size = 241651, upload-time = "2026-01-26T02:46:35.7Z" },
- { url = "https://files.pythonhosted.org/packages/2c/c9/1a2a18f383cf129add66b6c36b75c3911a7ba95cf26cb141482de085cc12/multidict-6.7.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:1fa6609d0364f4f6f58351b4659a1f3e0e898ba2a8c5cac04cb2c7bc556b0bc5", size = 236371, upload-time = "2026-01-26T02:46:37.37Z" },
- { url = "https://files.pythonhosted.org/packages/bb/aa/77d87e3fca31325b87e0eb72d5fe9a7472dcb51391a42df7ac1f3842f6c0/multidict-6.7.1-cp39-cp39-win32.whl", hash = "sha256:6f77ce314a29263e67adadc7e7c1bc699fcb3a305059ab973d038f87caa42ed0", size = 41426, upload-time = "2026-01-26T02:46:39.026Z" },
- { url = "https://files.pythonhosted.org/packages/e3/b3/e8863e6a2da15a9d7e98976ff402e871b7352c76566df6c18d0378e0d9cf/multidict-6.7.1-cp39-cp39-win_amd64.whl", hash = "sha256:f537b55778cd3cbee430abe3131255d3a78202e0f9ea7ffc6ada893a4bcaeea4", size = 46180, upload-time = "2026-01-26T02:46:40.422Z" },
- { url = "https://files.pythonhosted.org/packages/93/d3/dd4fa951ad5b5fa216bf30054d705683d13405eea7459833d78f31b74c9c/multidict-6.7.1-cp39-cp39-win_arm64.whl", hash = "sha256:749aa54f578f2e5f439538706a475aa844bfa8ef75854b1401e6e528e4937cf9", size = 43231, upload-time = "2026-01-26T02:46:41.945Z" },
{ url = "https://files.pythonhosted.org/packages/81/08/7036c080d7117f28a4af526d794aab6a84463126db031b007717c1a6676e/multidict-6.7.1-py3-none-any.whl", hash = "sha256:55d97cc6dae627efa6a6e548885712d4864b81110ac76fa4e534c03819fa4a56", size = 12319, upload-time = "2026-01-26T02:46:44.004Z" },
]
@@ -3928,12 +3194,6 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/32/2a/66ba933fe6c76bd40d1fe916a83f04fed253152f451a877520b3c4a5e41e/mypy-1.19.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:28902ee51f12e0f19e1e16fbe2f8f06b6637f482c459dd393efddd0ec7f82045", size = 13601998, upload-time = "2025-12-15T05:03:13.056Z" },
{ url = "https://files.pythonhosted.org/packages/e3/da/5055c63e377c5c2418760411fd6a63ee2b96cf95397259038756c042574f/mypy-1.19.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:481daf36a4c443332e2ae9c137dfee878fcea781a2e3f895d54bd3002a900957", size = 13807476, upload-time = "2025-12-15T05:03:17.977Z" },
{ url = "https://files.pythonhosted.org/packages/cd/09/4ebd873390a063176f06b0dbf1f7783dd87bd120eae7727fa4ae4179b685/mypy-1.19.1-cp314-cp314-win_amd64.whl", hash = "sha256:8bb5c6f6d043655e055be9b542aa5f3bdd30e4f3589163e85f93f3640060509f", size = 10281872, upload-time = "2025-12-15T05:03:05.549Z" },
- { url = "https://files.pythonhosted.org/packages/b5/f7/88436084550ca9af5e610fa45286be04c3b63374df3e021c762fe8c4369f/mypy-1.19.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7bcfc336a03a1aaa26dfce9fff3e287a3ba99872a157561cbfcebe67c13308e3", size = 13102606, upload-time = "2025-12-15T05:02:46.833Z" },
- { url = "https://files.pythonhosted.org/packages/ca/a5/43dfad311a734b48a752790571fd9e12d61893849a01bff346a54011957f/mypy-1.19.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b7951a701c07ea584c4fe327834b92a30825514c868b1f69c30445093fdd9d5a", size = 12164496, upload-time = "2025-12-15T05:03:41.947Z" },
- { url = "https://files.pythonhosted.org/packages/88/f0/efbfa391395cce2f2771f937e0620cfd185ec88f2b9cd88711028a768e96/mypy-1.19.1-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b13cfdd6c87fc3efb69ea4ec18ef79c74c3f98b4e5498ca9b85ab3b2c2329a67", size = 12772068, upload-time = "2025-12-15T05:02:53.689Z" },
- { url = "https://files.pythonhosted.org/packages/25/05/58b3ba28f5aed10479e899a12d2120d582ba9fa6288851b20bf1c32cbb4f/mypy-1.19.1-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4f28f99c824ecebcdaa2e55d82953e38ff60ee5ec938476796636b86afa3956e", size = 13520385, upload-time = "2025-12-15T05:02:38.328Z" },
- { url = "https://files.pythonhosted.org/packages/c5/a0/c006ccaff50b31e542ae69b92fe7e2f55d99fba3a55e01067dd564325f85/mypy-1.19.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:c608937067d2fc5a4dd1a5ce92fd9e1398691b8c5d012d66e1ddd430e9244376", size = 13796221, upload-time = "2025-12-15T05:03:22.147Z" },
- { url = "https://files.pythonhosted.org/packages/b2/ff/8bdb051cd710f01b880472241bd36b3f817a8e1c5d5540d0b761675b6de2/mypy-1.19.1-cp39-cp39-win_amd64.whl", hash = "sha256:409088884802d511ee52ca067707b90c883426bd95514e8cfda8281dc2effe24", size = 10055456, upload-time = "2025-12-15T05:03:35.169Z" },
{ url = "https://files.pythonhosted.org/packages/8d/f4/4ce9a05ce5ded1de3ec1c1d96cf9f9504a04e54ce0ed55cfa38619a32b8d/mypy-1.19.1-py3-none-any.whl", hash = "sha256:f1235f5ea01b7db5468d53ece6aaddf1ad0b88d9e7462b86ef96fe04995d7247", size = 2471239, upload-time = "2025-12-15T05:03:07.248Z" },
]
@@ -3946,31 +3206,12 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505", size = 4963, upload-time = "2025-04-22T14:54:22.983Z" },
]
-[[package]]
-name = "nexus-rpc"
-version = "1.1.0"
-source = { registry = "https://pypi.org/simple" }
-resolution-markers = [
- "python_full_version < '3.10'",
-]
-dependencies = [
- { name = "typing-extensions", marker = "python_full_version < '3.10'" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/ef/66/540687556bd28cf1ec370cc6881456203dfddb9dab047b8979c6865b5984/nexus_rpc-1.1.0.tar.gz", hash = "sha256:d65ad6a2f54f14e53ebe39ee30555eaeb894102437125733fb13034a04a44553", size = 77383, upload-time = "2025-07-07T19:03:58.368Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/bf/2f/9e9d0dcaa4c6ffa22b7aa31069a8a264c753ff8027b36af602cce038c92f/nexus_rpc-1.1.0-py3-none-any.whl", hash = "sha256:d1b007af2aba186a27e736f8eaae39c03aed05b488084ff6c3d1785c9ba2ad38", size = 27743, upload-time = "2025-07-07T19:03:57.556Z" },
-]
-
[[package]]
name = "nexus-rpc"
version = "1.2.0"
source = { registry = "https://pypi.org/simple" }
-resolution-markers = [
- "python_full_version >= '3.14'",
- "python_full_version >= '3.10' and python_full_version < '3.14'",
-]
dependencies = [
- { name = "typing-extensions", marker = "python_full_version >= '3.10'" },
+ { name = "typing-extensions" },
]
sdist = { url = "https://files.pythonhosted.org/packages/06/50/95d7bc91f900da5e22662c82d9bf0f72a4b01f2a552708bf2f43807707a1/nexus_rpc-1.2.0.tar.gz", hash = "sha256:b4ddaffa4d3996aaeadf49b80dfcdfbca48fe4cb616defaf3b3c5c2c8fc61890", size = 74142, upload-time = "2025-11-17T19:17:06.798Z" }
wheels = [
@@ -4001,7 +3242,7 @@ name = "openapi-pydantic"
version = "0.5.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "pydantic", marker = "python_full_version >= '3.10'" },
+ { name = "pydantic" },
]
sdist = { url = "https://files.pythonhosted.org/packages/02/2e/58d83848dd1a79cb92ed8e63f6ba901ca282c5f09d04af9423ec26c56fd7/openapi_pydantic-0.5.1.tar.gz", hash = "sha256:ff6835af6bde7a459fb93eb93bb92b8749b754fc6e51b2f1590a19dc3005ee0d", size = 60892, upload-time = "2025-01-08T19:29:27.083Z" }
wheels = [
@@ -4026,7 +3267,7 @@ name = "opentelemetry-exporter-otlp-proto-common"
version = "1.39.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "opentelemetry-proto", marker = "python_full_version >= '3.10'" },
+ { name = "opentelemetry-proto" },
]
sdist = { url = "https://files.pythonhosted.org/packages/e9/9d/22d241b66f7bbde88a3bfa6847a351d2c46b84de23e71222c6aae25c7050/opentelemetry_exporter_otlp_proto_common-1.39.1.tar.gz", hash = "sha256:763370d4737a59741c89a67b50f9e39271639ee4afc999dadfe768541c027464", size = 20409, upload-time = "2025-12-11T13:32:40.885Z" }
wheels = [
@@ -4038,13 +3279,13 @@ name = "opentelemetry-exporter-otlp-proto-http"
version = "1.39.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "googleapis-common-protos", marker = "python_full_version >= '3.10'" },
- { name = "opentelemetry-api", marker = "python_full_version >= '3.10'" },
- { name = "opentelemetry-exporter-otlp-proto-common", marker = "python_full_version >= '3.10'" },
- { name = "opentelemetry-proto", marker = "python_full_version >= '3.10'" },
- { name = "opentelemetry-sdk", marker = "python_full_version >= '3.10'" },
- { name = "requests", marker = "python_full_version >= '3.10'" },
- { name = "typing-extensions", marker = "python_full_version >= '3.10'" },
+ { name = "googleapis-common-protos" },
+ { name = "opentelemetry-api" },
+ { name = "opentelemetry-exporter-otlp-proto-common" },
+ { name = "opentelemetry-proto" },
+ { name = "opentelemetry-sdk" },
+ { name = "requests" },
+ { name = "typing-extensions" },
]
sdist = { url = "https://files.pythonhosted.org/packages/80/04/2a08fa9c0214ae38880df01e8bfae12b067ec0793446578575e5080d6545/opentelemetry_exporter_otlp_proto_http-1.39.1.tar.gz", hash = "sha256:31bdab9745c709ce90a49a0624c2bd445d31a28ba34275951a6a362d16a0b9cb", size = 17288, upload-time = "2025-12-11T13:32:42.029Z" }
wheels = [
@@ -4056,10 +3297,10 @@ name = "opentelemetry-instrumentation"
version = "0.60b1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "opentelemetry-api", marker = "python_full_version >= '3.10'" },
- { name = "opentelemetry-semantic-conventions", marker = "python_full_version >= '3.10'" },
- { name = "packaging", marker = "python_full_version >= '3.10'" },
- { name = "wrapt", marker = "python_full_version >= '3.10'" },
+ { name = "opentelemetry-api" },
+ { name = "opentelemetry-semantic-conventions" },
+ { name = "packaging" },
+ { name = "wrapt" },
]
sdist = { url = "https://files.pythonhosted.org/packages/41/0f/7e6b713ac117c1f5e4e3300748af699b9902a2e5e34c9cf443dde25a01fa/opentelemetry_instrumentation-0.60b1.tar.gz", hash = "sha256:57ddc7974c6eb35865af0426d1a17132b88b2ed8586897fee187fd5b8944bd6a", size = 31706, upload-time = "2025-12-11T13:36:42.515Z" }
wheels = [
@@ -4071,11 +3312,11 @@ name = "opentelemetry-instrumentation-httpx"
version = "0.60b1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "opentelemetry-api", marker = "python_full_version >= '3.10'" },
- { name = "opentelemetry-instrumentation", marker = "python_full_version >= '3.10'" },
- { name = "opentelemetry-semantic-conventions", marker = "python_full_version >= '3.10'" },
- { name = "opentelemetry-util-http", marker = "python_full_version >= '3.10'" },
- { name = "wrapt", marker = "python_full_version >= '3.10'" },
+ { name = "opentelemetry-api" },
+ { name = "opentelemetry-instrumentation" },
+ { name = "opentelemetry-semantic-conventions" },
+ { name = "opentelemetry-util-http" },
+ { name = "wrapt" },
]
sdist = { url = "https://files.pythonhosted.org/packages/86/08/11208bcfcab4fc2023252c3f322aa397fd9ad948355fea60f5fc98648603/opentelemetry_instrumentation_httpx-0.60b1.tar.gz", hash = "sha256:a506ebaf28c60112cbe70ad4f0338f8603f148938cb7b6794ce1051cd2b270ae", size = 20611, upload-time = "2025-12-11T13:37:01.661Z" }
wheels = [
@@ -4087,7 +3328,7 @@ name = "opentelemetry-proto"
version = "1.39.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "protobuf", version = "6.33.5", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
+ { name = "protobuf" },
]
sdist = { url = "https://files.pythonhosted.org/packages/49/1d/f25d76d8260c156c40c97c9ed4511ec0f9ce353f8108ca6e7561f82a06b2/opentelemetry_proto-1.39.1.tar.gz", hash = "sha256:6c8e05144fc0d3ed4d22c2289c6b126e03bcd0e6a7da0f16cedd2e1c2772e2c8", size = 46152, upload-time = "2025-12-11T13:32:48.681Z" }
wheels = [
@@ -4099,9 +3340,9 @@ name = "opentelemetry-sdk"
version = "1.39.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "opentelemetry-api", marker = "python_full_version >= '3.10'" },
- { name = "opentelemetry-semantic-conventions", marker = "python_full_version >= '3.10'" },
- { name = "typing-extensions", marker = "python_full_version >= '3.10'" },
+ { name = "opentelemetry-api" },
+ { name = "opentelemetry-semantic-conventions" },
+ { name = "typing-extensions" },
]
sdist = { url = "https://files.pythonhosted.org/packages/eb/fb/c76080c9ba07e1e8235d24cdcc4d125ef7aa3edf23eb4e497c2e50889adc/opentelemetry_sdk-1.39.1.tar.gz", hash = "sha256:cf4d4563caf7bff906c9f7967e2be22d0d6b349b908be0d90fb21c8e9c995cc6", size = 171460, upload-time = "2025-12-11T13:32:49.369Z" }
wheels = [
@@ -4113,8 +3354,8 @@ name = "opentelemetry-semantic-conventions"
version = "0.60b1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "opentelemetry-api", marker = "python_full_version >= '3.10'" },
- { name = "typing-extensions", marker = "python_full_version >= '3.10'" },
+ { name = "opentelemetry-api" },
+ { name = "typing-extensions" },
]
sdist = { url = "https://files.pythonhosted.org/packages/91/df/553f93ed38bf22f4b999d9be9c185adb558982214f33eae539d3b5cd0858/opentelemetry_semantic_conventions-0.60b1.tar.gz", hash = "sha256:87c228b5a0669b748c76d76df6c364c369c28f1c465e50f661e39737e84bc953", size = 137935, upload-time = "2025-12-11T13:32:50.487Z" }
wheels = [
@@ -4130,111 +3371,10 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/16/5c/d3f1733665f7cd582ef0842fb1d2ed0bc1fba10875160593342d22bba375/opentelemetry_util_http-0.60b1-py3-none-any.whl", hash = "sha256:66381ba28550c91bee14dcba8979ace443444af1ed609226634596b4b0faf199", size = 8947, upload-time = "2025-12-11T13:36:37.151Z" },
]
-[[package]]
-name = "orjson"
-version = "3.11.5"
-source = { registry = "https://pypi.org/simple" }
-resolution-markers = [
- "python_full_version < '3.10'",
-]
-sdist = { url = "https://files.pythonhosted.org/packages/04/b8/333fdb27840f3bf04022d21b654a35f58e15407183aeb16f3b41aa053446/orjson-3.11.5.tar.gz", hash = "sha256:82393ab47b4fe44ffd0a7659fa9cfaacc717eb617c93cde83795f14af5c2e9d5", size = 5972347, upload-time = "2025-12-06T15:55:39.458Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/79/19/b22cf9dad4db20c8737041046054cbd4f38bb5a2d0e4bb60487832ce3d76/orjson-3.11.5-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:df9eadb2a6386d5ea2bfd81309c505e125cfc9ba2b1b99a97e60985b0b3665d1", size = 245719, upload-time = "2025-12-06T15:53:43.877Z" },
- { url = "https://files.pythonhosted.org/packages/03/2e/b136dd6bf30ef5143fbe76a4c142828b55ccc618be490201e9073ad954a1/orjson-3.11.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ccc70da619744467d8f1f49a8cadae5ec7bbe054e5232d95f92ed8737f8c5870", size = 132467, upload-time = "2025-12-06T15:53:45.379Z" },
- { url = "https://files.pythonhosted.org/packages/ae/fc/ae99bfc1e1887d20a0268f0e2686eb5b13d0ea7bbe01de2b566febcd2130/orjson-3.11.5-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:073aab025294c2f6fc0807201c76fdaed86f8fc4be52c440fb78fbb759a1ac09", size = 130702, upload-time = "2025-12-06T15:53:46.659Z" },
- { url = "https://files.pythonhosted.org/packages/6e/43/ef7912144097765997170aca59249725c3ab8ef6079f93f9d708dd058df5/orjson-3.11.5-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:835f26fa24ba0bb8c53ae2a9328d1706135b74ec653ed933869b74b6909e63fd", size = 135907, upload-time = "2025-12-06T15:53:48.487Z" },
- { url = "https://files.pythonhosted.org/packages/3f/da/24d50e2d7f4092ddd4d784e37a3fa41f22ce8ed97abc9edd222901a96e74/orjson-3.11.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:667c132f1f3651c14522a119e4dd631fad98761fa960c55e8e7430bb2a1ba4ac", size = 139935, upload-time = "2025-12-06T15:53:49.88Z" },
- { url = "https://files.pythonhosted.org/packages/02/4a/b4cb6fcbfff5b95a3a019a8648255a0fac9b221fbf6b6e72be8df2361feb/orjson-3.11.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:42e8961196af655bb5e63ce6c60d25e8798cd4dfbc04f4203457fa3869322c2e", size = 137541, upload-time = "2025-12-06T15:53:51.226Z" },
- { url = "https://files.pythonhosted.org/packages/a5/99/a11bd129f18c2377c27b2846a9d9be04acec981f770d711ba0aaea563984/orjson-3.11.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75412ca06e20904c19170f8a24486c4e6c7887dea591ba18a1ab572f1300ee9f", size = 139031, upload-time = "2025-12-06T15:53:52.309Z" },
- { url = "https://files.pythonhosted.org/packages/64/29/d7b77d7911574733a036bb3e8ad7053ceb2b7d6ea42208b9dbc55b23b9ed/orjson-3.11.5-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:6af8680328c69e15324b5af3ae38abbfcf9cbec37b5346ebfd52339c3d7e8a18", size = 141622, upload-time = "2025-12-06T15:53:53.606Z" },
- { url = "https://files.pythonhosted.org/packages/93/41/332db96c1de76b2feda4f453e91c27202cd092835936ce2b70828212f726/orjson-3.11.5-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:a86fe4ff4ea523eac8f4b57fdac319faf037d3c1be12405e6a7e86b3fbc4756a", size = 413800, upload-time = "2025-12-06T15:53:54.866Z" },
- { url = "https://files.pythonhosted.org/packages/76/e1/5a0d148dd1f89ad2f9651df67835b209ab7fcb1118658cf353425d7563e9/orjson-3.11.5-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e607b49b1a106ee2086633167033afbd63f76f2999e9236f638b06b112b24ea7", size = 151198, upload-time = "2025-12-06T15:53:56.383Z" },
- { url = "https://files.pythonhosted.org/packages/0d/96/8db67430d317a01ae5cf7971914f6775affdcfe99f5bff9ef3da32492ecc/orjson-3.11.5-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7339f41c244d0eea251637727f016b3d20050636695bc78345cce9029b189401", size = 141984, upload-time = "2025-12-06T15:53:57.746Z" },
- { url = "https://files.pythonhosted.org/packages/71/49/40d21e1aa1ac569e521069228bb29c9b5a350344ccf922a0227d93c2ed44/orjson-3.11.5-cp310-cp310-win32.whl", hash = "sha256:8be318da8413cdbbce77b8c5fac8d13f6eb0f0db41b30bb598631412619572e8", size = 135272, upload-time = "2025-12-06T15:53:59.769Z" },
- { url = "https://files.pythonhosted.org/packages/c4/7e/d0e31e78be0c100e08be64f48d2850b23bcb4d4c70d114f4e43b39f6895a/orjson-3.11.5-cp310-cp310-win_amd64.whl", hash = "sha256:b9f86d69ae822cabc2a0f6c099b43e8733dda788405cba2665595b7e8dd8d167", size = 133360, upload-time = "2025-12-06T15:54:01.25Z" },
- { url = "https://files.pythonhosted.org/packages/fd/68/6b3659daec3a81aed5ab47700adb1a577c76a5452d35b91c88efee89987f/orjson-3.11.5-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:9c8494625ad60a923af6b2b0bd74107146efe9b55099e20d7740d995f338fcd8", size = 245318, upload-time = "2025-12-06T15:54:02.355Z" },
- { url = "https://files.pythonhosted.org/packages/e9/00/92db122261425f61803ccf0830699ea5567439d966cbc35856fe711bfe6b/orjson-3.11.5-cp311-cp311-macosx_15_0_arm64.whl", hash = "sha256:7bb2ce0b82bc9fd1168a513ddae7a857994b780b2945a8c51db4ab1c4b751ebc", size = 129491, upload-time = "2025-12-06T15:54:03.877Z" },
- { url = "https://files.pythonhosted.org/packages/94/4f/ffdcb18356518809d944e1e1f77589845c278a1ebbb5a8297dfefcc4b4cb/orjson-3.11.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:67394d3becd50b954c4ecd24ac90b5051ee7c903d167459f93e77fc6f5b4c968", size = 132167, upload-time = "2025-12-06T15:54:04.944Z" },
- { url = "https://files.pythonhosted.org/packages/97/c6/0a8caff96f4503f4f7dd44e40e90f4d14acf80d3b7a97cb88747bb712d3e/orjson-3.11.5-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:298d2451f375e5f17b897794bcc3e7b821c0f32b4788b9bcae47ada24d7f3cf7", size = 130516, upload-time = "2025-12-06T15:54:06.274Z" },
- { url = "https://files.pythonhosted.org/packages/4d/63/43d4dc9bd9954bff7052f700fdb501067f6fb134a003ddcea2a0bb3854ed/orjson-3.11.5-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aa5e4244063db8e1d87e0f54c3f7522f14b2dc937e65d5241ef0076a096409fd", size = 135695, upload-time = "2025-12-06T15:54:07.702Z" },
- { url = "https://files.pythonhosted.org/packages/87/6f/27e2e76d110919cb7fcb72b26166ee676480a701bcf8fc53ac5d0edce32f/orjson-3.11.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1db2088b490761976c1b2e956d5d4e6409f3732e9d79cfa69f876c5248d1baf9", size = 139664, upload-time = "2025-12-06T15:54:08.828Z" },
- { url = "https://files.pythonhosted.org/packages/d4/f8/5966153a5f1be49b5fbb8ca619a529fde7bc71aa0a376f2bb83fed248bcd/orjson-3.11.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c2ed66358f32c24e10ceea518e16eb3549e34f33a9d51f99ce23b0251776a1ef", size = 137289, upload-time = "2025-12-06T15:54:09.898Z" },
- { url = "https://files.pythonhosted.org/packages/a7/34/8acb12ff0299385c8bbcbb19fbe40030f23f15a6de57a9c587ebf71483fb/orjson-3.11.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c2021afda46c1ed64d74b555065dbd4c2558d510d8cec5ea6a53001b3e5e82a9", size = 138784, upload-time = "2025-12-06T15:54:11.022Z" },
- { url = "https://files.pythonhosted.org/packages/ee/27/910421ea6e34a527f73d8f4ee7bdffa48357ff79c7b8d6eb6f7b82dd1176/orjson-3.11.5-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b42ffbed9128e547a1647a3e50bc88ab28ae9daa61713962e0d3dd35e820c125", size = 141322, upload-time = "2025-12-06T15:54:12.427Z" },
- { url = "https://files.pythonhosted.org/packages/87/a3/4b703edd1a05555d4bb1753d6ce44e1a05b7a6d7c164d5b332c795c63d70/orjson-3.11.5-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:8d5f16195bb671a5dd3d1dbea758918bada8f6cc27de72bd64adfbd748770814", size = 413612, upload-time = "2025-12-06T15:54:13.858Z" },
- { url = "https://files.pythonhosted.org/packages/1b/36/034177f11d7eeea16d3d2c42a1883b0373978e08bc9dad387f5074c786d8/orjson-3.11.5-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:c0e5d9f7a0227df2927d343a6e3859bebf9208b427c79bd31949abcc2fa32fa5", size = 150993, upload-time = "2025-12-06T15:54:15.189Z" },
- { url = "https://files.pythonhosted.org/packages/44/2f/ea8b24ee046a50a7d141c0227c4496b1180b215e728e3b640684f0ea448d/orjson-3.11.5-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:23d04c4543e78f724c4dfe656b3791b5f98e4c9253e13b2636f1af5d90e4a880", size = 141774, upload-time = "2025-12-06T15:54:16.451Z" },
- { url = "https://files.pythonhosted.org/packages/8a/12/cc440554bf8200eb23348a5744a575a342497b65261cd65ef3b28332510a/orjson-3.11.5-cp311-cp311-win32.whl", hash = "sha256:c404603df4865f8e0afe981aa3c4b62b406e6d06049564d58934860b62b7f91d", size = 135109, upload-time = "2025-12-06T15:54:17.73Z" },
- { url = "https://files.pythonhosted.org/packages/a3/83/e0c5aa06ba73a6760134b169f11fb970caa1525fa4461f94d76e692299d9/orjson-3.11.5-cp311-cp311-win_amd64.whl", hash = "sha256:9645ef655735a74da4990c24ffbd6894828fbfa117bc97c1edd98c282ecb52e1", size = 133193, upload-time = "2025-12-06T15:54:19.426Z" },
- { url = "https://files.pythonhosted.org/packages/cb/35/5b77eaebc60d735e832c5b1a20b155667645d123f09d471db0a78280fb49/orjson-3.11.5-cp311-cp311-win_arm64.whl", hash = "sha256:1cbf2735722623fcdee8e712cbaaab9e372bbcb0c7924ad711b261c2eccf4a5c", size = 126830, upload-time = "2025-12-06T15:54:20.836Z" },
- { url = "https://files.pythonhosted.org/packages/ef/a4/8052a029029b096a78955eadd68ab594ce2197e24ec50e6b6d2ab3f4e33b/orjson-3.11.5-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:334e5b4bff9ad101237c2d799d9fd45737752929753bf4faf4b207335a416b7d", size = 245347, upload-time = "2025-12-06T15:54:22.061Z" },
- { url = "https://files.pythonhosted.org/packages/64/67/574a7732bd9d9d79ac620c8790b4cfe0717a3d5a6eb2b539e6e8995e24a0/orjson-3.11.5-cp312-cp312-macosx_15_0_arm64.whl", hash = "sha256:ff770589960a86eae279f5d8aa536196ebda8273a2a07db2a54e82b93bc86626", size = 129435, upload-time = "2025-12-06T15:54:23.615Z" },
- { url = "https://files.pythonhosted.org/packages/52/8d/544e77d7a29d90cf4d9eecd0ae801c688e7f3d1adfa2ebae5e1e94d38ab9/orjson-3.11.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ed24250e55efbcb0b35bed7caaec8cedf858ab2f9f2201f17b8938c618c8ca6f", size = 132074, upload-time = "2025-12-06T15:54:24.694Z" },
- { url = "https://files.pythonhosted.org/packages/6e/57/b9f5b5b6fbff9c26f77e785baf56ae8460ef74acdb3eae4931c25b8f5ba9/orjson-3.11.5-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a66d7769e98a08a12a139049aac2f0ca3adae989817f8c43337455fbc7669b85", size = 130520, upload-time = "2025-12-06T15:54:26.185Z" },
- { url = "https://files.pythonhosted.org/packages/f6/6d/d34970bf9eb33f9ec7c979a262cad86076814859e54eb9a059a52f6dc13d/orjson-3.11.5-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:86cfc555bfd5794d24c6a1903e558b50644e5e68e6471d66502ce5cb5fdef3f9", size = 136209, upload-time = "2025-12-06T15:54:27.264Z" },
- { url = "https://files.pythonhosted.org/packages/e7/39/bc373b63cc0e117a105ea12e57280f83ae52fdee426890d57412432d63b3/orjson-3.11.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a230065027bc2a025e944f9d4714976a81e7ecfa940923283bca7bbc1f10f626", size = 139837, upload-time = "2025-12-06T15:54:28.75Z" },
- { url = "https://files.pythonhosted.org/packages/cb/aa/7c4818c8d7d324da220f4f1af55c343956003aa4d1ce1857bdc1d396ba69/orjson-3.11.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b29d36b60e606df01959c4b982729c8845c69d1963f88686608be9ced96dbfaa", size = 137307, upload-time = "2025-12-06T15:54:29.856Z" },
- { url = "https://files.pythonhosted.org/packages/46/bf/0993b5a056759ba65145effe3a79dd5a939d4a070eaa5da2ee3180fbb13f/orjson-3.11.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c74099c6b230d4261fdc3169d50efc09abf38ace1a42ea2f9994b1d79153d477", size = 139020, upload-time = "2025-12-06T15:54:31.024Z" },
- { url = "https://files.pythonhosted.org/packages/65/e8/83a6c95db3039e504eda60fc388f9faedbb4f6472f5aba7084e06552d9aa/orjson-3.11.5-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e697d06ad57dd0c7a737771d470eedc18e68dfdefcdd3b7de7f33dfda5b6212e", size = 141099, upload-time = "2025-12-06T15:54:32.196Z" },
- { url = "https://files.pythonhosted.org/packages/b9/b4/24fdc024abfce31c2f6812973b0a693688037ece5dc64b7a60c1ce69e2f2/orjson-3.11.5-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:e08ca8a6c851e95aaecc32bc44a5aa75d0ad26af8cdac7c77e4ed93acf3d5b69", size = 413540, upload-time = "2025-12-06T15:54:33.361Z" },
- { url = "https://files.pythonhosted.org/packages/d9/37/01c0ec95d55ed0c11e4cae3e10427e479bba40c77312b63e1f9665e0737d/orjson-3.11.5-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:e8b5f96c05fce7d0218df3fdfeb962d6b8cfff7e3e20264306b46dd8b217c0f3", size = 151530, upload-time = "2025-12-06T15:54:34.6Z" },
- { url = "https://files.pythonhosted.org/packages/f9/d4/f9ebc57182705bb4bbe63f5bbe14af43722a2533135e1d2fb7affa0c355d/orjson-3.11.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ddbfdb5099b3e6ba6d6ea818f61997bb66de14b411357d24c4612cf1ebad08ca", size = 141863, upload-time = "2025-12-06T15:54:35.801Z" },
- { url = "https://files.pythonhosted.org/packages/0d/04/02102b8d19fdcb009d72d622bb5781e8f3fae1646bf3e18c53d1bc8115b5/orjson-3.11.5-cp312-cp312-win32.whl", hash = "sha256:9172578c4eb09dbfcf1657d43198de59b6cef4054de385365060ed50c458ac98", size = 135255, upload-time = "2025-12-06T15:54:37.209Z" },
- { url = "https://files.pythonhosted.org/packages/d4/fb/f05646c43d5450492cb387de5549f6de90a71001682c17882d9f66476af5/orjson-3.11.5-cp312-cp312-win_amd64.whl", hash = "sha256:2b91126e7b470ff2e75746f6f6ee32b9ab67b7a93c8ba1d15d3a0caaf16ec875", size = 133252, upload-time = "2025-12-06T15:54:38.401Z" },
- { url = "https://files.pythonhosted.org/packages/dc/a6/7b8c0b26ba18c793533ac1cd145e131e46fcf43952aa94c109b5b913c1f0/orjson-3.11.5-cp312-cp312-win_arm64.whl", hash = "sha256:acbc5fac7e06777555b0722b8ad5f574739e99ffe99467ed63da98f97f9ca0fe", size = 126777, upload-time = "2025-12-06T15:54:39.515Z" },
- { url = "https://files.pythonhosted.org/packages/10/43/61a77040ce59f1569edf38f0b9faadc90c8cf7e9bec2e0df51d0132c6bb7/orjson-3.11.5-cp313-cp313-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:3b01799262081a4c47c035dd77c1301d40f568f77cc7ec1bb7db5d63b0a01629", size = 245271, upload-time = "2025-12-06T15:54:40.878Z" },
- { url = "https://files.pythonhosted.org/packages/55/f9/0f79be617388227866d50edd2fd320cb8fb94dc1501184bb1620981a0aba/orjson-3.11.5-cp313-cp313-macosx_15_0_arm64.whl", hash = "sha256:61de247948108484779f57a9f406e4c84d636fa5a59e411e6352484985e8a7c3", size = 129422, upload-time = "2025-12-06T15:54:42.403Z" },
- { url = "https://files.pythonhosted.org/packages/77/42/f1bf1549b432d4a78bfa95735b79b5dac75b65b5bb815bba86ad406ead0a/orjson-3.11.5-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:894aea2e63d4f24a7f04a1908307c738d0dce992e9249e744b8f4e8dd9197f39", size = 132060, upload-time = "2025-12-06T15:54:43.531Z" },
- { url = "https://files.pythonhosted.org/packages/25/49/825aa6b929f1a6ed244c78acd7b22c1481fd7e5fda047dc8bf4c1a807eb6/orjson-3.11.5-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ddc21521598dbe369d83d4d40338e23d4101dad21dae0e79fa20465dbace019f", size = 130391, upload-time = "2025-12-06T15:54:45.059Z" },
- { url = "https://files.pythonhosted.org/packages/42/ec/de55391858b49e16e1aa8f0bbbb7e5997b7345d8e984a2dec3746d13065b/orjson-3.11.5-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7cce16ae2f5fb2c53c3eafdd1706cb7b6530a67cc1c17abe8ec747f5cd7c0c51", size = 135964, upload-time = "2025-12-06T15:54:46.576Z" },
- { url = "https://files.pythonhosted.org/packages/1c/40/820bc63121d2d28818556a2d0a09384a9f0262407cf9fa305e091a8048df/orjson-3.11.5-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e46c762d9f0e1cfb4ccc8515de7f349abbc95b59cb5a2bd68df5973fdef913f8", size = 139817, upload-time = "2025-12-06T15:54:48.084Z" },
- { url = "https://files.pythonhosted.org/packages/09/c7/3a445ca9a84a0d59d26365fd8898ff52bdfcdcb825bcc6519830371d2364/orjson-3.11.5-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d7345c759276b798ccd6d77a87136029e71e66a8bbf2d2755cbdde1d82e78706", size = 137336, upload-time = "2025-12-06T15:54:49.426Z" },
- { url = "https://files.pythonhosted.org/packages/9a/b3/dc0d3771f2e5d1f13368f56b339c6782f955c6a20b50465a91acb79fe961/orjson-3.11.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75bc2e59e6a2ac1dd28901d07115abdebc4563b5b07dd612bf64260a201b1c7f", size = 138993, upload-time = "2025-12-06T15:54:50.939Z" },
- { url = "https://files.pythonhosted.org/packages/d1/a2/65267e959de6abe23444659b6e19c888f242bf7725ff927e2292776f6b89/orjson-3.11.5-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:54aae9b654554c3b4edd61896b978568c6daa16af96fa4681c9b5babd469f863", size = 141070, upload-time = "2025-12-06T15:54:52.414Z" },
- { url = "https://files.pythonhosted.org/packages/63/c9/da44a321b288727a322c6ab17e1754195708786a04f4f9d2220a5076a649/orjson-3.11.5-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:4bdd8d164a871c4ec773f9de0f6fe8769c2d6727879c37a9666ba4183b7f8228", size = 413505, upload-time = "2025-12-06T15:54:53.67Z" },
- { url = "https://files.pythonhosted.org/packages/7f/17/68dc14fa7000eefb3d4d6d7326a190c99bb65e319f02747ef3ebf2452f12/orjson-3.11.5-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:a261fef929bcf98a60713bf5e95ad067cea16ae345d9a35034e73c3990e927d2", size = 151342, upload-time = "2025-12-06T15:54:55.113Z" },
- { url = "https://files.pythonhosted.org/packages/c4/c5/ccee774b67225bed630a57478529fc026eda33d94fe4c0eac8fe58d4aa52/orjson-3.11.5-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:c028a394c766693c5c9909dec76b24f37e6a1b91999e8d0c0d5feecbe93c3e05", size = 141823, upload-time = "2025-12-06T15:54:56.331Z" },
- { url = "https://files.pythonhosted.org/packages/67/80/5d00e4155d0cd7390ae2087130637671da713959bb558db9bac5e6f6b042/orjson-3.11.5-cp313-cp313-win32.whl", hash = "sha256:2cc79aaad1dfabe1bd2d50ee09814a1253164b3da4c00a78c458d82d04b3bdef", size = 135236, upload-time = "2025-12-06T15:54:57.507Z" },
- { url = "https://files.pythonhosted.org/packages/95/fe/792cc06a84808dbdc20ac6eab6811c53091b42f8e51ecebf14b540e9cfe4/orjson-3.11.5-cp313-cp313-win_amd64.whl", hash = "sha256:ff7877d376add4e16b274e35a3f58b7f37b362abf4aa31863dadacdd20e3a583", size = 133167, upload-time = "2025-12-06T15:54:58.71Z" },
- { url = "https://files.pythonhosted.org/packages/46/2c/d158bd8b50e3b1cfdcf406a7e463f6ffe3f0d167b99634717acdaf5e299f/orjson-3.11.5-cp313-cp313-win_arm64.whl", hash = "sha256:59ac72ea775c88b163ba8d21b0177628bd015c5dd060647bbab6e22da3aad287", size = 126712, upload-time = "2025-12-06T15:54:59.892Z" },
- { url = "https://files.pythonhosted.org/packages/c2/60/77d7b839e317ead7bb225d55bb50f7ea75f47afc489c81199befc5435b50/orjson-3.11.5-cp314-cp314-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:e446a8ea0a4c366ceafc7d97067bfd55292969143b57e3c846d87fc701e797a0", size = 245252, upload-time = "2025-12-06T15:55:01.127Z" },
- { url = "https://files.pythonhosted.org/packages/f1/aa/d4639163b400f8044cef0fb9aa51b0337be0da3a27187a20d1166e742370/orjson-3.11.5-cp314-cp314-macosx_15_0_arm64.whl", hash = "sha256:53deb5addae9c22bbe3739298f5f2196afa881ea75944e7720681c7080909a81", size = 129419, upload-time = "2025-12-06T15:55:02.723Z" },
- { url = "https://files.pythonhosted.org/packages/30/94/9eabf94f2e11c671111139edf5ec410d2f21e6feee717804f7e8872d883f/orjson-3.11.5-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:82cd00d49d6063d2b8791da5d4f9d20539c5951f965e45ccf4e96d33505ce68f", size = 132050, upload-time = "2025-12-06T15:55:03.918Z" },
- { url = "https://files.pythonhosted.org/packages/3d/c8/ca10f5c5322f341ea9a9f1097e140be17a88f88d1cfdd29df522970d9744/orjson-3.11.5-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3fd15f9fc8c203aeceff4fda211157fad114dde66e92e24097b3647a08f4ee9e", size = 130370, upload-time = "2025-12-06T15:55:05.173Z" },
- { url = "https://files.pythonhosted.org/packages/25/d4/e96824476d361ee2edd5c6290ceb8d7edf88d81148a6ce172fc00278ca7f/orjson-3.11.5-cp314-cp314-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9df95000fbe6777bf9820ae82ab7578e8662051bb5f83d71a28992f539d2cda7", size = 136012, upload-time = "2025-12-06T15:55:06.402Z" },
- { url = "https://files.pythonhosted.org/packages/85/8e/9bc3423308c425c588903f2d103cfcfe2539e07a25d6522900645a6f257f/orjson-3.11.5-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:92a8d676748fca47ade5bc3da7430ed7767afe51b2f8100e3cd65e151c0eaceb", size = 139809, upload-time = "2025-12-06T15:55:07.656Z" },
- { url = "https://files.pythonhosted.org/packages/e9/3c/b404e94e0b02a232b957c54643ce68d0268dacb67ac33ffdee24008c8b27/orjson-3.11.5-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:aa0f513be38b40234c77975e68805506cad5d57b3dfd8fe3baa7f4f4051e15b4", size = 137332, upload-time = "2025-12-06T15:55:08.961Z" },
- { url = "https://files.pythonhosted.org/packages/51/30/cc2d69d5ce0ad9b84811cdf4a0cd5362ac27205a921da524ff42f26d65e0/orjson-3.11.5-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa1863e75b92891f553b7922ce4ee10ed06db061e104f2b7815de80cdcb135ad", size = 138983, upload-time = "2025-12-06T15:55:10.595Z" },
- { url = "https://files.pythonhosted.org/packages/0e/87/de3223944a3e297d4707d2fe3b1ffb71437550e165eaf0ca8bbe43ccbcb1/orjson-3.11.5-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:d4be86b58e9ea262617b8ca6251a2f0d63cc132a6da4b5fcc8e0a4128782c829", size = 141069, upload-time = "2025-12-06T15:55:11.832Z" },
- { url = "https://files.pythonhosted.org/packages/65/30/81d5087ae74be33bcae3ff2d80f5ccaa4a8fedc6d39bf65a427a95b8977f/orjson-3.11.5-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:b923c1c13fa02084eb38c9c065afd860a5cff58026813319a06949c3af5732ac", size = 413491, upload-time = "2025-12-06T15:55:13.314Z" },
- { url = "https://files.pythonhosted.org/packages/d0/6f/f6058c21e2fc1efaf918986dbc2da5cd38044f1a2d4b7b91ad17c4acf786/orjson-3.11.5-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:1b6bd351202b2cd987f35a13b5e16471cf4d952b42a73c391cc537974c43ef6d", size = 151375, upload-time = "2025-12-06T15:55:14.715Z" },
- { url = "https://files.pythonhosted.org/packages/54/92/c6921f17d45e110892899a7a563a925b2273d929959ce2ad89e2525b885b/orjson-3.11.5-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:bb150d529637d541e6af06bbe3d02f5498d628b7f98267ff87647584293ab439", size = 141850, upload-time = "2025-12-06T15:55:15.94Z" },
- { url = "https://files.pythonhosted.org/packages/88/86/cdecb0140a05e1a477b81f24739da93b25070ee01ce7f7242f44a6437594/orjson-3.11.5-cp314-cp314-win32.whl", hash = "sha256:9cc1e55c884921434a84a0c3dd2699eb9f92e7b441d7f53f3941079ec6ce7499", size = 135278, upload-time = "2025-12-06T15:55:17.202Z" },
- { url = "https://files.pythonhosted.org/packages/e4/97/b638d69b1e947d24f6109216997e38922d54dcdcdb1b11c18d7efd2d3c59/orjson-3.11.5-cp314-cp314-win_amd64.whl", hash = "sha256:a4f3cb2d874e03bc7767c8f88adaa1a9a05cecea3712649c3b58589ec7317310", size = 133170, upload-time = "2025-12-06T15:55:18.468Z" },
- { url = "https://files.pythonhosted.org/packages/8f/dd/f4fff4a6fe601b4f8f3ba3aa6da8ac33d17d124491a3b804c662a70e1636/orjson-3.11.5-cp314-cp314-win_arm64.whl", hash = "sha256:38b22f476c351f9a1c43e5b07d8b5a02eb24a6ab8e75f700f7d479d4568346a5", size = 126713, upload-time = "2025-12-06T15:55:19.738Z" },
- { url = "https://files.pythonhosted.org/packages/50/c7/7b682849dd4c9fb701a981669b964ea700516ecbd8e88f62aae07c6852bd/orjson-3.11.5-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:1b280e2d2d284a6713b0cfec7b08918ebe57df23e3f76b27586197afca3cb1e9", size = 245298, upload-time = "2025-12-06T15:55:20.984Z" },
- { url = "https://files.pythonhosted.org/packages/1b/3f/194355a9335707a15fdc79ddc670148987b43d04712dd26898a694539ce6/orjson-3.11.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3c8d8a112b274fae8c5f0f01954cb0480137072c271f3f4958127b010dfefaec", size = 132150, upload-time = "2025-12-06T15:55:22.364Z" },
- { url = "https://files.pythonhosted.org/packages/e9/08/d74b3a986d37e6c2e04b8821c62927620c9a1924bb49ea51519a87751b86/orjson-3.11.5-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5f0a2ae6f09ac7bd47d2d5a5305c1d9ed08ac057cda55bb0a49fa506f0d2da00", size = 130490, upload-time = "2025-12-06T15:55:23.619Z" },
- { url = "https://files.pythonhosted.org/packages/b2/16/ebd04c38c1db01e493a68eee442efdffc505a43112eccd481e0146c6acc2/orjson-3.11.5-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c0d87bd1896faac0d10b4f849016db81a63e4ec5df38757ffae84d45ab38aa71", size = 135726, upload-time = "2025-12-06T15:55:24.912Z" },
- { url = "https://files.pythonhosted.org/packages/06/64/2ce4b2c09a099403081c37639c224bdcdfe401138bd66fed5c96d4f8dbd3/orjson-3.11.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:801a821e8e6099b8c459ac7540b3c32dba6013437c57fdcaec205b169754f38c", size = 139640, upload-time = "2025-12-06T15:55:26.535Z" },
- { url = "https://files.pythonhosted.org/packages/cd/e2/425796df8ee1d7cea3a7edf868920121dd09162859dbb76fffc9a5c37fd3/orjson-3.11.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:69a0f6ac618c98c74b7fbc8c0172ba86f9e01dbf9f62aa0b1776c2231a7bffe5", size = 137289, upload-time = "2025-12-06T15:55:27.78Z" },
- { url = "https://files.pythonhosted.org/packages/32/a2/88e482eb8e899a037dcc9eff85ef117a568e6ca1ffa1a2b2be3fcb51b7bb/orjson-3.11.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fea7339bdd22e6f1060c55ac31b6a755d86a5b2ad3657f2669ec243f8e3b2bdb", size = 138761, upload-time = "2025-12-06T15:55:29.388Z" },
- { url = "https://files.pythonhosted.org/packages/f1/fd/131dd6d32eeb74c513bfa487f434a2150811d0fbd9cb06689284f2f21b34/orjson-3.11.5-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:4dad582bc93cef8f26513e12771e76385a7e6187fd713157e971c784112aad56", size = 141357, upload-time = "2025-12-06T15:55:31.064Z" },
- { url = "https://files.pythonhosted.org/packages/7a/90/e4a0abbcca7b53e9098ac854f27f5ed9949c796f3c760bc04af997da0eb2/orjson-3.11.5-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:0522003e9f7fba91982e83a97fec0708f5a714c96c4209db7104e6b9d132f111", size = 413638, upload-time = "2025-12-06T15:55:32.344Z" },
- { url = "https://files.pythonhosted.org/packages/d1/c2/df91e385514924120001ade9cd52d6295251023d3bfa2c0a01f38cfc485a/orjson-3.11.5-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:7403851e430a478440ecc1258bcbacbfbd8175f9ac1e39031a7121dd0de05ff8", size = 150972, upload-time = "2025-12-06T15:55:33.725Z" },
- { url = "https://files.pythonhosted.org/packages/a6/ff/c76cc5a30a4451191ff1b868a331ad1354433335277fc40931f5fc3cab9d/orjson-3.11.5-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:5f691263425d3177977c8d1dd896cde7b98d93cbf390b2544a090675e83a6a0a", size = 141729, upload-time = "2025-12-06T15:55:35.317Z" },
- { url = "https://files.pythonhosted.org/packages/27/c3/7830bf74389ea1eaab2b017d8b15d1cab2bb0737d9412dfa7fb8644f7d78/orjson-3.11.5-cp39-cp39-win32.whl", hash = "sha256:61026196a1c4b968e1b1e540563e277843082e9e97d78afa03eb89315af531f1", size = 135100, upload-time = "2025-12-06T15:55:36.57Z" },
- { url = "https://files.pythonhosted.org/packages/69/e6/babf31154e047e465bc194eb72d1326d7c52ad4d7f50bf92b02b3cacda5c/orjson-3.11.5-cp39-cp39-win_amd64.whl", hash = "sha256:09b94b947ac08586af635ef922d69dc9bc63321527a3a04647f4986a73f4bd30", size = 133189, upload-time = "2025-12-06T15:55:38.143Z" },
-]
-
[[package]]
name = "orjson"
version = "3.11.7"
source = { registry = "https://pypi.org/simple" }
-resolution-markers = [
- "python_full_version >= '3.14'",
- "python_full_version >= '3.10' and python_full_version < '3.14'",
-]
sdist = { url = "https://files.pythonhosted.org/packages/53/45/b268004f745ede84e5798b48ee12b05129d19235d0e15267aa57dcdb400b/orjson-3.11.7.tar.gz", hash = "sha256:9b1a67243945819ce55d24a30b59d6a168e86220452d2c96f4d1f093e71c0c49", size = 6144992, upload-time = "2026-02-02T15:38:49.29Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/de/1a/a373746fa6d0e116dd9e54371a7b54622c44d12296d5d0f3ad5e3ff33490/orjson-3.11.7-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:a02c833f38f36546ba65a452127633afce4cf0dd7296b753d3bb54e55e5c0174", size = 229140, upload-time = "2026-02-02T15:37:06.082Z" },
@@ -4371,242 +3511,106 @@ wheels = [
[[package]]
name = "pillow"
-version = "11.3.0"
-source = { registry = "https://pypi.org/simple" }
-resolution-markers = [
- "python_full_version < '3.10'",
-]
-sdist = { url = "https://files.pythonhosted.org/packages/f3/0d/d0d6dea55cd152ce3d6767bb38a8fc10e33796ba4ba210cbab9354b6d238/pillow-11.3.0.tar.gz", hash = "sha256:3828ee7586cd0b2091b6209e5ad53e20d0649bbe87164a459d0676e035e8f523", size = 47113069, upload-time = "2025-07-01T09:16:30.666Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/4c/5d/45a3553a253ac8763f3561371432a90bdbe6000fbdcf1397ffe502aa206c/pillow-11.3.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:1b9c17fd4ace828b3003dfd1e30bff24863e0eb59b535e8f80194d9cc7ecf860", size = 5316554, upload-time = "2025-07-01T09:13:39.342Z" },
- { url = "https://files.pythonhosted.org/packages/7c/c8/67c12ab069ef586a25a4a79ced553586748fad100c77c0ce59bb4983ac98/pillow-11.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:65dc69160114cdd0ca0f35cb434633c75e8e7fad4cf855177a05bf38678f73ad", size = 4686548, upload-time = "2025-07-01T09:13:41.835Z" },
- { url = "https://files.pythonhosted.org/packages/2f/bd/6741ebd56263390b382ae4c5de02979af7f8bd9807346d068700dd6d5cf9/pillow-11.3.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7107195ddc914f656c7fc8e4a5e1c25f32e9236ea3ea860f257b0436011fddd0", size = 5859742, upload-time = "2025-07-03T13:09:47.439Z" },
- { url = "https://files.pythonhosted.org/packages/ca/0b/c412a9e27e1e6a829e6ab6c2dca52dd563efbedf4c9c6aa453d9a9b77359/pillow-11.3.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:cc3e831b563b3114baac7ec2ee86819eb03caa1a2cef0b481a5675b59c4fe23b", size = 7633087, upload-time = "2025-07-03T13:09:51.796Z" },
- { url = "https://files.pythonhosted.org/packages/59/9d/9b7076aaf30f5dd17e5e5589b2d2f5a5d7e30ff67a171eb686e4eecc2adf/pillow-11.3.0-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f1f182ebd2303acf8c380a54f615ec883322593320a9b00438eb842c1f37ae50", size = 5963350, upload-time = "2025-07-01T09:13:43.865Z" },
- { url = "https://files.pythonhosted.org/packages/f0/16/1a6bf01fb622fb9cf5c91683823f073f053005c849b1f52ed613afcf8dae/pillow-11.3.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4445fa62e15936a028672fd48c4c11a66d641d2c05726c7ec1f8ba6a572036ae", size = 6631840, upload-time = "2025-07-01T09:13:46.161Z" },
- { url = "https://files.pythonhosted.org/packages/7b/e6/6ff7077077eb47fde78739e7d570bdcd7c10495666b6afcd23ab56b19a43/pillow-11.3.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:71f511f6b3b91dd543282477be45a033e4845a40278fa8dcdbfdb07109bf18f9", size = 6074005, upload-time = "2025-07-01T09:13:47.829Z" },
- { url = "https://files.pythonhosted.org/packages/c3/3a/b13f36832ea6d279a697231658199e0a03cd87ef12048016bdcc84131601/pillow-11.3.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:040a5b691b0713e1f6cbe222e0f4f74cd233421e105850ae3b3c0ceda520f42e", size = 6708372, upload-time = "2025-07-01T09:13:52.145Z" },
- { url = "https://files.pythonhosted.org/packages/6c/e4/61b2e1a7528740efbc70b3d581f33937e38e98ef3d50b05007267a55bcb2/pillow-11.3.0-cp310-cp310-win32.whl", hash = "sha256:89bd777bc6624fe4115e9fac3352c79ed60f3bb18651420635f26e643e3dd1f6", size = 6277090, upload-time = "2025-07-01T09:13:53.915Z" },
- { url = "https://files.pythonhosted.org/packages/a9/d3/60c781c83a785d6afbd6a326ed4d759d141de43aa7365725cbcd65ce5e54/pillow-11.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:19d2ff547c75b8e3ff46f4d9ef969a06c30ab2d4263a9e287733aa8b2429ce8f", size = 6985988, upload-time = "2025-07-01T09:13:55.699Z" },
- { url = "https://files.pythonhosted.org/packages/9f/28/4f4a0203165eefb3763939c6789ba31013a2e90adffb456610f30f613850/pillow-11.3.0-cp310-cp310-win_arm64.whl", hash = "sha256:819931d25e57b513242859ce1876c58c59dc31587847bf74cfe06b2e0cb22d2f", size = 2422899, upload-time = "2025-07-01T09:13:57.497Z" },
- { url = "https://files.pythonhosted.org/packages/db/26/77f8ed17ca4ffd60e1dcd220a6ec6d71210ba398cfa33a13a1cd614c5613/pillow-11.3.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:1cd110edf822773368b396281a2293aeb91c90a2db00d78ea43e7e861631b722", size = 5316531, upload-time = "2025-07-01T09:13:59.203Z" },
- { url = "https://files.pythonhosted.org/packages/cb/39/ee475903197ce709322a17a866892efb560f57900d9af2e55f86db51b0a5/pillow-11.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9c412fddd1b77a75aa904615ebaa6001f169b26fd467b4be93aded278266b288", size = 4686560, upload-time = "2025-07-01T09:14:01.101Z" },
- { url = "https://files.pythonhosted.org/packages/d5/90/442068a160fd179938ba55ec8c97050a612426fae5ec0a764e345839f76d/pillow-11.3.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7d1aa4de119a0ecac0a34a9c8bde33f34022e2e8f99104e47a3ca392fd60e37d", size = 5870978, upload-time = "2025-07-03T13:09:55.638Z" },
- { url = "https://files.pythonhosted.org/packages/13/92/dcdd147ab02daf405387f0218dcf792dc6dd5b14d2573d40b4caeef01059/pillow-11.3.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:91da1d88226663594e3f6b4b8c3c8d85bd504117d043740a8e0ec449087cc494", size = 7641168, upload-time = "2025-07-03T13:10:00.37Z" },
- { url = "https://files.pythonhosted.org/packages/6e/db/839d6ba7fd38b51af641aa904e2960e7a5644d60ec754c046b7d2aee00e5/pillow-11.3.0-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:643f189248837533073c405ec2f0bb250ba54598cf80e8c1e043381a60632f58", size = 5973053, upload-time = "2025-07-01T09:14:04.491Z" },
- { url = "https://files.pythonhosted.org/packages/f2/2f/d7675ecae6c43e9f12aa8d58b6012683b20b6edfbdac7abcb4e6af7a3784/pillow-11.3.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:106064daa23a745510dabce1d84f29137a37224831d88eb4ce94bb187b1d7e5f", size = 6640273, upload-time = "2025-07-01T09:14:06.235Z" },
- { url = "https://files.pythonhosted.org/packages/45/ad/931694675ede172e15b2ff03c8144a0ddaea1d87adb72bb07655eaffb654/pillow-11.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:cd8ff254faf15591e724dc7c4ddb6bf4793efcbe13802a4ae3e863cd300b493e", size = 6082043, upload-time = "2025-07-01T09:14:07.978Z" },
- { url = "https://files.pythonhosted.org/packages/3a/04/ba8f2b11fc80d2dd462d7abec16351b45ec99cbbaea4387648a44190351a/pillow-11.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:932c754c2d51ad2b2271fd01c3d121daaa35e27efae2a616f77bf164bc0b3e94", size = 6715516, upload-time = "2025-07-01T09:14:10.233Z" },
- { url = "https://files.pythonhosted.org/packages/48/59/8cd06d7f3944cc7d892e8533c56b0acb68399f640786313275faec1e3b6f/pillow-11.3.0-cp311-cp311-win32.whl", hash = "sha256:b4b8f3efc8d530a1544e5962bd6b403d5f7fe8b9e08227c6b255f98ad82b4ba0", size = 6274768, upload-time = "2025-07-01T09:14:11.921Z" },
- { url = "https://files.pythonhosted.org/packages/f1/cc/29c0f5d64ab8eae20f3232da8f8571660aa0ab4b8f1331da5c2f5f9a938e/pillow-11.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:1a992e86b0dd7aeb1f053cd506508c0999d710a8f07b4c791c63843fc6a807ac", size = 6986055, upload-time = "2025-07-01T09:14:13.623Z" },
- { url = "https://files.pythonhosted.org/packages/c6/df/90bd886fabd544c25addd63e5ca6932c86f2b701d5da6c7839387a076b4a/pillow-11.3.0-cp311-cp311-win_arm64.whl", hash = "sha256:30807c931ff7c095620fe04448e2c2fc673fcbb1ffe2a7da3fb39613489b1ddd", size = 2423079, upload-time = "2025-07-01T09:14:15.268Z" },
- { url = "https://files.pythonhosted.org/packages/40/fe/1bc9b3ee13f68487a99ac9529968035cca2f0a51ec36892060edcc51d06a/pillow-11.3.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fdae223722da47b024b867c1ea0be64e0df702c5e0a60e27daad39bf960dd1e4", size = 5278800, upload-time = "2025-07-01T09:14:17.648Z" },
- { url = "https://files.pythonhosted.org/packages/2c/32/7e2ac19b5713657384cec55f89065fb306b06af008cfd87e572035b27119/pillow-11.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:921bd305b10e82b4d1f5e802b6850677f965d8394203d182f078873851dada69", size = 4686296, upload-time = "2025-07-01T09:14:19.828Z" },
- { url = "https://files.pythonhosted.org/packages/8e/1e/b9e12bbe6e4c2220effebc09ea0923a07a6da1e1f1bfbc8d7d29a01ce32b/pillow-11.3.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:eb76541cba2f958032d79d143b98a3a6b3ea87f0959bbe256c0b5e416599fd5d", size = 5871726, upload-time = "2025-07-03T13:10:04.448Z" },
- { url = "https://files.pythonhosted.org/packages/8d/33/e9200d2bd7ba00dc3ddb78df1198a6e80d7669cce6c2bdbeb2530a74ec58/pillow-11.3.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:67172f2944ebba3d4a7b54f2e95c786a3a50c21b88456329314caaa28cda70f6", size = 7644652, upload-time = "2025-07-03T13:10:10.391Z" },
- { url = "https://files.pythonhosted.org/packages/41/f1/6f2427a26fc683e00d985bc391bdd76d8dd4e92fac33d841127eb8fb2313/pillow-11.3.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:97f07ed9f56a3b9b5f49d3661dc9607484e85c67e27f3e8be2c7d28ca032fec7", size = 5977787, upload-time = "2025-07-01T09:14:21.63Z" },
- { url = "https://files.pythonhosted.org/packages/e4/c9/06dd4a38974e24f932ff5f98ea3c546ce3f8c995d3f0985f8e5ba48bba19/pillow-11.3.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:676b2815362456b5b3216b4fd5bd89d362100dc6f4945154ff172e206a22c024", size = 6645236, upload-time = "2025-07-01T09:14:23.321Z" },
- { url = "https://files.pythonhosted.org/packages/40/e7/848f69fb79843b3d91241bad658e9c14f39a32f71a301bcd1d139416d1be/pillow-11.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3e184b2f26ff146363dd07bde8b711833d7b0202e27d13540bfe2e35a323a809", size = 6086950, upload-time = "2025-07-01T09:14:25.237Z" },
- { url = "https://files.pythonhosted.org/packages/0b/1a/7cff92e695a2a29ac1958c2a0fe4c0b2393b60aac13b04a4fe2735cad52d/pillow-11.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6be31e3fc9a621e071bc17bb7de63b85cbe0bfae91bb0363c893cbe67247780d", size = 6723358, upload-time = "2025-07-01T09:14:27.053Z" },
- { url = "https://files.pythonhosted.org/packages/26/7d/73699ad77895f69edff76b0f332acc3d497f22f5d75e5360f78cbcaff248/pillow-11.3.0-cp312-cp312-win32.whl", hash = "sha256:7b161756381f0918e05e7cb8a371fff367e807770f8fe92ecb20d905d0e1c149", size = 6275079, upload-time = "2025-07-01T09:14:30.104Z" },
- { url = "https://files.pythonhosted.org/packages/8c/ce/e7dfc873bdd9828f3b6e5c2bbb74e47a98ec23cc5c74fc4e54462f0d9204/pillow-11.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:a6444696fce635783440b7f7a9fc24b3ad10a9ea3f0ab66c5905be1c19ccf17d", size = 6986324, upload-time = "2025-07-01T09:14:31.899Z" },
- { url = "https://files.pythonhosted.org/packages/16/8f/b13447d1bf0b1f7467ce7d86f6e6edf66c0ad7cf44cf5c87a37f9bed9936/pillow-11.3.0-cp312-cp312-win_arm64.whl", hash = "sha256:2aceea54f957dd4448264f9bf40875da0415c83eb85f55069d89c0ed436e3542", size = 2423067, upload-time = "2025-07-01T09:14:33.709Z" },
- { url = "https://files.pythonhosted.org/packages/1e/93/0952f2ed8db3a5a4c7a11f91965d6184ebc8cd7cbb7941a260d5f018cd2d/pillow-11.3.0-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:1c627742b539bba4309df89171356fcb3cc5a9178355b2727d1b74a6cf155fbd", size = 2128328, upload-time = "2025-07-01T09:14:35.276Z" },
- { url = "https://files.pythonhosted.org/packages/4b/e8/100c3d114b1a0bf4042f27e0f87d2f25e857e838034e98ca98fe7b8c0a9c/pillow-11.3.0-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:30b7c02f3899d10f13d7a48163c8969e4e653f8b43416d23d13d1bbfdc93b9f8", size = 2170652, upload-time = "2025-07-01T09:14:37.203Z" },
- { url = "https://files.pythonhosted.org/packages/aa/86/3f758a28a6e381758545f7cdb4942e1cb79abd271bea932998fc0db93cb6/pillow-11.3.0-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:7859a4cc7c9295f5838015d8cc0a9c215b77e43d07a25e460f35cf516df8626f", size = 2227443, upload-time = "2025-07-01T09:14:39.344Z" },
- { url = "https://files.pythonhosted.org/packages/01/f4/91d5b3ffa718df2f53b0dc109877993e511f4fd055d7e9508682e8aba092/pillow-11.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ec1ee50470b0d050984394423d96325b744d55c701a439d2bd66089bff963d3c", size = 5278474, upload-time = "2025-07-01T09:14:41.843Z" },
- { url = "https://files.pythonhosted.org/packages/f9/0e/37d7d3eca6c879fbd9dba21268427dffda1ab00d4eb05b32923d4fbe3b12/pillow-11.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7db51d222548ccfd274e4572fdbf3e810a5e66b00608862f947b163e613b67dd", size = 4686038, upload-time = "2025-07-01T09:14:44.008Z" },
- { url = "https://files.pythonhosted.org/packages/ff/b0/3426e5c7f6565e752d81221af9d3676fdbb4f352317ceafd42899aaf5d8a/pillow-11.3.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:2d6fcc902a24ac74495df63faad1884282239265c6839a0a6416d33faedfae7e", size = 5864407, upload-time = "2025-07-03T13:10:15.628Z" },
- { url = "https://files.pythonhosted.org/packages/fc/c1/c6c423134229f2a221ee53f838d4be9d82bab86f7e2f8e75e47b6bf6cd77/pillow-11.3.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f0f5d8f4a08090c6d6d578351a2b91acf519a54986c055af27e7a93feae6d3f1", size = 7639094, upload-time = "2025-07-03T13:10:21.857Z" },
- { url = "https://files.pythonhosted.org/packages/ba/c9/09e6746630fe6372c67c648ff9deae52a2bc20897d51fa293571977ceb5d/pillow-11.3.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c37d8ba9411d6003bba9e518db0db0c58a680ab9fe5179f040b0463644bc9805", size = 5973503, upload-time = "2025-07-01T09:14:45.698Z" },
- { url = "https://files.pythonhosted.org/packages/d5/1c/a2a29649c0b1983d3ef57ee87a66487fdeb45132df66ab30dd37f7dbe162/pillow-11.3.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:13f87d581e71d9189ab21fe0efb5a23e9f28552d5be6979e84001d3b8505abe8", size = 6642574, upload-time = "2025-07-01T09:14:47.415Z" },
- { url = "https://files.pythonhosted.org/packages/36/de/d5cc31cc4b055b6c6fd990e3e7f0f8aaf36229a2698501bcb0cdf67c7146/pillow-11.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:023f6d2d11784a465f09fd09a34b150ea4672e85fb3d05931d89f373ab14abb2", size = 6084060, upload-time = "2025-07-01T09:14:49.636Z" },
- { url = "https://files.pythonhosted.org/packages/d5/ea/502d938cbaeec836ac28a9b730193716f0114c41325db428e6b280513f09/pillow-11.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:45dfc51ac5975b938e9809451c51734124e73b04d0f0ac621649821a63852e7b", size = 6721407, upload-time = "2025-07-01T09:14:51.962Z" },
- { url = "https://files.pythonhosted.org/packages/45/9c/9c5e2a73f125f6cbc59cc7087c8f2d649a7ae453f83bd0362ff7c9e2aee2/pillow-11.3.0-cp313-cp313-win32.whl", hash = "sha256:a4d336baed65d50d37b88ca5b60c0fa9d81e3a87d4a7930d3880d1624d5b31f3", size = 6273841, upload-time = "2025-07-01T09:14:54.142Z" },
- { url = "https://files.pythonhosted.org/packages/23/85/397c73524e0cd212067e0c969aa245b01d50183439550d24d9f55781b776/pillow-11.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:0bce5c4fd0921f99d2e858dc4d4d64193407e1b99478bc5cacecba2311abde51", size = 6978450, upload-time = "2025-07-01T09:14:56.436Z" },
- { url = "https://files.pythonhosted.org/packages/17/d2/622f4547f69cd173955194b78e4d19ca4935a1b0f03a302d655c9f6aae65/pillow-11.3.0-cp313-cp313-win_arm64.whl", hash = "sha256:1904e1264881f682f02b7f8167935cce37bc97db457f8e7849dc3a6a52b99580", size = 2423055, upload-time = "2025-07-01T09:14:58.072Z" },
- { url = "https://files.pythonhosted.org/packages/dd/80/a8a2ac21dda2e82480852978416cfacd439a4b490a501a288ecf4fe2532d/pillow-11.3.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:4c834a3921375c48ee6b9624061076bc0a32a60b5532b322cc0ea64e639dd50e", size = 5281110, upload-time = "2025-07-01T09:14:59.79Z" },
- { url = "https://files.pythonhosted.org/packages/44/d6/b79754ca790f315918732e18f82a8146d33bcd7f4494380457ea89eb883d/pillow-11.3.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:5e05688ccef30ea69b9317a9ead994b93975104a677a36a8ed8106be9260aa6d", size = 4689547, upload-time = "2025-07-01T09:15:01.648Z" },
- { url = "https://files.pythonhosted.org/packages/49/20/716b8717d331150cb00f7fdd78169c01e8e0c219732a78b0e59b6bdb2fd6/pillow-11.3.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:1019b04af07fc0163e2810167918cb5add8d74674b6267616021ab558dc98ced", size = 5901554, upload-time = "2025-07-03T13:10:27.018Z" },
- { url = "https://files.pythonhosted.org/packages/74/cf/a9f3a2514a65bb071075063a96f0a5cf949c2f2fce683c15ccc83b1c1cab/pillow-11.3.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f944255db153ebb2b19c51fe85dd99ef0ce494123f21b9db4877ffdfc5590c7c", size = 7669132, upload-time = "2025-07-03T13:10:33.01Z" },
- { url = "https://files.pythonhosted.org/packages/98/3c/da78805cbdbee9cb43efe8261dd7cc0b4b93f2ac79b676c03159e9db2187/pillow-11.3.0-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1f85acb69adf2aaee8b7da124efebbdb959a104db34d3a2cb0f3793dbae422a8", size = 6005001, upload-time = "2025-07-01T09:15:03.365Z" },
- { url = "https://files.pythonhosted.org/packages/6c/fa/ce044b91faecf30e635321351bba32bab5a7e034c60187fe9698191aef4f/pillow-11.3.0-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:05f6ecbeff5005399bb48d198f098a9b4b6bdf27b8487c7f38ca16eeb070cd59", size = 6668814, upload-time = "2025-07-01T09:15:05.655Z" },
- { url = "https://files.pythonhosted.org/packages/7b/51/90f9291406d09bf93686434f9183aba27b831c10c87746ff49f127ee80cb/pillow-11.3.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:a7bc6e6fd0395bc052f16b1a8670859964dbd7003bd0af2ff08342eb6e442cfe", size = 6113124, upload-time = "2025-07-01T09:15:07.358Z" },
- { url = "https://files.pythonhosted.org/packages/cd/5a/6fec59b1dfb619234f7636d4157d11fb4e196caeee220232a8d2ec48488d/pillow-11.3.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:83e1b0161c9d148125083a35c1c5a89db5b7054834fd4387499e06552035236c", size = 6747186, upload-time = "2025-07-01T09:15:09.317Z" },
- { url = "https://files.pythonhosted.org/packages/49/6b/00187a044f98255225f172de653941e61da37104a9ea60e4f6887717e2b5/pillow-11.3.0-cp313-cp313t-win32.whl", hash = "sha256:2a3117c06b8fb646639dce83694f2f9eac405472713fcb1ae887469c0d4f6788", size = 6277546, upload-time = "2025-07-01T09:15:11.311Z" },
- { url = "https://files.pythonhosted.org/packages/e8/5c/6caaba7e261c0d75bab23be79f1d06b5ad2a2ae49f028ccec801b0e853d6/pillow-11.3.0-cp313-cp313t-win_amd64.whl", hash = "sha256:857844335c95bea93fb39e0fa2726b4d9d758850b34075a7e3ff4f4fa3aa3b31", size = 6985102, upload-time = "2025-07-01T09:15:13.164Z" },
- { url = "https://files.pythonhosted.org/packages/f3/7e/b623008460c09a0cb38263c93b828c666493caee2eb34ff67f778b87e58c/pillow-11.3.0-cp313-cp313t-win_arm64.whl", hash = "sha256:8797edc41f3e8536ae4b10897ee2f637235c94f27404cac7297f7b607dd0716e", size = 2424803, upload-time = "2025-07-01T09:15:15.695Z" },
- { url = "https://files.pythonhosted.org/packages/73/f4/04905af42837292ed86cb1b1dabe03dce1edc008ef14c473c5c7e1443c5d/pillow-11.3.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:d9da3df5f9ea2a89b81bb6087177fb1f4d1c7146d583a3fe5c672c0d94e55e12", size = 5278520, upload-time = "2025-07-01T09:15:17.429Z" },
- { url = "https://files.pythonhosted.org/packages/41/b0/33d79e377a336247df6348a54e6d2a2b85d644ca202555e3faa0cf811ecc/pillow-11.3.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:0b275ff9b04df7b640c59ec5a3cb113eefd3795a8df80bac69646ef699c6981a", size = 4686116, upload-time = "2025-07-01T09:15:19.423Z" },
- { url = "https://files.pythonhosted.org/packages/49/2d/ed8bc0ab219ae8768f529597d9509d184fe8a6c4741a6864fea334d25f3f/pillow-11.3.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0743841cabd3dba6a83f38a92672cccbd69af56e3e91777b0ee7f4dba4385632", size = 5864597, upload-time = "2025-07-03T13:10:38.404Z" },
- { url = "https://files.pythonhosted.org/packages/b5/3d/b932bb4225c80b58dfadaca9d42d08d0b7064d2d1791b6a237f87f661834/pillow-11.3.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2465a69cf967b8b49ee1b96d76718cd98c4e925414ead59fdf75cf0fd07df673", size = 7638246, upload-time = "2025-07-03T13:10:44.987Z" },
- { url = "https://files.pythonhosted.org/packages/09/b5/0487044b7c096f1b48f0d7ad416472c02e0e4bf6919541b111efd3cae690/pillow-11.3.0-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:41742638139424703b4d01665b807c6468e23e699e8e90cffefe291c5832b027", size = 5973336, upload-time = "2025-07-01T09:15:21.237Z" },
- { url = "https://files.pythonhosted.org/packages/a8/2d/524f9318f6cbfcc79fbc004801ea6b607ec3f843977652fdee4857a7568b/pillow-11.3.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:93efb0b4de7e340d99057415c749175e24c8864302369e05914682ba642e5d77", size = 6642699, upload-time = "2025-07-01T09:15:23.186Z" },
- { url = "https://files.pythonhosted.org/packages/6f/d2/a9a4f280c6aefedce1e8f615baaa5474e0701d86dd6f1dede66726462bbd/pillow-11.3.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7966e38dcd0fa11ca390aed7c6f20454443581d758242023cf36fcb319b1a874", size = 6083789, upload-time = "2025-07-01T09:15:25.1Z" },
- { url = "https://files.pythonhosted.org/packages/fe/54/86b0cd9dbb683a9d5e960b66c7379e821a19be4ac5810e2e5a715c09a0c0/pillow-11.3.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:98a9afa7b9007c67ed84c57c9e0ad86a6000da96eaa638e4f8abe5b65ff83f0a", size = 6720386, upload-time = "2025-07-01T09:15:27.378Z" },
- { url = "https://files.pythonhosted.org/packages/e7/95/88efcaf384c3588e24259c4203b909cbe3e3c2d887af9e938c2022c9dd48/pillow-11.3.0-cp314-cp314-win32.whl", hash = "sha256:02a723e6bf909e7cea0dac1b0e0310be9d7650cd66222a5f1c571455c0a45214", size = 6370911, upload-time = "2025-07-01T09:15:29.294Z" },
- { url = "https://files.pythonhosted.org/packages/2e/cc/934e5820850ec5eb107e7b1a72dd278140731c669f396110ebc326f2a503/pillow-11.3.0-cp314-cp314-win_amd64.whl", hash = "sha256:a418486160228f64dd9e9efcd132679b7a02a5f22c982c78b6fc7dab3fefb635", size = 7117383, upload-time = "2025-07-01T09:15:31.128Z" },
- { url = "https://files.pythonhosted.org/packages/d6/e9/9c0a616a71da2a5d163aa37405e8aced9a906d574b4a214bede134e731bc/pillow-11.3.0-cp314-cp314-win_arm64.whl", hash = "sha256:155658efb5e044669c08896c0c44231c5e9abcaadbc5cd3648df2f7c0b96b9a6", size = 2511385, upload-time = "2025-07-01T09:15:33.328Z" },
- { url = "https://files.pythonhosted.org/packages/1a/33/c88376898aff369658b225262cd4f2659b13e8178e7534df9e6e1fa289f6/pillow-11.3.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:59a03cdf019efbfeeed910bf79c7c93255c3d54bc45898ac2a4140071b02b4ae", size = 5281129, upload-time = "2025-07-01T09:15:35.194Z" },
- { url = "https://files.pythonhosted.org/packages/1f/70/d376247fb36f1844b42910911c83a02d5544ebd2a8bad9efcc0f707ea774/pillow-11.3.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:f8a5827f84d973d8636e9dc5764af4f0cf2318d26744b3d902931701b0d46653", size = 4689580, upload-time = "2025-07-01T09:15:37.114Z" },
- { url = "https://files.pythonhosted.org/packages/eb/1c/537e930496149fbac69efd2fc4329035bbe2e5475b4165439e3be9cb183b/pillow-11.3.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ee92f2fd10f4adc4b43d07ec5e779932b4eb3dbfbc34790ada5a6669bc095aa6", size = 5902860, upload-time = "2025-07-03T13:10:50.248Z" },
- { url = "https://files.pythonhosted.org/packages/bd/57/80f53264954dcefeebcf9dae6e3eb1daea1b488f0be8b8fef12f79a3eb10/pillow-11.3.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c96d333dcf42d01f47b37e0979b6bd73ec91eae18614864622d9b87bbd5bbf36", size = 7670694, upload-time = "2025-07-03T13:10:56.432Z" },
- { url = "https://files.pythonhosted.org/packages/70/ff/4727d3b71a8578b4587d9c276e90efad2d6fe0335fd76742a6da08132e8c/pillow-11.3.0-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4c96f993ab8c98460cd0c001447bff6194403e8b1d7e149ade5f00594918128b", size = 6005888, upload-time = "2025-07-01T09:15:39.436Z" },
- { url = "https://files.pythonhosted.org/packages/05/ae/716592277934f85d3be51d7256f3636672d7b1abfafdc42cf3f8cbd4b4c8/pillow-11.3.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:41342b64afeba938edb034d122b2dda5db2139b9a4af999729ba8818e0056477", size = 6670330, upload-time = "2025-07-01T09:15:41.269Z" },
- { url = "https://files.pythonhosted.org/packages/e7/bb/7fe6cddcc8827b01b1a9766f5fdeb7418680744f9082035bdbabecf1d57f/pillow-11.3.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:068d9c39a2d1b358eb9f245ce7ab1b5c3246c7c8c7d9ba58cfa5b43146c06e50", size = 6114089, upload-time = "2025-07-01T09:15:43.13Z" },
- { url = "https://files.pythonhosted.org/packages/8b/f5/06bfaa444c8e80f1a8e4bff98da9c83b37b5be3b1deaa43d27a0db37ef84/pillow-11.3.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:a1bc6ba083b145187f648b667e05a2534ecc4b9f2784c2cbe3089e44868f2b9b", size = 6748206, upload-time = "2025-07-01T09:15:44.937Z" },
- { url = "https://files.pythonhosted.org/packages/f0/77/bc6f92a3e8e6e46c0ca78abfffec0037845800ea38c73483760362804c41/pillow-11.3.0-cp314-cp314t-win32.whl", hash = "sha256:118ca10c0d60b06d006be10a501fd6bbdfef559251ed31b794668ed569c87e12", size = 6377370, upload-time = "2025-07-01T09:15:46.673Z" },
- { url = "https://files.pythonhosted.org/packages/4a/82/3a721f7d69dca802befb8af08b7c79ebcab461007ce1c18bd91a5d5896f9/pillow-11.3.0-cp314-cp314t-win_amd64.whl", hash = "sha256:8924748b688aa210d79883357d102cd64690e56b923a186f35a82cbc10f997db", size = 7121500, upload-time = "2025-07-01T09:15:48.512Z" },
- { url = "https://files.pythonhosted.org/packages/89/c7/5572fa4a3f45740eaab6ae86fcdf7195b55beac1371ac8c619d880cfe948/pillow-11.3.0-cp314-cp314t-win_arm64.whl", hash = "sha256:79ea0d14d3ebad43ec77ad5272e6ff9bba5b679ef73375ea760261207fa8e0aa", size = 2512835, upload-time = "2025-07-01T09:15:50.399Z" },
- { url = "https://files.pythonhosted.org/packages/9e/8e/9c089f01677d1264ab8648352dcb7773f37da6ad002542760c80107da816/pillow-11.3.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:48d254f8a4c776de343051023eb61ffe818299eeac478da55227d96e241de53f", size = 5316478, upload-time = "2025-07-01T09:15:52.209Z" },
- { url = "https://files.pythonhosted.org/packages/b5/a9/5749930caf674695867eb56a581e78eb5f524b7583ff10b01b6e5048acb3/pillow-11.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:7aee118e30a4cf54fdd873bd3a29de51e29105ab11f9aad8c32123f58c8f8081", size = 4686522, upload-time = "2025-07-01T09:15:54.162Z" },
- { url = "https://files.pythonhosted.org/packages/43/46/0b85b763eb292b691030795f9f6bb6fcaf8948c39413c81696a01c3577f7/pillow-11.3.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:23cff760a9049c502721bdb743a7cb3e03365fafcdfc2ef9784610714166e5a4", size = 5853376, upload-time = "2025-07-03T13:11:01.066Z" },
- { url = "https://files.pythonhosted.org/packages/5e/c6/1a230ec0067243cbd60bc2dad5dc3ab46a8a41e21c15f5c9b52b26873069/pillow-11.3.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:6359a3bc43f57d5b375d1ad54a0074318a0844d11b76abccf478c37c986d3cfc", size = 7626020, upload-time = "2025-07-03T13:11:06.479Z" },
- { url = "https://files.pythonhosted.org/packages/63/dd/f296c27ffba447bfad76c6a0c44c1ea97a90cb9472b9304c94a732e8dbfb/pillow-11.3.0-cp39-cp39-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:092c80c76635f5ecb10f3f83d76716165c96f5229addbd1ec2bdbbda7d496e06", size = 5956732, upload-time = "2025-07-01T09:15:56.111Z" },
- { url = "https://files.pythonhosted.org/packages/a5/a0/98a3630f0b57f77bae67716562513d3032ae70414fcaf02750279c389a9e/pillow-11.3.0-cp39-cp39-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cadc9e0ea0a2431124cde7e1697106471fc4c1da01530e679b2391c37d3fbb3a", size = 6624404, upload-time = "2025-07-01T09:15:58.245Z" },
- { url = "https://files.pythonhosted.org/packages/de/e6/83dfba5646a290edd9a21964da07674409e410579c341fc5b8f7abd81620/pillow-11.3.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:6a418691000f2a418c9135a7cf0d797c1bb7d9a485e61fe8e7722845b95ef978", size = 6067760, upload-time = "2025-07-01T09:16:00.003Z" },
- { url = "https://files.pythonhosted.org/packages/bc/41/15ab268fe6ee9a2bc7391e2bbb20a98d3974304ab1a406a992dcb297a370/pillow-11.3.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:97afb3a00b65cc0804d1c7abddbf090a81eaac02768af58cbdcaaa0a931e0b6d", size = 6700534, upload-time = "2025-07-01T09:16:02.29Z" },
- { url = "https://files.pythonhosted.org/packages/64/79/6d4f638b288300bed727ff29f2a3cb63db054b33518a95f27724915e3fbc/pillow-11.3.0-cp39-cp39-win32.whl", hash = "sha256:ea944117a7974ae78059fcc1800e5d3295172bb97035c0c1d9345fca1419da71", size = 6277091, upload-time = "2025-07-01T09:16:04.4Z" },
- { url = "https://files.pythonhosted.org/packages/46/05/4106422f45a05716fd34ed21763f8ec182e8ea00af6e9cb05b93a247361a/pillow-11.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:e5c5858ad8ec655450a7c7df532e9842cf8df7cc349df7225c60d5d348c8aada", size = 6986091, upload-time = "2025-07-01T09:16:06.342Z" },
- { url = "https://files.pythonhosted.org/packages/63/c6/287fd55c2c12761d0591549d48885187579b7c257bef0c6660755b0b59ae/pillow-11.3.0-cp39-cp39-win_arm64.whl", hash = "sha256:6abdbfd3aea42be05702a8dd98832329c167ee84400a1d1f61ab11437f1717eb", size = 2422632, upload-time = "2025-07-01T09:16:08.142Z" },
- { url = "https://files.pythonhosted.org/packages/6f/8b/209bd6b62ce8367f47e68a218bffac88888fdf2c9fcf1ecadc6c3ec1ebc7/pillow-11.3.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:3cee80663f29e3843b68199b9d6f4f54bd1d4a6b59bdd91bceefc51238bcb967", size = 5270556, upload-time = "2025-07-01T09:16:09.961Z" },
- { url = "https://files.pythonhosted.org/packages/2e/e6/231a0b76070c2cfd9e260a7a5b504fb72da0a95279410fa7afd99d9751d6/pillow-11.3.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:b5f56c3f344f2ccaf0dd875d3e180f631dc60a51b314295a3e681fe8cf851fbe", size = 4654625, upload-time = "2025-07-01T09:16:11.913Z" },
- { url = "https://files.pythonhosted.org/packages/13/f4/10cf94fda33cb12765f2397fc285fa6d8eb9c29de7f3185165b702fc7386/pillow-11.3.0-pp310-pypy310_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:e67d793d180c9df62f1f40aee3accca4829d3794c95098887edc18af4b8b780c", size = 4874207, upload-time = "2025-07-03T13:11:10.201Z" },
- { url = "https://files.pythonhosted.org/packages/72/c9/583821097dc691880c92892e8e2d41fe0a5a3d6021f4963371d2f6d57250/pillow-11.3.0-pp310-pypy310_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d000f46e2917c705e9fb93a3606ee4a819d1e3aa7a9b442f6444f07e77cf5e25", size = 6583939, upload-time = "2025-07-03T13:11:15.68Z" },
- { url = "https://files.pythonhosted.org/packages/3b/8e/5c9d410f9217b12320efc7c413e72693f48468979a013ad17fd690397b9a/pillow-11.3.0-pp310-pypy310_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:527b37216b6ac3a12d7838dc3bd75208ec57c1c6d11ef01902266a5a0c14fc27", size = 4957166, upload-time = "2025-07-01T09:16:13.74Z" },
- { url = "https://files.pythonhosted.org/packages/62/bb/78347dbe13219991877ffb3a91bf09da8317fbfcd4b5f9140aeae020ad71/pillow-11.3.0-pp310-pypy310_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:be5463ac478b623b9dd3937afd7fb7ab3d79dd290a28e2b6df292dc75063eb8a", size = 5581482, upload-time = "2025-07-01T09:16:16.107Z" },
- { url = "https://files.pythonhosted.org/packages/d9/28/1000353d5e61498aaeaaf7f1e4b49ddb05f2c6575f9d4f9f914a3538b6e1/pillow-11.3.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:8dc70ca24c110503e16918a658b869019126ecfe03109b754c402daff12b3d9f", size = 6984596, upload-time = "2025-07-01T09:16:18.07Z" },
- { url = "https://files.pythonhosted.org/packages/9e/e3/6fa84033758276fb31da12e5fb66ad747ae83b93c67af17f8c6ff4cc8f34/pillow-11.3.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7c8ec7a017ad1bd562f93dbd8505763e688d388cde6e4a010ae1486916e713e6", size = 5270566, upload-time = "2025-07-01T09:16:19.801Z" },
- { url = "https://files.pythonhosted.org/packages/5b/ee/e8d2e1ab4892970b561e1ba96cbd59c0d28cf66737fc44abb2aec3795a4e/pillow-11.3.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:9ab6ae226de48019caa8074894544af5b53a117ccb9d3b3dcb2871464c829438", size = 4654618, upload-time = "2025-07-01T09:16:21.818Z" },
- { url = "https://files.pythonhosted.org/packages/f2/6d/17f80f4e1f0761f02160fc433abd4109fa1548dcfdca46cfdadaf9efa565/pillow-11.3.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:fe27fb049cdcca11f11a7bfda64043c37b30e6b91f10cb5bab275806c32f6ab3", size = 4874248, upload-time = "2025-07-03T13:11:20.738Z" },
- { url = "https://files.pythonhosted.org/packages/de/5f/c22340acd61cef960130585bbe2120e2fd8434c214802f07e8c03596b17e/pillow-11.3.0-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:465b9e8844e3c3519a983d58b80be3f668e2a7a5db97f2784e7079fbc9f9822c", size = 6583963, upload-time = "2025-07-03T13:11:26.283Z" },
- { url = "https://files.pythonhosted.org/packages/31/5e/03966aedfbfcbb4d5f8aa042452d3361f325b963ebbadddac05b122e47dd/pillow-11.3.0-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5418b53c0d59b3824d05e029669efa023bbef0f3e92e75ec8428f3799487f361", size = 4957170, upload-time = "2025-07-01T09:16:23.762Z" },
- { url = "https://files.pythonhosted.org/packages/cc/2d/e082982aacc927fc2cab48e1e731bdb1643a1406acace8bed0900a61464e/pillow-11.3.0-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:504b6f59505f08ae014f724b6207ff6222662aab5cc9542577fb084ed0676ac7", size = 5581505, upload-time = "2025-07-01T09:16:25.593Z" },
- { url = "https://files.pythonhosted.org/packages/34/e7/ae39f538fd6844e982063c3a5e4598b8ced43b9633baa3a85ef33af8c05c/pillow-11.3.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:c84d689db21a1c397d001aa08241044aa2069e7587b398c8cc63020390b1c1b8", size = 6984598, upload-time = "2025-07-01T09:16:27.732Z" },
-]
-
-[[package]]
-name = "pillow"
-version = "12.1.0"
-source = { registry = "https://pypi.org/simple" }
-resolution-markers = [
- "python_full_version >= '3.14'",
- "python_full_version >= '3.10' and python_full_version < '3.14'",
-]
-sdist = { url = "https://files.pythonhosted.org/packages/d0/02/d52c733a2452ef1ffcc123b68e6606d07276b0e358db70eabad7e40042b7/pillow-12.1.0.tar.gz", hash = "sha256:5c5ae0a06e9ea030ab786b0251b32c7e4ce10e58d983c0d5c56029455180b5b9", size = 46977283, upload-time = "2026-01-02T09:13:29.892Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/fe/41/f73d92b6b883a579e79600d391f2e21cb0df767b2714ecbd2952315dfeef/pillow-12.1.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:fb125d860738a09d363a88daa0f59c4533529a90e564785e20fe875b200b6dbd", size = 5304089, upload-time = "2026-01-02T09:10:24.953Z" },
- { url = "https://files.pythonhosted.org/packages/94/55/7aca2891560188656e4a91ed9adba305e914a4496800da6b5c0a15f09edf/pillow-12.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cad302dc10fac357d3467a74a9561c90609768a6f73a1923b0fd851b6486f8b0", size = 4657815, upload-time = "2026-01-02T09:10:27.063Z" },
- { url = "https://files.pythonhosted.org/packages/e9/d2/b28221abaa7b4c40b7dba948f0f6a708bd7342c4d47ce342f0ea39643974/pillow-12.1.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:a40905599d8079e09f25027423aed94f2823adaf2868940de991e53a449e14a8", size = 6222593, upload-time = "2026-01-02T09:10:29.115Z" },
- { url = "https://files.pythonhosted.org/packages/71/b8/7a61fb234df6a9b0b479f69e66901209d89ff72a435b49933f9122f94cac/pillow-12.1.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:92a7fe4225365c5e3a8e598982269c6d6698d3e783b3b1ae979e7819f9cd55c1", size = 8027579, upload-time = "2026-01-02T09:10:31.182Z" },
- { url = "https://files.pythonhosted.org/packages/ea/51/55c751a57cc524a15a0e3db20e5cde517582359508d62305a627e77fd295/pillow-12.1.0-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f10c98f49227ed8383d28174ee95155a675c4ed7f85e2e573b04414f7e371bda", size = 6335760, upload-time = "2026-01-02T09:10:33.02Z" },
- { url = "https://files.pythonhosted.org/packages/dc/7c/60e3e6f5e5891a1a06b4c910f742ac862377a6fe842f7184df4a274ce7bf/pillow-12.1.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8637e29d13f478bc4f153d8daa9ffb16455f0a6cb287da1b432fdad2bfbd66c7", size = 7027127, upload-time = "2026-01-02T09:10:35.009Z" },
- { url = "https://files.pythonhosted.org/packages/06/37/49d47266ba50b00c27ba63a7c898f1bb41a29627ced8c09e25f19ebec0ff/pillow-12.1.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:21e686a21078b0f9cb8c8a961d99e6a4ddb88e0fc5ea6e130172ddddc2e5221a", size = 6449896, upload-time = "2026-01-02T09:10:36.793Z" },
- { url = "https://files.pythonhosted.org/packages/f9/e5/67fd87d2913902462cd9b79c6211c25bfe95fcf5783d06e1367d6d9a741f/pillow-12.1.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:2415373395a831f53933c23ce051021e79c8cd7979822d8cc478547a3f4da8ef", size = 7151345, upload-time = "2026-01-02T09:10:39.064Z" },
- { url = "https://files.pythonhosted.org/packages/bd/15/f8c7abf82af68b29f50d77c227e7a1f87ce02fdc66ded9bf603bc3b41180/pillow-12.1.0-cp310-cp310-win32.whl", hash = "sha256:e75d3dba8fc1ddfec0cd752108f93b83b4f8d6ab40e524a95d35f016b9683b09", size = 6325568, upload-time = "2026-01-02T09:10:41.035Z" },
- { url = "https://files.pythonhosted.org/packages/d4/24/7d1c0e160b6b5ac2605ef7d8be537e28753c0db5363d035948073f5513d7/pillow-12.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:64efdf00c09e31efd754448a383ea241f55a994fd079866b92d2bbff598aad91", size = 7032367, upload-time = "2026-01-02T09:10:43.09Z" },
- { url = "https://files.pythonhosted.org/packages/f4/03/41c038f0d7a06099254c60f618d0ec7be11e79620fc23b8e85e5b31d9a44/pillow-12.1.0-cp310-cp310-win_arm64.whl", hash = "sha256:f188028b5af6b8fb2e9a76ac0f841a575bd1bd396e46ef0840d9b88a48fdbcea", size = 2452345, upload-time = "2026-01-02T09:10:44.795Z" },
- { url = "https://files.pythonhosted.org/packages/43/c4/bf8328039de6cc22182c3ef007a2abfbbdab153661c0a9aa78af8d706391/pillow-12.1.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:a83e0850cb8f5ac975291ebfc4170ba481f41a28065277f7f735c202cd8e0af3", size = 5304057, upload-time = "2026-01-02T09:10:46.627Z" },
- { url = "https://files.pythonhosted.org/packages/43/06/7264c0597e676104cc22ca73ee48f752767cd4b1fe084662620b17e10120/pillow-12.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b6e53e82ec2db0717eabb276aa56cf4e500c9a7cec2c2e189b55c24f65a3e8c0", size = 4657811, upload-time = "2026-01-02T09:10:49.548Z" },
- { url = "https://files.pythonhosted.org/packages/72/64/f9189e44474610daf83da31145fa56710b627b5c4c0b9c235e34058f6b31/pillow-12.1.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:40a8e3b9e8773876d6e30daed22f016509e3987bab61b3b7fe309d7019a87451", size = 6232243, upload-time = "2026-01-02T09:10:51.62Z" },
- { url = "https://files.pythonhosted.org/packages/ef/30/0df458009be6a4caca4ca2c52975e6275c387d4e5c95544e34138b41dc86/pillow-12.1.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:800429ac32c9b72909c671aaf17ecd13110f823ddb7db4dfef412a5587c2c24e", size = 8037872, upload-time = "2026-01-02T09:10:53.446Z" },
- { url = "https://files.pythonhosted.org/packages/e4/86/95845d4eda4f4f9557e25381d70876aa213560243ac1a6d619c46caaedd9/pillow-12.1.0-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0b022eaaf709541b391ee069f0022ee5b36c709df71986e3f7be312e46f42c84", size = 6345398, upload-time = "2026-01-02T09:10:55.426Z" },
- { url = "https://files.pythonhosted.org/packages/5c/1f/8e66ab9be3aaf1435bc03edd1ebdf58ffcd17f7349c1d970cafe87af27d9/pillow-12.1.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1f345e7bc9d7f368887c712aa5054558bad44d2a301ddf9248599f4161abc7c0", size = 7034667, upload-time = "2026-01-02T09:10:57.11Z" },
- { url = "https://files.pythonhosted.org/packages/f9/f6/683b83cb9b1db1fb52b87951b1c0b99bdcfceaa75febf11406c19f82cb5e/pillow-12.1.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d70347c8a5b7ccd803ec0c85c8709f036e6348f1e6a5bf048ecd9c64d3550b8b", size = 6458743, upload-time = "2026-01-02T09:10:59.331Z" },
- { url = "https://files.pythonhosted.org/packages/9a/7d/de833d63622538c1d58ce5395e7c6cb7e7dce80decdd8bde4a484e095d9f/pillow-12.1.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1fcc52d86ce7a34fd17cb04e87cfdb164648a3662a6f20565910a99653d66c18", size = 7159342, upload-time = "2026-01-02T09:11:01.82Z" },
- { url = "https://files.pythonhosted.org/packages/8c/40/50d86571c9e5868c42b81fe7da0c76ca26373f3b95a8dd675425f4a92ec1/pillow-12.1.0-cp311-cp311-win32.whl", hash = "sha256:3ffaa2f0659e2f740473bcf03c702c39a8d4b2b7ffc629052028764324842c64", size = 6328655, upload-time = "2026-01-02T09:11:04.556Z" },
- { url = "https://files.pythonhosted.org/packages/6c/af/b1d7e301c4cd26cd45d4af884d9ee9b6fab893b0ad2450d4746d74a6968c/pillow-12.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:806f3987ffe10e867bab0ddad45df1148a2b98221798457fa097ad85d6e8bc75", size = 7031469, upload-time = "2026-01-02T09:11:06.538Z" },
- { url = "https://files.pythonhosted.org/packages/48/36/d5716586d887fb2a810a4a61518a327a1e21c8b7134c89283af272efe84b/pillow-12.1.0-cp311-cp311-win_arm64.whl", hash = "sha256:9f5fefaca968e700ad1a4a9de98bf0869a94e397fe3524c4c9450c1445252304", size = 2452515, upload-time = "2026-01-02T09:11:08.226Z" },
- { url = "https://files.pythonhosted.org/packages/20/31/dc53fe21a2f2996e1b7d92bf671cdb157079385183ef7c1ae08b485db510/pillow-12.1.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a332ac4ccb84b6dde65dbace8431f3af08874bf9770719d32a635c4ef411b18b", size = 5262642, upload-time = "2026-01-02T09:11:10.138Z" },
- { url = "https://files.pythonhosted.org/packages/ab/c1/10e45ac9cc79419cedf5121b42dcca5a50ad2b601fa080f58c22fb27626e/pillow-12.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:907bfa8a9cb790748a9aa4513e37c88c59660da3bcfffbd24a7d9e6abf224551", size = 4657464, upload-time = "2026-01-02T09:11:12.319Z" },
- { url = "https://files.pythonhosted.org/packages/ad/26/7b82c0ab7ef40ebede7a97c72d473bda5950f609f8e0c77b04af574a0ddb/pillow-12.1.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:efdc140e7b63b8f739d09a99033aa430accce485ff78e6d311973a67b6bf3208", size = 6234878, upload-time = "2026-01-02T09:11:14.096Z" },
- { url = "https://files.pythonhosted.org/packages/76/25/27abc9792615b5e886ca9411ba6637b675f1b77af3104710ac7353fe5605/pillow-12.1.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:bef9768cab184e7ae6e559c032e95ba8d07b3023c289f79a2bd36e8bf85605a5", size = 8044868, upload-time = "2026-01-02T09:11:15.903Z" },
- { url = "https://files.pythonhosted.org/packages/0a/ea/f200a4c36d836100e7bc738fc48cd963d3ba6372ebc8298a889e0cfc3359/pillow-12.1.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:742aea052cf5ab5034a53c3846165bc3ce88d7c38e954120db0ab867ca242661", size = 6349468, upload-time = "2026-01-02T09:11:17.631Z" },
- { url = "https://files.pythonhosted.org/packages/11/8f/48d0b77ab2200374c66d344459b8958c86693be99526450e7aee714e03e4/pillow-12.1.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a6dfc2af5b082b635af6e08e0d1f9f1c4e04d17d4e2ca0ef96131e85eda6eb17", size = 7041518, upload-time = "2026-01-02T09:11:19.389Z" },
- { url = "https://files.pythonhosted.org/packages/1d/23/c281182eb986b5d31f0a76d2a2c8cd41722d6fb8ed07521e802f9bba52de/pillow-12.1.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:609e89d9f90b581c8d16358c9087df76024cf058fa693dd3e1e1620823f39670", size = 6462829, upload-time = "2026-01-02T09:11:21.28Z" },
- { url = "https://files.pythonhosted.org/packages/25/ef/7018273e0faac099d7b00982abdcc39142ae6f3bd9ceb06de09779c4a9d6/pillow-12.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:43b4899cfd091a9693a1278c4982f3e50f7fb7cff5153b05174b4afc9593b616", size = 7166756, upload-time = "2026-01-02T09:11:23.559Z" },
- { url = "https://files.pythonhosted.org/packages/8f/c8/993d4b7ab2e341fe02ceef9576afcf5830cdec640be2ac5bee1820d693d4/pillow-12.1.0-cp312-cp312-win32.whl", hash = "sha256:aa0c9cc0b82b14766a99fbe6084409972266e82f459821cd26997a488a7261a7", size = 6328770, upload-time = "2026-01-02T09:11:25.661Z" },
- { url = "https://files.pythonhosted.org/packages/a7/87/90b358775a3f02765d87655237229ba64a997b87efa8ccaca7dd3e36e7a7/pillow-12.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:d70534cea9e7966169ad29a903b99fc507e932069a881d0965a1a84bb57f6c6d", size = 7033406, upload-time = "2026-01-02T09:11:27.474Z" },
- { url = "https://files.pythonhosted.org/packages/5d/cf/881b457eccacac9e5b2ddd97d5071fb6d668307c57cbf4e3b5278e06e536/pillow-12.1.0-cp312-cp312-win_arm64.whl", hash = "sha256:65b80c1ee7e14a87d6a068dd3b0aea268ffcabfe0498d38661b00c5b4b22e74c", size = 2452612, upload-time = "2026-01-02T09:11:29.309Z" },
- { url = "https://files.pythonhosted.org/packages/dd/c7/2530a4aa28248623e9d7f27316b42e27c32ec410f695929696f2e0e4a778/pillow-12.1.0-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:7b5dd7cbae20285cdb597b10eb5a2c13aa9de6cde9bb64a3c1317427b1db1ae1", size = 4062543, upload-time = "2026-01-02T09:11:31.566Z" },
- { url = "https://files.pythonhosted.org/packages/8f/1f/40b8eae823dc1519b87d53c30ed9ef085506b05281d313031755c1705f73/pillow-12.1.0-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:29a4cef9cb672363926f0470afc516dbf7305a14d8c54f7abbb5c199cd8f8179", size = 4138373, upload-time = "2026-01-02T09:11:33.367Z" },
- { url = "https://files.pythonhosted.org/packages/d4/77/6fa60634cf06e52139fd0e89e5bbf055e8166c691c42fb162818b7fda31d/pillow-12.1.0-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:681088909d7e8fa9e31b9799aaa59ba5234c58e5e4f1951b4c4d1082a2e980e0", size = 3601241, upload-time = "2026-01-02T09:11:35.011Z" },
- { url = "https://files.pythonhosted.org/packages/4f/bf/28ab865de622e14b747f0cd7877510848252d950e43002e224fb1c9ababf/pillow-12.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:983976c2ab753166dc66d36af6e8ec15bb511e4a25856e2227e5f7e00a160587", size = 5262410, upload-time = "2026-01-02T09:11:36.682Z" },
- { url = "https://files.pythonhosted.org/packages/1c/34/583420a1b55e715937a85bd48c5c0991598247a1fd2eb5423188e765ea02/pillow-12.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:db44d5c160a90df2d24a24760bbd37607d53da0b34fb546c4c232af7192298ac", size = 4657312, upload-time = "2026-01-02T09:11:38.535Z" },
- { url = "https://files.pythonhosted.org/packages/1d/fd/f5a0896839762885b3376ff04878f86ab2b097c2f9a9cdccf4eda8ba8dc0/pillow-12.1.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:6b7a9d1db5dad90e2991645874f708e87d9a3c370c243c2d7684d28f7e133e6b", size = 6232605, upload-time = "2026-01-02T09:11:40.602Z" },
- { url = "https://files.pythonhosted.org/packages/98/aa/938a09d127ac1e70e6ed467bd03834350b33ef646b31edb7452d5de43792/pillow-12.1.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:6258f3260986990ba2fa8a874f8b6e808cf5abb51a94015ca3dc3c68aa4f30ea", size = 8041617, upload-time = "2026-01-02T09:11:42.721Z" },
- { url = "https://files.pythonhosted.org/packages/17/e8/538b24cb426ac0186e03f80f78bc8dc7246c667f58b540bdd57c71c9f79d/pillow-12.1.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e115c15e3bc727b1ca3e641a909f77f8ca72a64fff150f666fcc85e57701c26c", size = 6346509, upload-time = "2026-01-02T09:11:44.955Z" },
- { url = "https://files.pythonhosted.org/packages/01/9a/632e58ec89a32738cabfd9ec418f0e9898a2b4719afc581f07c04a05e3c9/pillow-12.1.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6741e6f3074a35e47c77b23a4e4f2d90db3ed905cb1c5e6e0d49bff2045632bc", size = 7038117, upload-time = "2026-01-02T09:11:46.736Z" },
- { url = "https://files.pythonhosted.org/packages/c7/a2/d40308cf86eada842ca1f3ffa45d0ca0df7e4ab33c83f81e73f5eaed136d/pillow-12.1.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:935b9d1aed48fcfb3f838caac506f38e29621b44ccc4f8a64d575cb1b2a88644", size = 6460151, upload-time = "2026-01-02T09:11:48.625Z" },
- { url = "https://files.pythonhosted.org/packages/f1/88/f5b058ad6453a085c5266660a1417bdad590199da1b32fb4efcff9d33b05/pillow-12.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5fee4c04aad8932da9f8f710af2c1a15a83582cfb884152a9caa79d4efcdbf9c", size = 7164534, upload-time = "2026-01-02T09:11:50.445Z" },
- { url = "https://files.pythonhosted.org/packages/19/ce/c17334caea1db789163b5d855a5735e47995b0b5dc8745e9a3605d5f24c0/pillow-12.1.0-cp313-cp313-win32.whl", hash = "sha256:a786bf667724d84aa29b5db1c61b7bfdde380202aaca12c3461afd6b71743171", size = 6332551, upload-time = "2026-01-02T09:11:52.234Z" },
- { url = "https://files.pythonhosted.org/packages/e5/07/74a9d941fa45c90a0d9465098fe1ec85de3e2afbdc15cc4766622d516056/pillow-12.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:461f9dfdafa394c59cd6d818bdfdbab4028b83b02caadaff0ffd433faf4c9a7a", size = 7040087, upload-time = "2026-01-02T09:11:54.822Z" },
- { url = "https://files.pythonhosted.org/packages/88/09/c99950c075a0e9053d8e880595926302575bc742b1b47fe1bbcc8d388d50/pillow-12.1.0-cp313-cp313-win_arm64.whl", hash = "sha256:9212d6b86917a2300669511ed094a9406888362e085f2431a7da985a6b124f45", size = 2452470, upload-time = "2026-01-02T09:11:56.522Z" },
- { url = "https://files.pythonhosted.org/packages/b5/ba/970b7d85ba01f348dee4d65412476321d40ee04dcb51cd3735b9dc94eb58/pillow-12.1.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:00162e9ca6d22b7c3ee8e61faa3c3253cd19b6a37f126cad04f2f88b306f557d", size = 5264816, upload-time = "2026-01-02T09:11:58.227Z" },
- { url = "https://files.pythonhosted.org/packages/10/60/650f2fb55fdba7a510d836202aa52f0baac633e50ab1cf18415d332188fb/pillow-12.1.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:7d6daa89a00b58c37cb1747ec9fb7ac3bc5ffd5949f5888657dfddde6d1312e0", size = 4660472, upload-time = "2026-01-02T09:12:00.798Z" },
- { url = "https://files.pythonhosted.org/packages/2b/c0/5273a99478956a099d533c4f46cbaa19fd69d606624f4334b85e50987a08/pillow-12.1.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:e2479c7f02f9d505682dc47df8c0ea1fc5e264c4d1629a5d63fe3e2334b89554", size = 6268974, upload-time = "2026-01-02T09:12:02.572Z" },
- { url = "https://files.pythonhosted.org/packages/b4/26/0bf714bc2e73d5267887d47931d53c4ceeceea6978148ed2ab2a4e6463c4/pillow-12.1.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f188d580bd870cda1e15183790d1cc2fa78f666e76077d103edf048eed9c356e", size = 8073070, upload-time = "2026-01-02T09:12:04.75Z" },
- { url = "https://files.pythonhosted.org/packages/43/cf/1ea826200de111a9d65724c54f927f3111dc5ae297f294b370a670c17786/pillow-12.1.0-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0fde7ec5538ab5095cc02df38ee99b0443ff0e1c847a045554cf5f9af1f4aa82", size = 6380176, upload-time = "2026-01-02T09:12:06.626Z" },
- { url = "https://files.pythonhosted.org/packages/03/e0/7938dd2b2013373fd85d96e0f38d62b7a5a262af21ac274250c7ca7847c9/pillow-12.1.0-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0ed07dca4a8464bada6139ab38f5382f83e5f111698caf3191cb8dbf27d908b4", size = 7067061, upload-time = "2026-01-02T09:12:08.624Z" },
- { url = "https://files.pythonhosted.org/packages/86/ad/a2aa97d37272a929a98437a8c0ac37b3cf012f4f8721e1bd5154699b2518/pillow-12.1.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:f45bd71d1fa5e5749587613037b172e0b3b23159d1c00ef2fc920da6f470e6f0", size = 6491824, upload-time = "2026-01-02T09:12:10.488Z" },
- { url = "https://files.pythonhosted.org/packages/a4/44/80e46611b288d51b115826f136fb3465653c28f491068a72d3da49b54cd4/pillow-12.1.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:277518bf4fe74aa91489e1b20577473b19ee70fb97c374aa50830b279f25841b", size = 7190911, upload-time = "2026-01-02T09:12:12.772Z" },
- { url = "https://files.pythonhosted.org/packages/86/77/eacc62356b4cf81abe99ff9dbc7402750044aed02cfd6a503f7c6fc11f3e/pillow-12.1.0-cp313-cp313t-win32.whl", hash = "sha256:7315f9137087c4e0ee73a761b163fc9aa3b19f5f606a7fc08d83fd3e4379af65", size = 6336445, upload-time = "2026-01-02T09:12:14.775Z" },
- { url = "https://files.pythonhosted.org/packages/e7/3c/57d81d0b74d218706dafccb87a87ea44262c43eef98eb3b164fd000e0491/pillow-12.1.0-cp313-cp313t-win_amd64.whl", hash = "sha256:0ddedfaa8b5f0b4ffbc2fa87b556dc59f6bb4ecb14a53b33f9189713ae8053c0", size = 7045354, upload-time = "2026-01-02T09:12:16.599Z" },
- { url = "https://files.pythonhosted.org/packages/ac/82/8b9b97bba2e3576a340f93b044a3a3a09841170ab4c1eb0d5c93469fd32f/pillow-12.1.0-cp313-cp313t-win_arm64.whl", hash = "sha256:80941e6d573197a0c28f394753de529bb436b1ca990ed6e765cf42426abc39f8", size = 2454547, upload-time = "2026-01-02T09:12:18.704Z" },
- { url = "https://files.pythonhosted.org/packages/8c/87/bdf971d8bbcf80a348cc3bacfcb239f5882100fe80534b0ce67a784181d8/pillow-12.1.0-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:5cb7bc1966d031aec37ddb9dcf15c2da5b2e9f7cc3ca7c54473a20a927e1eb91", size = 4062533, upload-time = "2026-01-02T09:12:20.791Z" },
- { url = "https://files.pythonhosted.org/packages/ff/4f/5eb37a681c68d605eb7034c004875c81f86ec9ef51f5be4a63eadd58859a/pillow-12.1.0-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:97e9993d5ed946aba26baf9c1e8cf18adbab584b99f452ee72f7ee8acb882796", size = 4138546, upload-time = "2026-01-02T09:12:23.664Z" },
- { url = "https://files.pythonhosted.org/packages/11/6d/19a95acb2edbace40dcd582d077b991646b7083c41b98da4ed7555b59733/pillow-12.1.0-cp314-cp314-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:414b9a78e14ffeb98128863314e62c3f24b8a86081066625700b7985b3f529bd", size = 3601163, upload-time = "2026-01-02T09:12:26.338Z" },
- { url = "https://files.pythonhosted.org/packages/fc/36/2b8138e51cb42e4cc39c3297713455548be855a50558c3ac2beebdc251dd/pillow-12.1.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:e6bdb408f7c9dd2a5ff2b14a3b0bb6d4deb29fb9961e6eb3ae2031ae9a5cec13", size = 5266086, upload-time = "2026-01-02T09:12:28.782Z" },
- { url = "https://files.pythonhosted.org/packages/53/4b/649056e4d22e1caa90816bf99cef0884aed607ed38075bd75f091a607a38/pillow-12.1.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:3413c2ae377550f5487991d444428f1a8ae92784aac79caa8b1e3b89b175f77e", size = 4657344, upload-time = "2026-01-02T09:12:31.117Z" },
- { url = "https://files.pythonhosted.org/packages/6c/6b/c5742cea0f1ade0cd61485dc3d81f05261fc2276f537fbdc00802de56779/pillow-12.1.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:e5dcbe95016e88437ecf33544ba5db21ef1b8dd6e1b434a2cb2a3d605299e643", size = 6232114, upload-time = "2026-01-02T09:12:32.936Z" },
- { url = "https://files.pythonhosted.org/packages/bf/8f/9f521268ce22d63991601aafd3d48d5ff7280a246a1ef62d626d67b44064/pillow-12.1.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d0a7735df32ccbcc98b98a1ac785cc4b19b580be1bdf0aeb5c03223220ea09d5", size = 8042708, upload-time = "2026-01-02T09:12:34.78Z" },
- { url = "https://files.pythonhosted.org/packages/1a/eb/257f38542893f021502a1bbe0c2e883c90b5cff26cc33b1584a841a06d30/pillow-12.1.0-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0c27407a2d1b96774cbc4a7594129cc027339fd800cd081e44497722ea1179de", size = 6347762, upload-time = "2026-01-02T09:12:36.748Z" },
- { url = "https://files.pythonhosted.org/packages/c4/5a/8ba375025701c09b309e8d5163c5a4ce0102fa86bbf8800eb0d7ac87bc51/pillow-12.1.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:15c794d74303828eaa957ff8070846d0efe8c630901a1c753fdc63850e19ecd9", size = 7039265, upload-time = "2026-01-02T09:12:39.082Z" },
- { url = "https://files.pythonhosted.org/packages/cf/dc/cf5e4cdb3db533f539e88a7bbf9f190c64ab8a08a9bc7a4ccf55067872e4/pillow-12.1.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c990547452ee2800d8506c4150280757f88532f3de2a58e3022e9b179107862a", size = 6462341, upload-time = "2026-01-02T09:12:40.946Z" },
- { url = "https://files.pythonhosted.org/packages/d0/47/0291a25ac9550677e22eda48510cfc4fa4b2ef0396448b7fbdc0a6946309/pillow-12.1.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:b63e13dd27da389ed9475b3d28510f0f954bca0041e8e551b2a4eb1eab56a39a", size = 7165395, upload-time = "2026-01-02T09:12:42.706Z" },
- { url = "https://files.pythonhosted.org/packages/4f/4c/e005a59393ec4d9416be06e6b45820403bb946a778e39ecec62f5b2b991e/pillow-12.1.0-cp314-cp314-win32.whl", hash = "sha256:1a949604f73eb07a8adab38c4fe50791f9919344398bdc8ac6b307f755fc7030", size = 6431413, upload-time = "2026-01-02T09:12:44.944Z" },
- { url = "https://files.pythonhosted.org/packages/1c/af/f23697f587ac5f9095d67e31b81c95c0249cd461a9798a061ed6709b09b5/pillow-12.1.0-cp314-cp314-win_amd64.whl", hash = "sha256:4f9f6a650743f0ddee5593ac9e954ba1bdbc5e150bc066586d4f26127853ab94", size = 7176779, upload-time = "2026-01-02T09:12:46.727Z" },
- { url = "https://files.pythonhosted.org/packages/b3/36/6a51abf8599232f3e9afbd16d52829376a68909fe14efe29084445db4b73/pillow-12.1.0-cp314-cp314-win_arm64.whl", hash = "sha256:808b99604f7873c800c4840f55ff389936ef1948e4e87645eaf3fccbc8477ac4", size = 2543105, upload-time = "2026-01-02T09:12:49.243Z" },
- { url = "https://files.pythonhosted.org/packages/82/54/2e1dd20c8749ff225080d6ba465a0cab4387f5db0d1c5fb1439e2d99923f/pillow-12.1.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:bc11908616c8a283cf7d664f77411a5ed2a02009b0097ff8abbba5e79128ccf2", size = 5268571, upload-time = "2026-01-02T09:12:51.11Z" },
- { url = "https://files.pythonhosted.org/packages/57/61/571163a5ef86ec0cf30d265ac2a70ae6fc9e28413d1dc94fa37fae6bda89/pillow-12.1.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:896866d2d436563fa2a43a9d72f417874f16b5545955c54a64941e87c1376c61", size = 4660426, upload-time = "2026-01-02T09:12:52.865Z" },
- { url = "https://files.pythonhosted.org/packages/5e/e1/53ee5163f794aef1bf84243f755ee6897a92c708505350dd1923f4afec48/pillow-12.1.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8e178e3e99d3c0ea8fc64b88447f7cac8ccf058af422a6cedc690d0eadd98c51", size = 6269908, upload-time = "2026-01-02T09:12:54.884Z" },
- { url = "https://files.pythonhosted.org/packages/bc/0b/b4b4106ff0ee1afa1dc599fde6ab230417f800279745124f6c50bcffed8e/pillow-12.1.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:079af2fb0c599c2ec144ba2c02766d1b55498e373b3ac64687e43849fbbef5bc", size = 8074733, upload-time = "2026-01-02T09:12:56.802Z" },
- { url = "https://files.pythonhosted.org/packages/19/9f/80b411cbac4a732439e629a26ad3ef11907a8c7fc5377b7602f04f6fe4e7/pillow-12.1.0-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bdec5e43377761c5dbca620efb69a77f6855c5a379e32ac5b158f54c84212b14", size = 6381431, upload-time = "2026-01-02T09:12:58.823Z" },
- { url = "https://files.pythonhosted.org/packages/8f/b7/d65c45db463b66ecb6abc17c6ba6917a911202a07662247e1355ce1789e7/pillow-12.1.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:565c986f4b45c020f5421a4cea13ef294dde9509a8577f29b2fc5edc7587fff8", size = 7068529, upload-time = "2026-01-02T09:13:00.885Z" },
- { url = "https://files.pythonhosted.org/packages/50/96/dfd4cd726b4a45ae6e3c669fc9e49deb2241312605d33aba50499e9d9bd1/pillow-12.1.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:43aca0a55ce1eefc0aefa6253661cb54571857b1a7b2964bd8a1e3ef4b729924", size = 6492981, upload-time = "2026-01-02T09:13:03.314Z" },
- { url = "https://files.pythonhosted.org/packages/4d/1c/b5dc52cf713ae46033359c5ca920444f18a6359ce1020dd3e9c553ea5bc6/pillow-12.1.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:0deedf2ea233722476b3a81e8cdfbad786f7adbed5d848469fa59fe52396e4ef", size = 7191878, upload-time = "2026-01-02T09:13:05.276Z" },
- { url = "https://files.pythonhosted.org/packages/53/26/c4188248bd5edaf543864fe4834aebe9c9cb4968b6f573ce014cc42d0720/pillow-12.1.0-cp314-cp314t-win32.whl", hash = "sha256:b17fbdbe01c196e7e159aacb889e091f28e61020a8abeac07b68079b6e626988", size = 6438703, upload-time = "2026-01-02T09:13:07.491Z" },
- { url = "https://files.pythonhosted.org/packages/b8/0e/69ed296de8ea05cb03ee139cee600f424ca166e632567b2d66727f08c7ed/pillow-12.1.0-cp314-cp314t-win_amd64.whl", hash = "sha256:27b9baecb428899db6c0de572d6d305cfaf38ca1596b5c0542a5182e3e74e8c6", size = 7182927, upload-time = "2026-01-02T09:13:09.841Z" },
- { url = "https://files.pythonhosted.org/packages/fc/f5/68334c015eed9b5cff77814258717dec591ded209ab5b6fb70e2ae873d1d/pillow-12.1.0-cp314-cp314t-win_arm64.whl", hash = "sha256:f61333d817698bdcdd0f9d7793e365ac3d2a21c1f1eb02b32ad6aefb8d8ea831", size = 2545104, upload-time = "2026-01-02T09:13:12.068Z" },
- { url = "https://files.pythonhosted.org/packages/8b/bc/224b1d98cffd7164b14707c91aac83c07b047fbd8f58eba4066a3e53746a/pillow-12.1.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:ca94b6aac0d7af2a10ba08c0f888b3d5114439b6b3ef39968378723622fed377", size = 5228605, upload-time = "2026-01-02T09:13:14.084Z" },
- { url = "https://files.pythonhosted.org/packages/0c/ca/49ca7769c4550107de049ed85208240ba0f330b3f2e316f24534795702ce/pillow-12.1.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:351889afef0f485b84078ea40fe33727a0492b9af3904661b0abbafee0355b72", size = 4622245, upload-time = "2026-01-02T09:13:15.964Z" },
- { url = "https://files.pythonhosted.org/packages/73/48/fac807ce82e5955bcc2718642b94b1bd22a82a6d452aea31cbb678cddf12/pillow-12.1.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:bb0984b30e973f7e2884362b7d23d0a348c7143ee559f38ef3eaab640144204c", size = 5247593, upload-time = "2026-01-02T09:13:17.913Z" },
- { url = "https://files.pythonhosted.org/packages/d2/95/3e0742fe358c4664aed4fd05d5f5373dcdad0b27af52aa0972568541e3f4/pillow-12.1.0-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:84cabc7095dd535ca934d57e9ce2a72ffd216e435a84acb06b2277b1de2689bd", size = 6989008, upload-time = "2026-01-02T09:13:20.083Z" },
- { url = "https://files.pythonhosted.org/packages/5a/74/fe2ac378e4e202e56d50540d92e1ef4ff34ed687f3c60f6a121bcf99437e/pillow-12.1.0-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:53d8b764726d3af1a138dd353116f774e3862ec7e3794e0c8781e30db0f35dfc", size = 5313824, upload-time = "2026-01-02T09:13:22.405Z" },
- { url = "https://files.pythonhosted.org/packages/f3/77/2a60dee1adee4e2655ac328dd05c02a955c1cd683b9f1b82ec3feb44727c/pillow-12.1.0-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5da841d81b1a05ef940a8567da92decaa15bc4d7dedb540a8c219ad83d91808a", size = 5963278, upload-time = "2026-01-02T09:13:24.706Z" },
- { url = "https://files.pythonhosted.org/packages/2d/71/64e9b1c7f04ae0027f788a248e6297d7fcc29571371fe7d45495a78172c0/pillow-12.1.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:75af0b4c229ac519b155028fa1be632d812a519abba9b46b20e50c6caa184f19", size = 7029809, upload-time = "2026-01-02T09:13:26.541Z" },
-]
-
-[[package]]
-name = "platformdirs"
-version = "4.4.0"
-source = { registry = "https://pypi.org/simple" }
-resolution-markers = [
- "python_full_version < '3.10'",
-]
-sdist = { url = "https://files.pythonhosted.org/packages/23/e8/21db9c9987b0e728855bd57bff6984f67952bea55d6f75e055c46b5383e8/platformdirs-4.4.0.tar.gz", hash = "sha256:ca753cf4d81dc309bc67b0ea38fd15dc97bc30ce419a7f58d13eb3bf14c4febf", size = 21634, upload-time = "2025-08-26T14:32:04.268Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/40/4b/2028861e724d3bd36227adfa20d3fd24c3fc6d52032f4a93c133be5d17ce/platformdirs-4.4.0-py3-none-any.whl", hash = "sha256:abd01743f24e5287cd7a5db3752faf1a2d65353f38ec26d98e25a6db65958c85", size = 18654, upload-time = "2025-08-26T14:32:02.735Z" },
+version = "12.1.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/1f/42/5c74462b4fd957fcd7b13b04fb3205ff8349236ea74c7c375766d6c82288/pillow-12.1.1.tar.gz", hash = "sha256:9ad8fa5937ab05218e2b6a4cff30295ad35afd2f83ac592e68c0d871bb0fdbc4", size = 46980264, upload-time = "2026-02-11T04:23:07.146Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/1d/30/5bd3d794762481f8c8ae9c80e7b76ecea73b916959eb587521358ef0b2f9/pillow-12.1.1-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:1f1625b72740fdda5d77b4def688eb8fd6490975d06b909fd19f13f391e077e0", size = 5304099, upload-time = "2026-02-11T04:20:06.13Z" },
+ { url = "https://files.pythonhosted.org/packages/bd/c1/aab9e8f3eeb4490180e357955e15c2ef74b31f64790ff356c06fb6cf6d84/pillow-12.1.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:178aa072084bd88ec759052feca8e56cbb14a60b39322b99a049e58090479713", size = 4657880, upload-time = "2026-02-11T04:20:09.291Z" },
+ { url = "https://files.pythonhosted.org/packages/f1/0a/9879e30d56815ad529d3985aeff5af4964202425c27261a6ada10f7cbf53/pillow-12.1.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b66e95d05ba806247aaa1561f080abc7975daf715c30780ff92a20e4ec546e1b", size = 6222587, upload-time = "2026-02-11T04:20:10.82Z" },
+ { url = "https://files.pythonhosted.org/packages/5a/5f/a1b72ff7139e4f89014e8d451442c74a774d5c43cd938fb0a9f878576b37/pillow-12.1.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:89c7e895002bbe49cdc5426150377cbbc04767d7547ed145473f496dfa40408b", size = 8027678, upload-time = "2026-02-11T04:20:12.455Z" },
+ { url = "https://files.pythonhosted.org/packages/e2/c2/c7cb187dac79a3d22c3ebeae727abee01e077c8c7d930791dc592f335153/pillow-12.1.1-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3a5cbdcddad0af3da87cb16b60d23648bc3b51967eb07223e9fed77a82b457c4", size = 6335777, upload-time = "2026-02-11T04:20:14.441Z" },
+ { url = "https://files.pythonhosted.org/packages/0c/7b/f9b09a7804ec7336effb96c26d37c29d27225783dc1501b7d62dcef6ae25/pillow-12.1.1-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9f51079765661884a486727f0729d29054242f74b46186026582b4e4769918e4", size = 7027140, upload-time = "2026-02-11T04:20:16.387Z" },
+ { url = "https://files.pythonhosted.org/packages/98/b2/2fa3c391550bd421b10849d1a2144c44abcd966daadd2f7c12e19ea988c4/pillow-12.1.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:99c1506ea77c11531d75e3a412832a13a71c7ebc8192ab9e4b2e355555920e3e", size = 6449855, upload-time = "2026-02-11T04:20:18.554Z" },
+ { url = "https://files.pythonhosted.org/packages/96/ff/9caf4b5b950c669263c39e96c78c0d74a342c71c4f43fd031bb5cb7ceac9/pillow-12.1.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:36341d06738a9f66c8287cf8b876d24b18db9bd8740fa0672c74e259ad408cff", size = 7151329, upload-time = "2026-02-11T04:20:20.646Z" },
+ { url = "https://files.pythonhosted.org/packages/7b/f8/4b24841f582704da675ca535935bccb32b00a6da1226820845fac4a71136/pillow-12.1.1-cp310-cp310-win32.whl", hash = "sha256:6c52f062424c523d6c4db85518774cc3d50f5539dd6eed32b8f6229b26f24d40", size = 6325574, upload-time = "2026-02-11T04:20:22.43Z" },
+ { url = "https://files.pythonhosted.org/packages/f8/f9/9f6b01c0881d7036063aa6612ef04c0e2cad96be21325a1e92d0203f8e91/pillow-12.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:c6008de247150668a705a6338156efb92334113421ceecf7438a12c9a12dab23", size = 7032347, upload-time = "2026-02-11T04:20:23.932Z" },
+ { url = "https://files.pythonhosted.org/packages/79/13/c7922edded3dcdaf10c59297540b72785620abc0538872c819915746757d/pillow-12.1.1-cp310-cp310-win_arm64.whl", hash = "sha256:1a9b0ee305220b392e1124a764ee4265bd063e54a751a6b62eff69992f457fa9", size = 2453457, upload-time = "2026-02-11T04:20:25.392Z" },
+ { url = "https://files.pythonhosted.org/packages/2b/46/5da1ec4a5171ee7bf1a0efa064aba70ba3d6e0788ce3f5acd1375d23c8c0/pillow-12.1.1-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:e879bb6cd5c73848ef3b2b48b8af9ff08c5b71ecda8048b7dd22d8a33f60be32", size = 5304084, upload-time = "2026-02-11T04:20:27.501Z" },
+ { url = "https://files.pythonhosted.org/packages/78/93/a29e9bc02d1cf557a834da780ceccd54e02421627200696fcf805ebdc3fb/pillow-12.1.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:365b10bb9417dd4498c0e3b128018c4a624dc11c7b97d8cc54effe3b096f4c38", size = 4657866, upload-time = "2026-02-11T04:20:29.827Z" },
+ { url = "https://files.pythonhosted.org/packages/13/84/583a4558d492a179d31e4aae32eadce94b9acf49c0337c4ce0b70e0a01f2/pillow-12.1.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d4ce8e329c93845720cd2014659ca67eac35f6433fd3050393d85f3ecef0dad5", size = 6232148, upload-time = "2026-02-11T04:20:31.329Z" },
+ { url = "https://files.pythonhosted.org/packages/d5/e2/53c43334bbbb2d3b938978532fbda8e62bb6e0b23a26ce8592f36bcc4987/pillow-12.1.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fc354a04072b765eccf2204f588a7a532c9511e8b9c7f900e1b64e3e33487090", size = 8038007, upload-time = "2026-02-11T04:20:34.225Z" },
+ { url = "https://files.pythonhosted.org/packages/b8/a6/3d0e79c8a9d58150dd98e199d7c1c56861027f3829a3a60b3c2784190180/pillow-12.1.1-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7e7976bf1910a8116b523b9f9f58bf410f3e8aa330cd9a2bb2953f9266ab49af", size = 6345418, upload-time = "2026-02-11T04:20:35.858Z" },
+ { url = "https://files.pythonhosted.org/packages/a2/c8/46dfeac5825e600579157eea177be43e2f7ff4a99da9d0d0a49533509ac5/pillow-12.1.1-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:597bd9c8419bc7c6af5604e55847789b69123bbe25d65cc6ad3012b4f3c98d8b", size = 7034590, upload-time = "2026-02-11T04:20:37.91Z" },
+ { url = "https://files.pythonhosted.org/packages/af/bf/e6f65d3db8a8bbfeaf9e13cc0417813f6319863a73de934f14b2229ada18/pillow-12.1.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2c1fc0f2ca5f96a3c8407e41cca26a16e46b21060fe6d5b099d2cb01412222f5", size = 6458655, upload-time = "2026-02-11T04:20:39.496Z" },
+ { url = "https://files.pythonhosted.org/packages/f9/c2/66091f3f34a25894ca129362e510b956ef26f8fb67a0e6417bc5744e56f1/pillow-12.1.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:578510d88c6229d735855e1f278aa305270438d36a05031dfaae5067cc8eb04d", size = 7159286, upload-time = "2026-02-11T04:20:41.139Z" },
+ { url = "https://files.pythonhosted.org/packages/7b/5a/24bc8eb526a22f957d0cec6243146744966d40857e3d8deb68f7902ca6c1/pillow-12.1.1-cp311-cp311-win32.whl", hash = "sha256:7311c0a0dcadb89b36b7025dfd8326ecfa36964e29913074d47382706e516a7c", size = 6328663, upload-time = "2026-02-11T04:20:43.184Z" },
+ { url = "https://files.pythonhosted.org/packages/31/03/bef822e4f2d8f9d7448c133d0a18185d3cce3e70472774fffefe8b0ed562/pillow-12.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:fbfa2a7c10cc2623f412753cddf391c7f971c52ca40a3f65dc5039b2939e8563", size = 7031448, upload-time = "2026-02-11T04:20:44.696Z" },
+ { url = "https://files.pythonhosted.org/packages/49/70/f76296f53610bd17b2e7d31728b8b7825e3ac3b5b3688b51f52eab7c0818/pillow-12.1.1-cp311-cp311-win_arm64.whl", hash = "sha256:b81b5e3511211631b3f672a595e3221252c90af017e399056d0faabb9538aa80", size = 2453651, upload-time = "2026-02-11T04:20:46.243Z" },
+ { url = "https://files.pythonhosted.org/packages/07/d3/8df65da0d4df36b094351dce696f2989bec731d4f10e743b1c5f4da4d3bf/pillow-12.1.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:ab323b787d6e18b3d91a72fc99b1a2c28651e4358749842b8f8dfacd28ef2052", size = 5262803, upload-time = "2026-02-11T04:20:47.653Z" },
+ { url = "https://files.pythonhosted.org/packages/d6/71/5026395b290ff404b836e636f51d7297e6c83beceaa87c592718747e670f/pillow-12.1.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:adebb5bee0f0af4909c30db0d890c773d1a92ffe83da908e2e9e720f8edf3984", size = 4657601, upload-time = "2026-02-11T04:20:49.328Z" },
+ { url = "https://files.pythonhosted.org/packages/b1/2e/1001613d941c67442f745aff0f7cc66dd8df9a9c084eb497e6a543ee6f7e/pillow-12.1.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:bb66b7cc26f50977108790e2456b7921e773f23db5630261102233eb355a3b79", size = 6234995, upload-time = "2026-02-11T04:20:51.032Z" },
+ { url = "https://files.pythonhosted.org/packages/07/26/246ab11455b2549b9233dbd44d358d033a2f780fa9007b61a913c5b2d24e/pillow-12.1.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:aee2810642b2898bb187ced9b349e95d2a7272930796e022efaf12e99dccd293", size = 8045012, upload-time = "2026-02-11T04:20:52.882Z" },
+ { url = "https://files.pythonhosted.org/packages/b2/8b/07587069c27be7535ac1fe33874e32de118fbd34e2a73b7f83436a88368c/pillow-12.1.1-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a0b1cd6232e2b618adcc54d9882e4e662a089d5768cd188f7c245b4c8c44a397", size = 6349638, upload-time = "2026-02-11T04:20:54.444Z" },
+ { url = "https://files.pythonhosted.org/packages/ff/79/6df7b2ee763d619cda2fb4fea498e5f79d984dae304d45a8999b80d6cf5c/pillow-12.1.1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7aac39bcf8d4770d089588a2e1dd111cbaa42df5a94be3114222057d68336bd0", size = 7041540, upload-time = "2026-02-11T04:20:55.97Z" },
+ { url = "https://files.pythonhosted.org/packages/2c/5e/2ba19e7e7236d7529f4d873bdaf317a318896bac289abebd4bb00ef247f0/pillow-12.1.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ab174cd7d29a62dd139c44bf74b698039328f45cb03b4596c43473a46656b2f3", size = 6462613, upload-time = "2026-02-11T04:20:57.542Z" },
+ { url = "https://files.pythonhosted.org/packages/03/03/31216ec124bb5c3dacd74ce8efff4cc7f52643653bad4825f8f08c697743/pillow-12.1.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:339ffdcb7cbeaa08221cd401d517d4b1fe7a9ed5d400e4a8039719238620ca35", size = 7166745, upload-time = "2026-02-11T04:20:59.196Z" },
+ { url = "https://files.pythonhosted.org/packages/1f/e7/7c4552d80052337eb28653b617eafdef39adfb137c49dd7e831b8dc13bc5/pillow-12.1.1-cp312-cp312-win32.whl", hash = "sha256:5d1f9575a12bed9e9eedd9a4972834b08c97a352bd17955ccdebfeca5913fa0a", size = 6328823, upload-time = "2026-02-11T04:21:01.385Z" },
+ { url = "https://files.pythonhosted.org/packages/3d/17/688626d192d7261bbbf98846fc98995726bddc2c945344b65bec3a29d731/pillow-12.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:21329ec8c96c6e979cd0dfd29406c40c1d52521a90544463057d2aaa937d66a6", size = 7033367, upload-time = "2026-02-11T04:21:03.536Z" },
+ { url = "https://files.pythonhosted.org/packages/ed/fe/a0ef1f73f939b0eca03ee2c108d0043a87468664770612602c63266a43c4/pillow-12.1.1-cp312-cp312-win_arm64.whl", hash = "sha256:af9a332e572978f0218686636610555ae3defd1633597be015ed50289a03c523", size = 2453811, upload-time = "2026-02-11T04:21:05.116Z" },
+ { url = "https://files.pythonhosted.org/packages/d5/11/6db24d4bd7685583caeae54b7009584e38da3c3d4488ed4cd25b439de486/pillow-12.1.1-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:d242e8ac078781f1de88bf823d70c1a9b3c7950a44cdf4b7c012e22ccbcd8e4e", size = 4062689, upload-time = "2026-02-11T04:21:06.804Z" },
+ { url = "https://files.pythonhosted.org/packages/33/c0/ce6d3b1fe190f0021203e0d9b5b99e57843e345f15f9ef22fcd43842fd21/pillow-12.1.1-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:02f84dfad02693676692746df05b89cf25597560db2857363a208e393429f5e9", size = 4138535, upload-time = "2026-02-11T04:21:08.452Z" },
+ { url = "https://files.pythonhosted.org/packages/a0/c6/d5eb6a4fb32a3f9c21a8c7613ec706534ea1cf9f4b3663e99f0d83f6fca8/pillow-12.1.1-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:e65498daf4b583091ccbb2556c7000abf0f3349fcd57ef7adc9a84a394ed29f6", size = 3601364, upload-time = "2026-02-11T04:21:10.194Z" },
+ { url = "https://files.pythonhosted.org/packages/14/a1/16c4b823838ba4c9c52c0e6bbda903a3fe5a1bdbf1b8eb4fff7156f3e318/pillow-12.1.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:6c6db3b84c87d48d0088943bf33440e0c42370b99b1c2a7989216f7b42eede60", size = 5262561, upload-time = "2026-02-11T04:21:11.742Z" },
+ { url = "https://files.pythonhosted.org/packages/bb/ad/ad9dc98ff24f485008aa5cdedaf1a219876f6f6c42a4626c08bc4e80b120/pillow-12.1.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:8b7e5304e34942bf62e15184219a7b5ad4ff7f3bb5cca4d984f37df1a0e1aee2", size = 4657460, upload-time = "2026-02-11T04:21:13.786Z" },
+ { url = "https://files.pythonhosted.org/packages/9e/1b/f1a4ea9a895b5732152789326202a82464d5254759fbacae4deea3069334/pillow-12.1.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:18e5bddd742a44b7e6b1e773ab5db102bd7a94c32555ba656e76d319d19c3850", size = 6232698, upload-time = "2026-02-11T04:21:15.949Z" },
+ { url = "https://files.pythonhosted.org/packages/95/f4/86f51b8745070daf21fd2e5b1fe0eb35d4db9ca26e6d58366562fb56a743/pillow-12.1.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fc44ef1f3de4f45b50ccf9136999d71abb99dca7706bc75d222ed350b9fd2289", size = 8041706, upload-time = "2026-02-11T04:21:17.723Z" },
+ { url = "https://files.pythonhosted.org/packages/29/9b/d6ecd956bb1266dd1045e995cce9b8d77759e740953a1c9aad9502a0461e/pillow-12.1.1-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5a8eb7ed8d4198bccbd07058416eeec51686b498e784eda166395a23eb99138e", size = 6346621, upload-time = "2026-02-11T04:21:19.547Z" },
+ { url = "https://files.pythonhosted.org/packages/71/24/538bff45bde96535d7d998c6fed1a751c75ac7c53c37c90dc2601b243893/pillow-12.1.1-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:47b94983da0c642de92ced1702c5b6c292a84bd3a8e1d1702ff923f183594717", size = 7038069, upload-time = "2026-02-11T04:21:21.378Z" },
+ { url = "https://files.pythonhosted.org/packages/94/0e/58cb1a6bc48f746bc4cb3adb8cabff73e2742c92b3bf7a220b7cf69b9177/pillow-12.1.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:518a48c2aab7ce596d3bf79d0e275661b846e86e4d0e7dec34712c30fe07f02a", size = 6460040, upload-time = "2026-02-11T04:21:23.148Z" },
+ { url = "https://files.pythonhosted.org/packages/6c/57/9045cb3ff11eeb6c1adce3b2d60d7d299d7b273a2e6c8381a524abfdc474/pillow-12.1.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a550ae29b95c6dc13cf69e2c9dc5747f814c54eeb2e32d683e5e93af56caa029", size = 7164523, upload-time = "2026-02-11T04:21:25.01Z" },
+ { url = "https://files.pythonhosted.org/packages/73/f2/9be9cb99f2175f0d4dbadd6616ce1bf068ee54a28277ea1bf1fbf729c250/pillow-12.1.1-cp313-cp313-win32.whl", hash = "sha256:a003d7422449f6d1e3a34e3dd4110c22148336918ddbfc6a32581cd54b2e0b2b", size = 6332552, upload-time = "2026-02-11T04:21:27.238Z" },
+ { url = "https://files.pythonhosted.org/packages/3f/eb/b0834ad8b583d7d9d42b80becff092082a1c3c156bb582590fcc973f1c7c/pillow-12.1.1-cp313-cp313-win_amd64.whl", hash = "sha256:344cf1e3dab3be4b1fa08e449323d98a2a3f819ad20f4b22e77a0ede31f0faa1", size = 7040108, upload-time = "2026-02-11T04:21:29.462Z" },
+ { url = "https://files.pythonhosted.org/packages/d5/7d/fc09634e2aabdd0feabaff4a32f4a7d97789223e7c2042fd805ea4b4d2c2/pillow-12.1.1-cp313-cp313-win_arm64.whl", hash = "sha256:5c0dd1636633e7e6a0afe7bf6a51a14992b7f8e60de5789018ebbdfae55b040a", size = 2453712, upload-time = "2026-02-11T04:21:31.072Z" },
+ { url = "https://files.pythonhosted.org/packages/19/2a/b9d62794fc8a0dd14c1943df68347badbd5511103e0d04c035ffe5cf2255/pillow-12.1.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0330d233c1a0ead844fc097a7d16c0abff4c12e856c0b325f231820fee1f39da", size = 5264880, upload-time = "2026-02-11T04:21:32.865Z" },
+ { url = "https://files.pythonhosted.org/packages/26/9d/e03d857d1347fa5ed9247e123fcd2a97b6220e15e9cb73ca0a8d91702c6e/pillow-12.1.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:5dae5f21afb91322f2ff791895ddd8889e5e947ff59f71b46041c8ce6db790bc", size = 4660616, upload-time = "2026-02-11T04:21:34.97Z" },
+ { url = "https://files.pythonhosted.org/packages/f7/ec/8a6d22afd02570d30954e043f09c32772bfe143ba9285e2fdb11284952cd/pillow-12.1.1-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:2e0c664be47252947d870ac0d327fea7e63985a08794758aa8af5b6cb6ec0c9c", size = 6269008, upload-time = "2026-02-11T04:21:36.623Z" },
+ { url = "https://files.pythonhosted.org/packages/3d/1d/6d875422c9f28a4a361f495a5f68d9de4a66941dc2c619103ca335fa6446/pillow-12.1.1-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:691ab2ac363b8217f7d31b3497108fb1f50faab2f75dfb03284ec2f217e87bf8", size = 8073226, upload-time = "2026-02-11T04:21:38.585Z" },
+ { url = "https://files.pythonhosted.org/packages/a1/cd/134b0b6ee5eda6dc09e25e24b40fdafe11a520bc725c1d0bbaa5e00bf95b/pillow-12.1.1-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e9e8064fb1cc019296958595f6db671fba95209e3ceb0c4734c9baf97de04b20", size = 6380136, upload-time = "2026-02-11T04:21:40.562Z" },
+ { url = "https://files.pythonhosted.org/packages/7a/a9/7628f013f18f001c1b98d8fffe3452f306a70dc6aba7d931019e0492f45e/pillow-12.1.1-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:472a8d7ded663e6162dafdf20015c486a7009483ca671cece7a9279b512fcb13", size = 7067129, upload-time = "2026-02-11T04:21:42.521Z" },
+ { url = "https://files.pythonhosted.org/packages/1e/f8/66ab30a2193b277785601e82ee2d49f68ea575d9637e5e234faaa98efa4c/pillow-12.1.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:89b54027a766529136a06cfebeecb3a04900397a3590fd252160b888479517bf", size = 6491807, upload-time = "2026-02-11T04:21:44.22Z" },
+ { url = "https://files.pythonhosted.org/packages/da/0b/a877a6627dc8318fdb84e357c5e1a758c0941ab1ddffdafd231983788579/pillow-12.1.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:86172b0831b82ce4f7877f280055892b31179e1576aa00d0df3bb1bbf8c3e524", size = 7190954, upload-time = "2026-02-11T04:21:46.114Z" },
+ { url = "https://files.pythonhosted.org/packages/83/43/6f732ff85743cf746b1361b91665d9f5155e1483817f693f8d57ea93147f/pillow-12.1.1-cp313-cp313t-win32.whl", hash = "sha256:44ce27545b6efcf0fdbdceb31c9a5bdea9333e664cda58a7e674bb74608b3986", size = 6336441, upload-time = "2026-02-11T04:21:48.22Z" },
+ { url = "https://files.pythonhosted.org/packages/3b/44/e865ef3986611bb75bfabdf94a590016ea327833f434558801122979cd0e/pillow-12.1.1-cp313-cp313t-win_amd64.whl", hash = "sha256:a285e3eb7a5a45a2ff504e31f4a8d1b12ef62e84e5411c6804a42197c1cf586c", size = 7045383, upload-time = "2026-02-11T04:21:50.015Z" },
+ { url = "https://files.pythonhosted.org/packages/a8/c6/f4fb24268d0c6908b9f04143697ea18b0379490cb74ba9e8d41b898bd005/pillow-12.1.1-cp313-cp313t-win_arm64.whl", hash = "sha256:cc7d296b5ea4d29e6570dabeaed58d31c3fea35a633a69679fb03d7664f43fb3", size = 2456104, upload-time = "2026-02-11T04:21:51.633Z" },
+ { url = "https://files.pythonhosted.org/packages/03/d0/bebb3ffbf31c5a8e97241476c4cf8b9828954693ce6744b4a2326af3e16b/pillow-12.1.1-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:417423db963cb4be8bac3fc1204fe61610f6abeed1580a7a2cbb2fbda20f12af", size = 4062652, upload-time = "2026-02-11T04:21:53.19Z" },
+ { url = "https://files.pythonhosted.org/packages/2d/c0/0e16fb0addda4851445c28f8350d8c512f09de27bbb0d6d0bbf8b6709605/pillow-12.1.1-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:b957b71c6b2387610f556a7eb0828afbe40b4a98036fc0d2acfa5a44a0c2036f", size = 4138823, upload-time = "2026-02-11T04:22:03.088Z" },
+ { url = "https://files.pythonhosted.org/packages/6b/fb/6170ec655d6f6bb6630a013dd7cf7bc218423d7b5fa9071bf63dc32175ae/pillow-12.1.1-cp314-cp314-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:097690ba1f2efdeb165a20469d59d8bb03c55fb6621eb2041a060ae8ea3e9642", size = 3601143, upload-time = "2026-02-11T04:22:04.909Z" },
+ { url = "https://files.pythonhosted.org/packages/59/04/dc5c3f297510ba9a6837cbb318b87dd2b8f73eb41a43cc63767f65cb599c/pillow-12.1.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:2815a87ab27848db0321fb78c7f0b2c8649dee134b7f2b80c6a45c6831d75ccd", size = 5266254, upload-time = "2026-02-11T04:22:07.656Z" },
+ { url = "https://files.pythonhosted.org/packages/05/30/5db1236b0d6313f03ebf97f5e17cda9ca060f524b2fcc875149a8360b21c/pillow-12.1.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:f7ed2c6543bad5a7d5530eb9e78c53132f93dfa44a28492db88b41cdab885202", size = 4657499, upload-time = "2026-02-11T04:22:09.613Z" },
+ { url = "https://files.pythonhosted.org/packages/6f/18/008d2ca0eb612e81968e8be0bbae5051efba24d52debf930126d7eaacbba/pillow-12.1.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:652a2c9ccfb556235b2b501a3a7cf3742148cd22e04b5625c5fe057ea3e3191f", size = 6232137, upload-time = "2026-02-11T04:22:11.434Z" },
+ { url = "https://files.pythonhosted.org/packages/70/f1/f14d5b8eeb4b2cd62b9f9f847eb6605f103df89ef619ac68f92f748614ea/pillow-12.1.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d6e4571eedf43af33d0fc233a382a76e849badbccdf1ac438841308652a08e1f", size = 8042721, upload-time = "2026-02-11T04:22:13.321Z" },
+ { url = "https://files.pythonhosted.org/packages/5a/d6/17824509146e4babbdabf04d8171491fa9d776f7061ff6e727522df9bd03/pillow-12.1.1-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b574c51cf7d5d62e9be37ba446224b59a2da26dc4c1bb2ecbe936a4fb1a7cb7f", size = 6347798, upload-time = "2026-02-11T04:22:15.449Z" },
+ { url = "https://files.pythonhosted.org/packages/d1/ee/c85a38a9ab92037a75615aba572c85ea51e605265036e00c5b67dfafbfe2/pillow-12.1.1-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a37691702ed687799de29a518d63d4682d9016932db66d4e90c345831b02fb4e", size = 7039315, upload-time = "2026-02-11T04:22:17.24Z" },
+ { url = "https://files.pythonhosted.org/packages/ec/f3/bc8ccc6e08a148290d7523bde4d9a0d6c981db34631390dc6e6ec34cacf6/pillow-12.1.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:f95c00d5d6700b2b890479664a06e754974848afaae5e21beb4d83c106923fd0", size = 6462360, upload-time = "2026-02-11T04:22:19.111Z" },
+ { url = "https://files.pythonhosted.org/packages/f6/ab/69a42656adb1d0665ab051eec58a41f169ad295cf81ad45406963105408f/pillow-12.1.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:559b38da23606e68681337ad74622c4dbba02254fc9cb4488a305dd5975c7eeb", size = 7165438, upload-time = "2026-02-11T04:22:21.041Z" },
+ { url = "https://files.pythonhosted.org/packages/02/46/81f7aa8941873f0f01d4b55cc543b0a3d03ec2ee30d617a0448bf6bd6dec/pillow-12.1.1-cp314-cp314-win32.whl", hash = "sha256:03edcc34d688572014ff223c125a3f77fb08091e4607e7745002fc214070b35f", size = 6431503, upload-time = "2026-02-11T04:22:22.833Z" },
+ { url = "https://files.pythonhosted.org/packages/40/72/4c245f7d1044b67affc7f134a09ea619d4895333d35322b775b928180044/pillow-12.1.1-cp314-cp314-win_amd64.whl", hash = "sha256:50480dcd74fa63b8e78235957d302d98d98d82ccbfac4c7e12108ba9ecbdba15", size = 7176748, upload-time = "2026-02-11T04:22:24.64Z" },
+ { url = "https://files.pythonhosted.org/packages/e4/ad/8a87bdbe038c5c698736e3348af5c2194ffb872ea52f11894c95f9305435/pillow-12.1.1-cp314-cp314-win_arm64.whl", hash = "sha256:5cb1785d97b0c3d1d1a16bc1d710c4a0049daefc4935f3a8f31f827f4d3d2e7f", size = 2544314, upload-time = "2026-02-11T04:22:26.685Z" },
+ { url = "https://files.pythonhosted.org/packages/6c/9d/efd18493f9de13b87ede7c47e69184b9e859e4427225ea962e32e56a49bc/pillow-12.1.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:1f90cff8aa76835cba5769f0b3121a22bd4eb9e6884cfe338216e557a9a548b8", size = 5268612, upload-time = "2026-02-11T04:22:29.884Z" },
+ { url = "https://files.pythonhosted.org/packages/f8/f1/4f42eb2b388eb2ffc660dcb7f7b556c1015c53ebd5f7f754965ef997585b/pillow-12.1.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1f1be78ce9466a7ee64bfda57bdba0f7cc499d9794d518b854816c41bf0aa4e9", size = 4660567, upload-time = "2026-02-11T04:22:31.799Z" },
+ { url = "https://files.pythonhosted.org/packages/01/54/df6ef130fa43e4b82e32624a7b821a2be1c5653a5fdad8469687a7db4e00/pillow-12.1.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:42fc1f4677106188ad9a55562bbade416f8b55456f522430fadab3cef7cd4e60", size = 6269951, upload-time = "2026-02-11T04:22:33.921Z" },
+ { url = "https://files.pythonhosted.org/packages/a9/48/618752d06cc44bb4aae8ce0cd4e6426871929ed7b46215638088270d9b34/pillow-12.1.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:98edb152429ab62a1818039744d8fbb3ccab98a7c29fc3d5fcef158f3f1f68b7", size = 8074769, upload-time = "2026-02-11T04:22:35.877Z" },
+ { url = "https://files.pythonhosted.org/packages/c3/bd/f1d71eb39a72fa088d938655afba3e00b38018d052752f435838961127d8/pillow-12.1.1-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d470ab1178551dd17fdba0fef463359c41aaa613cdcd7ff8373f54be629f9f8f", size = 6381358, upload-time = "2026-02-11T04:22:37.698Z" },
+ { url = "https://files.pythonhosted.org/packages/64/ef/c784e20b96674ed36a5af839305f55616f8b4f8aa8eeccf8531a6e312243/pillow-12.1.1-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6408a7b064595afcab0a49393a413732a35788f2a5092fdc6266952ed67de586", size = 7068558, upload-time = "2026-02-11T04:22:39.597Z" },
+ { url = "https://files.pythonhosted.org/packages/73/cb/8059688b74422ae61278202c4e1ad992e8a2e7375227be0a21c6b87ca8d5/pillow-12.1.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:5d8c41325b382c07799a3682c1c258469ea2ff97103c53717b7893862d0c98ce", size = 6493028, upload-time = "2026-02-11T04:22:42.73Z" },
+ { url = "https://files.pythonhosted.org/packages/c6/da/e3c008ed7d2dd1f905b15949325934510b9d1931e5df999bb15972756818/pillow-12.1.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:c7697918b5be27424e9ce568193efd13d925c4481dd364e43f5dff72d33e10f8", size = 7191940, upload-time = "2026-02-11T04:22:44.543Z" },
+ { url = "https://files.pythonhosted.org/packages/01/4a/9202e8d11714c1fc5951f2e1ef362f2d7fbc595e1f6717971d5dd750e969/pillow-12.1.1-cp314-cp314t-win32.whl", hash = "sha256:d2912fd8114fc5545aa3a4b5576512f64c55a03f3ebcca4c10194d593d43ea36", size = 6438736, upload-time = "2026-02-11T04:22:46.347Z" },
+ { url = "https://files.pythonhosted.org/packages/f3/ca/cbce2327eb9885476b3957b2e82eb12c866a8b16ad77392864ad601022ce/pillow-12.1.1-cp314-cp314t-win_amd64.whl", hash = "sha256:4ceb838d4bd9dab43e06c363cab2eebf63846d6a4aeaea283bbdfd8f1a8ed58b", size = 7182894, upload-time = "2026-02-11T04:22:48.114Z" },
+ { url = "https://files.pythonhosted.org/packages/ec/d2/de599c95ba0a973b94410477f8bf0b6f0b5e67360eb89bcb1ad365258beb/pillow-12.1.1-cp314-cp314t-win_arm64.whl", hash = "sha256:7b03048319bfc6170e93bd60728a1af51d3dd7704935feb228c4d4faab35d334", size = 2546446, upload-time = "2026-02-11T04:22:50.342Z" },
+ { url = "https://files.pythonhosted.org/packages/56/11/5d43209aa4cb58e0cc80127956ff1796a68b928e6324bbf06ef4db34367b/pillow-12.1.1-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:600fd103672b925fe62ed08e0d874ea34d692474df6f4bf7ebe148b30f89f39f", size = 5228606, upload-time = "2026-02-11T04:22:52.106Z" },
+ { url = "https://files.pythonhosted.org/packages/5f/d5/3b005b4e4fda6698b371fa6c21b097d4707585d7db99e98d9b0b87ac612a/pillow-12.1.1-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:665e1b916b043cef294bc54d47bf02d87e13f769bc4bc5fa225a24b3a6c5aca9", size = 4622321, upload-time = "2026-02-11T04:22:53.827Z" },
+ { url = "https://files.pythonhosted.org/packages/df/36/ed3ea2d594356fd8037e5a01f6156c74bc8d92dbb0fa60746cc96cabb6e8/pillow-12.1.1-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:495c302af3aad1ca67420ddd5c7bd480c8867ad173528767d906428057a11f0e", size = 5247579, upload-time = "2026-02-11T04:22:56.094Z" },
+ { url = "https://files.pythonhosted.org/packages/54/9a/9cc3e029683cf6d20ae5085da0dafc63148e3252c2f13328e553aaa13cfb/pillow-12.1.1-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8fd420ef0c52c88b5a035a0886f367748c72147b2b8f384c9d12656678dfdfa9", size = 6989094, upload-time = "2026-02-11T04:22:58.288Z" },
+ { url = "https://files.pythonhosted.org/packages/00/98/fc53ab36da80b88df0967896b6c4b4cd948a0dc5aa40a754266aa3ae48b3/pillow-12.1.1-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f975aa7ef9684ce7e2c18a3aa8f8e2106ce1e46b94ab713d156b2898811651d3", size = 5313850, upload-time = "2026-02-11T04:23:00.554Z" },
+ { url = "https://files.pythonhosted.org/packages/30/02/00fa585abfd9fe9d73e5f6e554dc36cc2b842898cbfc46d70353dae227f8/pillow-12.1.1-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8089c852a56c2966cf18835db62d9b34fef7ba74c726ad943928d494fa7f4735", size = 5963343, upload-time = "2026-02-11T04:23:02.934Z" },
+ { url = "https://files.pythonhosted.org/packages/f2/26/c56ce33ca856e358d27fda9676c055395abddb82c35ac0f593877ed4562e/pillow-12.1.1-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:cb9bb857b2d057c6dfc72ac5f3b44836924ba15721882ef103cecb40d002d80e", size = 7029880, upload-time = "2026-02-11T04:23:04.783Z" },
]
[[package]]
name = "platformdirs"
version = "4.5.1"
source = { registry = "https://pypi.org/simple" }
-resolution-markers = [
- "python_full_version >= '3.14'",
- "python_full_version >= '3.10' and python_full_version < '3.14'",
-]
sdist = { url = "https://files.pythonhosted.org/packages/cf/86/0248f086a84f01b37aaec0fa567b397df1a119f73c16f6c7a9aac73ea309/platformdirs-4.5.1.tar.gz", hash = "sha256:61d5cdcc6065745cdd94f0f878977f8de9437be93de97c1c12f853c9c0cdcbda", size = 21715, upload-time = "2025-12-05T13:52:58.638Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/cb/28/3bfe2fa5a7b9c46fe7e13c97bda14c895fb10fa2ebf1d0abb90e0cea7ee1/platformdirs-4.5.1-py3-none-any.whl", hash = "sha256:d03afa3963c806a9bed9d5125c8f4cb2fdaf74a55ab60e5d59b3fde758104d31", size = 18731, upload-time = "2025-12-05T13:52:56.823Z" },
@@ -4617,8 +3621,7 @@ name = "playwright"
version = "1.58.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "greenlet", version = "3.2.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
- { name = "greenlet", version = "3.3.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
+ { name = "greenlet" },
{ name = "pyee" },
]
wheels = [
@@ -4797,51 +3800,13 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/08/02/87b25304249a35c0915d236575bc3574a323f60b47939a2262b77632a3ee/propcache-0.4.1-cp314-cp314t-win32.whl", hash = "sha256:05674a162469f31358c30bcaa8883cb7829fa3110bf9c0991fe27d7896c42d85", size = 42546, upload-time = "2025-10-08T19:48:32.872Z" },
{ url = "https://files.pythonhosted.org/packages/cb/ef/3c6ecf8b317aa982f309835e8f96987466123c6e596646d4e6a1dfcd080f/propcache-0.4.1-cp314-cp314t-win_amd64.whl", hash = "sha256:990f6b3e2a27d683cb7602ed6c86f15ee6b43b1194736f9baaeb93d0016633b1", size = 46259, upload-time = "2025-10-08T19:48:34.226Z" },
{ url = "https://files.pythonhosted.org/packages/c4/2d/346e946d4951f37eca1e4f55be0f0174c52cd70720f84029b02f296f4a38/propcache-0.4.1-cp314-cp314t-win_arm64.whl", hash = "sha256:ecef2343af4cc68e05131e45024ba34f6095821988a9d0a02aa7c73fcc448aa9", size = 40428, upload-time = "2025-10-08T19:48:35.441Z" },
- { url = "https://files.pythonhosted.org/packages/9b/01/0ebaec9003f5d619a7475165961f8e3083cf8644d704b60395df3601632d/propcache-0.4.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:3d233076ccf9e450c8b3bc6720af226b898ef5d051a2d145f7d765e6e9f9bcff", size = 80277, upload-time = "2025-10-08T19:48:36.647Z" },
- { url = "https://files.pythonhosted.org/packages/34/58/04af97ac586b4ef6b9026c3fd36ee7798b737a832f5d3440a4280dcebd3a/propcache-0.4.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:357f5bb5c377a82e105e44bd3d52ba22b616f7b9773714bff93573988ef0a5fb", size = 45865, upload-time = "2025-10-08T19:48:37.859Z" },
- { url = "https://files.pythonhosted.org/packages/7c/19/b65d98ae21384518b291d9939e24a8aeac4fdb5101b732576f8f7540e834/propcache-0.4.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:cbc3b6dfc728105b2a57c06791eb07a94229202ea75c59db644d7d496b698cac", size = 47636, upload-time = "2025-10-08T19:48:39.038Z" },
- { url = "https://files.pythonhosted.org/packages/b3/0f/317048c6d91c356c7154dca5af019e6effeb7ee15fa6a6db327cc19e12b4/propcache-0.4.1-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:182b51b421f0501952d938dc0b0eb45246a5b5153c50d42b495ad5fb7517c888", size = 201126, upload-time = "2025-10-08T19:48:40.774Z" },
- { url = "https://files.pythonhosted.org/packages/71/69/0b2a7a5a6ee83292b4b997dbd80549d8ce7d40b6397c1646c0d9495f5a85/propcache-0.4.1-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4b536b39c5199b96fc6245eb5fb796c497381d3942f169e44e8e392b29c9ebcc", size = 209837, upload-time = "2025-10-08T19:48:42.167Z" },
- { url = "https://files.pythonhosted.org/packages/a5/92/c699ac495a6698df6e497fc2de27af4b6ace10d8e76528357ce153722e45/propcache-0.4.1-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:db65d2af507bbfbdcedb254a11149f894169d90488dd3e7190f7cdcb2d6cd57a", size = 215578, upload-time = "2025-10-08T19:48:43.56Z" },
- { url = "https://files.pythonhosted.org/packages/b3/ee/14de81c5eb02c0ee4f500b4e39c4e1bd0677c06e72379e6ab18923c773fc/propcache-0.4.1-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fd2dbc472da1f772a4dae4fa24be938a6c544671a912e30529984dd80400cd88", size = 197187, upload-time = "2025-10-08T19:48:45.309Z" },
- { url = "https://files.pythonhosted.org/packages/1d/94/48dce9aaa6d8dd5a0859bad75158ec522546d4ac23f8e2f05fac469477dd/propcache-0.4.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:daede9cd44e0f8bdd9e6cc9a607fc81feb80fae7a5fc6cecaff0e0bb32e42d00", size = 193478, upload-time = "2025-10-08T19:48:47.743Z" },
- { url = "https://files.pythonhosted.org/packages/60/b5/0516b563e801e1ace212afde869a0596a0d7115eec0b12d296d75633fb29/propcache-0.4.1-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:71b749281b816793678ae7f3d0d84bd36e694953822eaad408d682efc5ca18e0", size = 190650, upload-time = "2025-10-08T19:48:49.373Z" },
- { url = "https://files.pythonhosted.org/packages/24/89/e0f7d4a5978cd56f8cd67735f74052f257dc471ec901694e430f0d1572fe/propcache-0.4.1-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:0002004213ee1f36cfb3f9a42b5066100c44276b9b72b4e1504cddd3d692e86e", size = 200251, upload-time = "2025-10-08T19:48:51.4Z" },
- { url = "https://files.pythonhosted.org/packages/06/7d/a1fac863d473876ed4406c914f2e14aa82d2f10dd207c9e16fc383cc5a24/propcache-0.4.1-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:fe49d0a85038f36ba9e3ffafa1103e61170b28e95b16622e11be0a0ea07c6781", size = 200919, upload-time = "2025-10-08T19:48:53.227Z" },
- { url = "https://files.pythonhosted.org/packages/c3/4e/f86a256ff24944cf5743e4e6c6994e3526f6acfcfb55e21694c2424f758c/propcache-0.4.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:99d43339c83aaf4d32bda60928231848eee470c6bda8d02599cc4cebe872d183", size = 193211, upload-time = "2025-10-08T19:48:55.027Z" },
- { url = "https://files.pythonhosted.org/packages/6e/3f/3fbad5f4356b068f1b047d300a6ff2c66614d7030f078cd50be3fec04228/propcache-0.4.1-cp39-cp39-win32.whl", hash = "sha256:a129e76735bc792794d5177069691c3217898b9f5cee2b2661471e52ffe13f19", size = 38314, upload-time = "2025-10-08T19:48:56.792Z" },
- { url = "https://files.pythonhosted.org/packages/a4/45/d78d136c3a3d215677abb886785aae744da2c3005bcb99e58640c56529b1/propcache-0.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:948dab269721ae9a87fd16c514a0a2c2a1bdb23a9a61b969b0f9d9ee2968546f", size = 41912, upload-time = "2025-10-08T19:48:57.995Z" },
- { url = "https://files.pythonhosted.org/packages/fc/2a/b0632941f25139f4e58450b307242951f7c2717a5704977c6d5323a800af/propcache-0.4.1-cp39-cp39-win_arm64.whl", hash = "sha256:5fd37c406dd6dc85aa743e214cef35dc54bbdd1419baac4f6ae5e5b1a2976938", size = 38450, upload-time = "2025-10-08T19:48:59.349Z" },
{ url = "https://files.pythonhosted.org/packages/5b/5a/bc7b4a4ef808fa59a816c17b20c4bef6884daebbdf627ff2a161da67da19/propcache-0.4.1-py3-none-any.whl", hash = "sha256:af2a6052aeb6cf17d3e46ee169099044fd8224cbaf75c76a2ef596e8163e2237", size = 13305, upload-time = "2025-10-08T19:49:00.792Z" },
]
-[[package]]
-name = "protobuf"
-version = "5.29.6"
-source = { registry = "https://pypi.org/simple" }
-resolution-markers = [
- "python_full_version < '3.10'",
-]
-sdist = { url = "https://files.pythonhosted.org/packages/7e/57/394a763c103e0edf87f0938dafcd918d53b4c011dfc5c8ae80f3b0452dbb/protobuf-5.29.6.tar.gz", hash = "sha256:da9ee6a5424b6b30fd5e45c5ea663aef540ca95f9ad99d1e887e819cdf9b8723", size = 425623, upload-time = "2026-02-04T22:54:40.584Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/d4/88/9ee58ff7863c479d6f8346686d4636dd4c415b0cbeed7a6a7d0617639c2a/protobuf-5.29.6-cp310-abi3-win32.whl", hash = "sha256:62e8a3114992c7c647bce37dcc93647575fc52d50e48de30c6fcb28a6a291eb1", size = 423357, upload-time = "2026-02-04T22:54:25.805Z" },
- { url = "https://files.pythonhosted.org/packages/1c/66/2dc736a4d576847134fb6d80bd995c569b13cdc7b815d669050bf0ce2d2c/protobuf-5.29.6-cp310-abi3-win_amd64.whl", hash = "sha256:7e6ad413275be172f67fdee0f43484b6de5a904cc1c3ea9804cb6fe2ff366eda", size = 435175, upload-time = "2026-02-04T22:54:28.592Z" },
- { url = "https://files.pythonhosted.org/packages/06/db/49b05966fd208ae3f44dcd33837b6243b4915c57561d730a43f881f24dea/protobuf-5.29.6-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:b5a169e664b4057183a34bdc424540e86eea47560f3c123a0d64de4e137f9269", size = 418619, upload-time = "2026-02-04T22:54:30.266Z" },
- { url = "https://files.pythonhosted.org/packages/b7/d7/48cbf6b0c3c39761e47a99cb483405f0fde2be22cf00d71ef316ce52b458/protobuf-5.29.6-cp38-abi3-manylinux2014_aarch64.whl", hash = "sha256:a8866b2cff111f0f863c1b3b9e7572dc7eaea23a7fae27f6fc613304046483e6", size = 320284, upload-time = "2026-02-04T22:54:31.782Z" },
- { url = "https://files.pythonhosted.org/packages/e3/dd/cadd6ec43069247d91f6345fa7a0d2858bef6af366dbd7ba8f05d2c77d3b/protobuf-5.29.6-cp38-abi3-manylinux2014_x86_64.whl", hash = "sha256:e3387f44798ac1106af0233c04fb8abf543772ff241169946f698b3a9a3d3ab9", size = 320478, upload-time = "2026-02-04T22:54:32.909Z" },
- { url = "https://files.pythonhosted.org/packages/30/a4/ff263f5687815e1a10a9243a3a6463af42ca251224bf4b8fc4c93b9f5b80/protobuf-5.29.6-cp39-cp39-win32.whl", hash = "sha256:cb4c86de9cd8a7f3a256b9744220d87b847371c6b2f10bde87768918ef33ba49", size = 423352, upload-time = "2026-02-04T22:54:37.375Z" },
- { url = "https://files.pythonhosted.org/packages/5c/64/e943206d3b5069050d570a2c53a90631240d99adcc9a91c6ff7b41876f4d/protobuf-5.29.6-cp39-cp39-win_amd64.whl", hash = "sha256:76e07e6567f8baf827137e8d5b8204b6c7b6488bbbff1bf0a72b383f77999c18", size = 435222, upload-time = "2026-02-04T22:54:38.418Z" },
- { url = "https://files.pythonhosted.org/packages/5a/cb/e3065b447186cb70aa65acc70c86baf482d82bf75625bf5a2c4f6919c6a3/protobuf-5.29.6-py3-none-any.whl", hash = "sha256:6b9edb641441b2da9fa8f428760fc136a49cf97a52076010cf22a2ff73438a86", size = 173126, upload-time = "2026-02-04T22:54:39.462Z" },
-]
-
[[package]]
name = "protobuf"
version = "6.33.5"
source = { registry = "https://pypi.org/simple" }
-resolution-markers = [
- "python_full_version >= '3.14'",
- "python_full_version >= '3.10' and python_full_version < '3.14'",
-]
sdist = { url = "https://files.pythonhosted.org/packages/ba/25/7c72c307aafc96fa87062aa6291d9f7c94836e43214d43722e86037aac02/protobuf-6.33.5.tar.gz", hash = "sha256:6ddcac2a081f8b7b9642c09406bc6a4290128fce5f471cddd165960bb9119e5c", size = 444465, upload-time = "2026-01-29T21:51:33.494Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/b1/79/af92d0a8369732b027e6d6084251dd8e782c685c72da161bd4a2e00fbabb/protobuf-6.33.5-cp310-abi3-win32.whl", hash = "sha256:d71b040839446bac0f4d162e758bea99c8251161dae9d0983a3b88dee345153b", size = 425769, upload-time = "2026-01-29T21:51:21.751Z" },
@@ -4850,36 +3815,13 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/4e/b1/c79468184310de09d75095ed1314b839eb2f72df71097db9d1404a1b2717/protobuf-6.33.5-cp39-abi3-manylinux2014_aarch64.whl", hash = "sha256:9b71e0281f36f179d00cbcb119cb19dec4d14a81393e5ea220f64b286173e190", size = 324638, upload-time = "2026-01-29T21:51:26.423Z" },
{ url = "https://files.pythonhosted.org/packages/c5/f5/65d838092fd01c44d16037953fd4c2cc851e783de9b8f02b27ec4ffd906f/protobuf-6.33.5-cp39-abi3-manylinux2014_s390x.whl", hash = "sha256:8afa18e1d6d20af15b417e728e9f60f3aa108ee76f23c3b2c07a2c3b546d3afd", size = 339411, upload-time = "2026-01-29T21:51:27.446Z" },
{ url = "https://files.pythonhosted.org/packages/9b/53/a9443aa3ca9ba8724fdfa02dd1887c1bcd8e89556b715cfbacca6b63dbec/protobuf-6.33.5-cp39-abi3-manylinux2014_x86_64.whl", hash = "sha256:cbf16ba3350fb7b889fca858fb215967792dc125b35c7976ca4818bee3521cf0", size = 323465, upload-time = "2026-01-29T21:51:28.925Z" },
- { url = "https://files.pythonhosted.org/packages/08/60/84d5f6dcda9165e4d6a56ac8433c9f40a8906bf2966150b8a0cfde097d78/protobuf-6.33.5-cp39-cp39-win32.whl", hash = "sha256:a3157e62729aafb8df6da2c03aa5c0937c7266c626ce11a278b6eb7963c4e37c", size = 425892, upload-time = "2026-01-29T21:51:30.382Z" },
- { url = "https://files.pythonhosted.org/packages/68/19/33d7dc2dc84439587fa1e21e1c0026c01ad2af0a62f58fd54002a7546307/protobuf-6.33.5-cp39-cp39-win_amd64.whl", hash = "sha256:8f04fa32763dcdb4973d537d6b54e615cc61108c7cb38fe59310c3192d29510a", size = 437137, upload-time = "2026-01-29T21:51:31.456Z" },
{ url = "https://files.pythonhosted.org/packages/57/bf/2086963c69bdac3d7cff1cc7ff79b8ce5ea0bec6797a017e1be338a46248/protobuf-6.33.5-py3-none-any.whl", hash = "sha256:69915a973dd0f60f31a08b8318b73eab2bd6a392c79184b3612226b0a3f8ec02", size = 170687, upload-time = "2026-01-29T21:51:32.557Z" },
]
-[[package]]
-name = "pwdlib"
-version = "0.2.1"
-source = { registry = "https://pypi.org/simple" }
-resolution-markers = [
- "python_full_version < '3.10'",
-]
-sdist = { url = "https://files.pythonhosted.org/packages/82/a0/9daed437a6226f632a25d98d65d60ba02bdafa920c90dcb6454c611ead6c/pwdlib-0.2.1.tar.gz", hash = "sha256:9a1d8a8fa09a2f7ebf208265e55d7d008103cbdc82b9e4902ffdd1ade91add5e", size = 11699, upload-time = "2024-08-19T06:48:59.58Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/01/f3/0dae5078a486f0fdf4d4a1121e103bc42694a9da9bea7b0f2c63f29cfbd3/pwdlib-0.2.1-py3-none-any.whl", hash = "sha256:1823dc6f22eae472b540e889ecf57fd424051d6a4023ec0bcf7f0de2d9d7ef8c", size = 8082, upload-time = "2024-08-19T06:49:00.997Z" },
-]
-
-[package.optional-dependencies]
-argon2 = [
- { name = "argon2-cffi", version = "23.1.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
-]
-
[[package]]
name = "pwdlib"
version = "0.3.0"
source = { registry = "https://pypi.org/simple" }
-resolution-markers = [
- "python_full_version >= '3.14'",
- "python_full_version >= '3.10' and python_full_version < '3.14'",
-]
sdist = { url = "https://files.pythonhosted.org/packages/5f/41/a7c0d8a003c36ce3828ae3ed0391fe6a15aad65f082dbd6bec817ea95c0b/pwdlib-0.3.0.tar.gz", hash = "sha256:6ca30f9642a1467d4f5d0a4d18619de1c77f17dfccb42dd200b144127d3c83fc", size = 215810, upload-time = "2025-10-25T12:44:24.395Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/62/0c/9086a357d02a050fbb3270bf5043ac284dbfb845670e16c9389a41defc9e/pwdlib-0.3.0-py3-none-any.whl", hash = "sha256:f86c15c138858c09f3bba0a10984d4f9178158c55deaa72eac0210849b1a140d", size = 8633, upload-time = "2025-10-25T12:44:23.406Z" },
@@ -4887,7 +3829,7 @@ wheels = [
[package.optional-dependencies]
argon2 = [
- { name = "argon2-cffi", version = "25.1.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
+ { name = "argon2-cffi" },
]
[[package]]
@@ -4895,8 +3837,8 @@ name = "py-key-value-aio"
version = "0.3.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "beartype", marker = "python_full_version >= '3.10'" },
- { name = "py-key-value-shared", marker = "python_full_version >= '3.10'" },
+ { name = "beartype" },
+ { name = "py-key-value-shared" },
]
sdist = { url = "https://files.pythonhosted.org/packages/93/ce/3136b771dddf5ac905cc193b461eb67967cf3979688c6696e1f2cdcde7ea/py_key_value_aio-0.3.0.tar.gz", hash = "sha256:858e852fcf6d696d231266da66042d3355a7f9871650415feef9fca7a6cd4155", size = 50801, upload-time = "2025-11-17T16:50:04.711Z" }
wheels = [
@@ -4905,17 +3847,17 @@ wheels = [
[package.optional-dependencies]
disk = [
- { name = "diskcache", marker = "python_full_version >= '3.10'" },
- { name = "pathvalidate", marker = "python_full_version >= '3.10'" },
+ { name = "diskcache" },
+ { name = "pathvalidate" },
]
keyring = [
- { name = "keyring", marker = "python_full_version >= '3.10'" },
+ { name = "keyring" },
]
memory = [
- { name = "cachetools", marker = "python_full_version >= '3.10'" },
+ { name = "cachetools" },
]
redis = [
- { name = "redis", marker = "python_full_version >= '3.10'" },
+ { name = "redis" },
]
[[package]]
@@ -4923,8 +3865,8 @@ name = "py-key-value-shared"
version = "0.3.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "beartype", marker = "python_full_version >= '3.10'" },
- { name = "typing-extensions", marker = "python_full_version >= '3.10'" },
+ { name = "beartype" },
+ { name = "typing-extensions" },
]
sdist = { url = "https://files.pythonhosted.org/packages/7b/e4/1971dfc4620a3a15b4579fe99e024f5edd6e0967a71154771a059daff4db/py_key_value_shared-0.3.0.tar.gz", hash = "sha256:8fdd786cf96c3e900102945f92aa1473138ebe960ef49da1c833790160c28a4b", size = 11666, upload-time = "2025-11-17T16:50:06.849Z" }
wheels = [
@@ -4952,26 +3894,10 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl", hash = "sha256:29253a9207ce32b64c3ac6600edc75368f98473906e8fd1043bd6b5b1de2c14a", size = 181259, upload-time = "2025-03-28T02:41:19.028Z" },
]
-[[package]]
-name = "pycparser"
-version = "2.23"
-source = { registry = "https://pypi.org/simple" }
-resolution-markers = [
- "python_full_version < '3.10'",
-]
-sdist = { url = "https://files.pythonhosted.org/packages/fe/cf/d2d3b9f5699fb1e4615c8e32ff220203e43b248e1dfcc6736ad9057731ca/pycparser-2.23.tar.gz", hash = "sha256:78816d4f24add8f10a06d6f05b4d424ad9e96cfebf68a4ddc99c65c0720d00c2", size = 173734, upload-time = "2025-09-09T13:23:47.91Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/a0/e3/59cd50310fc9b59512193629e1984c1f95e5c8ae6e5d8c69532ccc65a7fe/pycparser-2.23-py3-none-any.whl", hash = "sha256:e5c6e8d3fbad53479cab09ac03729e0a9faf2bee3db8208a550daf5af81a5934", size = 118140, upload-time = "2025-09-09T13:23:46.651Z" },
-]
-
[[package]]
name = "pycparser"
version = "3.0"
source = { registry = "https://pypi.org/simple" }
-resolution-markers = [
- "python_full_version >= '3.14'",
- "python_full_version >= '3.10' and python_full_version < '3.14'",
-]
sdist = { url = "https://files.pythonhosted.org/packages/1b/7d/92392ff7815c21062bea51aa7b87d45576f649f16458d78b7cf94b9ab2e6/pycparser-3.0.tar.gz", hash = "sha256:600f49d217304a5902ac3c37e1281c9fe94e4d0489de643a9504c5cdfdfc6b29", size = 103492, upload-time = "2026-01-21T14:26:51.89Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl", hash = "sha256:b727414169a36b7d524c1c3e31839a521725078d7b2ff038656844266160a992", size = 48172, upload-time = "2026-01-21T14:26:50.693Z" },
@@ -4997,126 +3923,31 @@ email = [
{ name = "email-validator" },
]
-[[package]]
-name = "pydantic-ai"
-version = "0.8.1"
-source = { registry = "https://pypi.org/simple" }
-resolution-markers = [
- "python_full_version < '3.10'",
-]
-dependencies = [
- { name = "pydantic-ai-slim", version = "0.8.1", source = { registry = "https://pypi.org/simple" }, extra = ["ag-ui", "anthropic", "bedrock", "cli", "cohere", "evals", "google", "groq", "huggingface", "mistral", "openai", "retries", "temporal", "vertexai"], marker = "python_full_version < '3.10'" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/56/d7/fcc18ce80008e888404a3615f973aa3f39b98384d61b03621144c9f4c2d4/pydantic_ai-0.8.1.tar.gz", hash = "sha256:05974382082ee4f3706909d06bdfcc5e95f39e29230cc4d00e47429080099844", size = 43772581, upload-time = "2025-08-29T14:46:23.201Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/f9/04/802b8cf834dffcda8baabb3b76c549243694a83346c3f54e47a3a4d519fb/pydantic_ai-0.8.1-py3-none-any.whl", hash = "sha256:5fa923097132aa69b4d6a310b462dc091009c7b87705edf4443d37b887d5ef9a", size = 10188, upload-time = "2025-08-29T14:46:11.137Z" },
-]
-
[[package]]
name = "pydantic-ai"
version = "1.56.0"
source = { registry = "https://pypi.org/simple" }
-resolution-markers = [
- "python_full_version >= '3.14'",
- "python_full_version >= '3.10' and python_full_version < '3.14'",
-]
dependencies = [
- { name = "pydantic-ai-slim", version = "1.56.0", source = { registry = "https://pypi.org/simple" }, extra = ["ag-ui", "anthropic", "bedrock", "cli", "cohere", "evals", "fastmcp", "google", "groq", "huggingface", "logfire", "mcp", "mistral", "openai", "retries", "temporal", "ui", "vertexai", "xai"], marker = "python_full_version >= '3.10'" },
+ { name = "pydantic-ai-slim", extra = ["ag-ui", "anthropic", "bedrock", "cli", "cohere", "evals", "fastmcp", "google", "groq", "huggingface", "logfire", "mcp", "mistral", "openai", "retries", "temporal", "ui", "vertexai", "xai"] },
]
sdist = { url = "https://files.pythonhosted.org/packages/60/1a/800a1e02b259152a49d4c11d9103784a7482c7e9b067eeea23e949d3d80f/pydantic_ai-1.56.0.tar.gz", hash = "sha256:643ff71612df52315b3b4c4b41543657f603f567223eb33245dc8098f005bdc4", size = 11795, upload-time = "2026-02-06T01:13:21.122Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/5c/35/f4a7fd2b9962ddb9b021f76f293e74fda71da190bb74b57ed5b343c93022/pydantic_ai-1.56.0-py3-none-any.whl", hash = "sha256:b6b3ac74bdc004693834750da4420ea2cde0d3cbc3f134c0b7544f98f1c00859", size = 7222, upload-time = "2026-02-06T01:13:11.755Z" },
]
-[[package]]
-name = "pydantic-ai-slim"
-version = "0.8.1"
-source = { registry = "https://pypi.org/simple" }
-resolution-markers = [
- "python_full_version < '3.10'",
-]
-dependencies = [
- { name = "eval-type-backport", marker = "python_full_version < '3.10'" },
- { name = "exceptiongroup", marker = "python_full_version < '3.10'" },
- { name = "genai-prices", marker = "python_full_version < '3.10'" },
- { name = "griffe", version = "1.14.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
- { name = "httpx", marker = "python_full_version < '3.10'" },
- { name = "opentelemetry-api", marker = "python_full_version < '3.10'" },
- { name = "pydantic", marker = "python_full_version < '3.10'" },
- { name = "pydantic-graph", version = "0.8.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
- { name = "typing-inspection", marker = "python_full_version < '3.10'" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/a2/91/08137459b3745900501b3bd11852ced6c81b7ce6e628696d75b09bb786c5/pydantic_ai_slim-0.8.1.tar.gz", hash = "sha256:12ef3dcbe5e1dad195d5e256746ef960f6e59aeddda1a55bdd553ee375ff53ae", size = 218906, upload-time = "2025-08-29T14:46:27.517Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/11/ce/8dbadd04f578d02a9825a46e931005743fe223736296f30b55846c084fab/pydantic_ai_slim-0.8.1-py3-none-any.whl", hash = "sha256:fc7edc141b21fe42bc54a2d92c1127f8a75160c5e57a168dba154d3f4adb963f", size = 297821, upload-time = "2025-08-29T14:46:14.647Z" },
-]
-
-[package.optional-dependencies]
-ag-ui = [
- { name = "ag-ui-protocol", marker = "python_full_version < '3.10'" },
- { name = "starlette", version = "0.49.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
-]
-anthropic = [
- { name = "anthropic", marker = "python_full_version < '3.10'" },
-]
-bedrock = [
- { name = "boto3", marker = "python_full_version < '3.10'" },
-]
-cli = [
- { name = "argcomplete", marker = "python_full_version < '3.10'" },
- { name = "prompt-toolkit", marker = "python_full_version < '3.10'" },
- { name = "pyperclip", marker = "python_full_version < '3.10'" },
- { name = "rich", marker = "python_full_version < '3.10'" },
-]
-cohere = [
- { name = "cohere", marker = "python_full_version < '3.10' and sys_platform != 'emscripten'" },
-]
-evals = [
- { name = "pydantic-evals", version = "0.8.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
-]
-google = [
- { name = "google-genai", version = "1.47.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
-]
-groq = [
- { name = "groq", marker = "python_full_version < '3.10'" },
-]
-huggingface = [
- { name = "huggingface-hub", extra = ["inference"], marker = "python_full_version < '3.10'" },
-]
-mistral = [
- { name = "mistralai", marker = "python_full_version < '3.10'" },
-]
-openai = [
- { name = "openai", marker = "python_full_version < '3.10'" },
-]
-retries = [
- { name = "tenacity", version = "9.1.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
-]
-temporal = [
- { name = "temporalio", version = "1.16.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
-]
-vertexai = [
- { name = "google-auth", marker = "python_full_version < '3.10'" },
- { name = "requests", marker = "python_full_version < '3.10'" },
-]
-
[[package]]
name = "pydantic-ai-slim"
version = "1.56.0"
source = { registry = "https://pypi.org/simple" }
-resolution-markers = [
- "python_full_version >= '3.14'",
- "python_full_version >= '3.10' and python_full_version < '3.14'",
-]
dependencies = [
- { name = "exceptiongroup", marker = "python_full_version == '3.10.*'" },
- { name = "genai-prices", marker = "python_full_version >= '3.10'" },
- { name = "griffe", version = "1.15.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
- { name = "httpx", marker = "python_full_version >= '3.10'" },
- { name = "opentelemetry-api", marker = "python_full_version >= '3.10'" },
- { name = "pydantic", marker = "python_full_version >= '3.10'" },
- { name = "pydantic-graph", version = "1.56.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
- { name = "typing-inspection", marker = "python_full_version >= '3.10'" },
+ { name = "exceptiongroup", marker = "python_full_version < '3.11'" },
+ { name = "genai-prices" },
+ { name = "griffe" },
+ { name = "httpx" },
+ { name = "opentelemetry-api" },
+ { name = "pydantic" },
+ { name = "pydantic-graph" },
+ { name = "typing-inspection" },
]
sdist = { url = "https://files.pythonhosted.org/packages/ce/5c/3a577825b9c1da8f287be7f2ee6fe9aab48bc8a80e65c8518052c589f51c/pydantic_ai_slim-1.56.0.tar.gz", hash = "sha256:9f9f9c56b1c735837880a515ae5661b465b40207b25f3a3434178098b2137f05", size = 415265, upload-time = "2026-02-06T01:13:23.58Z" }
wheels = [
@@ -5125,67 +3956,67 @@ wheels = [
[package.optional-dependencies]
ag-ui = [
- { name = "ag-ui-protocol", marker = "python_full_version >= '3.10'" },
- { name = "starlette", version = "0.52.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
+ { name = "ag-ui-protocol" },
+ { name = "starlette" },
]
anthropic = [
- { name = "anthropic", marker = "python_full_version >= '3.10'" },
+ { name = "anthropic" },
]
bedrock = [
- { name = "boto3", marker = "python_full_version >= '3.10'" },
+ { name = "boto3" },
]
cli = [
- { name = "argcomplete", marker = "python_full_version >= '3.10'" },
- { name = "prompt-toolkit", marker = "python_full_version >= '3.10'" },
- { name = "pyperclip", marker = "python_full_version >= '3.10'" },
- { name = "rich", marker = "python_full_version >= '3.10'" },
+ { name = "argcomplete" },
+ { name = "prompt-toolkit" },
+ { name = "pyperclip" },
+ { name = "rich" },
]
cohere = [
- { name = "cohere", marker = "python_full_version >= '3.10' and sys_platform != 'emscripten'" },
+ { name = "cohere", marker = "sys_platform != 'emscripten'" },
]
evals = [
- { name = "pydantic-evals", version = "1.56.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
+ { name = "pydantic-evals" },
]
fastmcp = [
- { name = "fastmcp", marker = "python_full_version >= '3.10'" },
+ { name = "fastmcp" },
]
google = [
- { name = "google-genai", version = "1.62.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
+ { name = "google-genai" },
]
groq = [
- { name = "groq", marker = "python_full_version >= '3.10'" },
+ { name = "groq" },
]
huggingface = [
- { name = "huggingface-hub", extra = ["inference"], marker = "python_full_version >= '3.10'" },
+ { name = "huggingface-hub", extra = ["inference"] },
]
logfire = [
- { name = "logfire", extra = ["httpx"], marker = "python_full_version >= '3.10'" },
+ { name = "logfire", extra = ["httpx"] },
]
mcp = [
- { name = "mcp", marker = "python_full_version >= '3.10'" },
+ { name = "mcp" },
]
mistral = [
- { name = "mistralai", marker = "python_full_version >= '3.10'" },
+ { name = "mistralai" },
]
openai = [
- { name = "openai", marker = "python_full_version >= '3.10'" },
- { name = "tiktoken", marker = "python_full_version >= '3.10'" },
+ { name = "openai" },
+ { name = "tiktoken" },
]
retries = [
- { name = "tenacity", version = "9.1.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
+ { name = "tenacity" },
]
temporal = [
- { name = "temporalio", version = "1.20.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
+ { name = "temporalio" },
]
ui = [
- { name = "starlette", version = "0.52.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
+ { name = "starlette" },
]
vertexai = [
- { name = "google-auth", marker = "python_full_version >= '3.10'" },
- { name = "requests", marker = "python_full_version >= '3.10'" },
+ { name = "google-auth" },
+ { name = "requests" },
]
xai = [
- { name = "xai-sdk", marker = "python_full_version >= '3.10'" },
+ { name = "xai-sdk" },
]
[[package]]
@@ -5280,19 +4111,6 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/5c/96/5fb7d8c3c17bc8c62fdb031c47d77a1af698f1d7a406b0f79aaa1338f9ad/pydantic_core-2.41.5-cp314-cp314t-win32.whl", hash = "sha256:b4ececa40ac28afa90871c2cc2b9ffd2ff0bf749380fbdf57d165fd23da353aa", size = 1988906, upload-time = "2025-11-04T13:41:56.606Z" },
{ url = "https://files.pythonhosted.org/packages/22/ed/182129d83032702912c2e2d8bbe33c036f342cc735737064668585dac28f/pydantic_core-2.41.5-cp314-cp314t-win_amd64.whl", hash = "sha256:80aa89cad80b32a912a65332f64a4450ed00966111b6615ca6816153d3585a8c", size = 1981607, upload-time = "2025-11-04T13:41:58.889Z" },
{ url = "https://files.pythonhosted.org/packages/9f/ed/068e41660b832bb0b1aa5b58011dea2a3fe0ba7861ff38c4d4904c1c1a99/pydantic_core-2.41.5-cp314-cp314t-win_arm64.whl", hash = "sha256:35b44f37a3199f771c3eaa53051bc8a70cd7b54f333531c59e29fd4db5d15008", size = 1974769, upload-time = "2025-11-04T13:42:01.186Z" },
- { url = "https://files.pythonhosted.org/packages/54/db/160dffb57ed9a3705c4cbcbff0ac03bdae45f1ca7d58ab74645550df3fbd/pydantic_core-2.41.5-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:8bfeaf8735be79f225f3fefab7f941c712aaca36f1128c9d7e2352ee1aa87bdf", size = 2107999, upload-time = "2025-11-04T13:42:03.885Z" },
- { url = "https://files.pythonhosted.org/packages/a3/7d/88e7de946f60d9263cc84819f32513520b85c0f8322f9b8f6e4afc938383/pydantic_core-2.41.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:346285d28e4c8017da95144c7f3acd42740d637ff41946af5ce6e5e420502dd5", size = 1929745, upload-time = "2025-11-04T13:42:06.075Z" },
- { url = "https://files.pythonhosted.org/packages/d5/c2/aef51e5b283780e85e99ff19db0f05842d2d4a8a8cd15e63b0280029b08f/pydantic_core-2.41.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a75dafbf87d6276ddc5b2bf6fae5254e3d0876b626eb24969a574fff9149ee5d", size = 1920220, upload-time = "2025-11-04T13:42:08.457Z" },
- { url = "https://files.pythonhosted.org/packages/c7/97/492ab10f9ac8695cd76b2fdb24e9e61f394051df71594e9bcc891c9f586e/pydantic_core-2.41.5-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7b93a4d08587e2b7e7882de461e82b6ed76d9026ce91ca7915e740ecc7855f60", size = 2067296, upload-time = "2025-11-04T13:42:10.817Z" },
- { url = "https://files.pythonhosted.org/packages/ec/23/984149650e5269c59a2a4c41d234a9570adc68ab29981825cfaf4cfad8f4/pydantic_core-2.41.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e8465ab91a4bd96d36dde3263f06caa6a8a6019e4113f24dc753d79a8b3a3f82", size = 2231548, upload-time = "2025-11-04T13:42:13.843Z" },
- { url = "https://files.pythonhosted.org/packages/71/0c/85bcbb885b9732c28bec67a222dbed5ed2d77baee1f8bba2002e8cd00c5c/pydantic_core-2.41.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:299e0a22e7ae2b85c1a57f104538b2656e8ab1873511fd718a1c1c6f149b77b5", size = 2362571, upload-time = "2025-11-04T13:42:16.208Z" },
- { url = "https://files.pythonhosted.org/packages/c0/4a/412d2048be12c334003e9b823a3fa3d038e46cc2d64dd8aab50b31b65499/pydantic_core-2.41.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:707625ef0983fcfb461acfaf14de2067c5942c6bb0f3b4c99158bed6fedd3cf3", size = 2068175, upload-time = "2025-11-04T13:42:18.911Z" },
- { url = "https://files.pythonhosted.org/packages/73/f4/c58b6a776b502d0a5540ad02e232514285513572060f0d78f7832ca3c98b/pydantic_core-2.41.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f41eb9797986d6ebac5e8edff36d5cef9de40def462311b3eb3eeded1431e425", size = 2177203, upload-time = "2025-11-04T13:42:22.578Z" },
- { url = "https://files.pythonhosted.org/packages/ed/ae/f06ea4c7e7a9eead3d165e7623cd2ea0cb788e277e4f935af63fc98fa4e6/pydantic_core-2.41.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0384e2e1021894b1ff5a786dbf94771e2986ebe2869533874d7e43bc79c6f504", size = 2148191, upload-time = "2025-11-04T13:42:24.89Z" },
- { url = "https://files.pythonhosted.org/packages/c1/57/25a11dcdc656bf5f8b05902c3c2934ac3ea296257cc4a3f79a6319e61856/pydantic_core-2.41.5-cp39-cp39-musllinux_1_1_armv7l.whl", hash = "sha256:f0cd744688278965817fd0839c4a4116add48d23890d468bc436f78beb28abf5", size = 2343907, upload-time = "2025-11-04T13:42:27.683Z" },
- { url = "https://files.pythonhosted.org/packages/96/82/e33d5f4933d7a03327c0c43c65d575e5919d4974ffc026bc917a5f7b9f61/pydantic_core-2.41.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:753e230374206729bf0a807954bcc6c150d3743928a73faffee51ac6557a03c3", size = 2322174, upload-time = "2025-11-04T13:42:30.776Z" },
- { url = "https://files.pythonhosted.org/packages/81/45/4091be67ce9f469e81656f880f3506f6a5624121ec5eb3eab37d7581897d/pydantic_core-2.41.5-cp39-cp39-win32.whl", hash = "sha256:873e0d5b4fb9b89ef7c2d2a963ea7d02879d9da0da8d9d4933dee8ee86a8b460", size = 1990353, upload-time = "2025-11-04T13:42:33.111Z" },
- { url = "https://files.pythonhosted.org/packages/44/8a/a98aede18db6e9cd5d66bcacd8a409fcf8134204cdede2e7de35c5a2c5ef/pydantic_core-2.41.5-cp39-cp39-win_amd64.whl", hash = "sha256:e4f4a984405e91527a0d62649ee21138f8e3d0ef103be488c1dc11a80d7f184b", size = 2015698, upload-time = "2025-11-04T13:42:35.484Z" },
{ url = "https://files.pythonhosted.org/packages/11/72/90fda5ee3b97e51c494938a4a44c3a35a9c96c19bba12372fb9c634d6f57/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-macosx_10_12_x86_64.whl", hash = "sha256:b96d5f26b05d03cc60f11a7761a5ded1741da411e7fe0909e27a5e6a0cb7b034", size = 2115441, upload-time = "2025-11-04T13:42:39.557Z" },
{ url = "https://files.pythonhosted.org/packages/1f/53/8942f884fa33f50794f119012dc6a1a02ac43a56407adaac20463df8e98f/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-macosx_11_0_arm64.whl", hash = "sha256:634e8609e89ceecea15e2d61bc9ac3718caaaa71963717bf3c8f38bfde64242c", size = 1930291, upload-time = "2025-11-04T13:42:42.169Z" },
{ url = "https://files.pythonhosted.org/packages/79/c8/ecb9ed9cd942bce09fc888ee960b52654fbdbede4ba6c2d6e0d3b1d8b49c/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:93e8740d7503eb008aa2df04d3b9735f845d43ae845e6dcd2be0b55a2da43cd2", size = 1948632, upload-time = "2025-11-04T13:42:44.564Z" },
@@ -5319,42 +4137,17 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/36/c7/cfc8e811f061c841d7990b0201912c3556bfeb99cdcb7ed24adc8d6f8704/pydantic_core-2.41.5-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:56121965f7a4dc965bff783d70b907ddf3d57f6eba29b6d2e5dabfaf07799c51", size = 2145302, upload-time = "2025-11-04T13:43:46.64Z" },
]
-[[package]]
-name = "pydantic-evals"
-version = "0.8.1"
-source = { registry = "https://pypi.org/simple" }
-resolution-markers = [
- "python_full_version < '3.10'",
-]
-dependencies = [
- { name = "anyio", marker = "python_full_version < '3.10'" },
- { name = "eval-type-backport", marker = "python_full_version < '3.10'" },
- { name = "logfire-api", marker = "python_full_version < '3.10'" },
- { name = "pydantic", marker = "python_full_version < '3.10'" },
- { name = "pydantic-ai-slim", version = "0.8.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
- { name = "pyyaml", marker = "python_full_version < '3.10'" },
- { name = "rich", marker = "python_full_version < '3.10'" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/6c/9d/460a1f2c9f5f263e9d8e9661acbd654ccc81ad3373ea43048d914091a817/pydantic_evals-0.8.1.tar.gz", hash = "sha256:c398a623c31c19ce70e346ad75654fcb1517c3f6a821461f64fe5cbbe0813023", size = 43933, upload-time = "2025-08-29T14:46:28.903Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/6f/f9/1d21c4687167c4fa76fd3b1ed47f9bc2d38fd94cbacd9aa3f19e82e59830/pydantic_evals-0.8.1-py3-none-any.whl", hash = "sha256:6c76333b1d79632f619eb58a24ac656e9f402c47c75ad750ba0230d7f5514344", size = 52602, upload-time = "2025-08-29T14:46:16.602Z" },
-]
-
[[package]]
name = "pydantic-evals"
version = "1.56.0"
source = { registry = "https://pypi.org/simple" }
-resolution-markers = [
- "python_full_version >= '3.14'",
- "python_full_version >= '3.10' and python_full_version < '3.14'",
-]
dependencies = [
- { name = "anyio", marker = "python_full_version >= '3.10'" },
- { name = "logfire-api", marker = "python_full_version >= '3.10'" },
- { name = "pydantic", marker = "python_full_version >= '3.10'" },
- { name = "pydantic-ai-slim", version = "1.56.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
- { name = "pyyaml", marker = "python_full_version >= '3.10'" },
- { name = "rich", marker = "python_full_version >= '3.10'" },
+ { name = "anyio" },
+ { name = "logfire-api" },
+ { name = "pydantic" },
+ { name = "pydantic-ai-slim" },
+ { name = "pyyaml" },
+ { name = "rich" },
]
sdist = { url = "https://files.pythonhosted.org/packages/98/f2/8c59284a2978af3fbda45ae3217218eaf8b071207a9290b54b7613983e5d/pydantic_evals-1.56.0.tar.gz", hash = "sha256:206635107127af6a3ee4b1fc8f77af6afb14683615a2d6b3609f79467c1c0d28", size = 47210, upload-time = "2026-02-06T01:13:25.714Z" }
wheels = [
@@ -5374,72 +4167,29 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/fe/17/fabd56da47096d240dd45ba627bead0333b0cf0ee8ada9bec579287dadf3/pydantic_extra_types-2.11.0-py3-none-any.whl", hash = "sha256:84b864d250a0fc62535b7ec591e36f2c5b4d1325fa0017eb8cda9aeb63b374a6", size = 74296, upload-time = "2025-12-31T16:18:26.38Z" },
]
-[[package]]
-name = "pydantic-graph"
-version = "0.8.1"
-source = { registry = "https://pypi.org/simple" }
-resolution-markers = [
- "python_full_version < '3.10'",
-]
-dependencies = [
- { name = "httpx", marker = "python_full_version < '3.10'" },
- { name = "logfire-api", marker = "python_full_version < '3.10'" },
- { name = "pydantic", marker = "python_full_version < '3.10'" },
- { name = "typing-inspection", marker = "python_full_version < '3.10'" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/bd/97/b35b7cb82d9f1bb6d5c6d21bba54f6196a3a5f593373f3a9c163a3821fd7/pydantic_graph-0.8.1.tar.gz", hash = "sha256:c61675a05c74f661d4ff38d04b74bd652c1e0959467801986f2f85dc7585410d", size = 21675, upload-time = "2025-08-29T14:46:29.839Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/3d/e3/5908643b049bb2384d143885725cbeb0f53707d418357d4d1ac8d2c82629/pydantic_graph-0.8.1-py3-none-any.whl", hash = "sha256:f1dd5db0fe22f4e3323c04c65e2f0013846decc312b3efc3196666764556b765", size = 27239, upload-time = "2025-08-29T14:46:18.317Z" },
-]
-
[[package]]
name = "pydantic-graph"
version = "1.56.0"
source = { registry = "https://pypi.org/simple" }
-resolution-markers = [
- "python_full_version >= '3.14'",
- "python_full_version >= '3.10' and python_full_version < '3.14'",
-]
dependencies = [
- { name = "httpx", marker = "python_full_version >= '3.10'" },
- { name = "logfire-api", marker = "python_full_version >= '3.10'" },
- { name = "pydantic", marker = "python_full_version >= '3.10'" },
- { name = "typing-inspection", marker = "python_full_version >= '3.10'" },
+ { name = "httpx" },
+ { name = "logfire-api" },
+ { name = "pydantic" },
+ { name = "typing-inspection" },
]
sdist = { url = "https://files.pythonhosted.org/packages/ff/03/f92881cdb12d6f43e60e9bfd602e41c95408f06e2324d3729f7a194e2bcd/pydantic_graph-1.56.0.tar.gz", hash = "sha256:5e22972dbb43dbc379ab9944252ff864019abf3c7d465dcdf572fc8aec9a44a1", size = 58460, upload-time = "2026-02-06T01:13:26.708Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/08/07/8c823eb4d196137c123d4d67434e185901d3cbaea3b0c2b7667da84e72c1/pydantic_graph-1.56.0-py3-none-any.whl", hash = "sha256:ec3f0a1d6fcedd4eb9c59fef45079c2ee4d4185878d70dae26440a9c974c6bb3", size = 72346, upload-time = "2026-02-06T01:13:18.792Z" },
]
-[[package]]
-name = "pydantic-settings"
-version = "2.11.0"
-source = { registry = "https://pypi.org/simple" }
-resolution-markers = [
- "python_full_version < '3.10'",
-]
-dependencies = [
- { name = "pydantic", marker = "python_full_version < '3.10'" },
- { name = "python-dotenv", marker = "python_full_version < '3.10'" },
- { name = "typing-inspection", marker = "python_full_version < '3.10'" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/20/c5/dbbc27b814c71676593d1c3f718e6cd7d4f00652cefa24b75f7aa3efb25e/pydantic_settings-2.11.0.tar.gz", hash = "sha256:d0e87a1c7d33593beb7194adb8470fc426e95ba02af83a0f23474a04c9a08180", size = 188394, upload-time = "2025-09-24T14:19:11.764Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/83/d6/887a1ff844e64aa823fb4905978d882a633cfe295c32eacad582b78a7d8b/pydantic_settings-2.11.0-py3-none-any.whl", hash = "sha256:fe2cea3413b9530d10f3a5875adffb17ada5c1e1bab0b2885546d7310415207c", size = 48608, upload-time = "2025-09-24T14:19:10.015Z" },
-]
-
[[package]]
name = "pydantic-settings"
version = "2.12.0"
source = { registry = "https://pypi.org/simple" }
-resolution-markers = [
- "python_full_version >= '3.14'",
- "python_full_version >= '3.10' and python_full_version < '3.14'",
-]
dependencies = [
- { name = "pydantic", marker = "python_full_version >= '3.10'" },
- { name = "python-dotenv", marker = "python_full_version >= '3.10'" },
- { name = "typing-inspection", marker = "python_full_version >= '3.10'" },
+ { name = "pydantic" },
+ { name = "python-dotenv" },
+ { name = "typing-inspection" },
]
sdist = { url = "https://files.pythonhosted.org/packages/43/4b/ac7e0aae12027748076d72a8764ff1c9d82ca75a7a52622e67ed3f765c54/pydantic_settings-2.12.0.tar.gz", hash = "sha256:005538ef951e3c2a68e1c08b292b5f2e71490def8589d4221b95dab00dafcfd0", size = 194184, upload-time = "2025-11-10T14:25:47.013Z" }
wheels = [
@@ -5451,19 +4201,19 @@ name = "pydocket"
version = "0.17.5"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "cloudpickle", marker = "python_full_version >= '3.10'" },
- { name = "croniter", marker = "python_full_version >= '3.10'" },
- { name = "exceptiongroup", marker = "python_full_version == '3.10.*'" },
- { name = "fakeredis", extra = ["lua"], marker = "python_full_version >= '3.10'" },
- { name = "opentelemetry-api", marker = "python_full_version >= '3.10'" },
- { name = "prometheus-client", marker = "python_full_version >= '3.10'" },
- { name = "py-key-value-aio", extra = ["memory", "redis"], marker = "python_full_version >= '3.10'" },
- { name = "python-json-logger", marker = "python_full_version >= '3.10'" },
- { name = "redis", marker = "python_full_version >= '3.10'" },
- { name = "rich", marker = "python_full_version >= '3.10'" },
- { name = "taskgroup", marker = "python_full_version == '3.10.*'" },
- { name = "typer", marker = "python_full_version >= '3.10'" },
- { name = "typing-extensions", marker = "python_full_version >= '3.10'" },
+ { name = "cloudpickle" },
+ { name = "croniter" },
+ { name = "exceptiongroup", marker = "python_full_version < '3.11'" },
+ { name = "fakeredis", extra = ["lua"] },
+ { name = "opentelemetry-api" },
+ { name = "prometheus-client" },
+ { name = "py-key-value-aio", extra = ["memory", "redis"] },
+ { name = "python-json-logger" },
+ { name = "redis" },
+ { name = "rich" },
+ { name = "taskgroup", marker = "python_full_version < '3.11'" },
+ { name = "typer" },
+ { name = "typing-extensions" },
]
sdist = { url = "https://files.pythonhosted.org/packages/73/26/ac23ead3725475468b50b486939bf5feda27180050a614a7407344a0af0e/pydocket-0.17.5.tar.gz", hash = "sha256:19a6976d8fd11c1acf62feb0291a339e06beaefa100f73dd38c6499760ad3e62", size = 334829, upload-time = "2026-01-30T18:44:39.702Z" }
wheels = [
@@ -5491,8 +4241,7 @@ dependencies = [
{ name = "pynacl" },
{ name = "requests" },
{ name = "typing-extensions" },
- { name = "urllib3", version = "1.26.20", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
- { name = "urllib3", version = "2.6.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
+ { name = "urllib3" },
]
sdist = { url = "https://files.pythonhosted.org/packages/c1/74/e560bdeffea72ecb26cff27f0fad548bbff5ecc51d6a155311ea7f9e4c4c/pygithub-2.8.1.tar.gz", hash = "sha256:341b7c78521cb07324ff670afd1baa2bf5c286f8d9fd302c1798ba594a5400c9", size = 2246994, upload-time = "2025-09-02T17:41:54.674Z" }
wheels = [
@@ -5527,8 +4276,7 @@ name = "pymdown-extensions"
version = "10.20.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "markdown", version = "3.9", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
- { name = "markdown", version = "3.10.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
+ { name = "markdown" },
{ name = "pyyaml" },
]
sdist = { url = "https://files.pythonhosted.org/packages/1e/6c/9e370934bfa30e889d12e61d0dae009991294f40055c238980066a7fbd83/pymdown_extensions-10.20.1.tar.gz", hash = "sha256:e7e39c865727338d434b55f1dd8da51febcffcaebd6e1a0b9c836243f660740a", size = 852860, upload-time = "2026-01-24T05:56:56.758Z" }
@@ -5587,8 +4335,7 @@ source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "colorama", marker = "sys_platform == 'win32'" },
{ name = "exceptiongroup", marker = "python_full_version < '3.11'" },
- { name = "iniconfig", version = "2.1.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
- { name = "iniconfig", version = "2.3.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
+ { name = "iniconfig" },
{ name = "packaging" },
{ name = "pluggy" },
{ name = "pygments" },
@@ -5605,7 +4352,6 @@ version = "4.2.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "cffi" },
- { name = "importlib-metadata", marker = "python_full_version < '3.10'" },
{ name = "pytest" },
{ name = "rich" },
]
@@ -5623,8 +4369,6 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/f9/14/8d9340d7dc0ae647991b28a396e16b3403e10def883cde90d6b663d3f7ec/pytest_codspeed-4.2.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a0ebd87f2a99467a1cfd8e83492c4712976e43d353ee0b5f71cbb057f1393aca", size = 251057, upload-time = "2025-10-24T09:02:49.102Z" },
{ url = "https://files.pythonhosted.org/packages/4b/39/48cf6afbca55bc7c8c93c3d4ae926a1068bcce3f0241709db19b078d5418/pytest_codspeed-4.2.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:dbbb2d61b85bef8fc7e2193f723f9ac2db388a48259d981bbce96319043e9830", size = 267983, upload-time = "2025-10-24T09:02:50.558Z" },
{ url = "https://files.pythonhosted.org/packages/33/86/4407341efb5dceb3e389635749ce1d670542d6ca148bd34f9d5334295faf/pytest_codspeed-4.2.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:748411c832147bfc85f805af78a1ab1684f52d08e14aabe22932bbe46c079a5f", size = 256732, upload-time = "2025-10-24T09:02:51.603Z" },
- { url = "https://files.pythonhosted.org/packages/fe/60/c395c19c14a1345d41ac3f7f0a9b372b666e88f9ba1f71988215174882bb/pytest_codspeed-4.2.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:238e17abe8f08d8747fa6c7acff34fefd3c40f17a56a7847ca13dc8d6e8c6009", size = 261935, upload-time = "2025-10-24T09:02:52.702Z" },
- { url = "https://files.pythonhosted.org/packages/15/ed/442fb6a1832c2c9002653f24770873839b24c091bd2ed658090c7862c563/pytest_codspeed-4.2.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0881a736285f33b9a8894da8fe8e1775aa1a4310226abe5d1f0329228efb680c", size = 250770, upload-time = "2025-10-24T09:02:53.73Z" },
{ url = "https://files.pythonhosted.org/packages/25/0e/8cb71fd3ed4ed08c07aec1245aea7bc1b661ba55fd9c392db76f1978d453/pytest_codspeed-4.2.0-py3-none-any.whl", hash = "sha256:e81bbb45c130874ef99aca97929d72682733527a49f84239ba575b5cb843bab0", size = 113726, upload-time = "2025-10-24T09:02:54.785Z" },
]
@@ -5658,26 +4402,10 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/51/e5/fecf13f06e5e5f67e8837d777d1bc43fac0ed2b77a676804df5c34744727/python_json_logger-4.0.0-py3-none-any.whl", hash = "sha256:af09c9daf6a813aa4cc7180395f50f2a9e5fa056034c9953aec92e381c5ba1e2", size = 15548, upload-time = "2025-10-06T04:15:17.553Z" },
]
-[[package]]
-name = "python-multipart"
-version = "0.0.20"
-source = { registry = "https://pypi.org/simple" }
-resolution-markers = [
- "python_full_version < '3.10'",
-]
-sdist = { url = "https://files.pythonhosted.org/packages/f3/87/f44d7c9f274c7ee665a29b885ec97089ec5dc034c7f3fafa03da9e39a09e/python_multipart-0.0.20.tar.gz", hash = "sha256:8dd0cab45b8e23064ae09147625994d090fa46f5b0d1e13af944c331a7fa9d13", size = 37158, upload-time = "2024-12-16T19:45:46.972Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/45/58/38b5afbc1a800eeea951b9285d3912613f2603bdf897a4ab0f4bd7f405fc/python_multipart-0.0.20-py3-none-any.whl", hash = "sha256:8a62d3a8335e06589fe01f2a3e178cdcc632f3fbe0d492ad9ee0ec35aab1f104", size = 24546, upload-time = "2024-12-16T19:45:44.423Z" },
-]
-
[[package]]
name = "python-multipart"
version = "0.0.22"
source = { registry = "https://pypi.org/simple" }
-resolution-markers = [
- "python_full_version >= '3.14'",
- "python_full_version >= '3.10' and python_full_version < '3.14'",
-]
sdist = { url = "https://files.pythonhosted.org/packages/94/01/979e98d542a70714b0cb2b6728ed0b7c46792b695e3eaec3e20711271ca3/python_multipart-0.0.22.tar.gz", hash = "sha256:7340bef99a7e0032613f56dc36027b959fd3b30a787ed62d310e951f7c3a3a58", size = 37612, upload-time = "2026-01-25T10:15:56.219Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/1b/d0/397f9626e711ff749a95d96b7af99b9c566a9bb5129b8e4c10fc4d100304/python_multipart-0.0.22-py3-none-any.whl", hash = "sha256:2b2cd894c83d21bf49d702499531c7bafd057d730c201782048f7945d82de155", size = 24579, upload-time = "2026-01-25T10:15:54.811Z" },
@@ -5731,11 +4459,6 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/cf/35/3aa899645e29b6375b4aed9f8d21df219e7c958c4c186b465e42ee0a06bf/pytokens-0.4.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d31b97b3de0f61571a124a00ffe9a81fb9939146c122c11060725bd5aea79975", size = 303485, upload-time = "2026-01-30T01:03:28.558Z" },
{ url = "https://files.pythonhosted.org/packages/52/a0/07907b6ff512674d9b201859f7d212298c44933633c946703a20c25e9d81/pytokens-0.4.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:967cf6e3fd4adf7de8fc73cd3043754ae79c36475c1c11d514fc72cf5490094a", size = 306698, upload-time = "2026-01-30T01:03:29.653Z" },
{ url = "https://files.pythonhosted.org/packages/39/2a/cbbf9250020a4a8dd53ba83a46c097b69e5eb49dd14e708f496f548c6612/pytokens-0.4.1-cp314-cp314t-win_amd64.whl", hash = "sha256:584c80c24b078eec1e227079d56dc22ff755e0ba8654d8383b2c549107528918", size = 116287, upload-time = "2026-01-30T01:03:30.912Z" },
- { url = "https://files.pythonhosted.org/packages/51/2a/f125667ce48105bf1f4e50e03cfa7b24b8c4f47684d7f1cf4dcb6f6b1c15/pytokens-0.4.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:34bcc734bd2f2d5fe3b34e7b3c0116bfb2397f2d9666139988e7a3eb5f7400e3", size = 161464, upload-time = "2026-01-30T01:03:39.11Z" },
- { url = "https://files.pythonhosted.org/packages/40/df/065a30790a7ca6bb48ad9018dd44668ed9135610ebf56a2a4cb8e513fd5c/pytokens-0.4.1-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:941d4343bf27b605e9213b26bfa1c4bf197c9c599a9627eb7305b0defcfe40c1", size = 246159, upload-time = "2026-01-30T01:03:40.131Z" },
- { url = "https://files.pythonhosted.org/packages/a5/1c/fd09976a7e04960dabc07ab0e0072c7813d566ec67d5490a4c600683c158/pytokens-0.4.1-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3ad72b851e781478366288743198101e5eb34a414f1d5627cdd585ca3b25f1db", size = 259120, upload-time = "2026-01-30T01:03:41.233Z" },
- { url = "https://files.pythonhosted.org/packages/52/49/59fdc6fc5a390ae9f308eadeb97dfc70fc2d804ffc49dd39fc97604622ec/pytokens-0.4.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:682fa37ff4d8e95f7df6fe6fe6a431e8ed8e788023c6bcc0f0880a12eab80ad1", size = 262196, upload-time = "2026-01-30T01:03:42.696Z" },
- { url = "https://files.pythonhosted.org/packages/3d/e7/d6734dccf0080e3dc00a55b0827ab5af30c886f8bc127bbc04bc3445daec/pytokens-0.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:30f51edd9bb7f85c748979384165601d028b84f7bd13fe14d3e065304093916a", size = 103510, upload-time = "2026-01-30T01:03:43.915Z" },
{ url = "https://files.pythonhosted.org/packages/c6/78/397db326746f0a342855b81216ae1f0a32965deccfd7c830a2dbc66d2483/pytokens-0.4.1-py3-none-any.whl", hash = "sha256:26cef14744a8385f35d0e095dc8b3a7583f6c953c2e3d269c7f82484bf5ad2de", size = 13729, upload-time = "2026-01-30T01:03:45.029Z" },
]
@@ -5768,9 +4491,6 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/c9/31/097f2e132c4f16d99a22bfb777e0fd88bd8e1c634304e102f313af69ace5/pywin32-311-cp314-cp314-win32.whl", hash = "sha256:b7a2c10b93f8986666d0c803ee19b5990885872a7de910fc460f9b0c2fbf92ee", size = 8840714, upload-time = "2025-07-14T20:13:32.449Z" },
{ url = "https://files.pythonhosted.org/packages/90/4b/07c77d8ba0e01349358082713400435347df8426208171ce297da32c313d/pywin32-311-cp314-cp314-win_amd64.whl", hash = "sha256:3aca44c046bd2ed8c90de9cb8427f581c479e594e99b5c0bb19b29c10fd6cb87", size = 9656800, upload-time = "2025-07-14T20:13:34.312Z" },
{ url = "https://files.pythonhosted.org/packages/c0/d2/21af5c535501a7233e734b8af901574572da66fcc254cb35d0609c9080dd/pywin32-311-cp314-cp314-win_arm64.whl", hash = "sha256:a508e2d9025764a8270f93111a970e1d0fbfc33f4153b388bb649b7eec4f9b42", size = 8932540, upload-time = "2025-07-14T20:13:36.379Z" },
- { url = "https://files.pythonhosted.org/packages/59/42/b86689aac0cdaee7ae1c58d464b0ff04ca909c19bb6502d4973cdd9f9544/pywin32-311-cp39-cp39-win32.whl", hash = "sha256:aba8f82d551a942cb20d4a83413ccbac30790b50efb89a75e4f586ac0bb8056b", size = 8760837, upload-time = "2025-07-14T20:12:59.59Z" },
- { url = "https://files.pythonhosted.org/packages/9f/8a/1403d0353f8c5a2f0829d2b1c4becbf9da2f0a4d040886404fc4a5431e4d/pywin32-311-cp39-cp39-win_amd64.whl", hash = "sha256:e0c4cfb0621281fe40387df582097fd796e80430597cb9944f0ae70447bacd91", size = 9590187, upload-time = "2025-07-14T20:13:01.419Z" },
- { url = "https://files.pythonhosted.org/packages/60/22/e0e8d802f124772cec9c75430b01a212f86f9de7546bda715e54140d5aeb/pywin32-311-cp39-cp39-win_arm64.whl", hash = "sha256:62ea666235135fee79bb154e695f3ff67370afefd71bd7fea7512fc70ef31e3d", size = 8778162, upload-time = "2025-07-14T20:13:03.544Z" },
]
[[package]]
@@ -5844,15 +4564,6 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/da/92/1446574745d74df0c92e6aa4a7b0b3130706a4142b2d1a5869f2eaa423c6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65", size = 829923, upload-time = "2025-09-25T21:32:54.537Z" },
{ url = "https://files.pythonhosted.org/packages/f0/7a/1c7270340330e575b92f397352af856a8c06f230aa3e76f86b39d01b416a/pyyaml-6.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9", size = 174062, upload-time = "2025-09-25T21:32:55.767Z" },
{ url = "https://files.pythonhosted.org/packages/f1/12/de94a39c2ef588c7e6455cfbe7343d3b2dc9d6b6b2f40c4c6565744c873d/pyyaml-6.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b", size = 149341, upload-time = "2025-09-25T21:32:56.828Z" },
- { url = "https://files.pythonhosted.org/packages/9f/62/67fc8e68a75f738c9200422bf65693fb79a4cd0dc5b23310e5202e978090/pyyaml-6.0.3-cp39-cp39-macosx_10_13_x86_64.whl", hash = "sha256:b865addae83924361678b652338317d1bd7e79b1f4596f96b96c77a5a34b34da", size = 184450, upload-time = "2025-09-25T21:33:00.618Z" },
- { url = "https://files.pythonhosted.org/packages/ae/92/861f152ce87c452b11b9d0977952259aa7df792d71c1053365cc7b09cc08/pyyaml-6.0.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c3355370a2c156cffb25e876646f149d5d68f5e0a3ce86a5084dd0b64a994917", size = 174319, upload-time = "2025-09-25T21:33:02.086Z" },
- { url = "https://files.pythonhosted.org/packages/d0/cd/f0cfc8c74f8a030017a2b9c771b7f47e5dd702c3e28e5b2071374bda2948/pyyaml-6.0.3-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3c5677e12444c15717b902a5798264fa7909e41153cdf9ef7ad571b704a63dd9", size = 737631, upload-time = "2025-09-25T21:33:03.25Z" },
- { url = "https://files.pythonhosted.org/packages/ef/b2/18f2bd28cd2055a79a46c9b0895c0b3d987ce40ee471cecf58a1a0199805/pyyaml-6.0.3-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5ed875a24292240029e4483f9d4a4b8a1ae08843b9c54f43fcc11e404532a8a5", size = 836795, upload-time = "2025-09-25T21:33:05.014Z" },
- { url = "https://files.pythonhosted.org/packages/73/b9/793686b2d54b531203c160ef12bec60228a0109c79bae6c1277961026770/pyyaml-6.0.3-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0150219816b6a1fa26fb4699fb7daa9caf09eb1999f3b70fb6e786805e80375a", size = 750767, upload-time = "2025-09-25T21:33:06.398Z" },
- { url = "https://files.pythonhosted.org/packages/a9/86/a137b39a611def2ed78b0e66ce2fe13ee701a07c07aebe55c340ed2a050e/pyyaml-6.0.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:fa160448684b4e94d80416c0fa4aac48967a969efe22931448d853ada8baf926", size = 727982, upload-time = "2025-09-25T21:33:08.708Z" },
- { url = "https://files.pythonhosted.org/packages/dd/62/71c27c94f457cf4418ef8ccc71735324c549f7e3ea9d34aba50874563561/pyyaml-6.0.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:27c0abcb4a5dac13684a37f76e701e054692a9b2d3064b70f5e4eb54810553d7", size = 755677, upload-time = "2025-09-25T21:33:09.876Z" },
- { url = "https://files.pythonhosted.org/packages/29/3d/6f5e0d58bd924fb0d06c3a6bad00effbdae2de5adb5cda5648006ffbd8d3/pyyaml-6.0.3-cp39-cp39-win32.whl", hash = "sha256:1ebe39cb5fc479422b83de611d14e2c0d3bb2a18bbcb01f229ab3cfbd8fee7a0", size = 142592, upload-time = "2025-09-25T21:33:10.983Z" },
- { url = "https://files.pythonhosted.org/packages/f0/0c/25113e0b5e103d7f1490c0e947e303fe4a696c10b501dea7a9f49d4e876c/pyyaml-6.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:2e71d11abed7344e42a8849600193d15b6def118602c4c176f748e4583246007", size = 158777, upload-time = "2025-09-25T21:33:15.55Z" },
]
[[package]]
@@ -5881,7 +4592,7 @@ name = "redis"
version = "7.1.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "async-timeout", marker = "python_full_version >= '3.10' and python_full_version < '3.11.3'" },
+ { name = "async-timeout", marker = "python_full_version < '3.11.3'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/43/c8/983d5c6579a411d8a99bc5823cc5712768859b5ce2c8afe1a65b37832c81/redis-7.1.0.tar.gz", hash = "sha256:b1cc3cfa5a2cb9c2ab3ba700864fb0ad75617b41f01352ce5779dabf6d5f9c3c", size = 4796669, upload-time = "2025-11-19T15:54:39.961Z" }
wheels = [
@@ -5893,9 +4604,9 @@ name = "referencing"
version = "0.36.2"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "attrs", marker = "python_full_version >= '3.10'" },
- { name = "rpds-py", marker = "python_full_version >= '3.10'" },
- { name = "typing-extensions", marker = "python_full_version >= '3.10' and python_full_version < '3.13'" },
+ { name = "attrs" },
+ { name = "rpds-py" },
+ { name = "typing-extensions", marker = "python_full_version < '3.13'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/2f/db/98b5c277be99dd18bfd91dd04e1b759cad18d1a338188c936e92f921c7e2/referencing-0.36.2.tar.gz", hash = "sha256:df2e89862cd09deabbdba16944cc3f10feb6b3e6f18e902f7cc25609a34775aa", size = 74744, upload-time = "2025-01-25T08:48:16.138Z" }
wheels = [
@@ -6021,23 +4732,6 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/e3/0d/3a6cfa9ae99606afb612d8fb7a66b245a9d5ff0f29bb347c8a30b6ad561b/regex-2026.1.15-cp314-cp314t-win32.whl", hash = "sha256:e90b8db97f6f2c97eb045b51a6b2c5ed69cedd8392459e0642d4199b94fabd7e", size = 274667, upload-time = "2026-01-14T23:17:19.301Z" },
{ url = "https://files.pythonhosted.org/packages/5b/b2/297293bb0742fd06b8d8e2572db41a855cdf1cae0bf009b1cb74fe07e196/regex-2026.1.15-cp314-cp314t-win_amd64.whl", hash = "sha256:5ef19071f4ac9f0834793af85bd04a920b4407715624e40cb7a0631a11137cdf", size = 284386, upload-time = "2026-01-14T23:17:21.231Z" },
{ url = "https://files.pythonhosted.org/packages/95/e4/a3b9480c78cf8ee86626cb06f8d931d74d775897d44201ccb813097ae697/regex-2026.1.15-cp314-cp314t-win_arm64.whl", hash = "sha256:ca89c5e596fc05b015f27561b3793dc2fa0917ea0d7507eebb448efd35274a70", size = 274837, upload-time = "2026-01-14T23:17:23.146Z" },
- { url = "https://files.pythonhosted.org/packages/a2/e7/0e1913dc52eee9c5cf8417c9813c4c55972a3f37d27cfa2e623b79b63dbc/regex-2026.1.15-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:55b4ea996a8e4458dd7b584a2f89863b1655dd3d17b88b46cbb9becc495a0ec5", size = 488185, upload-time = "2026-01-14T23:17:25.2Z" },
- { url = "https://files.pythonhosted.org/packages/78/df/c52c1ff4221529faad0953e197982fe9508c6dbb42327e31bf98ea07472a/regex-2026.1.15-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7e1e28be779884189cdd57735e997f282b64fd7ccf6e2eef3e16e57d7a34a815", size = 290628, upload-time = "2026-01-14T23:17:27.125Z" },
- { url = "https://files.pythonhosted.org/packages/4b/d2/a2fef3717deaff647d7de2bccf899a576c7eaf042b6b271fc4474515fe97/regex-2026.1.15-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0057de9eaef45783ff69fa94ae9f0fd906d629d0bd4c3217048f46d1daa32e9b", size = 288509, upload-time = "2026-01-14T23:17:29.017Z" },
- { url = "https://files.pythonhosted.org/packages/70/89/faf5ee5c69168753c845a3d58b4683f61c899d162bfe1264fca88d5b3924/regex-2026.1.15-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cc7cd0b2be0f0269283a45c0d8b2c35e149d1319dcb4a43c9c3689fa935c1ee6", size = 781088, upload-time = "2026-01-14T23:17:30.961Z" },
- { url = "https://files.pythonhosted.org/packages/7d/2c/707e5c380ad547c93686e21144e7e24dc2064dd84ec5b751b6dbdfc9be2b/regex-2026.1.15-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8db052bbd981e1666f09e957f3790ed74080c2229007c1dd67afdbf0b469c48b", size = 850516, upload-time = "2026-01-14T23:17:32.946Z" },
- { url = "https://files.pythonhosted.org/packages/5d/3b/baa816cdcad1c0f8195f9f40ab2b2a2246c8a2989dcd90641c0c6559e3fd/regex-2026.1.15-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:343db82cb3712c31ddf720f097ef17c11dab2f67f7a3e7be976c4f82eba4e6df", size = 898124, upload-time = "2026-01-14T23:17:36.019Z" },
- { url = "https://files.pythonhosted.org/packages/e7/74/1eb46bde30899825ed9fdf645eba16b7b97c49d12d300f5177989b9a09a4/regex-2026.1.15-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:55e9d0118d97794367309635df398bdfd7c33b93e2fdfa0b239661cd74b4c14e", size = 791290, upload-time = "2026-01-14T23:17:38.097Z" },
- { url = "https://files.pythonhosted.org/packages/c4/5d/b72e176fb21e2ec248baed01151a342d1f44dd43c2b6bb6a41ad183b274e/regex-2026.1.15-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:008b185f235acd1e53787333e5690082e4f156c44c87d894f880056089e9bc7c", size = 781996, upload-time = "2026-01-14T23:17:40.109Z" },
- { url = "https://files.pythonhosted.org/packages/61/0e/d3b3710eaafd994a4a71205d114abc38cda8691692a2ce2313abe68e7eb7/regex-2026.1.15-cp39-cp39-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:fd65af65e2aaf9474e468f9e571bd7b189e1df3a61caa59dcbabd0000e4ea839", size = 767578, upload-time = "2026-01-14T23:17:42.134Z" },
- { url = "https://files.pythonhosted.org/packages/09/51/c6a6311833e040f95d229a34d82ac1cec2af8a5c00d58b244f2fceecef87/regex-2026.1.15-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:f42e68301ff4afee63e365a5fc302b81bb8ba31af625a671d7acb19d10168a8c", size = 774354, upload-time = "2026-01-14T23:17:44.392Z" },
- { url = "https://files.pythonhosted.org/packages/cc/97/c522d1f19fb2c549aaf680b115c110cd124c02062bc8c95f33db8583b4bb/regex-2026.1.15-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:f7792f27d3ee6e0244ea4697d92b825f9a329ab5230a78c1a68bd274e64b5077", size = 845297, upload-time = "2026-01-14T23:17:47.145Z" },
- { url = "https://files.pythonhosted.org/packages/99/a0/99468c386ab68a5e24c946c5c353c29c33a95523e275c17839f2446db15d/regex-2026.1.15-cp39-cp39-musllinux_1_2_riscv64.whl", hash = "sha256:dbaf3c3c37ef190439981648ccbf0c02ed99ae066087dd117fcb616d80b010a4", size = 755132, upload-time = "2026-01-14T23:17:49.796Z" },
- { url = "https://files.pythonhosted.org/packages/70/33/d5748c7b6c9d3621f12570583561ba529e2d1b12e4f70b8f17979b133e65/regex-2026.1.15-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:adc97a9077c2696501443d8ad3fa1b4fc6d131fc8fd7dfefd1a723f89071cf0a", size = 835662, upload-time = "2026-01-14T23:17:52.559Z" },
- { url = "https://files.pythonhosted.org/packages/ad/15/1986972c276672505437f1ba3c9706c2d91f321cfb9b2f4d06e8bff1b999/regex-2026.1.15-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:069f56a7bf71d286a6ff932a9e6fb878f151c998ebb2519a9f6d1cee4bffdba3", size = 779513, upload-time = "2026-01-14T23:17:54.711Z" },
- { url = "https://files.pythonhosted.org/packages/bc/f9/124f6a5cb3969d8e30471ed4f46cfc17c47aef1a9863ee8b4ba1d98b1bc4/regex-2026.1.15-cp39-cp39-win32.whl", hash = "sha256:ea4e6b3566127fda5e007e90a8fd5a4169f0cf0619506ed426db647f19c8454a", size = 265923, upload-time = "2026-01-14T23:17:56.69Z" },
- { url = "https://files.pythonhosted.org/packages/7b/c2/bb8fad7d27f1d71fc9772befd544bccd22eddc62a6735f57b003b4aff005/regex-2026.1.15-cp39-cp39-win_amd64.whl", hash = "sha256:cda1ed70d2b264952e88adaa52eea653a33a1b98ac907ae2f86508eb44f65cdc", size = 277900, upload-time = "2026-01-14T23:17:58.72Z" },
- { url = "https://files.pythonhosted.org/packages/f7/fa/4e033327c1d8350bc812cac906d873984d3d4b39529252f392a47ccc356d/regex-2026.1.15-cp39-cp39-win_arm64.whl", hash = "sha256:b325d4714c3c48277bfea1accd94e193ad6ed42b4bad79ad64f3b8f8a31260a5", size = 270413, upload-time = "2026-01-14T23:18:00.764Z" },
]
[[package]]
@@ -6048,8 +4742,7 @@ dependencies = [
{ name = "certifi" },
{ name = "charset-normalizer" },
{ name = "idna" },
- { name = "urllib3", version = "1.26.20", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
- { name = "urllib3", version = "2.6.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
+ { name = "urllib3" },
]
sdist = { url = "https://files.pythonhosted.org/packages/c9/74/b3ff8e6c8446842c3f5c837e9c3dfcfe2018ea6ecef224c710c85ef728f4/requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf", size = 134517, upload-time = "2025-08-18T20:46:02.573Z" }
wheels = [
@@ -6061,8 +4754,7 @@ name = "rich"
version = "14.3.2"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "markdown-it-py", version = "3.0.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
- { name = "markdown-it-py", version = "4.0.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
+ { name = "markdown-it-py" },
{ name = "pygments" },
]
sdist = { url = "https://files.pythonhosted.org/packages/74/99/a4cab2acbb884f80e558b0771e97e21e939c5dfb460f488d19df485e8298/rich-14.3.2.tar.gz", hash = "sha256:e712f11c1a562a11843306f5ed999475f09ac31ffb64281f73ab29ffdda8b3b8", size = 230143, upload-time = "2026-02-01T16:20:47.908Z" }
@@ -6075,8 +4767,8 @@ name = "rich-rst"
version = "1.3.2"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "docutils", marker = "python_full_version >= '3.10'" },
- { name = "rich", marker = "python_full_version >= '3.10'" },
+ { name = "docutils" },
+ { name = "rich" },
]
sdist = { url = "https://files.pythonhosted.org/packages/bc/6d/a506aaa4a9eaa945ed8ab2b7347859f53593864289853c5d6d62b77246e0/rich_rst-1.3.2.tar.gz", hash = "sha256:a1196fdddf1e364b02ec68a05e8ff8f6914fee10fbca2e6b6735f166bb0da8d4", size = 14936, upload-time = "2025-10-14T16:49:45.332Z" }
wheels = [
@@ -6088,8 +4780,7 @@ name = "rich-toolkit"
version = "0.18.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "click", version = "8.1.8", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
- { name = "click", version = "8.3.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
+ { name = "click" },
{ name = "rich" },
{ name = "typing-extensions" },
]
@@ -6193,20 +4884,6 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/fc/d3/18210222b37e87e36357f7b300b7d98c6dd62b133771e71ae27acba83a4f/rignore-0.7.6-cp314-cp314t-win32.whl", hash = "sha256:c1d8f117f7da0a4a96a8daef3da75bc090e3792d30b8b12cfadc240c631353f9", size = 647033, upload-time = "2025-11-05T21:42:00.095Z" },
{ url = "https://files.pythonhosted.org/packages/3e/87/033eebfbee3ec7d92b3bb1717d8f68c88e6fc7de54537040f3b3a405726f/rignore-0.7.6-cp314-cp314t-win_amd64.whl", hash = "sha256:ca36e59408bec81de75d307c568c2d0d410fb880b1769be43611472c61e85c96", size = 725647, upload-time = "2025-11-05T21:41:44.449Z" },
{ url = "https://files.pythonhosted.org/packages/79/62/b88e5879512c55b8ee979c666ee6902adc4ed05007226de266410ae27965/rignore-0.7.6-cp314-cp314t-win_arm64.whl", hash = "sha256:b83adabeb3e8cf662cabe1931b83e165b88c526fa6af6b3aa90429686e474896", size = 656035, upload-time = "2025-11-05T21:41:31.13Z" },
- { url = "https://files.pythonhosted.org/packages/b9/b4/e7577504d926ced2d6a3fa5ec5f27756639a1ed58a6a3fbefcf3a5659721/rignore-0.7.6-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:b3746bda73f2fe6a9c3ab2f20b792e7d810b30acbdba044313fbd2d0174802e7", size = 886535, upload-time = "2025-11-05T20:42:49.317Z" },
- { url = "https://files.pythonhosted.org/packages/2b/74/098bc71a33e2997bc3291d500760123d23e3a6d354380d26c8a7ddc036de/rignore-0.7.6-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:67a99cf19a5137cc12f14b78dc1bb3f48500f1d5580702c623297d5297bf2752", size = 826621, upload-time = "2025-11-05T20:42:32.421Z" },
- { url = "https://files.pythonhosted.org/packages/7b/73/5f8c276d71009a7e73fb3af6ec3bb930269efeae5830de5c796fa1fb020f/rignore-0.7.6-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b9e851cfa87033c0c3fd9d35dd8b102aff2981db8bc6e0cab27b460bfe38bf3f", size = 900335, upload-time = "2025-11-05T20:40:59.178Z" },
- { url = "https://files.pythonhosted.org/packages/0d/5f/dde3758084a087e6a5cd981c5277c6171d12127deed64fc4fbf12fb8ceaa/rignore-0.7.6-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e9b0def154665036516114437a5d603274e5451c0dc9694f622cc3b7e94603e7", size = 874274, upload-time = "2025-11-05T20:41:14.512Z" },
- { url = "https://files.pythonhosted.org/packages/58/b9/da85646824ab728036378ce62c330316108a52f30f36e6c69cac6ceda376/rignore-0.7.6-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b81274a47e8121224f7f637392b5dfcd9558e32a53e67ba7d04007d8b5281da9", size = 1171639, upload-time = "2025-11-05T20:41:31.206Z" },
- { url = "https://files.pythonhosted.org/packages/35/d1/8c12b779b7f0302c03c1d41511f2ab47012afecdfcd684fbec80af06b331/rignore-0.7.6-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d75d0b0696fb476664bea1169c8e67b13197750b91eceb4f10b3c7f379c7a204", size = 943985, upload-time = "2025-11-05T20:41:45.598Z" },
- { url = "https://files.pythonhosted.org/packages/79/bf/c233a85d31e4f94b911e92ee7e2dd2b962a5c2528f5ebd79a702596f0626/rignore-0.7.6-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6ad3aa4dca77cef9168d0c142f72376f5bd27d1d4b8a81561bd01276d3ad9fe1", size = 961707, upload-time = "2025-11-05T20:42:16.461Z" },
- { url = "https://files.pythonhosted.org/packages/9d/eb/cadee9316a5f2a52b4aa7051967ecb94ec17938d6b425bd842d9317559eb/rignore-0.7.6-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:00f8a59e19d219f44a93af7173de197e0d0e61c386364da20ebe98a303cbe38c", size = 986638, upload-time = "2025-11-05T20:42:00.65Z" },
- { url = "https://files.pythonhosted.org/packages/d0/f0/2c3042c8c9639056593def5e99c3bfe850fbb9a38d061ba67b6314315bad/rignore-0.7.6-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:dd6c682f3cdd741e7a30af2581f6a382ac910080977cd1f97c651467b6268352", size = 1080136, upload-time = "2025-11-05T21:40:21.551Z" },
- { url = "https://files.pythonhosted.org/packages/fc/28/7237b9eb1257b593ee51cd7ef8eed7cc32f50ccff18cb4d7cfe1e6dc54d7/rignore-0.7.6-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:ae4e93193f75ebf6b820241594a78f347785cfd5a5fbbac94634052589418352", size = 1139413, upload-time = "2025-11-05T21:40:39.025Z" },
- { url = "https://files.pythonhosted.org/packages/a5/df/c3f382a31ad7ed68510b411c28fec42354d2c43fecb7c053d998ee9410ed/rignore-0.7.6-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:1163d8b5d3a320d4d7cc8635213328850dc41f60e438c7869d540061adf66c98", size = 1120204, upload-time = "2025-11-05T21:40:56.062Z" },
- { url = "https://files.pythonhosted.org/packages/9c/3d/e8585c4e9c0077255ba599684aee78326176ab13ff13805ea62aa7e3235f/rignore-0.7.6-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:3e685f47b4c58b2df7dee81ebc1ec9dbb7f798b9455c3f22be6d75ac6bddee30", size = 1129757, upload-time = "2025-11-05T21:41:14.148Z" },
- { url = "https://files.pythonhosted.org/packages/fd/56/852226c13f89ddbbf12d639900941dc55dcbcf79f5d15294796fd3279d73/rignore-0.7.6-cp39-cp39-win32.whl", hash = "sha256:2af6a0a76575220863cd838693c808a94e750640e0c8a3e9f707e93c2f131fdf", size = 648265, upload-time = "2025-11-05T21:41:58.589Z" },
- { url = "https://files.pythonhosted.org/packages/cc/c6/14e7585dc453a870fe99b1270ee95e2adff02ea0d297cd6e2c4aa46cd43a/rignore-0.7.6-cp39-cp39-win_amd64.whl", hash = "sha256:a326eab6db9ab85b4afb5e6eb28736a9f2b885a9246d9e8c1989bc693dd059a0", size = 728715, upload-time = "2025-11-05T21:41:42.823Z" },
{ url = "https://files.pythonhosted.org/packages/85/12/62d690b4644c330d7ac0f739b7f078190ab4308faa909a60842d0e4af5b2/rignore-0.7.6-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:c3d3a523af1cd4ed2c0cba8d277a32d329b0c96ef9901fb7ca45c8cfaccf31a5", size = 887462, upload-time = "2025-11-05T20:42:50.804Z" },
{ url = "https://files.pythonhosted.org/packages/05/bc/6528a0e97ed2bd7a7c329183367d1ffbc5b9762ae8348d88dae72cc9d1f5/rignore-0.7.6-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:990853566e65184a506e1e2af2d15045afad3ebaebb8859cb85b882081915110", size = 826918, upload-time = "2025-11-05T20:42:33.689Z" },
{ url = "https://files.pythonhosted.org/packages/3e/2c/7d7bad116e09a04e9e1688c6f891fa2d4fd33f11b69ac0bd92419ddebeae/rignore-0.7.6-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1cab9ff2e436ce7240d7ee301c8ef806ed77c1fd6b8a8239ff65f9bbbcb5b8a3", size = 900922, upload-time = "2025-11-05T20:41:00.361Z" },
@@ -6231,18 +4908,6 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/67/56/36d5d34210e5e7dfcd134eed8335b19e80ae940ee758f493e4f2b344dd70/rignore-0.7.6-pp311-pypy311_pp73-musllinux_1_2_armv7l.whl", hash = "sha256:c081f17290d8a2b96052b79207622aa635686ea39d502b976836384ede3d303c", size = 1139789, upload-time = "2025-11-05T21:40:42.119Z" },
{ url = "https://files.pythonhosted.org/packages/6b/5b/bb4f9420802bf73678033a4a55ab1bede36ce2e9b41fec5f966d83d932b3/rignore-0.7.6-pp311-pypy311_pp73-musllinux_1_2_i686.whl", hash = "sha256:57e8327aacc27f921968cb2a174f9e47b084ce9a7dd0122c8132d22358f6bd79", size = 1120308, upload-time = "2025-11-05T21:40:59.402Z" },
{ url = "https://files.pythonhosted.org/packages/ce/8b/a1299085b28a2f6135e30370b126e3c5055b61908622f2488ade67641479/rignore-0.7.6-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:d8955b57e42f2a5434670d5aa7b75eaf6e74602ccd8955dddf7045379cd762fb", size = 1129444, upload-time = "2025-11-05T21:41:17.906Z" },
- { url = "https://files.pythonhosted.org/packages/47/98/80ef6fda78161e88ef9336fcbe851afccf78c48e69e8266a23fb7922b5aa/rignore-0.7.6-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:e6ba1511c0ab8cd1ed8d6055bb0a6e629f48bfe04854293e0cd2dd88bd7153f8", size = 887180, upload-time = "2025-11-05T21:40:07.665Z" },
- { url = "https://files.pythonhosted.org/packages/21/d7/8666e7081f8476b003d8d2c8f39ecc17c93b7efd261740d15b6830acde82/rignore-0.7.6-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:50586d90be15f9aa8a2e2ee5a042ee6c51e28848812a35f0c95d4bfc0533d469", size = 827029, upload-time = "2025-11-05T20:42:36.628Z" },
- { url = "https://files.pythonhosted.org/packages/01/aa/3aba657d17b1737f4180b143866fedd269de15f361a8cb26ba363c0c3c13/rignore-0.7.6-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5b129873dd0ade248e67f25a09b5b72288cbef76ba1a9aae6bac193ee1d8be72", size = 901338, upload-time = "2025-11-05T20:41:03.059Z" },
- { url = "https://files.pythonhosted.org/packages/90/cc/d8c2c9770f5f61b28999c582804f282f2227c155ba13dfb0e9ea03daeaaf/rignore-0.7.6-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d9d6dd947556ddebfd62753005104986ee14a4e0663818aed19cdf2c33a6b5d5", size = 877563, upload-time = "2025-11-05T20:41:19.209Z" },
- { url = "https://files.pythonhosted.org/packages/55/63/42dd625bf96989be4a928b5444ddec9101ee63a98a15646e611b3ce58b82/rignore-0.7.6-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:91b95faa532efba888b196331e9af69e693635d469185ac52c796e435e2484e5", size = 1171087, upload-time = "2025-11-05T20:41:35.558Z" },
- { url = "https://files.pythonhosted.org/packages/bf/1e/4130fb622c2081c5322caf7a8888d1d265b99cd5d62cb714b512b8911233/rignore-0.7.6-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a1016f430fb56f7e400838bbc56fdf43adddb6fcb7bf2a14731dfd725c2fae6c", size = 944335, upload-time = "2025-11-05T20:41:49.859Z" },
- { url = "https://files.pythonhosted.org/packages/0f/b9/3d3ef7773da85e002fab53b1fdd9e9bb111cc86792b761cb38bd00c1532e/rignore-0.7.6-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f00c519861926dc703ecbb7bbeb884be67099f96f98b175671fa0a54718f55d1", size = 961500, upload-time = "2025-11-05T20:42:20.798Z" },
- { url = "https://files.pythonhosted.org/packages/1f/bc/346c874a31a721064935c60666a19016b6b01cd716cf73d52dc64e467b30/rignore-0.7.6-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e34d172bf50e881b7c02e530ae8b1ea96093f0b16634c344f637227b39707b41", size = 987741, upload-time = "2025-11-05T20:42:05.071Z" },
- { url = "https://files.pythonhosted.org/packages/6d/b8/d12dc548da8fdb63292a38727b035153495220cd93730019ee8ed3bdcffb/rignore-0.7.6-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:101d3143619898db1e7bede2e3e647daf19bb867c4fb25978016d67978d14868", size = 1081057, upload-time = "2025-11-05T21:40:26.53Z" },
- { url = "https://files.pythonhosted.org/packages/8e/51/7eea5d949212709740ad07e01c524336e44608ef0614a2a1cb31c9a0ea30/rignore-0.7.6-pp39-pypy39_pp73-musllinux_1_2_armv7l.whl", hash = "sha256:c9f3b420f54199a2b2b3b532d8c7e0860be3fa51f67501113cca6c7bfc392840", size = 1141653, upload-time = "2025-11-05T21:40:43.676Z" },
- { url = "https://files.pythonhosted.org/packages/c4/2b/76ec843cc392fcb4e37d6a8340e823a0bf644872e191d2f5652a4c2c18ee/rignore-0.7.6-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:1c6795e3694d750ae5ef172eab7d68a52aefbd9168d2e06647df691db2b03a50", size = 1121465, upload-time = "2025-11-05T21:41:00.904Z" },
- { url = "https://files.pythonhosted.org/packages/7c/9d/e69ad5cf03211a1076f9fe04ca2698c9cb8208b63419c928c26646bdf1d9/rignore-0.7.6-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:750a83a254b020e1193bfa7219dc7edca26bd8888a94cdc59720cbe386ab0c72", size = 1130110, upload-time = "2025-11-05T21:41:20.263Z" },
]
[[package]]
@@ -6421,8 +5086,8 @@ name = "secretstorage"
version = "3.5.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "cryptography", marker = "python_full_version >= '3.10'" },
- { name = "jeepney", marker = "python_full_version >= '3.10'" },
+ { name = "cryptography" },
+ { name = "jeepney" },
]
sdist = { url = "https://files.pythonhosted.org/packages/1c/03/e834bcd866f2f8a49a85eaff47340affa3bfa391ee9912a952a1faa68c7b/secretstorage-3.5.0.tar.gz", hash = "sha256:f04b8e4689cbce351744d5537bf6b1329c6fc68f91fa666f60a380edddcd11be", size = 19884, upload-time = "2025-11-23T19:02:53.191Z" }
wheels = [
@@ -6435,8 +5100,7 @@ version = "2.52.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "certifi" },
- { name = "urllib3", version = "1.26.20", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
- { name = "urllib3", version = "2.6.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
+ { name = "urllib3" },
]
sdist = { url = "https://files.pythonhosted.org/packages/59/eb/1b497650eb564701f9a7b8a95c51b2abe9347ed2c0b290ba78f027ebe4ea/sentry_sdk-2.52.0.tar.gz", hash = "sha256:fa0bec872cfec0302970b2996825723d67390cdd5f0229fb9efed93bd5384899", size = 410273, upload-time = "2026-02-04T15:03:54.706Z" }
wheels = [
@@ -6506,8 +5170,7 @@ name = "sqlalchemy"
version = "2.0.46"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "greenlet", version = "3.2.4", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version < '3.10' and platform_machine == 'AMD64') or (python_full_version < '3.10' and platform_machine == 'WIN32') or (python_full_version < '3.10' and platform_machine == 'aarch64') or (python_full_version < '3.10' and platform_machine == 'amd64') or (python_full_version < '3.10' and platform_machine == 'ppc64le') or (python_full_version < '3.10' and platform_machine == 'win32') or (python_full_version < '3.10' and platform_machine == 'x86_64')" },
- { name = "greenlet", version = "3.3.1", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version >= '3.10' and platform_machine == 'AMD64') or (python_full_version >= '3.10' and platform_machine == 'WIN32') or (python_full_version >= '3.10' and platform_machine == 'aarch64') or (python_full_version >= '3.10' and platform_machine == 'amd64') or (python_full_version >= '3.10' and platform_machine == 'ppc64le') or (python_full_version >= '3.10' and platform_machine == 'win32') or (python_full_version >= '3.10' and platform_machine == 'x86_64')" },
+ { name = "greenlet", marker = "platform_machine == 'AMD64' or platform_machine == 'WIN32' or platform_machine == 'aarch64' or platform_machine == 'amd64' or platform_machine == 'ppc64le' or platform_machine == 'win32' or platform_machine == 'x86_64'" },
{ name = "typing-extensions" },
]
sdist = { url = "https://files.pythonhosted.org/packages/06/aa/9ce0f3e7a9829ead5c8ce549392f33a12c4555a6c0609bb27d882e9c7ddf/sqlalchemy-2.0.46.tar.gz", hash = "sha256:cf36851ee7219c170bb0793dbc3da3e80c582e04a5437bc601bfe8c85c9216d7", size = 9865393, upload-time = "2026-01-21T18:03:45.119Z" }
@@ -6555,13 +5218,6 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/d7/53/3b37dda0a5b137f21ef608d8dfc77b08477bab0fe2ac9d3e0a66eaeab6fc/sqlalchemy-2.0.46-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:42a1643dc5427b69aca967dae540a90b0fbf57eaf248f13a90ea5930e0966863", size = 3526296, upload-time = "2026-01-21T18:45:12.657Z" },
{ url = "https://files.pythonhosted.org/packages/33/75/f28622ba6dde79cd545055ea7bd4062dc934e0621f7b3be2891f8563f8de/sqlalchemy-2.0.46-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:ff33c6e6ad006bbc0f34f5faf941cfc62c45841c64c0a058ac38c799f15b5ede", size = 3470008, upload-time = "2026-01-21T18:33:11.725Z" },
{ url = "https://files.pythonhosted.org/packages/a9/42/4afecbbc38d5e99b18acef446453c76eec6fbd03db0a457a12a056836e22/sqlalchemy-2.0.46-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:82ec52100ec1e6ec671563bbd02d7c7c8d0b9e71a0723c72f22ecf52d1755330", size = 3476137, upload-time = "2026-01-21T18:45:15.001Z" },
- { url = "https://files.pythonhosted.org/packages/9a/06/a29b51a577cc5746712ed8a2870794659a6bf405264b32dd5ccc380844d1/sqlalchemy-2.0.46-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:90bde6c6b1827565a95fde597da001212ab436f1b2e0c2dcc7246e14db26e2a3", size = 2158097, upload-time = "2026-01-21T18:24:45.892Z" },
- { url = "https://files.pythonhosted.org/packages/be/55/44689ed21b5a82708502243310878cfc76e0f326ed16103f4336f605055b/sqlalchemy-2.0.46-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:94b1e5f3a5f1ff4f42d5daab047428cd45a3380e51e191360a35cef71c9a7a2a", size = 3233722, upload-time = "2026-01-21T18:30:56.334Z" },
- { url = "https://files.pythonhosted.org/packages/be/11/1d6024d9cdd2108d500b399bdc77a1738119789aa70c83d68e1012d32596/sqlalchemy-2.0.46-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:93bb0aae40b52c57fd74ef9c6933c08c040ba98daf23ad33c3f9893494b8d3ce", size = 3233038, upload-time = "2026-01-21T18:32:26.945Z" },
- { url = "https://files.pythonhosted.org/packages/38/6d/f813e3204baea710f2d82a61821bdf7b39cebda6dbba7cdeb976b0552239/sqlalchemy-2.0.46-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:c4e2cc868b7b5208aec6c960950b7bb821f82c2fe66446c92ee0a571765e91a5", size = 3183163, upload-time = "2026-01-21T18:30:58.647Z" },
- { url = "https://files.pythonhosted.org/packages/8d/5d/32b70643ef73c1bb3723a98316b89182cad2b9a6744d5335f1d69fcdb3f2/sqlalchemy-2.0.46-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:965c62be8256d10c11f8907e7a8d3e18127a4c527a5919d85fa87fd9ecc2cfdc", size = 3205174, upload-time = "2026-01-21T18:32:28.684Z" },
- { url = "https://files.pythonhosted.org/packages/99/a9/b9f7bd299b7550925e1e7d71d634e1eee23c035abed7de125fda7c74b0c8/sqlalchemy-2.0.46-cp39-cp39-win32.whl", hash = "sha256:9397b381dcee8a2d6b99447ae85ea2530dcac82ca494d1db877087a13e38926d", size = 2117095, upload-time = "2026-01-21T18:34:02.596Z" },
- { url = "https://files.pythonhosted.org/packages/04/0b/2e376b34a7c2f3d9d40811c3412fdc65cd35c6da2d660c283ad24bd9bab1/sqlalchemy-2.0.46-cp39-cp39-win_amd64.whl", hash = "sha256:4396c948d8217e83e2c202fbdcc0389cf8c93d2c1c5e60fa5c5a955eae0e64be", size = 2140517, upload-time = "2026-01-21T18:34:03.958Z" },
{ url = "https://files.pythonhosted.org/packages/fc/a1/9c4efa03300926601c19c18582531b45aededfb961ab3c3585f1e24f120b/sqlalchemy-2.0.46-py3-none-any.whl", hash = "sha256:f9c11766e7e7c0a2767dda5acb006a118640c9fc0a4104214b96269bfb78399e", size = 1937882, upload-time = "2026-01-21T18:22:10.456Z" },
]
@@ -6583,80 +5239,37 @@ name = "sse-starlette"
version = "3.2.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "anyio", marker = "python_full_version >= '3.10'" },
- { name = "starlette", version = "0.52.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
+ { name = "anyio" },
+ { name = "starlette" },
]
sdist = { url = "https://files.pythonhosted.org/packages/8b/8d/00d280c03ffd39aaee0e86ec81e2d3b9253036a0f93f51d10503adef0e65/sse_starlette-3.2.0.tar.gz", hash = "sha256:8127594edfb51abe44eac9c49e59b0b01f1039d0c7461c6fd91d4e03b70da422", size = 27253, upload-time = "2026-01-17T13:11:05.62Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/96/7f/832f015020844a8b8f7a9cbc103dd76ba8e3875004c41e08440ea3a2b41a/sse_starlette-3.2.0-py3-none-any.whl", hash = "sha256:5876954bd51920fc2cd51baee47a080eb88a37b5b784e615abb0b283f801cdbf", size = 12763, upload-time = "2026-01-17T13:11:03.775Z" },
]
-[[package]]
-name = "starlette"
-version = "0.49.3"
-source = { registry = "https://pypi.org/simple" }
-resolution-markers = [
- "python_full_version < '3.10'",
-]
-dependencies = [
- { name = "anyio", marker = "python_full_version < '3.10'" },
- { name = "typing-extensions", marker = "python_full_version < '3.10'" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/de/1a/608df0b10b53b0beb96a37854ee05864d182ddd4b1156a22f1ad3860425a/starlette-0.49.3.tar.gz", hash = "sha256:1c14546f299b5901a1ea0e34410575bc33bbd741377a10484a54445588d00284", size = 2655031, upload-time = "2025-11-01T15:12:26.13Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/a3/e0/021c772d6a662f43b63044ab481dc6ac7592447605b5b35a957785363122/starlette-0.49.3-py3-none-any.whl", hash = "sha256:b579b99715fdc2980cf88c8ec96d3bf1ce16f5a8051a7c2b84ef9b1cdecaea2f", size = 74340, upload-time = "2025-11-01T15:12:24.387Z" },
-]
-
[[package]]
name = "starlette"
version = "0.52.1"
source = { registry = "https://pypi.org/simple" }
-resolution-markers = [
- "python_full_version >= '3.14'",
- "python_full_version >= '3.10' and python_full_version < '3.14'",
-]
dependencies = [
- { name = "anyio", marker = "python_full_version >= '3.10'" },
- { name = "typing-extensions", marker = "python_full_version >= '3.10' and python_full_version < '3.13'" },
+ { name = "anyio" },
+ { name = "typing-extensions", marker = "python_full_version < '3.13'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/c4/68/79977123bb7be889ad680d79a40f339082c1978b5cfcf62c2d8d196873ac/starlette-0.52.1.tar.gz", hash = "sha256:834edd1b0a23167694292e94f597773bc3f89f362be6effee198165a35d62933", size = 2653702, upload-time = "2026-01-18T13:34:11.062Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/81/0d/13d1d239a25cbfb19e740db83143e95c772a1fe10202dda4b76792b114dd/starlette-0.52.1-py3-none-any.whl", hash = "sha256:0029d43eb3d273bc4f83a08720b4912ea4b071087a3b48db01b7c839f7954d74", size = 74272, upload-time = "2026-01-18T13:34:09.188Z" },
]
-[[package]]
-name = "strawberry-graphql"
-version = "0.283.3"
-source = { registry = "https://pypi.org/simple" }
-resolution-markers = [
- "python_full_version < '3.10'",
-]
-dependencies = [
- { name = "graphql-core", marker = "python_full_version < '3.10'" },
- { name = "lia-web", marker = "python_full_version < '3.10'" },
- { name = "packaging", marker = "python_full_version < '3.10'" },
- { name = "python-dateutil", marker = "python_full_version < '3.10'" },
- { name = "typing-extensions", marker = "python_full_version < '3.10'" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/30/74/729c227b1e7fce28678290a5013ddceb543f350b6c14ae83400ab2c727d1/strawberry_graphql-0.283.3.tar.gz", hash = "sha256:375e545856b7587debd4e0f1e2a6fca19d09cc126238a07b9e5164e5eb09342a", size = 212141, upload-time = "2025-10-10T20:03:46.985Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/23/1b/aa358ef730d727d2e42810bf943542a8cc4c15aa2401f8629d356643a06f/strawberry_graphql-0.283.3-py3-none-any.whl", hash = "sha256:3751d86a219d81a16a13f335bb7d2fa3f57a85fab83d7d284b8ea88e2261d68b", size = 309885, upload-time = "2025-10-10T20:03:44.051Z" },
-]
-
[[package]]
name = "strawberry-graphql"
version = "0.291.2"
source = { registry = "https://pypi.org/simple" }
-resolution-markers = [
- "python_full_version >= '3.14'",
- "python_full_version >= '3.10' and python_full_version < '3.14'",
-]
dependencies = [
- { name = "cross-web", marker = "python_full_version >= '3.10'" },
- { name = "graphql-core", marker = "python_full_version >= '3.10'" },
- { name = "packaging", marker = "python_full_version >= '3.10'" },
- { name = "python-dateutil", marker = "python_full_version >= '3.10'" },
- { name = "typing-extensions", marker = "python_full_version >= '3.10'" },
+ { name = "cross-web" },
+ { name = "graphql-core" },
+ { name = "packaging" },
+ { name = "python-dateutil" },
+ { name = "typing-extensions" },
]
sdist = { url = "https://files.pythonhosted.org/packages/33/dd/e0e68f4b17da6ff5773fcd4bebf86fc4ff8620c854be816d047e9af8c4aa/strawberry_graphql-0.291.2.tar.gz", hash = "sha256:e6076604a786e8437bc64a27348584c082113442f072daf757b56e4863543a97", size = 217730, upload-time = "2026-02-06T14:40:51.173Z" }
wheels = [
@@ -6680,50 +5293,24 @@ name = "taskgroup"
version = "0.2.2"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "exceptiongroup", marker = "python_full_version >= '3.10' and python_full_version < '3.14'" },
- { name = "typing-extensions", marker = "python_full_version >= '3.10' and python_full_version < '3.14'" },
+ { name = "exceptiongroup", marker = "python_full_version < '3.14'" },
+ { name = "typing-extensions", marker = "python_full_version < '3.14'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/f0/8d/e218e0160cc1b692e6e0e5ba34e8865dbb171efeb5fc9a704544b3020605/taskgroup-0.2.2.tar.gz", hash = "sha256:078483ac3e78f2e3f973e2edbf6941374fbea81b9c5d0a96f51d297717f4752d", size = 11504, upload-time = "2025-01-03T09:24:13.761Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/d1/b1/74babcc824a57904e919f3af16d86c08b524c0691504baf038ef2d7f655c/taskgroup-0.2.2-py2.py3-none-any.whl", hash = "sha256:e2c53121609f4ae97303e9ea1524304b4de6faf9eb2c9280c7f87976479a52fb", size = 14237, upload-time = "2025-01-03T09:24:11.41Z" },
]
-[[package]]
-name = "temporalio"
-version = "1.16.0"
-source = { registry = "https://pypi.org/simple" }
-resolution-markers = [
- "python_full_version < '3.10'",
-]
-dependencies = [
- { name = "nexus-rpc", version = "1.1.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
- { name = "protobuf", version = "5.29.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
- { name = "python-dateutil", marker = "python_full_version < '3.10'" },
- { name = "types-protobuf", marker = "python_full_version < '3.10'" },
- { name = "typing-extensions", marker = "python_full_version < '3.10'" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/f3/32/375ab75d0ebb468cf9c8abbc450a03d3a8c66401fc320b338bd8c00d36b4/temporalio-1.16.0.tar.gz", hash = "sha256:dd926f3e30626fd4edf5e0ce596b75ecb5bbe0e4a0281e545ac91b5577967c91", size = 1733873, upload-time = "2025-08-21T22:12:50.879Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/e0/36/12bb7234c83ddca4b8b032c8f1a9e07a03067c6ed6d2ddb39c770a4c87c6/temporalio-1.16.0-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:547c0853310350d3e5b5b9c806246cbf2feb523f685b05bf14ec1b0ece8a7bb6", size = 12540769, upload-time = "2025-08-21T22:11:24.551Z" },
- { url = "https://files.pythonhosted.org/packages/3c/16/a7d402435b8f994979abfeffd3f5ffcaaeada467ac16438e61c51c9f7abe/temporalio-1.16.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5b05bb0d06025645aed6f936615311a6774eb8dc66280f32a810aac2283e1258", size = 12968631, upload-time = "2025-08-21T22:11:48.375Z" },
- { url = "https://files.pythonhosted.org/packages/11/6f/16663eef877b61faa5fd917b3a63497416ec4319195af75f6169a1594479/temporalio-1.16.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0a08aed4e0f6c2b6bfc779b714e91dfe8c8491a0ddb4c4370627bb07f9bddcfd", size = 13164612, upload-time = "2025-08-21T22:12:16.366Z" },
- { url = "https://files.pythonhosted.org/packages/af/0e/8c6704ca7033aa09dc084f285d70481d758972cc341adc3c84d5f82f7b01/temporalio-1.16.0-cp39-abi3-win_amd64.whl", hash = "sha256:7c190362b0d7254f1f93fb71456063e7b299ac85a89f6227758af82c6a5aa65b", size = 13177058, upload-time = "2025-08-21T22:12:44.239Z" },
-]
-
[[package]]
name = "temporalio"
version = "1.20.0"
source = { registry = "https://pypi.org/simple" }
-resolution-markers = [
- "python_full_version >= '3.14'",
- "python_full_version >= '3.10' and python_full_version < '3.14'",
-]
dependencies = [
- { name = "nexus-rpc", version = "1.2.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
- { name = "protobuf", version = "6.33.5", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
- { name = "python-dateutil", marker = "python_full_version == '3.10.*'" },
- { name = "types-protobuf", marker = "python_full_version >= '3.10'" },
- { name = "typing-extensions", marker = "python_full_version >= '3.10'" },
+ { name = "nexus-rpc" },
+ { name = "protobuf" },
+ { name = "python-dateutil", marker = "python_full_version < '3.11'" },
+ { name = "types-protobuf" },
+ { name = "typing-extensions" },
]
sdist = { url = "https://files.pythonhosted.org/packages/21/db/7d5118d28b0918888e1ec98f56f659fdb006351e06d95f30f4274962a76f/temporalio-1.20.0.tar.gz", hash = "sha256:5a6a85b7d298b7359bffa30025f7deac83c74ac095a4c6952fbf06c249a2a67c", size = 1850498, upload-time = "2025-11-25T21:25:20.225Z" }
wheels = [
@@ -6734,51 +5321,19 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/11/23/5689c014a76aff3b744b3ee0d80815f63b1362637814f5fbb105244df09b/temporalio-1.20.0-cp310-abi3-win_amd64.whl", hash = "sha256:eacfd571b653e0a0f4aa6593f4d06fc628797898f0900d400e833a1f40cad03a", size = 12745027, upload-time = "2025-11-25T21:25:16.827Z" },
]
-[[package]]
-name = "tenacity"
-version = "9.1.2"
-source = { registry = "https://pypi.org/simple" }
-resolution-markers = [
- "python_full_version < '3.10'",
-]
-sdist = { url = "https://files.pythonhosted.org/packages/0a/d4/2b0cd0fe285e14b36db076e78c93766ff1d529d70408bd1d2a5a84f1d929/tenacity-9.1.2.tar.gz", hash = "sha256:1169d376c297e7de388d18b4481760d478b0e99a777cad3a9c86e556f4b697cb", size = 48036, upload-time = "2025-04-02T08:25:09.966Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/e5/30/643397144bfbfec6f6ef821f36f33e57d35946c44a2352d3c9f0ae847619/tenacity-9.1.2-py3-none-any.whl", hash = "sha256:f77bf36710d8b73a50b2dd155c97b870017ad21afe6ab300326b0371b3b05138", size = 28248, upload-time = "2025-04-02T08:25:07.678Z" },
-]
-
[[package]]
name = "tenacity"
version = "9.1.3"
source = { registry = "https://pypi.org/simple" }
-resolution-markers = [
- "python_full_version >= '3.14'",
- "python_full_version >= '3.10' and python_full_version < '3.14'",
-]
sdist = { url = "https://files.pythonhosted.org/packages/1e/4a/c3357c8742f361785e3702bb4c9c68c4cb37a80aa657640b820669be5af1/tenacity-9.1.3.tar.gz", hash = "sha256:a6724c947aa717087e2531f883bde5c9188f603f6669a9b8d54eb998e604c12a", size = 49002, upload-time = "2026-02-05T06:33:12.866Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/64/6b/cdc85edb15e384d8e934aad89638cc8646e118c80de94c60125d0fc0a185/tenacity-9.1.3-py3-none-any.whl", hash = "sha256:51171cfc6b8a7826551e2f029426b10a6af189c5ac6986adcd7eb36d42f17954", size = 28858, upload-time = "2026-02-05T06:33:11.219Z" },
]
-[[package]]
-name = "termcolor"
-version = "3.1.0"
-source = { registry = "https://pypi.org/simple" }
-resolution-markers = [
- "python_full_version < '3.10'",
-]
-sdist = { url = "https://files.pythonhosted.org/packages/ca/6c/3d75c196ac07ac8749600b60b03f4f6094d54e132c4d94ebac6ee0e0add0/termcolor-3.1.0.tar.gz", hash = "sha256:6a6dd7fbee581909eeec6a756cff1d7f7c376063b14e4a298dc4980309e55970", size = 14324, upload-time = "2025-04-30T11:37:53.791Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/4f/bd/de8d508070629b6d84a30d01d57e4a65c69aa7f5abe7560b8fad3b50ea59/termcolor-3.1.0-py3-none-any.whl", hash = "sha256:591dd26b5c2ce03b9e43f391264626557873ce1d379019786f99b0c2bee140aa", size = 7684, upload-time = "2025-04-30T11:37:52.382Z" },
-]
-
[[package]]
name = "termcolor"
version = "3.3.0"
source = { registry = "https://pypi.org/simple" }
-resolution-markers = [
- "python_full_version >= '3.14'",
- "python_full_version >= '3.10' and python_full_version < '3.14'",
-]
sdist = { url = "https://files.pythonhosted.org/packages/46/79/cf31d7a93a8fdc6aa0fbb665be84426a8c5a557d9240b6239e9e11e35fc5/termcolor-3.3.0.tar.gz", hash = "sha256:348871ca648ec6a9a983a13ab626c0acce02f515b9e1983332b17af7979521c5", size = 14434, upload-time = "2025-12-29T12:55:21.882Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/33/d1/8bb87d21e9aeb323cc03034f5eaf2c8f69841e40e4853c2627edf8111ed3/termcolor-3.3.0-py3-none-any.whl", hash = "sha256:cf642efadaf0a8ebbbf4bc7a31cec2f9b5f21a9f726f4ccbb08192c9c26f43a5", size = 7734, upload-time = "2025-12-29T12:55:20.718Z" },
@@ -6798,8 +5353,8 @@ name = "tiktoken"
version = "0.12.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "regex", marker = "python_full_version >= '3.10'" },
- { name = "requests", marker = "python_full_version >= '3.10'" },
+ { name = "regex" },
+ { name = "requests" },
]
sdist = { url = "https://files.pythonhosted.org/packages/7d/ab/4d017d0f76ec3171d469d80fc03dfbb4e48a4bcaddaa831b31d526f05edc/tiktoken-0.12.0.tar.gz", hash = "sha256:b18ba7ee2b093863978fcb14f74b3707cdc8d4d4d3836853ce7ec60772139931", size = 37806, upload-time = "2025-10-06T20:22:45.419Z" }
wheels = [
@@ -6852,40 +5407,14 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/28/c0/3c7a39ff68022ddfd7d93f3337ad90389a342f761c4d71de99a3ccc57857/tiktoken-0.12.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:54c891b416a0e36b8e2045b12b33dd66fb34a4fe7965565f1b482da50da3e86a", size = 1194908, upload-time = "2025-10-06T20:22:32.073Z" },
{ url = "https://files.pythonhosted.org/packages/ab/0d/c1ad6f4016a3968c048545f5d9b8ffebf577774b2ede3e2e352553b685fe/tiktoken-0.12.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5edb8743b88d5be814b1a8a8854494719080c28faaa1ccbef02e87354fe71ef0", size = 1253706, upload-time = "2025-10-06T20:22:33.385Z" },
{ url = "https://files.pythonhosted.org/packages/af/df/c7891ef9d2712ad774777271d39fdef63941ffba0a9d59b7ad1fd2765e57/tiktoken-0.12.0-cp314-cp314t-win_amd64.whl", hash = "sha256:f61c0aea5565ac82e2ec50a05e02a6c44734e91b51c10510b084ea1b8e633a71", size = 920667, upload-time = "2025-10-06T20:22:34.444Z" },
- { url = "https://files.pythonhosted.org/packages/c7/d1/7507bfb9c2ceef52ae3ae813013215c185648e21127538aae66dedd3af9c/tiktoken-0.12.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:d51d75a5bffbf26f86554d28e78bfb921eae998edc2675650fd04c7e1f0cdc1e", size = 1053407, upload-time = "2025-10-06T20:22:35.492Z" },
- { url = "https://files.pythonhosted.org/packages/ee/4a/8ea1da602ac39dee4356b4cd6040a2325507482c36043044b6f581597b4f/tiktoken-0.12.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:09eb4eae62ae7e4c62364d9ec3a57c62eea707ac9a2b2c5d6bd05de6724ea179", size = 997150, upload-time = "2025-10-06T20:22:37.286Z" },
- { url = "https://files.pythonhosted.org/packages/2c/1a/62d1d36b167eccd441aff2f0091551ca834295541b949d161021aa658167/tiktoken-0.12.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:df37684ace87d10895acb44b7f447d4700349b12197a526da0d4a4149fde074c", size = 1131575, upload-time = "2025-10-06T20:22:39.023Z" },
- { url = "https://files.pythonhosted.org/packages/f7/16/544207d63c8c50edd2321228f21d236e4e49d235128bb7e3e0f69eed0807/tiktoken-0.12.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:4c9614597ac94bb294544345ad8cf30dac2129c05e2db8dc53e082f355857af7", size = 1154920, upload-time = "2025-10-06T20:22:40.175Z" },
- { url = "https://files.pythonhosted.org/packages/99/4c/0a3504157c81364fc0c64cada54efef0567961357e786706ea63bc8946e1/tiktoken-0.12.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:20cf97135c9a50de0b157879c3c4accbb29116bcf001283d26e073ff3b345946", size = 1196766, upload-time = "2025-10-06T20:22:41.365Z" },
- { url = "https://files.pythonhosted.org/packages/d4/46/8e6a258ae65447c75770fe5ea8968acab369e8c9f537f727c91f83772325/tiktoken-0.12.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:15d875454bbaa3728be39880ddd11a5a2a9e548c29418b41e8fd8a767172b5ec", size = 1258278, upload-time = "2025-10-06T20:22:42.846Z" },
- { url = "https://files.pythonhosted.org/packages/35/43/3b95de4f5e76f3cafc70dac9b1b9cfe759ff3bfd494ac91a280e93772e90/tiktoken-0.12.0-cp39-cp39-win_amd64.whl", hash = "sha256:2cff3688ba3c639ebe816f8d58ffbbb0aa7433e23e08ab1cade5d175fc973fb3", size = 881888, upload-time = "2025-10-06T20:22:44.059Z" },
-]
-
-[[package]]
-name = "tinycss2"
-version = "1.4.0"
-source = { registry = "https://pypi.org/simple" }
-resolution-markers = [
- "python_full_version < '3.10'",
-]
-dependencies = [
- { name = "webencodings", marker = "python_full_version < '3.10'" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/7a/fd/7a5ee21fd08ff70d3d33a5781c255cbe779659bd03278feb98b19ee550f4/tinycss2-1.4.0.tar.gz", hash = "sha256:10c0972f6fc0fbee87c3edb76549357415e94548c1ae10ebccdea16fb404a9b7", size = 87085, upload-time = "2024-10-24T14:58:29.895Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/e6/34/ebdc18bae6aa14fbee1a08b63c015c72b64868ff7dae68808ab500c492e2/tinycss2-1.4.0-py3-none-any.whl", hash = "sha256:3a49cf47b7675da0b15d0c6e1df8df4ebd96e9394bb905a5775adb0d884c5289", size = 26610, upload-time = "2024-10-24T14:58:28.029Z" },
]
[[package]]
name = "tinycss2"
version = "1.5.1"
source = { registry = "https://pypi.org/simple" }
-resolution-markers = [
- "python_full_version >= '3.14'",
- "python_full_version >= '3.10' and python_full_version < '3.14'",
-]
dependencies = [
- { name = "webencodings", marker = "python_full_version >= '3.10'" },
+ { name = "webencodings" },
]
sdist = { url = "https://files.pythonhosted.org/packages/a3/ae/2ca4913e5c0f09781d75482874c3a95db9105462a92ddd303c7d285d3df2/tinycss2-1.5.1.tar.gz", hash = "sha256:d339d2b616ba90ccce58da8495a78f46e55d4d25f9fd71dfd526f07e7d53f957", size = 88195, upload-time = "2025-11-23T10:29:10.082Z" }
wheels = [
@@ -6920,10 +5449,6 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/46/cd/e4851401f3d8f6f45d8480262ab6a5c8cb9c4302a790a35aa14eeed6d2fd/tokenizers-0.22.2-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e10bf9113d209be7cd046d40fbabbaf3278ff6d18eb4da4c500443185dc1896c", size = 3161308, upload-time = "2026-01-05T10:40:40.737Z" },
{ url = "https://files.pythonhosted.org/packages/6f/6e/55553992a89982cd12d4a66dddb5e02126c58677ea3931efcbe601d419db/tokenizers-0.22.2-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:64d94e84f6660764e64e7e0b22baa72f6cd942279fdbb21d46abd70d179f0195", size = 3718964, upload-time = "2026-01-05T10:40:46.56Z" },
{ url = "https://files.pythonhosted.org/packages/59/8c/b1c87148aa15e099243ec9f0cf9d0e970cc2234c3257d558c25a2c5304e6/tokenizers-0.22.2-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f01a9c019878532f98927d2bacb79bbb404b43d3437455522a00a30718cdedb5", size = 3373542, upload-time = "2026-01-05T10:40:52.803Z" },
- { url = "https://files.pythonhosted.org/packages/27/46/8d7db1dff181be50b207ab0a7483a22d5c3a4f903a9afc7cf7e465ad8109/tokenizers-0.22.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:319f659ee992222f04e58f84cbf407cfa66a65fe3a8de44e8ad2bc53e7d99012", size = 3287784, upload-time = "2026-01-05T10:40:37.108Z" },
- { url = "https://files.pythonhosted.org/packages/5b/6e/3bc33cae8bf114afa5a98e35eb065c72b7c37d01d370906a893f33881767/tokenizers-0.22.2-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1e50f8554d504f617d9e9d6e4c2c2884a12b388a97c5c77f0bc6cf4cd032feee", size = 3164301, upload-time = "2026-01-05T10:40:42.367Z" },
- { url = "https://files.pythonhosted.org/packages/91/fc/6aa749d7d443aab4daa6f8bc00338389149fd2534e25b772285c3301993e/tokenizers-0.22.2-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1a62ba2c5faa2dd175aaeed7b15abf18d20266189fb3406c5d0550dd34dd5f37", size = 3717771, upload-time = "2026-01-05T10:40:49.076Z" },
- { url = "https://files.pythonhosted.org/packages/fc/60/5b440d251863bd33f9b0a416c695b0309487b83abf6f2dafe9163a3aeac2/tokenizers-0.22.2-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:143b999bdc46d10febb15cbffb4207ddd1f410e2c755857b5a0797961bbdc113", size = 3377740, upload-time = "2026-01-05T10:40:54.859Z" },
]
[[package]]
@@ -6992,43 +5517,18 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/16/e1/3079a9ff9b8e11b846c6ac5c8b5bfb7ff225eee721825310c91b3b50304f/tqdm-4.67.3-py3-none-any.whl", hash = "sha256:ee1e4c0e59148062281c49d80b25b67771a127c85fc9676d3be5f243206826bf", size = 78374, upload-time = "2026-02-03T17:35:50.982Z" },
]
-[[package]]
-name = "trio"
-version = "0.31.0"
-source = { registry = "https://pypi.org/simple" }
-resolution-markers = [
- "python_full_version < '3.10'",
-]
-dependencies = [
- { name = "attrs", marker = "python_full_version < '3.10'" },
- { name = "cffi", marker = "python_full_version < '3.10' and implementation_name != 'pypy' and os_name == 'nt'" },
- { name = "exceptiongroup", marker = "python_full_version < '3.10'" },
- { name = "idna", marker = "python_full_version < '3.10'" },
- { name = "outcome", marker = "python_full_version < '3.10'" },
- { name = "sniffio", marker = "python_full_version < '3.10'" },
- { name = "sortedcontainers", marker = "python_full_version < '3.10'" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/76/8f/c6e36dd11201e2a565977d8b13f0b027ba4593c1a80bed5185489178e257/trio-0.31.0.tar.gz", hash = "sha256:f71d551ccaa79d0cb73017a33ef3264fde8335728eb4c6391451fe5d253a9d5b", size = 605825, upload-time = "2025-09-09T15:17:15.242Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/31/5b/94237a3485620dbff9741df02ff6d8acaa5fdec67d81ab3f62e4d8511bf7/trio-0.31.0-py3-none-any.whl", hash = "sha256:b5d14cd6293d79298b49c3485ffd9c07e3ce03a6da8c7dfbe0cb3dd7dc9a4774", size = 512679, upload-time = "2025-09-09T15:17:13.821Z" },
-]
-
[[package]]
name = "trio"
version = "0.32.0"
source = { registry = "https://pypi.org/simple" }
-resolution-markers = [
- "python_full_version >= '3.14'",
- "python_full_version >= '3.10' and python_full_version < '3.14'",
-]
dependencies = [
- { name = "attrs", marker = "python_full_version >= '3.10'" },
- { name = "cffi", marker = "python_full_version >= '3.10' and implementation_name != 'pypy' and os_name == 'nt'" },
- { name = "exceptiongroup", marker = "python_full_version == '3.10.*'" },
- { name = "idna", marker = "python_full_version >= '3.10'" },
- { name = "outcome", marker = "python_full_version >= '3.10'" },
- { name = "sniffio", marker = "python_full_version >= '3.10'" },
- { name = "sortedcontainers", marker = "python_full_version >= '3.10'" },
+ { name = "attrs" },
+ { name = "cffi", marker = "implementation_name != 'pypy' and os_name == 'nt'" },
+ { name = "exceptiongroup", marker = "python_full_version < '3.11'" },
+ { name = "idna" },
+ { name = "outcome" },
+ { name = "sniffio" },
+ { name = "sortedcontainers" },
]
sdist = { url = "https://files.pythonhosted.org/packages/d8/ce/0041ddd9160aac0031bcf5ab786c7640d795c797e67c438e15cfedf815c8/trio-0.32.0.tar.gz", hash = "sha256:150f29ec923bcd51231e1d4c71c7006e65247d68759dd1c19af4ea815a25806b", size = 605323, upload-time = "2025-10-31T07:18:17.466Z" }
wheels = [
@@ -7040,8 +5540,7 @@ name = "typer"
version = "0.21.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "click", version = "8.1.8", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
- { name = "click", version = "8.3.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
+ { name = "click" },
{ name = "rich" },
{ name = "shellingham" },
{ name = "typing-extensions" },
@@ -7069,31 +5568,12 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/aa/43/58e75bac4219cbafee83179505ff44cae3153ec279be0e30583a73b8f108/types_protobuf-6.32.1.20251210-py3-none-any.whl", hash = "sha256:2641f78f3696822a048cfb8d0ff42ccd85c25f12f871fbebe86da63793692140", size = 77921, upload-time = "2025-12-10T03:14:24.477Z" },
]
-[[package]]
-name = "types-requests"
-version = "2.31.0.6"
-source = { registry = "https://pypi.org/simple" }
-resolution-markers = [
- "python_full_version < '3.10'",
-]
-dependencies = [
- { name = "types-urllib3", marker = "python_full_version < '3.10'" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/f9/b8/c1e8d39996b4929b918aba10dba5de07a8b3f4c8487bb61bb79882544e69/types-requests-2.31.0.6.tar.gz", hash = "sha256:cd74ce3b53c461f1228a9b783929ac73a666658f223e28ed29753771477b3bd0", size = 15535, upload-time = "2023-09-27T06:19:38.443Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/5c/a1/6f8dc74d9069e790d604ddae70cb46dcbac668f1bb08136e7b0f2f5cd3bf/types_requests-2.31.0.6-py3-none-any.whl", hash = "sha256:a2db9cb228a81da8348b49ad6db3f5519452dd20a9c1e1a868c83c5fe88fd1a9", size = 14516, upload-time = "2023-09-27T06:19:36.373Z" },
-]
-
[[package]]
name = "types-requests"
version = "2.32.4.20260107"
source = { registry = "https://pypi.org/simple" }
-resolution-markers = [
- "python_full_version >= '3.14'",
- "python_full_version >= '3.10' and python_full_version < '3.14'",
-]
dependencies = [
- { name = "urllib3", version = "2.6.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
+ { name = "urllib3" },
]
sdist = { url = "https://files.pythonhosted.org/packages/0f/f3/a0663907082280664d745929205a89d41dffb29e89a50f753af7d57d0a96/types_requests-2.32.4.20260107.tar.gz", hash = "sha256:018a11ac158f801bfa84857ddec1650750e393df8a004a8a9ae2a9bec6fcb24f", size = 23165, upload-time = "2026-01-07T03:20:54.091Z" }
wheels = [
@@ -7109,15 +5589,6 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/d7/f2/d812543c350674d8b3f6e17c8922248ee3bb752c2a76f64beb8c538b40cf/types_ujson-5.10.0.20250822-py3-none-any.whl", hash = "sha256:3e9e73a6dc62ccc03449d9ac2c580cd1b7a8e4873220db498f7dd056754be080", size = 7657, upload-time = "2025-08-22T03:02:18.699Z" },
]
-[[package]]
-name = "types-urllib3"
-version = "1.26.25.14"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/73/de/b9d7a68ad39092368fb21dd6194b362b98a1daeea5dcfef5e1adb5031c7e/types-urllib3-1.26.25.14.tar.gz", hash = "sha256:229b7f577c951b8c1b92c1bc2b2fdb0b49847bd2af6d1cc2a2e3dd340f3bda8f", size = 11239, upload-time = "2023-07-20T15:19:31.307Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/11/7b/3fc711b2efea5e85a7a0bbfe269ea944aa767bbba5ec52f9ee45d362ccf3/types_urllib3-1.26.25.14-py3-none-any.whl", hash = "sha256:9683bbb7fb72e32bfe9d2be6e04875fbe1b3eeec3cbb4ea231435aa7fd6b4f0e", size = 15377, upload-time = "2023-07-20T15:19:30.379Z" },
-]
-
[[package]]
name = "typing-extensions"
version = "4.15.0"
@@ -7211,17 +5682,6 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/30/ed/5a057199fb0a5deabe0957073a1c1c1c02a3e99476cd03daee98ea21fa57/ujson-5.11.0-cp314-cp314t-win32.whl", hash = "sha256:aa6d7a5e09217ff93234e050e3e380da62b084e26b9f2e277d2606406a2fc2e5", size = 41859, upload-time = "2025-08-20T11:56:30.495Z" },
{ url = "https://files.pythonhosted.org/packages/aa/03/b19c6176bdf1dc13ed84b886e99677a52764861b6cc023d5e7b6ebda249d/ujson-5.11.0-cp314-cp314t-win_amd64.whl", hash = "sha256:48055e1061c1bb1f79e75b4ac39e821f3f35a9b82de17fce92c3140149009bec", size = 46183, upload-time = "2025-08-20T11:56:31.574Z" },
{ url = "https://files.pythonhosted.org/packages/5d/ca/a0413a3874b2dc1708b8796ca895bf363292f9c70b2e8ca482b7dbc0259d/ujson-5.11.0-cp314-cp314t-win_arm64.whl", hash = "sha256:1194b943e951092db611011cb8dbdb6cf94a3b816ed07906e14d3bc6ce0e90ab", size = 40264, upload-time = "2025-08-20T11:56:32.773Z" },
- { url = "https://files.pythonhosted.org/packages/39/bf/c6f59cdf74ce70bd937b97c31c42fd04a5ed1a9222d0197e77e4bd899841/ujson-5.11.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:65f3c279f4ed4bf9131b11972040200c66ae040368abdbb21596bf1564899694", size = 55283, upload-time = "2025-08-20T11:56:33.947Z" },
- { url = "https://files.pythonhosted.org/packages/8d/c1/a52d55638c0c644b8a63059f95ad5ffcb4ad8f60d8bc3e8680f78e77cc75/ujson-5.11.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:99c49400572cd77050894e16864a335225191fd72a818ea6423ae1a06467beac", size = 53168, upload-time = "2025-08-20T11:56:35.141Z" },
- { url = "https://files.pythonhosted.org/packages/75/6c/e64e19a01d59c8187d01ffc752ee3792a09f5edaaac2a0402de004459dd7/ujson-5.11.0-cp39-cp39-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0654a2691fc252c3c525e3d034bb27b8a7546c9d3eb33cd29ce6c9feda361a6a", size = 57809, upload-time = "2025-08-20T11:56:36.293Z" },
- { url = "https://files.pythonhosted.org/packages/9f/36/910117b7a8a1c188396f6194ca7bc8fd75e376d8f7e3cf5eb6219fc8b09d/ujson-5.11.0-cp39-cp39-manylinux_2_24_i686.manylinux_2_28_i686.whl", hash = "sha256:6b6ec7e7321d7fc19abdda3ad809baef935f49673951a8bab486aea975007e02", size = 59797, upload-time = "2025-08-20T11:56:37.746Z" },
- { url = "https://files.pythonhosted.org/packages/c7/17/bcc85d282ee2f4cdef5f577e0a43533eedcae29cc6405edf8c62a7a50368/ujson-5.11.0-cp39-cp39-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f62b9976fabbcde3ab6e413f4ec2ff017749819a0786d84d7510171109f2d53c", size = 57378, upload-time = "2025-08-20T11:56:39.123Z" },
- { url = "https://files.pythonhosted.org/packages/ef/39/120bb76441bf835f3c3f42db9c206f31ba875711637a52a8209949ab04b0/ujson-5.11.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:7f1a27ab91083b4770e160d17f61b407f587548f2c2b5fbf19f94794c495594a", size = 1036515, upload-time = "2025-08-20T11:56:40.848Z" },
- { url = "https://files.pythonhosted.org/packages/b6/ae/fe1b4ff6388f681f6710e9494656957725b1e73ae50421ec04567df9fb75/ujson-5.11.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:ecd6ff8a3b5a90c292c2396c2d63c687fd0ecdf17de390d852524393cd9ed052", size = 1195753, upload-time = "2025-08-20T11:56:42.341Z" },
- { url = "https://files.pythonhosted.org/packages/92/20/005b93f2cf846ae50b46812fcf24bbdd127521197e5f1e1a82e3b3e730a1/ujson-5.11.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:9aacbeb23fdbc4b256a7d12e0beb9063a1ba5d9e0dbb2cfe16357c98b4334596", size = 1088844, upload-time = "2025-08-20T11:56:43.777Z" },
- { url = "https://files.pythonhosted.org/packages/41/9e/3142023c30008e2b24d7368a389b26d28d62fcd3f596d3d898a72dd09173/ujson-5.11.0-cp39-cp39-win32.whl", hash = "sha256:674f306e3e6089f92b126eb2fe41bcb65e42a15432c143365c729fdb50518547", size = 39652, upload-time = "2025-08-20T11:56:45.034Z" },
- { url = "https://files.pythonhosted.org/packages/ca/89/f4de0a3c485d0163f85f552886251876645fb62cbbe24fcdc0874b9fae03/ujson-5.11.0-cp39-cp39-win_amd64.whl", hash = "sha256:c6618f480f7c9ded05e78a1938873fde68baf96cdd74e6d23c7e0a8441175c4b", size = 43783, upload-time = "2025-08-20T11:56:46.156Z" },
- { url = "https://files.pythonhosted.org/packages/48/b1/2d50987a7b7cccb5c1fbe9ae7b184211106237b32c7039118c41d79632ea/ujson-5.11.0-cp39-cp39-win_arm64.whl", hash = "sha256:5600202a731af24a25e2d7b6eb3f648e4ecd4bb67c4d5cf12f8fab31677469c9", size = 38430, upload-time = "2025-08-20T11:56:47.653Z" },
{ url = "https://files.pythonhosted.org/packages/50/17/30275aa2933430d8c0c4ead951cc4fdb922f575a349aa0b48a6f35449e97/ujson-5.11.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:abae0fb58cc820092a0e9e8ba0051ac4583958495bfa5262a12f628249e3b362", size = 51206, upload-time = "2025-08-20T11:56:48.797Z" },
{ url = "https://files.pythonhosted.org/packages/c3/15/42b3924258eac2551f8f33fa4e35da20a06a53857ccf3d4deb5e5d7c0b6c/ujson-5.11.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:fac6c0649d6b7c3682a0a6e18d3de6857977378dce8d419f57a0b20e3d775b39", size = 48907, upload-time = "2025-08-20T11:56:50.136Z" },
{ url = "https://files.pythonhosted.org/packages/94/7e/0519ff7955aba581d1fe1fb1ca0e452471250455d182f686db5ac9e46119/ujson-5.11.0-pp311-pypy311_pp73-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4b42c115c7c6012506e8168315150d1e3f76e7ba0f4f95616f4ee599a1372bbc", size = 50319, upload-time = "2025-08-20T11:56:51.63Z" },
@@ -7230,71 +5690,23 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/52/5b/8c5e33228f7f83f05719964db59f3f9f276d272dc43752fa3bbf0df53e7b/ujson-5.11.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:416389ec19ef5f2013592f791486bef712ebce0cd59299bf9df1ba40bb2f6e04", size = 43835, upload-time = "2025-08-20T11:56:55.237Z" },
]
-[[package]]
-name = "urllib3"
-version = "1.26.20"
-source = { registry = "https://pypi.org/simple" }
-resolution-markers = [
- "python_full_version < '3.10'",
-]
-sdist = { url = "https://files.pythonhosted.org/packages/e4/e8/6ff5e6bc22095cfc59b6ea711b687e2b7ed4bdb373f7eeec370a97d7392f/urllib3-1.26.20.tar.gz", hash = "sha256:40c2dc0c681e47eb8f90e7e27bf6ff7df2e677421fd46756da1161c39ca70d32", size = 307380, upload-time = "2024-08-29T15:43:11.37Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/33/cf/8435d5a7159e2a9c83a95896ed596f68cf798005fe107cc655b5c5c14704/urllib3-1.26.20-py2.py3-none-any.whl", hash = "sha256:0ed14ccfbf1c30a9072c7ca157e4319b70d65f623e91e7b32fadb2853431016e", size = 144225, upload-time = "2024-08-29T15:43:08.921Z" },
-]
-
[[package]]
name = "urllib3"
version = "2.6.3"
source = { registry = "https://pypi.org/simple" }
-resolution-markers = [
- "python_full_version >= '3.14'",
- "python_full_version >= '3.10' and python_full_version < '3.14'",
-]
sdist = { url = "https://files.pythonhosted.org/packages/c7/24/5f1b3bdffd70275f6661c76461e25f024d5a38a46f04aaca912426a2b1d3/urllib3-2.6.3.tar.gz", hash = "sha256:1b62b6884944a57dbe321509ab94fd4d3b307075e0c2eae991ac71ee15ad38ed", size = 435556, upload-time = "2026-01-07T16:24:43.925Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl", hash = "sha256:bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4", size = 131584, upload-time = "2026-01-07T16:24:42.685Z" },
]
-[[package]]
-name = "uvicorn"
-version = "0.39.0"
-source = { registry = "https://pypi.org/simple" }
-resolution-markers = [
- "python_full_version < '3.10'",
-]
-dependencies = [
- { name = "click", version = "8.1.8", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
- { name = "h11", marker = "python_full_version < '3.10'" },
- { name = "typing-extensions", marker = "python_full_version < '3.10'" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/ae/4f/f9fdac7cf6dd79790eb165639b5c452ceeabc7bbabbba4569155470a287d/uvicorn-0.39.0.tar.gz", hash = "sha256:610512b19baa93423d2892d7823741f6d27717b642c8964000d7194dded19302", size = 82001, upload-time = "2025-12-21T13:05:17.973Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/6b/25/db2b1c6c35bf22e17fe5412d2ee5d3fd7a20d07ebc9dac8b58f7db2e23a0/uvicorn-0.39.0-py3-none-any.whl", hash = "sha256:7beec21bd2693562b386285b188a7963b06853c0d006302b3e4cfed950c9929a", size = 68491, upload-time = "2025-12-21T13:05:16.291Z" },
-]
-
-[package.optional-dependencies]
-standard = [
- { name = "colorama", marker = "python_full_version < '3.10' and sys_platform == 'win32'" },
- { name = "httptools", marker = "python_full_version < '3.10'" },
- { name = "python-dotenv", marker = "python_full_version < '3.10'" },
- { name = "pyyaml", marker = "python_full_version < '3.10'" },
- { name = "uvloop", marker = "python_full_version < '3.10' and platform_python_implementation != 'PyPy' and sys_platform != 'cygwin' and sys_platform != 'win32'" },
- { name = "watchfiles", marker = "python_full_version < '3.10'" },
- { name = "websockets", marker = "python_full_version < '3.10'" },
-]
-
[[package]]
name = "uvicorn"
version = "0.40.0"
source = { registry = "https://pypi.org/simple" }
-resolution-markers = [
- "python_full_version >= '3.14'",
- "python_full_version >= '3.10' and python_full_version < '3.14'",
-]
dependencies = [
- { name = "click", version = "8.3.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
- { name = "h11", marker = "python_full_version >= '3.10'" },
- { name = "typing-extensions", marker = "python_full_version == '3.10.*'" },
+ { name = "click" },
+ { name = "h11" },
+ { name = "typing-extensions", marker = "python_full_version < '3.11'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/c3/d1/8f3c683c9561a4e6689dd3b1d345c815f10f86acd044ee1fb9a4dcd0b8c5/uvicorn-0.40.0.tar.gz", hash = "sha256:839676675e87e73694518b5574fd0f24c9d97b46bea16df7b8c05ea1a51071ea", size = 81761, upload-time = "2025-12-21T14:16:22.45Z" }
wheels = [
@@ -7303,13 +5715,13 @@ wheels = [
[package.optional-dependencies]
standard = [
- { name = "colorama", marker = "python_full_version >= '3.10' and sys_platform == 'win32'" },
- { name = "httptools", marker = "python_full_version >= '3.10'" },
- { name = "python-dotenv", marker = "python_full_version >= '3.10'" },
- { name = "pyyaml", marker = "python_full_version >= '3.10'" },
- { name = "uvloop", marker = "python_full_version >= '3.10' and platform_python_implementation != 'PyPy' and sys_platform != 'cygwin' and sys_platform != 'win32'" },
- { name = "watchfiles", marker = "python_full_version >= '3.10'" },
- { name = "websockets", marker = "python_full_version >= '3.10'" },
+ { name = "colorama", marker = "sys_platform == 'win32'" },
+ { name = "httptools" },
+ { name = "python-dotenv" },
+ { name = "pyyaml" },
+ { name = "uvloop", marker = "platform_python_implementation != 'PyPy' and sys_platform != 'cygwin' and sys_platform != 'win32'" },
+ { name = "watchfiles" },
+ { name = "websockets" },
]
[[package]]
@@ -7354,12 +5766,6 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/c1/37/945b4ca0ac27e3dc4952642d4c900edd030b3da6c9634875af6e13ae80e5/uvloop-0.22.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b91328c72635f6f9e0282e4a57da7470c7350ab1c9f48546c0f2866205349d21", size = 4467065, upload-time = "2025-10-16T22:16:58.206Z" },
{ url = "https://files.pythonhosted.org/packages/97/cc/48d232f33d60e2e2e0b42f4e73455b146b76ebe216487e862700457fbf3c/uvloop-0.22.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:daf620c2995d193449393d6c62131b3fbd40a63bf7b307a1527856ace637fe88", size = 4328384, upload-time = "2025-10-16T22:16:59.36Z" },
{ url = "https://files.pythonhosted.org/packages/e4/16/c1fd27e9549f3c4baf1dc9c20c456cd2f822dbf8de9f463824b0c0357e06/uvloop-0.22.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6cde23eeda1a25c75b2e07d39970f3374105d5eafbaab2a4482be82f272d5a5e", size = 4296730, upload-time = "2025-10-16T22:17:00.744Z" },
- { url = "https://files.pythonhosted.org/packages/bd/1b/6fbd611aeba01ef802c5876c94d7be603a9710db055beacbad39e75a31aa/uvloop-0.22.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:b45649628d816c030dba3c80f8e2689bab1c89518ed10d426036cdc47874dfc4", size = 1345858, upload-time = "2025-10-16T22:17:11.106Z" },
- { url = "https://files.pythonhosted.org/packages/9e/91/2c84f00bdbe3c51023cc83b027bac1fe959ba4a552e970da5ef0237f7945/uvloop-0.22.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ea721dd3203b809039fcc2983f14608dae82b212288b346e0bfe46ec2fab0b7c", size = 743913, upload-time = "2025-10-16T22:17:12.165Z" },
- { url = "https://files.pythonhosted.org/packages/cc/10/76aec83886d41a88aca5681db6a2c0601622d0d2cb66cd0d200587f962ad/uvloop-0.22.1-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0ae676de143db2b2f60a9696d7eca5bb9d0dd6cc3ac3dad59a8ae7e95f9e1b54", size = 3635818, upload-time = "2025-10-16T22:17:13.812Z" },
- { url = "https://files.pythonhosted.org/packages/d5/9a/733fcb815d345979fc54d3cdc3eb50bc75a47da3e4003ea7ada58e6daa65/uvloop-0.22.1-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:17d4e97258b0172dfa107b89aa1eeba3016f4b1974ce85ca3ef6a66b35cbf659", size = 3685477, upload-time = "2025-10-16T22:17:15.307Z" },
- { url = "https://files.pythonhosted.org/packages/83/fb/bee1eb11cc92bd91f76d97869bb6a816e80d59fd73721b0a3044dc703d9c/uvloop-0.22.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:05e4b5f86e621cf3927631789999e697e58f0d2d32675b67d9ca9eb0bca55743", size = 3496128, upload-time = "2025-10-16T22:17:16.558Z" },
- { url = "https://files.pythonhosted.org/packages/76/ee/3fdfeaa9776c0fd585d358c92b1dbca669720ffa476f0bbe64ed8f245bd7/uvloop-0.22.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:286322a90bea1f9422a470d5d2ad82d38080be0a29c4dd9b3e6384320a4d11e7", size = 3602565, upload-time = "2025-10-16T22:17:17.755Z" },
]
[[package]]
@@ -7380,13 +5786,8 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/68/98/b0345cabdce2041a01293ba483333582891a3bd5769b08eceb0d406056ef/watchdog-6.0.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:490ab2ef84f11129844c23fb14ecf30ef3d8a6abafd3754a6f75ca1e6654136c", size = 96480, upload-time = "2024-11-01T14:06:42.952Z" },
{ url = "https://files.pythonhosted.org/packages/85/83/cdf13902c626b28eedef7ec4f10745c52aad8a8fe7eb04ed7b1f111ca20e/watchdog-6.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:76aae96b00ae814b181bb25b1b98076d5fc84e8a53cd8885a318b42b6d3a5134", size = 88451, upload-time = "2024-11-01T14:06:45.084Z" },
{ url = "https://files.pythonhosted.org/packages/fe/c4/225c87bae08c8b9ec99030cd48ae9c4eca050a59bf5c2255853e18c87b50/watchdog-6.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a175f755fc2279e0b7312c0035d52e27211a5bc39719dd529625b1930917345b", size = 89057, upload-time = "2024-11-01T14:06:47.324Z" },
- { url = "https://files.pythonhosted.org/packages/05/52/7223011bb760fce8ddc53416beb65b83a3ea6d7d13738dde75eeb2c89679/watchdog-6.0.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e6f0e77c9417e7cd62af82529b10563db3423625c5fce018430b249bf977f9e8", size = 96390, upload-time = "2024-11-01T14:06:49.325Z" },
- { url = "https://files.pythonhosted.org/packages/9c/62/d2b21bc4e706d3a9d467561f487c2938cbd881c69f3808c43ac1ec242391/watchdog-6.0.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:90c8e78f3b94014f7aaae121e6b909674df5b46ec24d6bebc45c44c56729af2a", size = 88386, upload-time = "2024-11-01T14:06:50.536Z" },
- { url = "https://files.pythonhosted.org/packages/ea/22/1c90b20eda9f4132e4603a26296108728a8bfe9584b006bd05dd94548853/watchdog-6.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e7631a77ffb1f7d2eefa4445ebbee491c720a5661ddf6df3498ebecae5ed375c", size = 89017, upload-time = "2024-11-01T14:06:51.717Z" },
{ url = "https://files.pythonhosted.org/packages/30/ad/d17b5d42e28a8b91f8ed01cb949da092827afb9995d4559fd448d0472763/watchdog-6.0.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:c7ac31a19f4545dd92fc25d200694098f42c9a8e391bc00bdd362c5736dbf881", size = 87902, upload-time = "2024-11-01T14:06:53.119Z" },
{ url = "https://files.pythonhosted.org/packages/5c/ca/c3649991d140ff6ab67bfc85ab42b165ead119c9e12211e08089d763ece5/watchdog-6.0.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:9513f27a1a582d9808cf21a07dae516f0fab1cf2d7683a742c498b93eedabb11", size = 88380, upload-time = "2024-11-01T14:06:55.19Z" },
- { url = "https://files.pythonhosted.org/packages/5b/79/69f2b0e8d3f2afd462029031baafb1b75d11bb62703f0e1022b2e54d49ee/watchdog-6.0.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7a0e56874cfbc4b9b05c60c8a1926fedf56324bb08cfbc188969777940aef3aa", size = 87903, upload-time = "2024-11-01T14:06:57.052Z" },
- { url = "https://files.pythonhosted.org/packages/e2/2b/dc048dd71c2e5f0f7ebc04dd7912981ec45793a03c0dc462438e0591ba5d/watchdog-6.0.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:e6439e374fc012255b4ec786ae3c4bc838cd7309a540e5fe0952d03687d8804e", size = 88381, upload-time = "2024-11-01T14:06:58.193Z" },
{ url = "https://files.pythonhosted.org/packages/a9/c7/ca4bf3e518cb57a686b2feb4f55a1892fd9a3dd13f470fca14e00f80ea36/watchdog-6.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:7607498efa04a3542ae3e05e64da8202e58159aa1fa4acddf7678d34a35d4f13", size = 79079, upload-time = "2024-11-01T14:06:59.472Z" },
{ url = "https://files.pythonhosted.org/packages/5c/51/d46dc9332f9a647593c947b4b88e2381c8dfc0942d15b8edc0310fa4abb1/watchdog-6.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:9041567ee8953024c83343288ccc458fd0a2d811d6a0fd68c4c22609e3490379", size = 79078, upload-time = "2024-11-01T14:07:01.431Z" },
{ url = "https://files.pythonhosted.org/packages/d4/57/04edbf5e169cd318d5f07b4766fee38e825d64b6913ca157ca32d1a42267/watchdog-6.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:82dc3e3143c7e38ec49d61af98d6558288c415eac98486a5c581726e0737c00e", size = 79076, upload-time = "2024-11-01T14:07:02.568Z" },
@@ -7492,18 +5893,6 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/4f/55/2af26693fd15165c4ff7857e38330e1b61ab8c37d15dc79118cdba115b7a/watchfiles-1.1.1-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8c91ed27800188c2ae96d16e3149f199d62f86c7af5f5f4d2c61a3ed8cd3666c", size = 455072, upload-time = "2025-10-14T15:05:48.928Z" },
{ url = "https://files.pythonhosted.org/packages/66/1d/d0d200b10c9311ec25d2273f8aad8c3ef7cc7ea11808022501811208a750/watchfiles-1.1.1-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:311ff15a0bae3714ffb603e6ba6dbfba4065ab60865d15a6ec544133bdb21099", size = 629104, upload-time = "2025-10-14T15:05:49.908Z" },
{ url = "https://files.pythonhosted.org/packages/e3/bd/fa9bb053192491b3867ba07d2343d9f2252e00811567d30ae8d0f78136fe/watchfiles-1.1.1-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:a916a2932da8f8ab582f242c065f5c81bed3462849ca79ee357dd9551b0e9b01", size = 622112, upload-time = "2025-10-14T15:05:50.941Z" },
- { url = "https://files.pythonhosted.org/packages/a4/68/a7303a15cc797ab04d58f1fea7f67c50bd7f80090dfd7e750e7576e07582/watchfiles-1.1.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:c882d69f6903ef6092bedfb7be973d9319940d56b8427ab9187d1ecd73438a70", size = 409220, upload-time = "2025-10-14T15:05:51.917Z" },
- { url = "https://files.pythonhosted.org/packages/99/b8/d1857ce9ac76034c053fa7ef0e0ef92d8bd031e842ea6f5171725d31e88f/watchfiles-1.1.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d6ff426a7cb54f310d51bfe83fe9f2bbe40d540c741dc974ebc30e6aa238f52e", size = 396712, upload-time = "2025-10-14T15:05:53.437Z" },
- { url = "https://files.pythonhosted.org/packages/41/7a/da7ada566f48beaa6a30b13335b49d1f6febaf3a5ddbd1d92163a1002cf4/watchfiles-1.1.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:79ff6c6eadf2e3fc0d7786331362e6ef1e51125892c75f1004bd6b52155fb956", size = 451462, upload-time = "2025-10-14T15:05:54.742Z" },
- { url = "https://files.pythonhosted.org/packages/e2/b2/7cb9e0d5445a8d45c4cccd68a590d9e3a453289366b96ff37d1075aaebef/watchfiles-1.1.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c1f5210f1b8fc91ead1283c6fd89f70e76fb07283ec738056cf34d51e9c1d62c", size = 460811, upload-time = "2025-10-14T15:05:55.743Z" },
- { url = "https://files.pythonhosted.org/packages/04/9d/b07d4491dde6db6ea6c680fdec452f4be363d65c82004faf2d853f59b76f/watchfiles-1.1.1-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b9c4702f29ca48e023ffd9b7ff6b822acdf47cb1ff44cb490a3f1d5ec8987e9c", size = 490576, upload-time = "2025-10-14T15:05:56.983Z" },
- { url = "https://files.pythonhosted.org/packages/56/03/e64dcab0a1806157db272a61b7891b062f441a30580a581ae72114259472/watchfiles-1.1.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:acb08650863767cbc58bca4813b92df4d6c648459dcaa3d4155681962b2aa2d3", size = 597726, upload-time = "2025-10-14T15:05:57.986Z" },
- { url = "https://files.pythonhosted.org/packages/5c/8e/a827cf4a8d5f2903a19a934dcf512082eb07675253e154d4cd9367978a58/watchfiles-1.1.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:08af70fd77eee58549cd69c25055dc344f918d992ff626068242259f98d598a2", size = 474900, upload-time = "2025-10-14T15:05:59.378Z" },
- { url = "https://files.pythonhosted.org/packages/dc/a6/94fed0b346b85b22303a12eee5f431006fae6af70d841cac2f4403245533/watchfiles-1.1.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c3631058c37e4a0ec440bf583bc53cdbd13e5661bb6f465bc1d88ee9a0a4d02", size = 457521, upload-time = "2025-10-14T15:06:00.419Z" },
- { url = "https://files.pythonhosted.org/packages/c4/64/bc3331150e8f3c778d48a4615d4b72b3d2d87868635e6c54bbd924946189/watchfiles-1.1.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:cf57a27fb986c6243d2ee78392c503826056ffe0287e8794503b10fb51b881be", size = 632191, upload-time = "2025-10-14T15:06:01.621Z" },
- { url = "https://files.pythonhosted.org/packages/e4/84/f39e19549c2f3ec97225dcb2ceb9a7bb3c5004ed227aad1f321bf0ff2051/watchfiles-1.1.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d7e7067c98040d646982daa1f37a33d3544138ea155536c2e0e63e07ff8a7e0f", size = 623923, upload-time = "2025-10-14T15:06:02.671Z" },
- { url = "https://files.pythonhosted.org/packages/0e/24/0759ae15d9a0c9c5fe946bd4cf45ab9e7bad7cfede2c06dc10f59171b29f/watchfiles-1.1.1-cp39-cp39-win32.whl", hash = "sha256:6c9c9262f454d1c4d8aaa7050121eb4f3aea197360553699520767daebf2180b", size = 274010, upload-time = "2025-10-14T15:06:03.779Z" },
- { url = "https://files.pythonhosted.org/packages/7e/3b/eb26cddd4dfa081e2bf6918be3b2fc05ee3b55c1d21331d5562ee0c6aaad/watchfiles-1.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:74472234c8370669850e1c312490f6026d132ca2d396abfad8830b4f1c096957", size = 289090, upload-time = "2025-10-14T15:06:04.821Z" },
{ url = "https://files.pythonhosted.org/packages/ba/4c/a888c91e2e326872fa4705095d64acd8aa2fb9c1f7b9bd0588f33850516c/watchfiles-1.1.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:17ef139237dfced9da49fb7f2232c86ca9421f666d78c264c7ffca6601d154c3", size = 409611, upload-time = "2025-10-14T15:06:05.809Z" },
{ url = "https://files.pythonhosted.org/packages/1e/c7/5420d1943c8e3ce1a21c0a9330bcf7edafb6aa65d26b21dbb3267c9e8112/watchfiles-1.1.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:672b8adf25b1a0d35c96b5888b7b18699d27d4194bac8beeae75be4b7a3fc9b2", size = 396889, upload-time = "2025-10-14T15:06:07.035Z" },
{ url = "https://files.pythonhosted.org/packages/0c/e5/0072cef3804ce8d3aaddbfe7788aadff6b3d3f98a286fdbee9fd74ca59a7/watchfiles-1.1.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77a13aea58bc2b90173bc69f2a90de8e282648939a00a602e1dc4ee23e26b66d", size = 451616, upload-time = "2025-10-14T15:06:08.072Z" },
@@ -7512,10 +5901,6 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/bd/95/615e72cd27b85b61eec764a5ca51bd94d40b5adea5ff47567d9ebc4d275a/watchfiles-1.1.1-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:89eef07eee5e9d1fda06e38822ad167a044153457e6fd997f8a858ab7564a336", size = 396117, upload-time = "2025-10-14T15:06:11.28Z" },
{ url = "https://files.pythonhosted.org/packages/c9/81/e7fe958ce8a7fb5c73cc9fb07f5aeaf755e6aa72498c57d760af760c91f8/watchfiles-1.1.1-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ce19e06cbda693e9e7686358af9cd6f5d61312ab8b00488bc36f5aabbaf77e24", size = 450493, upload-time = "2025-10-14T15:06:12.321Z" },
{ url = "https://files.pythonhosted.org/packages/6e/d4/ed38dd3b1767193de971e694aa544356e63353c33a85d948166b5ff58b9e/watchfiles-1.1.1-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3e6f39af2eab0118338902798b5aa6664f46ff66bc0280de76fca67a7f262a49", size = 457546, upload-time = "2025-10-14T15:06:13.372Z" },
- { url = "https://files.pythonhosted.org/packages/00/db/38a2c52fdbbfe2fc7ffaaaaaebc927d52b9f4d5139bba3186c19a7463001/watchfiles-1.1.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:cdab464fee731e0884c35ae3588514a9bcf718d0e2c82169c1c4a85cc19c3c7f", size = 409210, upload-time = "2025-10-14T15:06:14.492Z" },
- { url = "https://files.pythonhosted.org/packages/d1/43/d7e8b71f6c21ff813ee8da1006f89b6c7fff047fb4c8b16ceb5e840599c5/watchfiles-1.1.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:3dbd8cbadd46984f802f6d479b7e3afa86c42d13e8f0f322d669d79722c8ec34", size = 397286, upload-time = "2025-10-14T15:06:16.177Z" },
- { url = "https://files.pythonhosted.org/packages/1f/5d/884074a5269317e75bd0b915644b702b89de73e61a8a7446e2b225f45b1f/watchfiles-1.1.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5524298e3827105b61951a29c3512deb9578586abf3a7c5da4a8069df247cccc", size = 451768, upload-time = "2025-10-14T15:06:18.266Z" },
- { url = "https://files.pythonhosted.org/packages/17/71/7ffcaa9b5e8961a25026058058c62ec8f604d2a6e8e1e94bee8a09e1593f/watchfiles-1.1.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b943d3668d61cfa528eb949577479d3b077fd25fb83c641235437bc0b5bc60e", size = 458561, upload-time = "2025-10-14T15:06:19.323Z" },
]
[[package]]
@@ -7586,29 +5971,12 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/33/2b/1f168cb6041853eef0362fb9554c3824367c5560cbdaad89ac40f8c2edfc/websockets-15.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:558d023b3df0bffe50a04e710bc87742de35060580a293c2a984299ed83bc4e4", size = 182195, upload-time = "2025-03-05T20:02:51.561Z" },
{ url = "https://files.pythonhosted.org/packages/86/eb/20b6cdf273913d0ad05a6a14aed4b9a85591c18a987a3d47f20fa13dcc47/websockets-15.0.1-cp313-cp313-win32.whl", hash = "sha256:ba9e56e8ceeeedb2e080147ba85ffcd5cd0711b89576b83784d8605a7df455fa", size = 176393, upload-time = "2025-03-05T20:02:53.814Z" },
{ url = "https://files.pythonhosted.org/packages/1b/6c/c65773d6cab416a64d191d6ee8a8b1c68a09970ea6909d16965d26bfed1e/websockets-15.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:e09473f095a819042ecb2ab9465aee615bd9c2028e4ef7d933600a8401c79561", size = 176837, upload-time = "2025-03-05T20:02:55.237Z" },
- { url = "https://files.pythonhosted.org/packages/36/db/3fff0bcbe339a6fa6a3b9e3fbc2bfb321ec2f4cd233692272c5a8d6cf801/websockets-15.0.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:5f4c04ead5aed67c8a1a20491d54cdfba5884507a48dd798ecaf13c74c4489f5", size = 175424, upload-time = "2025-03-05T20:02:56.505Z" },
- { url = "https://files.pythonhosted.org/packages/46/e6/519054c2f477def4165b0ec060ad664ed174e140b0d1cbb9fafa4a54f6db/websockets-15.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:abdc0c6c8c648b4805c5eacd131910d2a7f6455dfd3becab248ef108e89ab16a", size = 173077, upload-time = "2025-03-05T20:02:58.37Z" },
- { url = "https://files.pythonhosted.org/packages/1a/21/c0712e382df64c93a0d16449ecbf87b647163485ca1cc3f6cbadb36d2b03/websockets-15.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a625e06551975f4b7ea7102bc43895b90742746797e2e14b70ed61c43a90f09b", size = 173324, upload-time = "2025-03-05T20:02:59.773Z" },
- { url = "https://files.pythonhosted.org/packages/1c/cb/51ba82e59b3a664df54beed8ad95517c1b4dc1a913730e7a7db778f21291/websockets-15.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d591f8de75824cbb7acad4e05d2d710484f15f29d4a915092675ad3456f11770", size = 182094, upload-time = "2025-03-05T20:03:01.827Z" },
- { url = "https://files.pythonhosted.org/packages/fb/0f/bf3788c03fec679bcdaef787518dbe60d12fe5615a544a6d4cf82f045193/websockets-15.0.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:47819cea040f31d670cc8d324bb6435c6f133b8c7a19ec3d61634e62f8d8f9eb", size = 181094, upload-time = "2025-03-05T20:03:03.123Z" },
- { url = "https://files.pythonhosted.org/packages/5e/da/9fb8c21edbc719b66763a571afbaf206cb6d3736d28255a46fc2fe20f902/websockets-15.0.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac017dd64572e5c3bd01939121e4d16cf30e5d7e110a119399cf3133b63ad054", size = 181397, upload-time = "2025-03-05T20:03:04.443Z" },
- { url = "https://files.pythonhosted.org/packages/2e/65/65f379525a2719e91d9d90c38fe8b8bc62bd3c702ac651b7278609b696c4/websockets-15.0.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:4a9fac8e469d04ce6c25bb2610dc535235bd4aa14996b4e6dbebf5e007eba5ee", size = 181794, upload-time = "2025-03-05T20:03:06.708Z" },
- { url = "https://files.pythonhosted.org/packages/d9/26/31ac2d08f8e9304d81a1a7ed2851c0300f636019a57cbaa91342015c72cc/websockets-15.0.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:363c6f671b761efcb30608d24925a382497c12c506b51661883c3e22337265ed", size = 181194, upload-time = "2025-03-05T20:03:08.844Z" },
- { url = "https://files.pythonhosted.org/packages/98/72/1090de20d6c91994cd4b357c3f75a4f25ee231b63e03adea89671cc12a3f/websockets-15.0.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:2034693ad3097d5355bfdacfffcbd3ef5694f9718ab7f29c29689a9eae841880", size = 181164, upload-time = "2025-03-05T20:03:10.242Z" },
- { url = "https://files.pythonhosted.org/packages/2d/37/098f2e1c103ae8ed79b0e77f08d83b0ec0b241cf4b7f2f10edd0126472e1/websockets-15.0.1-cp39-cp39-win32.whl", hash = "sha256:3b1ac0d3e594bf121308112697cf4b32be538fb1444468fb0a6ae4feebc83411", size = 176381, upload-time = "2025-03-05T20:03:12.77Z" },
- { url = "https://files.pythonhosted.org/packages/75/8b/a32978a3ab42cebb2ebdd5b05df0696a09f4d436ce69def11893afa301f0/websockets-15.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:b7643a03db5c95c799b89b31c036d5f27eeb4d259c798e878d6937d71832b1e4", size = 176841, upload-time = "2025-03-05T20:03:14.367Z" },
{ url = "https://files.pythonhosted.org/packages/02/9e/d40f779fa16f74d3468357197af8d6ad07e7c5a27ea1ca74ceb38986f77a/websockets-15.0.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:0c9e74d766f2818bb95f84c25be4dea09841ac0f734d1966f415e4edfc4ef1c3", size = 173109, upload-time = "2025-03-05T20:03:17.769Z" },
{ url = "https://files.pythonhosted.org/packages/bc/cd/5b887b8585a593073fd92f7c23ecd3985cd2c3175025a91b0d69b0551372/websockets-15.0.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:1009ee0c7739c08a0cd59de430d6de452a55e42d6b522de7aa15e6f67db0b8e1", size = 173343, upload-time = "2025-03-05T20:03:19.094Z" },
{ url = "https://files.pythonhosted.org/packages/fe/ae/d34f7556890341e900a95acf4886833646306269f899d58ad62f588bf410/websockets-15.0.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76d1f20b1c7a2fa82367e04982e708723ba0e7b8d43aa643d3dcd404d74f1475", size = 174599, upload-time = "2025-03-05T20:03:21.1Z" },
{ url = "https://files.pythonhosted.org/packages/71/e6/5fd43993a87db364ec60fc1d608273a1a465c0caba69176dd160e197ce42/websockets-15.0.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f29d80eb9a9263b8d109135351caf568cc3f80b9928bccde535c235de55c22d9", size = 174207, upload-time = "2025-03-05T20:03:23.221Z" },
{ url = "https://files.pythonhosted.org/packages/2b/fb/c492d6daa5ec067c2988ac80c61359ace5c4c674c532985ac5a123436cec/websockets-15.0.1-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b359ed09954d7c18bbc1680f380c7301f92c60bf924171629c5db97febb12f04", size = 174155, upload-time = "2025-03-05T20:03:25.321Z" },
{ url = "https://files.pythonhosted.org/packages/68/a1/dcb68430b1d00b698ae7a7e0194433bce4f07ded185f0ee5fb21e2a2e91e/websockets-15.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:cad21560da69f4ce7658ca2cb83138fb4cf695a2ba3e475e0559e05991aa8122", size = 176884, upload-time = "2025-03-05T20:03:27.934Z" },
- { url = "https://files.pythonhosted.org/packages/b7/48/4b67623bac4d79beb3a6bb27b803ba75c1bdedc06bd827e465803690a4b2/websockets-15.0.1-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7f493881579c90fc262d9cdbaa05a6b54b3811c2f300766748db79f098db9940", size = 173106, upload-time = "2025-03-05T20:03:29.404Z" },
- { url = "https://files.pythonhosted.org/packages/ed/f0/adb07514a49fe5728192764e04295be78859e4a537ab8fcc518a3dbb3281/websockets-15.0.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:47b099e1f4fbc95b701b6e85768e1fcdaf1630f3cbe4765fa216596f12310e2e", size = 173339, upload-time = "2025-03-05T20:03:30.755Z" },
- { url = "https://files.pythonhosted.org/packages/87/28/bd23c6344b18fb43df40d0700f6d3fffcd7cef14a6995b4f976978b52e62/websockets-15.0.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:67f2b6de947f8c757db2db9c71527933ad0019737ec374a8a6be9a956786aaf9", size = 174597, upload-time = "2025-03-05T20:03:32.247Z" },
- { url = "https://files.pythonhosted.org/packages/6d/79/ca288495863d0f23a60f546f0905ae8f3ed467ad87f8b6aceb65f4c013e4/websockets-15.0.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d08eb4c2b7d6c41da6ca0600c077e93f5adcfd979cd777d747e9ee624556da4b", size = 174205, upload-time = "2025-03-05T20:03:33.731Z" },
- { url = "https://files.pythonhosted.org/packages/04/e4/120ff3180b0872b1fe6637f6f995bcb009fb5c87d597c1fc21456f50c848/websockets-15.0.1-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b826973a4a2ae47ba357e4e82fa44a463b8f168e1ca775ac64521442b19e87f", size = 174150, upload-time = "2025-03-05T20:03:35.757Z" },
- { url = "https://files.pythonhosted.org/packages/cb/c3/30e2f9c539b8da8b1d76f64012f3b19253271a63413b2d3adb94b143407f/websockets-15.0.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:21c1fa28a6a7e3cbdc171c694398b6df4744613ce9b36b1a498e816787e28123", size = 176877, upload-time = "2025-03-05T20:03:37.199Z" },
{ url = "https://files.pythonhosted.org/packages/fa/a8/5b41e0da817d64113292ab1f8247140aac61cbf6cfd085d6a0fa77f4984f/websockets-15.0.1-py3-none-any.whl", hash = "sha256:f7a866fbc1e97b5c617ee4116daaa09b722101d4a3c170c787450ba409f9736f", size = 169743, upload-time = "2025-03-05T20:03:39.41Z" },
]
@@ -7690,16 +6058,6 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/be/44/a1bd64b723d13bb151d6cc91b986146a1952385e0392a78567e12149c7b4/wrapt-1.17.3-cp314-cp314t-win32.whl", hash = "sha256:41b1d2bc74c2cac6f9074df52b2efbef2b30bdfe5f40cb78f8ca22963bc62977", size = 38717, upload-time = "2025-08-12T05:53:15.214Z" },
{ url = "https://files.pythonhosted.org/packages/79/d9/7cfd5a312760ac4dd8bf0184a6ee9e43c33e47f3dadc303032ce012b8fa3/wrapt-1.17.3-cp314-cp314t-win_amd64.whl", hash = "sha256:73d496de46cd2cdbdbcce4ae4bcdb4afb6a11234a1df9c085249d55166b95116", size = 41334, upload-time = "2025-08-12T05:53:14.178Z" },
{ url = "https://files.pythonhosted.org/packages/46/78/10ad9781128ed2f99dbc474f43283b13fea8ba58723e98844367531c18e9/wrapt-1.17.3-cp314-cp314t-win_arm64.whl", hash = "sha256:f38e60678850c42461d4202739f9bf1e3a737c7ad283638251e79cc49effb6b6", size = 38471, upload-time = "2025-08-12T05:52:57.784Z" },
- { url = "https://files.pythonhosted.org/packages/41/be/be9b3b0a461ee3e30278706f3f3759b9b69afeedef7fe686036286c04ac6/wrapt-1.17.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:30ce38e66630599e1193798285706903110d4f057aab3168a34b7fdc85569afc", size = 53485, upload-time = "2025-08-12T05:51:53.11Z" },
- { url = "https://files.pythonhosted.org/packages/b3/a8/8f61d6b8f526efc8c10e12bf80b4206099fea78ade70427846a37bc9cbea/wrapt-1.17.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:65d1d00fbfb3ea5f20add88bbc0f815150dbbde3b026e6c24759466c8b5a9ef9", size = 38675, upload-time = "2025-08-12T05:51:42.885Z" },
- { url = "https://files.pythonhosted.org/packages/48/f1/23950c29a25637b74b322f9e425a17cc01a478f6afb35138ecb697f9558d/wrapt-1.17.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a7c06742645f914f26c7f1fa47b8bc4c91d222f76ee20116c43d5ef0912bba2d", size = 38956, upload-time = "2025-08-12T05:52:03.149Z" },
- { url = "https://files.pythonhosted.org/packages/43/46/dd0791943613885f62619f18ee6107e6133237a6b6ed8a9ecfac339d0b4f/wrapt-1.17.3-cp39-cp39-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:7e18f01b0c3e4a07fe6dfdb00e29049ba17eadbc5e7609a2a3a4af83ab7d710a", size = 81745, upload-time = "2025-08-12T05:52:49.62Z" },
- { url = "https://files.pythonhosted.org/packages/dd/ec/bb2d19bd1a614cc4f438abac13ae26c57186197920432d2a915183b15a8b/wrapt-1.17.3-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0f5f51a6466667a5a356e6381d362d259125b57f059103dd9fdc8c0cf1d14139", size = 82833, upload-time = "2025-08-12T05:52:27.738Z" },
- { url = "https://files.pythonhosted.org/packages/8d/eb/66579aea6ad36f07617fedca8e282e49c7c9bab64c63b446cfe4f7f47a49/wrapt-1.17.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:59923aa12d0157f6b82d686c3fd8e1166fa8cdfb3e17b42ce3b6147ff81528df", size = 81889, upload-time = "2025-08-12T05:52:29.023Z" },
- { url = "https://files.pythonhosted.org/packages/04/9c/a56b5ac0e2473bdc3fb11b22dd69ff423154d63861cf77911cdde5e38fd2/wrapt-1.17.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:46acc57b331e0b3bcb3e1ca3b421d65637915cfcd65eb783cb2f78a511193f9b", size = 81344, upload-time = "2025-08-12T05:52:50.869Z" },
- { url = "https://files.pythonhosted.org/packages/93/4c/9bd735c42641d81cb58d7bfb142c58f95c833962d15113026705add41a07/wrapt-1.17.3-cp39-cp39-win32.whl", hash = "sha256:3e62d15d3cfa26e3d0788094de7b64efa75f3a53875cdbccdf78547aed547a81", size = 36462, upload-time = "2025-08-12T05:53:19.623Z" },
- { url = "https://files.pythonhosted.org/packages/f0/ea/0b72f29cb5ebc16eb55c57dc0c98e5de76fc97f435fd407f7d409459c0a6/wrapt-1.17.3-cp39-cp39-win_amd64.whl", hash = "sha256:1f23fa283f51c890eda8e34e4937079114c74b4c81d2b2f1f1d94948f5cc3d7f", size = 38740, upload-time = "2025-08-12T05:53:18.271Z" },
- { url = "https://files.pythonhosted.org/packages/c3/8b/9eae65fb92321e38dbfec7719b87d840a4b92fde83fd1bbf238c5488d055/wrapt-1.17.3-cp39-cp39-win_arm64.whl", hash = "sha256:24c2ed34dc222ed754247a2702b1e1e89fdbaa4016f324b4b8f1a802d4ffe87f", size = 36806, upload-time = "2025-08-12T05:52:58.765Z" },
{ url = "https://files.pythonhosted.org/packages/1f/f6/a933bd70f98e9cf3e08167fc5cd7aaaca49147e48411c0bd5ae701bb2194/wrapt-1.17.3-py3-none-any.whl", hash = "sha256:7171ae35d2c33d326ac19dd8facb1e82e5fd04ef8c6c0e394d7af55a55051c22", size = 23591, upload-time = "2025-08-12T05:53:20.674Z" },
]
@@ -7708,14 +6066,14 @@ name = "xai-sdk"
version = "1.6.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "aiohttp", marker = "python_full_version >= '3.10'" },
- { name = "googleapis-common-protos", marker = "python_full_version >= '3.10'" },
- { name = "grpcio", marker = "python_full_version >= '3.10'" },
- { name = "opentelemetry-sdk", marker = "python_full_version >= '3.10'" },
- { name = "packaging", marker = "python_full_version >= '3.10'" },
- { name = "protobuf", version = "6.33.5", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
- { name = "pydantic", marker = "python_full_version >= '3.10'" },
- { name = "requests", marker = "python_full_version >= '3.10'" },
+ { name = "aiohttp" },
+ { name = "googleapis-common-protos" },
+ { name = "grpcio" },
+ { name = "opentelemetry-sdk" },
+ { name = "packaging" },
+ { name = "protobuf" },
+ { name = "pydantic" },
+ { name = "requests" },
]
sdist = { url = "https://files.pythonhosted.org/packages/9e/66/1e0163eac090733d0ed0836a0cd3c14f5b59abeaa6fdba71c7b56b1916e4/xai_sdk-1.6.1.tar.gz", hash = "sha256:b55528df188f8c8448484021d735f75b0e7d71719ddeb432c5f187ac67e3c983", size = 388223, upload-time = "2026-01-29T03:13:07.373Z" }
wheels = [
@@ -7845,22 +6203,6 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/35/18/55e6011f7c044dc80b98893060773cefcfdbf60dfefb8cb2f58b9bacbd83/yarl-1.22.0-cp314-cp314t-win32.whl", hash = "sha256:8009b3173bcd637be650922ac455946197d858b3630b6d8787aa9e5c4564533e", size = 89056, upload-time = "2025-10-06T14:12:13.317Z" },
{ url = "https://files.pythonhosted.org/packages/f9/86/0f0dccb6e59a9e7f122c5afd43568b1d31b8ab7dda5f1b01fb5c7025c9a9/yarl-1.22.0-cp314-cp314t-win_amd64.whl", hash = "sha256:9fb17ea16e972c63d25d4a97f016d235c78dd2344820eb35bc034bc32012ee27", size = 96292, upload-time = "2025-10-06T14:12:15.398Z" },
{ url = "https://files.pythonhosted.org/packages/48/b7/503c98092fb3b344a179579f55814b613c1fbb1c23b3ec14a7b008a66a6e/yarl-1.22.0-cp314-cp314t-win_arm64.whl", hash = "sha256:9f6d73c1436b934e3f01df1e1b21ff765cd1d28c77dfb9ace207f746d4610ee1", size = 85171, upload-time = "2025-10-06T14:12:16.935Z" },
- { url = "https://files.pythonhosted.org/packages/94/fd/6480106702a79bcceda5fd9c63cb19a04a6506bd5ce7fd8d9b63742f0021/yarl-1.22.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:3aa27acb6de7a23785d81557577491f6c38a5209a254d1191519d07d8fe51748", size = 141301, upload-time = "2025-10-06T14:12:19.01Z" },
- { url = "https://files.pythonhosted.org/packages/42/e1/6d95d21b17a93e793e4ec420a925fe1f6a9342338ca7a563ed21129c0990/yarl-1.22.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:af74f05666a5e531289cb1cc9c883d1de2088b8e5b4de48004e5ca8a830ac859", size = 93864, upload-time = "2025-10-06T14:12:21.05Z" },
- { url = "https://files.pythonhosted.org/packages/32/58/b8055273c203968e89808413ea4c984988b6649baabf10f4522e67c22d2f/yarl-1.22.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:62441e55958977b8167b2709c164c91a6363e25da322d87ae6dd9c6019ceecf9", size = 94706, upload-time = "2025-10-06T14:12:23.287Z" },
- { url = "https://files.pythonhosted.org/packages/18/91/d7bfbc28a88c2895ecd0da6a874def0c147de78afc52c773c28e1aa233a3/yarl-1.22.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b580e71cac3f8113d3135888770903eaf2f507e9421e5697d6ee6d8cd1c7f054", size = 347100, upload-time = "2025-10-06T14:12:28.527Z" },
- { url = "https://files.pythonhosted.org/packages/bd/e8/37a1e7b99721c0564b1fc7b0a4d1f595ef6fb8060d82ca61775b644185f7/yarl-1.22.0-cp39-cp39-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e81fda2fb4a07eda1a2252b216aa0df23ebcd4d584894e9612e80999a78fd95b", size = 318902, upload-time = "2025-10-06T14:12:30.528Z" },
- { url = "https://files.pythonhosted.org/packages/1c/ef/34724449d7ef2db4f22df644f2dac0b8a275d20f585e526937b3ae47b02d/yarl-1.22.0-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:99b6fc1d55782461b78221e95fc357b47ad98b041e8e20f47c1411d0aacddc60", size = 363302, upload-time = "2025-10-06T14:12:32.295Z" },
- { url = "https://files.pythonhosted.org/packages/8a/04/88a39a5dad39889f192cce8d66cc4c58dbeca983e83f9b6bf23822a7ed91/yarl-1.22.0-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:088e4e08f033db4be2ccd1f34cf29fe994772fb54cfe004bbf54db320af56890", size = 370816, upload-time = "2025-10-06T14:12:34.01Z" },
- { url = "https://files.pythonhosted.org/packages/6b/1f/5e895e547129413f56c76be2c3ce4b96c797d2d0ff3e16a817d9269b12e6/yarl-1.22.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2e4e1f6f0b4da23e61188676e3ed027ef0baa833a2e633c29ff8530800edccba", size = 346465, upload-time = "2025-10-06T14:12:35.977Z" },
- { url = "https://files.pythonhosted.org/packages/11/13/a750e9fd6f9cc9ed3a52a70fe58ffe505322f0efe0d48e1fd9ffe53281f5/yarl-1.22.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:84fc3ec96fce86ce5aa305eb4aa9358279d1aa644b71fab7b8ed33fe3ba1a7ca", size = 341506, upload-time = "2025-10-06T14:12:37.788Z" },
- { url = "https://files.pythonhosted.org/packages/3c/67/bb6024de76e7186611ebe626aec5b71a2d2ecf9453e795f2dbd80614784c/yarl-1.22.0-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:5dbeefd6ca588b33576a01b0ad58aa934bc1b41ef89dee505bf2932b22ddffba", size = 335030, upload-time = "2025-10-06T14:12:39.775Z" },
- { url = "https://files.pythonhosted.org/packages/a2/be/50b38447fd94a7992996a62b8b463d0579323fcfc08c61bdba949eef8a5d/yarl-1.22.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:14291620375b1060613f4aab9ebf21850058b6b1b438f386cc814813d901c60b", size = 358560, upload-time = "2025-10-06T14:12:41.547Z" },
- { url = "https://files.pythonhosted.org/packages/e2/89/c020b6f547578c4e3dbb6335bf918f26e2f34ad0d1e515d72fd33ac0c635/yarl-1.22.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:a4fcfc8eb2c34148c118dfa02e6427ca278bfd0f3df7c5f99e33d2c0e81eae3e", size = 357290, upload-time = "2025-10-06T14:12:43.861Z" },
- { url = "https://files.pythonhosted.org/packages/8c/52/c49a619ee35a402fa3a7019a4fa8d26878fec0d1243f6968bbf516789578/yarl-1.22.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:029866bde8d7b0878b9c160e72305bbf0a7342bcd20b9999381704ae03308dc8", size = 350700, upload-time = "2025-10-06T14:12:46.868Z" },
- { url = "https://files.pythonhosted.org/packages/ab/c9/f5042d87777bf6968435f04a2bbb15466b2f142e6e47fa4f34d1a3f32f0c/yarl-1.22.0-cp39-cp39-win32.whl", hash = "sha256:4dcc74149ccc8bba31ce1944acee24813e93cfdee2acda3c172df844948ddf7b", size = 82323, upload-time = "2025-10-06T14:12:48.633Z" },
- { url = "https://files.pythonhosted.org/packages/fd/58/d00f7cad9eba20c4eefac2682f34661d1d1b3a942fc0092eb60e78cfb733/yarl-1.22.0-cp39-cp39-win_amd64.whl", hash = "sha256:10619d9fdee46d20edc49d3479e2f8269d0779f1b031e6f7c2aa1c76be04b7ed", size = 87145, upload-time = "2025-10-06T14:12:50.241Z" },
- { url = "https://files.pythonhosted.org/packages/c2/a3/70904f365080780d38b919edd42d224b8c4ce224a86950d2eaa2a24366ad/yarl-1.22.0-cp39-cp39-win_arm64.whl", hash = "sha256:dd7afd3f8b0bfb4e0d9fc3c31bfe8a4ec7debe124cfd90619305def3c8ca8cd2", size = 82173, upload-time = "2025-10-06T14:12:51.869Z" },
{ url = "https://files.pythonhosted.org/packages/73/ae/b48f95715333080afb75a4504487cbe142cae1268afc482d06692d605ae6/yarl-1.22.0-py3-none-any.whl", hash = "sha256:1380560bdba02b6b6c90de54133c81c9f2a453dee9912fe58c1dcced1edb7cff", size = 46814, upload-time = "2025-10-06T14:12:53.872Z" },
]