Browse Source

Merge branch 'master' into fix/response_model_default_factory

pull/9704/head
Peanut 2 years ago
committed by GitHub
parent
commit
4544b1e32d
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 7
      .github/actions/watch-previews/Dockerfile
  2. 10
      .github/actions/watch-previews/action.yml
  3. 101
      .github/actions/watch-previews/app/main.py
  4. 87
      .github/workflows/build-docs.yml
  5. 21
      .github/workflows/deploy-docs.yml
  6. 2
      .github/workflows/publish.yml
  7. 1
      .gitignore
  8. 1
      README.md
  9. 1
      docs/az/docs/index.md
  10. 1
      docs/de/docs/index.md
  11. 4
      docs/en/data/external_links.yml
  12. 1
      docs/en/docs/index.md
  13. 42
      docs/en/docs/release-notes.md
  14. 2
      docs/en/docs/tutorial/debugging.md
  15. 6
      docs/en/docs/tutorial/schema-extra-example.md
  16. 2
      docs/en/docs/tutorial/security/index.md
  17. 4
      docs/en/mkdocs.yml
  18. 1
      docs/es/docs/index.md
  19. 2
      docs/es/docs/tutorial/first-steps.md
  20. 1
      docs/fa/docs/index.md
  21. 1
      docs/fr/docs/index.md
  22. 1
      docs/he/docs/index.md
  23. 1
      docs/id/docs/index.md
  24. 1
      docs/it/docs/index.md
  25. 1
      docs/ja/docs/index.md
  26. 1
      docs/ko/docs/index.md
  27. 1
      docs/nl/docs/index.md
  28. 1
      docs/pl/docs/index.md
  29. 1
      docs/pt/docs/index.md
  30. 1
      docs/ru/docs/index.md
  31. 111
      docs/ru/docs/tutorial/metadata.md
  32. 179
      docs/ru/docs/tutorial/path-operation-configuration.md
  33. 2
      docs/ru/mkdocs.yml
  34. 1
      docs/sq/docs/index.md
  35. 1
      docs/sv/docs/index.md
  36. 1
      docs/tr/docs/index.md
  37. 1
      docs/uk/docs/index.md
  38. 16
      docs/zh/docs/advanced/security/index.md
  39. 433
      docs/zh/docs/advanced/settings.md
  40. 214
      docs/zh/docs/advanced/websockets.md
  41. 1
      docs/zh/docs/index.md
  42. 212
      docs/zh/docs/tutorial/testing.md
  43. 5
      docs/zh/mkdocs.yml
  44. 2
      fastapi/__init__.py
  45. 4
      requirements-docs.txt
  46. 4
      requirements-tests.txt
  47. 4
      requirements.txt
  48. 152
      scripts/docs.py
  49. 11
      scripts/zip-docs.sh

7
.github/actions/watch-previews/Dockerfile

@ -1,7 +0,0 @@
FROM python:3.7
RUN pip install httpx PyGithub "pydantic==1.5.1"
COPY ./app /app
CMD ["python", "/app/main.py"]

10
.github/actions/watch-previews/action.yml

@ -1,10 +0,0 @@
name: "Watch docs previews in PRs"
description: "Check PRs and trigger new docs deploys"
author: "Sebastián Ramírez <[email protected]>"
inputs:
token:
description: 'Token for the repo. Can be passed in using {{ secrets.GITHUB_TOKEN }}'
required: true
runs:
using: 'docker'
image: 'Dockerfile'

101
.github/actions/watch-previews/app/main.py

@ -1,101 +0,0 @@
import logging
from datetime import datetime
from pathlib import Path
from typing import List, Union
import httpx
from github import Github
from github.NamedUser import NamedUser
from pydantic import BaseModel, BaseSettings, SecretStr
github_api = "https://api.github.com"
netlify_api = "https://api.netlify.com"
class Settings(BaseSettings):
input_token: SecretStr
github_repository: str
github_event_path: Path
github_event_name: Union[str, None] = None
class Artifact(BaseModel):
id: int
node_id: str
name: str
size_in_bytes: int
url: str
archive_download_url: str
expired: bool
created_at: datetime
updated_at: datetime
class ArtifactResponse(BaseModel):
total_count: int
artifacts: List[Artifact]
def get_message(commit: str) -> str:
return f"Docs preview for commit {commit} at"
if __name__ == "__main__":
logging.basicConfig(level=logging.INFO)
settings = Settings()
logging.info(f"Using config: {settings.json()}")
g = Github(settings.input_token.get_secret_value())
repo = g.get_repo(settings.github_repository)
owner: NamedUser = repo.owner
headers = {"Authorization": f"token {settings.input_token.get_secret_value()}"}
prs = list(repo.get_pulls(state="open"))
response = httpx.get(
f"{github_api}/repos/{settings.github_repository}/actions/artifacts",
headers=headers,
)
data = response.json()
artifacts_response = ArtifactResponse.parse_obj(data)
for pr in prs:
logging.info("-----")
logging.info(f"Processing PR #{pr.number}: {pr.title}")
pr_comments = list(pr.get_issue_comments())
pr_commits = list(pr.get_commits())
last_commit = pr_commits[0]
for pr_commit in pr_commits:
if pr_commit.commit.author.date > last_commit.commit.author.date:
last_commit = pr_commit
commit = last_commit.commit.sha
logging.info(f"Last commit: {commit}")
message = get_message(commit)
notified = False
for pr_comment in pr_comments:
if message in pr_comment.body:
notified = True
logging.info(f"Docs preview was notified: {notified}")
if not notified:
artifact_name = f"docs-zip-{commit}"
use_artifact: Union[Artifact, None] = None
for artifact in artifacts_response.artifacts:
if artifact.name == artifact_name:
use_artifact = artifact
break
if not use_artifact:
logging.info("Artifact not available")
else:
logging.info(f"Existing artifact: {use_artifact.name}")
response = httpx.post(
"https://api.github.com/repos/tiangolo/fastapi/actions/workflows/preview-docs.yml/dispatches",
headers=headers,
json={
"ref": "master",
"inputs": {
"pr": f"{pr.number}",
"name": artifact_name,
"commit": commit,
},
},
)
logging.info(
f"Trigger sent, response status: {response.status_code} - content: {response.content}"
)
logging.info("Finished")

87
.github/workflows/build-docs.yml

@ -4,10 +4,64 @@ on:
branches:
- master
pull_request:
types: [opened, synchronize]
types:
- opened
- synchronize
jobs:
changes:
runs-on: ubuntu-latest
# Required permissions
permissions:
pull-requests: read
# Set job outputs to values from filter step
outputs:
docs: ${{ steps.filter.outputs.docs }}
steps:
- uses: actions/checkout@v3
# For pull requests it's not necessary to checkout the code but for master it is
- uses: dorny/paths-filter@v2
id: filter
with:
filters: |
docs:
- README.md
- docs/**
- docs_src/**
- requirements-docs.txt
langs:
needs:
- changes
runs-on: ubuntu-latest
outputs:
langs: ${{ steps.show-langs.outputs.langs }}
steps:
- uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: "3.11"
- uses: actions/cache@v3
id: cache
with:
path: ${{ env.pythonLocation }}
key: ${{ runner.os }}-python-docs-${{ env.pythonLocation }}-${{ hashFiles('pyproject.toml', 'requirements-docs.txt') }}-v03
- name: Install docs extras
if: steps.cache.outputs.cache-hit != 'true'
run: pip install -r requirements-docs.txt
- name: Export Language Codes
id: show-langs
run: |
echo "langs=$(python ./scripts/docs.py langs-json)" >> $GITHUB_OUTPUT
build-docs:
needs:
- changes
- langs
if: ${{ needs.changes.outputs.docs == 'true' }}
runs-on: ubuntu-latest
strategy:
matrix:
lang: ${{ fromJson(needs.langs.outputs.langs) }}
steps:
- name: Dump GitHub context
env:
@ -29,21 +83,24 @@ jobs:
- name: Install Material for MkDocs Insiders
if: ( github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false ) && steps.cache.outputs.cache-hit != 'true'
run: pip install git+https://${{ secrets.ACTIONS_TOKEN }}@github.com/squidfunk/mkdocs-material-insiders.git
- name: Update Languages
run: python ./scripts/docs.py update-languages
- name: Build Docs
run: python ./scripts/docs.py build-all
- name: Zip docs
run: bash ./scripts/zip-docs.sh
run: python ./scripts/docs.py build-lang ${{ matrix.lang }}
- uses: actions/upload-artifact@v3
with:
name: docs-zip
path: ./site/docs.zip
- name: Deploy to Netlify
uses: nwtgck/[email protected]
name: docs-site
path: ./site/**
# https://github.com/marketplace/actions/alls-green#why
docs-all-green: # This job does nothing and is only used for the branch protection
if: always()
needs:
- build-docs
runs-on: ubuntu-latest
steps:
- name: Decide whether the needed jobs succeeded or failed
uses: re-actors/alls-green@release/v1
with:
publish-dir: './site'
production-branch: master
github-token: ${{ secrets.FASTAPI_BUILD_DOCS_NETLIFY }}
enable-commit-comment: false
env:
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }}
jobs: ${{ toJSON(needs) }}
allowed-skips: build-docs

21
.github/workflows/preview-docs.yml → .github/workflows/deploy-docs.yml

@ -1,4 +1,4 @@
name: Preview Docs
name: Deploy Docs
on:
workflow_run:
workflows:
@ -7,39 +7,42 @@ on:
- completed
jobs:
preview-docs:
deploy-docs:
runs-on: ubuntu-latest
steps:
- name: Dump GitHub context
env:
GITHUB_CONTEXT: ${{ toJson(github) }}
run: echo "$GITHUB_CONTEXT"
- uses: actions/checkout@v3
- name: Clean site
run: |
rm -rf ./site
mkdir ./site
- name: Download Artifact Docs
id: download
uses: dawidd6/[email protected]
with:
if_no_artifact_found: ignore
github_token: ${{ secrets.FASTAPI_PREVIEW_DOCS_DOWNLOAD_ARTIFACTS }}
workflow: build-docs.yml
run_id: ${{ github.event.workflow_run.id }}
name: docs-zip
name: docs-site
path: ./site/
- name: Unzip docs
run: |
cd ./site
unzip docs.zip
rm -f docs.zip
- name: Deploy to Netlify
if: steps.download.outputs.found_artifact == 'true'
id: netlify
uses: nwtgck/[email protected]
with:
publish-dir: './site'
production-deploy: false
production-deploy: ${{ github.event.workflow_run.head_repository.full_name == github.repository && github.event.workflow_run.head_branch == 'master' }}
github-token: ${{ secrets.FASTAPI_PREVIEW_DOCS_NETLIFY }}
enable-commit-comment: false
env:
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }}
- name: Comment Deploy
if: steps.netlify.outputs.deploy-url != ''
uses: ./.github/actions/comment-docs-preview-in-pr
with:
token: ${{ secrets.FASTAPI_PREVIEW_DOCS_COMMENT_DEPLOY }}

2
.github/workflows/publish.yml

@ -32,7 +32,7 @@ jobs:
- name: Build distribution
run: python -m build
- name: Publish
uses: pypa/[email protected].5
uses: pypa/[email protected].6
with:
password: ${{ secrets.PYPI_API_TOKEN }}
- name: Dump GitHub context

1
.gitignore

@ -16,6 +16,7 @@ Pipfile.lock
env3.*
env
docs_build
site_build
venv
docs.zip
archive.zip

1
README.md

@ -446,7 +446,6 @@ To understand more about it, see the section <a href="https://fastapi.tiangolo.c
Used by Pydantic:
* <a href="https://github.com/esnme/ultrajson" target="_blank"><code>ujson</code></a> - for faster JSON <abbr title="converting the string that comes from an HTTP request into Python data">"parsing"</abbr>.
* <a href="https://github.com/JoshData/python-email-validator" target="_blank"><code>email_validator</code></a> - for email validation.
Used by Starlette:

1
docs/az/docs/index.md

@ -441,7 +441,6 @@ To understand more about it, see the section <a href="https://fastapi.tiangolo.c
Used by Pydantic:
* <a href="https://github.com/esnme/ultrajson" target="_blank"><code>ujson</code></a> - for faster JSON <abbr title="converting the string that comes from an HTTP request into Python data">"parsing"</abbr>.
* <a href="https://github.com/JoshData/python-email-validator" target="_blank"><code>email_validator</code></a> - for email validation.
Used by Starlette:

1
docs/de/docs/index.md

@ -440,7 +440,6 @@ To understand more about it, see the section <a href="https://fastapi.tiangolo.c
Used by Pydantic:
* <a href="https://github.com/esnme/ultrajson" target="_blank"><code>ujson</code></a> - for faster JSON <abbr title="converting the string that comes from an HTTP request into Python data">"parsing"</abbr>.
* <a href="https://github.com/JoshData/python-email-validator" target="_blank"><code>email_validator</code></a> - for email validation.
Used by Starlette:

4
docs/en/data/external_links.yml

@ -233,6 +233,10 @@ articles:
link: https://medium.com/@krishnardt365/fastapi-docker-and-postgres-91943e71be92
title: Fastapi, Docker(Docker compose) and Postgres
german:
- author: Marcel Sander (actidoo)
author_link: https://www.actidoo.com
link: https://www.actidoo.com/de/blog/python-fastapi-domain-driven-design
title: Domain-driven Design mit Python und FastAPI
- author: Nico Axtmann
author_link: https://twitter.com/_nicoax
link: https://blog.codecentric.de/2019/08/inbetriebnahme-eines-scikit-learn-modells-mit-onnx-und-fastapi/

1
docs/en/docs/index.md

@ -445,7 +445,6 @@ To understand more about it, see the section <a href="https://fastapi.tiangolo.c
Used by Pydantic:
* <a href="https://github.com/esnme/ultrajson" target="_blank"><code>ujson</code></a> - for faster JSON <abbr title="converting the string that comes from an HTTP request into Python data">"parsing"</abbr>.
* <a href="https://github.com/JoshData/python-email-validator" target="_blank"><code>email_validator</code></a> - for email validation.
Used by Starlette:

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

@ -2,16 +2,52 @@
## Latest Changes
* 👷 Refactor Docs CI, run in multiple workers with a dynamic matrix to optimize speed. PR [#9732](https://github.com/tiangolo/fastapi/pull/9732) by [@tiangolo](https://github.com/tiangolo).
* 🔥 Remove old internal GitHub Action watch-previews that is no longer needed. PR [#9730](https://github.com/tiangolo/fastapi/pull/9730) by [@tiangolo](https://github.com/tiangolo).
* ⬆️ Upgrade MkDocs and MkDocs Material. PR [#9729](https://github.com/tiangolo/fastapi/pull/9729) by [@tiangolo](https://github.com/tiangolo).
* 👷 Build and deploy docs only on docs changes. PR [#9728](https://github.com/tiangolo/fastapi/pull/9728) by [@tiangolo](https://github.com/tiangolo).
## 0.98.0
### Features
* ✨ Allow disabling `redirect_slashes` at the FastAPI app level. PR [#3432](https://github.com/tiangolo/fastapi/pull/3432) by [@cyberlis](https://github.com/cyberlis).
### Docs
* 📝 Update docs on Pydantic using ujson internally. PR [#5804](https://github.com/tiangolo/fastapi/pull/5804) by [@mvasilkov](https://github.com/mvasilkov).
* ✏ Rewording in `docs/en/docs/tutorial/debugging.md`. PR [#9581](https://github.com/tiangolo/fastapi/pull/9581) by [@ivan-abc](https://github.com/ivan-abc).
* 📝 Add german blog post (Domain-driven Design mit Python und FastAPI). PR [#9261](https://github.com/tiangolo/fastapi/pull/9261) by [@msander](https://github.com/msander).
* ✏️ Tweak wording in `docs/en/docs/tutorial/security/index.md`. PR [#9561](https://github.com/tiangolo/fastapi/pull/9561) by [@jyothish-mohan](https://github.com/jyothish-mohan).
* 📝 Update `Annotated` notes in `docs/en/docs/tutorial/schema-extra-example.md`. PR [#9620](https://github.com/tiangolo/fastapi/pull/9620) by [@Alexandrhub](https://github.com/Alexandrhub).
* ✏️ Fix typo `Annotation` -> `Annotated` in `docs/en/docs/tutorial/query-params-str-validations.md`. PR [#9625](https://github.com/tiangolo/fastapi/pull/9625) by [@mccricardo](https://github.com/mccricardo).
* 📝 Use in memory database for testing SQL in docs. PR [#1223](https://github.com/tiangolo/fastapi/pull/1223) by [@HarshaLaxman](https://github.com/HarshaLaxman).
### Translations
* 🌐 Add Russian translation for `docs/ru/docs/tutorial/metadata.md`. PR [#9681](https://github.com/tiangolo/fastapi/pull/9681) by [@TabarakoAkula](https://github.com/TabarakoAkula).
* 🌐 Fix typo in Spanish translation for `docs/es/docs/tutorial/first-steps.md`. PR [#9571](https://github.com/tiangolo/fastapi/pull/9571) by [@lilidl-nft](https://github.com/lilidl-nft).
* 🌐 Add Russian translation for `docs/tutorial/path-operation-configuration.md`. PR [#9696](https://github.com/tiangolo/fastapi/pull/9696) by [@TabarakoAkula](https://github.com/TabarakoAkula).
* 🌐 Add Chinese translation for `docs/zh/docs/advanced/security/index.md`. PR [#9666](https://github.com/tiangolo/fastapi/pull/9666) by [@lordqyxz](https://github.com/lordqyxz).
* 🌐 Add Chinese translations for `docs/zh/docs/advanced/settings.md`. PR [#9652](https://github.com/tiangolo/fastapi/pull/9652) by [@ChoyeonChern](https://github.com/ChoyeonChern).
* 🌐 Add Chinese translations for `docs/zh/docs/advanced/websockets.md`. PR [#9651](https://github.com/tiangolo/fastapi/pull/9651) by [@ChoyeonChern](https://github.com/ChoyeonChern).
* 🌐 Add Chinese translation for `docs/zh/docs/tutorial/testing.md`. PR [#9641](https://github.com/tiangolo/fastapi/pull/9641) by [@wdh99](https://github.com/wdh99).
* 🌐 Add Russian translation for `docs/tutorial/extra-models.md`. PR [#9619](https://github.com/tiangolo/fastapi/pull/9619) by [@ivan-abc](https://github.com/ivan-abc).
* 🌐 Add Russian translation for `docs/tutorial/cors.md`. PR [#9608](https://github.com/tiangolo/fastapi/pull/9608) by [@ivan-abc](https://github.com/ivan-abc).
* 🌐 Add Polish translation for `docs/pl/docs/features.md`. PR [#5348](https://github.com/tiangolo/fastapi/pull/5348) by [@mbroton](https://github.com/mbroton).
* 🌐 Add Russian translation for `docs/ru/docs/tutorial/body-nested-models.md`. PR [#9605](https://github.com/tiangolo/fastapi/pull/9605) by [@Alexandrhub](https://github.com/Alexandrhub).
* ✏️ Fix typo `Annotation` -> `Annotated` in `docs/en/docs/tutorial/query-params-str-validations.md`. PR [#9625](https://github.com/tiangolo/fastapi/pull/9625) by [@mccricardo](https://github.com/mccricardo).
### Internal
* ⬆ Bump ruff from 0.0.272 to 0.0.275. PR [#9721](https://github.com/tiangolo/fastapi/pull/9721) by [@dependabot[bot]](https://github.com/apps/dependabot).
* ⬆ Update uvicorn[standard] requirement from <0.21.0,>=0.12.0 to >=0.12.0,<0.23.0. PR [#9463](https://github.com/tiangolo/fastapi/pull/9463) by [@dependabot[bot]](https://github.com/apps/dependabot).
* ⬆ Bump mypy from 1.3.0 to 1.4.0. PR [#9719](https://github.com/tiangolo/fastapi/pull/9719) by [@dependabot[bot]](https://github.com/apps/dependabot).
* ⬆ Update pre-commit requirement from <3.0.0,>=2.17.0 to >=2.17.0,<4.0.0. PR [#9251](https://github.com/tiangolo/fastapi/pull/9251) by [@dependabot[bot]](https://github.com/apps/dependabot).
* ⬆ Bump pypa/gh-action-pypi-publish from 1.8.5 to 1.8.6. PR [#9482](https://github.com/tiangolo/fastapi/pull/9482) by [@dependabot[bot]](https://github.com/apps/dependabot).
* ✏️ Fix tooltips for light/dark theme toggler in docs. PR [#9588](https://github.com/tiangolo/fastapi/pull/9588) by [@pankaj1707k](https://github.com/pankaj1707k).
* 🔧 Set minimal hatchling version needed to build the package. PR [#9240](https://github.com/tiangolo/fastapi/pull/9240) by [@mgorny](https://github.com/mgorny).
* 📝 Add repo link to PyPI. PR [#9559](https://github.com/tiangolo/fastapi/pull/9559) by [@JacobCoffee](https://github.com/JacobCoffee).
* ✏️ Fix typos in data for tests. PR [#4958](https://github.com/tiangolo/fastapi/pull/4958) by [@ryanrussell](https://github.com/ryanrussell).
* 📝 Use in memory database for testing SQL in docs. PR [#1223](https://github.com/tiangolo/fastapi/pull/1223) by [@HarshaLaxman](https://github.com/HarshaLaxman).
* ✨ Add allow disabling `redirect_slashes` at the FastAPI app level. PR [#3432](https://github.com/tiangolo/fastapi/pull/3432) by [@cyberlis](https://github.com/cyberlis).
* 🔧 Update sponsors, add Flint. PR [#9699](https://github.com/tiangolo/fastapi/pull/9699) by [@tiangolo](https://github.com/tiangolo).
* 👷 Lint in CI only once, only with one version of Python, run tests with all of them. PR [#9686](https://github.com/tiangolo/fastapi/pull/9686) by [@tiangolo](https://github.com/tiangolo).

2
docs/en/docs/tutorial/debugging.md

@ -64,7 +64,7 @@ from myapp import app
# Some more code
```
in that case, the automatic variable inside of `myapp.py` will not have the variable `__name__` with a value of `"__main__"`.
in that case, the automatically created variable inside of `myapp.py` will not have the variable `__name__` with a value of `"__main__"`.
So, the line:

6
docs/en/docs/tutorial/schema-extra-example.md

@ -86,6 +86,9 @@ Here we pass an `example` of the data expected in `Body()`:
=== "Python 3.10+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="18-23"
{!> ../../../docs_src/schema_extra_example/tutorial003_py310.py!}
```
@ -138,6 +141,9 @@ Each specific example `dict` in the `examples` can contain:
=== "Python 3.10+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="19-45"
{!> ../../../docs_src/schema_extra_example/tutorial004_py310.py!}
```

2
docs/en/docs/tutorial/security/index.md

@ -26,7 +26,7 @@ That's what all the systems with "login with Facebook, Google, Twitter, GitHub"
### OAuth 1
There was an OAuth 1, which is very different from OAuth2, and more complex, as it included directly specifications on how to encrypt the communication.
There was an OAuth 1, which is very different from OAuth2, and more complex, as it included direct specifications on how to encrypt the communication.
It is not very popular or used nowadays.

4
docs/en/mkdocs.yml

@ -11,14 +11,14 @@ theme:
accent: amber
toggle:
icon: material/lightbulb
name: Switch to light mode
name: Switch to dark mode
- media: '(prefers-color-scheme: dark)'
scheme: slate
primary: teal
accent: amber
toggle:
icon: material/lightbulb-outline
name: Switch to dark mode
name: Switch to light mode
features:
- search.suggest
- search.highlight

1
docs/es/docs/index.md

@ -433,7 +433,6 @@ Para entender más al respecto revisa la sección <a href="https://fastapi.tiang
Usadas por Pydantic:
* <a href="https://github.com/esnme/ultrajson" target="_blank"><code>ujson</code></a> - para <abbr title="convertir el string que viene de un HTTP request a datos de Python">"parsing"</abbr> de JSON más rápido.
* <a href="https://github.com/JoshData/python-email-validator" target="_blank"><code>email_validator</code></a> - para validación de emails.
Usados por Starlette:

2
docs/es/docs/tutorial/first-steps.md

@ -181,7 +181,7 @@ $ uvicorn main:my_awesome_api --reload
</div>
### Paso 3: crea un *operación de path*
### Paso 3: crea una *operación de path*
#### Path

1
docs/fa/docs/index.md

@ -436,7 +436,6 @@ item: Item
استفاده شده توسط Pydantic:
* <a href="https://github.com/esnme/ultrajson" target="_blank"><code>ujson</code></a> - برای <abbr title="تبدیل داده‌های موجود در درخواست‌های HTTP به داده پایتونی">"تجزیه (parse)"</abbr> سریع‌تر JSON .
* <a href="https://github.com/JoshData/python-email-validator" target="_blank"><code>email_validator</code></a> - برای اعتبارسنجی آدرس‌های ایمیل.
استفاده شده توسط Starlette:

1
docs/fr/docs/index.md

@ -445,7 +445,6 @@ Pour en savoir plus, consultez la section <a href="https://fastapi.tiangolo.com/
Utilisées par Pydantic:
* <a href="https://github.com/esnme/ultrajson" target="_blank"><code>ujson</code></a> - pour un <abbr title="convertit la chaine de caractère d'une requête HTTP en donnée Python">"décodage" <abbr title="JavaScript Object Notation">JSON</abbr></abbr> plus rapide.
* <a href="https://github.com/JoshData/python-email-validator" target="_blank"><code>email_validator</code></a> - pour la validation des adresses email.
Utilisées par Starlette :

1
docs/he/docs/index.md

@ -440,7 +440,6 @@ item: Item
בשימוש Pydantic:
- <a href="https://github.com/esnme/ultrajson" target="_blank"><code>ujson</code></a> - <abbr title="המרת המחרוזת שמגיעה מבקשת HTTP למידע פייתון">"פרסור"</abbr> JSON.
- <a href="https://github.com/JoshData/python-email-validator" target="_blank"><code>email_validator</code></a> - לאימות כתובות אימייל.
בשימוש Starlette:

1
docs/id/docs/index.md

@ -441,7 +441,6 @@ To understand more about it, see the section <a href="https://fastapi.tiangolo.c
Used by Pydantic:
* <a href="https://github.com/esnme/ultrajson" target="_blank"><code>ujson</code></a> - for faster JSON <abbr title="converting the string that comes from an HTTP request into Python data">"parsing"</abbr>.
* <a href="https://github.com/JoshData/python-email-validator" target="_blank"><code>email_validator</code></a> - for email validation.
Used by Starlette:

1
docs/it/docs/index.md

@ -438,7 +438,6 @@ To understand more about it, see the section <a href="https://fastapi.tiangolo.c
Used by Pydantic:
* <a href="https://github.com/esnme/ultrajson" target="_blank"><code>ujson</code></a> - for faster JSON <abbr title="converting the string that comes from an HTTP request into Python data">"parsing"</abbr>.
* <a href="https://github.com/JoshData/python-email-validator" target="_blank"><code>email_validator</code></a> - for email validation.
Used by Starlette:

1
docs/ja/docs/index.md

@ -431,7 +431,6 @@ item: Item
Pydantic によって使用されるもの:
- <a href="https://github.com/esnme/ultrajson" target="_blank"><code>ujson</code></a> - より速い JSON への<abbr title="converting the string that comes from an HTTP request into Python data">"変換"</abbr>.
- <a href="https://github.com/JoshData/python-email-validator" target="_blank"><code>email_validator</code></a> - E メールの検証
Starlette によって使用されるもの:

1
docs/ko/docs/index.md

@ -437,7 +437,6 @@ item: Item
Pydantic이 사용하는:
* <a href="https://github.com/esnme/ultrajson" target="_blank"><code>ujson</code></a> - 더 빠른 JSON <abbr title="HTTP 요청에서 파이썬 데이터로 가는 문자열 변환">"파싱"</abbr>.
* <a href="https://github.com/JoshData/python-email-validator" target="_blank"><code>email_validator</code></a> - 이메일 유효성 검사.
Starlette이 사용하는:

1
docs/nl/docs/index.md

@ -444,7 +444,6 @@ To understand more about it, see the section <a href="https://fastapi.tiangolo.c
Used by Pydantic:
* <a href="https://github.com/esnme/ultrajson" target="_blank"><code>ujson</code></a> - for faster JSON <abbr title="converting the string that comes from an HTTP request into Python data">"parsing"</abbr>.
* <a href="https://github.com/JoshData/python-email-validator" target="_blank"><code>email_validator</code></a> - for email validation.
Used by Starlette:

1
docs/pl/docs/index.md

@ -435,7 +435,6 @@ Aby dowiedzieć się o tym więcej, zobacz sekcję <a href="https://fastapi.tian
Używane przez Pydantic:
* <a href="https://github.com/esnme/ultrajson" target="_blank"><code>ujson</code></a> - dla szybszego <abbr title="przetwarzania stringa który przychodzi z żądaniem HTTP na dane używane przez Pythona">"parsowania"</abbr> danych JSON.
* <a href="https://github.com/JoshData/python-email-validator" target="_blank"><code>email_validator</code></a> - dla walidacji adresów email.
Używane przez Starlette:

1
docs/pt/docs/index.md

@ -430,7 +430,6 @@ Para entender mais sobre performance, veja a seção <a href="https://fastapi.ti
Usados por Pydantic:
* <a href="https://github.com/esnme/ultrajson" target="_blank"><code>ujson</code></a> - para JSON mais rápido <abbr title="converte uma string que chega de uma requisição HTTP para dados Python">"parsing"</abbr>.
* <a href="https://github.com/JoshData/python-email-validator" target="_blank"><code>email_validator</code></a> - para validação de email.
Usados por Starlette:

1
docs/ru/docs/index.md

@ -439,7 +439,6 @@ item: Item
Используется Pydantic:
* <a href="https://github.com/esnme/ultrajson" target="_blank"><code>ujson</code></a> - для более быстрого JSON <abbr title="преобразования строки, полученной из HTTP-запроса, в данные Python">"парсинга"</abbr>.
* <a href="https://github.com/JoshData/python-email-validator" target="_blank"><code>email_validator</code></a> - для проверки электронной почты.
Используется Starlette:

111
docs/ru/docs/tutorial/metadata.md

@ -0,0 +1,111 @@
# URL-адреса метаданных и документации
Вы можете настроить несколько конфигураций метаданных в вашем **FastAPI** приложении.
## Метаданные для API
Вы можете задать следующие поля, которые используются в спецификации OpenAPI и в UI автоматической документации API:
| Параметр | Тип | Описание |
|------------|--|-------------|
| `title` | `str` | Заголовок API. |
| `description` | `str` | Краткое описание API. Может быть использован Markdown. |
| `version` | `string` | Версия API. Версия вашего собственного приложения, а не OpenAPI. К примеру `2.5.0`. |
| `terms_of_service` | `str` | Ссылка к условиям пользования API. Если указано, то это должен быть URL-адрес. |
| `contact` | `dict` | Контактная информация для открытого API. Может содержать несколько полей. <details><summary>поля <code>contact</code></summary><table><thead><tr><th>Параметр</th><th>Тип</th><th>Описание</th></tr></thead><tbody><tr><td><code>name</code></td><td><code>str</code></td><td>Идентификационное имя контактного лица/организации.</td></tr><tr><td><code>url</code></td><td><code>str</code></td><td>URL указывающий на контактную информацию. ДОЛЖЕН быть в формате URL.</td></tr><tr><td><code>email</code></td><td><code>str</code></td><td>Email адрес контактного лица/организации. ДОЛЖЕН быть в формате email адреса.</td></tr></tbody></table></details> |
| `license_info` | `dict` | Информация о лицензии открытого API. Может содержать несколько полей. <details><summary>поля <code>license_info</code></summary><table><thead><tr><th>Параметр</th><th>Тип</th><th>Описание</th></tr></thead><tbody><tr><td><code>name</code></td><td><code>str</code></td><td><strong>ОБЯЗАТЕЛЬНО</strong> (если установлен параметр <code>license_info</code>). Название лицензии, используемой для API</td></tr><tr><td><code>url</code></td><td><code>str</code></td><td>URL, указывающий на лицензию, используемую для API. ДОЛЖЕН быть в формате URL.</td></tr></tbody></table></details> |
Вы можете задать их следующим образом:
```Python hl_lines="3-16 19-31"
{!../../../docs_src/metadata/tutorial001.py!}
```
!!! tip "Подсказка"
Вы можете использовать Markdown в поле `description`, и оно будет отображено в выводе.
С этой конфигурацией автоматическая документация API будут выглядеть так:
<img src="/img/tutorial/metadata/image01.png">
## Метаданные для тегов
Вы также можете добавить дополнительные метаданные для различных тегов, используемых для группировки ваших операций пути с помощью параметра `openapi_tags`.
Он принимает список, содержащий один словарь для каждого тега.
Каждый словарь может содержать в себе:
* `name` (**обязательно**): `str`-значение с тем же именем тега, которое вы используете в параметре `tags` в ваших *операциях пути* и `APIRouter`ах.
* `description`: `str`-значение с кратким описанием для тега. Может содержать Markdown и будет отображаться в UI документации.
* `externalDocs`: `dict`-значение описывающее внешнюю документацию. Включает в себя:
* `description`: `str`-значение с кратким описанием для внешней документации.
* `url` (**обязательно**): `str`-значение с URL-адресом для внешней документации.
### Создание метаданных для тегов
Давайте попробуем сделать это на примере с тегами для `users` и `items`.
Создайте метаданные для ваших тегов и передайте их в параметре `openapi_tags`:
```Python hl_lines="3-16 18"
{!../../../docs_src/metadata/tutorial004.py!}
```
Помните, что вы можете использовать Markdown внутри описания, к примеру "login" будет отображен жирным шрифтом (**login**) и "fancy" будет отображаться курсивом (_fancy_).
!!! tip "Подсказка"
Вам необязательно добавлять метаданные для всех используемых тегов
### Используйте собственные теги
Используйте параметр `tags` с вашими *операциями пути*`APIRouter`ами), чтобы присвоить им различные теги:
```Python hl_lines="21 26"
{!../../../docs_src/metadata/tutorial004.py!}
```
!!! info "Дополнительная информация"
Узнайте больше о тегах в [Конфигурации операции пути](../path-operation-configuration/#tags){.internal-link target=_blank}.
### Проверьте документацию
Теперь, если вы проверите документацию, вы увидите всю дополнительную информацию:
<img src="/img/tutorial/metadata/image02.png">
### Порядок расположения тегов
Порядок расположения словарей метаданных для каждого тега определяет также порядок, отображаемый в документах UI
К примеру, несмотря на то, что `users` будут идти после `items` в алфавитном порядке, они отображаются раньше, потому что мы добавляем свои метаданные в качестве первого словаря в списке.
## URL-адреса OpenAPI
По умолчанию схема OpenAPI отображена по адресу `/openapi.json`.
Но вы можете изменить это с помощью параметра `openapi_url`.
К примеру, чтобы задать её отображение по адресу `/api/v1/openapi.json`:
```Python hl_lines="3"
{!../../../docs_src/metadata/tutorial002.py!}
```
Если вы хотите отключить схему OpenAPI полностью, вы можете задать `openapi_url=None`, это также отключит пользовательские интерфейсы документации, которые его использует.
## URL-адреса документации
Вы можете изменить конфигурацию двух пользовательских интерфейсов документации, среди которых
* **Swagger UI**: отображаемый по адресу `/docs`.
* Вы можете задать его URL с помощью параметра `docs_url`.
* Вы можете отключить это с помощью настройки `docs_url=None`.
* **ReDoc**: отображаемый по адресу `/redoc`.
* Вы можете задать его URL с помощью параметра `redoc_url`.
* Вы можете отключить это с помощью настройки `redoc_url=None`.
К примеру, чтобы задать отображение Swagger UI по адресу `/documentation` и отключить ReDoc:
```Python hl_lines="3"
{!../../../docs_src/metadata/tutorial003.py!}
```

179
docs/ru/docs/tutorial/path-operation-configuration.md

@ -0,0 +1,179 @@
# Конфигурация операций пути
Существует несколько параметров, которые вы можете передать вашему *декоратору операций пути* для его настройки.
!!! warning "Внимание"
Помните, что эти параметры передаются непосредственно *декоратору операций пути*, а не вашей *функции-обработчику операций пути*.
## Коды состояния
Вы можете определить (HTTP) `status_code`, который будет использован в ответах вашей *операции пути*.
Вы можете передать только `int`-значение кода, например `404`.
Но если вы не помните, для чего нужен каждый числовой код, вы можете использовать сокращенные константы в параметре `status`:
=== "Python 3.10+"
```Python hl_lines="1 15"
{!> ../../../docs_src/path_operation_configuration/tutorial001_py310.py!}
```
=== "Python 3.9+"
```Python hl_lines="3 17"
{!> ../../../docs_src/path_operation_configuration/tutorial001_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="3 17"
{!> ../../../docs_src/path_operation_configuration/tutorial001.py!}
```
Этот код состояния будет использован в ответе и будет добавлен в схему OpenAPI.
!!! note "Технические детали"
Вы также можете использовать `from starlette import status`.
**FastAPI** предоставляет тот же `starlette.status` под псевдонимом `fastapi.status` для удобства разработчика. Но его источник - это непосредственно Starlette.
## Теги
Вы можете добавлять теги к вашим *операциям пути*, добавив параметр `tags` с `list` заполненным `str`-значениями (обычно в нём только одна строка):
=== "Python 3.10+"
```Python hl_lines="15 20 25"
{!> ../../../docs_src/path_operation_configuration/tutorial002_py310.py!}
```
=== "Python 3.9+"
```Python hl_lines="17 22 27"
{!> ../../../docs_src/path_operation_configuration/tutorial002_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="17 22 27"
{!> ../../../docs_src/path_operation_configuration/tutorial002.py!}
```
Они будут добавлены в схему OpenAPI и будут использованы в автоматической документации интерфейса:
<img src="/img/tutorial/path-operation-configuration/image01.png">
### Теги с перечислениями
Если у вас большое приложение, вы можете прийти к необходимости добавить **несколько тегов**, и возможно, вы захотите убедиться в том, что всегда используете **один и тот же тег** для связанных *операций пути*.
В этих случаях, имеет смысл хранить теги в классе `Enum`.
**FastAPI** поддерживает это так же, как и в случае с обычными строками:
```Python hl_lines="1 8-10 13 18"
{!../../../docs_src/path_operation_configuration/tutorial002b.py!}
```
## Краткое и развёрнутое содержание
Вы можете добавить параметры `summary` и `description`:
=== "Python 3.10+"
```Python hl_lines="18-19"
{!> ../../../docs_src/path_operation_configuration/tutorial003_py310.py!}
```
=== "Python 3.9+"
```Python hl_lines="20-21"
{!> ../../../docs_src/path_operation_configuration/tutorial003_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="20-21"
{!> ../../../docs_src/path_operation_configuration/tutorial003.py!}
```
## Описание из строк документации
Так как описания обычно длинные и содержат много строк, вы можете объявить описание *операции пути* в функции <abbr title="многострочный текст, первое выражение внутри функции (не присвоенный какой-либо переменной), используемый для документации">строки документации</abbr> и **FastAPI** прочитает её отсюда.
Вы можете использовать <a href="https://en.wikipedia.org/wiki/Markdown" class="external-link" target="_blank">Markdown</a> в строке документации, и он будет интерпретирован и отображён корректно (с учетом отступа в строке документации).
=== "Python 3.10+"
```Python hl_lines="17-25"
{!> ../../../docs_src/path_operation_configuration/tutorial004_py310.py!}
```
=== "Python 3.9+"
```Python hl_lines="19-27"
{!> ../../../docs_src/path_operation_configuration/tutorial004_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="19-27"
{!> ../../../docs_src/path_operation_configuration/tutorial004.py!}
```
Он будет использован в интерактивной документации:
<img src="/img/tutorial/path-operation-configuration/image02.png">
## Описание ответа
Вы можете указать описание ответа с помощью параметра `response_description`:
=== "Python 3.10+"
```Python hl_lines="19"
{!> ../../../docs_src/path_operation_configuration/tutorial005_py310.py!}
```
=== "Python 3.9+"
```Python hl_lines="21"
{!> ../../../docs_src/path_operation_configuration/tutorial005_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="21"
{!> ../../../docs_src/path_operation_configuration/tutorial005.py!}
```
!!! info "Дополнительная информация"
Помните, что `response_description` относится конкретно к ответу, а `description` относится к *операции пути* в целом.
!!! check "Технические детали"
OpenAPI указывает, что каждой *операции пути* необходимо описание ответа.
Если вдруг вы не укажете его, то **FastAPI** автоматически сгенерирует это описание с текстом "Successful response".
<img src="/img/tutorial/path-operation-configuration/image03.png">
## Обозначение *операции пути* как устаревшей
Если вам необходимо пометить *операцию пути* как <abbr title="устаревшее, не рекомендовано к использованию">устаревшую</abbr>, при этом не удаляя её, передайте параметр `deprecated`:
```Python hl_lines="16"
{!../../../docs_src/path_operation_configuration/tutorial006.py!}
```
Он будет четко помечен как устаревший в интерактивной документации:
<img src="/img/tutorial/path-operation-configuration/image04.png">
Проверьте, как будут выглядеть устаревшие и не устаревшие *операции пути*:
<img src="/img/tutorial/path-operation-configuration/image05.png">
## Резюме
Вы можете легко конфигурировать и добавлять метаданные в ваши *операции пути*, передавая параметры *декораторам операций пути*.

2
docs/ru/mkdocs.yml

@ -81,6 +81,8 @@ nav:
- tutorial/response-status-code.md
- tutorial/query-params.md
- tutorial/body-multiple-params.md
- tutorial/metadata.md
- tutorial/path-operation-configuration.md
- tutorial/cors.md
- tutorial/static-files.md
- tutorial/debugging.md

1
docs/sq/docs/index.md

@ -441,7 +441,6 @@ To understand more about it, see the section <a href="https://fastapi.tiangolo.c
Used by Pydantic:
* <a href="https://github.com/esnme/ultrajson" target="_blank"><code>ujson</code></a> - for faster JSON <abbr title="converting the string that comes from an HTTP request into Python data">"parsing"</abbr>.
* <a href="https://github.com/JoshData/python-email-validator" target="_blank"><code>email_validator</code></a> - for email validation.
Used by Starlette:

1
docs/sv/docs/index.md

@ -444,7 +444,6 @@ To understand more about it, see the section <a href="https://fastapi.tiangolo.c
Used by Pydantic:
* <a href="https://github.com/esnme/ultrajson" target="_blank"><code>ujson</code></a> - for faster JSON <abbr title="converting the string that comes from an HTTP request into Python data">"parsing"</abbr>.
* <a href="https://github.com/JoshData/python-email-validator" target="_blank"><code>email_validator</code></a> - for email validation.
Used by Starlette:

1
docs/tr/docs/index.md

@ -449,7 +449,6 @@ Daha fazla bilgi için, bu bölüme bir göz at <a href="https://fastapi.tiangol
Pydantic tarafında kullanılan:
* <a href="https://github.com/esnme/ultrajson" target="_blank"><code>ujson</code></a> - daha hızlı JSON <abbr title="HTTP bağlantısından gelen stringi Python objesine çevirmek için">"dönüşümü"</abbr> için.
* <a href="https://github.com/JoshData/python-email-validator" target="_blank"><code>email_validator</code></a> - email doğrulaması için.
Starlette tarafında kullanılan:

1
docs/uk/docs/index.md

@ -441,7 +441,6 @@ To understand more about it, see the section <a href="https://fastapi.tiangolo.c
Used by Pydantic:
* <a href="https://github.com/esnme/ultrajson" target="_blank"><code>ujson</code></a> - for faster JSON <abbr title="converting the string that comes from an HTTP request into Python data">"parsing"</abbr>.
* <a href="https://github.com/JoshData/python-email-validator" target="_blank"><code>email_validator</code></a> - for email validation.
Used by Starlette:

16
docs/zh/docs/advanced/security/index.md

@ -0,0 +1,16 @@
# 高级安全 - 介绍
## 附加特性
除 [教程 - 用户指南: 安全性](../../tutorial/security/){.internal-link target=_blank} 中涵盖的功能之外,还有一些额外的功能来处理安全性.
!!! tip "小贴士"
接下来的章节 **并不一定是 "高级的"**.
而且对于你的使用场景来说,解决方案很可能就在其中。
## 先阅读教程
接下来的部分假设你已经阅读了主要的 [教程 - 用户指南: 安全性](../../tutorial/security/){.internal-link target=_blank}.
它们都基于相同的概念,但支持一些额外的功能.

433
docs/zh/docs/advanced/settings.md

@ -0,0 +1,433 @@
# 设置和环境变量
在许多情况下,您的应用程序可能需要一些外部设置或配置,例如密钥、数据库凭据、电子邮件服务的凭据等等。
这些设置中的大多数是可变的(可以更改的),比如数据库的 URL。而且许多设置可能是敏感的,比如密钥。
因此,通常会将它们提供为由应用程序读取的环境变量。
## 环境变量
!!! tip
如果您已经知道什么是"环境变量"以及如何使用它们,请随意跳到下面的下一节。
环境变量(也称为"env var")是一种存在于 Python 代码之外、存在于操作系统中的变量,可以被您的 Python 代码(或其他程序)读取。
您可以在 shell 中创建和使用环境变量,而无需使用 Python:
=== "Linux、macOS、Windows Bash"
<div class="termy">
```console
// 您可以创建一个名为 MY_NAME 的环境变量
$ export MY_NAME="Wade Wilson"
// 然后您可以与其他程序一起使用它,例如
$ echo "Hello $MY_NAME"
Hello Wade Wilson
```
</div>
=== "Windows PowerShell"
<div class="termy">
```console
// 创建一个名为 MY_NAME 的环境变量
$ $Env:MY_NAME = "Wade Wilson"
// 与其他程序一起使用它,例如
$ echo "Hello $Env:MY_NAME"
Hello Wade Wilson
```
</div>
### 在 Python 中读取环境变量
您还可以在 Python 之外的地方(例如终端中或使用任何其他方法)创建环境变量,然后在 Python 中读取它们。
例如,您可以有一个名为 `main.py` 的文件,其中包含以下内容:
```Python hl_lines="3"
import os
name = os.getenv("MY_NAME", "World")
print(f"Hello {name} from Python")
```
!!! tip
<a href="https://docs.python.org/3.8/library/os.html#os.getenv" class="external-link" target="_blank">`os.getenv()`</a> 的第二个参数是要返回的默认值。
如果没有提供默认值,默认为 `None`,此处我们提供了 `"World"` 作为要使用的默认值。
然后,您可以调用该 Python 程序:
<div class="termy">
```console
// 这里我们还没有设置环境变量
$ python main.py
// 因为我们没有设置环境变量,所以我们得到默认值
Hello World from Python
// 但是如果我们先创建一个环境变量
$ export MY_NAME="Wade Wilson"
// 然后再次调用程序
$ python main.py
// 现在它可以读取环境变量
Hello Wade Wilson from Python
```
</div>
由于环境变量可以在代码之外设置,但可以由代码读取,并且不需要与其他文件一起存储(提交到 `git`),因此通常将它们用于配置或设置。
您还可以仅为特定程序调用创建一个环境变量,该环境变量仅对该程序可用,并且仅在其运行期间有效。
要做到这一点,在程序本身之前的同一行创建它:
<div class="termy">
```console
// 在此程序调用行中创建一个名为 MY_NAME 的环境变量
$ MY_NAME="Wade Wilson" python main.py
// 现在它可以读取环境变量
Hello Wade Wilson from Python
// 之后环境变量不再存在
$ python main.py
Hello World from Python
```
</div>
!!! tip
您可以在 <a href="https://12factor.net/config" class="external-link" target="_blank">Twelve-Factor App: Config</a> 中阅读更多相关信息。
### 类型和验证
这些环境变量只能处理文本字符串,因为它们是外部于 Python 的,并且必须与其他程序和整个系统兼容(甚至与不同的操作系统,如 Linux、Windows、macOS)。
这意味着从环境变量中在 Python 中读取的任何值都将是 `str` 类型,任何类型的转换或验证都必须在代码中完成。
## Pydantic 的 `Settings`
幸运的是,Pydantic 提供了一个很好的工具来处理来自环境变量的设置,即<a href="https://pydantic-docs.helpmanual.io/usage/settings/" class="external-link" target="_blank">Pydantic: Settings management</a>
### 创建 `Settings` 对象
从 Pydantic 导入 `BaseSettings` 并创建一个子类,与 Pydantic 模型非常相似。
与 Pydantic 模型一样,您使用类型注释声明类属性,还可以指定默认值。
您可以使用与 Pydantic 模型相同的验证功能和工具,比如不同的数据类型和使用 `Field()` 进行附加验证。
```Python hl_lines="2 5-8 11"
{!../../../docs_src/settings/tutorial001.py!}
```
!!! tip
如果您需要一个快速的复制粘贴示例,请不要使用此示例,而应使用下面的最后一个示例。
然后,当您创建该 `Settings` 类的实例(在此示例中是 `settings` 对象)时,Pydantic 将以不区分大小写的方式读取环境变量,因此,大写的变量 `APP_NAME` 仍将为属性 `app_name` 读取。
然后,它将转换和验证数据。因此,当您使用该 `settings` 对象时,您将获得您声明的类型的数据(例如 `items_per_user` 将为 `int` 类型)。
### 使用 `settings`
然后,您可以在应用程序中使用新的 `settings` 对象:
```Python hl_lines="18-20"
{!../../../docs_src/settings/tutorial001.py!}
```
### 运行服务器
接下来,您将运行服务器,并将配置作为环境变量传递。例如,您可以设置一个 `ADMIN_EMAIL``APP_NAME`,如下所示:
<div class="termy">
```console
$ ADMIN_EMAIL="[email protected]" APP_NAME="ChimichangApp"uvicorn main:app
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
```
</div>
!!! tip
要为单个命令设置多个环境变量,只需用空格分隔它们,并将它们全部放在命令之前。
然后,`admin_email` 设置将为 `"[email protected]"`
`app_name` 将为 `"ChimichangApp"`
`items_per_user` 将保持其默认值为 `50`
## 在另一个模块中设置
您可以将这些设置放在另一个模块文件中,就像您在[Bigger Applications - Multiple Files](../tutorial/bigger-applications.md){.internal-link target=_blank}中所见的那样。
例如,您可以创建一个名为 `config.py` 的文件,其中包含以下内容:
```Python
{!../../../docs_src/settings/app01/config.py!}
```
然后在一个名为 `main.py` 的文件中使用它:
```Python hl_lines="3 11-13"
{!../../../docs_src/settings/app01/main.py!}
```
!!! tip
您还需要一个名为 `__init__.py` 的文件,就像您在[Bigger Applications - Multiple Files](../tutorial/bigger-applications.md){.internal-link target=_blank}中看到的那样。
## 在依赖项中使用设置
在某些情况下,从依赖项中提供设置可能比在所有地方都使用全局对象 `settings` 更有用。
这在测试期间尤其有用,因为很容易用自定义设置覆盖依赖项。
### 配置文件
根据前面的示例,您的 `config.py` 文件可能如下所示:
```Python hl_lines="10"
{!../../../docs_src/settings/app02/config.py!}
```
请注意,现在我们不创建默认实例 `settings = Settings()`
### 主应用程序文件
现在我们创建一个依赖项,返回一个新的 `config.Settings()`
=== "Python 3.9+"
```Python hl_lines="6 12-13"
{!> ../../../docs_src/settings/app02_an_py39/main.py!}
```
=== "Python 3.6+"
```Python hl_lines="6 12-13"
{!> ../../../docs_src/settings/app02_an/main.py!}
```
=== "Python 3.6+ 非注解版本"
!!! tip
如果可能,请尽量使用 `Annotated` 版本。
```Python hl_lines="5 11-12"
{!> ../../../docs_src/settings/app02/main.py!}
```
!!! tip
我们稍后会讨论 `@lru_cache()`
目前,您可以将 `get_settings()` 视为普通函数。
然后,我们可以将其作为依赖项从“路径操作函数”中引入,并在需要时使用它。
=== "Python 3.9+"
```Python hl_lines="17 19-21"
{!> ../../../docs_src/settings/app02_an_py39/main.py!}
```
=== "Python 3.6+"
```Python hl_lines="17 19-21"
{!> ../../../docs_src/settings/app02_an/main.py!}
```
=== "Python 3.6+ 非注解版本"
!!! tip
如果可能,请尽量使用 `Annotated` 版本。
```Python hl_lines="16 18-20"
{!> ../../../docs_src/settings/app02/main.py!}
```
### 设置和测试
然后,在测试期间,通过创建 `get_settings` 的依赖项覆盖,很容易提供一个不同的设置对象:
```Python hl_lines="9-10 13 21"
{!../../../docs_src/settings/app02/test_main.py!}
```
在依赖项覆盖中,我们在创建新的 `Settings` 对象时为 `admin_email` 设置了一个新值,然后返回该新对象。
然后,我们可以测试它是否被使用。
## 从 `.env` 文件中读取设置
如果您有许多可能经常更改的设置,可能在不同的环境中,将它们放在一个文件中,然后从该文件中读取它们,就像它们是环境变量一样,可能非常有用。
这种做法相当常见,有一个名称,这些环境变量通常放在一个名为 `.env` 的文件中,该文件被称为“dotenv”。
!!! tip
以点 (`.`) 开头的文件是 Unix-like 系统(如 Linux 和 macOS)中的隐藏文件。
但是,dotenv 文件实际上不一定要具有确切的文件名。
Pydantic 支持使用外部库从这些类型的文件中读取。您可以在<a href="https://pydantic-docs.helpmanual.io/usage/settings/#dotenv-env-support" class="external-link" target="_blank">Pydantic 设置: Dotenv (.env) 支持</a>中阅读更多相关信息。
!!! tip
要使其工作,您需要执行 `pip install python-dotenv`
### `.env` 文件
您可以使用以下内容创建一个名为 `.env` 的文件:
```bash
ADMIN_EMAIL="[email protected]"
APP_NAME="ChimichangApp"
```
### 从 `.env` 文件中读取设置
然后,您可以使用以下方式更新您的 `config.py`
```Python hl_lines="9-10"
{!../../../docs_src/settings/app03/config.py!}
```
在这里,我们在 Pydantic 的 `Settings` 类中创建了一个名为 `Config` 的类,并将 `env_file` 设置为我们想要使用的 dotenv 文件的文件名。
!!! tip
`Config` 类仅用于 Pydantic 配置。您可以在<a href="https://pydantic-docs.helpmanual.io/usage/model_config/" class="external-link" target="_blank">Pydantic Model Config</a>中阅读更多相关信息。
### 使用 `lru_cache` 仅创建一次 `Settings`
从磁盘中读取文件通常是一项耗时的(慢)操作,因此您可能希望仅在首次读取后并重复使用相同的设置对象,而不是为每个请求都读取它。
但是,每次执行以下操作:
```Python
Settings()
```
都会创建一个新的 `Settings` 对象,并且在创建时会再次读取 `.env` 文件。
如果依赖项函数只是这样的:
```Python
def get_settings():
return Settings()
```
我们将为每个请求创建该对象,并且将在每个请求中读取 `.env` 文件。 ⚠️
但是,由于我们在顶部使用了 `@lru_cache()` 装饰器,因此只有在第一次调用它时,才会创建 `Settings` 对象一次。 ✔️
=== "Python 3.9+"
```Python hl_lines="1 11"
{!> ../../../docs_src/settings/app03_an_py39/main.py!}
```
=== "Python 3.6+"
```Python hl_lines="1 11"
{!> ../../../docs_src/settings/app03_an/main.py!}
```
=== "Python 3.6+ 非注解版本"
!!! tip
如果可能,请尽量使用 `Annotated` 版本。
```Python hl_lines="1 10"
{!> ../../../docs_src/settings/app03/main.py!}
```
然后,在下一次请求的依赖项中对 `get_settings()` 进行任何后续调用时,它不会执行 `get_settings()` 的内部代码并创建新的 `Settings` 对象,而是返回在第一次调用时返回的相同对象,一次又一次。
#### `lru_cache` 技术细节
`@lru_cache()` 修改了它所装饰的函数,以返回第一次返回的相同值,而不是再次计算它,每次都执行函数的代码。
因此,下面的函数将对每个参数组合执行一次。然后,每个参数组合返回的值将在使用完全相同的参数组合调用函数时再次使用。
例如,如果您有一个函数:
```Python
@lru_cache()
def say_hi(name: str, salutation: str = "Ms."):
return f"Hello {salutation} {name}"
```
您的程序可以像这样执行:
```mermaid
sequenceDiagram
participant code as Code
participant function as say_hi()
participant execute as Execute function
rect rgba(0, 255, 0, .1)
code ->> function: say_hi(name="Camila")
function ->> execute: 执行函数代码
execute ->> code: 返回结果
end
rect rgba(0, 255, 255, .1)
code ->> function: say_hi(name="Camila")
function ->> code: 返回存储的结果
end
rect rgba(0, 255, 0, .1)
code ->> function: say_hi(name="Rick")
function ->> execute: 执行函数代码
execute ->> code: 返回结果
end
rect rgba(0, 255, 0, .1)
code ->> function: say_hi(name="Rick", salutation="Mr.")
function ->> execute: 执行函数代码
execute ->> code: 返回结果
end
rect rgba(0, 255, 255, .1)
code ->> function: say_hi(name="Rick")
function ->> code: 返回存储的结果
end
rect rgba(0, 255, 255, .1)
code ->> function: say_hi(name="Camila")
function ->> code: 返回存储的结果
end
```
对于我们的依赖项 `get_settings()`,该函数甚至不接受任何参数,因此它始终返回相同的值。
这样,它的行为几乎就像是一个全局变量。但是由于它使用了依赖项函数,因此我们可以轻松地进行测试时的覆盖。
`@lru_cache()``functools` 的一部分,它是 Python 标准库的一部分,您可以在<a href="https://docs.python.org/3/library/functools.html#functools.lru_cache" class="external-link" target="_blank">Python 文档中了解有关 `@lru_cache()` 的更多信息</a>
## 小结
您可以使用 Pydantic 设置处理应用程序的设置或配置,利用 Pydantic 模型的所有功能。
* 通过使用依赖项,您可以简化测试。
* 您可以使用 `.env` 文件。
* 使用 `@lru_cache()` 可以避免为每个请求重复读取 dotenv 文件,同时允许您在测试时进行覆盖。

214
docs/zh/docs/advanced/websockets.md

@ -0,0 +1,214 @@
# WebSockets
您可以在 **FastAPI** 中使用 [WebSockets](https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API)。
## 安装 `WebSockets`
首先,您需要安装 `WebSockets`
```console
$ pip install websockets
---> 100%
```
## WebSockets 客户端
### 在生产环境中
在您的生产系统中,您可能使用现代框架(如React、Vue.js或Angular)创建了一个前端。
要使用 WebSockets 与后端进行通信,您可能会使用前端的工具。
或者,您可能有一个原生移动应用程序,直接使用原生代码与 WebSocket 后端通信。
或者,您可能有其他与 WebSocket 终端通信的方式。
---
但是,在本示例中,我们将使用一个非常简单的HTML文档,其中包含一些JavaScript,全部放在一个长字符串中。
当然,这并不是最优的做法,您不应该在生产环境中使用它。
在生产环境中,您应该选择上述任一选项。
但这是一种专注于 WebSockets 的服务器端并提供一个工作示例的最简单方式:
```Python hl_lines="2 6-38 41-43"
{!../../../docs_src/websockets/tutorial001.py!}
```
## 创建 `websocket`
在您的 **FastAPI** 应用程序中,创建一个 `websocket`
```Python hl_lines="1 46-47"
{!../../../docs_src/websockets/tutorial001.py!}
```
!!! note "技术细节"
您也可以使用 `from starlette.websockets import WebSocket`
**FastAPI** 直接提供了相同的 `WebSocket`,只是为了方便开发人员。但它直接来自 Starlette。
## 等待消息并发送消息
在您的 WebSocket 路由中,您可以使用 `await` 等待消息并发送消息。
```Python hl_lines="48-52"
{!../../../docs_src/websockets/tutorial001.py!}
```
您可以接收和发送二进制、文本和 JSON 数据。
## 尝试一下
如果您的文件名为 `main.py`,请使用以下命令运行应用程序:
```console
$ uvicorn main:app --reload
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
```
在浏览器中打开 <a href="http://127.0.0.1:8000" class="external-link" target="_blank">http://127.0.0.1:8000</a>
您将看到一个简单的页面,如下所示:
<img src="/img/tutorial/websockets/image01.png">
您可以在输入框中输入消息并发送:
<img src="/img/tutorial/websockets/image02.png">
您的 **FastAPI** 应用程序将回复:
<img src="/img/tutorial/websockets/image03.png">
您可以发送(和接收)多条消息:
<img src="/img/tutorial/websockets/image04.png">
所有这些消息都将使用同一个 WebSocket 连
接。
## 使用 `Depends` 和其他依赖项
在 WebSocket 端点中,您可以从 `fastapi` 导入并使用以下内容:
* `Depends`
* `Security`
* `Cookie`
* `Header`
* `Path`
* `Query`
它们的工作方式与其他 FastAPI 端点/ *路径操作* 相同:
=== "Python 3.10+"
```Python hl_lines="68-69 82"
{!> ../../../docs_src/websockets/tutorial002_an_py310.py!}
```
=== "Python 3.9+"
```Python hl_lines="68-69 82"
{!> ../../../docs_src/websockets/tutorial002_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="69-70 83"
{!> ../../../docs_src/websockets/tutorial002_an.py!}
```
=== "Python 3.10+ 非带注解版本"
!!! tip
如果可能,请尽量使用 `Annotated` 版本。
```Python hl_lines="66-67 79"
{!> ../../../docs_src/websockets/tutorial002_py310.py!}
```
=== "Python 3.6+ 非带注解版本"
!!! tip
如果可能,请尽量使用 `Annotated` 版本。
```Python hl_lines="68-69 81"
{!> ../../../docs_src/websockets/tutorial002.py!}
```
!!! info
由于这是一个 WebSocket,抛出 `HTTPException` 并不是很合理,而是抛出 `WebSocketException`
您可以使用<a href="https://tools.ietf.org/html/rfc6455#section-7.4.1" class="external-link" target="_blank">规范中定义的有效代码</a>
### 尝试带有依赖项的 WebSockets
如果您的文件名为 `main.py`,请使用以下命令运行应用程序:
```console
$ uvicorn main:app --reload
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
```
在浏览器中打开 <a href="http://127.0.0.1:8000" class="external-link" target="_blank">http://127.0.0.1:8000</a>
在页面中,您可以设置:
* "Item ID",用于路径。
* "Token",作为查询参数。
!!! tip
注意,查询参数 `token` 将由依赖项处理。
通过这样,您可以连接 WebSocket,然后发送和接收消息:
<img src="/img/tutorial/websockets/image05.png">
## 处理断开连接和多个客户端
当 WebSocket 连接关闭时,`await websocket.receive_text()` 将引发 `WebSocketDisconnect` 异常,您可以捕获并处理该异常,就像本示例中的示例一样。
=== "Python 3.9+"
```Python hl_lines="79-81"
{!> ../../../docs_src/websockets/tutorial003_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="81-83"
{!> ../../../docs_src/websockets/tutorial003.py!}
```
尝试以下操作:
* 使用多个浏览器选项卡打开应用程序。
* 从这些选项卡中发送消息。
* 然后关闭其中一个选项卡。
这将引发 `WebSocketDisconnect` 异常,并且所有其他客户端都会收到类似以下的消息:
```
Client #1596980209979 left the chat
```
!!! tip
上面的应用程序是一个最小和简单的示例,用于演示如何处理和向多个 WebSocket 连接广播消息。
但请记住,由于所有内容都在内存中以单个列表的形式处理,因此它只能在进程运行时工作,并且只能使用单个进程。
如果您需要与 FastAPI 集成更简单但更强大的功能,支持 Redis、PostgreSQL 或其他功能,请查看 [encode/broadcaster](https://github.com/encode/broadcaster)。
## 更多信息
要了解更多选项,请查看 Starlette 的文档:
* [WebSocket 类](https://www.starlette.io/websockets/)
* [基于类的 WebSocket 处理](https://www.starlette.io/endpoints/#websocketendpoint)。

1
docs/zh/docs/index.md

@ -437,7 +437,6 @@ item: Item
用于 Pydantic:
* <a href="https://github.com/esnme/ultrajson" target="_blank"><code>ujson</code></a> - 更快的 JSON <abbr title="将来自 HTTP 请求中的字符串转换为 Python 数据类型">「解析」</abbr>
* <a href="https://github.com/JoshData/python-email-validator" target="_blank"><code>email_validator</code></a> - 用于 email 校验。
用于 Starlette:

212
docs/zh/docs/tutorial/testing.md

@ -0,0 +1,212 @@
# 测试
感谢 <a href="https://www.starlette.io/testclient/" class="external-link" target="_blank">Starlette</a>,测试**FastAPI** 应用轻松又愉快。
它基于 <a href="https://www.python-httpx.org" class="external-link" target="_blank">HTTPX</a>, 而HTTPX又是基于Requests设计的,所以很相似且易懂。
有了它,你可以直接与**FastAPI**一起使用 <a href="https://docs.pytest.org/" class="external-link" target="_blank">pytest</a>
## 使用 `TestClient`
!!! 信息
要使用 `TestClient`,先要安装 <a href="https://www.python-httpx.org" class="external-link" target="_blank">`httpx`</a>.
例:`pip install httpx`.
导入 `TestClient`.
通过传入你的**FastAPI**应用创建一个 `TestClient`
创建名字以 `test_` 开头的函数(这是标准的 `pytest` 约定)。
像使用 `httpx` 那样使用 `TestClient` 对象。
为你需要检查的地方用标准的Python表达式写个简单的 `assert` 语句(重申,标准的`pytest`)。
```Python hl_lines="2 12 15-18"
{!../../../docs_src/app_testing/tutorial001.py!}
```
!!! 提示
注意测试函数是普通的 `def`,不是 `async def`
还有client的调用也是普通的调用,不是用 `await`
这让你可以直接使用 `pytest` 而不会遇到麻烦。
!!! note "技术细节"
你也可以用 `from starlette.testclient import TestClient`
**FastAPI** 提供了和 `starlette.testclient` 一样的 `fastapi.testclient`,只是为了方便开发者。但它直接来自Starlette。
!!! 提示
除了发送请求之外,如果你还想测试时在FastAPI应用中调用 `async` 函数(例如异步数据库函数), 可以在高级教程中看下 [Async Tests](../advanced/async-tests.md){.internal-link target=_blank} 。
## 分离测试
在实际应用中,你可能会把你的测试放在另一个文件里。
您的**FastAPI**应用程序也可能由一些文件/模块组成等等。
### **FastAPI** app 文件
假设你有一个像 [更大的应用](./bigger-applications.md){.internal-link target=_blank} 中所描述的文件结构:
```
.
├── app
│   ├── __init__.py
│   └── main.py
```
`main.py` 文件中你有一个 **FastAPI** app:
```Python
{!../../../docs_src/app_testing/main.py!}
```
### 测试文件
然后你会有一个包含测试的文件 `test_main.py` 。app可以像Python包那样存在(一样是目录,但有个 `__init__.py` 文件):
``` hl_lines="5"
.
├── app
│   ├── __init__.py
│   ├── main.py
│   └── test_main.py
```
因为这文件在同一个包中,所以你可以通过相对导入从 `main` 模块(`main.py`)导入`app`对象:
```Python hl_lines="3"
{!../../../docs_src/app_testing/test_main.py!}
```
...然后测试代码和之前一样的。
## 测试:扩展示例
现在让我们扩展这个例子,并添加更多细节,看下如何测试不同部分。
### 扩展后的 **FastAPI** app 文件
让我们继续之前的文件结构:
```
.
├── app
│   ├── __init__.py
│   ├── main.py
│   └── test_main.py
```
假设现在包含**FastAPI** app的文件 `main.py` 有些其他**路径操作**。
有个 `GET` 操作会返回错误。
有个 `POST` 操作会返回一些错误。
所有*路径操作* 都需要一个`X-Token` 头。
=== "Python 3.10+"
```Python
{!> ../../../docs_src/app_testing/app_b_an_py310/main.py!}
```
=== "Python 3.9+"
```Python
{!> ../../../docs_src/app_testing/app_b_an_py39/main.py!}
```
=== "Python 3.6+"
```Python
{!> ../../../docs_src/app_testing/app_b_an/main.py!}
```
=== "Python 3.10+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python
{!> ../../../docs_src/app_testing/app_b_py310/main.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python
{!> ../../../docs_src/app_testing/app_b/main.py!}
```
### 扩展后的测试文件
然后您可以使用扩展后的测试更新`test_main.py`:
```Python
{!> ../../../docs_src/app_testing/app_b/test_main.py!}
```
每当你需要客户端在请求中传递信息,但你不知道如何传递时,你可以通过搜索(谷歌)如何用 `httpx`做,或者是用 `requests` 做,毕竟HTTPX的设计是基于Requests的设计的。
接着只需在测试中同样操作。
示例:
* 传一个*路径* 或*查询* 参数,添加到URL上。
* 传一个JSON体,传一个Python对象(例如一个`dict`)到参数 `json`
* 如果你需要发送 *Form Data* 而不是 JSON,使用 `data` 参数。
* 要发送 *headers*,传 `dict``headers` 参数。
* 对于 *cookies*,传 `dict``cookies` 参数。
关于如何传数据给后端的更多信息 (使用`httpx` 或 `TestClient`),请查阅 <a href="https://www.python-httpx.org" class="external-link" target="_blank">HTTPX 文档</a>.
!!! 信息
注意 `TestClient` 接收可以被转化为JSON的数据,而不是Pydantic模型。
如果你在测试中有一个Pydantic模型,并且你想在测试时发送它的数据给应用,你可以使用在[JSON Compatible Encoder](encoder.md){.internal-link target=_blank}介绍的`jsonable_encoder` 。
## 运行起来
之后,你只需要安装 `pytest`:
<div class="termy">
```console
$ pip install pytest
---> 100%
```
</div>
他会自动检测文件和测试,执行测试,然后向你报告结果。
执行测试:
<div class="termy">
```console
$ pytest
================ test session starts ================
platform linux -- Python 3.6.9, pytest-5.3.5, py-1.8.1, pluggy-0.13.1
rootdir: /home/user/code/superawesome-cli/app
plugins: forked-1.1.3, xdist-1.31.0, cov-2.8.1
collected 6 items
---> 100%
test_main.py <span style="color: green; white-space: pre;">...... [100%]</span>
<span style="color: green;">================= 1 passed in 0.03s =================</span>
```
</div>

5
docs/zh/mkdocs.yml

@ -109,6 +109,7 @@ nav:
- tutorial/bigger-applications.md
- tutorial/metadata.md
- tutorial/static-files.md
- tutorial/testing.md
- tutorial/debugging.md
- 高级用户指南:
- advanced/index.md
@ -118,8 +119,12 @@ nav:
- advanced/custom-response.md
- advanced/response-cookies.md
- advanced/response-change-status-code.md
- advanced/settings.md
- advanced/response-headers.md
- advanced/websockets.md
- advanced/wsgi.md
- 高级安全:
- advanced/security/index.md
- contributing.md
- help-fastapi.md
- benchmarks.md

2
fastapi/__init__.py

@ -1,6 +1,6 @@
"""FastAPI framework, high performance, easy to learn, fast to code, ready for production"""
__version__ = "0.97.0"
__version__ = "0.98.0"
from starlette import status as status

4
requirements-docs.txt

@ -1,6 +1,6 @@
-e .
mkdocs >=1.1.2,<2.0.0
mkdocs-material >=8.1.4,<9.0.0
mkdocs==1.4.3
mkdocs-material==9.1.16
mdx-include >=1.4.1,<2.0.0
mkdocs-markdownextradata-plugin >=0.1.7,<0.3.0
typer-cli >=0.0.13,<0.0.14

4
requirements-tests.txt

@ -1,8 +1,8 @@
-e .
pytest >=7.1.3,<8.0.0
coverage[toml] >= 6.5.0,< 8.0
mypy ==1.3.0
ruff ==0.0.272
mypy ==1.4.0
ruff ==0.0.275
black == 23.3.0
httpx >=0.23.0,<0.24.0
email_validator >=1.1.1,<2.0.0

4
requirements.txt

@ -1,5 +1,5 @@
-e .[all]
-r requirements-tests.txt
-r requirements-docs.txt
uvicorn[standard] >=0.12.0,<0.21.0
pre-commit >=2.17.0,<3.0.0
uvicorn[standard] >=0.12.0,<0.23.0
pre-commit >=2.17.0,<4.0.0

152
scripts/docs.py

@ -1,3 +1,4 @@
import json
import os
import re
import shutil
@ -133,75 +134,83 @@ def build_lang(
build_lang_path = build_dir_path / lang
en_lang_path = Path("docs/en")
site_path = Path("site").absolute()
build_site_path = Path("site_build").absolute()
build_site_dist_path = build_site_path / lang
if lang == "en":
dist_path = site_path
else:
dist_path: Path = site_path / lang
shutil.rmtree(build_lang_path, ignore_errors=True)
shutil.copytree(lang_path, build_lang_path)
shutil.copytree(en_docs_path / "data", build_lang_path / "data")
overrides_src = en_docs_path / "overrides"
overrides_dest = build_lang_path / "overrides"
for path in overrides_src.iterdir():
dest_path = overrides_dest / path.name
if not dest_path.exists():
shutil.copy(path, dest_path)
en_config_path: Path = en_lang_path / mkdocs_name
en_config: dict = mkdocs.utils.yaml_load(en_config_path.read_text(encoding="utf-8"))
nav = en_config["nav"]
lang_config_path: Path = lang_path / mkdocs_name
lang_config: dict = mkdocs.utils.yaml_load(
lang_config_path.read_text(encoding="utf-8")
)
lang_nav = lang_config["nav"]
# Exclude first 2 entries FastAPI and Languages, for custom handling
use_nav = nav[2:]
lang_use_nav = lang_nav[2:]
file_to_nav = get_file_to_nav_map(use_nav)
sections = get_sections(use_nav)
lang_file_to_nav = get_file_to_nav_map(lang_use_nav)
use_lang_file_to_nav = get_file_to_nav_map(lang_use_nav)
for file in file_to_nav:
file_path = Path(file)
lang_file_path: Path = build_lang_path / "docs" / file_path
en_file_path: Path = en_lang_path / "docs" / file_path
lang_file_path.parent.mkdir(parents=True, exist_ok=True)
if not lang_file_path.is_file():
en_text = en_file_path.read_text(encoding="utf-8")
lang_text = get_text_with_translate_missing(en_text)
lang_file_path.write_text(lang_text, encoding="utf-8")
file_key = file_to_nav[file]
use_lang_file_to_nav[file] = file_key
if file_key:
composite_key = ()
new_key = ()
for key_part in file_key:
composite_key += (key_part,)
key_first_file = sections[composite_key]
if key_first_file in lang_file_to_nav:
new_key = lang_file_to_nav[key_first_file]
else:
new_key += (key_part,)
use_lang_file_to_nav[file] = new_key
key_to_section = {(): []}
for file, orig_file_key in file_to_nav.items():
if file in use_lang_file_to_nav:
file_key = use_lang_file_to_nav[file]
else:
file_key = orig_file_key
section = get_key_section(key_to_section=key_to_section, key=file_key)
section.append(file)
new_nav = key_to_section[()]
export_lang_nav = [lang_nav[0], nav[1]] + new_nav
lang_config["nav"] = export_lang_nav
build_lang_config_path: Path = build_lang_path / mkdocs_name
build_lang_config_path.write_text(
yaml.dump(lang_config, sort_keys=False, width=200, allow_unicode=True),
encoding="utf-8",
)
if not lang == "en":
shutil.copytree(en_docs_path / "data", build_lang_path / "data")
overrides_src = en_docs_path / "overrides"
overrides_dest = build_lang_path / "overrides"
for path in overrides_src.iterdir():
dest_path = overrides_dest / path.name
if not dest_path.exists():
shutil.copy(path, dest_path)
en_config_path: Path = en_lang_path / mkdocs_name
en_config: dict = mkdocs.utils.yaml_load(
en_config_path.read_text(encoding="utf-8")
)
nav = en_config["nav"]
lang_config_path: Path = lang_path / mkdocs_name
lang_config: dict = mkdocs.utils.yaml_load(
lang_config_path.read_text(encoding="utf-8")
)
lang_nav = lang_config["nav"]
# Exclude first 2 entries FastAPI and Languages, for custom handling
use_nav = nav[2:]
lang_use_nav = lang_nav[2:]
file_to_nav = get_file_to_nav_map(use_nav)
sections = get_sections(use_nav)
lang_file_to_nav = get_file_to_nav_map(lang_use_nav)
use_lang_file_to_nav = get_file_to_nav_map(lang_use_nav)
for file in file_to_nav:
file_path = Path(file)
lang_file_path: Path = build_lang_path / "docs" / file_path
en_file_path: Path = en_lang_path / "docs" / file_path
lang_file_path.parent.mkdir(parents=True, exist_ok=True)
if not lang_file_path.is_file():
en_text = en_file_path.read_text(encoding="utf-8")
lang_text = get_text_with_translate_missing(en_text)
lang_file_path.write_text(lang_text, encoding="utf-8")
file_key = file_to_nav[file]
use_lang_file_to_nav[file] = file_key
if file_key:
composite_key = ()
new_key = ()
for key_part in file_key:
composite_key += (key_part,)
key_first_file = sections[composite_key]
if key_first_file in lang_file_to_nav:
new_key = lang_file_to_nav[key_first_file]
else:
new_key += (key_part,)
use_lang_file_to_nav[file] = new_key
key_to_section = {(): []}
for file, orig_file_key in file_to_nav.items():
if file in use_lang_file_to_nav:
file_key = use_lang_file_to_nav[file]
else:
file_key = orig_file_key
section = get_key_section(key_to_section=key_to_section, key=file_key)
section.append(file)
new_nav = key_to_section[()]
export_lang_nav = [lang_nav[0], nav[1]] + new_nav
lang_config["nav"] = export_lang_nav
build_lang_config_path: Path = build_lang_path / mkdocs_name
build_lang_config_path.write_text(
yaml.dump(lang_config, sort_keys=False, width=200, allow_unicode=True),
encoding="utf-8",
)
current_dir = os.getcwd()
os.chdir(build_lang_path)
subprocess.run(["mkdocs", "build", "--site-dir", dist_path], check=True)
shutil.rmtree(build_site_dist_path, ignore_errors=True)
shutil.rmtree(dist_path, ignore_errors=True)
subprocess.run(["mkdocs", "build", "--site-dir", build_site_dist_path], check=True)
shutil.copytree(build_site_dist_path, dist_path, dirs_exist_ok=True)
os.chdir(current_dir)
typer.secho(f"Successfully built docs for: {lang}", color=typer.colors.GREEN)
@ -271,18 +280,8 @@ def build_all():
Build mkdocs site for en, and then build each language inside, end result is located
at directory ./site/ with each language inside.
"""
site_path = Path("site").absolute()
update_languages(lang=None)
current_dir = os.getcwd()
os.chdir(en_docs_path)
typer.echo("Building docs for: en")
subprocess.run(["mkdocs", "build", "--site-dir", site_path], check=True)
os.chdir(current_dir)
langs = []
for lang in get_lang_paths():
if lang == en_docs_path or not lang.is_dir():
continue
langs.append(lang.name)
langs = [lang.name for lang in get_lang_paths() if lang.is_dir()]
cpu_count = os.cpu_count() or 1
process_pool_size = cpu_count * 4
typer.echo(f"Using process pool size: {process_pool_size}")
@ -397,6 +396,15 @@ def update_config(lang: str):
)
@app.command()
def langs_json():
langs = []
for lang_path in get_lang_paths():
if lang_path.is_dir():
langs.append(lang_path.name)
print(json.dumps(langs))
def get_key_section(
*, key_to_section: Dict[Tuple[str, ...], list], key: Tuple[str, ...]
) -> list:

11
scripts/zip-docs.sh

@ -1,11 +0,0 @@
#!/usr/bin/env bash
set -x
set -e
cd ./site
if [ -f docs.zip ]; then
rm -rf docs.zip
fi
zip -r docs.zip ./
Loading…
Cancel
Save