Browse Source

Merge branch 'master' into master

pull/13326/head
Manish 2 days ago
committed by GitHub
parent
commit
b372ea142c
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 45
      .github/DISCUSSION_TEMPLATE/translations.yml
  2. 77
      .github/workflows/translate.yml
  3. 2
      .pre-commit-config.yaml
  4. 1
      README.md
  5. 3
      docs/bn/docs/about/index.md
  6. 3
      docs/en/data/sponsors.yml
  7. 1
      docs/en/data/sponsors_badge.yml
  8. 37
      docs/en/docs/contributing.md
  9. BIN
      docs/en/docs/img/sponsors/mobbai-banner.png
  10. BIN
      docs/en/docs/img/sponsors/mobbai.png
  11. 24
      docs/en/docs/release-notes.md
  12. 6
      docs/en/overrides/main.html
  13. 50
      docs/es/llm-prompt.md
  14. 444
      docs/fa/docs/async.md
  15. 298
      docs/fa/docs/environment-variables.md
  16. 578
      docs/fa/docs/python-types.md
  17. 12
      docs/ja/docs/tutorial/body.md
  18. 207
      docs/pt/docs/async.md
  19. 112
      docs/pt/docs/project-generation.md
  20. 2
      requirements-docs-tests.txt
  21. 2
      requirements-github-actions.txt
  22. 1
      requirements-translations.txt
  23. 258
      scripts/translate.py
  24. 8
      tests/test_tutorial/test_custom_request_and_route/test_tutorial002.py

45
.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. 😎

77
.github/workflows/translate.yml

@ -0,0 +1,77 @@
name: Translate
on:
workflow_dispatch:
inputs:
debug_enabled:
description: Run with tmate debugging enabled (https://github.com/marketplace/actions/debugging-with-tmate)
required: false
default: "false"
command:
description: Command to run
type: choice
options:
- translate-page
- translate-lang
- update-outdated
- add-missing
- update-and-add
- remove-all-removable
language:
description: Language to translate to as a letter code (e.g. "es" for Spanish)
type: string
required: false
default: ""
en_path:
description: File path in English to translate (e.g. docs/en/docs/index.md)
type: string
required: false
default: ""
env:
UV_SYSTEM_PYTHON: 1
jobs:
job:
if: github.repository_owner == 'fastapi'
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Dump GitHub context
env:
GITHUB_CONTEXT: ${{ toJson(github) }}
run: echo "$GITHUB_CONTEXT"
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Setup uv
uses: astral-sh/setup-uv@v6
with:
version: "0.4.15"
enable-cache: true
cache-dependency-glob: |
requirements**.txt
pyproject.toml
- name: Install Dependencies
run: uv pip install -r requirements-github-actions.txt -r requirements-translations.txt
# Allow debugging with tmate
- name: Setup tmate session
uses: mxschmitt/action-tmate@v3
if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.debug_enabled == 'true' }}
with:
limit-access-to-actor: true
env:
GITHUB_TOKEN: ${{ secrets.FASTAPI_TRANSLATIONS }}
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
- name: FastAPI Translate
run: |
python ./scripts/translate.py ${{ github.event.inputs.command }}
python ./scripts/translate.py make-pr
env:
GITHUB_TOKEN: ${{ secrets.FASTAPI_TRANSLATIONS }}
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
LANGUAGE: ${{ github.event.inputs.language }}
EN_PATH: ${{ github.event.inputs.en_path }}

2
.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.5
hooks:
- id: ruff
args:

1
README.md

@ -55,6 +55,7 @@ The key features are:
<a href="https://docs.render.com/deploy-fastapi?utm_source=deploydoc&utm_medium=referral&utm_campaign=fastapi" target="_blank" title="Deploy & scale any full-stack web app on Render. Focus on building apps, not infra."><img src="https://fastapi.tiangolo.com/img/sponsors/render.svg"></a>
<a href="https://www.coderabbit.ai/?utm_source=fastapi&utm_medium=badge&utm_campaign=fastapi" target="_blank" title="Cut Code Review Time & Bugs in Half with CodeRabbit"><img src="https://fastapi.tiangolo.com/img/sponsors/coderabbit.png"></a>
<a href="https://subtotal.com/?utm_source=fastapi&utm_medium=sponsorship&utm_campaign=open-source" target="_blank" title="The Gold Standard in Retail Account Linking"><img src="https://fastapi.tiangolo.com/img/sponsors/subtotal.svg"></a>
<a href="https://vibe.mobb.ai/?utm_source=Fast+APi&utm_medium=Image&utm_campaign=MVS" target="_blank" title="Secure Your AI-Generated Code to Unlock Dev Productivity"><img src="https://fastapi.tiangolo.com/img/sponsors/mobbai.png"></a>
<a href="https://databento.com/" target="_blank" title="Pay as you go for market data"><img src="https://fastapi.tiangolo.com/img/sponsors/databento.svg"></a>
<a href="https://speakeasy.com/editor?utm_source=fastapi+repo&utm_medium=github+sponsorship" target="_blank" title="SDKs for your API | Speakeasy"><img src="https://fastapi.tiangolo.com/img/sponsors/speakeasy.png"></a>
<a href="https://www.svix.com/" target="_blank" title="Svix - Webhooks as a service"><img src="https://fastapi.tiangolo.com/img/sponsors/svix.svg"></a>

3
docs/bn/docs/about/index.md

@ -0,0 +1,3 @@
# সম্পর্কে
**FastAPI** সম্পর্কে বিস্তারিত — এর ডিজাইন, অনুপ্রেরণা ও আরও অনেক কিছু। 🤓

3
docs/en/data/sponsors.yml

@ -26,6 +26,9 @@ gold:
- url: https://subtotal.com/?utm_source=fastapi&utm_medium=sponsorship&utm_campaign=open-source
title: The Gold Standard in Retail Account Linking
img: https://fastapi.tiangolo.com/img/sponsors/subtotal.svg
- url: https://vibe.mobb.ai/?utm_source=Fast+APi&utm_medium=Image&utm_campaign=MVS
title: Secure Your AI-Generated Code to Unlock Dev Productivity
img: https://fastapi.tiangolo.com/img/sponsors/mobbai.png
silver:
- url: https://databento.com/
title: Pay as you go for market data

1
docs/en/data/sponsors_badge.yml

@ -43,3 +43,4 @@ logins:
- permitio
- LambdaTest-Inc
- dribia
- madisonredtfeldt

37
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:
<div class="termy">
```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
```
</div>
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

BIN
docs/en/docs/img/sponsors/mobbai-banner.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

BIN
docs/en/docs/img/sponsors/mobbai.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

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

@ -7,8 +7,32 @@ 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).
* 🌐 Add Persian translation for `docs/fa/docs/async.md`. PR [#13541](https://github.com/fastapi/fastapi/pull/13541) by [@Mohammad222PR](https://github.com/Mohammad222PR).
* 🌐 Add Bangali translation for `docs/bn/about/index.md`. PR [#13882](https://github.com/fastapi/fastapi/pull/13882) by [@sajjadrahman56](https://github.com/sajjadrahman56).
### Internal
* ⚒️ Update translate script, update prompt to minimize generated diff. PR [#13947](https://github.com/fastapi/fastapi/pull/13947) by [@YuriiMotov](https://github.com/YuriiMotov).
* ⬆ [pre-commit.ci] pre-commit autoupdate. PR [#13943](https://github.com/fastapi/fastapi/pull/13943) by [@pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci).
* ⚒️ Tweak translate script and CI. PR [#13939](https://github.com/fastapi/fastapi/pull/13939) by [@tiangolo](https://github.com/tiangolo).
* 👷 Add CI to translate with LLMs. PR [#13937](https://github.com/fastapi/fastapi/pull/13937) by [@tiangolo](https://github.com/tiangolo).
* ⚒️ 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).

6
docs/en/overrides/main.html

@ -80,6 +80,12 @@
<img class="sponsor-image" src="/img/sponsors/subtotal-banner.svg" />
</a>
</div>
<div class="item">
<a title="Secure Your AI-Generated Code to Unlock Dev Productivity" style="display: block; position: relative;" href="https://vibe.mobb.ai/?utm_source=Fast+APi&utm_medium=Image&utm_campaign=MVS" target="_blank">
<span class="sponsor-badge">sponsor</span>
<img class="sponsor-image" src="/img/sponsors/mobbai-banner.png" />
</a>
</div>
</div>
</div>
{% endblock %}

50
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:

444
docs/fa/docs/async.md

@ -0,0 +1,444 @@
# هم‌زمانی و async / await
جزئیات در مورد سینتکس `async def` برای *توابع عملیات مسیر* و یه کم پیش‌زمینه در مورد کد ناهم‌زمان، هم‌زمانی و موازی‌سازی.
## عجله داری؟
<abbr title="خیلی طولانی بود؛ نخوندم"><strong>TL;DR:</strong></abbr>
اگه از کتابخونه‌های سوم‌شخصی استفاده می‌کنی که بهت می‌گن با `await` صداشون کنی، مثل:
```Python
results = await some_library()
```
اون وقت، *توابع عملیات مسیرت* رو با `async def` تعریف کن، اینجوری:
```Python hl_lines="2"
@app.get('/')
async def read_results():
results = await some_library()
return results
```
/// note
فقط توی توابعی که با `async def` ساخته شدن می‌تونی از `await` استفاده کنی.
///
---
اگه از یه کتابخونه سوم‌شخص استفاده می‌کنی که با یه چیزی (مثل دیتابیس، API، سیستم فایل و غیره) ارتباط داره و از `await` پشتیبانی نمی‌کنه (که الان برای بیشتر کتابخونه‌های دیتابیس اینجوریه)، اون وقت *توابع عملیات مسیرت* رو عادی، فقط با `def` تعریف کن، اینجوری:
```Python hl_lines="2"
@app.get('/')
def results():
results = some_library()
return results
```
---
اگه برنامه‌ات (به هر دلیلی) لازم نیست با چیز دیگه‌ای ارتباط برقرار کنه و منتظر جوابش بمونه، از `async def` استفاده کن.
---
اگه نمی‌دونی چیکار کنی، از `def` معمولی استفاده کن.
---
**توجه**: می‌تونی توی *توابع عملیات مسیرت* هر چقدر که لازم داری `def` و `async def` رو قاطی کنی و هر کدوم رو با بهترین گزینه برات تعریف کنی. FastAPI خودش کار درست رو باهاشون انجام می‌ده.
به هر حال، توی هر کدوم از موقعیت‌های بالا، FastAPI هنوز ناهم‌زمان کار می‌کنه و خیلی خیلی سریع هست.
ولی با دنبال کردن مراحل بالا، می‌تونه یه سری بهینه‌سازی عملکرد هم بکنه.
## جزئیات فنی
نسخه‌های مدرن پایتون از **"کد ناهم‌زمان"** با چیزی که بهش **"کروتین"** می‌گن پشتیبانی می‌کنن، با سینتکس **`async` و `await`**.
بیاید این جمله رو تکه‌تکه توی بخش‌های زیر ببینیم:
* **کد ناهم‌زمان**
* **`async` و `await`**
* **کروتین‌ها**
## کد ناهم‌زمان
کد ناهم‌زمان یعنی زبون 💬 یه راهی داره که به کامپیوتر / برنامه 🤖 بگه توی یه جای کد، باید منتظر بمونه تا *یه چیز دیگه* یه جای دیگه تموم بشه. فرض کن اون *یه چیز دیگه* اسمش "فایل-آروم" 📝 باشه.
پس، توی اون مدت، کامپیوتر می‌تونه بره یه کار دیگه بکنه، تا وقتی "فایل-آروم" 📝 تموم بشه.
بعدش کامپیوتر / برنامه 🤖 هر وقت فرصتی داشته باشه برمی‌گرده، چون دوباره منتظره، یا هر وقت همه کاری که اون لحظه داشته تموم کرده. و می‌بینه آیا کارایی که منتظرشون بوده تموم شدن یا نه، و هر کاری که باید بکنه رو انجام می‌ده.
بعد، اون 🤖 اولین کاری که تموم شده (مثلاً "فایل-آروم" 📝 ما) رو برمی‌داره و هر کاری که باید باهاش بکنه رو ادامه می‌ده.
این "منتظر یه چیز دیگه بودن" معمولاً به عملیات <abbr title="ورودی و خروجی">I/O</abbr> اشاره داره که نسبتاً "آروم" هستن (نسبت به سرعت پردازنده و حافظه RAM)، مثل منتظر موندن برای:
* داده‌هایی که از کلاینت از طریق شبکه فرستاده می‌شن
* داده‌هایی که برنامه‌ات فرستاده تا از طریق شبکه به کلاینت برسه
* محتوای یه فایل توی دیسک که سیستم بخوندش و به برنامه‌ات بده
* محتوایی که برنامه‌ات به سیستم داده تا توی دیسک بنویسه
* یه عملیات API از راه دور
* یه عملیات دیتابیس که تموم بشه
* یه کوئری دیتابیس که نتایجش برگرده
* و غیره.
چون زمان اجرا بیشتر صرف انتظار برای عملیات <abbr title="ورودی و خروجی">I/O</abbr> می‌شه، بهشون می‌گن عملیات "I/O bound".
بهش "ناهم‌زمان" می‌گن چون کامپیوتر / برنامه لازم نیست با کار آروم "هم‌زمان" باشه، منتظر لحظه دقیق تموم شدن کار بمونه، در حالی که هیچ کاری نمی‌کنه، تا نتیجه رو بگیره و کارش رو ادامه بده.
به جاش، چون یه سیستم "ناهم‌زمان" هست، وقتی کار تموم شد، می‌تونه یه کم توی صف منتظر بمونه (چند میکروثانیه) تا کامپیوتر / برنامه هر کاری که رفته بکنه رو تموم کنه، و بعد برگرده نتیجه رو بگیره و باهاش کار کنه.
برای "هم‌زمان" (برخلاف "ناهم‌زمان") معمولاً از اصطلاح "ترتیبی" هم استفاده می‌کنن، چون کامپیوتر / برنامه همه مراحل رو به ترتیب دنبال می‌کنه قبل از اینکه بره سراغ یه کار دیگه، حتی اگه اون مراحل شامل انتظار باشن.
### هم‌زمانی و برگرها
این ایده **ناهم‌زمان** که بالا توضیح دادم گاهی بهش **"هم‌زمانی"** هم می‌گن. با **"موازی‌سازی"** فرق داره.
**هم‌زمانی** و **موازی‌سازی** هر دو به "اتفاق افتادن چیزای مختلف کم‌وبیش همزمان" ربط دارن.
ولی جزئیات بین *هم‌زمانی* و *موازی‌سازی* خیلی متفاوته.
برای دیدن فرقش، این داستان در مورد برگرها رو تصور کن:
### برگرهای هم‌زمان
با عشقت می‌ری فست‌فود بگیرین، توی صف وایمیستی در حالی که صندوقدار سفارش آدمای جلوی تو رو می‌گیره. 😍
<img src="/img/async/concurrent-burgers/concurrent-burgers-01.png" class="illustration">
بعد نوبت تو می‌شه، سفارش دو تا برگر خیلی شیک برای خودت و عشقت می‌دی. 🍔🍔
<img src="/img/async/concurrent-burgers/concurrent-burgers-02.png" class="illustration">
صندوقدار یه چیزی به آشپز توی آشپزخونه می‌گه تا بدونن باید برگرهای تو رو آماده کنن (گرچه الان دارن برگرهای مشتریای قبلی رو درست می‌کنن).
<img src="/img/async/concurrent-burgers/concurrent-burgers-03.png" class="illustration">
پول رو می‌دی. 💸
صندوقدار شماره نوبتت رو بهت می‌ده.
<img src="/img/async/concurrent-burgers/concurrent-burgers-04.png" class="illustration">
وقتی منتظری، با عشقت می‌ری یه میز انتخاب می‌کنی، می‌شینی و کلی با عشقت حرف می‌زنی (چون برگرهات خیلی شیکن و آماده کردنشون یه کم طول می‌کشه).
وقتی پشت میز با عشقت نشستی، در حالی که منتظر برگرهایی، می‌تونی اون زمان رو صرف تحسین این کنی که عشقت چقدر باحال، ناز و باهوشه ✨😍✨.
<img src="/img/async/concurrent-burgers/concurrent-burgers-05.png" class="illustration">
وقتی منتظری و با عشقت حرف می‌زنی، هر از گاهی شماره‌ای که رو پیشخون نشون داده می‌شه رو چک می‌کنی که ببینی نوبتت شده یا نه.
بعد یه جایی بالاخره نوبتت می‌شه. می‌ری پیشخون، برگرهات رو می‌گیری و برمی‌گردی سر میز.
<img src="/img/async/concurrent-burgers/concurrent-burgers-06.png" class="illustration">
تو و عشقت برگرها رو می‌خورین و یه وقت خوب باهم دارین. ✨
<img src="/img/async/concurrent-burgers/concurrent-burgers-07.png" class="illustration">
/// info
تصاویر قشنگ از <a href="https://www.instagram.com/ketrinadrawsalot" class="external-link" target="_blank">کترینا تامپسون</a>. 🎨
///
---
تصور کن تو توی این داستان کامپیوتر / برنامه 🤖 هستی.
وقتی توی صف هستی، فقط بیکاری 😴، منتظر نوبتت هستی، کار خیلی "مفیدی" نمی‌کنی. ولی صف سریع پیش می‌ره چون صندوقدار فقط سفارش می‌گیره (آمادشون نمی‌کنه)، پس این خوبه.
بعد، وقتی نوبتت می‌شه، کار "مفید" واقعی می‌کنی، منو رو پردازش می‌کنی، تصمیم می‌گیری چی می‌خوای، انتخاب عشقت رو می‌گیری، پول می‌دی، چک می‌کنی اسکناس یا کارت درست رو دادی، چک می‌کنی درست حساب شده، چک می‌کنی سفارش آیتمای درست رو داره و غیره.
ولی بعد، گرچه هنوز برگرهات رو نداری، کارت با صندوقدار "موقتاً متوقف" ⏸ می‌شه، چون باید منتظر بمونی 🕙 تا برگرهات آماده بشن.
ولی وقتی از پیشخون دور می‌شی و با شماره نوبتت سر میز می‌شینی، می‌تونی توجهت رو 🔀 به عشقت بدی و "کار" ⏯ 🤓 رو اون بکنی. بعدش دوباره داری یه چیز خیلی "مفید" انجام می‌دی، مثل لاس زدن با عشقت 😍.
بعد صندوقدار 💁 با گذاشتن شماره‌ات رو نمایشگر پیشخون می‌گه "من با درست کردن برگرها تموم کردم"، ولی تو مثل دیوونه‌ها وقتی شماره‌ات رو نمایشگر میاد فوری نمی‌پری. می‌دونی کسی برگرهات رو نمی‌دزده چون شماره نوبتت رو داری، و اونا هم مال خودشون رو دارن.
پس منتظر می‌مونی تا عشقت داستانش رو تموم کنه (کار فعلی ⏯ / وظیفه‌ای که داره پردازش می‌شه 🤓)، آروم لبخند می‌زنی و می‌گی که می‌ری برگرها رو بیاری ⏸.
بعد می‌ری پیشخون 🔀، به کار اولیه که حالا تموم شده ⏯، برگرها رو می‌گیری، تشکر می‌کنی و می‌برشون سر میز. این مرحله / وظیفه تعامل با پیشخون رو تموم می‌کنه ⏹. این به نوبه خودش یه وظیفه جدید، "خوردن برگرها" 🔀 ⏯، می‌سازه، ولی اون قبلی که "گرفتن برگرها" بود تموم شده ⏹.
### برگرهای موازی
حالا فرض کن اینا "برگرهای هم‌زمان" نیستن، بلکه "برگرهای موازی" هستن.
با عشقت می‌ری فست‌فود موازی بگیری.
توی صف وایمیستی در حالی که چند تا (مثلاً 8 تا) صندوقدار که همزمان آشپز هم هستن سفارش آدمای جلوی تو رو می‌گیرن.
همه قبل تو منتظرن برگرهاشون آماده بشه قبل از اینکه پیشخون رو ترک کنن، چون هر کدوم از 8 تا صندوقدار می‌ره و برگر رو همون موقع درست می‌کنه قبل از اینکه سفارش بعدی رو بگیره.
<img src="/img/async/parallel-burgers/parallel-burgers-01.png" class="illustration">
بالاخره نوبت تو می‌شه، سفارش دو تا برگر خیلی شیک برای خودت و عشقت می‌دی.
پول رو می‌دی 💸.
<img src="/img/async/parallel-burgers/parallel-burgers-02.png" class="illustration">
صندوقدار می‌ره آشپزخونه.
منتظر می‌مونی، جلوی پیشخون وایستادی 🕙، که کسی قبل از تو برگرهات رو نگیره، چون شماره نوبت نیست.
<img src="/img/async/parallel-burgers/parallel-burgers-03.png" class="illustration">
چون تو و عشقت مشغول این هستین که نذارین کسی جلوتون بیاد و هر وقت برگرها رسیدن اونا رو بگیره، نمی‌تونی به عشقت توجه کنی. 😞
این کار "هم‌زمان" هست، تو با صندوقدار/آشپز 👨‍🍳 "هم‌زمان" هستی. باید منتظر بمونی 🕙 و درست همون لحظه که صندوقدار/آشپز 👨‍🍳 برگرها رو تموم می‌کنه و بهت می‌ده اونجا باشی، وگرنه ممکنه یکی دیگه اونا رو بگیره.
<img src="/img/async/parallel-burgers/parallel-burgers-04.png" class="illustration">
بعد صندوقدار/آشپزت 👨‍🍳 بالاخره بعد از یه مدت طولانی انتظار 🕙 جلوی پیشخون با برگرهات برمی‌گرده.
<img src="/img/async/parallel-burgers/parallel-burgers-05.png" class="illustration">
برگرهات رو می‌گیری و با عشقت می‌ری سر میز.
فقط می‌خورینشون، و تمومه. ⏹
<img src="/img/async/parallel-burgers/parallel-burgers-06.png" class="illustration">
حرف زدن یا لاس زدن زیاد نبود چون بیشتر وقت صرف انتظار 🕙 جلوی پیشخون شد. 😞
/// info
تصاویر قشنگ از <a href="https://www.instagram.com/ketrinadrawsalot" class="external-link" target="_blank">کترینا تامپسون</a>. 🎨
///
---
توی این سناریوی برگرهای موازی، تو یه کامپیوتر / برنامه 🤖 با دو تا پردازنده (تو و عشقت) هستی، هر دو منتظر 🕙 و توجهشون ⏯ رو برای مدت طولانی "انتظار جلوی پیشخون" 🕙 گذاشتن.
فست‌فود 8 تا پردازنده (صندوقدار/آشپز) داره. در حالی که فست‌فود برگرهای هم‌زمان شاید فقط 2 تا داشته (یه صندوقدار و یه آشپز).
ولی با این حال، تجربه نهایی بهترین نیست. 😞
---
این معادل موازی داستان برگرها بود. 🍔
برای یه مثال "واقعی‌تر" از زندگی، یه بانک رو تصور کن.
تا همین چند وقت پیش، بیشتر بانک‌ها چند تا صندوقدار 👨‍💼👨‍💼👨‍💼👨‍💼 داشتن و یه صف بزرگ 🕙🕙🕙🕙🕙🕙🕙🕙.
همه صندوقدارها کار رو با یه مشتری بعد از اون یکی 👨‍💼⏯ انجام می‌دادن.
و باید توی صف 🕙 مدت زیادی منتظر بمونی وگرنه نوبتت رو از دست می‌دی.
احتمالاً نمی‌خوای عشقت 😍 رو با خودت ببری بانک 🏦 برای کارای روزمره.
### نتیجه‌گیری برگرها
توی این سناریوی "برگرهای فست‌فود با عشقت"، چون کلی انتظار 🕙 هست، خیلی منطقی‌تره که یه سیستم هم‌زمان ⏸🔀⏯ داشته باشی.
این برای بیشتر برنامه‌های وب هم صدق می‌کنه.
خیلی خیلی کاربر، ولی سرورت منتظر 🕙 اتصال نه‌چندان خوبشون هست تا درخواست‌هاشون رو بفرستن.
و بعد دوباره منتظر 🕙 که جواب‌ها برگردن.
این "انتظار" 🕙 توی میکروثانیه‌ها اندازه‌گیری می‌شه، ولی با این حال، جمعش که بکنی آخرش کلی انتظار می‌شه.
برای همین استفاده از کد ناهم‌زمان ⏸🔀⏯ برای APIهای وب خیلی منطقیه.
این نوع ناهم‌زمانی چیزیه که NodeJS رو محبوب کرد (گرچه NodeJS موازی نیست) و نقطه قوت Go به‌عنوان یه زبون برنامه‌نویسیه.
و همون سطح عملکردی هست که با **FastAPI** می‌گیری.
و چون می‌تونی هم‌زمانی و موازی‌سازی رو همزمان داشته باشی، عملکرد بالاتری از بیشتر فریم‌ورک‌های تست‌شده NodeJS می‌گیری و هم‌تراز با Go، که یه زبون کامپایل‌شده نزدیک به C هست <a href="https://www.techempower.com/benchmarks/#section=data-r17&hw=ph&test=query&l=zijmkf-1" class="external-link" target="_blank">(همه اینا به لطف Starlette)</a>.
### آیا هم‌زمانی از موازی‌سازی بهتره؟
نه! این نتیجه داستان نیست.
هم‌زمانی با موازی‌سازی فرق داره. و توی **سناریوهای خاص** که کلی انتظار دارن بهتره. به همین خاطر، معمولاً برای توسعه برنامه‌های وب خیلی از موازی‌سازی بهتره. ولی نه برای همه‌چیز.
برای اینکه یه تعادل بذاریم، این داستان کوتاه رو تصور کن:
> باید یه خونه بزرگ و کثیف رو تمیز کنی.
*آره، کل داستان همینه*.
---
هیچ انتظاری 🕙 اونجا نیست، فقط کلی کار برای انجام دادن توی جاهای مختلف خونه.
می‌تونی مثل مثال برگرها نوبت بذاری، اول پذیرایی، بعد آشپزخونه، ولی چون منتظر چیزی نیستی 🕙، فقط داری تمیز می‌کنی و تمیز می‌کنی، نوبت‌ها هیچ تأثیری نداره.
با نوبت یا بدون نوبت (هم‌زمانی) همون قدر طول می‌کشه تا تمومش کنی و همون مقدار کار رو کردی.
ولی توی این موقعیت، اگه بتونی اون 8 تا صندوقدار/آشپز/حالا-تمیزکار رو بیاری، و هر کدومشون (به‌علاوه خودت) یه قسمت از خونه رو تمیز کنن، می‌تونی همه کار رو **موازی** انجام بدی، با کمک اضافی، و خیلی زودتر تمومش کنی.
توی این سناریو، هر کدوم از تمیزکارها (از جمله خودت) یه پردازنده‌ست که کار خودش رو می‌کنه.
و چون بیشتر زمان اجرا صرف کار واقعی می‌شه (به جای انتظار)، و کار توی کامپیوتر با <abbr title="واحد پردازش مرکزی">CPU</abbr> انجام می‌شه، به این مشکلات می‌گن "CPU bound".
---
مثال‌های رایج عملیات CPU bound چیزایی هستن که نیاز به پردازش ریاضی پیچیده دارن.
مثلاً:
* پردازش **صدا** یا **تصویر**.
* **بینایی کامپیوتری**: یه تصویر از میلیون‌ها پیکسل تشکیل شده، هر پیکسل 3 تا مقدار / رنگ داره، پردازشش معمولاً نیاز داره چیزی رو رو اون پیکسل‌ها همزمان حساب کنی.
* **یادگیری ماشین**: معمولاً کلی ضرب "ماتریس" و "بردار" لازم داره. یه جدول بزرگ پر از عدد رو تصور کن که همه‌شون رو همزمان ضرب می‌کنی.
* **یادگیری عمیق**: این یه زیرشاخه از یادگیری ماشینه، پس همون قضیه صدق می‌کنه. فقط این که یه جدول عدد برای ضرب کردن نیست، بلکه یه مجموعه بزرگ از اونا هست، و توی خیلی موارد از یه پردازنده خاص برای ساخت و / یا استفاده از این مدل‌ها استفاده می‌کنی.
### هم‌زمانی + موازی‌سازی: وب + یادگیری ماشین
با **FastAPI** می‌تونی از هم‌زمانی که برای توسعه وب خیلی رایجه (همون جذابیت اصلی NodeJS) استفاده کنی.
ولی می‌تونی از فواید موازی‌سازی و چندپردازشی (اجرای چند پروسه به‌صورت موازی) برای کارای **CPU bound** مثل سیستم‌های یادگیری ماشین هم بهره ببری.
این، به‌علاوه این واقعیت ساده که پایتون زبون اصلی برای **علم داده**، یادگیری ماشین و به‌خصوص یادگیری عمیقه، باعث می‌شه FastAPI یه انتخاب خیلی خوب برای APIها و برنامه‌های وب علم داده / یادگیری ماشین باشه (بین خیلی چیزای دیگه).
برای دیدن اینکه چطور توی محیط واقعی به این موازی‌سازی برسی، بخش [استقرار](deployment/index.md){.internal-link target=_blank} رو ببین.
## `async` و `await`
نسخه‌های مدرن پایتون یه راه خیلی ساده و قابل‌فهم برای تعریف کد ناهم‌زمان دارن. این باعث می‌شه مثل کد "ترتیبی" معمولی به نظر بیاد و توی لحظه‌های درست "انتظار" رو برات انجام بده.
وقتی یه عملیاتی هست که قبل از دادن نتیجه‌ها نیاز به انتظار داره و از این قابلیت‌های جدید پایتون پشتیبانی می‌کنه، می‌تونی اینجوری کدنویسیش کنی:
```Python
burgers = await get_burgers(2)
```
نکته کلیدی اینجا `await` هست. به پایتون می‌گه که باید ⏸ منتظر بمونه تا `get_burgers(2)` کارش 🕙 تموم بشه قبل از اینکه نتیجه‌ها رو توی `burgers` ذخیره کنه. با این، پایتون می‌دونه که می‌تونه بره یه کار دیگه 🔀 ⏯ توی این مدت بکنه (مثل گرفتن یه درخواست دیگه).
برای اینکه `await` کار کنه، باید توی یه تابع باشه که از این ناهم‌زمانی پشتیبانی کنه. برای این کار، فقط با `async def` تعریفش می‌کنی:
```Python hl_lines="1"
async def get_burgers(number: int):
# یه سری کار ناهم‌زمان برای ساختن برگرها انجام بده
return burgers
```
...به جای `def`:
```Python hl_lines="2"
# این ناهم‌زمان نیست
def get_sequential_burgers(number: int):
# یه سری کار ترتیبی برای ساختن برگرها انجام بده
return burgers
```
با `async def`، پایتون می‌دونه که توی اون تابع باید حواسش به عبارت‌های `await` باشه، و می‌تونه اجرای اون تابع رو "موقتاً متوقف" ⏸ کنه و بره یه کار دیگه 🔀 قبل از برگشتن بکنه.
وقتی می‌خوای یه تابع `async def` رو صدا کنی، باید "منتظرش" بمونی. پس این کار نمی‌کنه:
```Python
# این کار نمی‌کنه، چون get_burgers با async def تعریف شده
burgers = get_burgers(2)
```
---
پس، اگه از یه کتابخونه استفاده می‌کنی که بهت می‌گه می‌تونی با `await` صداش کنی، باید *توابع عملیات مسیرت* که ازش استفاده می‌کنن رو با `async def` بسازی، مثل:
```Python hl_lines="2-3"
@app.get('/burgers')
async def read_burgers():
burgers = await get_burgers(2)
return burgers
```
### جزئیات فنی‌تر
شاید متوجه شده باشی که `await` فقط توی توابعی که با `async def` تعریف شدن می‌تونه استفاده بشه.
ولی در عین حال، توابعی که با `async def` تعریف شدن باید "منتظر"شون بمونی. پس توابع با `async def` فقط توی توابعی که با `async def` تعریف شدن می‌تونن صدا زده بشن.
حالا، قضیه مرغ و تخم‌مرغ چیه، چطور اولین تابع `async` رو صدا می‌کنی؟
اگه با **FastAPI** کار می‌کنی، لازم نیست نگران این باشی، چون اون "اولین" تابع، *تابع عملیات مسیرت* هست، و FastAPI می‌دونه چطور کار درست رو بکنه.
ولی اگه بخوای بدون FastAPI از `async` / `await` استفاده کنی، اینم ممکنه.
### کد ناهم‌زمان خودت رو بنویس
Starlette (و **FastAPI**) بر پایه <a href="https://anyio.readthedocs.io/en/stable/" class="external-link" target="_blank">AnyIO</a> هستن، که باعث می‌شه با کتابخونه استاندارد پایتون <a href="https://docs.python.org/3/library/asyncio-task.html" class="external-link" target="_blank">asyncio</a> و <a href="https://trio.readthedocs.io/en/stable/" class="external-link" target="_blank">Trio</a> سازگار باشه.
به‌خصوص، می‌تونی مستقیماً از <a href="https://anyio.readthedocs.io/en/stable/" class="external-link" target="_blank">AnyIO</a> برای موارد استفاده پیشرفته هم‌زمانی که نیاز به الگوهای پیچیده‌تر توی کد خودت دارن استفاده کنی.
و حتی اگه از FastAPI استفاده نکنی، می‌تونی برنامه‌های ناهم‌زمان خودت رو با <a href="https://anyio.readthedocs.io/en/stable/" class="external-link" target="_blank">AnyIO</a> بنویسی تا خیلی سازگار باشه و فوایدش رو بگیری (مثل *هم‌زمانی ساختاریافته*).
من یه کتابخونه دیگه روی AnyIO ساختم، یه لایه نازک روش، تا یه کم annotationهای نوع رو بهتر کنم و **تکمیل خودکار** بهتر، **خطاهای درون‌خطی** و غیره بگیرم. یه مقدمه و آموزش ساده هم داره که بهت کمک می‌کنه **بفهمی** و **کد ناهم‌زمان خودت رو بنویسی**: <a href="https://asyncer.tiangolo.com/" class="external-link" target="_blank">Asyncer</a>. اگه بخوای **کد ناهم‌زمان رو با کد معمولی** (بلاک‌کننده/هم‌زمان) ترکیب کنی خیلی به‌دردت می‌خوره.
### شکل‌های دیگه کد ناهم‌زمان
این سبک استفاده از `async` و `await` توی زبون نسبتاً جدیده.
ولی کار با کد ناهم‌زمان رو خیلی ساده‌تر می‌کنه.
همین سینتکس (یا تقریباً یکسان) اخیراً توی نسخه‌های مدرن جاوااسکریپت (توی مرورگر و NodeJS) هم اضافه شده.
ولی قبل از اون، مدیریت کد ناهم‌زمان خیلی پیچیده‌تر و سخت‌تر بود.
توی نسخه‌های قبلی پایتون، می‌تونستی از نخ‌ها یا <a href="https://www.gevent.org/" class="external-link" target="_blank">Gevent</a> استفاده کنی. ولی کد خیلی پیچیده‌تر می‌شه برای فهمیدن، دیباگ کردن و فکر کردن بهش.
توی نسخه‌های قبلی NodeJS / جاوااسکریپت مرورگر، از "کال‌بک‌ها" استفاده می‌کردی. که می‌رسید به <a href="http://callbackhell.com/" class="external-link" target="_blank">جهان کال‌بک‌ها</a>.
## کروتین‌ها
**کروتین** فقط یه اصطلاح خیلی شیک برای چیزیه که یه تابع `async def` برمی‌گردونه. پایتون می‌دونه که این یه چیزی مثل تابع هست، می‌تونه شروع بشه و یه جایی تموم بشه، ولی ممکنه داخلش هم موقف ⏸ بشه، هر وقت یه `await` توش باشه.
ولی همه این قابلیت استفاده از کد ناهم‌زمان با `async` و `await` خیلی وقتا خلاصه می‌شه به استفاده از "کروتین‌ها". این قابل مقایسه با ویژگی اصلی Go، یعنی "Goroutineها" هست.
## نتیجه‌گیری
بیاید همون جمله از بالا رو ببینیم:
> نسخه‌های مدرن پایتون از **"کد ناهم‌زمان"** با چیزی که بهش **"کروتین"** می‌گن پشتیبانی می‌کنن، با سینتکس **`async` و `await`**.
حالا باید بیشتر برات معنی بده. ✨
همه اینا چیزیه که به FastAPI (از طریق Starlette) قدرت می‌ده و باعث می‌شه عملکرد چشمگیری داشته باشه.
## جزئیات خیلی فنی
/// warning
احتمالاً می‌تونی اینو رد کنی.
اینا جزئیات خیلی فنی از نحوه کار **FastAPI** زیر پوسته‌ست.
اگه یه کم دانش فنی (کروتین‌ها، نخ‌ها، بلاک کردن و غیره) داری و کنجکاوی که FastAPI چطور `async def` رو در مقابل `def` معمولی مدیریت می‌کنه، ادامه بده.
///
### توابع عملیات مسیر
وقتی یه *تابع عملیات مسیر* رو با `def` معمولی به جای `async def` تعریف می‌کنی، توی یه استخر نخ خارجی اجرا می‌شه که بعدش منتظرش می‌مونن، به جای اینکه مستقیم صداش کنن (چون سرور رو بلاک می‌کنه).
اگه از یه فریم‌ورک ناهم‌زمان دیگه میای که به روش بالا کار نمی‌کنه و عادت داری *توابع عملیات مسیر* ساده فقط محاسباتی رو با `def` معمولی برای یه سود کوچیک عملکرد (حدود 100 نانوثانیه) تعریف کنی، توجه کن که توی **FastAPI** اثرش کاملاً برعکسه. توی این موارد، بهتره از `async def` استفاده کنی مگه اینکه *توابع عملیات مسیرت* کدی داشته باشن که عملیات <abbr title="ورودی/خروجی: خوندن یا نوشتن دیسک، ارتباطات شبکه">I/O</abbr> بلاک‌کننده انجام بده.
با این حال، توی هر دو موقعیت، احتمالش زیاده که **FastAPI** هنوز [سریع‌تر](index.md#performance){.internal-link target=_blank} از فریم‌ورک قبلی‌ات باشه (یا حداقل قابل مقایسه باهاش).
### وابستگی‌ها
همین برای [وابستگی‌ها](tutorial/dependencies/index.md){.internal-link target=_blank} هم صدق می‌کنه. اگه یه وابستگی یه تابع `def` معمولی به جای `async def` باشه، توی استخر نخ خارجی اجرا می‌شه.
### زیروابستگی‌ها
می‌تونی چند تا وابستگی و [زیروابستگی](tutorial/dependencies/sub-dependencies.md){.internal-link target=_blank} داشته باشی که همدیگه رو نیاز دارن (به‌عنوان پارامترهای تعریف تابع)، بعضی‌هاشون ممکنه با `async def` ساخته بشن و بعضی‌ها با `def` معمولی. بازم کار می‌کنه، و اونایی که با `def` معمولی ساخته شدن توی یه نخ خارجی (از استخر نخ) صدا زده می‌شن به جای اینکه "منتظرشون" بمونن.
### توابع کاربردی دیگه
هر تابع کاربردی دیگه‌ای که مستقیم خودت صداش می‌کنی می‌تونه با `def` معمولی یا `async def` ساخته بشه و FastAPI رو نحوه صدازدنش تأثیر نمی‌ذاره.
این برخلاف توابعی هست که FastAPI برات صداشون می‌کنه: *توابع عملیات مسیر* و وابستگی‌ها.
اگه تابع کاربردیت یه تابع معمولی با `def` باشه، مستقیم صداش می‌کنن (همون‌طور که توی کدت نوشتی)، نه توی استخر نخ، اگه تابع با `async def` ساخته شده باشه، باید وقتی توی کدت صداش می‌کنی `await`ش کنی.
---
دوباره، اینا جزئیات خیلی فنی هستن که احتمالاً اگه دنبالشون اومده باشی برات مفید باشن.
وگرنه، با راهنمایی‌های بخش بالا باید خوب باشی: <a href="#in-a-hurry">عجله داری؟</a>.

298
docs/fa/docs/environment-variables.md

@ -0,0 +1,298 @@
# متغیرهای محیطی
/// tip
اگه از قبل می‌دونی متغیرهای محیطی چی هستن و چطور ازشون استفاده می‌شه، می‌تونی این بخش رو رد کنی.
///
یه متغیر محیطی (که بهش "**env var**" هم می‌گن) یه متغیریه که **خارج** از کد پایتون، توی **سیستم‌عامل** زندگی می‌کنه و می‌تونه توسط کد پایتونت (یا برنامه‌های دیگه) خونده بشه.
متغیرهای محیطی می‌تونن برای مدیریت **تنظیمات** برنامه، به‌عنوان بخشی از **نصب** پایتون و غیره مفید باشن.
## ساخت و استفاده از متغیرهای محیطی
می‌تونی متغیرهای محیطی رو توی **شل (ترمینال)** **بسازی** و ازشون استفاده کنی، بدون اینکه به پایتون نیاز داشته باشی:
//// tab | لینوکس، مک‌اواس، ویندوز بش
<div class="termy">
```console
// می‌تونی یه متغیر محیطی به اسم MY_NAME بسازی با
$ export MY_NAME="Wade Wilson"
// بعد می‌تونی با برنامه‌های دیگه ازش استفاده کنی، مثل
$ echo "Hello $MY_NAME"
Hello Wade Wilson
```
</div>
////
//// tab | ویندوز پاورشل
<div class="termy">
```console
// یه متغیر محیطی به اسم MY_NAME بساز
$ $Env:MY_NAME = "Wade Wilson"
// با برنامه‌های دیگه ازش استفاده کن، مثل
$ echo "Hello $Env:MY_NAME"
Hello Wade Wilson
```
</div>
////
## خوندن متغیرهای محیطی توی پایتون
می‌تونی متغیرهای محیطی رو **خارج** از پایتون، توی ترمینال (یا با هر روش دیگه) بسازی، و بعد توی **پایتون** اونا رو بخونی.
مثلاً می‌تونی یه فایل `main.py` داشته باشی با:
```Python hl_lines="3"
import os
name = os.getenv("MY_NAME", "World")
print(f"Hello {name} from Python")
```
/// tip
آرگومان دوم <a href="https://docs.python.org/3.8/library/os.html#os.getenv" class="external-link" target="_blank">`os.getenv()`</a> مقدار پیش‌فرضیه که برمی‌گردونه.
اگه ندی، به‌صورت پیش‌فرض `None` هست، اینجا ما `"World"` رو به‌عنوان مقدار پیش‌فرض گذاشتیم.
///
بعد می‌تونی اون برنامه پایتون رو صدا کنی:
//// tab | لینوکس، مک‌اواس، ویندوز بش
<div class="termy">
```console
// اینجا هنوز متغیر محیطی رو تنظیم نکردیم
$ python main.py
// چون متغیر محیطی رو تنظیم نکردیم، مقدار پیش‌فرض رو می‌گیریم
Hello World from Python
// ولی اگه اول یه متغیر محیطی بسازیم
$ export MY_NAME="Wade Wilson"
// و بعد دوباره برنامه رو صدا کنیم
$ python main.py
// حالا می‌تونه متغیر محیطی رو بخونه
Hello Wade Wilson from Python
```
</div>
////
//// tab | ویندوز پاورشل
<div class="termy">
```console
// اینجا هنوز متغیر محیطی رو تنظیم نکردیم
$ python main.py
// چون متغیر محیطی رو تنظیم نکردیم، مقدار پیش‌فرض رو می‌گیریم
Hello World from Python
// ولی اگه اول یه متغیر محیطی بسازیم
$ $Env:MY_NAME = "Wade Wilson"
// و بعد دوباره برنامه رو صدا کنیم
$ python main.py
// حالا می‌تونه متغیر محیطی رو بخونه
Hello Wade Wilson from Python
```
</div>
////
چون متغیرهای محیطی می‌تونن خارج از کد تنظیم بشن، ولی کد می‌تونه اونا رو بخونه، و لازم نیست با بقیه فایل‌ها ذخیره (کمیتی به `git`) بشن، معمولاً برای پیکربندی یا **تنظیمات** استفاده می‌شن.
همچنین می‌تونی یه متغیر محیطی رو فقط برای **یه اجرای خاص برنامه** بسازی، که فقط برای اون برنامه و فقط برای مدت زمان اجراش در دسترسه.
برای این کار، درست قبل از خود برنامه، توی همون خط بسازش:
<div class="termy">
```console
// یه متغیر محیطی MY_NAME رو توی خط برای این اجرای برنامه بساز
$ MY_NAME="Wade Wilson" python main.py
// حالا می‌تونه متغیر محیطی رو بخونه
Hello Wade Wilson from Python
// متغیر محیطی بعدش دیگه وجود نداره
$ python main.py
Hello World from Python
```
</div>
/// tip
می‌تونی بیشتر در موردش توی <a href="https://12factor.net/config" class="external-link" target="_blank">برنامه دوازده‌فاکتوری: پیکربندی</a> بخونی.
///
## نوع‌ها و اعتبارسنجی
این متغیرهای محیطی فقط می‌تونن **رشته‌های متنی** رو نگه دارن، چون خارج از پایتون هستن و باید با برنامه‌های دیگه و بقیه سیستم (و حتی سیستم‌عامل‌های مختلف مثل لینوکس، ویندوز، مک‌اواس) سازگار باشن.
یعنی **هر مقداری** که توی پایتون از یه متغیر محیطی خونده می‌شه یه `str` هست، و هر تبدیل به نوع دیگه یا هر اعتبارسنجی باید توی کد انجام بشه.
توی [راهنمای کاربر پیشرفته - تنظیمات و متغیرهای محیطی](./advanced/settings.md){.internal-link target=_blank} بیشتر در مورد استفاده از متغیرهای محیطی برای مدیریت **تنظیمات برنامه** یاد می‌گیری.
## متغیر محیطی `PATH`
یه متغیر محیطی **خاص** به اسم **`PATH`** وجود داره که سیستم‌عامل‌ها (لینوکس، مک‌اواس، ویندوز) ازش برای پیدا کردن برنامه‌هایی که قراره اجرا بشن استفاده می‌کنن.
مقدار متغیر `PATH` یه رشته طولانی از پوشه‌هاست که توی لینوکس و مک‌اواس با دونقطه `:` و توی ویندوز با نقطه‌ویرگول `;` از هم جدا شدن.
مثلاً، متغیر محیطی `PATH` می‌تونه اینجوری باشه:
//// tab | لینوکس، مک‌اواس
```plaintext
/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
```
یعنی سیستم باید دنبال برنامه‌ها توی این پوشه‌ها بگرده:
* `/usr/local/bin`
* `/usr/bin`
* `/bin`
* `/usr/sbin`
* `/sbin`
////
//// tab | ویندوز
```plaintext
C:\Program Files\Python312\Scripts;C:\Program Files\Python312;C:\Windows\System32
```
یعنی سیستم باید دنبال برنامه‌ها توی این پوشه‌ها بگرده:
* `C:\Program Files\Python312\Scripts`
* `C:\Program Files\Python312`
* `C:\Windows\System32`
////
وقتی یه **دستور** توی ترمینال تایپ می‌کنی، سیستم‌عامل **دنبال** برنامه توی **هر کدوم از این پوشه‌ها** که توی متغیر محیطی `PATH` لیست شدن می‌گرده.
مثلاً، وقتی توی ترمینال `python` تایپ می‌کنی، سیستم‌عامل دنبال یه برنامه به اسم `python` توی **اولین پوشه** توی اون لیست می‌گرده.
اگه پیداش کنه، **استفاده‌ش می‌کنه**. وگرنه توی **پوشه‌های بعدی** دنبالش می‌گرده.
### نصب پایتون و به‌روزرسانی `PATH`
وقتی پایتون رو نصب می‌کنی، ممکنه ازت بپرسن آیا می‌خوای متغیر محیطی `PATH` رو به‌روزرسانی کنی.
//// tab | لینوکس، مک‌اواس
فرض کن پایتون رو نصب کردی و توی یه پوشه `/opt/custompython/bin` قرار گرفته.
اگه بگی بله برای به‌روزرسانی متغیر محیطی `PATH`، نصاب `/opt/custompython/bin` رو به متغیر محیطی `PATH` اضافه می‌کنه.
ممکنه اینجوری بشه:
```plaintext
/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/custompython/bin
```
این‌جوری، وقتی توی ترمینال `python` تایپ می‌کنی، سیستم برنامه پایتون رو توی `/opt/custompython/bin` (آخرین پوشه) پیدا می‌کنه و از اون استفاده می‌کنه.
////
//// tab | ویندوز
فرض کن پایتون رو نصب کردی و توی یه پوشه `C:\opt\custompython\bin` قرار گرفته.
اگه بگی بله برای به‌روزرسانی متغیر محیطی `PATH`، نصاب `C:\opt\custompython\bin` رو به متغیر محیطی `PATH` اضافه می‌کنه.
```plaintext
C:\Program Files\Python312\Scripts;C:\Program Files\Python312;C:\Windows\System32;C:\opt\custompython\bin
```
این‌جوری، وقتی توی ترمینال `python` تایپ می‌کنی، سیستم برنامه پایتون رو توی `C:\opt\custompython\bin` (آخرین پوشه) پیدا می‌کنه و از اون استفاده می‌کنه.
////
پس، اگه تایپ کنی:
<div class="termy">
```console
$ python
```
</div>
//// tab | لینوکس، مک‌اواس
سیستم برنامه `python` رو توی `/opt/custompython/bin` **پیدا** می‌کنه و اجراش می‌کنه.
تقریباً معادل اینه که تایپ کنی:
<div class="termy">
```console
$ /opt/custompython/bin/python
```
</div>
////
//// tab | ویندوز
سیستم برنامه `python` رو توی `C:\opt\custompython\bin\python` **پیدا** می‌کنه و اجراش می‌کنه.
تقریباً معادل اینه که تایپ کنی:
<div class="termy">
```console
$ C:\opt\custompython\bin\python
```
</div>
////
این اطلاعات وقتی در مورد [محیط‌های مجازی](virtual-environments.md){.internal-link target=_blank} یاد می‌گیری به‌دردت می‌خوره.
## نتیجه‌گیری
با این باید یه درک پایه‌ای از **متغیرهای محیطی** و نحوه استفاده‌شون توی پایتون داشته باشی.
می‌تونی بیشتر در موردشون توی <a href="https://en.wikipedia.org/wiki/Environment_variable" class="external-link" target="_blank">ویکی‌پدیا برای متغیر محیطی</a> بخونی.
توی خیلی موارد مشخص نیست که متغیرهای محیطی چطور می‌تونن فوری مفید و کاربردی باشن. ولی توی موقعیت‌های مختلف توسعه مدام پیداشون می‌شه، پس خوبه که در موردشون بدونی.
مثلاً، توی بخش بعدی در مورد [محیط‌های مجازی](virtual-environments.md) به این اطلاعات نیاز داری.

578
docs/fa/docs/python-types.md

@ -0,0 +1,578 @@
# مقدمه‌ای بر انواع نوع در پایتون
پایتون از "نوع‌نما"های اختیاری (که بهشون "type hints" یا "type annotations" هم می‌گن) پشتیبانی می‌کنه.
این **"نوع‌نماها"** یا annotationها یه سینتکس خاص هستن که بهت اجازه می‌دن <abbr title="مثلاً: str, int, float, bool">نوع</abbr> یه متغیر رو مشخص کنی.
با مشخص کردن نوع متغیرها، ویرایشگرها و ابزارها می‌تونن پشتیبانی بهتری بهت بدن.
این فقط یه **آموزش سریع / یادآوری** در مورد نوع‌نماهای پایتونه. فقط حداقل چیزایی که برای استفاده ازشون با **FastAPI** لازمه رو پوشش می‌ده... که در واقع خیلی کمه.
**FastAPI** کاملاً بر پایه این نوع‌نماهاست و این بهش کلی مزیت و فایده می‌ده.
ولی حتی اگه هیچ‌وقت از **FastAPI** استفاده نکنی، بازم یادگیری یه کم در موردشون به نفعته.
/// note
اگه حرفه‌ای پایتونی و همه‌چیز رو در مورد نوع‌نماها می‌دونی، برو سراغ فصل بعدی.
///
## انگیزه
بیاید با یه مثال ساده شروع کنیم:
{* ../../docs_src/python_types/tutorial001.py *}
وقتی این برنامه رو اجرا کنی، خروجی اینه:
```
John Doe
```
این تابع این کارا رو می‌کنه:
* یه `first_name` و `last_name` می‌گیره.
* حرف اول هر کدوم رو با `title()` بزرگ می‌کنه.
* <abbr title="اونا رو کنار هم می‌ذاره، یکی بعد از اون یکی.">ترکیبشون</abbr> می‌کنه با یه فاصله وسطشون.
{* ../../docs_src/python_types/tutorial001.py hl[2] *}
### ویرایشش کن
این یه برنامه خیلی ساده‌ست.
ولی حالا تصور کن داری از صفر می‌نویسیش.
یه جایی شروع کردی به تعریف تابع، پارامترهات آماده‌ست...
ولی بعد باید "اون متدی که حرف اول رو بزرگ می‌کنه" رو صدا کنی.
آیا اسمش `upper` بود؟ یا `uppercase`؟ شاید `first_uppercase`؟ یا `capitalize`؟
بعد، با دوست قدیمی برنامه‌نویسا، تکمیل خودکار ویرایشگر، امتحان می‌کنی.
پارامتر اول تابع، `first_name` رو تایپ می‌کنی، بعد یه نقطه (`.`) می‌ذاری و `Ctrl+Space` رو می‌زنی تا تکمیل خودکار بیاد.
ولی متأسفانه، چیز مفیدی نمی‌گیری:
<img src="/img/python-types/image01.png">
### نوع اضافه کن
بیا فقط یه خط از نسخه قبلی رو تغییر بدیم.
دقیقاً این بخش، پارامترهای تابع رو، از:
```Python
first_name, last_name
```
به:
```Python
first_name: str, last_name: str
```
عوض می‌کنیم.
همینه.
اینا همون "نوع‌نماها" هستن:
{* ../../docs_src/python_types/tutorial002.py hl[1] *}
این با تعریف مقدار پیش‌فرض فرق داره، مثل:
```Python
first_name="john", last_name="doe"
```
یه چیز متفاوته.
ما از دونقطه (`:`) استفاده می‌کنیم، نه علامت مساوی (`=`)‌.
و اضافه کردن نوع‌نماها معمولاً چیزی که اتفاق می‌افته رو از چیزی که بدون اونا می‌افتاد تغییر نمی‌ده.
ولی حالا، دوباره تصور کن وسط ساختن اون تابع هستی، ولی این بار با نوع‌نماها.
توی همون نقطه، سعی می‌کنی تکمیل خودکار رو با `Ctrl+Space` فعال کنی و اینو می‌بینی:
<img src="/img/python-types/image02.png">
با این، می‌تونی اسکرول کنی، گزینه‌ها رو ببینی، تا وقتی که اون چیزی که "به نظرت آشنا میاد" رو پیدا کنی:
<img src="/img/python-types/image03.png">
## انگیزه بیشتر
این تابع رو چک کن، الان نوع‌نما داره:
{* ../../docs_src/python_types/tutorial003.py hl[1] *}
چون ویرایشگر نوع متغیرها رو می‌دونه، فقط تکمیل خودکار نمی‌گیری، بلکه چک خطاها هم داری:
<img src="/img/python-types/image04.png">
حالا می‌دونی که باید درستش کنی، `age` رو با `str(age)` به یه رشته تبدیل کنی:
{* ../../docs_src/python_types/tutorial004.py hl[2] *}
## تعریف نوع‌ها
تازه اصلی‌ترین جا برای تعریف نوع‌نماها رو دیدی. به‌عنوان پارامترهای تابع.
این هم اصلی‌ترین جاییه که با **FastAPI** ازشون استفاده می‌کنی.
### نوع‌های ساده
می‌تونی همه نوع‌های استاندارد پایتون رو تعریف کنی، نه فقط `str`.
مثلاً می‌تونی از اینا استفاده کنی:
* `int`
* `float`
* `bool`
* `bytes`
{* ../../docs_src/python_types/tutorial005.py hl[1] *}
### نوع‌های عمومی با پارامترهای نوع
یه سری ساختار داده هستن که می‌تونن مقدارهای دیگه رو نگه دارن، مثل `dict`، `list`، `set` و `tuple`. و مقدارهای داخلیشون هم می‌تونن نوع خودشون رو داشته باشن.
به این نوع‌ها که نوع‌های داخلی دارن می‌گن "**عمومی**" یا "generic". و می‌شه اونا رو تعریف کرد، حتی با نوع‌های داخلیشون.
برای تعریف این نوع‌ها و نوع‌های داخلیشون، می‌تونی از ماژول استاندارد پایتون `typing` استفاده کنی. این ماژول مخصوص پشتیبانی از نوع‌نماهاست.
#### نسخه‌های جدیدتر پایتون
سینتکس با استفاده از `typing` با همه نسخه‌ها، از پایتون 3.6 تا جدیدترین‌ها، از جمله پایتون 3.9، 3.10 و غیره **سازگاره**.
با پیشرفت پایتون، **نسخه‌های جدیدتر** پشتیبانی بهتری برای این نوع‌نماها دارن و توی خیلی موارد حتی لازم نیست ماژول `typing` رو وارد کنی و ازش برای تعریف نوع‌نماها استفاده کنی.
اگه بتونی برای پروژه‌ات از یه نسخه جدیدتر پایتون استفاده کنی، می‌تونی از این سادگی اضافه بهره ببری.
توی همه مستندات، مثال‌هایی هستن که با هر نسخه پایتون سازگارن (وقتی تفاوتی هست).
مثلاً "**Python 3.6+**" یعنی با پایتون 3.6 یا بالاتر (مثل 3.7، 3.8، 3.9، 3.10 و غیره) سازگاره. و "**Python 3.9+**" یعنی با پایتون 3.9 یا بالاتر (مثل 3.10 و غیره) سازگاره.
اگه بتونی از **جدیدترین نسخه‌های پایتون** استفاده کنی، از مثال‌های نسخه آخر استفاده کن، چون اونا **بهترین و ساده‌ترین سینتکس** رو دارن، مثلاً "**Python 3.10+**".
#### لیست
مثلاً، بیایم یه متغیر تعریف کنیم که یه `list` از `str` باشه.
//// tab | Python 3.9+
متغیر رو با همون سینتکس دونقطه (`:`) تعریف کن.
به‌عنوان نوع، `list` رو بذار.
چون لیست یه نوعه که نوع‌های داخلی داره، اونا رو توی کروشه‌ها می‌ذاری:
```Python hl_lines="1"
{!> ../../docs_src/python_types/tutorial006_py39.py!}
```
////
//// tab | Python 3.8+
از `typing`، `List` رو (با `L` بزرگ) وارد کن:
```Python hl_lines="1"
{!> ../../docs_src/python_types/tutorial006.py!}
```
متغیر رو با همون سینتکس دونقطه (`:`) تعریف کن.
به‌عنوان نوع، `List` رو که از `typing` وارد کردی بذار.
چون لیست یه نوعه که نوع‌های داخلی داره، اونا رو توی کروشه‌ها می‌ذاری:
```Python hl_lines="4"
{!> ../../docs_src/python_types/tutorial006.py!}
```
////
/// info
اون نوع‌های داخلی توی کروشه‌ها بهشون "پارامترهای نوع" می‌گن.
توی این مورد، `str` پارامتر نوعیه که به `List` (یا `list` توی پایتون 3.9 و بالاتر) پاس داده شده.
///
یعنی: "متغیر `items` یه `list` هست، و هر کدوم از آیتم‌های این لیست یه `str` هستن".
/// tip
اگه از پایتون 3.9 یا بالاتر استفاده می‌کنی، لازم نیست `List` رو از `typing` وارد کنی، می‌تونی همون نوع معمولی `list` رو به جاش استفاده کنی.
///
با این کار، ویرایشگرت حتی وقتی داری آیتم‌های لیست رو پردازش می‌کنی بهت کمک می‌کنه:
<img src="/img/python-types/image05.png">
بدون نوع‌ها، رسیدن به این تقریباً غیرممکنه.
توجه کن که متغیر `item` یکی از عناصر توی لیست `items` هست.
و با این حال، ویرایشگر می‌دونه که یه `str` هست و براش پشتیبانی می‌ده.
#### تاپل و ست
برای تعریف `tuple`ها و `set`ها هم همین کار رو می‌کنی:
//// tab | Python 3.9+
```Python hl_lines="1"
{!> ../../docs_src/python_types/tutorial007_py39.py!}
```
////
//// tab | Python 3.8+
```Python hl_lines="1 4"
{!> ../../docs_src/python_types/tutorial007.py!}
```
////
یعنی:
* متغیر `items_t` یه `tuple` با 3 تا آیتمه، یه `int`، یه `int` دیگه، و یه `str`.
* متغیر `items_s` یه `set` هست، و هر کدوم از آیتم‌هاش از نوع `bytes` هستن.
#### دیکشنری
برای تعریف یه `dict`، 2 تا پارامتر نوع می‌دی، که با کاما از هم جدا شدن.
پارامتر نوع اول برای کلیدهای `dict` هست.
پارامتر نوع دوم برای مقدارهای `dict` هست:
//// tab | Python 3.9+
```Python hl_lines="1"
{!> ../../docs_src/python_types/tutorial008_py39.py!}
```
////
//// tab | Python 3.8+
```Python hl_lines="1 4"
{!> ../../docs_src/python_types/tutorial008.py!}
```
////
یعنی:
* متغیر `prices` یه `dict` هست:
* کلیدهای این `dict` از نوع `str` هستن (مثلاً اسم هر آیتم).
* مقدارهای این `dict` از نوع `float` هستن (مثلاً قیمت هر آیتم).
#### اتحادیه
می‌تونی تعریف کنی که یه متغیر می‌تونه هر کدوم از **چند تا نوع** باشه، مثلاً یه `int` یا یه `str`.
توی پایتون 3.6 و بالاتر (از جمله پایتون 3.10) می‌تونی از نوع `Union` توی `typing` استفاده کنی و نوع‌های ممکن رو توی کروشه‌ها بذاری.
توی پایتون 3.10 یه **سینتکس جدید** هم هست که می‌تونی نوع‌های ممکن رو با یه <abbr title="بهش 'عملگر بیتی یا' هم می‌گن، ولی اینجا معنی‌ش مهم نیست">خط عمودی (`|`)</abbr> جدا کنی.
//// tab | Python 3.10+
```Python hl_lines="1"
{!> ../../docs_src/python_types/tutorial008b_py310.py!}
```
////
//// tab | Python 3.8+
```Python hl_lines="1 4"
{!> ../../docs_src/python_types/tutorial008b.py!}
```
////
توی هر دو حالت یعنی `item` می‌تونه یه `int` یا یه `str` باشه.
#### شاید `None`
می‌تونی تعریف کنی که یه مقدار می‌تونه یه نوع باشه، مثلاً `str`، ولی می‌تونه `None` هم باشه.
توی پایتون 3.6 و بالاتر (از جمله پایتون 3.10) می‌تونی با وارد کردن و استفاده از `Optional` از ماژول `typing` اینو تعریف کنی.
```Python hl_lines="1 4"
{!../../docs_src/python_types/tutorial009.py!}
```
استفاده از `Optional[str]` به جای فقط `str` به ویرایشگر کمک می‌کنه خطاهایی که ممکنه فکر کنی یه مقدار همیشه `str` هست رو پیدا کنه، در حالی که می‌تونه `None` هم باشه.
`Optional[Something]` در واقع میان‌بر برای `Union[Something, None]` هست، این دو تا معادلن.
یعنی توی پایتون 3.10، می‌تونی از `Something | None` استفاده کنی:
//// tab | Python 3.10+
```Python hl_lines="1"
{!> ../../docs_src/python_types/tutorial009_py310.py!}
```
////
//// tab | Python 3.8+
```Python hl_lines="1 4"
{!> ../../docs_src/python_types/tutorial009.py!}
```
////
//// tab | Python 3.8+ جایگزین
```Python hl_lines="1 4"
{!> ../../docs_src/python_types/tutorial009b.py!}
```
////
#### استفاده از `Union` یا `Optional`
اگه از نسخه پایتون زیر 3.10 استفاده می‌کنی، یه نکته از دید خیلی **شخصی** خودم:
* 🚨 از `Optional[SomeType]` استفاده نکن
* به جاش ✨ **از `Union[SomeType, None]` استفاده کن** ✨.
هر دو معادلن و زیر پوسته یکی‌ان، ولی من `Union` رو به `Optional` ترجیح می‌دم چون کلمه "**اختیاری**" انگار暗示 می‌کنه که مقدار اختیاریه، در حالی که در واقع یعنی "می‌تونه `None` باشه"، حتی اگه اختیاری نباشه و هنوز لازم باشه.
فکر می‌کنم `Union[SomeType, None]` واضح‌تر نشون می‌ده چی معنی می‌ده.
فقط بحث کلمات و اسم‌هاست. ولی این کلمات می‌تونن رو طرز فکر تو و تیمت نسبت به کد تأثیر بذارن.
به‌عنوان مثال، این تابع رو ببین:
{* ../../docs_src/python_types/tutorial009c.py hl[1,4] *}
پارامتر `name` به‌عنوان `Optional[str]` تعریف شده، ولی **اختیاری نیست**، نمی‌تونی تابع رو بدون پارامتر صدا کنی:
```Python
say_hi() # اوه نه، این خطا می‌ده! 😱
```
پارامتر `name` **هنوز لازمه** (نه *اختیاری*) چون مقدار پیش‌فرض نداره. با این حال، `name` مقدار `None` رو قبول می‌کنه:
```Python
say_hi(name=None) # این کار می‌کنه، None معتبره 🎉
```
خبر خوب اینه که وقتی رو پایتون 3.10 باشی، لازم نیست نگران این باشی، چون می‌تونی به‌سادگی از `|` برای تعریف اتحادیه نوع‌ها استفاده کنی:
{* ../../docs_src/python_types/tutorial009c_py310.py hl[1,4] *}
اون موقع دیگه لازم نیست نگران اسم‌هایی مثل `Optional` و `Union` باشی. 😎
#### نوع‌های عمومی
این نوع‌هایی که پارامترهای نوع رو توی کروشه‌ها می‌گیرن بهشون **نوع‌های عمومی** یا **Generics** می‌گن، مثلاً:
//// tab | Python 3.10+
می‌تونی از همون نوع‌های داخلی به‌عنوان نوع‌های عمومی استفاده کنی (با کروشه‌ها و نوع‌ها داخلشون):
* `list`
* `tuple`
* `set`
* `dict`
و همون‌طور که توی پایتون 3.8 بود، از ماژول `typing`:
* `Union`
* `Optional` (همون‌طور که توی پایتون 3.8 بود)
* ...و بقیه.
توی پایتون 3.10، به‌عنوان جایگزین برای استفاده از نوع‌های عمومی `Union` و `Optional`، می‌تونی از <abbr title="بهش 'عملگر بیتی یا' هم می‌گن، ولی اینجا معنی‌ش مهم نیست">خط عمودی (`|`)</abbr> برای تعریف اتحادیه نوع‌ها استفاده کنی، که خیلی بهتر و ساده‌تره.
////
//// tab | Python 3.9+
می‌تونی از همون نوع‌های داخلی به‌عنوان نوع‌های عمومی استفاده کنی (با کروشه‌ها و نوع‌ها داخلشون):
* `list`
* `tuple`
* `set`
* `dict`
و همون‌طور که توی پایتون 3.8 بود، از ماژول `typing`:
* `Union`
* `Optional`
* ...و بقیه.
////
//// tab | Python 3.8+
* `List`
* `Tuple`
* `Set`
* `Dict`
* `Union`
* `Optional`
* ...و بقیه.
////
### کلاس‌ها به‌عنوان نوع
می‌تونی یه کلاس رو هم به‌عنوان نوع یه متغیر تعریف کنی.
فرض کن یه کلاس `Person` داری، با یه نام:
{* ../../docs_src/python_types/tutorial010.py hl[1:3] *}
بعد می‌تونی یه متغیر رو از نوع `Person` تعریف کنی:
{* ../../docs_src/python_types/tutorial010.py hl[6] *}
و بعد، دوباره، همه پشتیبانی ویرایشگر رو داری:
<img src="/img/python-types/image06.png">
توجه کن که این یعنی "`one_person` یه **نمونه** از کلاس `Person` هست".
یعنی "`one_person` خود **کلاس** به اسم `Person` نیست".
## مدل‌های Pydantic
<a href="https://docs.pydantic.dev/" class="external-link" target="_blank">Pydantic</a> یه کتابخونه پایتونه برای اعتبارسنجی داده‌ها.
"شکل" داده‌ها رو به‌عنوان کلاس‌هایی با ویژگی‌ها تعریف می‌کنی.
و هر ویژگی یه نوع داره.
بعد یه نمونه از اون کلاس رو با یه سری مقدار می‌سازی و اون مقدارها رو اعتبارسنجی می‌کنه، به نوع مناسب تبدیلشون می‌کنه (اگه لازم باشه) و یه شیء با همه داده‌ها بهت می‌ده.
و با اون شیء نهایی همه پشتیبانی ویرایشگر رو می‌گیری.
یه مثال از مستندات رسمی Pydantic:
//// tab | Python 3.10+
```Python
{!> ../../docs_src/python_types/tutorial011_py310.py!}
```
////
//// tab | Python 3.9+
```Python
{!> ../../docs_src/python_types/tutorial011_py39.py!}
```
////
//// tab | Python 3.8+
```Python
{!> ../../docs_src/python_types/tutorial011.py!}
```
////
/// info
برای اطلاعات بیشتر در مورد <a href="https://docs.pydantic.dev/" class="external-link" target="_blank">Pydantic، مستنداتش رو چک کن</a>.
///
**FastAPI** کاملاً بر پایه Pydantic هست.
توی [آموزش - راهنمای کاربر](tutorial/index.md){.internal-link target=_blank} خیلی بیشتر از اینا رو توی عمل می‌بینی.
/// tip
Pydantic یه رفتار خاص داره وقتی از `Optional` یا `Union[Something, None]` بدون مقدار پیش‌فرض استفاده می‌کنی، می‌تونی توی مستندات Pydantic در مورد <a href="https://docs.pydantic.dev/2.3/usage/models/#required-fields" class="external-link" target="_blank">فیلدهای اختیاری لازم</a> بیشتر بخونی.
///
## نوع‌نماها با Annotationهای متادیتا
پایتون یه قابلیت هم داره که بهت اجازه می‌ده **<abbr title="داده در مورد داده، اینجا یعنی اطلاعات در مورد نوع، مثلاً یه توضیح">متادیتا</abbr> اضافی** رو توی این نوع‌نماها بذاری با استفاده از `Annotated`.
//// tab | Python 3.9+
توی پایتون 3.9، `Annotated` بخشی از کتابخونه استاندارده، پس می‌تونی از `typing` واردش کنی.
```Python hl_lines="1 4"
{!> ../../docs_src/python_types/tutorial013_py39.py!}
```
////
//// tab | Python 3.8+
توی نسخه‌های زیر پایتون 3.9، `Annotated` رو از `typing_extensions` وارد می‌کنی.
با **FastAPI** از قبل نصب شده.
```Python hl_lines="1 4"
{!> ../../docs_src/python_types/tutorial013.py!}
```
////
خود پایتون با این `Annotated` کاری نمی‌کنه. و برای ویرایشگرها و ابزارهای دیگه، نوع هنوز `str` هست.
ولی می‌تونی از این فضا توی `Annotated` استفاده کنی تا به **FastAPI** متادیتای اضافی در مورد اینکه چطور می‌خوای برنامه‌ات رفتار کنه بدی.
نکته مهم اینه که **اولین *پارامتر نوع*** که به `Annotated` می‌دی، **نوع واقعی** هست. بقیش فقط متادیتا برای ابزارهای دیگه‌ست.
الان فقط باید بدونی که `Annotated` وجود داره، و اینکه پایتون استاندارده. 😎
بعداً می‌بینی که چقدر **قوی** می‌تونه باشه.
/// tip
اینکه این **پایتون استاندارده** یعنی هنوز **بهترین تجربه توسعه‌دهنده** رو توی ویرایشگرت، با ابزارهایی که برای تحلیل و بازسازی کدت استفاده می‌کنی و غیره می‌گیری. ✨
و همین‌طور کدت با خیلی از ابزارها و کتابخونه‌های دیگه پایتون خیلی سازگار می‌مونه. 🚀
///
## نوع‌نماها توی **FastAPI**
**FastAPI** از این نوع‌نماها استفاده می‌کنه تا چند تا کار بکنه.
با **FastAPI** پارامترها رو با نوع‌نماها تعریف می‌کنی و اینا رو می‌گیری:
* **پشتیبانی ویرایشگر**.
* **چک نوع‌ها**.
...و **FastAPI** از همون تعریف‌ها برای اینا استفاده می‌کنه:
* **تعریف نیازها**: از پارامترهای مسیر درخواست، پارامترهای کوئری، هدرها، بدنه‌ها، وابستگی‌ها و غیره.
* **تبدیل داده**: از درخواست به نوع مورد نیاز.
* **اعتبارسنجی داده**: که از هر درخواست میاد:
* تولید **خطاهای خودکار** که به کلاینت برمی‌گرده وقتی داده نامعتبره.
* **مستندسازی** API با استفاده از OpenAPI:
* که بعدش توسط رابط‌های کاربری مستندات تعاملی خودکار استفاده می‌شه.
اینا شاید همه‌ش انتزاعی به نظر بیاد. نگران نباش. همه اینا رو توی عمل توی [آموزش - راهنمای کاربر](tutorial/index.md){.internal-link target=_blank} می‌بینی.
نکته مهم اینه که با استفاده از نوع‌های استاندارد پایتون، توی یه جا (به جای اضافه کردن کلاس‌های بیشتر، دکوراتورها و غیره)، **FastAPI** کلی از کار رو برات انجام می‌ده.
/// info
اگه همه آموزش رو گذروندی و برگشتی که بیشتر در مورد نوع‌ها ببینی، یه منبع خوب <a href="https://mypy.readthedocs.io/en/latest/cheat_sheet_py3.html" class="external-link" target="_blank">"تقلب‌نامه" از `mypy`</a> هست.
///

12
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] *}
関数パラメータは以下の様に認識されます:

207
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 <abbr title="Entrada e Saída">I/O</abbr> 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 <abbr title="Entrada e Saída">I/O</abbr> 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 <abbr title="Entrada e Saída">I/O</abbr>, 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 <abbr title="Entrada e Saída">I/O</abbr>, 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 <a href="https://www.techempower.com/benchmarks/#section=data-r17&hw=ph&test=query&l=zijmkf-1" class="external-link" target="_blank">(tudo graças ao Starlette)</a>.
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 <a href="https://www.techempower.com/benchmarks/#section=data-r17&hw=ph&test=query&l=zijmkf-1" class="external-link" target="_blank">(tudo graças ao Starlette)</a>.
### 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 <abbr title="Unidade de Processamento Central">CPU</abbr>, 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 <abbr title="Unidade de Processamento Central">CPU</abbr>. 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, <a href="https://docs.python.org/3/library/asyncio-task.html#coroutine" class="external-link" target="_blank">verifique a documentação oficial Python</a>.
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 <a href="https://anyio.readthedocs.io/en/stable/" class="external-link" target="_blank">AnyIO</a>, o que o torna compatível com ambos o <a href="https://docs.python.org/3/library/asyncio-task.html" class="external-link" target="_blank">asyncio</a> da biblioteca padrão do Python, e o <a href="https://trio.readthedocs.io/en/stable/" class="external-link" target="_blank">Trio</a>.
Em particular, você pode usar diretamente o <a href="https://anyio.readthedocs.io/en/stable/" class="external-link" target="_blank">AnyIO</a> 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 <a href="https://anyio.readthedocs.io/en/stable/" class="external-link" target="_blank">AnyIO</a> 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**: <a href="https://asyncer.tiangolo.com/" class="external-link" target="_blank">Asyncer</a>. 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 <a href="http://www.gevent.org/" class="external-link" target="_blank">Gevent</a>. 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 <a href="http://www.gevent.org/" class="external-link" target="_blank">Gevent</a>. 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 <a href="http://callbackhell.com/" class="external-link" target="_blank">inferno do callback</a>.
Nas versões anteriores do NodeJS / Navegador JavaScript, você utilizaria "callbacks". O que leva ao <a href="http://callbackhell.com/" class="external-link" target="_blank">inferno do callback</a>.
## 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 <abbr title="Input/Output: disco lendo ou escrevendo, comunicações de rede.">IO</abbr>.
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 <abbr title="Input/Output: disco lendo ou escrevendo, comunicações de rede.">IO</abbr>.
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: <a href="#in-a-hurry">Com pressa?</a>.

112
docs/pt/docs/project-generation.md

@ -1,84 +1,28 @@
# Geração de Projetos - Modelo
Você pode usar um gerador de projetos para começar, por já incluir configurações iniciais, segurança, banco de dados e os primeiros _endpoints_ API já feitos para você.
Um gerador de projetos sempre terá uma pré-configuração que você pode atualizar e adaptar para suas próprias necessidades, mas pode ser um bom ponto de partida para seu projeto.
## Full Stack FastAPI PostgreSQL
GitHub: <a href="https://github.com/tiangolo/full-stack-fastapi-postgresql" class="external-link" target="_blank">https://github.com/tiangolo/full-stack-fastapi-postgresql</a>
### Full Stack FastAPI PostgreSQL - Recursos
* Integração completa **Docker**.
* Modo de implantação Docker Swarm.
* Integração e otimização **Docker Compose** para desenvolvimento local.
* **Pronto para Produção** com servidor _web_ usando Uvicorn e Gunicorn.
* _Backend_ <a href="https://github.com/fastapi/fastapi" class="external-link" target="_blank">**FastAPI**</a> Python:
* **Rápido**: Alta performance, no nível de **NodeJS** e **Go** (graças ao Starlette e Pydantic).
* **Intuitivo**: Ótimo suporte de editor. <abbr title="também conhecido como auto-complete, auto completação, IntelliSense">_Auto-Complete_</abbr> em todo lugar. Menos tempo _debugando_.
* **Fácil**: Projetado para ser fácil de usar e aprender. Menos tempo lendo documentações.
* **Curto**: Minimize duplicação de código. Múltiplos recursos para cada declaração de parâmetro.
* **Robusto**: Tenha código pronto para produção. Com documentação interativa automática.
* **Baseado em Padrões**: Baseado em (e completamente compatível com) padrões abertos para APIs: <a href="https://github.com/OAI/OpenAPI-Specification" class="external-link" target="_blank">OpenAPI</a> e <a href="http://json-schema.org/" class="external-link" target="_blank">JSON Schema</a>.
* <a href="https://fastapi.tiangolo.com/features/" class="external-link" target="_blank">**Muitos outros recursos**</a> incluindo validação automática, serialização, documentação interativa, autenticação com _tokens_ OAuth2 JWT etc.
* **Senha segura** _hashing_ por padrão.
* Autenticação **Token JWT**.
* Modelos **SQLAlchemy** (independente de extensões Flask, para que eles possam ser usados com _workers_ Celery diretamente).
* Modelos básicos para usuários (modifique e remova conforme suas necessidades).
* Migrações **Alembic**.
* **CORS** (_Cross Origin Resource Sharing_ - Compartilhamento de Recursos Entre Origens).
* _Worker_ **Celery** que pode importar e usar modelos e códigos do resto do _backend_ seletivamente.
* Testes _backend_ _REST_ baseados no **Pytest**, integrados com Docker, então você pode testar a interação completa da API, independente do banco de dados. Como roda no Docker, ele pode construir um novo repositório de dados do zero toda vez (assim você pode usar ElasticSearch, MongoDB, CouchDB, ou o que quiser, e apenas testar que a API esteja funcionando).
* Fácil integração com Python através dos **Kernels Jupyter** para desenvolvimento remoto ou no Docker com extensões como Atom Hydrogen ou Visual Studio Code Jupyter.
* _Frontend_ **Vue**:
* Gerado com Vue CLI.
* Controle de **Autenticação JWT**.
* Visualização de _login_.
* Após o _login_, visualização do painel de controle principal.
* Painel de controle principal com criação e edição de usuário.
* Edição do próprio usuário.
* **Vuex**.
* **Vue-router**.
* **Vuetify** para belos componentes _material design_.
* **TypeScript**.
* Servidor Docker baseado em **Nginx** (configurado para rodar "lindamente" com Vue-router).
* Construção multi-estágio Docker, então você não precisa salvar ou _commitar_ código compilado.
* Testes _frontend_ rodados na hora da construção (pode ser desabilitado também).
* Feito tão modular quanto possível, então ele funciona fora da caixa, mas você pode gerar novamente com Vue CLI ou criar conforme você queira, e reutilizar o que quiser.
* **PGAdmin** para banco de dados PostgreSQL, você pode modificar para usar PHPMyAdmin e MySQL facilmente.
* **Flower** para monitoração de tarefas Celery.
* Balanceamento de carga entre _frontend_ e _backend_ com **Traefik**, então você pode ter ambos sob o mesmo domínio, separados por rota, mas servidos por diferentes containers.
* Integração Traefik, incluindo geração automática de certificados **HTTPS** Let's Encrypt.
* GitLab **CI** (integração contínua), incluindo testes _frontend_ e _backend_.
## Full Stack FastAPI Couchbase
GitHub: <a href="https://github.com/tiangolo/full-stack-fastapi-couchbase" class="external-link" target="_blank">https://github.com/tiangolo/full-stack-fastapi-couchbase</a>
⚠️ **WARNING** ⚠️
Se você está iniciando um novo projeto do zero, verifique as alternativas aqui.
Por exemplo, o gerador de projetos <a href="https://github.com/tiangolo/full-stack-fastapi-postgresql" class="external-link" target="_blank">Full Stack FastAPI PostgreSQL</a> pode ser uma alternativa melhor, como ele é ativamente mantido e utilizado. E ele inclui todos os novos recursos e melhorias.
Você ainda é livre para utilizar o gerador baseado em Couchbase se quiser, ele provavelmente ainda funciona bem, e você já tem um projeto gerado com ele que roda bem também (e você provavelmente já atualizou ele para encaixar nas suas necessidades).
Você pode ler mais sobre nas documentaçãoes do repositório.
## Full Stack FastAPI MongoDB
...pode demorar, dependendo do meu tempo disponível e outros fatores. 😅 🎉
## Modelos de Aprendizado de Máquina com spaCy e FastAPI
GitHub: <a href="https://github.com/microsoft/cookiecutter-spacy-fastapi" class="external-link" target="_blank">https://github.com/microsoft/cookiecutter-spacy-fastapi</a>
### Modelos de Aprendizado de Máquina com spaCy e FastAPI - Recursos
* Integração com modelo NER **spaCy**.
* Formato de requisição **Busca Cognitiva Azure** acoplado.
* Servidor Python _web_ **Pronto para Produção** usando Uvicorn e Gunicorn.
* Implantação **Azure DevOps** Kubernetes (AKS) CI/CD acoplada.
* **Multilingual** facilmente escolhido como uma das linguagens spaCy acopladas durante a configuração do projeto.
* **Facilmente extensível** para outros modelos de _frameworks_ (Pytorch, Tensorflow), não apenas spaCy.
# Full Stack FastAPI Template
_Templates_, embora tipicamente venham com alguma configuração específica, são desenhados para serem flexíveis e customizáveis. Isso permite que você os modifique e adapte para as especificações do seu projeto, fazendo-os um excelente ponto de partida. 🏁
Você pode usar esse _template_ para começar, já que ele inclui várias configurações iniciais, segurança, banco de dados, e alguns _endpoints_ de API já feitos para você.
Repositório GitHub: <a href="https://github.com/tiangolo/full-stack-fastapi-template" class="external-link" target="_blank">Full Stack FastAPI Template</a>
## Full Stack FastAPI Template - Pilha de Tecnologias e Recursos
- ⚡ [**FastAPI**](https://fastapi.tiangolo.com) para a API do backend em Python.
- 🧰 [SQLModel](https://sqlmodel.tiangolo.com) para as interações do Python com bancos de dados SQL (ORM).
- 🔍 [Pydantic](https://docs.pydantic.dev), usado pelo FastAPI, para validação de dados e gerenciamento de configurações.
- 💾 [PostgreSQL](https://www.postgresql.org) como banco de dados SQL.
- 🚀 [React](https://react.dev) para o frontend.
- 💃 Usando TypeScript, hooks, [Vite](https://vitejs.dev), e outras partes de uma _stack_ frontend moderna.
- 🎨 [Chakra UI](https://chakra-ui.com) para os componentes de frontend.
- 🤖 Um cliente frontend automaticamente gerado.
- 🧪 [Playwright](https://playwright.dev) para testes Ponta-a-Ponta.
- 🦇 Suporte para modo escuro.
- 🐋 [Docker Compose](https://www.docker.com) para desenvolvimento e produção.
- 🔒 _Hash_ seguro de senhas por padrão.
- 🔑 Autenticação por token JWT.
- 📫 Recuperação de senhas baseada em email.
- ✅ Testes com [Pytest](https://pytest.org).
- 📞 [Traefik](https://traefik.io) como proxy reverso / balanceador de carga.
- 🚢 Instruções de _deployment_ usando Docker Compose, incluindo como configurar um proxy frontend com Traefik para gerenciar automaticamente certificados HTTPS.
- 🏭 CI (Integração Contínua) e CD (_Deploy_ Contínuo) baseado em GitHub Actions.

2
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

2
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

1
requirements-translations.txt

@ -1 +1,2 @@
pydantic-ai==0.0.30
GitPython==3.1.45

258
scripts/translate.py

@ -1,10 +1,15 @@
import secrets
import subprocess
from functools import lru_cache
from pathlib import Path
from typing import Iterable
from typing import Annotated, Iterable
import git
import typer
import yaml
from github import Github
from pydantic_ai import Agent
from rich import print
non_translated_sections = (
"reference/",
@ -21,6 +26,8 @@ non_translated_sections = (
general_prompt = """
For technical terms in English that don't have a common translation term use the original term in English.
If you have instructions to translate specific terms or phrases in a specific way, please follow those instructions instead of keeping the old and outdated content.
For code snippets or fragments, surrounded by backticks (`), don't translate the content, keep the original in English. For example, `list`, `dict`, keep them as is.
The content is written in markdown, write the translation in markdown as well. Don't add triple backticks (`) around the generated translation content.
@ -28,8 +35,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,56 +83,81 @@ def generate_lang_path(*, lang: str, path: Path) -> Path:
return out_path
def translate_page(*, lang: str, path: Path) -> None:
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(
*,
language: Annotated[str, typer.Option(envvar="LANGUAGE")],
en_path: Annotated[Path, typer.Option(envvar="EN_PATH")],
) -> None:
langs = get_langs()
language = langs[lang]
lang_path = Path(f"docs/{lang}")
language_name = langs[language]
lang_path = Path(f"docs/{language}")
lang_path.mkdir(exist_ok=True)
lang_prompt_path = lang_path / "llm-prompt.md"
assert lang_prompt_path.exists(), f"Prompt file not found: {lang_prompt_path}"
lang_prompt_content = lang_prompt_path.read_text()
en_docs_path = Path("docs/en/docs")
assert str(path).startswith(str(en_docs_path)), (
assert str(en_path).startswith(str(en_docs_path)), (
f"Path must be inside {en_docs_path}"
)
out_path = generate_lang_path(lang=lang, path=path)
out_path = generate_lang_path(lang=language, path=en_path)
out_path.parent.mkdir(parents=True, exist_ok=True)
original_content = path.read_text()
original_content = en_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 {en_path} to {language} ({language_name})")
agent = Agent("openai:gpt-4o")
prompt_segments = [
lang_prompt_content,
general_prompt,
lang_prompt_content,
]
if old_translation:
prompt_segments.extend(
[
"There's an existing previous translation for this content that is probably outdated with old content or old instructions.",
"Update the translation given your current instructions and the original content.",
"If you have instructions to translate specific terms or phrases in a specific way, please follow those instructions instead of keeping the old and outdated content.",
"Update the translation only where necessary:",
"- If the original English content has changed, reflect that in the translation.",
"- If the previous translation violates current instructions, update it.",
"- Otherwise, preserve the original translation **line-by-line** as-is.",
"Do not:",
"- Rephrase or rewrite correct lines just to improve the style.",
"- Add or remove line breaks unless the English source changed.",
"- Change formatting or whitespace unless absolutely required.",
"Only change what must be changed. The goal is to minimize diffs for easier review.",
"Previous translation:",
f"%%%\n{old_translation}%%%",
]
)
prompt_segments.extend(
[
f"Translate to {language} ({lang}).",
f"Translate to {language} ({language_name}).",
"Original content:",
f"%%%\n{original_content}%%%",
]
)
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 +181,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_lang(language: Annotated[str, typer.Option(envvar="LANGUAGE")]) -> None:
paths_to_process = list(iter_en_paths_to_translate())
print("Original paths:")
for p in paths_to_process:
print(f" - {p}")
@ -132,7 +198,7 @@ def translate_all(lang: str) -> None:
missing_paths: list[Path] = []
skipped_paths: list[Path] = []
for p in paths_to_process:
lang_path = generate_lang_path(lang=lang, path=p)
lang_path = generate_lang_path(lang=language, path=p)
if lang_path.exists():
skipped_paths.append(p)
continue
@ -147,16 +213,158 @@ def translate_all(lang: str) -> None:
print(f"Total paths to process: {len(missing_paths)}")
for p in missing_paths:
print(f"Translating: {p}")
translate_page(lang="es", path=p)
translate_page(language="es", en_path=p)
print(f"Done translating: {p}")
def main(*, lang: str, path: Path = None) -> None:
if path:
translate_page(lang=lang, path=path)
else:
translate_all(lang=lang)
@app.command()
def list_removable(language: str) -> list[Path]:
removable_paths: list[Path] = []
lang_paths = Path(f"docs/{language}").rglob("*.md")
for path in lang_paths:
en_path = generate_en_path(lang=language, 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(language: str) -> None:
removable_paths = list_removable(language)
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_missing(language: str) -> list[Path]:
missing_paths: list[Path] = []
en_lang_paths = list(iter_en_paths_to_translate())
for path in en_lang_paths:
lang_path = generate_lang_path(lang=language, path=path)
if not lang_path.exists():
missing_paths.append(path)
print(missing_paths)
return missing_paths
@app.command()
def list_outdated(language: 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=language, path=path)
if not lang_path.exists():
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(language: Annotated[str, typer.Option(envvar="LANGUAGE")]) -> None:
outdated_paths = list_outdated(language)
for path in outdated_paths:
print(f"Updating lang: {language} path: {path}")
translate_page(language=language, en_path=path)
print(f"Done updating: {path}")
print("Done updating all outdated paths")
@app.command()
def add_missing(language: Annotated[str, typer.Option(envvar="LANGUAGE")]) -> None:
missing_paths = list_missing(language)
for path in missing_paths:
print(f"Adding lang: {language} path: {path}")
translate_page(language=language, en_path=path)
print(f"Done adding: {path}")
print("Done adding all missing paths")
@app.command()
def update_and_add(language: Annotated[str, typer.Option(envvar="LANGUAGE")]) -> None:
print(f"Updating outdated translations for {language}")
update_outdated(language=language)
print(f"Adding missing translations for {language}")
add_missing(language=language)
print(f"Done updating and adding for {language}")
@app.command()
def make_pr(
*,
language: Annotated[str | None, typer.Option(envvar="LANGUAGE")] = None,
github_token: Annotated[str, typer.Option(envvar="GITHUB_TOKEN")],
github_repository: Annotated[str, typer.Option(envvar="GITHUB_REPOSITORY")],
) -> None:
print("Setting up GitHub Actions git user")
repo = git.Repo(Path(__file__).absolute().parent.parent)
if not repo.is_dirty(untracked_files=True):
print("Repository is clean, no changes to commit")
return
subprocess.run(["git", "config", "user.name", "github-actions"], check=True)
subprocess.run(
["git", "config", "user.email", "github-actions@github.com"], check=True
)
branch_name = "translate"
if language:
branch_name += f"-{language}"
branch_name += f"-{secrets.token_hex(4)}"
print(f"Creating a new branch {branch_name}")
subprocess.run(["git", "checkout", "-b", branch_name], check=True)
print("Adding updated files")
git_path = Path("docs")
subprocess.run(["git", "add", str(git_path)], check=True)
print("Committing updated file")
message = "🌐 Update translations"
if language:
message += f" for {language}"
subprocess.run(["git", "commit", "-m", message], check=True)
print("Pushing branch")
subprocess.run(["git", "push", "origin", branch_name], check=True)
print("Creating PR")
g = Github(github_token)
gh_repo = g.get_repo(github_repository)
pr = gh_repo.create_pull(
title=message, body=message, base="master", head=branch_name
)
print(f"Created PR: {pr.number}")
print("Finished")
if __name__ == "__main__":
typer.run(main)
app()

8
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"],

Loading…
Cancel
Save