mirror of
https://github.com/fastapi/fastapi.git
synced 2026-01-11 23:49:40 -05:00
Compare commits
1 Commits
master
...
translate-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5aa87f4dc7 |
4
.github/workflows/build-docs.yml
vendored
4
.github/workflows/build-docs.yml
vendored
@@ -91,13 +91,13 @@ jobs:
|
||||
run: uv sync --locked --no-dev --group docs
|
||||
- name: Update Languages
|
||||
run: uv run ./scripts/docs.py update-languages
|
||||
- uses: actions/cache@v5
|
||||
- uses: actions/cache@v4
|
||||
with:
|
||||
key: mkdocs-cards-${{ matrix.lang }}-${{ github.ref }}
|
||||
path: docs/${{ matrix.lang }}/.cache
|
||||
- name: Build Docs
|
||||
run: uv run ./scripts/docs.py build-lang ${{ matrix.lang }}
|
||||
- uses: actions/upload-artifact@v6
|
||||
- uses: actions/upload-artifact@v5
|
||||
with:
|
||||
name: docs-site-${{ matrix.lang }}
|
||||
path: ./site/**
|
||||
|
||||
2
.github/workflows/deploy-docs.yml
vendored
2
.github/workflows/deploy-docs.yml
vendored
@@ -45,7 +45,7 @@ jobs:
|
||||
run: |
|
||||
rm -rf ./site
|
||||
mkdir ./site
|
||||
- uses: actions/download-artifact@v7
|
||||
- uses: actions/download-artifact@v6
|
||||
with:
|
||||
path: ./site/
|
||||
pattern: docs-site-*
|
||||
|
||||
6
.github/workflows/issue-manager.yml
vendored
6
.github/workflows/issue-manager.yml
vendored
@@ -41,15 +41,11 @@ jobs:
|
||||
"message": "As this PR has been waiting for the original user for a while but seems to be inactive, it's now going to be closed. But if there's anyone interested, feel free to create a new PR.",
|
||||
"reminder": {
|
||||
"before": "P3D",
|
||||
"message": "Heads-up: this will be closed in 3 days unless there's new activity."
|
||||
"message": "Heads-up: this will be closed in 3 days unless there’s new activity."
|
||||
}
|
||||
},
|
||||
"invalid": {
|
||||
"delay": 0,
|
||||
"message": "This was marked as invalid and will be closed now. If this is an error, please provide additional details."
|
||||
},
|
||||
"maybe-ai": {
|
||||
"delay": 0,
|
||||
"message": "This was marked as potentially AI generated and will be closed now. If this is an error, please provide additional details, make sure to read the docs about contributing and AI."
|
||||
}
|
||||
}
|
||||
|
||||
2
.github/workflows/smokeshow.yml
vendored
2
.github/workflows/smokeshow.yml
vendored
@@ -28,7 +28,7 @@ jobs:
|
||||
pyproject.toml
|
||||
uv.lock
|
||||
- run: uv sync --locked --no-dev --group github-actions
|
||||
- uses: actions/download-artifact@v7
|
||||
- uses: actions/download-artifact@v6
|
||||
with:
|
||||
name: coverage-html
|
||||
path: htmlcov
|
||||
|
||||
6
.github/workflows/test.yml
vendored
6
.github/workflows/test.yml
vendored
@@ -84,7 +84,7 @@ jobs:
|
||||
# Do not store coverage for all possible combinations to avoid file size max errors in Smokeshow
|
||||
- name: Store coverage files
|
||||
if: matrix.coverage == 'coverage'
|
||||
uses: actions/upload-artifact@v6
|
||||
uses: actions/upload-artifact@v5
|
||||
with:
|
||||
name: coverage-${{ runner.os }}-${{ matrix.python-version }}-${{ hashFiles('**/coverage/.coverage.*') }}
|
||||
path: coverage
|
||||
@@ -112,7 +112,7 @@ jobs:
|
||||
- name: Install Dependencies
|
||||
run: uv sync --locked --no-dev --group tests --extra all
|
||||
- name: Get coverage files
|
||||
uses: actions/download-artifact@v7
|
||||
uses: actions/download-artifact@v6
|
||||
with:
|
||||
pattern: coverage-*
|
||||
path: coverage
|
||||
@@ -121,7 +121,7 @@ jobs:
|
||||
- run: uv run coverage combine coverage
|
||||
- run: uv run coverage html --title "Coverage for ${{ github.sha }}"
|
||||
- name: Store coverage HTML
|
||||
uses: actions/upload-artifact@v6
|
||||
uses: actions/upload-artifact@v5
|
||||
with:
|
||||
name: coverage-html
|
||||
path: htmlcov
|
||||
|
||||
@@ -177,81 +177,252 @@ as Uvicorn by default will use the port `8000`, the documentation on port `8008`
|
||||
|
||||
### Translations
|
||||
|
||||
/// warning | Attention
|
||||
|
||||
**Update on Translations**
|
||||
|
||||
We're updating the way we handle documentation translations.
|
||||
|
||||
Until now, we invited community members to translate pages via pull requests, which were then reviewed by at least two native speakers. While this has helped bring FastAPI to many more users, we’ve also run into several challenges - some languages have only a few translated pages, others are outdated and hard to maintain over time.
|
||||
To improve this, we’re working on automation tools 🤖 to manage translations more efficiently. Once ready, documentation will be machine-translated and still reviewed by at least two native speakers ✅ before publishing. This will allow us to keep translations up-to-date while reducing the review burden on maintainers.
|
||||
|
||||
What’s changing now:
|
||||
|
||||
* 🚫 We’re no longer accepting new community-submitted translation PRs.
|
||||
|
||||
* ⏳ Existing open PRs will be reviewed and can still be merged if completed within the next 3 weeks (since July 11 2025).
|
||||
|
||||
* 🌐 In the future, we will only support languages where at least three active native speakers are available to review and maintain translations.
|
||||
|
||||
This transition will help us keep translations more consistent and timely while better supporting our contributors 🙌. Thank you to everyone who has contributed so far — your help has been invaluable! 💖
|
||||
|
||||
///
|
||||
|
||||
|
||||
Help with translations is VERY MUCH appreciated! And it can't be done without the help from the community. 🌎 🚀
|
||||
|
||||
Here are the steps to help with translations.
|
||||
|
||||
#### Review Translation PRs
|
||||
|
||||
Translation pull requests are made by LLMs guided with prompts designed by the FastAPI team together with the community of native speakers for each supported language.
|
||||
|
||||
These translations are normally still reviewed by native speakers, and here's where you can help!
|
||||
#### Tips and guidelines
|
||||
|
||||
* Check the currently <a href="https://github.com/fastapi/fastapi/pulls" class="external-link" target="_blank">existing pull requests</a> for your language. You can filter the pull requests by the ones with the label for your language. For example, for Spanish, the label is <a href="https://github.com/fastapi/fastapi/pulls?q=is%3Aopen+sort%3Aupdated-desc+label%3Alang-es+label%3Aawaiting-review" class="external-link" target="_blank">`lang-es`</a>.
|
||||
|
||||
* When reviewing a pull request, it's better not to suggest changes in the same pull request, because it is LLM generated, and it won't be possible to make sure that small individual changes are replicated in other similar sections, or that they are preserved when translating the same content again.
|
||||
|
||||
* Instead of adding suggestions to the translation PR, make the suggestions to the LLM prompt file for that language, in a new PR. For example, for Spanish, the LLM prompt file is at: <a href="https://github.com/fastapi/fastapi/blob/master/docs/es/llm-prompt.md" class="external-link" target="_blank">`docs/es/llm-prompt.md`</a>.
|
||||
* Review those pull requests, requesting changes or approving them. For the languages I don't speak, I'll wait for several others to review the translation before merging.
|
||||
|
||||
/// tip
|
||||
|
||||
You can <a href="https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/commenting-on-a-pull-request" class="external-link" target="_blank">add comments with change suggestions</a> to existing pull requests.
|
||||
|
||||
Check the docs about <a href="https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/about-pull-request-reviews" class="external-link" target="_blank">adding a pull request review</a> to approve it or request changes.
|
||||
|
||||
///
|
||||
|
||||
#### Subscribe to Notifications for Your Language
|
||||
|
||||
* Check if there's a <a href="https://github.com/fastapi/fastapi/discussions/categories/translations" class="external-link" target="_blank">GitHub Discussion</a> to coordinate translations for your language. You can subscribe to it, and when there's a new pull request to review, an automatic comment will be added to the discussion.
|
||||
|
||||
* If you translate pages, add a single pull request per page translated. That will make it much easier for others to review it.
|
||||
|
||||
* To check the 2-letter code for the language you want to translate, you can use the table <a href="https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes" class="external-link" target="_blank">List of ISO 639-1 codes</a>.
|
||||
|
||||
#### Existing language
|
||||
|
||||
Let's say you want to translate a page for a language that already has translations for some pages, like Spanish.
|
||||
|
||||
In the case of Spanish, the 2-letter code is `es`. So, the directory for Spanish translations is located at `docs/es/`.
|
||||
|
||||
/// tip
|
||||
|
||||
The main ("official") language is English, located at `docs/en/`.
|
||||
|
||||
///
|
||||
|
||||
Now run the live server for the docs in Spanish:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
// Use the command "live" and pass the language code as a CLI argument
|
||||
$ python ./scripts/docs.py live es
|
||||
|
||||
<span style="color: green;">[INFO]</span> Serving on http://127.0.0.1:8008
|
||||
<span style="color: green;">[INFO]</span> Start watching changes
|
||||
<span style="color: green;">[INFO]</span> Start detecting changes
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
/// tip
|
||||
|
||||
Alternatively, you can perform the same steps that scripts does manually.
|
||||
|
||||
Go into the language directory, for the Spanish translations it's at `docs/es/`:
|
||||
|
||||
```console
|
||||
$ cd docs/es/
|
||||
```
|
||||
|
||||
Then run `mkdocs` in that directory:
|
||||
|
||||
```console
|
||||
$ mkdocs serve --dev-addr 127.0.0.1:8008
|
||||
```
|
||||
|
||||
///
|
||||
|
||||
Now you can go to <a href="http://127.0.0.1:8008" class="external-link" target="_blank">http://127.0.0.1:8008</a> and see your changes live.
|
||||
|
||||
You will see that every language has all the pages. But some pages are not translated and have an info box at the top, about the missing translation.
|
||||
|
||||
Now let's say that you want to add a translation for the section [Features](features.md){.internal-link target=_blank}.
|
||||
|
||||
* Copy the file at:
|
||||
|
||||
```
|
||||
docs/en/docs/features.md
|
||||
```
|
||||
|
||||
* Paste it in exactly the same location but for the language you want to translate, e.g.:
|
||||
|
||||
```
|
||||
docs/es/docs/features.md
|
||||
```
|
||||
|
||||
/// tip
|
||||
|
||||
Notice that the only change in the path and file name is the language code, from `en` to `es`.
|
||||
|
||||
///
|
||||
|
||||
If you go to your browser you will see that now the docs show your new section (the info box at the top is gone). 🎉
|
||||
|
||||
Now you can translate it all and see how it looks as you save the file.
|
||||
|
||||
#### Don't Translate these Pages
|
||||
|
||||
🚨 Don't translate:
|
||||
|
||||
* Files under `reference/`
|
||||
* `release-notes.md`
|
||||
* `fastapi-people.md`
|
||||
* `external-links.md`
|
||||
* `newsletter.md`
|
||||
* `management-tasks.md`
|
||||
* `management.md`
|
||||
* `contributing.md`
|
||||
|
||||
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.
|
||||
|
||||
* The first step would be for you to find other 2 people that would be willing to be reviewing translation PRs for that language with you.
|
||||
* Once there are at least 3 people that would be willing to commit to help maintain that language, you can continue the next steps.
|
||||
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.
|
||||
* Tag the other 2 people that will help with the language, and ask them to confirm there they will help.
|
||||
* 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 LLMs, and the team of native speakers can review the translation, and help tweak the LLM prompts.
|
||||
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.
|
||||
|
||||
## Automated Code and AI
|
||||
#### New Language
|
||||
|
||||
You are encouraged to use all the tools you want to do your work and contribute as efficiently as possible, this includes AI (LLM) tools, etc. Nevertheless, contributions should have meaningful human intervention, judgement, context, etc.
|
||||
/// note
|
||||
|
||||
If the **human effort** put in a PR, e.g. writing LLM prompts, is **less** than the **effort we would need to put** to **review it**, please **don't** submit the PR.
|
||||
These steps will be performed by the FastAPI team.
|
||||
|
||||
Think of it this way: we can already write LLM prompts or run automated tools ourselves, and that would be faster than reviewing external PRs.
|
||||
///
|
||||
|
||||
### Closing Automated and AI PRs
|
||||
Checking the link from above (List of ISO 639-1 codes), you can see that the 2-letter code for Latin is `la`.
|
||||
|
||||
If we see PRs that seem AI generated or automated in similar ways, we'll flag them and close them.
|
||||
Now you can create a new directory for the new language, running the following script:
|
||||
|
||||
The same applies to comments and descriptions, please don't copy paste the content generated by an LLM.
|
||||
<div class="termy">
|
||||
|
||||
### Human Effort Denial of Service
|
||||
```console
|
||||
// Use the command new-lang, pass the language code as a CLI argument
|
||||
$ python ./scripts/docs.py new-lang la
|
||||
|
||||
Using automated tools and AI to submit PRs or comments that we have to carefully review and handle would be the equivalent of a <a href="https://en.wikipedia.org/wiki/Denial-of-service_attack" class="external-link" target="_blank">Denial-of-service attack</a> on our human effort.
|
||||
Successfully initialized: docs/la
|
||||
```
|
||||
|
||||
It would be very little effort from the person submitting the PR (an LLM prompt) that generates a large amount of effort on our side (carefully reviewing code).
|
||||
</div>
|
||||
|
||||
Please don't do that.
|
||||
Now you can check in your code editor the newly created directory `docs/la/`.
|
||||
|
||||
We'll need to block accounts that spam us with repeated automated PRs or comments.
|
||||
That command created a file `docs/la/mkdocs.yml` with a simple config that inherits everything from the `en` version:
|
||||
|
||||
### Use Tools Wisely
|
||||
```yaml
|
||||
INHERIT: ../en/mkdocs.yml
|
||||
```
|
||||
|
||||
As Uncle Ben said:
|
||||
/// tip
|
||||
|
||||
<blockquote>
|
||||
With great <strike>power</strike> <strong>tools</strong> comes great responsibility.
|
||||
</blockquote>
|
||||
You could also simply create that file with those contents manually.
|
||||
|
||||
Avoid inadvertently doing harm.
|
||||
///
|
||||
|
||||
You have amazing tools at hand, use them wisely to help effectively.
|
||||
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/la/mkdocs.yml` and `docs/la/index.md`. 🎉
|
||||
|
||||
#### Preview the result
|
||||
|
||||
As already mentioned above, you can use the `./scripts/docs.py` with the `live` command to preview the results (or `mkdocs serve`).
|
||||
|
||||
Once you are done, you can also test it all as it would look online, including all the other languages.
|
||||
|
||||
To do that, first build all the docs:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
// Use the command "build-all", this will take a bit
|
||||
$ python ./scripts/docs.py build-all
|
||||
|
||||
Building docs for: en
|
||||
Building docs for: es
|
||||
Successfully built docs for: es
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
This builds all those independent MkDocs sites for each language, combines them, and generates the final output at `./site/`.
|
||||
|
||||
Then you can serve that with the command `serve`:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
// Use the command "serve" after running "build-all"
|
||||
$ python ./scripts/docs.py serve
|
||||
|
||||
Warning: this is a very simple server. For development, use mkdocs serve instead.
|
||||
This is here only to preview a site with translations already built.
|
||||
Make sure you run the build-all command first.
|
||||
Serving at: http://127.0.0.1:8008
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
#### Translation specific tips and guidelines
|
||||
|
||||
* Translate only the Markdown documents (`.md`). Do not translate the code examples at `./docs_src`.
|
||||
|
||||
* In code blocks within the Markdown document, translate comments (`# a comment`), but leave the rest unchanged.
|
||||
|
||||
* Do not change anything enclosed in "``" (inline code).
|
||||
|
||||
* In lines starting with `///` translate only the text part after `|`. Leave the rest unchanged.
|
||||
|
||||
* You can translate info boxes like `/// warning` with for example `/// warning | Achtung`. But do not change the word immediately after the `///`, it determines the color of the info box.
|
||||
|
||||
* Do not change the paths in links to images, code files, Markdown documents.
|
||||
|
||||
* However, when a Markdown document is translated, the `#hash-parts` in links to its headings may change. Update these links if possible.
|
||||
* Search for such links in the translated document using the regex `#[^# ]`.
|
||||
* Search in all documents already translated into your language for `your-translated-document.md`. For example VS Code has an option "Edit" -> "Find in Files".
|
||||
* When translating a document, do not "pre-translate" `#hash-parts` that link to headings in untranslated documents.
|
||||
|
||||
@@ -196,11 +196,31 @@ They have contributed source code, documentation, etc. 📦
|
||||
|
||||
There are hundreds of other contributors, you can see them all in the <a href="https://github.com/fastapi/fastapi/graphs/contributors" class="external-link" target="_blank">FastAPI GitHub Contributors page</a>. 👷
|
||||
|
||||
## Top Translators
|
||||
|
||||
These are the **Top Translators**. 🌐
|
||||
|
||||
These users have created the most Pull Requests with [translations to other languages](contributing.md#translations){.internal-link target=_blank} that have been *merged*.
|
||||
|
||||
<div class="user-list user-list-center">
|
||||
|
||||
{% for user in (translators.values() | list)[:50] %}
|
||||
|
||||
{% if user.login not in skip_users %}
|
||||
|
||||
<div class="user"><a href="{{ user.url }}" target="_blank"><div class="avatar-wrapper"><img src="{{ user.avatarUrl }}"/></div><div class="title">@{{ user.login }}</div></a> <div class="count">Translations: {{ user.count }}</div></div>
|
||||
|
||||
{% endif %}
|
||||
|
||||
{% endfor %}
|
||||
|
||||
</div>
|
||||
|
||||
## Top Translation Reviewers
|
||||
|
||||
These users are the **Top Translation Reviewers**. 🕵️
|
||||
|
||||
Translation reviewers have the [**power to approve translations**](contributing.md#translations){.internal-link target=_blank} of the documentation. Without them, there wouldn't be documentation in several other languages.
|
||||
I only speak a few languages (and not very well 😅). So, the reviewers are the ones that have the [**power to approve translations**](contributing.md#translations){.internal-link target=_blank} of the documentation. Without them, there wouldn't be documentation in several other languages.
|
||||
|
||||
<div class="user-list user-list-center">
|
||||
{% for user in (translation_reviewers.values() | list)[:50] %}
|
||||
|
||||
@@ -74,7 +74,7 @@ Make sure you use a supported label from the <a href="https://github.com/tiangol
|
||||
* `refactor`: Refactors
|
||||
* This is normally for changes to the internal code that don't change the behavior. Normally it improves maintainability, or enables future features, etc.
|
||||
* `upgrade`: Upgrades
|
||||
* This is for upgrades to direct dependencies from the project, or extra optional dependencies, normally in `pyproject.toml`. So, things that would affect final users, they would end up receiving the upgrade in their code base once they update. But this is not for upgrades to internal dependencies used for development, testing, docs, etc. Those internal dependencies or GitHub Action versions should be marked as `internal`, not `upgrade`.
|
||||
* This is for upgrades to direct dependencies from the project, or extra optional dependencies, normally in `pyproject.toml`. So, things that would affect final users, they would end up receiving the upgrade in their code base once they update. But this is not for upgrades to internal dependencies used for development, testing, docs, etc. Those internal dependencies, normally in `requirements.txt` files or GitHub Action versions should be marked as `internal`, not `upgrade`.
|
||||
* `docs`: Docs
|
||||
* Changes in docs. This includes updating the docs, fixing typos. But it doesn't include changes to translations.
|
||||
* You can normally quickly detect it by going to the "Files changed" tab in the PR and checking if the updated file(s) starts with `docs/en/docs`. The original version of the docs is always in English, so in `docs/en/docs`.
|
||||
@@ -106,25 +106,135 @@ This way, we can notice when there are new translations ready, because they have
|
||||
|
||||
## Merge Translation PRs
|
||||
|
||||
Translations are generated automatically with LLMs and scripts.
|
||||
For Spanish, as I'm a native speaker and it's a language close to me, I will give it a final review myself and in most cases tweak the PR a bit before merging it.
|
||||
|
||||
There's one GitHub Action that can be manually run to add or update translations for a language: <a href="https://github.com/fastapi/fastapi/actions/workflows/translate.yml" class="external-link" target="_blank">`translate.yml`</a>.
|
||||
For the other languages, confirm that:
|
||||
|
||||
For these language translation PRs, confirm that:
|
||||
|
||||
* The PR was automated (authored by @tiangolo), not made by another user.
|
||||
* The title is correct following the instructions above.
|
||||
* It has the labels `lang-all` and `lang-{lang code}`.
|
||||
* If the PR is approved by at least one native speaker, you can merge it.
|
||||
* The PR changes only one Markdown file adding a translation.
|
||||
* Or in some cases, at most two files, if they are small, for the same language, and people reviewed them.
|
||||
* If it's the first translation for that language, it will have additional `mkdocs.yml` files, for those cases follow the instructions below.
|
||||
* The PR doesn't add any additional or extraneous files.
|
||||
* The translation seems to have a similar structure as the original English file.
|
||||
* The translation doesn't seem to change the original content, for example with obvious additional documentation sections.
|
||||
* The translation doesn't use different Markdown structures, for example adding HTML tags when the original didn't have them.
|
||||
* The "admonition" sections, like `tip`, `info`, etc. are not changed or translated. For example:
|
||||
|
||||
```
|
||||
/// tip
|
||||
|
||||
This is a tip.
|
||||
|
||||
///
|
||||
|
||||
```
|
||||
|
||||
looks like this:
|
||||
|
||||
/// tip
|
||||
|
||||
This is a tip.
|
||||
|
||||
///
|
||||
|
||||
...it could be translated as:
|
||||
|
||||
```
|
||||
/// tip
|
||||
|
||||
Esto es un consejo.
|
||||
|
||||
///
|
||||
|
||||
```
|
||||
|
||||
...but needs to keep the exact `tip` keyword. If it was translated to `consejo`, like:
|
||||
|
||||
```
|
||||
/// consejo
|
||||
|
||||
Esto es un consejo.
|
||||
|
||||
///
|
||||
|
||||
```
|
||||
|
||||
it would change the style to the default one, it would look like:
|
||||
|
||||
/// consejo
|
||||
|
||||
Esto es un consejo.
|
||||
|
||||
///
|
||||
|
||||
Those don't have to be translated, but if they are, they need to be written as:
|
||||
|
||||
```
|
||||
/// tip | consejo
|
||||
|
||||
Esto es un consejo.
|
||||
|
||||
///
|
||||
|
||||
```
|
||||
|
||||
Which looks like:
|
||||
|
||||
/// tip | consejo
|
||||
|
||||
Esto es un consejo.
|
||||
|
||||
///
|
||||
|
||||
## First Translation PR
|
||||
|
||||
When there's a first translation for a language, it will have a `docs/{lang code}/docs/index.md` translated file and a `docs/{lang code}/mkdocs.yml`.
|
||||
|
||||
For example, for Bosnian, it would be:
|
||||
|
||||
* `docs/bs/docs/index.md`
|
||||
* `docs/bs/mkdocs.yml`
|
||||
|
||||
The `mkdocs.yml` file will have only the following content:
|
||||
|
||||
```YAML
|
||||
INHERIT: ../en/mkdocs.yml
|
||||
```
|
||||
|
||||
The language code would normally be in the <a href="https://en.wikipedia.org/wiki/List_of_ISO_639_language_codes" class="external-link" target="_blank">ISO 639-1 list of language codes</a>.
|
||||
|
||||
In any case, the language code should be in the file <a href="https://github.com/fastapi/fastapi/blob/master/docs/language_names.yml" class="external-link" target="_blank">docs/language_names.yml</a>.
|
||||
|
||||
There won't be yet a label for the language code, for example, if it was Bosnian, there wouldn't be a `lang-bs`. Before creating the label and adding it to the PR, create the GitHub Discussion:
|
||||
|
||||
* Go to the <a href="https://github.com/fastapi/fastapi/discussions/categories/translations" class="external-link" target="_blank">Translations GitHub Discussions</a>
|
||||
* Create a new discussion with the title `Bosnian Translations` (or the language name in English)
|
||||
* A description of:
|
||||
|
||||
```Markdown
|
||||
## Bosnian translations
|
||||
|
||||
This is the issue to track translations of the docs to Bosnian. 🚀
|
||||
|
||||
Here are the [PRs to review with the label `lang-bs`](https://github.com/fastapi/fastapi/pulls?q=is%3Apr+is%3Aopen+sort%3Aupdated-desc+label%3Alang-bs+label%3A%22awaiting-review%22). 🤓
|
||||
```
|
||||
|
||||
Update "Bosnian" with the new language.
|
||||
|
||||
And update the search link to point to the new language label that will be created, like `lang-bs`.
|
||||
|
||||
Create and add the label to that new Discussion just created, like `lang-bs`.
|
||||
|
||||
Then go back to the PR, and add the label, like `lang-bs`, and `lang-all` and `awaiting-review`.
|
||||
|
||||
Now the GitHub action will automatically detect the label `lang-bs` and will post in that Discussion that this PR is waiting to be reviewed.
|
||||
|
||||
## Review PRs
|
||||
|
||||
* If a PR doesn't explain what it does or why, if it seems like it could be useful, ask for more information. Otherwise, feel free to close it.
|
||||
If a PR doesn't explain what it does or why, ask for more information.
|
||||
|
||||
* If a PR seems to be spam, meaningless, only to change statistics (to appear as "contributor") or similar, you can simply mark it as `invalid`, and it will be automatically closed.
|
||||
|
||||
* If a PR seems to be AI generated, and seems like reviewing it would take more time from you than the time it took to write the prompt, mark it as `maybe-ai`, and it will be automatically closed.
|
||||
|
||||
* A PR should have a specific use case that it is solving.
|
||||
A PR should have a specific use case that it is solving.
|
||||
|
||||
* If the PR is for a feature, it should have docs.
|
||||
* Unless it's a feature we want to discourage, like support for a corner case that we don't want users to use.
|
||||
@@ -144,12 +254,27 @@ Every month, a GitHub Action updates the FastAPI People data. Those PRs look lik
|
||||
|
||||
If the tests are passing, you can merge it right away.
|
||||
|
||||
## External Links PRs
|
||||
|
||||
When people add external links they edit this file <a href="https://github.com/fastapi/fastapi/blob/master/docs/en/data/external_links.yml" class="external-link" target="_blank">external_links.yml</a>.
|
||||
|
||||
* Make sure the new link is in the correct category (e.g. "Podcasts") and language (e.g. "Japanese").
|
||||
* A new link should be at the top of its list.
|
||||
* The link URL should work (it should not return a 404).
|
||||
* The content of the link should be about FastAPI.
|
||||
* The new addition should have these fields:
|
||||
* `author`: The name of the author.
|
||||
* `link`: The URL with the content.
|
||||
* `title`: The title of the link (the title of the article, podcast, etc).
|
||||
|
||||
After checking all these things and ensuring the PR has the right labels, you can merge it.
|
||||
|
||||
## Dependabot PRs
|
||||
|
||||
Dependabot will create PRs to update dependencies for several things, and those PRs all look similar, but some are way more delicate than others.
|
||||
|
||||
* If the PR is for a direct dependency, so, Dependabot is modifying `pyproject.toml` in the main dependencies, **don't merge it**. 😱 Let me check it first. There's a good chance that some additional tweaks or updates are needed.
|
||||
* If the PR updates one of the internal dependencies, for example the group `dev` in `pyproject.toml`, or GitHub Action versions, if the tests are passing, the release notes (shown in a summary in the PR) don't show any obvious potential breaking change, you can merge it. 😎
|
||||
* If the PR is for a direct dependency, so, Dependabot is modifying `pyproject.toml`, **don't merge it**. 😱 Let me check it first. There's a good chance that some additional tweaks or updates are needed.
|
||||
* If the PR updates one of the internal dependencies, for example it's modifying `requirements.txt` files, or GitHub Action versions, if the tests are passing, the release notes (shown in a summary in the PR) don't show any obvious potential breaking change, you can merge it. 😎
|
||||
|
||||
## Mark GitHub Discussions Answers
|
||||
|
||||
|
||||
@@ -9,10 +9,6 @@ hide:
|
||||
|
||||
### Docs
|
||||
|
||||
* 📝 Add contribution instructions about LLM generated code and comments and automated tools for PRs. PR [#14706](https://github.com/fastapi/fastapi/pull/14706) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 📝 Update docs for management tasks. PR [#14705](https://github.com/fastapi/fastapi/pull/14705) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 📝 Update docs about managing translations. PR [#14704](https://github.com/fastapi/fastapi/pull/14704) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 📝 Update docs for contributing with translations. PR [#14701](https://github.com/fastapi/fastapi/pull/14701) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 📝 Specify language code for code block. PR [#14656](https://github.com/fastapi/fastapi/pull/14656) by [@YuriiMotov](https://github.com/YuriiMotov).
|
||||
|
||||
### Translations
|
||||
@@ -26,9 +22,6 @@ hide:
|
||||
|
||||
### Internal
|
||||
|
||||
* ⬆ Bump actions/cache from 4 to 5. PR [#14511](https://github.com/fastapi/fastapi/pull/14511) by [@dependabot[bot]](https://github.com/apps/dependabot).
|
||||
* ⬆ Bump actions/upload-artifact from 5 to 6. PR [#14525](https://github.com/fastapi/fastapi/pull/14525) by [@dependabot[bot]](https://github.com/apps/dependabot).
|
||||
* ⬆ Bump actions/download-artifact from 6 to 7. PR [#14526](https://github.com/fastapi/fastapi/pull/14526) by [@dependabot[bot]](https://github.com/apps/dependabot).
|
||||
* 👷 Tweak CI input names. PR [#14688](https://github.com/fastapi/fastapi/pull/14688) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 🔨 Refactor translation script to allow committing in place. PR [#14687](https://github.com/fastapi/fastapi/pull/14687) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 🐛 Fix translation script path. PR [#14685](https://github.com/fastapi/fastapi/pull/14685) by [@tiangolo](https://github.com/tiangolo).
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# Arquivo de teste de LLM { #llm-test-file }
|
||||
|
||||
Este documento testa se o <abbr title="Large Language Model – Modelo de Linguagem de Grande Porte">LLM</abbr>, que traduz a documentação, entende o `general_prompt` em `scripts/translate.py` e o prompt específico do idioma em `docs/{language code}/llm-prompt.md`. O prompt específico do idioma é anexado ao `general_prompt`.
|
||||
Este documento testa se o <abbr title="Large Language Model - Modelo de Linguagem de Grande Porte">LLM</abbr>, que traduz a documentação, entende o `general_prompt` em `scripts/translate.py` e o prompt específico do idioma em `docs/{language code}/llm-prompt.md`. O prompt específico do idioma é anexado ao `general_prompt`.
|
||||
|
||||
Os testes adicionados aqui serão vistos por todos os autores dos prompts específicos de idioma.
|
||||
Os testes adicionados aqui serão vistos por todos os designers de prompts específicos de idioma.
|
||||
|
||||
Use da seguinte forma:
|
||||
|
||||
@@ -23,7 +23,7 @@ Este é um trecho de código: `foo`. E este é outro trecho de código: `bar`. E
|
||||
|
||||
////
|
||||
|
||||
//// tab | Informações
|
||||
//// tab | Informação
|
||||
|
||||
O conteúdo dos trechos de código deve ser deixado como está.
|
||||
|
||||
@@ -45,9 +45,9 @@ O LLM provavelmente vai traduzir isso errado. O interessante é apenas se ele ma
|
||||
|
||||
////
|
||||
|
||||
//// tab | Informações
|
||||
//// tab | Informação
|
||||
|
||||
O autor do prompt pode escolher se deseja converter aspas neutras em aspas tipográficas. Também é aceitável deixá-las como estão.
|
||||
O designer do prompt pode escolher se deseja converter aspas neutras em aspas tipográficas. Também é aceitável deixá-las como estão.
|
||||
|
||||
Veja, por exemplo, a seção `### Quotes` em `docs/de/llm-prompt.md`.
|
||||
|
||||
@@ -67,7 +67,7 @@ Pesado: `Yesterday, my friend wrote: "If you spell incorrectly correctly, you ha
|
||||
|
||||
////
|
||||
|
||||
//// tab | Informações
|
||||
//// tab | Informação
|
||||
|
||||
... No entanto, as aspas dentro de trechos de código devem permanecer como estão.
|
||||
|
||||
@@ -112,7 +112,7 @@ works(foo="bar") # Isto funciona 🎉
|
||||
|
||||
////
|
||||
|
||||
//// tab | Informações
|
||||
//// tab | Informação
|
||||
|
||||
O código em blocos de código não deve ser modificado, com exceção dos comentários.
|
||||
|
||||
@@ -154,7 +154,7 @@ Algum texto
|
||||
|
||||
////
|
||||
|
||||
//// tab | Informações
|
||||
//// tab | Informação
|
||||
|
||||
Abas e blocos `Info`/`Note`/`Warning`/etc. devem ter a tradução do seu título adicionada após uma barra vertical (`|`).
|
||||
|
||||
@@ -181,7 +181,7 @@ O texto do link deve ser traduzido, o endereço do link deve apontar para a trad
|
||||
|
||||
////
|
||||
|
||||
//// tab | Informações
|
||||
//// tab | Informação
|
||||
|
||||
Os links devem ser traduzidos, mas seus endereços devem permanecer inalterados. Uma exceção são links absolutos para páginas da documentação do FastAPI. Nesse caso, devem apontar para a tradução.
|
||||
|
||||
@@ -197,10 +197,10 @@ Aqui estão algumas coisas envolvidas em elementos HTML "abbr" (algumas são inv
|
||||
|
||||
### O abbr fornece uma frase completa { #the-abbr-gives-a-full-phrase }
|
||||
|
||||
* <abbr title="Getting Things Done – Fazer as Coisas">GTD</abbr>
|
||||
* <abbr title="menos que"><code>lt</code></abbr>
|
||||
* <abbr title="XML Web Token – Token Web XML">XWT</abbr>
|
||||
* <abbr title="Parallel Server Gateway Interface – Interface de Gateway de Servidor Paralelo">PSGI</abbr>
|
||||
* <abbr title="Getting Things Done - Fazer as Coisas">GTD</abbr>
|
||||
* <abbr title="less than - menor que"><code>lt</code></abbr>
|
||||
* <abbr title="XML Web Token - Token Web XML">XWT</abbr>
|
||||
* <abbr title="Parallel Server Gateway Interface - Interface de Gateway de Servidor Paralelo">PSGI</abbr>
|
||||
|
||||
### O abbr fornece uma explicação { #the-abbr-gives-an-explanation }
|
||||
|
||||
@@ -209,12 +209,12 @@ Aqui estão algumas coisas envolvidas em elementos HTML "abbr" (algumas são inv
|
||||
|
||||
### O abbr fornece uma frase completa e uma explicação { #the-abbr-gives-a-full-phrase-and-an-explanation }
|
||||
|
||||
* <abbr title="Mozilla Developer Network – Rede de Desenvolvedores da Mozilla: documentação para desenvolvedores, escrita pelo pessoal do Firefox">MDN</abbr>
|
||||
* <abbr title="Input/Output – Entrada/Saída: leitura ou escrita em disco, comunicações de rede.">I/O</abbr>.
|
||||
* <abbr title="Mozilla Developer Network - Rede de Desenvolvedores da Mozilla: documentação para desenvolvedores, escrita pelo pessoal do Firefox">MDN</abbr>
|
||||
* <abbr title="Input/Output: disk reading or writing, network communications.">I/O</abbr>.
|
||||
|
||||
////
|
||||
|
||||
//// tab | Informações
|
||||
//// tab | Informação
|
||||
|
||||
Os atributos "title" dos elementos "abbr" são traduzidos seguindo algumas instruções específicas.
|
||||
|
||||
@@ -242,7 +242,7 @@ Olá novamente.
|
||||
|
||||
////
|
||||
|
||||
//// tab | Informações
|
||||
//// tab | Informação
|
||||
|
||||
A única regra rígida para títulos é que o LLM deixe a parte do hash dentro de chaves inalterada, o que garante que os links não quebrem.
|
||||
|
||||
@@ -494,7 +494,7 @@ Para algumas instruções específicas do idioma, veja, por exemplo, a seção `
|
||||
|
||||
////
|
||||
|
||||
//// tab | Informações
|
||||
//// tab | Informação
|
||||
|
||||
Esta é uma lista não completa e não normativa de termos (principalmente) técnicos vistos na documentação. Pode ser útil para o autor do prompt descobrir para quais termos o LLM precisa de uma ajudinha. Por exemplo, quando ele continua revertendo uma boa tradução para uma tradução subótima. Ou quando tem problemas para conjugar/declinar um termo no seu idioma.
|
||||
|
||||
|
||||
@@ -10,21 +10,21 @@ Se você não é um "especialista" no OpenAPI, você provavelmente não precisa
|
||||
|
||||
Você pode definir o `operationId` do OpenAPI que será utilizado na sua *operação de rota* com o parâmetro `operation_id`.
|
||||
|
||||
Você precisa ter certeza que ele é único para cada operação.
|
||||
Você (você deveria) ter certeza de que ele é único para cada operação.
|
||||
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial001_py39.py hl[6] *}
|
||||
|
||||
### Utilizando o nome da *função de operação de rota* como o operationId { #using-the-path-operation-function-name-as-the-operationid }
|
||||
|
||||
Se você quiser utilizar o nome das funções da sua API como `operationId`s, você pode iterar sobre todos esses nomes e sobrescrever o `operation_id` em cada *operação de rota* utilizando o `APIRoute.name` dela.
|
||||
Se você quiser utilizar o nome das funções da sua API como `operationId`s, você pode iterar sobre todos esses nomes e sobrescrever o `operation_id` de cada *operação de rota* utilizando o `APIRoute.name` dela.
|
||||
|
||||
Você deve fazer isso depois de adicionar todas as suas *operações de rota*.
|
||||
Você (você deveria) fazer isso depois de adicionar todas as suas *operações de rota*.
|
||||
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial002_py39.py hl[2, 12:21, 24] *}
|
||||
|
||||
/// tip | Dica
|
||||
|
||||
Se você chamar `app.openapi()` manualmente, os `operationId`s devem ser atualizados antes dessa chamada.
|
||||
Se você chamar `app.openapi()` manualmente, você (você deveria) atualizar os `operationId`s antes disso.
|
||||
|
||||
///
|
||||
|
||||
@@ -44,11 +44,11 @@ Para excluir uma *operação de rota* do esquema OpenAPI gerado (e por consequê
|
||||
|
||||
## Descrição avançada a partir de docstring { #advanced-description-from-docstring }
|
||||
|
||||
Você pode limitar as linhas utilizadas a partir de uma docstring de uma *função de operação de rota* para o OpenAPI.
|
||||
Você pode limitar as linhas utilizadas a partir da docstring de uma *função de operação de rota* para o OpenAPI.
|
||||
|
||||
Adicionar um `\f` (um caractere de escape para alimentação de formulário) faz com que o **FastAPI** restrinja a saída utilizada pelo OpenAPI até esse ponto.
|
||||
Adicionar um `\f` (um caractere de escape "form feed") faz com que o **FastAPI** trunque a saída utilizada pelo OpenAPI até esse ponto.
|
||||
|
||||
Ele não será mostrado na documentação, mas outras ferramentas (como o Sphinx) serão capazes de utilizar o resto do texto.
|
||||
Ele não será mostrado na documentação, mas outras ferramentas (como o Sphinx) serão capazes de utilizar o resto.
|
||||
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial004_py310.py hl[17:27] *}
|
||||
|
||||
@@ -56,19 +56,19 @@ Ele não será mostrado na documentação, mas outras ferramentas (como o Sphinx
|
||||
|
||||
Você provavelmente já viu como declarar o `response_model` e `status_code` para uma *operação de rota*.
|
||||
|
||||
Isso define os metadados sobre a resposta principal da *operação de rota*.
|
||||
Isso define os metadados sobre a response principal da *operação de rota*.
|
||||
|
||||
Você também pode declarar respostas adicionais, com seus modelos, códigos de status, etc.
|
||||
Você também pode declarar responses adicionais, com seus modelos, códigos de status, etc.
|
||||
|
||||
Existe um capítulo inteiro da nossa documentação sobre isso, você pode ler em [Retornos Adicionais no OpenAPI](additional-responses.md){.internal-link target=_blank}.
|
||||
Existe um capítulo inteiro da nossa documentação sobre isso, você pode ler em [Respostas Adicionais no OpenAPI](additional-responses.md){.internal-link target=_blank}.
|
||||
|
||||
## Extras do OpenAPI { #openapi-extra }
|
||||
|
||||
Quando você declara uma *operação de rota* na sua aplicação, o **FastAPI** irá gerar os metadados relevantes da *operação de rota* automaticamente para serem incluídos no esquema do OpenAPI.
|
||||
Quando você declara uma *operação de rota* na sua aplicação, o **FastAPI** gera automaticamente os metadados relevantes sobre essa *operação de rota* para serem incluídos no esquema do OpenAPI.
|
||||
|
||||
/// note | Detalhes Técnicos
|
||||
|
||||
Na especificação do OpenAPI, isso é chamado de um <a href="https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#operation-object" class="external-link" target="_blank">Objeto de Operação</a>.
|
||||
Na especificação do OpenAPI, isso é chamado de <a href="https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#operation-object" class="external-link" target="_blank">Objeto de Operação</a>.
|
||||
|
||||
///
|
||||
|
||||
@@ -76,13 +76,13 @@ Ele possui toda a informação sobre a *operação de rota* e é usado para gera
|
||||
|
||||
Ele inclui os atributos `tags`, `parameters`, `requestBody`, `responses`, etc.
|
||||
|
||||
Esse esquema específico para uma *operação de rota* normalmente é gerado automaticamente pelo **FastAPI**, mas você também pode estender ele.
|
||||
Esse esquema OpenAPI específico para uma *operação de rota* normalmente é gerado automaticamente pelo **FastAPI**, mas você também pode estendê-lo.
|
||||
|
||||
/// tip | Dica
|
||||
|
||||
Esse é um ponto de extensão de baixo nível.
|
||||
|
||||
Caso você só precise declarar respostas adicionais, uma forma conveniente de fazer isso é com [Retornos Adicionais no OpenAPI](additional-responses.md){.internal-link target=_blank}.
|
||||
Caso você só precise declarar responses adicionais, uma forma mais conveniente de fazer isso é com [Respostas Adicionais no OpenAPI](additional-responses.md){.internal-link target=_blank}.
|
||||
|
||||
///
|
||||
|
||||
@@ -98,7 +98,7 @@ Se você abrir os documentos criados automaticamente para a API, sua extensão a
|
||||
|
||||
<img src="/img/tutorial/path-operation-advanced-configuration/image01.png">
|
||||
|
||||
E se você olhar o esquema OpenAPI resultante (na rota `/openapi.json` da sua API), você verá que a sua extensão também faz parte da *operação de rota* específica:
|
||||
E se você olhar o OpenAPI resultante (em `/openapi.json` na sua API), você verá que a sua extensão também faz parte da *operação de rota* específica:
|
||||
|
||||
```JSON hl_lines="22"
|
||||
{
|
||||
@@ -131,70 +131,38 @@ E se você olhar o esquema OpenAPI resultante (na rota `/openapi.json` da sua AP
|
||||
|
||||
### Esquema de *operação de rota* do OpenAPI personalizado { #custom-openapi-path-operation-schema }
|
||||
|
||||
O dicionário em `openapi_extra` vai ter todos os seus níveis mesclados dentro do esquema OpenAPI gerado automaticamente para a *operação de rota*.
|
||||
O dicionário em `openapi_extra` será mesclado profundamente com o esquema OpenAPI gerado automaticamente para a *operação de rota*.
|
||||
|
||||
Então, você pode adicionar dados extras para o esquema gerado automaticamente.
|
||||
Assim, você poderia adicionar dados adicionais ao esquema gerado automaticamente.
|
||||
|
||||
Por exemplo, você poderia optar por ler e validar a requisição com seu próprio código, sem utilizar funcionalidades automatizadas do FastAPI com o Pydantic, mas você ainda pode quere definir a requisição no esquema OpenAPI.
|
||||
Por exemplo, você poderia decidir ler e validar a request com seu próprio código, sem usar as funcionalidades automáticas do FastAPI com o Pydantic, mas ainda assim poderia querer definir a request no esquema OpenAPI.
|
||||
|
||||
Você pode fazer isso com `openapi_extra`:
|
||||
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial006_py39.py hl[19:36, 39:40] *}
|
||||
|
||||
Nesse exemplo, nós não declaramos nenhum modelo do Pydantic. Na verdade, o corpo da requisição não está nem mesmo <abbr title="convertido de um formato plano, como bytes, para objetos Python">analisado</abbr> como JSON, ele é lido diretamente como `bytes` e a função `magic_data_reader()` seria a responsável por analisar ele de alguma forma.
|
||||
Neste exemplo, não declaramos nenhum modelo do Pydantic. Na verdade, o corpo da request nem sequer é <abbr title="converted from some plain format, like bytes, into Python objects - convertido de algum formato simples, como bytes, para objetos Python">parsed</abbr> como JSON, ele é lido diretamente como `bytes`, e a função `magic_data_reader()` seria a responsável por fazer o parsing dele de alguma forma.
|
||||
|
||||
De toda forma, nós podemos declarar o esquema esperado para o corpo da requisição.
|
||||
Mesmo assim, podemos declarar o esquema esperado para o corpo da request.
|
||||
|
||||
### Tipo de conteúdo do OpenAPI personalizado { #custom-openapi-content-type }
|
||||
|
||||
Utilizando esse mesmo truque, você pode utilizar um modelo Pydantic para definir o JSON Schema que é então incluído na seção do esquema personalizado do OpenAPI na *operação de rota*.
|
||||
Utilizando esse mesmo truque, você poderia usar um modelo Pydantic para definir o JSON Schema que é então incluído na seção do esquema OpenAPI personalizado da *operação de rota*.
|
||||
|
||||
E você pode fazer isso até mesmo quando os dados da requisição não seguem o formato JSON.
|
||||
E você poderia fazer isso mesmo que o tipo de dados na request não seja JSON.
|
||||
|
||||
Por exemplo, nesta aplicação nós não usamos a funcionalidade integrada ao FastAPI de extrair o JSON Schema dos modelos Pydantic nem a validação automática do JSON. Na verdade, estamos declarando o tipo do conteúdo da requisição como YAML, em vez de JSON:
|
||||
|
||||
//// tab | Pydantic v2
|
||||
Por exemplo, nesta aplicação não usamos a funcionalidade integrada do FastAPI para extrair o JSON Schema dos modelos Pydantic nem a validação automática para JSON. Na verdade, estamos declarando o tipo de conteúdo da request como YAML, e não JSON:
|
||||
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py39.py hl[15:20, 22] *}
|
||||
|
||||
////
|
||||
Mesmo assim, embora não estejamos usando a funcionalidade integrada padrão, ainda estamos usando um modelo Pydantic para gerar manualmente o JSON Schema para os dados que queremos receber em YAML.
|
||||
|
||||
//// tab | Pydantic v1
|
||||
Então usamos a request diretamente e extraímos o corpo como `bytes`. Isso significa que o FastAPI nem sequer vai tentar fazer o parsing do payload da request como JSON.
|
||||
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial007_pv1_py39.py hl[15:20, 22] *}
|
||||
|
||||
////
|
||||
|
||||
/// info | Informação
|
||||
|
||||
Na versão 1 do Pydantic, o método para obter o JSON Schema de um modelo é `Item.schema()`, na versão 2 do Pydantic, o método é `Item.model_json_schema()`.
|
||||
|
||||
///
|
||||
|
||||
Entretanto, mesmo que não utilizemos a funcionalidade integrada por padrão, ainda estamos usando um modelo Pydantic para gerar um JSON Schema manualmente para os dados que queremos receber no formato YAML.
|
||||
|
||||
Então utilizamos a requisição diretamente, e extraímos o corpo como `bytes`. Isso significa que o FastAPI não vai sequer tentar analisar o corpo da requisição como JSON.
|
||||
|
||||
E então no nosso código, nós analisamos o conteúdo YAML diretamente, e estamos utilizando o mesmo modelo Pydantic para validar o conteúdo YAML:
|
||||
|
||||
//// tab | Pydantic v2
|
||||
E então no nosso código, fazemos o parsing desse conteúdo YAML diretamente, e então estamos novamente usando o mesmo modelo Pydantic para validar o conteúdo YAML:
|
||||
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py39.py hl[24:31] *}
|
||||
|
||||
////
|
||||
|
||||
//// tab | Pydantic v1
|
||||
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial007_pv1_py39.py hl[24:31] *}
|
||||
|
||||
////
|
||||
|
||||
/// info | Informação
|
||||
|
||||
Na versão 1 do Pydantic, o método para analisar e validar um objeto era `Item.parse_obj()`, na versão 2 do Pydantic, o método é chamado de `Item.model_validate()`.
|
||||
|
||||
///
|
||||
|
||||
/// tip | Dica
|
||||
|
||||
Aqui reutilizamos o mesmo modelo do Pydantic.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Configurações e Variáveis de Ambiente { #settings-and-environment-variables }
|
||||
|
||||
Em muitos casos, sua aplicação pode precisar de configurações externas, por exemplo chaves secretas, credenciais de banco de dados, credenciais para serviços de e-mail, etc.
|
||||
Em muitos casos, sua aplicação pode precisar de algumas configurações externas, por exemplo chaves secretas, credenciais de banco de dados, credenciais para serviços de e-mail, etc.
|
||||
|
||||
A maioria dessas configurações é variável (pode mudar), como URLs de banco de dados. E muitas podem ser sensíveis, como segredos.
|
||||
|
||||
@@ -12,7 +12,7 @@ Para entender variáveis de ambiente, você pode ler [Variáveis de Ambiente](..
|
||||
|
||||
///
|
||||
|
||||
## Tipagem e validação { #types-and-validation }
|
||||
## Tipos e validação { #types-and-validation }
|
||||
|
||||
Essas variáveis de ambiente só conseguem lidar com strings de texto, pois são externas ao Python e precisam ser compatíveis com outros programas e com o resto do sistema (e até com diferentes sistemas operacionais, como Linux, Windows, macOS).
|
||||
|
||||
@@ -46,12 +46,6 @@ $ pip install "fastapi[all]"
|
||||
|
||||
</div>
|
||||
|
||||
/// info | Informação
|
||||
|
||||
No Pydantic v1 ele vinha incluído no pacote principal. Agora é distribuído como um pacote independente para que você possa optar por instalá-lo ou não, caso não precise dessa funcionalidade.
|
||||
|
||||
///
|
||||
|
||||
### Criar o objeto `Settings` { #create-the-settings-object }
|
||||
|
||||
Importe `BaseSettings` do Pydantic e crie uma subclasse, muito parecido com um modelo do Pydantic.
|
||||
@@ -60,24 +54,8 @@ Da mesma forma que com modelos do Pydantic, você declara atributos de classe co
|
||||
|
||||
Você pode usar as mesmas funcionalidades e ferramentas de validação que usa em modelos do Pydantic, como diferentes tipos de dados e validações adicionais com `Field()`.
|
||||
|
||||
//// tab | Pydantic v2
|
||||
|
||||
{* ../../docs_src/settings/tutorial001_py39.py hl[2,5:8,11] *}
|
||||
|
||||
////
|
||||
|
||||
//// tab | Pydantic v1
|
||||
|
||||
/// info | Informação
|
||||
|
||||
No Pydantic v1 você importaria `BaseSettings` diretamente de `pydantic` em vez de `pydantic_settings`.
|
||||
|
||||
///
|
||||
|
||||
{* ../../docs_src/settings/tutorial001_pv1_py39.py hl[2,5:8,11] *}
|
||||
|
||||
////
|
||||
|
||||
/// tip | Dica
|
||||
|
||||
Se você quer algo rápido para copiar e colar, não use este exemplo, use o último abaixo.
|
||||
@@ -140,7 +118,7 @@ Você também precisaria de um arquivo `__init__.py` como visto em [Aplicações
|
||||
|
||||
## Configurações em uma dependência { #settings-in-a-dependency }
|
||||
|
||||
Em algumas ocasiões, pode ser útil fornecer as configurações a partir de uma dependência, em vez de ter um objeto global `settings` usado em todos os lugares.
|
||||
Em algumas ocasiões, pode ser útil fornecer as configurações a partir de uma dependência, em vez de ter um objeto global com `settings` que é usado em todos os lugares.
|
||||
|
||||
Isso pode ser especialmente útil durante os testes, pois é muito fácil sobrescrever uma dependência com suas próprias configurações personalizadas.
|
||||
|
||||
@@ -215,8 +193,6 @@ APP_NAME="ChimichangApp"
|
||||
|
||||
E então atualizar seu `config.py` com:
|
||||
|
||||
//// tab | Pydantic v2
|
||||
|
||||
{* ../../docs_src/settings/app03_an_py39/config.py hl[9] *}
|
||||
|
||||
/// tip | Dica
|
||||
@@ -225,31 +201,11 @@ O atributo `model_config` é usado apenas para configuração do Pydantic. Você
|
||||
|
||||
///
|
||||
|
||||
////
|
||||
|
||||
//// tab | Pydantic v1
|
||||
|
||||
{* ../../docs_src/settings/app03_an_py39/config_pv1.py hl[9:10] *}
|
||||
|
||||
/// tip | Dica
|
||||
|
||||
A classe `Config` é usada apenas para configuração do Pydantic. Você pode ler mais em <a href="https://docs.pydantic.dev/1.10/usage/model_config/" class="external-link" target="_blank">Pydantic Model Config</a>.
|
||||
|
||||
///
|
||||
|
||||
////
|
||||
|
||||
/// info | Informação
|
||||
|
||||
Na versão 1 do Pydantic a configuração era feita em uma classe interna `Config`, na versão 2 do Pydantic é feita em um atributo `model_config`. Esse atributo recebe um `dict`, e para ter autocompletar e erros inline você pode importar e usar `SettingsConfigDict` para definir esse `dict`.
|
||||
|
||||
///
|
||||
|
||||
Aqui definimos a configuração `env_file` dentro da sua classe `Settings` do Pydantic e definimos o valor como o nome do arquivo dotenv que queremos usar.
|
||||
Aqui definimos a configuração `env_file` dentro da sua classe `Settings` do Pydantic e definimos o valor como o nome do arquivo com o arquivo dotenv que queremos usar.
|
||||
|
||||
### Criando o `Settings` apenas uma vez com `lru_cache` { #creating-the-settings-only-once-with-lru-cache }
|
||||
|
||||
Ler um arquivo do disco normalmente é uma operação custosa (lenta), então você provavelmente vai querer fazer isso apenas uma vez e depois reutilizar o mesmo objeto de configurações, em vez de lê-lo a cada requisição.
|
||||
Ler um arquivo do disco normalmente é uma operação custosa (lenta), então você provavelmente vai querer fazer isso apenas uma vez e depois reutilizar o mesmo objeto de configurações, em vez de lê-lo a cada request.
|
||||
|
||||
Mas toda vez que fizermos:
|
||||
|
||||
@@ -266,13 +222,13 @@ def get_settings():
|
||||
return Settings()
|
||||
```
|
||||
|
||||
criaríamos esse objeto para cada requisição e leríamos o arquivo `.env` para cada requisição. ⚠️
|
||||
criaríamos esse objeto para cada request e leríamos o arquivo `.env` para cada request. ⚠️
|
||||
|
||||
Mas como estamos usando o decorador `@lru_cache` por cima, o objeto `Settings` será criado apenas uma vez, na primeira vez em que for chamado. ✔️
|
||||
|
||||
{* ../../docs_src/settings/app03_an_py39/main.py hl[1,11] *}
|
||||
|
||||
Em qualquer chamada subsequente de `get_settings()` nas dependências das próximas requisições, em vez de executar o código interno de `get_settings()` e criar um novo objeto `Settings`, ele retornará o mesmo objeto que foi retornado na primeira chamada, repetidamente.
|
||||
Em qualquer chamada subsequente de `get_settings()` nas dependências para os próximos requests, em vez de executar o código interno de `get_settings()` e criar um novo objeto `Settings`, ele retornará o mesmo objeto que foi retornado na primeira chamada, repetidamente.
|
||||
|
||||
#### Detalhes Técnicos do `lru_cache` { #lru-cache-technical-details }
|
||||
|
||||
@@ -343,4 +299,4 @@ Você pode usar Pydantic Settings para lidar com as configurações da sua aplic
|
||||
|
||||
* Usando uma dependência você pode simplificar os testes.
|
||||
* Você pode usar arquivos `.env` com ele.
|
||||
* Usar `@lru_cache` permite evitar ler o arquivo dotenv repetidamente a cada requisição, enquanto permite sobrescrevê-lo durante os testes.
|
||||
* Usar `@lru_cache` permite evitar ler o arquivo dotenv repetidamente a cada request, enquanto permite sobrescrevê-lo durante os testes.
|
||||
|
||||
@@ -2,21 +2,23 @@
|
||||
|
||||
Se você tem uma aplicação FastAPI antiga, pode estar usando o Pydantic versão 1.
|
||||
|
||||
O FastAPI tem suporte ao Pydantic v1 ou v2 desde a versão 0.100.0.
|
||||
A versão 0.100.0 do FastAPI tinha suporte ao Pydantic v1 ou v2. Ela usaria o que estivesse instalado.
|
||||
|
||||
Se você tiver o Pydantic v2 instalado, ele será utilizado. Se, em vez disso, tiver o Pydantic v1, será ele que será utilizado.
|
||||
A versão 0.119.0 do FastAPI introduziu suporte parcial ao Pydantic v1 de dentro do Pydantic v2 (como `pydantic.v1`), para facilitar a migração para o v2.
|
||||
|
||||
O Pydantic v1 está agora descontinuado e o suporte a ele será removido nas próximas versões do FastAPI, você deveria migrar para o Pydantic v2. Assim, você terá as funcionalidades, melhorias e correções mais recentes.
|
||||
O FastAPI 0.126.0 removeu o suporte ao Pydantic v1, ao mesmo tempo em que ainda dá suporte ao `pydantic.v1` por mais algum tempo.
|
||||
|
||||
/// warning | Atenção
|
||||
|
||||
Além disso, a equipe do Pydantic interrompeu o suporte ao Pydantic v1 para as versões mais recentes do Python, a partir do **Python 3.14**.
|
||||
A equipe do Pydantic interrompeu o suporte ao Pydantic v1 para as versões mais recentes do Python, a partir do **Python 3.14**.
|
||||
|
||||
Isso inclui `pydantic.v1`, que não é mais suportado no Python 3.14 e superiores.
|
||||
|
||||
Se quiser usar as funcionalidades mais recentes do Python, você precisará garantir que usa o Pydantic v2.
|
||||
|
||||
///
|
||||
|
||||
Se você tem uma aplicação FastAPI antiga com Pydantic v1, aqui vou mostrar como migrá-la para o Pydantic v2 e as **novas funcionalidades no FastAPI 0.119.0** para ajudar em uma migração gradual.
|
||||
Se você tem uma aplicação FastAPI antiga com Pydantic v1, aqui vou mostrar como migrá-la para o Pydantic v2, e as **funcionalidades no FastAPI 0.119.0** para ajudar em uma migração gradual.
|
||||
|
||||
## Guia oficial { #official-guide }
|
||||
|
||||
@@ -44,7 +46,7 @@ Depois disso, você pode rodar os testes e verificar se tudo funciona. Se funcio
|
||||
|
||||
## Pydantic v1 no v2 { #pydantic-v1-in-v2 }
|
||||
|
||||
O Pydantic v2 inclui tudo do Pydantic v1 como um submódulo `pydantic.v1`.
|
||||
O Pydantic v2 inclui tudo do Pydantic v1 como um submódulo `pydantic.v1`. Mas isso não é mais suportado em versões acima do Python 3.13.
|
||||
|
||||
Isso significa que você pode instalar a versão mais recente do Pydantic v2 e importar e usar os componentes antigos do Pydantic v1 a partir desse submódulo, como se tivesse o Pydantic v1 antigo instalado.
|
||||
|
||||
@@ -86,7 +88,7 @@ graph TB
|
||||
style V2Field fill:#f9fff3
|
||||
```
|
||||
|
||||
...but, you can have separated models using Pydantic v1 and v2 in the same app.
|
||||
...mas, você pode ter modelos separados usando Pydantic v1 e v2 na mesma aplicação.
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
@@ -106,7 +108,7 @@ graph TB
|
||||
style V2Field fill:#f9fff3
|
||||
```
|
||||
|
||||
Em alguns casos, é até possível ter modelos Pydantic v1 e v2 na mesma operação de rota na sua aplicação FastAPI:
|
||||
Em alguns casos, é até possível ter modelos Pydantic v1 e v2 na mesma **operação de rota** na sua aplicação FastAPI:
|
||||
|
||||
{* ../../docs_src/pydantic_v1_in_v2/tutorial003_an_py310.py hl[2:3,6,12,21:22] *}
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
# Esquemas OpenAPI Separados para Entrada e Saída ou Não { #separate-openapi-schemas-for-input-and-output-or-not }
|
||||
|
||||
Ao usar **Pydantic v2**, o OpenAPI gerado é um pouco mais exato e **correto** do que antes. 😎
|
||||
Desde que o **Pydantic v2** foi lançado, o OpenAPI gerado é um pouco mais exato e **correto** do que antes. 😎
|
||||
|
||||
Inclusive, em alguns casos, ele terá até **dois JSON Schemas** no OpenAPI para o mesmo modelo Pydantic, para entrada e saída, dependendo se eles possuem **valores padrão**.
|
||||
De fato, em alguns casos, ele terá até **dois JSON Schemas** no OpenAPI para o mesmo modelo Pydantic, para entrada e saída, dependendo se eles têm **valores padrão**.
|
||||
|
||||
Vamos ver como isso funciona e como alterar se for necessário.
|
||||
Vamos ver como isso funciona e como alterar isso se você precisar fazer isso.
|
||||
|
||||
## Modelos Pydantic para Entrada e Saída { #pydantic-models-for-input-and-output }
|
||||
|
||||
@@ -34,11 +34,11 @@ Mas se você usar o mesmo modelo como saída, como aqui:
|
||||
|
||||
{* ../../docs_src/separate_openapi_schemas/tutorial001_py310.py hl[19] *}
|
||||
|
||||
... então, como `description` tem um valor padrão, se você **não retornar nada** para esse campo, ele ainda terá o **valor padrão**.
|
||||
... então, como `description` tem um valor padrão, se você **não retornar nada** para esse campo, ele ainda terá esse **valor padrão**.
|
||||
|
||||
### Modelo para Dados de Resposta de Saída { #model-for-output-response-data }
|
||||
|
||||
Se você interagir com a documentação e verificar a resposta, mesmo que o código não tenha adicionado nada em um dos campos `description`, a resposta JSON contém o valor padrão (`null`):
|
||||
Se você interagir com a documentação e verificar a resposta, mesmo que o código não tenha adicionado nada em um dos campos `description`, a response JSON contém o valor padrão (`null`):
|
||||
|
||||
<div class="screenshot">
|
||||
<img src="/img/tutorial/separate-openapi-schemas/image02.png">
|
||||
@@ -95,10 +95,8 @@ O suporte para `separate_input_output_schemas` foi adicionado no FastAPI `0.102.
|
||||
|
||||
### Mesmo Esquema para Modelos de Entrada e Saída na Documentação { #same-schema-for-input-and-output-models-in-docs }
|
||||
|
||||
E agora haverá um único esquema para entrada e saída para o modelo, apenas `Item`, e `description` **não será obrigatório**:
|
||||
E agora haverá um único esquema para entrada e saída para o modelo, apenas `Item`, e ele terá `description` como **não obrigatório**:
|
||||
|
||||
<div class="screenshot">
|
||||
<img src="/img/tutorial/separate-openapi-schemas/image05.png">
|
||||
</div>
|
||||
|
||||
Esse é o mesmo comportamento do Pydantic v1. 🤓
|
||||
|
||||
@@ -40,8 +40,8 @@ Os recursos chave são:
|
||||
* **Rápido**: alta performance, equivalente a **NodeJS** e **Go** (graças ao Starlette e Pydantic). [Um dos frameworks mais rápidos disponíveis](#performance).
|
||||
* **Rápido para codar**: Aumenta a velocidade para desenvolver recursos entre 200% a 300%. *
|
||||
* **Poucos bugs**: Reduz cerca de 40% de erros induzidos por humanos (desenvolvedores). *
|
||||
* **Intuitivo**: Grande suporte a _IDEs_. <abbr title="também conhecido como autocompletar, preenchimento automático, IntelliSense">Preenchimento automático</abbr> em todos os lugares. Menos tempo debugando.
|
||||
* **Fácil**: Projetado para ser fácil de aprender e usar. Menos tempo lendo documentação.
|
||||
* **Intuitivo**: Grande suporte a editores. <abbr title="também conhecido como autocompletar, preenchimento automático, IntelliSense">Completação</abbr> em todos os lugares. Menos tempo debugando.
|
||||
* **Fácil**: Projetado para ser fácil de aprender e usar. Menos tempo lendo docs.
|
||||
* **Enxuto**: Minimize duplicação de código. Múltiplas funcionalidades para cada declaração de parâmetro. Menos bugs.
|
||||
* **Robusto**: Tenha código pronto para produção. E com documentação interativa automática.
|
||||
* **Baseado em padrões**: Baseado em (e totalmente compatível com) os padrões abertos para APIs: <a href="https://github.com/OAI/OpenAPI-Specification" class="external-link" target="_blank">OpenAPI</a> (anteriormente conhecido como Swagger) e <a href="https://json-schema.org/" class="external-link" target="_blank">JSON Schema</a>.
|
||||
@@ -93,7 +93,7 @@ Os recursos chave são:
|
||||
|
||||
"*Estou extremamente entusiasmado com o **FastAPI**. É tão divertido!*"
|
||||
|
||||
<div style="text-align: right; margin-right: 10%;">Brian Okken - <strong><a href="https://pythonbytes.fm/episodes/show/123/time-to-right-the-py-wrongs?time_in_sec=855" target="_blank">Python Bytes</a> podcaster</strong> <a href="https://x.com/brianokken/status/1112220079972728832" target="_blank"><small>(ref)</small></a></div>
|
||||
<div style="text-align: right; margin-right: 10%;">Brian Okken - <strong><a href="https://pythonbytes.fm/episodes/show/123/time-to-right-the-py-wrongs?time_in_sec=855" target="_blank">Python Bytes</a> apresentador do podcast</strong> <a href="https://x.com/brianokken/status/1112220079972728832" target="_blank"><small>(ref)</small></a></div>
|
||||
|
||||
---
|
||||
|
||||
@@ -117,6 +117,12 @@ Os recursos chave são:
|
||||
|
||||
---
|
||||
|
||||
## Mini documentário do FastAPI { #fastapi-mini-documentary }
|
||||
|
||||
Há um <a href="https://www.youtube.com/watch?v=mpR8ngthqiE" class="external-link" target="_blank">mini documentário do FastAPI</a> lançado no final de 2025, você pode assisti-lo online:
|
||||
|
||||
<a href="https://www.youtube.com/watch?v=mpR8ngthqiE" target="_blank"><img src="https://fastapi.tiangolo.com/img/fastapi-documentary.jpg" alt="FastAPI Mini Documentary"></a>
|
||||
|
||||
## **Typer**, o FastAPI das interfaces de linhas de comando { #typer-the-fastapi-of-clis }
|
||||
|
||||
<a href="https://typer.tiangolo.com" target="_blank"><img src="https://typer.tiangolo.com/img/logo-margin/logo-margin-vector.svg" style="width: 20%;"></a>
|
||||
@@ -255,10 +261,10 @@ Você verá a resposta JSON como:
|
||||
|
||||
Você acabou de criar uma API que:
|
||||
|
||||
* Recebe requisições HTTP nas _rotas_ `/` e `/items/{item_id}`.
|
||||
* Ambas _rotas_ fazem <em>operações</em> `GET` (também conhecido como _métodos_ HTTP).
|
||||
* A _rota_ `/items/{item_id}` tem um _parâmetro de rota_ `item_id` que deve ser um `int`.
|
||||
* A _rota_ `/items/{item_id}` tem um _parâmetro query_ `q` `str` opcional.
|
||||
* Recebe requisições HTTP nos _paths_ `/` e `/items/{item_id}`.
|
||||
* Ambos _paths_ fazem <em>operações</em> `GET` (também conhecido como _métodos_ HTTP).
|
||||
* O _path_ `/items/{item_id}` tem um _parâmetro de path_ `item_id` que deve ser um `int`.
|
||||
* O _path_ `/items/{item_id}` tem um _parâmetro query_ `q` `str` opcional.
|
||||
|
||||
### Documentação Interativa da API { #interactive-api-docs }
|
||||
|
||||
@@ -370,7 +376,7 @@ item: Item
|
||||
* Validação até para objetos JSON profundamente aninhados.
|
||||
* <abbr title="também conhecido como: serialização, parsing, marshalling">Conversão</abbr> de dados de entrada: vindo da rede para dados e tipos Python. Consegue ler:
|
||||
* JSON.
|
||||
* Parâmetros de rota.
|
||||
* Parâmetros de path.
|
||||
* Parâmetros de _query_ .
|
||||
* _Cookies_.
|
||||
* Cabeçalhos.
|
||||
@@ -390,7 +396,7 @@ item: Item
|
||||
|
||||
Voltando ao código do exemplo anterior, **FastAPI** irá:
|
||||
|
||||
* Validar que existe um `item_id` na rota para requisições `GET` e `PUT`.
|
||||
* Validar que existe um `item_id` no path para requisições `GET` e `PUT`.
|
||||
* Validar que `item_id` é do tipo `int` para requisições `GET` e `PUT`.
|
||||
* Se não é validado, o cliente verá um útil, claro erro.
|
||||
* Verificar se existe um parâmetro de _query_ opcional nomeado como `q` (como em `http://127.0.0.1:8000/items/foo?q=somequery`) para requisições `GET`.
|
||||
@@ -399,7 +405,7 @@ Voltando ao código do exemplo anterior, **FastAPI** irá:
|
||||
* Para requisições `PUT` para `/items/{item_id}`, lerá o corpo como JSON:
|
||||
* Verifica que tem um atributo obrigatório `name` que deve ser `str`.
|
||||
* Verifica que tem um atributo obrigatório `price` que deve ser `float`.
|
||||
* Verifica que tem an atributo opcional `is_offer`, que deve ser `bool`, se presente.
|
||||
* Verifica que tem um atributo opcional `is_offer`, que deve ser `bool`, se presente.
|
||||
* Tudo isso também funciona para objetos JSON profundamente aninhados.
|
||||
* Converter de e para JSON automaticamente.
|
||||
* Documentar tudo com OpenAPI, que poderá ser usado por:
|
||||
@@ -452,9 +458,9 @@ Para um exemplo mais completo incluindo mais recursos, veja <a href="https://fas
|
||||
|
||||
### Implemente sua aplicação (opcional) { #deploy-your-app-optional }
|
||||
|
||||
Você pode opcionalmente implantar sua aplicação FastAPI na <a href="https://fastapicloud.com" class="external-link" target="_blank">FastAPI Cloud</a>, inscreva-se na lista de espera se ainda não o fez. 🚀
|
||||
Você pode opcionalmente implantar sua aplicação FastAPI na <a href="https://fastapicloud.com" class="external-link" target="_blank">FastAPI Cloud</a>, vá e participe da lista de espera caso ainda não o tenha feito. 🚀
|
||||
|
||||
Se você já tem uma conta na **FastAPI Cloud** (nós convidamos você da lista de espera 😉), pode implantar sua aplicação com um único comando.
|
||||
Se você já tem uma conta na **FastAPI Cloud** (nós convidamos você da lista de espera 😉), você pode implantar sua aplicação com um único comando.
|
||||
|
||||
Antes de implantar, certifique-se de que está autenticado:
|
||||
|
||||
@@ -506,7 +512,7 @@ Siga os tutoriais do seu provedor de nuvem para implantar aplicações FastAPI c
|
||||
|
||||
Testes de performance da _Independent TechEmpower_ mostram aplicações **FastAPI** rodando sob Uvicorn como <a href="https://www.techempower.com/benchmarks/#section=test&runid=7464e520-0dc2-473d-bd34-dbdfd7e85911&hw=ph&test=query&l=zijzen-7" class="external-link" target="_blank">um dos _frameworks_ Python mais rápidos disponíveis</a>, somente atrás de Starlette e Uvicorn (utilizados internamente pelo FastAPI). (*)
|
||||
|
||||
Para entender mais sobre performance, veja a seção <a href="https://fastapi.tiangolo.com/pt/benchmarks/" class="internal-link" target="_blank">Comparações</a>.
|
||||
Para entender mais sobre isso, veja a seção <a href="https://fastapi.tiangolo.com/pt/benchmarks/" class="internal-link" target="_blank">Comparações</a>.
|
||||
|
||||
## Dependências { #dependencies }
|
||||
|
||||
|
||||
@@ -31,11 +31,11 @@ Digamos que você tenha uma estrutura de arquivos como esta:
|
||||
|
||||
/// tip | Dica
|
||||
|
||||
Existem vários arquivos `__init__.py` presentes em cada diretório ou subdiretório.
|
||||
Existem vários arquivos `__init__.py`: um em cada diretório ou subdiretório.
|
||||
|
||||
Isso permite a importação de código de um arquivo para outro.
|
||||
Isso é o que permite importar código de um arquivo para outro.
|
||||
|
||||
Por exemplo, no arquivo `app/main.py`, você poderia ter uma linha como:
|
||||
Por exemplo, em `app/main.py`, você poderia ter uma linha como:
|
||||
|
||||
```
|
||||
from app.routers import items
|
||||
@@ -43,47 +43,47 @@ from app.routers import items
|
||||
|
||||
///
|
||||
|
||||
* O diretório `app` contém todo o código da aplicação. Ele possui um arquivo `app/__init__.py` vazio, o que o torna um "pacote Python" (uma coleção de "módulos Python"): `app`.
|
||||
* Dentro dele, o arquivo `app/main.py` está localizado em um pacote Python (diretório com `__init__.py`). Portanto, ele é um "módulo" desse pacote: `app.main`.
|
||||
* Existem também um arquivo `app/dependencies.py`, assim como o `app/main.py`, ele é um "módulo": `app.dependencies`.
|
||||
* O diretório `app` contém tudo. E ele tem um arquivo vazio `app/__init__.py`, então ele é um "pacote Python" (uma coleção de "módulos Python"): `app`.
|
||||
* Ele contém um arquivo `app/main.py`. Como ele está dentro de um pacote Python (um diretório com um arquivo `__init__.py`), ele é um "módulo" desse pacote: `app.main`.
|
||||
* Também há um arquivo `app/dependencies.py`, assim como `app/main.py`, ele é um "módulo": `app.dependencies`.
|
||||
* Há um subdiretório `app/routers/` com outro arquivo `__init__.py`, então ele é um "subpacote Python": `app.routers`.
|
||||
* O arquivo `app/routers/items.py` está dentro de um pacote, `app/routers/`, portanto, é um "submódulo": `app.routers.items`.
|
||||
* O mesmo com `app/routers/users.py`, ele é outro submódulo: `app.routers.users`.
|
||||
* Há também um subdiretório `app/internal/` com outro arquivo `__init__.py`, então ele é outro "subpacote Python":`app.internal`.
|
||||
* O arquivo `app/routers/items.py` está dentro de um pacote, `app/routers/`, então, ele é um submódulo: `app.routers.items`.
|
||||
* O mesmo com `app/routers/users.py`, ele é outro submódulo: `app.routers.users`.
|
||||
* Há também um subdiretório `app/internal/` com outro arquivo `__init__.py`, então ele é outro "subpacote Python": `app.internal`.
|
||||
* E o arquivo `app/internal/admin.py` é outro submódulo: `app.internal.admin`.
|
||||
|
||||
<img src="/img/tutorial/bigger-applications/package.drawio.svg">
|
||||
|
||||
A mesma estrutura de arquivos com comentários:
|
||||
|
||||
```
|
||||
```bash
|
||||
.
|
||||
├── app # "app" é um pacote Python
|
||||
│ ├── __init__.py # este arquivo torna "app" um "pacote Python"
|
||||
│ ├── main.py # "main" módulo, e.g. import app.main
|
||||
│ ├── dependencies.py # "dependencies" módulo, e.g. import app.dependencies
|
||||
│ └── routers # "routers" é um "subpacote Python"
|
||||
│ └── routers # "routers" é um "subpacote Python"
|
||||
│ │ ├── __init__.py # torna "routers" um "subpacote Python"
|
||||
│ │ ├── items.py # "items" submódulo, e.g. import app.routers.items
|
||||
│ │ └── users.py # "users" submódulo, e.g. import app.routers.users
|
||||
│ └── internal # "internal" é um "subpacote Python"
|
||||
│ ├── __init__.py # torna "internal" um "subpacote Python"
|
||||
│ └── internal # "internal" é um "subpacote Python"
|
||||
│ ├── __init__.py # torna "internal" um "subpacote Python"
|
||||
│ └── admin.py # "admin" submódulo, e.g. import app.internal.admin
|
||||
```
|
||||
|
||||
## `APIRouter` { #apirouter }
|
||||
|
||||
Vamos supor que o arquivo dedicado a lidar apenas com usuários seja o submódulo em `/app/routers/users.py`.
|
||||
Digamos que o arquivo dedicado a lidar apenas com usuários seja o submódulo em `/app/routers/users.py`.
|
||||
|
||||
Você quer manter as *operações de rota* relacionadas aos seus usuários separadas do restante do código, para mantê-lo organizado.
|
||||
|
||||
Mas ele ainda faz parte da mesma aplicação/web API **FastAPI** (faz parte do mesmo "pacote Python").
|
||||
|
||||
Você pode criar as *operações de rotas* para esse módulo usando o `APIRouter`.
|
||||
Você pode criar as *operações de rota* para esse módulo usando o `APIRouter`.
|
||||
|
||||
### Importe `APIRouter` { #import-apirouter }
|
||||
|
||||
você o importa e cria uma "instância" da mesma maneira que faria com a classe `FastAPI`:
|
||||
Você o importa e cria uma "instância" da mesma maneira que faria com a classe `FastAPI`:
|
||||
|
||||
{* ../../docs_src/bigger_applications/app_an_py39/routers/users.py hl[1,3] title["app/routers/users.py"] *}
|
||||
|
||||
@@ -91,7 +91,7 @@ você o importa e cria uma "instância" da mesma maneira que faria com a classe
|
||||
|
||||
E então você o utiliza para declarar suas *operações de rota*.
|
||||
|
||||
Utilize-o da mesma maneira que utilizaria a classe `FastAPI`:
|
||||
Utilize-o da mesma maneira que utilizaria a classe `FastAPI`:
|
||||
|
||||
{* ../../docs_src/bigger_applications/app_an_py39/routers/users.py hl[6,11,16] title["app/routers/users.py"] *}
|
||||
|
||||
@@ -151,7 +151,7 @@ Então, em vez de adicionar tudo isso a cada *operação de rota*, podemos adici
|
||||
|
||||
{* ../../docs_src/bigger_applications/app_an_py39/routers/items.py hl[5:10,16,21] title["app/routers/items.py"] *}
|
||||
|
||||
Como o caminho de cada *operação de rota* deve começar com `/`, como em:
|
||||
Como o path de cada *operação de rota* tem que começar com `/`, como em:
|
||||
|
||||
```Python hl_lines="1"
|
||||
@router.get("/{item_id}")
|
||||
@@ -173,7 +173,7 @@ Observe que, assim como [dependências em *decoradores de operação de rota*](d
|
||||
|
||||
///
|
||||
|
||||
O resultado final é que os caminhos dos itens agora são:
|
||||
O resultado final é que os paths dos itens agora são:
|
||||
|
||||
* `/items/`
|
||||
* `/items/{item_id}`
|
||||
@@ -186,7 +186,7 @@ O resultado final é que os caminhos dos itens agora são:
|
||||
* Todas essas *operações de rota* terão a lista de `dependencies` avaliada/executada antes delas.
|
||||
* Se você também declarar dependências em uma *operação de rota* específica, **elas também serão executadas**.
|
||||
* As dependências do roteador são executadas primeiro, depois as [`dependencies` no decorador](dependencies/dependencies-in-path-operation-decorators.md){.internal-link target=_blank} e, em seguida, as dependências de parâmetros normais.
|
||||
* Você também pode adicionar [dependências de `Segurança` com `scopes`](../advanced/security/oauth2-scopes.md){.internal-link target=_blank}.
|
||||
* Você também pode adicionar [`Security` dependencies com `scopes`](../advanced/security/oauth2-scopes.md){.internal-link target=_blank}.
|
||||
|
||||
/// tip | Dica
|
||||
|
||||
@@ -232,7 +232,7 @@ significaria:
|
||||
|
||||
Mas esse arquivo não existe, nossas dependências estão em um arquivo em `app/dependencies.py`.
|
||||
|
||||
Lembre-se de como nossa estrutura app/file se parece:
|
||||
Lembre-se de como nossa estrutura de app/arquivos se parece:
|
||||
|
||||
<img src="/img/tutorial/bigger-applications/package.drawio.svg">
|
||||
|
||||
@@ -246,7 +246,7 @@ from ..dependencies import get_token_header
|
||||
|
||||
significa:
|
||||
|
||||
* Começando no mesmo pacote em que este módulo (o arquivo `app/routers/items.py`) reside (o diretório `app/routers/`)...
|
||||
* Começando no mesmo pacote em que este módulo (o arquivo `app/routers/items.py`) vive (o diretório `app/routers/`)...
|
||||
* vá para o pacote pai (o diretório `app/`)...
|
||||
* e lá, encontre o módulo `dependencies` (o arquivo em `app/dependencies.py`)...
|
||||
* e dele, importe a função `get_token_header`.
|
||||
@@ -283,7 +283,7 @@ Mas ainda podemos adicionar _mais_ `tags` que serão aplicadas a uma *operação
|
||||
|
||||
/// tip | Dica
|
||||
|
||||
Esta última operação de caminho terá a combinação de tags: `["items", "custom"]`.
|
||||
Esta última operação de rota terá a combinação de tags: `["items", "custom"]`.
|
||||
|
||||
E também terá ambas as respostas na documentação, uma para `404` e uma para `403`.
|
||||
|
||||
@@ -376,7 +376,7 @@ Então, para poder usar ambos no mesmo arquivo, importamos os submódulos direta
|
||||
|
||||
{* ../../docs_src/bigger_applications/app_an_py39/main.py hl[5] title["app/main.py"] *}
|
||||
|
||||
### Inclua os `APIRouter`s para `usuários` e `itens` { #include-the-apirouters-for-users-and-items }
|
||||
### Inclua os `APIRouter`s para `users` e `items` { #include-the-apirouters-for-users-and-items }
|
||||
|
||||
Agora, vamos incluir os `router`s dos submódulos `users` e `items`:
|
||||
|
||||
@@ -390,7 +390,7 @@ E `items.router` contém o `APIRouter` dentro do arquivo `app/routers/items.py`.
|
||||
|
||||
///
|
||||
|
||||
Com `app.include_router()` podemos adicionar cada `APIRouter` ao aplicativo principal `FastAPI`.
|
||||
Com `app.include_router()` podemos adicionar cada `APIRouter` à aplicação principal `FastAPI`.
|
||||
|
||||
Ele incluirá todas as rotas daquele roteador como parte dele.
|
||||
|
||||
@@ -453,7 +453,7 @@ e funcionará corretamente, junto com todas as outras *operações de rota* adic
|
||||
|
||||
/// note | Detalhes Técnicos Avançados
|
||||
|
||||
**Observação**: este é um detalhe muito técnico que você provavelmente pode **simplesmente pular**.
|
||||
**Nota**: este é um detalhe muito técnico que você provavelmente pode **simplesmente pular**.
|
||||
|
||||
---
|
||||
|
||||
@@ -481,7 +481,7 @@ $ fastapi dev app/main.py
|
||||
|
||||
E abra os documentos em <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>.
|
||||
|
||||
Você verá a documentação automática da API, incluindo os caminhos de todos os submódulos, usando os caminhos (e prefixos) corretos e as tags corretas:
|
||||
Você verá a documentação automática da API, incluindo os paths de todos os submódulos, usando os paths (e prefixos) corretos e as tags corretas:
|
||||
|
||||
<img src="/img/tutorial/bigger-applications/image01.png">
|
||||
|
||||
@@ -495,10 +495,10 @@ Esse é um uso avançado que você pode não precisar, mas está lá caso precis
|
||||
|
||||
## Inclua um `APIRouter` em outro { #include-an-apirouter-in-another }
|
||||
|
||||
Da mesma forma que você pode incluir um `APIRouter` em um aplicativo `FastAPI`, você pode incluir um `APIRouter` em outro `APIRouter` usando:
|
||||
Da mesma forma que você pode incluir um `APIRouter` em uma aplicação `FastAPI`, você pode incluir um `APIRouter` em outro `APIRouter` usando:
|
||||
|
||||
```Python
|
||||
router.include_router(other_router)
|
||||
```
|
||||
|
||||
Certifique-se de fazer isso antes de incluir `router` no aplicativo `FastAPI`, para que as *operações de rota* de `other_router` também sejam incluídas.
|
||||
Certifique-se de fazer isso antes de incluir `router` na aplicação `FastAPI`, para que as *operações de rota* de `other_router` também sejam incluídas.
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
# Corpo - Atualizações { #body-updates }
|
||||
|
||||
## Atualização de dados existentes com `PUT` { #update-replacing-with-put }
|
||||
## Atualização substituindo com `PUT` { #update-replacing-with-put }
|
||||
|
||||
Para atualizar um item, você pode usar a operação <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PUT" class="external-link" target="_blank">HTTP `PUT`</a>.
|
||||
|
||||
Você pode usar `jsonable_encoder` para converter os dados de entrada em dados que podem ser armazenados como JSON (por exemplo, com um banco de dados NoSQL). Por exemplo, convertendo `datetime` em `str`.
|
||||
Você pode usar o `jsonable_encoder` para converter os dados de entrada em dados que podem ser armazenados como JSON (por exemplo, com um banco de dados NoSQL). Por exemplo, convertendo `datetime` em `str`.
|
||||
|
||||
{* ../../docs_src/body_updates/tutorial001_py310.py hl[28:33] *}
|
||||
|
||||
@@ -22,13 +22,13 @@ Isso significa que, se você quiser atualizar o item `bar` usando `PUT` com um c
|
||||
}
|
||||
```
|
||||
|
||||
Como ele não inclui o atributo já armazenado `"tax": 20.2`, o modelo de entrada assumiria o valor padrão de `"tax": 10.5`.
|
||||
como ele não inclui o atributo já armazenado `"tax": 20.2`, o modelo de entrada assumiria o valor padrão de `"tax": 10.5`.
|
||||
|
||||
E os dados seriam salvos com esse "novo" `tax` de `10.5`.
|
||||
|
||||
## Atualizações parciais com `PATCH` { #partial-updates-with-patch }
|
||||
|
||||
Você também pode usar a operação <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PATCH" class="external-link" target="_blank">HTTP `PATCH`</a> para atualizar parcialmente os dados.
|
||||
Você também pode usar a operação <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PATCH" class="external-link" target="_blank">HTTP `PATCH`</a> para atualizar os dados *parcialmente*.
|
||||
|
||||
Isso significa que você pode enviar apenas os dados que deseja atualizar, deixando o restante intacto.
|
||||
|
||||
@@ -40,27 +40,19 @@ E muitas equipes usam apenas `PUT`, mesmo para atualizações parciais.
|
||||
|
||||
Você é **livre** para usá-los como preferir, **FastAPI** não impõe restrições.
|
||||
|
||||
Mas este guia te dá uma ideia de como eles são destinados a serem usados.
|
||||
Mas este guia mostra, mais ou menos, como eles devem ser usados.
|
||||
|
||||
///
|
||||
|
||||
### Usando o parâmetro `exclude_unset` do Pydantic { #using-pydantics-exclude-unset-parameter }
|
||||
|
||||
Se você quiser receber atualizações parciais, é muito útil usar o parâmetro `exclude_unset` no método `.model_dump()` do modelo do Pydantic.
|
||||
Se você quiser receber atualizações parciais, é muito útil usar o parâmetro `exclude_unset` no `.model_dump()` do modelo do Pydantic.
|
||||
|
||||
Como `item.model_dump(exclude_unset=True)`.
|
||||
|
||||
/// info | Informação
|
||||
Isso geraria um `dict` com apenas os dados que foram definidos ao criar o modelo `item`, excluindo valores padrão.
|
||||
|
||||
No Pydantic v1, o método que era chamado `.dict()` e foi descontinuado (mas ainda suportado) no Pydantic v2. Agora, deve-se usar o método `.model_dump()`.
|
||||
|
||||
Os exemplos aqui usam `.dict()` para compatibilidade com o Pydantic v1, mas você deve usar `.model_dump()` a partir do Pydantic v2.
|
||||
|
||||
///
|
||||
|
||||
Isso gera um `dict` com apenas os dados definidos ao criar o modelo `item`, excluindo os valores padrão.
|
||||
|
||||
Então, você pode usar isso para gerar um `dict` com apenas os dados definidos (enviados na solicitação), omitindo valores padrão:
|
||||
Então, você pode usar isso para gerar um `dict` com apenas os dados definidos (enviados na request), omitindo valores padrão:
|
||||
|
||||
{* ../../docs_src/body_updates/tutorial002_py310.py hl[32] *}
|
||||
|
||||
@@ -68,31 +60,23 @@ Então, você pode usar isso para gerar um `dict` com apenas os dados definidos
|
||||
|
||||
Agora, você pode criar uma cópia do modelo existente usando `.model_copy()`, e passar o parâmetro `update` com um `dict` contendo os dados para atualizar.
|
||||
|
||||
/// info | Informação
|
||||
|
||||
No Pydantic v1, o método era chamado `.copy()`, ele foi descontinuado (mas ainda suportado) no Pydantic v2, e renomeado para `.model_copy()`.
|
||||
|
||||
Os exemplos aqui usam `.copy()` para compatibilidade com o Pydantic v1, mas você deve usar `.model_copy()` com o Pydantic v2.
|
||||
|
||||
///
|
||||
|
||||
Como `stored_item_model.model_copy(update=update_data)`:
|
||||
|
||||
{* ../../docs_src/body_updates/tutorial002_py310.py hl[33] *}
|
||||
|
||||
### Recapitulando as atualizações parciais { #partial-updates-recap }
|
||||
|
||||
Resumindo, para aplicar atualizações parciais você pode:
|
||||
Resumindo, para aplicar atualizações parciais você faria:
|
||||
|
||||
* (Opcionalmente) usar `PATCH` em vez de `PUT`.
|
||||
* Recuperar os dados armazenados.
|
||||
* Colocar esses dados em um modelo do Pydantic.
|
||||
* Gerar um `dict` sem valores padrão a partir do modelo de entrada (usando `exclude_unset`).
|
||||
* Dessa forma, você pode atualizar apenas os valores definidos pelo usuário, em vez de substituir os valores já armazenados com valores padrão em seu modelo.
|
||||
* Dessa forma, você pode atualizar apenas os valores realmente definidos pelo usuário, em vez de sobrescrever os valores já armazenados com valores padrão no seu modelo.
|
||||
* Criar uma cópia do modelo armazenado, atualizando seus atributos com as atualizações parciais recebidas (usando o parâmetro `update`).
|
||||
* Converter o modelo copiado em algo que possa ser armazenado no seu banco de dados (por exemplo, usando o `jsonable_encoder`).
|
||||
* Isso é comparável ao uso do método `.model_dump()`, mas garante (e converte) os valores para tipos de dados que possam ser convertidos em JSON, por exemplo, `datetime` para `str`.
|
||||
* Salvar os dados no seu banco de dados.
|
||||
* Converter o modelo copiado em algo que possa ser armazenado na sua BD (por exemplo, usando o `jsonable_encoder`).
|
||||
* Isso é comparável a usar o método `.model_dump()` do modelo novamente, mas garante (e converte) os valores para tipos de dados que possam ser convertidos em JSON, por exemplo, `datetime` em `str`.
|
||||
* Salvar os dados na sua BD.
|
||||
* Retornar o modelo atualizado.
|
||||
|
||||
{* ../../docs_src/body_updates/tutorial002_py310.py hl[28:35] *}
|
||||
@@ -101,7 +85,7 @@ Resumindo, para aplicar atualizações parciais você pode:
|
||||
|
||||
Você pode realmente usar essa mesma técnica com uma operação HTTP `PUT`.
|
||||
|
||||
Mas o exemplo aqui usa `PATCH` porque foi criado para esses casos de uso.
|
||||
Mas o exemplo aqui usa `PATCH` porque ele foi criado para esses casos de uso.
|
||||
|
||||
///
|
||||
|
||||
@@ -109,8 +93,8 @@ Mas o exemplo aqui usa `PATCH` porque foi criado para esses casos de uso.
|
||||
|
||||
Observe que o modelo de entrada ainda é validado.
|
||||
|
||||
Portanto, se você quiser receber atualizações parciais que possam omitir todos os atributos, precisará ter um modelo com todos os atributos marcados como opcionais (com valores padrão ou `None`).
|
||||
Portanto, se você quiser receber atualizações parciais que possam omitir todos os atributos, você precisa ter um modelo com todos os atributos marcados como opcionais (com valores padrão ou `None`).
|
||||
|
||||
Para distinguir os modelos com todos os valores opcionais para **atualizações** e modelos com valores obrigatórios para **criação**, você pode usar as ideias descritas em [Modelos Adicionais](extra-models.md){.internal-link target=_blank}.
|
||||
Para distinguir dos modelos com todos os valores opcionais para **atualizações** e modelos com valores obrigatórios para **criação**, você pode usar as ideias descritas em [Modelos Extras](extra-models.md){.internal-link target=_blank}.
|
||||
|
||||
///
|
||||
|
||||
@@ -10,7 +10,7 @@ Para declarar um corpo da **requisição**, você utiliza os modelos do <a href=
|
||||
|
||||
/// info | Informação
|
||||
|
||||
Para enviar dados, você deve usar um dos: `POST` (o mais comum), `PUT`, `DELETE` ou `PATCH`.
|
||||
Para enviar dados, (você deveria) usar um dos: `POST` (o mais comum), `PUT`, `DELETE` ou `PATCH`.
|
||||
|
||||
Enviar um corpo em uma requisição `GET` não tem um comportamento definido nas especificações, porém é suportado pelo FastAPI, apenas para casos de uso bem complexos/extremos.
|
||||
|
||||
@@ -32,7 +32,8 @@ Utilize os tipos Python padrão para todos os atributos:
|
||||
|
||||
{* ../../docs_src/body/tutorial001_py310.py hl[5:9] *}
|
||||
|
||||
Assim como quando declaramos parâmetros de consulta, quando um atributo do modelo possui um valor padrão, ele se torna opcional. Caso contrário, se torna obrigatório. Use `None` para torná-lo opcional.
|
||||
|
||||
Assim como quando declaramos parâmetros de consulta, quando um atributo do modelo possui um valor padrão, ele não é obrigatório. Caso contrário, é obrigatório. Use `None` para torná-lo apenas opcional.
|
||||
|
||||
Por exemplo, o modelo acima declara um JSON "`object`" (ou `dict` no Python) como esse:
|
||||
|
||||
@@ -73,7 +74,7 @@ Apenas com essa declaração de tipos do Python, o **FastAPI** irá:
|
||||
* Entregar a você a informação recebida no parâmetro `item`.
|
||||
* Como você o declarou na função como do tipo `Item`, você também terá o suporte do editor (completação, etc) para todos os atributos e seus tipos.
|
||||
* Gerar definições de <a href="https://json-schema.org" class="external-link" target="_blank">JSON Schema</a> para o seu modelo; você também pode usá-las em qualquer outro lugar se fizer sentido para o seu projeto.
|
||||
* Esses schemas farão parte do esquema OpenAPI gerado, e serão usados pelas <abbr title="User Interfaces – Interfaces de usuário">UIs</abbr> de documentação automática.
|
||||
* Esses schemas farão parte do esquema OpenAPI gerado, e serão usados pelas <abbr title="User Interfaces - Interfaces de usuário">UIs</abbr> de documentação automática.
|
||||
|
||||
## Documentação automática { #automatic-docs }
|
||||
|
||||
@@ -113,7 +114,7 @@ Se você utiliza o <a href="https://www.jetbrains.com/pycharm/" class="external-
|
||||
|
||||
Melhora o suporte do editor para seus modelos Pydantic com:
|
||||
|
||||
* preenchimento automático
|
||||
* auto-completion
|
||||
* verificação de tipos
|
||||
* refatoração
|
||||
* buscas
|
||||
@@ -127,14 +128,6 @@ Dentro da função, você pode acessar todos os atributos do objeto do modelo di
|
||||
|
||||
{* ../../docs_src/body/tutorial002_py310.py *}
|
||||
|
||||
/// info | Informação
|
||||
|
||||
No Pydantic v1 o método se chamava `.dict()`, ele foi descontinuado (mas ainda é suportado) no Pydantic v2, e renomeado para `.model_dump()`.
|
||||
|
||||
Os exemplos aqui usam `.dict()` para compatibilidade com o Pydantic v1, mas você deve usar `.model_dump()` se puder usar o Pydantic v2.
|
||||
|
||||
///
|
||||
|
||||
## Corpo da requisição + parâmetros de rota { #request-body-path-parameters }
|
||||
|
||||
Você pode declarar parâmetros de rota e corpo da requisição ao mesmo tempo.
|
||||
@@ -143,6 +136,7 @@ O **FastAPI** irá reconhecer que os parâmetros da função que combinam com pa
|
||||
|
||||
{* ../../docs_src/body/tutorial003_py310.py hl[15:16] *}
|
||||
|
||||
|
||||
## Corpo da requisição + parâmetros de rota + parâmetros de consulta { #request-body-path-query-parameters }
|
||||
|
||||
Você também pode declarar parâmetros de **corpo**, **rota** e **consulta**, ao mesmo tempo.
|
||||
|
||||
@@ -22,21 +22,13 @@ Aqui está uma ideia geral de como os modelos poderiam parecer com seus campos d
|
||||
|
||||
{* ../../docs_src/extra_models/tutorial001_py310.py hl[7,9,14,20,22,27:28,31:33,38:39] *}
|
||||
|
||||
/// info | Informação
|
||||
### Sobre `**user_in.model_dump()` { #about-user-in-model-dump }
|
||||
|
||||
No Pydantic v1 o método se chamava `.dict()`, ele foi descontinuado (mas ainda é suportado) no Pydantic v2 e renomeado para `.model_dump()`.
|
||||
|
||||
Os exemplos aqui usam `.dict()` por compatibilidade com o Pydantic v1, mas você deve usar `.model_dump()` se puder usar o Pydantic v2.
|
||||
|
||||
///
|
||||
|
||||
### Sobre `**user_in.dict()` { #about-user-in-dict }
|
||||
|
||||
#### O `.dict()` do Pydantic { #pydantics-dict }
|
||||
#### O `.model_dump()` do Pydantic { #pydantics-model-dump }
|
||||
|
||||
`user_in` é um modelo Pydantic da classe `UserIn`.
|
||||
|
||||
Os modelos Pydantic possuem um método `.dict()` que retorna um `dict` com os dados do modelo.
|
||||
Os modelos Pydantic possuem um método `.model_dump()` que retorna um `dict` com os dados do modelo.
|
||||
|
||||
Então, se criarmos um objeto Pydantic `user_in` como:
|
||||
|
||||
@@ -47,7 +39,7 @@ user_in = UserIn(username="john", password="secret", email="john.doe@example.com
|
||||
e depois chamarmos:
|
||||
|
||||
```Python
|
||||
user_dict = user_in.dict()
|
||||
user_dict = user_in.model_dump()
|
||||
```
|
||||
|
||||
agora temos um `dict` com os dados na variável `user_dict` (é um `dict` em vez de um objeto de modelo Pydantic).
|
||||
@@ -103,20 +95,20 @@ UserInDB(
|
||||
|
||||
#### Um modelo Pydantic a partir do conteúdo de outro { #a-pydantic-model-from-the-contents-of-another }
|
||||
|
||||
Como no exemplo acima, obtivemos o `user_dict` a partir do `user_in.dict()`, este código:
|
||||
Como no exemplo acima, obtivemos o `user_dict` a partir do `user_in.model_dump()`, este código:
|
||||
|
||||
```Python
|
||||
user_dict = user_in.dict()
|
||||
user_dict = user_in.model_dump()
|
||||
UserInDB(**user_dict)
|
||||
```
|
||||
|
||||
seria equivalente a:
|
||||
|
||||
```Python
|
||||
UserInDB(**user_in.dict())
|
||||
UserInDB(**user_in.model_dump())
|
||||
```
|
||||
|
||||
...porque `user_in.dict()` é um `dict`, e depois fazemos o Python "desembrulhá-lo" passando-o para `UserInDB` precedido por `**`.
|
||||
...porque `user_in.model_dump()` é um `dict`, e depois fazemos o Python "desembrulhá-lo" passando-o para `UserInDB` precedido por `**`.
|
||||
|
||||
Então, obtemos um modelo Pydantic a partir dos dados em outro modelo Pydantic.
|
||||
|
||||
@@ -125,7 +117,7 @@ Então, obtemos um modelo Pydantic a partir dos dados em outro modelo Pydantic.
|
||||
E, então, adicionando o argumento de palavra-chave extra `hashed_password=hashed_password`, como em:
|
||||
|
||||
```Python
|
||||
UserInDB(**user_in.dict(), hashed_password=hashed_password)
|
||||
UserInDB(**user_in.model_dump(), hashed_password=hashed_password)
|
||||
```
|
||||
|
||||
...acaba sendo como:
|
||||
@@ -166,7 +158,7 @@ Dessa forma, podemos declarar apenas as diferenças entre os modelos (com `passw
|
||||
|
||||
## `Union` ou `anyOf` { #union-or-anyof }
|
||||
|
||||
Você pode declarar uma resposta como o `Union` de dois ou mais tipos, o que significa que a resposta seria qualquer um deles.
|
||||
Você pode declarar uma response como o `Union` de dois ou mais tipos, o que significa que a response seria qualquer um deles.
|
||||
|
||||
Isso será definido no OpenAPI com `anyOf`.
|
||||
|
||||
@@ -196,7 +188,7 @@ Mas se colocarmos isso na atribuição `response_model=PlaneItem | CarItem`, ter
|
||||
|
||||
## Lista de modelos { #list-of-models }
|
||||
|
||||
Da mesma forma, você pode declarar respostas de listas de objetos.
|
||||
Da mesma forma, você pode declarar responses de listas de objetos.
|
||||
|
||||
Para isso, use o padrão Python `typing.List` (ou simplesmente `list` no Python 3.9 e superior):
|
||||
|
||||
@@ -204,7 +196,7 @@ Para isso, use o padrão Python `typing.List` (ou simplesmente `list` no Python
|
||||
|
||||
## Resposta com `dict` arbitrário { #response-with-arbitrary-dict }
|
||||
|
||||
Você também pode declarar uma resposta usando um simples `dict` arbitrário, declarando apenas o tipo das chaves e valores, sem usar um modelo Pydantic.
|
||||
Você também pode declarar uma response usando um simples `dict` arbitrário, declarando apenas o tipo das chaves e valores, sem usar um modelo Pydantic.
|
||||
|
||||
Isso é útil se você não souber os nomes de campo / atributo válidos (que seriam necessários para um modelo Pydantic) antecipadamente.
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Parâmetros de consulta e validações de string { #query-parameters-and-string-validations }
|
||||
|
||||
O **FastAPI** permite declarar informações adicionais e validações para os seus parâmetros.
|
||||
O **FastAPI** permite declarar informações adicionais e validação para os seus parâmetros.
|
||||
|
||||
Vamos usar esta aplicação como exemplo:
|
||||
|
||||
@@ -33,7 +33,7 @@ Para isso, primeiro importe:
|
||||
|
||||
O FastAPI adicionou suporte a `Annotated` (e passou a recomendá-lo) na versão 0.95.0.
|
||||
|
||||
Se você tiver uma versão mais antiga, terá erros ao tentar usar `Annotated`.
|
||||
Se você tiver uma versão mais antiga, (você deveria) obteria erros ao tentar usar `Annotated`.
|
||||
|
||||
Certifique-se de [Atualizar a versão do FastAPI](../deployment/versions.md#upgrading-the-fastapi-versions){.internal-link target=_blank} para pelo menos 0.95.1 antes de usar `Annotated`.
|
||||
|
||||
@@ -109,7 +109,7 @@ Agora o FastAPI vai:
|
||||
|
||||
## Alternativa (antiga): `Query` como valor padrão { #alternative-old-query-as-the-default-value }
|
||||
|
||||
Versões anteriores do FastAPI (antes de <abbr title="antes de 2023-03">0.95.0</abbr>) exigiam que você usasse `Query` como valor padrão do seu parâmetro, em vez de colocá-lo em `Annotated`. É muito provável que você veja código assim por aí, então vou te explicar.
|
||||
Versões anteriores do FastAPI (antes de <abbr title="before 2023-03">0.95.0</abbr>) exigiam que você usasse `Query` como valor padrão do seu parâmetro, em vez de colocá-lo em `Annotated`, é muito provável que você veja código assim por aí, então vou te explicar.
|
||||
|
||||
/// tip | Dica
|
||||
|
||||
@@ -206,20 +206,6 @@ Se você se sentir perdido com essas ideias de **"expressão regular"**, não se
|
||||
|
||||
Agora você sabe que, sempre que precisar delas, pode usá-las no **FastAPI**.
|
||||
|
||||
### Pydantic v1 `regex` em vez de `pattern` { #pydantic-v1-regex-instead-of-pattern }
|
||||
|
||||
Antes da versão 2 do Pydantic e antes do FastAPI 0.100.0, o parâmetro se chamava `regex` em vez de `pattern`, mas agora está descontinuado.
|
||||
|
||||
Você ainda pode ver algum código usando isso:
|
||||
|
||||
//// tab | Pydantic v1
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial004_regex_an_py310.py hl[11] *}
|
||||
|
||||
////
|
||||
|
||||
Mas saiba que isso está descontinuado e deve ser atualizado para usar o novo parâmetro `pattern`. 🤓
|
||||
|
||||
## Valores padrão { #default-values }
|
||||
|
||||
Você pode, claro, usar valores padrão diferentes de `None`.
|
||||
@@ -280,7 +266,7 @@ Então, com uma URL como:
|
||||
http://localhost:8000/items/?q=foo&q=bar
|
||||
```
|
||||
|
||||
você receberá os múltiplos valores do *parâmetro de consulta* `q` (`foo` e `bar`) em uma `list` Python dentro da sua *função de operação de rota*, no *parâmetro da função* `q`.
|
||||
(você deveria) receber os múltiplos valores dos *parâmetros de consulta* `q` (`foo` e `bar`) em uma `list` Python dentro da sua *função de operação de rota*, no *parâmetro da função* `q`.
|
||||
|
||||
Assim, a resposta para essa URL seria:
|
||||
|
||||
@@ -386,7 +372,7 @@ Então você pode declarar um `alias`, e esse alias será usado para encontrar o
|
||||
|
||||
Agora digamos que você não gosta mais desse parâmetro.
|
||||
|
||||
Você tem que deixá-lo por um tempo, pois há clientes usando-o, mas quer que a documentação mostre claramente que ele está <abbr title="obsoleto, recomenda-se não usá-lo">descontinuado</abbr>.
|
||||
Você tem que deixá-lo por um tempo, pois há clientes usando-o, mas quer que a documentação mostre claramente que ele está <abbr title="obsolete, recommended not to use it - obsoleto, recomendado não o usar">deprecated</abbr>.
|
||||
|
||||
Então passe o parâmetro `deprecated=True` para `Query`:
|
||||
|
||||
@@ -416,7 +402,7 @@ O Pydantic também tem <a href="https://docs.pydantic.dev/latest/concepts/valida
|
||||
|
||||
///
|
||||
|
||||
Por exemplo, este validador personalizado verifica se o ID do item começa com `isbn-` para um número de livro <abbr title="ISBN significa Número Padrão Internacional de Livro">ISBN</abbr> ou com `imdb-` para um ID de URL de filme <abbr title="IMDB (Internet Movie Database) é um site com informações sobre filmes">IMDB</abbr>:
|
||||
Por exemplo, este validador personalizado verifica se o ID do item começa com `isbn-` para um número de livro <abbr title="ISBN means International Standard Book Number - ISBN significa Número Padrão Internacional de Livro">ISBN</abbr> ou com `imdb-` para um ID de URL de filme <abbr title="IMDB (Internet Movie Database) is a website with information about movies - IMDB (Internet Movie Database) é um site com informações sobre filmes">IMDB</abbr>:
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py hl[5,16:19,24] *}
|
||||
|
||||
@@ -440,7 +426,7 @@ O ponto importante é apenas usar **`AfterValidator` com uma função dentro de
|
||||
|
||||
---
|
||||
|
||||
Mas se você está curioso sobre este exemplo específico e ainda entretido, aqui vão alguns detalhes extras.
|
||||
Mas se você está curioso sobre este exemplo específico de código e ainda entretido, aqui vão alguns detalhes extras.
|
||||
|
||||
#### String com `value.startswith()` { #string-with-value-startswith }
|
||||
|
||||
|
||||
@@ -252,20 +252,6 @@ Então, se você enviar uma solicitação para essa *operação de rota* para o
|
||||
|
||||
/// info | Informação
|
||||
|
||||
No Pydantic v1, o método era chamado `.dict()`, ele foi descontinuado (mas ainda suportado) no Pydantic v2 e renomeado para `.model_dump()`.
|
||||
|
||||
Os exemplos aqui usam `.dict()` para compatibilidade com Pydantic v1, mas você deve usar `.model_dump()` em vez disso se puder usar Pydantic v2.
|
||||
|
||||
///
|
||||
|
||||
/// info | Informação
|
||||
|
||||
O FastAPI usa `.dict()` do modelo Pydantic com <a href="https://docs.pydantic.dev/1.10/usage/exporting_models/#modeldict" class="external-link" target="_blank">seu parâmetro `exclude_unset`</a> para chegar a isso.
|
||||
|
||||
///
|
||||
|
||||
/// info | Informação
|
||||
|
||||
Você também pode usar:
|
||||
|
||||
* `response_model_exclude_defaults=True`
|
||||
|
||||
@@ -8,39 +8,17 @@ Aqui estão várias maneiras de fazer isso.
|
||||
|
||||
Você pode declarar `examples` para um modelo Pydantic que serão adicionados ao JSON Schema gerado.
|
||||
|
||||
//// tab | Pydantic v2
|
||||
|
||||
{* ../../docs_src/schema_extra_example/tutorial001_py310.py hl[13:24] *}
|
||||
|
||||
////
|
||||
|
||||
//// tab | Pydantic v1
|
||||
|
||||
{* ../../docs_src/schema_extra_example/tutorial001_pv1_py310.py hl[13:23] *}
|
||||
|
||||
////
|
||||
|
||||
Essas informações extras serão adicionadas como estão ao **JSON Schema** de saída para esse modelo e serão usadas na documentação da API.
|
||||
|
||||
//// tab | Pydantic v2
|
||||
Você pode usar o atributo `model_config`, que recebe um `dict`, conforme descrito na <a href="https://docs.pydantic.dev/latest/api/config/" class="external-link" target="_blank">documentação do Pydantic: Configuration</a>.
|
||||
|
||||
Na versão 2 do Pydantic, você usaria o atributo `model_config`, que recebe um `dict`, conforme descrito na <a href="https://docs.pydantic.dev/latest/api/config/" class="external-link" target="_blank">documentação do Pydantic: Configuration</a>.
|
||||
|
||||
Você pode definir `"json_schema_extra"` com um `dict` contendo quaisquer dados adicionais que você queira que apareçam no JSON Schema gerado, incluindo `examples`.
|
||||
|
||||
////
|
||||
|
||||
//// tab | Pydantic v1
|
||||
|
||||
Na versão 1 do Pydantic, você usaria uma classe interna `Config` e `schema_extra`, conforme descrito na <a href="https://docs.pydantic.dev/1.10/usage/schema/#schema-customization" class="external-link" target="_blank">documentação do Pydantic: Schema customization</a>.
|
||||
|
||||
Você pode definir `schema_extra` com um `dict` contendo quaisquer dados adicionais que você queira que apareçam no JSON Schema gerado, incluindo `examples`.
|
||||
|
||||
////
|
||||
Você pode definir `"json_schema_extra"` com um `dict` contendo quaisquer dados adicionais que você gostaria que aparecessem no JSON Schema gerado, incluindo `examples`.
|
||||
|
||||
/// tip | Dica
|
||||
|
||||
Você pode usar a mesma técnica para estender o JSON Schema e adicionar suas próprias informações extras personalizadas.
|
||||
Você poderia usar a mesma técnica para estender o JSON Schema e adicionar suas próprias informações extras personalizadas.
|
||||
|
||||
Por exemplo, você poderia usá-la para adicionar metadados para uma interface de usuário de front-end, etc.
|
||||
|
||||
@@ -100,13 +78,13 @@ No entanto, <abbr title="2023-08-26">no momento em que isto foi escrito</abbr>,
|
||||
|
||||
### `examples` específicos do OpenAPI { #openapi-specific-examples }
|
||||
|
||||
Antes do **JSON Schema** suportar `examples`, o OpenAPI já tinha suporte para um campo diferente também chamado `examples`.
|
||||
Desde antes de o **JSON Schema** suportar `examples`, o OpenAPI já tinha suporte para um campo diferente também chamado `examples`.
|
||||
|
||||
Esse `examples` específico do OpenAPI vai em outra seção da especificação. Ele fica nos **detalhes de cada função de operação de rota**, não dentro de cada JSON Schema.
|
||||
Esse `examples` **específico do OpenAPI** vai em outra seção da especificação do OpenAPI. Ele fica nos **detalhes de cada *operação de rota***, não dentro de cada JSON Schema.
|
||||
|
||||
E o Swagger UI tem suportado esse campo `examples` particular há algum tempo. Então, você pode usá-lo para **mostrar** diferentes **exemplos na UI da documentação**.
|
||||
|
||||
O formato desse campo `examples` específico do OpenAPI é um `dict` com **vários exemplos** (em vez de uma `list`), cada um com informações extras que também serão adicionadas ao **OpenAPI**.
|
||||
O formato desse campo específico do OpenAPI `examples` é um `dict` com **vários exemplos** (em vez de uma `list`), cada um com informações extras que também serão adicionadas ao **OpenAPI**.
|
||||
|
||||
Isso não vai dentro de cada JSON Schema contido no OpenAPI, vai fora, diretamente na *operação de rota*.
|
||||
|
||||
@@ -167,12 +145,12 @@ O JSON Schema não tinha `examples`, então o OpenAPI adicionou seu próprio cam
|
||||
|
||||
O OpenAPI também adicionou os campos `example` e `examples` a outras partes da especificação:
|
||||
|
||||
* <a href="https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#parameter-object" class="external-link" target="_blank">`Parameter Object` (na especificação)</a>, usado no FastAPI por:
|
||||
* <a href="https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#parameter-object" class="external-link" target="_blank">`Parameter Object` (na especificação)</a> que era usado no FastAPI por:
|
||||
* `Path()`
|
||||
* `Query()`
|
||||
* `Header()`
|
||||
* `Cookie()`
|
||||
* <a href="https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#media-type-object" class="external-link" target="_blank">`Request Body Object`, no campo `content`, no `Media Type Object` (na especificação)</a>, usado no FastAPI por:
|
||||
* <a href="https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#media-type-object" class="external-link" target="_blank">`Request Body Object`, no campo `content`, no `Media Type Object` (na especificação)</a> que era usado no FastAPI por:
|
||||
* `Body()`
|
||||
* `File()`
|
||||
* `Form()`
|
||||
@@ -185,13 +163,13 @@ Esse parâmetro antigo `examples` específico do OpenAPI agora é `openapi_examp
|
||||
|
||||
### Campo `examples` do JSON Schema { #json-schemas-examples-field }
|
||||
|
||||
Depois, o JSON Schema adicionou um campo <a href="https://json-schema.org/draft/2019-09/json-schema-validation.html#rfc.section.9.5" class="external-link" target="_blank">`examples`</a> em uma nova versão da especificação.
|
||||
Mas então o JSON Schema adicionou um campo <a href="https://json-schema.org/draft/2019-09/json-schema-validation.html#rfc.section.9.5" class="external-link" target="_blank">`examples`</a> em uma nova versão da especificação.
|
||||
|
||||
E então o novo OpenAPI 3.1.0 passou a se basear na versão mais recente (JSON Schema 2020-12), que incluiu esse novo campo `examples`.
|
||||
|
||||
Agora, esse novo campo `examples` tem precedência sobre o antigo (e customizado) campo único `example`, que agora está descontinuado.
|
||||
E agora esse novo campo `examples` tem precedência sobre o antigo campo único `example` (e customizado), que agora está descontinuado.
|
||||
|
||||
Esse novo campo `examples` no JSON Schema é **apenas uma `list`** de exemplos, não um `dict` com metadados extras como nos outros lugares do OpenAPI (descritos acima).
|
||||
Esse novo campo `examples` no JSON Schema é **apenas uma `list`** de exemplos, não um dict com metadados extras como nos outros lugares do OpenAPI (descritos acima).
|
||||
|
||||
/// info | Informação
|
||||
|
||||
@@ -213,7 +191,7 @@ Mas agora que o FastAPI 0.99.0 e superiores usam o OpenAPI 3.1.0, que usa o JSON
|
||||
|
||||
### Swagger UI e `examples` específicos do OpenAPI { #swagger-ui-and-openapi-specific-examples }
|
||||
|
||||
Como o Swagger UI não suportava vários exemplos no JSON Schema (em 2023-08-26), os usuários não tinham uma forma de mostrar vários exemplos na documentação.
|
||||
Agora, como o Swagger UI não suportava vários exemplos no JSON Schema (em 2023-08-26), os usuários não tinham uma forma de mostrar vários exemplos na documentação.
|
||||
|
||||
Para resolver isso, o FastAPI `0.103.0` **adicionou suporte** para declarar o mesmo antigo campo **específico do OpenAPI** `examples` com o novo parâmetro `openapi_examples`. 🤓
|
||||
|
||||
|
||||
@@ -130,9 +130,14 @@ def new_lang(lang: str = typer.Argument(..., callback=lang_callback)):
|
||||
new_path.mkdir()
|
||||
new_config_path: Path = Path(new_path) / mkdocs_name
|
||||
new_config_path.write_text("INHERIT: ../en/mkdocs.yml\n", encoding="utf-8")
|
||||
new_llm_prompt_path: Path = new_path / "llm-prompt.md"
|
||||
new_llm_prompt_path.write_text("", encoding="utf-8")
|
||||
print(f"Successfully initialized: {new_path}")
|
||||
new_config_docs_path: Path = new_path / "docs"
|
||||
new_config_docs_path.mkdir()
|
||||
en_index_path: Path = en_docs_path / "docs" / "index.md"
|
||||
new_index_path: Path = new_config_docs_path / "index.md"
|
||||
en_index_content = en_index_path.read_text(encoding="utf-8")
|
||||
new_index_content = f"{missing_translation_snippet}\n\n{en_index_content}"
|
||||
new_index_path.write_text(new_index_content, encoding="utf-8")
|
||||
typer.secho(f"Successfully initialized: {new_path}", color=typer.colors.GREEN)
|
||||
update_languages()
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user