diff --git a/.github/DISCUSSION_TEMPLATE/translations.yml b/.github/DISCUSSION_TEMPLATE/translations.yml
new file mode 100644
index 000000000..16e304d99
--- /dev/null
+++ b/.github/DISCUSSION_TEMPLATE/translations.yml
@@ -0,0 +1,45 @@
+labels: [lang-all]
+body:
+ - type: markdown
+ attributes:
+ value: |
+ Thanks for your interest in helping translate the FastAPI docs! đ
+
+ Please follow these instructions carefully to propose a new language translation. đ
+
+ This structured process helps ensure translations can be properly maintained long-term.
+ - type: checkboxes
+ id: checks
+ attributes:
+ label: Initial Checks
+ description: Please confirm and check all the following options.
+ options:
+ - label: I checked that this language is not already being translated in FastAPI docs.
+ required: true
+ - label: I searched existing discussions to ensure no one else proposed this language.
+ required: true
+ - label: I am a native speaker of the language I want to help translate.
+ required: true
+ - type: input
+ id: language
+ attributes:
+ label: Target Language
+ description: What language do you want to translate the FastAPI docs into?
+ placeholder: e.g. Latin
+ validations:
+ required: true
+ - type: textarea
+ id: additional_info
+ attributes:
+ label: Additional Information
+ description: Any other relevant information about your translation proposal
+ - type: markdown
+ attributes:
+ value: |
+ Translations are automatized with AI and then reviewed by native speakers. đ€ đ
+
+ This allows us to keep them consistent and up-to-date.
+
+ If there are several native speakers commenting on this discussion and
+ committing to help review new translations, the FastAPI team will review it
+ and potentially make it an official translation. đ
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 680cafce9..e461b0133 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.12.2
+ rev: v0.12.4
hooks:
- id: ruff
args:
diff --git a/docs/en/docs/contributing.md b/docs/en/docs/contributing.md
index 91c39c927..2583fd1fb 100644
--- a/docs/en/docs/contributing.md
+++ b/docs/en/docs/contributing.md
@@ -315,30 +315,47 @@ Now you can translate it all and see how it looks as you save the file.
Some of these files are updated very frequently and a translation would always be behind, or they include the main content from English source files, etc.
+#### Request a New Language
+
+Let's say that you want to request translations for a language that is not yet translated, not even some pages. For example, Latin.
+
+If there is no discussion for that language, you can start by requesting the new language. For that, you can follow these steps:
+
+* Create a new discussion following the template.
+* Get a few native speakers to comment on the discussion and commit to help review translations for that language.
+
+Once there are several people in the discussion, the FastAPI team can evaluate it and can make it an official translation.
+
+Then the docs will be automatically translated using AI, and the team of native speakers can review the translation, and help tweak the AI prompts.
+
+Once there's a new translation, for example if docs are updated or there's a new section, there will be a comment in the same discussion with the link to the new translation to review.
+
#### New Language
-Let's say that you want to add translations for a language that is not yet translated, not even some pages.
+/// note
-Let's say you want to add translations for Creole, and it's not yet there in the docs.
+These steps will be performed by the FastAPI team.
+
+///
-Checking the link from above, the code for "Creole" is `ht`.
+Checking the link from above (List of ISO 639-1 codes), you can see that the 2-letter code for Latin is `la`.
-The next step is to run the script to generate a new translation directory:
+Now you can create a new directory for the new language, running the following script:
```console
// Use the command new-lang, pass the language code as a CLI argument
-$ python ./scripts/docs.py new-lang ht
+$ python ./scripts/docs.py new-lang la
-Successfully initialized: docs/ht
+Successfully initialized: docs/la
```
-Now you can check in your code editor the newly created directory `docs/ht/`.
+Now you can check in your code editor the newly created directory `docs/la/`.
-That command created a file `docs/ht/mkdocs.yml` with a simple config that inherits everything from the `en` version:
+That command created a file `docs/la/mkdocs.yml` with a simple config that inherits everything from the `en` version:
```yaml
INHERIT: ../en/mkdocs.yml
@@ -350,11 +367,11 @@ You could also simply create that file with those contents manually.
///
-That command also created a dummy file `docs/ht/index.md` for the main page, you can start by translating that one.
+That command also created a dummy file `docs/la/index.md` for the main page, you can start by translating that one.
You can continue with the previous instructions for an "Existing Language" for that process.
-You can make the first pull request with those two files, `docs/ht/mkdocs.yml` and `docs/ht/index.md`. đ
+You can make the first pull request with those two files, `docs/la/mkdocs.yml` and `docs/la/index.md`. đ
#### Preview the result
diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md
index e198e9437..f3984fa9e 100644
--- a/docs/en/docs/release-notes.md
+++ b/docs/en/docs/release-notes.md
@@ -7,8 +7,14 @@ hide:
## Latest Changes
+### Docs
+
+* đ Add discussion template for new language translation requests. PR [#13535](https://github.com/fastapi/fastapi/pull/13535) by [@alejsdev](https://github.com/alejsdev).
+
### Translations
+* đ Update Portuguese Translation for `docs/pt/docs/async.md`. PR [#13863](https://github.com/fastapi/fastapi/pull/13863) by [@EdmilsonRodrigues](https://github.com/EdmilsonRodrigues).
+* đ Fix highlight line in `docs/ja/docs/tutorial/body.md`. PR [#13927](https://github.com/fastapi/fastapi/pull/13927) by [@KoyoMiyazaki](https://github.com/KoyoMiyazaki).
* đ Add Persian translation for `docs/fa/docs/environment-variables.md`. PR [#13923](https://github.com/fastapi/fastapi/pull/13923) by [@Mohammad222PR](https://github.com/Mohammad222PR).
* đ Add Persian translation for `docs/fa/docs/python-types.md`. PR [#13524](https://github.com/fastapi/fastapi/pull/13524) by [@Mohammad222PR](https://github.com/Mohammad222PR).
* đ Update Portuguese Translation for `docs/pt/docs/project-generation.md`. PR [#13875](https://github.com/fastapi/fastapi/pull/13875) by [@EdmilsonRodrigues](https://github.com/EdmilsonRodrigues).
@@ -17,6 +23,11 @@ hide:
### Internal
+* âïž Update translate script, show and update outdated translations. PR [#13933](https://github.com/fastapi/fastapi/pull/13933) by [@tiangolo](https://github.com/tiangolo).
+* đš Refactor translate script with extra feedback (prints). PR [#13932](https://github.com/fastapi/fastapi/pull/13932) by [@tiangolo](https://github.com/tiangolo).
+* đš Update translations script to remove old (removed) files. PR [#13928](https://github.com/fastapi/fastapi/pull/13928) by [@tiangolo](https://github.com/tiangolo).
+* ⏠[pre-commit.ci] pre-commit autoupdate. PR [#13894](https://github.com/fastapi/fastapi/pull/13894) by [@pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci).
+* ⏠Update httpx requirement to >=0.23.0,<0.29.0. PR [#13114](https://github.com/fastapi/fastapi/pull/13114) by [@yan12125](https://github.com/yan12125).
* đ§ Update sponsors: Add Mobb. PR [#13916](https://github.com/fastapi/fastapi/pull/13916) by [@tiangolo](https://github.com/tiangolo).
* đ„ Update FastAPI People - Experts. PR [#13889](https://github.com/fastapi/fastapi/pull/13889) by [@tiangolo](https://github.com/tiangolo).
* đš Update FastAPI People sleep interval, use external settings. PR [#13888](https://github.com/fastapi/fastapi/pull/13888) by [@tiangolo](https://github.com/tiangolo).
diff --git a/docs/es/llm-prompt.md b/docs/es/llm-prompt.md
index 3340dbc99..936ed9bba 100644
--- a/docs/es/llm-prompt.md
+++ b/docs/es/llm-prompt.md
@@ -4,56 +4,6 @@ Use the informal grammar (use "tĂș" instead of "usted").
For instructions or titles in imperative, keep them in imperative, for example "Edit it" to "EdĂtalo".
-There are special blocks of notes, tips and others that look like:
-
-/// note
-
-To translate it, keep the same line and add the translation after a vertical bar:
-
-/// note | Nota
-
-Some examples:
-
-Source:
-
-/// tip
-
-Result:
-
-/// tip | Consejo
-
-Source:
-
-/// details | Preview
-
-Result:
-
-/// details | Vista previa
-
-Source:
-
-/// warning
-
-Result:
-
-/// warning | Advertencia
-
-Source:
-
-/// info
-
-Result:
-
-/// info | InformaciĂłn
-
-Source:
-
-/// note | Technical Details
-
-Result:
-
-/// note | Detalles Técnicos
-
---
For the next terms, use the following translations:
diff --git a/docs/ja/docs/tutorial/body.md b/docs/ja/docs/tutorial/body.md
index 8376959d5..1298eec7e 100644
--- a/docs/ja/docs/tutorial/body.md
+++ b/docs/ja/docs/tutorial/body.md
@@ -22,7 +22,7 @@ GET ăȘăŻăšăčăă§ăăăŁăé俥ăăăăšăŻă仿§ă§ăŻæȘćźçŸ©
ăŸăćăă«ă `pydantic` ăă `BaseModel` ăă€ăłăăŒăăăćż
èŠăăăăŸă:
-{* ../../docs_src/body/tutorial001.py hl[2] *}
+{* ../../docs_src/body/tutorial001.py hl[4] *}
## ăăŒăżăąăă«ăźäœæ
@@ -30,7 +30,7 @@ GET ăȘăŻăšăčăă§ăăăŁăé俥ăăăăšăŻă仿§ă§ăŻæȘćźçŸ©
ăăčăŠăźć±æ§ă«pythonæšæșăźćăäœżçšăăŸă:
-{* ../../docs_src/body/tutorial001.py hl[5:9] *}
+{* ../../docs_src/body/tutorial001.py hl[7:11] *}
ăŻăšăȘăă©ăĄăŒăżăźćźŁèšăšćæ§ă«ăăąăă«ć±æ§ăăăă©ă«ăć€ăăă€ăšăăćż
é ăȘ㱿§ă§ăŻăȘăăȘăăŸăăăă仄ć€ăŻćż
é ă«ăȘăăŸăăăȘăă·ă§ăă«ăȘ㱿§ă«ăăăć Žć㯠`None` ăäœżçšăăŠăă ăăă
@@ -58,7 +58,7 @@ GET ăȘăŻăšăčăă§ăăăŁăé俥ăăăăšăŻă仿§ă§ăŻæȘćźçŸ©
*ăăčăȘăăŹăŒă·ă§ăł* ă«ć ăăăăă«ăăăčăă©ăĄăŒăżăăŻăšăȘăă©ăĄăŒăżăšćăæ§ă«ćźŁèšăăŸă:
-{* ../../docs_src/body/tutorial001.py hl[16] *}
+{* ../../docs_src/body/tutorial001.py hl[18] *}
...ăăăŠăäœæăăăąăă« `Item` ă§ćă柣èšăăŸăă
@@ -125,7 +125,7 @@ GET ăȘăŻăšăčăă§ăăăŁăé俥ăăăăšăŻă仿§ă§ăŻæȘćźçŸ©
éąæ°ć
éšă§ăăąăă«ăźć
šăŠăźć±æ§ă«çŽæ„ăąăŻă»ăčă§ăăŸă:
-{* ../../docs_src/body/tutorial002.py hl[19] *}
+{* ../../docs_src/body/tutorial002.py hl[21] *}
## ăȘăŻăšăčăăă㣠+ ăăčăă©ăĄăŒăż
@@ -133,7 +133,7 @@ GET ăȘăŻăšăčăă§ăăăŁăé俥ăăăăšăŻă仿§ă§ăŻæȘćźçŸ©
**FastAPI** ăŻăăčăă©ăĄăŒăżă§ăăéąæ°ăă©ăĄăŒăżăŻ**ăăčăăćăćă**ăPydanticăąăă«ă«ăăŁăŠćźŁèšăăăéąæ°ăă©ăĄăŒăżăŻ**ăȘăŻăšăčăăăăŁăăćăćă**ăšăăăăšăèȘèăăŸăă
-{* ../../docs_src/body/tutorial003.py hl[15:16] *}
+{* ../../docs_src/body/tutorial003.py hl[17:18] *}
## ăȘăŻăšăčăăă㣠+ ăăčăă©ăĄăŒăż + ăŻăšăȘăă©ăĄăŒăż
@@ -141,7 +141,7 @@ GET ăȘăŻăšăčăă§ăăăŁăé俥ăăăăšăŻă仿§ă§ăŻæȘćźçŸ©
**FastAPI** ăŻăăăăăèȘèăăé©ćăȘć ŽæăăăăŒăżăććŸăăŸăă
-{* ../../docs_src/body/tutorial004.py hl[16] *}
+{* ../../docs_src/body/tutorial004.py hl[18] *}
éąæ°ăă©ăĄăŒăżăŻä»„äžăźæ§ă«èȘèăăăŸă:
diff --git a/docs/pt/docs/async.md b/docs/pt/docs/async.md
index 0d6bdbf0e..4425eba77 100644
--- a/docs/pt/docs/async.md
+++ b/docs/pt/docs/async.md
@@ -40,7 +40,7 @@ def results():
---
-Se sua aplicação (de alguma forma) não tem que se comunicar com nada mais e tem que esperar que o respondam, use `async def`.
+Se sua aplicação (de alguma forma) não tem que se comunicar com nada mais e esperar que o respondam, use `async def`.
---
@@ -52,7 +52,7 @@ Se vocĂȘ simplesmente nĂŁo sabe, use apenas `def`.
De qualquer forma, em ambos os casos acima, FastAPI irĂĄ trabalhar assincronamente e ser extremamente rĂĄpido.
-Seguindo os passos acima, ele serå capaz de fazer algumas otimizaçÔes de performance.
+Mas, seguindo os passos acima, ele serå capaz de fazer algumas otimizaçÔes de performance.
## Detalhes Técnicos
@@ -66,36 +66,36 @@ Vamos ver aquela frase por partes na seção abaixo:
## CĂłdigo assĂncrono
-CĂłdigo assĂncrono apenas significa que a linguagem đŹ tem um jeito de dizer para o computador / programa đ€ que em certo ponto, ele đ€ terĂĄ que esperar por *algo* para finalizar em outro lugar. Vamos dizer que esse *algo* seja chamado "arquivo lento" đ.
+CĂłdigo assĂncrono apenas significa que a linguagem đŹ tem um jeito de dizer para o computador / programa đ€ que em certo ponto do cĂłdigo, ele đ€ terĂĄ que esperar *algo* finalizar em outro lugar. Vamos dizer que esse *algo* seja chamado "arquivo lento" đ.
-EntĂŁo, durante esse tempo, o computador pode ir e fazer outro trabalho, enquanto o "arquivo lento" đ termine.
+EntĂŁo, durante esse tempo, o computador pode ir e fazer outro trabalho, enquanto o "arquivo lento" đ termina.
-EntĂŁo o computador / programa đ€ irĂĄ voltar toda hora que tiver uma chance porquĂȘ ele ainda estĂĄ esperando o "arquivo lento", ou ele đ€ nunca irĂĄ terminar todo o trabalho que tem atĂ© esse ponto. E ele đ€ irĂĄ ver se alguma das tarefas que estava esperando jĂĄ terminaram, fazendo o que quer que tinham que fazer.
+EntĂŁo o computador / programa đ€ irĂĄ voltar sempre que tiver uma chance, seja porque ele estĂĄ esperando novamente, ou quando ele đ€ terminar todo o trabalho que tem atĂ© esse ponto. E ele đ€ irĂĄ ver se alguma das tarefas que estava esperando jĂĄ terminaram de fazer o que quer que tinham que fazer.
-Depois, ele đ€ pega a primeira tarefa para finalizar (vamos dizer, nosso "arquivo lento" đ) e continua o que ele tem que fazer com isso.
+Depois, ele đ€ pega a primeira tarefa para finalizar (vamos dizer, nosso "arquivo lento" đ) e continua o que tem que fazer com ela.
-Esse "esperar por algo" normalmente se refere a operaçÔes I/O que são relativamente "lentas" (comparadas a velocidade do processador e da memória RAM), como esperar por:
+Esse "esperar por algo" normalmente se refere a operaçÔes I/O que são relativamente "lentas" (comparadas à velocidade do processador e da memória RAM), como esperar por:
* dados do cliente para serem enviados através da rede
-* dados enviados pelo seu programa para serem recebidos pelo clente através da rede
-* conteĂșdo de um arquivo no disco pra ser lido pelo sistema e entregar ao seu programa
+* dados enviados pelo seu programa serem recebidos pelo clente através da rede
+* conteĂșdo de um arquivo no disco ser lido pelo sistema e entregue ao seu programa
* conteĂșdo que seu programa deu ao sistema para ser escrito no disco
-* uma operação remota API
-* uma operação no banco de dados para finalizar
-* uma solicitação no banco de dados esperando o retorno do resultado
+* uma operação em uma API remota
+* uma operação no banco de dados finalizar
+* uma solicitação no banco de dados retornar o resultado
* etc.
-Enquanto o tempo de execução é consumido mais pela espera das operaçÔes I/O, essas operaçÔes são chamadas de operaçÔes "limitadas por I/O".
+Quanto o tempo de execução é consumido majoritariamente pela espera de operaçÔes I/O, essas operaçÔes são chamadas operaçÔes "limitadas por I/O".
-Isso Ă© chamado de "assĂncrono" porquĂȘ o computador / programa nĂŁo tem que ser "sincronizado" com a tarefa lenta, esperando pelo exato momento que a tarefa finalize, enquanto nĂŁo faz nada, para ser capaz de pegar o resultado da tarefa e dar continuidade ao trabalho.
+Isso Ă© chamado de "assĂncrono" porque o computador / programa nĂŁo tem que ser "sincronizado" com a tarefa lenta, esperando pelo momento exato em que a tarefa finaliza, enquanto nĂŁo faz nada, para ser capaz de pegar o resultado da tarefa e dar continuidade ao trabalho.
-Ao invĂ©s disso, sendo um sistema "assĂncrono", uma vez finalizada, a tarefa pode esperar um pouco (alguns microssegundos) para que o computador / programa finalize o que quer que esteja fazendo,e entĂŁo volte para pegar o resultado e continue trabalhando com ele.
+Ao invĂ©s disso, sendo um sistema "assĂncrono", uma vez finalizada, a tarefa pode esperar na fila um pouco (alguns microssegundos) para que o computador / programa finalize o que quer que esteja fazendo, e entĂŁo volte para pegar o resultado e continue trabalhando com ele.
-Para "sĂncrono" (contrĂĄrio de "assĂncrono") tambĂ©m Ă© utilizado o termo "sequencial", porquĂȘ o computador / programa segue todos os passos, na sequĂȘncia, antes de trocar para uma tarefa diferente, mesmo se alguns passos envolvam esperar.
+Para "sĂncrono" (contrĂĄrio de "assĂncrono") tambĂ©m Ă© utilizado o termo "sequencial", porquĂȘ o computador / programa segue todos os passos, em sequĂȘncia, antes de trocar para uma tarefa diferente, mesmo se alguns passos envolvam esperar.
### ConcorrĂȘncia e hambĂșrgueres
-Essa idĂ©ia de cĂłdigo **assĂncrono** descrito acima Ă© algo Ă s vezes chamado de **"concorrĂȘncia"**. E Ă© diferente de **"paralelismo"**.
+Essa idĂ©ia de cĂłdigo **assĂncrono** descrita acima Ă© Ă s vezes chamado de **"concorrĂȘncia"**. Isso Ă© diferente de **"paralelismo"**.
**ConcorrĂȘncia** e **paralelismo** ambos sĂŁo relacionados a "diferentes coisas acontecendo mais ou menos ao mesmo tempo".
@@ -105,117 +105,115 @@ Para ver essa diferença, imagine a seguinte histĂłria sobre hambĂșrgueres:
### HambĂșrgueres concorrentes
-VocĂȘ vai com seu _crush_ :heart_eyes: na lanchonete, fica na fila enquanto o caixa pega os pedidos das pessoas na sua frente.
+VocĂȘ vai com seu _crush_ na lanchonete, e fica na fila enquanto o caixa pega os pedidos das pessoas na sua frente. đ
-EntĂŁo chega a sua vez, vocĂȘ pede dois saborosos hambĂșrgueres para vocĂȘ e seu _crush_ :heart_eyes:.
+EntĂŁo chega a sua vez, vocĂȘ pede dois saborosos hambĂșrgueres para vocĂȘ e seu _crush_. đđ
-VocĂȘ paga.
+O caixa diz alguma coisa para o cozinheiro na cozinha para que eles saivam que tĂȘm que preparar seus hambĂșrgueres (mesmo que ele esteja atualmente preparando os lanches dos outros clientes).
-O caixa diz alguma coisa para o cara na cozinha para que ele tenha que preparar seus hambĂșrgueres (mesmo embora ele esteja preparando os lanches dos outros clientes).
+VocĂȘ paga. đž
O caixa te entrega seu nĂșmero de chamada.
-Enquanto vocĂȘ espera, vocĂȘ vai com seu _crush_ :heart_eyes: e pega uma mesa, senta e conversa com seu _crush_ :heart_eyes: por um bom tempo (como seus hambĂșrgueres sĂŁo muito saborosos, leva um tempo para serem preparados).
+Enquanto vocĂȘ espera, vocĂȘ vai com seu _crush_ e pega uma mesa, senta e conversa com seu _crush_ por um bom tempo (jĂĄ que seus hambĂșrgueres sĂŁo muito saborosos, e leva um tempo para serem preparados).
-Enquanto vocĂȘ estĂĄ sentado na mesa com seu _crush_ :heart_eyes:, esperando os hambĂșrgueres, vocĂȘ pode gastar o tempo admirando como lindo, maravilhoso e esperto Ă© seu _crush_ :heart_eyes:.
+JĂĄ que vocĂȘ estĂĄ sentado na mesa com seu _crush_, esperando os hambĂșrgueres, vocĂȘ pode passar esse tempo admirando o quĂŁo lindo, maravilhoso e esperto Ă© seu _crush_ âšđâš.
-Enquanto espera e conversa com seu _crush_ :heart_eyes:, de tempos em tempos, vocĂȘ verifica o nĂșmero de chamada exibido no balcĂŁo para ver se jĂĄ Ă© sua vez.
+Enquanto espera e conversa com seu _crush_, de tempos em tempos, vocĂȘ verifica o nĂșmero da chamada exibido no balcĂŁo para ver se jĂĄ Ă© sua vez.
-EntĂŁo a certo ponto, Ă© finalmente sua vez. VocĂȘ vai no balcĂŁo, pega seus hambĂșrgueres e volta para a mesa.
+EntĂŁo em algum momento, Ă© finalmente sua vez. VocĂȘ vai ao balcĂŁo, pega seus hambĂșrgueres e volta para a mesa.
-VocĂȘ e seu _crush_ :heart_eyes: comem os hambĂșrgueres e aproveitam o tempo.
+VocĂȘ e seu _crush_ comem os hambĂșrgueres e aproveitam o tempo. âš
---
-Imagine que vocĂȘ seja o computador / programa nessa histĂłria.
+Imagine que vocĂȘ seja o computador / programa nessa histĂłria.
-Enquanto vocĂȘ estĂĄ na fila, tranquilo, esperando por sua vez, nĂŁo estĂĄ fazendo nada "produtivo". Mas a fila Ă© rĂĄpida porquĂȘ o caixa sĂł estĂĄ pegando os pedidos, entĂŁo estĂĄ tudo bem.
+Enquanto vocĂȘ estĂĄ na fila, vocĂȘ estĂĄ somente ocioso đŽ, esperando por sua vez, sem fazer nada muito "produtivo". Mas a fila Ă© rĂĄpida porque o caixa sĂł estĂĄ pegando os pedidos (nĂŁo os preparando), entĂŁo estĂĄ tudo bem.
-EntĂŁo, quando Ă© sua vez, vocĂȘ faz o trabalho "produtivo" de verdade, vocĂȘ processa o menu, decide o que quer, pega a escolha de seu _crush_ :heart_eyes:, paga, verifica se entregou o valor correto em dinheiro ou cartĂŁo de crĂ©dito, verifica se foi cobrado corretamente, verifica se seu pedido estĂĄ correto etc.
+EntĂŁo, quando Ă© sua vez, vocĂȘ faz trabalho realmente "produtivo", vocĂȘ processa o menu, decide o que quer, pega a escolha de seu _crush_, paga, verifica se entregou o cartĂŁo ou a cĂ©dula correta, verifica se foi cobrado corretamente, verifica se seu pedido estĂĄ correto etc.
-Mas entĂŁo, embora vocĂȘ ainda nĂŁo tenha os hambĂșrgueres, seu trabalho no caixa estĂĄ "pausado", porquĂȘ vocĂȘ tem que esperar seus hambĂșrgueres estarem prontos.
+Mas entĂŁo, embora vocĂȘ ainda nĂŁo tenha os hambĂșrgueres, seu trabalho no caixa estĂĄ "pausado" âž, porque vocĂȘ tem que esperar đ seus hambĂșrgueres ficarem prontos.
-Mas enquanto vocĂȘ se afasta do balcĂŁo e senta na mesa com o nĂșmero da sua chamada, vocĂȘ pode trocar sua atenção para seu _crush_ :heart_eyes:, e "trabalhar" nisso. EntĂŁo vocĂȘ estĂĄ novamente fazendo algo muito "produtivo", como flertar com seu _crush_ :heart_eyes:.
+Contudo, Ă medida que vocĂȘ se afasta do balcĂŁo e senta na mesa, com um nĂșmero para sua chamada, vocĂȘ pode trocar đ sua atenção para seu _crush_, e "trabalhar" ⯠đ€ nisso. EntĂŁo vocĂȘ estĂĄ novamente fazendo algo muito "produtivo", como flertar com seu _crush_ đ.
-EntĂŁo o caixa diz que "seus hambĂșrgueres estĂŁo prontos" colocando seu nĂșmero no balcĂŁo, mas vocĂȘ nĂŁo corre que nem um maluco imediatamente quando o nĂșmero exibido Ă© o seu. VocĂȘ sabe que ninguĂ©m irĂĄ roubar seus hambĂșrgueres porquĂȘ vocĂȘ tem o nĂșmero de chamada, e os outros tem os nĂșmeros deles.
+EntĂŁo o caixa đ diz que "seus hambĂșrgueres estĂŁo prontos" colocando seu nĂșmero no balcĂŁo, mas vocĂȘ nĂŁo corre que nem um maluco imediatamente quando o nĂșmero exibido Ă© o seu. VocĂȘ sabe que ninguĂ©m irĂĄ roubar seus hambĂșrgueres porque vocĂȘ tem o seu nĂșmero da chamada, e os outros tĂȘm os deles.
-EntĂŁo vocĂȘ espera que seu _crush_ :heart_eyes: termine a histĂłria que estava contando (terminar o trabalho atual / tarefa sendo processada), sorri gentilmente e diz que vocĂȘ estĂĄ indo buscar os hambĂșrgueres.
+EntĂŁo vocĂȘ espera seu _crush_ terminar a histĂłria que estava contando (terminar o trabalho atual ⯠/ tarefa sendo processada đ€), sorri gentilmente e diz que vocĂȘ estĂĄ indo buscar os hambĂșrgueres.
-EntĂŁo vocĂȘ vai no balcĂŁo, para a tarefa inicial que agora estĂĄ finalizada, pega os hambĂșrgueres, e leva para a mesa. Isso finaliza esse passo / tarefa da interação com o balcĂŁo. Agora Ă© criada uma nova tarefa, "comer hambĂșrgueres", mas a tarefa anterior, "pegar os hambĂșrgueres" jĂĄ estĂĄ finalizada.
+EntĂŁo vocĂȘ vai ao balcĂŁo đ, para a tarefa inicial que agora estĂĄ finalizadaâŻ, pega os hambĂșrgueres, agradece, e leva-os para a mesa. Isso finaliza esse passo / tarefa da interação com o balcĂŁo âč. Isso, por sua vez, cria uma nova tarefa, a de "comer hambĂșrgueres" đ âŻ, mas a tarefa anterior de "pegar os hambĂșrgueres" jĂĄ estĂĄ finalizada âč.
### HambĂșrgueres paralelos
-VocĂȘ vai com seu _crush_ :heart_eyes: em uma lanchonete paralela.
+Agora vamos imaginar que esses nĂŁo sĂŁo "HambĂșrgueres Concorrentes", e sim "HambĂșrgueres Paralelos"
-VocĂȘ fica na fila enquanto alguns (vamos dizer 8) caixas pegam os pedidos das pessoas na sua frente.
+VocĂȘ vai com seu _crush_ na lanchonete paralela.
-Todo mundo antes de vocĂȘ estĂĄ esperando pelos hambĂșrgueres estarem prontos antes de deixar o caixa porquĂȘ cada um dos 8 caixas vai e prepara o hambĂșrguer antes de pegar o prĂłximo pedido.
+VocĂȘ fica na fila enquanto vĂĄrios (vamos dizer 8) caixas que tambĂ©m sĂŁo cozinheiros pegam os pedidos das pessoas na sua frente.
-EntĂŁo Ă© finalmente sua vez, e pede 2 hambĂșrgueres muito saborosos para vocĂȘ e seu _crush_ :heart_eyes:.
+Todo mundo na sua frente estĂĄ esperando seus hambĂșrgueres ficarem prontos antes de deixar o caixa porque cada um dos 8 caixas vai e prepara o hambĂșrguer logo apĂłs receber o pedido, antes de pegar o prĂłximo pedido.
-VocĂȘ paga.
+EntĂŁo Ă© finalmente sua vez, vocĂȘ pede 2 hambĂșrgueres muito saborosos para vocĂȘ e seu _crush_.
+
+VocĂȘ paga đž.
O caixa vai para a cozinha.
-VocĂȘ espera, na frente do balcĂŁo, para que ninguĂ©m pegue seus hambĂșrgueres antes de vocĂȘ, jĂĄ que nĂŁo tem nĂșmeros de chamadas.
+VocĂȘ espera, na frente do balcĂŁo đ, para que ninguĂ©m pegue seus hambĂșrgueres antes de vocĂȘ, jĂĄ que nĂŁo tem nĂșmeros de chamadas.
-Enquanto vocĂȘ e seu _crush_ :heart_eyes: estĂŁo ocupados nĂŁo permitindo que ninguĂ©m passe a frente e pegue seus hambĂșrgueres assim que estiverem prontos, vocĂȘ nĂŁo pode dar atenção ao seu _crush_ :heart_eyes:.
+Como vocĂȘ e seu _crush_ estĂŁo ocupados nĂŁo permitindo que ninguĂ©m passe na frente e pegue seus hambĂșrgueres assim que estiverem prontos, vocĂȘ nĂŁo pode dar atenção ao seu _crush_. đ
-Isso Ă© trabalho "sĂncrono", vocĂȘ estĂĄ "sincronizado" com o caixa / cozinheiro. VocĂȘ tem que esperar e estar lĂĄ no exato momento que o caixa / cozinheiro terminar os hambĂșrgueres e dĂĄ-los a vocĂȘ, ou entĂŁo, outro alguĂ©m pode pegĂĄ-los.
+Isso Ă© trabalho "sĂncrono", vocĂȘ estĂĄ "sincronizado" com o caixa / cozinheirođšâđł. VocĂȘ tem que esperar đ e estar lĂĄ no exato momento que o caixa / cozinheiro đšâđł terminar os hambĂșrgueres e os der a vocĂȘ, ou entĂŁo, outro alguĂ©m pode pegĂĄ-los.
-EntĂŁo seu caixa / cozinheiro finalmente volta com seus hambĂșrgueres, depois de um longo tempo esperando por eles em frente ao balcĂŁo.
+EntĂŁo seu caixa / cozinheiro đšâđł finalmente volta com seus hambĂșrgueres, depois de um longo tempo esperando đ por eles em frente ao balcĂŁo.
-VocĂȘ pega seus hambĂșrgueres e vai para a mesa com seu _crush_ :heart_eyes:.
+VocĂȘ pega seus hambĂșrgueres e vai para a mesa com seu _crush_.
-VocĂȘs comem os hambĂșrgueres, e o trabalho estĂĄ terminado.
+VocĂȘs comem os hambĂșrgueres, e o trabalho estĂĄ terminado. âč
-NĂŁo houve muita conversa ou flerte jĂĄ que a maior parte do tempo foi gasto esperando os lanches na frente do balcĂŁo.
+NĂŁo houve muita conversa ou flerte jĂĄ que a maior parte do tempo foi gasto esperando đ na frente do balcĂŁo. đ
---
-Nesse cenĂĄrio dos hambĂșrgueres paralelos, vocĂȘ Ă© um computador / programa com dois processadores (vocĂȘ e seu _crush_ :heart_eyes:), ambos esperando e dedicando a atenção de estar "esperando no balcĂŁo" por um bom tempo.
+Nesse cenĂĄrio dos hambĂșrgueres paralelos, vocĂȘ Ă© um computador / programa com dois processadores (vocĂȘ e seu _crush_), ambos esperando đ e dedicando sua atenção ⯠"esperando no balcĂŁo" đ por um bom tempo.
-A lanchonete paralela tem 8 processadores (caixas / cozinheiros). Enquanto a lanchonete dos hambĂșrgueres concorrentes tinham apenas 2 (um caixa e um cozinheiro).
+A lanchonete paralela tem 8 processadores (caixas / cozinheiros), enquanto a lanchonete dos hambĂșrgueres concorrentes tinha apenas 2 (um caixa e um cozinheiro).
-Ainda assim, a Ășltima experiĂȘncia nĂŁo foi a melhor.
+Ainda assim, a experiĂȘncia final nĂŁo foi a melhor. đ
---
-Essa poderia ser a histĂłria paralela equivalente aos hambĂșrgueres.
+Essa seria o equivalente paralelo Ă histĂłrio dos hambĂșrgueres. đ
Para um exemplo "mais real", imagine um banco.
-Até recentemente, a maioria dos bancos tinha muitos caixas e uma grande fila.
+AtĂ© recentemente, a maioria dos bancos tinham muitos caixas đšâđŒđšâđŒđšâđŒđšâđŒ e uma grande fila đđđđđđđđ.
-Todos os caixas fazendo todo o trabalho, um cliente apĂłs o outro.
+Todos os caixas fazendo todo o trabalho, um cliente apĂłs o outro đšâđŒâŻ.
-E vocĂȘ tinha que esperar na fila por um longo tempo ou poderia perder a vez.
+E vocĂȘ tinha que esperar đ na fila por um longo tempo ou poderia perder a vez.
-VocĂȘ provavelmente nĂŁo gostaria de levar seu _crush_ :heart_eyes: com vocĂȘ para um rolezinho no banco.
+VocĂȘ provavelmente nĂŁo gostaria de levar seu _crush_ đ com vocĂȘ para um rolezinho no banco đŠ.
### ConclusĂŁo dos hambĂșrgueres
-Nesse cenĂĄrio dos "hambĂșrgueres com seu _crush_ :heart_eyes:", como tem muita espera, faz mais sentido ter um sistema concorrente.
+Nesse cenĂĄrio dos "hambĂșrgueres com seu _crush_", como tem muita espera, faz mais sentido ter um sistema concorrente âžđâŻ.
Esse é o caso da maioria das aplicaçÔes web.
-Geralmente são muitos usuårios, e seu servidor estå esperando pelas suas conexÔes não tão boas para enviar as requisiçÔes.
-
-E entĂŁo esperando novamente pelas respostas voltarem.
-
-Essa "espera" Ă© medida em microssegundos, e ainda assim, somando tudo, Ă© um monte de espera no final.
+Muitos, muitos usuĂĄrios, mas seu servidor estĂĄ esperando đ pela sua conexĂŁo nĂŁo tĂŁo boa enviar suas requisiçÔes.
-Por isso que faz muito mais sentido utilizar cĂłdigo assĂncrono para APIs web.
+E entĂŁo esperando đ novamente as respostas voltarem.
-A maioria dos frameworks Python existentes mais populares (incluindo Flask e Django) foram criados antes que os novos recursos assĂncronos existissem em Python. EntĂŁo, os meios que eles podem ser colocados em produção para suportar execução paralela mais a forma antiga de execução assĂncrona nĂŁo sĂŁo tĂŁo poderosos quanto as novas capacidades.
+Essa "espera" đ Ă© medida em microssegundos, mas ainda assim, somando tudo, Ă© um monte de espera no final.
-Mesmo embora a especificação principal para web assĂncrono em Python (ASGI) foi desenvolvida no Django, para adicionar suporte para WebSockets.
+Por isso que faz bastante sentido utilizar cĂłdigo assĂncrono âžđ⯠para APIs web.
-Esse tipo de assincronicidade é o que fez NodeJS popular (embora NodeJS não seja paralelo) e que essa seja a força do Go como uma linguagem de programa.
+Esse tipo de assincronicidade é o que fez NodeJS popular (embora NodeJS não seja paralelo) e essa é a força do Go como uma linguagem de programação.
E esse Ă© o mesmo nĂvel de performance que vocĂȘ tem com o **FastAPI**.
-E como vocĂȘ pode ter paralelismo e sincronicidade ao mesmo tempo, vocĂȘ tem uma maior performance do que a maioria dos frameworks NodeJS testados e lado a lado com Go, que Ă© uma linguagem compilada prĂłxima ao C (tudo graças ao Starlette).
+E como vocĂȘ pode ter paralelismo e assincronicidade ao mesmo tempo, vocĂȘ tem uma maior performance do que a maioria dos frameworks NodeJS testados e lado a lado com Go, que Ă© uma linguagem compilada, mais prĂłxima ao C (tudo graças ao Starlette).
### ConcorrĂȘncia Ă© melhor que paralelismo?
@@ -225,64 +223,64 @@ ConcorrĂȘncia Ă© diferente de paralelismo. E Ă© melhor em cenĂĄrios **especĂfic
EntĂŁo, para equilibrar tudo, imagine a seguinte historinha:
-> VocĂȘ tem que limpar uma grande casa suja.
+> VocĂȘ tem que limpar uma casa grande e suja.
*Sim, essa Ă© toda a histĂłria*.
---
-NĂŁo hĂĄ espera em lugar algum, apenas um monte de trabalho para ser feito, em mĂșltiplos cĂŽmodos da casa.
+NĂŁo hĂĄ espera đ em lugar algum, apenas um monte de trabalho para ser feito, em mĂșltiplos cĂŽmodos da casa.
-VocĂȘ poderia ter chamadas como no exemplo dos hambĂșrgueres, primeiro a sala de estar, entĂŁo a cozinha, mas vocĂȘ nĂŁo estĂĄ esperando por nada, apenas limpar e limpar, as chamadas nĂŁo afetariam em nada.
+VocĂȘ poderia ter turnos como no exemplo dos hambĂșrgueres, primeiro a sala de estar, entĂŁo a cozinha, mas como vocĂȘ nĂŁo estĂĄ esperando por nada, apenas limpando e limpando, as chamadas nĂŁo afetariam em nada.
-Levaria o mesmo tempo para finalizar com ou sem chamadas (concorrĂȘncia) e vocĂȘ teria feito o mesmo tanto de trabalho.
+Levaria o mesmo tempo para finalizar com ou sem turnos (concorrĂȘncia) e vocĂȘ teria feito o mesmo tanto de trabalho.
Mas nesse caso, se vocĂȘ trouxesse os 8 ex-caixas / cozinheiros / agora-faxineiros, e cada um deles (mais vocĂȘ) pudessem dividir a casa para limpĂĄ-la, vocĂȘs fariam toda a limpeza em **paralelo**, com a ajuda extra, e terminariam muito mais cedo.
Nesse cenĂĄrio, cada um dos faxineiros (incluindo vocĂȘ) poderia ser um processador, fazendo a sua parte do trabalho.
-E a maior parte do tempo de execução é tomada por trabalho (ao invés de ficar esperando), e o trabalho em um computador é feito pela CPU, que podem gerar problemas que são chamados de "limite de CPU".
+E a maior parte do tempo de execução é tomada por trabalho real (ao invés de ficar esperando), e o trabalho em um computador é feito pela CPU. Eles chamam esses problemas de "limitados por CPU".
---
-Exemplos comuns de limite de CPU sĂŁo coisas que exigem processamento matemĂĄtico complexo.
+Exemplos comuns de operaçÔes limitadas por CPU são coisas que exigem processamento matemåtico complexo.
Por exemplo:
* **Processamento de ĂĄudio** ou **imagem**
-* **Visão do Computador**: uma imagem é composta por milhÔes de pixels, cada pixel tem 3 valores (cores, processamento que normalmente exige alguma computação em todos esses pixels ao mesmo tempo)
+* **Visão Computacional**: uma imagem é composta por milhÔes de pixels, cada pixel tem 3 valores / cores, processar isso normalmente exige alguma computação em todos esses pixels ao mesmo tempo
-* **Machine Learning**: Normalmente exige muita multiplicação de matrizes e vetores. Pense numa grande folha de papel com nĂșmeros e multiplicando todos eles juntos e ao mesmo tempo.
+* **Machine Learning**: Normalmente exige muita multiplicação de matrizes e vetores. Pense numa grande planilha com nĂșmeros e em multiplicar todos eles juntos e ao mesmo tempo.
-* **Deep Learning**: Esse Ă© um subcampo do Machine Learning, entĂŁo o mesmo se aplica. A diferença Ă© que nĂŁo hĂĄ apenas uma grande folha de papel com nĂșmeros para multiplicar, mas um grande conjunto de folhas de papel, e em muitos casos, vocĂȘ utiliza um processador especial para construir e/ou usar modelos.
+* **Deep Learning**: Esse Ă© um subcampo do Machine Learning, entĂŁo, o mesmo se aplica. A diferença Ă© que nĂŁo hĂĄ apenas uma grande planilha com nĂșmeros para multiplicar, mas um grande conjunto delas, e em muitos casos, vocĂȘ utiliza um processador especial para construir e/ou usar esses modelos.
### ConcorrĂȘncia + Paralelismo: Web + Machine learning
Com **FastAPI** vocĂȘ pode levar a vantagem da concorrĂȘncia que Ă© muito comum para desenvolvimento web (o mesmo atrativo de NodeJS).
-Mas vocĂȘ tambĂ©m pode explorar os benefĂcios do paralelismo e multiprocessamento (tendo mĂșltiplos processadores rodando em paralelo) para trabalhos pesados que geram **limite de CPU** como aqueles em sistemas de Machine Learning.
+Mas vocĂȘ tambĂ©m pode explorar os benefĂcios do paralelismo e multiprocessamento (tendo mĂșltiplos processadores rodando em paralelo) para trabalhos **limitados por CPU** como aqueles em sistemas de Machine Learning.
-Isso, mais o simples fato que Python é a principal linguagem para **Data Science**, Machine Learning e especialmente Deep Learning, faz do FastAPI uma ótima escolha para APIs web e aplicaçÔes com Data Science / Machine Learning (entre muitas outras).
+Isso, somado ao simples fato que Python é a principal linguagem para **Data Science**, Machine Learning e especialmente Deep Learning, faz do FastAPI uma ótima escolha para APIs web e aplicaçÔes com Data Science / Machine Learning (entre muitas outras).
Para ver como alcançar esse paralelismo em produção veja a seção sobre [Deployment](deployment/index.md){.internal-link target=_blank}.
## `async` e `await`
-VersĂ”es modernas do Python tem um modo muito intuitivo para definir cĂłdigo assĂncrono. Isso faz parecer normal o cĂłdigo "sequencial" e fazer o "esperar" para vocĂȘ nos momentos certos.
+VersĂ”es modernas do Python tĂȘm um modo muito intuitivo para definir cĂłdigo assĂncrono. Isso faz parecer do mesmo jeito do cĂłdigo normal "sequencial" e fazer a "espera" para vocĂȘ nos momentos certos.
-Quando tem uma operação que exigirĂĄ espera antes de dar os resultados e tem suporte para esses recursos Python, vocĂȘ pode escrever assim:
+Quando tem uma operação que exigirĂĄ espera antes de dar os resultados e tem suporte para esses novos recursos do Python, vocĂȘ pode escrever assim:
```Python
burgers = await get_burgers(2)
```
-A chave aqui é o `await`. Ele diz ao Python que ele tem que esperar por `get_burgers(2)` para finalizar suas coisas antes de armazenar os resultados em `burgers`. Com isso, o Python saberå que ele pode ir e fazer outras coisas nesse meio tempo (como receber outra requisição).
+A chave aqui Ă© o `await`. Ele diz ao Python que ele tem que esperar por `get_burgers(2)` finalizar suas coisas đ antes de armazenar os resultados em `burgers`. Com isso, o Python saberĂĄ que ele pode ir e fazer outras coisas đ ⯠nesse meio tempo (como receber outra requisição).
Para o `await` funcionar, tem que estar dentro de uma função que suporte essa assincronicidade. Para fazer isso, apenas declare a função com `async def`:
```Python hl_lines="1"
async def get_burgers(number: int):
- # Fazer alguma coisa assĂncrona para criar os hambĂșrgueres
+ # Faz alguma coisa assĂncrona para criar os hambĂșrgueres
return burgers
```
@@ -295,9 +293,9 @@ def get_sequential_burgers(number: int):
return burgers
```
-Com `async def`, o Python sabe que, dentro dessa função, tem que estar ciente das expressÔes `await`, e que isso pode "pausar" a execução dessa função, e poderå fazer outra coisa antes de voltar.
+Com `async def`, o Python sabe que, dentro dessa função, ele deve estar ciente das expressĂ”es `await`, e que isso poderĂĄ "pausar" âž a execução dessa função, e ir fazer outra coisa đ antes de voltar.
-Quando vocĂȘ quiser chamar uma função `async def`, vocĂȘ tem que "esperar". EntĂŁo, isso nĂŁo funcionarĂĄ:
+Quando vocĂȘ quiser chamar uma função `async def`, vocĂȘ tem que "esperar" ela. EntĂŁo, isso nĂŁo funcionarĂĄ:
```Python
# Isso nĂŁo irĂĄ funcionar, porquĂȘ get_burgers foi definido com: async def
@@ -319,13 +317,24 @@ async def read_burgers():
VocĂȘ deve ter observado que `await` pode ser usado somente dentro de funçÔes definidas com `async def`.
-Mas ao mesmo tempo, funçÔes definidas com `async def` tem que ser aguardadas. Então, funçÔes com `async def` pdem ser chamadas somente dentro de funçÔes definidas com `async def` também.
+Mas ao mesmo tempo, funçÔes definidas com `async def` tĂȘm que ser "aguardadas". EntĂŁo, funçÔes com `async def` pdem ser chamadas somente dentro de funçÔes definidas com `async def` tambĂ©m.
EntĂŁo, sobre o ovo e a galinha, como vocĂȘ chama a primeira função async?
Se vocĂȘ estivar trabalhando com **FastAPI** nĂŁo terĂĄ que se preocupar com isso, porquĂȘ essa "primeira" função serĂĄ a sua *função de operação de rota*, e o FastAPI saberĂĄ como fazer a coisa certa.
-Mas se vocĂȘ quiser usar `async` / `await` sem FastAPI, verifique a documentação oficial Python.
+Mas se vocĂȘ quiser usar `async` / `await` sem FastAPI, vocĂȘ tambĂ©m pode fazĂȘ-lo.
+
+### Escreva seu prĂłprio cĂłdigo assĂncrono
+
+Starlette (e **FastAPI**) sĂŁo baseados no AnyIO, o que o torna compatĂvel com ambos o asyncio da biblioteca padrĂŁo do Python, e o Trio.
+
+Em particular, vocĂȘ pode usar diretamente o AnyIO para seus casos de uso avançados de concorrĂȘncia que requerem padrĂ”es mais avançados no seu prĂłprio cĂłdigo.
+
+E atĂ© se vocĂȘ nĂŁo estiver utilizando FastAPI, vocĂȘ tambĂ©m pode escrever suas prĂłprias aplicaçÔes assĂncronas com o AnyIO por ser altamente compatĂvel e ganhar seus benefĂcios (e.g. *concorrĂȘncia estruturada*).
+
+Eu criei outra biblioteca em cima do AnyIO, como uma fina camada acima, para melhorar um pouco as anotaçÔes de tipo e obter melhor **autocompletar**, **erros de linha**, etc. Ela tambĂ©m possui uma introdução amigĂĄvel e um tutorial para ajudar vocĂȘ a **entender** e escrever **seu prĂłprio cĂłdigo async**: Asyncer. Seria particularmente Ăștil se vocĂȘ precisar **combinar cĂłdigo async com cĂłdigo regular** (bloqueador/sĂncrono).
+
### Outras formas de cĂłdigo assĂncrono
@@ -337,25 +346,25 @@ Essa mesma sintaxe (ou quase a mesma) foi tambĂ©m incluĂda recentemente em vers
Mas antes disso, controlar cĂłdigo assĂncrono era bem mais complexo e difĂcil.
-Nas versĂ”es anteriores do Python, vocĂȘ poderia utilizar threads ou Gevent. Mas o cĂłdigo Ă© um pouco mais complexo de entender, debugar, e pensar sobre.
+Nas versĂ”es anteriores do Python, vocĂȘ poderia utilizar threads ou Gevent. Mas o cĂłdigo Ă© bem mais complexo de entender, debugar, e pensar sobre.
-Nas versĂ”es anteriores do NodeJS / Navegador JavaScript, vocĂȘ poderia utilizar "callbacks". O que leva ao inferno do callback.
+Nas versĂ”es anteriores do NodeJS / Navegador JavaScript, vocĂȘ utilizaria "callbacks". O que leva ao inferno do callback.
## Corrotinas
-**Corrotina** é apenas um jeito bonitinho para a coisa que é retornada de uma função `async def`. O Python sabe que é uma função que pode começar e terminar em algum ponto, mas que pode ser pausada internamente também, sempre que tiver um `await` dentro dela.
+**Corrotina** é apenas um jeito bonitinho para a coisa que é retornada de uma função `async def`. O Python sabe que é algo como uma função, que pode começar e que vai terminar em algum ponto, mas que pode ser pausada ➠internamente também, sempre que tiver um `await` dentro dela.
-Mas toda essa funcionalidade de cĂłdigo assĂncrono com `async` e `await` Ă© muitas vezes resumida como "corrotina". Ă comparĂĄvel ao principal recurso chave do Go, a "Gorotina".
+Mas toda essa funcionalidade de cĂłdigo assĂncrono com `async` e `await` Ă© muitas vezes resumida como usando "corrotinas". Ă comparĂĄvel ao principal recurso chave do Go, a "Gorrotina".
## ConclusĂŁo
-Vamos ver a mesma frase com o conteĂșdo cima:
+Vamos ver a mesma frase de cima:
-> VersĂ”es modernas do Python tem suporte para **"cĂłdigo assĂncrono"** usando algo chamado **"corrotinas"**, com sintaxe **`async` e `await`**.
+> VersĂ”es modernas do Python tĂȘm suporte para **"cĂłdigo assĂncrono"** usando algo chamado **"corrotinas"**, com sintaxe **`async` e `await`**.
-Isso pode fazer mais sentido agora.
+Isso pode fazer mais sentido agora. âš
-Tudo isso é o que deixa o FastAPI poderoso (através do Starlette) e que o faz ter uma performance impressionante.
+Tudo isso é o que empodera o FastAPI (através do Starlette) e que o faz ter uma performance tão impressionante.
## Detalhes muito técnicos
@@ -365,25 +374,25 @@ VocĂȘ pode provavelmente pular isso.
Esses são detalhes muito técnicos de como **FastAPI** funciona por baixo do capÎ.
-Se vocĂȘ tem algum conhecimento tĂ©cnico (corrotinas, threads, blocking etc) e estĂĄ curioso sobre como o FastAPI controla o `async def` vs normal `def`, vĂĄ em frente.
+Se vocĂȘ tem certo conhecimento tĂ©cnico (corrotinas, threads, blocking etc) e estĂĄ curioso sobre como o FastAPI controla o `async def` vs normal `def`, vĂĄ em frente.
///
### FunçÔes de operação de rota
-Quando vocĂȘ declara uma *função de operação de rota* com `def` normal ao invĂ©s de `async def`, ela Ă© rodada em uma threadpool externa que entĂŁo Ă© aguardada, ao invĂ©s de ser chamada diretamente (ela poderia bloquear o servidor).
+Quando vocĂȘ declara uma *função de operação de rota* com `def` normal ao invĂ©s de `async def`, ela Ă© rodada em uma threadpool externa que Ă© entĂŁo aguardada, ao invĂ©s de ser chamada diretamente (jĂĄ que ela bloquearia o servidor).
-Se vocĂȘ estĂĄ chegando de outro framework assĂncrono que nĂŁo faz o trabalho descrito acima e vocĂȘ estĂĄ acostumado a definir triviais *funçÔes de operação de rota* com simples `def` para ter um mĂnimo ganho de performance (cerca de 100 nanosegundos), por favor observe que no **FastAPI** o efeito pode ser bem o oposto. Nesses casos, Ă© melhor usar `async def` a menos que suas *funçÔes de operação de rota* utilizem cĂłdigo que performem bloqueamento IO.
+Se vocĂȘ estĂĄ chegando de outro framework assĂncrono que nĂŁo funciona como descrito acima e vocĂȘ estĂĄ acostumado a definir *funçÔes de operação de rota* triviais somente de computação com simples `def` para ter um mĂnimo ganho de performance (cerca de 100 nanosegundos), por favor observe que no **FastAPI** o efeito pode ser bem o oposto. Nesses casos, Ă© melhor usar `async def` a menos que suas *funçÔes de operação de rota* utilizem cĂłdigo que performe bloqueamento IO.
-Ainda, em ambas as situaçÔes, as chances são que o **FastAPI** serå [ainda mais råpido](index.md#performance){.internal-link target=_blank} do que (ou ao menos comparåvel a) seus frameworks antecessores.
+Ainda, em ambas as situaçÔes, as chances são que o **FastAPI** [ainda serå mais råpido](index.md#performance){.internal-link target=_blank} do que (ou ao menos comparåvel a) seu framework anterior.
### DependĂȘncias
-O mesmo se aplica para as dependĂȘncias. Se uma dependĂȘncia tem as funçÔes com padrĂŁo `def` ao invĂ©s de `async def`, ela Ă© rodada no threadpool externo.
+O mesmo se aplica para as [dependĂȘncias](tutorial/dependencies/index.md){.internal-link target=_blank}. Se uma dependĂȘncia tem as funçÔes com padrĂŁo `def` ao invĂ©s de `async def`, ela Ă© rodada no threadpool externo.
### Sub-dependĂȘncias
-VocĂȘ pode ter mĂșltiplas dependĂȘncias e sub-dependĂȘncias exigindo uma a outra (como parĂąmetros de definiçÔes de funçÔes), algumas delas podem ser criadas com `async def` e algumas com `def` normal. Isso ainda poderia funcionar, e aquelas criadas com `def` podem ser chamadas em uma thread externa ao invĂ©s de serem "aguardadas".
+VocĂȘ pode ter mĂșltiplas dependĂȘncias e [sub-dependĂȘncias](tutorial/dependencies/sub-dependencies.md){.internal-link target=_blank} requisitando uma Ă outra (como parĂąmetros de definiçÔes de funçÔes), algumas delas podem ser criadas com `async def` e algumas com `def` normal. Isso ainda funcionaria, e aquelas criadas com `def` normal seriam chamadas em uma thread externa (do threadpool) ao invĂ©s de serem "aguardadas".
### Outras funçÔes de utilidade
@@ -395,6 +404,6 @@ Se sua função de utilidade é uma função normal com `def`, ela serå chamada
---
-Novamente, esses sĂŁo detalhes muito tĂ©cnicos que provavelmente possam ser Ășteis caso vocĂȘ esteja procurando por eles.
+Novamente, esses sĂŁo detalhes muito tĂ©cnicos que provavelmente seriam Ășteis caso vocĂȘ esteja procurando por eles.
Caso contrĂĄrio, vocĂȘ deve ficar bem com as dicas da seção acima: Com pressa?.
diff --git a/requirements-docs-tests.txt b/requirements-docs-tests.txt
index 71f4a7ab9..e7684a2e3 100644
--- a/requirements-docs-tests.txt
+++ b/requirements-docs-tests.txt
@@ -1,4 +1,4 @@
# For mkdocstrings and tests
-httpx >=0.23.0,<0.28.0
+httpx >=0.23.0,<0.29.0
# For linting and generating docs versions
ruff ==0.11.2
diff --git a/requirements-github-actions.txt b/requirements-github-actions.txt
index 920aefea6..f807d06a8 100644
--- a/requirements-github-actions.txt
+++ b/requirements-github-actions.txt
@@ -1,6 +1,6 @@
PyGithub>=2.3.0,<3.0.0
pydantic>=2.5.3,<3.0.0
pydantic-settings>=2.1.0,<3.0.0
-httpx>=0.27.0,<0.28.0
+httpx>=0.27.0,<0.29.0
pyyaml >=5.3.1,<7.0.0
smokeshow
diff --git a/requirements-translations.txt b/requirements-translations.txt
index 7a2a8004e..90f718032 100644
--- a/requirements-translations.txt
+++ b/requirements-translations.txt
@@ -1 +1,2 @@
pydantic-ai==0.0.30
+GitPython==3.1.45
diff --git a/scripts/translate.py b/scripts/translate.py
index 9a2136d1b..b78d7211b 100644
--- a/scripts/translate.py
+++ b/scripts/translate.py
@@ -2,9 +2,11 @@ from functools import lru_cache
from pathlib import Path
from typing import Iterable
+import git
import typer
import yaml
from pydantic_ai import Agent
+from rich import print
non_translated_sections = (
"reference/",
@@ -28,8 +30,38 @@ The content is written in markdown, write the translation in markdown as well. D
When there's an example of code, the console or a terminal, normally surrounded by triple backticks and a keyword like "console" or "bash" (e.g. ```console), do not translate the content, keep the original in English.
The original content will be surrounded by triple percentage signs (%) and you should translate it to the target language. Do not include the triple percentage signs in the translation.
+
+There are special blocks of notes, tips and others that look like:
+
+/// note
+
+To translate it, keep the same line and add the translation after a vertical bar.
+
+For example, if you were translating to Spanish, you would write:
+
+/// note | Nota
+
+Some examples in Spanish:
+
+Source:
+
+/// tip
+
+Result:
+
+/// tip | Consejo
+
+Source:
+
+/// details | Preview
+
+Result:
+
+/// details | Vista previa
"""
+app = typer.Typer()
+
@lru_cache
def get_langs() -> dict[str, str]:
@@ -46,6 +78,17 @@ def generate_lang_path(*, lang: str, path: Path) -> Path:
return out_path
+def generate_en_path(*, lang: str, path: Path) -> Path:
+ en_docs_path = Path("docs/en/docs")
+ assert not str(path).startswith(str(en_docs_path)), (
+ f"Path must not be inside {en_docs_path}"
+ )
+ lang_docs_path = Path(f"docs/{lang}/docs")
+ out_path = Path(str(path).replace(str(lang_docs_path), str(en_docs_path)))
+ return out_path
+
+
+@app.command()
def translate_page(*, lang: str, path: Path) -> None:
langs = get_langs()
language = langs[lang]
@@ -64,12 +107,14 @@ def translate_page(*, lang: str, path: Path) -> None:
original_content = path.read_text()
old_translation: str | None = None
if out_path.exists():
+ print(f"Found existing translation: {out_path}")
old_translation = out_path.read_text()
+ print(f"Translating {path} to {lang} ({language})")
agent = Agent("openai:gpt-4o")
prompt_segments = [
- lang_prompt_content,
general_prompt,
+ lang_prompt_content,
]
if old_translation:
prompt_segments.extend(
@@ -89,13 +134,14 @@ def translate_page(*, lang: str, path: Path) -> None:
]
)
prompt = "\n\n".join(prompt_segments)
-
+ print(f"Running agent for {out_path}")
result = agent.run_sync(prompt)
out_content = f"{result.data.strip()}\n"
+ print(f"Saving translation to {out_path}")
out_path.write_text(out_content)
-def iter_paths_to_translate() -> Iterable[Path]:
+def iter_all_en_paths() -> Iterable[Path]:
"""
Iterate on the markdown files to translate in order of priority.
"""
@@ -119,12 +165,16 @@ def iter_paths_to_translate() -> Iterable[Path]:
yield path
-def translate_all(lang: str) -> None:
- paths_to_process: list[Path] = []
- for path in iter_paths_to_translate():
+def iter_en_paths_to_translate() -> Iterable[Path]:
+ for path in iter_all_en_paths():
if str(path).replace("docs/en/docs/", "").startswith(non_translated_sections):
continue
- paths_to_process.append(path)
+ yield path
+
+
+@app.command()
+def translate_all(lang: str) -> None:
+ paths_to_process = list(iter_en_paths_to_translate())
print("Original paths:")
for p in paths_to_process:
print(f" - {p}")
@@ -151,12 +201,82 @@ def translate_all(lang: str) -> None:
print(f"Done translating: {p}")
-def main(*, lang: str, path: Path = None) -> None:
- if path:
+@app.command()
+def list_removable(lang: str) -> list[Path]:
+ removable_paths: list[Path] = []
+ lang_paths = Path(f"docs/{lang}").rglob("*.md")
+ for path in lang_paths:
+ en_path = generate_en_path(lang=lang, path=path)
+ if not en_path.exists():
+ removable_paths.append(path)
+ print(removable_paths)
+ return removable_paths
+
+
+@app.command()
+def list_all_removable() -> list[Path]:
+ all_removable_paths: list[Path] = []
+ langs = get_langs()
+ for lang in langs:
+ if lang == "en":
+ continue
+ removable_paths = list_removable(lang)
+ all_removable_paths.extend(removable_paths)
+ print(all_removable_paths)
+ return all_removable_paths
+
+
+@app.command()
+def remove_removable(lang: str) -> None:
+ removable_paths = list_removable(lang)
+ for path in removable_paths:
+ path.unlink()
+ print(f"Removed: {path}")
+ print("Done removing all removable paths")
+
+
+@app.command()
+def remove_all_removable() -> None:
+ all_removable = list_all_removable()
+ for removable_path in all_removable:
+ removable_path.unlink()
+ print(f"Removed: {removable_path}")
+ print("Done removing all removable paths")
+
+
+@app.command()
+def list_outdated(lang: str) -> list[Path]:
+ dir_path = Path(__file__).absolute().parent.parent
+ repo = git.Repo(dir_path)
+
+ outdated_paths: list[Path] = []
+ en_lang_paths = list(iter_en_paths_to_translate())
+ for path in en_lang_paths:
+ lang_path = generate_lang_path(lang=lang, path=path)
+ if not lang_path.exists():
+ outdated_paths.append(path)
+ continue
+ en_commit_datetime = list(repo.iter_commits(paths=path, max_count=1))[
+ 0
+ ].committed_datetime
+ lang_commit_datetime = list(repo.iter_commits(paths=lang_path, max_count=1))[
+ 0
+ ].committed_datetime
+ if lang_commit_datetime < en_commit_datetime:
+ outdated_paths.append(path)
+ print(outdated_paths)
+ return outdated_paths
+
+
+@app.command()
+def update_outdated(lang: str) -> None:
+ outdated_paths = list_outdated(lang)
+ for path in outdated_paths:
+ print(f"Updating lang: {lang} path: {path}")
translate_page(lang=lang, path=path)
- else:
- translate_all(lang=lang)
+ print(f"Done updating: {path}")
+ print("Done updating all outdated paths")
if __name__ == "__main__":
- typer.run(main)
+ app()
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 6f7355aaa..647f1c5dd 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
@@ -1,4 +1,4 @@
-from dirty_equals import IsDict
+from dirty_equals import IsDict, IsOneOf
from fastapi.testclient import TestClient
from docs_src.custom_request_and_route.tutorial002 import app
@@ -24,14 +24,16 @@ def test_exception_handler_body_access():
"input": {"numbers": [1, 2, 3]},
}
],
- "body": '{"numbers": [1, 2, 3]}',
+ # httpx 0.28.0 switches to compact JSON https://github.com/encode/httpx/issues/3363
+ "body": IsOneOf('{"numbers": [1, 2, 3]}', '{"numbers":[1,2,3]}'),
}
}
) | IsDict(
# TODO: remove when deprecating Pydantic v1
{
"detail": {
- "body": '{"numbers": [1, 2, 3]}',
+ # httpx 0.28.0 switches to compact JSON https://github.com/encode/httpx/issues/3363
+ "body": IsOneOf('{"numbers": [1, 2, 3]}', '{"numbers":[1,2,3]}'),
"errors": [
{
"loc": ["body"],