diff --git a/.github/workflows/issue-manager.yml b/.github/workflows/issue-manager.yml
index fbb856792..439084434 100644
--- a/.github/workflows/issue-manager.yml
+++ b/.github/workflows/issue-manager.yml
@@ -27,7 +27,7 @@ jobs:
env:
GITHUB_CONTEXT: ${{ toJson(github) }}
run: echo "$GITHUB_CONTEXT"
- - uses: tiangolo/issue-manager@0.5.0
+ - uses: tiangolo/issue-manager@0.5.1
with:
token: ${{ secrets.GITHUB_TOKEN }}
config: >
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 7e58afd4b..f74816f12 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -14,7 +14,7 @@ repos:
- id: end-of-file-fixer
- id: trailing-whitespace
- repo: https://github.com/astral-sh/ruff-pre-commit
- rev: v0.6.3
+ rev: v0.6.4
hooks:
- id: ruff
args:
diff --git a/docs/en/docs/environment-variables.md b/docs/en/docs/environment-variables.md
index 78e82d5af..43dd06add 100644
--- a/docs/en/docs/environment-variables.md
+++ b/docs/en/docs/environment-variables.md
@@ -243,8 +243,6 @@ This way, when you type `python` in the terminal, the system will find the Pytho
////
-This way, when you type `python` in the terminal, the system will find the Python program in `/opt/custompython/bin` (the last directory) and use that one.
-
So, if you type:
diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md
index e09eb57b6..01c9fb225 100644
--- a/docs/en/docs/release-notes.md
+++ b/docs/en/docs/release-notes.md
@@ -7,12 +7,32 @@ hide:
## Latest Changes
+### Internal
+
+* ➕ Add inline-snapshot for tests. PR [#12189](https://github.com/fastapi/fastapi/pull/12189) by [@tiangolo](https://github.com/tiangolo).
+
+## 0.114.1
+
+### Refactors
+
+* ⚡️ Improve performance in request body parsing with a cache for internal model fields. PR [#12184](https://github.com/fastapi/fastapi/pull/12184) by [@tiangolo](https://github.com/tiangolo).
+
+### Docs
+
+* 📝 Remove duplicate line in docs for `docs/en/docs/environment-variables.md`. PR [#12169](https://github.com/fastapi/fastapi/pull/12169) by [@prometek](https://github.com/prometek).
+
### Translations
+* 🌐 Add Portuguese translation for `docs/pt/docs/virtual-environments.md`. PR [#12163](https://github.com/fastapi/fastapi/pull/12163) by [@marcelomarkus](https://github.com/marcelomarkus).
+* 🌐 Add Portuguese translation for `docs/pt/docs/environment-variables.md`. PR [#12162](https://github.com/fastapi/fastapi/pull/12162) by [@marcelomarkus](https://github.com/marcelomarkus).
+* 🌐 Add Portuguese translation for `docs/pt/docs/tutorial/testing.md`. PR [#12164](https://github.com/fastapi/fastapi/pull/12164) by [@marcelomarkus](https://github.com/marcelomarkus).
+* 🌐 Add Portuguese translation for `docs/pt/docs/tutorial/debugging.md`. PR [#12165](https://github.com/fastapi/fastapi/pull/12165) by [@marcelomarkus](https://github.com/marcelomarkus).
* 🌐 Add Korean translation for `docs/ko/docs/project-generation.md`. PR [#12157](https://github.com/fastapi/fastapi/pull/12157) by [@BORA040126](https://github.com/BORA040126).
### Internal
+* ⬆ Bump tiangolo/issue-manager from 0.5.0 to 0.5.1. PR [#12173](https://github.com/fastapi/fastapi/pull/12173) by [@dependabot[bot]](https://github.com/apps/dependabot).
+* ⬆ [pre-commit.ci] pre-commit autoupdate. PR [#12176](https://github.com/fastapi/fastapi/pull/12176) by [@pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci).
* 👷 Update `issue-manager.yml`. PR [#12159](https://github.com/fastapi/fastapi/pull/12159) by [@tiangolo](https://github.com/tiangolo).
* ✏️ Fix typo in `fastapi/params.py`. PR [#12143](https://github.com/fastapi/fastapi/pull/12143) by [@surreal30](https://github.com/surreal30).
diff --git a/docs/pt/docs/environment-variables.md b/docs/pt/docs/environment-variables.md
new file mode 100644
index 000000000..360d1c496
--- /dev/null
+++ b/docs/pt/docs/environment-variables.md
@@ -0,0 +1,298 @@
+# Variáveis de Ambiente
+
+/// tip | "Dica"
+
+Se você já sabe o que são "variáveis de ambiente" e como usá-las, pode pular esta seção.
+
+///
+
+Uma variável de ambiente (também conhecida como "**env var**") é uma variável que existe **fora** do código Python, no **sistema operacional**, e pode ser lida pelo seu código Python (ou por outros programas também).
+
+Variáveis de ambiente podem ser úteis para lidar com **configurações** do aplicativo, como parte da **instalação** do Python, etc.
+
+## Criar e Usar Variáveis de Ambiente
+
+Você pode **criar** e usar variáveis de ambiente no **shell (terminal)**, sem precisar do Python:
+
+//// tab | Linux, macOS, Windows Bash
+
+
+
+```console
+// Você pode criar uma variável de ambiente MY_NAME com
+$ export MY_NAME="Wade Wilson"
+
+// Então você pode usá-la com outros programas, como
+$ echo "Hello $MY_NAME"
+
+Hello Wade Wilson
+```
+
+
+
+////
+
+//// tab | Windows PowerShell
+
+
+
+```console
+// Criar uma variável de ambiente MY_NAME
+$ $Env:MY_NAME = "Wade Wilson"
+
+// Usá-la com outros programas, como
+$ echo "Hello $Env:MY_NAME"
+
+Hello Wade Wilson
+```
+
+
+
+////
+
+## Ler Variáveis de Ambiente no Python
+
+Você também pode criar variáveis de ambiente **fora** do Python, no terminal (ou com qualquer outro método) e depois **lê-las no Python**.
+
+Por exemplo, você poderia ter um arquivo `main.py` com:
+
+```Python hl_lines="3"
+import os
+
+name = os.getenv("MY_NAME", "World")
+print(f"Hello {name} from Python")
+```
+
+/// tip | "Dica"
+
+O segundo argumento para
`os.getenv()` é o valor padrão a ser retornado.
+
+Se não for fornecido, é `None` por padrão, Aqui fornecemos `"World"` como o valor padrão a ser usado.
+
+///
+
+Então você poderia chamar esse programa Python:
+
+//// tab | Linux, macOS, Windows Bash
+
+
+
+```console
+// Aqui ainda não definimos a variável de ambiente
+$ python main.py
+
+// Como não definimos a variável de ambiente, obtemos o valor padrão
+
+Hello World from Python
+
+// Mas se criarmos uma variável de ambiente primeiro
+$ export MY_NAME="Wade Wilson"
+
+// E então chamar o programa novamente
+$ python main.py
+
+// Agora ele pode ler a variável de ambiente
+
+Hello Wade Wilson from Python
+```
+
+
+
+////
+
+//// tab | Windows PowerShell
+
+
+
+```console
+// Aqui ainda não definimos a variável de ambiente
+$ python main.py
+
+// Como não definimos a variável de ambiente, obtemos o valor padrão
+
+Hello World from Python
+
+// Mas se criarmos uma variável de ambiente primeiro
+$ $Env:MY_NAME = "Wade Wilson"
+
+// E então chamar o programa novamente
+$ python main.py
+
+// Agora ele pode ler a variável de ambiente
+
+Hello Wade Wilson from Python
+```
+
+
+
+////
+
+Como as variáveis de ambiente podem ser definidas fora do código, mas podem ser lidas pelo código e não precisam ser armazenadas (com versão no `git`) com o restante dos arquivos, é comum usá-las para configurações ou **definições**.
+
+Você também pode criar uma variável de ambiente apenas para uma **invocação específica do programa**, que só está disponível para aquele programa e apenas pela duração dele.
+
+Para fazer isso, crie-a na mesma linha, antes do próprio programa:
+
+
+
+```console
+// Criar uma variável de ambiente MY_NAME para esta chamada de programa
+$ MY_NAME="Wade Wilson" python main.py
+
+// Agora ele pode ler a variável de ambiente
+
+Hello Wade Wilson from Python
+
+// A variável de ambiente não existe mais depois
+$ python main.py
+
+Hello World from Python
+```
+
+
+
+/// tip | "Dica"
+
+Você pode ler mais sobre isso em
The Twelve-Factor App: Config.
+
+///
+
+## Tipos e Validação
+
+Essas variáveis de ambiente só podem lidar com **strings de texto**, pois são externas ao Python e precisam ser compatíveis com outros programas e com o resto do sistema (e até mesmo com diferentes sistemas operacionais, como Linux, Windows, macOS).
+
+Isso significa que **qualquer valor** lido em Python de uma variável de ambiente **será uma `str`**, e qualquer conversão para um tipo diferente ou qualquer validação precisa ser feita no código.
+
+Você aprenderá mais sobre como usar variáveis de ambiente para lidar com **configurações do aplicativo** no [Guia do Usuário Avançado - Configurações e Variáveis de Ambiente](./advanced/settings.md){.internal-link target=_blank}.
+
+## Variável de Ambiente `PATH`
+
+Existe uma variável de ambiente **especial** chamada **`PATH`** que é usada pelos sistemas operacionais (Linux, macOS, Windows) para encontrar programas para executar.
+
+O valor da variável `PATH` é uma longa string composta por diretórios separados por dois pontos `:` no Linux e macOS, e por ponto e vírgula `;` no Windows.
+
+Por exemplo, a variável de ambiente `PATH` poderia ter esta aparência:
+
+//// tab | Linux, macOS
+
+```plaintext
+/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
+```
+
+Isso significa que o sistema deve procurar programas nos diretórios:
+
+* `/usr/local/bin`
+* `/usr/bin`
+* `/bin`
+* `/usr/sbin`
+* `/sbin`
+
+////
+
+//// tab | Windows
+
+```plaintext
+C:\Program Files\Python312\Scripts;C:\Program Files\Python312;C:\Windows\System32
+```
+
+Isso significa que o sistema deve procurar programas nos diretórios:
+
+* `C:\Program Files\Python312\Scripts`
+* `C:\Program Files\Python312`
+* `C:\Windows\System32`
+
+////
+
+Quando você digita um **comando** no terminal, o sistema operacional **procura** o programa em **cada um dos diretórios** listados na variável de ambiente `PATH`.
+
+Por exemplo, quando você digita `python` no terminal, o sistema operacional procura um programa chamado `python` no **primeiro diretório** dessa lista.
+
+Se ele o encontrar, então ele o **usará**. Caso contrário, ele continua procurando nos **outros diretórios**.
+
+### Instalando o Python e Atualizando o `PATH`
+
+Durante a instalação do Python, você pode ser questionado sobre a atualização da variável de ambiente `PATH`.
+
+//// tab | Linux, macOS
+
+Vamos supor que você instale o Python e ele fique em um diretório `/opt/custompython/bin`.
+
+Se você concordar em atualizar a variável de ambiente `PATH`, o instalador adicionará `/opt/custompython/bin` para a variável de ambiente `PATH`.
+
+Poderia parecer assim:
+
+```plaintext
+/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/custompython/bin
+```
+
+Dessa forma, ao digitar `python` no terminal, o sistema encontrará o programa Python em `/opt/custompython/bin` (último diretório) e o utilizará.
+
+////
+
+//// tab | Windows
+
+Digamos que você instala o Python e ele acaba em um diretório `C:\opt\custompython\bin`.
+
+Se você disser sim para atualizar a variável de ambiente `PATH`, o instalador adicionará `C:\opt\custompython\bin` à variável de ambiente `PATH`.
+
+```plaintext
+C:\Program Files\Python312\Scripts;C:\Program Files\Python312;C:\Windows\System32;C:\opt\custompython\bin
+```
+
+Dessa forma, quando você digitar `python` no terminal, o sistema encontrará o programa Python em `C:\opt\custompython\bin` (o último diretório) e o utilizará.
+
+////
+
+Então, se você digitar:
+
+
+
+```console
+$ python
+```
+
+
+
+//// tab | Linux, macOS
+
+O sistema **encontrará** o programa `python` em `/opt/custompython/bin` e o executará.
+
+Seria aproximadamente equivalente a digitar:
+
+
+
+```console
+$ /opt/custompython/bin/python
+```
+
+
+
+////
+
+//// tab | Windows
+
+O sistema **encontrará** o programa `python` em `C:\opt\custompython\bin\python` e o executará.
+
+Seria aproximadamente equivalente a digitar:
+
+
+
+```console
+$ C:\opt\custompython\bin\python
+```
+
+
+
+////
+
+Essas informações serão úteis ao aprender sobre [Ambientes Virtuais](virtual-environments.md){.internal-link target=_blank}.
+
+## Conclusão
+
+Com isso, você deve ter uma compreensão básica do que são **variáveis de ambiente** e como usá-las em Python.
+
+Você também pode ler mais sobre elas na
Wikipedia para Variáveis de Ambiente.
+
+Em muitos casos, não é muito óbvio como as variáveis de ambiente seriam úteis e aplicáveis imediatamente. Mas elas continuam aparecendo em muitos cenários diferentes quando você está desenvolvendo, então é bom saber sobre elas.
+
+Por exemplo, você precisará dessas informações na próxima seção, sobre [Ambientes Virtuais](virtual-environments.md).
diff --git a/docs/pt/docs/tutorial/debugging.md b/docs/pt/docs/tutorial/debugging.md
new file mode 100644
index 000000000..54582fcbc
--- /dev/null
+++ b/docs/pt/docs/tutorial/debugging.md
@@ -0,0 +1,115 @@
+# Depuração
+
+Você pode conectar o depurador no seu editor, por exemplo, com o Visual Studio Code ou PyCharm.
+
+## Chamar `uvicorn`
+
+Em seu aplicativo FastAPI, importe e execute `uvicorn` diretamente:
+
+```Python hl_lines="1 15"
+{!../../../docs_src/debugging/tutorial001.py!}
+```
+
+### Sobre `__name__ == "__main__"`
+
+O objetivo principal de `__name__ == "__main__"` é ter algum código que seja executado quando seu arquivo for chamado com:
+
+
+
+```console
+$ python myapp.py
+```
+
+
+
+mas não é chamado quando outro arquivo o importa, como em:
+
+```Python
+from myapp import app
+```
+
+#### Mais detalhes
+
+Digamos que seu arquivo se chama `myapp.py`.
+
+Se você executá-lo com:
+
+
+
+```console
+$ python myapp.py
+```
+
+
+
+então a variável interna `__name__` no seu arquivo, criada automaticamente pelo Python, terá como valor a string `"__main__"`.
+
+Então, a seção:
+
+```Python
+ uvicorn.run(app, host="0.0.0.0", port=8000)
+```
+
+vai executar.
+
+---
+
+Isso não acontecerá se você importar esse módulo (arquivo).
+
+Então, se você tiver outro arquivo `importer.py` com:
+
+```Python
+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__"`.
+
+Então, a linha:
+
+```Python
+ uvicorn.run(app, host="0.0.0.0", port=8000)
+```
+
+não será executada.
+
+/// info | "Informação"
+
+Para mais informações, consulte
a documentação oficial do Python.
+
+///
+
+## Execute seu código com seu depurador
+
+Como você está executando o servidor Uvicorn diretamente do seu código, você pode chamar seu programa Python (seu aplicativo FastAPI) diretamente do depurador.
+
+---
+
+Por exemplo, no Visual Studio Code, você pode:
+
+* Ir para o painel "Debug".
+* "Add configuration...".
+* Selecionar "Python"
+* Executar o depurador com a opção "`Python: Current File (Integrated Terminal)`".
+
+Em seguida, ele iniciará o servidor com seu código **FastAPI**, parará em seus pontos de interrupção, etc.
+
+Veja como pode parecer:
+
+

+
+---
+
+Se você usar o Pycharm, você pode:
+
+* Abrir o menu "Executar".
+* Selecionar a opção "Depurar...".
+* Então um menu de contexto aparece.
+* Selecionar o arquivo para depurar (neste caso, `main.py`).
+
+Em seguida, ele iniciará o servidor com seu código **FastAPI**, parará em seus pontos de interrupção, etc.
+
+Veja como pode parecer:
+
+

diff --git a/docs/pt/docs/tutorial/testing.md b/docs/pt/docs/tutorial/testing.md
new file mode 100644
index 000000000..f734a7d9a
--- /dev/null
+++ b/docs/pt/docs/tutorial/testing.md
@@ -0,0 +1,249 @@
+# Testando
+
+Graças ao
Starlette, testar aplicativos **FastAPI** é fácil e agradável.
+
+Ele é baseado no
HTTPX, que por sua vez é projetado com base em Requests, por isso é muito familiar e intuitivo.
+
+Com ele, você pode usar o
pytest diretamente com **FastAPI**.
+
+## Usando `TestClient`
+
+/// info | "Informação"
+
+Para usar o `TestClient`, primeiro instale o
`httpx`.
+
+Certifique-se de criar um [ambiente virtual](../virtual-environments.md){.internal-link target=_blank}, ativá-lo e instalá-lo, por exemplo:
+
+```console
+$ pip install httpx
+```
+
+///
+
+Importe `TestClient`.
+
+Crie um `TestClient` passando seu aplicativo **FastAPI** para ele.
+
+Crie funções com um nome que comece com `test_` (essa é a convenção padrão do `pytest`).
+
+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).
+
+```Python hl_lines="2 12 15-18"
+{!../../../docs_src/app_testing/tutorial001.py!}
+```
+
+/// tip | "Dica"
+
+Observe que as funções de teste são `def` normais, não `async def`.
+
+E as chamadas para o cliente também são chamadas normais, não usando `await`.
+
+Isso permite que você use `pytest` diretamente sem complicações.
+
+///
+
+/// note | "Detalhes técnicos"
+
+Você também pode usar `from starlette.testclient import TestClient`.
+
+**FastAPI** fornece o mesmo `starlette.testclient` que `fastapi.testclient` apenas como uma conveniência para você, o desenvolvedor. Mas ele vem diretamente da Starlette.
+
+///
+
+/// tip | "Dica"
+
+Se você quiser chamar funções `async` em seus testes além de enviar solicitações ao seu aplicativo FastAPI (por exemplo, funções de banco de dados assíncronas), dê uma olhada em [Testes assíncronos](../advanced/async-tests.md){.internal-link target=_blank} no tutorial avançado.
+
+///
+
+## Separando testes
+
+Em uma aplicação real, você provavelmente teria seus testes em um arquivo diferente.
+
+E seu aplicativo **FastAPI** também pode ser composto de vários arquivos/módulos, etc.
+
+### Arquivo do aplicativo **FastAPI**
+
+Digamos que você tenha uma estrutura de arquivo conforme descrito em [Aplicativos maiores](bigger-applications.md){.internal-link target=_blank}:
+
+```
+.
+├── app
+│ ├── __init__.py
+│ └── main.py
+```
+
+No arquivo `main.py` você tem seu aplicativo **FastAPI**:
+
+
+```Python
+{!../../../docs_src/app_testing/main.py!}
+```
+
+### Arquivo de teste
+
+Então você poderia ter um arquivo `test_main.py` com seus testes. Ele poderia estar no mesmo pacote Python (o mesmo diretório com um arquivo `__init__.py`):
+
+``` hl_lines="5"
+.
+├── app
+│ ├── __init__.py
+│ ├── main.py
+│ └── test_main.py
+```
+
+Como esse arquivo está no mesmo pacote, você pode usar importações relativas para importar o objeto `app` do módulo `main` (`main.py`):
+
+```Python hl_lines="3"
+{!../../../docs_src/app_testing/test_main.py!}
+```
+
+...e ter o código para os testes como antes.
+
+## Testando: exemplo estendido
+
+Agora vamos estender este exemplo e adicionar mais detalhes para ver como testar diferentes partes.
+
+### Arquivo de aplicativo **FastAPI** estendido
+
+Vamos continuar com a mesma estrutura de arquivo de antes:
+
+```
+.
+├── app
+│ ├── __init__.py
+│ ├── main.py
+│ └── test_main.py
+```
+
+Digamos que agora o arquivo `main.py` com seu aplicativo **FastAPI** tenha algumas outras **operações de rotas**.
+
+Ele tem uma operação `GET` que pode retornar um erro.
+
+Ele tem uma operação `POST` que pode retornar vários erros.
+
+Ambas as *operações de rotas* requerem um cabeçalho `X-Token`.
+
+//// tab | Python 3.10+
+
+```Python
+{!> ../../../docs_src/app_testing/app_b_an_py310/main.py!}
+```
+
+////
+
+//// tab | Python 3.9+
+
+```Python
+{!> ../../../docs_src/app_testing/app_b_an_py39/main.py!}
+```
+
+////
+
+//// tab | Python 3.8+
+
+```Python
+{!> ../../../docs_src/app_testing/app_b_an/main.py!}
+```
+
+////
+
+//// tab | Python 3.10+ non-Annotated
+
+/// tip | "Dica"
+
+Prefira usar a versão `Annotated` se possível.
+
+///
+
+```Python
+{!> ../../../docs_src/app_testing/app_b_py310/main.py!}
+```
+
+////
+
+//// tab | Python 3.8+ non-Annotated
+
+/// tip | "Dica"
+
+Prefira usar a versão `Annotated` se possível.
+
+///
+
+```Python
+{!> ../../../docs_src/app_testing/app_b/main.py!}
+```
+
+////
+
+### Arquivo de teste estendido
+
+Você pode então atualizar `test_main.py` com os testes estendidos:
+
+```Python
+{!> ../../../docs_src/app_testing/app_b/test_main.py!}
+```
+
+Sempre que você precisar que o cliente passe informações na requisição e não souber como, você pode pesquisar (no Google) como fazer isso no `httpx`, ou até mesmo como fazer isso com `requests`, já que o design do HTTPX é baseado no design do Requests.
+
+Depois é só fazer o mesmo nos seus testes.
+
+Por exemplo:
+
+* Para passar um parâmetro *path* ou *query*, adicione-o à própria URL.
+* Para passar um corpo JSON, passe um objeto Python (por exemplo, um `dict`) para o parâmetro `json`.
+* Se você precisar enviar *Dados de Formulário* em vez de JSON, use o parâmetro `data`.
+* Para passar *headers*, use um `dict` no parâmetro `headers`.
+* Para *cookies*, um `dict` no parâmetro `cookies`.
+
+Para mais informações sobre como passar dados para o backend (usando `httpx` ou `TestClient`), consulte a
documentação do HTTPX.
+
+/// info | "Informação"
+
+Observe que o `TestClient` recebe dados que podem ser convertidos para JSON, não para modelos Pydantic.
+
+Se você tiver um modelo Pydantic em seu teste e quiser enviar seus dados para o aplicativo durante o teste, poderá usar o `jsonable_encoder` descrito em [Codificador compatível com JSON](encoder.md){.internal-link target=_blank}.
+
+///
+
+## Execute-o
+
+Depois disso, você só precisa instalar o `pytest`.
+
+Certifique-se de criar um [ambiente virtual](../virtual-environments.md){.internal-link target=_blank}, ativá-lo e instalá-lo, por exemplo:
+
+
+
+```console
+$ pip install pytest
+
+---> 100%
+```
+
+
+
+Ele detectará os arquivos e os testes automaticamente, os executará e informará os resultados para você.
+
+Execute os testes com:
+
+
+
+```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/pt/docs/virtual-environments.md b/docs/pt/docs/virtual-environments.md
new file mode 100644
index 000000000..863c8d65e
--- /dev/null
+++ b/docs/pt/docs/virtual-environments.md
@@ -0,0 +1,844 @@
+# Ambientes Virtuais
+
+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.
+
+/// info | "Informação"
+
+Se você já sabe sobre ambientes virtuais, como criá-los e usá-los, talvez seja melhor pular esta seção. 🤓
+
+///
+
+/// tip | "Dica"
+
+Um **ambiente virtual** é diferente de uma **variável de ambiente**.
+
+Uma **variável de ambiente** é uma variável no sistema que pode ser usada por programas.
+
+Um **ambiente virtual** é um diretório com alguns arquivos.
+
+///
+
+/// info | "Informação"
+
+Esta página lhe ensinará como usar **ambientes virtuais** e como eles funcionam.
+
+Se você estiver pronto para adotar uma **ferramenta que gerencia tudo** para você (incluindo a instalação do Python), experimente
uv.
+
+///
+
+## Criar um Projeto
+
+Primeiro, crie um diretório para seu projeto.
+
+O que normalmente faço é criar um diretório chamado `code` dentro do meu diretório home/user.
+
+E dentro disso eu crio um diretório por projeto.
+
+
+
+```console
+// Vá para o diretório inicial
+$ cd
+// Crie um diretório para todos os seus projetos de código
+$ mkdir code
+// Entre nesse diretório de código
+$ cd code
+// Crie um diretório para este projeto
+$ mkdir awesome-project
+// Entre no diretório do projeto
+$ cd awesome-project
+```
+
+
+
+## Crie um ambiente virtual
+
+Ao começar a trabalhar em um projeto Python **pela primeira vez**, crie um ambiente virtual **
dentro do seu projeto**.
+
+/// tip | "Dica"
+
+Você só precisa fazer isso **uma vez por projeto**, não toda vez que trabalhar.
+
+///
+
+//// tab | `venv`
+
+Para criar um ambiente virtual, você pode usar o módulo `venv` que vem com o Python.
+
+
+
+```console
+$ python -m venv .venv
+```
+
+
+
+/// details | O que esse comando significa
+
+* `python`: usa o programa chamado `python`
+* `-m`: chama um módulo como um script, nós diremos a ele qual módulo vem em seguida
+* `venv`: usa o módulo chamado `venv` que normalmente vem instalado com o Python
+* `.venv`: cria o ambiente virtual no novo diretório `.venv`
+
+///
+
+////
+
+//// tab | `uv`
+
+Se você tiver o
`uv` instalado, poderá usá-lo para criar um ambiente virtual.
+
+
+
+```console
+$ uv venv
+```
+
+
+
+/// tip | "Dica"
+
+Por padrão, `uv` criará um ambiente virtual em um diretório chamado `.venv`.
+
+Mas você pode personalizá-lo passando um argumento adicional com o nome do diretório.
+
+///
+
+////
+
+Esse comando cria um novo ambiente virtual em um diretório chamado `.venv`.
+
+/// details | `.venv` ou outro nome
+
+Você pode criar o ambiente virtual em um diretório diferente, mas há uma convenção para chamá-lo de `.venv`.
+
+///
+
+## Ative o ambiente virtual
+
+Ative o novo ambiente virtual para que qualquer comando Python que você executar ou pacote que você instalar o utilize.
+
+/// tip | "Dica"
+
+Faça isso **toda vez** que iniciar uma **nova sessão de terminal** para trabalhar no projeto.
+
+///
+
+//// tab | Linux, macOS
+
+
+
+```console
+$ source .venv/bin/activate
+```
+
+
+
+////
+
+//// tab | Windows PowerShell
+
+
+
+```console
+$ .venv\Scripts\Activate.ps1
+```
+
+
+
+////
+
+//// tab | Windows Bash
+
+Ou se você usa o Bash para Windows (por exemplo,
Git Bash):
+
+
+
+```console
+$ source .venv/Scripts/activate
+```
+
+
+
+////
+
+/// tip | "Dica"
+
+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.
+
+///
+
+## Verifique se o ambiente virtual está ativo
+
+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 pretendido.
+
+///
+
+//// tab | Linux, macOS, Windows Bash
+
+
+
+```console
+$ which python
+
+/home/user/code/awesome-project/.venv/bin/python
+```
+
+
+
+Se ele mostrar o binário `python` em `.venv/bin/python`, dentro do seu projeto (neste caso `awesome-project`), então funcionou. 🎉
+
+////
+
+//// tab | Windows PowerShell
+
+
+
+```console
+$ Get-Command python
+
+C:\Users\user\code\awesome-project\.venv\Scripts\python
+```
+
+
+
+Se ele mostrar o binário `python` em `.venv\Scripts\python`, dentro do seu projeto (neste caso `awesome-project`), então funcionou. 🎉
+
+////
+
+## Atualizar `pip`
+
+/// tip | "Dica"
+
+Se você usar
`uv`, você o usará para instalar coisas em vez do `pip`, então não precisará atualizar o `pip`. 😎
+
+///
+
+Se você estiver usando `pip` para instalar pacotes (ele vem por padrão com o Python), você deve **atualizá-lo** para a versão mais recente.
+
+Muitos erros exóticos durante a instalação de um pacote são resolvidos apenas atualizando o `pip` primeiro.
+
+/// tip | "Dica"
+
+Normalmente, você faria isso **uma vez**, logo após criar o ambiente virtual.
+
+///
+
+Certifique-se de que o ambiente virtual esteja ativo (com o comando acima) e execute:
+
+
+
+```console
+$ python -m pip install --upgrade pip
+
+---> 100%
+```
+
+
+
+## Adicionar `.gitignore`
+
+Se você estiver usando **Git** (você deveria), adicione um arquivo `.gitignore` para excluir tudo em seu `.venv` do Git.
+
+/// tip | "Dica"
+
+Se você usou
`uv` para criar o ambiente virtual, ele já fez isso para você, você pode pular esta etapa. 😎
+
+///
+
+/// tip | "Dica"
+
+Faça isso **uma vez**, logo após criar o ambiente virtual.
+
+///
+
+
+
+```console
+$ echo "*" > .venv/.gitignore
+```
+
+
+
+/// details | O que esse comando significa
+
+* `echo "*"`: irá "imprimir" o texto `*` no terminal (a próxima parte muda isso um pouco)
+* `>`: qualquer coisa impressa no terminal pelo comando à esquerda de `>` não deve ser impressa, mas sim escrita no arquivo que vai à direita de `>`
+* `.gitignore`: o nome do arquivo onde o texto deve ser escrito
+
+E `*` para Git significa "tudo". Então, ele ignorará tudo no diretório `.venv`.
+
+Esse comando criará um arquivo `.gitignore` com o conteúdo:
+
+```gitignore
+*
+```
+
+///
+
+## Instalar Pacotes
+
+Após ativar o ambiente, você pode instalar pacotes nele.
+
+/// tip | "Dica"
+
+Faça isso **uma vez** ao instalar ou atualizar os pacotes que seu projeto precisa.
+
+Se precisar atualizar uma versão ou adicionar um novo pacote, você **fará isso novamente**.
+
+///
+
+### Instalar pacotes diretamente
+
+Se estiver com pressa e não quiser usar um arquivo para declarar os requisitos de pacote do seu projeto, você pode instalá-los diretamente.
+
+/// tip | "Dica"
+
+É uma (muito) boa ideia colocar os pacotes e versões que seu programa precisa em um arquivo (por exemplo `requirements.txt` ou `pyproject.toml`).
+
+///
+
+//// tab | `pip`
+
+
+
+```console
+$ pip install "fastapi[standard]"
+
+---> 100%
+```
+
+
+
+////
+
+//// tab | `uv`
+
+Se você tem o
`uv`:
+
+
+
+```console
+$ uv pip install "fastapi[standard]"
+---> 100%
+```
+
+
+
+////
+
+### Instalar a partir de `requirements.txt`
+
+Se você tiver um `requirements.txt`, agora poderá usá-lo para instalar seus pacotes.
+
+//// tab | `pip`
+
+
+
+```console
+$ pip install -r requirements.txt
+---> 100%
+```
+
+
+
+////
+
+//// tab | `uv`
+
+Se você tem o
`uv`:
+
+
+
+```console
+$ uv pip install -r requirements.txt
+---> 100%
+```
+
+
+
+////
+
+/// details | `requirements.txt`
+
+Um `requirements.txt` com alguns pacotes poderia se parecer com:
+
+```requirements.txt
+fastapi[standard]==0.113.0
+pydantic==2.8.0
+```
+
+///
+
+## Execute seu programa
+
+Depois de ativar o ambiente virtual, você pode executar seu programa, e ele usará o Python dentro do seu ambiente virtual com os pacotes que você instalou lá.
+
+
+
+```console
+$ python main.py
+
+Hello World
+```
+
+
+
+## Configure seu editor
+
+Você provavelmente usaria um editor. Certifique-se de configurá-lo para usar o mesmo ambiente virtual que você criou (ele provavelmente o detectará automaticamente) para que você possa obter erros de preenchimento automático e em linha.
+
+Por exemplo:
+
+*
VS Code
+*
PyCharm
+
+/// tip | "Dica"
+
+Normalmente, você só precisa fazer isso **uma vez**, ao criar o ambiente virtual.
+
+///
+
+## Desativar o ambiente virtual
+
+Quando terminar de trabalhar no seu projeto, você pode **desativar** o ambiente virtual.
+
+
+
+```console
+$ deactivate
+```
+
+
+
+Dessa forma, quando você executar `python`, ele não tentará executá-lo naquele ambiente virtual com os pacotes instalados nele.
+
+## Pronto para trabalhar
+
+Agora você está pronto para começar a trabalhar no seu projeto.
+
+
+
+/// tip | "Dica"
+
+Você quer entender o que é tudo isso acima?
+
+Continue lendo. 👇🤓
+
+///
+
+## Por que ambientes virtuais
+
+Para trabalhar com o FastAPI, você precisa instalar o
Python.
+
+Depois disso, você precisará **instalar** o FastAPI e quaisquer outros **pacotes** que queira usar.
+
+Para instalar pacotes, você normalmente usaria o comando `pip` que vem com o Python (ou alternativas semelhantes).
+
+No entanto, se você usar `pip` diretamente, os pacotes serão instalados no seu **ambiente Python global** (a instalação global do Python).
+
+### O Problema
+
+Então, qual é o problema em instalar pacotes no ambiente global do Python?
+
+Em algum momento, você provavelmente acabará escrevendo muitos programas diferentes que dependem de **pacotes diferentes**. E alguns desses projetos em que você trabalha dependerão de **versões diferentes** do mesmo pacote. 😱
+
+Por exemplo, você pode criar um projeto chamado `philosophers-stone`, este programa depende de outro pacote chamado **`harry`, usando a versão `1`**. Então, você precisa instalar `harry`.
+
+```mermaid
+flowchart LR
+ stone(philosophers-stone) -->|requires| harry-1[harry v1]
+```
+
+Então, em algum momento depois, você cria outro projeto chamado `prisoner-of-azkaban`, e esse projeto também depende de `harry`, mas esse projeto precisa do **`harry` versão `3`**.
+
+```mermaid
+flowchart LR
+ azkaban(prisoner-of-azkaban) --> |requires| harry-3[harry v3]
+```
+
+Mas agora o problema é que, se você instalar os pacotes globalmente (no ambiente global) em vez de em um **ambiente virtual** local, você terá que escolher qual versão do `harry` instalar.
+
+Se você quiser executar `philosophers-stone`, precisará primeiro instalar `harry` versão `1`, por exemplo com:
+
+
+
+```console
+$ pip install "harry==1"
+```
+
+
+
+E então você acabaria com `harry` versão `1` instalado em seu ambiente Python global.
+
+```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
+```
+
+Mas se você quiser executar `prisoner-of-azkaban`, você precisará desinstalar `harry` versão `1` e instalar `harry` versão `3` (ou apenas instalar a versão `3` desinstalaria automaticamente a versão `1`).
+
+
+
+```console
+$ pip install "harry==3"
+```
+
+
+
+E então você acabaria com `harry` versão `3` instalado em seu ambiente Python global.
+
+E se você tentar executar `philosophers-stone` novamente, há uma chance de que **não funcione** porque ele precisa de `harry` versão `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 | "Dica"
+
+É muito comum em pacotes Python tentar ao máximo **evitar alterações drásticas** em **novas versões**, mas é melhor prevenir do que remediar e instalar versões mais recentes intencionalmente e, quando possível, executar os testes para verificar se tudo está funcionando corretamente.
+
+///
+
+Agora, imagine isso com **muitos** outros **pacotes** dos quais todos os seus **projetos dependem**. Isso é muito difícil de gerenciar. E você provavelmente acabaria executando alguns projetos com algumas **versões incompatíveis** dos pacotes, e não saberia por que algo não está funcionando.
+
+Além disso, dependendo do seu sistema operacional (por exemplo, Linux, Windows, macOS), ele pode ter vindo com o Python já instalado. E, nesse caso, provavelmente tinha alguns pacotes pré-instalados com algumas versões específicas **necessárias para o seu sistema**. Se você instalar pacotes no ambiente global do Python, poderá acabar **quebrando** alguns dos programas que vieram com seu sistema operacional.
+
+## Onde os pacotes são instalados
+
+Quando você instala o Python, ele cria alguns diretórios com alguns arquivos no seu computador.
+
+Alguns desses diretórios são os responsáveis por ter todos os pacotes que você instala.
+
+Quando você executa:
+
+
+
+```console
+// Não execute isso agora, é apenas um exemplo 🤓
+$ pip install "fastapi[standard]"
+---> 100%
+```
+
+
+
+Isso fará o download de um arquivo compactado com o código FastAPI, normalmente do
PyPI.
+
+Ele também fará o **download** de arquivos para outros pacotes dos quais o FastAPI depende.
+
+Em seguida, ele **extrairá** todos esses arquivos e os colocará em um diretório no seu computador.
+
+Por padrão, ele colocará os arquivos baixados e extraídos no diretório que vem com a instalação do Python, que é o **ambiente global**.
+
+## O que são ambientes virtuais
+
+A solução para os problemas de ter todos os pacotes no ambiente global é usar um **ambiente virtual para cada projeto** em que você trabalha.
+
+Um ambiente virtual é um **diretório**, muito semelhante ao global, onde você pode instalar os pacotes para um projeto.
+
+Dessa forma, cada projeto terá seu próprio ambiente virtual (diretório `.venv`) com seus próprios pacotes.
+
+```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
+```
+
+## O que significa ativar um ambiente virtual
+
+Quando você ativa um ambiente virtual, por exemplo com:
+
+//// tab | Linux, macOS
+
+
+
+```console
+$ source .venv/bin/activate
+```
+
+
+
+////
+
+//// tab | Windows PowerShell
+
+
+
+```console
+$ .venv\Scripts\Activate.ps1
+```
+
+
+
+////
+
+//// tab | Windows Bash
+
+Ou se você usa o Bash para Windows (por exemplo,
Git Bash):
+
+
+
+```console
+$ source .venv/Scripts/activate
+```
+
+
+
+////
+
+Esse comando criará ou modificará algumas [variáveis de ambiente](environment-variables.md){.internal-link target=_blank} que estarão disponíveis para os próximos comandos.
+
+Uma dessas variáveis é a variável `PATH`.
+
+/// tip | "Dica"
+
+Você pode aprender mais sobre a variável de ambiente `PATH` na seção [Variáveis de ambiente](environment-variables.md#path-environment-variable){.internal-link target=_blank}.
+
+///
+
+A ativação de um ambiente virtual adiciona seu caminho `.venv/bin` (no Linux e macOS) ou `.venv\Scripts` (no Windows) à variável de ambiente `PATH`.
+
+Digamos que antes de ativar o ambiente, a variável `PATH` estava assim:
+
+//// tab | Linux, macOS
+
+```plaintext
+/usr/bin:/bin:/usr/sbin:/sbin
+```
+
+Isso significa que o sistema procuraria programas em:
+
+* `/usr/bin`
+* `/bin`
+* `/usr/sbin`
+* `/sbin`
+
+////
+
+//// tab | Windows
+
+```plaintext
+C:\Windows\System32
+```
+
+Isso significa que o sistema procuraria programas em:
+
+* `C:\Windows\System32`
+
+////
+
+Após ativar o ambiente virtual, a variável `PATH` ficaria mais ou menos assim:
+
+//// tab | Linux, macOS
+
+```plaintext
+/home/user/code/awesome-project/.venv/bin:/usr/bin:/bin:/usr/sbin:/sbin
+```
+
+Isso significa que o sistema agora começará a procurar primeiro por programas em:
+
+```plaintext
+/home/user/code/awesome-project/.venv/bin
+```
+
+antes de procurar nos outros diretórios.
+
+Então, quando você digita `python` no terminal, o sistema encontrará o programa Python em
+
+```plaintext
+/home/user/code/awesome-project/.venv/bin/python
+```
+
+e usa esse.
+
+////
+
+//// tab | Windows
+
+```plaintext
+C:\Users\user\code\awesome-project\.venv\Scripts;C:\Windows\System32
+```
+
+Isso significa que o sistema agora começará a procurar primeiro por programas em:
+
+```plaintext
+C:\Users\user\code\awesome-project\.venv\Scripts
+```
+
+antes de procurar nos outros diretórios.
+
+Então, quando você digita `python` no terminal, o sistema encontrará o programa Python em
+
+```plaintext
+C:\Users\user\code\awesome-project\.venv\Scripts\python
+```
+
+e usa esse.
+
+////
+
+Um detalhe importante é que ele colocará o caminho do ambiente virtual no **início** da variável `PATH`. O sistema o encontrará **antes** de encontrar qualquer outro Python disponível. Dessa forma, quando você executar `python`, ele usará o Python **do ambiente virtual** em vez de qualquer outro `python` (por exemplo, um `python` de um ambiente global).
+
+Ativar um ambiente virtual também muda algumas outras coisas, mas esta é uma das mais importantes.
+
+## Verificando um ambiente virtual
+
+Ao verificar se um ambiente virtual está ativo, por exemplo com:
+
+//// 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
+```
+
+
+
+////
+
+Isso significa que o programa `python` que será usado é aquele **no ambiente virtual**.
+
+você usa `which` no Linux e macOS e `Get-Command` no Windows PowerShell.
+
+A maneira como esse comando funciona é que ele vai e verifica na variável de ambiente `PATH`, passando por **cada caminho em ordem**, procurando pelo programa chamado `python`. Uma vez que ele o encontre, ele **mostrará o caminho** para esse programa.
+
+A parte mais importante é que quando você chama ``python`, esse é exatamente o "`python`" que será executado.
+
+Assim, você pode confirmar se está no ambiente virtual correto.
+
+/// tip | "Dica"
+
+É fácil ativar um ambiente virtual, obter um Python e então **ir para outro projeto**.
+
+E o segundo projeto **não funcionaria** porque você está usando o **Python incorreto**, de um ambiente virtual para outro projeto.
+
+É útil poder verificar qual `python` está sendo usado. 🤓
+
+///
+
+## Por que desativar um ambiente virtual
+
+Por exemplo, você pode estar trabalhando em um projeto `philosophers-stone`, **ativar esse ambiente virtual**, instalar pacotes e trabalhar com esse ambiente.
+
+E então você quer trabalhar em **outro projeto** `prisoner-of-azkaban`.
+
+Você vai para aquele projeto:
+
+
+
+```console
+$ cd ~/code/prisoner-of-azkaban
+```
+
+
+
+Se você não desativar o ambiente virtual para `philosophers-stone`, quando você executar `python` no terminal, ele tentará usar o Python de `philosophers-stone`.
+
+
+
+```console
+$ cd ~/code/prisoner-of-azkaban
+
+$ python main.py
+
+// Erro ao importar o Sirius, ele não está instalado 😱
+Traceback (most recent call last):
+ File "main.py", line 1, in
+ import sirius
+```
+
+
+
+Mas se você desativar o ambiente virtual e ativar o novo para `prisoner-of-askaban`, quando você executar `python`, ele usará o Python do ambiente virtual em `prisoner-of-azkaban`.
+
+
+
+```console
+$ cd ~/code/prisoner-of-azkaban
+
+// Você não precisa estar no diretório antigo para desativar, você pode fazer isso de onde estiver, mesmo depois de ir para o outro projeto 😎
+$ deactivate
+
+// Ative o ambiente virtual em prisoner-of-azkaban/.venv 🚀
+$ source .venv/bin/activate
+
+// Agora, quando você executar o python, ele encontrará o pacote sirius instalado neste ambiente virtual ✨
+$ python main.py
+
+Eu juro solenemente 🐺
+```
+
+
+
+## Alternativas
+
+Este é um guia simples para você começar e lhe ensinar como tudo funciona **por baixo**.
+
+Existem muitas **alternativas** para gerenciar ambientes virtuais, dependências de pacotes (requisitos) e projetos.
+
+Quando estiver pronto e quiser usar uma ferramenta para **gerenciar todo o projeto**, dependências de pacotes, ambientes virtuais, etc., sugiro que você experimente o
uv.
+
+`uv` pode fazer muitas coisas, ele pode:
+
+* **Instalar o Python** para você, incluindo versões diferentes
+* Gerenciar o **ambiente virtual** para seus projetos
+* Instalar **pacotes**
+* Gerenciar **dependências e versões** de pacotes para seu projeto
+* Certifique-se de ter um conjunto **exato** de pacotes e versões para instalar, incluindo suas dependências, para que você possa ter certeza de que pode executar seu projeto em produção exatamente da mesma forma que em seu computador durante o desenvolvimento, isso é chamado de **bloqueio**
+* E muitas outras coisas
+
+## Conclusão
+
+Se você leu e entendeu tudo isso, agora **você sabe muito mais** sobre ambientes virtuais do que muitos desenvolvedores por aí. 🤓
+
+Saber esses detalhes provavelmente será útil no futuro, quando você estiver depurando algo que parece complexo, mas você saberá **como tudo funciona**. 😎
diff --git a/fastapi/__init__.py b/fastapi/__init__.py
index dce17360f..c2ed4859a 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.114.0"
+__version__ = "0.114.1"
from starlette import status as status
diff --git a/fastapi/_compat.py b/fastapi/_compat.py
index f940d6597..4b07b44fa 100644
--- a/fastapi/_compat.py
+++ b/fastapi/_compat.py
@@ -2,6 +2,7 @@ from collections import deque
from copy import copy
from dataclasses import dataclass, is_dataclass
from enum import Enum
+from functools import lru_cache
from typing import (
Any,
Callable,
@@ -649,3 +650,8 @@ def is_uploadfile_sequence_annotation(annotation: Any) -> bool:
is_uploadfile_or_nonable_uploadfile_annotation(sub_annotation)
for sub_annotation in get_args(annotation)
)
+
+
+@lru_cache
+def get_cached_model_fields(model: Type[BaseModel]) -> List[ModelField]:
+ return get_model_fields(model)
diff --git a/fastapi/dependencies/utils.py b/fastapi/dependencies/utils.py
index 6083b7319..f18eace9d 100644
--- a/fastapi/dependencies/utils.py
+++ b/fastapi/dependencies/utils.py
@@ -32,8 +32,8 @@ from fastapi._compat import (
evaluate_forwardref,
field_annotation_is_scalar,
get_annotation_from_field_info,
+ get_cached_model_fields,
get_missing_field_error,
- get_model_fields,
is_bytes_field,
is_bytes_sequence_field,
is_scalar_field,
@@ -810,7 +810,7 @@ async def request_body_to_args(
fields_to_extract: List[ModelField] = body_fields
if single_not_embedded_field and lenient_issubclass(first_field.type_, BaseModel):
- fields_to_extract = get_model_fields(first_field.type_)
+ fields_to_extract = get_cached_model_fields(first_field.type_)
if isinstance(received_body, FormData):
body_to_process = await _extract_form_body(fields_to_extract, received_body)
diff --git a/pyproject.toml b/pyproject.toml
index bb87be470..1be2817a1 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -241,3 +241,7 @@ known-third-party = ["fastapi", "pydantic", "starlette"]
[tool.ruff.lint.pyupgrade]
# Preserve types, even if a file imports `from __future__ import annotations`.
keep-runtime-typing = true
+
+[tool.inline-snapshot]
+# default-flags=["fix"]
+# default-flags=["create"]
diff --git a/requirements-tests.txt b/requirements-tests.txt
index de5fdb8a2..2f2576dd5 100644
--- a/requirements-tests.txt
+++ b/requirements-tests.txt
@@ -3,7 +3,7 @@
pytest >=7.1.3,<8.0.0
coverage[toml] >= 6.5.0,< 8.0
mypy ==1.8.0
-ruff ==0.6.3
+ruff ==0.6.4
dirty-equals ==0.6.0
# TODO: once removing databases from tutorial, upgrade SQLAlchemy
# probably when including SQLModel
@@ -14,7 +14,7 @@ anyio[trio] >=3.2.1,<4.0.0
PyJWT==2.8.0
pyyaml >=5.3.1,<7.0.0
passlib[bcrypt] >=1.7.2,<2.0.0
-
+inline-snapshot==0.13.0
# types
types-ujson ==5.7.0.1
types-orjson ==3.6.2
diff --git a/tests/test_compat.py b/tests/test_compat.py
index 270475bf3..f4a3093c5 100644
--- a/tests/test_compat.py
+++ b/tests/test_compat.py
@@ -5,6 +5,7 @@ from fastapi._compat import (
ModelField,
Undefined,
_get_model_config,
+ get_cached_model_fields,
get_model_fields,
is_bytes_sequence_annotation,
is_scalar_field,
@@ -102,3 +103,18 @@ def test_is_pv1_scalar_field():
fields = get_model_fields(Model)
assert not is_scalar_field(fields[0])
+
+
+def test_get_model_fields_cached():
+ class Model(BaseModel):
+ foo: str
+
+ non_cached_fields = get_model_fields(Model)
+ non_cached_fields2 = get_model_fields(Model)
+ cached_fields = get_cached_model_fields(Model)
+ cached_fields2 = get_cached_model_fields(Model)
+ for f1, f2 in zip(cached_fields, cached_fields2):
+ assert f1 is f2
+
+ assert non_cached_fields is not non_cached_fields2
+ assert cached_fields is cached_fields2