From ffb8965260c71657f26644673f218b99b1315cc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Wed, 11 Feb 2026 04:33:49 -0800 Subject: [PATCH 01/20] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Update=20build=20set?= =?UTF-8?q?up=20for=20`fastapi-slim`,=20deprecate=20it,=20and=20make=20it?= =?UTF-8?q?=20only=20depend=20on=20`fastapi`=20(#14894)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/test-redistribute.yml | 9 ----- fastapi-slim/README.md | 54 +++++++++++++++++++++++++ pdm_build.py | 28 +++++++++++-- pyproject.toml | 23 +++++++++++ 4 files changed, 101 insertions(+), 13 deletions(-) create mode 100644 fastapi-slim/README.md diff --git a/.github/workflows/test-redistribute.yml b/.github/workflows/test-redistribute.yml index 0491d33ba..ad9df4bf9 100644 --- a/.github/workflows/test-redistribute.yml +++ b/.github/workflows/test-redistribute.yml @@ -12,11 +12,6 @@ on: jobs: test-redistribute: runs-on: ubuntu-latest - strategy: - matrix: - package: - - fastapi - - fastapi-slim steps: - name: Dump GitHub context env: @@ -30,8 +25,6 @@ jobs: - name: Install build dependencies run: pip install build - name: Build source distribution - env: - TIANGOLO_BUILD_PACKAGE: ${{ matrix.package }} run: python -m build --sdist - name: Decompress source distribution run: | @@ -41,8 +34,6 @@ jobs: run: | cd dist/fastapi*/ pip install --group tests --editable .[all] - env: - TIANGOLO_BUILD_PACKAGE: ${{ matrix.package }} - name: Run source distribution tests run: | cd dist/fastapi*/ diff --git a/fastapi-slim/README.md b/fastapi-slim/README.md new file mode 100644 index 000000000..e378a9c8c --- /dev/null +++ b/fastapi-slim/README.md @@ -0,0 +1,54 @@ +

+ FastAPI +

+

+ FastAPI framework, high performance, easy to learn, fast to code, ready for production +

+

+ + Test + + + Coverage + + + Package version + + + Supported Python versions + +

+ +--- + +**Documentation**: https://fastapi.tiangolo.com + +**Source Code**: https://github.com/fastapi/fastapi + +--- + +FastAPI is a modern, fast (high-performance), web framework for building APIs with Python based on standard Python type hints. + +## `fastapi-slim` + +⚠️ Do not install this package. ⚠️ + +This package, `fastapi-slim`, does nothing other than depend on `fastapi`. + +All the functionality has been integrated into `fastapi`. + +The only reason this package exists is as a migration path for old projects that used to depend on `fastapi-slim`, so that they can get the latest version of `fastapi`. + +You **should not** install this package. + +Install instead: + +```bash +pip install fastapi +``` + +This package is deprecated and will stop receiving any updates and published versions. + +## License + +This project is licensed under the terms of the MIT license. diff --git a/pdm_build.py b/pdm_build.py index a0eb88eeb..67e71cbb0 100644 --- a/pdm_build.py +++ b/pdm_build.py @@ -3,18 +3,38 @@ from typing import Any from pdm.backend.hooks import Context -TIANGOLO_BUILD_PACKAGE = os.getenv("TIANGOLO_BUILD_PACKAGE", "fastapi") +TIANGOLO_BUILD_PACKAGE = os.getenv("TIANGOLO_BUILD_PACKAGE", "typer") def pdm_build_initialize(context: Context) -> None: metadata = context.config.metadata + # Get main version + version = metadata["version"] # Get custom config for the current package, from the env var - config: dict[str, Any] = context.config.data["tool"]["tiangolo"][ + all_configs_config: dict[str, Any] = context.config.data["tool"]["tiangolo"][ "_internal-slim-build" - ]["packages"].get(TIANGOLO_BUILD_PACKAGE) - if not config: + ]["packages"] + + if TIANGOLO_BUILD_PACKAGE not in all_configs_config: return + + config = all_configs_config[TIANGOLO_BUILD_PACKAGE] project_config: dict[str, Any] = config["project"] # Override main [project] configs with custom configs for this package for key, value in project_config.items(): metadata[key] = value + # Get custom build config for the current package + build_config: dict[str, Any] = ( + config.get("tool", {}).get("pdm", {}).get("build", {}) + ) + # Override PDM build config with custom build config for this package + for key, value in build_config.items(): + context.config.build_config[key] = value + # Get main dependencies + dependencies: list[str] = metadata.get("dependencies", []) + # Sync versions in dependencies + new_dependencies = [] + for dep in dependencies: + new_dep = f"{dep}>={version}" + new_dependencies.append(new_dep) + metadata["dependencies"] = new_dependencies diff --git a/pyproject.toml b/pyproject.toml index 4895c2d34..d8c43f7a4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -202,6 +202,29 @@ source-includes = [ [tool.tiangolo._internal-slim-build.packages.fastapi-slim.project] name = "fastapi-slim" +readme = "fastapi-slim/README.md" +dependencies = [ + "fastapi", +] +optional-dependencies = {} +scripts = {} + +[tool.tiangolo._internal-slim-build.packages.fastapi-slim.tool.pdm.build] +# excludes needs to explicitly exclude the top level python packages, +# otherwise PDM includes them by default +# A "*" glob pattern can't be used here because in PDM internals, the patterns are put +# in a set (unordered, order varies) and each excluded file is assigned one of the +# glob patterns that matches, as the set is unordered, the matched pattern could be "*" +# independent of the order here. And then the internal code would give it a lower score +# than the one for a default included file. +# By not using "*" and explicitly excluding the top level packages, they get a higher +# score than the default inclusion +excludes = ["fastapi", "tests", "pdm_build.py"] +# source-includes needs to explicitly define some value because PDM will check the +# truthy value of the list, and if empty, will include some defaults, including "tests", +# an empty string doesn't match anything, but makes the list truthy, so that PDM +# doesn't override it during the build. +source-includes = [""] [tool.mypy] plugins = ["pydantic.mypy"] From 417f1ee07825c6f4e983629bee6039857197112f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 11 Feb 2026 12:34:12 +0000 Subject: [PATCH 02/20] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [skip ci] --- docs/en/docs/release-notes.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index bf8850828..014bae1ab 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -11,6 +11,10 @@ hide: * 📝 Fix grammar in `docs/en/docs/tutorial/first-steps.md`. PR [#14708](https://github.com/fastapi/fastapi/pull/14708) by [@SanjanaS10](https://github.com/SanjanaS10). +### Internal + +* ♻️ Update build setup for `fastapi-slim`, deprecate it, and make it only depend on `fastapi`. PR [#14894](https://github.com/fastapi/fastapi/pull/14894) by [@tiangolo](https://github.com/tiangolo). + ## 0.128.7 ### Features From aac30fd7071d79798130137728aeb363c8c5f695 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Wed, 11 Feb 2026 05:37:09 -0800 Subject: [PATCH 03/20] =?UTF-8?q?=F0=9F=94=A8=20Tweak=20PDM=20hook=20scrip?= =?UTF-8?q?t=20(#14895)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pdm_build.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pdm_build.py b/pdm_build.py index 67e71cbb0..b1b662bd3 100644 --- a/pdm_build.py +++ b/pdm_build.py @@ -3,7 +3,7 @@ from typing import Any from pdm.backend.hooks import Context -TIANGOLO_BUILD_PACKAGE = os.getenv("TIANGOLO_BUILD_PACKAGE", "typer") +TIANGOLO_BUILD_PACKAGE = os.getenv("TIANGOLO_BUILD_PACKAGE") def pdm_build_initialize(context: Context) -> None: From 1ed9bd49230b192bb531f4195d3d6a309261a777 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 11 Feb 2026 13:37:37 +0000 Subject: [PATCH 04/20] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [skip ci] --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 014bae1ab..65668c8ab 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -13,6 +13,7 @@ hide: ### Internal +* 🔨 Tweak PDM hook script. PR [#14895](https://github.com/fastapi/fastapi/pull/14895) by [@tiangolo](https://github.com/tiangolo). * ♻️ Update build setup for `fastapi-slim`, deprecate it, and make it only depend on `fastapi`. PR [#14894](https://github.com/fastapi/fastapi/pull/14894) by [@tiangolo](https://github.com/tiangolo). ## 0.128.7 From bdd20051c42d08762b2cdcc6571e4356014de572 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Wed, 11 Feb 2026 16:16:34 +0100 Subject: [PATCH 05/20] =?UTF-8?q?=F0=9F=94=96=20Release=20version=200.128.?= =?UTF-8?q?8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 2 ++ fastapi/__init__.py | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 65668c8ab..be11b7827 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -7,6 +7,8 @@ hide: ## Latest Changes +## 0.128.8 + ### Docs * 📝 Fix grammar in `docs/en/docs/tutorial/first-steps.md`. PR [#14708](https://github.com/fastapi/fastapi/pull/14708) by [@SanjanaS10](https://github.com/SanjanaS10). diff --git a/fastapi/__init__.py b/fastapi/__init__.py index a9fe3e971..9931216ee 100644 --- a/fastapi/__init__.py +++ b/fastapi/__init__.py @@ -1,6 +1,6 @@ """FastAPI framework, high performance, easy to learn, fast to code, ready for production""" -__version__ = "0.128.7" +__version__ = "0.128.8" from starlette import status as status From ad4e8e006016e088dbccdb73305a58a1338b1ad9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Wed, 11 Feb 2026 10:32:12 -0800 Subject: [PATCH 06/20] =?UTF-8?q?=E2=9E=96=20Drop=20support=20for=20Python?= =?UTF-8?q?=203.9=20(#14897)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: github-actions[bot] --- .github/workflows/test.yml | 6 +- .../en/docs/advanced/advanced-python-types.md | 61 + docs/en/docs/deployment/docker.md | 8 +- docs/en/docs/python-types.md | 156 +- docs/en/docs/tutorial/body-multiple-params.md | 7 - docs/en/docs/tutorial/body.md | 2 +- .../dependencies/classes-as-dependencies.md | 24 +- .../tutorial/dependencies/sub-dependencies.md | 4 +- docs/en/docs/tutorial/extra-models.md | 4 +- .../tutorial/query-params-str-validations.md | 24 - docs/en/mkdocs.yml | 1 + fastapi/_compat/shared.py | 30 +- fastapi/dependencies/utils.py | 77 +- pyproject.toml | 3 +- tests/test_dependencies_utils.py | 8 + uv.lock | 2300 +++-------------- 16 files changed, 485 insertions(+), 2230 deletions(-) create mode 100644 docs/en/docs/advanced/advanced-python-types.md create mode 100644 tests/test_dependencies_utils.py diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 3fb837c04..338f6c390 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -56,14 +56,10 @@ jobs: - starlette-pypi - starlette-git include: - - os: ubuntu-latest - python-version: "3.9" - coverage: coverage - uv-resolution: lowest-direct - os: macos-latest python-version: "3.10" coverage: coverage - uv-resolution: highest + uv-resolution: lowest-direct - os: windows-latest python-version: "3.12" coverage: coverage diff --git a/docs/en/docs/advanced/advanced-python-types.md b/docs/en/docs/advanced/advanced-python-types.md new file mode 100644 index 000000000..6495cbe44 --- /dev/null +++ b/docs/en/docs/advanced/advanced-python-types.md @@ -0,0 +1,61 @@ +# Advanced Python Types { #advanced-python-types } + +Here are some additional ideas that might be useful when working with Python types. + +## Using `Union` or `Optional` { #using-union-or-optional } + +If your code for some reason can't use `|`, for example if it's not in a type annotation but in something like `response_model=`, instead of using the vertical bar (`|`) you can use `Union` from `typing`. + +For example, you could declare that something could be a `str` or `None`: + +```python +from typing import Union + + +def say_hi(name: Union[str, None]): + print(f"Hi {name}!") +``` + +`typing` also has a shortcut to declare that something could be `None`, with `Optional`. + +Here's a tip from my very **subjective** point of view: + +* 🚨 Avoid using `Optional[SomeType]` +* Instead ✨ **use `Union[SomeType, None]`** ✨. + +Both are equivalent and underneath they are the same, but I would recommend `Union` instead of `Optional` because the word "**optional**" would seem to imply that the value is optional, and it actually means "it can be `None`", even if it's not optional and is still required. + +I think `Union[SomeType, None]` is more explicit about what it means. + +It's just about the words and names. But those words can affect how you and your teammates think about the code. + +As an example, let's take this function: + +```python +from typing import Optional + + +def say_hi(name: Optional[str]): + print(f"Hey {name}!") +``` + +The parameter `name` is defined as `Optional[str]`, but it is **not optional**, you cannot call the function without the parameter: + +```Python +say_hi() # Oh, no, this throws an error! 😱 +``` + +The `name` parameter is **still required** (not *optional*) because it doesn't have a default value. Still, `name` accepts `None` as the value: + +```Python +say_hi(name=None) # This works, None is valid 🎉 +``` + +The good news is, in most cases, you will be able to simply use `|` to define unions of types: + +```python +def say_hi(name: str | None): + print(f"Hey {name}!") +``` + +So, normally you don't have to worry about names like `Optional` and `Union`. 😎 diff --git a/docs/en/docs/deployment/docker.md b/docs/en/docs/deployment/docker.md index 0f15a60a4..4806d779d 100644 --- a/docs/en/docs/deployment/docker.md +++ b/docs/en/docs/deployment/docker.md @@ -14,7 +14,7 @@ In a hurry and already know this stuff? Jump to the [`Dockerfile` below 👇](#b Dockerfile Preview 👀 ```Dockerfile -FROM python:3.9 +FROM python:3.14 WORKDIR /code @@ -166,7 +166,7 @@ Now in the same project directory create a file `Dockerfile` with: ```{ .dockerfile .annotate } # (1)! -FROM python:3.9 +FROM python:3.14 # (2)! WORKDIR /code @@ -390,7 +390,7 @@ If your FastAPI is a single file, for example, `main.py` without an `./app` dire Then you would just have to change the corresponding paths to copy the file inside the `Dockerfile`: ```{ .dockerfile .annotate hl_lines="10 13" } -FROM python:3.9 +FROM python:3.14 WORKDIR /code @@ -499,7 +499,7 @@ Of course, there are **special cases** where you could want to have **a containe In those cases, you can use the `--workers` command line option to set the number of workers that you want to run: ```{ .dockerfile .annotate } -FROM python:3.9 +FROM python:3.14 WORKDIR /code diff --git a/docs/en/docs/python-types.md b/docs/en/docs/python-types.md index 6de170ada..f2ad35d71 100644 --- a/docs/en/docs/python-types.md +++ b/docs/en/docs/python-types.md @@ -135,27 +135,30 @@ You can use, for example: {* ../../docs_src/python_types/tutorial005_py39.py hl[1] *} -### Generic types with type parameters { #generic-types-with-type-parameters } +### `typing` module { #typing-module } -There are some data structures that can contain other values, like `dict`, `list`, `set` and `tuple`. And the internal values can have their own type too. +For some additional use cases, you might need to import some things from the standard library `typing` module, for example when you want to declare that something has "any type", you can use `Any` from `typing`: -These types that have internal types are called "**generic**" types. And it's possible to declare them, even with their internal types. +```python +from typing import Any -To declare those types and the internal types, you can use the standard Python module `typing`. It exists specifically to support these type hints. -#### Newer versions of Python { #newer-versions-of-python } +def some_function(data: Any): + print(data) +``` -The syntax using `typing` is **compatible** with all versions, from Python 3.6 to the latest ones, including Python 3.9, Python 3.10, etc. +### Generic types { #generic-types } -As Python advances, **newer versions** come with improved support for these type annotations and in many cases you won't even need to import and use the `typing` module to declare the type annotations. +Some types can take "type parameters" in square brackets, to define their internal types, for example a "list of strings" would be declared `list[str]`. -If you can choose a more recent version of Python for your project, you will be able to take advantage of that extra simplicity. +These types that can take type parameters are called **Generic types** or **Generics**. -In all the docs there are examples compatible with each version of Python (when there's a difference). +You can use the same builtin types as generics (with square brackets and types inside): -For example "**Python 3.6+**" means it's compatible with Python 3.6 or above (including 3.7, 3.8, 3.9, 3.10, etc). And "**Python 3.9+**" means it's compatible with Python 3.9 or above (including 3.10, etc). - -If you can use the **latest versions of Python**, use the examples for the latest version, those will have the **best and simplest syntax**, for example, "**Python 3.10+**". +* `list` +* `tuple` +* `set` +* `dict` #### List { #list } @@ -220,44 +223,20 @@ This means: You can declare that a variable can be any of **several types**, for example, an `int` or a `str`. -In Python 3.6 and above (including Python 3.10) you can use the `Union` type from `typing` and put inside the square brackets the possible types to accept. +To define it you use the vertical bar (`|`) to separate both types. -In Python 3.10 there's also a **new syntax** where you can put the possible types separated by a vertical bar (`|`). - -//// tab | Python 3.10+ +This is called a "union", because the variable can be anything in the union of those two sets of types. ```Python hl_lines="1" {!> ../../docs_src/python_types/tutorial008b_py310.py!} ``` -//// - -//// tab | Python 3.9+ - -```Python hl_lines="1 4" -{!> ../../docs_src/python_types/tutorial008b_py39.py!} -``` - -//// - -In both cases this means that `item` could be an `int` or a `str`. +This means that `item` could be an `int` or a `str`. #### Possibly `None` { #possibly-none } You can declare that a value could have a type, like `str`, but that it could also be `None`. -In Python 3.6 and above (including Python 3.10) you can declare it by importing and using `Optional` from the `typing` module. - -```Python hl_lines="1 4" -{!../../docs_src/python_types/tutorial009_py39.py!} -``` - -Using `Optional[str]` instead of just `str` will let the editor help you detect errors where you could be assuming that a value is always a `str`, when it could actually be `None` too. - -`Optional[Something]` is actually a shortcut for `Union[Something, None]`, they are equivalent. - -This also means that in Python 3.10, you can use `Something | None`: - //// tab | Python 3.10+ ```Python hl_lines="1" @@ -266,96 +245,7 @@ This also means that in Python 3.10, you can use `Something | None`: //// -//// tab | Python 3.9+ - -```Python hl_lines="1 4" -{!> ../../docs_src/python_types/tutorial009_py39.py!} -``` - -//// - -//// tab | Python 3.9+ alternative - -```Python hl_lines="1 4" -{!> ../../docs_src/python_types/tutorial009b_py39.py!} -``` - -//// - -#### Using `Union` or `Optional` { #using-union-or-optional } - -If you are using a Python version below 3.10, here's a tip from my very **subjective** point of view: - -* 🚨 Avoid using `Optional[SomeType]` -* Instead ✨ **use `Union[SomeType, None]`** ✨. - -Both are equivalent and underneath they are the same, but I would recommend `Union` instead of `Optional` because the word "**optional**" would seem to imply that the value is optional, and it actually means "it can be `None`", even if it's not optional and is still required. - -I think `Union[SomeType, None]` is more explicit about what it means. - -It's just about the words and names. But those words can affect how you and your teammates think about the code. - -As an example, let's take this function: - -{* ../../docs_src/python_types/tutorial009c_py39.py hl[1,4] *} - -The parameter `name` is defined as `Optional[str]`, but it is **not optional**, you cannot call the function without the parameter: - -```Python -say_hi() # Oh, no, this throws an error! 😱 -``` - -The `name` parameter is **still required** (not *optional*) because it doesn't have a default value. Still, `name` accepts `None` as the value: - -```Python -say_hi(name=None) # This works, None is valid 🎉 -``` - -The good news is, once you are on Python 3.10 you won't have to worry about that, as you will be able to simply use `|` to define unions of types: - -{* ../../docs_src/python_types/tutorial009c_py310.py hl[1,4] *} - -And then you won't have to worry about names like `Optional` and `Union`. 😎 - -#### Generic types { #generic-types } - -These types that take type parameters in square brackets are called **Generic types** or **Generics**, for example: - -//// tab | Python 3.10+ - -You can use the same builtin types as generics (with square brackets and types inside): - -* `list` -* `tuple` -* `set` -* `dict` - -And the same as with previous Python versions, from the `typing` module: - -* `Union` -* `Optional` -* ...and others. - -In Python 3.10, as an alternative to using the generics `Union` and `Optional`, you can use the vertical bar (`|`) to declare unions of types, that's a lot better and simpler. - -//// - -//// tab | Python 3.9+ - -You can use the same builtin types as generics (with square brackets and types inside): - -* `list` -* `tuple` -* `set` -* `dict` - -And generics from the `typing` module: - -* `Union` -* `Optional` -* ...and others. - -//// +Using `str | None` instead of just `str` will let the editor help you detect errors where you could be assuming that a value is always a `str`, when it could actually be `None` too. ### Classes as types { #classes-as-types } @@ -403,17 +293,11 @@ To learn more about Required Optional fields. - -/// - ## Type Hints with Metadata Annotations { #type-hints-with-metadata-annotations } Python also has a feature that allows putting **additional metadata** in these type hints using `Annotated`. -Since Python 3.9, `Annotated` is a part of the standard library, so you can import it from `typing`. +You can import `Annotated` from `typing`. {* ../../docs_src/python_types/tutorial013_py39.py hl[1,4] *} diff --git a/docs/en/docs/tutorial/body-multiple-params.md b/docs/en/docs/tutorial/body-multiple-params.md index bb0c58368..d904fb839 100644 --- a/docs/en/docs/tutorial/body-multiple-params.md +++ b/docs/en/docs/tutorial/body-multiple-params.md @@ -106,13 +106,6 @@ As, by default, singular values are interpreted as query parameters, you don't h q: str | None = None ``` -Or in Python 3.9: - -```Python -q: Union[str, None] = None -``` - - For example: {* ../../docs_src/body_multiple_params/tutorial004_an_py310.py hl[28] *} diff --git a/docs/en/docs/tutorial/body.md b/docs/en/docs/tutorial/body.md index 2d0dfcbb5..fb4471836 100644 --- a/docs/en/docs/tutorial/body.md +++ b/docs/en/docs/tutorial/body.md @@ -155,7 +155,7 @@ The function parameters will be recognized as follows: FastAPI will know that the value of `q` is not required because of the default value `= None`. -The `str | None` (Python 3.10+) or `Union` in `Union[str, None]` (Python 3.9+) is not used by FastAPI to determine that the value is not required, it will know it's not required because it has a default value of `= None`. +The `str | None` is not used by FastAPI to determine that the value is not required, it will know it's not required because it has a default value of `= None`. But adding the type annotations will allow your editor to give you better support and detect errors. diff --git a/docs/en/docs/tutorial/dependencies/classes-as-dependencies.md b/docs/en/docs/tutorial/dependencies/classes-as-dependencies.md index 0a6a786b5..d9a02d5b8 100644 --- a/docs/en/docs/tutorial/dependencies/classes-as-dependencies.md +++ b/docs/en/docs/tutorial/dependencies/classes-as-dependencies.md @@ -101,7 +101,7 @@ Now you can declare your dependency using this class. Notice how we write `CommonQueryParams` twice in the above code: -//// tab | Python 3.9+ +//// tab | Python 3.10+ ```Python commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)] @@ -109,7 +109,7 @@ commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)] //// -//// tab | Python 3.9+ non-Annotated +//// tab | Python 3.10+ non-Annotated /// tip @@ -137,7 +137,7 @@ It is from this one that FastAPI will extract the declared parameters and that i In this case, the first `CommonQueryParams`, in: -//// tab | Python 3.9+ +//// tab | Python 3.10+ ```Python commons: Annotated[CommonQueryParams, ... @@ -145,7 +145,7 @@ commons: Annotated[CommonQueryParams, ... //// -//// tab | Python 3.9+ non-Annotated +//// tab | Python 3.10+ non-Annotated /// tip @@ -163,7 +163,7 @@ commons: CommonQueryParams ... You could actually write just: -//// tab | Python 3.9+ +//// tab | Python 3.10+ ```Python commons: Annotated[Any, Depends(CommonQueryParams)] @@ -171,7 +171,7 @@ commons: Annotated[Any, Depends(CommonQueryParams)] //// -//// tab | Python 3.9+ non-Annotated +//// tab | Python 3.10+ non-Annotated /// tip @@ -197,7 +197,7 @@ But declaring the type is encouraged as that way your editor will know what will But you see that we are having some code repetition here, writing `CommonQueryParams` twice: -//// tab | Python 3.9+ +//// tab | Python 3.10+ ```Python commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)] @@ -205,7 +205,7 @@ commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)] //// -//// tab | Python 3.9+ non-Annotated +//// tab | Python 3.10+ non-Annotated /// tip @@ -225,7 +225,7 @@ For those specific cases, you can do the following: Instead of writing: -//// tab | Python 3.9+ +//// tab | Python 3.10+ ```Python commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)] @@ -233,7 +233,7 @@ commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)] //// -//// tab | Python 3.9+ non-Annotated +//// tab | Python 3.10+ non-Annotated /// tip @@ -249,7 +249,7 @@ commons: CommonQueryParams = Depends(CommonQueryParams) ...you write: -//// tab | Python 3.9+ +//// tab | Python 3.10+ ```Python commons: Annotated[CommonQueryParams, Depends()] @@ -257,7 +257,7 @@ commons: Annotated[CommonQueryParams, Depends()] //// -//// tab | Python 3.9+ non-Annotated +//// tab | Python 3.10+ non-Annotated /// tip diff --git a/docs/en/docs/tutorial/dependencies/sub-dependencies.md b/docs/en/docs/tutorial/dependencies/sub-dependencies.md index b9a4e3ce7..99588dd3c 100644 --- a/docs/en/docs/tutorial/dependencies/sub-dependencies.md +++ b/docs/en/docs/tutorial/dependencies/sub-dependencies.md @@ -62,7 +62,7 @@ And it will save the returned value in a TypeGuard[type[_T]]: try: return isinstance(cls, type) and issubclass(cls, class_or_tuple) # type: ignore[arg-type] @@ -57,13 +55,13 @@ def lenient_issubclass( raise # pragma: no cover -def _annotation_is_sequence(annotation: Union[type[Any], None]) -> bool: +def _annotation_is_sequence(annotation: type[Any] | None) -> bool: if lenient_issubclass(annotation, (str, bytes)): return False return lenient_issubclass(annotation, sequence_types) -def field_annotation_is_sequence(annotation: Union[type[Any], None]) -> bool: +def field_annotation_is_sequence(annotation: type[Any] | None) -> bool: origin = get_origin(annotation) if origin is Union or origin is UnionType: for arg in get_args(annotation): @@ -79,7 +77,7 @@ def value_is_sequence(value: Any) -> bool: return isinstance(value, sequence_types) and not isinstance(value, (str, bytes)) -def _annotation_is_complex(annotation: Union[type[Any], None]) -> bool: +def _annotation_is_complex(annotation: type[Any] | None) -> bool: return ( lenient_issubclass(annotation, (BaseModel, Mapping, UploadFile)) or _annotation_is_sequence(annotation) @@ -87,7 +85,7 @@ def _annotation_is_complex(annotation: Union[type[Any], None]) -> bool: ) -def field_annotation_is_complex(annotation: Union[type[Any], None]) -> bool: +def field_annotation_is_complex(annotation: type[Any] | None) -> bool: origin = get_origin(annotation) if origin is Union or origin is UnionType: return any(field_annotation_is_complex(arg) for arg in get_args(annotation)) @@ -108,7 +106,7 @@ def field_annotation_is_scalar(annotation: Any) -> bool: return annotation is Ellipsis or not field_annotation_is_complex(annotation) -def field_annotation_is_scalar_sequence(annotation: Union[type[Any], None]) -> bool: +def field_annotation_is_scalar_sequence(annotation: type[Any] | None) -> bool: origin = get_origin(annotation) if origin is Union or origin is UnionType: at_least_one_scalar_sequence = False diff --git a/fastapi/dependencies/utils.py b/fastapi/dependencies/utils.py index 23d8cd9fb..ab18ec2db 100644 --- a/fastapi/dependencies/utils.py +++ b/fastapi/dependencies/utils.py @@ -1,18 +1,19 @@ import dataclasses import inspect import sys -from collections.abc import Mapping, Sequence +from collections.abc import Callable, Mapping, Sequence from contextlib import AsyncExitStack, contextmanager from copy import copy, deepcopy from dataclasses import dataclass from typing import ( Annotated, Any, - Callable, ForwardRef, - Optional, + Literal, Union, cast, + get_args, + get_origin, ) from fastapi import params @@ -63,7 +64,6 @@ from starlette.datastructures import ( from starlette.requests import HTTPConnection, Request from starlette.responses import Response from starlette.websockets import WebSocket -from typing_extensions import Literal, get_args, get_origin from typing_inspection.typing_objects import is_typealiastype multipart_not_installed_error = ( @@ -127,8 +127,8 @@ def get_flat_dependant( dependant: Dependant, *, skip_repeats: bool = False, - visited: Optional[list[DependencyCacheKey]] = None, - parent_oauth_scopes: Optional[list[str]] = None, + visited: list[DependencyCacheKey] | None = None, + parent_oauth_scopes: list[str] | None = None, ) -> Dependant: if visited is None: visited = [] @@ -199,20 +199,17 @@ def get_flat_params(dependant: Dependant) -> list[ModelField]: def _get_signature(call: Callable[..., Any]) -> inspect.Signature: - if sys.version_info >= (3, 10): - try: - signature = inspect.signature(call, eval_str=True) - except NameError: - # Handle type annotations with if TYPE_CHECKING, not used by FastAPI - # e.g. dependency return types - if sys.version_info >= (3, 14): - from annotationlib import Format + try: + signature = inspect.signature(call, eval_str=True) + except NameError: + # Handle type annotations with if TYPE_CHECKING, not used by FastAPI + # e.g. dependency return types + if sys.version_info >= (3, 14): + from annotationlib import Format - signature = inspect.signature(call, annotation_format=Format.FORWARDREF) - else: - signature = inspect.signature(call) - else: - signature = inspect.signature(call) + signature = inspect.signature(call, annotation_format=Format.FORWARDREF) + else: + signature = inspect.signature(call) return signature @@ -258,11 +255,11 @@ def get_dependant( *, path: str, call: Callable[..., Any], - name: Optional[str] = None, - own_oauth_scopes: Optional[list[str]] = None, - parent_oauth_scopes: Optional[list[str]] = None, + name: str | None = None, + own_oauth_scopes: list[str] | None = None, + parent_oauth_scopes: list[str] | None = None, use_cache: bool = True, - scope: Union[Literal["function", "request"], None] = None, + scope: Literal["function", "request"] | None = None, ) -> Dependant: dependant = Dependant( call=call, @@ -331,7 +328,7 @@ def get_dependant( def add_non_field_param_to_dependency( *, param_name: str, type_annotation: Any, dependant: Dependant -) -> Optional[bool]: +) -> bool | None: if lenient_issubclass(type_annotation, Request): dependant.request_param_name = param_name return True @@ -356,8 +353,8 @@ def add_non_field_param_to_dependency( @dataclass class ParamDetails: type_annotation: Any - depends: Optional[params.Depends] - field: Optional[ModelField] + depends: params.Depends | None + field: ModelField | None def analyze_param( @@ -399,7 +396,7 @@ def analyze_param( ) ] if fastapi_specific_annotations: - fastapi_annotation: Union[FieldInfo, params.Depends, None] = ( + fastapi_annotation: FieldInfo | params.Depends | None = ( fastapi_specific_annotations[-1] ) else: @@ -560,20 +557,20 @@ async def _solve_generator( class SolvedDependency: values: dict[str, Any] errors: list[Any] - background_tasks: Optional[StarletteBackgroundTasks] + background_tasks: StarletteBackgroundTasks | None response: Response dependency_cache: dict[DependencyCacheKey, Any] async def solve_dependencies( *, - request: Union[Request, WebSocket], + request: Request | WebSocket, dependant: Dependant, - body: Optional[Union[dict[str, Any], FormData]] = None, - background_tasks: Optional[StarletteBackgroundTasks] = None, - response: Optional[Response] = None, - dependency_overrides_provider: Optional[Any] = None, - dependency_cache: Optional[dict[DependencyCacheKey, Any]] = None, + body: dict[str, Any] | FormData | None = None, + background_tasks: StarletteBackgroundTasks | None = None, + response: Response | None = None, + dependency_overrides_provider: Any | None = None, + dependency_cache: dict[DependencyCacheKey, Any] | None = None, # TODO: remove this parameter later, no longer used, not removing it yet as some # people might be monkey patching this function (although that's not supported) async_exit_stack: AsyncExitStack, @@ -721,7 +718,7 @@ def _is_json_field(field: ModelField) -> bool: def _get_multidict_value( - field: ModelField, values: Mapping[str, Any], alias: Union[str, None] = None + field: ModelField, values: Mapping[str, Any], alias: str | None = None ) -> Any: alias = alias or get_validation_alias(field) if ( @@ -753,7 +750,7 @@ def _get_multidict_value( def request_params_to_args( fields: Sequence[ModelField], - received_params: Union[Mapping[str, Any], QueryParams, Headers], + received_params: Mapping[str, Any] | QueryParams | Headers, ) -> tuple[dict[str, Any], list[Any]]: values: dict[str, Any] = {} errors: list[dict[str, Any]] = [] @@ -901,7 +898,7 @@ async def _extract_form_body( ): # For types assert isinstance(value, sequence_types) - results: list[Union[bytes, str]] = [] + results: list[bytes | str] = [] for sub_value in value: results.append(await sub_value.read()) value = serialize_sequence_value(field=field, value=results) @@ -920,7 +917,7 @@ async def _extract_form_body( async def request_body_to_args( body_fields: list[ModelField], - received_body: Optional[Union[dict[str, Any], FormData]], + received_body: dict[str, Any] | FormData | None, embed_body_fields: bool, ) -> tuple[dict[str, Any], list[dict[str, Any]]]: values: dict[str, Any] = {} @@ -950,7 +947,7 @@ async def request_body_to_args( return {first_field.name: v_}, errors_ for field in body_fields: loc = ("body", get_validation_alias(field)) - value: Optional[Any] = None + value: Any | None = None if body_to_process is not None: try: value = body_to_process.get(get_validation_alias(field)) @@ -970,7 +967,7 @@ async def request_body_to_args( def get_body_field( *, flat_dependant: Dependant, name: str, embed_body_fields: bool -) -> Optional[ModelField]: +) -> ModelField | None: """ Get a ModelField representing the request body for a path operation, combining all body parameters into a single field if necessary. diff --git a/pyproject.toml b/pyproject.toml index d8c43f7a4..e1ce30507 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,7 +9,7 @@ description = "FastAPI framework, high performance, easy to learn, fast to code, readme = "README.md" license = "MIT" license-files = ["LICENSE"] -requires-python = ">=3.9" +requires-python = ">=3.10" authors = [ { name = "Sebastián Ramírez", email = "tiangolo@gmail.com" }, ] @@ -33,7 +33,6 @@ classifiers = [ "Framework :: Pydantic :: 2", "Intended Audience :: Developers", "Programming Language :: Python :: 3 :: Only", - "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", diff --git a/tests/test_dependencies_utils.py b/tests/test_dependencies_utils.py new file mode 100644 index 000000000..9257d1c9e --- /dev/null +++ b/tests/test_dependencies_utils.py @@ -0,0 +1,8 @@ +from fastapi.dependencies.utils import get_typed_annotation + + +def test_get_typed_annotation(): + # For coverage + annotation = "None" + typed_annotation = get_typed_annotation(annotation, globals()) + assert typed_annotation is None diff --git a/uv.lock b/uv.lock index 9a807f8b4..736b0e145 100644 --- a/uv.lock +++ b/uv.lock @@ -1,10 +1,9 @@ version = 1 revision = 3 -requires-python = ">=3.9" +requires-python = ">=3.10" resolution-markers = [ "python_full_version >= '3.14'", - "python_full_version >= '3.10' and python_full_version < '3.14'", - "python_full_version < '3.10'", + "python_full_version < '3.14'", ] [[package]] @@ -158,23 +157,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/3c/5f/24155e30ba7f8c96918af1350eb0663e2430aad9e001c0489d89cd708ab1/aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:fc353029f176fd2b3ec6cfc71be166aba1936fe5d73dd1992ce289ca6647a9aa", size = 1769801, upload-time = "2026-01-03T17:32:20.25Z" }, { url = "https://files.pythonhosted.org/packages/eb/f8/7314031ff5c10e6ece114da79b338ec17eeff3a079e53151f7e9f43c4723/aiohttp-3.13.3-cp314-cp314t-win32.whl", hash = "sha256:2e41b18a58da1e474a057b3d35248d8320029f61d70a37629535b16a0c8f3767", size = 466523, upload-time = "2026-01-03T17:32:22.215Z" }, { url = "https://files.pythonhosted.org/packages/b4/63/278a98c715ae467624eafe375542d8ba9b4383a016df8fdefe0ae28382a7/aiohttp-3.13.3-cp314-cp314t-win_amd64.whl", hash = "sha256:44531a36aa2264a1860089ffd4dce7baf875ee5a6079d5fb42e261c704ef7344", size = 499694, upload-time = "2026-01-03T17:32:24.546Z" }, - { url = "https://files.pythonhosted.org/packages/bf/79/446655656861d3e7e2c32bfcf160c7aa9e9dc63776a691b124dba65cdd77/aiohttp-3.13.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:31a83ea4aead760dfcb6962efb1d861db48c34379f2ff72db9ddddd4cda9ea2e", size = 741433, upload-time = "2026-01-03T17:32:26.453Z" }, - { url = "https://files.pythonhosted.org/packages/cb/49/773c4b310b5140d2fb5e79bb0bf40b7b41dad80a288ca1a8759f5f72bda9/aiohttp-3.13.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:988a8c5e317544fdf0d39871559e67b6341065b87fceac641108c2096d5506b7", size = 497332, upload-time = "2026-01-03T17:32:28.37Z" }, - { url = "https://files.pythonhosted.org/packages/bc/31/1dcbc4b83a4e6f76a0ad883f07f21ffbfe29750c89db97381701508c9f45/aiohttp-3.13.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9b174f267b5cfb9a7dba9ee6859cecd234e9a681841eb85068059bc867fb8f02", size = 492365, upload-time = "2026-01-03T17:32:30.234Z" }, - { url = "https://files.pythonhosted.org/packages/5a/b5/b50657496c8754482cd7964e50aaf3aa84b3db61ed45daec4c1aec5b94b4/aiohttp-3.13.3-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:947c26539750deeaee933b000fb6517cc770bbd064bad6033f1cff4803881e43", size = 1660440, upload-time = "2026-01-03T17:32:32.586Z" }, - { url = "https://files.pythonhosted.org/packages/2a/73/9b69e5139d89d75127569298931444ad78ea86a5befd5599780b1e9a6880/aiohttp-3.13.3-cp39-cp39-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:9ebf57d09e131f5323464bd347135a88622d1c0976e88ce15b670e7ad57e4bd6", size = 1632740, upload-time = "2026-01-03T17:32:34.793Z" }, - { url = "https://files.pythonhosted.org/packages/ef/fe/3ea9b5af694b4e3aec0d0613a806132ca744747146fca68e96bf056f61a7/aiohttp-3.13.3-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4ae5b5a0e1926e504c81c5b84353e7a5516d8778fbbff00429fe7b05bb25cbce", size = 1719782, upload-time = "2026-01-03T17:32:37.737Z" }, - { url = "https://files.pythonhosted.org/packages/fb/c2/46b3b06e60851cbb71efb0f79a3267279cbef7b12c58e68a1e897f269cca/aiohttp-3.13.3-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2ba0eea45eb5cc3172dbfc497c066f19c41bac70963ea1a67d51fc92e4cf9a80", size = 1813527, upload-time = "2026-01-03T17:32:39.973Z" }, - { url = "https://files.pythonhosted.org/packages/36/23/71ceb78c769ed65fe4c697692de232b63dab399210678d2b00961ccb0619/aiohttp-3.13.3-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bae5c2ed2eae26cc382020edad80d01f36cb8e746da40b292e68fec40421dc6a", size = 1661268, upload-time = "2026-01-03T17:32:42.082Z" }, - { url = "https://files.pythonhosted.org/packages/c4/8d/86e929523d955e85ebab7c0e2b9e0cb63604cfc27dc3280e10d0063cf682/aiohttp-3.13.3-cp39-cp39-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:8a60e60746623925eab7d25823329941aee7242d559baa119ca2b253c88a7bd6", size = 1552742, upload-time = "2026-01-03T17:32:44.622Z" }, - { url = "https://files.pythonhosted.org/packages/3a/ea/3f5987cba1bab6bd151f0d97aa60f0ce04d3c83316692a6bb6ba2fb69f92/aiohttp-3.13.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:e50a2e1404f063427c9d027378472316201a2290959a295169bcf25992d04558", size = 1632918, upload-time = "2026-01-03T17:32:46.749Z" }, - { url = "https://files.pythonhosted.org/packages/be/2c/7e1e85121f2e31ee938cb83a8f32dfafd4908530c10fabd6d46761c12ac7/aiohttp-3.13.3-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:9a9dc347e5a3dc7dfdbc1f82da0ef29e388ddb2ed281bfce9dd8248a313e62b7", size = 1644446, upload-time = "2026-01-03T17:32:49.063Z" }, - { url = "https://files.pythonhosted.org/packages/5d/35/ce6133d423ad0e8ca976a7c848f7146bca3520eea4ccf6b95e2d077c9d20/aiohttp-3.13.3-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:b46020d11d23fe16551466c77823df9cc2f2c1e63cc965daf67fa5eec6ca1877", size = 1689487, upload-time = "2026-01-03T17:32:51.113Z" }, - { url = "https://files.pythonhosted.org/packages/50/f7/ff7a27c15603d460fd1366b3c22054f7ae4fa9310aca40b43bde35867fcd/aiohttp-3.13.3-cp39-cp39-musllinux_1_2_riscv64.whl", hash = "sha256:69c56fbc1993fa17043e24a546959c0178fe2b5782405ad4559e6c13975c15e3", size = 1540715, upload-time = "2026-01-03T17:32:53.38Z" }, - { url = "https://files.pythonhosted.org/packages/17/02/053f11346e5b962e6d8a1c4f8c70c29d5970a1b4b8e7894c68e12c27a57f/aiohttp-3.13.3-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:b99281b0704c103d4e11e72a76f1b543d4946fea7dd10767e7e1b5f00d4e5704", size = 1711835, upload-time = "2026-01-03T17:32:56.088Z" }, - { url = "https://files.pythonhosted.org/packages/fb/71/9b9761ddf276fd6708d13720197cbac19b8d67ecfa9116777924056cfcaa/aiohttp-3.13.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:40c5e40ecc29ba010656c18052b877a1c28f84344825efa106705e835c28530f", size = 1649593, upload-time = "2026-01-03T17:32:58.181Z" }, - { url = "https://files.pythonhosted.org/packages/ae/72/5d817e9ea218acae12a5e3b9ad1178cf0c12fc3570c0b47eea2daf95f9ea/aiohttp-3.13.3-cp39-cp39-win32.whl", hash = "sha256:56339a36b9f1fc708260c76c87e593e2afb30d26de9ae1eb445b5e051b98a7a1", size = 434831, upload-time = "2026-01-03T17:33:00.577Z" }, - { url = "https://files.pythonhosted.org/packages/39/cb/22659d9bf3149b7a2927bc2769cc9c8f8f5a80eba098398e03c199a43a85/aiohttp-3.13.3-cp39-cp39-win_amd64.whl", hash = "sha256:c6b8568a3bb5819a0ad087f16d40e5a3fb6099f39ea1d5625a3edc1e923fc538", size = 457697, upload-time = "2026-01-03T17:33:03.167Z" }, ] [[package]] @@ -243,8 +225,7 @@ wheels = [ [package.optional-dependencies] trio = [ - { name = "trio", version = "0.31.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "trio", version = "0.32.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "trio" }, ] [[package]] @@ -256,31 +237,12 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/74/f5/9373290775639cb67a2fce7f629a1c240dce9f12fe927bc32b2736e16dfc/argcomplete-3.6.3-py3-none-any.whl", hash = "sha256:f5007b3a600ccac5d25bbce33089211dfd49eab4a7718da3f10e3082525a92ce", size = 43846, upload-time = "2025-10-20T03:33:33.021Z" }, ] -[[package]] -name = "argon2-cffi" -version = "23.1.0" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.10'", -] -dependencies = [ - { name = "argon2-cffi-bindings", marker = "python_full_version < '3.10'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/31/fa/57ec2c6d16ecd2ba0cf15f3c7d1c3c2e7b5fcb83555ff56d7ab10888ec8f/argon2_cffi-23.1.0.tar.gz", hash = "sha256:879c3e79a2729ce768ebb7d36d4609e3a78a4ca2ec3a9f12286ca057e3d0db08", size = 42798, upload-time = "2023-08-15T14:13:12.711Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a4/6a/e8a041599e78b6b3752da48000b14c8d1e8a04ded09c88c714ba047f34f5/argon2_cffi-23.1.0-py3-none-any.whl", hash = "sha256:c670642b78ba29641818ab2e68bd4e6a78ba53b7eff7b4c3815ae16abf91c7ea", size = 15124, upload-time = "2023-08-15T14:13:10.752Z" }, -] - [[package]] name = "argon2-cffi" version = "25.1.0" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.14'", - "python_full_version >= '3.10' and python_full_version < '3.14'", -] dependencies = [ - { name = "argon2-cffi-bindings", marker = "python_full_version >= '3.10'" }, + { name = "argon2-cffi-bindings" }, ] sdist = { url = "https://files.pythonhosted.org/packages/0e/89/ce5af8a7d472a67cc819d5d998aa8c82c5d860608c4db9f46f1162d7dab9/argon2_cffi-25.1.0.tar.gz", hash = "sha256:694ae5cc8a42f4c4e2bf2ca0e64e51e23a040c6a517a85074683d3959e1346c1", size = 45706, upload-time = "2025-06-03T06:55:32.073Z" } wheels = [ @@ -355,7 +317,7 @@ name = "authlib" version = "1.6.7" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "cryptography", marker = "python_full_version >= '3.10'" }, + { name = "cryptography" }, ] sdist = { url = "https://files.pythonhosted.org/packages/49/dc/ed1681bf1339dd6ea1ce56136bad4baabc6f7ad466e375810702b0237047/authlib-1.6.7.tar.gz", hash = "sha256:dbf10100011d1e1b34048c9d120e83f13b35d69a826ae762b93d2fb5aafc337b", size = 164950, upload-time = "2026-02-06T14:04:14.171Z" } wheels = [ @@ -403,69 +365,19 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/71/cc/18245721fa7747065ab478316c7fea7c74777d07f37ae60db2e84f8172e8/beartype-0.22.9-py3-none-any.whl", hash = "sha256:d16c9bbc61ea14637596c5f6fbff2ee99cbe3573e46a716401734ef50c3060c2", size = 1333658, upload-time = "2025-12-13T06:50:28.266Z" }, ] -[[package]] -name = "black" -version = "25.11.0" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.10'", -] -dependencies = [ - { name = "click", version = "8.1.8", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "mypy-extensions", marker = "python_full_version < '3.10'" }, - { name = "packaging", marker = "python_full_version < '3.10'" }, - { name = "pathspec", marker = "python_full_version < '3.10'" }, - { name = "platformdirs", version = "4.4.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "pytokens", marker = "python_full_version < '3.10'" }, - { name = "tomli", marker = "python_full_version < '3.10'" }, - { name = "typing-extensions", marker = "python_full_version < '3.10'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/8c/ad/33adf4708633d047950ff2dfdea2e215d84ac50ef95aff14a614e4b6e9b2/black-25.11.0.tar.gz", hash = "sha256:9a323ac32f5dc75ce7470501b887250be5005a01602e931a15e45593f70f6e08", size = 655669, upload-time = "2025-11-10T01:53:50.558Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b3/d2/6caccbc96f9311e8ec3378c296d4f4809429c43a6cd2394e3c390e86816d/black-25.11.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ec311e22458eec32a807f029b2646f661e6859c3f61bc6d9ffb67958779f392e", size = 1743501, upload-time = "2025-11-10T01:59:06.202Z" }, - { url = "https://files.pythonhosted.org/packages/69/35/b986d57828b3f3dccbf922e2864223197ba32e74c5004264b1c62bc9f04d/black-25.11.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1032639c90208c15711334d681de2e24821af0575573db2810b0763bcd62e0f0", size = 1597308, upload-time = "2025-11-10T01:57:58.633Z" }, - { url = "https://files.pythonhosted.org/packages/39/8e/8b58ef4b37073f52b64a7b2dd8c9a96c84f45d6f47d878d0aa557e9a2d35/black-25.11.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0c0f7c461df55cf32929b002335883946a4893d759f2df343389c4396f3b6b37", size = 1656194, upload-time = "2025-11-10T01:57:10.909Z" }, - { url = "https://files.pythonhosted.org/packages/8d/30/9c2267a7955ecc545306534ab88923769a979ac20a27cf618d370091e5dd/black-25.11.0-cp310-cp310-win_amd64.whl", hash = "sha256:f9786c24d8e9bd5f20dc7a7f0cdd742644656987f6ea6947629306f937726c03", size = 1347996, upload-time = "2025-11-10T01:57:22.391Z" }, - { url = "https://files.pythonhosted.org/packages/c4/62/d304786b75ab0c530b833a89ce7d997924579fb7484ecd9266394903e394/black-25.11.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:895571922a35434a9d8ca67ef926da6bc9ad464522a5fe0db99b394ef1c0675a", size = 1727891, upload-time = "2025-11-10T02:01:40.507Z" }, - { url = "https://files.pythonhosted.org/packages/82/5d/ffe8a006aa522c9e3f430e7b93568a7b2163f4b3f16e8feb6d8c3552761a/black-25.11.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:cb4f4b65d717062191bdec8e4a442539a8ea065e6af1c4f4d36f0cdb5f71e170", size = 1581875, upload-time = "2025-11-10T01:57:51.192Z" }, - { url = "https://files.pythonhosted.org/packages/cb/c8/7c8bda3108d0bb57387ac41b4abb5c08782b26da9f9c4421ef6694dac01a/black-25.11.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d81a44cbc7e4f73a9d6ae449ec2317ad81512d1e7dce7d57f6333fd6259737bc", size = 1642716, upload-time = "2025-11-10T01:56:51.589Z" }, - { url = "https://files.pythonhosted.org/packages/34/b9/f17dea34eecb7cc2609a89627d480fb6caea7b86190708eaa7eb15ed25e7/black-25.11.0-cp311-cp311-win_amd64.whl", hash = "sha256:7eebd4744dfe92ef1ee349dc532defbf012a88b087bb7ddd688ff59a447b080e", size = 1352904, upload-time = "2025-11-10T01:59:26.252Z" }, - { url = "https://files.pythonhosted.org/packages/7f/12/5c35e600b515f35ffd737da7febdb2ab66bb8c24d88560d5e3ef3d28c3fd/black-25.11.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:80e7486ad3535636657aa180ad32a7d67d7c273a80e12f1b4bfa0823d54e8fac", size = 1772831, upload-time = "2025-11-10T02:03:47Z" }, - { url = "https://files.pythonhosted.org/packages/1a/75/b3896bec5a2bb9ed2f989a970ea40e7062f8936f95425879bbe162746fe5/black-25.11.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6cced12b747c4c76bc09b4db057c319d8545307266f41aaee665540bc0e04e96", size = 1608520, upload-time = "2025-11-10T01:58:46.895Z" }, - { url = "https://files.pythonhosted.org/packages/f3/b5/2bfc18330eddbcfb5aab8d2d720663cd410f51b2ed01375f5be3751595b0/black-25.11.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6cb2d54a39e0ef021d6c5eef442e10fd71fcb491be6413d083a320ee768329dd", size = 1682719, upload-time = "2025-11-10T01:56:55.24Z" }, - { url = "https://files.pythonhosted.org/packages/96/fb/f7dc2793a22cdf74a72114b5ed77fe3349a2e09ef34565857a2f917abdf2/black-25.11.0-cp312-cp312-win_amd64.whl", hash = "sha256:ae263af2f496940438e5be1a0c1020e13b09154f3af4df0835ea7f9fe7bfa409", size = 1362684, upload-time = "2025-11-10T01:57:07.639Z" }, - { url = "https://files.pythonhosted.org/packages/ad/47/3378d6a2ddefe18553d1115e36aea98f4a90de53b6a3017ed861ba1bd3bc/black-25.11.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0a1d40348b6621cc20d3d7530a5b8d67e9714906dfd7346338249ad9c6cedf2b", size = 1772446, upload-time = "2025-11-10T02:02:16.181Z" }, - { url = "https://files.pythonhosted.org/packages/ba/4b/0f00bfb3d1f7e05e25bfc7c363f54dc523bb6ba502f98f4ad3acf01ab2e4/black-25.11.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:51c65d7d60bb25429ea2bf0731c32b2a2442eb4bd3b2afcb47830f0b13e58bfd", size = 1607983, upload-time = "2025-11-10T02:02:52.502Z" }, - { url = "https://files.pythonhosted.org/packages/99/fe/49b0768f8c9ae57eb74cc10a1f87b4c70453551d8ad498959721cc345cb7/black-25.11.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:936c4dd07669269f40b497440159a221ee435e3fddcf668e0c05244a9be71993", size = 1682481, upload-time = "2025-11-10T01:57:12.35Z" }, - { url = "https://files.pythonhosted.org/packages/55/17/7e10ff1267bfa950cc16f0a411d457cdff79678fbb77a6c73b73a5317904/black-25.11.0-cp313-cp313-win_amd64.whl", hash = "sha256:f42c0ea7f59994490f4dccd64e6b2dd49ac57c7c84f38b8faab50f8759db245c", size = 1363869, upload-time = "2025-11-10T01:58:24.608Z" }, - { url = "https://files.pythonhosted.org/packages/67/c0/cc865ce594d09e4cd4dfca5e11994ebb51604328489f3ca3ae7bb38a7db5/black-25.11.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:35690a383f22dd3e468c85dc4b915217f87667ad9cce781d7b42678ce63c4170", size = 1771358, upload-time = "2025-11-10T02:03:33.331Z" }, - { url = "https://files.pythonhosted.org/packages/37/77/4297114d9e2fd2fc8ab0ab87192643cd49409eb059e2940391e7d2340e57/black-25.11.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:dae49ef7369c6caa1a1833fd5efb7c3024bb7e4499bf64833f65ad27791b1545", size = 1612902, upload-time = "2025-11-10T01:59:33.382Z" }, - { url = "https://files.pythonhosted.org/packages/de/63/d45ef97ada84111e330b2b2d45e1dd163e90bd116f00ac55927fb6bf8adb/black-25.11.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5bd4a22a0b37401c8e492e994bce79e614f91b14d9ea911f44f36e262195fdda", size = 1680571, upload-time = "2025-11-10T01:57:04.239Z" }, - { url = "https://files.pythonhosted.org/packages/ff/4b/5604710d61cdff613584028b4cb4607e56e148801ed9b38ee7970799dab6/black-25.11.0-cp314-cp314-win_amd64.whl", hash = "sha256:aa211411e94fdf86519996b7f5f05e71ba34835d8f0c0f03c00a26271da02664", size = 1382599, upload-time = "2025-11-10T01:57:57.427Z" }, - { url = "https://files.pythonhosted.org/packages/d5/9a/5b2c0e3215fe748fcf515c2dd34658973a1210bf610e24de5ba887e4f1c8/black-25.11.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a3bb5ce32daa9ff0605d73b6f19da0b0e6c1f8f2d75594db539fdfed722f2b06", size = 1743063, upload-time = "2025-11-10T02:02:43.175Z" }, - { url = "https://files.pythonhosted.org/packages/a1/20/245164c6efc27333409c62ba54dcbfbe866c6d1957c9a6c0647786e950da/black-25.11.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9815ccee1e55717fe9a4b924cae1646ef7f54e0f990da39a34fc7b264fcf80a2", size = 1596867, upload-time = "2025-11-10T02:00:17.157Z" }, - { url = "https://files.pythonhosted.org/packages/ca/6f/1a3859a7da205f3d50cf3a8bec6bdc551a91c33ae77a045bb24c1f46ab54/black-25.11.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:92285c37b93a1698dcbc34581867b480f1ba3a7b92acf1fe0467b04d7a4da0dc", size = 1655678, upload-time = "2025-11-10T01:57:09.028Z" }, - { url = "https://files.pythonhosted.org/packages/56/1a/6dec1aeb7be90753d4fcc273e69bc18bfd34b353223ed191da33f7519410/black-25.11.0-cp39-cp39-win_amd64.whl", hash = "sha256:43945853a31099c7c0ff8dface53b4de56c41294fa6783c0441a8b1d9bf668bc", size = 1347452, upload-time = "2025-11-10T01:57:01.871Z" }, - { url = "https://files.pythonhosted.org/packages/00/5d/aed32636ed30a6e7f9efd6ad14e2a0b0d687ae7c8c7ec4e4a557174b895c/black-25.11.0-py3-none-any.whl", hash = "sha256:e3f562da087791e96cefcd9dda058380a442ab322a02e222add53736451f604b", size = 204918, upload-time = "2025-11-10T01:53:48.917Z" }, -] - [[package]] name = "black" version = "26.1.0" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.14'", - "python_full_version >= '3.10' and python_full_version < '3.14'", -] dependencies = [ - { name = "click", version = "8.3.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, - { name = "mypy-extensions", marker = "python_full_version >= '3.10'" }, - { name = "packaging", marker = "python_full_version >= '3.10'" }, - { name = "pathspec", marker = "python_full_version >= '3.10'" }, - { name = "platformdirs", version = "4.5.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, - { name = "pytokens", marker = "python_full_version >= '3.10'" }, - { name = "tomli", marker = "python_full_version == '3.10.*'" }, - { name = "typing-extensions", marker = "python_full_version == '3.10.*'" }, + { name = "click" }, + { name = "mypy-extensions" }, + { name = "packaging" }, + { name = "pathspec" }, + { name = "platformdirs" }, + { name = "pytokens" }, + { name = "tomli", marker = "python_full_version < '3.11'" }, + { name = "typing-extensions", marker = "python_full_version < '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/13/88/560b11e521c522440af991d46848a2bde64b5f7202ec14e1f46f9509d328/black-26.1.0.tar.gz", hash = "sha256:d294ac3340eef9c9eb5d29288e96dc719ff269a88e27b396340459dd85da4c58", size = 658785, upload-time = "2026-01-18T04:50:11.993Z" } wheels = [ @@ -527,8 +439,7 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "jmespath" }, { name = "python-dateutil" }, - { name = "urllib3", version = "1.26.20", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "urllib3", version = "2.6.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "urllib3" }, ] sdist = { url = "https://files.pythonhosted.org/packages/af/d6/def916ad1d13de5d511074afcde538a958e2e8a7c7020fb698d1f392f63b/botocore-1.42.43.tar.gz", hash = "sha256:41d04ead0b0862eec21f841811fb5764fe370a2df9b319e0d5297325c50fba1b", size = 14934077, upload-time = "2026-02-05T20:31:35.15Z" } wheels = [ @@ -564,10 +475,8 @@ dependencies = [ { name = "cairocffi" }, { name = "cssselect2" }, { name = "defusedxml" }, - { name = "pillow", version = "11.3.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "pillow", version = "12.1.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, - { name = "tinycss2", version = "1.4.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "tinycss2", version = "1.5.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "pillow" }, + { name = "tinycss2" }, ] sdist = { url = "https://files.pythonhosted.org/packages/ab/b9/5106168bd43d7cd8b7cc2a2ee465b385f14b63f4c092bb89eee2d48c8e67/cairosvg-2.8.2.tar.gz", hash = "sha256:07cbf4e86317b27a92318a4cac2a4bb37a5e9c1b8a27355d06874b22f85bef9f", size = 8398590, upload-time = "2025-05-15T06:56:32.653Z" } wheels = [ @@ -588,8 +497,7 @@ name = "cffi" version = "2.0.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pycparser", version = "2.23", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10' and implementation_name != 'PyPy'" }, - { name = "pycparser", version = "3.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10' and implementation_name != 'PyPy'" }, + { name = "pycparser", marker = "implementation_name != 'PyPy'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/eb/56/b1ba7935a17738ae8453301356628e8147c79dbb825bcbc73dc7401f9846/cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529", size = 523588, upload-time = "2025-09-08T23:24:04.541Z" } wheels = [ @@ -664,18 +572,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/a0/1d/ec1a60bd1a10daa292d3cd6bb0b359a81607154fb8165f3ec95fe003b85c/cffi-2.0.0-cp314-cp314t-win32.whl", hash = "sha256:1fc9ea04857caf665289b7a75923f2c6ed559b8298a1b8c49e59f7dd95c8481e", size = 180487, upload-time = "2025-09-08T23:23:40.423Z" }, { url = "https://files.pythonhosted.org/packages/bf/41/4c1168c74fac325c0c8156f04b6749c8b6a8f405bbf91413ba088359f60d/cffi-2.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:d68b6cef7827e8641e8ef16f4494edda8b36104d79773a334beaa1e3521430f6", size = 191726, upload-time = "2025-09-08T23:23:41.742Z" }, { url = "https://files.pythonhosted.org/packages/ae/3a/dbeec9d1ee0844c679f6bb5d6ad4e9f198b1224f4e7a32825f47f6192b0c/cffi-2.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:0a1527a803f0a659de1af2e1fd700213caba79377e27e4693648c2923da066f9", size = 184195, upload-time = "2025-09-08T23:23:43.004Z" }, - { url = "https://files.pythonhosted.org/packages/c0/cc/08ed5a43f2996a16b462f64a7055c6e962803534924b9b2f1371d8c00b7b/cffi-2.0.0-cp39-cp39-macosx_10_13_x86_64.whl", hash = "sha256:fe562eb1a64e67dd297ccc4f5addea2501664954f2692b69a76449ec7913ecbf", size = 184288, upload-time = "2025-09-08T23:23:48.404Z" }, - { url = "https://files.pythonhosted.org/packages/3d/de/38d9726324e127f727b4ecc376bc85e505bfe61ef130eaf3f290c6847dd4/cffi-2.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:de8dad4425a6ca6e4e5e297b27b5c824ecc7581910bf9aee86cb6835e6812aa7", size = 180509, upload-time = "2025-09-08T23:23:49.73Z" }, - { url = "https://files.pythonhosted.org/packages/9b/13/c92e36358fbcc39cf0962e83223c9522154ee8630e1df7c0b3a39a8124e2/cffi-2.0.0-cp39-cp39-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:4647afc2f90d1ddd33441e5b0e85b16b12ddec4fca55f0d9671fef036ecca27c", size = 208813, upload-time = "2025-09-08T23:23:51.263Z" }, - { url = "https://files.pythonhosted.org/packages/15/12/a7a79bd0df4c3bff744b2d7e52cc1b68d5e7e427b384252c42366dc1ecbc/cffi-2.0.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3f4d46d8b35698056ec29bca21546e1551a205058ae1a181d871e278b0b28165", size = 216498, upload-time = "2025-09-08T23:23:52.494Z" }, - { url = "https://files.pythonhosted.org/packages/a3/ad/5c51c1c7600bdd7ed9a24a203ec255dccdd0ebf4527f7b922a0bde2fb6ed/cffi-2.0.0-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:e6e73b9e02893c764e7e8d5bb5ce277f1a009cd5243f8228f75f842bf937c534", size = 203243, upload-time = "2025-09-08T23:23:53.836Z" }, - { url = "https://files.pythonhosted.org/packages/32/f2/81b63e288295928739d715d00952c8c6034cb6c6a516b17d37e0c8be5600/cffi-2.0.0-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:cb527a79772e5ef98fb1d700678fe031e353e765d1ca2d409c92263c6d43e09f", size = 203158, upload-time = "2025-09-08T23:23:55.169Z" }, - { url = "https://files.pythonhosted.org/packages/1f/74/cc4096ce66f5939042ae094e2e96f53426a979864aa1f96a621ad128be27/cffi-2.0.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:61d028e90346df14fedc3d1e5441df818d095f3b87d286825dfcbd6459b7ef63", size = 216548, upload-time = "2025-09-08T23:23:56.506Z" }, - { url = "https://files.pythonhosted.org/packages/e8/be/f6424d1dc46b1091ffcc8964fa7c0ab0cd36839dd2761b49c90481a6ba1b/cffi-2.0.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:0f6084a0ea23d05d20c3edcda20c3d006f9b6f3fefeac38f59262e10cef47ee2", size = 218897, upload-time = "2025-09-08T23:23:57.825Z" }, - { url = "https://files.pythonhosted.org/packages/f7/e0/dda537c2309817edf60109e39265f24f24aa7f050767e22c98c53fe7f48b/cffi-2.0.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:1cd13c99ce269b3ed80b417dcd591415d3372bcac067009b6e0f59c7d4015e65", size = 211249, upload-time = "2025-09-08T23:23:59.139Z" }, - { url = "https://files.pythonhosted.org/packages/2b/e7/7c769804eb75e4c4b35e658dba01de1640a351a9653c3d49ca89d16ccc91/cffi-2.0.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:89472c9762729b5ae1ad974b777416bfda4ac5642423fa93bd57a09204712322", size = 218041, upload-time = "2025-09-08T23:24:00.496Z" }, - { url = "https://files.pythonhosted.org/packages/aa/d9/6218d78f920dcd7507fc16a766b5ef8f3b913cc7aa938e7fc80b9978d089/cffi-2.0.0-cp39-cp39-win32.whl", hash = "sha256:2081580ebb843f759b9f617314a24ed5738c51d2aee65d31e02f6f7a2b97707a", size = 172138, upload-time = "2025-09-08T23:24:01.7Z" }, - { url = "https://files.pythonhosted.org/packages/54/8f/a1e836f82d8e32a97e6b29cc8f641779181ac7363734f12df27db803ebda/cffi-2.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:b882b3df248017dba09d6b16defe9b5c407fe32fc7c65a9c69798e6175601be9", size = 182794, upload-time = "2025-09-08T23:24:02.943Z" }, ] [[package]] @@ -764,50 +660,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b0/6f/8f7af07237c34a1defe7defc565a9bc1807762f672c0fde711a4b22bf9c0/charset_normalizer-3.4.4-cp314-cp314-win32.whl", hash = "sha256:f9d332f8c2a2fcbffe1378594431458ddbef721c1769d78e2cbc06280d8155f9", size = 99940, upload-time = "2025-10-14T04:41:49.946Z" }, { url = "https://files.pythonhosted.org/packages/4b/51/8ade005e5ca5b0d80fb4aff72a3775b325bdc3d27408c8113811a7cbe640/charset_normalizer-3.4.4-cp314-cp314-win_amd64.whl", hash = "sha256:8a6562c3700cce886c5be75ade4a5db4214fda19fede41d9792d100288d8f94c", size = 107104, upload-time = "2025-10-14T04:41:51.051Z" }, { url = "https://files.pythonhosted.org/packages/da/5f/6b8f83a55bb8278772c5ae54a577f3099025f9ade59d0136ac24a0df4bde/charset_normalizer-3.4.4-cp314-cp314-win_arm64.whl", hash = "sha256:de00632ca48df9daf77a2c65a484531649261ec9f25489917f09e455cb09ddb2", size = 100743, upload-time = "2025-10-14T04:41:52.122Z" }, - { url = "https://files.pythonhosted.org/packages/46/7c/0c4760bccf082737ca7ab84a4c2034fcc06b1f21cf3032ea98bd6feb1725/charset_normalizer-3.4.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:a9768c477b9d7bd54bc0c86dbaebdec6f03306675526c9927c0e8a04e8f94af9", size = 209609, upload-time = "2025-10-14T04:42:10.922Z" }, - { url = "https://files.pythonhosted.org/packages/bb/a4/69719daef2f3d7f1819de60c9a6be981b8eeead7542d5ec4440f3c80e111/charset_normalizer-3.4.4-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1bee1e43c28aa63cb16e5c14e582580546b08e535299b8b6158a7c9c768a1f3d", size = 149029, upload-time = "2025-10-14T04:42:12.38Z" }, - { url = "https://files.pythonhosted.org/packages/e6/21/8d4e1d6c1e6070d3672908b8e4533a71b5b53e71d16828cc24d0efec564c/charset_normalizer-3.4.4-cp39-cp39-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:fd44c878ea55ba351104cb93cc85e74916eb8fa440ca7903e57575e97394f608", size = 144580, upload-time = "2025-10-14T04:42:13.549Z" }, - { url = "https://files.pythonhosted.org/packages/a7/0a/a616d001b3f25647a9068e0b9199f697ce507ec898cacb06a0d5a1617c99/charset_normalizer-3.4.4-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:0f04b14ffe5fdc8c4933862d8306109a2c51e0704acfa35d51598eb45a1e89fc", size = 162340, upload-time = "2025-10-14T04:42:14.892Z" }, - { url = "https://files.pythonhosted.org/packages/85/93/060b52deb249a5450460e0585c88a904a83aec474ab8e7aba787f45e79f2/charset_normalizer-3.4.4-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:cd09d08005f958f370f539f186d10aec3377d55b9eeb0d796025d4886119d76e", size = 159619, upload-time = "2025-10-14T04:42:16.676Z" }, - { url = "https://files.pythonhosted.org/packages/dd/21/0274deb1cc0632cd587a9a0ec6b4674d9108e461cb4cd40d457adaeb0564/charset_normalizer-3.4.4-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4fe7859a4e3e8457458e2ff592f15ccb02f3da787fcd31e0183879c3ad4692a1", size = 153980, upload-time = "2025-10-14T04:42:17.917Z" }, - { url = "https://files.pythonhosted.org/packages/28/2b/e3d7d982858dccc11b31906976323d790dded2017a0572f093ff982d692f/charset_normalizer-3.4.4-cp39-cp39-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:fa09f53c465e532f4d3db095e0c55b615f010ad81803d383195b6b5ca6cbf5f3", size = 152174, upload-time = "2025-10-14T04:42:19.018Z" }, - { url = "https://files.pythonhosted.org/packages/6e/ff/4a269f8e35f1e58b2df52c131a1fa019acb7ef3f8697b7d464b07e9b492d/charset_normalizer-3.4.4-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:7fa17817dc5625de8a027cb8b26d9fefa3ea28c8253929b8d6649e705d2835b6", size = 151666, upload-time = "2025-10-14T04:42:20.171Z" }, - { url = "https://files.pythonhosted.org/packages/da/c9/ec39870f0b330d58486001dd8e532c6b9a905f5765f58a6f8204926b4a93/charset_normalizer-3.4.4-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:5947809c8a2417be3267efc979c47d76a079758166f7d43ef5ae8e9f92751f88", size = 145550, upload-time = "2025-10-14T04:42:21.324Z" }, - { url = "https://files.pythonhosted.org/packages/75/8f/d186ab99e40e0ed9f82f033d6e49001701c81244d01905dd4a6924191a30/charset_normalizer-3.4.4-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:4902828217069c3c5c71094537a8e623f5d097858ac6ca8252f7b4d10b7560f1", size = 163721, upload-time = "2025-10-14T04:42:22.46Z" }, - { url = "https://files.pythonhosted.org/packages/96/b1/6047663b9744df26a7e479ac1e77af7134b1fcf9026243bb48ee2d18810f/charset_normalizer-3.4.4-cp39-cp39-musllinux_1_2_riscv64.whl", hash = "sha256:7c308f7e26e4363d79df40ca5b2be1c6ba9f02bdbccfed5abddb7859a6ce72cf", size = 152127, upload-time = "2025-10-14T04:42:23.712Z" }, - { url = "https://files.pythonhosted.org/packages/59/78/e5a6eac9179f24f704d1be67d08704c3c6ab9f00963963524be27c18ed87/charset_normalizer-3.4.4-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:2c9d3c380143a1fedbff95a312aa798578371eb29da42106a29019368a475318", size = 161175, upload-time = "2025-10-14T04:42:24.87Z" }, - { url = "https://files.pythonhosted.org/packages/e5/43/0e626e42d54dd2f8dd6fc5e1c5ff00f05fbca17cb699bedead2cae69c62f/charset_normalizer-3.4.4-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:cb01158d8b88ee68f15949894ccc6712278243d95f344770fa7593fa2d94410c", size = 155375, upload-time = "2025-10-14T04:42:27.246Z" }, - { url = "https://files.pythonhosted.org/packages/e9/91/d9615bf2e06f35e4997616ff31248c3657ed649c5ab9d35ea12fce54e380/charset_normalizer-3.4.4-cp39-cp39-win32.whl", hash = "sha256:2677acec1a2f8ef614c6888b5b4ae4060cc184174a938ed4e8ef690e15d3e505", size = 99692, upload-time = "2025-10-14T04:42:28.425Z" }, - { url = "https://files.pythonhosted.org/packages/d1/a9/6c040053909d9d1ef4fcab45fddec083aedc9052c10078339b47c8573ea8/charset_normalizer-3.4.4-cp39-cp39-win_amd64.whl", hash = "sha256:f8e160feb2aed042cd657a72acc0b481212ed28b1b9a95c0cee1621b524e1966", size = 107192, upload-time = "2025-10-14T04:42:29.482Z" }, - { url = "https://files.pythonhosted.org/packages/f0/c6/4fa536b2c0cd3edfb7ccf8469fa0f363ea67b7213a842b90909ca33dd851/charset_normalizer-3.4.4-cp39-cp39-win_arm64.whl", hash = "sha256:b5d84d37db046c5ca74ee7bb47dd6cbc13f80665fdde3e8040bdd3fb015ecb50", size = 100220, upload-time = "2025-10-14T04:42:30.632Z" }, { url = "https://files.pythonhosted.org/packages/0a/4c/925909008ed5a988ccbb72dcc897407e5d6d3bd72410d69e051fc0c14647/charset_normalizer-3.4.4-py3-none-any.whl", hash = "sha256:7a32c560861a02ff789ad905a2fe94e3f840803362c84fecf1851cb4cf3dc37f", size = 53402, upload-time = "2025-10-14T04:42:31.76Z" }, ] -[[package]] -name = "click" -version = "8.1.8" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.10'", -] -dependencies = [ - { name = "colorama", marker = "python_full_version < '3.10' and sys_platform == 'win32'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/b9/2e/0090cbf739cee7d23781ad4b89a9894a41538e4fcf4c31dcdd705b78eb8b/click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a", size = 226593, upload-time = "2024-12-21T18:38:44.339Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2", size = 98188, upload-time = "2024-12-21T18:38:41.666Z" }, -] - [[package]] name = "click" version = "8.3.1" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.14'", - "python_full_version >= '3.10' and python_full_version < '3.14'", -] dependencies = [ - { name = "colorama", marker = "python_full_version >= '3.10' and sys_platform == 'win32'" }, + { name = "colorama", marker = "sys_platform == 'win32'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/3d/fa/656b739db8587d7b5dfa22e22ed02566950fbfbcdc20311993483657a5c0/click-8.3.1.tar.gz", hash = "sha256:12ff4785d337a1bb490bb7e9c2b1ee5da3112e94a8622f26a6c77f5d2fc6842a", size = 295065, upload-time = "2025-11-15T20:45:42.706Z" } wheels = [ @@ -834,8 +695,7 @@ dependencies = [ { name = "pydantic-core" }, { name = "requests" }, { name = "tokenizers" }, - { name = "types-requests", version = "2.31.0.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "types-requests", version = "2.32.4.20260107", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "types-requests" }, { name = "typing-extensions" }, ] sdist = { url = "https://files.pythonhosted.org/packages/35/37/65af9c50b5d5772a5528c6a949799f98ae286b8ebb924e0fac0619b3ae88/cohere-5.20.4.tar.gz", hash = "sha256:3b3017048ff5d5b4f113180947d538ca3d0f274de5875f0345be4c8cb3d5119a", size = 180737, upload-time = "2026-02-05T14:47:54.639Z" } @@ -852,133 +712,10 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, ] -[[package]] -name = "coverage" -version = "7.10.7" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.10'", -] -sdist = { url = "https://files.pythonhosted.org/packages/51/26/d22c300112504f5f9a9fd2297ce33c35f3d353e4aeb987c8419453b2a7c2/coverage-7.10.7.tar.gz", hash = "sha256:f4ab143ab113be368a3e9b795f9cd7906c5ef407d6173fe9675a902e1fffc239", size = 827704, upload-time = "2025-09-21T20:03:56.815Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e5/6c/3a3f7a46888e69d18abe3ccc6fe4cb16cccb1e6a2f99698931dafca489e6/coverage-7.10.7-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:fc04cc7a3db33664e0c2d10eb8990ff6b3536f6842c9590ae8da4c614b9ed05a", size = 217987, upload-time = "2025-09-21T20:00:57.218Z" }, - { url = "https://files.pythonhosted.org/packages/03/94/952d30f180b1a916c11a56f5c22d3535e943aa22430e9e3322447e520e1c/coverage-7.10.7-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e201e015644e207139f7e2351980feb7040e6f4b2c2978892f3e3789d1c125e5", size = 218388, upload-time = "2025-09-21T20:01:00.081Z" }, - { url = "https://files.pythonhosted.org/packages/50/2b/9e0cf8ded1e114bcd8b2fd42792b57f1c4e9e4ea1824cde2af93a67305be/coverage-7.10.7-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:240af60539987ced2c399809bd34f7c78e8abe0736af91c3d7d0e795df633d17", size = 245148, upload-time = "2025-09-21T20:01:01.768Z" }, - { url = "https://files.pythonhosted.org/packages/19/20/d0384ac06a6f908783d9b6aa6135e41b093971499ec488e47279f5b846e6/coverage-7.10.7-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:8421e088bc051361b01c4b3a50fd39a4b9133079a2229978d9d30511fd05231b", size = 246958, upload-time = "2025-09-21T20:01:03.355Z" }, - { url = "https://files.pythonhosted.org/packages/60/83/5c283cff3d41285f8eab897651585db908a909c572bdc014bcfaf8a8b6ae/coverage-7.10.7-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6be8ed3039ae7f7ac5ce058c308484787c86e8437e72b30bf5e88b8ea10f3c87", size = 248819, upload-time = "2025-09-21T20:01:04.968Z" }, - { url = "https://files.pythonhosted.org/packages/60/22/02eb98fdc5ff79f423e990d877693e5310ae1eab6cb20ae0b0b9ac45b23b/coverage-7.10.7-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e28299d9f2e889e6d51b1f043f58d5f997c373cc12e6403b90df95b8b047c13e", size = 245754, upload-time = "2025-09-21T20:01:06.321Z" }, - { url = "https://files.pythonhosted.org/packages/b4/bc/25c83bcf3ad141b32cd7dc45485ef3c01a776ca3aa8ef0a93e77e8b5bc43/coverage-7.10.7-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:c4e16bd7761c5e454f4efd36f345286d6f7c5fa111623c355691e2755cae3b9e", size = 246860, upload-time = "2025-09-21T20:01:07.605Z" }, - { url = "https://files.pythonhosted.org/packages/3c/b7/95574702888b58c0928a6e982038c596f9c34d52c5e5107f1eef729399b5/coverage-7.10.7-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:b1c81d0e5e160651879755c9c675b974276f135558cf4ba79fee7b8413a515df", size = 244877, upload-time = "2025-09-21T20:01:08.829Z" }, - { url = "https://files.pythonhosted.org/packages/47/b6/40095c185f235e085df0e0b158f6bd68cc6e1d80ba6c7721dc81d97ec318/coverage-7.10.7-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:606cc265adc9aaedcc84f1f064f0e8736bc45814f15a357e30fca7ecc01504e0", size = 245108, upload-time = "2025-09-21T20:01:10.527Z" }, - { url = "https://files.pythonhosted.org/packages/c8/50/4aea0556da7a4b93ec9168420d170b55e2eb50ae21b25062513d020c6861/coverage-7.10.7-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:10b24412692df990dbc34f8fb1b6b13d236ace9dfdd68df5b28c2e39cafbba13", size = 245752, upload-time = "2025-09-21T20:01:11.857Z" }, - { url = "https://files.pythonhosted.org/packages/6a/28/ea1a84a60828177ae3b100cb6723838523369a44ec5742313ed7db3da160/coverage-7.10.7-cp310-cp310-win32.whl", hash = "sha256:b51dcd060f18c19290d9b8a9dd1e0181538df2ce0717f562fff6cf74d9fc0b5b", size = 220497, upload-time = "2025-09-21T20:01:13.459Z" }, - { url = "https://files.pythonhosted.org/packages/fc/1a/a81d46bbeb3c3fd97b9602ebaa411e076219a150489bcc2c025f151bd52d/coverage-7.10.7-cp310-cp310-win_amd64.whl", hash = "sha256:3a622ac801b17198020f09af3eaf45666b344a0d69fc2a6ffe2ea83aeef1d807", size = 221392, upload-time = "2025-09-21T20:01:14.722Z" }, - { url = "https://files.pythonhosted.org/packages/d2/5d/c1a17867b0456f2e9ce2d8d4708a4c3a089947d0bec9c66cdf60c9e7739f/coverage-7.10.7-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a609f9c93113be646f44c2a0256d6ea375ad047005d7f57a5c15f614dc1b2f59", size = 218102, upload-time = "2025-09-21T20:01:16.089Z" }, - { url = "https://files.pythonhosted.org/packages/54/f0/514dcf4b4e3698b9a9077f084429681bf3aad2b4a72578f89d7f643eb506/coverage-7.10.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:65646bb0359386e07639c367a22cf9b5bf6304e8630b565d0626e2bdf329227a", size = 218505, upload-time = "2025-09-21T20:01:17.788Z" }, - { url = "https://files.pythonhosted.org/packages/20/f6/9626b81d17e2a4b25c63ac1b425ff307ecdeef03d67c9a147673ae40dc36/coverage-7.10.7-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:5f33166f0dfcce728191f520bd2692914ec70fac2713f6bf3ce59c3deacb4699", size = 248898, upload-time = "2025-09-21T20:01:19.488Z" }, - { url = "https://files.pythonhosted.org/packages/b0/ef/bd8e719c2f7417ba03239052e099b76ea1130ac0cbb183ee1fcaa58aaff3/coverage-7.10.7-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:35f5e3f9e455bb17831876048355dca0f758b6df22f49258cb5a91da23ef437d", size = 250831, upload-time = "2025-09-21T20:01:20.817Z" }, - { url = "https://files.pythonhosted.org/packages/a5/b6/bf054de41ec948b151ae2b79a55c107f5760979538f5fb80c195f2517718/coverage-7.10.7-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4da86b6d62a496e908ac2898243920c7992499c1712ff7c2b6d837cc69d9467e", size = 252937, upload-time = "2025-09-21T20:01:22.171Z" }, - { url = "https://files.pythonhosted.org/packages/0f/e5/3860756aa6f9318227443c6ce4ed7bf9e70bb7f1447a0353f45ac5c7974b/coverage-7.10.7-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:6b8b09c1fad947c84bbbc95eca841350fad9cbfa5a2d7ca88ac9f8d836c92e23", size = 249021, upload-time = "2025-09-21T20:01:23.907Z" }, - { url = "https://files.pythonhosted.org/packages/26/0f/bd08bd042854f7fd07b45808927ebcce99a7ed0f2f412d11629883517ac2/coverage-7.10.7-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:4376538f36b533b46f8971d3a3e63464f2c7905c9800db97361c43a2b14792ab", size = 250626, upload-time = "2025-09-21T20:01:25.721Z" }, - { url = "https://files.pythonhosted.org/packages/8e/a7/4777b14de4abcc2e80c6b1d430f5d51eb18ed1d75fca56cbce5f2db9b36e/coverage-7.10.7-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:121da30abb574f6ce6ae09840dae322bef734480ceafe410117627aa54f76d82", size = 248682, upload-time = "2025-09-21T20:01:27.105Z" }, - { url = "https://files.pythonhosted.org/packages/34/72/17d082b00b53cd45679bad682fac058b87f011fd8b9fe31d77f5f8d3a4e4/coverage-7.10.7-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:88127d40df529336a9836870436fc2751c339fbaed3a836d42c93f3e4bd1d0a2", size = 248402, upload-time = "2025-09-21T20:01:28.629Z" }, - { url = "https://files.pythonhosted.org/packages/81/7a/92367572eb5bdd6a84bfa278cc7e97db192f9f45b28c94a9ca1a921c3577/coverage-7.10.7-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ba58bbcd1b72f136080c0bccc2400d66cc6115f3f906c499013d065ac33a4b61", size = 249320, upload-time = "2025-09-21T20:01:30.004Z" }, - { url = "https://files.pythonhosted.org/packages/2f/88/a23cc185f6a805dfc4fdf14a94016835eeb85e22ac3a0e66d5e89acd6462/coverage-7.10.7-cp311-cp311-win32.whl", hash = "sha256:972b9e3a4094b053a4e46832b4bc829fc8a8d347160eb39d03f1690316a99c14", size = 220536, upload-time = "2025-09-21T20:01:32.184Z" }, - { url = "https://files.pythonhosted.org/packages/fe/ef/0b510a399dfca17cec7bc2f05ad8bd78cf55f15c8bc9a73ab20c5c913c2e/coverage-7.10.7-cp311-cp311-win_amd64.whl", hash = "sha256:a7b55a944a7f43892e28ad4bc0561dfd5f0d73e605d1aa5c3c976b52aea121d2", size = 221425, upload-time = "2025-09-21T20:01:33.557Z" }, - { url = "https://files.pythonhosted.org/packages/51/7f/023657f301a276e4ba1850f82749bc136f5a7e8768060c2e5d9744a22951/coverage-7.10.7-cp311-cp311-win_arm64.whl", hash = "sha256:736f227fb490f03c6488f9b6d45855f8e0fd749c007f9303ad30efab0e73c05a", size = 220103, upload-time = "2025-09-21T20:01:34.929Z" }, - { url = "https://files.pythonhosted.org/packages/13/e4/eb12450f71b542a53972d19117ea5a5cea1cab3ac9e31b0b5d498df1bd5a/coverage-7.10.7-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7bb3b9ddb87ef7725056572368040c32775036472d5a033679d1fa6c8dc08417", size = 218290, upload-time = "2025-09-21T20:01:36.455Z" }, - { url = "https://files.pythonhosted.org/packages/37/66/593f9be12fc19fb36711f19a5371af79a718537204d16ea1d36f16bd78d2/coverage-7.10.7-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:18afb24843cbc175687225cab1138c95d262337f5473512010e46831aa0c2973", size = 218515, upload-time = "2025-09-21T20:01:37.982Z" }, - { url = "https://files.pythonhosted.org/packages/66/80/4c49f7ae09cafdacc73fbc30949ffe77359635c168f4e9ff33c9ebb07838/coverage-7.10.7-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:399a0b6347bcd3822be369392932884b8216d0944049ae22925631a9b3d4ba4c", size = 250020, upload-time = "2025-09-21T20:01:39.617Z" }, - { url = "https://files.pythonhosted.org/packages/a6/90/a64aaacab3b37a17aaedd83e8000142561a29eb262cede42d94a67f7556b/coverage-7.10.7-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:314f2c326ded3f4b09be11bc282eb2fc861184bc95748ae67b360ac962770be7", size = 252769, upload-time = "2025-09-21T20:01:41.341Z" }, - { url = "https://files.pythonhosted.org/packages/98/2e/2dda59afd6103b342e096f246ebc5f87a3363b5412609946c120f4e7750d/coverage-7.10.7-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c41e71c9cfb854789dee6fc51e46743a6d138b1803fab6cb860af43265b42ea6", size = 253901, upload-time = "2025-09-21T20:01:43.042Z" }, - { url = "https://files.pythonhosted.org/packages/53/dc/8d8119c9051d50f3119bb4a75f29f1e4a6ab9415cd1fa8bf22fcc3fb3b5f/coverage-7.10.7-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc01f57ca26269c2c706e838f6422e2a8788e41b3e3c65e2f41148212e57cd59", size = 250413, upload-time = "2025-09-21T20:01:44.469Z" }, - { url = "https://files.pythonhosted.org/packages/98/b3/edaff9c5d79ee4d4b6d3fe046f2b1d799850425695b789d491a64225d493/coverage-7.10.7-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a6442c59a8ac8b85812ce33bc4d05bde3fb22321fa8294e2a5b487c3505f611b", size = 251820, upload-time = "2025-09-21T20:01:45.915Z" }, - { url = "https://files.pythonhosted.org/packages/11/25/9a0728564bb05863f7e513e5a594fe5ffef091b325437f5430e8cfb0d530/coverage-7.10.7-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:78a384e49f46b80fb4c901d52d92abe098e78768ed829c673fbb53c498bef73a", size = 249941, upload-time = "2025-09-21T20:01:47.296Z" }, - { url = "https://files.pythonhosted.org/packages/e0/fd/ca2650443bfbef5b0e74373aac4df67b08180d2f184b482c41499668e258/coverage-7.10.7-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:5e1e9802121405ede4b0133aa4340ad8186a1d2526de5b7c3eca519db7bb89fb", size = 249519, upload-time = "2025-09-21T20:01:48.73Z" }, - { url = "https://files.pythonhosted.org/packages/24/79/f692f125fb4299b6f963b0745124998ebb8e73ecdfce4ceceb06a8c6bec5/coverage-7.10.7-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:d41213ea25a86f69efd1575073d34ea11aabe075604ddf3d148ecfec9e1e96a1", size = 251375, upload-time = "2025-09-21T20:01:50.529Z" }, - { url = "https://files.pythonhosted.org/packages/5e/75/61b9bbd6c7d24d896bfeec57acba78e0f8deac68e6baf2d4804f7aae1f88/coverage-7.10.7-cp312-cp312-win32.whl", hash = "sha256:77eb4c747061a6af8d0f7bdb31f1e108d172762ef579166ec84542f711d90256", size = 220699, upload-time = "2025-09-21T20:01:51.941Z" }, - { url = "https://files.pythonhosted.org/packages/ca/f3/3bf7905288b45b075918d372498f1cf845b5b579b723c8fd17168018d5f5/coverage-7.10.7-cp312-cp312-win_amd64.whl", hash = "sha256:f51328ffe987aecf6d09f3cd9d979face89a617eacdaea43e7b3080777f647ba", size = 221512, upload-time = "2025-09-21T20:01:53.481Z" }, - { url = "https://files.pythonhosted.org/packages/5c/44/3e32dbe933979d05cf2dac5e697c8599cfe038aaf51223ab901e208d5a62/coverage-7.10.7-cp312-cp312-win_arm64.whl", hash = "sha256:bda5e34f8a75721c96085903c6f2197dc398c20ffd98df33f866a9c8fd95f4bf", size = 220147, upload-time = "2025-09-21T20:01:55.2Z" }, - { url = "https://files.pythonhosted.org/packages/9a/94/b765c1abcb613d103b64fcf10395f54d69b0ef8be6a0dd9c524384892cc7/coverage-7.10.7-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:981a651f543f2854abd3b5fcb3263aac581b18209be49863ba575de6edf4c14d", size = 218320, upload-time = "2025-09-21T20:01:56.629Z" }, - { url = "https://files.pythonhosted.org/packages/72/4f/732fff31c119bb73b35236dd333030f32c4bfe909f445b423e6c7594f9a2/coverage-7.10.7-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:73ab1601f84dc804f7812dc297e93cd99381162da39c47040a827d4e8dafe63b", size = 218575, upload-time = "2025-09-21T20:01:58.203Z" }, - { url = "https://files.pythonhosted.org/packages/87/02/ae7e0af4b674be47566707777db1aa375474f02a1d64b9323e5813a6cdd5/coverage-7.10.7-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:a8b6f03672aa6734e700bbcd65ff050fd19cddfec4b031cc8cf1c6967de5a68e", size = 249568, upload-time = "2025-09-21T20:01:59.748Z" }, - { url = "https://files.pythonhosted.org/packages/a2/77/8c6d22bf61921a59bce5471c2f1f7ac30cd4ac50aadde72b8c48d5727902/coverage-7.10.7-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:10b6ba00ab1132a0ce4428ff68cf50a25efd6840a42cdf4239c9b99aad83be8b", size = 252174, upload-time = "2025-09-21T20:02:01.192Z" }, - { url = "https://files.pythonhosted.org/packages/b1/20/b6ea4f69bbb52dac0aebd62157ba6a9dddbfe664f5af8122dac296c3ee15/coverage-7.10.7-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c79124f70465a150e89340de5963f936ee97097d2ef76c869708c4248c63ca49", size = 253447, upload-time = "2025-09-21T20:02:02.701Z" }, - { url = "https://files.pythonhosted.org/packages/f9/28/4831523ba483a7f90f7b259d2018fef02cb4d5b90bc7c1505d6e5a84883c/coverage-7.10.7-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:69212fbccdbd5b0e39eac4067e20a4a5256609e209547d86f740d68ad4f04911", size = 249779, upload-time = "2025-09-21T20:02:04.185Z" }, - { url = "https://files.pythonhosted.org/packages/a7/9f/4331142bc98c10ca6436d2d620c3e165f31e6c58d43479985afce6f3191c/coverage-7.10.7-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:7ea7c6c9d0d286d04ed3541747e6597cbe4971f22648b68248f7ddcd329207f0", size = 251604, upload-time = "2025-09-21T20:02:06.034Z" }, - { url = "https://files.pythonhosted.org/packages/ce/60/bda83b96602036b77ecf34e6393a3836365481b69f7ed7079ab85048202b/coverage-7.10.7-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b9be91986841a75042b3e3243d0b3cb0b2434252b977baaf0cd56e960fe1e46f", size = 249497, upload-time = "2025-09-21T20:02:07.619Z" }, - { url = "https://files.pythonhosted.org/packages/5f/af/152633ff35b2af63977edd835d8e6430f0caef27d171edf2fc76c270ef31/coverage-7.10.7-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:b281d5eca50189325cfe1f365fafade89b14b4a78d9b40b05ddd1fc7d2a10a9c", size = 249350, upload-time = "2025-09-21T20:02:10.34Z" }, - { url = "https://files.pythonhosted.org/packages/9d/71/d92105d122bd21cebba877228990e1646d862e34a98bb3374d3fece5a794/coverage-7.10.7-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:99e4aa63097ab1118e75a848a28e40d68b08a5e19ce587891ab7fd04475e780f", size = 251111, upload-time = "2025-09-21T20:02:12.122Z" }, - { url = "https://files.pythonhosted.org/packages/a2/9e/9fdb08f4bf476c912f0c3ca292e019aab6712c93c9344a1653986c3fd305/coverage-7.10.7-cp313-cp313-win32.whl", hash = "sha256:dc7c389dce432500273eaf48f410b37886be9208b2dd5710aaf7c57fd442c698", size = 220746, upload-time = "2025-09-21T20:02:13.919Z" }, - { url = "https://files.pythonhosted.org/packages/b1/b1/a75fd25df44eab52d1931e89980d1ada46824c7a3210be0d3c88a44aaa99/coverage-7.10.7-cp313-cp313-win_amd64.whl", hash = "sha256:cac0fdca17b036af3881a9d2729a850b76553f3f716ccb0360ad4dbc06b3b843", size = 221541, upload-time = "2025-09-21T20:02:15.57Z" }, - { url = "https://files.pythonhosted.org/packages/14/3a/d720d7c989562a6e9a14b2c9f5f2876bdb38e9367126d118495b89c99c37/coverage-7.10.7-cp313-cp313-win_arm64.whl", hash = "sha256:4b6f236edf6e2f9ae8fcd1332da4e791c1b6ba0dc16a2dc94590ceccb482e546", size = 220170, upload-time = "2025-09-21T20:02:17.395Z" }, - { url = "https://files.pythonhosted.org/packages/bb/22/e04514bf2a735d8b0add31d2b4ab636fc02370730787c576bb995390d2d5/coverage-7.10.7-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:a0ec07fd264d0745ee396b666d47cef20875f4ff2375d7c4f58235886cc1ef0c", size = 219029, upload-time = "2025-09-21T20:02:18.936Z" }, - { url = "https://files.pythonhosted.org/packages/11/0b/91128e099035ece15da3445d9015e4b4153a6059403452d324cbb0a575fa/coverage-7.10.7-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:dd5e856ebb7bfb7672b0086846db5afb4567a7b9714b8a0ebafd211ec7ce6a15", size = 219259, upload-time = "2025-09-21T20:02:20.44Z" }, - { url = "https://files.pythonhosted.org/packages/8b/51/66420081e72801536a091a0c8f8c1f88a5c4bf7b9b1bdc6222c7afe6dc9b/coverage-7.10.7-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:f57b2a3c8353d3e04acf75b3fed57ba41f5c0646bbf1d10c7c282291c97936b4", size = 260592, upload-time = "2025-09-21T20:02:22.313Z" }, - { url = "https://files.pythonhosted.org/packages/5d/22/9b8d458c2881b22df3db5bb3e7369e63d527d986decb6c11a591ba2364f7/coverage-7.10.7-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:1ef2319dd15a0b009667301a3f84452a4dc6fddfd06b0c5c53ea472d3989fbf0", size = 262768, upload-time = "2025-09-21T20:02:24.287Z" }, - { url = "https://files.pythonhosted.org/packages/f7/08/16bee2c433e60913c610ea200b276e8eeef084b0d200bdcff69920bd5828/coverage-7.10.7-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:83082a57783239717ceb0ad584de3c69cf581b2a95ed6bf81ea66034f00401c0", size = 264995, upload-time = "2025-09-21T20:02:26.133Z" }, - { url = "https://files.pythonhosted.org/packages/20/9d/e53eb9771d154859b084b90201e5221bca7674ba449a17c101a5031d4054/coverage-7.10.7-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:50aa94fb1fb9a397eaa19c0d5ec15a5edd03a47bf1a3a6111a16b36e190cff65", size = 259546, upload-time = "2025-09-21T20:02:27.716Z" }, - { url = "https://files.pythonhosted.org/packages/ad/b0/69bc7050f8d4e56a89fb550a1577d5d0d1db2278106f6f626464067b3817/coverage-7.10.7-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:2120043f147bebb41c85b97ac45dd173595ff14f2a584f2963891cbcc3091541", size = 262544, upload-time = "2025-09-21T20:02:29.216Z" }, - { url = "https://files.pythonhosted.org/packages/ef/4b/2514b060dbd1bc0aaf23b852c14bb5818f244c664cb16517feff6bb3a5ab/coverage-7.10.7-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:2fafd773231dd0378fdba66d339f84904a8e57a262f583530f4f156ab83863e6", size = 260308, upload-time = "2025-09-21T20:02:31.226Z" }, - { url = "https://files.pythonhosted.org/packages/54/78/7ba2175007c246d75e496f64c06e94122bdb914790a1285d627a918bd271/coverage-7.10.7-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:0b944ee8459f515f28b851728ad224fa2d068f1513ef6b7ff1efafeb2185f999", size = 258920, upload-time = "2025-09-21T20:02:32.823Z" }, - { url = "https://files.pythonhosted.org/packages/c0/b3/fac9f7abbc841409b9a410309d73bfa6cfb2e51c3fada738cb607ce174f8/coverage-7.10.7-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:4b583b97ab2e3efe1b3e75248a9b333bd3f8b0b1b8e5b45578e05e5850dfb2c2", size = 261434, upload-time = "2025-09-21T20:02:34.86Z" }, - { url = "https://files.pythonhosted.org/packages/ee/51/a03bec00d37faaa891b3ff7387192cef20f01604e5283a5fabc95346befa/coverage-7.10.7-cp313-cp313t-win32.whl", hash = "sha256:2a78cd46550081a7909b3329e2266204d584866e8d97b898cd7fb5ac8d888b1a", size = 221403, upload-time = "2025-09-21T20:02:37.034Z" }, - { url = "https://files.pythonhosted.org/packages/53/22/3cf25d614e64bf6d8e59c7c669b20d6d940bb337bdee5900b9ca41c820bb/coverage-7.10.7-cp313-cp313t-win_amd64.whl", hash = "sha256:33a5e6396ab684cb43dc7befa386258acb2d7fae7f67330ebb85ba4ea27938eb", size = 222469, upload-time = "2025-09-21T20:02:39.011Z" }, - { url = "https://files.pythonhosted.org/packages/49/a1/00164f6d30d8a01c3c9c48418a7a5be394de5349b421b9ee019f380df2a0/coverage-7.10.7-cp313-cp313t-win_arm64.whl", hash = "sha256:86b0e7308289ddde73d863b7683f596d8d21c7d8664ce1dee061d0bcf3fbb4bb", size = 220731, upload-time = "2025-09-21T20:02:40.939Z" }, - { url = "https://files.pythonhosted.org/packages/23/9c/5844ab4ca6a4dd97a1850e030a15ec7d292b5c5cb93082979225126e35dd/coverage-7.10.7-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:b06f260b16ead11643a5a9f955bd4b5fd76c1a4c6796aeade8520095b75de520", size = 218302, upload-time = "2025-09-21T20:02:42.527Z" }, - { url = "https://files.pythonhosted.org/packages/f0/89/673f6514b0961d1f0e20ddc242e9342f6da21eaba3489901b565c0689f34/coverage-7.10.7-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:212f8f2e0612778f09c55dd4872cb1f64a1f2b074393d139278ce902064d5b32", size = 218578, upload-time = "2025-09-21T20:02:44.468Z" }, - { url = "https://files.pythonhosted.org/packages/05/e8/261cae479e85232828fb17ad536765c88dd818c8470aca690b0ac6feeaa3/coverage-7.10.7-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:3445258bcded7d4aa630ab8296dea4d3f15a255588dd535f980c193ab6b95f3f", size = 249629, upload-time = "2025-09-21T20:02:46.503Z" }, - { url = "https://files.pythonhosted.org/packages/82/62/14ed6546d0207e6eda876434e3e8475a3e9adbe32110ce896c9e0c06bb9a/coverage-7.10.7-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:bb45474711ba385c46a0bfe696c695a929ae69ac636cda8f532be9e8c93d720a", size = 252162, upload-time = "2025-09-21T20:02:48.689Z" }, - { url = "https://files.pythonhosted.org/packages/ff/49/07f00db9ac6478e4358165a08fb41b469a1b053212e8a00cb02f0d27a05f/coverage-7.10.7-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:813922f35bd800dca9994c5971883cbc0d291128a5de6b167c7aa697fcf59360", size = 253517, upload-time = "2025-09-21T20:02:50.31Z" }, - { url = "https://files.pythonhosted.org/packages/a2/59/c5201c62dbf165dfbc91460f6dbbaa85a8b82cfa6131ac45d6c1bfb52deb/coverage-7.10.7-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:93c1b03552081b2a4423091d6fb3787265b8f86af404cff98d1b5342713bdd69", size = 249632, upload-time = "2025-09-21T20:02:51.971Z" }, - { url = "https://files.pythonhosted.org/packages/07/ae/5920097195291a51fb00b3a70b9bbd2edbfe3c84876a1762bd1ef1565ebc/coverage-7.10.7-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:cc87dd1b6eaf0b848eebb1c86469b9f72a1891cb42ac7adcfbce75eadb13dd14", size = 251520, upload-time = "2025-09-21T20:02:53.858Z" }, - { url = "https://files.pythonhosted.org/packages/b9/3c/a815dde77a2981f5743a60b63df31cb322c944843e57dbd579326625a413/coverage-7.10.7-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:39508ffda4f343c35f3236fe8d1a6634a51f4581226a1262769d7f970e73bffe", size = 249455, upload-time = "2025-09-21T20:02:55.807Z" }, - { url = "https://files.pythonhosted.org/packages/aa/99/f5cdd8421ea656abefb6c0ce92556709db2265c41e8f9fc6c8ae0f7824c9/coverage-7.10.7-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:925a1edf3d810537c5a3abe78ec5530160c5f9a26b1f4270b40e62cc79304a1e", size = 249287, upload-time = "2025-09-21T20:02:57.784Z" }, - { url = "https://files.pythonhosted.org/packages/c3/7a/e9a2da6a1fc5d007dd51fca083a663ab930a8c4d149c087732a5dbaa0029/coverage-7.10.7-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2c8b9a0636f94c43cd3576811e05b89aa9bc2d0a85137affc544ae5cb0e4bfbd", size = 250946, upload-time = "2025-09-21T20:02:59.431Z" }, - { url = "https://files.pythonhosted.org/packages/ef/5b/0b5799aa30380a949005a353715095d6d1da81927d6dbed5def2200a4e25/coverage-7.10.7-cp314-cp314-win32.whl", hash = "sha256:b7b8288eb7cdd268b0304632da8cb0bb93fadcfec2fe5712f7b9cc8f4d487be2", size = 221009, upload-time = "2025-09-21T20:03:01.324Z" }, - { url = "https://files.pythonhosted.org/packages/da/b0/e802fbb6eb746de006490abc9bb554b708918b6774b722bb3a0e6aa1b7de/coverage-7.10.7-cp314-cp314-win_amd64.whl", hash = "sha256:1ca6db7c8807fb9e755d0379ccc39017ce0a84dcd26d14b5a03b78563776f681", size = 221804, upload-time = "2025-09-21T20:03:03.4Z" }, - { url = "https://files.pythonhosted.org/packages/9e/e8/71d0c8e374e31f39e3389bb0bd19e527d46f00ea8571ec7ec8fd261d8b44/coverage-7.10.7-cp314-cp314-win_arm64.whl", hash = "sha256:097c1591f5af4496226d5783d036bf6fd6cd0cbc132e071b33861de756efb880", size = 220384, upload-time = "2025-09-21T20:03:05.111Z" }, - { url = "https://files.pythonhosted.org/packages/62/09/9a5608d319fa3eba7a2019addeacb8c746fb50872b57a724c9f79f146969/coverage-7.10.7-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:a62c6ef0d50e6de320c270ff91d9dd0a05e7250cac2a800b7784bae474506e63", size = 219047, upload-time = "2025-09-21T20:03:06.795Z" }, - { url = "https://files.pythonhosted.org/packages/f5/6f/f58d46f33db9f2e3647b2d0764704548c184e6f5e014bef528b7f979ef84/coverage-7.10.7-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:9fa6e4dd51fe15d8738708a973470f67a855ca50002294852e9571cdbd9433f2", size = 219266, upload-time = "2025-09-21T20:03:08.495Z" }, - { url = "https://files.pythonhosted.org/packages/74/5c/183ffc817ba68e0b443b8c934c8795553eb0c14573813415bd59941ee165/coverage-7.10.7-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:8fb190658865565c549b6b4706856d6a7b09302c797eb2cf8e7fe9dabb043f0d", size = 260767, upload-time = "2025-09-21T20:03:10.172Z" }, - { url = "https://files.pythonhosted.org/packages/0f/48/71a8abe9c1ad7e97548835e3cc1adbf361e743e9d60310c5f75c9e7bf847/coverage-7.10.7-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:affef7c76a9ef259187ef31599a9260330e0335a3011732c4b9effa01e1cd6e0", size = 262931, upload-time = "2025-09-21T20:03:11.861Z" }, - { url = "https://files.pythonhosted.org/packages/84/fd/193a8fb132acfc0a901f72020e54be5e48021e1575bb327d8ee1097a28fd/coverage-7.10.7-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6e16e07d85ca0cf8bafe5f5d23a0b850064e8e945d5677492b06bbe6f09cc699", size = 265186, upload-time = "2025-09-21T20:03:13.539Z" }, - { url = "https://files.pythonhosted.org/packages/b1/8f/74ecc30607dd95ad50e3034221113ccb1c6d4e8085cc761134782995daae/coverage-7.10.7-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:03ffc58aacdf65d2a82bbeb1ffe4d01ead4017a21bfd0454983b88ca73af94b9", size = 259470, upload-time = "2025-09-21T20:03:15.584Z" }, - { url = "https://files.pythonhosted.org/packages/0f/55/79ff53a769f20d71b07023ea115c9167c0bb56f281320520cf64c5298a96/coverage-7.10.7-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:1b4fd784344d4e52647fd7857b2af5b3fbe6c239b0b5fa63e94eb67320770e0f", size = 262626, upload-time = "2025-09-21T20:03:17.673Z" }, - { url = "https://files.pythonhosted.org/packages/88/e2/dac66c140009b61ac3fc13af673a574b00c16efdf04f9b5c740703e953c0/coverage-7.10.7-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:0ebbaddb2c19b71912c6f2518e791aa8b9f054985a0769bdb3a53ebbc765c6a1", size = 260386, upload-time = "2025-09-21T20:03:19.36Z" }, - { url = "https://files.pythonhosted.org/packages/a2/f1/f48f645e3f33bb9ca8a496bc4a9671b52f2f353146233ebd7c1df6160440/coverage-7.10.7-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:a2d9a3b260cc1d1dbdb1c582e63ddcf5363426a1a68faa0f5da28d8ee3c722a0", size = 258852, upload-time = "2025-09-21T20:03:21.007Z" }, - { url = "https://files.pythonhosted.org/packages/bb/3b/8442618972c51a7affeead957995cfa8323c0c9bcf8fa5a027421f720ff4/coverage-7.10.7-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:a3cc8638b2480865eaa3926d192e64ce6c51e3d29c849e09d5b4ad95efae5399", size = 261534, upload-time = "2025-09-21T20:03:23.12Z" }, - { url = "https://files.pythonhosted.org/packages/b2/dc/101f3fa3a45146db0cb03f5b4376e24c0aac818309da23e2de0c75295a91/coverage-7.10.7-cp314-cp314t-win32.whl", hash = "sha256:67f8c5cbcd3deb7a60b3345dffc89a961a484ed0af1f6f73de91705cc6e31235", size = 221784, upload-time = "2025-09-21T20:03:24.769Z" }, - { url = "https://files.pythonhosted.org/packages/4c/a1/74c51803fc70a8a40d7346660379e144be772bab4ac7bb6e6b905152345c/coverage-7.10.7-cp314-cp314t-win_amd64.whl", hash = "sha256:e1ed71194ef6dea7ed2d5cb5f7243d4bcd334bfb63e59878519be558078f848d", size = 222905, upload-time = "2025-09-21T20:03:26.93Z" }, - { url = "https://files.pythonhosted.org/packages/12/65/f116a6d2127df30bcafbceef0302d8a64ba87488bf6f73a6d8eebf060873/coverage-7.10.7-cp314-cp314t-win_arm64.whl", hash = "sha256:7fe650342addd8524ca63d77b2362b02345e5f1a093266787d210c70a50b471a", size = 220922, upload-time = "2025-09-21T20:03:28.672Z" }, - { url = "https://files.pythonhosted.org/packages/a3/ad/d1c25053764b4c42eb294aae92ab617d2e4f803397f9c7c8295caa77a260/coverage-7.10.7-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:fff7b9c3f19957020cac546c70025331113d2e61537f6e2441bc7657913de7d3", size = 217978, upload-time = "2025-09-21T20:03:30.362Z" }, - { url = "https://files.pythonhosted.org/packages/52/2f/b9f9daa39b80ece0b9548bbb723381e29bc664822d9a12c2135f8922c22b/coverage-7.10.7-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:bc91b314cef27742da486d6839b677b3f2793dfe52b51bbbb7cf736d5c29281c", size = 218370, upload-time = "2025-09-21T20:03:32.147Z" }, - { url = "https://files.pythonhosted.org/packages/dd/6e/30d006c3b469e58449650642383dddf1c8fb63d44fdf92994bfd46570695/coverage-7.10.7-cp39-cp39-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:567f5c155eda8df1d3d439d40a45a6a5f029b429b06648235f1e7e51b522b396", size = 244802, upload-time = "2025-09-21T20:03:33.919Z" }, - { url = "https://files.pythonhosted.org/packages/b0/49/8a070782ce7e6b94ff6a0b6d7c65ba6bc3091d92a92cef4cd4eb0767965c/coverage-7.10.7-cp39-cp39-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:2af88deffcc8a4d5974cf2d502251bc3b2db8461f0b66d80a449c33757aa9f40", size = 246625, upload-time = "2025-09-21T20:03:36.09Z" }, - { url = "https://files.pythonhosted.org/packages/6a/92/1c1c5a9e8677ce56d42b97bdaca337b2d4d9ebe703d8c174ede52dbabd5f/coverage-7.10.7-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c7315339eae3b24c2d2fa1ed7d7a38654cba34a13ef19fbcb9425da46d3dc594", size = 248399, upload-time = "2025-09-21T20:03:38.342Z" }, - { url = "https://files.pythonhosted.org/packages/c0/54/b140edee7257e815de7426d5d9846b58505dffc29795fff2dfb7f8a1c5a0/coverage-7.10.7-cp39-cp39-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:912e6ebc7a6e4adfdbb1aec371ad04c68854cd3bf3608b3514e7ff9062931d8a", size = 245142, upload-time = "2025-09-21T20:03:40.591Z" }, - { url = "https://files.pythonhosted.org/packages/e4/9e/6d6b8295940b118e8b7083b29226c71f6154f7ff41e9ca431f03de2eac0d/coverage-7.10.7-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:f49a05acd3dfe1ce9715b657e28d138578bc40126760efb962322c56e9ca344b", size = 246284, upload-time = "2025-09-21T20:03:42.355Z" }, - { url = "https://files.pythonhosted.org/packages/db/e5/5e957ca747d43dbe4d9714358375c7546cb3cb533007b6813fc20fce37ad/coverage-7.10.7-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:cce2109b6219f22ece99db7644b9622f54a4e915dad65660ec435e89a3ea7cc3", size = 244353, upload-time = "2025-09-21T20:03:44.218Z" }, - { url = "https://files.pythonhosted.org/packages/9a/45/540fc5cc92536a1b783b7ef99450bd55a4b3af234aae35a18a339973ce30/coverage-7.10.7-cp39-cp39-musllinux_1_2_riscv64.whl", hash = "sha256:f3c887f96407cea3916294046fc7dab611c2552beadbed4ea901cbc6a40cc7a0", size = 244430, upload-time = "2025-09-21T20:03:46.065Z" }, - { url = "https://files.pythonhosted.org/packages/75/0b/8287b2e5b38c8fe15d7e3398849bb58d382aedc0864ea0fa1820e8630491/coverage-7.10.7-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:635adb9a4507c9fd2ed65f39693fa31c9a3ee3a8e6dc64df033e8fdf52a7003f", size = 245311, upload-time = "2025-09-21T20:03:48.19Z" }, - { url = "https://files.pythonhosted.org/packages/0c/1d/29724999984740f0c86d03e6420b942439bf5bd7f54d4382cae386a9d1e9/coverage-7.10.7-cp39-cp39-win32.whl", hash = "sha256:5a02d5a850e2979b0a014c412573953995174743a3f7fa4ea5a6e9a3c5617431", size = 220500, upload-time = "2025-09-21T20:03:50.024Z" }, - { url = "https://files.pythonhosted.org/packages/43/11/4b1e6b129943f905ca54c339f343877b55b365ae2558806c1be4f7476ed5/coverage-7.10.7-cp39-cp39-win_amd64.whl", hash = "sha256:c134869d5ffe34547d14e174c866fd8fe2254918cc0a95e99052903bc1543e07", size = 221408, upload-time = "2025-09-21T20:03:51.803Z" }, - { url = "https://files.pythonhosted.org/packages/ec/16/114df1c291c22cac3b0c127a73e0af5c12ed7bbb6558d310429a0ae24023/coverage-7.10.7-py3-none-any.whl", hash = "sha256:f7941f6f2fe6dd6807a1208737b8a0cbcf1cc6d7b07d24998ad2d63590868260", size = 209952, upload-time = "2025-09-21T20:03:53.918Z" }, -] - -[package.optional-dependencies] -toml = [ - { name = "tomli", marker = "python_full_version < '3.10'" }, -] - [[package]] name = "coverage" version = "7.13.3" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.14'", - "python_full_version >= '3.10' and python_full_version < '3.14'", -] sdist = { url = "https://files.pythonhosted.org/packages/11/43/3e4ac666cc35f231fa70c94e9f38459299de1a152813f9d2f60fc5f3ecaf/coverage-7.13.3.tar.gz", hash = "sha256:f7f6182d3dfb8802c1747eacbfe611b669455b69b7c037484bb1efbbb56711ac", size = 826832, upload-time = "2026-02-03T14:02:30.944Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/ab/07/1c8099563a8a6c389a31c2d0aa1497cee86d6248bb4b9ba5e779215db9f9/coverage-7.13.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0b4f345f7265cdbdb5ec2521ffff15fa49de6d6c39abf89fc7ad68aa9e3a55f0", size = 219143, upload-time = "2026-02-03T13:59:40.459Z" }, @@ -1076,7 +813,7 @@ wheels = [ [package.optional-dependencies] toml = [ - { name = "tomli", marker = "python_full_version >= '3.10' and python_full_version <= '3.11'" }, + { name = "tomli", marker = "python_full_version <= '3.11'" }, ] [[package]] @@ -1084,8 +821,8 @@ name = "croniter" version = "6.0.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "python-dateutil", marker = "python_full_version >= '3.10'" }, - { name = "pytz", marker = "python_full_version >= '3.10'" }, + { name = "python-dateutil" }, + { name = "pytz" }, ] sdist = { url = "https://files.pythonhosted.org/packages/ad/2f/44d1ae153a0e27be56be43465e5cb39b9650c781e001e7864389deb25090/croniter-6.0.0.tar.gz", hash = "sha256:37c504b313956114a983ece2c2b07790b1f1094fe9d81cc94739214748255577", size = 64481, upload-time = "2024-12-17T17:17:47.32Z" } wheels = [ @@ -1169,8 +906,7 @@ name = "cssselect2" version = "0.8.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "tinycss2", version = "1.4.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "tinycss2", version = "1.5.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "tinycss2" }, { name = "webencodings" }, ] sdist = { url = "https://files.pythonhosted.org/packages/9f/86/fd7f58fc498b3166f3a7e8e0cddb6e620fe1da35b02248b1bd59e95dbaaa/cssselect2-0.8.0.tar.gz", hash = "sha256:7674ffb954a3b46162392aee2a3a0aedb2e14ecf99fcc28644900f4e6e3e9d3a", size = 35716, upload-time = "2025-03-05T14:46:07.988Z" } @@ -1192,12 +928,12 @@ name = "cyclopts" version = "4.5.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "attrs", marker = "python_full_version >= '3.10'" }, - { name = "docstring-parser", marker = "python_full_version >= '3.10'" }, - { name = "rich", marker = "python_full_version >= '3.10'" }, - { name = "rich-rst", marker = "python_full_version >= '3.10'" }, - { name = "tomli", marker = "python_full_version == '3.10.*'" }, - { name = "typing-extensions", marker = "python_full_version == '3.10.*'" }, + { name = "attrs" }, + { name = "docstring-parser" }, + { name = "rich" }, + { name = "rich-rst" }, + { name = "tomli", marker = "python_full_version < '3.11'" }, + { name = "typing-extensions", marker = "python_full_version < '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/d4/93/6085aa89c3fff78a5180987354538d72e43b0db27e66a959302d0c07821a/cyclopts-4.5.1.tar.gz", hash = "sha256:fadc45304763fd9f5d6033727f176898d17a1778e194436964661a005078a3dd", size = 162075, upload-time = "2026-01-25T15:23:54.07Z" } wheels = [ @@ -1240,26 +976,10 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl", hash = "sha256:7bffd925d65168f85027d8da9af6bddab658135b840670a223589bc0c8ef02b2", size = 20277, upload-time = "2023-12-24T09:54:30.421Z" }, ] -[[package]] -name = "dnspython" -version = "2.7.0" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.10'", -] -sdist = { url = "https://files.pythonhosted.org/packages/b5/4a/263763cb2ba3816dd94b08ad3a33d5fdae34ecb856678773cc40a3605829/dnspython-2.7.0.tar.gz", hash = "sha256:ce9c432eda0dc91cf618a5cedf1a4e142651196bbcd2c80e89ed5a907e5cfaf1", size = 345197, upload-time = "2024-10-05T20:14:59.362Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/68/1b/e0a87d256e40e8c888847551b20a017a6b98139178505dc7ffb96f04e954/dnspython-2.7.0-py3-none-any.whl", hash = "sha256:b4c34b7d10b51bcc3a5071e7b8dee77939f1e878477eeecc965e9835f63c6c86", size = 313632, upload-time = "2024-10-05T20:14:57.687Z" }, -] - [[package]] name = "dnspython" version = "2.8.0" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.14'", - "python_full_version >= '3.10' and python_full_version < '3.14'", -] sdist = { url = "https://files.pythonhosted.org/packages/8c/8b/57666417c0f90f08bcafa776861060426765fdb422eb10212086fb811d26/dnspython-2.8.0.tar.gz", hash = "sha256:181d3c6996452cb1189c4046c61599b84a5a86e099562ffde77d26984ff26d0f", size = 368251, upload-time = "2025-09-07T18:58:00.022Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl", hash = "sha256:01d9bbc4a2d76bf0db7c1f729812ded6d912bd318d3b1cf81d30c0f845dbf3af", size = 331094, upload-time = "2025-09-07T18:57:58.071Z" }, @@ -1288,8 +1008,7 @@ name = "email-validator" version = "2.3.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "dnspython", version = "2.7.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "dnspython", version = "2.8.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "dnspython" }, { name = "idna" }, ] sdist = { url = "https://files.pythonhosted.org/packages/f5/22/900cb125c76b7aaa450ce02fd727f452243f2e91a61af068b40adba60ea9/email_validator-2.3.0.tar.gz", hash = "sha256:9fc05c37f2f6cf439ff414f8fc46d917929974a82244c20eb10231ba60c54426", size = 51238, upload-time = "2025-08-26T13:09:06.831Z" } @@ -1332,9 +1051,9 @@ name = "fakeredis" version = "2.33.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "redis", marker = "python_full_version >= '3.10'" }, - { name = "sortedcontainers", marker = "python_full_version >= '3.10'" }, - { name = "typing-extensions", marker = "python_full_version == '3.10.*'" }, + { name = "redis" }, + { name = "sortedcontainers" }, + { name = "typing-extensions", marker = "python_full_version < '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/5f/f9/57464119936414d60697fcbd32f38909bb5688b616ae13de6e98384433e0/fakeredis-2.33.0.tar.gz", hash = "sha256:d7bc9a69d21df108a6451bbffee23b3eba432c21a654afc7ff2d295428ec5770", size = 175187, upload-time = "2025-12-16T19:45:52.269Z" } wheels = [ @@ -1343,7 +1062,7 @@ wheels = [ [package.optional-dependencies] lua = [ - { name = "lupa", marker = "python_full_version >= '3.10'" }, + { name = "lupa" }, ] [[package]] @@ -1352,8 +1071,7 @@ source = { editable = "." } dependencies = [ { name = "annotated-doc" }, { name = "pydantic" }, - { name = "starlette", version = "0.49.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "starlette", version = "0.52.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "starlette" }, { name = "typing-extensions" }, { name = "typing-inspection" }, ] @@ -1365,17 +1083,13 @@ all = [ { name = "httpx" }, { name = "itsdangerous" }, { name = "jinja2" }, - { name = "orjson", version = "3.11.5", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "orjson", version = "3.11.7", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "orjson" }, { name = "pydantic-extra-types" }, - { name = "pydantic-settings", version = "2.11.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "pydantic-settings", version = "2.12.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, - { name = "python-multipart", version = "0.0.20", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "python-multipart", version = "0.0.22", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "pydantic-settings" }, + { name = "python-multipart" }, { name = "pyyaml" }, { name = "ujson" }, - { name = "uvicorn", version = "0.39.0", source = { registry = "https://pypi.org/simple" }, extra = ["standard"], marker = "python_full_version < '3.10'" }, - { name = "uvicorn", version = "0.40.0", source = { registry = "https://pypi.org/simple" }, extra = ["standard"], marker = "python_full_version >= '3.10'" }, + { name = "uvicorn", extra = ["standard"] }, ] standard = [ { name = "email-validator" }, @@ -1383,12 +1097,9 @@ standard = [ { name = "httpx" }, { name = "jinja2" }, { name = "pydantic-extra-types" }, - { name = "pydantic-settings", version = "2.11.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "pydantic-settings", version = "2.12.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, - { name = "python-multipart", version = "0.0.20", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "python-multipart", version = "0.0.22", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, - { name = "uvicorn", version = "0.39.0", source = { registry = "https://pypi.org/simple" }, extra = ["standard"], marker = "python_full_version < '3.10'" }, - { name = "uvicorn", version = "0.40.0", source = { registry = "https://pypi.org/simple" }, extra = ["standard"], marker = "python_full_version >= '3.10'" }, + { name = "pydantic-settings" }, + { name = "python-multipart" }, + { name = "uvicorn", extra = ["standard"] }, ] standard-no-fastapi-cloud-cli = [ { name = "email-validator" }, @@ -1396,23 +1107,18 @@ standard-no-fastapi-cloud-cli = [ { name = "httpx" }, { name = "jinja2" }, { name = "pydantic-extra-types" }, - { name = "pydantic-settings", version = "2.11.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "pydantic-settings", version = "2.12.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, - { name = "python-multipart", version = "0.0.20", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "python-multipart", version = "0.0.22", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, - { name = "uvicorn", version = "0.39.0", source = { registry = "https://pypi.org/simple" }, extra = ["standard"], marker = "python_full_version < '3.10'" }, - { name = "uvicorn", version = "0.40.0", source = { registry = "https://pypi.org/simple" }, extra = ["standard"], marker = "python_full_version >= '3.10'" }, + { name = "pydantic-settings" }, + { name = "python-multipart" }, + { name = "uvicorn", extra = ["standard"] }, ] [package.dev-dependencies] dev = [ { name = "a2wsgi" }, { name = "anyio", extra = ["trio"] }, - { name = "black", version = "25.11.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "black", version = "26.1.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "black" }, { name = "cairosvg" }, - { name = "coverage", version = "7.10.7", source = { registry = "https://pypi.org/simple" }, extra = ["toml"], marker = "python_full_version < '3.10'" }, - { name = "coverage", version = "7.13.3", source = { registry = "https://pypi.org/simple" }, extra = ["toml"], marker = "python_full_version >= '3.10'" }, + { name = "coverage", extra = ["toml"] }, { name = "dirty-equals" }, { name = "flask" }, { name = "gitpython" }, @@ -1426,17 +1132,13 @@ dev = [ { name = "mkdocs-macros-plugin" }, { name = "mkdocs-material" }, { name = "mkdocs-redirects" }, - { name = "mkdocstrings", version = "0.30.1", source = { registry = "https://pypi.org/simple" }, extra = ["python"], marker = "python_full_version < '3.10'" }, - { name = "mkdocstrings", version = "1.0.2", source = { registry = "https://pypi.org/simple" }, extra = ["python"], marker = "python_full_version >= '3.10'" }, + { name = "mkdocstrings", extra = ["python"] }, { name = "mypy" }, - { name = "pillow", version = "11.3.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "pillow", version = "12.1.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "pillow" }, { name = "playwright" }, { name = "prek" }, - { name = "pwdlib", version = "0.2.1", source = { registry = "https://pypi.org/simple" }, extra = ["argon2"], marker = "python_full_version < '3.10'" }, - { name = "pwdlib", version = "0.3.0", source = { registry = "https://pypi.org/simple" }, extra = ["argon2"], marker = "python_full_version >= '3.10'" }, - { name = "pydantic-ai", version = "0.8.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "pydantic-ai", version = "1.56.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "pwdlib", extra = ["argon2"] }, + { name = "pydantic-ai" }, { name = "pygithub" }, { name = "pyjwt" }, { name = "pytest" }, @@ -1445,15 +1147,13 @@ dev = [ { name = "pyyaml" }, { name = "ruff" }, { name = "sqlmodel" }, - { name = "strawberry-graphql", version = "0.283.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "strawberry-graphql", version = "0.291.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "strawberry-graphql" }, { name = "typer" }, { name = "types-orjson" }, { name = "types-ujson" }, ] docs = [ - { name = "black", version = "25.11.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "black", version = "26.1.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "black" }, { name = "cairosvg" }, { name = "griffe-typingdoc" }, { name = "griffe-warnings-deprecated" }, @@ -1464,10 +1164,8 @@ docs = [ { name = "mkdocs-macros-plugin" }, { name = "mkdocs-material" }, { name = "mkdocs-redirects" }, - { name = "mkdocstrings", version = "0.30.1", source = { registry = "https://pypi.org/simple" }, extra = ["python"], marker = "python_full_version < '3.10'" }, - { name = "mkdocstrings", version = "1.0.2", source = { registry = "https://pypi.org/simple" }, extra = ["python"], marker = "python_full_version >= '3.10'" }, - { name = "pillow", version = "11.3.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "pillow", version = "12.1.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "mkdocstrings", extra = ["python"] }, + { name = "pillow" }, { name = "python-slugify" }, { name = "pyyaml" }, { name = "ruff" }, @@ -1480,8 +1178,7 @@ docs-tests = [ github-actions = [ { name = "httpx" }, { name = "pydantic" }, - { name = "pydantic-settings", version = "2.11.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "pydantic-settings", version = "2.12.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "pydantic-settings" }, { name = "pygithub" }, { name = "pyyaml" }, { name = "smokeshow" }, @@ -1489,30 +1186,26 @@ github-actions = [ tests = [ { name = "a2wsgi" }, { name = "anyio", extra = ["trio"] }, - { name = "coverage", version = "7.10.7", source = { registry = "https://pypi.org/simple" }, extra = ["toml"], marker = "python_full_version < '3.10'" }, - { name = "coverage", version = "7.13.3", source = { registry = "https://pypi.org/simple" }, extra = ["toml"], marker = "python_full_version >= '3.10'" }, + { name = "coverage", extra = ["toml"] }, { name = "dirty-equals" }, { name = "flask" }, { name = "httpx" }, { name = "inline-snapshot" }, { name = "mypy" }, - { name = "pwdlib", version = "0.2.1", source = { registry = "https://pypi.org/simple" }, extra = ["argon2"], marker = "python_full_version < '3.10'" }, - { name = "pwdlib", version = "0.3.0", source = { registry = "https://pypi.org/simple" }, extra = ["argon2"], marker = "python_full_version >= '3.10'" }, + { name = "pwdlib", extra = ["argon2"] }, { name = "pyjwt" }, { name = "pytest" }, { name = "pytest-codspeed" }, { name = "pyyaml" }, { name = "ruff" }, { name = "sqlmodel" }, - { name = "strawberry-graphql", version = "0.283.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "strawberry-graphql", version = "0.291.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "strawberry-graphql" }, { name = "types-orjson" }, { name = "types-ujson" }, ] translations = [ { name = "gitpython" }, - { name = "pydantic-ai", version = "0.8.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "pydantic-ai", version = "1.56.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "pydantic-ai" }, { name = "pygithub" }, ] @@ -1659,8 +1352,7 @@ dependencies = [ { name = "rich-toolkit" }, { name = "tomli", marker = "python_full_version < '3.11'" }, { name = "typer" }, - { name = "uvicorn", version = "0.39.0", source = { registry = "https://pypi.org/simple" }, extra = ["standard"], marker = "python_full_version < '3.10'" }, - { name = "uvicorn", version = "0.40.0", source = { registry = "https://pypi.org/simple" }, extra = ["standard"], marker = "python_full_version >= '3.10'" }, + { name = "uvicorn", extra = ["standard"] }, ] sdist = { url = "https://files.pythonhosted.org/packages/d3/ca/d90fb3bfbcbd6e56c77afd9d114dd6ce8955d8bb90094399d1c70e659e40/fastapi_cli-0.0.20.tar.gz", hash = "sha256:d17c2634f7b96b6b560bc16b0035ed047d523c912011395f49f00a421692bc3a", size = 19786, upload-time = "2025-12-22T17:13:33.794Z" } wheels = [ @@ -1670,12 +1362,10 @@ wheels = [ [package.optional-dependencies] standard = [ { name = "fastapi-cloud-cli" }, - { name = "uvicorn", version = "0.39.0", source = { registry = "https://pypi.org/simple" }, extra = ["standard"], marker = "python_full_version < '3.10'" }, - { name = "uvicorn", version = "0.40.0", source = { registry = "https://pypi.org/simple" }, extra = ["standard"], marker = "python_full_version >= '3.10'" }, + { name = "uvicorn", extra = ["standard"] }, ] standard-no-fastapi-cloud-cli = [ - { name = "uvicorn", version = "0.39.0", source = { registry = "https://pypi.org/simple" }, extra = ["standard"], marker = "python_full_version < '3.10'" }, - { name = "uvicorn", version = "0.40.0", source = { registry = "https://pypi.org/simple" }, extra = ["standard"], marker = "python_full_version >= '3.10'" }, + { name = "uvicorn", extra = ["standard"] }, ] [[package]] @@ -1690,8 +1380,7 @@ dependencies = [ { name = "rignore" }, { name = "sentry-sdk" }, { name = "typer" }, - { name = "uvicorn", version = "0.39.0", source = { registry = "https://pypi.org/simple" }, extra = ["standard"], marker = "python_full_version < '3.10'" }, - { name = "uvicorn", version = "0.40.0", source = { registry = "https://pypi.org/simple" }, extra = ["standard"], marker = "python_full_version >= '3.10'" }, + { name = "uvicorn", extra = ["standard"] }, ] sdist = { url = "https://files.pythonhosted.org/packages/11/15/6c3d85d63964340fde6f36cc80f3f365d35f371e6a918d68ff3a3d588ef2/fastapi_cloud_cli-0.11.0.tar.gz", hash = "sha256:ecc83a5db106be35af528eccb01aa9bced1d29783efd48c8c1c831cf111eea99", size = 36170, upload-time = "2026-01-15T09:51:33.681Z" } wheels = [ @@ -1793,20 +1482,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c9/e2/dfa19a4b260b8ab3581b7484dcb80c09b25324f4daa6b6ae1c7640d1607a/fastar-0.8.0-cp314-cp314t-win32.whl", hash = "sha256:187f61dc739afe45ac8e47ed7fd1adc45d52eac110cf27d579155720507d6fbe", size = 455767, upload-time = "2025-11-26T02:36:34.758Z" }, { url = "https://files.pythonhosted.org/packages/51/47/df65c72afc1297797b255f90c4778b5d6f1f0f80282a134d5ab610310ed9/fastar-0.8.0-cp314-cp314t-win_amd64.whl", hash = "sha256:40e9d763cf8bf85ce2fa256e010aa795c0fe3d3bd1326d5c3084e6ce7857127e", size = 489971, upload-time = "2025-11-26T02:36:22.081Z" }, { url = "https://files.pythonhosted.org/packages/85/11/0aa8455af26f0ae89e42be67f3a874255ee5d7f0f026fc86e8d56f76b428/fastar-0.8.0-cp314-cp314t-win_arm64.whl", hash = "sha256:e59673307b6a08210987059a2bdea2614fe26e3335d0e5d1a3d95f49a05b1418", size = 460467, upload-time = "2025-11-26T02:36:07.978Z" }, - { url = "https://files.pythonhosted.org/packages/fd/0d/462ce073b1f87cc6bf33b656c340c103eeb67487d118b761a697f1ee454f/fastar-0.8.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:923afc2db5192e56e71952a88e3fe5965c7c9c910d385d2db7573136f064f2fa", size = 709519, upload-time = "2025-11-26T02:34:44.783Z" }, - { url = "https://files.pythonhosted.org/packages/0d/f1/ceca1e04fd3266f866efdbb5d343fee1d8ff8fe94c64c8d1aab68b483ad0/fastar-0.8.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4fbe775356930f3aab0ce709fdf8ecf90c10882f5bbdcea215c89a3b14090c50", size = 632509, upload-time = "2025-11-26T02:34:29.428Z" }, - { url = "https://files.pythonhosted.org/packages/4f/db/fdb07e9dce80ebb38138f166a30dc482c82cc8dfcfda1024e8b100a53d1c/fastar-0.8.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:2ff516154e77f4bf78c31a0c11aa78a8a80e11b6964ec6f28982e42ffcbb543c", size = 871400, upload-time = "2025-11-26T02:33:58.461Z" }, - { url = "https://files.pythonhosted.org/packages/54/6d/d0a342528002cf7527339fd275bdee5e5cc90c2f193e8418d3510ffedcd7/fastar-0.8.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0d2fdd1c987ff2300bdf39baed556f8e155f8577018775e794a268ecf1707610", size = 765781, upload-time = "2025-11-26T02:32:53.929Z" }, - { url = "https://files.pythonhosted.org/packages/bc/96/dd2721e7160eed7bc9c3b695e942868c7ba2fab41947278fa380c18569be/fastar-0.8.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d80e4dad8ee2362a71870b1e735800bb5e97f12ebbee4bd0cf15a81ad2428b5a", size = 766126, upload-time = "2025-11-26T02:33:10.075Z" }, - { url = "https://files.pythonhosted.org/packages/9c/ac/6533d2608254def722cd8c852f4ac8fb413fc43ad3251b7fb99863ffaa83/fastar-0.8.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a17abee1febf5363ed2633f5e13de4be481ba1ab5f77860d39470eccdc4b65af", size = 932549, upload-time = "2025-11-26T02:33:25.866Z" }, - { url = "https://files.pythonhosted.org/packages/97/dc/aac042d0d0017b8d75ff34381cc28b482ace0d78a26d4eef9a8674f850c2/fastar-0.8.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:64cbde8e0ece3d799090a4727f936f66c5990d3ac59416f3de76a2c676e8e568", size = 821860, upload-time = "2025-11-26T02:33:41.423Z" }, - { url = "https://files.pythonhosted.org/packages/b2/ef/c31057572e3a5a2c90da4986d8594d0ff33097b4a44058f9f52103c33677/fastar-0.8.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:63d98b26590d293a9d9a379bae88367a8f3a6137c28819ed6dd6e11aca4a5c6e", size = 821660, upload-time = "2025-11-26T02:34:13.84Z" }, - { url = "https://files.pythonhosted.org/packages/39/00/d42fc84e8ce8587eb746406aa74ec231f97ce659a48bc064d5ff5cd78889/fastar-0.8.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:bf440983d4d64582bddf2f0bd3c43ea1db93a8c31cf7c20e473bffaf6d9c0b6d", size = 987026, upload-time = "2025-11-26T02:35:01.181Z" }, - { url = "https://files.pythonhosted.org/packages/aa/d9/5e4d37faca6f2df6a0bf1efc340192a871356162a7cc53626dc117645ad6/fastar-0.8.0-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:1d90cbf984a39afda27afe08e40c2d8eddc49c5e80590af641610c7b6dc20161", size = 1042165, upload-time = "2025-11-26T02:35:18.729Z" }, - { url = "https://files.pythonhosted.org/packages/77/fd/bb4731243e42f385e8db9da824971f5d0380e6b31466c36eb089d631c589/fastar-0.8.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:ca0db5e563d84b639fe15385eeca940777b6d2f0a1f3bb7cd5b55ab7124f0554", size = 1046990, upload-time = "2025-11-26T02:35:36.158Z" }, - { url = "https://files.pythonhosted.org/packages/c4/50/2ac066f771858ea45d885cfde7262b286a223af9538d3f85d29d5159b4fb/fastar-0.8.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:42ff3052d74684a636423d4f040db88eebd4caf20842fa5f06020e0130c01f69", size = 995637, upload-time = "2025-11-26T02:35:54.714Z" }, - { url = "https://files.pythonhosted.org/packages/d3/04/c884ea3fa7c154ac0e89219a337c9d6e0d52d0eb5547b3f99b896eca417e/fastar-0.8.0-cp39-cp39-win32.whl", hash = "sha256:15e3dfaa769d2117ef707e5f47c62126d1b63f8e9c85133112f33f1fbdf8942f", size = 456817, upload-time = "2025-11-26T02:36:33.198Z" }, - { url = "https://files.pythonhosted.org/packages/aa/0f/3a5758cca852bb221e78950fbfece0b932c6de6981ee36fb0ac57cf66c13/fastar-0.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:5153aa1c194316d0f67b6884a62d122d51fce4196263e92e4bca2a6c47cd44c0", size = 490633, upload-time = "2025-11-26T02:36:19.976Z" }, { url = "https://files.pythonhosted.org/packages/25/9f/6eaa810c240236eff2edf736cd50a17c97dbab1693cda4f7bcea09d13418/fastar-0.8.0-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:2127cf2e80ffd49744a160201e0e2f55198af6c028a7b3f750026e0b1f1caa4e", size = 710544, upload-time = "2025-11-26T02:34:46.195Z" }, { url = "https://files.pythonhosted.org/packages/1d/a5/58ff9e49a1cd5fbfc8f1238226cbf83b905376a391a6622cdd396b2cfa29/fastar-0.8.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:ff85094f10003801339ac4fa9b20a3410c2d8f284d4cba2dc99de6e98c877812", size = 634020, upload-time = "2025-11-26T02:34:31.085Z" }, { url = "https://files.pythonhosted.org/packages/80/94/f839257c6600a83fbdb5a7fcc06319599086137b25ba38ca3d2c0fe14562/fastar-0.8.0-pp310-pypy310_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:3dbca235f0bd804cca6602fe055d3892bebf95fb802e6c6c7d872fb10f7abc6c", size = 871735, upload-time = "2025-11-26T02:34:00.088Z" }, @@ -1831,18 +1506,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/a4/b9/9a8c3fd59958c1c8027bc075af11722cdc62c4968bb277e841d131232289/fastar-0.8.0-pp311-pypy311_pp73-musllinux_1_2_armv7l.whl", hash = "sha256:382bfe82c026086487cb17fee12f4c1e2b4e67ce230f2e04487d3e7ddfd69031", size = 1042911, upload-time = "2025-11-26T02:35:21.857Z" }, { url = "https://files.pythonhosted.org/packages/e2/2f/c3f30963b47022134b8a231c12845f4d7cfba520f59bbc1a82468aea77c7/fastar-0.8.0-pp311-pypy311_pp73-musllinux_1_2_i686.whl", hash = "sha256:908d2b9a1ff3d549cc304b32f95706a536da8f0bcb0bc0f9e4c1cce39b80e218", size = 1047464, upload-time = "2025-11-26T02:35:39.376Z" }, { url = "https://files.pythonhosted.org/packages/9e/8a/218ab6d9a2bab3b07718e6cd8405529600edc1e9c266320e8524c8f63251/fastar-0.8.0-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:1aa7dbde2d2d73eb5b6203d0f74875cb66350f0f1b4325b4839fc8fbbf5d074e", size = 997309, upload-time = "2025-11-26T02:35:57.722Z" }, - { url = "https://files.pythonhosted.org/packages/4e/ef/da0cbac6da78b22ddb6ec0bbf3ad1813f8dd991a911342fc20e5feabaa15/fastar-0.8.0-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:284036bae786a520456ad3f58e72aaf1bd5d74e309132e568343564daa4ae383", size = 710367, upload-time = "2025-11-26T02:34:48.853Z" }, - { url = "https://files.pythonhosted.org/packages/c4/f0/951d368b4538477fe44651aaa7436318c22bf89e8e18086a68bd89e14a82/fastar-0.8.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:5aba0942b4f56acdb8fa8aa7cb506f70c1a17bf13dcab318a17ffb467cb2e7ec", size = 633744, upload-time = "2025-11-26T02:34:33.723Z" }, - { url = "https://files.pythonhosted.org/packages/1e/d2/5f37b634aff1e27191874b7f0fb7306e60566d984df06ff5c2f901ef123b/fastar-0.8.0-pp39-pypy39_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:52eda6230799db7bbd44461c622161e9bcd43603399da19b0daab2782e0030b0", size = 871412, upload-time = "2025-11-26T02:34:02.738Z" }, - { url = "https://files.pythonhosted.org/packages/b4/cd/41148c74cc164aacb8b5e7cb938a7ecc5a4e595f95e312aafcc8dbe36e48/fastar-0.8.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f860566b9f3cb1900980f46a4c3f003990c0009c11730f988f758542c17a2364", size = 766470, upload-time = "2025-11-26T02:32:58.503Z" }, - { url = "https://files.pythonhosted.org/packages/5f/89/b5715d4f969f15fe78b184ae42295e71f0ad2e0e083f0625212271cbda55/fastar-0.8.0-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:78f3fe5f45437c66d1dbece5f31aa487e48ef46d76b2082b873d5fa18013ebe1", size = 765285, upload-time = "2025-11-26T02:33:14.148Z" }, - { url = "https://files.pythonhosted.org/packages/39/4a/88223721278a663684c4fa6cb95ca296e0ba385362de4809a5e85cacfb36/fastar-0.8.0-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:82bc445202bbc53f067bb15e3b8639f01fd54d3096a0f9601240690cfd7c9684", size = 933881, upload-time = "2025-11-26T02:33:29.637Z" }, - { url = "https://files.pythonhosted.org/packages/ac/73/a13d6d57029378477c4d9232eddfb81bb2f74e0e91bdbca864c74223d877/fastar-0.8.0-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3b1208b5453cfe7192e54765f73844b80d684bd8dc6d6acbbb60ead42590b13e", size = 822511, upload-time = "2025-11-26T02:33:45.882Z" }, - { url = "https://files.pythonhosted.org/packages/a4/96/79000571a10d93e2110e72b5e7155e6bf138c8cb896117cfb768c74d01ff/fastar-0.8.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8922754c66699e27d4f1ce07c9c256228054cdc9bb36363e8bb5b503453a6da", size = 822204, upload-time = "2025-11-26T02:34:18.164Z" }, - { url = "https://files.pythonhosted.org/packages/35/e4/c2066024f336349ce36f85b0df9d082981d453cfdb5c139af2c5eebcc49a/fastar-0.8.0-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:92cad46dfbb9969359823c9f61165ec32d5d675d86e863889416e9b64efea95c", size = 987454, upload-time = "2025-11-26T02:35:05.827Z" }, - { url = "https://files.pythonhosted.org/packages/4a/b7/e3a062534af02610dea226d2c14e70beb90b91a23562fed8f76bfa35e6cd/fastar-0.8.0-pp39-pypy39_pp73-musllinux_1_2_armv7l.whl", hash = "sha256:f4eb9560a447ff6a4b377f08b6e5d3a31909a612b028f2c57810ffaf570eceb8", size = 1041310, upload-time = "2025-11-26T02:35:23.305Z" }, - { url = "https://files.pythonhosted.org/packages/91/73/1640476553705ee29ff9350a3b6c707ac150be53094d326e0d81d62a65ec/fastar-0.8.0-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:52455794e6cc2b6a6dbf141a1c4312a1a1215d75e8849a35fcff694454da880f", size = 1047020, upload-time = "2025-11-26T02:35:40.95Z" }, - { url = "https://files.pythonhosted.org/packages/b7/79/9b492c4da885a6699bc76032dbc285c565429ca1b6dc6b5aa5c908111d22/fastar-0.8.0-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:8de5decfa18a03807ae26ba5af095c2c04ac31ae915e9a849363a4495463171f", size = 996379, upload-time = "2025-11-26T02:35:59.297Z" }, ] [[package]] @@ -1890,12 +1553,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/a7/1c/6dfd082a205be4510543221b734b1191299e6a1810c452b6bc76dfa6968e/fastavro-1.12.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b6a3462934b20a74f9ece1daa49c2e4e749bd9a35fa2657b53bf62898fba80f5", size = 3433972, upload-time = "2025-10-10T15:42:14.485Z" }, { url = "https://files.pythonhosted.org/packages/24/90/9de694625a1a4b727b1ad0958d220cab25a9b6cf7f16a5c7faa9ea7b2261/fastavro-1.12.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:1f81011d54dd47b12437b51dd93a70a9aa17b61307abf26542fc3c13efbc6c51", size = 3368752, upload-time = "2025-10-10T15:42:16.618Z" }, { url = "https://files.pythonhosted.org/packages/fa/93/b44f67589e4d439913dab6720f7e3507b0fa8b8e56d06f6fc875ced26afb/fastavro-1.12.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:43ded16b3f4a9f1a42f5970c2aa618acb23ea59c4fcaa06680bdf470b255e5a8", size = 3386636, upload-time = "2025-10-10T15:42:18.974Z" }, - { url = "https://files.pythonhosted.org/packages/8f/b8/67f5682cd59cb59ec6eecb5479b132caaf69709d1e1ceda4f92d8c69d7f1/fastavro-1.12.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:02281432dcb11c78b3280da996eff61ee0eff39c5de06c6e0fbf19275093e6d4", size = 1002311, upload-time = "2025-10-10T15:42:20.415Z" }, - { url = "https://files.pythonhosted.org/packages/93/38/2f15a7ad24e4b6e0239016c068f142358732bf8ead0315ee926b88634bec/fastavro-1.12.1-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4128978b930aaf930332db4b3acc290783183f3be06a241ae4a482f3ed8ce892", size = 3195871, upload-time = "2025-10-10T15:42:22.675Z" }, - { url = "https://files.pythonhosted.org/packages/c1/e5/6fc0250b3006b1b42c1ab9f0511ccd44e1aeb15a63a77fc780ee97f58797/fastavro-1.12.1-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:546ffffda6610fca672f0ed41149808e106d8272bb246aa7539fa8bb6f117f17", size = 3204127, upload-time = "2025-10-10T15:42:24.855Z" }, - { url = "https://files.pythonhosted.org/packages/c6/43/1f3909eb096eb1066e416f0875abe783b73fabe823ad616f6956b3e80e84/fastavro-1.12.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:a7d840ccd9aacada3ddc80fbcc4ea079b658107fe62e9d289a0de9d54e95d366", size = 3135604, upload-time = "2025-10-10T15:42:28.899Z" }, - { url = "https://files.pythonhosted.org/packages/e6/61/ec083a3a5d7c2b97d0e2c9e137a6e667583afe884af0e49318f7ee7eaa5a/fastavro-1.12.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:3100ad643e7fa658469a2a2db229981c1a000ff16b8037c0b58ce3ec4d2107e8", size = 3210932, upload-time = "2025-10-10T15:42:30.891Z" }, - { url = "https://files.pythonhosted.org/packages/9e/ba/b814fb09b32c8f3059451c33bb11d55eb23188e6a499f5dde628d13bc076/fastavro-1.12.1-cp39-cp39-win_amd64.whl", hash = "sha256:a38607444281619eda3a9c1be9f5397634012d1b237142eee1540e810b30ac8b", size = 510328, upload-time = "2025-10-10T15:42:32.415Z" }, ] [[package]] @@ -1903,50 +1560,34 @@ name = "fastmcp" version = "2.14.5" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "authlib", marker = "python_full_version >= '3.10'" }, - { name = "cyclopts", marker = "python_full_version >= '3.10'" }, - { name = "exceptiongroup", marker = "python_full_version >= '3.10'" }, - { name = "httpx", marker = "python_full_version >= '3.10'" }, - { name = "jsonref", marker = "python_full_version >= '3.10'" }, - { name = "jsonschema-path", marker = "python_full_version >= '3.10'" }, - { name = "mcp", marker = "python_full_version >= '3.10'" }, - { name = "openapi-pydantic", marker = "python_full_version >= '3.10'" }, - { name = "packaging", marker = "python_full_version >= '3.10'" }, - { name = "platformdirs", version = "4.5.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, - { name = "py-key-value-aio", extra = ["disk", "keyring", "memory"], marker = "python_full_version >= '3.10'" }, - { name = "pydantic", extra = ["email"], marker = "python_full_version >= '3.10'" }, - { name = "pydocket", marker = "python_full_version >= '3.10'" }, - { name = "pyperclip", marker = "python_full_version >= '3.10'" }, - { name = "python-dotenv", marker = "python_full_version >= '3.10'" }, - { name = "rich", marker = "python_full_version >= '3.10'" }, - { name = "uvicorn", version = "0.40.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, - { name = "websockets", marker = "python_full_version >= '3.10'" }, + { name = "authlib" }, + { name = "cyclopts" }, + { name = "exceptiongroup" }, + { name = "httpx" }, + { name = "jsonref" }, + { name = "jsonschema-path" }, + { name = "mcp" }, + { name = "openapi-pydantic" }, + { name = "packaging" }, + { name = "platformdirs" }, + { name = "py-key-value-aio", extra = ["disk", "keyring", "memory"] }, + { name = "pydantic", extra = ["email"] }, + { name = "pydocket" }, + { name = "pyperclip" }, + { name = "python-dotenv" }, + { name = "rich" }, + { name = "uvicorn" }, + { name = "websockets" }, ] sdist = { url = "https://files.pythonhosted.org/packages/3b/32/982678d44f13849530a74ab101ed80e060c2ee6cf87471f062dcf61705fd/fastmcp-2.14.5.tar.gz", hash = "sha256:38944dc582c541d55357082bda2241cedb42cd3a78faea8a9d6a2662c62a42d7", size = 8296329, upload-time = "2026-02-03T15:35:21.005Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/e5/c1/1a35ec68ff76ea8443aa115b18bcdee748a4ada2124537ee90522899ff9f/fastmcp-2.14.5-py3-none-any.whl", hash = "sha256:d81e8ec813f5089d3624bec93944beaefa86c0c3a4ef1111cbef676a761ebccf", size = 417784, upload-time = "2026-02-03T15:35:18.489Z" }, ] -[[package]] -name = "filelock" -version = "3.19.1" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.10'", -] -sdist = { url = "https://files.pythonhosted.org/packages/40/bb/0ab3e58d22305b6f5440629d20683af28959bf793d98d11950e305c1c326/filelock-3.19.1.tar.gz", hash = "sha256:66eda1888b0171c998b35be2bcc0f6d75c388a7ce20c3f3f37aa8e96c2dddf58", size = 17687, upload-time = "2025-08-14T16:56:03.016Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/42/14/42b2651a2f46b022ccd948bca9f2d5af0fd8929c4eec235b8d6d844fbe67/filelock-3.19.1-py3-none-any.whl", hash = "sha256:d38e30481def20772f5baf097c122c3babc4fcdb7e14e57049eb9d88c6dc017d", size = 15988, upload-time = "2025-08-14T16:56:01.633Z" }, -] - [[package]] name = "filelock" version = "3.20.3" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.14'", - "python_full_version >= '3.10' and python_full_version < '3.14'", -] sdist = { url = "https://files.pythonhosted.org/packages/1d/65/ce7f1b70157833bf3cb851b556a37d4547ceafc158aa9b34b36782f23696/filelock-3.20.3.tar.gz", hash = "sha256:18c57ee915c7ec61cff0ecf7f0f869936c7c30191bb0cf406f1341778d0834e1", size = 19485, upload-time = "2026-01-09T17:55:05.421Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/b5/36/7fb70f04bf00bc646cd5bb45aa9eddb15e19437a28b8fb2b4a5249fac770/filelock-3.20.3-py3-none-any.whl", hash = "sha256:4b0dda527ee31078689fc205ec4f1c1bf7d56cf88b6dc9426c4f230e46c2dce1", size = 16701, upload-time = "2026-01-09T17:55:04.334Z" }, @@ -1958,9 +1599,7 @@ version = "3.1.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "blinker" }, - { name = "click", version = "8.1.8", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "click", version = "8.3.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, - { name = "importlib-metadata", marker = "python_full_version < '3.10'" }, + { name = "click" }, { name = "itsdangerous" }, { name = "jinja2" }, { name = "markupsafe" }, @@ -2089,45 +1728,13 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/af/d3/76bd4ed4317e7119c2b7f57c3f6934aba26d277acc6309f873341640e21f/frozenlist-1.8.0-cp314-cp314t-win32.whl", hash = "sha256:342c97bf697ac5480c0a7ec73cd700ecfa5a8a40ac923bd035484616efecc2df", size = 44676, upload-time = "2025-10-06T05:37:52.222Z" }, { url = "https://files.pythonhosted.org/packages/89/76/c615883b7b521ead2944bb3480398cbb07e12b7b4e4d073d3752eb721558/frozenlist-1.8.0-cp314-cp314t-win_amd64.whl", hash = "sha256:06be8f67f39c8b1dc671f5d83aaefd3358ae5cdcf8314552c57e7ed3e6475bdd", size = 49451, upload-time = "2025-10-06T05:37:53.425Z" }, { url = "https://files.pythonhosted.org/packages/e0/a3/5982da14e113d07b325230f95060e2169f5311b1017ea8af2a29b374c289/frozenlist-1.8.0-cp314-cp314t-win_arm64.whl", hash = "sha256:102e6314ca4da683dca92e3b1355490fed5f313b768500084fbe6371fddfdb79", size = 42507, upload-time = "2025-10-06T05:37:54.513Z" }, - { url = "https://files.pythonhosted.org/packages/c2/59/ae5cdac87a00962122ea37bb346d41b66aec05f9ce328fa2b9e216f8967b/frozenlist-1.8.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:d8b7138e5cd0647e4523d6685b0eac5d4be9a184ae9634492f25c6eb38c12a47", size = 86967, upload-time = "2025-10-06T05:37:55.607Z" }, - { url = "https://files.pythonhosted.org/packages/8a/10/17059b2db5a032fd9323c41c39e9d1f5f9d0c8f04d1e4e3e788573086e61/frozenlist-1.8.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a6483e309ca809f1efd154b4d37dc6d9f61037d6c6a81c2dc7a15cb22c8c5dca", size = 49984, upload-time = "2025-10-06T05:37:57.049Z" }, - { url = "https://files.pythonhosted.org/packages/4b/de/ad9d82ca8e5fa8f0c636e64606553c79e2b859ad253030b62a21fe9986f5/frozenlist-1.8.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1b9290cf81e95e93fdf90548ce9d3c1211cf574b8e3f4b3b7cb0537cf2227068", size = 50240, upload-time = "2025-10-06T05:37:58.145Z" }, - { url = "https://files.pythonhosted.org/packages/4e/45/3dfb7767c2a67d123650122b62ce13c731b6c745bc14424eea67678b508c/frozenlist-1.8.0-cp39-cp39-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:59a6a5876ca59d1b63af8cd5e7ffffb024c3dc1e9cf9301b21a2e76286505c95", size = 219472, upload-time = "2025-10-06T05:37:59.239Z" }, - { url = "https://files.pythonhosted.org/packages/0b/bf/5bf23d913a741b960d5c1dac7c1985d8a2a1d015772b2d18ea168b08e7ff/frozenlist-1.8.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6dc4126390929823e2d2d9dc79ab4046ed74680360fc5f38b585c12c66cdf459", size = 221531, upload-time = "2025-10-06T05:38:00.521Z" }, - { url = "https://files.pythonhosted.org/packages/d0/03/27ec393f3b55860859f4b74cdc8c2a4af3dbf3533305e8eacf48a4fd9a54/frozenlist-1.8.0-cp39-cp39-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:332db6b2563333c5671fecacd085141b5800cb866be16d5e3eb15a2086476675", size = 219211, upload-time = "2025-10-06T05:38:01.842Z" }, - { url = "https://files.pythonhosted.org/packages/3a/ad/0fd00c404fa73fe9b169429e9a972d5ed807973c40ab6b3cf9365a33d360/frozenlist-1.8.0-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9ff15928d62a0b80bb875655c39bf517938c7d589554cbd2669be42d97c2cb61", size = 231775, upload-time = "2025-10-06T05:38:03.384Z" }, - { url = "https://files.pythonhosted.org/packages/8a/c3/86962566154cb4d2995358bc8331bfc4ea19d07db1a96f64935a1607f2b6/frozenlist-1.8.0-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:7bf6cdf8e07c8151fba6fe85735441240ec7f619f935a5205953d58009aef8c6", size = 236631, upload-time = "2025-10-06T05:38:04.609Z" }, - { url = "https://files.pythonhosted.org/packages/ea/9e/6ffad161dbd83782d2c66dc4d378a9103b31770cb1e67febf43aea42d202/frozenlist-1.8.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:48e6d3f4ec5c7273dfe83ff27c91083c6c9065af655dc2684d2c200c94308bb5", size = 218632, upload-time = "2025-10-06T05:38:05.917Z" }, - { url = "https://files.pythonhosted.org/packages/58/b2/4677eee46e0a97f9b30735e6ad0bf6aba3e497986066eb68807ac85cf60f/frozenlist-1.8.0-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:1a7607e17ad33361677adcd1443edf6f5da0ce5e5377b798fba20fae194825f3", size = 235967, upload-time = "2025-10-06T05:38:07.614Z" }, - { url = "https://files.pythonhosted.org/packages/05/f3/86e75f8639c5a93745ca7addbbc9de6af56aebb930d233512b17e46f6493/frozenlist-1.8.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:5a3a935c3a4e89c733303a2d5a7c257ea44af3a56c8202df486b7f5de40f37e1", size = 228799, upload-time = "2025-10-06T05:38:08.845Z" }, - { url = "https://files.pythonhosted.org/packages/30/00/39aad3a7f0d98f5eb1d99a3c311215674ed87061aecee7851974b335c050/frozenlist-1.8.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:940d4a017dbfed9daf46a3b086e1d2167e7012ee297fef9e1c545c4d022f5178", size = 230566, upload-time = "2025-10-06T05:38:10.52Z" }, - { url = "https://files.pythonhosted.org/packages/0d/4d/aa144cac44568d137846ddc4d5210fb5d9719eb1d7ec6fa2728a54b5b94a/frozenlist-1.8.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:b9be22a69a014bc47e78072d0ecae716f5eb56c15238acca0f43d6eb8e4a5bda", size = 217715, upload-time = "2025-10-06T05:38:11.832Z" }, - { url = "https://files.pythonhosted.org/packages/64/4c/8f665921667509d25a0dd72540513bc86b356c95541686f6442a3283019f/frozenlist-1.8.0-cp39-cp39-win32.whl", hash = "sha256:1aa77cb5697069af47472e39612976ed05343ff2e84a3dcf15437b232cbfd087", size = 39933, upload-time = "2025-10-06T05:38:13.061Z" }, - { url = "https://files.pythonhosted.org/packages/79/bd/bcc926f87027fad5e59926ff12d136e1082a115025d33c032d1cd69ab377/frozenlist-1.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:7398c222d1d405e796970320036b1b563892b65809d9e5261487bb2c7f7b5c6a", size = 44121, upload-time = "2025-10-06T05:38:14.572Z" }, - { url = "https://files.pythonhosted.org/packages/4c/07/9c2e4eb7584af4b705237b971b89a4155a8e57599c4483a131a39256a9a0/frozenlist-1.8.0-cp39-cp39-win_arm64.whl", hash = "sha256:b4f3b365f31c6cd4af24545ca0a244a53688cad8834e32f56831c4923b50a103", size = 40312, upload-time = "2025-10-06T05:38:15.699Z" }, { url = "https://files.pythonhosted.org/packages/9a/9a/e35b4a917281c0b8419d4207f4334c8e8c5dbf4f3f5f9ada73958d937dcc/frozenlist-1.8.0-py3-none-any.whl", hash = "sha256:0c18a16eab41e82c295618a77502e17b195883241c563b00f0aa5106fc4eaa0d", size = 13409, upload-time = "2025-10-06T05:38:16.721Z" }, ] -[[package]] -name = "fsspec" -version = "2025.10.0" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.10'", -] -sdist = { url = "https://files.pythonhosted.org/packages/24/7f/2747c0d332b9acfa75dc84447a066fdf812b5a6b8d30472b74d309bfe8cb/fsspec-2025.10.0.tar.gz", hash = "sha256:b6789427626f068f9a83ca4e8a3cc050850b6c0f71f99ddb4f542b8266a26a59", size = 309285, upload-time = "2025-10-30T14:58:44.036Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/eb/02/a6b21098b1d5d6249b7c5ab69dde30108a71e4e819d4a9778f1de1d5b70d/fsspec-2025.10.0-py3-none-any.whl", hash = "sha256:7c7712353ae7d875407f97715f0e1ffcc21e33d5b24556cb1e090ae9409ec61d", size = 200966, upload-time = "2025-10-30T14:58:42.53Z" }, -] - [[package]] name = "fsspec" version = "2026.2.0" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.14'", - "python_full_version >= '3.10' and python_full_version < '3.14'", -] sdist = { url = "https://files.pythonhosted.org/packages/51/7c/f60c259dcbf4f0c47cc4ddb8f7720d2dcdc8888c8e5ad84c73ea4531cc5b/fsspec-2026.2.0.tar.gz", hash = "sha256:6544e34b16869f5aacd5b90bdf1a71acb37792ea3ddf6125ee69a22a53fb8bff", size = 313441, upload-time = "2026-02-05T21:50:53.743Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/e6/ab/fb21f4c939bb440104cc2b396d3be1d9b7a9fd3c6c2a53d98c45b3d7c954/fsspec-2026.2.0-py3-none-any.whl", hash = "sha256:98de475b5cb3bd66bedd5c4679e87b4fdfe1a3bf4d707b151b3c07e58c9a2437", size = 202505, upload-time = "2026-02-05T21:50:51.819Z" }, @@ -2138,7 +1745,6 @@ name = "genai-prices" version = "0.0.52" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "eval-type-backport", marker = "python_full_version < '3.10'" }, { name = "httpx" }, { name = "pydantic" }, ] @@ -2177,7 +1783,6 @@ version = "3.1.46" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "gitdb" }, - { name = "typing-extensions", marker = "python_full_version < '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/df/b5/59d16470a1f0dfe8c793f9ef56fd3826093fc52b3bd96d6b9d6c26c7e27b/gitpython-3.1.46.tar.gz", hash = "sha256:400124c7d0ef4ea03f7310ac2fbf7151e09ff97f2a3288d64a440c584a29c37f", size = 215371, upload-time = "2026-01-01T15:37:32.073Z" } wheels = [ @@ -2200,50 +1805,24 @@ wheels = [ [package.optional-dependencies] requests = [ - { name = "requests", marker = "python_full_version >= '3.10'" }, -] - -[[package]] -name = "google-genai" -version = "1.47.0" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.10'", -] -dependencies = [ - { name = "anyio", marker = "python_full_version < '3.10'" }, - { name = "google-auth", marker = "python_full_version < '3.10'" }, - { name = "httpx", marker = "python_full_version < '3.10'" }, - { name = "pydantic", marker = "python_full_version < '3.10'" }, - { name = "requests", marker = "python_full_version < '3.10'" }, - { name = "tenacity", version = "9.1.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "typing-extensions", marker = "python_full_version < '3.10'" }, - { name = "websockets", marker = "python_full_version < '3.10'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/9f/97/784fba9bc6c41263ff90cb9063eadfdd755dde79cfa5a8d0e397b067dcf9/google_genai-1.47.0.tar.gz", hash = "sha256:ecece00d0a04e6739ea76cc8dad82ec9593d9380aaabef078990e60574e5bf59", size = 241471, upload-time = "2025-10-29T22:01:02.88Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/89/ef/e080e8d67c270ea320956bb911a9359664fc46d3b87d1f029decd33e5c4c/google_genai-1.47.0-py3-none-any.whl", hash = "sha256:e3851237556cbdec96007d8028b4b1f2425cdc5c099a8dc36b72a57e42821b60", size = 241506, upload-time = "2025-10-29T22:01:00.982Z" }, + { name = "requests" }, ] [[package]] name = "google-genai" version = "1.62.0" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.14'", - "python_full_version >= '3.10' and python_full_version < '3.14'", -] dependencies = [ - { name = "anyio", marker = "python_full_version >= '3.10'" }, - { name = "distro", marker = "python_full_version >= '3.10'" }, - { name = "google-auth", extra = ["requests"], marker = "python_full_version >= '3.10'" }, - { name = "httpx", marker = "python_full_version >= '3.10'" }, - { name = "pydantic", marker = "python_full_version >= '3.10'" }, - { name = "requests", marker = "python_full_version >= '3.10'" }, - { name = "sniffio", marker = "python_full_version >= '3.10'" }, - { name = "tenacity", version = "9.1.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, - { name = "typing-extensions", marker = "python_full_version >= '3.10'" }, - { name = "websockets", marker = "python_full_version >= '3.10'" }, + { name = "anyio" }, + { name = "distro" }, + { name = "google-auth", extra = ["requests"] }, + { name = "httpx" }, + { name = "pydantic" }, + { name = "requests" }, + { name = "sniffio" }, + { name = "tenacity" }, + { name = "typing-extensions" }, + { name = "websockets" }, ] sdist = { url = "https://files.pythonhosted.org/packages/94/4c/71b32b5c8db420cf2fd0d5ef8a672adbde97d85e5d44a0b4fca712264ef1/google_genai-1.62.0.tar.gz", hash = "sha256:709468a14c739a080bc240a4f3191df597bf64485b1ca3728e0fb67517774c18", size = 490888, upload-time = "2026-02-04T22:48:41.989Z" } wheels = [ @@ -2255,7 +1834,7 @@ name = "googleapis-common-protos" version = "1.72.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "protobuf", version = "6.33.5", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "protobuf" }, ] sdist = { url = "https://files.pythonhosted.org/packages/e5/7b/adfd75544c415c487b33061fe7ae526165241c1ea133f9a9125a56b39fd8/googleapis_common_protos-1.72.0.tar.gz", hash = "sha256:e55a601c1b32b52d7a3e65f43563e2aa61bcd737998ee672ac9b951cd49319f5", size = 147433, upload-time = "2025-11-06T18:29:24.087Z" } wheels = [ @@ -2266,98 +1845,15 @@ wheels = [ name = "graphql-core" version = "3.2.7" source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions", marker = "python_full_version < '3.10'" }, -] sdist = { url = "https://files.pythonhosted.org/packages/ac/9b/037a640a2983b09aed4a823f9cf1729e6d780b0671f854efa4727a7affbe/graphql_core-3.2.7.tar.gz", hash = "sha256:27b6904bdd3b43f2a0556dad5d579bdfdeab1f38e8e8788e555bdcb586a6f62c", size = 513484, upload-time = "2025-11-01T22:30:40.436Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/0a/14/933037032608787fb92e365883ad6a741c235e0ff992865ec5d904a38f1e/graphql_core-3.2.7-py3-none-any.whl", hash = "sha256:17fc8f3ca4a42913d8e24d9ac9f08deddf0a0b2483076575757f6c412ead2ec0", size = 207262, upload-time = "2025-11-01T22:30:38.912Z" }, ] -[[package]] -name = "greenlet" -version = "3.2.4" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.10'", -] -sdist = { url = "https://files.pythonhosted.org/packages/03/b8/704d753a5a45507a7aab61f18db9509302ed3d0a27ac7e0359ec2905b1a6/greenlet-3.2.4.tar.gz", hash = "sha256:0dca0d95ff849f9a364385f36ab49f50065d76964944638be9691e1832e9f86d", size = 188260, upload-time = "2025-08-07T13:24:33.51Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7d/ed/6bfa4109fcb23a58819600392564fea69cdc6551ffd5e69ccf1d52a40cbc/greenlet-3.2.4-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:8c68325b0d0acf8d91dde4e6f930967dd52a5302cd4062932a6b2e7c2969f47c", size = 271061, upload-time = "2025-08-07T13:17:15.373Z" }, - { url = "https://files.pythonhosted.org/packages/2a/fc/102ec1a2fc015b3a7652abab7acf3541d58c04d3d17a8d3d6a44adae1eb1/greenlet-3.2.4-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:94385f101946790ae13da500603491f04a76b6e4c059dab271b3ce2e283b2590", size = 629475, upload-time = "2025-08-07T13:42:54.009Z" }, - { url = "https://files.pythonhosted.org/packages/c5/26/80383131d55a4ac0fb08d71660fd77e7660b9db6bdb4e8884f46d9f2cc04/greenlet-3.2.4-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f10fd42b5ee276335863712fa3da6608e93f70629c631bf77145021600abc23c", size = 640802, upload-time = "2025-08-07T13:45:25.52Z" }, - { url = "https://files.pythonhosted.org/packages/9f/7c/e7833dbcd8f376f3326bd728c845d31dcde4c84268d3921afcae77d90d08/greenlet-3.2.4-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:c8c9e331e58180d0d83c5b7999255721b725913ff6bc6cf39fa2a45841a4fd4b", size = 636703, upload-time = "2025-08-07T13:53:12.622Z" }, - { url = "https://files.pythonhosted.org/packages/e9/49/547b93b7c0428ede7b3f309bc965986874759f7d89e4e04aeddbc9699acb/greenlet-3.2.4-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:58b97143c9cc7b86fc458f215bd0932f1757ce649e05b640fea2e79b54cedb31", size = 635417, upload-time = "2025-08-07T13:18:25.189Z" }, - { url = "https://files.pythonhosted.org/packages/7f/91/ae2eb6b7979e2f9b035a9f612cf70f1bf54aad4e1d125129bef1eae96f19/greenlet-3.2.4-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c2ca18a03a8cfb5b25bc1cbe20f3d9a4c80d8c3b13ba3df49ac3961af0b1018d", size = 584358, upload-time = "2025-08-07T13:18:23.708Z" }, - { url = "https://files.pythonhosted.org/packages/f7/85/433de0c9c0252b22b16d413c9407e6cb3b41df7389afc366ca204dbc1393/greenlet-3.2.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:9fe0a28a7b952a21e2c062cd5756d34354117796c6d9215a87f55e38d15402c5", size = 1113550, upload-time = "2025-08-07T13:42:37.467Z" }, - { url = "https://files.pythonhosted.org/packages/a1/8d/88f3ebd2bc96bf7747093696f4335a0a8a4c5acfcf1b757717c0d2474ba3/greenlet-3.2.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8854167e06950ca75b898b104b63cc646573aa5fef1353d4508ecdd1ee76254f", size = 1137126, upload-time = "2025-08-07T13:18:20.239Z" }, - { url = "https://files.pythonhosted.org/packages/f1/29/74242b7d72385e29bcc5563fba67dad94943d7cd03552bac320d597f29b2/greenlet-3.2.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f47617f698838ba98f4ff4189aef02e7343952df3a615f847bb575c3feb177a7", size = 1544904, upload-time = "2025-11-04T12:42:04.763Z" }, - { url = "https://files.pythonhosted.org/packages/c8/e2/1572b8eeab0f77df5f6729d6ab6b141e4a84ee8eb9bc8c1e7918f94eda6d/greenlet-3.2.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:af41be48a4f60429d5cad9d22175217805098a9ef7c40bfef44f7669fb9d74d8", size = 1611228, upload-time = "2025-11-04T12:42:08.423Z" }, - { url = "https://files.pythonhosted.org/packages/d6/6f/b60b0291d9623c496638c582297ead61f43c4b72eef5e9c926ef4565ec13/greenlet-3.2.4-cp310-cp310-win_amd64.whl", hash = "sha256:73f49b5368b5359d04e18d15828eecc1806033db5233397748f4ca813ff1056c", size = 298654, upload-time = "2025-08-07T13:50:00.469Z" }, - { url = "https://files.pythonhosted.org/packages/a4/de/f28ced0a67749cac23fecb02b694f6473f47686dff6afaa211d186e2ef9c/greenlet-3.2.4-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:96378df1de302bc38e99c3a9aa311967b7dc80ced1dcc6f171e99842987882a2", size = 272305, upload-time = "2025-08-07T13:15:41.288Z" }, - { url = "https://files.pythonhosted.org/packages/09/16/2c3792cba130000bf2a31c5272999113f4764fd9d874fb257ff588ac779a/greenlet-3.2.4-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:1ee8fae0519a337f2329cb78bd7a8e128ec0f881073d43f023c7b8d4831d5246", size = 632472, upload-time = "2025-08-07T13:42:55.044Z" }, - { url = "https://files.pythonhosted.org/packages/ae/8f/95d48d7e3d433e6dae5b1682e4292242a53f22df82e6d3dda81b1701a960/greenlet-3.2.4-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:94abf90142c2a18151632371140b3dba4dee031633fe614cb592dbb6c9e17bc3", size = 644646, upload-time = "2025-08-07T13:45:26.523Z" }, - { url = "https://files.pythonhosted.org/packages/d5/5e/405965351aef8c76b8ef7ad370e5da58d57ef6068df197548b015464001a/greenlet-3.2.4-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:4d1378601b85e2e5171b99be8d2dc85f594c79967599328f95c1dc1a40f1c633", size = 640519, upload-time = "2025-08-07T13:53:13.928Z" }, - { url = "https://files.pythonhosted.org/packages/25/5d/382753b52006ce0218297ec1b628e048c4e64b155379331f25a7316eb749/greenlet-3.2.4-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0db5594dce18db94f7d1650d7489909b57afde4c580806b8d9203b6e79cdc079", size = 639707, upload-time = "2025-08-07T13:18:27.146Z" }, - { url = "https://files.pythonhosted.org/packages/1f/8e/abdd3f14d735b2929290a018ecf133c901be4874b858dd1c604b9319f064/greenlet-3.2.4-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2523e5246274f54fdadbce8494458a2ebdcdbc7b802318466ac5606d3cded1f8", size = 587684, upload-time = "2025-08-07T13:18:25.164Z" }, - { url = "https://files.pythonhosted.org/packages/5d/65/deb2a69c3e5996439b0176f6651e0052542bb6c8f8ec2e3fba97c9768805/greenlet-3.2.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:1987de92fec508535687fb807a5cea1560f6196285a4cde35c100b8cd632cc52", size = 1116647, upload-time = "2025-08-07T13:42:38.655Z" }, - { url = "https://files.pythonhosted.org/packages/3f/cc/b07000438a29ac5cfb2194bfc128151d52f333cee74dd7dfe3fb733fc16c/greenlet-3.2.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:55e9c5affaa6775e2c6b67659f3a71684de4c549b3dd9afca3bc773533d284fa", size = 1142073, upload-time = "2025-08-07T13:18:21.737Z" }, - { url = "https://files.pythonhosted.org/packages/67/24/28a5b2fa42d12b3d7e5614145f0bd89714c34c08be6aabe39c14dd52db34/greenlet-3.2.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c9c6de1940a7d828635fbd254d69db79e54619f165ee7ce32fda763a9cb6a58c", size = 1548385, upload-time = "2025-11-04T12:42:11.067Z" }, - { url = "https://files.pythonhosted.org/packages/6a/05/03f2f0bdd0b0ff9a4f7b99333d57b53a7709c27723ec8123056b084e69cd/greenlet-3.2.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:03c5136e7be905045160b1b9fdca93dd6727b180feeafda6818e6496434ed8c5", size = 1613329, upload-time = "2025-11-04T12:42:12.928Z" }, - { url = "https://files.pythonhosted.org/packages/d8/0f/30aef242fcab550b0b3520b8e3561156857c94288f0332a79928c31a52cf/greenlet-3.2.4-cp311-cp311-win_amd64.whl", hash = "sha256:9c40adce87eaa9ddb593ccb0fa6a07caf34015a29bf8d344811665b573138db9", size = 299100, upload-time = "2025-08-07T13:44:12.287Z" }, - { url = "https://files.pythonhosted.org/packages/44/69/9b804adb5fd0671f367781560eb5eb586c4d495277c93bde4307b9e28068/greenlet-3.2.4-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:3b67ca49f54cede0186854a008109d6ee71f66bd57bb36abd6d0a0267b540cdd", size = 274079, upload-time = "2025-08-07T13:15:45.033Z" }, - { url = "https://files.pythonhosted.org/packages/46/e9/d2a80c99f19a153eff70bc451ab78615583b8dac0754cfb942223d2c1a0d/greenlet-3.2.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ddf9164e7a5b08e9d22511526865780a576f19ddd00d62f8a665949327fde8bb", size = 640997, upload-time = "2025-08-07T13:42:56.234Z" }, - { url = "https://files.pythonhosted.org/packages/3b/16/035dcfcc48715ccd345f3a93183267167cdd162ad123cd93067d86f27ce4/greenlet-3.2.4-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f28588772bb5fb869a8eb331374ec06f24a83a9c25bfa1f38b6993afe9c1e968", size = 655185, upload-time = "2025-08-07T13:45:27.624Z" }, - { url = "https://files.pythonhosted.org/packages/31/da/0386695eef69ffae1ad726881571dfe28b41970173947e7c558d9998de0f/greenlet-3.2.4-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:5c9320971821a7cb77cfab8d956fa8e39cd07ca44b6070db358ceb7f8797c8c9", size = 649926, upload-time = "2025-08-07T13:53:15.251Z" }, - { url = "https://files.pythonhosted.org/packages/68/88/69bf19fd4dc19981928ceacbc5fd4bb6bc2215d53199e367832e98d1d8fe/greenlet-3.2.4-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c60a6d84229b271d44b70fb6e5fa23781abb5d742af7b808ae3f6efd7c9c60f6", size = 651839, upload-time = "2025-08-07T13:18:30.281Z" }, - { url = "https://files.pythonhosted.org/packages/19/0d/6660d55f7373b2ff8152401a83e02084956da23ae58cddbfb0b330978fe9/greenlet-3.2.4-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3b3812d8d0c9579967815af437d96623f45c0f2ae5f04e366de62a12d83a8fb0", size = 607586, upload-time = "2025-08-07T13:18:28.544Z" }, - { url = "https://files.pythonhosted.org/packages/8e/1a/c953fdedd22d81ee4629afbb38d2f9d71e37d23caace44775a3a969147d4/greenlet-3.2.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:abbf57b5a870d30c4675928c37278493044d7c14378350b3aa5d484fa65575f0", size = 1123281, upload-time = "2025-08-07T13:42:39.858Z" }, - { url = "https://files.pythonhosted.org/packages/3f/c7/12381b18e21aef2c6bd3a636da1088b888b97b7a0362fac2e4de92405f97/greenlet-3.2.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:20fb936b4652b6e307b8f347665e2c615540d4b42b3b4c8a321d8286da7e520f", size = 1151142, upload-time = "2025-08-07T13:18:22.981Z" }, - { url = "https://files.pythonhosted.org/packages/27/45/80935968b53cfd3f33cf99ea5f08227f2646e044568c9b1555b58ffd61c2/greenlet-3.2.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ee7a6ec486883397d70eec05059353b8e83eca9168b9f3f9a361971e77e0bcd0", size = 1564846, upload-time = "2025-11-04T12:42:15.191Z" }, - { url = "https://files.pythonhosted.org/packages/69/02/b7c30e5e04752cb4db6202a3858b149c0710e5453b71a3b2aec5d78a1aab/greenlet-3.2.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:326d234cbf337c9c3def0676412eb7040a35a768efc92504b947b3e9cfc7543d", size = 1633814, upload-time = "2025-11-04T12:42:17.175Z" }, - { url = "https://files.pythonhosted.org/packages/e9/08/b0814846b79399e585f974bbeebf5580fbe59e258ea7be64d9dfb253c84f/greenlet-3.2.4-cp312-cp312-win_amd64.whl", hash = "sha256:a7d4e128405eea3814a12cc2605e0e6aedb4035bf32697f72deca74de4105e02", size = 299899, upload-time = "2025-08-07T13:38:53.448Z" }, - { url = "https://files.pythonhosted.org/packages/49/e8/58c7f85958bda41dafea50497cbd59738c5c43dbbea5ee83d651234398f4/greenlet-3.2.4-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:1a921e542453fe531144e91e1feedf12e07351b1cf6c9e8a3325ea600a715a31", size = 272814, upload-time = "2025-08-07T13:15:50.011Z" }, - { url = "https://files.pythonhosted.org/packages/62/dd/b9f59862e9e257a16e4e610480cfffd29e3fae018a68c2332090b53aac3d/greenlet-3.2.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:cd3c8e693bff0fff6ba55f140bf390fa92c994083f838fece0f63be121334945", size = 641073, upload-time = "2025-08-07T13:42:57.23Z" }, - { url = "https://files.pythonhosted.org/packages/f7/0b/bc13f787394920b23073ca3b6c4a7a21396301ed75a655bcb47196b50e6e/greenlet-3.2.4-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:710638eb93b1fa52823aa91bf75326f9ecdfd5e0466f00789246a5280f4ba0fc", size = 655191, upload-time = "2025-08-07T13:45:29.752Z" }, - { url = "https://files.pythonhosted.org/packages/f2/d6/6adde57d1345a8d0f14d31e4ab9c23cfe8e2cd39c3baf7674b4b0338d266/greenlet-3.2.4-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:c5111ccdc9c88f423426df3fd1811bfc40ed66264d35aa373420a34377efc98a", size = 649516, upload-time = "2025-08-07T13:53:16.314Z" }, - { url = "https://files.pythonhosted.org/packages/7f/3b/3a3328a788d4a473889a2d403199932be55b1b0060f4ddd96ee7cdfcad10/greenlet-3.2.4-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d76383238584e9711e20ebe14db6c88ddcedc1829a9ad31a584389463b5aa504", size = 652169, upload-time = "2025-08-07T13:18:32.861Z" }, - { url = "https://files.pythonhosted.org/packages/ee/43/3cecdc0349359e1a527cbf2e3e28e5f8f06d3343aaf82ca13437a9aa290f/greenlet-3.2.4-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:23768528f2911bcd7e475210822ffb5254ed10d71f4028387e5a99b4c6699671", size = 610497, upload-time = "2025-08-07T13:18:31.636Z" }, - { url = "https://files.pythonhosted.org/packages/b8/19/06b6cf5d604e2c382a6f31cafafd6f33d5dea706f4db7bdab184bad2b21d/greenlet-3.2.4-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:00fadb3fedccc447f517ee0d3fd8fe49eae949e1cd0f6a611818f4f6fb7dc83b", size = 1121662, upload-time = "2025-08-07T13:42:41.117Z" }, - { url = "https://files.pythonhosted.org/packages/a2/15/0d5e4e1a66fab130d98168fe984c509249c833c1a3c16806b90f253ce7b9/greenlet-3.2.4-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:d25c5091190f2dc0eaa3f950252122edbbadbb682aa7b1ef2f8af0f8c0afefae", size = 1149210, upload-time = "2025-08-07T13:18:24.072Z" }, - { url = "https://files.pythonhosted.org/packages/1c/53/f9c440463b3057485b8594d7a638bed53ba531165ef0ca0e6c364b5cc807/greenlet-3.2.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:6e343822feb58ac4d0a1211bd9399de2b3a04963ddeec21530fc426cc121f19b", size = 1564759, upload-time = "2025-11-04T12:42:19.395Z" }, - { url = "https://files.pythonhosted.org/packages/47/e4/3bb4240abdd0a8d23f4f88adec746a3099f0d86bfedb623f063b2e3b4df0/greenlet-3.2.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ca7f6f1f2649b89ce02f6f229d7c19f680a6238af656f61e0115b24857917929", size = 1634288, upload-time = "2025-11-04T12:42:21.174Z" }, - { url = "https://files.pythonhosted.org/packages/0b/55/2321e43595e6801e105fcfdee02b34c0f996eb71e6ddffca6b10b7e1d771/greenlet-3.2.4-cp313-cp313-win_amd64.whl", hash = "sha256:554b03b6e73aaabec3745364d6239e9e012d64c68ccd0b8430c64ccc14939a8b", size = 299685, upload-time = "2025-08-07T13:24:38.824Z" }, - { url = "https://files.pythonhosted.org/packages/22/5c/85273fd7cc388285632b0498dbbab97596e04b154933dfe0f3e68156c68c/greenlet-3.2.4-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:49a30d5fda2507ae77be16479bdb62a660fa51b1eb4928b524975b3bde77b3c0", size = 273586, upload-time = "2025-08-07T13:16:08.004Z" }, - { url = "https://files.pythonhosted.org/packages/d1/75/10aeeaa3da9332c2e761e4c50d4c3556c21113ee3f0afa2cf5769946f7a3/greenlet-3.2.4-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:299fd615cd8fc86267b47597123e3f43ad79c9d8a22bebdce535e53550763e2f", size = 686346, upload-time = "2025-08-07T13:42:59.944Z" }, - { url = "https://files.pythonhosted.org/packages/c0/aa/687d6b12ffb505a4447567d1f3abea23bd20e73a5bed63871178e0831b7a/greenlet-3.2.4-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:c17b6b34111ea72fc5a4e4beec9711d2226285f0386ea83477cbb97c30a3f3a5", size = 699218, upload-time = "2025-08-07T13:45:30.969Z" }, - { url = "https://files.pythonhosted.org/packages/dc/8b/29aae55436521f1d6f8ff4e12fb676f3400de7fcf27fccd1d4d17fd8fecd/greenlet-3.2.4-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b4a1870c51720687af7fa3e7cda6d08d801dae660f75a76f3845b642b4da6ee1", size = 694659, upload-time = "2025-08-07T13:53:17.759Z" }, - { url = "https://files.pythonhosted.org/packages/92/2e/ea25914b1ebfde93b6fc4ff46d6864564fba59024e928bdc7de475affc25/greenlet-3.2.4-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:061dc4cf2c34852b052a8620d40f36324554bc192be474b9e9770e8c042fd735", size = 695355, upload-time = "2025-08-07T13:18:34.517Z" }, - { url = "https://files.pythonhosted.org/packages/72/60/fc56c62046ec17f6b0d3060564562c64c862948c9d4bc8aa807cf5bd74f4/greenlet-3.2.4-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:44358b9bf66c8576a9f57a590d5f5d6e72fa4228b763d0e43fee6d3b06d3a337", size = 657512, upload-time = "2025-08-07T13:18:33.969Z" }, - { url = "https://files.pythonhosted.org/packages/23/6e/74407aed965a4ab6ddd93a7ded3180b730d281c77b765788419484cdfeef/greenlet-3.2.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:2917bdf657f5859fbf3386b12d68ede4cf1f04c90c3a6bc1f013dd68a22e2269", size = 1612508, upload-time = "2025-11-04T12:42:23.427Z" }, - { url = "https://files.pythonhosted.org/packages/0d/da/343cd760ab2f92bac1845ca07ee3faea9fe52bee65f7bcb19f16ad7de08b/greenlet-3.2.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:015d48959d4add5d6c9f6c5210ee3803a830dce46356e3bc326d6776bde54681", size = 1680760, upload-time = "2025-11-04T12:42:25.341Z" }, - { url = "https://files.pythonhosted.org/packages/e3/a5/6ddab2b4c112be95601c13428db1d8b6608a8b6039816f2ba09c346c08fc/greenlet-3.2.4-cp314-cp314-win_amd64.whl", hash = "sha256:e37ab26028f12dbb0ff65f29a8d3d44a765c61e729647bf2ddfbbed621726f01", size = 303425, upload-time = "2025-08-07T13:32:27.59Z" }, - { url = "https://files.pythonhosted.org/packages/f7/c0/93885c4106d2626bf51fdec377d6aef740dfa5c4877461889a7cf8e565cc/greenlet-3.2.4-cp39-cp39-macosx_11_0_universal2.whl", hash = "sha256:b6a7c19cf0d2742d0809a4c05975db036fdff50cd294a93632d6a310bf9ac02c", size = 269859, upload-time = "2025-08-07T13:16:16.003Z" }, - { url = "https://files.pythonhosted.org/packages/4d/f5/33f05dc3ba10a02dedb1485870cf81c109227d3d3aa280f0e48486cac248/greenlet-3.2.4-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:27890167f55d2387576d1f41d9487ef171849ea0359ce1510ca6e06c8bece11d", size = 627610, upload-time = "2025-08-07T13:43:01.345Z" }, - { url = "https://files.pythonhosted.org/packages/b2/a7/9476decef51a0844195f99ed5dc611d212e9b3515512ecdf7321543a7225/greenlet-3.2.4-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:18d9260df2b5fbf41ae5139e1be4e796d99655f023a636cd0e11e6406cca7d58", size = 639417, upload-time = "2025-08-07T13:45:32.094Z" }, - { url = "https://files.pythonhosted.org/packages/bd/e0/849b9159cbb176f8c0af5caaff1faffdece7a8417fcc6fe1869770e33e21/greenlet-3.2.4-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:671df96c1f23c4a0d4077a325483c1503c96a1b7d9db26592ae770daa41233d4", size = 634751, upload-time = "2025-08-07T13:53:18.848Z" }, - { url = "https://files.pythonhosted.org/packages/5f/d3/844e714a9bbd39034144dca8b658dcd01839b72bb0ec7d8014e33e3705f0/greenlet-3.2.4-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:16458c245a38991aa19676900d48bd1a6f2ce3e16595051a4db9d012154e8433", size = 634020, upload-time = "2025-08-07T13:18:36.841Z" }, - { url = "https://files.pythonhosted.org/packages/6b/4c/f3de2a8de0e840ecb0253ad0dc7e2bb3747348e798ec7e397d783a3cb380/greenlet-3.2.4-cp39-cp39-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c9913f1a30e4526f432991f89ae263459b1c64d1608c0d22a5c79c287b3c70df", size = 582817, upload-time = "2025-08-07T13:18:35.48Z" }, - { url = "https://files.pythonhosted.org/packages/89/80/7332915adc766035c8980b161c2e5d50b2f941f453af232c164cff5e0aeb/greenlet-3.2.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b90654e092f928f110e0007f572007c9727b5265f7632c2fa7415b4689351594", size = 1111985, upload-time = "2025-08-07T13:42:42.425Z" }, - { url = "https://files.pythonhosted.org/packages/66/71/1928e2c80197353bcb9b50aa19c4d8e26ee6d7a900c564907665cf4b9a41/greenlet-3.2.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:81701fd84f26330f0d5f4944d4e92e61afe6319dcd9775e39396e39d7c3e5f98", size = 1136137, upload-time = "2025-08-07T13:18:26.168Z" }, - { url = "https://files.pythonhosted.org/packages/4b/bf/7bd33643e48ed45dcc0e22572f650767832bd4e1287f97434943cc402148/greenlet-3.2.4-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:28a3c6b7cd72a96f61b0e4b2a36f681025b60ae4779cc73c1535eb5f29560b10", size = 1542941, upload-time = "2025-11-04T12:42:27.427Z" }, - { url = "https://files.pythonhosted.org/packages/9b/74/4bc433f91d0d09a1c22954a371f9df928cb85e72640870158853a83415e5/greenlet-3.2.4-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:52206cd642670b0b320a1fd1cbfd95bca0e043179c1d8a045f2c6109dfe973be", size = 1609685, upload-time = "2025-11-04T12:42:29.242Z" }, - { url = "https://files.pythonhosted.org/packages/89/48/a5dc74dde38aeb2b15d418cec76ed50e1dd3d620ccda84d8199703248968/greenlet-3.2.4-cp39-cp39-win32.whl", hash = "sha256:65458b409c1ed459ea899e939f0e1cdb14f58dbc803f2f93c5eab5694d32671b", size = 281400, upload-time = "2025-08-07T14:02:20.263Z" }, - { url = "https://files.pythonhosted.org/packages/e5/44/342c4591db50db1076b8bda86ed0ad59240e3e1da17806a4cf10a6d0e447/greenlet-3.2.4-cp39-cp39-win_amd64.whl", hash = "sha256:d2e685ade4dafd447ede19c31277a224a239a0a1a4eca4e6390efedf20260cfb", size = 298533, upload-time = "2025-08-07T13:56:34.168Z" }, -] - [[package]] name = "greenlet" version = "3.3.1" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.14'", - "python_full_version >= '3.10' and python_full_version < '3.14'", -] sdist = { url = "https://files.pythonhosted.org/packages/8a/99/1cd3411c56a410994669062bd73dd58270c00cc074cac15f385a1fd91f8a/greenlet-3.3.1.tar.gz", hash = "sha256:41848f3230b58c08bb43dee542e74a2a2e34d3c59dc3076cec9151aeeedcae98", size = 184690, upload-time = "2026-01-23T15:31:02.076Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/fe/65/5b235b40581ad75ab97dcd8b4218022ae8e3ab77c13c919f1a1dfe9171fd/greenlet-3.3.1-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:04bee4775f40ecefcdaa9d115ab44736cd4b9c5fba733575bfe9379419582e13", size = 273723, upload-time = "2026-01-23T15:30:37.521Z" }, @@ -2414,31 +1910,12 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e1/2b/98c7f93e6db9977aaee07eb1e51ca63bd5f779b900d362791d3252e60558/greenlet-3.3.1-cp314-cp314t-win_amd64.whl", hash = "sha256:301860987846c24cb8964bdec0e31a96ad4a2a801b41b4ef40963c1b44f33451", size = 233181, upload-time = "2026-01-23T15:33:00.29Z" }, ] -[[package]] -name = "griffe" -version = "1.14.0" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.10'", -] -dependencies = [ - { name = "colorama", marker = "python_full_version < '3.10'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/ec/d7/6c09dd7ce4c7837e4cdb11dce980cb45ae3cd87677298dc3b781b6bce7d3/griffe-1.14.0.tar.gz", hash = "sha256:9d2a15c1eca966d68e00517de5d69dd1bc5c9f2335ef6c1775362ba5b8651a13", size = 424684, upload-time = "2025-09-05T15:02:29.167Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2a/b1/9ff6578d789a89812ff21e4e0f80ffae20a65d5dd84e7a17873fe3b365be/griffe-1.14.0-py3-none-any.whl", hash = "sha256:0e9d52832cccf0f7188cfe585ba962d2674b241c01916d780925df34873bceb0", size = 144439, upload-time = "2025-09-05T15:02:27.511Z" }, -] - [[package]] name = "griffe" version = "1.15.0" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.14'", - "python_full_version >= '3.10' and python_full_version < '3.14'", -] dependencies = [ - { name = "colorama", marker = "python_full_version >= '3.10'" }, + { name = "colorama" }, ] sdist = { url = "https://files.pythonhosted.org/packages/0d/0c/3a471b6e31951dce2360477420d0a8d1e00dea6cf33b70f3e8c3ab6e28e1/griffe-1.15.0.tar.gz", hash = "sha256:7726e3afd6f298fbc3696e67958803e7ac843c1cfe59734b6251a40cdbfb5eea", size = 424112, upload-time = "2025-11-10T15:03:15.52Z" } wheels = [ @@ -2450,8 +1927,7 @@ name = "griffe-typingdoc" version = "0.3.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "griffe", version = "1.14.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "griffe", version = "1.15.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "griffe" }, { name = "typing-extensions" }, ] sdist = { url = "https://files.pythonhosted.org/packages/be/77/d5e5fa0a8391bc2890ae45255847197299739833108dd76ee3c9b2ff0bba/griffe_typingdoc-0.3.0.tar.gz", hash = "sha256:59d9ef98d02caa7aed88d8df1119c9e48c02ed049ea50ce4018ace9331d20f8b", size = 33169, upload-time = "2025-10-23T12:01:39.037Z" } @@ -2464,8 +1940,7 @@ name = "griffe-warnings-deprecated" version = "1.1.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "griffe", version = "1.14.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "griffe", version = "1.15.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "griffe" }, ] sdist = { url = "https://files.pythonhosted.org/packages/7e/0e/f034e1714eb2c694d6196c75f77a02f9c69d19f9961c4804a016397bf3e5/griffe_warnings_deprecated-1.1.0.tar.gz", hash = "sha256:7bf21de327d59c66c7ce08d0166aa4292ce0577ff113de5878f428d102b6f7c5", size = 33260, upload-time = "2024-12-10T21:02:18.395Z" } wheels = [ @@ -2494,7 +1969,7 @@ name = "grpcio" version = "1.78.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "typing-extensions", marker = "python_full_version >= '3.10'" }, + { name = "typing-extensions" }, ] sdist = { url = "https://files.pythonhosted.org/packages/06/8a/3d098f35c143a89520e568e6539cc098fcd294495910e359889ce8741c84/grpcio-1.78.0.tar.gz", hash = "sha256:7382b95189546f375c174f53a5fa873cef91c4b8005faa05cc5b3beea9c4f1c5", size = 12852416, upload-time = "2026-02-06T09:57:18.093Z" } wheels = [ @@ -2548,16 +2023,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/3c/05/33a7a4985586f27e1de4803887c417ec7ced145ebd069bc38a9607059e2b/grpcio-1.78.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:207db540302c884b8848036b80db352a832b99dfdf41db1eb554c2c2c7800f65", size = 7696837, upload-time = "2026-02-06T09:56:40.173Z" }, { url = "https://files.pythonhosted.org/packages/73/77/7382241caf88729b106e49e7d18e3116216c778e6a7e833826eb96de22f7/grpcio-1.78.0-cp314-cp314-win32.whl", hash = "sha256:57bab6deef2f4f1ca76cc04565df38dc5713ae6c17de690721bdf30cb1e0545c", size = 4142439, upload-time = "2026-02-06T09:56:43.258Z" }, { url = "https://files.pythonhosted.org/packages/48/b2/b096ccce418882fbfda4f7496f9357aaa9a5af1896a9a7f60d9f2b275a06/grpcio-1.78.0-cp314-cp314-win_amd64.whl", hash = "sha256:dce09d6116df20a96acfdbf85e4866258c3758180e8c49845d6ba8248b6d0bbb", size = 4929852, upload-time = "2026-02-06T09:56:45.885Z" }, - { url = "https://files.pythonhosted.org/packages/58/6c/40a4bba2c753ea8eeb8d776a31e9c54f4e506edf36db93a3db5456725294/grpcio-1.78.0-cp39-cp39-linux_armv7l.whl", hash = "sha256:86f85dd7c947baa707078a236288a289044836d4b640962018ceb9cd1f899af5", size = 5947902, upload-time = "2026-02-06T09:56:48.469Z" }, - { url = "https://files.pythonhosted.org/packages/c0/4c/ed7664a37a7008be41204c77e0d88bbc4ac531bcf0c27668cd066f9ff6e2/grpcio-1.78.0-cp39-cp39-macosx_11_0_universal2.whl", hash = "sha256:de8cb00d1483a412a06394b8303feec5dcb3b55f81d83aa216dbb6a0b86a94f5", size = 11824772, upload-time = "2026-02-06T09:56:51.264Z" }, - { url = "https://files.pythonhosted.org/packages/9a/5b/45a5c23ba3c4a0f51352366d9b25369a2a51163ab1c93482cb8408726617/grpcio-1.78.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:e888474dee2f59ff68130f8a397792d8cb8e17e6b3434339657ba4ee90845a8c", size = 6521579, upload-time = "2026-02-06T09:56:54.967Z" }, - { url = "https://files.pythonhosted.org/packages/9a/e3/392e647d918004231e3d1c780ed125c48939bfc8f845adb8b5820410da3e/grpcio-1.78.0-cp39-cp39-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:86ce2371bfd7f212cf60d8517e5e854475c2c43ce14aa910e136ace72c6db6c1", size = 7199330, upload-time = "2026-02-06T09:56:57.611Z" }, - { url = "https://files.pythonhosted.org/packages/68/2f/42a52d78bdbdb3f1310ed690a3511cd004740281ca75d300b7bd6d9d3de3/grpcio-1.78.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:b0c689c02947d636bc7fab3e30cc3a3445cca99c834dfb77cd4a6cabfc1c5597", size = 6726696, upload-time = "2026-02-06T09:57:00.357Z" }, - { url = "https://files.pythonhosted.org/packages/0f/83/b3d932a4fbb2dce3056f6df2926fc2d3ddc5d5acbafbec32c84033cf3f23/grpcio-1.78.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:ce7599575eeb25c0f4dc1be59cada6219f3b56176f799627f44088b21381a28a", size = 7299076, upload-time = "2026-02-06T09:57:04.124Z" }, - { url = "https://files.pythonhosted.org/packages/ba/d9/70ea1be55efaf91fd19f7258b1292772a8226cf1b0e237717fba671073cb/grpcio-1.78.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:684083fd383e9dc04c794adb838d4faea08b291ce81f64ecd08e4577c7398adf", size = 8284493, upload-time = "2026-02-06T09:57:06.746Z" }, - { url = "https://files.pythonhosted.org/packages/d0/2f/3dddccf49e3e75564655b84175fca092d3efd81d2979fc89c4b1c1d879dc/grpcio-1.78.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:ab399ef5e3cd2a721b1038a0f3021001f19c5ab279f145e1146bb0b9f1b2b12c", size = 7724340, upload-time = "2026-02-06T09:57:09.453Z" }, - { url = "https://files.pythonhosted.org/packages/79/ae/dfdb3183141db787a9363078a98764675996a7c2448883153091fd7c8527/grpcio-1.78.0-cp39-cp39-win32.whl", hash = "sha256:f3d6379493e18ad4d39537a82371c5281e153e963cecb13f953ebac155756525", size = 4077641, upload-time = "2026-02-06T09:57:11.881Z" }, - { url = "https://files.pythonhosted.org/packages/aa/aa/694b2f505345cfdd234cffb2525aa379a81695e6c02fd40d7e9193e871c6/grpcio-1.78.0-cp39-cp39-win_amd64.whl", hash = "sha256:5361a0630a7fdb58a6a97638ab70e1dae2893c4d08d7aba64ded28bb9e7a29df", size = 4799428, upload-time = "2026-02-06T09:57:14.493Z" }, ] [[package]] @@ -2661,13 +2126,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/4d/31/14df99e1c43bd132eec921c2e7e11cda7852f65619bc0fc5bdc2d0cb126c/httptools-0.7.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:f084813239e1eb403ddacd06a30de3d3e09a9b76e7894dcda2b22f8a726e9c60", size = 452631, upload-time = "2025-10-10T03:54:58.219Z" }, { url = "https://files.pythonhosted.org/packages/22/d2/b7e131f7be8d854d48cb6d048113c30f9a46dca0c9a8b08fcb3fcd588cdc/httptools-0.7.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:7347714368fb2b335e9063bc2b96f2f87a9ceffcd9758ac295f8bbcd3ffbc0ca", size = 452910, upload-time = "2025-10-10T03:54:59.366Z" }, { url = "https://files.pythonhosted.org/packages/53/cf/878f3b91e4e6e011eff6d1fa9ca39f7eb17d19c9d7971b04873734112f30/httptools-0.7.1-cp314-cp314-win_amd64.whl", hash = "sha256:cfabda2a5bb85aa2a904ce06d974a3f30fb36cc63d7feaddec05d2050acede96", size = 88205, upload-time = "2025-10-10T03:55:00.389Z" }, - { url = "https://files.pythonhosted.org/packages/90/de/b1fe0e8890f0292c266117d4cd268186758a9c34e576fbd573fdf3beacff/httptools-0.7.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:ac50afa68945df63ec7a2707c506bd02239272288add34539a2ef527254626a4", size = 206454, upload-time = "2025-10-10T03:55:01.528Z" }, - { url = "https://files.pythonhosted.org/packages/57/a7/a675c90b49e550c7635ce209c01bc61daa5b08aef17da27ef4e0e78fcf3f/httptools-0.7.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:de987bb4e7ac95b99b805b99e0aae0ad51ae61df4263459d36e07cf4052d8b3a", size = 110260, upload-time = "2025-10-10T03:55:02.418Z" }, - { url = "https://files.pythonhosted.org/packages/03/44/fb5ef8136e6e97f7b020e97e40c03a999f97e68574d4998fa52b0a62b01b/httptools-0.7.1-cp39-cp39-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:d169162803a24425eb5e4d51d79cbf429fd7a491b9e570a55f495ea55b26f0bf", size = 441524, upload-time = "2025-10-10T03:55:03.292Z" }, - { url = "https://files.pythonhosted.org/packages/b4/62/8496a5425341867796d7e2419695f74a74607054e227bbaeabec8323e87f/httptools-0.7.1-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:49794f9250188a57fa73c706b46cb21a313edb00d337ca4ce1a011fe3c760b28", size = 440877, upload-time = "2025-10-10T03:55:04.282Z" }, - { url = "https://files.pythonhosted.org/packages/e8/f1/26c2e5214106bf6ed04d03e518ff28ca0c6b5390c5da7b12bbf94b40ae43/httptools-0.7.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:aeefa0648362bb97a7d6b5ff770bfb774930a327d7f65f8208394856862de517", size = 425775, upload-time = "2025-10-10T03:55:05.341Z" }, - { url = "https://files.pythonhosted.org/packages/3a/34/7500a19257139725281f7939a7d1aa3701cf1ac4601a1690f9ab6f510e15/httptools-0.7.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:0d92b10dbf0b3da4823cde6a96d18e6ae358a9daa741c71448975f6a2c339cad", size = 425001, upload-time = "2025-10-10T03:55:06.389Z" }, - { url = "https://files.pythonhosted.org/packages/71/04/31a7949d645ebf33a67f56a0024109444a52a271735e0647a210264f3e61/httptools-0.7.1-cp39-cp39-win_amd64.whl", hash = "sha256:5ddbd045cfcb073db2449563dd479057f2c2b681ebc232380e63ef15edc9c023", size = 86818, upload-time = "2025-10-10T03:55:07.316Z" }, ] [[package]] @@ -2699,10 +2157,8 @@ name = "huggingface-hub" version = "0.36.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "filelock", version = "3.19.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "filelock", version = "3.20.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, - { name = "fsspec", version = "2025.10.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "fsspec", version = "2026.2.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "filelock" }, + { name = "fsspec" }, { name = "hf-xet", marker = "platform_machine == 'aarch64' or platform_machine == 'amd64' or platform_machine == 'arm64' or platform_machine == 'x86_64'" }, { name = "packaging" }, { name = "pyyaml" }, @@ -2741,26 +2197,10 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/fa/5e/f8e9a1d23b9c20a551a8a02ea3637b4642e22c2626e3a13a9a29cdea99eb/importlib_metadata-8.7.1-py3-none-any.whl", hash = "sha256:5a1f80bf1daa489495071efbb095d75a634cf28a8bc299581244063b53176151", size = 27865, upload-time = "2025-12-21T10:00:18.329Z" }, ] -[[package]] -name = "iniconfig" -version = "2.1.0" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.10'", -] -sdist = { url = "https://files.pythonhosted.org/packages/f2/97/ebf4da567aa6827c909642694d71c9fcf53e5b504f2d96afea02718862f3/iniconfig-2.1.0.tar.gz", hash = "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7", size = 4793, upload-time = "2025-03-19T20:09:59.721Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl", hash = "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760", size = 6050, upload-time = "2025-03-19T20:10:01.071Z" }, -] - [[package]] name = "iniconfig" version = "2.3.0" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.14'", - "python_full_version >= '3.10' and python_full_version < '3.14'", -] sdist = { url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", size = 20503, upload-time = "2025-10-18T21:55:43.219Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" }, @@ -2805,7 +2245,7 @@ name = "jaraco-classes" version = "3.4.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "more-itertools", marker = "python_full_version >= '3.10'" }, + { name = "more-itertools" }, ] sdist = { url = "https://files.pythonhosted.org/packages/06/c0/ed4a27bc5571b99e3cff68f8a9fa5b56ff7df1c2251cc715a652ddd26402/jaraco.classes-3.4.0.tar.gz", hash = "sha256:47a024b51d0239c0dd8c8540c6c7f484be3b8fcf0b2d85c13825780d3b3f3acd", size = 11780, upload-time = "2024-03-31T07:27:36.643Z" } wheels = [ @@ -2817,7 +2257,7 @@ name = "jaraco-context" version = "6.1.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "backports-tarfile", marker = "python_full_version >= '3.10' and python_full_version < '3.12'" }, + { name = "backports-tarfile", marker = "python_full_version < '3.12'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/cb/9c/a788f5bb29c61e456b8ee52ce76dbdd32fd72cd73dd67bc95f42c7a8d13c/jaraco_context-6.1.0.tar.gz", hash = "sha256:129a341b0a85a7db7879e22acd66902fda67882db771754574338898b2d5d86f", size = 15850, upload-time = "2026-01-13T02:53:53.847Z" } wheels = [ @@ -2829,7 +2269,7 @@ name = "jaraco-functools" version = "4.4.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "more-itertools", marker = "python_full_version >= '3.10'" }, + { name = "more-itertools" }, ] sdist = { url = "https://files.pythonhosted.org/packages/0f/27/056e0638a86749374d6f57d0b0db39f29509cce9313cf91bdc0ac4d91084/jaraco_functools-4.4.0.tar.gz", hash = "sha256:da21933b0417b89515562656547a77b4931f98176eb173644c0d35032a33d6bb", size = 19943, upload-time = "2025-12-21T09:29:43.6Z" } wheels = [ @@ -2950,18 +2390,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/47/66/eea81dfff765ed66c68fd2ed8c96245109e13c896c2a5015c7839c92367e/jiter-0.13.0-cp314-cp314t-win32.whl", hash = "sha256:24dc96eca9f84da4131cdf87a95e6ce36765c3b156fc9ae33280873b1c32d5f6", size = 201196, upload-time = "2026-02-02T12:37:19.101Z" }, { url = "https://files.pythonhosted.org/packages/ff/32/4ac9c7a76402f8f00d00842a7f6b83b284d0cf7c1e9d4227bc95aa6d17fa/jiter-0.13.0-cp314-cp314t-win_amd64.whl", hash = "sha256:0a8d76c7524087272c8ae913f5d9d608bd839154b62c4322ef65723d2e5bb0b8", size = 204215, upload-time = "2026-02-02T12:37:20.495Z" }, { url = "https://files.pythonhosted.org/packages/f9/8e/7def204fea9f9be8b3c21a6f2dd6c020cf56c7d5ff753e0e23ed7f9ea57e/jiter-0.13.0-cp314-cp314t-win_arm64.whl", hash = "sha256:2c26cf47e2cad140fa23b6d58d435a7c0161f5c514284802f25e87fddfe11024", size = 187152, upload-time = "2026-02-02T12:37:22.124Z" }, - { url = "https://files.pythonhosted.org/packages/41/95/8e6611379c9ce8534ff94dd800c50d6d0061b2c9ae6386fbcd86c7386f0a/jiter-0.13.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:4397ee562b9f69d283e5674445551b47a5e8076fdde75e71bfac5891113dc543", size = 313635, upload-time = "2026-02-02T12:37:23.545Z" }, - { url = "https://files.pythonhosted.org/packages/70/ea/17db64dcaf84bbb187874232222030ea4d689e6008f93bda6e7c691bc4c7/jiter-0.13.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:7f90023f8f672e13ea1819507d2d21b9d2d1c18920a3b3a5f1541955a85b5504", size = 309761, upload-time = "2026-02-02T12:37:25.075Z" }, - { url = "https://files.pythonhosted.org/packages/a3/36/b2e2a7b12b94ecc7248acf2a8fe6288be893d1ebb9728655ceada22f00ad/jiter-0.13.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ed0240dd1536a98c3ab55e929c60dfff7c899fecafcb7d01161b21a99fc8c363", size = 355245, upload-time = "2026-02-02T12:37:26.646Z" }, - { url = "https://files.pythonhosted.org/packages/77/3f/5b159663c5be622daec20074c997bb66bc1fac63c167c02aef3df476fb32/jiter-0.13.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6207fc61c395b26fffdcf637a0b06b4326f35bfa93c6e92fe1a166a21aeb6731", size = 365842, upload-time = "2026-02-02T12:37:28.207Z" }, - { url = "https://files.pythonhosted.org/packages/98/30/76a68fa2c9c815c6b7802a92fc354080d66ffba9acc4690fd85622f77ad4/jiter-0.13.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:00203f47c214156df427b5989de74cb340c65c8180d09be1bf9de81d0abad599", size = 489223, upload-time = "2026-02-02T12:37:29.571Z" }, - { url = "https://files.pythonhosted.org/packages/a3/39/7c5cb85ccd71241513c878054c26a55828ccded6567d931a23ea4be73787/jiter-0.13.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c26ad6967c9dcedf10c995a21539c3aa57d4abad7001b7a84f621a263a6b605", size = 375762, upload-time = "2026-02-02T12:37:31.186Z" }, - { url = "https://files.pythonhosted.org/packages/a8/6a/381cd18d050b0102e60324e8d3f51f37ef02c56e9f4e5f0b7d26ba18958d/jiter-0.13.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a576f5dce9ac7de5d350b8e2f552cf364f32975ed84717c35379a51c7cb198bd", size = 364996, upload-time = "2026-02-02T12:37:32.931Z" }, - { url = "https://files.pythonhosted.org/packages/37/1e/d66310f1f7085c13ea6f1119c9566ec5d2cfd1dc90df963118a6869247bb/jiter-0.13.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b22945be8425d161f2e536cdae66da300b6b000f1c0ba3ddf237d1bfd45d21b8", size = 395463, upload-time = "2026-02-02T12:37:34.446Z" }, - { url = "https://files.pythonhosted.org/packages/c0/ab/06ae77cb293f860b152c356c635c15aaa800ce48772865a41704d9fac80d/jiter-0.13.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:6eeb7db8bc77dc20476bc2f7407a23dbe3d46d9cc664b166e3d474e1c1de4baa", size = 520944, upload-time = "2026-02-02T12:37:35.987Z" }, - { url = "https://files.pythonhosted.org/packages/f1/8e/57b49b20361c42a80d455a6d83cb38626204508cab4298d6a22880205319/jiter-0.13.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:19cd6f85e1dc090277c3ce90a5b7d96f32127681d825e71c9dce28788e39fc0c", size = 554955, upload-time = "2026-02-02T12:37:37.656Z" }, - { url = "https://files.pythonhosted.org/packages/79/dd/113489973c3b4256e383321aea11bd57389e401912fa48eb145a99b38767/jiter-0.13.0-cp39-cp39-win32.whl", hash = "sha256:dc3ce84cfd4fa9628fe62c4f85d0d597a4627d4242cfafac32a12cc1455d00f7", size = 206876, upload-time = "2026-02-02T12:37:39.225Z" }, - { url = "https://files.pythonhosted.org/packages/6e/73/2bdfc7133c5ee0c8f18cfe4a7582f3cfbbf3ff672cec1b5f4ca67ff9d041/jiter-0.13.0-cp39-cp39-win_amd64.whl", hash = "sha256:9ffda299e417dc83362963966c50cb76d42da673ee140de8a8ac762d4bb2378b", size = 206404, upload-time = "2026-02-02T12:37:40.632Z" }, { url = "https://files.pythonhosted.org/packages/79/b3/3c29819a27178d0e461a8571fb63c6ae38be6dc36b78b3ec2876bbd6a910/jiter-0.13.0-graalpy311-graalpy242_311_native-macosx_10_12_x86_64.whl", hash = "sha256:b1cbfa133241d0e6bdab48dcdc2604e8ba81512f6bbd68ec3e8e1357dd3c316c", size = 307016, upload-time = "2026-02-02T12:37:42.755Z" }, { url = "https://files.pythonhosted.org/packages/eb/ae/60993e4b07b1ac5ebe46da7aa99fdbb802eb986c38d26e3883ac0125c4e0/jiter-0.13.0-graalpy311-graalpy242_311_native-macosx_11_0_arm64.whl", hash = "sha256:db367d8be9fad6e8ebbac4a7578b7af562e506211036cba2c06c3b998603c3d2", size = 305024, upload-time = "2026-02-02T12:37:44.774Z" }, { url = "https://files.pythonhosted.org/packages/77/fa/2227e590e9cf98803db2811f172b2d6460a21539ab73006f251c66f44b14/jiter-0.13.0-graalpy311-graalpy242_311_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45f6f8efb2f3b0603092401dc2df79fa89ccbc027aaba4174d2d4133ed661434", size = 339337, upload-time = "2026-02-02T12:37:46.668Z" }, @@ -2995,10 +2423,10 @@ name = "jsonschema" version = "4.26.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "attrs", marker = "python_full_version >= '3.10'" }, - { name = "jsonschema-specifications", marker = "python_full_version >= '3.10'" }, - { name = "referencing", marker = "python_full_version >= '3.10'" }, - { name = "rpds-py", marker = "python_full_version >= '3.10'" }, + { name = "attrs" }, + { name = "jsonschema-specifications" }, + { name = "referencing" }, + { name = "rpds-py" }, ] sdist = { url = "https://files.pythonhosted.org/packages/b3/fc/e067678238fa451312d4c62bf6e6cf5ec56375422aee02f9cb5f909b3047/jsonschema-4.26.0.tar.gz", hash = "sha256:0c26707e2efad8aa1bfc5b7ce170f3fccc2e4918ff85989ba9ffa9facb2be326", size = 366583, upload-time = "2026-01-07T13:41:07.246Z" } wheels = [ @@ -3010,10 +2438,10 @@ name = "jsonschema-path" version = "0.3.4" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pathable", marker = "python_full_version >= '3.10'" }, - { name = "pyyaml", marker = "python_full_version >= '3.10'" }, - { name = "referencing", marker = "python_full_version >= '3.10'" }, - { name = "requests", marker = "python_full_version >= '3.10'" }, + { name = "pathable" }, + { name = "pyyaml" }, + { name = "referencing" }, + { name = "requests" }, ] sdist = { url = "https://files.pythonhosted.org/packages/6e/45/41ebc679c2a4fced6a722f624c18d658dee42612b83ea24c1caf7c0eb3a8/jsonschema_path-0.3.4.tar.gz", hash = "sha256:8365356039f16cc65fddffafda5f58766e34bebab7d6d105616ab52bc4297001", size = 11159, upload-time = "2025-01-24T14:33:16.547Z" } wheels = [ @@ -3025,7 +2453,7 @@ name = "jsonschema-specifications" version = "2025.9.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "referencing", marker = "python_full_version >= '3.10'" }, + { name = "referencing" }, ] sdist = { url = "https://files.pythonhosted.org/packages/19/74/a633ee74eb36c44aa6d1095e7cc5569bebf04342ee146178e2d36600708b/jsonschema_specifications-2025.9.1.tar.gz", hash = "sha256:b540987f239e745613c7a9176f3edb72b832a4ac465cf02712288397832b5e8d", size = 32855, upload-time = "2025-09-08T01:34:59.186Z" } wheels = [ @@ -3037,31 +2465,19 @@ name = "keyring" version = "25.7.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "importlib-metadata", marker = "python_full_version >= '3.10' and python_full_version < '3.12'" }, - { name = "jaraco-classes", marker = "python_full_version >= '3.10'" }, - { name = "jaraco-context", marker = "python_full_version >= '3.10'" }, - { name = "jaraco-functools", marker = "python_full_version >= '3.10'" }, - { name = "jeepney", marker = "python_full_version >= '3.10' and sys_platform == 'linux'" }, - { name = "pywin32-ctypes", marker = "python_full_version >= '3.10' and sys_platform == 'win32'" }, - { name = "secretstorage", marker = "python_full_version >= '3.10' and sys_platform == 'linux'" }, + { name = "importlib-metadata", marker = "python_full_version < '3.12'" }, + { name = "jaraco-classes" }, + { name = "jaraco-context" }, + { name = "jaraco-functools" }, + { name = "jeepney", marker = "sys_platform == 'linux'" }, + { name = "pywin32-ctypes", marker = "sys_platform == 'win32'" }, + { name = "secretstorage", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/43/4b/674af6ef2f97d56f0ab5153bf0bfa28ccb6c3ed4d1babf4305449668807b/keyring-25.7.0.tar.gz", hash = "sha256:fe01bd85eb3f8fb3dd0405defdeac9a5b4f6f0439edbb3149577f244a2e8245b", size = 63516, upload-time = "2025-11-16T16:26:09.482Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/81/db/e655086b7f3a705df045bf0933bdd9c2f79bb3c97bfef1384598bb79a217/keyring-25.7.0-py3-none-any.whl", hash = "sha256:be4a0b195f149690c166e850609a477c532ddbfbaed96a404d4e43f8d5e2689f", size = 39160, upload-time = "2025-11-16T16:26:08.402Z" }, ] -[[package]] -name = "lia-web" -version = "0.3.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "cross-web", marker = "python_full_version < '3.10'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/05/3d/7d574a7a5cf5fbc5fc09c07ea3696dd400353b7702bc009cf596b8c12035/lia_web-0.3.1.tar.gz", hash = "sha256:7f551269eddd729f1437e9341ad21622a849eb0c0975d9232ccbbaadbdc74c06", size = 2021, upload-time = "2025-12-25T20:41:51.195Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a1/8b/b628fc18658f94b3d094708a18b71083cf47628e85cbc6b9edba54d5b2d7/lia_web-0.3.1-py3-none-any.whl", hash = "sha256:e4e6e7a9381e228aca60a6f3d67dbae9a5f4638eced242d931f95797ddba3f8b", size = 5933, upload-time = "2025-12-25T20:41:52.289Z" }, -] - [[package]] name = "librt" version = "0.7.8" @@ -3133,16 +2549,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/22/f0/07fb6ab5c39a4ca9af3e37554f9d42f25c464829254d72e4ebbd81da351c/librt-0.7.8-cp314-cp314t-win32.whl", hash = "sha256:171ca3a0a06c643bd0a2f62a8944e1902c94aa8e5da4db1ea9a8daf872685365", size = 41173, upload-time = "2026-01-14T12:55:59.315Z" }, { url = "https://files.pythonhosted.org/packages/24/d4/7e4be20993dc6a782639625bd2f97f3c66125c7aa80c82426956811cfccf/librt-0.7.8-cp314-cp314t-win_amd64.whl", hash = "sha256:445b7304145e24c60288a2f172b5ce2ca35c0f81605f5299f3fa567e189d2e32", size = 47668, upload-time = "2026-01-14T12:56:00.261Z" }, { url = "https://files.pythonhosted.org/packages/fc/85/69f92b2a7b3c0f88ffe107c86b952b397004b5b8ea5a81da3d9c04c04422/librt-0.7.8-cp314-cp314t-win_arm64.whl", hash = "sha256:8766ece9de08527deabcd7cb1b4f1a967a385d26e33e536d6d8913db6ef74f06", size = 40550, upload-time = "2026-01-14T12:56:01.542Z" }, - { url = "https://files.pythonhosted.org/packages/3b/9b/2668bb01f568bc89ace53736df950845f8adfcacdf6da087d5cef12110cb/librt-0.7.8-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c7e8f88f79308d86d8f39c491773cbb533d6cb7fa6476f35d711076ee04fceb6", size = 56680, upload-time = "2026-01-14T12:56:02.602Z" }, - { url = "https://files.pythonhosted.org/packages/b3/d4/dbb3edf2d0ec4ba08dcaf1865833d32737ad208962d4463c022cea6e9d3c/librt-0.7.8-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:389bd25a0db916e1d6bcb014f11aa9676cedaa485e9ec3752dfe19f196fd377b", size = 58612, upload-time = "2026-01-14T12:56:03.616Z" }, - { url = "https://files.pythonhosted.org/packages/0f/c9/64b029de4ac9901fcd47832c650a0fd050555a452bd455ce8deddddfbb9f/librt-0.7.8-cp39-cp39-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:73fd300f501a052f2ba52ede721232212f3b06503fa12665408ecfc9d8fd149c", size = 163654, upload-time = "2026-01-14T12:56:04.975Z" }, - { url = "https://files.pythonhosted.org/packages/81/5c/95e2abb1b48eb8f8c7fc2ae945321a6b82777947eb544cc785c3f37165b2/librt-0.7.8-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6d772edc6a5f7835635c7562f6688e031f0b97e31d538412a852c49c9a6c92d5", size = 172477, upload-time = "2026-01-14T12:56:06.103Z" }, - { url = "https://files.pythonhosted.org/packages/7e/27/9bdf12e05b0eb089dd008d9c8aabc05748aad9d40458ade5e627c9538158/librt-0.7.8-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bfde8a130bd0f239e45503ab39fab239ace094d63ee1d6b67c25a63d741c0f71", size = 186220, upload-time = "2026-01-14T12:56:09.958Z" }, - { url = "https://files.pythonhosted.org/packages/53/6a/c3774f4cc95e68ed444a39f2c8bd383fd18673db7d6b98cfa709f6634b93/librt-0.7.8-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:fdec6e2368ae4f796fc72fad7fd4bd1753715187e6d870932b0904609e7c878e", size = 183841, upload-time = "2026-01-14T12:56:11.109Z" }, - { url = "https://files.pythonhosted.org/packages/58/6b/48702c61cf83e9c04ad5cec8cad7e5e22a2cde23a13db8ef341598897ddd/librt-0.7.8-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:00105e7d541a8f2ee5be52caacea98a005e0478cfe78c8080fbb7b5d2b340c63", size = 179751, upload-time = "2026-01-14T12:56:12.278Z" }, - { url = "https://files.pythonhosted.org/packages/35/87/5f607fc73a131d4753f4db948833063c6aad18e18a4e6fbf64316c37ae65/librt-0.7.8-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:c6f8947d3dfd7f91066c5b4385812c18be26c9d5a99ca56667547f2c39149d94", size = 199319, upload-time = "2026-01-14T12:56:13.425Z" }, - { url = "https://files.pythonhosted.org/packages/6e/cc/b7c5ac28ae0f0645a9681248bae4ede665bba15d6f761c291853c5c5b78e/librt-0.7.8-cp39-cp39-win32.whl", hash = "sha256:41d7bb1e07916aeb12ae4a44e3025db3691c4149ab788d0315781b4d29b86afb", size = 43434, upload-time = "2026-01-14T12:56:14.781Z" }, - { url = "https://files.pythonhosted.org/packages/e4/5d/dce0c92f786495adf2c1e6784d9c50a52fb7feb1cfb17af97a08281a6e82/librt-0.7.8-cp39-cp39-win_amd64.whl", hash = "sha256:e90a8e237753c83b8e484d478d9a996dc5e39fd5bd4c6ce32563bc8123f132be", size = 49801, upload-time = "2026-01-14T12:56:15.827Z" }, ] [[package]] @@ -3150,14 +2556,14 @@ name = "logfire" version = "4.22.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "executing", marker = "python_full_version >= '3.10'" }, - { name = "opentelemetry-exporter-otlp-proto-http", marker = "python_full_version >= '3.10'" }, - { name = "opentelemetry-instrumentation", marker = "python_full_version >= '3.10'" }, - { name = "opentelemetry-sdk", marker = "python_full_version >= '3.10'" }, - { name = "protobuf", version = "6.33.5", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, - { name = "rich", marker = "python_full_version >= '3.10'" }, - { name = "tomli", marker = "python_full_version == '3.10.*'" }, - { name = "typing-extensions", marker = "python_full_version >= '3.10'" }, + { name = "executing" }, + { name = "opentelemetry-exporter-otlp-proto-http" }, + { name = "opentelemetry-instrumentation" }, + { name = "opentelemetry-sdk" }, + { name = "protobuf" }, + { name = "rich" }, + { name = "tomli", marker = "python_full_version < '3.11'" }, + { name = "typing-extensions" }, ] sdist = { url = "https://files.pythonhosted.org/packages/b1/29/4386b331b8aecad429c043bbd1b7684cdb56ff9e11a5bd96845483dc0968/logfire-4.22.0.tar.gz", hash = "sha256:284b3b955c7515d4428dbc1e04784c3e652e62acf7597bd64a0aa9ecb6a7dedd", size = 654771, upload-time = "2026-02-04T12:17:57.635Z" } wheels = [ @@ -3166,7 +2572,7 @@ wheels = [ [package.optional-dependencies] httpx = [ - { name = "opentelemetry-instrumentation-httpx", marker = "python_full_version >= '3.10'" }, + { name = "opentelemetry-instrumentation-httpx" }, ] [[package]] @@ -3250,42 +2656,12 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b4/a0/89e6a024c3b4485b89ef86881c9d55e097e7cb0bdb74efb746f2fa6a9a76/lupa-2.6-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:9abb98d5a8fd27c8285302e82199f0e56e463066f88f619d6594a450bf269d80", size = 2153693, upload-time = "2025-10-24T07:19:31.379Z" }, { url = "https://files.pythonhosted.org/packages/b6/36/a0f007dc58fc1bbf51fb85dcc82fcb1f21b8c4261361de7dab0e3d8521ef/lupa-2.6-cp314-cp314t-win32.whl", hash = "sha256:1849efeba7a8f6fb8aa2c13790bee988fd242ae404bd459509640eeea3d1e291", size = 1590104, upload-time = "2025-10-24T07:19:33.514Z" }, { url = "https://files.pythonhosted.org/packages/7d/5e/db903ce9cf82c48d6b91bf6d63ae4c8d0d17958939a4e04ba6b9f38b8643/lupa-2.6-cp314-cp314t-win_amd64.whl", hash = "sha256:fc1498d1a4fc028bc521c26d0fad4ca00ed63b952e32fb95949bda76a04bad52", size = 1913818, upload-time = "2025-10-24T07:19:36.039Z" }, - { url = "https://files.pythonhosted.org/packages/fb/c5/918ed6c3af793764bae155d68df47bab2635ab7c94dee3dbb5d9c6d5ba38/lupa-2.6-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8897dc6c3249786b2cdf2f83324febb436193d4581b6a71dea49f77bf8b19bb0", size = 956718, upload-time = "2025-10-24T07:20:03.086Z" }, - { url = "https://files.pythonhosted.org/packages/da/91/0ca797da854478225c0f6a8fc3c500a2f5c11826d732735beb5dffff9e85/lupa-2.6-cp39-cp39-macosx_11_0_universal2.whl", hash = "sha256:4446396ca3830be0c106c70db4b4f622c37b2d447874c07952cafb9c57949a4a", size = 1923934, upload-time = "2025-10-24T07:20:05.428Z" }, - { url = "https://files.pythonhosted.org/packages/f5/7f/98a6a2535285d43457eb665822ab08447e2196b614db3152772d457ca426/lupa-2.6-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:5826e687c89995a6eaafeae242071ba16448eec1a9ee8e17ed48551b5d1e21c2", size = 987286, upload-time = "2025-10-24T07:20:07.338Z" }, - { url = "https://files.pythonhosted.org/packages/5f/50/edad7c180ab28aa543e6c3895e56a2c7a6ff92140a283316e6086f118552/lupa-2.6-cp39-cp39-manylinux2010_i686.manylinux_2_12_i686.manylinux_2_28_i686.whl", hash = "sha256:5871935cb36d1d22f9c04ac0db75c06751bd95edcfa0d9309f732de908e297a9", size = 1176541, upload-time = "2025-10-24T07:20:09.305Z" }, - { url = "https://files.pythonhosted.org/packages/24/b3/27a0ec4c73011e86f9bd2eada010062308a4ed32921898d066ae54e064e1/lupa-2.6-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:43eb6e43ea8512d0d65b995d36dd9d77aa02598035e25b84c23a1b58700c9fb2", size = 1058981, upload-time = "2025-10-24T07:20:11.7Z" }, - { url = "https://files.pythonhosted.org/packages/a4/12/d55d45a8c253e7981f59ae920bac49dbd49888954b25fd1eb3a7be1321db/lupa-2.6-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:559714053018d9885cc8c36a33c5b7eb9aad30fb6357719cac3ce4dc6b39157e", size = 2103336, upload-time = "2025-10-24T07:20:13.71Z" }, - { url = "https://files.pythonhosted.org/packages/ab/17/058cc212c22d6a25990226afd02c741b2813b5f325396a9180b4accb70ac/lupa-2.6-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:57ac88a00ce59bd9d4ddcd4fca8e02564765725f5068786b011c9d1be3de20c5", size = 1083209, upload-time = "2025-10-24T07:20:15.587Z" }, - { url = "https://files.pythonhosted.org/packages/e6/01/8ca3a56a4e127784a15f0c7ec1f67e9894c2e9d4bf402389ddda4ea8081b/lupa-2.6-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:b683fbd867c2e54c44a686361b75eee7e7a790da55afdbe89f1f23b106de0274", size = 1193077, upload-time = "2025-10-24T07:20:17.857Z" }, - { url = "https://files.pythonhosted.org/packages/07/1b/c7fe79bcda6d489306bb7c1a9b4d545b7f0930b9ce80080643fc39b3fdc9/lupa-2.6-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:d2f656903a2ed2e074bf2b7d300968028dfa327a45b055be8e3b51ef0b82f9bf", size = 2198584, upload-time = "2025-10-24T07:20:20.468Z" }, - { url = "https://files.pythonhosted.org/packages/9e/df/3f7631eea3478ac3868cbcb2763c1a4e2f7b875fcb2683f956bf7aabf65f/lupa-2.6-cp39-cp39-win32.whl", hash = "sha256:bf28f68ae231b72008523ab5ac23835ba0f76e0e99ec38b59766080a84eb596a", size = 1414693, upload-time = "2025-10-24T07:20:23.477Z" }, - { url = "https://files.pythonhosted.org/packages/08/e0/3fd9617814663129fa4a9b33a980c3fe344297337cb550c738f87f730f6b/lupa-2.6-cp39-cp39-win_amd64.whl", hash = "sha256:b4b2e9b3795a9897cf6cfcc58d08210fdc0d13ab47c9a0e13858c68932d8353c", size = 1658877, upload-time = "2025-10-24T07:20:27.086Z" }, -] - -[[package]] -name = "markdown" -version = "3.9" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.10'", -] -dependencies = [ - { name = "importlib-metadata", marker = "python_full_version < '3.10'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/8d/37/02347f6d6d8279247a5837082ebc26fc0d5aaeaf75aa013fcbb433c777ab/markdown-3.9.tar.gz", hash = "sha256:d2900fe1782bd33bdbbd56859defef70c2e78fc46668f8eb9df3128138f2cb6a", size = 364585, upload-time = "2025-09-04T20:25:22.885Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/70/ae/44c4a6a4cbb496d93c6257954260fe3a6e91b7bed2240e5dad2a717f5111/markdown-3.9-py3-none-any.whl", hash = "sha256:9f4d91ed810864ea88a6f32c07ba8bee1346c0cc1f6b1f9f6c822f2a9667d280", size = 107441, upload-time = "2025-09-04T20:25:21.784Z" }, ] [[package]] name = "markdown" version = "3.10.1" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.14'", - "python_full_version >= '3.10' and python_full_version < '3.14'", -] sdist = { url = "https://files.pythonhosted.org/packages/b7/b1/af95bcae8549f1f3fd70faacb29075826a0d689a27f232e8cee315efa053/markdown-3.10.1.tar.gz", hash = "sha256:1c19c10bd5c14ac948c53d0d762a04e2fa35a6d58a6b7b1e6bfcbe6fefc0001a", size = 365402, upload-time = "2026-01-21T18:09:28.206Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/59/1b/6ef961f543593969d25b2afe57a3564200280528caa9bd1082eecdd7b3bc/markdown-3.10.1-py3-none-any.whl", hash = "sha256:867d788939fe33e4b736426f5b9f651ad0c0ae0ecf89df0ca5d1176c70812fe3", size = 107684, upload-time = "2026-01-21T18:09:27.203Z" }, @@ -3296,39 +2672,19 @@ name = "markdown-include-variants" version = "0.0.8" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "markdown", version = "3.9", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "markdown", version = "3.10.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "markdown" }, ] sdist = { url = "https://files.pythonhosted.org/packages/c5/47/ec9eae4a6d2f336d95681df43720e2b25b045dc3ed44ae6d30a5ce2f5dff/markdown_include_variants-0.0.8.tar.gz", hash = "sha256:46d812340c64dcd3646b1eaa356bafb31626dd7b4955d15c44ff8c48c6357227", size = 46882, upload-time = "2025-12-12T16:11:04.254Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/4e/0e/130958e7ec50d13f2ee7b6c142df5c352520a9251baf1652e41262703857/markdown_include_variants-0.0.8-py3-none-any.whl", hash = "sha256:425a300ae25fbcd598506cba67859a9dfa047333e869e0ff2e11a5e354b326dc", size = 8120, upload-time = "2025-12-12T16:11:02.881Z" }, ] -[[package]] -name = "markdown-it-py" -version = "3.0.0" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.10'", -] -dependencies = [ - { name = "mdurl", marker = "python_full_version < '3.10'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/38/71/3b932df36c1a044d397a1f92d1cf91ee0a503d91e470cbd670aa66b07ed0/markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb", size = 74596, upload-time = "2023-06-03T06:41:14.443Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1", size = 87528, upload-time = "2023-06-03T06:41:11.019Z" }, -] - [[package]] name = "markdown-it-py" version = "4.0.0" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.14'", - "python_full_version >= '3.10' and python_full_version < '3.14'", -] dependencies = [ - { name = "mdurl", marker = "python_full_version >= '3.10'" }, + { name = "mdurl" }, ] sdist = { url = "https://files.pythonhosted.org/packages/5b/f5/4ec618ed16cc4f8fb3b701563655a69816155e79e24a17b651541804721d/markdown_it_py-4.0.0.tar.gz", hash = "sha256:cb0a2b4aa34f932c007117b194e945bd74e0ec24133ceb5bac59009cda1cb9f3", size = 73070, upload-time = "2025-08-11T12:57:52.854Z" } wheels = [ @@ -3418,17 +2774,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/fb/df/5bd7a48c256faecd1d36edc13133e51397e41b73bb77e1a69deab746ebac/markupsafe-3.0.3-cp314-cp314t-win32.whl", hash = "sha256:915c04ba3851909ce68ccc2b8e2cd691618c4dc4c4232fb7982bca3f41fd8c3d", size = 14819, upload-time = "2025-09-27T18:37:26.285Z" }, { url = "https://files.pythonhosted.org/packages/1a/8a/0402ba61a2f16038b48b39bccca271134be00c5c9f0f623208399333c448/markupsafe-3.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4faffd047e07c38848ce017e8725090413cd80cbc23d86e55c587bf979e579c9", size = 15426, upload-time = "2025-09-27T18:37:27.316Z" }, { url = "https://files.pythonhosted.org/packages/70/bc/6f1c2f612465f5fa89b95bead1f44dcb607670fd42891d8fdcd5d039f4f4/markupsafe-3.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:32001d6a8fc98c8cb5c947787c5d08b0a50663d139f1305bac5885d98d9b40fa", size = 14146, upload-time = "2025-09-27T18:37:28.327Z" }, - { url = "https://files.pythonhosted.org/packages/56/23/0d8c13a44bde9154821586520840643467aee574d8ce79a17da539ee7fed/markupsafe-3.0.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:15d939a21d546304880945ca1ecb8a039db6b4dc49b2c5a400387cdae6a62e26", size = 11623, upload-time = "2025-09-27T18:37:29.296Z" }, - { url = "https://files.pythonhosted.org/packages/fd/23/07a2cb9a8045d5f3f0890a8c3bc0859d7a47bfd9a560b563899bec7b72ed/markupsafe-3.0.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f71a396b3bf33ecaa1626c255855702aca4d3d9fea5e051b41ac59a9c1c41edc", size = 12049, upload-time = "2025-09-27T18:37:30.234Z" }, - { url = "https://files.pythonhosted.org/packages/bc/e4/6be85eb81503f8e11b61c0b6369b6e077dcf0a74adbd9ebf6b349937b4e9/markupsafe-3.0.3-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0f4b68347f8c5eab4a13419215bdfd7f8c9b19f2b25520968adfad23eb0ce60c", size = 21923, upload-time = "2025-09-27T18:37:31.177Z" }, - { url = "https://files.pythonhosted.org/packages/6f/bc/4dc914ead3fe6ddaef035341fee0fc956949bbd27335b611829292b89ee2/markupsafe-3.0.3-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e8fc20152abba6b83724d7ff268c249fa196d8259ff481f3b1476383f8f24e42", size = 20543, upload-time = "2025-09-27T18:37:32.168Z" }, - { url = "https://files.pythonhosted.org/packages/89/6e/5fe81fbcfba4aef4093d5f856e5c774ec2057946052d18d168219b7bd9f9/markupsafe-3.0.3-cp39-cp39-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:949b8d66bc381ee8b007cd945914c721d9aba8e27f71959d750a46f7c282b20b", size = 20585, upload-time = "2025-09-27T18:37:33.166Z" }, - { url = "https://files.pythonhosted.org/packages/f6/f6/e0e5a3d3ae9c4020f696cd055f940ef86b64fe88de26f3a0308b9d3d048c/markupsafe-3.0.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:3537e01efc9d4dccdf77221fb1cb3b8e1a38d5428920e0657ce299b20324d758", size = 21387, upload-time = "2025-09-27T18:37:34.185Z" }, - { url = "https://files.pythonhosted.org/packages/c8/25/651753ef4dea08ea790f4fbb65146a9a44a014986996ca40102e237aa49a/markupsafe-3.0.3-cp39-cp39-musllinux_1_2_riscv64.whl", hash = "sha256:591ae9f2a647529ca990bc681daebdd52c8791ff06c2bfa05b65163e28102ef2", size = 20133, upload-time = "2025-09-27T18:37:35.138Z" }, - { url = "https://files.pythonhosted.org/packages/dc/0a/c3cf2b4fef5f0426e8a6d7fce3cb966a17817c568ce59d76b92a233fdbec/markupsafe-3.0.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:a320721ab5a1aba0a233739394eb907f8c8da5c98c9181d1161e77a0c8e36f2d", size = 20588, upload-time = "2025-09-27T18:37:36.096Z" }, - { url = "https://files.pythonhosted.org/packages/cd/1b/a7782984844bd519ad4ffdbebbba2671ec5d0ebbeac34736c15fb86399e8/markupsafe-3.0.3-cp39-cp39-win32.whl", hash = "sha256:df2449253ef108a379b8b5d6b43f4b1a8e81a061d6537becd5582fba5f9196d7", size = 14566, upload-time = "2025-09-27T18:37:37.09Z" }, - { url = "https://files.pythonhosted.org/packages/18/1f/8d9c20e1c9440e215a44be5ab64359e207fcb4f675543f1cf9a2a7f648d0/markupsafe-3.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:7c3fb7d25180895632e5d3148dbdc29ea38ccb7fd210aa27acbd1201a1902c6e", size = 15053, upload-time = "2025-09-27T18:37:38.054Z" }, - { url = "https://files.pythonhosted.org/packages/4e/d3/fe08482b5cd995033556d45041a4f4e76e7f0521112a9c9991d40d39825f/markupsafe-3.0.3-cp39-cp39-win_arm64.whl", hash = "sha256:38664109c14ffc9e7437e86b4dceb442b0096dfe3541d7864d9cbe1da4cf36c8", size = 13928, upload-time = "2025-09-27T18:37:39.037Z" }, ] [[package]] @@ -3436,20 +2781,20 @@ name = "mcp" version = "1.26.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "anyio", marker = "python_full_version >= '3.10'" }, - { name = "httpx", marker = "python_full_version >= '3.10'" }, - { name = "httpx-sse", marker = "python_full_version >= '3.10'" }, - { name = "jsonschema", marker = "python_full_version >= '3.10'" }, - { name = "pydantic", marker = "python_full_version >= '3.10'" }, - { name = "pydantic-settings", version = "2.12.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, - { name = "pyjwt", extra = ["crypto"], marker = "python_full_version >= '3.10'" }, - { name = "python-multipart", version = "0.0.22", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, - { name = "pywin32", marker = "python_full_version >= '3.10' and sys_platform == 'win32'" }, - { name = "sse-starlette", marker = "python_full_version >= '3.10'" }, - { name = "starlette", version = "0.52.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, - { name = "typing-extensions", marker = "python_full_version >= '3.10'" }, - { name = "typing-inspection", marker = "python_full_version >= '3.10'" }, - { name = "uvicorn", version = "0.40.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10' and sys_platform != 'emscripten'" }, + { name = "anyio" }, + { name = "httpx" }, + { name = "httpx-sse" }, + { name = "jsonschema" }, + { name = "pydantic" }, + { name = "pydantic-settings" }, + { name = "pyjwt", extra = ["crypto"] }, + { name = "python-multipart" }, + { name = "pywin32", marker = "sys_platform == 'win32'" }, + { name = "sse-starlette" }, + { name = "starlette" }, + { name = "typing-extensions" }, + { name = "typing-inspection" }, + { name = "uvicorn", marker = "sys_platform != 'emscripten'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/fc/6d/62e76bbb8144d6ed86e202b5edd8a4cb631e7c8130f3f4893c3f90262b10/mcp-1.26.0.tar.gz", hash = "sha256:db6e2ef491eecc1a0d93711a76f28dec2e05999f93afd48795da1c1137142c66", size = 608005, upload-time = "2026-01-24T19:40:32.468Z" } wheels = [ @@ -3471,8 +2816,7 @@ version = "1.4.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cyclic" }, - { name = "markdown", version = "3.9", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "markdown", version = "3.10.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "markdown" }, { name = "rcslice" }, ] sdist = { url = "https://files.pythonhosted.org/packages/bf/f0/f395a9cf164471d3c7bbe58cbd64d74289575a8b85a962b49a804ab7ed34/mdx_include-1.4.2.tar.gz", hash = "sha256:992f9fbc492b5cf43f7d8cb4b90b52a4e4c5fdd7fd04570290a83eea5c84f297", size = 15051, upload-time = "2022-07-26T05:46:14.129Z" } @@ -3512,14 +2856,11 @@ name = "mkdocs" version = "1.6.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "click", version = "8.1.8", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "click", version = "8.3.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "click" }, { name = "colorama", marker = "sys_platform == 'win32'" }, { name = "ghp-import" }, - { name = "importlib-metadata", marker = "python_full_version < '3.10'" }, { name = "jinja2" }, - { name = "markdown", version = "3.9", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "markdown", version = "3.10.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "markdown" }, { name = "markupsafe" }, { name = "mergedeep" }, { name = "mkdocs-get-deps" }, @@ -3539,8 +2880,7 @@ name = "mkdocs-autorefs" version = "1.4.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "markdown", version = "3.9", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "markdown", version = "3.10.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "markdown" }, { name = "markupsafe" }, { name = "mkdocs" }, ] @@ -3554,10 +2894,8 @@ name = "mkdocs-get-deps" version = "0.2.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "importlib-metadata", marker = "python_full_version < '3.10'" }, { name = "mergedeep" }, - { name = "platformdirs", version = "4.4.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "platformdirs", version = "4.5.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "platformdirs" }, { name = "pyyaml" }, ] sdist = { url = "https://files.pythonhosted.org/packages/98/f5/ed29cd50067784976f25ed0ed6fcd3c2ce9eb90650aa3b2796ddf7b6870b/mkdocs_get_deps-0.2.0.tar.gz", hash = "sha256:162b3d129c7fad9b19abfdcb9c1458a651628e4b1dea628ac68790fb3061c60c", size = 10239, upload-time = "2023-11-20T17:51:09.981Z" } @@ -3579,8 +2917,7 @@ dependencies = [ { name = "pyyaml" }, { name = "requests" }, { name = "super-collections" }, - { name = "termcolor", version = "3.1.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "termcolor", version = "3.3.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "termcolor" }, ] sdist = { url = "https://files.pythonhosted.org/packages/92/15/e6a44839841ebc9c5872fa0e6fad1c3757424e4fe026093b68e9f386d136/mkdocs_macros_plugin-1.5.0.tar.gz", hash = "sha256:12aa45ce7ecb7a445c66b9f649f3dd05e9b92e8af6bc65e4acd91d26f878c01f", size = 37730, upload-time = "2025-11-13T08:08:55.545Z" } wheels = [ @@ -3596,8 +2933,7 @@ dependencies = [ { name = "backrefs" }, { name = "colorama" }, { name = "jinja2" }, - { name = "markdown", version = "3.9", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "markdown", version = "3.10.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "markdown" }, { name = "mkdocs" }, { name = "mkdocs-material-extensions" }, { name = "paginate" }, @@ -3631,47 +2967,17 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c4/ec/38443b1f2a3821bbcb24e46cd8ba979154417794d54baf949fefde1c2146/mkdocs_redirects-1.2.2-py3-none-any.whl", hash = "sha256:7dbfa5647b79a3589da4401403d69494bd1f4ad03b9c15136720367e1f340ed5", size = 6142, upload-time = "2024-11-07T14:57:19.143Z" }, ] -[[package]] -name = "mkdocstrings" -version = "0.30.1" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.10'", -] -dependencies = [ - { name = "importlib-metadata", marker = "python_full_version < '3.10'" }, - { name = "jinja2", marker = "python_full_version < '3.10'" }, - { name = "markdown", version = "3.9", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "markupsafe", marker = "python_full_version < '3.10'" }, - { name = "mkdocs", marker = "python_full_version < '3.10'" }, - { name = "mkdocs-autorefs", marker = "python_full_version < '3.10'" }, - { name = "pymdown-extensions", marker = "python_full_version < '3.10'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/c5/33/2fa3243439f794e685d3e694590d28469a9b8ea733af4b48c250a3ffc9a0/mkdocstrings-0.30.1.tar.gz", hash = "sha256:84a007aae9b707fb0aebfc9da23db4b26fc9ab562eb56e335e9ec480cb19744f", size = 106350, upload-time = "2025-09-19T10:49:26.446Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7b/2c/f0dc4e1ee7f618f5bff7e05898d20bf8b6e7fa612038f768bfa295f136a4/mkdocstrings-0.30.1-py3-none-any.whl", hash = "sha256:41bd71f284ca4d44a668816193e4025c950b002252081e387433656ae9a70a82", size = 36704, upload-time = "2025-09-19T10:49:24.805Z" }, -] - -[package.optional-dependencies] -python = [ - { name = "mkdocstrings-python", version = "1.18.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, -] - [[package]] name = "mkdocstrings" version = "1.0.2" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.14'", - "python_full_version >= '3.10' and python_full_version < '3.14'", -] dependencies = [ - { name = "jinja2", marker = "python_full_version >= '3.10'" }, - { name = "markdown", version = "3.10.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, - { name = "markupsafe", marker = "python_full_version >= '3.10'" }, - { name = "mkdocs", marker = "python_full_version >= '3.10'" }, - { name = "mkdocs-autorefs", marker = "python_full_version >= '3.10'" }, - { name = "pymdown-extensions", marker = "python_full_version >= '3.10'" }, + { name = "jinja2" }, + { name = "markdown" }, + { name = "markupsafe" }, + { name = "mkdocs" }, + { name = "mkdocs-autorefs" }, + { name = "pymdown-extensions" }, ] sdist = { url = "https://files.pythonhosted.org/packages/63/4d/1ca8a9432579184599714aaeb36591414cc3d3bfd9d494f6db540c995ae4/mkdocstrings-1.0.2.tar.gz", hash = "sha256:48edd0ccbcb9e30a3121684e165261a9d6af4d63385fc4f39a54a49ac3b32ea8", size = 101048, upload-time = "2026-01-24T15:57:25.735Z" } wheels = [ @@ -3680,40 +2986,18 @@ wheels = [ [package.optional-dependencies] python = [ - { name = "mkdocstrings-python", version = "2.0.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, -] - -[[package]] -name = "mkdocstrings-python" -version = "1.18.2" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.10'", -] -dependencies = [ - { name = "griffe", version = "1.14.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "mkdocs-autorefs", marker = "python_full_version < '3.10'" }, - { name = "mkdocstrings", version = "0.30.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "typing-extensions", marker = "python_full_version < '3.10'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/95/ae/58ab2bfbee2792e92a98b97e872f7c003deb903071f75d8d83aa55db28fa/mkdocstrings_python-1.18.2.tar.gz", hash = "sha256:4ad536920a07b6336f50d4c6d5603316fafb1172c5c882370cbbc954770ad323", size = 207972, upload-time = "2025-08-28T16:11:19.847Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d5/8f/ce008599d9adebf33ed144e7736914385e8537f5fc686fdb7cceb8c22431/mkdocstrings_python-1.18.2-py3-none-any.whl", hash = "sha256:944fe6deb8f08f33fa936d538233c4036e9f53e840994f6146e8e94eb71b600d", size = 138215, upload-time = "2025-08-28T16:11:18.176Z" }, + { name = "mkdocstrings-python" }, ] [[package]] name = "mkdocstrings-python" version = "2.0.1" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.14'", - "python_full_version >= '3.10' and python_full_version < '3.14'", -] dependencies = [ - { name = "griffe", version = "1.15.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, - { name = "mkdocs-autorefs", marker = "python_full_version >= '3.10'" }, - { name = "mkdocstrings", version = "1.0.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, - { name = "typing-extensions", marker = "python_full_version == '3.10.*'" }, + { name = "griffe" }, + { name = "mkdocs-autorefs" }, + { name = "mkdocstrings" }, + { name = "typing-extensions", marker = "python_full_version < '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/24/75/d30af27a2906f00eb90143470272376d728521997800f5dce5b340ba35bc/mkdocstrings_python-2.0.1.tar.gz", hash = "sha256:843a562221e6a471fefdd4b45cc6c22d2607ccbad632879234fa9692e9cf7732", size = 199345, upload-time = "2025-12-03T14:26:11.755Z" } wheels = [ @@ -3864,24 +3148,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/5f/60/c3a5187bf66f6fb546ff4ab8fb5a077cbdd832d7b1908d4365c7f74a1917/multidict-6.7.1-cp314-cp314t-win32.whl", hash = "sha256:98655c737850c064a65e006a3df7c997cd3b220be4ec8fe26215760b9697d4d7", size = 48008, upload-time = "2026-01-26T02:46:07.468Z" }, { url = "https://files.pythonhosted.org/packages/0c/f7/addf1087b860ac60e6f382240f64fb99f8bfb532bb06f7c542b83c29ca61/multidict-6.7.1-cp314-cp314t-win_amd64.whl", hash = "sha256:497bde6223c212ba11d462853cfa4f0ae6ef97465033e7dc9940cdb3ab5b48e5", size = 53542, upload-time = "2026-01-26T02:46:08.809Z" }, { url = "https://files.pythonhosted.org/packages/4c/81/4629d0aa32302ef7b2ec65c75a728cc5ff4fa410c50096174c1632e70b3e/multidict-6.7.1-cp314-cp314t-win_arm64.whl", hash = "sha256:2bbd113e0d4af5db41d5ebfe9ccaff89de2120578164f86a5d17d5a576d1e5b2", size = 44719, upload-time = "2026-01-26T02:46:11.146Z" }, - { url = "https://files.pythonhosted.org/packages/9e/ee/74525ebe3eb5fddcd6735fc03cbea3feeed4122b53bc798ac32d297ac9ae/multidict-6.7.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:65573858d27cdeaca41893185677dc82395159aa28875a8867af66532d413a8f", size = 77107, upload-time = "2026-01-26T02:46:12.608Z" }, - { url = "https://files.pythonhosted.org/packages/f0/9a/ce8744e777a74b3050b1bf56be3eed1053b3457302ea055f1ea437200a23/multidict-6.7.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c524c6fb8fc342793708ab111c4dbc90ff9abd568de220432500e47e990c0358", size = 44943, upload-time = "2026-01-26T02:46:14.016Z" }, - { url = "https://files.pythonhosted.org/packages/83/9c/1d2a283d9c6f31e260cb6c2fccadc3edcf6c4c14ee0929cd2af4d2606dd7/multidict-6.7.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:aa23b001d968faef416ff70dc0f1ab045517b9b42a90edd3e9bcdb06479e31d5", size = 44603, upload-time = "2026-01-26T02:46:15.391Z" }, - { url = "https://files.pythonhosted.org/packages/87/9d/3b186201671583d8e8d6d79c07481a5aafd0ba7575e3d8566baec80c1e82/multidict-6.7.1-cp39-cp39-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:6704fa2b7453b2fb121740555fa1ee20cd98c4d011120caf4d2b8d4e7c76eec0", size = 240573, upload-time = "2026-01-26T02:46:16.783Z" }, - { url = "https://files.pythonhosted.org/packages/42/7d/a52f5d4d0754311d1ac78478e34dff88de71259a8585e05ee14e5f877caf/multidict-6.7.1-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:121a34e5bfa410cdf2c8c49716de160de3b1dbcd86b49656f5681e4543bcd1a8", size = 240106, upload-time = "2026-01-26T02:46:18.432Z" }, - { url = "https://files.pythonhosted.org/packages/84/9f/d80118e6c30ff55b7d171bdc5520aad4b9626e657520b8d7c8ca8c2fad12/multidict-6.7.1-cp39-cp39-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:026d264228bcd637d4e060844e39cdc60f86c479e463d49075dedc21b18fbbe0", size = 219418, upload-time = "2026-01-26T02:46:20.526Z" }, - { url = "https://files.pythonhosted.org/packages/c7/bd/896e60b3457f194de77c7de64f9acce9f75da0518a5230ce1df534f6747b/multidict-6.7.1-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:0e697826df7eb63418ee190fd06ce9f1803593bb4b9517d08c60d9b9a7f69d8f", size = 252124, upload-time = "2026-01-26T02:46:22.157Z" }, - { url = "https://files.pythonhosted.org/packages/f4/de/ba6b30447c36a37078d0ba604aa12c1a52887af0c355236ca6e0a9d5286f/multidict-6.7.1-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:bb08271280173720e9fea9ede98e5231defcbad90f1624bea26f32ec8a956e2f", size = 249402, upload-time = "2026-01-26T02:46:23.718Z" }, - { url = "https://files.pythonhosted.org/packages/c2/b2/50a383c96230e432895a2fd3bcfe1b65785899598259d871d5de6b93180c/multidict-6.7.1-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c6b3228e1d80af737b72925ce5fb4daf5a335e49cd7ab77ed7b9fdfbf58c526e", size = 240346, upload-time = "2026-01-26T02:46:25.393Z" }, - { url = "https://files.pythonhosted.org/packages/89/37/16d391fd8da544b1489306e38a46785fa41dd0f0ef766837ed7d4676dde0/multidict-6.7.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:3943debf0fbb57bdde5901695c11094a9a36723e5c03875f87718ee15ca2f4d2", size = 237010, upload-time = "2026-01-26T02:46:27.408Z" }, - { url = "https://files.pythonhosted.org/packages/b0/24/3152ee026eda86d5d3e3685182911e6951af7a016579da931080ce6ac9ad/multidict-6.7.1-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:98c5787b0a0d9a41d9311eae44c3b76e6753def8d8870ab501320efe75a6a5f8", size = 232018, upload-time = "2026-01-26T02:46:29.941Z" }, - { url = "https://files.pythonhosted.org/packages/9c/1f/48d3c27a72be7fd23a55d8847193c459959bf35a5bb5844530dab00b739b/multidict-6.7.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:08ccb2a6dc72009093ebe7f3f073e5ec5964cba9a706fa94b1a1484039b87941", size = 241498, upload-time = "2026-01-26T02:46:32.052Z" }, - { url = "https://files.pythonhosted.org/packages/1a/45/413643ae2952d0decdf6c1250f86d08a43e143271441e81027e38d598bd7/multidict-6.7.1-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:eb351f72c26dc9abe338ca7294661aa22969ad8ffe7ef7d5541d19f368dc854a", size = 247957, upload-time = "2026-01-26T02:46:33.666Z" }, - { url = "https://files.pythonhosted.org/packages/50/f8/f1d0ac23df15e0470776388bdb261506f63af1f81d28bacb5e262d6e12b6/multidict-6.7.1-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:ac1c665bad8b5d762f5f85ebe4d94130c26965f11de70c708c75671297c776de", size = 241651, upload-time = "2026-01-26T02:46:35.7Z" }, - { url = "https://files.pythonhosted.org/packages/2c/c9/1a2a18f383cf129add66b6c36b75c3911a7ba95cf26cb141482de085cc12/multidict-6.7.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:1fa6609d0364f4f6f58351b4659a1f3e0e898ba2a8c5cac04cb2c7bc556b0bc5", size = 236371, upload-time = "2026-01-26T02:46:37.37Z" }, - { url = "https://files.pythonhosted.org/packages/bb/aa/77d87e3fca31325b87e0eb72d5fe9a7472dcb51391a42df7ac1f3842f6c0/multidict-6.7.1-cp39-cp39-win32.whl", hash = "sha256:6f77ce314a29263e67adadc7e7c1bc699fcb3a305059ab973d038f87caa42ed0", size = 41426, upload-time = "2026-01-26T02:46:39.026Z" }, - { url = "https://files.pythonhosted.org/packages/e3/b3/e8863e6a2da15a9d7e98976ff402e871b7352c76566df6c18d0378e0d9cf/multidict-6.7.1-cp39-cp39-win_amd64.whl", hash = "sha256:f537b55778cd3cbee430abe3131255d3a78202e0f9ea7ffc6ada893a4bcaeea4", size = 46180, upload-time = "2026-01-26T02:46:40.422Z" }, - { url = "https://files.pythonhosted.org/packages/93/d3/dd4fa951ad5b5fa216bf30054d705683d13405eea7459833d78f31b74c9c/multidict-6.7.1-cp39-cp39-win_arm64.whl", hash = "sha256:749aa54f578f2e5f439538706a475aa844bfa8ef75854b1401e6e528e4937cf9", size = 43231, upload-time = "2026-01-26T02:46:41.945Z" }, { url = "https://files.pythonhosted.org/packages/81/08/7036c080d7117f28a4af526d794aab6a84463126db031b007717c1a6676e/multidict-6.7.1-py3-none-any.whl", hash = "sha256:55d97cc6dae627efa6a6e548885712d4864b81110ac76fa4e534c03819fa4a56", size = 12319, upload-time = "2026-01-26T02:46:44.004Z" }, ] @@ -3928,12 +3194,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/32/2a/66ba933fe6c76bd40d1fe916a83f04fed253152f451a877520b3c4a5e41e/mypy-1.19.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:28902ee51f12e0f19e1e16fbe2f8f06b6637f482c459dd393efddd0ec7f82045", size = 13601998, upload-time = "2025-12-15T05:03:13.056Z" }, { url = "https://files.pythonhosted.org/packages/e3/da/5055c63e377c5c2418760411fd6a63ee2b96cf95397259038756c042574f/mypy-1.19.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:481daf36a4c443332e2ae9c137dfee878fcea781a2e3f895d54bd3002a900957", size = 13807476, upload-time = "2025-12-15T05:03:17.977Z" }, { url = "https://files.pythonhosted.org/packages/cd/09/4ebd873390a063176f06b0dbf1f7783dd87bd120eae7727fa4ae4179b685/mypy-1.19.1-cp314-cp314-win_amd64.whl", hash = "sha256:8bb5c6f6d043655e055be9b542aa5f3bdd30e4f3589163e85f93f3640060509f", size = 10281872, upload-time = "2025-12-15T05:03:05.549Z" }, - { url = "https://files.pythonhosted.org/packages/b5/f7/88436084550ca9af5e610fa45286be04c3b63374df3e021c762fe8c4369f/mypy-1.19.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7bcfc336a03a1aaa26dfce9fff3e287a3ba99872a157561cbfcebe67c13308e3", size = 13102606, upload-time = "2025-12-15T05:02:46.833Z" }, - { url = "https://files.pythonhosted.org/packages/ca/a5/43dfad311a734b48a752790571fd9e12d61893849a01bff346a54011957f/mypy-1.19.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b7951a701c07ea584c4fe327834b92a30825514c868b1f69c30445093fdd9d5a", size = 12164496, upload-time = "2025-12-15T05:03:41.947Z" }, - { url = "https://files.pythonhosted.org/packages/88/f0/efbfa391395cce2f2771f937e0620cfd185ec88f2b9cd88711028a768e96/mypy-1.19.1-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b13cfdd6c87fc3efb69ea4ec18ef79c74c3f98b4e5498ca9b85ab3b2c2329a67", size = 12772068, upload-time = "2025-12-15T05:02:53.689Z" }, - { url = "https://files.pythonhosted.org/packages/25/05/58b3ba28f5aed10479e899a12d2120d582ba9fa6288851b20bf1c32cbb4f/mypy-1.19.1-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4f28f99c824ecebcdaa2e55d82953e38ff60ee5ec938476796636b86afa3956e", size = 13520385, upload-time = "2025-12-15T05:02:38.328Z" }, - { url = "https://files.pythonhosted.org/packages/c5/a0/c006ccaff50b31e542ae69b92fe7e2f55d99fba3a55e01067dd564325f85/mypy-1.19.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:c608937067d2fc5a4dd1a5ce92fd9e1398691b8c5d012d66e1ddd430e9244376", size = 13796221, upload-time = "2025-12-15T05:03:22.147Z" }, - { url = "https://files.pythonhosted.org/packages/b2/ff/8bdb051cd710f01b880472241bd36b3f817a8e1c5d5540d0b761675b6de2/mypy-1.19.1-cp39-cp39-win_amd64.whl", hash = "sha256:409088884802d511ee52ca067707b90c883426bd95514e8cfda8281dc2effe24", size = 10055456, upload-time = "2025-12-15T05:03:35.169Z" }, { url = "https://files.pythonhosted.org/packages/8d/f4/4ce9a05ce5ded1de3ec1c1d96cf9f9504a04e54ce0ed55cfa38619a32b8d/mypy-1.19.1-py3-none-any.whl", hash = "sha256:f1235f5ea01b7db5468d53ece6aaddf1ad0b88d9e7462b86ef96fe04995d7247", size = 2471239, upload-time = "2025-12-15T05:03:07.248Z" }, ] @@ -3946,31 +3206,12 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505", size = 4963, upload-time = "2025-04-22T14:54:22.983Z" }, ] -[[package]] -name = "nexus-rpc" -version = "1.1.0" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.10'", -] -dependencies = [ - { name = "typing-extensions", marker = "python_full_version < '3.10'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/ef/66/540687556bd28cf1ec370cc6881456203dfddb9dab047b8979c6865b5984/nexus_rpc-1.1.0.tar.gz", hash = "sha256:d65ad6a2f54f14e53ebe39ee30555eaeb894102437125733fb13034a04a44553", size = 77383, upload-time = "2025-07-07T19:03:58.368Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/bf/2f/9e9d0dcaa4c6ffa22b7aa31069a8a264c753ff8027b36af602cce038c92f/nexus_rpc-1.1.0-py3-none-any.whl", hash = "sha256:d1b007af2aba186a27e736f8eaae39c03aed05b488084ff6c3d1785c9ba2ad38", size = 27743, upload-time = "2025-07-07T19:03:57.556Z" }, -] - [[package]] name = "nexus-rpc" version = "1.2.0" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.14'", - "python_full_version >= '3.10' and python_full_version < '3.14'", -] dependencies = [ - { name = "typing-extensions", marker = "python_full_version >= '3.10'" }, + { name = "typing-extensions" }, ] sdist = { url = "https://files.pythonhosted.org/packages/06/50/95d7bc91f900da5e22662c82d9bf0f72a4b01f2a552708bf2f43807707a1/nexus_rpc-1.2.0.tar.gz", hash = "sha256:b4ddaffa4d3996aaeadf49b80dfcdfbca48fe4cb616defaf3b3c5c2c8fc61890", size = 74142, upload-time = "2025-11-17T19:17:06.798Z" } wheels = [ @@ -4001,7 +3242,7 @@ name = "openapi-pydantic" version = "0.5.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pydantic", marker = "python_full_version >= '3.10'" }, + { name = "pydantic" }, ] sdist = { url = "https://files.pythonhosted.org/packages/02/2e/58d83848dd1a79cb92ed8e63f6ba901ca282c5f09d04af9423ec26c56fd7/openapi_pydantic-0.5.1.tar.gz", hash = "sha256:ff6835af6bde7a459fb93eb93bb92b8749b754fc6e51b2f1590a19dc3005ee0d", size = 60892, upload-time = "2025-01-08T19:29:27.083Z" } wheels = [ @@ -4026,7 +3267,7 @@ name = "opentelemetry-exporter-otlp-proto-common" version = "1.39.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "opentelemetry-proto", marker = "python_full_version >= '3.10'" }, + { name = "opentelemetry-proto" }, ] sdist = { url = "https://files.pythonhosted.org/packages/e9/9d/22d241b66f7bbde88a3bfa6847a351d2c46b84de23e71222c6aae25c7050/opentelemetry_exporter_otlp_proto_common-1.39.1.tar.gz", hash = "sha256:763370d4737a59741c89a67b50f9e39271639ee4afc999dadfe768541c027464", size = 20409, upload-time = "2025-12-11T13:32:40.885Z" } wheels = [ @@ -4038,13 +3279,13 @@ name = "opentelemetry-exporter-otlp-proto-http" version = "1.39.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "googleapis-common-protos", marker = "python_full_version >= '3.10'" }, - { name = "opentelemetry-api", marker = "python_full_version >= '3.10'" }, - { name = "opentelemetry-exporter-otlp-proto-common", marker = "python_full_version >= '3.10'" }, - { name = "opentelemetry-proto", marker = "python_full_version >= '3.10'" }, - { name = "opentelemetry-sdk", marker = "python_full_version >= '3.10'" }, - { name = "requests", marker = "python_full_version >= '3.10'" }, - { name = "typing-extensions", marker = "python_full_version >= '3.10'" }, + { name = "googleapis-common-protos" }, + { name = "opentelemetry-api" }, + { name = "opentelemetry-exporter-otlp-proto-common" }, + { name = "opentelemetry-proto" }, + { name = "opentelemetry-sdk" }, + { name = "requests" }, + { name = "typing-extensions" }, ] sdist = { url = "https://files.pythonhosted.org/packages/80/04/2a08fa9c0214ae38880df01e8bfae12b067ec0793446578575e5080d6545/opentelemetry_exporter_otlp_proto_http-1.39.1.tar.gz", hash = "sha256:31bdab9745c709ce90a49a0624c2bd445d31a28ba34275951a6a362d16a0b9cb", size = 17288, upload-time = "2025-12-11T13:32:42.029Z" } wheels = [ @@ -4056,10 +3297,10 @@ name = "opentelemetry-instrumentation" version = "0.60b1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "opentelemetry-api", marker = "python_full_version >= '3.10'" }, - { name = "opentelemetry-semantic-conventions", marker = "python_full_version >= '3.10'" }, - { name = "packaging", marker = "python_full_version >= '3.10'" }, - { name = "wrapt", marker = "python_full_version >= '3.10'" }, + { name = "opentelemetry-api" }, + { name = "opentelemetry-semantic-conventions" }, + { name = "packaging" }, + { name = "wrapt" }, ] sdist = { url = "https://files.pythonhosted.org/packages/41/0f/7e6b713ac117c1f5e4e3300748af699b9902a2e5e34c9cf443dde25a01fa/opentelemetry_instrumentation-0.60b1.tar.gz", hash = "sha256:57ddc7974c6eb35865af0426d1a17132b88b2ed8586897fee187fd5b8944bd6a", size = 31706, upload-time = "2025-12-11T13:36:42.515Z" } wheels = [ @@ -4071,11 +3312,11 @@ name = "opentelemetry-instrumentation-httpx" version = "0.60b1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "opentelemetry-api", marker = "python_full_version >= '3.10'" }, - { name = "opentelemetry-instrumentation", marker = "python_full_version >= '3.10'" }, - { name = "opentelemetry-semantic-conventions", marker = "python_full_version >= '3.10'" }, - { name = "opentelemetry-util-http", marker = "python_full_version >= '3.10'" }, - { name = "wrapt", marker = "python_full_version >= '3.10'" }, + { name = "opentelemetry-api" }, + { name = "opentelemetry-instrumentation" }, + { name = "opentelemetry-semantic-conventions" }, + { name = "opentelemetry-util-http" }, + { name = "wrapt" }, ] sdist = { url = "https://files.pythonhosted.org/packages/86/08/11208bcfcab4fc2023252c3f322aa397fd9ad948355fea60f5fc98648603/opentelemetry_instrumentation_httpx-0.60b1.tar.gz", hash = "sha256:a506ebaf28c60112cbe70ad4f0338f8603f148938cb7b6794ce1051cd2b270ae", size = 20611, upload-time = "2025-12-11T13:37:01.661Z" } wheels = [ @@ -4087,7 +3328,7 @@ name = "opentelemetry-proto" version = "1.39.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "protobuf", version = "6.33.5", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "protobuf" }, ] sdist = { url = "https://files.pythonhosted.org/packages/49/1d/f25d76d8260c156c40c97c9ed4511ec0f9ce353f8108ca6e7561f82a06b2/opentelemetry_proto-1.39.1.tar.gz", hash = "sha256:6c8e05144fc0d3ed4d22c2289c6b126e03bcd0e6a7da0f16cedd2e1c2772e2c8", size = 46152, upload-time = "2025-12-11T13:32:48.681Z" } wheels = [ @@ -4099,9 +3340,9 @@ name = "opentelemetry-sdk" version = "1.39.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "opentelemetry-api", marker = "python_full_version >= '3.10'" }, - { name = "opentelemetry-semantic-conventions", marker = "python_full_version >= '3.10'" }, - { name = "typing-extensions", marker = "python_full_version >= '3.10'" }, + { name = "opentelemetry-api" }, + { name = "opentelemetry-semantic-conventions" }, + { name = "typing-extensions" }, ] sdist = { url = "https://files.pythonhosted.org/packages/eb/fb/c76080c9ba07e1e8235d24cdcc4d125ef7aa3edf23eb4e497c2e50889adc/opentelemetry_sdk-1.39.1.tar.gz", hash = "sha256:cf4d4563caf7bff906c9f7967e2be22d0d6b349b908be0d90fb21c8e9c995cc6", size = 171460, upload-time = "2025-12-11T13:32:49.369Z" } wheels = [ @@ -4113,8 +3354,8 @@ name = "opentelemetry-semantic-conventions" version = "0.60b1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "opentelemetry-api", marker = "python_full_version >= '3.10'" }, - { name = "typing-extensions", marker = "python_full_version >= '3.10'" }, + { name = "opentelemetry-api" }, + { name = "typing-extensions" }, ] sdist = { url = "https://files.pythonhosted.org/packages/91/df/553f93ed38bf22f4b999d9be9c185adb558982214f33eae539d3b5cd0858/opentelemetry_semantic_conventions-0.60b1.tar.gz", hash = "sha256:87c228b5a0669b748c76d76df6c364c369c28f1c465e50f661e39737e84bc953", size = 137935, upload-time = "2025-12-11T13:32:50.487Z" } wheels = [ @@ -4130,111 +3371,10 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/16/5c/d3f1733665f7cd582ef0842fb1d2ed0bc1fba10875160593342d22bba375/opentelemetry_util_http-0.60b1-py3-none-any.whl", hash = "sha256:66381ba28550c91bee14dcba8979ace443444af1ed609226634596b4b0faf199", size = 8947, upload-time = "2025-12-11T13:36:37.151Z" }, ] -[[package]] -name = "orjson" -version = "3.11.5" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.10'", -] -sdist = { url = "https://files.pythonhosted.org/packages/04/b8/333fdb27840f3bf04022d21b654a35f58e15407183aeb16f3b41aa053446/orjson-3.11.5.tar.gz", hash = "sha256:82393ab47b4fe44ffd0a7659fa9cfaacc717eb617c93cde83795f14af5c2e9d5", size = 5972347, upload-time = "2025-12-06T15:55:39.458Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/79/19/b22cf9dad4db20c8737041046054cbd4f38bb5a2d0e4bb60487832ce3d76/orjson-3.11.5-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:df9eadb2a6386d5ea2bfd81309c505e125cfc9ba2b1b99a97e60985b0b3665d1", size = 245719, upload-time = "2025-12-06T15:53:43.877Z" }, - { url = "https://files.pythonhosted.org/packages/03/2e/b136dd6bf30ef5143fbe76a4c142828b55ccc618be490201e9073ad954a1/orjson-3.11.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ccc70da619744467d8f1f49a8cadae5ec7bbe054e5232d95f92ed8737f8c5870", size = 132467, upload-time = "2025-12-06T15:53:45.379Z" }, - { url = "https://files.pythonhosted.org/packages/ae/fc/ae99bfc1e1887d20a0268f0e2686eb5b13d0ea7bbe01de2b566febcd2130/orjson-3.11.5-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:073aab025294c2f6fc0807201c76fdaed86f8fc4be52c440fb78fbb759a1ac09", size = 130702, upload-time = "2025-12-06T15:53:46.659Z" }, - { url = "https://files.pythonhosted.org/packages/6e/43/ef7912144097765997170aca59249725c3ab8ef6079f93f9d708dd058df5/orjson-3.11.5-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:835f26fa24ba0bb8c53ae2a9328d1706135b74ec653ed933869b74b6909e63fd", size = 135907, upload-time = "2025-12-06T15:53:48.487Z" }, - { url = "https://files.pythonhosted.org/packages/3f/da/24d50e2d7f4092ddd4d784e37a3fa41f22ce8ed97abc9edd222901a96e74/orjson-3.11.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:667c132f1f3651c14522a119e4dd631fad98761fa960c55e8e7430bb2a1ba4ac", size = 139935, upload-time = "2025-12-06T15:53:49.88Z" }, - { url = "https://files.pythonhosted.org/packages/02/4a/b4cb6fcbfff5b95a3a019a8648255a0fac9b221fbf6b6e72be8df2361feb/orjson-3.11.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:42e8961196af655bb5e63ce6c60d25e8798cd4dfbc04f4203457fa3869322c2e", size = 137541, upload-time = "2025-12-06T15:53:51.226Z" }, - { url = "https://files.pythonhosted.org/packages/a5/99/a11bd129f18c2377c27b2846a9d9be04acec981f770d711ba0aaea563984/orjson-3.11.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75412ca06e20904c19170f8a24486c4e6c7887dea591ba18a1ab572f1300ee9f", size = 139031, upload-time = "2025-12-06T15:53:52.309Z" }, - { url = "https://files.pythonhosted.org/packages/64/29/d7b77d7911574733a036bb3e8ad7053ceb2b7d6ea42208b9dbc55b23b9ed/orjson-3.11.5-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:6af8680328c69e15324b5af3ae38abbfcf9cbec37b5346ebfd52339c3d7e8a18", size = 141622, upload-time = "2025-12-06T15:53:53.606Z" }, - { url = "https://files.pythonhosted.org/packages/93/41/332db96c1de76b2feda4f453e91c27202cd092835936ce2b70828212f726/orjson-3.11.5-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:a86fe4ff4ea523eac8f4b57fdac319faf037d3c1be12405e6a7e86b3fbc4756a", size = 413800, upload-time = "2025-12-06T15:53:54.866Z" }, - { url = "https://files.pythonhosted.org/packages/76/e1/5a0d148dd1f89ad2f9651df67835b209ab7fcb1118658cf353425d7563e9/orjson-3.11.5-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e607b49b1a106ee2086633167033afbd63f76f2999e9236f638b06b112b24ea7", size = 151198, upload-time = "2025-12-06T15:53:56.383Z" }, - { url = "https://files.pythonhosted.org/packages/0d/96/8db67430d317a01ae5cf7971914f6775affdcfe99f5bff9ef3da32492ecc/orjson-3.11.5-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7339f41c244d0eea251637727f016b3d20050636695bc78345cce9029b189401", size = 141984, upload-time = "2025-12-06T15:53:57.746Z" }, - { url = "https://files.pythonhosted.org/packages/71/49/40d21e1aa1ac569e521069228bb29c9b5a350344ccf922a0227d93c2ed44/orjson-3.11.5-cp310-cp310-win32.whl", hash = "sha256:8be318da8413cdbbce77b8c5fac8d13f6eb0f0db41b30bb598631412619572e8", size = 135272, upload-time = "2025-12-06T15:53:59.769Z" }, - { url = "https://files.pythonhosted.org/packages/c4/7e/d0e31e78be0c100e08be64f48d2850b23bcb4d4c70d114f4e43b39f6895a/orjson-3.11.5-cp310-cp310-win_amd64.whl", hash = "sha256:b9f86d69ae822cabc2a0f6c099b43e8733dda788405cba2665595b7e8dd8d167", size = 133360, upload-time = "2025-12-06T15:54:01.25Z" }, - { url = "https://files.pythonhosted.org/packages/fd/68/6b3659daec3a81aed5ab47700adb1a577c76a5452d35b91c88efee89987f/orjson-3.11.5-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:9c8494625ad60a923af6b2b0bd74107146efe9b55099e20d7740d995f338fcd8", size = 245318, upload-time = "2025-12-06T15:54:02.355Z" }, - { url = "https://files.pythonhosted.org/packages/e9/00/92db122261425f61803ccf0830699ea5567439d966cbc35856fe711bfe6b/orjson-3.11.5-cp311-cp311-macosx_15_0_arm64.whl", hash = "sha256:7bb2ce0b82bc9fd1168a513ddae7a857994b780b2945a8c51db4ab1c4b751ebc", size = 129491, upload-time = "2025-12-06T15:54:03.877Z" }, - { url = "https://files.pythonhosted.org/packages/94/4f/ffdcb18356518809d944e1e1f77589845c278a1ebbb5a8297dfefcc4b4cb/orjson-3.11.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:67394d3becd50b954c4ecd24ac90b5051ee7c903d167459f93e77fc6f5b4c968", size = 132167, upload-time = "2025-12-06T15:54:04.944Z" }, - { url = "https://files.pythonhosted.org/packages/97/c6/0a8caff96f4503f4f7dd44e40e90f4d14acf80d3b7a97cb88747bb712d3e/orjson-3.11.5-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:298d2451f375e5f17b897794bcc3e7b821c0f32b4788b9bcae47ada24d7f3cf7", size = 130516, upload-time = "2025-12-06T15:54:06.274Z" }, - { url = "https://files.pythonhosted.org/packages/4d/63/43d4dc9bd9954bff7052f700fdb501067f6fb134a003ddcea2a0bb3854ed/orjson-3.11.5-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aa5e4244063db8e1d87e0f54c3f7522f14b2dc937e65d5241ef0076a096409fd", size = 135695, upload-time = "2025-12-06T15:54:07.702Z" }, - { url = "https://files.pythonhosted.org/packages/87/6f/27e2e76d110919cb7fcb72b26166ee676480a701bcf8fc53ac5d0edce32f/orjson-3.11.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1db2088b490761976c1b2e956d5d4e6409f3732e9d79cfa69f876c5248d1baf9", size = 139664, upload-time = "2025-12-06T15:54:08.828Z" }, - { url = "https://files.pythonhosted.org/packages/d4/f8/5966153a5f1be49b5fbb8ca619a529fde7bc71aa0a376f2bb83fed248bcd/orjson-3.11.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c2ed66358f32c24e10ceea518e16eb3549e34f33a9d51f99ce23b0251776a1ef", size = 137289, upload-time = "2025-12-06T15:54:09.898Z" }, - { url = "https://files.pythonhosted.org/packages/a7/34/8acb12ff0299385c8bbcbb19fbe40030f23f15a6de57a9c587ebf71483fb/orjson-3.11.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c2021afda46c1ed64d74b555065dbd4c2558d510d8cec5ea6a53001b3e5e82a9", size = 138784, upload-time = "2025-12-06T15:54:11.022Z" }, - { url = "https://files.pythonhosted.org/packages/ee/27/910421ea6e34a527f73d8f4ee7bdffa48357ff79c7b8d6eb6f7b82dd1176/orjson-3.11.5-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b42ffbed9128e547a1647a3e50bc88ab28ae9daa61713962e0d3dd35e820c125", size = 141322, upload-time = "2025-12-06T15:54:12.427Z" }, - { url = "https://files.pythonhosted.org/packages/87/a3/4b703edd1a05555d4bb1753d6ce44e1a05b7a6d7c164d5b332c795c63d70/orjson-3.11.5-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:8d5f16195bb671a5dd3d1dbea758918bada8f6cc27de72bd64adfbd748770814", size = 413612, upload-time = "2025-12-06T15:54:13.858Z" }, - { url = "https://files.pythonhosted.org/packages/1b/36/034177f11d7eeea16d3d2c42a1883b0373978e08bc9dad387f5074c786d8/orjson-3.11.5-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:c0e5d9f7a0227df2927d343a6e3859bebf9208b427c79bd31949abcc2fa32fa5", size = 150993, upload-time = "2025-12-06T15:54:15.189Z" }, - { url = "https://files.pythonhosted.org/packages/44/2f/ea8b24ee046a50a7d141c0227c4496b1180b215e728e3b640684f0ea448d/orjson-3.11.5-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:23d04c4543e78f724c4dfe656b3791b5f98e4c9253e13b2636f1af5d90e4a880", size = 141774, upload-time = "2025-12-06T15:54:16.451Z" }, - { url = "https://files.pythonhosted.org/packages/8a/12/cc440554bf8200eb23348a5744a575a342497b65261cd65ef3b28332510a/orjson-3.11.5-cp311-cp311-win32.whl", hash = "sha256:c404603df4865f8e0afe981aa3c4b62b406e6d06049564d58934860b62b7f91d", size = 135109, upload-time = "2025-12-06T15:54:17.73Z" }, - { url = "https://files.pythonhosted.org/packages/a3/83/e0c5aa06ba73a6760134b169f11fb970caa1525fa4461f94d76e692299d9/orjson-3.11.5-cp311-cp311-win_amd64.whl", hash = "sha256:9645ef655735a74da4990c24ffbd6894828fbfa117bc97c1edd98c282ecb52e1", size = 133193, upload-time = "2025-12-06T15:54:19.426Z" }, - { url = "https://files.pythonhosted.org/packages/cb/35/5b77eaebc60d735e832c5b1a20b155667645d123f09d471db0a78280fb49/orjson-3.11.5-cp311-cp311-win_arm64.whl", hash = "sha256:1cbf2735722623fcdee8e712cbaaab9e372bbcb0c7924ad711b261c2eccf4a5c", size = 126830, upload-time = "2025-12-06T15:54:20.836Z" }, - { url = "https://files.pythonhosted.org/packages/ef/a4/8052a029029b096a78955eadd68ab594ce2197e24ec50e6b6d2ab3f4e33b/orjson-3.11.5-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:334e5b4bff9ad101237c2d799d9fd45737752929753bf4faf4b207335a416b7d", size = 245347, upload-time = "2025-12-06T15:54:22.061Z" }, - { url = "https://files.pythonhosted.org/packages/64/67/574a7732bd9d9d79ac620c8790b4cfe0717a3d5a6eb2b539e6e8995e24a0/orjson-3.11.5-cp312-cp312-macosx_15_0_arm64.whl", hash = "sha256:ff770589960a86eae279f5d8aa536196ebda8273a2a07db2a54e82b93bc86626", size = 129435, upload-time = "2025-12-06T15:54:23.615Z" }, - { url = "https://files.pythonhosted.org/packages/52/8d/544e77d7a29d90cf4d9eecd0ae801c688e7f3d1adfa2ebae5e1e94d38ab9/orjson-3.11.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ed24250e55efbcb0b35bed7caaec8cedf858ab2f9f2201f17b8938c618c8ca6f", size = 132074, upload-time = "2025-12-06T15:54:24.694Z" }, - { url = "https://files.pythonhosted.org/packages/6e/57/b9f5b5b6fbff9c26f77e785baf56ae8460ef74acdb3eae4931c25b8f5ba9/orjson-3.11.5-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a66d7769e98a08a12a139049aac2f0ca3adae989817f8c43337455fbc7669b85", size = 130520, upload-time = "2025-12-06T15:54:26.185Z" }, - { url = "https://files.pythonhosted.org/packages/f6/6d/d34970bf9eb33f9ec7c979a262cad86076814859e54eb9a059a52f6dc13d/orjson-3.11.5-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:86cfc555bfd5794d24c6a1903e558b50644e5e68e6471d66502ce5cb5fdef3f9", size = 136209, upload-time = "2025-12-06T15:54:27.264Z" }, - { url = "https://files.pythonhosted.org/packages/e7/39/bc373b63cc0e117a105ea12e57280f83ae52fdee426890d57412432d63b3/orjson-3.11.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a230065027bc2a025e944f9d4714976a81e7ecfa940923283bca7bbc1f10f626", size = 139837, upload-time = "2025-12-06T15:54:28.75Z" }, - { url = "https://files.pythonhosted.org/packages/cb/aa/7c4818c8d7d324da220f4f1af55c343956003aa4d1ce1857bdc1d396ba69/orjson-3.11.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b29d36b60e606df01959c4b982729c8845c69d1963f88686608be9ced96dbfaa", size = 137307, upload-time = "2025-12-06T15:54:29.856Z" }, - { url = "https://files.pythonhosted.org/packages/46/bf/0993b5a056759ba65145effe3a79dd5a939d4a070eaa5da2ee3180fbb13f/orjson-3.11.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c74099c6b230d4261fdc3169d50efc09abf38ace1a42ea2f9994b1d79153d477", size = 139020, upload-time = "2025-12-06T15:54:31.024Z" }, - { url = "https://files.pythonhosted.org/packages/65/e8/83a6c95db3039e504eda60fc388f9faedbb4f6472f5aba7084e06552d9aa/orjson-3.11.5-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e697d06ad57dd0c7a737771d470eedc18e68dfdefcdd3b7de7f33dfda5b6212e", size = 141099, upload-time = "2025-12-06T15:54:32.196Z" }, - { url = "https://files.pythonhosted.org/packages/b9/b4/24fdc024abfce31c2f6812973b0a693688037ece5dc64b7a60c1ce69e2f2/orjson-3.11.5-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:e08ca8a6c851e95aaecc32bc44a5aa75d0ad26af8cdac7c77e4ed93acf3d5b69", size = 413540, upload-time = "2025-12-06T15:54:33.361Z" }, - { url = "https://files.pythonhosted.org/packages/d9/37/01c0ec95d55ed0c11e4cae3e10427e479bba40c77312b63e1f9665e0737d/orjson-3.11.5-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:e8b5f96c05fce7d0218df3fdfeb962d6b8cfff7e3e20264306b46dd8b217c0f3", size = 151530, upload-time = "2025-12-06T15:54:34.6Z" }, - { url = "https://files.pythonhosted.org/packages/f9/d4/f9ebc57182705bb4bbe63f5bbe14af43722a2533135e1d2fb7affa0c355d/orjson-3.11.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ddbfdb5099b3e6ba6d6ea818f61997bb66de14b411357d24c4612cf1ebad08ca", size = 141863, upload-time = "2025-12-06T15:54:35.801Z" }, - { url = "https://files.pythonhosted.org/packages/0d/04/02102b8d19fdcb009d72d622bb5781e8f3fae1646bf3e18c53d1bc8115b5/orjson-3.11.5-cp312-cp312-win32.whl", hash = "sha256:9172578c4eb09dbfcf1657d43198de59b6cef4054de385365060ed50c458ac98", size = 135255, upload-time = "2025-12-06T15:54:37.209Z" }, - { url = "https://files.pythonhosted.org/packages/d4/fb/f05646c43d5450492cb387de5549f6de90a71001682c17882d9f66476af5/orjson-3.11.5-cp312-cp312-win_amd64.whl", hash = "sha256:2b91126e7b470ff2e75746f6f6ee32b9ab67b7a93c8ba1d15d3a0caaf16ec875", size = 133252, upload-time = "2025-12-06T15:54:38.401Z" }, - { url = "https://files.pythonhosted.org/packages/dc/a6/7b8c0b26ba18c793533ac1cd145e131e46fcf43952aa94c109b5b913c1f0/orjson-3.11.5-cp312-cp312-win_arm64.whl", hash = "sha256:acbc5fac7e06777555b0722b8ad5f574739e99ffe99467ed63da98f97f9ca0fe", size = 126777, upload-time = "2025-12-06T15:54:39.515Z" }, - { url = "https://files.pythonhosted.org/packages/10/43/61a77040ce59f1569edf38f0b9faadc90c8cf7e9bec2e0df51d0132c6bb7/orjson-3.11.5-cp313-cp313-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:3b01799262081a4c47c035dd77c1301d40f568f77cc7ec1bb7db5d63b0a01629", size = 245271, upload-time = "2025-12-06T15:54:40.878Z" }, - { url = "https://files.pythonhosted.org/packages/55/f9/0f79be617388227866d50edd2fd320cb8fb94dc1501184bb1620981a0aba/orjson-3.11.5-cp313-cp313-macosx_15_0_arm64.whl", hash = "sha256:61de247948108484779f57a9f406e4c84d636fa5a59e411e6352484985e8a7c3", size = 129422, upload-time = "2025-12-06T15:54:42.403Z" }, - { url = "https://files.pythonhosted.org/packages/77/42/f1bf1549b432d4a78bfa95735b79b5dac75b65b5bb815bba86ad406ead0a/orjson-3.11.5-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:894aea2e63d4f24a7f04a1908307c738d0dce992e9249e744b8f4e8dd9197f39", size = 132060, upload-time = "2025-12-06T15:54:43.531Z" }, - { url = "https://files.pythonhosted.org/packages/25/49/825aa6b929f1a6ed244c78acd7b22c1481fd7e5fda047dc8bf4c1a807eb6/orjson-3.11.5-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ddc21521598dbe369d83d4d40338e23d4101dad21dae0e79fa20465dbace019f", size = 130391, upload-time = "2025-12-06T15:54:45.059Z" }, - { url = "https://files.pythonhosted.org/packages/42/ec/de55391858b49e16e1aa8f0bbbb7e5997b7345d8e984a2dec3746d13065b/orjson-3.11.5-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7cce16ae2f5fb2c53c3eafdd1706cb7b6530a67cc1c17abe8ec747f5cd7c0c51", size = 135964, upload-time = "2025-12-06T15:54:46.576Z" }, - { url = "https://files.pythonhosted.org/packages/1c/40/820bc63121d2d28818556a2d0a09384a9f0262407cf9fa305e091a8048df/orjson-3.11.5-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e46c762d9f0e1cfb4ccc8515de7f349abbc95b59cb5a2bd68df5973fdef913f8", size = 139817, upload-time = "2025-12-06T15:54:48.084Z" }, - { url = "https://files.pythonhosted.org/packages/09/c7/3a445ca9a84a0d59d26365fd8898ff52bdfcdcb825bcc6519830371d2364/orjson-3.11.5-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d7345c759276b798ccd6d77a87136029e71e66a8bbf2d2755cbdde1d82e78706", size = 137336, upload-time = "2025-12-06T15:54:49.426Z" }, - { url = "https://files.pythonhosted.org/packages/9a/b3/dc0d3771f2e5d1f13368f56b339c6782f955c6a20b50465a91acb79fe961/orjson-3.11.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75bc2e59e6a2ac1dd28901d07115abdebc4563b5b07dd612bf64260a201b1c7f", size = 138993, upload-time = "2025-12-06T15:54:50.939Z" }, - { url = "https://files.pythonhosted.org/packages/d1/a2/65267e959de6abe23444659b6e19c888f242bf7725ff927e2292776f6b89/orjson-3.11.5-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:54aae9b654554c3b4edd61896b978568c6daa16af96fa4681c9b5babd469f863", size = 141070, upload-time = "2025-12-06T15:54:52.414Z" }, - { url = "https://files.pythonhosted.org/packages/63/c9/da44a321b288727a322c6ab17e1754195708786a04f4f9d2220a5076a649/orjson-3.11.5-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:4bdd8d164a871c4ec773f9de0f6fe8769c2d6727879c37a9666ba4183b7f8228", size = 413505, upload-time = "2025-12-06T15:54:53.67Z" }, - { url = "https://files.pythonhosted.org/packages/7f/17/68dc14fa7000eefb3d4d6d7326a190c99bb65e319f02747ef3ebf2452f12/orjson-3.11.5-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:a261fef929bcf98a60713bf5e95ad067cea16ae345d9a35034e73c3990e927d2", size = 151342, upload-time = "2025-12-06T15:54:55.113Z" }, - { url = "https://files.pythonhosted.org/packages/c4/c5/ccee774b67225bed630a57478529fc026eda33d94fe4c0eac8fe58d4aa52/orjson-3.11.5-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:c028a394c766693c5c9909dec76b24f37e6a1b91999e8d0c0d5feecbe93c3e05", size = 141823, upload-time = "2025-12-06T15:54:56.331Z" }, - { url = "https://files.pythonhosted.org/packages/67/80/5d00e4155d0cd7390ae2087130637671da713959bb558db9bac5e6f6b042/orjson-3.11.5-cp313-cp313-win32.whl", hash = "sha256:2cc79aaad1dfabe1bd2d50ee09814a1253164b3da4c00a78c458d82d04b3bdef", size = 135236, upload-time = "2025-12-06T15:54:57.507Z" }, - { url = "https://files.pythonhosted.org/packages/95/fe/792cc06a84808dbdc20ac6eab6811c53091b42f8e51ecebf14b540e9cfe4/orjson-3.11.5-cp313-cp313-win_amd64.whl", hash = "sha256:ff7877d376add4e16b274e35a3f58b7f37b362abf4aa31863dadacdd20e3a583", size = 133167, upload-time = "2025-12-06T15:54:58.71Z" }, - { url = "https://files.pythonhosted.org/packages/46/2c/d158bd8b50e3b1cfdcf406a7e463f6ffe3f0d167b99634717acdaf5e299f/orjson-3.11.5-cp313-cp313-win_arm64.whl", hash = "sha256:59ac72ea775c88b163ba8d21b0177628bd015c5dd060647bbab6e22da3aad287", size = 126712, upload-time = "2025-12-06T15:54:59.892Z" }, - { url = "https://files.pythonhosted.org/packages/c2/60/77d7b839e317ead7bb225d55bb50f7ea75f47afc489c81199befc5435b50/orjson-3.11.5-cp314-cp314-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:e446a8ea0a4c366ceafc7d97067bfd55292969143b57e3c846d87fc701e797a0", size = 245252, upload-time = "2025-12-06T15:55:01.127Z" }, - { url = "https://files.pythonhosted.org/packages/f1/aa/d4639163b400f8044cef0fb9aa51b0337be0da3a27187a20d1166e742370/orjson-3.11.5-cp314-cp314-macosx_15_0_arm64.whl", hash = "sha256:53deb5addae9c22bbe3739298f5f2196afa881ea75944e7720681c7080909a81", size = 129419, upload-time = "2025-12-06T15:55:02.723Z" }, - { url = "https://files.pythonhosted.org/packages/30/94/9eabf94f2e11c671111139edf5ec410d2f21e6feee717804f7e8872d883f/orjson-3.11.5-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:82cd00d49d6063d2b8791da5d4f9d20539c5951f965e45ccf4e96d33505ce68f", size = 132050, upload-time = "2025-12-06T15:55:03.918Z" }, - { url = "https://files.pythonhosted.org/packages/3d/c8/ca10f5c5322f341ea9a9f1097e140be17a88f88d1cfdd29df522970d9744/orjson-3.11.5-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3fd15f9fc8c203aeceff4fda211157fad114dde66e92e24097b3647a08f4ee9e", size = 130370, upload-time = "2025-12-06T15:55:05.173Z" }, - { url = "https://files.pythonhosted.org/packages/25/d4/e96824476d361ee2edd5c6290ceb8d7edf88d81148a6ce172fc00278ca7f/orjson-3.11.5-cp314-cp314-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9df95000fbe6777bf9820ae82ab7578e8662051bb5f83d71a28992f539d2cda7", size = 136012, upload-time = "2025-12-06T15:55:06.402Z" }, - { url = "https://files.pythonhosted.org/packages/85/8e/9bc3423308c425c588903f2d103cfcfe2539e07a25d6522900645a6f257f/orjson-3.11.5-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:92a8d676748fca47ade5bc3da7430ed7767afe51b2f8100e3cd65e151c0eaceb", size = 139809, upload-time = "2025-12-06T15:55:07.656Z" }, - { url = "https://files.pythonhosted.org/packages/e9/3c/b404e94e0b02a232b957c54643ce68d0268dacb67ac33ffdee24008c8b27/orjson-3.11.5-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:aa0f513be38b40234c77975e68805506cad5d57b3dfd8fe3baa7f4f4051e15b4", size = 137332, upload-time = "2025-12-06T15:55:08.961Z" }, - { url = "https://files.pythonhosted.org/packages/51/30/cc2d69d5ce0ad9b84811cdf4a0cd5362ac27205a921da524ff42f26d65e0/orjson-3.11.5-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa1863e75b92891f553b7922ce4ee10ed06db061e104f2b7815de80cdcb135ad", size = 138983, upload-time = "2025-12-06T15:55:10.595Z" }, - { url = "https://files.pythonhosted.org/packages/0e/87/de3223944a3e297d4707d2fe3b1ffb71437550e165eaf0ca8bbe43ccbcb1/orjson-3.11.5-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:d4be86b58e9ea262617b8ca6251a2f0d63cc132a6da4b5fcc8e0a4128782c829", size = 141069, upload-time = "2025-12-06T15:55:11.832Z" }, - { url = "https://files.pythonhosted.org/packages/65/30/81d5087ae74be33bcae3ff2d80f5ccaa4a8fedc6d39bf65a427a95b8977f/orjson-3.11.5-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:b923c1c13fa02084eb38c9c065afd860a5cff58026813319a06949c3af5732ac", size = 413491, upload-time = "2025-12-06T15:55:13.314Z" }, - { url = "https://files.pythonhosted.org/packages/d0/6f/f6058c21e2fc1efaf918986dbc2da5cd38044f1a2d4b7b91ad17c4acf786/orjson-3.11.5-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:1b6bd351202b2cd987f35a13b5e16471cf4d952b42a73c391cc537974c43ef6d", size = 151375, upload-time = "2025-12-06T15:55:14.715Z" }, - { url = "https://files.pythonhosted.org/packages/54/92/c6921f17d45e110892899a7a563a925b2273d929959ce2ad89e2525b885b/orjson-3.11.5-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:bb150d529637d541e6af06bbe3d02f5498d628b7f98267ff87647584293ab439", size = 141850, upload-time = "2025-12-06T15:55:15.94Z" }, - { url = "https://files.pythonhosted.org/packages/88/86/cdecb0140a05e1a477b81f24739da93b25070ee01ce7f7242f44a6437594/orjson-3.11.5-cp314-cp314-win32.whl", hash = "sha256:9cc1e55c884921434a84a0c3dd2699eb9f92e7b441d7f53f3941079ec6ce7499", size = 135278, upload-time = "2025-12-06T15:55:17.202Z" }, - { url = "https://files.pythonhosted.org/packages/e4/97/b638d69b1e947d24f6109216997e38922d54dcdcdb1b11c18d7efd2d3c59/orjson-3.11.5-cp314-cp314-win_amd64.whl", hash = "sha256:a4f3cb2d874e03bc7767c8f88adaa1a9a05cecea3712649c3b58589ec7317310", size = 133170, upload-time = "2025-12-06T15:55:18.468Z" }, - { url = "https://files.pythonhosted.org/packages/8f/dd/f4fff4a6fe601b4f8f3ba3aa6da8ac33d17d124491a3b804c662a70e1636/orjson-3.11.5-cp314-cp314-win_arm64.whl", hash = "sha256:38b22f476c351f9a1c43e5b07d8b5a02eb24a6ab8e75f700f7d479d4568346a5", size = 126713, upload-time = "2025-12-06T15:55:19.738Z" }, - { url = "https://files.pythonhosted.org/packages/50/c7/7b682849dd4c9fb701a981669b964ea700516ecbd8e88f62aae07c6852bd/orjson-3.11.5-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:1b280e2d2d284a6713b0cfec7b08918ebe57df23e3f76b27586197afca3cb1e9", size = 245298, upload-time = "2025-12-06T15:55:20.984Z" }, - { url = "https://files.pythonhosted.org/packages/1b/3f/194355a9335707a15fdc79ddc670148987b43d04712dd26898a694539ce6/orjson-3.11.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3c8d8a112b274fae8c5f0f01954cb0480137072c271f3f4958127b010dfefaec", size = 132150, upload-time = "2025-12-06T15:55:22.364Z" }, - { url = "https://files.pythonhosted.org/packages/e9/08/d74b3a986d37e6c2e04b8821c62927620c9a1924bb49ea51519a87751b86/orjson-3.11.5-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5f0a2ae6f09ac7bd47d2d5a5305c1d9ed08ac057cda55bb0a49fa506f0d2da00", size = 130490, upload-time = "2025-12-06T15:55:23.619Z" }, - { url = "https://files.pythonhosted.org/packages/b2/16/ebd04c38c1db01e493a68eee442efdffc505a43112eccd481e0146c6acc2/orjson-3.11.5-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c0d87bd1896faac0d10b4f849016db81a63e4ec5df38757ffae84d45ab38aa71", size = 135726, upload-time = "2025-12-06T15:55:24.912Z" }, - { url = "https://files.pythonhosted.org/packages/06/64/2ce4b2c09a099403081c37639c224bdcdfe401138bd66fed5c96d4f8dbd3/orjson-3.11.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:801a821e8e6099b8c459ac7540b3c32dba6013437c57fdcaec205b169754f38c", size = 139640, upload-time = "2025-12-06T15:55:26.535Z" }, - { url = "https://files.pythonhosted.org/packages/cd/e2/425796df8ee1d7cea3a7edf868920121dd09162859dbb76fffc9a5c37fd3/orjson-3.11.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:69a0f6ac618c98c74b7fbc8c0172ba86f9e01dbf9f62aa0b1776c2231a7bffe5", size = 137289, upload-time = "2025-12-06T15:55:27.78Z" }, - { url = "https://files.pythonhosted.org/packages/32/a2/88e482eb8e899a037dcc9eff85ef117a568e6ca1ffa1a2b2be3fcb51b7bb/orjson-3.11.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fea7339bdd22e6f1060c55ac31b6a755d86a5b2ad3657f2669ec243f8e3b2bdb", size = 138761, upload-time = "2025-12-06T15:55:29.388Z" }, - { url = "https://files.pythonhosted.org/packages/f1/fd/131dd6d32eeb74c513bfa487f434a2150811d0fbd9cb06689284f2f21b34/orjson-3.11.5-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:4dad582bc93cef8f26513e12771e76385a7e6187fd713157e971c784112aad56", size = 141357, upload-time = "2025-12-06T15:55:31.064Z" }, - { url = "https://files.pythonhosted.org/packages/7a/90/e4a0abbcca7b53e9098ac854f27f5ed9949c796f3c760bc04af997da0eb2/orjson-3.11.5-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:0522003e9f7fba91982e83a97fec0708f5a714c96c4209db7104e6b9d132f111", size = 413638, upload-time = "2025-12-06T15:55:32.344Z" }, - { url = "https://files.pythonhosted.org/packages/d1/c2/df91e385514924120001ade9cd52d6295251023d3bfa2c0a01f38cfc485a/orjson-3.11.5-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:7403851e430a478440ecc1258bcbacbfbd8175f9ac1e39031a7121dd0de05ff8", size = 150972, upload-time = "2025-12-06T15:55:33.725Z" }, - { url = "https://files.pythonhosted.org/packages/a6/ff/c76cc5a30a4451191ff1b868a331ad1354433335277fc40931f5fc3cab9d/orjson-3.11.5-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:5f691263425d3177977c8d1dd896cde7b98d93cbf390b2544a090675e83a6a0a", size = 141729, upload-time = "2025-12-06T15:55:35.317Z" }, - { url = "https://files.pythonhosted.org/packages/27/c3/7830bf74389ea1eaab2b017d8b15d1cab2bb0737d9412dfa7fb8644f7d78/orjson-3.11.5-cp39-cp39-win32.whl", hash = "sha256:61026196a1c4b968e1b1e540563e277843082e9e97d78afa03eb89315af531f1", size = 135100, upload-time = "2025-12-06T15:55:36.57Z" }, - { url = "https://files.pythonhosted.org/packages/69/e6/babf31154e047e465bc194eb72d1326d7c52ad4d7f50bf92b02b3cacda5c/orjson-3.11.5-cp39-cp39-win_amd64.whl", hash = "sha256:09b94b947ac08586af635ef922d69dc9bc63321527a3a04647f4986a73f4bd30", size = 133189, upload-time = "2025-12-06T15:55:38.143Z" }, -] - [[package]] name = "orjson" version = "3.11.7" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.14'", - "python_full_version >= '3.10' and python_full_version < '3.14'", -] sdist = { url = "https://files.pythonhosted.org/packages/53/45/b268004f745ede84e5798b48ee12b05129d19235d0e15267aa57dcdb400b/orjson-3.11.7.tar.gz", hash = "sha256:9b1a67243945819ce55d24a30b59d6a168e86220452d2c96f4d1f093e71c0c49", size = 6144992, upload-time = "2026-02-02T15:38:49.29Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/de/1a/a373746fa6d0e116dd9e54371a7b54622c44d12296d5d0f3ad5e3ff33490/orjson-3.11.7-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:a02c833f38f36546ba65a452127633afce4cf0dd7296b753d3bb54e55e5c0174", size = 229140, upload-time = "2026-02-02T15:37:06.082Z" }, @@ -4369,130 +3509,10 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/9a/70/875f4a23bfc4731703a5835487d0d2fb999031bd415e7d17c0ae615c18b7/pathvalidate-3.3.1-py3-none-any.whl", hash = "sha256:5263baab691f8e1af96092fa5137ee17df5bdfbd6cff1fcac4d6ef4bc2e1735f", size = 24305, upload-time = "2025-06-15T09:07:19.117Z" }, ] -[[package]] -name = "pillow" -version = "11.3.0" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.10'", -] -sdist = { url = "https://files.pythonhosted.org/packages/f3/0d/d0d6dea55cd152ce3d6767bb38a8fc10e33796ba4ba210cbab9354b6d238/pillow-11.3.0.tar.gz", hash = "sha256:3828ee7586cd0b2091b6209e5ad53e20d0649bbe87164a459d0676e035e8f523", size = 47113069, upload-time = "2025-07-01T09:16:30.666Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/4c/5d/45a3553a253ac8763f3561371432a90bdbe6000fbdcf1397ffe502aa206c/pillow-11.3.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:1b9c17fd4ace828b3003dfd1e30bff24863e0eb59b535e8f80194d9cc7ecf860", size = 5316554, upload-time = "2025-07-01T09:13:39.342Z" }, - { url = "https://files.pythonhosted.org/packages/7c/c8/67c12ab069ef586a25a4a79ced553586748fad100c77c0ce59bb4983ac98/pillow-11.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:65dc69160114cdd0ca0f35cb434633c75e8e7fad4cf855177a05bf38678f73ad", size = 4686548, upload-time = "2025-07-01T09:13:41.835Z" }, - { url = "https://files.pythonhosted.org/packages/2f/bd/6741ebd56263390b382ae4c5de02979af7f8bd9807346d068700dd6d5cf9/pillow-11.3.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7107195ddc914f656c7fc8e4a5e1c25f32e9236ea3ea860f257b0436011fddd0", size = 5859742, upload-time = "2025-07-03T13:09:47.439Z" }, - { url = "https://files.pythonhosted.org/packages/ca/0b/c412a9e27e1e6a829e6ab6c2dca52dd563efbedf4c9c6aa453d9a9b77359/pillow-11.3.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:cc3e831b563b3114baac7ec2ee86819eb03caa1a2cef0b481a5675b59c4fe23b", size = 7633087, upload-time = "2025-07-03T13:09:51.796Z" }, - { url = "https://files.pythonhosted.org/packages/59/9d/9b7076aaf30f5dd17e5e5589b2d2f5a5d7e30ff67a171eb686e4eecc2adf/pillow-11.3.0-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f1f182ebd2303acf8c380a54f615ec883322593320a9b00438eb842c1f37ae50", size = 5963350, upload-time = "2025-07-01T09:13:43.865Z" }, - { url = "https://files.pythonhosted.org/packages/f0/16/1a6bf01fb622fb9cf5c91683823f073f053005c849b1f52ed613afcf8dae/pillow-11.3.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4445fa62e15936a028672fd48c4c11a66d641d2c05726c7ec1f8ba6a572036ae", size = 6631840, upload-time = "2025-07-01T09:13:46.161Z" }, - { url = "https://files.pythonhosted.org/packages/7b/e6/6ff7077077eb47fde78739e7d570bdcd7c10495666b6afcd23ab56b19a43/pillow-11.3.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:71f511f6b3b91dd543282477be45a033e4845a40278fa8dcdbfdb07109bf18f9", size = 6074005, upload-time = "2025-07-01T09:13:47.829Z" }, - { url = "https://files.pythonhosted.org/packages/c3/3a/b13f36832ea6d279a697231658199e0a03cd87ef12048016bdcc84131601/pillow-11.3.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:040a5b691b0713e1f6cbe222e0f4f74cd233421e105850ae3b3c0ceda520f42e", size = 6708372, upload-time = "2025-07-01T09:13:52.145Z" }, - { url = "https://files.pythonhosted.org/packages/6c/e4/61b2e1a7528740efbc70b3d581f33937e38e98ef3d50b05007267a55bcb2/pillow-11.3.0-cp310-cp310-win32.whl", hash = "sha256:89bd777bc6624fe4115e9fac3352c79ed60f3bb18651420635f26e643e3dd1f6", size = 6277090, upload-time = "2025-07-01T09:13:53.915Z" }, - { url = "https://files.pythonhosted.org/packages/a9/d3/60c781c83a785d6afbd6a326ed4d759d141de43aa7365725cbcd65ce5e54/pillow-11.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:19d2ff547c75b8e3ff46f4d9ef969a06c30ab2d4263a9e287733aa8b2429ce8f", size = 6985988, upload-time = "2025-07-01T09:13:55.699Z" }, - { url = "https://files.pythonhosted.org/packages/9f/28/4f4a0203165eefb3763939c6789ba31013a2e90adffb456610f30f613850/pillow-11.3.0-cp310-cp310-win_arm64.whl", hash = "sha256:819931d25e57b513242859ce1876c58c59dc31587847bf74cfe06b2e0cb22d2f", size = 2422899, upload-time = "2025-07-01T09:13:57.497Z" }, - { url = "https://files.pythonhosted.org/packages/db/26/77f8ed17ca4ffd60e1dcd220a6ec6d71210ba398cfa33a13a1cd614c5613/pillow-11.3.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:1cd110edf822773368b396281a2293aeb91c90a2db00d78ea43e7e861631b722", size = 5316531, upload-time = "2025-07-01T09:13:59.203Z" }, - { url = "https://files.pythonhosted.org/packages/cb/39/ee475903197ce709322a17a866892efb560f57900d9af2e55f86db51b0a5/pillow-11.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9c412fddd1b77a75aa904615ebaa6001f169b26fd467b4be93aded278266b288", size = 4686560, upload-time = "2025-07-01T09:14:01.101Z" }, - { url = "https://files.pythonhosted.org/packages/d5/90/442068a160fd179938ba55ec8c97050a612426fae5ec0a764e345839f76d/pillow-11.3.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7d1aa4de119a0ecac0a34a9c8bde33f34022e2e8f99104e47a3ca392fd60e37d", size = 5870978, upload-time = "2025-07-03T13:09:55.638Z" }, - { url = "https://files.pythonhosted.org/packages/13/92/dcdd147ab02daf405387f0218dcf792dc6dd5b14d2573d40b4caeef01059/pillow-11.3.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:91da1d88226663594e3f6b4b8c3c8d85bd504117d043740a8e0ec449087cc494", size = 7641168, upload-time = "2025-07-03T13:10:00.37Z" }, - { url = "https://files.pythonhosted.org/packages/6e/db/839d6ba7fd38b51af641aa904e2960e7a5644d60ec754c046b7d2aee00e5/pillow-11.3.0-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:643f189248837533073c405ec2f0bb250ba54598cf80e8c1e043381a60632f58", size = 5973053, upload-time = "2025-07-01T09:14:04.491Z" }, - { url = "https://files.pythonhosted.org/packages/f2/2f/d7675ecae6c43e9f12aa8d58b6012683b20b6edfbdac7abcb4e6af7a3784/pillow-11.3.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:106064daa23a745510dabce1d84f29137a37224831d88eb4ce94bb187b1d7e5f", size = 6640273, upload-time = "2025-07-01T09:14:06.235Z" }, - { url = "https://files.pythonhosted.org/packages/45/ad/931694675ede172e15b2ff03c8144a0ddaea1d87adb72bb07655eaffb654/pillow-11.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:cd8ff254faf15591e724dc7c4ddb6bf4793efcbe13802a4ae3e863cd300b493e", size = 6082043, upload-time = "2025-07-01T09:14:07.978Z" }, - { url = "https://files.pythonhosted.org/packages/3a/04/ba8f2b11fc80d2dd462d7abec16351b45ec99cbbaea4387648a44190351a/pillow-11.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:932c754c2d51ad2b2271fd01c3d121daaa35e27efae2a616f77bf164bc0b3e94", size = 6715516, upload-time = "2025-07-01T09:14:10.233Z" }, - { url = "https://files.pythonhosted.org/packages/48/59/8cd06d7f3944cc7d892e8533c56b0acb68399f640786313275faec1e3b6f/pillow-11.3.0-cp311-cp311-win32.whl", hash = "sha256:b4b8f3efc8d530a1544e5962bd6b403d5f7fe8b9e08227c6b255f98ad82b4ba0", size = 6274768, upload-time = "2025-07-01T09:14:11.921Z" }, - { url = "https://files.pythonhosted.org/packages/f1/cc/29c0f5d64ab8eae20f3232da8f8571660aa0ab4b8f1331da5c2f5f9a938e/pillow-11.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:1a992e86b0dd7aeb1f053cd506508c0999d710a8f07b4c791c63843fc6a807ac", size = 6986055, upload-time = "2025-07-01T09:14:13.623Z" }, - { url = "https://files.pythonhosted.org/packages/c6/df/90bd886fabd544c25addd63e5ca6932c86f2b701d5da6c7839387a076b4a/pillow-11.3.0-cp311-cp311-win_arm64.whl", hash = "sha256:30807c931ff7c095620fe04448e2c2fc673fcbb1ffe2a7da3fb39613489b1ddd", size = 2423079, upload-time = "2025-07-01T09:14:15.268Z" }, - { url = "https://files.pythonhosted.org/packages/40/fe/1bc9b3ee13f68487a99ac9529968035cca2f0a51ec36892060edcc51d06a/pillow-11.3.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fdae223722da47b024b867c1ea0be64e0df702c5e0a60e27daad39bf960dd1e4", size = 5278800, upload-time = "2025-07-01T09:14:17.648Z" }, - { url = "https://files.pythonhosted.org/packages/2c/32/7e2ac19b5713657384cec55f89065fb306b06af008cfd87e572035b27119/pillow-11.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:921bd305b10e82b4d1f5e802b6850677f965d8394203d182f078873851dada69", size = 4686296, upload-time = "2025-07-01T09:14:19.828Z" }, - { url = "https://files.pythonhosted.org/packages/8e/1e/b9e12bbe6e4c2220effebc09ea0923a07a6da1e1f1bfbc8d7d29a01ce32b/pillow-11.3.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:eb76541cba2f958032d79d143b98a3a6b3ea87f0959bbe256c0b5e416599fd5d", size = 5871726, upload-time = "2025-07-03T13:10:04.448Z" }, - { url = "https://files.pythonhosted.org/packages/8d/33/e9200d2bd7ba00dc3ddb78df1198a6e80d7669cce6c2bdbeb2530a74ec58/pillow-11.3.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:67172f2944ebba3d4a7b54f2e95c786a3a50c21b88456329314caaa28cda70f6", size = 7644652, upload-time = "2025-07-03T13:10:10.391Z" }, - { url = "https://files.pythonhosted.org/packages/41/f1/6f2427a26fc683e00d985bc391bdd76d8dd4e92fac33d841127eb8fb2313/pillow-11.3.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:97f07ed9f56a3b9b5f49d3661dc9607484e85c67e27f3e8be2c7d28ca032fec7", size = 5977787, upload-time = "2025-07-01T09:14:21.63Z" }, - { url = "https://files.pythonhosted.org/packages/e4/c9/06dd4a38974e24f932ff5f98ea3c546ce3f8c995d3f0985f8e5ba48bba19/pillow-11.3.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:676b2815362456b5b3216b4fd5bd89d362100dc6f4945154ff172e206a22c024", size = 6645236, upload-time = "2025-07-01T09:14:23.321Z" }, - { url = "https://files.pythonhosted.org/packages/40/e7/848f69fb79843b3d91241bad658e9c14f39a32f71a301bcd1d139416d1be/pillow-11.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3e184b2f26ff146363dd07bde8b711833d7b0202e27d13540bfe2e35a323a809", size = 6086950, upload-time = "2025-07-01T09:14:25.237Z" }, - { url = "https://files.pythonhosted.org/packages/0b/1a/7cff92e695a2a29ac1958c2a0fe4c0b2393b60aac13b04a4fe2735cad52d/pillow-11.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6be31e3fc9a621e071bc17bb7de63b85cbe0bfae91bb0363c893cbe67247780d", size = 6723358, upload-time = "2025-07-01T09:14:27.053Z" }, - { url = "https://files.pythonhosted.org/packages/26/7d/73699ad77895f69edff76b0f332acc3d497f22f5d75e5360f78cbcaff248/pillow-11.3.0-cp312-cp312-win32.whl", hash = "sha256:7b161756381f0918e05e7cb8a371fff367e807770f8fe92ecb20d905d0e1c149", size = 6275079, upload-time = "2025-07-01T09:14:30.104Z" }, - { url = "https://files.pythonhosted.org/packages/8c/ce/e7dfc873bdd9828f3b6e5c2bbb74e47a98ec23cc5c74fc4e54462f0d9204/pillow-11.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:a6444696fce635783440b7f7a9fc24b3ad10a9ea3f0ab66c5905be1c19ccf17d", size = 6986324, upload-time = "2025-07-01T09:14:31.899Z" }, - { url = "https://files.pythonhosted.org/packages/16/8f/b13447d1bf0b1f7467ce7d86f6e6edf66c0ad7cf44cf5c87a37f9bed9936/pillow-11.3.0-cp312-cp312-win_arm64.whl", hash = "sha256:2aceea54f957dd4448264f9bf40875da0415c83eb85f55069d89c0ed436e3542", size = 2423067, upload-time = "2025-07-01T09:14:33.709Z" }, - { url = "https://files.pythonhosted.org/packages/1e/93/0952f2ed8db3a5a4c7a11f91965d6184ebc8cd7cbb7941a260d5f018cd2d/pillow-11.3.0-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:1c627742b539bba4309df89171356fcb3cc5a9178355b2727d1b74a6cf155fbd", size = 2128328, upload-time = "2025-07-01T09:14:35.276Z" }, - { url = "https://files.pythonhosted.org/packages/4b/e8/100c3d114b1a0bf4042f27e0f87d2f25e857e838034e98ca98fe7b8c0a9c/pillow-11.3.0-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:30b7c02f3899d10f13d7a48163c8969e4e653f8b43416d23d13d1bbfdc93b9f8", size = 2170652, upload-time = "2025-07-01T09:14:37.203Z" }, - { url = "https://files.pythonhosted.org/packages/aa/86/3f758a28a6e381758545f7cdb4942e1cb79abd271bea932998fc0db93cb6/pillow-11.3.0-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:7859a4cc7c9295f5838015d8cc0a9c215b77e43d07a25e460f35cf516df8626f", size = 2227443, upload-time = "2025-07-01T09:14:39.344Z" }, - { url = "https://files.pythonhosted.org/packages/01/f4/91d5b3ffa718df2f53b0dc109877993e511f4fd055d7e9508682e8aba092/pillow-11.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ec1ee50470b0d050984394423d96325b744d55c701a439d2bd66089bff963d3c", size = 5278474, upload-time = "2025-07-01T09:14:41.843Z" }, - { url = "https://files.pythonhosted.org/packages/f9/0e/37d7d3eca6c879fbd9dba21268427dffda1ab00d4eb05b32923d4fbe3b12/pillow-11.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7db51d222548ccfd274e4572fdbf3e810a5e66b00608862f947b163e613b67dd", size = 4686038, upload-time = "2025-07-01T09:14:44.008Z" }, - { url = "https://files.pythonhosted.org/packages/ff/b0/3426e5c7f6565e752d81221af9d3676fdbb4f352317ceafd42899aaf5d8a/pillow-11.3.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:2d6fcc902a24ac74495df63faad1884282239265c6839a0a6416d33faedfae7e", size = 5864407, upload-time = "2025-07-03T13:10:15.628Z" }, - { url = "https://files.pythonhosted.org/packages/fc/c1/c6c423134229f2a221ee53f838d4be9d82bab86f7e2f8e75e47b6bf6cd77/pillow-11.3.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f0f5d8f4a08090c6d6d578351a2b91acf519a54986c055af27e7a93feae6d3f1", size = 7639094, upload-time = "2025-07-03T13:10:21.857Z" }, - { url = "https://files.pythonhosted.org/packages/ba/c9/09e6746630fe6372c67c648ff9deae52a2bc20897d51fa293571977ceb5d/pillow-11.3.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c37d8ba9411d6003bba9e518db0db0c58a680ab9fe5179f040b0463644bc9805", size = 5973503, upload-time = "2025-07-01T09:14:45.698Z" }, - { url = "https://files.pythonhosted.org/packages/d5/1c/a2a29649c0b1983d3ef57ee87a66487fdeb45132df66ab30dd37f7dbe162/pillow-11.3.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:13f87d581e71d9189ab21fe0efb5a23e9f28552d5be6979e84001d3b8505abe8", size = 6642574, upload-time = "2025-07-01T09:14:47.415Z" }, - { url = "https://files.pythonhosted.org/packages/36/de/d5cc31cc4b055b6c6fd990e3e7f0f8aaf36229a2698501bcb0cdf67c7146/pillow-11.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:023f6d2d11784a465f09fd09a34b150ea4672e85fb3d05931d89f373ab14abb2", size = 6084060, upload-time = "2025-07-01T09:14:49.636Z" }, - { url = "https://files.pythonhosted.org/packages/d5/ea/502d938cbaeec836ac28a9b730193716f0114c41325db428e6b280513f09/pillow-11.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:45dfc51ac5975b938e9809451c51734124e73b04d0f0ac621649821a63852e7b", size = 6721407, upload-time = "2025-07-01T09:14:51.962Z" }, - { url = "https://files.pythonhosted.org/packages/45/9c/9c5e2a73f125f6cbc59cc7087c8f2d649a7ae453f83bd0362ff7c9e2aee2/pillow-11.3.0-cp313-cp313-win32.whl", hash = "sha256:a4d336baed65d50d37b88ca5b60c0fa9d81e3a87d4a7930d3880d1624d5b31f3", size = 6273841, upload-time = "2025-07-01T09:14:54.142Z" }, - { url = "https://files.pythonhosted.org/packages/23/85/397c73524e0cd212067e0c969aa245b01d50183439550d24d9f55781b776/pillow-11.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:0bce5c4fd0921f99d2e858dc4d4d64193407e1b99478bc5cacecba2311abde51", size = 6978450, upload-time = "2025-07-01T09:14:56.436Z" }, - { url = "https://files.pythonhosted.org/packages/17/d2/622f4547f69cd173955194b78e4d19ca4935a1b0f03a302d655c9f6aae65/pillow-11.3.0-cp313-cp313-win_arm64.whl", hash = "sha256:1904e1264881f682f02b7f8167935cce37bc97db457f8e7849dc3a6a52b99580", size = 2423055, upload-time = "2025-07-01T09:14:58.072Z" }, - { url = "https://files.pythonhosted.org/packages/dd/80/a8a2ac21dda2e82480852978416cfacd439a4b490a501a288ecf4fe2532d/pillow-11.3.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:4c834a3921375c48ee6b9624061076bc0a32a60b5532b322cc0ea64e639dd50e", size = 5281110, upload-time = "2025-07-01T09:14:59.79Z" }, - { url = "https://files.pythonhosted.org/packages/44/d6/b79754ca790f315918732e18f82a8146d33bcd7f4494380457ea89eb883d/pillow-11.3.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:5e05688ccef30ea69b9317a9ead994b93975104a677a36a8ed8106be9260aa6d", size = 4689547, upload-time = "2025-07-01T09:15:01.648Z" }, - { url = "https://files.pythonhosted.org/packages/49/20/716b8717d331150cb00f7fdd78169c01e8e0c219732a78b0e59b6bdb2fd6/pillow-11.3.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:1019b04af07fc0163e2810167918cb5add8d74674b6267616021ab558dc98ced", size = 5901554, upload-time = "2025-07-03T13:10:27.018Z" }, - { url = "https://files.pythonhosted.org/packages/74/cf/a9f3a2514a65bb071075063a96f0a5cf949c2f2fce683c15ccc83b1c1cab/pillow-11.3.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f944255db153ebb2b19c51fe85dd99ef0ce494123f21b9db4877ffdfc5590c7c", size = 7669132, upload-time = "2025-07-03T13:10:33.01Z" }, - { url = "https://files.pythonhosted.org/packages/98/3c/da78805cbdbee9cb43efe8261dd7cc0b4b93f2ac79b676c03159e9db2187/pillow-11.3.0-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1f85acb69adf2aaee8b7da124efebbdb959a104db34d3a2cb0f3793dbae422a8", size = 6005001, upload-time = "2025-07-01T09:15:03.365Z" }, - { url = "https://files.pythonhosted.org/packages/6c/fa/ce044b91faecf30e635321351bba32bab5a7e034c60187fe9698191aef4f/pillow-11.3.0-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:05f6ecbeff5005399bb48d198f098a9b4b6bdf27b8487c7f38ca16eeb070cd59", size = 6668814, upload-time = "2025-07-01T09:15:05.655Z" }, - { url = "https://files.pythonhosted.org/packages/7b/51/90f9291406d09bf93686434f9183aba27b831c10c87746ff49f127ee80cb/pillow-11.3.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:a7bc6e6fd0395bc052f16b1a8670859964dbd7003bd0af2ff08342eb6e442cfe", size = 6113124, upload-time = "2025-07-01T09:15:07.358Z" }, - { url = "https://files.pythonhosted.org/packages/cd/5a/6fec59b1dfb619234f7636d4157d11fb4e196caeee220232a8d2ec48488d/pillow-11.3.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:83e1b0161c9d148125083a35c1c5a89db5b7054834fd4387499e06552035236c", size = 6747186, upload-time = "2025-07-01T09:15:09.317Z" }, - { url = "https://files.pythonhosted.org/packages/49/6b/00187a044f98255225f172de653941e61da37104a9ea60e4f6887717e2b5/pillow-11.3.0-cp313-cp313t-win32.whl", hash = "sha256:2a3117c06b8fb646639dce83694f2f9eac405472713fcb1ae887469c0d4f6788", size = 6277546, upload-time = "2025-07-01T09:15:11.311Z" }, - { url = "https://files.pythonhosted.org/packages/e8/5c/6caaba7e261c0d75bab23be79f1d06b5ad2a2ae49f028ccec801b0e853d6/pillow-11.3.0-cp313-cp313t-win_amd64.whl", hash = "sha256:857844335c95bea93fb39e0fa2726b4d9d758850b34075a7e3ff4f4fa3aa3b31", size = 6985102, upload-time = "2025-07-01T09:15:13.164Z" }, - { url = "https://files.pythonhosted.org/packages/f3/7e/b623008460c09a0cb38263c93b828c666493caee2eb34ff67f778b87e58c/pillow-11.3.0-cp313-cp313t-win_arm64.whl", hash = "sha256:8797edc41f3e8536ae4b10897ee2f637235c94f27404cac7297f7b607dd0716e", size = 2424803, upload-time = "2025-07-01T09:15:15.695Z" }, - { url = "https://files.pythonhosted.org/packages/73/f4/04905af42837292ed86cb1b1dabe03dce1edc008ef14c473c5c7e1443c5d/pillow-11.3.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:d9da3df5f9ea2a89b81bb6087177fb1f4d1c7146d583a3fe5c672c0d94e55e12", size = 5278520, upload-time = "2025-07-01T09:15:17.429Z" }, - { url = "https://files.pythonhosted.org/packages/41/b0/33d79e377a336247df6348a54e6d2a2b85d644ca202555e3faa0cf811ecc/pillow-11.3.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:0b275ff9b04df7b640c59ec5a3cb113eefd3795a8df80bac69646ef699c6981a", size = 4686116, upload-time = "2025-07-01T09:15:19.423Z" }, - { url = "https://files.pythonhosted.org/packages/49/2d/ed8bc0ab219ae8768f529597d9509d184fe8a6c4741a6864fea334d25f3f/pillow-11.3.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0743841cabd3dba6a83f38a92672cccbd69af56e3e91777b0ee7f4dba4385632", size = 5864597, upload-time = "2025-07-03T13:10:38.404Z" }, - { url = "https://files.pythonhosted.org/packages/b5/3d/b932bb4225c80b58dfadaca9d42d08d0b7064d2d1791b6a237f87f661834/pillow-11.3.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2465a69cf967b8b49ee1b96d76718cd98c4e925414ead59fdf75cf0fd07df673", size = 7638246, upload-time = "2025-07-03T13:10:44.987Z" }, - { url = "https://files.pythonhosted.org/packages/09/b5/0487044b7c096f1b48f0d7ad416472c02e0e4bf6919541b111efd3cae690/pillow-11.3.0-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:41742638139424703b4d01665b807c6468e23e699e8e90cffefe291c5832b027", size = 5973336, upload-time = "2025-07-01T09:15:21.237Z" }, - { url = "https://files.pythonhosted.org/packages/a8/2d/524f9318f6cbfcc79fbc004801ea6b607ec3f843977652fdee4857a7568b/pillow-11.3.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:93efb0b4de7e340d99057415c749175e24c8864302369e05914682ba642e5d77", size = 6642699, upload-time = "2025-07-01T09:15:23.186Z" }, - { url = "https://files.pythonhosted.org/packages/6f/d2/a9a4f280c6aefedce1e8f615baaa5474e0701d86dd6f1dede66726462bbd/pillow-11.3.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7966e38dcd0fa11ca390aed7c6f20454443581d758242023cf36fcb319b1a874", size = 6083789, upload-time = "2025-07-01T09:15:25.1Z" }, - { url = "https://files.pythonhosted.org/packages/fe/54/86b0cd9dbb683a9d5e960b66c7379e821a19be4ac5810e2e5a715c09a0c0/pillow-11.3.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:98a9afa7b9007c67ed84c57c9e0ad86a6000da96eaa638e4f8abe5b65ff83f0a", size = 6720386, upload-time = "2025-07-01T09:15:27.378Z" }, - { url = "https://files.pythonhosted.org/packages/e7/95/88efcaf384c3588e24259c4203b909cbe3e3c2d887af9e938c2022c9dd48/pillow-11.3.0-cp314-cp314-win32.whl", hash = "sha256:02a723e6bf909e7cea0dac1b0e0310be9d7650cd66222a5f1c571455c0a45214", size = 6370911, upload-time = "2025-07-01T09:15:29.294Z" }, - { url = "https://files.pythonhosted.org/packages/2e/cc/934e5820850ec5eb107e7b1a72dd278140731c669f396110ebc326f2a503/pillow-11.3.0-cp314-cp314-win_amd64.whl", hash = "sha256:a418486160228f64dd9e9efcd132679b7a02a5f22c982c78b6fc7dab3fefb635", size = 7117383, upload-time = "2025-07-01T09:15:31.128Z" }, - { url = "https://files.pythonhosted.org/packages/d6/e9/9c0a616a71da2a5d163aa37405e8aced9a906d574b4a214bede134e731bc/pillow-11.3.0-cp314-cp314-win_arm64.whl", hash = "sha256:155658efb5e044669c08896c0c44231c5e9abcaadbc5cd3648df2f7c0b96b9a6", size = 2511385, upload-time = "2025-07-01T09:15:33.328Z" }, - { url = "https://files.pythonhosted.org/packages/1a/33/c88376898aff369658b225262cd4f2659b13e8178e7534df9e6e1fa289f6/pillow-11.3.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:59a03cdf019efbfeeed910bf79c7c93255c3d54bc45898ac2a4140071b02b4ae", size = 5281129, upload-time = "2025-07-01T09:15:35.194Z" }, - { url = "https://files.pythonhosted.org/packages/1f/70/d376247fb36f1844b42910911c83a02d5544ebd2a8bad9efcc0f707ea774/pillow-11.3.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:f8a5827f84d973d8636e9dc5764af4f0cf2318d26744b3d902931701b0d46653", size = 4689580, upload-time = "2025-07-01T09:15:37.114Z" }, - { url = "https://files.pythonhosted.org/packages/eb/1c/537e930496149fbac69efd2fc4329035bbe2e5475b4165439e3be9cb183b/pillow-11.3.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ee92f2fd10f4adc4b43d07ec5e779932b4eb3dbfbc34790ada5a6669bc095aa6", size = 5902860, upload-time = "2025-07-03T13:10:50.248Z" }, - { url = "https://files.pythonhosted.org/packages/bd/57/80f53264954dcefeebcf9dae6e3eb1daea1b488f0be8b8fef12f79a3eb10/pillow-11.3.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c96d333dcf42d01f47b37e0979b6bd73ec91eae18614864622d9b87bbd5bbf36", size = 7670694, upload-time = "2025-07-03T13:10:56.432Z" }, - { url = "https://files.pythonhosted.org/packages/70/ff/4727d3b71a8578b4587d9c276e90efad2d6fe0335fd76742a6da08132e8c/pillow-11.3.0-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4c96f993ab8c98460cd0c001447bff6194403e8b1d7e149ade5f00594918128b", size = 6005888, upload-time = "2025-07-01T09:15:39.436Z" }, - { url = "https://files.pythonhosted.org/packages/05/ae/716592277934f85d3be51d7256f3636672d7b1abfafdc42cf3f8cbd4b4c8/pillow-11.3.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:41342b64afeba938edb034d122b2dda5db2139b9a4af999729ba8818e0056477", size = 6670330, upload-time = "2025-07-01T09:15:41.269Z" }, - { url = "https://files.pythonhosted.org/packages/e7/bb/7fe6cddcc8827b01b1a9766f5fdeb7418680744f9082035bdbabecf1d57f/pillow-11.3.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:068d9c39a2d1b358eb9f245ce7ab1b5c3246c7c8c7d9ba58cfa5b43146c06e50", size = 6114089, upload-time = "2025-07-01T09:15:43.13Z" }, - { url = "https://files.pythonhosted.org/packages/8b/f5/06bfaa444c8e80f1a8e4bff98da9c83b37b5be3b1deaa43d27a0db37ef84/pillow-11.3.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:a1bc6ba083b145187f648b667e05a2534ecc4b9f2784c2cbe3089e44868f2b9b", size = 6748206, upload-time = "2025-07-01T09:15:44.937Z" }, - { url = "https://files.pythonhosted.org/packages/f0/77/bc6f92a3e8e6e46c0ca78abfffec0037845800ea38c73483760362804c41/pillow-11.3.0-cp314-cp314t-win32.whl", hash = "sha256:118ca10c0d60b06d006be10a501fd6bbdfef559251ed31b794668ed569c87e12", size = 6377370, upload-time = "2025-07-01T09:15:46.673Z" }, - { url = "https://files.pythonhosted.org/packages/4a/82/3a721f7d69dca802befb8af08b7c79ebcab461007ce1c18bd91a5d5896f9/pillow-11.3.0-cp314-cp314t-win_amd64.whl", hash = "sha256:8924748b688aa210d79883357d102cd64690e56b923a186f35a82cbc10f997db", size = 7121500, upload-time = "2025-07-01T09:15:48.512Z" }, - { url = "https://files.pythonhosted.org/packages/89/c7/5572fa4a3f45740eaab6ae86fcdf7195b55beac1371ac8c619d880cfe948/pillow-11.3.0-cp314-cp314t-win_arm64.whl", hash = "sha256:79ea0d14d3ebad43ec77ad5272e6ff9bba5b679ef73375ea760261207fa8e0aa", size = 2512835, upload-time = "2025-07-01T09:15:50.399Z" }, - { url = "https://files.pythonhosted.org/packages/9e/8e/9c089f01677d1264ab8648352dcb7773f37da6ad002542760c80107da816/pillow-11.3.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:48d254f8a4c776de343051023eb61ffe818299eeac478da55227d96e241de53f", size = 5316478, upload-time = "2025-07-01T09:15:52.209Z" }, - { url = "https://files.pythonhosted.org/packages/b5/a9/5749930caf674695867eb56a581e78eb5f524b7583ff10b01b6e5048acb3/pillow-11.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:7aee118e30a4cf54fdd873bd3a29de51e29105ab11f9aad8c32123f58c8f8081", size = 4686522, upload-time = "2025-07-01T09:15:54.162Z" }, - { url = "https://files.pythonhosted.org/packages/43/46/0b85b763eb292b691030795f9f6bb6fcaf8948c39413c81696a01c3577f7/pillow-11.3.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:23cff760a9049c502721bdb743a7cb3e03365fafcdfc2ef9784610714166e5a4", size = 5853376, upload-time = "2025-07-03T13:11:01.066Z" }, - { url = "https://files.pythonhosted.org/packages/5e/c6/1a230ec0067243cbd60bc2dad5dc3ab46a8a41e21c15f5c9b52b26873069/pillow-11.3.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:6359a3bc43f57d5b375d1ad54a0074318a0844d11b76abccf478c37c986d3cfc", size = 7626020, upload-time = "2025-07-03T13:11:06.479Z" }, - { url = "https://files.pythonhosted.org/packages/63/dd/f296c27ffba447bfad76c6a0c44c1ea97a90cb9472b9304c94a732e8dbfb/pillow-11.3.0-cp39-cp39-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:092c80c76635f5ecb10f3f83d76716165c96f5229addbd1ec2bdbbda7d496e06", size = 5956732, upload-time = "2025-07-01T09:15:56.111Z" }, - { url = "https://files.pythonhosted.org/packages/a5/a0/98a3630f0b57f77bae67716562513d3032ae70414fcaf02750279c389a9e/pillow-11.3.0-cp39-cp39-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cadc9e0ea0a2431124cde7e1697106471fc4c1da01530e679b2391c37d3fbb3a", size = 6624404, upload-time = "2025-07-01T09:15:58.245Z" }, - { url = "https://files.pythonhosted.org/packages/de/e6/83dfba5646a290edd9a21964da07674409e410579c341fc5b8f7abd81620/pillow-11.3.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:6a418691000f2a418c9135a7cf0d797c1bb7d9a485e61fe8e7722845b95ef978", size = 6067760, upload-time = "2025-07-01T09:16:00.003Z" }, - { url = "https://files.pythonhosted.org/packages/bc/41/15ab268fe6ee9a2bc7391e2bbb20a98d3974304ab1a406a992dcb297a370/pillow-11.3.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:97afb3a00b65cc0804d1c7abddbf090a81eaac02768af58cbdcaaa0a931e0b6d", size = 6700534, upload-time = "2025-07-01T09:16:02.29Z" }, - { url = "https://files.pythonhosted.org/packages/64/79/6d4f638b288300bed727ff29f2a3cb63db054b33518a95f27724915e3fbc/pillow-11.3.0-cp39-cp39-win32.whl", hash = "sha256:ea944117a7974ae78059fcc1800e5d3295172bb97035c0c1d9345fca1419da71", size = 6277091, upload-time = "2025-07-01T09:16:04.4Z" }, - { url = "https://files.pythonhosted.org/packages/46/05/4106422f45a05716fd34ed21763f8ec182e8ea00af6e9cb05b93a247361a/pillow-11.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:e5c5858ad8ec655450a7c7df532e9842cf8df7cc349df7225c60d5d348c8aada", size = 6986091, upload-time = "2025-07-01T09:16:06.342Z" }, - { url = "https://files.pythonhosted.org/packages/63/c6/287fd55c2c12761d0591549d48885187579b7c257bef0c6660755b0b59ae/pillow-11.3.0-cp39-cp39-win_arm64.whl", hash = "sha256:6abdbfd3aea42be05702a8dd98832329c167ee84400a1d1f61ab11437f1717eb", size = 2422632, upload-time = "2025-07-01T09:16:08.142Z" }, - { url = "https://files.pythonhosted.org/packages/6f/8b/209bd6b62ce8367f47e68a218bffac88888fdf2c9fcf1ecadc6c3ec1ebc7/pillow-11.3.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:3cee80663f29e3843b68199b9d6f4f54bd1d4a6b59bdd91bceefc51238bcb967", size = 5270556, upload-time = "2025-07-01T09:16:09.961Z" }, - { url = "https://files.pythonhosted.org/packages/2e/e6/231a0b76070c2cfd9e260a7a5b504fb72da0a95279410fa7afd99d9751d6/pillow-11.3.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:b5f56c3f344f2ccaf0dd875d3e180f631dc60a51b314295a3e681fe8cf851fbe", size = 4654625, upload-time = "2025-07-01T09:16:11.913Z" }, - { url = "https://files.pythonhosted.org/packages/13/f4/10cf94fda33cb12765f2397fc285fa6d8eb9c29de7f3185165b702fc7386/pillow-11.3.0-pp310-pypy310_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:e67d793d180c9df62f1f40aee3accca4829d3794c95098887edc18af4b8b780c", size = 4874207, upload-time = "2025-07-03T13:11:10.201Z" }, - { url = "https://files.pythonhosted.org/packages/72/c9/583821097dc691880c92892e8e2d41fe0a5a3d6021f4963371d2f6d57250/pillow-11.3.0-pp310-pypy310_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d000f46e2917c705e9fb93a3606ee4a819d1e3aa7a9b442f6444f07e77cf5e25", size = 6583939, upload-time = "2025-07-03T13:11:15.68Z" }, - { url = "https://files.pythonhosted.org/packages/3b/8e/5c9d410f9217b12320efc7c413e72693f48468979a013ad17fd690397b9a/pillow-11.3.0-pp310-pypy310_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:527b37216b6ac3a12d7838dc3bd75208ec57c1c6d11ef01902266a5a0c14fc27", size = 4957166, upload-time = "2025-07-01T09:16:13.74Z" }, - { url = "https://files.pythonhosted.org/packages/62/bb/78347dbe13219991877ffb3a91bf09da8317fbfcd4b5f9140aeae020ad71/pillow-11.3.0-pp310-pypy310_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:be5463ac478b623b9dd3937afd7fb7ab3d79dd290a28e2b6df292dc75063eb8a", size = 5581482, upload-time = "2025-07-01T09:16:16.107Z" }, - { url = "https://files.pythonhosted.org/packages/d9/28/1000353d5e61498aaeaaf7f1e4b49ddb05f2c6575f9d4f9f914a3538b6e1/pillow-11.3.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:8dc70ca24c110503e16918a658b869019126ecfe03109b754c402daff12b3d9f", size = 6984596, upload-time = "2025-07-01T09:16:18.07Z" }, - { url = "https://files.pythonhosted.org/packages/9e/e3/6fa84033758276fb31da12e5fb66ad747ae83b93c67af17f8c6ff4cc8f34/pillow-11.3.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7c8ec7a017ad1bd562f93dbd8505763e688d388cde6e4a010ae1486916e713e6", size = 5270566, upload-time = "2025-07-01T09:16:19.801Z" }, - { url = "https://files.pythonhosted.org/packages/5b/ee/e8d2e1ab4892970b561e1ba96cbd59c0d28cf66737fc44abb2aec3795a4e/pillow-11.3.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:9ab6ae226de48019caa8074894544af5b53a117ccb9d3b3dcb2871464c829438", size = 4654618, upload-time = "2025-07-01T09:16:21.818Z" }, - { url = "https://files.pythonhosted.org/packages/f2/6d/17f80f4e1f0761f02160fc433abd4109fa1548dcfdca46cfdadaf9efa565/pillow-11.3.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:fe27fb049cdcca11f11a7bfda64043c37b30e6b91f10cb5bab275806c32f6ab3", size = 4874248, upload-time = "2025-07-03T13:11:20.738Z" }, - { url = "https://files.pythonhosted.org/packages/de/5f/c22340acd61cef960130585bbe2120e2fd8434c214802f07e8c03596b17e/pillow-11.3.0-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:465b9e8844e3c3519a983d58b80be3f668e2a7a5db97f2784e7079fbc9f9822c", size = 6583963, upload-time = "2025-07-03T13:11:26.283Z" }, - { url = "https://files.pythonhosted.org/packages/31/5e/03966aedfbfcbb4d5f8aa042452d3361f325b963ebbadddac05b122e47dd/pillow-11.3.0-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5418b53c0d59b3824d05e029669efa023bbef0f3e92e75ec8428f3799487f361", size = 4957170, upload-time = "2025-07-01T09:16:23.762Z" }, - { url = "https://files.pythonhosted.org/packages/cc/2d/e082982aacc927fc2cab48e1e731bdb1643a1406acace8bed0900a61464e/pillow-11.3.0-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:504b6f59505f08ae014f724b6207ff6222662aab5cc9542577fb084ed0676ac7", size = 5581505, upload-time = "2025-07-01T09:16:25.593Z" }, - { url = "https://files.pythonhosted.org/packages/34/e7/ae39f538fd6844e982063c3a5e4598b8ced43b9633baa3a85ef33af8c05c/pillow-11.3.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:c84d689db21a1c397d001aa08241044aa2069e7587b398c8cc63020390b1c1b8", size = 6984598, upload-time = "2025-07-01T09:16:27.732Z" }, -] - [[package]] name = "pillow" version = "12.1.0" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.14'", - "python_full_version >= '3.10' and python_full_version < '3.14'", -] sdist = { url = "https://files.pythonhosted.org/packages/d0/02/d52c733a2452ef1ffcc123b68e6606d07276b0e358db70eabad7e40042b7/pillow-12.1.0.tar.gz", hash = "sha256:5c5ae0a06e9ea030ab786b0251b32c7e4ce10e58d983c0d5c56029455180b5b9", size = 46977283, upload-time = "2026-01-02T09:13:29.892Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/fe/41/f73d92b6b883a579e79600d391f2e21cb0df767b2714ecbd2952315dfeef/pillow-12.1.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:fb125d860738a09d363a88daa0f59c4533529a90e564785e20fe875b200b6dbd", size = 5304089, upload-time = "2026-01-02T09:10:24.953Z" }, @@ -4587,26 +3607,10 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/2d/71/64e9b1c7f04ae0027f788a248e6297d7fcc29571371fe7d45495a78172c0/pillow-12.1.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:75af0b4c229ac519b155028fa1be632d812a519abba9b46b20e50c6caa184f19", size = 7029809, upload-time = "2026-01-02T09:13:26.541Z" }, ] -[[package]] -name = "platformdirs" -version = "4.4.0" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.10'", -] -sdist = { url = "https://files.pythonhosted.org/packages/23/e8/21db9c9987b0e728855bd57bff6984f67952bea55d6f75e055c46b5383e8/platformdirs-4.4.0.tar.gz", hash = "sha256:ca753cf4d81dc309bc67b0ea38fd15dc97bc30ce419a7f58d13eb3bf14c4febf", size = 21634, upload-time = "2025-08-26T14:32:04.268Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/40/4b/2028861e724d3bd36227adfa20d3fd24c3fc6d52032f4a93c133be5d17ce/platformdirs-4.4.0-py3-none-any.whl", hash = "sha256:abd01743f24e5287cd7a5db3752faf1a2d65353f38ec26d98e25a6db65958c85", size = 18654, upload-time = "2025-08-26T14:32:02.735Z" }, -] - [[package]] name = "platformdirs" version = "4.5.1" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.14'", - "python_full_version >= '3.10' and python_full_version < '3.14'", -] sdist = { url = "https://files.pythonhosted.org/packages/cf/86/0248f086a84f01b37aaec0fa567b397df1a119f73c16f6c7a9aac73ea309/platformdirs-4.5.1.tar.gz", hash = "sha256:61d5cdcc6065745cdd94f0f878977f8de9437be93de97c1c12f853c9c0cdcbda", size = 21715, upload-time = "2025-12-05T13:52:58.638Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/cb/28/3bfe2fa5a7b9c46fe7e13c97bda14c895fb10fa2ebf1d0abb90e0cea7ee1/platformdirs-4.5.1-py3-none-any.whl", hash = "sha256:d03afa3963c806a9bed9d5125c8f4cb2fdaf74a55ab60e5d59b3fde758104d31", size = 18731, upload-time = "2025-12-05T13:52:56.823Z" }, @@ -4617,8 +3621,7 @@ name = "playwright" version = "1.58.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "greenlet", version = "3.2.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "greenlet", version = "3.3.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "greenlet" }, { name = "pyee" }, ] wheels = [ @@ -4797,51 +3800,13 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/08/02/87b25304249a35c0915d236575bc3574a323f60b47939a2262b77632a3ee/propcache-0.4.1-cp314-cp314t-win32.whl", hash = "sha256:05674a162469f31358c30bcaa8883cb7829fa3110bf9c0991fe27d7896c42d85", size = 42546, upload-time = "2025-10-08T19:48:32.872Z" }, { url = "https://files.pythonhosted.org/packages/cb/ef/3c6ecf8b317aa982f309835e8f96987466123c6e596646d4e6a1dfcd080f/propcache-0.4.1-cp314-cp314t-win_amd64.whl", hash = "sha256:990f6b3e2a27d683cb7602ed6c86f15ee6b43b1194736f9baaeb93d0016633b1", size = 46259, upload-time = "2025-10-08T19:48:34.226Z" }, { url = "https://files.pythonhosted.org/packages/c4/2d/346e946d4951f37eca1e4f55be0f0174c52cd70720f84029b02f296f4a38/propcache-0.4.1-cp314-cp314t-win_arm64.whl", hash = "sha256:ecef2343af4cc68e05131e45024ba34f6095821988a9d0a02aa7c73fcc448aa9", size = 40428, upload-time = "2025-10-08T19:48:35.441Z" }, - { url = "https://files.pythonhosted.org/packages/9b/01/0ebaec9003f5d619a7475165961f8e3083cf8644d704b60395df3601632d/propcache-0.4.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:3d233076ccf9e450c8b3bc6720af226b898ef5d051a2d145f7d765e6e9f9bcff", size = 80277, upload-time = "2025-10-08T19:48:36.647Z" }, - { url = "https://files.pythonhosted.org/packages/34/58/04af97ac586b4ef6b9026c3fd36ee7798b737a832f5d3440a4280dcebd3a/propcache-0.4.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:357f5bb5c377a82e105e44bd3d52ba22b616f7b9773714bff93573988ef0a5fb", size = 45865, upload-time = "2025-10-08T19:48:37.859Z" }, - { url = "https://files.pythonhosted.org/packages/7c/19/b65d98ae21384518b291d9939e24a8aeac4fdb5101b732576f8f7540e834/propcache-0.4.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:cbc3b6dfc728105b2a57c06791eb07a94229202ea75c59db644d7d496b698cac", size = 47636, upload-time = "2025-10-08T19:48:39.038Z" }, - { url = "https://files.pythonhosted.org/packages/b3/0f/317048c6d91c356c7154dca5af019e6effeb7ee15fa6a6db327cc19e12b4/propcache-0.4.1-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:182b51b421f0501952d938dc0b0eb45246a5b5153c50d42b495ad5fb7517c888", size = 201126, upload-time = "2025-10-08T19:48:40.774Z" }, - { url = "https://files.pythonhosted.org/packages/71/69/0b2a7a5a6ee83292b4b997dbd80549d8ce7d40b6397c1646c0d9495f5a85/propcache-0.4.1-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4b536b39c5199b96fc6245eb5fb796c497381d3942f169e44e8e392b29c9ebcc", size = 209837, upload-time = "2025-10-08T19:48:42.167Z" }, - { url = "https://files.pythonhosted.org/packages/a5/92/c699ac495a6698df6e497fc2de27af4b6ace10d8e76528357ce153722e45/propcache-0.4.1-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:db65d2af507bbfbdcedb254a11149f894169d90488dd3e7190f7cdcb2d6cd57a", size = 215578, upload-time = "2025-10-08T19:48:43.56Z" }, - { url = "https://files.pythonhosted.org/packages/b3/ee/14de81c5eb02c0ee4f500b4e39c4e1bd0677c06e72379e6ab18923c773fc/propcache-0.4.1-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fd2dbc472da1f772a4dae4fa24be938a6c544671a912e30529984dd80400cd88", size = 197187, upload-time = "2025-10-08T19:48:45.309Z" }, - { url = "https://files.pythonhosted.org/packages/1d/94/48dce9aaa6d8dd5a0859bad75158ec522546d4ac23f8e2f05fac469477dd/propcache-0.4.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:daede9cd44e0f8bdd9e6cc9a607fc81feb80fae7a5fc6cecaff0e0bb32e42d00", size = 193478, upload-time = "2025-10-08T19:48:47.743Z" }, - { url = "https://files.pythonhosted.org/packages/60/b5/0516b563e801e1ace212afde869a0596a0d7115eec0b12d296d75633fb29/propcache-0.4.1-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:71b749281b816793678ae7f3d0d84bd36e694953822eaad408d682efc5ca18e0", size = 190650, upload-time = "2025-10-08T19:48:49.373Z" }, - { url = "https://files.pythonhosted.org/packages/24/89/e0f7d4a5978cd56f8cd67735f74052f257dc471ec901694e430f0d1572fe/propcache-0.4.1-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:0002004213ee1f36cfb3f9a42b5066100c44276b9b72b4e1504cddd3d692e86e", size = 200251, upload-time = "2025-10-08T19:48:51.4Z" }, - { url = "https://files.pythonhosted.org/packages/06/7d/a1fac863d473876ed4406c914f2e14aa82d2f10dd207c9e16fc383cc5a24/propcache-0.4.1-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:fe49d0a85038f36ba9e3ffafa1103e61170b28e95b16622e11be0a0ea07c6781", size = 200919, upload-time = "2025-10-08T19:48:53.227Z" }, - { url = "https://files.pythonhosted.org/packages/c3/4e/f86a256ff24944cf5743e4e6c6994e3526f6acfcfb55e21694c2424f758c/propcache-0.4.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:99d43339c83aaf4d32bda60928231848eee470c6bda8d02599cc4cebe872d183", size = 193211, upload-time = "2025-10-08T19:48:55.027Z" }, - { url = "https://files.pythonhosted.org/packages/6e/3f/3fbad5f4356b068f1b047d300a6ff2c66614d7030f078cd50be3fec04228/propcache-0.4.1-cp39-cp39-win32.whl", hash = "sha256:a129e76735bc792794d5177069691c3217898b9f5cee2b2661471e52ffe13f19", size = 38314, upload-time = "2025-10-08T19:48:56.792Z" }, - { url = "https://files.pythonhosted.org/packages/a4/45/d78d136c3a3d215677abb886785aae744da2c3005bcb99e58640c56529b1/propcache-0.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:948dab269721ae9a87fd16c514a0a2c2a1bdb23a9a61b969b0f9d9ee2968546f", size = 41912, upload-time = "2025-10-08T19:48:57.995Z" }, - { url = "https://files.pythonhosted.org/packages/fc/2a/b0632941f25139f4e58450b307242951f7c2717a5704977c6d5323a800af/propcache-0.4.1-cp39-cp39-win_arm64.whl", hash = "sha256:5fd37c406dd6dc85aa743e214cef35dc54bbdd1419baac4f6ae5e5b1a2976938", size = 38450, upload-time = "2025-10-08T19:48:59.349Z" }, { url = "https://files.pythonhosted.org/packages/5b/5a/bc7b4a4ef808fa59a816c17b20c4bef6884daebbdf627ff2a161da67da19/propcache-0.4.1-py3-none-any.whl", hash = "sha256:af2a6052aeb6cf17d3e46ee169099044fd8224cbaf75c76a2ef596e8163e2237", size = 13305, upload-time = "2025-10-08T19:49:00.792Z" }, ] -[[package]] -name = "protobuf" -version = "5.29.6" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.10'", -] -sdist = { url = "https://files.pythonhosted.org/packages/7e/57/394a763c103e0edf87f0938dafcd918d53b4c011dfc5c8ae80f3b0452dbb/protobuf-5.29.6.tar.gz", hash = "sha256:da9ee6a5424b6b30fd5e45c5ea663aef540ca95f9ad99d1e887e819cdf9b8723", size = 425623, upload-time = "2026-02-04T22:54:40.584Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d4/88/9ee58ff7863c479d6f8346686d4636dd4c415b0cbeed7a6a7d0617639c2a/protobuf-5.29.6-cp310-abi3-win32.whl", hash = "sha256:62e8a3114992c7c647bce37dcc93647575fc52d50e48de30c6fcb28a6a291eb1", size = 423357, upload-time = "2026-02-04T22:54:25.805Z" }, - { url = "https://files.pythonhosted.org/packages/1c/66/2dc736a4d576847134fb6d80bd995c569b13cdc7b815d669050bf0ce2d2c/protobuf-5.29.6-cp310-abi3-win_amd64.whl", hash = "sha256:7e6ad413275be172f67fdee0f43484b6de5a904cc1c3ea9804cb6fe2ff366eda", size = 435175, upload-time = "2026-02-04T22:54:28.592Z" }, - { url = "https://files.pythonhosted.org/packages/06/db/49b05966fd208ae3f44dcd33837b6243b4915c57561d730a43f881f24dea/protobuf-5.29.6-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:b5a169e664b4057183a34bdc424540e86eea47560f3c123a0d64de4e137f9269", size = 418619, upload-time = "2026-02-04T22:54:30.266Z" }, - { url = "https://files.pythonhosted.org/packages/b7/d7/48cbf6b0c3c39761e47a99cb483405f0fde2be22cf00d71ef316ce52b458/protobuf-5.29.6-cp38-abi3-manylinux2014_aarch64.whl", hash = "sha256:a8866b2cff111f0f863c1b3b9e7572dc7eaea23a7fae27f6fc613304046483e6", size = 320284, upload-time = "2026-02-04T22:54:31.782Z" }, - { url = "https://files.pythonhosted.org/packages/e3/dd/cadd6ec43069247d91f6345fa7a0d2858bef6af366dbd7ba8f05d2c77d3b/protobuf-5.29.6-cp38-abi3-manylinux2014_x86_64.whl", hash = "sha256:e3387f44798ac1106af0233c04fb8abf543772ff241169946f698b3a9a3d3ab9", size = 320478, upload-time = "2026-02-04T22:54:32.909Z" }, - { url = "https://files.pythonhosted.org/packages/30/a4/ff263f5687815e1a10a9243a3a6463af42ca251224bf4b8fc4c93b9f5b80/protobuf-5.29.6-cp39-cp39-win32.whl", hash = "sha256:cb4c86de9cd8a7f3a256b9744220d87b847371c6b2f10bde87768918ef33ba49", size = 423352, upload-time = "2026-02-04T22:54:37.375Z" }, - { url = "https://files.pythonhosted.org/packages/5c/64/e943206d3b5069050d570a2c53a90631240d99adcc9a91c6ff7b41876f4d/protobuf-5.29.6-cp39-cp39-win_amd64.whl", hash = "sha256:76e07e6567f8baf827137e8d5b8204b6c7b6488bbbff1bf0a72b383f77999c18", size = 435222, upload-time = "2026-02-04T22:54:38.418Z" }, - { url = "https://files.pythonhosted.org/packages/5a/cb/e3065b447186cb70aa65acc70c86baf482d82bf75625bf5a2c4f6919c6a3/protobuf-5.29.6-py3-none-any.whl", hash = "sha256:6b9edb641441b2da9fa8f428760fc136a49cf97a52076010cf22a2ff73438a86", size = 173126, upload-time = "2026-02-04T22:54:39.462Z" }, -] - [[package]] name = "protobuf" version = "6.33.5" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.14'", - "python_full_version >= '3.10' and python_full_version < '3.14'", -] sdist = { url = "https://files.pythonhosted.org/packages/ba/25/7c72c307aafc96fa87062aa6291d9f7c94836e43214d43722e86037aac02/protobuf-6.33.5.tar.gz", hash = "sha256:6ddcac2a081f8b7b9642c09406bc6a4290128fce5f471cddd165960bb9119e5c", size = 444465, upload-time = "2026-01-29T21:51:33.494Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/b1/79/af92d0a8369732b027e6d6084251dd8e782c685c72da161bd4a2e00fbabb/protobuf-6.33.5-cp310-abi3-win32.whl", hash = "sha256:d71b040839446bac0f4d162e758bea99c8251161dae9d0983a3b88dee345153b", size = 425769, upload-time = "2026-01-29T21:51:21.751Z" }, @@ -4850,36 +3815,13 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/4e/b1/c79468184310de09d75095ed1314b839eb2f72df71097db9d1404a1b2717/protobuf-6.33.5-cp39-abi3-manylinux2014_aarch64.whl", hash = "sha256:9b71e0281f36f179d00cbcb119cb19dec4d14a81393e5ea220f64b286173e190", size = 324638, upload-time = "2026-01-29T21:51:26.423Z" }, { url = "https://files.pythonhosted.org/packages/c5/f5/65d838092fd01c44d16037953fd4c2cc851e783de9b8f02b27ec4ffd906f/protobuf-6.33.5-cp39-abi3-manylinux2014_s390x.whl", hash = "sha256:8afa18e1d6d20af15b417e728e9f60f3aa108ee76f23c3b2c07a2c3b546d3afd", size = 339411, upload-time = "2026-01-29T21:51:27.446Z" }, { url = "https://files.pythonhosted.org/packages/9b/53/a9443aa3ca9ba8724fdfa02dd1887c1bcd8e89556b715cfbacca6b63dbec/protobuf-6.33.5-cp39-abi3-manylinux2014_x86_64.whl", hash = "sha256:cbf16ba3350fb7b889fca858fb215967792dc125b35c7976ca4818bee3521cf0", size = 323465, upload-time = "2026-01-29T21:51:28.925Z" }, - { url = "https://files.pythonhosted.org/packages/08/60/84d5f6dcda9165e4d6a56ac8433c9f40a8906bf2966150b8a0cfde097d78/protobuf-6.33.5-cp39-cp39-win32.whl", hash = "sha256:a3157e62729aafb8df6da2c03aa5c0937c7266c626ce11a278b6eb7963c4e37c", size = 425892, upload-time = "2026-01-29T21:51:30.382Z" }, - { url = "https://files.pythonhosted.org/packages/68/19/33d7dc2dc84439587fa1e21e1c0026c01ad2af0a62f58fd54002a7546307/protobuf-6.33.5-cp39-cp39-win_amd64.whl", hash = "sha256:8f04fa32763dcdb4973d537d6b54e615cc61108c7cb38fe59310c3192d29510a", size = 437137, upload-time = "2026-01-29T21:51:31.456Z" }, { url = "https://files.pythonhosted.org/packages/57/bf/2086963c69bdac3d7cff1cc7ff79b8ce5ea0bec6797a017e1be338a46248/protobuf-6.33.5-py3-none-any.whl", hash = "sha256:69915a973dd0f60f31a08b8318b73eab2bd6a392c79184b3612226b0a3f8ec02", size = 170687, upload-time = "2026-01-29T21:51:32.557Z" }, ] -[[package]] -name = "pwdlib" -version = "0.2.1" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.10'", -] -sdist = { url = "https://files.pythonhosted.org/packages/82/a0/9daed437a6226f632a25d98d65d60ba02bdafa920c90dcb6454c611ead6c/pwdlib-0.2.1.tar.gz", hash = "sha256:9a1d8a8fa09a2f7ebf208265e55d7d008103cbdc82b9e4902ffdd1ade91add5e", size = 11699, upload-time = "2024-08-19T06:48:59.58Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/01/f3/0dae5078a486f0fdf4d4a1121e103bc42694a9da9bea7b0f2c63f29cfbd3/pwdlib-0.2.1-py3-none-any.whl", hash = "sha256:1823dc6f22eae472b540e889ecf57fd424051d6a4023ec0bcf7f0de2d9d7ef8c", size = 8082, upload-time = "2024-08-19T06:49:00.997Z" }, -] - -[package.optional-dependencies] -argon2 = [ - { name = "argon2-cffi", version = "23.1.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, -] - [[package]] name = "pwdlib" version = "0.3.0" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.14'", - "python_full_version >= '3.10' and python_full_version < '3.14'", -] sdist = { url = "https://files.pythonhosted.org/packages/5f/41/a7c0d8a003c36ce3828ae3ed0391fe6a15aad65f082dbd6bec817ea95c0b/pwdlib-0.3.0.tar.gz", hash = "sha256:6ca30f9642a1467d4f5d0a4d18619de1c77f17dfccb42dd200b144127d3c83fc", size = 215810, upload-time = "2025-10-25T12:44:24.395Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/62/0c/9086a357d02a050fbb3270bf5043ac284dbfb845670e16c9389a41defc9e/pwdlib-0.3.0-py3-none-any.whl", hash = "sha256:f86c15c138858c09f3bba0a10984d4f9178158c55deaa72eac0210849b1a140d", size = 8633, upload-time = "2025-10-25T12:44:23.406Z" }, @@ -4887,7 +3829,7 @@ wheels = [ [package.optional-dependencies] argon2 = [ - { name = "argon2-cffi", version = "25.1.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "argon2-cffi" }, ] [[package]] @@ -4895,8 +3837,8 @@ name = "py-key-value-aio" version = "0.3.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "beartype", marker = "python_full_version >= '3.10'" }, - { name = "py-key-value-shared", marker = "python_full_version >= '3.10'" }, + { name = "beartype" }, + { name = "py-key-value-shared" }, ] sdist = { url = "https://files.pythonhosted.org/packages/93/ce/3136b771dddf5ac905cc193b461eb67967cf3979688c6696e1f2cdcde7ea/py_key_value_aio-0.3.0.tar.gz", hash = "sha256:858e852fcf6d696d231266da66042d3355a7f9871650415feef9fca7a6cd4155", size = 50801, upload-time = "2025-11-17T16:50:04.711Z" } wheels = [ @@ -4905,17 +3847,17 @@ wheels = [ [package.optional-dependencies] disk = [ - { name = "diskcache", marker = "python_full_version >= '3.10'" }, - { name = "pathvalidate", marker = "python_full_version >= '3.10'" }, + { name = "diskcache" }, + { name = "pathvalidate" }, ] keyring = [ - { name = "keyring", marker = "python_full_version >= '3.10'" }, + { name = "keyring" }, ] memory = [ - { name = "cachetools", marker = "python_full_version >= '3.10'" }, + { name = "cachetools" }, ] redis = [ - { name = "redis", marker = "python_full_version >= '3.10'" }, + { name = "redis" }, ] [[package]] @@ -4923,8 +3865,8 @@ name = "py-key-value-shared" version = "0.3.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "beartype", marker = "python_full_version >= '3.10'" }, - { name = "typing-extensions", marker = "python_full_version >= '3.10'" }, + { name = "beartype" }, + { name = "typing-extensions" }, ] sdist = { url = "https://files.pythonhosted.org/packages/7b/e4/1971dfc4620a3a15b4579fe99e024f5edd6e0967a71154771a059daff4db/py_key_value_shared-0.3.0.tar.gz", hash = "sha256:8fdd786cf96c3e900102945f92aa1473138ebe960ef49da1c833790160c28a4b", size = 11666, upload-time = "2025-11-17T16:50:06.849Z" } wheels = [ @@ -4952,26 +3894,10 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl", hash = "sha256:29253a9207ce32b64c3ac6600edc75368f98473906e8fd1043bd6b5b1de2c14a", size = 181259, upload-time = "2025-03-28T02:41:19.028Z" }, ] -[[package]] -name = "pycparser" -version = "2.23" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.10'", -] -sdist = { url = "https://files.pythonhosted.org/packages/fe/cf/d2d3b9f5699fb1e4615c8e32ff220203e43b248e1dfcc6736ad9057731ca/pycparser-2.23.tar.gz", hash = "sha256:78816d4f24add8f10a06d6f05b4d424ad9e96cfebf68a4ddc99c65c0720d00c2", size = 173734, upload-time = "2025-09-09T13:23:47.91Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a0/e3/59cd50310fc9b59512193629e1984c1f95e5c8ae6e5d8c69532ccc65a7fe/pycparser-2.23-py3-none-any.whl", hash = "sha256:e5c6e8d3fbad53479cab09ac03729e0a9faf2bee3db8208a550daf5af81a5934", size = 118140, upload-time = "2025-09-09T13:23:46.651Z" }, -] - [[package]] name = "pycparser" version = "3.0" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.14'", - "python_full_version >= '3.10' and python_full_version < '3.14'", -] sdist = { url = "https://files.pythonhosted.org/packages/1b/7d/92392ff7815c21062bea51aa7b87d45576f649f16458d78b7cf94b9ab2e6/pycparser-3.0.tar.gz", hash = "sha256:600f49d217304a5902ac3c37e1281c9fe94e4d0489de643a9504c5cdfdfc6b29", size = 103492, upload-time = "2026-01-21T14:26:51.89Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl", hash = "sha256:b727414169a36b7d524c1c3e31839a521725078d7b2ff038656844266160a992", size = 48172, upload-time = "2026-01-21T14:26:50.693Z" }, @@ -4997,126 +3923,31 @@ email = [ { name = "email-validator" }, ] -[[package]] -name = "pydantic-ai" -version = "0.8.1" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.10'", -] -dependencies = [ - { name = "pydantic-ai-slim", version = "0.8.1", source = { registry = "https://pypi.org/simple" }, extra = ["ag-ui", "anthropic", "bedrock", "cli", "cohere", "evals", "google", "groq", "huggingface", "mistral", "openai", "retries", "temporal", "vertexai"], marker = "python_full_version < '3.10'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/56/d7/fcc18ce80008e888404a3615f973aa3f39b98384d61b03621144c9f4c2d4/pydantic_ai-0.8.1.tar.gz", hash = "sha256:05974382082ee4f3706909d06bdfcc5e95f39e29230cc4d00e47429080099844", size = 43772581, upload-time = "2025-08-29T14:46:23.201Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f9/04/802b8cf834dffcda8baabb3b76c549243694a83346c3f54e47a3a4d519fb/pydantic_ai-0.8.1-py3-none-any.whl", hash = "sha256:5fa923097132aa69b4d6a310b462dc091009c7b87705edf4443d37b887d5ef9a", size = 10188, upload-time = "2025-08-29T14:46:11.137Z" }, -] - [[package]] name = "pydantic-ai" version = "1.56.0" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.14'", - "python_full_version >= '3.10' and python_full_version < '3.14'", -] dependencies = [ - { name = "pydantic-ai-slim", version = "1.56.0", source = { registry = "https://pypi.org/simple" }, extra = ["ag-ui", "anthropic", "bedrock", "cli", "cohere", "evals", "fastmcp", "google", "groq", "huggingface", "logfire", "mcp", "mistral", "openai", "retries", "temporal", "ui", "vertexai", "xai"], marker = "python_full_version >= '3.10'" }, + { name = "pydantic-ai-slim", extra = ["ag-ui", "anthropic", "bedrock", "cli", "cohere", "evals", "fastmcp", "google", "groq", "huggingface", "logfire", "mcp", "mistral", "openai", "retries", "temporal", "ui", "vertexai", "xai"] }, ] sdist = { url = "https://files.pythonhosted.org/packages/60/1a/800a1e02b259152a49d4c11d9103784a7482c7e9b067eeea23e949d3d80f/pydantic_ai-1.56.0.tar.gz", hash = "sha256:643ff71612df52315b3b4c4b41543657f603f567223eb33245dc8098f005bdc4", size = 11795, upload-time = "2026-02-06T01:13:21.122Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/5c/35/f4a7fd2b9962ddb9b021f76f293e74fda71da190bb74b57ed5b343c93022/pydantic_ai-1.56.0-py3-none-any.whl", hash = "sha256:b6b3ac74bdc004693834750da4420ea2cde0d3cbc3f134c0b7544f98f1c00859", size = 7222, upload-time = "2026-02-06T01:13:11.755Z" }, ] -[[package]] -name = "pydantic-ai-slim" -version = "0.8.1" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.10'", -] -dependencies = [ - { name = "eval-type-backport", marker = "python_full_version < '3.10'" }, - { name = "exceptiongroup", marker = "python_full_version < '3.10'" }, - { name = "genai-prices", marker = "python_full_version < '3.10'" }, - { name = "griffe", version = "1.14.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "httpx", marker = "python_full_version < '3.10'" }, - { name = "opentelemetry-api", marker = "python_full_version < '3.10'" }, - { name = "pydantic", marker = "python_full_version < '3.10'" }, - { name = "pydantic-graph", version = "0.8.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "typing-inspection", marker = "python_full_version < '3.10'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/a2/91/08137459b3745900501b3bd11852ced6c81b7ce6e628696d75b09bb786c5/pydantic_ai_slim-0.8.1.tar.gz", hash = "sha256:12ef3dcbe5e1dad195d5e256746ef960f6e59aeddda1a55bdd553ee375ff53ae", size = 218906, upload-time = "2025-08-29T14:46:27.517Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/11/ce/8dbadd04f578d02a9825a46e931005743fe223736296f30b55846c084fab/pydantic_ai_slim-0.8.1-py3-none-any.whl", hash = "sha256:fc7edc141b21fe42bc54a2d92c1127f8a75160c5e57a168dba154d3f4adb963f", size = 297821, upload-time = "2025-08-29T14:46:14.647Z" }, -] - -[package.optional-dependencies] -ag-ui = [ - { name = "ag-ui-protocol", marker = "python_full_version < '3.10'" }, - { name = "starlette", version = "0.49.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, -] -anthropic = [ - { name = "anthropic", marker = "python_full_version < '3.10'" }, -] -bedrock = [ - { name = "boto3", marker = "python_full_version < '3.10'" }, -] -cli = [ - { name = "argcomplete", marker = "python_full_version < '3.10'" }, - { name = "prompt-toolkit", marker = "python_full_version < '3.10'" }, - { name = "pyperclip", marker = "python_full_version < '3.10'" }, - { name = "rich", marker = "python_full_version < '3.10'" }, -] -cohere = [ - { name = "cohere", marker = "python_full_version < '3.10' and sys_platform != 'emscripten'" }, -] -evals = [ - { name = "pydantic-evals", version = "0.8.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, -] -google = [ - { name = "google-genai", version = "1.47.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, -] -groq = [ - { name = "groq", marker = "python_full_version < '3.10'" }, -] -huggingface = [ - { name = "huggingface-hub", extra = ["inference"], marker = "python_full_version < '3.10'" }, -] -mistral = [ - { name = "mistralai", marker = "python_full_version < '3.10'" }, -] -openai = [ - { name = "openai", marker = "python_full_version < '3.10'" }, -] -retries = [ - { name = "tenacity", version = "9.1.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, -] -temporal = [ - { name = "temporalio", version = "1.16.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, -] -vertexai = [ - { name = "google-auth", marker = "python_full_version < '3.10'" }, - { name = "requests", marker = "python_full_version < '3.10'" }, -] - [[package]] name = "pydantic-ai-slim" version = "1.56.0" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.14'", - "python_full_version >= '3.10' and python_full_version < '3.14'", -] dependencies = [ - { name = "exceptiongroup", marker = "python_full_version == '3.10.*'" }, - { name = "genai-prices", marker = "python_full_version >= '3.10'" }, - { name = "griffe", version = "1.15.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, - { name = "httpx", marker = "python_full_version >= '3.10'" }, - { name = "opentelemetry-api", marker = "python_full_version >= '3.10'" }, - { name = "pydantic", marker = "python_full_version >= '3.10'" }, - { name = "pydantic-graph", version = "1.56.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, - { name = "typing-inspection", marker = "python_full_version >= '3.10'" }, + { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, + { name = "genai-prices" }, + { name = "griffe" }, + { name = "httpx" }, + { name = "opentelemetry-api" }, + { name = "pydantic" }, + { name = "pydantic-graph" }, + { name = "typing-inspection" }, ] sdist = { url = "https://files.pythonhosted.org/packages/ce/5c/3a577825b9c1da8f287be7f2ee6fe9aab48bc8a80e65c8518052c589f51c/pydantic_ai_slim-1.56.0.tar.gz", hash = "sha256:9f9f9c56b1c735837880a515ae5661b465b40207b25f3a3434178098b2137f05", size = 415265, upload-time = "2026-02-06T01:13:23.58Z" } wheels = [ @@ -5125,67 +3956,67 @@ wheels = [ [package.optional-dependencies] ag-ui = [ - { name = "ag-ui-protocol", marker = "python_full_version >= '3.10'" }, - { name = "starlette", version = "0.52.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "ag-ui-protocol" }, + { name = "starlette" }, ] anthropic = [ - { name = "anthropic", marker = "python_full_version >= '3.10'" }, + { name = "anthropic" }, ] bedrock = [ - { name = "boto3", marker = "python_full_version >= '3.10'" }, + { name = "boto3" }, ] cli = [ - { name = "argcomplete", marker = "python_full_version >= '3.10'" }, - { name = "prompt-toolkit", marker = "python_full_version >= '3.10'" }, - { name = "pyperclip", marker = "python_full_version >= '3.10'" }, - { name = "rich", marker = "python_full_version >= '3.10'" }, + { name = "argcomplete" }, + { name = "prompt-toolkit" }, + { name = "pyperclip" }, + { name = "rich" }, ] cohere = [ - { name = "cohere", marker = "python_full_version >= '3.10' and sys_platform != 'emscripten'" }, + { name = "cohere", marker = "sys_platform != 'emscripten'" }, ] evals = [ - { name = "pydantic-evals", version = "1.56.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "pydantic-evals" }, ] fastmcp = [ - { name = "fastmcp", marker = "python_full_version >= '3.10'" }, + { name = "fastmcp" }, ] google = [ - { name = "google-genai", version = "1.62.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "google-genai" }, ] groq = [ - { name = "groq", marker = "python_full_version >= '3.10'" }, + { name = "groq" }, ] huggingface = [ - { name = "huggingface-hub", extra = ["inference"], marker = "python_full_version >= '3.10'" }, + { name = "huggingface-hub", extra = ["inference"] }, ] logfire = [ - { name = "logfire", extra = ["httpx"], marker = "python_full_version >= '3.10'" }, + { name = "logfire", extra = ["httpx"] }, ] mcp = [ - { name = "mcp", marker = "python_full_version >= '3.10'" }, + { name = "mcp" }, ] mistral = [ - { name = "mistralai", marker = "python_full_version >= '3.10'" }, + { name = "mistralai" }, ] openai = [ - { name = "openai", marker = "python_full_version >= '3.10'" }, - { name = "tiktoken", marker = "python_full_version >= '3.10'" }, + { name = "openai" }, + { name = "tiktoken" }, ] retries = [ - { name = "tenacity", version = "9.1.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "tenacity" }, ] temporal = [ - { name = "temporalio", version = "1.20.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "temporalio" }, ] ui = [ - { name = "starlette", version = "0.52.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "starlette" }, ] vertexai = [ - { name = "google-auth", marker = "python_full_version >= '3.10'" }, - { name = "requests", marker = "python_full_version >= '3.10'" }, + { name = "google-auth" }, + { name = "requests" }, ] xai = [ - { name = "xai-sdk", marker = "python_full_version >= '3.10'" }, + { name = "xai-sdk" }, ] [[package]] @@ -5280,19 +4111,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/5c/96/5fb7d8c3c17bc8c62fdb031c47d77a1af698f1d7a406b0f79aaa1338f9ad/pydantic_core-2.41.5-cp314-cp314t-win32.whl", hash = "sha256:b4ececa40ac28afa90871c2cc2b9ffd2ff0bf749380fbdf57d165fd23da353aa", size = 1988906, upload-time = "2025-11-04T13:41:56.606Z" }, { url = "https://files.pythonhosted.org/packages/22/ed/182129d83032702912c2e2d8bbe33c036f342cc735737064668585dac28f/pydantic_core-2.41.5-cp314-cp314t-win_amd64.whl", hash = "sha256:80aa89cad80b32a912a65332f64a4450ed00966111b6615ca6816153d3585a8c", size = 1981607, upload-time = "2025-11-04T13:41:58.889Z" }, { url = "https://files.pythonhosted.org/packages/9f/ed/068e41660b832bb0b1aa5b58011dea2a3fe0ba7861ff38c4d4904c1c1a99/pydantic_core-2.41.5-cp314-cp314t-win_arm64.whl", hash = "sha256:35b44f37a3199f771c3eaa53051bc8a70cd7b54f333531c59e29fd4db5d15008", size = 1974769, upload-time = "2025-11-04T13:42:01.186Z" }, - { url = "https://files.pythonhosted.org/packages/54/db/160dffb57ed9a3705c4cbcbff0ac03bdae45f1ca7d58ab74645550df3fbd/pydantic_core-2.41.5-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:8bfeaf8735be79f225f3fefab7f941c712aaca36f1128c9d7e2352ee1aa87bdf", size = 2107999, upload-time = "2025-11-04T13:42:03.885Z" }, - { url = "https://files.pythonhosted.org/packages/a3/7d/88e7de946f60d9263cc84819f32513520b85c0f8322f9b8f6e4afc938383/pydantic_core-2.41.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:346285d28e4c8017da95144c7f3acd42740d637ff41946af5ce6e5e420502dd5", size = 1929745, upload-time = "2025-11-04T13:42:06.075Z" }, - { url = "https://files.pythonhosted.org/packages/d5/c2/aef51e5b283780e85e99ff19db0f05842d2d4a8a8cd15e63b0280029b08f/pydantic_core-2.41.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a75dafbf87d6276ddc5b2bf6fae5254e3d0876b626eb24969a574fff9149ee5d", size = 1920220, upload-time = "2025-11-04T13:42:08.457Z" }, - { url = "https://files.pythonhosted.org/packages/c7/97/492ab10f9ac8695cd76b2fdb24e9e61f394051df71594e9bcc891c9f586e/pydantic_core-2.41.5-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7b93a4d08587e2b7e7882de461e82b6ed76d9026ce91ca7915e740ecc7855f60", size = 2067296, upload-time = "2025-11-04T13:42:10.817Z" }, - { url = "https://files.pythonhosted.org/packages/ec/23/984149650e5269c59a2a4c41d234a9570adc68ab29981825cfaf4cfad8f4/pydantic_core-2.41.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e8465ab91a4bd96d36dde3263f06caa6a8a6019e4113f24dc753d79a8b3a3f82", size = 2231548, upload-time = "2025-11-04T13:42:13.843Z" }, - { url = "https://files.pythonhosted.org/packages/71/0c/85bcbb885b9732c28bec67a222dbed5ed2d77baee1f8bba2002e8cd00c5c/pydantic_core-2.41.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:299e0a22e7ae2b85c1a57f104538b2656e8ab1873511fd718a1c1c6f149b77b5", size = 2362571, upload-time = "2025-11-04T13:42:16.208Z" }, - { url = "https://files.pythonhosted.org/packages/c0/4a/412d2048be12c334003e9b823a3fa3d038e46cc2d64dd8aab50b31b65499/pydantic_core-2.41.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:707625ef0983fcfb461acfaf14de2067c5942c6bb0f3b4c99158bed6fedd3cf3", size = 2068175, upload-time = "2025-11-04T13:42:18.911Z" }, - { url = "https://files.pythonhosted.org/packages/73/f4/c58b6a776b502d0a5540ad02e232514285513572060f0d78f7832ca3c98b/pydantic_core-2.41.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f41eb9797986d6ebac5e8edff36d5cef9de40def462311b3eb3eeded1431e425", size = 2177203, upload-time = "2025-11-04T13:42:22.578Z" }, - { url = "https://files.pythonhosted.org/packages/ed/ae/f06ea4c7e7a9eead3d165e7623cd2ea0cb788e277e4f935af63fc98fa4e6/pydantic_core-2.41.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0384e2e1021894b1ff5a786dbf94771e2986ebe2869533874d7e43bc79c6f504", size = 2148191, upload-time = "2025-11-04T13:42:24.89Z" }, - { url = "https://files.pythonhosted.org/packages/c1/57/25a11dcdc656bf5f8b05902c3c2934ac3ea296257cc4a3f79a6319e61856/pydantic_core-2.41.5-cp39-cp39-musllinux_1_1_armv7l.whl", hash = "sha256:f0cd744688278965817fd0839c4a4116add48d23890d468bc436f78beb28abf5", size = 2343907, upload-time = "2025-11-04T13:42:27.683Z" }, - { url = "https://files.pythonhosted.org/packages/96/82/e33d5f4933d7a03327c0c43c65d575e5919d4974ffc026bc917a5f7b9f61/pydantic_core-2.41.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:753e230374206729bf0a807954bcc6c150d3743928a73faffee51ac6557a03c3", size = 2322174, upload-time = "2025-11-04T13:42:30.776Z" }, - { url = "https://files.pythonhosted.org/packages/81/45/4091be67ce9f469e81656f880f3506f6a5624121ec5eb3eab37d7581897d/pydantic_core-2.41.5-cp39-cp39-win32.whl", hash = "sha256:873e0d5b4fb9b89ef7c2d2a963ea7d02879d9da0da8d9d4933dee8ee86a8b460", size = 1990353, upload-time = "2025-11-04T13:42:33.111Z" }, - { url = "https://files.pythonhosted.org/packages/44/8a/a98aede18db6e9cd5d66bcacd8a409fcf8134204cdede2e7de35c5a2c5ef/pydantic_core-2.41.5-cp39-cp39-win_amd64.whl", hash = "sha256:e4f4a984405e91527a0d62649ee21138f8e3d0ef103be488c1dc11a80d7f184b", size = 2015698, upload-time = "2025-11-04T13:42:35.484Z" }, { url = "https://files.pythonhosted.org/packages/11/72/90fda5ee3b97e51c494938a4a44c3a35a9c96c19bba12372fb9c634d6f57/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-macosx_10_12_x86_64.whl", hash = "sha256:b96d5f26b05d03cc60f11a7761a5ded1741da411e7fe0909e27a5e6a0cb7b034", size = 2115441, upload-time = "2025-11-04T13:42:39.557Z" }, { url = "https://files.pythonhosted.org/packages/1f/53/8942f884fa33f50794f119012dc6a1a02ac43a56407adaac20463df8e98f/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-macosx_11_0_arm64.whl", hash = "sha256:634e8609e89ceecea15e2d61bc9ac3718caaaa71963717bf3c8f38bfde64242c", size = 1930291, upload-time = "2025-11-04T13:42:42.169Z" }, { url = "https://files.pythonhosted.org/packages/79/c8/ecb9ed9cd942bce09fc888ee960b52654fbdbede4ba6c2d6e0d3b1d8b49c/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:93e8740d7503eb008aa2df04d3b9735f845d43ae845e6dcd2be0b55a2da43cd2", size = 1948632, upload-time = "2025-11-04T13:42:44.564Z" }, @@ -5319,42 +4137,17 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/36/c7/cfc8e811f061c841d7990b0201912c3556bfeb99cdcb7ed24adc8d6f8704/pydantic_core-2.41.5-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:56121965f7a4dc965bff783d70b907ddf3d57f6eba29b6d2e5dabfaf07799c51", size = 2145302, upload-time = "2025-11-04T13:43:46.64Z" }, ] -[[package]] -name = "pydantic-evals" -version = "0.8.1" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.10'", -] -dependencies = [ - { name = "anyio", marker = "python_full_version < '3.10'" }, - { name = "eval-type-backport", marker = "python_full_version < '3.10'" }, - { name = "logfire-api", marker = "python_full_version < '3.10'" }, - { name = "pydantic", marker = "python_full_version < '3.10'" }, - { name = "pydantic-ai-slim", version = "0.8.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "pyyaml", marker = "python_full_version < '3.10'" }, - { name = "rich", marker = "python_full_version < '3.10'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/6c/9d/460a1f2c9f5f263e9d8e9661acbd654ccc81ad3373ea43048d914091a817/pydantic_evals-0.8.1.tar.gz", hash = "sha256:c398a623c31c19ce70e346ad75654fcb1517c3f6a821461f64fe5cbbe0813023", size = 43933, upload-time = "2025-08-29T14:46:28.903Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/6f/f9/1d21c4687167c4fa76fd3b1ed47f9bc2d38fd94cbacd9aa3f19e82e59830/pydantic_evals-0.8.1-py3-none-any.whl", hash = "sha256:6c76333b1d79632f619eb58a24ac656e9f402c47c75ad750ba0230d7f5514344", size = 52602, upload-time = "2025-08-29T14:46:16.602Z" }, -] - [[package]] name = "pydantic-evals" version = "1.56.0" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.14'", - "python_full_version >= '3.10' and python_full_version < '3.14'", -] dependencies = [ - { name = "anyio", marker = "python_full_version >= '3.10'" }, - { name = "logfire-api", marker = "python_full_version >= '3.10'" }, - { name = "pydantic", marker = "python_full_version >= '3.10'" }, - { name = "pydantic-ai-slim", version = "1.56.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, - { name = "pyyaml", marker = "python_full_version >= '3.10'" }, - { name = "rich", marker = "python_full_version >= '3.10'" }, + { name = "anyio" }, + { name = "logfire-api" }, + { name = "pydantic" }, + { name = "pydantic-ai-slim" }, + { name = "pyyaml" }, + { name = "rich" }, ] sdist = { url = "https://files.pythonhosted.org/packages/98/f2/8c59284a2978af3fbda45ae3217218eaf8b071207a9290b54b7613983e5d/pydantic_evals-1.56.0.tar.gz", hash = "sha256:206635107127af6a3ee4b1fc8f77af6afb14683615a2d6b3609f79467c1c0d28", size = 47210, upload-time = "2026-02-06T01:13:25.714Z" } wheels = [ @@ -5374,72 +4167,29 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/fe/17/fabd56da47096d240dd45ba627bead0333b0cf0ee8ada9bec579287dadf3/pydantic_extra_types-2.11.0-py3-none-any.whl", hash = "sha256:84b864d250a0fc62535b7ec591e36f2c5b4d1325fa0017eb8cda9aeb63b374a6", size = 74296, upload-time = "2025-12-31T16:18:26.38Z" }, ] -[[package]] -name = "pydantic-graph" -version = "0.8.1" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.10'", -] -dependencies = [ - { name = "httpx", marker = "python_full_version < '3.10'" }, - { name = "logfire-api", marker = "python_full_version < '3.10'" }, - { name = "pydantic", marker = "python_full_version < '3.10'" }, - { name = "typing-inspection", marker = "python_full_version < '3.10'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/bd/97/b35b7cb82d9f1bb6d5c6d21bba54f6196a3a5f593373f3a9c163a3821fd7/pydantic_graph-0.8.1.tar.gz", hash = "sha256:c61675a05c74f661d4ff38d04b74bd652c1e0959467801986f2f85dc7585410d", size = 21675, upload-time = "2025-08-29T14:46:29.839Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3d/e3/5908643b049bb2384d143885725cbeb0f53707d418357d4d1ac8d2c82629/pydantic_graph-0.8.1-py3-none-any.whl", hash = "sha256:f1dd5db0fe22f4e3323c04c65e2f0013846decc312b3efc3196666764556b765", size = 27239, upload-time = "2025-08-29T14:46:18.317Z" }, -] - [[package]] name = "pydantic-graph" version = "1.56.0" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.14'", - "python_full_version >= '3.10' and python_full_version < '3.14'", -] dependencies = [ - { name = "httpx", marker = "python_full_version >= '3.10'" }, - { name = "logfire-api", marker = "python_full_version >= '3.10'" }, - { name = "pydantic", marker = "python_full_version >= '3.10'" }, - { name = "typing-inspection", marker = "python_full_version >= '3.10'" }, + { name = "httpx" }, + { name = "logfire-api" }, + { name = "pydantic" }, + { name = "typing-inspection" }, ] sdist = { url = "https://files.pythonhosted.org/packages/ff/03/f92881cdb12d6f43e60e9bfd602e41c95408f06e2324d3729f7a194e2bcd/pydantic_graph-1.56.0.tar.gz", hash = "sha256:5e22972dbb43dbc379ab9944252ff864019abf3c7d465dcdf572fc8aec9a44a1", size = 58460, upload-time = "2026-02-06T01:13:26.708Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/08/07/8c823eb4d196137c123d4d67434e185901d3cbaea3b0c2b7667da84e72c1/pydantic_graph-1.56.0-py3-none-any.whl", hash = "sha256:ec3f0a1d6fcedd4eb9c59fef45079c2ee4d4185878d70dae26440a9c974c6bb3", size = 72346, upload-time = "2026-02-06T01:13:18.792Z" }, ] -[[package]] -name = "pydantic-settings" -version = "2.11.0" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.10'", -] -dependencies = [ - { name = "pydantic", marker = "python_full_version < '3.10'" }, - { name = "python-dotenv", marker = "python_full_version < '3.10'" }, - { name = "typing-inspection", marker = "python_full_version < '3.10'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/20/c5/dbbc27b814c71676593d1c3f718e6cd7d4f00652cefa24b75f7aa3efb25e/pydantic_settings-2.11.0.tar.gz", hash = "sha256:d0e87a1c7d33593beb7194adb8470fc426e95ba02af83a0f23474a04c9a08180", size = 188394, upload-time = "2025-09-24T14:19:11.764Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/83/d6/887a1ff844e64aa823fb4905978d882a633cfe295c32eacad582b78a7d8b/pydantic_settings-2.11.0-py3-none-any.whl", hash = "sha256:fe2cea3413b9530d10f3a5875adffb17ada5c1e1bab0b2885546d7310415207c", size = 48608, upload-time = "2025-09-24T14:19:10.015Z" }, -] - [[package]] name = "pydantic-settings" version = "2.12.0" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.14'", - "python_full_version >= '3.10' and python_full_version < '3.14'", -] dependencies = [ - { name = "pydantic", marker = "python_full_version >= '3.10'" }, - { name = "python-dotenv", marker = "python_full_version >= '3.10'" }, - { name = "typing-inspection", marker = "python_full_version >= '3.10'" }, + { name = "pydantic" }, + { name = "python-dotenv" }, + { name = "typing-inspection" }, ] sdist = { url = "https://files.pythonhosted.org/packages/43/4b/ac7e0aae12027748076d72a8764ff1c9d82ca75a7a52622e67ed3f765c54/pydantic_settings-2.12.0.tar.gz", hash = "sha256:005538ef951e3c2a68e1c08b292b5f2e71490def8589d4221b95dab00dafcfd0", size = 194184, upload-time = "2025-11-10T14:25:47.013Z" } wheels = [ @@ -5451,19 +4201,19 @@ name = "pydocket" version = "0.17.5" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "cloudpickle", marker = "python_full_version >= '3.10'" }, - { name = "croniter", marker = "python_full_version >= '3.10'" }, - { name = "exceptiongroup", marker = "python_full_version == '3.10.*'" }, - { name = "fakeredis", extra = ["lua"], marker = "python_full_version >= '3.10'" }, - { name = "opentelemetry-api", marker = "python_full_version >= '3.10'" }, - { name = "prometheus-client", marker = "python_full_version >= '3.10'" }, - { name = "py-key-value-aio", extra = ["memory", "redis"], marker = "python_full_version >= '3.10'" }, - { name = "python-json-logger", marker = "python_full_version >= '3.10'" }, - { name = "redis", marker = "python_full_version >= '3.10'" }, - { name = "rich", marker = "python_full_version >= '3.10'" }, - { name = "taskgroup", marker = "python_full_version == '3.10.*'" }, - { name = "typer", marker = "python_full_version >= '3.10'" }, - { name = "typing-extensions", marker = "python_full_version >= '3.10'" }, + { name = "cloudpickle" }, + { name = "croniter" }, + { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, + { name = "fakeredis", extra = ["lua"] }, + { name = "opentelemetry-api" }, + { name = "prometheus-client" }, + { name = "py-key-value-aio", extra = ["memory", "redis"] }, + { name = "python-json-logger" }, + { name = "redis" }, + { name = "rich" }, + { name = "taskgroup", marker = "python_full_version < '3.11'" }, + { name = "typer" }, + { name = "typing-extensions" }, ] sdist = { url = "https://files.pythonhosted.org/packages/73/26/ac23ead3725475468b50b486939bf5feda27180050a614a7407344a0af0e/pydocket-0.17.5.tar.gz", hash = "sha256:19a6976d8fd11c1acf62feb0291a339e06beaefa100f73dd38c6499760ad3e62", size = 334829, upload-time = "2026-01-30T18:44:39.702Z" } wheels = [ @@ -5491,8 +4241,7 @@ dependencies = [ { name = "pynacl" }, { name = "requests" }, { name = "typing-extensions" }, - { name = "urllib3", version = "1.26.20", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "urllib3", version = "2.6.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "urllib3" }, ] sdist = { url = "https://files.pythonhosted.org/packages/c1/74/e560bdeffea72ecb26cff27f0fad548bbff5ecc51d6a155311ea7f9e4c4c/pygithub-2.8.1.tar.gz", hash = "sha256:341b7c78521cb07324ff670afd1baa2bf5c286f8d9fd302c1798ba594a5400c9", size = 2246994, upload-time = "2025-09-02T17:41:54.674Z" } wheels = [ @@ -5527,8 +4276,7 @@ name = "pymdown-extensions" version = "10.20.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "markdown", version = "3.9", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "markdown", version = "3.10.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "markdown" }, { name = "pyyaml" }, ] sdist = { url = "https://files.pythonhosted.org/packages/1e/6c/9e370934bfa30e889d12e61d0dae009991294f40055c238980066a7fbd83/pymdown_extensions-10.20.1.tar.gz", hash = "sha256:e7e39c865727338d434b55f1dd8da51febcffcaebd6e1a0b9c836243f660740a", size = 852860, upload-time = "2026-01-24T05:56:56.758Z" } @@ -5587,8 +4335,7 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorama", marker = "sys_platform == 'win32'" }, { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, - { name = "iniconfig", version = "2.1.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "iniconfig", version = "2.3.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "iniconfig" }, { name = "packaging" }, { name = "pluggy" }, { name = "pygments" }, @@ -5605,7 +4352,6 @@ version = "4.2.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cffi" }, - { name = "importlib-metadata", marker = "python_full_version < '3.10'" }, { name = "pytest" }, { name = "rich" }, ] @@ -5623,8 +4369,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/f9/14/8d9340d7dc0ae647991b28a396e16b3403e10def883cde90d6b663d3f7ec/pytest_codspeed-4.2.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a0ebd87f2a99467a1cfd8e83492c4712976e43d353ee0b5f71cbb057f1393aca", size = 251057, upload-time = "2025-10-24T09:02:49.102Z" }, { url = "https://files.pythonhosted.org/packages/4b/39/48cf6afbca55bc7c8c93c3d4ae926a1068bcce3f0241709db19b078d5418/pytest_codspeed-4.2.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:dbbb2d61b85bef8fc7e2193f723f9ac2db388a48259d981bbce96319043e9830", size = 267983, upload-time = "2025-10-24T09:02:50.558Z" }, { url = "https://files.pythonhosted.org/packages/33/86/4407341efb5dceb3e389635749ce1d670542d6ca148bd34f9d5334295faf/pytest_codspeed-4.2.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:748411c832147bfc85f805af78a1ab1684f52d08e14aabe22932bbe46c079a5f", size = 256732, upload-time = "2025-10-24T09:02:51.603Z" }, - { url = "https://files.pythonhosted.org/packages/fe/60/c395c19c14a1345d41ac3f7f0a9b372b666e88f9ba1f71988215174882bb/pytest_codspeed-4.2.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:238e17abe8f08d8747fa6c7acff34fefd3c40f17a56a7847ca13dc8d6e8c6009", size = 261935, upload-time = "2025-10-24T09:02:52.702Z" }, - { url = "https://files.pythonhosted.org/packages/15/ed/442fb6a1832c2c9002653f24770873839b24c091bd2ed658090c7862c563/pytest_codspeed-4.2.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0881a736285f33b9a8894da8fe8e1775aa1a4310226abe5d1f0329228efb680c", size = 250770, upload-time = "2025-10-24T09:02:53.73Z" }, { url = "https://files.pythonhosted.org/packages/25/0e/8cb71fd3ed4ed08c07aec1245aea7bc1b661ba55fd9c392db76f1978d453/pytest_codspeed-4.2.0-py3-none-any.whl", hash = "sha256:e81bbb45c130874ef99aca97929d72682733527a49f84239ba575b5cb843bab0", size = 113726, upload-time = "2025-10-24T09:02:54.785Z" }, ] @@ -5658,26 +4402,10 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/51/e5/fecf13f06e5e5f67e8837d777d1bc43fac0ed2b77a676804df5c34744727/python_json_logger-4.0.0-py3-none-any.whl", hash = "sha256:af09c9daf6a813aa4cc7180395f50f2a9e5fa056034c9953aec92e381c5ba1e2", size = 15548, upload-time = "2025-10-06T04:15:17.553Z" }, ] -[[package]] -name = "python-multipart" -version = "0.0.20" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.10'", -] -sdist = { url = "https://files.pythonhosted.org/packages/f3/87/f44d7c9f274c7ee665a29b885ec97089ec5dc034c7f3fafa03da9e39a09e/python_multipart-0.0.20.tar.gz", hash = "sha256:8dd0cab45b8e23064ae09147625994d090fa46f5b0d1e13af944c331a7fa9d13", size = 37158, upload-time = "2024-12-16T19:45:46.972Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/45/58/38b5afbc1a800eeea951b9285d3912613f2603bdf897a4ab0f4bd7f405fc/python_multipart-0.0.20-py3-none-any.whl", hash = "sha256:8a62d3a8335e06589fe01f2a3e178cdcc632f3fbe0d492ad9ee0ec35aab1f104", size = 24546, upload-time = "2024-12-16T19:45:44.423Z" }, -] - [[package]] name = "python-multipart" version = "0.0.22" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.14'", - "python_full_version >= '3.10' and python_full_version < '3.14'", -] sdist = { url = "https://files.pythonhosted.org/packages/94/01/979e98d542a70714b0cb2b6728ed0b7c46792b695e3eaec3e20711271ca3/python_multipart-0.0.22.tar.gz", hash = "sha256:7340bef99a7e0032613f56dc36027b959fd3b30a787ed62d310e951f7c3a3a58", size = 37612, upload-time = "2026-01-25T10:15:56.219Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/1b/d0/397f9626e711ff749a95d96b7af99b9c566a9bb5129b8e4c10fc4d100304/python_multipart-0.0.22-py3-none-any.whl", hash = "sha256:2b2cd894c83d21bf49d702499531c7bafd057d730c201782048f7945d82de155", size = 24579, upload-time = "2026-01-25T10:15:54.811Z" }, @@ -5731,11 +4459,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/cf/35/3aa899645e29b6375b4aed9f8d21df219e7c958c4c186b465e42ee0a06bf/pytokens-0.4.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d31b97b3de0f61571a124a00ffe9a81fb9939146c122c11060725bd5aea79975", size = 303485, upload-time = "2026-01-30T01:03:28.558Z" }, { url = "https://files.pythonhosted.org/packages/52/a0/07907b6ff512674d9b201859f7d212298c44933633c946703a20c25e9d81/pytokens-0.4.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:967cf6e3fd4adf7de8fc73cd3043754ae79c36475c1c11d514fc72cf5490094a", size = 306698, upload-time = "2026-01-30T01:03:29.653Z" }, { url = "https://files.pythonhosted.org/packages/39/2a/cbbf9250020a4a8dd53ba83a46c097b69e5eb49dd14e708f496f548c6612/pytokens-0.4.1-cp314-cp314t-win_amd64.whl", hash = "sha256:584c80c24b078eec1e227079d56dc22ff755e0ba8654d8383b2c549107528918", size = 116287, upload-time = "2026-01-30T01:03:30.912Z" }, - { url = "https://files.pythonhosted.org/packages/51/2a/f125667ce48105bf1f4e50e03cfa7b24b8c4f47684d7f1cf4dcb6f6b1c15/pytokens-0.4.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:34bcc734bd2f2d5fe3b34e7b3c0116bfb2397f2d9666139988e7a3eb5f7400e3", size = 161464, upload-time = "2026-01-30T01:03:39.11Z" }, - { url = "https://files.pythonhosted.org/packages/40/df/065a30790a7ca6bb48ad9018dd44668ed9135610ebf56a2a4cb8e513fd5c/pytokens-0.4.1-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:941d4343bf27b605e9213b26bfa1c4bf197c9c599a9627eb7305b0defcfe40c1", size = 246159, upload-time = "2026-01-30T01:03:40.131Z" }, - { url = "https://files.pythonhosted.org/packages/a5/1c/fd09976a7e04960dabc07ab0e0072c7813d566ec67d5490a4c600683c158/pytokens-0.4.1-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3ad72b851e781478366288743198101e5eb34a414f1d5627cdd585ca3b25f1db", size = 259120, upload-time = "2026-01-30T01:03:41.233Z" }, - { url = "https://files.pythonhosted.org/packages/52/49/59fdc6fc5a390ae9f308eadeb97dfc70fc2d804ffc49dd39fc97604622ec/pytokens-0.4.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:682fa37ff4d8e95f7df6fe6fe6a431e8ed8e788023c6bcc0f0880a12eab80ad1", size = 262196, upload-time = "2026-01-30T01:03:42.696Z" }, - { url = "https://files.pythonhosted.org/packages/3d/e7/d6734dccf0080e3dc00a55b0827ab5af30c886f8bc127bbc04bc3445daec/pytokens-0.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:30f51edd9bb7f85c748979384165601d028b84f7bd13fe14d3e065304093916a", size = 103510, upload-time = "2026-01-30T01:03:43.915Z" }, { url = "https://files.pythonhosted.org/packages/c6/78/397db326746f0a342855b81216ae1f0a32965deccfd7c830a2dbc66d2483/pytokens-0.4.1-py3-none-any.whl", hash = "sha256:26cef14744a8385f35d0e095dc8b3a7583f6c953c2e3d269c7f82484bf5ad2de", size = 13729, upload-time = "2026-01-30T01:03:45.029Z" }, ] @@ -5768,9 +4491,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c9/31/097f2e132c4f16d99a22bfb777e0fd88bd8e1c634304e102f313af69ace5/pywin32-311-cp314-cp314-win32.whl", hash = "sha256:b7a2c10b93f8986666d0c803ee19b5990885872a7de910fc460f9b0c2fbf92ee", size = 8840714, upload-time = "2025-07-14T20:13:32.449Z" }, { url = "https://files.pythonhosted.org/packages/90/4b/07c77d8ba0e01349358082713400435347df8426208171ce297da32c313d/pywin32-311-cp314-cp314-win_amd64.whl", hash = "sha256:3aca44c046bd2ed8c90de9cb8427f581c479e594e99b5c0bb19b29c10fd6cb87", size = 9656800, upload-time = "2025-07-14T20:13:34.312Z" }, { url = "https://files.pythonhosted.org/packages/c0/d2/21af5c535501a7233e734b8af901574572da66fcc254cb35d0609c9080dd/pywin32-311-cp314-cp314-win_arm64.whl", hash = "sha256:a508e2d9025764a8270f93111a970e1d0fbfc33f4153b388bb649b7eec4f9b42", size = 8932540, upload-time = "2025-07-14T20:13:36.379Z" }, - { url = "https://files.pythonhosted.org/packages/59/42/b86689aac0cdaee7ae1c58d464b0ff04ca909c19bb6502d4973cdd9f9544/pywin32-311-cp39-cp39-win32.whl", hash = "sha256:aba8f82d551a942cb20d4a83413ccbac30790b50efb89a75e4f586ac0bb8056b", size = 8760837, upload-time = "2025-07-14T20:12:59.59Z" }, - { url = "https://files.pythonhosted.org/packages/9f/8a/1403d0353f8c5a2f0829d2b1c4becbf9da2f0a4d040886404fc4a5431e4d/pywin32-311-cp39-cp39-win_amd64.whl", hash = "sha256:e0c4cfb0621281fe40387df582097fd796e80430597cb9944f0ae70447bacd91", size = 9590187, upload-time = "2025-07-14T20:13:01.419Z" }, - { url = "https://files.pythonhosted.org/packages/60/22/e0e8d802f124772cec9c75430b01a212f86f9de7546bda715e54140d5aeb/pywin32-311-cp39-cp39-win_arm64.whl", hash = "sha256:62ea666235135fee79bb154e695f3ff67370afefd71bd7fea7512fc70ef31e3d", size = 8778162, upload-time = "2025-07-14T20:13:03.544Z" }, ] [[package]] @@ -5844,15 +4564,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/da/92/1446574745d74df0c92e6aa4a7b0b3130706a4142b2d1a5869f2eaa423c6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65", size = 829923, upload-time = "2025-09-25T21:32:54.537Z" }, { url = "https://files.pythonhosted.org/packages/f0/7a/1c7270340330e575b92f397352af856a8c06f230aa3e76f86b39d01b416a/pyyaml-6.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9", size = 174062, upload-time = "2025-09-25T21:32:55.767Z" }, { url = "https://files.pythonhosted.org/packages/f1/12/de94a39c2ef588c7e6455cfbe7343d3b2dc9d6b6b2f40c4c6565744c873d/pyyaml-6.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b", size = 149341, upload-time = "2025-09-25T21:32:56.828Z" }, - { url = "https://files.pythonhosted.org/packages/9f/62/67fc8e68a75f738c9200422bf65693fb79a4cd0dc5b23310e5202e978090/pyyaml-6.0.3-cp39-cp39-macosx_10_13_x86_64.whl", hash = "sha256:b865addae83924361678b652338317d1bd7e79b1f4596f96b96c77a5a34b34da", size = 184450, upload-time = "2025-09-25T21:33:00.618Z" }, - { url = "https://files.pythonhosted.org/packages/ae/92/861f152ce87c452b11b9d0977952259aa7df792d71c1053365cc7b09cc08/pyyaml-6.0.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c3355370a2c156cffb25e876646f149d5d68f5e0a3ce86a5084dd0b64a994917", size = 174319, upload-time = "2025-09-25T21:33:02.086Z" }, - { url = "https://files.pythonhosted.org/packages/d0/cd/f0cfc8c74f8a030017a2b9c771b7f47e5dd702c3e28e5b2071374bda2948/pyyaml-6.0.3-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3c5677e12444c15717b902a5798264fa7909e41153cdf9ef7ad571b704a63dd9", size = 737631, upload-time = "2025-09-25T21:33:03.25Z" }, - { url = "https://files.pythonhosted.org/packages/ef/b2/18f2bd28cd2055a79a46c9b0895c0b3d987ce40ee471cecf58a1a0199805/pyyaml-6.0.3-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5ed875a24292240029e4483f9d4a4b8a1ae08843b9c54f43fcc11e404532a8a5", size = 836795, upload-time = "2025-09-25T21:33:05.014Z" }, - { url = "https://files.pythonhosted.org/packages/73/b9/793686b2d54b531203c160ef12bec60228a0109c79bae6c1277961026770/pyyaml-6.0.3-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0150219816b6a1fa26fb4699fb7daa9caf09eb1999f3b70fb6e786805e80375a", size = 750767, upload-time = "2025-09-25T21:33:06.398Z" }, - { url = "https://files.pythonhosted.org/packages/a9/86/a137b39a611def2ed78b0e66ce2fe13ee701a07c07aebe55c340ed2a050e/pyyaml-6.0.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:fa160448684b4e94d80416c0fa4aac48967a969efe22931448d853ada8baf926", size = 727982, upload-time = "2025-09-25T21:33:08.708Z" }, - { url = "https://files.pythonhosted.org/packages/dd/62/71c27c94f457cf4418ef8ccc71735324c549f7e3ea9d34aba50874563561/pyyaml-6.0.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:27c0abcb4a5dac13684a37f76e701e054692a9b2d3064b70f5e4eb54810553d7", size = 755677, upload-time = "2025-09-25T21:33:09.876Z" }, - { url = "https://files.pythonhosted.org/packages/29/3d/6f5e0d58bd924fb0d06c3a6bad00effbdae2de5adb5cda5648006ffbd8d3/pyyaml-6.0.3-cp39-cp39-win32.whl", hash = "sha256:1ebe39cb5fc479422b83de611d14e2c0d3bb2a18bbcb01f229ab3cfbd8fee7a0", size = 142592, upload-time = "2025-09-25T21:33:10.983Z" }, - { url = "https://files.pythonhosted.org/packages/f0/0c/25113e0b5e103d7f1490c0e947e303fe4a696c10b501dea7a9f49d4e876c/pyyaml-6.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:2e71d11abed7344e42a8849600193d15b6def118602c4c176f748e4583246007", size = 158777, upload-time = "2025-09-25T21:33:15.55Z" }, ] [[package]] @@ -5881,7 +4592,7 @@ name = "redis" version = "7.1.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "async-timeout", marker = "python_full_version >= '3.10' and python_full_version < '3.11.3'" }, + { name = "async-timeout", marker = "python_full_version < '3.11.3'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/43/c8/983d5c6579a411d8a99bc5823cc5712768859b5ce2c8afe1a65b37832c81/redis-7.1.0.tar.gz", hash = "sha256:b1cc3cfa5a2cb9c2ab3ba700864fb0ad75617b41f01352ce5779dabf6d5f9c3c", size = 4796669, upload-time = "2025-11-19T15:54:39.961Z" } wheels = [ @@ -5893,9 +4604,9 @@ name = "referencing" version = "0.36.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "attrs", marker = "python_full_version >= '3.10'" }, - { name = "rpds-py", marker = "python_full_version >= '3.10'" }, - { name = "typing-extensions", marker = "python_full_version >= '3.10' and python_full_version < '3.13'" }, + { name = "attrs" }, + { name = "rpds-py" }, + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/2f/db/98b5c277be99dd18bfd91dd04e1b759cad18d1a338188c936e92f921c7e2/referencing-0.36.2.tar.gz", hash = "sha256:df2e89862cd09deabbdba16944cc3f10feb6b3e6f18e902f7cc25609a34775aa", size = 74744, upload-time = "2025-01-25T08:48:16.138Z" } wheels = [ @@ -6021,23 +4732,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e3/0d/3a6cfa9ae99606afb612d8fb7a66b245a9d5ff0f29bb347c8a30b6ad561b/regex-2026.1.15-cp314-cp314t-win32.whl", hash = "sha256:e90b8db97f6f2c97eb045b51a6b2c5ed69cedd8392459e0642d4199b94fabd7e", size = 274667, upload-time = "2026-01-14T23:17:19.301Z" }, { url = "https://files.pythonhosted.org/packages/5b/b2/297293bb0742fd06b8d8e2572db41a855cdf1cae0bf009b1cb74fe07e196/regex-2026.1.15-cp314-cp314t-win_amd64.whl", hash = "sha256:5ef19071f4ac9f0834793af85bd04a920b4407715624e40cb7a0631a11137cdf", size = 284386, upload-time = "2026-01-14T23:17:21.231Z" }, { url = "https://files.pythonhosted.org/packages/95/e4/a3b9480c78cf8ee86626cb06f8d931d74d775897d44201ccb813097ae697/regex-2026.1.15-cp314-cp314t-win_arm64.whl", hash = "sha256:ca89c5e596fc05b015f27561b3793dc2fa0917ea0d7507eebb448efd35274a70", size = 274837, upload-time = "2026-01-14T23:17:23.146Z" }, - { url = "https://files.pythonhosted.org/packages/a2/e7/0e1913dc52eee9c5cf8417c9813c4c55972a3f37d27cfa2e623b79b63dbc/regex-2026.1.15-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:55b4ea996a8e4458dd7b584a2f89863b1655dd3d17b88b46cbb9becc495a0ec5", size = 488185, upload-time = "2026-01-14T23:17:25.2Z" }, - { url = "https://files.pythonhosted.org/packages/78/df/c52c1ff4221529faad0953e197982fe9508c6dbb42327e31bf98ea07472a/regex-2026.1.15-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7e1e28be779884189cdd57735e997f282b64fd7ccf6e2eef3e16e57d7a34a815", size = 290628, upload-time = "2026-01-14T23:17:27.125Z" }, - { url = "https://files.pythonhosted.org/packages/4b/d2/a2fef3717deaff647d7de2bccf899a576c7eaf042b6b271fc4474515fe97/regex-2026.1.15-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0057de9eaef45783ff69fa94ae9f0fd906d629d0bd4c3217048f46d1daa32e9b", size = 288509, upload-time = "2026-01-14T23:17:29.017Z" }, - { url = "https://files.pythonhosted.org/packages/70/89/faf5ee5c69168753c845a3d58b4683f61c899d162bfe1264fca88d5b3924/regex-2026.1.15-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cc7cd0b2be0f0269283a45c0d8b2c35e149d1319dcb4a43c9c3689fa935c1ee6", size = 781088, upload-time = "2026-01-14T23:17:30.961Z" }, - { url = "https://files.pythonhosted.org/packages/7d/2c/707e5c380ad547c93686e21144e7e24dc2064dd84ec5b751b6dbdfc9be2b/regex-2026.1.15-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8db052bbd981e1666f09e957f3790ed74080c2229007c1dd67afdbf0b469c48b", size = 850516, upload-time = "2026-01-14T23:17:32.946Z" }, - { url = "https://files.pythonhosted.org/packages/5d/3b/baa816cdcad1c0f8195f9f40ab2b2a2246c8a2989dcd90641c0c6559e3fd/regex-2026.1.15-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:343db82cb3712c31ddf720f097ef17c11dab2f67f7a3e7be976c4f82eba4e6df", size = 898124, upload-time = "2026-01-14T23:17:36.019Z" }, - { url = "https://files.pythonhosted.org/packages/e7/74/1eb46bde30899825ed9fdf645eba16b7b97c49d12d300f5177989b9a09a4/regex-2026.1.15-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:55e9d0118d97794367309635df398bdfd7c33b93e2fdfa0b239661cd74b4c14e", size = 791290, upload-time = "2026-01-14T23:17:38.097Z" }, - { url = "https://files.pythonhosted.org/packages/c4/5d/b72e176fb21e2ec248baed01151a342d1f44dd43c2b6bb6a41ad183b274e/regex-2026.1.15-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:008b185f235acd1e53787333e5690082e4f156c44c87d894f880056089e9bc7c", size = 781996, upload-time = "2026-01-14T23:17:40.109Z" }, - { url = "https://files.pythonhosted.org/packages/61/0e/d3b3710eaafd994a4a71205d114abc38cda8691692a2ce2313abe68e7eb7/regex-2026.1.15-cp39-cp39-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:fd65af65e2aaf9474e468f9e571bd7b189e1df3a61caa59dcbabd0000e4ea839", size = 767578, upload-time = "2026-01-14T23:17:42.134Z" }, - { url = "https://files.pythonhosted.org/packages/09/51/c6a6311833e040f95d229a34d82ac1cec2af8a5c00d58b244f2fceecef87/regex-2026.1.15-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:f42e68301ff4afee63e365a5fc302b81bb8ba31af625a671d7acb19d10168a8c", size = 774354, upload-time = "2026-01-14T23:17:44.392Z" }, - { url = "https://files.pythonhosted.org/packages/cc/97/c522d1f19fb2c549aaf680b115c110cd124c02062bc8c95f33db8583b4bb/regex-2026.1.15-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:f7792f27d3ee6e0244ea4697d92b825f9a329ab5230a78c1a68bd274e64b5077", size = 845297, upload-time = "2026-01-14T23:17:47.145Z" }, - { url = "https://files.pythonhosted.org/packages/99/a0/99468c386ab68a5e24c946c5c353c29c33a95523e275c17839f2446db15d/regex-2026.1.15-cp39-cp39-musllinux_1_2_riscv64.whl", hash = "sha256:dbaf3c3c37ef190439981648ccbf0c02ed99ae066087dd117fcb616d80b010a4", size = 755132, upload-time = "2026-01-14T23:17:49.796Z" }, - { url = "https://files.pythonhosted.org/packages/70/33/d5748c7b6c9d3621f12570583561ba529e2d1b12e4f70b8f17979b133e65/regex-2026.1.15-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:adc97a9077c2696501443d8ad3fa1b4fc6d131fc8fd7dfefd1a723f89071cf0a", size = 835662, upload-time = "2026-01-14T23:17:52.559Z" }, - { url = "https://files.pythonhosted.org/packages/ad/15/1986972c276672505437f1ba3c9706c2d91f321cfb9b2f4d06e8bff1b999/regex-2026.1.15-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:069f56a7bf71d286a6ff932a9e6fb878f151c998ebb2519a9f6d1cee4bffdba3", size = 779513, upload-time = "2026-01-14T23:17:54.711Z" }, - { url = "https://files.pythonhosted.org/packages/bc/f9/124f6a5cb3969d8e30471ed4f46cfc17c47aef1a9863ee8b4ba1d98b1bc4/regex-2026.1.15-cp39-cp39-win32.whl", hash = "sha256:ea4e6b3566127fda5e007e90a8fd5a4169f0cf0619506ed426db647f19c8454a", size = 265923, upload-time = "2026-01-14T23:17:56.69Z" }, - { url = "https://files.pythonhosted.org/packages/7b/c2/bb8fad7d27f1d71fc9772befd544bccd22eddc62a6735f57b003b4aff005/regex-2026.1.15-cp39-cp39-win_amd64.whl", hash = "sha256:cda1ed70d2b264952e88adaa52eea653a33a1b98ac907ae2f86508eb44f65cdc", size = 277900, upload-time = "2026-01-14T23:17:58.72Z" }, - { url = "https://files.pythonhosted.org/packages/f7/fa/4e033327c1d8350bc812cac906d873984d3d4b39529252f392a47ccc356d/regex-2026.1.15-cp39-cp39-win_arm64.whl", hash = "sha256:b325d4714c3c48277bfea1accd94e193ad6ed42b4bad79ad64f3b8f8a31260a5", size = 270413, upload-time = "2026-01-14T23:18:00.764Z" }, ] [[package]] @@ -6048,8 +4742,7 @@ dependencies = [ { name = "certifi" }, { name = "charset-normalizer" }, { name = "idna" }, - { name = "urllib3", version = "1.26.20", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "urllib3", version = "2.6.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "urllib3" }, ] sdist = { url = "https://files.pythonhosted.org/packages/c9/74/b3ff8e6c8446842c3f5c837e9c3dfcfe2018ea6ecef224c710c85ef728f4/requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf", size = 134517, upload-time = "2025-08-18T20:46:02.573Z" } wheels = [ @@ -6061,8 +4754,7 @@ name = "rich" version = "14.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "markdown-it-py", version = "3.0.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "markdown-it-py", version = "4.0.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "markdown-it-py" }, { name = "pygments" }, ] sdist = { url = "https://files.pythonhosted.org/packages/74/99/a4cab2acbb884f80e558b0771e97e21e939c5dfb460f488d19df485e8298/rich-14.3.2.tar.gz", hash = "sha256:e712f11c1a562a11843306f5ed999475f09ac31ffb64281f73ab29ffdda8b3b8", size = 230143, upload-time = "2026-02-01T16:20:47.908Z" } @@ -6075,8 +4767,8 @@ name = "rich-rst" version = "1.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "docutils", marker = "python_full_version >= '3.10'" }, - { name = "rich", marker = "python_full_version >= '3.10'" }, + { name = "docutils" }, + { name = "rich" }, ] sdist = { url = "https://files.pythonhosted.org/packages/bc/6d/a506aaa4a9eaa945ed8ab2b7347859f53593864289853c5d6d62b77246e0/rich_rst-1.3.2.tar.gz", hash = "sha256:a1196fdddf1e364b02ec68a05e8ff8f6914fee10fbca2e6b6735f166bb0da8d4", size = 14936, upload-time = "2025-10-14T16:49:45.332Z" } wheels = [ @@ -6088,8 +4780,7 @@ name = "rich-toolkit" version = "0.18.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "click", version = "8.1.8", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "click", version = "8.3.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "click" }, { name = "rich" }, { name = "typing-extensions" }, ] @@ -6193,20 +4884,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/fc/d3/18210222b37e87e36357f7b300b7d98c6dd62b133771e71ae27acba83a4f/rignore-0.7.6-cp314-cp314t-win32.whl", hash = "sha256:c1d8f117f7da0a4a96a8daef3da75bc090e3792d30b8b12cfadc240c631353f9", size = 647033, upload-time = "2025-11-05T21:42:00.095Z" }, { url = "https://files.pythonhosted.org/packages/3e/87/033eebfbee3ec7d92b3bb1717d8f68c88e6fc7de54537040f3b3a405726f/rignore-0.7.6-cp314-cp314t-win_amd64.whl", hash = "sha256:ca36e59408bec81de75d307c568c2d0d410fb880b1769be43611472c61e85c96", size = 725647, upload-time = "2025-11-05T21:41:44.449Z" }, { url = "https://files.pythonhosted.org/packages/79/62/b88e5879512c55b8ee979c666ee6902adc4ed05007226de266410ae27965/rignore-0.7.6-cp314-cp314t-win_arm64.whl", hash = "sha256:b83adabeb3e8cf662cabe1931b83e165b88c526fa6af6b3aa90429686e474896", size = 656035, upload-time = "2025-11-05T21:41:31.13Z" }, - { url = "https://files.pythonhosted.org/packages/b9/b4/e7577504d926ced2d6a3fa5ec5f27756639a1ed58a6a3fbefcf3a5659721/rignore-0.7.6-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:b3746bda73f2fe6a9c3ab2f20b792e7d810b30acbdba044313fbd2d0174802e7", size = 886535, upload-time = "2025-11-05T20:42:49.317Z" }, - { url = "https://files.pythonhosted.org/packages/2b/74/098bc71a33e2997bc3291d500760123d23e3a6d354380d26c8a7ddc036de/rignore-0.7.6-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:67a99cf19a5137cc12f14b78dc1bb3f48500f1d5580702c623297d5297bf2752", size = 826621, upload-time = "2025-11-05T20:42:32.421Z" }, - { url = "https://files.pythonhosted.org/packages/7b/73/5f8c276d71009a7e73fb3af6ec3bb930269efeae5830de5c796fa1fb020f/rignore-0.7.6-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b9e851cfa87033c0c3fd9d35dd8b102aff2981db8bc6e0cab27b460bfe38bf3f", size = 900335, upload-time = "2025-11-05T20:40:59.178Z" }, - { url = "https://files.pythonhosted.org/packages/0d/5f/dde3758084a087e6a5cd981c5277c6171d12127deed64fc4fbf12fb8ceaa/rignore-0.7.6-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e9b0def154665036516114437a5d603274e5451c0dc9694f622cc3b7e94603e7", size = 874274, upload-time = "2025-11-05T20:41:14.512Z" }, - { url = "https://files.pythonhosted.org/packages/58/b9/da85646824ab728036378ce62c330316108a52f30f36e6c69cac6ceda376/rignore-0.7.6-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b81274a47e8121224f7f637392b5dfcd9558e32a53e67ba7d04007d8b5281da9", size = 1171639, upload-time = "2025-11-05T20:41:31.206Z" }, - { url = "https://files.pythonhosted.org/packages/35/d1/8c12b779b7f0302c03c1d41511f2ab47012afecdfcd684fbec80af06b331/rignore-0.7.6-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d75d0b0696fb476664bea1169c8e67b13197750b91eceb4f10b3c7f379c7a204", size = 943985, upload-time = "2025-11-05T20:41:45.598Z" }, - { url = "https://files.pythonhosted.org/packages/79/bf/c233a85d31e4f94b911e92ee7e2dd2b962a5c2528f5ebd79a702596f0626/rignore-0.7.6-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6ad3aa4dca77cef9168d0c142f72376f5bd27d1d4b8a81561bd01276d3ad9fe1", size = 961707, upload-time = "2025-11-05T20:42:16.461Z" }, - { url = "https://files.pythonhosted.org/packages/9d/eb/cadee9316a5f2a52b4aa7051967ecb94ec17938d6b425bd842d9317559eb/rignore-0.7.6-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:00f8a59e19d219f44a93af7173de197e0d0e61c386364da20ebe98a303cbe38c", size = 986638, upload-time = "2025-11-05T20:42:00.65Z" }, - { url = "https://files.pythonhosted.org/packages/d0/f0/2c3042c8c9639056593def5e99c3bfe850fbb9a38d061ba67b6314315bad/rignore-0.7.6-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:dd6c682f3cdd741e7a30af2581f6a382ac910080977cd1f97c651467b6268352", size = 1080136, upload-time = "2025-11-05T21:40:21.551Z" }, - { url = "https://files.pythonhosted.org/packages/fc/28/7237b9eb1257b593ee51cd7ef8eed7cc32f50ccff18cb4d7cfe1e6dc54d7/rignore-0.7.6-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:ae4e93193f75ebf6b820241594a78f347785cfd5a5fbbac94634052589418352", size = 1139413, upload-time = "2025-11-05T21:40:39.025Z" }, - { url = "https://files.pythonhosted.org/packages/a5/df/c3f382a31ad7ed68510b411c28fec42354d2c43fecb7c053d998ee9410ed/rignore-0.7.6-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:1163d8b5d3a320d4d7cc8635213328850dc41f60e438c7869d540061adf66c98", size = 1120204, upload-time = "2025-11-05T21:40:56.062Z" }, - { url = "https://files.pythonhosted.org/packages/9c/3d/e8585c4e9c0077255ba599684aee78326176ab13ff13805ea62aa7e3235f/rignore-0.7.6-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:3e685f47b4c58b2df7dee81ebc1ec9dbb7f798b9455c3f22be6d75ac6bddee30", size = 1129757, upload-time = "2025-11-05T21:41:14.148Z" }, - { url = "https://files.pythonhosted.org/packages/fd/56/852226c13f89ddbbf12d639900941dc55dcbcf79f5d15294796fd3279d73/rignore-0.7.6-cp39-cp39-win32.whl", hash = "sha256:2af6a0a76575220863cd838693c808a94e750640e0c8a3e9f707e93c2f131fdf", size = 648265, upload-time = "2025-11-05T21:41:58.589Z" }, - { url = "https://files.pythonhosted.org/packages/cc/c6/14e7585dc453a870fe99b1270ee95e2adff02ea0d297cd6e2c4aa46cd43a/rignore-0.7.6-cp39-cp39-win_amd64.whl", hash = "sha256:a326eab6db9ab85b4afb5e6eb28736a9f2b885a9246d9e8c1989bc693dd059a0", size = 728715, upload-time = "2025-11-05T21:41:42.823Z" }, { url = "https://files.pythonhosted.org/packages/85/12/62d690b4644c330d7ac0f739b7f078190ab4308faa909a60842d0e4af5b2/rignore-0.7.6-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:c3d3a523af1cd4ed2c0cba8d277a32d329b0c96ef9901fb7ca45c8cfaccf31a5", size = 887462, upload-time = "2025-11-05T20:42:50.804Z" }, { url = "https://files.pythonhosted.org/packages/05/bc/6528a0e97ed2bd7a7c329183367d1ffbc5b9762ae8348d88dae72cc9d1f5/rignore-0.7.6-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:990853566e65184a506e1e2af2d15045afad3ebaebb8859cb85b882081915110", size = 826918, upload-time = "2025-11-05T20:42:33.689Z" }, { url = "https://files.pythonhosted.org/packages/3e/2c/7d7bad116e09a04e9e1688c6f891fa2d4fd33f11b69ac0bd92419ddebeae/rignore-0.7.6-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1cab9ff2e436ce7240d7ee301c8ef806ed77c1fd6b8a8239ff65f9bbbcb5b8a3", size = 900922, upload-time = "2025-11-05T20:41:00.361Z" }, @@ -6231,18 +4908,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/67/56/36d5d34210e5e7dfcd134eed8335b19e80ae940ee758f493e4f2b344dd70/rignore-0.7.6-pp311-pypy311_pp73-musllinux_1_2_armv7l.whl", hash = "sha256:c081f17290d8a2b96052b79207622aa635686ea39d502b976836384ede3d303c", size = 1139789, upload-time = "2025-11-05T21:40:42.119Z" }, { url = "https://files.pythonhosted.org/packages/6b/5b/bb4f9420802bf73678033a4a55ab1bede36ce2e9b41fec5f966d83d932b3/rignore-0.7.6-pp311-pypy311_pp73-musllinux_1_2_i686.whl", hash = "sha256:57e8327aacc27f921968cb2a174f9e47b084ce9a7dd0122c8132d22358f6bd79", size = 1120308, upload-time = "2025-11-05T21:40:59.402Z" }, { url = "https://files.pythonhosted.org/packages/ce/8b/a1299085b28a2f6135e30370b126e3c5055b61908622f2488ade67641479/rignore-0.7.6-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:d8955b57e42f2a5434670d5aa7b75eaf6e74602ccd8955dddf7045379cd762fb", size = 1129444, upload-time = "2025-11-05T21:41:17.906Z" }, - { url = "https://files.pythonhosted.org/packages/47/98/80ef6fda78161e88ef9336fcbe851afccf78c48e69e8266a23fb7922b5aa/rignore-0.7.6-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:e6ba1511c0ab8cd1ed8d6055bb0a6e629f48bfe04854293e0cd2dd88bd7153f8", size = 887180, upload-time = "2025-11-05T21:40:07.665Z" }, - { url = "https://files.pythonhosted.org/packages/21/d7/8666e7081f8476b003d8d2c8f39ecc17c93b7efd261740d15b6830acde82/rignore-0.7.6-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:50586d90be15f9aa8a2e2ee5a042ee6c51e28848812a35f0c95d4bfc0533d469", size = 827029, upload-time = "2025-11-05T20:42:36.628Z" }, - { url = "https://files.pythonhosted.org/packages/01/aa/3aba657d17b1737f4180b143866fedd269de15f361a8cb26ba363c0c3c13/rignore-0.7.6-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5b129873dd0ade248e67f25a09b5b72288cbef76ba1a9aae6bac193ee1d8be72", size = 901338, upload-time = "2025-11-05T20:41:03.059Z" }, - { url = "https://files.pythonhosted.org/packages/90/cc/d8c2c9770f5f61b28999c582804f282f2227c155ba13dfb0e9ea03daeaaf/rignore-0.7.6-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d9d6dd947556ddebfd62753005104986ee14a4e0663818aed19cdf2c33a6b5d5", size = 877563, upload-time = "2025-11-05T20:41:19.209Z" }, - { url = "https://files.pythonhosted.org/packages/55/63/42dd625bf96989be4a928b5444ddec9101ee63a98a15646e611b3ce58b82/rignore-0.7.6-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:91b95faa532efba888b196331e9af69e693635d469185ac52c796e435e2484e5", size = 1171087, upload-time = "2025-11-05T20:41:35.558Z" }, - { url = "https://files.pythonhosted.org/packages/bf/1e/4130fb622c2081c5322caf7a8888d1d265b99cd5d62cb714b512b8911233/rignore-0.7.6-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a1016f430fb56f7e400838bbc56fdf43adddb6fcb7bf2a14731dfd725c2fae6c", size = 944335, upload-time = "2025-11-05T20:41:49.859Z" }, - { url = "https://files.pythonhosted.org/packages/0f/b9/3d3ef7773da85e002fab53b1fdd9e9bb111cc86792b761cb38bd00c1532e/rignore-0.7.6-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f00c519861926dc703ecbb7bbeb884be67099f96f98b175671fa0a54718f55d1", size = 961500, upload-time = "2025-11-05T20:42:20.798Z" }, - { url = "https://files.pythonhosted.org/packages/1f/bc/346c874a31a721064935c60666a19016b6b01cd716cf73d52dc64e467b30/rignore-0.7.6-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e34d172bf50e881b7c02e530ae8b1ea96093f0b16634c344f637227b39707b41", size = 987741, upload-time = "2025-11-05T20:42:05.071Z" }, - { url = "https://files.pythonhosted.org/packages/6d/b8/d12dc548da8fdb63292a38727b035153495220cd93730019ee8ed3bdcffb/rignore-0.7.6-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:101d3143619898db1e7bede2e3e647daf19bb867c4fb25978016d67978d14868", size = 1081057, upload-time = "2025-11-05T21:40:26.53Z" }, - { url = "https://files.pythonhosted.org/packages/8e/51/7eea5d949212709740ad07e01c524336e44608ef0614a2a1cb31c9a0ea30/rignore-0.7.6-pp39-pypy39_pp73-musllinux_1_2_armv7l.whl", hash = "sha256:c9f3b420f54199a2b2b3b532d8c7e0860be3fa51f67501113cca6c7bfc392840", size = 1141653, upload-time = "2025-11-05T21:40:43.676Z" }, - { url = "https://files.pythonhosted.org/packages/c4/2b/76ec843cc392fcb4e37d6a8340e823a0bf644872e191d2f5652a4c2c18ee/rignore-0.7.6-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:1c6795e3694d750ae5ef172eab7d68a52aefbd9168d2e06647df691db2b03a50", size = 1121465, upload-time = "2025-11-05T21:41:00.904Z" }, - { url = "https://files.pythonhosted.org/packages/7c/9d/e69ad5cf03211a1076f9fe04ca2698c9cb8208b63419c928c26646bdf1d9/rignore-0.7.6-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:750a83a254b020e1193bfa7219dc7edca26bd8888a94cdc59720cbe386ab0c72", size = 1130110, upload-time = "2025-11-05T21:41:20.263Z" }, ] [[package]] @@ -6421,8 +5086,8 @@ name = "secretstorage" version = "3.5.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "cryptography", marker = "python_full_version >= '3.10'" }, - { name = "jeepney", marker = "python_full_version >= '3.10'" }, + { name = "cryptography" }, + { name = "jeepney" }, ] sdist = { url = "https://files.pythonhosted.org/packages/1c/03/e834bcd866f2f8a49a85eaff47340affa3bfa391ee9912a952a1faa68c7b/secretstorage-3.5.0.tar.gz", hash = "sha256:f04b8e4689cbce351744d5537bf6b1329c6fc68f91fa666f60a380edddcd11be", size = 19884, upload-time = "2025-11-23T19:02:53.191Z" } wheels = [ @@ -6435,8 +5100,7 @@ version = "2.52.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "certifi" }, - { name = "urllib3", version = "1.26.20", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "urllib3", version = "2.6.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "urllib3" }, ] sdist = { url = "https://files.pythonhosted.org/packages/59/eb/1b497650eb564701f9a7b8a95c51b2abe9347ed2c0b290ba78f027ebe4ea/sentry_sdk-2.52.0.tar.gz", hash = "sha256:fa0bec872cfec0302970b2996825723d67390cdd5f0229fb9efed93bd5384899", size = 410273, upload-time = "2026-02-04T15:03:54.706Z" } wheels = [ @@ -6506,8 +5170,7 @@ name = "sqlalchemy" version = "2.0.46" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "greenlet", version = "3.2.4", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version < '3.10' and platform_machine == 'AMD64') or (python_full_version < '3.10' and platform_machine == 'WIN32') or (python_full_version < '3.10' and platform_machine == 'aarch64') or (python_full_version < '3.10' and platform_machine == 'amd64') or (python_full_version < '3.10' and platform_machine == 'ppc64le') or (python_full_version < '3.10' and platform_machine == 'win32') or (python_full_version < '3.10' and platform_machine == 'x86_64')" }, - { name = "greenlet", version = "3.3.1", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version >= '3.10' and platform_machine == 'AMD64') or (python_full_version >= '3.10' and platform_machine == 'WIN32') or (python_full_version >= '3.10' and platform_machine == 'aarch64') or (python_full_version >= '3.10' and platform_machine == 'amd64') or (python_full_version >= '3.10' and platform_machine == 'ppc64le') or (python_full_version >= '3.10' and platform_machine == 'win32') or (python_full_version >= '3.10' and platform_machine == 'x86_64')" }, + { name = "greenlet", marker = "platform_machine == 'AMD64' or platform_machine == 'WIN32' or platform_machine == 'aarch64' or platform_machine == 'amd64' or platform_machine == 'ppc64le' or platform_machine == 'win32' or platform_machine == 'x86_64'" }, { name = "typing-extensions" }, ] sdist = { url = "https://files.pythonhosted.org/packages/06/aa/9ce0f3e7a9829ead5c8ce549392f33a12c4555a6c0609bb27d882e9c7ddf/sqlalchemy-2.0.46.tar.gz", hash = "sha256:cf36851ee7219c170bb0793dbc3da3e80c582e04a5437bc601bfe8c85c9216d7", size = 9865393, upload-time = "2026-01-21T18:03:45.119Z" } @@ -6555,13 +5218,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d7/53/3b37dda0a5b137f21ef608d8dfc77b08477bab0fe2ac9d3e0a66eaeab6fc/sqlalchemy-2.0.46-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:42a1643dc5427b69aca967dae540a90b0fbf57eaf248f13a90ea5930e0966863", size = 3526296, upload-time = "2026-01-21T18:45:12.657Z" }, { url = "https://files.pythonhosted.org/packages/33/75/f28622ba6dde79cd545055ea7bd4062dc934e0621f7b3be2891f8563f8de/sqlalchemy-2.0.46-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:ff33c6e6ad006bbc0f34f5faf941cfc62c45841c64c0a058ac38c799f15b5ede", size = 3470008, upload-time = "2026-01-21T18:33:11.725Z" }, { url = "https://files.pythonhosted.org/packages/a9/42/4afecbbc38d5e99b18acef446453c76eec6fbd03db0a457a12a056836e22/sqlalchemy-2.0.46-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:82ec52100ec1e6ec671563bbd02d7c7c8d0b9e71a0723c72f22ecf52d1755330", size = 3476137, upload-time = "2026-01-21T18:45:15.001Z" }, - { url = "https://files.pythonhosted.org/packages/9a/06/a29b51a577cc5746712ed8a2870794659a6bf405264b32dd5ccc380844d1/sqlalchemy-2.0.46-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:90bde6c6b1827565a95fde597da001212ab436f1b2e0c2dcc7246e14db26e2a3", size = 2158097, upload-time = "2026-01-21T18:24:45.892Z" }, - { url = "https://files.pythonhosted.org/packages/be/55/44689ed21b5a82708502243310878cfc76e0f326ed16103f4336f605055b/sqlalchemy-2.0.46-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:94b1e5f3a5f1ff4f42d5daab047428cd45a3380e51e191360a35cef71c9a7a2a", size = 3233722, upload-time = "2026-01-21T18:30:56.334Z" }, - { url = "https://files.pythonhosted.org/packages/be/11/1d6024d9cdd2108d500b399bdc77a1738119789aa70c83d68e1012d32596/sqlalchemy-2.0.46-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:93bb0aae40b52c57fd74ef9c6933c08c040ba98daf23ad33c3f9893494b8d3ce", size = 3233038, upload-time = "2026-01-21T18:32:26.945Z" }, - { url = "https://files.pythonhosted.org/packages/38/6d/f813e3204baea710f2d82a61821bdf7b39cebda6dbba7cdeb976b0552239/sqlalchemy-2.0.46-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:c4e2cc868b7b5208aec6c960950b7bb821f82c2fe66446c92ee0a571765e91a5", size = 3183163, upload-time = "2026-01-21T18:30:58.647Z" }, - { url = "https://files.pythonhosted.org/packages/8d/5d/32b70643ef73c1bb3723a98316b89182cad2b9a6744d5335f1d69fcdb3f2/sqlalchemy-2.0.46-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:965c62be8256d10c11f8907e7a8d3e18127a4c527a5919d85fa87fd9ecc2cfdc", size = 3205174, upload-time = "2026-01-21T18:32:28.684Z" }, - { url = "https://files.pythonhosted.org/packages/99/a9/b9f7bd299b7550925e1e7d71d634e1eee23c035abed7de125fda7c74b0c8/sqlalchemy-2.0.46-cp39-cp39-win32.whl", hash = "sha256:9397b381dcee8a2d6b99447ae85ea2530dcac82ca494d1db877087a13e38926d", size = 2117095, upload-time = "2026-01-21T18:34:02.596Z" }, - { url = "https://files.pythonhosted.org/packages/04/0b/2e376b34a7c2f3d9d40811c3412fdc65cd35c6da2d660c283ad24bd9bab1/sqlalchemy-2.0.46-cp39-cp39-win_amd64.whl", hash = "sha256:4396c948d8217e83e2c202fbdcc0389cf8c93d2c1c5e60fa5c5a955eae0e64be", size = 2140517, upload-time = "2026-01-21T18:34:03.958Z" }, { url = "https://files.pythonhosted.org/packages/fc/a1/9c4efa03300926601c19c18582531b45aededfb961ab3c3585f1e24f120b/sqlalchemy-2.0.46-py3-none-any.whl", hash = "sha256:f9c11766e7e7c0a2767dda5acb006a118640c9fc0a4104214b96269bfb78399e", size = 1937882, upload-time = "2026-01-21T18:22:10.456Z" }, ] @@ -6583,80 +5239,37 @@ name = "sse-starlette" version = "3.2.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "anyio", marker = "python_full_version >= '3.10'" }, - { name = "starlette", version = "0.52.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "anyio" }, + { name = "starlette" }, ] sdist = { url = "https://files.pythonhosted.org/packages/8b/8d/00d280c03ffd39aaee0e86ec81e2d3b9253036a0f93f51d10503adef0e65/sse_starlette-3.2.0.tar.gz", hash = "sha256:8127594edfb51abe44eac9c49e59b0b01f1039d0c7461c6fd91d4e03b70da422", size = 27253, upload-time = "2026-01-17T13:11:05.62Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/96/7f/832f015020844a8b8f7a9cbc103dd76ba8e3875004c41e08440ea3a2b41a/sse_starlette-3.2.0-py3-none-any.whl", hash = "sha256:5876954bd51920fc2cd51baee47a080eb88a37b5b784e615abb0b283f801cdbf", size = 12763, upload-time = "2026-01-17T13:11:03.775Z" }, ] -[[package]] -name = "starlette" -version = "0.49.3" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.10'", -] -dependencies = [ - { name = "anyio", marker = "python_full_version < '3.10'" }, - { name = "typing-extensions", marker = "python_full_version < '3.10'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/de/1a/608df0b10b53b0beb96a37854ee05864d182ddd4b1156a22f1ad3860425a/starlette-0.49.3.tar.gz", hash = "sha256:1c14546f299b5901a1ea0e34410575bc33bbd741377a10484a54445588d00284", size = 2655031, upload-time = "2025-11-01T15:12:26.13Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a3/e0/021c772d6a662f43b63044ab481dc6ac7592447605b5b35a957785363122/starlette-0.49.3-py3-none-any.whl", hash = "sha256:b579b99715fdc2980cf88c8ec96d3bf1ce16f5a8051a7c2b84ef9b1cdecaea2f", size = 74340, upload-time = "2025-11-01T15:12:24.387Z" }, -] - [[package]] name = "starlette" version = "0.52.1" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.14'", - "python_full_version >= '3.10' and python_full_version < '3.14'", -] dependencies = [ - { name = "anyio", marker = "python_full_version >= '3.10'" }, - { name = "typing-extensions", marker = "python_full_version >= '3.10' and python_full_version < '3.13'" }, + { name = "anyio" }, + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/c4/68/79977123bb7be889ad680d79a40f339082c1978b5cfcf62c2d8d196873ac/starlette-0.52.1.tar.gz", hash = "sha256:834edd1b0a23167694292e94f597773bc3f89f362be6effee198165a35d62933", size = 2653702, upload-time = "2026-01-18T13:34:11.062Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/81/0d/13d1d239a25cbfb19e740db83143e95c772a1fe10202dda4b76792b114dd/starlette-0.52.1-py3-none-any.whl", hash = "sha256:0029d43eb3d273bc4f83a08720b4912ea4b071087a3b48db01b7c839f7954d74", size = 74272, upload-time = "2026-01-18T13:34:09.188Z" }, ] -[[package]] -name = "strawberry-graphql" -version = "0.283.3" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.10'", -] -dependencies = [ - { name = "graphql-core", marker = "python_full_version < '3.10'" }, - { name = "lia-web", marker = "python_full_version < '3.10'" }, - { name = "packaging", marker = "python_full_version < '3.10'" }, - { name = "python-dateutil", marker = "python_full_version < '3.10'" }, - { name = "typing-extensions", marker = "python_full_version < '3.10'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/30/74/729c227b1e7fce28678290a5013ddceb543f350b6c14ae83400ab2c727d1/strawberry_graphql-0.283.3.tar.gz", hash = "sha256:375e545856b7587debd4e0f1e2a6fca19d09cc126238a07b9e5164e5eb09342a", size = 212141, upload-time = "2025-10-10T20:03:46.985Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/23/1b/aa358ef730d727d2e42810bf943542a8cc4c15aa2401f8629d356643a06f/strawberry_graphql-0.283.3-py3-none-any.whl", hash = "sha256:3751d86a219d81a16a13f335bb7d2fa3f57a85fab83d7d284b8ea88e2261d68b", size = 309885, upload-time = "2025-10-10T20:03:44.051Z" }, -] - [[package]] name = "strawberry-graphql" version = "0.291.2" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.14'", - "python_full_version >= '3.10' and python_full_version < '3.14'", -] dependencies = [ - { name = "cross-web", marker = "python_full_version >= '3.10'" }, - { name = "graphql-core", marker = "python_full_version >= '3.10'" }, - { name = "packaging", marker = "python_full_version >= '3.10'" }, - { name = "python-dateutil", marker = "python_full_version >= '3.10'" }, - { name = "typing-extensions", marker = "python_full_version >= '3.10'" }, + { name = "cross-web" }, + { name = "graphql-core" }, + { name = "packaging" }, + { name = "python-dateutil" }, + { name = "typing-extensions" }, ] sdist = { url = "https://files.pythonhosted.org/packages/33/dd/e0e68f4b17da6ff5773fcd4bebf86fc4ff8620c854be816d047e9af8c4aa/strawberry_graphql-0.291.2.tar.gz", hash = "sha256:e6076604a786e8437bc64a27348584c082113442f072daf757b56e4863543a97", size = 217730, upload-time = "2026-02-06T14:40:51.173Z" } wheels = [ @@ -6680,50 +5293,24 @@ name = "taskgroup" version = "0.2.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "exceptiongroup", marker = "python_full_version >= '3.10' and python_full_version < '3.14'" }, - { name = "typing-extensions", marker = "python_full_version >= '3.10' and python_full_version < '3.14'" }, + { name = "exceptiongroup", marker = "python_full_version < '3.14'" }, + { name = "typing-extensions", marker = "python_full_version < '3.14'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/f0/8d/e218e0160cc1b692e6e0e5ba34e8865dbb171efeb5fc9a704544b3020605/taskgroup-0.2.2.tar.gz", hash = "sha256:078483ac3e78f2e3f973e2edbf6941374fbea81b9c5d0a96f51d297717f4752d", size = 11504, upload-time = "2025-01-03T09:24:13.761Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/d1/b1/74babcc824a57904e919f3af16d86c08b524c0691504baf038ef2d7f655c/taskgroup-0.2.2-py2.py3-none-any.whl", hash = "sha256:e2c53121609f4ae97303e9ea1524304b4de6faf9eb2c9280c7f87976479a52fb", size = 14237, upload-time = "2025-01-03T09:24:11.41Z" }, ] -[[package]] -name = "temporalio" -version = "1.16.0" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.10'", -] -dependencies = [ - { name = "nexus-rpc", version = "1.1.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "protobuf", version = "5.29.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "python-dateutil", marker = "python_full_version < '3.10'" }, - { name = "types-protobuf", marker = "python_full_version < '3.10'" }, - { name = "typing-extensions", marker = "python_full_version < '3.10'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/f3/32/375ab75d0ebb468cf9c8abbc450a03d3a8c66401fc320b338bd8c00d36b4/temporalio-1.16.0.tar.gz", hash = "sha256:dd926f3e30626fd4edf5e0ce596b75ecb5bbe0e4a0281e545ac91b5577967c91", size = 1733873, upload-time = "2025-08-21T22:12:50.879Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e0/36/12bb7234c83ddca4b8b032c8f1a9e07a03067c6ed6d2ddb39c770a4c87c6/temporalio-1.16.0-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:547c0853310350d3e5b5b9c806246cbf2feb523f685b05bf14ec1b0ece8a7bb6", size = 12540769, upload-time = "2025-08-21T22:11:24.551Z" }, - { url = "https://files.pythonhosted.org/packages/3c/16/a7d402435b8f994979abfeffd3f5ffcaaeada467ac16438e61c51c9f7abe/temporalio-1.16.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5b05bb0d06025645aed6f936615311a6774eb8dc66280f32a810aac2283e1258", size = 12968631, upload-time = "2025-08-21T22:11:48.375Z" }, - { url = "https://files.pythonhosted.org/packages/11/6f/16663eef877b61faa5fd917b3a63497416ec4319195af75f6169a1594479/temporalio-1.16.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0a08aed4e0f6c2b6bfc779b714e91dfe8c8491a0ddb4c4370627bb07f9bddcfd", size = 13164612, upload-time = "2025-08-21T22:12:16.366Z" }, - { url = "https://files.pythonhosted.org/packages/af/0e/8c6704ca7033aa09dc084f285d70481d758972cc341adc3c84d5f82f7b01/temporalio-1.16.0-cp39-abi3-win_amd64.whl", hash = "sha256:7c190362b0d7254f1f93fb71456063e7b299ac85a89f6227758af82c6a5aa65b", size = 13177058, upload-time = "2025-08-21T22:12:44.239Z" }, -] - [[package]] name = "temporalio" version = "1.20.0" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.14'", - "python_full_version >= '3.10' and python_full_version < '3.14'", -] dependencies = [ - { name = "nexus-rpc", version = "1.2.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, - { name = "protobuf", version = "6.33.5", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, - { name = "python-dateutil", marker = "python_full_version == '3.10.*'" }, - { name = "types-protobuf", marker = "python_full_version >= '3.10'" }, - { name = "typing-extensions", marker = "python_full_version >= '3.10'" }, + { name = "nexus-rpc" }, + { name = "protobuf" }, + { name = "python-dateutil", marker = "python_full_version < '3.11'" }, + { name = "types-protobuf" }, + { name = "typing-extensions" }, ] sdist = { url = "https://files.pythonhosted.org/packages/21/db/7d5118d28b0918888e1ec98f56f659fdb006351e06d95f30f4274962a76f/temporalio-1.20.0.tar.gz", hash = "sha256:5a6a85b7d298b7359bffa30025f7deac83c74ac095a4c6952fbf06c249a2a67c", size = 1850498, upload-time = "2025-11-25T21:25:20.225Z" } wheels = [ @@ -6734,51 +5321,19 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/11/23/5689c014a76aff3b744b3ee0d80815f63b1362637814f5fbb105244df09b/temporalio-1.20.0-cp310-abi3-win_amd64.whl", hash = "sha256:eacfd571b653e0a0f4aa6593f4d06fc628797898f0900d400e833a1f40cad03a", size = 12745027, upload-time = "2025-11-25T21:25:16.827Z" }, ] -[[package]] -name = "tenacity" -version = "9.1.2" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.10'", -] -sdist = { url = "https://files.pythonhosted.org/packages/0a/d4/2b0cd0fe285e14b36db076e78c93766ff1d529d70408bd1d2a5a84f1d929/tenacity-9.1.2.tar.gz", hash = "sha256:1169d376c297e7de388d18b4481760d478b0e99a777cad3a9c86e556f4b697cb", size = 48036, upload-time = "2025-04-02T08:25:09.966Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e5/30/643397144bfbfec6f6ef821f36f33e57d35946c44a2352d3c9f0ae847619/tenacity-9.1.2-py3-none-any.whl", hash = "sha256:f77bf36710d8b73a50b2dd155c97b870017ad21afe6ab300326b0371b3b05138", size = 28248, upload-time = "2025-04-02T08:25:07.678Z" }, -] - [[package]] name = "tenacity" version = "9.1.3" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.14'", - "python_full_version >= '3.10' and python_full_version < '3.14'", -] sdist = { url = "https://files.pythonhosted.org/packages/1e/4a/c3357c8742f361785e3702bb4c9c68c4cb37a80aa657640b820669be5af1/tenacity-9.1.3.tar.gz", hash = "sha256:a6724c947aa717087e2531f883bde5c9188f603f6669a9b8d54eb998e604c12a", size = 49002, upload-time = "2026-02-05T06:33:12.866Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/64/6b/cdc85edb15e384d8e934aad89638cc8646e118c80de94c60125d0fc0a185/tenacity-9.1.3-py3-none-any.whl", hash = "sha256:51171cfc6b8a7826551e2f029426b10a6af189c5ac6986adcd7eb36d42f17954", size = 28858, upload-time = "2026-02-05T06:33:11.219Z" }, ] -[[package]] -name = "termcolor" -version = "3.1.0" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.10'", -] -sdist = { url = "https://files.pythonhosted.org/packages/ca/6c/3d75c196ac07ac8749600b60b03f4f6094d54e132c4d94ebac6ee0e0add0/termcolor-3.1.0.tar.gz", hash = "sha256:6a6dd7fbee581909eeec6a756cff1d7f7c376063b14e4a298dc4980309e55970", size = 14324, upload-time = "2025-04-30T11:37:53.791Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/4f/bd/de8d508070629b6d84a30d01d57e4a65c69aa7f5abe7560b8fad3b50ea59/termcolor-3.1.0-py3-none-any.whl", hash = "sha256:591dd26b5c2ce03b9e43f391264626557873ce1d379019786f99b0c2bee140aa", size = 7684, upload-time = "2025-04-30T11:37:52.382Z" }, -] - [[package]] name = "termcolor" version = "3.3.0" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.14'", - "python_full_version >= '3.10' and python_full_version < '3.14'", -] sdist = { url = "https://files.pythonhosted.org/packages/46/79/cf31d7a93a8fdc6aa0fbb665be84426a8c5a557d9240b6239e9e11e35fc5/termcolor-3.3.0.tar.gz", hash = "sha256:348871ca648ec6a9a983a13ab626c0acce02f515b9e1983332b17af7979521c5", size = 14434, upload-time = "2025-12-29T12:55:21.882Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/33/d1/8bb87d21e9aeb323cc03034f5eaf2c8f69841e40e4853c2627edf8111ed3/termcolor-3.3.0-py3-none-any.whl", hash = "sha256:cf642efadaf0a8ebbbf4bc7a31cec2f9b5f21a9f726f4ccbb08192c9c26f43a5", size = 7734, upload-time = "2025-12-29T12:55:20.718Z" }, @@ -6798,8 +5353,8 @@ name = "tiktoken" version = "0.12.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "regex", marker = "python_full_version >= '3.10'" }, - { name = "requests", marker = "python_full_version >= '3.10'" }, + { name = "regex" }, + { name = "requests" }, ] sdist = { url = "https://files.pythonhosted.org/packages/7d/ab/4d017d0f76ec3171d469d80fc03dfbb4e48a4bcaddaa831b31d526f05edc/tiktoken-0.12.0.tar.gz", hash = "sha256:b18ba7ee2b093863978fcb14f74b3707cdc8d4d4d3836853ce7ec60772139931", size = 37806, upload-time = "2025-10-06T20:22:45.419Z" } wheels = [ @@ -6852,40 +5407,14 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/28/c0/3c7a39ff68022ddfd7d93f3337ad90389a342f761c4d71de99a3ccc57857/tiktoken-0.12.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:54c891b416a0e36b8e2045b12b33dd66fb34a4fe7965565f1b482da50da3e86a", size = 1194908, upload-time = "2025-10-06T20:22:32.073Z" }, { url = "https://files.pythonhosted.org/packages/ab/0d/c1ad6f4016a3968c048545f5d9b8ffebf577774b2ede3e2e352553b685fe/tiktoken-0.12.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5edb8743b88d5be814b1a8a8854494719080c28faaa1ccbef02e87354fe71ef0", size = 1253706, upload-time = "2025-10-06T20:22:33.385Z" }, { url = "https://files.pythonhosted.org/packages/af/df/c7891ef9d2712ad774777271d39fdef63941ffba0a9d59b7ad1fd2765e57/tiktoken-0.12.0-cp314-cp314t-win_amd64.whl", hash = "sha256:f61c0aea5565ac82e2ec50a05e02a6c44734e91b51c10510b084ea1b8e633a71", size = 920667, upload-time = "2025-10-06T20:22:34.444Z" }, - { url = "https://files.pythonhosted.org/packages/c7/d1/7507bfb9c2ceef52ae3ae813013215c185648e21127538aae66dedd3af9c/tiktoken-0.12.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:d51d75a5bffbf26f86554d28e78bfb921eae998edc2675650fd04c7e1f0cdc1e", size = 1053407, upload-time = "2025-10-06T20:22:35.492Z" }, - { url = "https://files.pythonhosted.org/packages/ee/4a/8ea1da602ac39dee4356b4cd6040a2325507482c36043044b6f581597b4f/tiktoken-0.12.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:09eb4eae62ae7e4c62364d9ec3a57c62eea707ac9a2b2c5d6bd05de6724ea179", size = 997150, upload-time = "2025-10-06T20:22:37.286Z" }, - { url = "https://files.pythonhosted.org/packages/2c/1a/62d1d36b167eccd441aff2f0091551ca834295541b949d161021aa658167/tiktoken-0.12.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:df37684ace87d10895acb44b7f447d4700349b12197a526da0d4a4149fde074c", size = 1131575, upload-time = "2025-10-06T20:22:39.023Z" }, - { url = "https://files.pythonhosted.org/packages/f7/16/544207d63c8c50edd2321228f21d236e4e49d235128bb7e3e0f69eed0807/tiktoken-0.12.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:4c9614597ac94bb294544345ad8cf30dac2129c05e2db8dc53e082f355857af7", size = 1154920, upload-time = "2025-10-06T20:22:40.175Z" }, - { url = "https://files.pythonhosted.org/packages/99/4c/0a3504157c81364fc0c64cada54efef0567961357e786706ea63bc8946e1/tiktoken-0.12.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:20cf97135c9a50de0b157879c3c4accbb29116bcf001283d26e073ff3b345946", size = 1196766, upload-time = "2025-10-06T20:22:41.365Z" }, - { url = "https://files.pythonhosted.org/packages/d4/46/8e6a258ae65447c75770fe5ea8968acab369e8c9f537f727c91f83772325/tiktoken-0.12.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:15d875454bbaa3728be39880ddd11a5a2a9e548c29418b41e8fd8a767172b5ec", size = 1258278, upload-time = "2025-10-06T20:22:42.846Z" }, - { url = "https://files.pythonhosted.org/packages/35/43/3b95de4f5e76f3cafc70dac9b1b9cfe759ff3bfd494ac91a280e93772e90/tiktoken-0.12.0-cp39-cp39-win_amd64.whl", hash = "sha256:2cff3688ba3c639ebe816f8d58ffbbb0aa7433e23e08ab1cade5d175fc973fb3", size = 881888, upload-time = "2025-10-06T20:22:44.059Z" }, -] - -[[package]] -name = "tinycss2" -version = "1.4.0" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.10'", -] -dependencies = [ - { name = "webencodings", marker = "python_full_version < '3.10'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/7a/fd/7a5ee21fd08ff70d3d33a5781c255cbe779659bd03278feb98b19ee550f4/tinycss2-1.4.0.tar.gz", hash = "sha256:10c0972f6fc0fbee87c3edb76549357415e94548c1ae10ebccdea16fb404a9b7", size = 87085, upload-time = "2024-10-24T14:58:29.895Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e6/34/ebdc18bae6aa14fbee1a08b63c015c72b64868ff7dae68808ab500c492e2/tinycss2-1.4.0-py3-none-any.whl", hash = "sha256:3a49cf47b7675da0b15d0c6e1df8df4ebd96e9394bb905a5775adb0d884c5289", size = 26610, upload-time = "2024-10-24T14:58:28.029Z" }, ] [[package]] name = "tinycss2" version = "1.5.1" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.14'", - "python_full_version >= '3.10' and python_full_version < '3.14'", -] dependencies = [ - { name = "webencodings", marker = "python_full_version >= '3.10'" }, + { name = "webencodings" }, ] sdist = { url = "https://files.pythonhosted.org/packages/a3/ae/2ca4913e5c0f09781d75482874c3a95db9105462a92ddd303c7d285d3df2/tinycss2-1.5.1.tar.gz", hash = "sha256:d339d2b616ba90ccce58da8495a78f46e55d4d25f9fd71dfd526f07e7d53f957", size = 88195, upload-time = "2025-11-23T10:29:10.082Z" } wheels = [ @@ -6920,10 +5449,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/46/cd/e4851401f3d8f6f45d8480262ab6a5c8cb9c4302a790a35aa14eeed6d2fd/tokenizers-0.22.2-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e10bf9113d209be7cd046d40fbabbaf3278ff6d18eb4da4c500443185dc1896c", size = 3161308, upload-time = "2026-01-05T10:40:40.737Z" }, { url = "https://files.pythonhosted.org/packages/6f/6e/55553992a89982cd12d4a66dddb5e02126c58677ea3931efcbe601d419db/tokenizers-0.22.2-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:64d94e84f6660764e64e7e0b22baa72f6cd942279fdbb21d46abd70d179f0195", size = 3718964, upload-time = "2026-01-05T10:40:46.56Z" }, { url = "https://files.pythonhosted.org/packages/59/8c/b1c87148aa15e099243ec9f0cf9d0e970cc2234c3257d558c25a2c5304e6/tokenizers-0.22.2-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f01a9c019878532f98927d2bacb79bbb404b43d3437455522a00a30718cdedb5", size = 3373542, upload-time = "2026-01-05T10:40:52.803Z" }, - { url = "https://files.pythonhosted.org/packages/27/46/8d7db1dff181be50b207ab0a7483a22d5c3a4f903a9afc7cf7e465ad8109/tokenizers-0.22.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:319f659ee992222f04e58f84cbf407cfa66a65fe3a8de44e8ad2bc53e7d99012", size = 3287784, upload-time = "2026-01-05T10:40:37.108Z" }, - { url = "https://files.pythonhosted.org/packages/5b/6e/3bc33cae8bf114afa5a98e35eb065c72b7c37d01d370906a893f33881767/tokenizers-0.22.2-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1e50f8554d504f617d9e9d6e4c2c2884a12b388a97c5c77f0bc6cf4cd032feee", size = 3164301, upload-time = "2026-01-05T10:40:42.367Z" }, - { url = "https://files.pythonhosted.org/packages/91/fc/6aa749d7d443aab4daa6f8bc00338389149fd2534e25b772285c3301993e/tokenizers-0.22.2-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1a62ba2c5faa2dd175aaeed7b15abf18d20266189fb3406c5d0550dd34dd5f37", size = 3717771, upload-time = "2026-01-05T10:40:49.076Z" }, - { url = "https://files.pythonhosted.org/packages/fc/60/5b440d251863bd33f9b0a416c695b0309487b83abf6f2dafe9163a3aeac2/tokenizers-0.22.2-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:143b999bdc46d10febb15cbffb4207ddd1f410e2c755857b5a0797961bbdc113", size = 3377740, upload-time = "2026-01-05T10:40:54.859Z" }, ] [[package]] @@ -6992,43 +5517,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/16/e1/3079a9ff9b8e11b846c6ac5c8b5bfb7ff225eee721825310c91b3b50304f/tqdm-4.67.3-py3-none-any.whl", hash = "sha256:ee1e4c0e59148062281c49d80b25b67771a127c85fc9676d3be5f243206826bf", size = 78374, upload-time = "2026-02-03T17:35:50.982Z" }, ] -[[package]] -name = "trio" -version = "0.31.0" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.10'", -] -dependencies = [ - { name = "attrs", marker = "python_full_version < '3.10'" }, - { name = "cffi", marker = "python_full_version < '3.10' and implementation_name != 'pypy' and os_name == 'nt'" }, - { name = "exceptiongroup", marker = "python_full_version < '3.10'" }, - { name = "idna", marker = "python_full_version < '3.10'" }, - { name = "outcome", marker = "python_full_version < '3.10'" }, - { name = "sniffio", marker = "python_full_version < '3.10'" }, - { name = "sortedcontainers", marker = "python_full_version < '3.10'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/76/8f/c6e36dd11201e2a565977d8b13f0b027ba4593c1a80bed5185489178e257/trio-0.31.0.tar.gz", hash = "sha256:f71d551ccaa79d0cb73017a33ef3264fde8335728eb4c6391451fe5d253a9d5b", size = 605825, upload-time = "2025-09-09T15:17:15.242Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/31/5b/94237a3485620dbff9741df02ff6d8acaa5fdec67d81ab3f62e4d8511bf7/trio-0.31.0-py3-none-any.whl", hash = "sha256:b5d14cd6293d79298b49c3485ffd9c07e3ce03a6da8c7dfbe0cb3dd7dc9a4774", size = 512679, upload-time = "2025-09-09T15:17:13.821Z" }, -] - [[package]] name = "trio" version = "0.32.0" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.14'", - "python_full_version >= '3.10' and python_full_version < '3.14'", -] dependencies = [ - { name = "attrs", marker = "python_full_version >= '3.10'" }, - { name = "cffi", marker = "python_full_version >= '3.10' and implementation_name != 'pypy' and os_name == 'nt'" }, - { name = "exceptiongroup", marker = "python_full_version == '3.10.*'" }, - { name = "idna", marker = "python_full_version >= '3.10'" }, - { name = "outcome", marker = "python_full_version >= '3.10'" }, - { name = "sniffio", marker = "python_full_version >= '3.10'" }, - { name = "sortedcontainers", marker = "python_full_version >= '3.10'" }, + { name = "attrs" }, + { name = "cffi", marker = "implementation_name != 'pypy' and os_name == 'nt'" }, + { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, + { name = "idna" }, + { name = "outcome" }, + { name = "sniffio" }, + { name = "sortedcontainers" }, ] sdist = { url = "https://files.pythonhosted.org/packages/d8/ce/0041ddd9160aac0031bcf5ab786c7640d795c797e67c438e15cfedf815c8/trio-0.32.0.tar.gz", hash = "sha256:150f29ec923bcd51231e1d4c71c7006e65247d68759dd1c19af4ea815a25806b", size = 605323, upload-time = "2025-10-31T07:18:17.466Z" } wheels = [ @@ -7040,8 +5540,7 @@ name = "typer" version = "0.21.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "click", version = "8.1.8", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "click", version = "8.3.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "click" }, { name = "rich" }, { name = "shellingham" }, { name = "typing-extensions" }, @@ -7069,31 +5568,12 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/aa/43/58e75bac4219cbafee83179505ff44cae3153ec279be0e30583a73b8f108/types_protobuf-6.32.1.20251210-py3-none-any.whl", hash = "sha256:2641f78f3696822a048cfb8d0ff42ccd85c25f12f871fbebe86da63793692140", size = 77921, upload-time = "2025-12-10T03:14:24.477Z" }, ] -[[package]] -name = "types-requests" -version = "2.31.0.6" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.10'", -] -dependencies = [ - { name = "types-urllib3", marker = "python_full_version < '3.10'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/f9/b8/c1e8d39996b4929b918aba10dba5de07a8b3f4c8487bb61bb79882544e69/types-requests-2.31.0.6.tar.gz", hash = "sha256:cd74ce3b53c461f1228a9b783929ac73a666658f223e28ed29753771477b3bd0", size = 15535, upload-time = "2023-09-27T06:19:38.443Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/5c/a1/6f8dc74d9069e790d604ddae70cb46dcbac668f1bb08136e7b0f2f5cd3bf/types_requests-2.31.0.6-py3-none-any.whl", hash = "sha256:a2db9cb228a81da8348b49ad6db3f5519452dd20a9c1e1a868c83c5fe88fd1a9", size = 14516, upload-time = "2023-09-27T06:19:36.373Z" }, -] - [[package]] name = "types-requests" version = "2.32.4.20260107" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.14'", - "python_full_version >= '3.10' and python_full_version < '3.14'", -] dependencies = [ - { name = "urllib3", version = "2.6.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "urllib3" }, ] sdist = { url = "https://files.pythonhosted.org/packages/0f/f3/a0663907082280664d745929205a89d41dffb29e89a50f753af7d57d0a96/types_requests-2.32.4.20260107.tar.gz", hash = "sha256:018a11ac158f801bfa84857ddec1650750e393df8a004a8a9ae2a9bec6fcb24f", size = 23165, upload-time = "2026-01-07T03:20:54.091Z" } wheels = [ @@ -7109,15 +5589,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d7/f2/d812543c350674d8b3f6e17c8922248ee3bb752c2a76f64beb8c538b40cf/types_ujson-5.10.0.20250822-py3-none-any.whl", hash = "sha256:3e9e73a6dc62ccc03449d9ac2c580cd1b7a8e4873220db498f7dd056754be080", size = 7657, upload-time = "2025-08-22T03:02:18.699Z" }, ] -[[package]] -name = "types-urllib3" -version = "1.26.25.14" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/73/de/b9d7a68ad39092368fb21dd6194b362b98a1daeea5dcfef5e1adb5031c7e/types-urllib3-1.26.25.14.tar.gz", hash = "sha256:229b7f577c951b8c1b92c1bc2b2fdb0b49847bd2af6d1cc2a2e3dd340f3bda8f", size = 11239, upload-time = "2023-07-20T15:19:31.307Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/11/7b/3fc711b2efea5e85a7a0bbfe269ea944aa767bbba5ec52f9ee45d362ccf3/types_urllib3-1.26.25.14-py3-none-any.whl", hash = "sha256:9683bbb7fb72e32bfe9d2be6e04875fbe1b3eeec3cbb4ea231435aa7fd6b4f0e", size = 15377, upload-time = "2023-07-20T15:19:30.379Z" }, -] - [[package]] name = "typing-extensions" version = "4.15.0" @@ -7211,17 +5682,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/30/ed/5a057199fb0a5deabe0957073a1c1c1c02a3e99476cd03daee98ea21fa57/ujson-5.11.0-cp314-cp314t-win32.whl", hash = "sha256:aa6d7a5e09217ff93234e050e3e380da62b084e26b9f2e277d2606406a2fc2e5", size = 41859, upload-time = "2025-08-20T11:56:30.495Z" }, { url = "https://files.pythonhosted.org/packages/aa/03/b19c6176bdf1dc13ed84b886e99677a52764861b6cc023d5e7b6ebda249d/ujson-5.11.0-cp314-cp314t-win_amd64.whl", hash = "sha256:48055e1061c1bb1f79e75b4ac39e821f3f35a9b82de17fce92c3140149009bec", size = 46183, upload-time = "2025-08-20T11:56:31.574Z" }, { url = "https://files.pythonhosted.org/packages/5d/ca/a0413a3874b2dc1708b8796ca895bf363292f9c70b2e8ca482b7dbc0259d/ujson-5.11.0-cp314-cp314t-win_arm64.whl", hash = "sha256:1194b943e951092db611011cb8dbdb6cf94a3b816ed07906e14d3bc6ce0e90ab", size = 40264, upload-time = "2025-08-20T11:56:32.773Z" }, - { url = "https://files.pythonhosted.org/packages/39/bf/c6f59cdf74ce70bd937b97c31c42fd04a5ed1a9222d0197e77e4bd899841/ujson-5.11.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:65f3c279f4ed4bf9131b11972040200c66ae040368abdbb21596bf1564899694", size = 55283, upload-time = "2025-08-20T11:56:33.947Z" }, - { url = "https://files.pythonhosted.org/packages/8d/c1/a52d55638c0c644b8a63059f95ad5ffcb4ad8f60d8bc3e8680f78e77cc75/ujson-5.11.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:99c49400572cd77050894e16864a335225191fd72a818ea6423ae1a06467beac", size = 53168, upload-time = "2025-08-20T11:56:35.141Z" }, - { url = "https://files.pythonhosted.org/packages/75/6c/e64e19a01d59c8187d01ffc752ee3792a09f5edaaac2a0402de004459dd7/ujson-5.11.0-cp39-cp39-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0654a2691fc252c3c525e3d034bb27b8a7546c9d3eb33cd29ce6c9feda361a6a", size = 57809, upload-time = "2025-08-20T11:56:36.293Z" }, - { url = "https://files.pythonhosted.org/packages/9f/36/910117b7a8a1c188396f6194ca7bc8fd75e376d8f7e3cf5eb6219fc8b09d/ujson-5.11.0-cp39-cp39-manylinux_2_24_i686.manylinux_2_28_i686.whl", hash = "sha256:6b6ec7e7321d7fc19abdda3ad809baef935f49673951a8bab486aea975007e02", size = 59797, upload-time = "2025-08-20T11:56:37.746Z" }, - { url = "https://files.pythonhosted.org/packages/c7/17/bcc85d282ee2f4cdef5f577e0a43533eedcae29cc6405edf8c62a7a50368/ujson-5.11.0-cp39-cp39-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f62b9976fabbcde3ab6e413f4ec2ff017749819a0786d84d7510171109f2d53c", size = 57378, upload-time = "2025-08-20T11:56:39.123Z" }, - { url = "https://files.pythonhosted.org/packages/ef/39/120bb76441bf835f3c3f42db9c206f31ba875711637a52a8209949ab04b0/ujson-5.11.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:7f1a27ab91083b4770e160d17f61b407f587548f2c2b5fbf19f94794c495594a", size = 1036515, upload-time = "2025-08-20T11:56:40.848Z" }, - { url = "https://files.pythonhosted.org/packages/b6/ae/fe1b4ff6388f681f6710e9494656957725b1e73ae50421ec04567df9fb75/ujson-5.11.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:ecd6ff8a3b5a90c292c2396c2d63c687fd0ecdf17de390d852524393cd9ed052", size = 1195753, upload-time = "2025-08-20T11:56:42.341Z" }, - { url = "https://files.pythonhosted.org/packages/92/20/005b93f2cf846ae50b46812fcf24bbdd127521197e5f1e1a82e3b3e730a1/ujson-5.11.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:9aacbeb23fdbc4b256a7d12e0beb9063a1ba5d9e0dbb2cfe16357c98b4334596", size = 1088844, upload-time = "2025-08-20T11:56:43.777Z" }, - { url = "https://files.pythonhosted.org/packages/41/9e/3142023c30008e2b24d7368a389b26d28d62fcd3f596d3d898a72dd09173/ujson-5.11.0-cp39-cp39-win32.whl", hash = "sha256:674f306e3e6089f92b126eb2fe41bcb65e42a15432c143365c729fdb50518547", size = 39652, upload-time = "2025-08-20T11:56:45.034Z" }, - { url = "https://files.pythonhosted.org/packages/ca/89/f4de0a3c485d0163f85f552886251876645fb62cbbe24fcdc0874b9fae03/ujson-5.11.0-cp39-cp39-win_amd64.whl", hash = "sha256:c6618f480f7c9ded05e78a1938873fde68baf96cdd74e6d23c7e0a8441175c4b", size = 43783, upload-time = "2025-08-20T11:56:46.156Z" }, - { url = "https://files.pythonhosted.org/packages/48/b1/2d50987a7b7cccb5c1fbe9ae7b184211106237b32c7039118c41d79632ea/ujson-5.11.0-cp39-cp39-win_arm64.whl", hash = "sha256:5600202a731af24a25e2d7b6eb3f648e4ecd4bb67c4d5cf12f8fab31677469c9", size = 38430, upload-time = "2025-08-20T11:56:47.653Z" }, { url = "https://files.pythonhosted.org/packages/50/17/30275aa2933430d8c0c4ead951cc4fdb922f575a349aa0b48a6f35449e97/ujson-5.11.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:abae0fb58cc820092a0e9e8ba0051ac4583958495bfa5262a12f628249e3b362", size = 51206, upload-time = "2025-08-20T11:56:48.797Z" }, { url = "https://files.pythonhosted.org/packages/c3/15/42b3924258eac2551f8f33fa4e35da20a06a53857ccf3d4deb5e5d7c0b6c/ujson-5.11.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:fac6c0649d6b7c3682a0a6e18d3de6857977378dce8d419f57a0b20e3d775b39", size = 48907, upload-time = "2025-08-20T11:56:50.136Z" }, { url = "https://files.pythonhosted.org/packages/94/7e/0519ff7955aba581d1fe1fb1ca0e452471250455d182f686db5ac9e46119/ujson-5.11.0-pp311-pypy311_pp73-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4b42c115c7c6012506e8168315150d1e3f76e7ba0f4f95616f4ee599a1372bbc", size = 50319, upload-time = "2025-08-20T11:56:51.63Z" }, @@ -7230,71 +5690,23 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/52/5b/8c5e33228f7f83f05719964db59f3f9f276d272dc43752fa3bbf0df53e7b/ujson-5.11.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:416389ec19ef5f2013592f791486bef712ebce0cd59299bf9df1ba40bb2f6e04", size = 43835, upload-time = "2025-08-20T11:56:55.237Z" }, ] -[[package]] -name = "urllib3" -version = "1.26.20" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.10'", -] -sdist = { url = "https://files.pythonhosted.org/packages/e4/e8/6ff5e6bc22095cfc59b6ea711b687e2b7ed4bdb373f7eeec370a97d7392f/urllib3-1.26.20.tar.gz", hash = "sha256:40c2dc0c681e47eb8f90e7e27bf6ff7df2e677421fd46756da1161c39ca70d32", size = 307380, upload-time = "2024-08-29T15:43:11.37Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/33/cf/8435d5a7159e2a9c83a95896ed596f68cf798005fe107cc655b5c5c14704/urllib3-1.26.20-py2.py3-none-any.whl", hash = "sha256:0ed14ccfbf1c30a9072c7ca157e4319b70d65f623e91e7b32fadb2853431016e", size = 144225, upload-time = "2024-08-29T15:43:08.921Z" }, -] - [[package]] name = "urllib3" version = "2.6.3" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.14'", - "python_full_version >= '3.10' and python_full_version < '3.14'", -] sdist = { url = "https://files.pythonhosted.org/packages/c7/24/5f1b3bdffd70275f6661c76461e25f024d5a38a46f04aaca912426a2b1d3/urllib3-2.6.3.tar.gz", hash = "sha256:1b62b6884944a57dbe321509ab94fd4d3b307075e0c2eae991ac71ee15ad38ed", size = 435556, upload-time = "2026-01-07T16:24:43.925Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl", hash = "sha256:bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4", size = 131584, upload-time = "2026-01-07T16:24:42.685Z" }, ] -[[package]] -name = "uvicorn" -version = "0.39.0" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.10'", -] -dependencies = [ - { name = "click", version = "8.1.8", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "h11", marker = "python_full_version < '3.10'" }, - { name = "typing-extensions", marker = "python_full_version < '3.10'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/ae/4f/f9fdac7cf6dd79790eb165639b5c452ceeabc7bbabbba4569155470a287d/uvicorn-0.39.0.tar.gz", hash = "sha256:610512b19baa93423d2892d7823741f6d27717b642c8964000d7194dded19302", size = 82001, upload-time = "2025-12-21T13:05:17.973Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/6b/25/db2b1c6c35bf22e17fe5412d2ee5d3fd7a20d07ebc9dac8b58f7db2e23a0/uvicorn-0.39.0-py3-none-any.whl", hash = "sha256:7beec21bd2693562b386285b188a7963b06853c0d006302b3e4cfed950c9929a", size = 68491, upload-time = "2025-12-21T13:05:16.291Z" }, -] - -[package.optional-dependencies] -standard = [ - { name = "colorama", marker = "python_full_version < '3.10' and sys_platform == 'win32'" }, - { name = "httptools", marker = "python_full_version < '3.10'" }, - { name = "python-dotenv", marker = "python_full_version < '3.10'" }, - { name = "pyyaml", marker = "python_full_version < '3.10'" }, - { name = "uvloop", marker = "python_full_version < '3.10' and platform_python_implementation != 'PyPy' and sys_platform != 'cygwin' and sys_platform != 'win32'" }, - { name = "watchfiles", marker = "python_full_version < '3.10'" }, - { name = "websockets", marker = "python_full_version < '3.10'" }, -] - [[package]] name = "uvicorn" version = "0.40.0" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.14'", - "python_full_version >= '3.10' and python_full_version < '3.14'", -] dependencies = [ - { name = "click", version = "8.3.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, - { name = "h11", marker = "python_full_version >= '3.10'" }, - { name = "typing-extensions", marker = "python_full_version == '3.10.*'" }, + { name = "click" }, + { name = "h11" }, + { name = "typing-extensions", marker = "python_full_version < '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/c3/d1/8f3c683c9561a4e6689dd3b1d345c815f10f86acd044ee1fb9a4dcd0b8c5/uvicorn-0.40.0.tar.gz", hash = "sha256:839676675e87e73694518b5574fd0f24c9d97b46bea16df7b8c05ea1a51071ea", size = 81761, upload-time = "2025-12-21T14:16:22.45Z" } wheels = [ @@ -7303,13 +5715,13 @@ wheels = [ [package.optional-dependencies] standard = [ - { name = "colorama", marker = "python_full_version >= '3.10' and sys_platform == 'win32'" }, - { name = "httptools", marker = "python_full_version >= '3.10'" }, - { name = "python-dotenv", marker = "python_full_version >= '3.10'" }, - { name = "pyyaml", marker = "python_full_version >= '3.10'" }, - { name = "uvloop", marker = "python_full_version >= '3.10' and platform_python_implementation != 'PyPy' and sys_platform != 'cygwin' and sys_platform != 'win32'" }, - { name = "watchfiles", marker = "python_full_version >= '3.10'" }, - { name = "websockets", marker = "python_full_version >= '3.10'" }, + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "httptools" }, + { name = "python-dotenv" }, + { name = "pyyaml" }, + { name = "uvloop", marker = "platform_python_implementation != 'PyPy' and sys_platform != 'cygwin' and sys_platform != 'win32'" }, + { name = "watchfiles" }, + { name = "websockets" }, ] [[package]] @@ -7354,12 +5766,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c1/37/945b4ca0ac27e3dc4952642d4c900edd030b3da6c9634875af6e13ae80e5/uvloop-0.22.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b91328c72635f6f9e0282e4a57da7470c7350ab1c9f48546c0f2866205349d21", size = 4467065, upload-time = "2025-10-16T22:16:58.206Z" }, { url = "https://files.pythonhosted.org/packages/97/cc/48d232f33d60e2e2e0b42f4e73455b146b76ebe216487e862700457fbf3c/uvloop-0.22.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:daf620c2995d193449393d6c62131b3fbd40a63bf7b307a1527856ace637fe88", size = 4328384, upload-time = "2025-10-16T22:16:59.36Z" }, { url = "https://files.pythonhosted.org/packages/e4/16/c1fd27e9549f3c4baf1dc9c20c456cd2f822dbf8de9f463824b0c0357e06/uvloop-0.22.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6cde23eeda1a25c75b2e07d39970f3374105d5eafbaab2a4482be82f272d5a5e", size = 4296730, upload-time = "2025-10-16T22:17:00.744Z" }, - { url = "https://files.pythonhosted.org/packages/bd/1b/6fbd611aeba01ef802c5876c94d7be603a9710db055beacbad39e75a31aa/uvloop-0.22.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:b45649628d816c030dba3c80f8e2689bab1c89518ed10d426036cdc47874dfc4", size = 1345858, upload-time = "2025-10-16T22:17:11.106Z" }, - { url = "https://files.pythonhosted.org/packages/9e/91/2c84f00bdbe3c51023cc83b027bac1fe959ba4a552e970da5ef0237f7945/uvloop-0.22.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ea721dd3203b809039fcc2983f14608dae82b212288b346e0bfe46ec2fab0b7c", size = 743913, upload-time = "2025-10-16T22:17:12.165Z" }, - { url = "https://files.pythonhosted.org/packages/cc/10/76aec83886d41a88aca5681db6a2c0601622d0d2cb66cd0d200587f962ad/uvloop-0.22.1-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0ae676de143db2b2f60a9696d7eca5bb9d0dd6cc3ac3dad59a8ae7e95f9e1b54", size = 3635818, upload-time = "2025-10-16T22:17:13.812Z" }, - { url = "https://files.pythonhosted.org/packages/d5/9a/733fcb815d345979fc54d3cdc3eb50bc75a47da3e4003ea7ada58e6daa65/uvloop-0.22.1-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:17d4e97258b0172dfa107b89aa1eeba3016f4b1974ce85ca3ef6a66b35cbf659", size = 3685477, upload-time = "2025-10-16T22:17:15.307Z" }, - { url = "https://files.pythonhosted.org/packages/83/fb/bee1eb11cc92bd91f76d97869bb6a816e80d59fd73721b0a3044dc703d9c/uvloop-0.22.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:05e4b5f86e621cf3927631789999e697e58f0d2d32675b67d9ca9eb0bca55743", size = 3496128, upload-time = "2025-10-16T22:17:16.558Z" }, - { url = "https://files.pythonhosted.org/packages/76/ee/3fdfeaa9776c0fd585d358c92b1dbca669720ffa476f0bbe64ed8f245bd7/uvloop-0.22.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:286322a90bea1f9422a470d5d2ad82d38080be0a29c4dd9b3e6384320a4d11e7", size = 3602565, upload-time = "2025-10-16T22:17:17.755Z" }, ] [[package]] @@ -7380,13 +5786,8 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/68/98/b0345cabdce2041a01293ba483333582891a3bd5769b08eceb0d406056ef/watchdog-6.0.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:490ab2ef84f11129844c23fb14ecf30ef3d8a6abafd3754a6f75ca1e6654136c", size = 96480, upload-time = "2024-11-01T14:06:42.952Z" }, { url = "https://files.pythonhosted.org/packages/85/83/cdf13902c626b28eedef7ec4f10745c52aad8a8fe7eb04ed7b1f111ca20e/watchdog-6.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:76aae96b00ae814b181bb25b1b98076d5fc84e8a53cd8885a318b42b6d3a5134", size = 88451, upload-time = "2024-11-01T14:06:45.084Z" }, { url = "https://files.pythonhosted.org/packages/fe/c4/225c87bae08c8b9ec99030cd48ae9c4eca050a59bf5c2255853e18c87b50/watchdog-6.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a175f755fc2279e0b7312c0035d52e27211a5bc39719dd529625b1930917345b", size = 89057, upload-time = "2024-11-01T14:06:47.324Z" }, - { url = "https://files.pythonhosted.org/packages/05/52/7223011bb760fce8ddc53416beb65b83a3ea6d7d13738dde75eeb2c89679/watchdog-6.0.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e6f0e77c9417e7cd62af82529b10563db3423625c5fce018430b249bf977f9e8", size = 96390, upload-time = "2024-11-01T14:06:49.325Z" }, - { url = "https://files.pythonhosted.org/packages/9c/62/d2b21bc4e706d3a9d467561f487c2938cbd881c69f3808c43ac1ec242391/watchdog-6.0.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:90c8e78f3b94014f7aaae121e6b909674df5b46ec24d6bebc45c44c56729af2a", size = 88386, upload-time = "2024-11-01T14:06:50.536Z" }, - { url = "https://files.pythonhosted.org/packages/ea/22/1c90b20eda9f4132e4603a26296108728a8bfe9584b006bd05dd94548853/watchdog-6.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e7631a77ffb1f7d2eefa4445ebbee491c720a5661ddf6df3498ebecae5ed375c", size = 89017, upload-time = "2024-11-01T14:06:51.717Z" }, { url = "https://files.pythonhosted.org/packages/30/ad/d17b5d42e28a8b91f8ed01cb949da092827afb9995d4559fd448d0472763/watchdog-6.0.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:c7ac31a19f4545dd92fc25d200694098f42c9a8e391bc00bdd362c5736dbf881", size = 87902, upload-time = "2024-11-01T14:06:53.119Z" }, { url = "https://files.pythonhosted.org/packages/5c/ca/c3649991d140ff6ab67bfc85ab42b165ead119c9e12211e08089d763ece5/watchdog-6.0.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:9513f27a1a582d9808cf21a07dae516f0fab1cf2d7683a742c498b93eedabb11", size = 88380, upload-time = "2024-11-01T14:06:55.19Z" }, - { url = "https://files.pythonhosted.org/packages/5b/79/69f2b0e8d3f2afd462029031baafb1b75d11bb62703f0e1022b2e54d49ee/watchdog-6.0.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7a0e56874cfbc4b9b05c60c8a1926fedf56324bb08cfbc188969777940aef3aa", size = 87903, upload-time = "2024-11-01T14:06:57.052Z" }, - { url = "https://files.pythonhosted.org/packages/e2/2b/dc048dd71c2e5f0f7ebc04dd7912981ec45793a03c0dc462438e0591ba5d/watchdog-6.0.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:e6439e374fc012255b4ec786ae3c4bc838cd7309a540e5fe0952d03687d8804e", size = 88381, upload-time = "2024-11-01T14:06:58.193Z" }, { url = "https://files.pythonhosted.org/packages/a9/c7/ca4bf3e518cb57a686b2feb4f55a1892fd9a3dd13f470fca14e00f80ea36/watchdog-6.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:7607498efa04a3542ae3e05e64da8202e58159aa1fa4acddf7678d34a35d4f13", size = 79079, upload-time = "2024-11-01T14:06:59.472Z" }, { url = "https://files.pythonhosted.org/packages/5c/51/d46dc9332f9a647593c947b4b88e2381c8dfc0942d15b8edc0310fa4abb1/watchdog-6.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:9041567ee8953024c83343288ccc458fd0a2d811d6a0fd68c4c22609e3490379", size = 79078, upload-time = "2024-11-01T14:07:01.431Z" }, { url = "https://files.pythonhosted.org/packages/d4/57/04edbf5e169cd318d5f07b4766fee38e825d64b6913ca157ca32d1a42267/watchdog-6.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:82dc3e3143c7e38ec49d61af98d6558288c415eac98486a5c581726e0737c00e", size = 79076, upload-time = "2024-11-01T14:07:02.568Z" }, @@ -7492,18 +5893,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/4f/55/2af26693fd15165c4ff7857e38330e1b61ab8c37d15dc79118cdba115b7a/watchfiles-1.1.1-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8c91ed27800188c2ae96d16e3149f199d62f86c7af5f5f4d2c61a3ed8cd3666c", size = 455072, upload-time = "2025-10-14T15:05:48.928Z" }, { url = "https://files.pythonhosted.org/packages/66/1d/d0d200b10c9311ec25d2273f8aad8c3ef7cc7ea11808022501811208a750/watchfiles-1.1.1-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:311ff15a0bae3714ffb603e6ba6dbfba4065ab60865d15a6ec544133bdb21099", size = 629104, upload-time = "2025-10-14T15:05:49.908Z" }, { url = "https://files.pythonhosted.org/packages/e3/bd/fa9bb053192491b3867ba07d2343d9f2252e00811567d30ae8d0f78136fe/watchfiles-1.1.1-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:a916a2932da8f8ab582f242c065f5c81bed3462849ca79ee357dd9551b0e9b01", size = 622112, upload-time = "2025-10-14T15:05:50.941Z" }, - { url = "https://files.pythonhosted.org/packages/a4/68/a7303a15cc797ab04d58f1fea7f67c50bd7f80090dfd7e750e7576e07582/watchfiles-1.1.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:c882d69f6903ef6092bedfb7be973d9319940d56b8427ab9187d1ecd73438a70", size = 409220, upload-time = "2025-10-14T15:05:51.917Z" }, - { url = "https://files.pythonhosted.org/packages/99/b8/d1857ce9ac76034c053fa7ef0e0ef92d8bd031e842ea6f5171725d31e88f/watchfiles-1.1.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d6ff426a7cb54f310d51bfe83fe9f2bbe40d540c741dc974ebc30e6aa238f52e", size = 396712, upload-time = "2025-10-14T15:05:53.437Z" }, - { url = "https://files.pythonhosted.org/packages/41/7a/da7ada566f48beaa6a30b13335b49d1f6febaf3a5ddbd1d92163a1002cf4/watchfiles-1.1.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:79ff6c6eadf2e3fc0d7786331362e6ef1e51125892c75f1004bd6b52155fb956", size = 451462, upload-time = "2025-10-14T15:05:54.742Z" }, - { url = "https://files.pythonhosted.org/packages/e2/b2/7cb9e0d5445a8d45c4cccd68a590d9e3a453289366b96ff37d1075aaebef/watchfiles-1.1.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c1f5210f1b8fc91ead1283c6fd89f70e76fb07283ec738056cf34d51e9c1d62c", size = 460811, upload-time = "2025-10-14T15:05:55.743Z" }, - { url = "https://files.pythonhosted.org/packages/04/9d/b07d4491dde6db6ea6c680fdec452f4be363d65c82004faf2d853f59b76f/watchfiles-1.1.1-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b9c4702f29ca48e023ffd9b7ff6b822acdf47cb1ff44cb490a3f1d5ec8987e9c", size = 490576, upload-time = "2025-10-14T15:05:56.983Z" }, - { url = "https://files.pythonhosted.org/packages/56/03/e64dcab0a1806157db272a61b7891b062f441a30580a581ae72114259472/watchfiles-1.1.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:acb08650863767cbc58bca4813b92df4d6c648459dcaa3d4155681962b2aa2d3", size = 597726, upload-time = "2025-10-14T15:05:57.986Z" }, - { url = "https://files.pythonhosted.org/packages/5c/8e/a827cf4a8d5f2903a19a934dcf512082eb07675253e154d4cd9367978a58/watchfiles-1.1.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:08af70fd77eee58549cd69c25055dc344f918d992ff626068242259f98d598a2", size = 474900, upload-time = "2025-10-14T15:05:59.378Z" }, - { url = "https://files.pythonhosted.org/packages/dc/a6/94fed0b346b85b22303a12eee5f431006fae6af70d841cac2f4403245533/watchfiles-1.1.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c3631058c37e4a0ec440bf583bc53cdbd13e5661bb6f465bc1d88ee9a0a4d02", size = 457521, upload-time = "2025-10-14T15:06:00.419Z" }, - { url = "https://files.pythonhosted.org/packages/c4/64/bc3331150e8f3c778d48a4615d4b72b3d2d87868635e6c54bbd924946189/watchfiles-1.1.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:cf57a27fb986c6243d2ee78392c503826056ffe0287e8794503b10fb51b881be", size = 632191, upload-time = "2025-10-14T15:06:01.621Z" }, - { url = "https://files.pythonhosted.org/packages/e4/84/f39e19549c2f3ec97225dcb2ceb9a7bb3c5004ed227aad1f321bf0ff2051/watchfiles-1.1.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d7e7067c98040d646982daa1f37a33d3544138ea155536c2e0e63e07ff8a7e0f", size = 623923, upload-time = "2025-10-14T15:06:02.671Z" }, - { url = "https://files.pythonhosted.org/packages/0e/24/0759ae15d9a0c9c5fe946bd4cf45ab9e7bad7cfede2c06dc10f59171b29f/watchfiles-1.1.1-cp39-cp39-win32.whl", hash = "sha256:6c9c9262f454d1c4d8aaa7050121eb4f3aea197360553699520767daebf2180b", size = 274010, upload-time = "2025-10-14T15:06:03.779Z" }, - { url = "https://files.pythonhosted.org/packages/7e/3b/eb26cddd4dfa081e2bf6918be3b2fc05ee3b55c1d21331d5562ee0c6aaad/watchfiles-1.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:74472234c8370669850e1c312490f6026d132ca2d396abfad8830b4f1c096957", size = 289090, upload-time = "2025-10-14T15:06:04.821Z" }, { url = "https://files.pythonhosted.org/packages/ba/4c/a888c91e2e326872fa4705095d64acd8aa2fb9c1f7b9bd0588f33850516c/watchfiles-1.1.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:17ef139237dfced9da49fb7f2232c86ca9421f666d78c264c7ffca6601d154c3", size = 409611, upload-time = "2025-10-14T15:06:05.809Z" }, { url = "https://files.pythonhosted.org/packages/1e/c7/5420d1943c8e3ce1a21c0a9330bcf7edafb6aa65d26b21dbb3267c9e8112/watchfiles-1.1.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:672b8adf25b1a0d35c96b5888b7b18699d27d4194bac8beeae75be4b7a3fc9b2", size = 396889, upload-time = "2025-10-14T15:06:07.035Z" }, { url = "https://files.pythonhosted.org/packages/0c/e5/0072cef3804ce8d3aaddbfe7788aadff6b3d3f98a286fdbee9fd74ca59a7/watchfiles-1.1.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77a13aea58bc2b90173bc69f2a90de8e282648939a00a602e1dc4ee23e26b66d", size = 451616, upload-time = "2025-10-14T15:06:08.072Z" }, @@ -7512,10 +5901,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/bd/95/615e72cd27b85b61eec764a5ca51bd94d40b5adea5ff47567d9ebc4d275a/watchfiles-1.1.1-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:89eef07eee5e9d1fda06e38822ad167a044153457e6fd997f8a858ab7564a336", size = 396117, upload-time = "2025-10-14T15:06:11.28Z" }, { url = "https://files.pythonhosted.org/packages/c9/81/e7fe958ce8a7fb5c73cc9fb07f5aeaf755e6aa72498c57d760af760c91f8/watchfiles-1.1.1-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ce19e06cbda693e9e7686358af9cd6f5d61312ab8b00488bc36f5aabbaf77e24", size = 450493, upload-time = "2025-10-14T15:06:12.321Z" }, { url = "https://files.pythonhosted.org/packages/6e/d4/ed38dd3b1767193de971e694aa544356e63353c33a85d948166b5ff58b9e/watchfiles-1.1.1-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3e6f39af2eab0118338902798b5aa6664f46ff66bc0280de76fca67a7f262a49", size = 457546, upload-time = "2025-10-14T15:06:13.372Z" }, - { url = "https://files.pythonhosted.org/packages/00/db/38a2c52fdbbfe2fc7ffaaaaaebc927d52b9f4d5139bba3186c19a7463001/watchfiles-1.1.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:cdab464fee731e0884c35ae3588514a9bcf718d0e2c82169c1c4a85cc19c3c7f", size = 409210, upload-time = "2025-10-14T15:06:14.492Z" }, - { url = "https://files.pythonhosted.org/packages/d1/43/d7e8b71f6c21ff813ee8da1006f89b6c7fff047fb4c8b16ceb5e840599c5/watchfiles-1.1.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:3dbd8cbadd46984f802f6d479b7e3afa86c42d13e8f0f322d669d79722c8ec34", size = 397286, upload-time = "2025-10-14T15:06:16.177Z" }, - { url = "https://files.pythonhosted.org/packages/1f/5d/884074a5269317e75bd0b915644b702b89de73e61a8a7446e2b225f45b1f/watchfiles-1.1.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5524298e3827105b61951a29c3512deb9578586abf3a7c5da4a8069df247cccc", size = 451768, upload-time = "2025-10-14T15:06:18.266Z" }, - { url = "https://files.pythonhosted.org/packages/17/71/7ffcaa9b5e8961a25026058058c62ec8f604d2a6e8e1e94bee8a09e1593f/watchfiles-1.1.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b943d3668d61cfa528eb949577479d3b077fd25fb83c641235437bc0b5bc60e", size = 458561, upload-time = "2025-10-14T15:06:19.323Z" }, ] [[package]] @@ -7586,29 +5971,12 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/33/2b/1f168cb6041853eef0362fb9554c3824367c5560cbdaad89ac40f8c2edfc/websockets-15.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:558d023b3df0bffe50a04e710bc87742de35060580a293c2a984299ed83bc4e4", size = 182195, upload-time = "2025-03-05T20:02:51.561Z" }, { url = "https://files.pythonhosted.org/packages/86/eb/20b6cdf273913d0ad05a6a14aed4b9a85591c18a987a3d47f20fa13dcc47/websockets-15.0.1-cp313-cp313-win32.whl", hash = "sha256:ba9e56e8ceeeedb2e080147ba85ffcd5cd0711b89576b83784d8605a7df455fa", size = 176393, upload-time = "2025-03-05T20:02:53.814Z" }, { url = "https://files.pythonhosted.org/packages/1b/6c/c65773d6cab416a64d191d6ee8a8b1c68a09970ea6909d16965d26bfed1e/websockets-15.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:e09473f095a819042ecb2ab9465aee615bd9c2028e4ef7d933600a8401c79561", size = 176837, upload-time = "2025-03-05T20:02:55.237Z" }, - { url = "https://files.pythonhosted.org/packages/36/db/3fff0bcbe339a6fa6a3b9e3fbc2bfb321ec2f4cd233692272c5a8d6cf801/websockets-15.0.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:5f4c04ead5aed67c8a1a20491d54cdfba5884507a48dd798ecaf13c74c4489f5", size = 175424, upload-time = "2025-03-05T20:02:56.505Z" }, - { url = "https://files.pythonhosted.org/packages/46/e6/519054c2f477def4165b0ec060ad664ed174e140b0d1cbb9fafa4a54f6db/websockets-15.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:abdc0c6c8c648b4805c5eacd131910d2a7f6455dfd3becab248ef108e89ab16a", size = 173077, upload-time = "2025-03-05T20:02:58.37Z" }, - { url = "https://files.pythonhosted.org/packages/1a/21/c0712e382df64c93a0d16449ecbf87b647163485ca1cc3f6cbadb36d2b03/websockets-15.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a625e06551975f4b7ea7102bc43895b90742746797e2e14b70ed61c43a90f09b", size = 173324, upload-time = "2025-03-05T20:02:59.773Z" }, - { url = "https://files.pythonhosted.org/packages/1c/cb/51ba82e59b3a664df54beed8ad95517c1b4dc1a913730e7a7db778f21291/websockets-15.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d591f8de75824cbb7acad4e05d2d710484f15f29d4a915092675ad3456f11770", size = 182094, upload-time = "2025-03-05T20:03:01.827Z" }, - { url = "https://files.pythonhosted.org/packages/fb/0f/bf3788c03fec679bcdaef787518dbe60d12fe5615a544a6d4cf82f045193/websockets-15.0.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:47819cea040f31d670cc8d324bb6435c6f133b8c7a19ec3d61634e62f8d8f9eb", size = 181094, upload-time = "2025-03-05T20:03:03.123Z" }, - { url = "https://files.pythonhosted.org/packages/5e/da/9fb8c21edbc719b66763a571afbaf206cb6d3736d28255a46fc2fe20f902/websockets-15.0.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac017dd64572e5c3bd01939121e4d16cf30e5d7e110a119399cf3133b63ad054", size = 181397, upload-time = "2025-03-05T20:03:04.443Z" }, - { url = "https://files.pythonhosted.org/packages/2e/65/65f379525a2719e91d9d90c38fe8b8bc62bd3c702ac651b7278609b696c4/websockets-15.0.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:4a9fac8e469d04ce6c25bb2610dc535235bd4aa14996b4e6dbebf5e007eba5ee", size = 181794, upload-time = "2025-03-05T20:03:06.708Z" }, - { url = "https://files.pythonhosted.org/packages/d9/26/31ac2d08f8e9304d81a1a7ed2851c0300f636019a57cbaa91342015c72cc/websockets-15.0.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:363c6f671b761efcb30608d24925a382497c12c506b51661883c3e22337265ed", size = 181194, upload-time = "2025-03-05T20:03:08.844Z" }, - { url = "https://files.pythonhosted.org/packages/98/72/1090de20d6c91994cd4b357c3f75a4f25ee231b63e03adea89671cc12a3f/websockets-15.0.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:2034693ad3097d5355bfdacfffcbd3ef5694f9718ab7f29c29689a9eae841880", size = 181164, upload-time = "2025-03-05T20:03:10.242Z" }, - { url = "https://files.pythonhosted.org/packages/2d/37/098f2e1c103ae8ed79b0e77f08d83b0ec0b241cf4b7f2f10edd0126472e1/websockets-15.0.1-cp39-cp39-win32.whl", hash = "sha256:3b1ac0d3e594bf121308112697cf4b32be538fb1444468fb0a6ae4feebc83411", size = 176381, upload-time = "2025-03-05T20:03:12.77Z" }, - { url = "https://files.pythonhosted.org/packages/75/8b/a32978a3ab42cebb2ebdd5b05df0696a09f4d436ce69def11893afa301f0/websockets-15.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:b7643a03db5c95c799b89b31c036d5f27eeb4d259c798e878d6937d71832b1e4", size = 176841, upload-time = "2025-03-05T20:03:14.367Z" }, { url = "https://files.pythonhosted.org/packages/02/9e/d40f779fa16f74d3468357197af8d6ad07e7c5a27ea1ca74ceb38986f77a/websockets-15.0.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:0c9e74d766f2818bb95f84c25be4dea09841ac0f734d1966f415e4edfc4ef1c3", size = 173109, upload-time = "2025-03-05T20:03:17.769Z" }, { url = "https://files.pythonhosted.org/packages/bc/cd/5b887b8585a593073fd92f7c23ecd3985cd2c3175025a91b0d69b0551372/websockets-15.0.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:1009ee0c7739c08a0cd59de430d6de452a55e42d6b522de7aa15e6f67db0b8e1", size = 173343, upload-time = "2025-03-05T20:03:19.094Z" }, { url = "https://files.pythonhosted.org/packages/fe/ae/d34f7556890341e900a95acf4886833646306269f899d58ad62f588bf410/websockets-15.0.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76d1f20b1c7a2fa82367e04982e708723ba0e7b8d43aa643d3dcd404d74f1475", size = 174599, upload-time = "2025-03-05T20:03:21.1Z" }, { url = "https://files.pythonhosted.org/packages/71/e6/5fd43993a87db364ec60fc1d608273a1a465c0caba69176dd160e197ce42/websockets-15.0.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f29d80eb9a9263b8d109135351caf568cc3f80b9928bccde535c235de55c22d9", size = 174207, upload-time = "2025-03-05T20:03:23.221Z" }, { url = "https://files.pythonhosted.org/packages/2b/fb/c492d6daa5ec067c2988ac80c61359ace5c4c674c532985ac5a123436cec/websockets-15.0.1-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b359ed09954d7c18bbc1680f380c7301f92c60bf924171629c5db97febb12f04", size = 174155, upload-time = "2025-03-05T20:03:25.321Z" }, { url = "https://files.pythonhosted.org/packages/68/a1/dcb68430b1d00b698ae7a7e0194433bce4f07ded185f0ee5fb21e2a2e91e/websockets-15.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:cad21560da69f4ce7658ca2cb83138fb4cf695a2ba3e475e0559e05991aa8122", size = 176884, upload-time = "2025-03-05T20:03:27.934Z" }, - { url = "https://files.pythonhosted.org/packages/b7/48/4b67623bac4d79beb3a6bb27b803ba75c1bdedc06bd827e465803690a4b2/websockets-15.0.1-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7f493881579c90fc262d9cdbaa05a6b54b3811c2f300766748db79f098db9940", size = 173106, upload-time = "2025-03-05T20:03:29.404Z" }, - { url = "https://files.pythonhosted.org/packages/ed/f0/adb07514a49fe5728192764e04295be78859e4a537ab8fcc518a3dbb3281/websockets-15.0.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:47b099e1f4fbc95b701b6e85768e1fcdaf1630f3cbe4765fa216596f12310e2e", size = 173339, upload-time = "2025-03-05T20:03:30.755Z" }, - { url = "https://files.pythonhosted.org/packages/87/28/bd23c6344b18fb43df40d0700f6d3fffcd7cef14a6995b4f976978b52e62/websockets-15.0.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:67f2b6de947f8c757db2db9c71527933ad0019737ec374a8a6be9a956786aaf9", size = 174597, upload-time = "2025-03-05T20:03:32.247Z" }, - { url = "https://files.pythonhosted.org/packages/6d/79/ca288495863d0f23a60f546f0905ae8f3ed467ad87f8b6aceb65f4c013e4/websockets-15.0.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d08eb4c2b7d6c41da6ca0600c077e93f5adcfd979cd777d747e9ee624556da4b", size = 174205, upload-time = "2025-03-05T20:03:33.731Z" }, - { url = "https://files.pythonhosted.org/packages/04/e4/120ff3180b0872b1fe6637f6f995bcb009fb5c87d597c1fc21456f50c848/websockets-15.0.1-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b826973a4a2ae47ba357e4e82fa44a463b8f168e1ca775ac64521442b19e87f", size = 174150, upload-time = "2025-03-05T20:03:35.757Z" }, - { url = "https://files.pythonhosted.org/packages/cb/c3/30e2f9c539b8da8b1d76f64012f3b19253271a63413b2d3adb94b143407f/websockets-15.0.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:21c1fa28a6a7e3cbdc171c694398b6df4744613ce9b36b1a498e816787e28123", size = 176877, upload-time = "2025-03-05T20:03:37.199Z" }, { url = "https://files.pythonhosted.org/packages/fa/a8/5b41e0da817d64113292ab1f8247140aac61cbf6cfd085d6a0fa77f4984f/websockets-15.0.1-py3-none-any.whl", hash = "sha256:f7a866fbc1e97b5c617ee4116daaa09b722101d4a3c170c787450ba409f9736f", size = 169743, upload-time = "2025-03-05T20:03:39.41Z" }, ] @@ -7690,16 +6058,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/be/44/a1bd64b723d13bb151d6cc91b986146a1952385e0392a78567e12149c7b4/wrapt-1.17.3-cp314-cp314t-win32.whl", hash = "sha256:41b1d2bc74c2cac6f9074df52b2efbef2b30bdfe5f40cb78f8ca22963bc62977", size = 38717, upload-time = "2025-08-12T05:53:15.214Z" }, { url = "https://files.pythonhosted.org/packages/79/d9/7cfd5a312760ac4dd8bf0184a6ee9e43c33e47f3dadc303032ce012b8fa3/wrapt-1.17.3-cp314-cp314t-win_amd64.whl", hash = "sha256:73d496de46cd2cdbdbcce4ae4bcdb4afb6a11234a1df9c085249d55166b95116", size = 41334, upload-time = "2025-08-12T05:53:14.178Z" }, { url = "https://files.pythonhosted.org/packages/46/78/10ad9781128ed2f99dbc474f43283b13fea8ba58723e98844367531c18e9/wrapt-1.17.3-cp314-cp314t-win_arm64.whl", hash = "sha256:f38e60678850c42461d4202739f9bf1e3a737c7ad283638251e79cc49effb6b6", size = 38471, upload-time = "2025-08-12T05:52:57.784Z" }, - { url = "https://files.pythonhosted.org/packages/41/be/be9b3b0a461ee3e30278706f3f3759b9b69afeedef7fe686036286c04ac6/wrapt-1.17.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:30ce38e66630599e1193798285706903110d4f057aab3168a34b7fdc85569afc", size = 53485, upload-time = "2025-08-12T05:51:53.11Z" }, - { url = "https://files.pythonhosted.org/packages/b3/a8/8f61d6b8f526efc8c10e12bf80b4206099fea78ade70427846a37bc9cbea/wrapt-1.17.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:65d1d00fbfb3ea5f20add88bbc0f815150dbbde3b026e6c24759466c8b5a9ef9", size = 38675, upload-time = "2025-08-12T05:51:42.885Z" }, - { url = "https://files.pythonhosted.org/packages/48/f1/23950c29a25637b74b322f9e425a17cc01a478f6afb35138ecb697f9558d/wrapt-1.17.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a7c06742645f914f26c7f1fa47b8bc4c91d222f76ee20116c43d5ef0912bba2d", size = 38956, upload-time = "2025-08-12T05:52:03.149Z" }, - { url = "https://files.pythonhosted.org/packages/43/46/dd0791943613885f62619f18ee6107e6133237a6b6ed8a9ecfac339d0b4f/wrapt-1.17.3-cp39-cp39-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:7e18f01b0c3e4a07fe6dfdb00e29049ba17eadbc5e7609a2a3a4af83ab7d710a", size = 81745, upload-time = "2025-08-12T05:52:49.62Z" }, - { url = "https://files.pythonhosted.org/packages/dd/ec/bb2d19bd1a614cc4f438abac13ae26c57186197920432d2a915183b15a8b/wrapt-1.17.3-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0f5f51a6466667a5a356e6381d362d259125b57f059103dd9fdc8c0cf1d14139", size = 82833, upload-time = "2025-08-12T05:52:27.738Z" }, - { url = "https://files.pythonhosted.org/packages/8d/eb/66579aea6ad36f07617fedca8e282e49c7c9bab64c63b446cfe4f7f47a49/wrapt-1.17.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:59923aa12d0157f6b82d686c3fd8e1166fa8cdfb3e17b42ce3b6147ff81528df", size = 81889, upload-time = "2025-08-12T05:52:29.023Z" }, - { url = "https://files.pythonhosted.org/packages/04/9c/a56b5ac0e2473bdc3fb11b22dd69ff423154d63861cf77911cdde5e38fd2/wrapt-1.17.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:46acc57b331e0b3bcb3e1ca3b421d65637915cfcd65eb783cb2f78a511193f9b", size = 81344, upload-time = "2025-08-12T05:52:50.869Z" }, - { url = "https://files.pythonhosted.org/packages/93/4c/9bd735c42641d81cb58d7bfb142c58f95c833962d15113026705add41a07/wrapt-1.17.3-cp39-cp39-win32.whl", hash = "sha256:3e62d15d3cfa26e3d0788094de7b64efa75f3a53875cdbccdf78547aed547a81", size = 36462, upload-time = "2025-08-12T05:53:19.623Z" }, - { url = "https://files.pythonhosted.org/packages/f0/ea/0b72f29cb5ebc16eb55c57dc0c98e5de76fc97f435fd407f7d409459c0a6/wrapt-1.17.3-cp39-cp39-win_amd64.whl", hash = "sha256:1f23fa283f51c890eda8e34e4937079114c74b4c81d2b2f1f1d94948f5cc3d7f", size = 38740, upload-time = "2025-08-12T05:53:18.271Z" }, - { url = "https://files.pythonhosted.org/packages/c3/8b/9eae65fb92321e38dbfec7719b87d840a4b92fde83fd1bbf238c5488d055/wrapt-1.17.3-cp39-cp39-win_arm64.whl", hash = "sha256:24c2ed34dc222ed754247a2702b1e1e89fdbaa4016f324b4b8f1a802d4ffe87f", size = 36806, upload-time = "2025-08-12T05:52:58.765Z" }, { url = "https://files.pythonhosted.org/packages/1f/f6/a933bd70f98e9cf3e08167fc5cd7aaaca49147e48411c0bd5ae701bb2194/wrapt-1.17.3-py3-none-any.whl", hash = "sha256:7171ae35d2c33d326ac19dd8facb1e82e5fd04ef8c6c0e394d7af55a55051c22", size = 23591, upload-time = "2025-08-12T05:53:20.674Z" }, ] @@ -7708,14 +6066,14 @@ name = "xai-sdk" version = "1.6.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "aiohttp", marker = "python_full_version >= '3.10'" }, - { name = "googleapis-common-protos", marker = "python_full_version >= '3.10'" }, - { name = "grpcio", marker = "python_full_version >= '3.10'" }, - { name = "opentelemetry-sdk", marker = "python_full_version >= '3.10'" }, - { name = "packaging", marker = "python_full_version >= '3.10'" }, - { name = "protobuf", version = "6.33.5", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, - { name = "pydantic", marker = "python_full_version >= '3.10'" }, - { name = "requests", marker = "python_full_version >= '3.10'" }, + { name = "aiohttp" }, + { name = "googleapis-common-protos" }, + { name = "grpcio" }, + { name = "opentelemetry-sdk" }, + { name = "packaging" }, + { name = "protobuf" }, + { name = "pydantic" }, + { name = "requests" }, ] sdist = { url = "https://files.pythonhosted.org/packages/9e/66/1e0163eac090733d0ed0836a0cd3c14f5b59abeaa6fdba71c7b56b1916e4/xai_sdk-1.6.1.tar.gz", hash = "sha256:b55528df188f8c8448484021d735f75b0e7d71719ddeb432c5f187ac67e3c983", size = 388223, upload-time = "2026-01-29T03:13:07.373Z" } wheels = [ @@ -7845,22 +6203,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/35/18/55e6011f7c044dc80b98893060773cefcfdbf60dfefb8cb2f58b9bacbd83/yarl-1.22.0-cp314-cp314t-win32.whl", hash = "sha256:8009b3173bcd637be650922ac455946197d858b3630b6d8787aa9e5c4564533e", size = 89056, upload-time = "2025-10-06T14:12:13.317Z" }, { url = "https://files.pythonhosted.org/packages/f9/86/0f0dccb6e59a9e7f122c5afd43568b1d31b8ab7dda5f1b01fb5c7025c9a9/yarl-1.22.0-cp314-cp314t-win_amd64.whl", hash = "sha256:9fb17ea16e972c63d25d4a97f016d235c78dd2344820eb35bc034bc32012ee27", size = 96292, upload-time = "2025-10-06T14:12:15.398Z" }, { url = "https://files.pythonhosted.org/packages/48/b7/503c98092fb3b344a179579f55814b613c1fbb1c23b3ec14a7b008a66a6e/yarl-1.22.0-cp314-cp314t-win_arm64.whl", hash = "sha256:9f6d73c1436b934e3f01df1e1b21ff765cd1d28c77dfb9ace207f746d4610ee1", size = 85171, upload-time = "2025-10-06T14:12:16.935Z" }, - { url = "https://files.pythonhosted.org/packages/94/fd/6480106702a79bcceda5fd9c63cb19a04a6506bd5ce7fd8d9b63742f0021/yarl-1.22.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:3aa27acb6de7a23785d81557577491f6c38a5209a254d1191519d07d8fe51748", size = 141301, upload-time = "2025-10-06T14:12:19.01Z" }, - { url = "https://files.pythonhosted.org/packages/42/e1/6d95d21b17a93e793e4ec420a925fe1f6a9342338ca7a563ed21129c0990/yarl-1.22.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:af74f05666a5e531289cb1cc9c883d1de2088b8e5b4de48004e5ca8a830ac859", size = 93864, upload-time = "2025-10-06T14:12:21.05Z" }, - { url = "https://files.pythonhosted.org/packages/32/58/b8055273c203968e89808413ea4c984988b6649baabf10f4522e67c22d2f/yarl-1.22.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:62441e55958977b8167b2709c164c91a6363e25da322d87ae6dd9c6019ceecf9", size = 94706, upload-time = "2025-10-06T14:12:23.287Z" }, - { url = "https://files.pythonhosted.org/packages/18/91/d7bfbc28a88c2895ecd0da6a874def0c147de78afc52c773c28e1aa233a3/yarl-1.22.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b580e71cac3f8113d3135888770903eaf2f507e9421e5697d6ee6d8cd1c7f054", size = 347100, upload-time = "2025-10-06T14:12:28.527Z" }, - { url = "https://files.pythonhosted.org/packages/bd/e8/37a1e7b99721c0564b1fc7b0a4d1f595ef6fb8060d82ca61775b644185f7/yarl-1.22.0-cp39-cp39-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e81fda2fb4a07eda1a2252b216aa0df23ebcd4d584894e9612e80999a78fd95b", size = 318902, upload-time = "2025-10-06T14:12:30.528Z" }, - { url = "https://files.pythonhosted.org/packages/1c/ef/34724449d7ef2db4f22df644f2dac0b8a275d20f585e526937b3ae47b02d/yarl-1.22.0-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:99b6fc1d55782461b78221e95fc357b47ad98b041e8e20f47c1411d0aacddc60", size = 363302, upload-time = "2025-10-06T14:12:32.295Z" }, - { url = "https://files.pythonhosted.org/packages/8a/04/88a39a5dad39889f192cce8d66cc4c58dbeca983e83f9b6bf23822a7ed91/yarl-1.22.0-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:088e4e08f033db4be2ccd1f34cf29fe994772fb54cfe004bbf54db320af56890", size = 370816, upload-time = "2025-10-06T14:12:34.01Z" }, - { url = "https://files.pythonhosted.org/packages/6b/1f/5e895e547129413f56c76be2c3ce4b96c797d2d0ff3e16a817d9269b12e6/yarl-1.22.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2e4e1f6f0b4da23e61188676e3ed027ef0baa833a2e633c29ff8530800edccba", size = 346465, upload-time = "2025-10-06T14:12:35.977Z" }, - { url = "https://files.pythonhosted.org/packages/11/13/a750e9fd6f9cc9ed3a52a70fe58ffe505322f0efe0d48e1fd9ffe53281f5/yarl-1.22.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:84fc3ec96fce86ce5aa305eb4aa9358279d1aa644b71fab7b8ed33fe3ba1a7ca", size = 341506, upload-time = "2025-10-06T14:12:37.788Z" }, - { url = "https://files.pythonhosted.org/packages/3c/67/bb6024de76e7186611ebe626aec5b71a2d2ecf9453e795f2dbd80614784c/yarl-1.22.0-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:5dbeefd6ca588b33576a01b0ad58aa934bc1b41ef89dee505bf2932b22ddffba", size = 335030, upload-time = "2025-10-06T14:12:39.775Z" }, - { url = "https://files.pythonhosted.org/packages/a2/be/50b38447fd94a7992996a62b8b463d0579323fcfc08c61bdba949eef8a5d/yarl-1.22.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:14291620375b1060613f4aab9ebf21850058b6b1b438f386cc814813d901c60b", size = 358560, upload-time = "2025-10-06T14:12:41.547Z" }, - { url = "https://files.pythonhosted.org/packages/e2/89/c020b6f547578c4e3dbb6335bf918f26e2f34ad0d1e515d72fd33ac0c635/yarl-1.22.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:a4fcfc8eb2c34148c118dfa02e6427ca278bfd0f3df7c5f99e33d2c0e81eae3e", size = 357290, upload-time = "2025-10-06T14:12:43.861Z" }, - { url = "https://files.pythonhosted.org/packages/8c/52/c49a619ee35a402fa3a7019a4fa8d26878fec0d1243f6968bbf516789578/yarl-1.22.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:029866bde8d7b0878b9c160e72305bbf0a7342bcd20b9999381704ae03308dc8", size = 350700, upload-time = "2025-10-06T14:12:46.868Z" }, - { url = "https://files.pythonhosted.org/packages/ab/c9/f5042d87777bf6968435f04a2bbb15466b2f142e6e47fa4f34d1a3f32f0c/yarl-1.22.0-cp39-cp39-win32.whl", hash = "sha256:4dcc74149ccc8bba31ce1944acee24813e93cfdee2acda3c172df844948ddf7b", size = 82323, upload-time = "2025-10-06T14:12:48.633Z" }, - { url = "https://files.pythonhosted.org/packages/fd/58/d00f7cad9eba20c4eefac2682f34661d1d1b3a942fc0092eb60e78cfb733/yarl-1.22.0-cp39-cp39-win_amd64.whl", hash = "sha256:10619d9fdee46d20edc49d3479e2f8269d0779f1b031e6f7c2aa1c76be04b7ed", size = 87145, upload-time = "2025-10-06T14:12:50.241Z" }, - { url = "https://files.pythonhosted.org/packages/c2/a3/70904f365080780d38b919edd42d224b8c4ce224a86950d2eaa2a24366ad/yarl-1.22.0-cp39-cp39-win_arm64.whl", hash = "sha256:dd7afd3f8b0bfb4e0d9fc3c31bfe8a4ec7debe124cfd90619305def3c8ca8cd2", size = 82173, upload-time = "2025-10-06T14:12:51.869Z" }, { url = "https://files.pythonhosted.org/packages/73/ae/b48f95715333080afb75a4504487cbe142cae1268afc482d06692d605ae6/yarl-1.22.0-py3-none-any.whl", hash = "sha256:1380560bdba02b6b6c90de54133c81c9f2a453dee9912fe58c1dcced1edb7cff", size = 46814, upload-time = "2025-10-06T14:12:53.872Z" }, ] From cc903bd440a4a443510c7b10ef7e9a1f88f44e0e Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 11 Feb 2026 18:32:39 +0000 Subject: [PATCH 07/20] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [skip ci] --- docs/en/docs/release-notes.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index be11b7827..e0ca3de72 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -7,6 +7,10 @@ hide: ## Latest Changes +### Breaking Changes + +* ➖ Drop support for Python 3.9. PR [#14897](https://github.com/fastapi/fastapi/pull/14897) by [@tiangolo](https://github.com/tiangolo). + ## 0.128.8 ### Docs From 3da206c06df1283518a54b18f27bed33f2d22612 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Wed, 11 Feb 2026 10:41:21 -0800 Subject: [PATCH 08/20] =?UTF-8?q?=F0=9F=8E=A8=20Update=20internal=20types?= =?UTF-8?q?=20for=20Python=203.10=20(#14898)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- fastapi/_compat/v2.py | 26 +- fastapi/applications.py | 354 +++++++++---------- fastapi/background.py | 3 +- fastapi/datastructures.py | 10 +- fastapi/dependencies/models.py | 32 +- fastapi/encoders.py | 13 +- fastapi/exceptions.py | 14 +- fastapi/openapi/docs.py | 8 +- fastapi/openapi/models.py | 326 ++++++++--------- fastapi/openapi/utils.py | 31 +- fastapi/param_functions.py | 380 ++++++++++---------- fastapi/params.py | 446 ++++++++++++------------ fastapi/routing.py | 412 +++++++++++----------- fastapi/security/api_key.py | 26 +- fastapi/security/http.py | 36 +- fastapi/security/oauth2.py | 42 +-- fastapi/security/open_id_connect_url.py | 8 +- fastapi/security/utils.py | 5 +- fastapi/types.py | 7 +- fastapi/utils.py | 18 +- 20 files changed, 1087 insertions(+), 1110 deletions(-) diff --git a/fastapi/_compat/v2.py b/fastapi/_compat/v2.py index 87b9fb47f..b83bc1b55 100644 --- a/fastapi/_compat/v2.py +++ b/fastapi/_compat/v2.py @@ -8,8 +8,11 @@ from functools import lru_cache from typing import ( Annotated, Any, + Literal, Union, cast, + get_args, + get_origin, ) from fastapi._compat import lenient_issubclass, shared @@ -32,7 +35,6 @@ from pydantic_core import Url as Url from pydantic_core.core_schema import ( with_info_plain_validator_function as with_info_plain_validator_function, ) -from typing_extensions import Literal, get_args, get_origin RequiredParam = PydanticUndefined Undefined = PydanticUndefined @@ -83,7 +85,7 @@ class ModelField: field_info: FieldInfo name: str mode: Literal["validation", "serialization"] = "validation" - config: Union[ConfigDict, None] = None + config: ConfigDict | None = None @property def alias(self) -> str: @@ -91,14 +93,14 @@ class ModelField: return a if a is not None else self.name @property - def validation_alias(self) -> Union[str, None]: + def validation_alias(self) -> str | None: va = self.field_info.validation_alias if isinstance(va, str) and va: return va return None @property - def serialization_alias(self) -> Union[str, None]: + def serialization_alias(self) -> str | None: sa = self.field_info.serialization_alias return sa or None @@ -143,7 +145,7 @@ class ModelField: value: Any, values: dict[str, Any] = {}, # noqa: B006 *, - loc: tuple[Union[int, str], ...] = (), + loc: tuple[int | str, ...] = (), ) -> tuple[Any, list[dict[str, Any]]]: try: return ( @@ -160,8 +162,8 @@ class ModelField: value: Any, *, mode: Literal["json", "python"] = "json", - include: Union[IncEx, None] = None, - exclude: Union[IncEx, None] = None, + include: IncEx | None = None, + exclude: IncEx | None = None, by_alias: bool = True, exclude_unset: bool = False, exclude_defaults: bool = False, @@ -202,7 +204,7 @@ def get_schema_from_model_field( ], separate_input_output_schemas: bool = True, ) -> dict[str, Any]: - override_mode: Union[Literal["validation"], None] = ( + override_mode: Literal["validation"] | None = ( None if (separate_input_output_schemas or _has_computed_fields(field)) else "validation" @@ -318,7 +320,7 @@ def serialize_sequence_value(*, field: ModelField, value: Any) -> Sequence[Any]: return shared.sequence_annotation_to_type[origin_type](value) # type: ignore[no-any-return,index] -def get_missing_field_error(loc: tuple[Union[int, str], ...]) -> dict[str, Any]: +def get_missing_field_error(loc: tuple[int | str, ...]) -> dict[str, Any]: error = ValidationError.from_exception_data( "Field required", [{"type": "missing", "loc": loc, "input": {}}] ).errors(include_url=False)[0] @@ -360,7 +362,7 @@ def get_cached_model_fields(model: type[BaseModel]) -> list[ModelField]: # Duplicate of several schema functions from Pydantic v1 to make them compatible with # Pydantic v2 and allow mixing the models -TypeModelOrEnum = Union[type["BaseModel"], type[Enum]] +TypeModelOrEnum = type["BaseModel"] | type[Enum] TypeModelSet = set[TypeModelOrEnum] @@ -377,7 +379,7 @@ def get_model_name_map(unique_models: TypeModelSet) -> dict[TypeModelOrEnum, str def get_flat_models_from_model( - model: type["BaseModel"], known_models: Union[TypeModelSet, None] = None + model: type["BaseModel"], known_models: TypeModelSet | None = None ) -> TypeModelSet: known_models = known_models or set() fields = get_model_fields(model) @@ -426,7 +428,7 @@ def get_flat_models_from_fields( def _regenerate_error_with_loc( - *, errors: Sequence[Any], loc_prefix: tuple[Union[str, int], ...] + *, errors: Sequence[Any], loc_prefix: tuple[str | int, ...] ) -> list[dict[str, Any]]: updated_loc_errors: list[Any] = [ {**err, "loc": loc_prefix + err.get("loc", ())} for err in errors diff --git a/fastapi/applications.py b/fastapi/applications.py index 340cabfc2..41d86143e 100644 --- a/fastapi/applications.py +++ b/fastapi/applications.py @@ -1,12 +1,9 @@ -from collections.abc import Awaitable, Coroutine, Sequence +from collections.abc import Awaitable, Callable, Coroutine, Sequence from enum import Enum from typing import ( Annotated, Any, - Callable, - Optional, TypeVar, - Union, ) from annotated_doc import Doc @@ -77,7 +74,7 @@ class FastAPI(Starlette): ), ] = False, routes: Annotated[ - Optional[list[BaseRoute]], + list[BaseRoute] | None, Doc( """ **Note**: you probably shouldn't use this parameter, it is inherited @@ -120,7 +117,7 @@ class FastAPI(Starlette): ), ] = "FastAPI", summary: Annotated[ - Optional[str], + str | None, Doc( """ A short summary of the API. @@ -203,7 +200,7 @@ class FastAPI(Starlette): ), ] = "0.1.0", openapi_url: Annotated[ - Optional[str], + str | None, Doc( """ The URL where the OpenAPI schema will be served from. @@ -226,7 +223,7 @@ class FastAPI(Starlette): ), ] = "/openapi.json", openapi_tags: Annotated[ - Optional[list[dict[str, Any]]], + list[dict[str, Any]] | None, Doc( """ A list of tags used by OpenAPI, these are the same `tags` you can set @@ -286,7 +283,7 @@ class FastAPI(Starlette): ), ] = None, servers: Annotated[ - Optional[list[dict[str, Union[str, Any]]]], + list[dict[str, str | Any]] | None, Doc( """ A `list` of `dict`s with connectivity information to a target server. @@ -335,7 +332,7 @@ class FastAPI(Starlette): ), ] = None, dependencies: Annotated[ - Optional[Sequence[Depends]], + Sequence[Depends] | None, Doc( """ A list of global dependencies, they will be applied to each @@ -402,7 +399,7 @@ class FastAPI(Starlette): ), ] = True, docs_url: Annotated[ - Optional[str], + str | None, Doc( """ The path to the automatic interactive API documentation. @@ -426,7 +423,7 @@ class FastAPI(Starlette): ), ] = "/docs", redoc_url: Annotated[ - Optional[str], + str | None, Doc( """ The path to the alternative automatic interactive API documentation @@ -450,7 +447,7 @@ class FastAPI(Starlette): ), ] = "/redoc", swagger_ui_oauth2_redirect_url: Annotated[ - Optional[str], + str | None, Doc( """ The OAuth2 redirect endpoint for the Swagger UI. @@ -463,7 +460,7 @@ class FastAPI(Starlette): ), ] = "/docs/oauth2-redirect", swagger_ui_init_oauth: Annotated[ - Optional[dict[str, Any]], + dict[str, Any] | None, Doc( """ OAuth2 configuration for the Swagger UI, by default shown at `/docs`. @@ -474,7 +471,7 @@ class FastAPI(Starlette): ), ] = None, middleware: Annotated[ - Optional[Sequence[Middleware]], + Sequence[Middleware] | None, Doc( """ List of middleware to be added when creating the application. @@ -488,12 +485,11 @@ class FastAPI(Starlette): ), ] = None, exception_handlers: Annotated[ - Optional[ - dict[ - Union[int, type[Exception]], - Callable[[Request, Any], Coroutine[Any, Any, Response]], - ] - ], + dict[ + int | type[Exception], + Callable[[Request, Any], Coroutine[Any, Any, Response]], + ] + | None, Doc( """ A dictionary with handlers for exceptions. @@ -507,7 +503,7 @@ class FastAPI(Starlette): ), ] = None, on_startup: Annotated[ - Optional[Sequence[Callable[[], Any]]], + Sequence[Callable[[], Any]] | None, Doc( """ A list of startup event handler functions. @@ -519,7 +515,7 @@ class FastAPI(Starlette): ), ] = None, on_shutdown: Annotated[ - Optional[Sequence[Callable[[], Any]]], + Sequence[Callable[[], Any]] | None, Doc( """ A list of shutdown event handler functions. @@ -532,7 +528,7 @@ class FastAPI(Starlette): ), ] = None, lifespan: Annotated[ - Optional[Lifespan[AppType]], + Lifespan[AppType] | None, Doc( """ A `Lifespan` context manager handler. This replaces `startup` and @@ -544,7 +540,7 @@ class FastAPI(Starlette): ), ] = None, terms_of_service: Annotated[ - Optional[str], + str | None, Doc( """ A URL to the Terms of Service for your API. @@ -563,7 +559,7 @@ class FastAPI(Starlette): ), ] = None, contact: Annotated[ - Optional[dict[str, Union[str, Any]]], + dict[str, str | Any] | None, Doc( """ A dictionary with the contact information for the exposed API. @@ -596,7 +592,7 @@ class FastAPI(Starlette): ), ] = None, license_info: Annotated[ - Optional[dict[str, Union[str, Any]]], + dict[str, str | Any] | None, Doc( """ A dictionary with the license information for the exposed API. @@ -685,7 +681,7 @@ class FastAPI(Starlette): ), ] = True, responses: Annotated[ - Optional[dict[Union[int, str], dict[str, Any]]], + dict[int | str, dict[str, Any]] | None, Doc( """ Additional responses to be shown in OpenAPI. @@ -701,7 +697,7 @@ class FastAPI(Starlette): ), ] = None, callbacks: Annotated[ - Optional[list[BaseRoute]], + list[BaseRoute] | None, Doc( """ OpenAPI callbacks that should apply to all *path operations*. @@ -714,7 +710,7 @@ class FastAPI(Starlette): ), ] = None, webhooks: Annotated[ - Optional[routing.APIRouter], + routing.APIRouter | None, Doc( """ Add OpenAPI webhooks. This is similar to `callbacks` but it doesn't @@ -730,7 +726,7 @@ class FastAPI(Starlette): ), ] = None, deprecated: Annotated[ - Optional[bool], + bool | None, Doc( """ Mark all *path operations* as deprecated. You probably don't need it, @@ -758,7 +754,7 @@ class FastAPI(Starlette): ), ] = True, swagger_ui_parameters: Annotated[ - Optional[dict[str, Any]], + dict[str, Any] | None, Doc( """ Parameters to configure Swagger UI, the autogenerated interactive API @@ -819,7 +815,7 @@ class FastAPI(Starlette): ), ] = True, openapi_external_docs: Annotated[ - Optional[dict[str, Any]], + dict[str, Any] | None, Doc( """ This field allows you to provide additional external documentation links. @@ -905,7 +901,7 @@ class FastAPI(Starlette): """ ), ] = "3.1.0" - self.openapi_schema: Optional[dict[str, Any]] = None + self.openapi_schema: dict[str, Any] | None = None if self.openapi_url: assert self.title, "A title must be provided for OpenAPI, e.g.: 'My API'" assert self.version, "A version must be provided for OpenAPI, e.g.: '2.1.0'" @@ -980,7 +976,7 @@ class FastAPI(Starlette): generate_unique_id_function=generate_unique_id_function, ) self.exception_handlers: dict[ - Any, Callable[[Request, Any], Union[Response, Awaitable[Response]]] + Any, Callable[[Request, Any], Response | Awaitable[Response]] ] = {} if exception_handlers is None else dict(exception_handlers) self.exception_handlers.setdefault(HTTPException, http_exception_handler) self.exception_handlers.setdefault( @@ -995,7 +991,7 @@ class FastAPI(Starlette): self.user_middleware: list[Middleware] = ( [] if middleware is None else list(middleware) ) - self.middleware_stack: Union[ASGIApp, None] = None + self.middleware_stack: ASGIApp | None = None self.setup() def build_middleware_stack(self) -> ASGIApp: @@ -1143,28 +1139,26 @@ class FastAPI(Starlette): endpoint: Callable[..., Any], *, response_model: Any = Default(None), - status_code: Optional[int] = None, - tags: Optional[list[Union[str, Enum]]] = None, - dependencies: Optional[Sequence[Depends]] = None, - summary: Optional[str] = None, - description: Optional[str] = None, + status_code: int | None = None, + tags: list[str | Enum] | None = None, + dependencies: Sequence[Depends] | None = None, + summary: str | None = None, + description: str | None = None, response_description: str = "Successful Response", - responses: Optional[dict[Union[int, str], dict[str, Any]]] = None, - deprecated: Optional[bool] = None, - methods: Optional[list[str]] = None, - operation_id: Optional[str] = None, - response_model_include: Optional[IncEx] = None, - response_model_exclude: Optional[IncEx] = None, + responses: dict[int | str, dict[str, Any]] | None = None, + deprecated: bool | None = None, + methods: list[str] | None = None, + operation_id: str | None = None, + response_model_include: IncEx | None = None, + response_model_exclude: IncEx | None = None, response_model_by_alias: bool = True, response_model_exclude_unset: bool = False, response_model_exclude_defaults: bool = False, response_model_exclude_none: bool = False, include_in_schema: bool = True, - response_class: Union[type[Response], DefaultPlaceholder] = Default( - JSONResponse - ), - name: Optional[str] = None, - openapi_extra: Optional[dict[str, Any]] = None, + response_class: type[Response] | DefaultPlaceholder = Default(JSONResponse), + name: str | None = None, + openapi_extra: dict[str, Any] | None = None, generate_unique_id_function: Callable[[routing.APIRoute], str] = Default( generate_unique_id ), @@ -1201,26 +1195,26 @@ class FastAPI(Starlette): path: str, *, response_model: Any = Default(None), - status_code: Optional[int] = None, - tags: Optional[list[Union[str, Enum]]] = None, - dependencies: Optional[Sequence[Depends]] = None, - summary: Optional[str] = None, - description: Optional[str] = None, + status_code: int | None = None, + tags: list[str | Enum] | None = None, + dependencies: Sequence[Depends] | None = None, + summary: str | None = None, + description: str | None = None, response_description: str = "Successful Response", - responses: Optional[dict[Union[int, str], dict[str, Any]]] = None, - deprecated: Optional[bool] = None, - methods: Optional[list[str]] = None, - operation_id: Optional[str] = None, - response_model_include: Optional[IncEx] = None, - response_model_exclude: Optional[IncEx] = None, + responses: dict[int | str, dict[str, Any]] | None = None, + deprecated: bool | None = None, + methods: list[str] | None = None, + operation_id: str | None = None, + response_model_include: IncEx | None = None, + response_model_exclude: IncEx | None = None, response_model_by_alias: bool = True, response_model_exclude_unset: bool = False, response_model_exclude_defaults: bool = False, response_model_exclude_none: bool = False, include_in_schema: bool = True, response_class: type[Response] = Default(JSONResponse), - name: Optional[str] = None, - openapi_extra: Optional[dict[str, Any]] = None, + name: str | None = None, + openapi_extra: dict[str, Any] | None = None, generate_unique_id_function: Callable[[routing.APIRoute], str] = Default( generate_unique_id ), @@ -1260,9 +1254,9 @@ class FastAPI(Starlette): self, path: str, endpoint: Callable[..., Any], - name: Optional[str] = None, + name: str | None = None, *, - dependencies: Optional[Sequence[Depends]] = None, + dependencies: Sequence[Depends] | None = None, ) -> None: self.router.add_api_websocket_route( path, @@ -1282,7 +1276,7 @@ class FastAPI(Starlette): ), ], name: Annotated[ - Optional[str], + str | None, Doc( """ A name for the WebSocket. Only used internally. @@ -1291,7 +1285,7 @@ class FastAPI(Starlette): ] = None, *, dependencies: Annotated[ - Optional[Sequence[Depends]], + Sequence[Depends] | None, Doc( """ A list of dependencies (using `Depends()`) to be used for this @@ -1342,7 +1336,7 @@ class FastAPI(Starlette): *, prefix: Annotated[str, Doc("An optional path prefix for the router.")] = "", tags: Annotated[ - Optional[list[Union[str, Enum]]], + list[str | Enum] | None, Doc( """ A list of tags to be applied to all the *path operations* in this @@ -1356,7 +1350,7 @@ class FastAPI(Starlette): ), ] = None, dependencies: Annotated[ - Optional[Sequence[Depends]], + Sequence[Depends] | None, Doc( """ A list of dependencies (using `Depends()`) to be applied to all the @@ -1384,7 +1378,7 @@ class FastAPI(Starlette): ), ] = None, responses: Annotated[ - Optional[dict[Union[int, str], dict[str, Any]]], + dict[int | str, dict[str, Any]] | None, Doc( """ Additional responses to be shown in OpenAPI. @@ -1400,7 +1394,7 @@ class FastAPI(Starlette): ), ] = None, deprecated: Annotated[ - Optional[bool], + bool | None, Doc( """ Mark all the *path operations* in this router as deprecated. @@ -1479,7 +1473,7 @@ class FastAPI(Starlette): ), ] = Default(JSONResponse), callbacks: Annotated[ - Optional[list[BaseRoute]], + list[BaseRoute] | None, Doc( """ List of *path operations* that will be used as OpenAPI callbacks. @@ -1589,7 +1583,7 @@ class FastAPI(Starlette): ), ] = Default(None), status_code: Annotated[ - Optional[int], + int | None, Doc( """ The default status code to be used for the response. @@ -1602,7 +1596,7 @@ class FastAPI(Starlette): ), ] = None, tags: Annotated[ - Optional[list[Union[str, Enum]]], + list[str | Enum] | None, Doc( """ A list of tags to be applied to the *path operation*. @@ -1615,7 +1609,7 @@ class FastAPI(Starlette): ), ] = None, dependencies: Annotated[ - Optional[Sequence[Depends]], + Sequence[Depends] | None, Doc( """ A list of dependencies (using `Depends()`) to be applied to the @@ -1627,7 +1621,7 @@ class FastAPI(Starlette): ), ] = None, summary: Annotated[ - Optional[str], + str | None, Doc( """ A summary for the *path operation*. @@ -1640,7 +1634,7 @@ class FastAPI(Starlette): ), ] = None, description: Annotated[ - Optional[str], + str | None, Doc( """ A description for the *path operation*. @@ -1668,7 +1662,7 @@ class FastAPI(Starlette): ), ] = "Successful Response", responses: Annotated[ - Optional[dict[Union[int, str], dict[str, Any]]], + dict[int | str, dict[str, Any]] | None, Doc( """ Additional responses that could be returned by this *path operation*. @@ -1678,7 +1672,7 @@ class FastAPI(Starlette): ), ] = None, deprecated: Annotated[ - Optional[bool], + bool | None, Doc( """ Mark this *path operation* as deprecated. @@ -1688,7 +1682,7 @@ class FastAPI(Starlette): ), ] = None, operation_id: Annotated[ - Optional[str], + str | None, Doc( """ Custom operation ID to be used by this *path operation*. @@ -1708,7 +1702,7 @@ class FastAPI(Starlette): ), ] = None, response_model_include: Annotated[ - Optional[IncEx], + IncEx | None, Doc( """ Configuration passed to Pydantic to include only certain fields in the @@ -1720,7 +1714,7 @@ class FastAPI(Starlette): ), ] = None, response_model_exclude: Annotated[ - Optional[IncEx], + IncEx | None, Doc( """ Configuration passed to Pydantic to exclude certain fields in the @@ -1822,7 +1816,7 @@ class FastAPI(Starlette): ), ] = Default(JSONResponse), name: Annotated[ - Optional[str], + str | None, Doc( """ Name for this *path operation*. Only used internally. @@ -1830,7 +1824,7 @@ class FastAPI(Starlette): ), ] = None, callbacks: Annotated[ - Optional[list[BaseRoute]], + list[BaseRoute] | None, Doc( """ List of *path operations* that will be used as OpenAPI callbacks. @@ -1846,7 +1840,7 @@ class FastAPI(Starlette): ), ] = None, openapi_extra: Annotated[ - Optional[dict[str, Any]], + dict[str, Any] | None, Doc( """ Extra metadata to be included in the OpenAPI schema for this *path @@ -1962,7 +1956,7 @@ class FastAPI(Starlette): ), ] = Default(None), status_code: Annotated[ - Optional[int], + int | None, Doc( """ The default status code to be used for the response. @@ -1975,7 +1969,7 @@ class FastAPI(Starlette): ), ] = None, tags: Annotated[ - Optional[list[Union[str, Enum]]], + list[str | Enum] | None, Doc( """ A list of tags to be applied to the *path operation*. @@ -1988,7 +1982,7 @@ class FastAPI(Starlette): ), ] = None, dependencies: Annotated[ - Optional[Sequence[Depends]], + Sequence[Depends] | None, Doc( """ A list of dependencies (using `Depends()`) to be applied to the @@ -2000,7 +1994,7 @@ class FastAPI(Starlette): ), ] = None, summary: Annotated[ - Optional[str], + str | None, Doc( """ A summary for the *path operation*. @@ -2013,7 +2007,7 @@ class FastAPI(Starlette): ), ] = None, description: Annotated[ - Optional[str], + str | None, Doc( """ A description for the *path operation*. @@ -2041,7 +2035,7 @@ class FastAPI(Starlette): ), ] = "Successful Response", responses: Annotated[ - Optional[dict[Union[int, str], dict[str, Any]]], + dict[int | str, dict[str, Any]] | None, Doc( """ Additional responses that could be returned by this *path operation*. @@ -2051,7 +2045,7 @@ class FastAPI(Starlette): ), ] = None, deprecated: Annotated[ - Optional[bool], + bool | None, Doc( """ Mark this *path operation* as deprecated. @@ -2061,7 +2055,7 @@ class FastAPI(Starlette): ), ] = None, operation_id: Annotated[ - Optional[str], + str | None, Doc( """ Custom operation ID to be used by this *path operation*. @@ -2081,7 +2075,7 @@ class FastAPI(Starlette): ), ] = None, response_model_include: Annotated[ - Optional[IncEx], + IncEx | None, Doc( """ Configuration passed to Pydantic to include only certain fields in the @@ -2093,7 +2087,7 @@ class FastAPI(Starlette): ), ] = None, response_model_exclude: Annotated[ - Optional[IncEx], + IncEx | None, Doc( """ Configuration passed to Pydantic to exclude certain fields in the @@ -2195,7 +2189,7 @@ class FastAPI(Starlette): ), ] = Default(JSONResponse), name: Annotated[ - Optional[str], + str | None, Doc( """ Name for this *path operation*. Only used internally. @@ -2203,7 +2197,7 @@ class FastAPI(Starlette): ), ] = None, callbacks: Annotated[ - Optional[list[BaseRoute]], + list[BaseRoute] | None, Doc( """ List of *path operations* that will be used as OpenAPI callbacks. @@ -2219,7 +2213,7 @@ class FastAPI(Starlette): ), ] = None, openapi_extra: Annotated[ - Optional[dict[str, Any]], + dict[str, Any] | None, Doc( """ Extra metadata to be included in the OpenAPI schema for this *path @@ -2340,7 +2334,7 @@ class FastAPI(Starlette): ), ] = Default(None), status_code: Annotated[ - Optional[int], + int | None, Doc( """ The default status code to be used for the response. @@ -2353,7 +2347,7 @@ class FastAPI(Starlette): ), ] = None, tags: Annotated[ - Optional[list[Union[str, Enum]]], + list[str | Enum] | None, Doc( """ A list of tags to be applied to the *path operation*. @@ -2366,7 +2360,7 @@ class FastAPI(Starlette): ), ] = None, dependencies: Annotated[ - Optional[Sequence[Depends]], + Sequence[Depends] | None, Doc( """ A list of dependencies (using `Depends()`) to be applied to the @@ -2378,7 +2372,7 @@ class FastAPI(Starlette): ), ] = None, summary: Annotated[ - Optional[str], + str | None, Doc( """ A summary for the *path operation*. @@ -2391,7 +2385,7 @@ class FastAPI(Starlette): ), ] = None, description: Annotated[ - Optional[str], + str | None, Doc( """ A description for the *path operation*. @@ -2419,7 +2413,7 @@ class FastAPI(Starlette): ), ] = "Successful Response", responses: Annotated[ - Optional[dict[Union[int, str], dict[str, Any]]], + dict[int | str, dict[str, Any]] | None, Doc( """ Additional responses that could be returned by this *path operation*. @@ -2429,7 +2423,7 @@ class FastAPI(Starlette): ), ] = None, deprecated: Annotated[ - Optional[bool], + bool | None, Doc( """ Mark this *path operation* as deprecated. @@ -2439,7 +2433,7 @@ class FastAPI(Starlette): ), ] = None, operation_id: Annotated[ - Optional[str], + str | None, Doc( """ Custom operation ID to be used by this *path operation*. @@ -2459,7 +2453,7 @@ class FastAPI(Starlette): ), ] = None, response_model_include: Annotated[ - Optional[IncEx], + IncEx | None, Doc( """ Configuration passed to Pydantic to include only certain fields in the @@ -2471,7 +2465,7 @@ class FastAPI(Starlette): ), ] = None, response_model_exclude: Annotated[ - Optional[IncEx], + IncEx | None, Doc( """ Configuration passed to Pydantic to exclude certain fields in the @@ -2573,7 +2567,7 @@ class FastAPI(Starlette): ), ] = Default(JSONResponse), name: Annotated[ - Optional[str], + str | None, Doc( """ Name for this *path operation*. Only used internally. @@ -2581,7 +2575,7 @@ class FastAPI(Starlette): ), ] = None, callbacks: Annotated[ - Optional[list[BaseRoute]], + list[BaseRoute] | None, Doc( """ List of *path operations* that will be used as OpenAPI callbacks. @@ -2597,7 +2591,7 @@ class FastAPI(Starlette): ), ] = None, openapi_extra: Annotated[ - Optional[dict[str, Any]], + dict[str, Any] | None, Doc( """ Extra metadata to be included in the OpenAPI schema for this *path @@ -2718,7 +2712,7 @@ class FastAPI(Starlette): ), ] = Default(None), status_code: Annotated[ - Optional[int], + int | None, Doc( """ The default status code to be used for the response. @@ -2731,7 +2725,7 @@ class FastAPI(Starlette): ), ] = None, tags: Annotated[ - Optional[list[Union[str, Enum]]], + list[str | Enum] | None, Doc( """ A list of tags to be applied to the *path operation*. @@ -2744,7 +2738,7 @@ class FastAPI(Starlette): ), ] = None, dependencies: Annotated[ - Optional[Sequence[Depends]], + Sequence[Depends] | None, Doc( """ A list of dependencies (using `Depends()`) to be applied to the @@ -2756,7 +2750,7 @@ class FastAPI(Starlette): ), ] = None, summary: Annotated[ - Optional[str], + str | None, Doc( """ A summary for the *path operation*. @@ -2769,7 +2763,7 @@ class FastAPI(Starlette): ), ] = None, description: Annotated[ - Optional[str], + str | None, Doc( """ A description for the *path operation*. @@ -2797,7 +2791,7 @@ class FastAPI(Starlette): ), ] = "Successful Response", responses: Annotated[ - Optional[dict[Union[int, str], dict[str, Any]]], + dict[int | str, dict[str, Any]] | None, Doc( """ Additional responses that could be returned by this *path operation*. @@ -2807,7 +2801,7 @@ class FastAPI(Starlette): ), ] = None, deprecated: Annotated[ - Optional[bool], + bool | None, Doc( """ Mark this *path operation* as deprecated. @@ -2817,7 +2811,7 @@ class FastAPI(Starlette): ), ] = None, operation_id: Annotated[ - Optional[str], + str | None, Doc( """ Custom operation ID to be used by this *path operation*. @@ -2837,7 +2831,7 @@ class FastAPI(Starlette): ), ] = None, response_model_include: Annotated[ - Optional[IncEx], + IncEx | None, Doc( """ Configuration passed to Pydantic to include only certain fields in the @@ -2849,7 +2843,7 @@ class FastAPI(Starlette): ), ] = None, response_model_exclude: Annotated[ - Optional[IncEx], + IncEx | None, Doc( """ Configuration passed to Pydantic to exclude certain fields in the @@ -2951,7 +2945,7 @@ class FastAPI(Starlette): ), ] = Default(JSONResponse), name: Annotated[ - Optional[str], + str | None, Doc( """ Name for this *path operation*. Only used internally. @@ -2959,7 +2953,7 @@ class FastAPI(Starlette): ), ] = None, callbacks: Annotated[ - Optional[list[BaseRoute]], + list[BaseRoute] | None, Doc( """ List of *path operations* that will be used as OpenAPI callbacks. @@ -2975,7 +2969,7 @@ class FastAPI(Starlette): ), ] = None, openapi_extra: Annotated[ - Optional[dict[str, Any]], + dict[str, Any] | None, Doc( """ Extra metadata to be included in the OpenAPI schema for this *path @@ -3091,7 +3085,7 @@ class FastAPI(Starlette): ), ] = Default(None), status_code: Annotated[ - Optional[int], + int | None, Doc( """ The default status code to be used for the response. @@ -3104,7 +3098,7 @@ class FastAPI(Starlette): ), ] = None, tags: Annotated[ - Optional[list[Union[str, Enum]]], + list[str | Enum] | None, Doc( """ A list of tags to be applied to the *path operation*. @@ -3117,7 +3111,7 @@ class FastAPI(Starlette): ), ] = None, dependencies: Annotated[ - Optional[Sequence[Depends]], + Sequence[Depends] | None, Doc( """ A list of dependencies (using `Depends()`) to be applied to the @@ -3129,7 +3123,7 @@ class FastAPI(Starlette): ), ] = None, summary: Annotated[ - Optional[str], + str | None, Doc( """ A summary for the *path operation*. @@ -3142,7 +3136,7 @@ class FastAPI(Starlette): ), ] = None, description: Annotated[ - Optional[str], + str | None, Doc( """ A description for the *path operation*. @@ -3170,7 +3164,7 @@ class FastAPI(Starlette): ), ] = "Successful Response", responses: Annotated[ - Optional[dict[Union[int, str], dict[str, Any]]], + dict[int | str, dict[str, Any]] | None, Doc( """ Additional responses that could be returned by this *path operation*. @@ -3180,7 +3174,7 @@ class FastAPI(Starlette): ), ] = None, deprecated: Annotated[ - Optional[bool], + bool | None, Doc( """ Mark this *path operation* as deprecated. @@ -3190,7 +3184,7 @@ class FastAPI(Starlette): ), ] = None, operation_id: Annotated[ - Optional[str], + str | None, Doc( """ Custom operation ID to be used by this *path operation*. @@ -3210,7 +3204,7 @@ class FastAPI(Starlette): ), ] = None, response_model_include: Annotated[ - Optional[IncEx], + IncEx | None, Doc( """ Configuration passed to Pydantic to include only certain fields in the @@ -3222,7 +3216,7 @@ class FastAPI(Starlette): ), ] = None, response_model_exclude: Annotated[ - Optional[IncEx], + IncEx | None, Doc( """ Configuration passed to Pydantic to exclude certain fields in the @@ -3324,7 +3318,7 @@ class FastAPI(Starlette): ), ] = Default(JSONResponse), name: Annotated[ - Optional[str], + str | None, Doc( """ Name for this *path operation*. Only used internally. @@ -3332,7 +3326,7 @@ class FastAPI(Starlette): ), ] = None, callbacks: Annotated[ - Optional[list[BaseRoute]], + list[BaseRoute] | None, Doc( """ List of *path operations* that will be used as OpenAPI callbacks. @@ -3348,7 +3342,7 @@ class FastAPI(Starlette): ), ] = None, openapi_extra: Annotated[ - Optional[dict[str, Any]], + dict[str, Any] | None, Doc( """ Extra metadata to be included in the OpenAPI schema for this *path @@ -3464,7 +3458,7 @@ class FastAPI(Starlette): ), ] = Default(None), status_code: Annotated[ - Optional[int], + int | None, Doc( """ The default status code to be used for the response. @@ -3477,7 +3471,7 @@ class FastAPI(Starlette): ), ] = None, tags: Annotated[ - Optional[list[Union[str, Enum]]], + list[str | Enum] | None, Doc( """ A list of tags to be applied to the *path operation*. @@ -3490,7 +3484,7 @@ class FastAPI(Starlette): ), ] = None, dependencies: Annotated[ - Optional[Sequence[Depends]], + Sequence[Depends] | None, Doc( """ A list of dependencies (using `Depends()`) to be applied to the @@ -3502,7 +3496,7 @@ class FastAPI(Starlette): ), ] = None, summary: Annotated[ - Optional[str], + str | None, Doc( """ A summary for the *path operation*. @@ -3515,7 +3509,7 @@ class FastAPI(Starlette): ), ] = None, description: Annotated[ - Optional[str], + str | None, Doc( """ A description for the *path operation*. @@ -3543,7 +3537,7 @@ class FastAPI(Starlette): ), ] = "Successful Response", responses: Annotated[ - Optional[dict[Union[int, str], dict[str, Any]]], + dict[int | str, dict[str, Any]] | None, Doc( """ Additional responses that could be returned by this *path operation*. @@ -3553,7 +3547,7 @@ class FastAPI(Starlette): ), ] = None, deprecated: Annotated[ - Optional[bool], + bool | None, Doc( """ Mark this *path operation* as deprecated. @@ -3563,7 +3557,7 @@ class FastAPI(Starlette): ), ] = None, operation_id: Annotated[ - Optional[str], + str | None, Doc( """ Custom operation ID to be used by this *path operation*. @@ -3583,7 +3577,7 @@ class FastAPI(Starlette): ), ] = None, response_model_include: Annotated[ - Optional[IncEx], + IncEx | None, Doc( """ Configuration passed to Pydantic to include only certain fields in the @@ -3595,7 +3589,7 @@ class FastAPI(Starlette): ), ] = None, response_model_exclude: Annotated[ - Optional[IncEx], + IncEx | None, Doc( """ Configuration passed to Pydantic to exclude certain fields in the @@ -3697,7 +3691,7 @@ class FastAPI(Starlette): ), ] = Default(JSONResponse), name: Annotated[ - Optional[str], + str | None, Doc( """ Name for this *path operation*. Only used internally. @@ -3705,7 +3699,7 @@ class FastAPI(Starlette): ), ] = None, callbacks: Annotated[ - Optional[list[BaseRoute]], + list[BaseRoute] | None, Doc( """ List of *path operations* that will be used as OpenAPI callbacks. @@ -3721,7 +3715,7 @@ class FastAPI(Starlette): ), ] = None, openapi_extra: Annotated[ - Optional[dict[str, Any]], + dict[str, Any] | None, Doc( """ Extra metadata to be included in the OpenAPI schema for this *path @@ -3837,7 +3831,7 @@ class FastAPI(Starlette): ), ] = Default(None), status_code: Annotated[ - Optional[int], + int | None, Doc( """ The default status code to be used for the response. @@ -3850,7 +3844,7 @@ class FastAPI(Starlette): ), ] = None, tags: Annotated[ - Optional[list[Union[str, Enum]]], + list[str | Enum] | None, Doc( """ A list of tags to be applied to the *path operation*. @@ -3863,7 +3857,7 @@ class FastAPI(Starlette): ), ] = None, dependencies: Annotated[ - Optional[Sequence[Depends]], + Sequence[Depends] | None, Doc( """ A list of dependencies (using `Depends()`) to be applied to the @@ -3875,7 +3869,7 @@ class FastAPI(Starlette): ), ] = None, summary: Annotated[ - Optional[str], + str | None, Doc( """ A summary for the *path operation*. @@ -3888,7 +3882,7 @@ class FastAPI(Starlette): ), ] = None, description: Annotated[ - Optional[str], + str | None, Doc( """ A description for the *path operation*. @@ -3916,7 +3910,7 @@ class FastAPI(Starlette): ), ] = "Successful Response", responses: Annotated[ - Optional[dict[Union[int, str], dict[str, Any]]], + dict[int | str, dict[str, Any]] | None, Doc( """ Additional responses that could be returned by this *path operation*. @@ -3926,7 +3920,7 @@ class FastAPI(Starlette): ), ] = None, deprecated: Annotated[ - Optional[bool], + bool | None, Doc( """ Mark this *path operation* as deprecated. @@ -3936,7 +3930,7 @@ class FastAPI(Starlette): ), ] = None, operation_id: Annotated[ - Optional[str], + str | None, Doc( """ Custom operation ID to be used by this *path operation*. @@ -3956,7 +3950,7 @@ class FastAPI(Starlette): ), ] = None, response_model_include: Annotated[ - Optional[IncEx], + IncEx | None, Doc( """ Configuration passed to Pydantic to include only certain fields in the @@ -3968,7 +3962,7 @@ class FastAPI(Starlette): ), ] = None, response_model_exclude: Annotated[ - Optional[IncEx], + IncEx | None, Doc( """ Configuration passed to Pydantic to exclude certain fields in the @@ -4070,7 +4064,7 @@ class FastAPI(Starlette): ), ] = Default(JSONResponse), name: Annotated[ - Optional[str], + str | None, Doc( """ Name for this *path operation*. Only used internally. @@ -4078,7 +4072,7 @@ class FastAPI(Starlette): ), ] = None, callbacks: Annotated[ - Optional[list[BaseRoute]], + list[BaseRoute] | None, Doc( """ List of *path operations* that will be used as OpenAPI callbacks. @@ -4094,7 +4088,7 @@ class FastAPI(Starlette): ), ] = None, openapi_extra: Annotated[ - Optional[dict[str, Any]], + dict[str, Any] | None, Doc( """ Extra metadata to be included in the OpenAPI schema for this *path @@ -4215,7 +4209,7 @@ class FastAPI(Starlette): ), ] = Default(None), status_code: Annotated[ - Optional[int], + int | None, Doc( """ The default status code to be used for the response. @@ -4228,7 +4222,7 @@ class FastAPI(Starlette): ), ] = None, tags: Annotated[ - Optional[list[Union[str, Enum]]], + list[str | Enum] | None, Doc( """ A list of tags to be applied to the *path operation*. @@ -4241,7 +4235,7 @@ class FastAPI(Starlette): ), ] = None, dependencies: Annotated[ - Optional[Sequence[Depends]], + Sequence[Depends] | None, Doc( """ A list of dependencies (using `Depends()`) to be applied to the @@ -4253,7 +4247,7 @@ class FastAPI(Starlette): ), ] = None, summary: Annotated[ - Optional[str], + str | None, Doc( """ A summary for the *path operation*. @@ -4266,7 +4260,7 @@ class FastAPI(Starlette): ), ] = None, description: Annotated[ - Optional[str], + str | None, Doc( """ A description for the *path operation*. @@ -4294,7 +4288,7 @@ class FastAPI(Starlette): ), ] = "Successful Response", responses: Annotated[ - Optional[dict[Union[int, str], dict[str, Any]]], + dict[int | str, dict[str, Any]] | None, Doc( """ Additional responses that could be returned by this *path operation*. @@ -4304,7 +4298,7 @@ class FastAPI(Starlette): ), ] = None, deprecated: Annotated[ - Optional[bool], + bool | None, Doc( """ Mark this *path operation* as deprecated. @@ -4314,7 +4308,7 @@ class FastAPI(Starlette): ), ] = None, operation_id: Annotated[ - Optional[str], + str | None, Doc( """ Custom operation ID to be used by this *path operation*. @@ -4334,7 +4328,7 @@ class FastAPI(Starlette): ), ] = None, response_model_include: Annotated[ - Optional[IncEx], + IncEx | None, Doc( """ Configuration passed to Pydantic to include only certain fields in the @@ -4346,7 +4340,7 @@ class FastAPI(Starlette): ), ] = None, response_model_exclude: Annotated[ - Optional[IncEx], + IncEx | None, Doc( """ Configuration passed to Pydantic to exclude certain fields in the @@ -4448,7 +4442,7 @@ class FastAPI(Starlette): ), ] = Default(JSONResponse), name: Annotated[ - Optional[str], + str | None, Doc( """ Name for this *path operation*. Only used internally. @@ -4456,7 +4450,7 @@ class FastAPI(Starlette): ), ] = None, callbacks: Annotated[ - Optional[list[BaseRoute]], + list[BaseRoute] | None, Doc( """ List of *path operations* that will be used as OpenAPI callbacks. @@ -4472,7 +4466,7 @@ class FastAPI(Starlette): ), ] = None, openapi_extra: Annotated[ - Optional[dict[str, Any]], + dict[str, Any] | None, Doc( """ Extra metadata to be included in the OpenAPI schema for this *path @@ -4541,7 +4535,7 @@ class FastAPI(Starlette): ) def websocket_route( - self, path: str, name: Union[str, None] = None + self, path: str, name: str | None = None ) -> Callable[[DecoratedCallable], DecoratedCallable]: def decorator(func: DecoratedCallable) -> DecoratedCallable: self.router.add_websocket_route(path, func, name=name) @@ -4627,7 +4621,7 @@ class FastAPI(Starlette): def exception_handler( self, exc_class_or_status_code: Annotated[ - Union[int, type[Exception]], + int | type[Exception], Doc( """ The Exception class this would handle, or a status code. diff --git a/fastapi/background.py b/fastapi/background.py index 20803ba67..7677058c4 100644 --- a/fastapi/background.py +++ b/fastapi/background.py @@ -1,4 +1,5 @@ -from typing import Annotated, Any, Callable +from collections.abc import Callable +from typing import Annotated, Any from annotated_doc import Doc from starlette.background import BackgroundTasks as StarletteBackgroundTasks diff --git a/fastapi/datastructures.py b/fastapi/datastructures.py index 2bf5fdb26..c04b5f0f3 100644 --- a/fastapi/datastructures.py +++ b/fastapi/datastructures.py @@ -1,10 +1,8 @@ -from collections.abc import Mapping +from collections.abc import Callable, Mapping from typing import ( Annotated, Any, BinaryIO, - Callable, - Optional, TypeVar, cast, ) @@ -58,11 +56,11 @@ class UploadFile(StarletteUploadFile): BinaryIO, Doc("The standard Python file object (non-async)."), ] - filename: Annotated[Optional[str], Doc("The original file name.")] - size: Annotated[Optional[int], Doc("The size of the file in bytes.")] + filename: Annotated[str | None, Doc("The original file name.")] + size: Annotated[int | None, Doc("The size of the file in bytes.")] headers: Annotated[Headers, Doc("The headers of the request.")] content_type: Annotated[ - Optional[str], Doc("The content type of the request, from the headers.") + str | None, Doc("The content type of the request, from the headers.") ] async def write( diff --git a/fastapi/dependencies/models.py b/fastapi/dependencies/models.py index 58392326d..25ffb0d2d 100644 --- a/fastapi/dependencies/models.py +++ b/fastapi/dependencies/models.py @@ -1,13 +1,13 @@ import inspect import sys +from collections.abc import Callable from dataclasses import dataclass, field from functools import cached_property, partial -from typing import Any, Callable, Optional, Union +from typing import Any, Literal from fastapi._compat import ModelField from fastapi.security.base import SecurityBase from fastapi.types import DependencyCacheKey -from typing_extensions import Literal if sys.version_info >= (3, 13): # pragma: no cover from inspect import iscoroutinefunction @@ -15,7 +15,7 @@ else: # pragma: no cover from asyncio import iscoroutinefunction -def _unwrapped_call(call: Optional[Callable[..., Any]]) -> Any: +def _unwrapped_call(call: Callable[..., Any] | None) -> Any: if call is None: return call # pragma: no cover unwrapped = inspect.unwrap(_impartial(call)) @@ -36,19 +36,19 @@ class Dependant: cookie_params: list[ModelField] = field(default_factory=list) body_params: list[ModelField] = field(default_factory=list) dependencies: list["Dependant"] = field(default_factory=list) - name: Optional[str] = None - call: Optional[Callable[..., Any]] = None - request_param_name: Optional[str] = None - websocket_param_name: Optional[str] = None - http_connection_param_name: Optional[str] = None - response_param_name: Optional[str] = None - background_tasks_param_name: Optional[str] = None - security_scopes_param_name: Optional[str] = None - own_oauth_scopes: Optional[list[str]] = None - parent_oauth_scopes: Optional[list[str]] = None + name: str | None = None + call: Callable[..., Any] | None = None + request_param_name: str | None = None + websocket_param_name: str | None = None + http_connection_param_name: str | None = None + response_param_name: str | None = None + background_tasks_param_name: str | None = None + security_scopes_param_name: str | None = None + own_oauth_scopes: list[str] | None = None + parent_oauth_scopes: list[str] | None = None use_cache: bool = True - path: Optional[str] = None - scope: Union[Literal["function", "request"], None] = None + path: str | None = None + scope: Literal["function", "request"] | None = None @cached_property def oauth_scopes(self) -> list[str]: @@ -185,7 +185,7 @@ class Dependant: return False @cached_property - def computed_scope(self) -> Union[str, None]: + def computed_scope(self) -> str | None: if self.scope: return self.scope if self.is_gen_callable or self.is_async_gen_callable: diff --git a/fastapi/encoders.py b/fastapi/encoders.py index b4661be4f..e20255c11 100644 --- a/fastapi/encoders.py +++ b/fastapi/encoders.py @@ -1,6 +1,7 @@ import dataclasses import datetime from collections import defaultdict, deque +from collections.abc import Callable from decimal import Decimal from enum import Enum from ipaddress import ( @@ -14,7 +15,7 @@ from ipaddress import ( from pathlib import Path, PurePath from re import Pattern from types import GeneratorType -from typing import Annotated, Any, Callable, Optional, Union +from typing import Annotated, Any from uuid import UUID from annotated_doc import Doc @@ -33,13 +34,13 @@ from ._compat import ( # Taken from Pydantic v1 as is -def isoformat(o: Union[datetime.date, datetime.time]) -> str: +def isoformat(o: datetime.date | datetime.time) -> str: return o.isoformat() # Adapted from Pydantic v1 # TODO: pv2 should this return strings instead? -def decimal_encoder(dec_value: Decimal) -> Union[int, float]: +def decimal_encoder(dec_value: Decimal) -> int | float: """ Encodes a Decimal as int if there's no exponent, otherwise float @@ -118,7 +119,7 @@ def jsonable_encoder( ), ], include: Annotated[ - Optional[IncEx], + IncEx | None, Doc( """ Pydantic's `include` parameter, passed to Pydantic models to set the @@ -127,7 +128,7 @@ def jsonable_encoder( ), ] = None, exclude: Annotated[ - Optional[IncEx], + IncEx | None, Doc( """ Pydantic's `exclude` parameter, passed to Pydantic models to set the @@ -177,7 +178,7 @@ def jsonable_encoder( ), ] = False, custom_encoder: Annotated[ - Optional[dict[Any, Callable[[Any], Any]]], + dict[Any, Callable[[Any], Any]] | None, Doc( """ Pydantic's `custom_encoder` parameter, passed to Pydantic models to define diff --git a/fastapi/exceptions.py b/fastapi/exceptions.py index 9924d0e2b..d7065c52f 100644 --- a/fastapi/exceptions.py +++ b/fastapi/exceptions.py @@ -1,5 +1,5 @@ from collections.abc import Mapping, Sequence -from typing import Annotated, Any, Optional, TypedDict, Union +from typing import Annotated, Any, TypedDict from annotated_doc import Doc from pydantic import BaseModel, create_model @@ -68,7 +68,7 @@ class HTTPException(StarletteHTTPException): ), ] = None, headers: Annotated[ - Optional[Mapping[str, str]], + Mapping[str, str] | None, Doc( """ Any headers to send to the client in the response. @@ -137,7 +137,7 @@ class WebSocketException(StarletteWebSocketException): ), ], reason: Annotated[ - Union[str, None], + str | None, Doc( """ The reason to close the WebSocket connection. @@ -176,7 +176,7 @@ class ValidationException(Exception): self, errors: Sequence[Any], *, - endpoint_ctx: Optional[EndpointContext] = None, + endpoint_ctx: EndpointContext | None = None, ) -> None: self._errors = errors self.endpoint_ctx = endpoint_ctx @@ -215,7 +215,7 @@ class RequestValidationError(ValidationException): errors: Sequence[Any], *, body: Any = None, - endpoint_ctx: Optional[EndpointContext] = None, + endpoint_ctx: EndpointContext | None = None, ) -> None: super().__init__(errors, endpoint_ctx=endpoint_ctx) self.body = body @@ -226,7 +226,7 @@ class WebSocketRequestValidationError(ValidationException): self, errors: Sequence[Any], *, - endpoint_ctx: Optional[EndpointContext] = None, + endpoint_ctx: EndpointContext | None = None, ) -> None: super().__init__(errors, endpoint_ctx=endpoint_ctx) @@ -237,7 +237,7 @@ class ResponseValidationError(ValidationException): errors: Sequence[Any], *, body: Any = None, - endpoint_ctx: Optional[EndpointContext] = None, + endpoint_ctx: EndpointContext | None = None, ) -> None: super().__init__(errors, endpoint_ctx=endpoint_ctx) self.body = body diff --git a/fastapi/openapi/docs.py b/fastapi/openapi/docs.py index bb387c609..b845f87c1 100644 --- a/fastapi/openapi/docs.py +++ b/fastapi/openapi/docs.py @@ -1,5 +1,5 @@ import json -from typing import Annotated, Any, Optional +from typing import Annotated, Any from annotated_doc import Doc from fastapi.encoders import jsonable_encoder @@ -85,7 +85,7 @@ def get_swagger_ui_html( ), ] = "https://fastapi.tiangolo.com/img/favicon.png", oauth2_redirect_url: Annotated[ - Optional[str], + str | None, Doc( """ The OAuth2 redirect URL, it is normally automatically handled by FastAPI. @@ -96,7 +96,7 @@ def get_swagger_ui_html( ), ] = None, init_oauth: Annotated[ - Optional[dict[str, Any]], + dict[str, Any] | None, Doc( """ A dictionary with Swagger UI OAuth2 initialization configurations. @@ -107,7 +107,7 @@ def get_swagger_ui_html( ), ] = None, swagger_ui_parameters: Annotated[ - Optional[dict[str, Any]], + dict[str, Any] | None, Doc( """ Configuration parameters for Swagger UI. diff --git a/fastapi/openapi/models.py b/fastapi/openapi/models.py index 095990639..d7950241f 100644 --- a/fastapi/openapi/models.py +++ b/fastapi/openapi/models.py @@ -1,6 +1,6 @@ -from collections.abc import Iterable, Mapping +from collections.abc import Callable, Iterable, Mapping from enum import Enum -from typing import Annotated, Any, Callable, Optional, Union +from typing import Annotated, Any, Literal, Optional, Union from fastapi._compat import with_info_plain_validator_function from fastapi.logger import logger @@ -10,7 +10,7 @@ from pydantic import ( Field, GetJsonSchemaHandler, ) -from typing_extensions import Literal, TypedDict +from typing_extensions import TypedDict from typing_extensions import deprecated as typing_deprecated try: @@ -59,37 +59,37 @@ class BaseModelWithConfig(BaseModel): class Contact(BaseModelWithConfig): - name: Optional[str] = None - url: Optional[AnyUrl] = None - email: Optional[EmailStr] = None + name: str | None = None + url: AnyUrl | None = None + email: EmailStr | None = None class License(BaseModelWithConfig): name: str - identifier: Optional[str] = None - url: Optional[AnyUrl] = None + identifier: str | None = None + url: AnyUrl | None = None class Info(BaseModelWithConfig): title: str - summary: Optional[str] = None - description: Optional[str] = None - termsOfService: Optional[str] = None - contact: Optional[Contact] = None - license: Optional[License] = None + summary: str | None = None + description: str | None = None + termsOfService: str | None = None + contact: Contact | None = None + license: License | None = None version: str class ServerVariable(BaseModelWithConfig): - enum: Annotated[Optional[list[str]], Field(min_length=1)] = None + enum: Annotated[list[str] | None, Field(min_length=1)] = None default: str - description: Optional[str] = None + description: str | None = None class Server(BaseModelWithConfig): - url: Union[AnyUrl, str] - description: Optional[str] = None - variables: Optional[dict[str, ServerVariable]] = None + url: AnyUrl | str + description: str | None = None + variables: dict[str, ServerVariable] | None = None class Reference(BaseModel): @@ -98,19 +98,19 @@ class Reference(BaseModel): class Discriminator(BaseModel): propertyName: str - mapping: Optional[dict[str, str]] = None + mapping: dict[str, str] | None = None class XML(BaseModelWithConfig): - name: Optional[str] = None - namespace: Optional[str] = None - prefix: Optional[str] = None - attribute: Optional[bool] = None - wrapped: Optional[bool] = None + name: str | None = None + namespace: str | None = None + prefix: str | None = None + attribute: bool | None = None + wrapped: bool | None = None class ExternalDocumentation(BaseModelWithConfig): - description: Optional[str] = None + description: str | None = None url: AnyUrl @@ -123,80 +123,80 @@ SchemaType = Literal[ class Schema(BaseModelWithConfig): # Ref: JSON Schema 2020-12: https://json-schema.org/draft/2020-12/json-schema-core.html#name-the-json-schema-core-vocabu # Core Vocabulary - schema_: Optional[str] = Field(default=None, alias="$schema") - vocabulary: Optional[str] = Field(default=None, alias="$vocabulary") - id: Optional[str] = Field(default=None, alias="$id") - anchor: Optional[str] = Field(default=None, alias="$anchor") - dynamicAnchor: Optional[str] = Field(default=None, alias="$dynamicAnchor") - ref: Optional[str] = Field(default=None, alias="$ref") - dynamicRef: Optional[str] = Field(default=None, alias="$dynamicRef") - defs: Optional[dict[str, "SchemaOrBool"]] = Field(default=None, alias="$defs") - comment: Optional[str] = Field(default=None, alias="$comment") + schema_: str | None = Field(default=None, alias="$schema") + vocabulary: str | None = Field(default=None, alias="$vocabulary") + id: str | None = Field(default=None, alias="$id") + anchor: str | None = Field(default=None, alias="$anchor") + dynamicAnchor: str | None = Field(default=None, alias="$dynamicAnchor") + ref: str | None = Field(default=None, alias="$ref") + dynamicRef: str | None = Field(default=None, alias="$dynamicRef") + defs: dict[str, "SchemaOrBool"] | None = Field(default=None, alias="$defs") + comment: str | None = Field(default=None, alias="$comment") # Ref: JSON Schema 2020-12: https://json-schema.org/draft/2020-12/json-schema-core.html#name-a-vocabulary-for-applying-s # A Vocabulary for Applying Subschemas - allOf: Optional[list["SchemaOrBool"]] = None - anyOf: Optional[list["SchemaOrBool"]] = None - oneOf: Optional[list["SchemaOrBool"]] = None + allOf: list["SchemaOrBool"] | None = None + anyOf: list["SchemaOrBool"] | None = None + oneOf: list["SchemaOrBool"] | None = None not_: Optional["SchemaOrBool"] = Field(default=None, alias="not") if_: Optional["SchemaOrBool"] = Field(default=None, alias="if") then: Optional["SchemaOrBool"] = None else_: Optional["SchemaOrBool"] = Field(default=None, alias="else") - dependentSchemas: Optional[dict[str, "SchemaOrBool"]] = None - prefixItems: Optional[list["SchemaOrBool"]] = None + dependentSchemas: dict[str, "SchemaOrBool"] | None = None + prefixItems: list["SchemaOrBool"] | None = None items: Optional["SchemaOrBool"] = None contains: Optional["SchemaOrBool"] = None - properties: Optional[dict[str, "SchemaOrBool"]] = None - patternProperties: Optional[dict[str, "SchemaOrBool"]] = None + properties: dict[str, "SchemaOrBool"] | None = None + patternProperties: dict[str, "SchemaOrBool"] | None = None additionalProperties: Optional["SchemaOrBool"] = None propertyNames: Optional["SchemaOrBool"] = None unevaluatedItems: Optional["SchemaOrBool"] = None unevaluatedProperties: Optional["SchemaOrBool"] = None # Ref: JSON Schema Validation 2020-12: https://json-schema.org/draft/2020-12/json-schema-validation.html#name-a-vocabulary-for-structural # A Vocabulary for Structural Validation - type: Optional[Union[SchemaType, list[SchemaType]]] = None - enum: Optional[list[Any]] = None - const: Optional[Any] = None - multipleOf: Optional[float] = Field(default=None, gt=0) - maximum: Optional[float] = None - exclusiveMaximum: Optional[float] = None - minimum: Optional[float] = None - exclusiveMinimum: Optional[float] = None - maxLength: Optional[int] = Field(default=None, ge=0) - minLength: Optional[int] = Field(default=None, ge=0) - pattern: Optional[str] = None - maxItems: Optional[int] = Field(default=None, ge=0) - minItems: Optional[int] = Field(default=None, ge=0) - uniqueItems: Optional[bool] = None - maxContains: Optional[int] = Field(default=None, ge=0) - minContains: Optional[int] = Field(default=None, ge=0) - maxProperties: Optional[int] = Field(default=None, ge=0) - minProperties: Optional[int] = Field(default=None, ge=0) - required: Optional[list[str]] = None - dependentRequired: Optional[dict[str, set[str]]] = None + type: SchemaType | list[SchemaType] | None = None + enum: list[Any] | None = None + const: Any | None = None + multipleOf: float | None = Field(default=None, gt=0) + maximum: float | None = None + exclusiveMaximum: float | None = None + minimum: float | None = None + exclusiveMinimum: float | None = None + maxLength: int | None = Field(default=None, ge=0) + minLength: int | None = Field(default=None, ge=0) + pattern: str | None = None + maxItems: int | None = Field(default=None, ge=0) + minItems: int | None = Field(default=None, ge=0) + uniqueItems: bool | None = None + maxContains: int | None = Field(default=None, ge=0) + minContains: int | None = Field(default=None, ge=0) + maxProperties: int | None = Field(default=None, ge=0) + minProperties: int | None = Field(default=None, ge=0) + required: list[str] | None = None + dependentRequired: dict[str, set[str]] | None = None # Ref: JSON Schema Validation 2020-12: https://json-schema.org/draft/2020-12/json-schema-validation.html#name-vocabularies-for-semantic-c # Vocabularies for Semantic Content With "format" - format: Optional[str] = None + format: str | None = None # Ref: JSON Schema Validation 2020-12: https://json-schema.org/draft/2020-12/json-schema-validation.html#name-a-vocabulary-for-the-conten # A Vocabulary for the Contents of String-Encoded Data - contentEncoding: Optional[str] = None - contentMediaType: Optional[str] = None + contentEncoding: str | None = None + contentMediaType: str | None = None contentSchema: Optional["SchemaOrBool"] = None # Ref: JSON Schema Validation 2020-12: https://json-schema.org/draft/2020-12/json-schema-validation.html#name-a-vocabulary-for-basic-meta # A Vocabulary for Basic Meta-Data Annotations - title: Optional[str] = None - description: Optional[str] = None - default: Optional[Any] = None - deprecated: Optional[bool] = None - readOnly: Optional[bool] = None - writeOnly: Optional[bool] = None - examples: Optional[list[Any]] = None + title: str | None = None + description: str | None = None + default: Any | None = None + deprecated: bool | None = None + readOnly: bool | None = None + writeOnly: bool | None = None + examples: list[Any] | None = None # Ref: OpenAPI 3.1.0: https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#schema-object # Schema Object - discriminator: Optional[Discriminator] = None - xml: Optional[XML] = None - externalDocs: Optional[ExternalDocumentation] = None + discriminator: Discriminator | None = None + xml: XML | None = None + externalDocs: ExternalDocumentation | None = None example: Annotated[ - Optional[Any], + Any | None, typing_deprecated( "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, " "although still supported. Use examples instead." @@ -206,14 +206,14 @@ class Schema(BaseModelWithConfig): # Ref: https://json-schema.org/draft/2020-12/json-schema-core.html#name-json-schema-documents # A JSON Schema MUST be an object or a boolean. -SchemaOrBool = Union[Schema, bool] +SchemaOrBool = Schema | bool class Example(TypedDict, total=False): - summary: Optional[str] - description: Optional[str] - value: Optional[Any] - externalValue: Optional[AnyUrl] + summary: str | None + description: str | None + value: Any | None + externalValue: AnyUrl | None __pydantic_config__ = {"extra": "allow"} # type: ignore[misc] @@ -226,33 +226,33 @@ class ParameterInType(Enum): class Encoding(BaseModelWithConfig): - contentType: Optional[str] = None - headers: Optional[dict[str, Union["Header", Reference]]] = None - style: Optional[str] = None - explode: Optional[bool] = None - allowReserved: Optional[bool] = None + contentType: str | None = None + headers: dict[str, Union["Header", Reference]] | None = None + style: str | None = None + explode: bool | None = None + allowReserved: bool | None = None class MediaType(BaseModelWithConfig): - schema_: Optional[Union[Schema, Reference]] = Field(default=None, alias="schema") - example: Optional[Any] = None - examples: Optional[dict[str, Union[Example, Reference]]] = None - encoding: Optional[dict[str, Encoding]] = None + schema_: Schema | Reference | None = Field(default=None, alias="schema") + example: Any | None = None + examples: dict[str, Example | Reference] | None = None + encoding: dict[str, Encoding] | None = None class ParameterBase(BaseModelWithConfig): - description: Optional[str] = None - required: Optional[bool] = None - deprecated: Optional[bool] = None + description: str | None = None + required: bool | None = None + deprecated: bool | None = None # Serialization rules for simple scenarios - style: Optional[str] = None - explode: Optional[bool] = None - allowReserved: Optional[bool] = None - schema_: Optional[Union[Schema, Reference]] = Field(default=None, alias="schema") - example: Optional[Any] = None - examples: Optional[dict[str, Union[Example, Reference]]] = None + style: str | None = None + explode: bool | None = None + allowReserved: bool | None = None + schema_: Schema | Reference | None = Field(default=None, alias="schema") + example: Any | None = None + examples: dict[str, Example | Reference] | None = None # Serialization rules for more complex scenarios - content: Optional[dict[str, MediaType]] = None + content: dict[str, MediaType] | None = None class Parameter(ParameterBase): @@ -265,57 +265,57 @@ class Header(ParameterBase): class RequestBody(BaseModelWithConfig): - description: Optional[str] = None + description: str | None = None content: dict[str, MediaType] - required: Optional[bool] = None + required: bool | None = None class Link(BaseModelWithConfig): - operationRef: Optional[str] = None - operationId: Optional[str] = None - parameters: Optional[dict[str, Union[Any, str]]] = None - requestBody: Optional[Union[Any, str]] = None - description: Optional[str] = None - server: Optional[Server] = None + operationRef: str | None = None + operationId: str | None = None + parameters: dict[str, Any | str] | None = None + requestBody: Any | str | None = None + description: str | None = None + server: Server | None = None class Response(BaseModelWithConfig): description: str - headers: Optional[dict[str, Union[Header, Reference]]] = None - content: Optional[dict[str, MediaType]] = None - links: Optional[dict[str, Union[Link, Reference]]] = None + headers: dict[str, Header | Reference] | None = None + content: dict[str, MediaType] | None = None + links: dict[str, Link | Reference] | None = None class Operation(BaseModelWithConfig): - tags: Optional[list[str]] = None - summary: Optional[str] = None - description: Optional[str] = None - externalDocs: Optional[ExternalDocumentation] = None - operationId: Optional[str] = None - parameters: Optional[list[Union[Parameter, Reference]]] = None - requestBody: Optional[Union[RequestBody, Reference]] = None + tags: list[str] | None = None + summary: str | None = None + description: str | None = None + externalDocs: ExternalDocumentation | None = None + operationId: str | None = None + parameters: list[Parameter | Reference] | None = None + requestBody: RequestBody | Reference | None = None # Using Any for Specification Extensions - responses: Optional[dict[str, Union[Response, Any]]] = None - callbacks: Optional[dict[str, Union[dict[str, "PathItem"], Reference]]] = None - deprecated: Optional[bool] = None - security: Optional[list[dict[str, list[str]]]] = None - servers: Optional[list[Server]] = None + responses: dict[str, Response | Any] | None = None + callbacks: dict[str, dict[str, "PathItem"] | Reference] | None = None + deprecated: bool | None = None + security: list[dict[str, list[str]]] | None = None + servers: list[Server] | None = None class PathItem(BaseModelWithConfig): - ref: Optional[str] = Field(default=None, alias="$ref") - summary: Optional[str] = None - description: Optional[str] = None - get: Optional[Operation] = None - put: Optional[Operation] = None - post: Optional[Operation] = None - delete: Optional[Operation] = None - options: Optional[Operation] = None - head: Optional[Operation] = None - patch: Optional[Operation] = None - trace: Optional[Operation] = None - servers: Optional[list[Server]] = None - parameters: Optional[list[Union[Parameter, Reference]]] = None + ref: str | None = Field(default=None, alias="$ref") + summary: str | None = None + description: str | None = None + get: Operation | None = None + put: Operation | None = None + post: Operation | None = None + delete: Operation | None = None + options: Operation | None = None + head: Operation | None = None + patch: Operation | None = None + trace: Operation | None = None + servers: list[Server] | None = None + parameters: list[Parameter | Reference] | None = None class SecuritySchemeType(Enum): @@ -327,7 +327,7 @@ class SecuritySchemeType(Enum): class SecurityBase(BaseModelWithConfig): type_: SecuritySchemeType = Field(alias="type") - description: Optional[str] = None + description: str | None = None class APIKeyIn(Enum): @@ -349,11 +349,11 @@ class HTTPBase(SecurityBase): class HTTPBearer(HTTPBase): scheme: Literal["bearer"] = "bearer" - bearerFormat: Optional[str] = None + bearerFormat: str | None = None class OAuthFlow(BaseModelWithConfig): - refreshUrl: Optional[str] = None + refreshUrl: str | None = None scopes: dict[str, str] = {} @@ -375,10 +375,10 @@ class OAuthFlowAuthorizationCode(OAuthFlow): class OAuthFlows(BaseModelWithConfig): - implicit: Optional[OAuthFlowImplicit] = None - password: Optional[OAuthFlowPassword] = None - clientCredentials: Optional[OAuthFlowClientCredentials] = None - authorizationCode: Optional[OAuthFlowAuthorizationCode] = None + implicit: OAuthFlowImplicit | None = None + password: OAuthFlowPassword | None = None + clientCredentials: OAuthFlowClientCredentials | None = None + authorizationCode: OAuthFlowAuthorizationCode | None = None class OAuth2(SecurityBase): @@ -393,41 +393,41 @@ class OpenIdConnect(SecurityBase): openIdConnectUrl: str -SecurityScheme = Union[APIKey, HTTPBase, OAuth2, OpenIdConnect, HTTPBearer] +SecurityScheme = APIKey | HTTPBase | OAuth2 | OpenIdConnect | HTTPBearer class Components(BaseModelWithConfig): - schemas: Optional[dict[str, Union[Schema, Reference]]] = None - responses: Optional[dict[str, Union[Response, Reference]]] = None - parameters: Optional[dict[str, Union[Parameter, Reference]]] = None - examples: Optional[dict[str, Union[Example, Reference]]] = None - requestBodies: Optional[dict[str, Union[RequestBody, Reference]]] = None - headers: Optional[dict[str, Union[Header, Reference]]] = None - securitySchemes: Optional[dict[str, Union[SecurityScheme, Reference]]] = None - links: Optional[dict[str, Union[Link, Reference]]] = None + schemas: dict[str, Schema | Reference] | None = None + responses: dict[str, Response | Reference] | None = None + parameters: dict[str, Parameter | Reference] | None = None + examples: dict[str, Example | Reference] | None = None + requestBodies: dict[str, RequestBody | Reference] | None = None + headers: dict[str, Header | Reference] | None = None + securitySchemes: dict[str, SecurityScheme | Reference] | None = None + links: dict[str, Link | Reference] | None = None # Using Any for Specification Extensions - callbacks: Optional[dict[str, Union[dict[str, PathItem], Reference, Any]]] = None - pathItems: Optional[dict[str, Union[PathItem, Reference]]] = None + callbacks: dict[str, dict[str, PathItem] | Reference | Any] | None = None + pathItems: dict[str, PathItem | Reference] | None = None class Tag(BaseModelWithConfig): name: str - description: Optional[str] = None - externalDocs: Optional[ExternalDocumentation] = None + description: str | None = None + externalDocs: ExternalDocumentation | None = None class OpenAPI(BaseModelWithConfig): openapi: str info: Info - jsonSchemaDialect: Optional[str] = None - servers: Optional[list[Server]] = None + jsonSchemaDialect: str | None = None + servers: list[Server] | None = None # Using Any for Specification Extensions - paths: Optional[dict[str, Union[PathItem, Any]]] = None - webhooks: Optional[dict[str, Union[PathItem, Reference]]] = None - components: Optional[Components] = None - security: Optional[list[dict[str, list[str]]]] = None - tags: Optional[list[Tag]] = None - externalDocs: Optional[ExternalDocumentation] = None + paths: dict[str, PathItem | Any] | None = None + webhooks: dict[str, PathItem | Reference] | None = None + components: Components | None = None + security: list[dict[str, list[str]]] | None = None + tags: list[Tag] | None = None + externalDocs: ExternalDocumentation | None = None Schema.model_rebuild() diff --git a/fastapi/openapi/utils.py b/fastapi/openapi/utils.py index bcad0be75..812003aee 100644 --- a/fastapi/openapi/utils.py +++ b/fastapi/openapi/utils.py @@ -3,7 +3,7 @@ import http.client import inspect import warnings from collections.abc import Sequence -from typing import Any, Optional, Union, cast +from typing import Any, Literal, cast from fastapi import routing from fastapi._compat import ( @@ -38,7 +38,6 @@ from fastapi.utils import ( from pydantic import BaseModel from starlette.responses import JSONResponse from starlette.routing import BaseRoute -from typing_extensions import Literal validation_error_definition = { "title": "ValidationError", @@ -180,13 +179,13 @@ def _get_openapi_operation_parameters( def get_openapi_operation_request_body( *, - body_field: Optional[ModelField], + body_field: ModelField | None, model_name_map: ModelNameMap, field_mapping: dict[ tuple[ModelField, Literal["validation", "serialization"]], dict[str, Any] ], separate_input_output_schemas: bool = True, -) -> Optional[dict[str, Any]]: +) -> dict[str, Any] | None: if not body_field: return None assert isinstance(body_field, ModelField) @@ -279,7 +278,7 @@ def get_openapi_path( else: current_response_class = route.response_class assert current_response_class, "A response class is needed to generate OpenAPI" - route_response_media_type: Optional[str] = current_response_class.media_type + route_response_media_type: str | None = current_response_class.media_type if route.include_in_schema: for method in route.methods: operation = get_openapi_operation_metadata( @@ -393,7 +392,7 @@ def get_openapi_path( "An additional response must be a dict" ) field = route.response_fields.get(additional_status_code) - additional_field_schema: Optional[dict[str, Any]] = None + additional_field_schema: dict[str, Any] | None = None if field: additional_field_schema = get_schema_from_model_field( field=field, @@ -408,7 +407,7 @@ def get_openapi_path( .setdefault("schema", {}) ) deep_dict_update(additional_schema, additional_field_schema) - status_text: Optional[str] = status_code_ranges.get( + status_text: str | None = status_code_ranges.get( str(additional_status_code).upper() ) or http.client.responses.get(int(additional_status_code)) description = ( @@ -482,17 +481,17 @@ def get_openapi( title: str, version: str, openapi_version: str = "3.1.0", - summary: Optional[str] = None, - description: Optional[str] = None, + summary: str | None = None, + description: str | None = None, routes: Sequence[BaseRoute], - webhooks: Optional[Sequence[BaseRoute]] = None, - tags: Optional[list[dict[str, Any]]] = None, - servers: Optional[list[dict[str, Union[str, Any]]]] = None, - terms_of_service: Optional[str] = None, - contact: Optional[dict[str, Union[str, Any]]] = None, - license_info: Optional[dict[str, Union[str, Any]]] = None, + webhooks: Sequence[BaseRoute] | None = None, + tags: list[dict[str, Any]] | None = None, + servers: list[dict[str, str | Any]] | None = None, + terms_of_service: str | None = None, + contact: dict[str, str | Any] | None = None, + license_info: dict[str, str | Any] | None = None, separate_input_output_schemas: bool = True, - external_docs: Optional[dict[str, Any]] = None, + external_docs: dict[str, Any] | None = None, ) -> dict[str, Any]: info: dict[str, Any] = {"title": title, "version": version} if summary: diff --git a/fastapi/param_functions.py b/fastapi/param_functions.py index 9bd92be4c..4be504f43 100644 --- a/fastapi/param_functions.py +++ b/fastapi/param_functions.py @@ -1,12 +1,12 @@ -from collections.abc import Sequence -from typing import Annotated, Any, Callable, Optional, Union +from collections.abc import Callable, Sequence +from typing import Annotated, Any, Literal from annotated_doc import Doc from fastapi import params from fastapi._compat import Undefined from fastapi.openapi.models import Example from pydantic import AliasChoices, AliasPath -from typing_extensions import Literal, deprecated +from typing_extensions import deprecated _Unset: Any = Undefined @@ -25,7 +25,7 @@ def Path( # noqa: N802 ] = ..., *, default_factory: Annotated[ - Union[Callable[[], Any], None], + Callable[[], Any] | None, Doc( """ A callable to generate the default value. @@ -36,7 +36,7 @@ def Path( # noqa: N802 ), ] = _Unset, alias: Annotated[ - Optional[str], + str | None, Doc( """ An alternative name for the parameter field. @@ -48,7 +48,7 @@ def Path( # noqa: N802 ), ] = None, alias_priority: Annotated[ - Union[int, None], + int | None, Doc( """ Priority of the alias. This affects whether an alias generator is used. @@ -56,7 +56,7 @@ def Path( # noqa: N802 ), ] = _Unset, validation_alias: Annotated[ - Union[str, AliasPath, AliasChoices, None], + str | AliasPath | AliasChoices | None, Doc( """ 'Whitelist' validation step. The parameter field will be the single one @@ -65,7 +65,7 @@ def Path( # noqa: N802 ), ] = None, serialization_alias: Annotated[ - Union[str, None], + str | None, Doc( """ 'Blacklist' validation step. The vanilla parameter field will be the @@ -75,7 +75,7 @@ def Path( # noqa: N802 ), ] = None, title: Annotated[ - Optional[str], + str | None, Doc( """ Human-readable title. @@ -86,7 +86,7 @@ def Path( # noqa: N802 ), ] = None, description: Annotated[ - Optional[str], + str | None, Doc( """ Human-readable description. @@ -94,7 +94,7 @@ def Path( # noqa: N802 ), ] = None, gt: Annotated[ - Optional[float], + float | None, Doc( """ Greater than. If set, value must be greater than this. Only applicable to @@ -106,7 +106,7 @@ def Path( # noqa: N802 ), ] = None, ge: Annotated[ - Optional[float], + float | None, Doc( """ Greater than or equal. If set, value must be greater than or equal to @@ -118,7 +118,7 @@ def Path( # noqa: N802 ), ] = None, lt: Annotated[ - Optional[float], + float | None, Doc( """ Less than. If set, value must be less than this. Only applicable to numbers. @@ -129,7 +129,7 @@ def Path( # noqa: N802 ), ] = None, le: Annotated[ - Optional[float], + float | None, Doc( """ Less than or equal. If set, value must be less than or equal to this. @@ -141,7 +141,7 @@ def Path( # noqa: N802 ), ] = None, min_length: Annotated[ - Optional[int], + int | None, Doc( """ Minimum length for strings. @@ -149,7 +149,7 @@ def Path( # noqa: N802 ), ] = None, max_length: Annotated[ - Optional[int], + int | None, Doc( """ Maximum length for strings. @@ -157,7 +157,7 @@ def Path( # noqa: N802 ), ] = None, pattern: Annotated[ - Optional[str], + str | None, Doc( """ RegEx pattern for strings. @@ -165,7 +165,7 @@ def Path( # noqa: N802 ), ] = None, regex: Annotated[ - Optional[str], + str | None, Doc( """ RegEx pattern for strings. @@ -176,7 +176,7 @@ def Path( # noqa: N802 ), ] = None, discriminator: Annotated[ - Union[str, None], + str | None, Doc( """ Parameter field name for discriminating the type in a tagged union. @@ -184,7 +184,7 @@ def Path( # noqa: N802 ), ] = None, strict: Annotated[ - Union[bool, None], + bool | None, Doc( """ If `True`, strict validation is applied to the field. @@ -192,7 +192,7 @@ def Path( # noqa: N802 ), ] = _Unset, multiple_of: Annotated[ - Union[float, None], + float | None, Doc( """ Value must be a multiple of this. Only applicable to numbers. @@ -200,7 +200,7 @@ def Path( # noqa: N802 ), ] = _Unset, allow_inf_nan: Annotated[ - Union[bool, None], + bool | None, Doc( """ Allow `inf`, `-inf`, `nan`. Only applicable to numbers. @@ -208,7 +208,7 @@ def Path( # noqa: N802 ), ] = _Unset, max_digits: Annotated[ - Union[int, None], + int | None, Doc( """ Maximum number of allow digits for strings. @@ -216,7 +216,7 @@ def Path( # noqa: N802 ), ] = _Unset, decimal_places: Annotated[ - Union[int, None], + int | None, Doc( """ Maximum number of decimal places allowed for numbers. @@ -224,7 +224,7 @@ def Path( # noqa: N802 ), ] = _Unset, examples: Annotated[ - Optional[list[Any]], + list[Any] | None, Doc( """ Example values for this field. @@ -235,14 +235,14 @@ def Path( # noqa: N802 ), ] = None, example: Annotated[ - Optional[Any], + Any | None, deprecated( "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, " "although still supported. Use examples instead." ), ] = _Unset, openapi_examples: Annotated[ - Optional[dict[str, Example]], + dict[str, Example] | None, Doc( """ OpenAPI-specific examples. @@ -259,7 +259,7 @@ def Path( # noqa: N802 ), ] = None, deprecated: Annotated[ - Union[deprecated, str, bool, None], + deprecated | str | bool | None, Doc( """ Mark this parameter field as deprecated. @@ -280,7 +280,7 @@ def Path( # noqa: N802 ), ] = True, json_schema_extra: Annotated[ - Union[dict[str, Any], None], + dict[str, Any] | None, Doc( """ Any additional JSON schema data. @@ -369,7 +369,7 @@ def Query( # noqa: N802 ] = Undefined, *, default_factory: Annotated[ - Union[Callable[[], Any], None], + Callable[[], Any] | None, Doc( """ A callable to generate the default value. @@ -380,7 +380,7 @@ def Query( # noqa: N802 ), ] = _Unset, alias: Annotated[ - Optional[str], + str | None, Doc( """ An alternative name for the parameter field. @@ -395,7 +395,7 @@ def Query( # noqa: N802 ), ] = None, alias_priority: Annotated[ - Union[int, None], + int | None, Doc( """ Priority of the alias. This affects whether an alias generator is used. @@ -403,7 +403,7 @@ def Query( # noqa: N802 ), ] = _Unset, validation_alias: Annotated[ - Union[str, AliasPath, AliasChoices, None], + str | AliasPath | AliasChoices | None, Doc( """ 'Whitelist' validation step. The parameter field will be the single one @@ -412,7 +412,7 @@ def Query( # noqa: N802 ), ] = None, serialization_alias: Annotated[ - Union[str, None], + str | None, Doc( """ 'Blacklist' validation step. The vanilla parameter field will be the @@ -422,7 +422,7 @@ def Query( # noqa: N802 ), ] = None, title: Annotated[ - Optional[str], + str | None, Doc( """ Human-readable title. @@ -433,7 +433,7 @@ def Query( # noqa: N802 ), ] = None, description: Annotated[ - Optional[str], + str | None, Doc( """ Human-readable description. @@ -444,7 +444,7 @@ def Query( # noqa: N802 ), ] = None, gt: Annotated[ - Optional[float], + float | None, Doc( """ Greater than. If set, value must be greater than this. Only applicable to @@ -456,7 +456,7 @@ def Query( # noqa: N802 ), ] = None, ge: Annotated[ - Optional[float], + float | None, Doc( """ Greater than or equal. If set, value must be greater than or equal to @@ -468,7 +468,7 @@ def Query( # noqa: N802 ), ] = None, lt: Annotated[ - Optional[float], + float | None, Doc( """ Less than. If set, value must be less than this. Only applicable to numbers. @@ -479,7 +479,7 @@ def Query( # noqa: N802 ), ] = None, le: Annotated[ - Optional[float], + float | None, Doc( """ Less than or equal. If set, value must be less than or equal to this. @@ -491,7 +491,7 @@ def Query( # noqa: N802 ), ] = None, min_length: Annotated[ - Optional[int], + int | None, Doc( """ Minimum length for strings. @@ -502,7 +502,7 @@ def Query( # noqa: N802 ), ] = None, max_length: Annotated[ - Optional[int], + int | None, Doc( """ Maximum length for strings. @@ -513,7 +513,7 @@ def Query( # noqa: N802 ), ] = None, pattern: Annotated[ - Optional[str], + str | None, Doc( """ RegEx pattern for strings. @@ -524,7 +524,7 @@ def Query( # noqa: N802 ), ] = None, regex: Annotated[ - Optional[str], + str | None, Doc( """ RegEx pattern for strings. @@ -535,7 +535,7 @@ def Query( # noqa: N802 ), ] = None, discriminator: Annotated[ - Union[str, None], + str | None, Doc( """ Parameter field name for discriminating the type in a tagged union. @@ -543,7 +543,7 @@ def Query( # noqa: N802 ), ] = None, strict: Annotated[ - Union[bool, None], + bool | None, Doc( """ If `True`, strict validation is applied to the field. @@ -551,7 +551,7 @@ def Query( # noqa: N802 ), ] = _Unset, multiple_of: Annotated[ - Union[float, None], + float | None, Doc( """ Value must be a multiple of this. Only applicable to numbers. @@ -559,7 +559,7 @@ def Query( # noqa: N802 ), ] = _Unset, allow_inf_nan: Annotated[ - Union[bool, None], + bool | None, Doc( """ Allow `inf`, `-inf`, `nan`. Only applicable to numbers. @@ -567,7 +567,7 @@ def Query( # noqa: N802 ), ] = _Unset, max_digits: Annotated[ - Union[int, None], + int | None, Doc( """ Maximum number of allow digits for strings. @@ -575,7 +575,7 @@ def Query( # noqa: N802 ), ] = _Unset, decimal_places: Annotated[ - Union[int, None], + int | None, Doc( """ Maximum number of decimal places allowed for numbers. @@ -583,7 +583,7 @@ def Query( # noqa: N802 ), ] = _Unset, examples: Annotated[ - Optional[list[Any]], + list[Any] | None, Doc( """ Example values for this field. @@ -594,14 +594,14 @@ def Query( # noqa: N802 ), ] = None, example: Annotated[ - Optional[Any], + Any | None, deprecated( "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, " "although still supported. Use examples instead." ), ] = _Unset, openapi_examples: Annotated[ - Optional[dict[str, Example]], + dict[str, Example] | None, Doc( """ OpenAPI-specific examples. @@ -618,7 +618,7 @@ def Query( # noqa: N802 ), ] = None, deprecated: Annotated[ - Union[deprecated, str, bool, None], + deprecated | str | bool | None, Doc( """ Mark this parameter field as deprecated. @@ -645,7 +645,7 @@ def Query( # noqa: N802 ), ] = True, json_schema_extra: Annotated[ - Union[dict[str, Any], None], + dict[str, Any] | None, Doc( """ Any additional JSON schema data. @@ -710,7 +710,7 @@ def Header( # noqa: N802 ] = Undefined, *, default_factory: Annotated[ - Union[Callable[[], Any], None], + Callable[[], Any] | None, Doc( """ A callable to generate the default value. @@ -721,7 +721,7 @@ def Header( # noqa: N802 ), ] = _Unset, alias: Annotated[ - Optional[str], + str | None, Doc( """ An alternative name for the parameter field. @@ -733,7 +733,7 @@ def Header( # noqa: N802 ), ] = None, alias_priority: Annotated[ - Union[int, None], + int | None, Doc( """ Priority of the alias. This affects whether an alias generator is used. @@ -741,7 +741,7 @@ def Header( # noqa: N802 ), ] = _Unset, validation_alias: Annotated[ - Union[str, AliasPath, AliasChoices, None], + str | AliasPath | AliasChoices | None, Doc( """ 'Whitelist' validation step. The parameter field will be the single one @@ -750,7 +750,7 @@ def Header( # noqa: N802 ), ] = None, serialization_alias: Annotated[ - Union[str, None], + str | None, Doc( """ 'Blacklist' validation step. The vanilla parameter field will be the @@ -771,7 +771,7 @@ def Header( # noqa: N802 ), ] = True, title: Annotated[ - Optional[str], + str | None, Doc( """ Human-readable title. @@ -779,7 +779,7 @@ def Header( # noqa: N802 ), ] = None, description: Annotated[ - Optional[str], + str | None, Doc( """ Human-readable description. @@ -787,7 +787,7 @@ def Header( # noqa: N802 ), ] = None, gt: Annotated[ - Optional[float], + float | None, Doc( """ Greater than. If set, value must be greater than this. Only applicable to @@ -796,7 +796,7 @@ def Header( # noqa: N802 ), ] = None, ge: Annotated[ - Optional[float], + float | None, Doc( """ Greater than or equal. If set, value must be greater than or equal to @@ -805,7 +805,7 @@ def Header( # noqa: N802 ), ] = None, lt: Annotated[ - Optional[float], + float | None, Doc( """ Less than. If set, value must be less than this. Only applicable to numbers. @@ -813,7 +813,7 @@ def Header( # noqa: N802 ), ] = None, le: Annotated[ - Optional[float], + float | None, Doc( """ Less than or equal. If set, value must be less than or equal to this. @@ -822,7 +822,7 @@ def Header( # noqa: N802 ), ] = None, min_length: Annotated[ - Optional[int], + int | None, Doc( """ Minimum length for strings. @@ -830,7 +830,7 @@ def Header( # noqa: N802 ), ] = None, max_length: Annotated[ - Optional[int], + int | None, Doc( """ Maximum length for strings. @@ -838,7 +838,7 @@ def Header( # noqa: N802 ), ] = None, pattern: Annotated[ - Optional[str], + str | None, Doc( """ RegEx pattern for strings. @@ -846,7 +846,7 @@ def Header( # noqa: N802 ), ] = None, regex: Annotated[ - Optional[str], + str | None, Doc( """ RegEx pattern for strings. @@ -857,7 +857,7 @@ def Header( # noqa: N802 ), ] = None, discriminator: Annotated[ - Union[str, None], + str | None, Doc( """ Parameter field name for discriminating the type in a tagged union. @@ -865,7 +865,7 @@ def Header( # noqa: N802 ), ] = None, strict: Annotated[ - Union[bool, None], + bool | None, Doc( """ If `True`, strict validation is applied to the field. @@ -873,7 +873,7 @@ def Header( # noqa: N802 ), ] = _Unset, multiple_of: Annotated[ - Union[float, None], + float | None, Doc( """ Value must be a multiple of this. Only applicable to numbers. @@ -881,7 +881,7 @@ def Header( # noqa: N802 ), ] = _Unset, allow_inf_nan: Annotated[ - Union[bool, None], + bool | None, Doc( """ Allow `inf`, `-inf`, `nan`. Only applicable to numbers. @@ -889,7 +889,7 @@ def Header( # noqa: N802 ), ] = _Unset, max_digits: Annotated[ - Union[int, None], + int | None, Doc( """ Maximum number of allow digits for strings. @@ -897,7 +897,7 @@ def Header( # noqa: N802 ), ] = _Unset, decimal_places: Annotated[ - Union[int, None], + int | None, Doc( """ Maximum number of decimal places allowed for numbers. @@ -905,7 +905,7 @@ def Header( # noqa: N802 ), ] = _Unset, examples: Annotated[ - Optional[list[Any]], + list[Any] | None, Doc( """ Example values for this field. @@ -916,14 +916,14 @@ def Header( # noqa: N802 ), ] = None, example: Annotated[ - Optional[Any], + Any | None, deprecated( "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, " "although still supported. Use examples instead." ), ] = _Unset, openapi_examples: Annotated[ - Optional[dict[str, Example]], + dict[str, Example] | None, Doc( """ OpenAPI-specific examples. @@ -940,7 +940,7 @@ def Header( # noqa: N802 ), ] = None, deprecated: Annotated[ - Union[deprecated, str, bool, None], + deprecated | str | bool | None, Doc( """ Mark this parameter field as deprecated. @@ -961,7 +961,7 @@ def Header( # noqa: N802 ), ] = True, json_schema_extra: Annotated[ - Union[dict[str, Any], None], + dict[str, Any] | None, Doc( """ Any additional JSON schema data. @@ -1027,7 +1027,7 @@ def Cookie( # noqa: N802 ] = Undefined, *, default_factory: Annotated[ - Union[Callable[[], Any], None], + Callable[[], Any] | None, Doc( """ A callable to generate the default value. @@ -1038,7 +1038,7 @@ def Cookie( # noqa: N802 ), ] = _Unset, alias: Annotated[ - Optional[str], + str | None, Doc( """ An alternative name for the parameter field. @@ -1050,7 +1050,7 @@ def Cookie( # noqa: N802 ), ] = None, alias_priority: Annotated[ - Union[int, None], + int | None, Doc( """ Priority of the alias. This affects whether an alias generator is used. @@ -1058,7 +1058,7 @@ def Cookie( # noqa: N802 ), ] = _Unset, validation_alias: Annotated[ - Union[str, AliasPath, AliasChoices, None], + str | AliasPath | AliasChoices | None, Doc( """ 'Whitelist' validation step. The parameter field will be the single one @@ -1067,7 +1067,7 @@ def Cookie( # noqa: N802 ), ] = None, serialization_alias: Annotated[ - Union[str, None], + str | None, Doc( """ 'Blacklist' validation step. The vanilla parameter field will be the @@ -1077,7 +1077,7 @@ def Cookie( # noqa: N802 ), ] = None, title: Annotated[ - Optional[str], + str | None, Doc( """ Human-readable title. @@ -1085,7 +1085,7 @@ def Cookie( # noqa: N802 ), ] = None, description: Annotated[ - Optional[str], + str | None, Doc( """ Human-readable description. @@ -1093,7 +1093,7 @@ def Cookie( # noqa: N802 ), ] = None, gt: Annotated[ - Optional[float], + float | None, Doc( """ Greater than. If set, value must be greater than this. Only applicable to @@ -1102,7 +1102,7 @@ def Cookie( # noqa: N802 ), ] = None, ge: Annotated[ - Optional[float], + float | None, Doc( """ Greater than or equal. If set, value must be greater than or equal to @@ -1111,7 +1111,7 @@ def Cookie( # noqa: N802 ), ] = None, lt: Annotated[ - Optional[float], + float | None, Doc( """ Less than. If set, value must be less than this. Only applicable to numbers. @@ -1119,7 +1119,7 @@ def Cookie( # noqa: N802 ), ] = None, le: Annotated[ - Optional[float], + float | None, Doc( """ Less than or equal. If set, value must be less than or equal to this. @@ -1128,7 +1128,7 @@ def Cookie( # noqa: N802 ), ] = None, min_length: Annotated[ - Optional[int], + int | None, Doc( """ Minimum length for strings. @@ -1136,7 +1136,7 @@ def Cookie( # noqa: N802 ), ] = None, max_length: Annotated[ - Optional[int], + int | None, Doc( """ Maximum length for strings. @@ -1144,7 +1144,7 @@ def Cookie( # noqa: N802 ), ] = None, pattern: Annotated[ - Optional[str], + str | None, Doc( """ RegEx pattern for strings. @@ -1152,7 +1152,7 @@ def Cookie( # noqa: N802 ), ] = None, regex: Annotated[ - Optional[str], + str | None, Doc( """ RegEx pattern for strings. @@ -1163,7 +1163,7 @@ def Cookie( # noqa: N802 ), ] = None, discriminator: Annotated[ - Union[str, None], + str | None, Doc( """ Parameter field name for discriminating the type in a tagged union. @@ -1171,7 +1171,7 @@ def Cookie( # noqa: N802 ), ] = None, strict: Annotated[ - Union[bool, None], + bool | None, Doc( """ If `True`, strict validation is applied to the field. @@ -1179,7 +1179,7 @@ def Cookie( # noqa: N802 ), ] = _Unset, multiple_of: Annotated[ - Union[float, None], + float | None, Doc( """ Value must be a multiple of this. Only applicable to numbers. @@ -1187,7 +1187,7 @@ def Cookie( # noqa: N802 ), ] = _Unset, allow_inf_nan: Annotated[ - Union[bool, None], + bool | None, Doc( """ Allow `inf`, `-inf`, `nan`. Only applicable to numbers. @@ -1195,7 +1195,7 @@ def Cookie( # noqa: N802 ), ] = _Unset, max_digits: Annotated[ - Union[int, None], + int | None, Doc( """ Maximum number of allow digits for strings. @@ -1203,7 +1203,7 @@ def Cookie( # noqa: N802 ), ] = _Unset, decimal_places: Annotated[ - Union[int, None], + int | None, Doc( """ Maximum number of decimal places allowed for numbers. @@ -1211,7 +1211,7 @@ def Cookie( # noqa: N802 ), ] = _Unset, examples: Annotated[ - Optional[list[Any]], + list[Any] | None, Doc( """ Example values for this field. @@ -1222,14 +1222,14 @@ def Cookie( # noqa: N802 ), ] = None, example: Annotated[ - Optional[Any], + Any | None, deprecated( "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, " "although still supported. Use examples instead." ), ] = _Unset, openapi_examples: Annotated[ - Optional[dict[str, Example]], + dict[str, Example] | None, Doc( """ OpenAPI-specific examples. @@ -1246,7 +1246,7 @@ def Cookie( # noqa: N802 ), ] = None, deprecated: Annotated[ - Union[deprecated, str, bool, None], + deprecated | str | bool | None, Doc( """ Mark this parameter field as deprecated. @@ -1267,7 +1267,7 @@ def Cookie( # noqa: N802 ), ] = True, json_schema_extra: Annotated[ - Union[dict[str, Any], None], + dict[str, Any] | None, Doc( """ Any additional JSON schema data. @@ -1332,7 +1332,7 @@ def Body( # noqa: N802 ] = Undefined, *, default_factory: Annotated[ - Union[Callable[[], Any], None], + Callable[[], Any] | None, Doc( """ A callable to generate the default value. @@ -1343,7 +1343,7 @@ def Body( # noqa: N802 ), ] = _Unset, embed: Annotated[ - Union[bool, None], + bool | None, Doc( """ When `embed` is `True`, the parameter will be expected in a JSON body as a @@ -1366,7 +1366,7 @@ def Body( # noqa: N802 ), ] = "application/json", alias: Annotated[ - Optional[str], + str | None, Doc( """ An alternative name for the parameter field. @@ -1378,7 +1378,7 @@ def Body( # noqa: N802 ), ] = None, alias_priority: Annotated[ - Union[int, None], + int | None, Doc( """ Priority of the alias. This affects whether an alias generator is used. @@ -1386,7 +1386,7 @@ def Body( # noqa: N802 ), ] = _Unset, validation_alias: Annotated[ - Union[str, AliasPath, AliasChoices, None], + str | AliasPath | AliasChoices | None, Doc( """ 'Whitelist' validation step. The parameter field will be the single one @@ -1395,7 +1395,7 @@ def Body( # noqa: N802 ), ] = None, serialization_alias: Annotated[ - Union[str, None], + str | None, Doc( """ 'Blacklist' validation step. The vanilla parameter field will be the @@ -1405,7 +1405,7 @@ def Body( # noqa: N802 ), ] = None, title: Annotated[ - Optional[str], + str | None, Doc( """ Human-readable title. @@ -1413,7 +1413,7 @@ def Body( # noqa: N802 ), ] = None, description: Annotated[ - Optional[str], + str | None, Doc( """ Human-readable description. @@ -1421,7 +1421,7 @@ def Body( # noqa: N802 ), ] = None, gt: Annotated[ - Optional[float], + float | None, Doc( """ Greater than. If set, value must be greater than this. Only applicable to @@ -1430,7 +1430,7 @@ def Body( # noqa: N802 ), ] = None, ge: Annotated[ - Optional[float], + float | None, Doc( """ Greater than or equal. If set, value must be greater than or equal to @@ -1439,7 +1439,7 @@ def Body( # noqa: N802 ), ] = None, lt: Annotated[ - Optional[float], + float | None, Doc( """ Less than. If set, value must be less than this. Only applicable to numbers. @@ -1447,7 +1447,7 @@ def Body( # noqa: N802 ), ] = None, le: Annotated[ - Optional[float], + float | None, Doc( """ Less than or equal. If set, value must be less than or equal to this. @@ -1456,7 +1456,7 @@ def Body( # noqa: N802 ), ] = None, min_length: Annotated[ - Optional[int], + int | None, Doc( """ Minimum length for strings. @@ -1464,7 +1464,7 @@ def Body( # noqa: N802 ), ] = None, max_length: Annotated[ - Optional[int], + int | None, Doc( """ Maximum length for strings. @@ -1472,7 +1472,7 @@ def Body( # noqa: N802 ), ] = None, pattern: Annotated[ - Optional[str], + str | None, Doc( """ RegEx pattern for strings. @@ -1480,7 +1480,7 @@ def Body( # noqa: N802 ), ] = None, regex: Annotated[ - Optional[str], + str | None, Doc( """ RegEx pattern for strings. @@ -1491,7 +1491,7 @@ def Body( # noqa: N802 ), ] = None, discriminator: Annotated[ - Union[str, None], + str | None, Doc( """ Parameter field name for discriminating the type in a tagged union. @@ -1499,7 +1499,7 @@ def Body( # noqa: N802 ), ] = None, strict: Annotated[ - Union[bool, None], + bool | None, Doc( """ If `True`, strict validation is applied to the field. @@ -1507,7 +1507,7 @@ def Body( # noqa: N802 ), ] = _Unset, multiple_of: Annotated[ - Union[float, None], + float | None, Doc( """ Value must be a multiple of this. Only applicable to numbers. @@ -1515,7 +1515,7 @@ def Body( # noqa: N802 ), ] = _Unset, allow_inf_nan: Annotated[ - Union[bool, None], + bool | None, Doc( """ Allow `inf`, `-inf`, `nan`. Only applicable to numbers. @@ -1523,7 +1523,7 @@ def Body( # noqa: N802 ), ] = _Unset, max_digits: Annotated[ - Union[int, None], + int | None, Doc( """ Maximum number of allow digits for strings. @@ -1531,7 +1531,7 @@ def Body( # noqa: N802 ), ] = _Unset, decimal_places: Annotated[ - Union[int, None], + int | None, Doc( """ Maximum number of decimal places allowed for numbers. @@ -1539,7 +1539,7 @@ def Body( # noqa: N802 ), ] = _Unset, examples: Annotated[ - Optional[list[Any]], + list[Any] | None, Doc( """ Example values for this field. @@ -1550,14 +1550,14 @@ def Body( # noqa: N802 ), ] = None, example: Annotated[ - Optional[Any], + Any | None, deprecated( "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, " "although still supported. Use examples instead." ), ] = _Unset, openapi_examples: Annotated[ - Optional[dict[str, Example]], + dict[str, Example] | None, Doc( """ OpenAPI-specific examples. @@ -1574,7 +1574,7 @@ def Body( # noqa: N802 ), ] = None, deprecated: Annotated[ - Union[deprecated, str, bool, None], + deprecated | str | bool | None, Doc( """ Mark this parameter field as deprecated. @@ -1595,7 +1595,7 @@ def Body( # noqa: N802 ), ] = True, json_schema_extra: Annotated[ - Union[dict[str, Any], None], + dict[str, Any] | None, Doc( """ Any additional JSON schema data. @@ -1662,7 +1662,7 @@ def Form( # noqa: N802 ] = Undefined, *, default_factory: Annotated[ - Union[Callable[[], Any], None], + Callable[[], Any] | None, Doc( """ A callable to generate the default value. @@ -1682,7 +1682,7 @@ def Form( # noqa: N802 ), ] = "application/x-www-form-urlencoded", alias: Annotated[ - Optional[str], + str | None, Doc( """ An alternative name for the parameter field. @@ -1694,7 +1694,7 @@ def Form( # noqa: N802 ), ] = None, alias_priority: Annotated[ - Union[int, None], + int | None, Doc( """ Priority of the alias. This affects whether an alias generator is used. @@ -1702,7 +1702,7 @@ def Form( # noqa: N802 ), ] = _Unset, validation_alias: Annotated[ - Union[str, AliasPath, AliasChoices, None], + str | AliasPath | AliasChoices | None, Doc( """ 'Whitelist' validation step. The parameter field will be the single one @@ -1711,7 +1711,7 @@ def Form( # noqa: N802 ), ] = None, serialization_alias: Annotated[ - Union[str, None], + str | None, Doc( """ 'Blacklist' validation step. The vanilla parameter field will be the @@ -1721,7 +1721,7 @@ def Form( # noqa: N802 ), ] = None, title: Annotated[ - Optional[str], + str | None, Doc( """ Human-readable title. @@ -1729,7 +1729,7 @@ def Form( # noqa: N802 ), ] = None, description: Annotated[ - Optional[str], + str | None, Doc( """ Human-readable description. @@ -1737,7 +1737,7 @@ def Form( # noqa: N802 ), ] = None, gt: Annotated[ - Optional[float], + float | None, Doc( """ Greater than. If set, value must be greater than this. Only applicable to @@ -1746,7 +1746,7 @@ def Form( # noqa: N802 ), ] = None, ge: Annotated[ - Optional[float], + float | None, Doc( """ Greater than or equal. If set, value must be greater than or equal to @@ -1755,7 +1755,7 @@ def Form( # noqa: N802 ), ] = None, lt: Annotated[ - Optional[float], + float | None, Doc( """ Less than. If set, value must be less than this. Only applicable to numbers. @@ -1763,7 +1763,7 @@ def Form( # noqa: N802 ), ] = None, le: Annotated[ - Optional[float], + float | None, Doc( """ Less than or equal. If set, value must be less than or equal to this. @@ -1772,7 +1772,7 @@ def Form( # noqa: N802 ), ] = None, min_length: Annotated[ - Optional[int], + int | None, Doc( """ Minimum length for strings. @@ -1780,7 +1780,7 @@ def Form( # noqa: N802 ), ] = None, max_length: Annotated[ - Optional[int], + int | None, Doc( """ Maximum length for strings. @@ -1788,7 +1788,7 @@ def Form( # noqa: N802 ), ] = None, pattern: Annotated[ - Optional[str], + str | None, Doc( """ RegEx pattern for strings. @@ -1796,7 +1796,7 @@ def Form( # noqa: N802 ), ] = None, regex: Annotated[ - Optional[str], + str | None, Doc( """ RegEx pattern for strings. @@ -1807,7 +1807,7 @@ def Form( # noqa: N802 ), ] = None, discriminator: Annotated[ - Union[str, None], + str | None, Doc( """ Parameter field name for discriminating the type in a tagged union. @@ -1815,7 +1815,7 @@ def Form( # noqa: N802 ), ] = None, strict: Annotated[ - Union[bool, None], + bool | None, Doc( """ If `True`, strict validation is applied to the field. @@ -1823,7 +1823,7 @@ def Form( # noqa: N802 ), ] = _Unset, multiple_of: Annotated[ - Union[float, None], + float | None, Doc( """ Value must be a multiple of this. Only applicable to numbers. @@ -1831,7 +1831,7 @@ def Form( # noqa: N802 ), ] = _Unset, allow_inf_nan: Annotated[ - Union[bool, None], + bool | None, Doc( """ Allow `inf`, `-inf`, `nan`. Only applicable to numbers. @@ -1839,7 +1839,7 @@ def Form( # noqa: N802 ), ] = _Unset, max_digits: Annotated[ - Union[int, None], + int | None, Doc( """ Maximum number of allow digits for strings. @@ -1847,7 +1847,7 @@ def Form( # noqa: N802 ), ] = _Unset, decimal_places: Annotated[ - Union[int, None], + int | None, Doc( """ Maximum number of decimal places allowed for numbers. @@ -1855,7 +1855,7 @@ def Form( # noqa: N802 ), ] = _Unset, examples: Annotated[ - Optional[list[Any]], + list[Any] | None, Doc( """ Example values for this field. @@ -1866,14 +1866,14 @@ def Form( # noqa: N802 ), ] = None, example: Annotated[ - Optional[Any], + Any | None, deprecated( "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, " "although still supported. Use examples instead." ), ] = _Unset, openapi_examples: Annotated[ - Optional[dict[str, Example]], + dict[str, Example] | None, Doc( """ OpenAPI-specific examples. @@ -1890,7 +1890,7 @@ def Form( # noqa: N802 ), ] = None, deprecated: Annotated[ - Union[deprecated, str, bool, None], + deprecated | str | bool | None, Doc( """ Mark this parameter field as deprecated. @@ -1911,7 +1911,7 @@ def Form( # noqa: N802 ), ] = True, json_schema_extra: Annotated[ - Union[dict[str, Any], None], + dict[str, Any] | None, Doc( """ Any additional JSON schema data. @@ -1977,7 +1977,7 @@ def File( # noqa: N802 ] = Undefined, *, default_factory: Annotated[ - Union[Callable[[], Any], None], + Callable[[], Any] | None, Doc( """ A callable to generate the default value. @@ -1997,7 +1997,7 @@ def File( # noqa: N802 ), ] = "multipart/form-data", alias: Annotated[ - Optional[str], + str | None, Doc( """ An alternative name for the parameter field. @@ -2009,7 +2009,7 @@ def File( # noqa: N802 ), ] = None, alias_priority: Annotated[ - Union[int, None], + int | None, Doc( """ Priority of the alias. This affects whether an alias generator is used. @@ -2017,7 +2017,7 @@ def File( # noqa: N802 ), ] = _Unset, validation_alias: Annotated[ - Union[str, AliasPath, AliasChoices, None], + str | AliasPath | AliasChoices | None, Doc( """ 'Whitelist' validation step. The parameter field will be the single one @@ -2026,7 +2026,7 @@ def File( # noqa: N802 ), ] = None, serialization_alias: Annotated[ - Union[str, None], + str | None, Doc( """ 'Blacklist' validation step. The vanilla parameter field will be the @@ -2036,7 +2036,7 @@ def File( # noqa: N802 ), ] = None, title: Annotated[ - Optional[str], + str | None, Doc( """ Human-readable title. @@ -2044,7 +2044,7 @@ def File( # noqa: N802 ), ] = None, description: Annotated[ - Optional[str], + str | None, Doc( """ Human-readable description. @@ -2052,7 +2052,7 @@ def File( # noqa: N802 ), ] = None, gt: Annotated[ - Optional[float], + float | None, Doc( """ Greater than. If set, value must be greater than this. Only applicable to @@ -2061,7 +2061,7 @@ def File( # noqa: N802 ), ] = None, ge: Annotated[ - Optional[float], + float | None, Doc( """ Greater than or equal. If set, value must be greater than or equal to @@ -2070,7 +2070,7 @@ def File( # noqa: N802 ), ] = None, lt: Annotated[ - Optional[float], + float | None, Doc( """ Less than. If set, value must be less than this. Only applicable to numbers. @@ -2078,7 +2078,7 @@ def File( # noqa: N802 ), ] = None, le: Annotated[ - Optional[float], + float | None, Doc( """ Less than or equal. If set, value must be less than or equal to this. @@ -2087,7 +2087,7 @@ def File( # noqa: N802 ), ] = None, min_length: Annotated[ - Optional[int], + int | None, Doc( """ Minimum length for strings. @@ -2095,7 +2095,7 @@ def File( # noqa: N802 ), ] = None, max_length: Annotated[ - Optional[int], + int | None, Doc( """ Maximum length for strings. @@ -2103,7 +2103,7 @@ def File( # noqa: N802 ), ] = None, pattern: Annotated[ - Optional[str], + str | None, Doc( """ RegEx pattern for strings. @@ -2111,7 +2111,7 @@ def File( # noqa: N802 ), ] = None, regex: Annotated[ - Optional[str], + str | None, Doc( """ RegEx pattern for strings. @@ -2122,7 +2122,7 @@ def File( # noqa: N802 ), ] = None, discriminator: Annotated[ - Union[str, None], + str | None, Doc( """ Parameter field name for discriminating the type in a tagged union. @@ -2130,7 +2130,7 @@ def File( # noqa: N802 ), ] = None, strict: Annotated[ - Union[bool, None], + bool | None, Doc( """ If `True`, strict validation is applied to the field. @@ -2138,7 +2138,7 @@ def File( # noqa: N802 ), ] = _Unset, multiple_of: Annotated[ - Union[float, None], + float | None, Doc( """ Value must be a multiple of this. Only applicable to numbers. @@ -2146,7 +2146,7 @@ def File( # noqa: N802 ), ] = _Unset, allow_inf_nan: Annotated[ - Union[bool, None], + bool | None, Doc( """ Allow `inf`, `-inf`, `nan`. Only applicable to numbers. @@ -2154,7 +2154,7 @@ def File( # noqa: N802 ), ] = _Unset, max_digits: Annotated[ - Union[int, None], + int | None, Doc( """ Maximum number of allow digits for strings. @@ -2162,7 +2162,7 @@ def File( # noqa: N802 ), ] = _Unset, decimal_places: Annotated[ - Union[int, None], + int | None, Doc( """ Maximum number of decimal places allowed for numbers. @@ -2170,7 +2170,7 @@ def File( # noqa: N802 ), ] = _Unset, examples: Annotated[ - Optional[list[Any]], + list[Any] | None, Doc( """ Example values for this field. @@ -2181,14 +2181,14 @@ def File( # noqa: N802 ), ] = None, example: Annotated[ - Optional[Any], + Any | None, deprecated( "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, " "although still supported. Use examples instead." ), ] = _Unset, openapi_examples: Annotated[ - Optional[dict[str, Example]], + dict[str, Example] | None, Doc( """ OpenAPI-specific examples. @@ -2205,7 +2205,7 @@ def File( # noqa: N802 ), ] = None, deprecated: Annotated[ - Union[deprecated, str, bool, None], + deprecated | str | bool | None, Doc( """ Mark this parameter field as deprecated. @@ -2226,7 +2226,7 @@ def File( # noqa: N802 ), ] = True, json_schema_extra: Annotated[ - Union[dict[str, Any], None], + dict[str, Any] | None, Doc( """ Any additional JSON schema data. @@ -2283,7 +2283,7 @@ def File( # noqa: N802 def Depends( # noqa: N802 dependency: Annotated[ - Optional[Callable[..., Any]], + Callable[..., Any] | None, Doc( """ A "dependable" callable (like a function). @@ -2315,7 +2315,7 @@ def Depends( # noqa: N802 ), ] = True, scope: Annotated[ - Union[Literal["function", "request"], None], + Literal["function", "request"] | None, Doc( """ Mainly for dependencies with `yield`, define when the dependency function @@ -2372,7 +2372,7 @@ def Depends( # noqa: N802 def Security( # noqa: N802 dependency: Annotated[ - Optional[Callable[..., Any]], + Callable[..., Any] | None, Doc( """ A "dependable" callable (like a function). @@ -2387,7 +2387,7 @@ def Security( # noqa: N802 ] = None, *, scopes: Annotated[ - Optional[Sequence[str]], + Sequence[str] | None, Doc( """ OAuth2 scopes required for the *path operation* that uses this Security diff --git a/fastapi/params.py b/fastapi/params.py index 72e797f83..68f987081 100644 --- a/fastapi/params.py +++ b/fastapi/params.py @@ -1,14 +1,14 @@ import warnings -from collections.abc import Sequence +from collections.abc import Callable, Sequence from dataclasses import dataclass from enum import Enum -from typing import Annotated, Any, Callable, Optional, Union +from typing import Annotated, Any, Literal from fastapi.exceptions import FastAPIDeprecationWarning from fastapi.openapi.models import Example from pydantic import AliasChoices, AliasPath from pydantic.fields import FieldInfo -from typing_extensions import Literal, deprecated +from typing_extensions import deprecated from ._compat import ( Undefined, @@ -31,45 +31,45 @@ class Param(FieldInfo): # type: ignore[misc] self, default: Any = Undefined, *, - default_factory: Union[Callable[[], Any], None] = _Unset, - annotation: Optional[Any] = None, - alias: Optional[str] = None, - alias_priority: Union[int, None] = _Unset, - validation_alias: Union[str, AliasPath, AliasChoices, None] = None, - serialization_alias: Union[str, None] = None, - title: Optional[str] = None, - description: Optional[str] = None, - gt: Optional[float] = None, - ge: Optional[float] = None, - lt: Optional[float] = None, - le: Optional[float] = None, - min_length: Optional[int] = None, - max_length: Optional[int] = None, - pattern: Optional[str] = None, + default_factory: Callable[[], Any] | None = _Unset, + annotation: Any | None = None, + alias: str | None = None, + alias_priority: int | None = _Unset, + validation_alias: str | AliasPath | AliasChoices | None = None, + serialization_alias: str | None = None, + title: str | None = None, + description: str | None = None, + gt: float | None = None, + ge: float | None = None, + lt: float | None = None, + le: float | None = None, + min_length: int | None = None, + max_length: int | None = None, + pattern: str | None = None, regex: Annotated[ - Optional[str], + str | None, deprecated( "Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead." ), ] = None, - discriminator: Union[str, None] = None, - strict: Union[bool, None] = _Unset, - multiple_of: Union[float, None] = _Unset, - allow_inf_nan: Union[bool, None] = _Unset, - max_digits: Union[int, None] = _Unset, - decimal_places: Union[int, None] = _Unset, - examples: Optional[list[Any]] = None, + discriminator: str | None = None, + strict: bool | None = _Unset, + multiple_of: float | None = _Unset, + allow_inf_nan: bool | None = _Unset, + max_digits: int | None = _Unset, + decimal_places: int | None = _Unset, + examples: list[Any] | None = None, example: Annotated[ - Optional[Any], + Any | None, deprecated( "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, " "although still supported. Use examples instead." ), ] = _Unset, - openapi_examples: Optional[dict[str, Example]] = None, - deprecated: Union[deprecated, str, bool, None] = None, + openapi_examples: dict[str, Example] | None = None, + deprecated: deprecated | str | bool | None = None, include_in_schema: bool = True, - json_schema_extra: Union[dict[str, Any], None] = None, + json_schema_extra: dict[str, Any] | None = None, **extra: Any, ): if example is not _Unset: @@ -142,45 +142,45 @@ class Path(Param): # type: ignore[misc] self, default: Any = ..., *, - default_factory: Union[Callable[[], Any], None] = _Unset, - annotation: Optional[Any] = None, - alias: Optional[str] = None, - alias_priority: Union[int, None] = _Unset, - validation_alias: Union[str, AliasPath, AliasChoices, None] = None, - serialization_alias: Union[str, None] = None, - title: Optional[str] = None, - description: Optional[str] = None, - gt: Optional[float] = None, - ge: Optional[float] = None, - lt: Optional[float] = None, - le: Optional[float] = None, - min_length: Optional[int] = None, - max_length: Optional[int] = None, - pattern: Optional[str] = None, + default_factory: Callable[[], Any] | None = _Unset, + annotation: Any | None = None, + alias: str | None = None, + alias_priority: int | None = _Unset, + validation_alias: str | AliasPath | AliasChoices | None = None, + serialization_alias: str | None = None, + title: str | None = None, + description: str | None = None, + gt: float | None = None, + ge: float | None = None, + lt: float | None = None, + le: float | None = None, + min_length: int | None = None, + max_length: int | None = None, + pattern: str | None = None, regex: Annotated[ - Optional[str], + str | None, deprecated( "Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead." ), ] = None, - discriminator: Union[str, None] = None, - strict: Union[bool, None] = _Unset, - multiple_of: Union[float, None] = _Unset, - allow_inf_nan: Union[bool, None] = _Unset, - max_digits: Union[int, None] = _Unset, - decimal_places: Union[int, None] = _Unset, - examples: Optional[list[Any]] = None, + discriminator: str | None = None, + strict: bool | None = _Unset, + multiple_of: float | None = _Unset, + allow_inf_nan: bool | None = _Unset, + max_digits: int | None = _Unset, + decimal_places: int | None = _Unset, + examples: list[Any] | None = None, example: Annotated[ - Optional[Any], + Any | None, deprecated( "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, " "although still supported. Use examples instead." ), ] = _Unset, - openapi_examples: Optional[dict[str, Example]] = None, - deprecated: Union[deprecated, str, bool, None] = None, + openapi_examples: dict[str, Example] | None = None, + deprecated: deprecated | str | bool | None = None, include_in_schema: bool = True, - json_schema_extra: Union[dict[str, Any], None] = None, + json_schema_extra: dict[str, Any] | None = None, **extra: Any, ): assert default is ..., "Path parameters cannot have a default value" @@ -226,45 +226,45 @@ class Query(Param): # type: ignore[misc] self, default: Any = Undefined, *, - default_factory: Union[Callable[[], Any], None] = _Unset, - annotation: Optional[Any] = None, - alias: Optional[str] = None, - alias_priority: Union[int, None] = _Unset, - validation_alias: Union[str, AliasPath, AliasChoices, None] = None, - serialization_alias: Union[str, None] = None, - title: Optional[str] = None, - description: Optional[str] = None, - gt: Optional[float] = None, - ge: Optional[float] = None, - lt: Optional[float] = None, - le: Optional[float] = None, - min_length: Optional[int] = None, - max_length: Optional[int] = None, - pattern: Optional[str] = None, + default_factory: Callable[[], Any] | None = _Unset, + annotation: Any | None = None, + alias: str | None = None, + alias_priority: int | None = _Unset, + validation_alias: str | AliasPath | AliasChoices | None = None, + serialization_alias: str | None = None, + title: str | None = None, + description: str | None = None, + gt: float | None = None, + ge: float | None = None, + lt: float | None = None, + le: float | None = None, + min_length: int | None = None, + max_length: int | None = None, + pattern: str | None = None, regex: Annotated[ - Optional[str], + str | None, deprecated( "Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead." ), ] = None, - discriminator: Union[str, None] = None, - strict: Union[bool, None] = _Unset, - multiple_of: Union[float, None] = _Unset, - allow_inf_nan: Union[bool, None] = _Unset, - max_digits: Union[int, None] = _Unset, - decimal_places: Union[int, None] = _Unset, - examples: Optional[list[Any]] = None, + discriminator: str | None = None, + strict: bool | None = _Unset, + multiple_of: float | None = _Unset, + allow_inf_nan: bool | None = _Unset, + max_digits: int | None = _Unset, + decimal_places: int | None = _Unset, + examples: list[Any] | None = None, example: Annotated[ - Optional[Any], + Any | None, deprecated( "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, " "although still supported. Use examples instead." ), ] = _Unset, - openapi_examples: Optional[dict[str, Example]] = None, - deprecated: Union[deprecated, str, bool, None] = None, + openapi_examples: dict[str, Example] | None = None, + deprecated: deprecated | str | bool | None = None, include_in_schema: bool = True, - json_schema_extra: Union[dict[str, Any], None] = None, + json_schema_extra: dict[str, Any] | None = None, **extra: Any, ): super().__init__( @@ -308,46 +308,46 @@ class Header(Param): # type: ignore[misc] self, default: Any = Undefined, *, - default_factory: Union[Callable[[], Any], None] = _Unset, - annotation: Optional[Any] = None, - alias: Optional[str] = None, - alias_priority: Union[int, None] = _Unset, - validation_alias: Union[str, AliasPath, AliasChoices, None] = None, - serialization_alias: Union[str, None] = None, + default_factory: Callable[[], Any] | None = _Unset, + annotation: Any | None = None, + alias: str | None = None, + alias_priority: int | None = _Unset, + validation_alias: str | AliasPath | AliasChoices | None = None, + serialization_alias: str | None = None, convert_underscores: bool = True, - title: Optional[str] = None, - description: Optional[str] = None, - gt: Optional[float] = None, - ge: Optional[float] = None, - lt: Optional[float] = None, - le: Optional[float] = None, - min_length: Optional[int] = None, - max_length: Optional[int] = None, - pattern: Optional[str] = None, + title: str | None = None, + description: str | None = None, + gt: float | None = None, + ge: float | None = None, + lt: float | None = None, + le: float | None = None, + min_length: int | None = None, + max_length: int | None = None, + pattern: str | None = None, regex: Annotated[ - Optional[str], + str | None, deprecated( "Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead." ), ] = None, - discriminator: Union[str, None] = None, - strict: Union[bool, None] = _Unset, - multiple_of: Union[float, None] = _Unset, - allow_inf_nan: Union[bool, None] = _Unset, - max_digits: Union[int, None] = _Unset, - decimal_places: Union[int, None] = _Unset, - examples: Optional[list[Any]] = None, + discriminator: str | None = None, + strict: bool | None = _Unset, + multiple_of: float | None = _Unset, + allow_inf_nan: bool | None = _Unset, + max_digits: int | None = _Unset, + decimal_places: int | None = _Unset, + examples: list[Any] | None = None, example: Annotated[ - Optional[Any], + Any | None, deprecated( "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, " "although still supported. Use examples instead." ), ] = _Unset, - openapi_examples: Optional[dict[str, Example]] = None, - deprecated: Union[deprecated, str, bool, None] = None, + openapi_examples: dict[str, Example] | None = None, + deprecated: deprecated | str | bool | None = None, include_in_schema: bool = True, - json_schema_extra: Union[dict[str, Any], None] = None, + json_schema_extra: dict[str, Any] | None = None, **extra: Any, ): self.convert_underscores = convert_underscores @@ -392,45 +392,45 @@ class Cookie(Param): # type: ignore[misc] self, default: Any = Undefined, *, - default_factory: Union[Callable[[], Any], None] = _Unset, - annotation: Optional[Any] = None, - alias: Optional[str] = None, - alias_priority: Union[int, None] = _Unset, - validation_alias: Union[str, AliasPath, AliasChoices, None] = None, - serialization_alias: Union[str, None] = None, - title: Optional[str] = None, - description: Optional[str] = None, - gt: Optional[float] = None, - ge: Optional[float] = None, - lt: Optional[float] = None, - le: Optional[float] = None, - min_length: Optional[int] = None, - max_length: Optional[int] = None, - pattern: Optional[str] = None, + default_factory: Callable[[], Any] | None = _Unset, + annotation: Any | None = None, + alias: str | None = None, + alias_priority: int | None = _Unset, + validation_alias: str | AliasPath | AliasChoices | None = None, + serialization_alias: str | None = None, + title: str | None = None, + description: str | None = None, + gt: float | None = None, + ge: float | None = None, + lt: float | None = None, + le: float | None = None, + min_length: int | None = None, + max_length: int | None = None, + pattern: str | None = None, regex: Annotated[ - Optional[str], + str | None, deprecated( "Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead." ), ] = None, - discriminator: Union[str, None] = None, - strict: Union[bool, None] = _Unset, - multiple_of: Union[float, None] = _Unset, - allow_inf_nan: Union[bool, None] = _Unset, - max_digits: Union[int, None] = _Unset, - decimal_places: Union[int, None] = _Unset, - examples: Optional[list[Any]] = None, + discriminator: str | None = None, + strict: bool | None = _Unset, + multiple_of: float | None = _Unset, + allow_inf_nan: bool | None = _Unset, + max_digits: int | None = _Unset, + decimal_places: int | None = _Unset, + examples: list[Any] | None = None, example: Annotated[ - Optional[Any], + Any | None, deprecated( "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, " "although still supported. Use examples instead." ), ] = _Unset, - openapi_examples: Optional[dict[str, Example]] = None, - deprecated: Union[deprecated, str, bool, None] = None, + openapi_examples: dict[str, Example] | None = None, + deprecated: deprecated | str | bool | None = None, include_in_schema: bool = True, - json_schema_extra: Union[dict[str, Any], None] = None, + json_schema_extra: dict[str, Any] | None = None, **extra: Any, ): super().__init__( @@ -472,47 +472,47 @@ class Body(FieldInfo): # type: ignore[misc] self, default: Any = Undefined, *, - default_factory: Union[Callable[[], Any], None] = _Unset, - annotation: Optional[Any] = None, - embed: Union[bool, None] = None, + default_factory: Callable[[], Any] | None = _Unset, + annotation: Any | None = None, + embed: bool | None = None, media_type: str = "application/json", - alias: Optional[str] = None, - alias_priority: Union[int, None] = _Unset, - validation_alias: Union[str, AliasPath, AliasChoices, None] = None, - serialization_alias: Union[str, None] = None, - title: Optional[str] = None, - description: Optional[str] = None, - gt: Optional[float] = None, - ge: Optional[float] = None, - lt: Optional[float] = None, - le: Optional[float] = None, - min_length: Optional[int] = None, - max_length: Optional[int] = None, - pattern: Optional[str] = None, + alias: str | None = None, + alias_priority: int | None = _Unset, + validation_alias: str | AliasPath | AliasChoices | None = None, + serialization_alias: str | None = None, + title: str | None = None, + description: str | None = None, + gt: float | None = None, + ge: float | None = None, + lt: float | None = None, + le: float | None = None, + min_length: int | None = None, + max_length: int | None = None, + pattern: str | None = None, regex: Annotated[ - Optional[str], + str | None, deprecated( "Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead." ), ] = None, - discriminator: Union[str, None] = None, - strict: Union[bool, None] = _Unset, - multiple_of: Union[float, None] = _Unset, - allow_inf_nan: Union[bool, None] = _Unset, - max_digits: Union[int, None] = _Unset, - decimal_places: Union[int, None] = _Unset, - examples: Optional[list[Any]] = None, + discriminator: str | None = None, + strict: bool | None = _Unset, + multiple_of: float | None = _Unset, + allow_inf_nan: bool | None = _Unset, + max_digits: int | None = _Unset, + decimal_places: int | None = _Unset, + examples: list[Any] | None = None, example: Annotated[ - Optional[Any], + Any | None, deprecated( "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, " "although still supported. Use examples instead." ), ] = _Unset, - openapi_examples: Optional[dict[str, Example]] = None, - deprecated: Union[deprecated, str, bool, None] = None, + openapi_examples: dict[str, Example] | None = None, + deprecated: deprecated | str | bool | None = None, include_in_schema: bool = True, - json_schema_extra: Union[dict[str, Any], None] = None, + json_schema_extra: dict[str, Any] | None = None, **extra: Any, ): self.embed = embed @@ -584,46 +584,46 @@ class Form(Body): # type: ignore[misc] self, default: Any = Undefined, *, - default_factory: Union[Callable[[], Any], None] = _Unset, - annotation: Optional[Any] = None, + default_factory: Callable[[], Any] | None = _Unset, + annotation: Any | None = None, media_type: str = "application/x-www-form-urlencoded", - alias: Optional[str] = None, - alias_priority: Union[int, None] = _Unset, - validation_alias: Union[str, AliasPath, AliasChoices, None] = None, - serialization_alias: Union[str, None] = None, - title: Optional[str] = None, - description: Optional[str] = None, - gt: Optional[float] = None, - ge: Optional[float] = None, - lt: Optional[float] = None, - le: Optional[float] = None, - min_length: Optional[int] = None, - max_length: Optional[int] = None, - pattern: Optional[str] = None, + alias: str | None = None, + alias_priority: int | None = _Unset, + validation_alias: str | AliasPath | AliasChoices | None = None, + serialization_alias: str | None = None, + title: str | None = None, + description: str | None = None, + gt: float | None = None, + ge: float | None = None, + lt: float | None = None, + le: float | None = None, + min_length: int | None = None, + max_length: int | None = None, + pattern: str | None = None, regex: Annotated[ - Optional[str], + str | None, deprecated( "Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead." ), ] = None, - discriminator: Union[str, None] = None, - strict: Union[bool, None] = _Unset, - multiple_of: Union[float, None] = _Unset, - allow_inf_nan: Union[bool, None] = _Unset, - max_digits: Union[int, None] = _Unset, - decimal_places: Union[int, None] = _Unset, - examples: Optional[list[Any]] = None, + discriminator: str | None = None, + strict: bool | None = _Unset, + multiple_of: float | None = _Unset, + allow_inf_nan: bool | None = _Unset, + max_digits: int | None = _Unset, + decimal_places: int | None = _Unset, + examples: list[Any] | None = None, example: Annotated[ - Optional[Any], + Any | None, deprecated( "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, " "although still supported. Use examples instead." ), ] = _Unset, - openapi_examples: Optional[dict[str, Example]] = None, - deprecated: Union[deprecated, str, bool, None] = None, + openapi_examples: dict[str, Example] | None = None, + deprecated: deprecated | str | bool | None = None, include_in_schema: bool = True, - json_schema_extra: Union[dict[str, Any], None] = None, + json_schema_extra: dict[str, Any] | None = None, **extra: Any, ): super().__init__( @@ -666,46 +666,46 @@ class File(Form): # type: ignore[misc] self, default: Any = Undefined, *, - default_factory: Union[Callable[[], Any], None] = _Unset, - annotation: Optional[Any] = None, + default_factory: Callable[[], Any] | None = _Unset, + annotation: Any | None = None, media_type: str = "multipart/form-data", - alias: Optional[str] = None, - alias_priority: Union[int, None] = _Unset, - validation_alias: Union[str, AliasPath, AliasChoices, None] = None, - serialization_alias: Union[str, None] = None, - title: Optional[str] = None, - description: Optional[str] = None, - gt: Optional[float] = None, - ge: Optional[float] = None, - lt: Optional[float] = None, - le: Optional[float] = None, - min_length: Optional[int] = None, - max_length: Optional[int] = None, - pattern: Optional[str] = None, + alias: str | None = None, + alias_priority: int | None = _Unset, + validation_alias: str | AliasPath | AliasChoices | None = None, + serialization_alias: str | None = None, + title: str | None = None, + description: str | None = None, + gt: float | None = None, + ge: float | None = None, + lt: float | None = None, + le: float | None = None, + min_length: int | None = None, + max_length: int | None = None, + pattern: str | None = None, regex: Annotated[ - Optional[str], + str | None, deprecated( "Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead." ), ] = None, - discriminator: Union[str, None] = None, - strict: Union[bool, None] = _Unset, - multiple_of: Union[float, None] = _Unset, - allow_inf_nan: Union[bool, None] = _Unset, - max_digits: Union[int, None] = _Unset, - decimal_places: Union[int, None] = _Unset, - examples: Optional[list[Any]] = None, + discriminator: str | None = None, + strict: bool | None = _Unset, + multiple_of: float | None = _Unset, + allow_inf_nan: bool | None = _Unset, + max_digits: int | None = _Unset, + decimal_places: int | None = _Unset, + examples: list[Any] | None = None, example: Annotated[ - Optional[Any], + Any | None, deprecated( "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, " "although still supported. Use examples instead." ), ] = _Unset, - openapi_examples: Optional[dict[str, Example]] = None, - deprecated: Union[deprecated, str, bool, None] = None, + openapi_examples: dict[str, Example] | None = None, + deprecated: deprecated | str | bool | None = None, include_in_schema: bool = True, - json_schema_extra: Union[dict[str, Any], None] = None, + json_schema_extra: dict[str, Any] | None = None, **extra: Any, ): super().__init__( @@ -745,11 +745,11 @@ class File(Form): # type: ignore[misc] @dataclass(frozen=True) class Depends: - dependency: Optional[Callable[..., Any]] = None + dependency: Callable[..., Any] | None = None use_cache: bool = True - scope: Union[Literal["function", "request"], None] = None + scope: Literal["function", "request"] | None = None @dataclass(frozen=True) class Security(Depends): - scopes: Optional[Sequence[str]] = None + scopes: Sequence[str] | None = None diff --git a/fastapi/routing.py b/fastapi/routing.py index ed873fda8..ea82ab14a 100644 --- a/fastapi/routing.py +++ b/fastapi/routing.py @@ -7,6 +7,7 @@ import types from collections.abc import ( AsyncIterator, Awaitable, + Callable, Collection, Coroutine, Generator, @@ -23,10 +24,7 @@ from enum import Enum, IntEnum from typing import ( Annotated, Any, - Callable, - Optional, TypeVar, - Union, ) from annotated_doc import Doc @@ -84,7 +82,7 @@ from typing_extensions import deprecated # Copy of starlette.routing.request_response modified to include the # dependencies' AsyncExitStack def request_response( - func: Callable[[Request], Union[Awaitable[Response], Response]], + func: Callable[[Request], Awaitable[Response] | Response], ) -> ASGIApp: """ Takes a function or coroutine `func(request) -> response`, @@ -168,10 +166,10 @@ class _AsyncLiftContextManager(AbstractAsyncContextManager[_T]): async def __aexit__( self, - exc_type: Optional[type[BaseException]], - exc_value: Optional[BaseException], - traceback: Optional[types.TracebackType], - ) -> Optional[bool]: + exc_type: type[BaseException] | None, + exc_value: BaseException | None, + traceback: types.TracebackType | None, + ) -> bool | None: return self._cm.__exit__(exc_type, exc_value, traceback) @@ -199,7 +197,7 @@ def _merge_lifespan_context( @asynccontextmanager async def merged_lifespan( app: AppType, - ) -> AsyncIterator[Optional[Mapping[str, Any]]]: + ) -> AsyncIterator[Mapping[str, Any] | None]: async with original_context(app) as maybe_original_state: async with nested_context(app) as maybe_nested_state: if maybe_nested_state is None and maybe_original_state is None: @@ -263,16 +261,16 @@ def _extract_endpoint_context(func: Any) -> EndpointContext: async def serialize_response( *, - field: Optional[ModelField] = None, + field: ModelField | None = None, response_content: Any, - include: Optional[IncEx] = None, - exclude: Optional[IncEx] = None, + include: IncEx | None = None, + exclude: IncEx | None = None, by_alias: bool = True, exclude_unset: bool = False, exclude_defaults: bool = False, exclude_none: bool = False, is_coroutine: bool = True, - endpoint_ctx: Optional[EndpointContext] = None, + endpoint_ctx: EndpointContext | None = None, ) -> Any: if field: if is_coroutine: @@ -318,17 +316,17 @@ async def run_endpoint_function( def get_request_handler( dependant: Dependant, - body_field: Optional[ModelField] = None, - status_code: Optional[int] = None, - response_class: Union[type[Response], DefaultPlaceholder] = Default(JSONResponse), - response_field: Optional[ModelField] = None, - response_model_include: Optional[IncEx] = None, - response_model_exclude: Optional[IncEx] = None, + body_field: ModelField | None = None, + status_code: int | None = None, + response_class: type[Response] | DefaultPlaceholder = Default(JSONResponse), + response_field: ModelField | None = None, + response_model_include: IncEx | None = None, + response_model_exclude: IncEx | None = None, response_model_by_alias: bool = True, response_model_exclude_unset: bool = False, response_model_exclude_defaults: bool = False, response_model_exclude_none: bool = False, - dependency_overrides_provider: Optional[Any] = None, + dependency_overrides_provider: Any | None = None, embed_body_fields: bool = False, ) -> Callable[[Request], Coroutine[Any, Any, Response]]: assert dependant.call is not None, "dependant.call must be a function" @@ -340,7 +338,7 @@ def get_request_handler( actual_response_class = response_class async def app(request: Request) -> Response: - response: Union[Response, None] = None + response: Response | None = None file_stack = request.scope.get("fastapi_middleware_astack") assert isinstance(file_stack, AsyncExitStack), ( "fastapi_middleware_astack not found in request scope" @@ -476,7 +474,7 @@ def get_request_handler( def get_websocket_app( dependant: Dependant, - dependency_overrides_provider: Optional[Any] = None, + dependency_overrides_provider: Any | None = None, embed_body_fields: bool = False, ) -> Callable[[WebSocket], Coroutine[Any, Any, Any]]: async def app(websocket: WebSocket) -> None: @@ -517,9 +515,9 @@ class APIWebSocketRoute(routing.WebSocketRoute): path: str, endpoint: Callable[..., Any], *, - name: Optional[str] = None, - dependencies: Optional[Sequence[params.Depends]] = None, - dependency_overrides_provider: Optional[Any] = None, + name: str | None = None, + dependencies: Sequence[params.Depends] | None = None, + dependency_overrides_provider: Any | None = None, ) -> None: self.path = path self.endpoint = endpoint @@ -560,33 +558,30 @@ class APIRoute(routing.Route): endpoint: Callable[..., Any], *, response_model: Any = Default(None), - status_code: Optional[int] = None, - tags: Optional[list[Union[str, Enum]]] = None, - dependencies: Optional[Sequence[params.Depends]] = None, - summary: Optional[str] = None, - description: Optional[str] = None, + status_code: int | None = None, + tags: list[str | Enum] | None = None, + dependencies: Sequence[params.Depends] | None = None, + summary: str | None = None, + description: str | None = None, response_description: str = "Successful Response", - responses: Optional[dict[Union[int, str], dict[str, Any]]] = None, - deprecated: Optional[bool] = None, - name: Optional[str] = None, - methods: Optional[Union[set[str], list[str]]] = None, - operation_id: Optional[str] = None, - response_model_include: Optional[IncEx] = None, - response_model_exclude: Optional[IncEx] = None, + responses: dict[int | str, dict[str, Any]] | None = None, + deprecated: bool | None = None, + name: str | None = None, + methods: set[str] | list[str] | None = None, + operation_id: str | None = None, + response_model_include: IncEx | None = None, + response_model_exclude: IncEx | None = None, response_model_by_alias: bool = True, response_model_exclude_unset: bool = False, response_model_exclude_defaults: bool = False, response_model_exclude_none: bool = False, include_in_schema: bool = True, - response_class: Union[type[Response], DefaultPlaceholder] = Default( - JSONResponse - ), - dependency_overrides_provider: Optional[Any] = None, - callbacks: Optional[list[BaseRoute]] = None, - openapi_extra: Optional[dict[str, Any]] = None, - generate_unique_id_function: Union[ - Callable[["APIRoute"], str], DefaultPlaceholder - ] = Default(generate_unique_id), + response_class: type[Response] | DefaultPlaceholder = Default(JSONResponse), + dependency_overrides_provider: Any | None = None, + callbacks: list[BaseRoute] | None = None, + openapi_extra: dict[str, Any] | None = None, + generate_unique_id_function: Callable[["APIRoute"], str] + | DefaultPlaceholder = Default(generate_unique_id), ) -> None: self.path = path self.endpoint = endpoint @@ -662,7 +657,7 @@ class APIRoute(routing.Route): ) response_fields[additional_status_code] = response_field if response_fields: - self.response_fields: dict[Union[int, str], ModelField] = response_fields + self.response_fields: dict[int | str, ModelField] = response_fields else: self.response_fields = {} @@ -742,7 +737,7 @@ class APIRouter(routing.Router): *, prefix: Annotated[str, Doc("An optional path prefix for the router.")] = "", tags: Annotated[ - Optional[list[Union[str, Enum]]], + list[str | Enum] | None, Doc( """ A list of tags to be applied to all the *path operations* in this @@ -756,7 +751,7 @@ class APIRouter(routing.Router): ), ] = None, dependencies: Annotated[ - Optional[Sequence[params.Depends]], + Sequence[params.Depends] | None, Doc( """ A list of dependencies (using `Depends()`) to be applied to all the @@ -779,7 +774,7 @@ class APIRouter(routing.Router): ), ] = Default(JSONResponse), responses: Annotated[ - Optional[dict[Union[int, str], dict[str, Any]]], + dict[int | str, dict[str, Any]] | None, Doc( """ Additional responses to be shown in OpenAPI. @@ -795,7 +790,7 @@ class APIRouter(routing.Router): ), ] = None, callbacks: Annotated[ - Optional[list[BaseRoute]], + list[BaseRoute] | None, Doc( """ OpenAPI callbacks that should apply to all *path operations* in this @@ -809,7 +804,7 @@ class APIRouter(routing.Router): ), ] = None, routes: Annotated[ - Optional[list[BaseRoute]], + list[BaseRoute] | None, Doc( """ **Note**: you probably shouldn't use this parameter, it is inherited @@ -840,7 +835,7 @@ class APIRouter(routing.Router): ), ] = True, default: Annotated[ - Optional[ASGIApp], + ASGIApp | None, Doc( """ Default function handler for this router. Used to handle @@ -849,7 +844,7 @@ class APIRouter(routing.Router): ), ] = None, dependency_overrides_provider: Annotated[ - Optional[Any], + Any | None, Doc( """ Only used internally by FastAPI to handle dependency overrides. @@ -871,7 +866,7 @@ class APIRouter(routing.Router): ), ] = APIRoute, on_startup: Annotated[ - Optional[Sequence[Callable[[], Any]]], + Sequence[Callable[[], Any]] | None, Doc( """ A list of startup event handler functions. @@ -883,7 +878,7 @@ class APIRouter(routing.Router): ), ] = None, on_shutdown: Annotated[ - Optional[Sequence[Callable[[], Any]]], + Sequence[Callable[[], Any]] | None, Doc( """ A list of shutdown event handler functions. @@ -898,7 +893,7 @@ class APIRouter(routing.Router): # the generic to Lifespan[AppType] is the type of the top level application # which the router cannot know statically, so we use typing.Any lifespan: Annotated[ - Optional[Lifespan[Any]], + Lifespan[Any] | None, Doc( """ A `Lifespan` context manager handler. This replaces `startup` and @@ -910,7 +905,7 @@ class APIRouter(routing.Router): ), ] = None, deprecated: Annotated[ - Optional[bool], + bool | None, Doc( """ Mark all *path operations* in this router as deprecated. @@ -987,7 +982,7 @@ class APIRouter(routing.Router): ) self.prefix = prefix - self.tags: list[Union[str, Enum]] = tags or [] + self.tags: list[str | Enum] = tags or [] self.dependencies = list(dependencies or []) self.deprecated = deprecated self.include_in_schema = include_in_schema @@ -1001,8 +996,8 @@ class APIRouter(routing.Router): def route( self, path: str, - methods: Optional[Collection[str]] = None, - name: Optional[str] = None, + methods: Collection[str] | None = None, + name: str | None = None, include_in_schema: bool = True, ) -> Callable[[DecoratedCallable], DecoratedCallable]: def decorator(func: DecoratedCallable) -> DecoratedCallable: @@ -1023,33 +1018,30 @@ class APIRouter(routing.Router): endpoint: Callable[..., Any], *, response_model: Any = Default(None), - status_code: Optional[int] = None, - tags: Optional[list[Union[str, Enum]]] = None, - dependencies: Optional[Sequence[params.Depends]] = None, - summary: Optional[str] = None, - description: Optional[str] = None, + status_code: int | None = None, + tags: list[str | Enum] | None = None, + dependencies: Sequence[params.Depends] | None = None, + summary: str | None = None, + description: str | None = None, response_description: str = "Successful Response", - responses: Optional[dict[Union[int, str], dict[str, Any]]] = None, - deprecated: Optional[bool] = None, - methods: Optional[Union[set[str], list[str]]] = None, - operation_id: Optional[str] = None, - response_model_include: Optional[IncEx] = None, - response_model_exclude: Optional[IncEx] = None, + responses: dict[int | str, dict[str, Any]] | None = None, + deprecated: bool | None = None, + methods: set[str] | list[str] | None = None, + operation_id: str | None = None, + response_model_include: IncEx | None = None, + response_model_exclude: IncEx | None = None, response_model_by_alias: bool = True, response_model_exclude_unset: bool = False, response_model_exclude_defaults: bool = False, response_model_exclude_none: bool = False, include_in_schema: bool = True, - response_class: Union[type[Response], DefaultPlaceholder] = Default( - JSONResponse - ), - name: Optional[str] = None, - route_class_override: Optional[type[APIRoute]] = None, - callbacks: Optional[list[BaseRoute]] = None, - openapi_extra: Optional[dict[str, Any]] = None, - generate_unique_id_function: Union[ - Callable[[APIRoute], str], DefaultPlaceholder - ] = Default(generate_unique_id), + response_class: type[Response] | DefaultPlaceholder = Default(JSONResponse), + name: str | None = None, + route_class_override: type[APIRoute] | None = None, + callbacks: list[BaseRoute] | None = None, + openapi_extra: dict[str, Any] | None = None, + generate_unique_id_function: Callable[[APIRoute], str] + | DefaultPlaceholder = Default(generate_unique_id), ) -> None: route_class = route_class_override or self.route_class responses = responses or {} @@ -1104,27 +1096,27 @@ class APIRouter(routing.Router): path: str, *, response_model: Any = Default(None), - status_code: Optional[int] = None, - tags: Optional[list[Union[str, Enum]]] = None, - dependencies: Optional[Sequence[params.Depends]] = None, - summary: Optional[str] = None, - description: Optional[str] = None, + status_code: int | None = None, + tags: list[str | Enum] | None = None, + dependencies: Sequence[params.Depends] | None = None, + summary: str | None = None, + description: str | None = None, response_description: str = "Successful Response", - responses: Optional[dict[Union[int, str], dict[str, Any]]] = None, - deprecated: Optional[bool] = None, - methods: Optional[list[str]] = None, - operation_id: Optional[str] = None, - response_model_include: Optional[IncEx] = None, - response_model_exclude: Optional[IncEx] = None, + responses: dict[int | str, dict[str, Any]] | None = None, + deprecated: bool | None = None, + methods: list[str] | None = None, + operation_id: str | None = None, + response_model_include: IncEx | None = None, + response_model_exclude: IncEx | None = None, response_model_by_alias: bool = True, response_model_exclude_unset: bool = False, response_model_exclude_defaults: bool = False, response_model_exclude_none: bool = False, include_in_schema: bool = True, response_class: type[Response] = Default(JSONResponse), - name: Optional[str] = None, - callbacks: Optional[list[BaseRoute]] = None, - openapi_extra: Optional[dict[str, Any]] = None, + name: str | None = None, + callbacks: list[BaseRoute] | None = None, + openapi_extra: dict[str, Any] | None = None, generate_unique_id_function: Callable[[APIRoute], str] = Default( generate_unique_id ), @@ -1165,9 +1157,9 @@ class APIRouter(routing.Router): self, path: str, endpoint: Callable[..., Any], - name: Optional[str] = None, + name: str | None = None, *, - dependencies: Optional[Sequence[params.Depends]] = None, + dependencies: Sequence[params.Depends] | None = None, ) -> None: current_dependencies = self.dependencies.copy() if dependencies: @@ -1193,7 +1185,7 @@ class APIRouter(routing.Router): ), ], name: Annotated[ - Optional[str], + str | None, Doc( """ A name for the WebSocket. Only used internally. @@ -1202,7 +1194,7 @@ class APIRouter(routing.Router): ] = None, *, dependencies: Annotated[ - Optional[Sequence[params.Depends]], + Sequence[params.Depends] | None, Doc( """ A list of dependencies (using `Depends()`) to be used for this @@ -1250,7 +1242,7 @@ class APIRouter(routing.Router): return decorator def websocket_route( - self, path: str, name: Union[str, None] = None + self, path: str, name: str | None = None ) -> Callable[[DecoratedCallable], DecoratedCallable]: def decorator(func: DecoratedCallable) -> DecoratedCallable: self.add_websocket_route(path, func, name=name) @@ -1264,7 +1256,7 @@ class APIRouter(routing.Router): *, prefix: Annotated[str, Doc("An optional path prefix for the router.")] = "", tags: Annotated[ - Optional[list[Union[str, Enum]]], + list[str | Enum] | None, Doc( """ A list of tags to be applied to all the *path operations* in this @@ -1278,7 +1270,7 @@ class APIRouter(routing.Router): ), ] = None, dependencies: Annotated[ - Optional[Sequence[params.Depends]], + Sequence[params.Depends] | None, Doc( """ A list of dependencies (using `Depends()`) to be applied to all the @@ -1301,7 +1293,7 @@ class APIRouter(routing.Router): ), ] = Default(JSONResponse), responses: Annotated[ - Optional[dict[Union[int, str], dict[str, Any]]], + dict[int | str, dict[str, Any]] | None, Doc( """ Additional responses to be shown in OpenAPI. @@ -1317,7 +1309,7 @@ class APIRouter(routing.Router): ), ] = None, callbacks: Annotated[ - Optional[list[BaseRoute]], + list[BaseRoute] | None, Doc( """ OpenAPI callbacks that should apply to all *path operations* in this @@ -1331,7 +1323,7 @@ class APIRouter(routing.Router): ), ] = None, deprecated: Annotated[ - Optional[bool], + bool | None, Doc( """ Mark all *path operations* in this router as deprecated. @@ -1554,7 +1546,7 @@ class APIRouter(routing.Router): ), ] = Default(None), status_code: Annotated[ - Optional[int], + int | None, Doc( """ The default status code to be used for the response. @@ -1567,7 +1559,7 @@ class APIRouter(routing.Router): ), ] = None, tags: Annotated[ - Optional[list[Union[str, Enum]]], + list[str | Enum] | None, Doc( """ A list of tags to be applied to the *path operation*. @@ -1580,7 +1572,7 @@ class APIRouter(routing.Router): ), ] = None, dependencies: Annotated[ - Optional[Sequence[params.Depends]], + Sequence[params.Depends] | None, Doc( """ A list of dependencies (using `Depends()`) to be applied to the @@ -1592,7 +1584,7 @@ class APIRouter(routing.Router): ), ] = None, summary: Annotated[ - Optional[str], + str | None, Doc( """ A summary for the *path operation*. @@ -1605,7 +1597,7 @@ class APIRouter(routing.Router): ), ] = None, description: Annotated[ - Optional[str], + str | None, Doc( """ A description for the *path operation*. @@ -1633,7 +1625,7 @@ class APIRouter(routing.Router): ), ] = "Successful Response", responses: Annotated[ - Optional[dict[Union[int, str], dict[str, Any]]], + dict[int | str, dict[str, Any]] | None, Doc( """ Additional responses that could be returned by this *path operation*. @@ -1643,7 +1635,7 @@ class APIRouter(routing.Router): ), ] = None, deprecated: Annotated[ - Optional[bool], + bool | None, Doc( """ Mark this *path operation* as deprecated. @@ -1653,7 +1645,7 @@ class APIRouter(routing.Router): ), ] = None, operation_id: Annotated[ - Optional[str], + str | None, Doc( """ Custom operation ID to be used by this *path operation*. @@ -1673,7 +1665,7 @@ class APIRouter(routing.Router): ), ] = None, response_model_include: Annotated[ - Optional[IncEx], + IncEx | None, Doc( """ Configuration passed to Pydantic to include only certain fields in the @@ -1685,7 +1677,7 @@ class APIRouter(routing.Router): ), ] = None, response_model_exclude: Annotated[ - Optional[IncEx], + IncEx | None, Doc( """ Configuration passed to Pydantic to exclude certain fields in the @@ -1787,7 +1779,7 @@ class APIRouter(routing.Router): ), ] = Default(JSONResponse), name: Annotated[ - Optional[str], + str | None, Doc( """ Name for this *path operation*. Only used internally. @@ -1795,7 +1787,7 @@ class APIRouter(routing.Router): ), ] = None, callbacks: Annotated[ - Optional[list[BaseRoute]], + list[BaseRoute] | None, Doc( """ List of *path operations* that will be used as OpenAPI callbacks. @@ -1811,7 +1803,7 @@ class APIRouter(routing.Router): ), ] = None, openapi_extra: Annotated[ - Optional[dict[str, Any]], + dict[str, Any] | None, Doc( """ Extra metadata to be included in the OpenAPI schema for this *path @@ -1931,7 +1923,7 @@ class APIRouter(routing.Router): ), ] = Default(None), status_code: Annotated[ - Optional[int], + int | None, Doc( """ The default status code to be used for the response. @@ -1944,7 +1936,7 @@ class APIRouter(routing.Router): ), ] = None, tags: Annotated[ - Optional[list[Union[str, Enum]]], + list[str | Enum] | None, Doc( """ A list of tags to be applied to the *path operation*. @@ -1957,7 +1949,7 @@ class APIRouter(routing.Router): ), ] = None, dependencies: Annotated[ - Optional[Sequence[params.Depends]], + Sequence[params.Depends] | None, Doc( """ A list of dependencies (using `Depends()`) to be applied to the @@ -1969,7 +1961,7 @@ class APIRouter(routing.Router): ), ] = None, summary: Annotated[ - Optional[str], + str | None, Doc( """ A summary for the *path operation*. @@ -1982,7 +1974,7 @@ class APIRouter(routing.Router): ), ] = None, description: Annotated[ - Optional[str], + str | None, Doc( """ A description for the *path operation*. @@ -2010,7 +2002,7 @@ class APIRouter(routing.Router): ), ] = "Successful Response", responses: Annotated[ - Optional[dict[Union[int, str], dict[str, Any]]], + dict[int | str, dict[str, Any]] | None, Doc( """ Additional responses that could be returned by this *path operation*. @@ -2020,7 +2012,7 @@ class APIRouter(routing.Router): ), ] = None, deprecated: Annotated[ - Optional[bool], + bool | None, Doc( """ Mark this *path operation* as deprecated. @@ -2030,7 +2022,7 @@ class APIRouter(routing.Router): ), ] = None, operation_id: Annotated[ - Optional[str], + str | None, Doc( """ Custom operation ID to be used by this *path operation*. @@ -2050,7 +2042,7 @@ class APIRouter(routing.Router): ), ] = None, response_model_include: Annotated[ - Optional[IncEx], + IncEx | None, Doc( """ Configuration passed to Pydantic to include only certain fields in the @@ -2062,7 +2054,7 @@ class APIRouter(routing.Router): ), ] = None, response_model_exclude: Annotated[ - Optional[IncEx], + IncEx | None, Doc( """ Configuration passed to Pydantic to exclude certain fields in the @@ -2164,7 +2156,7 @@ class APIRouter(routing.Router): ), ] = Default(JSONResponse), name: Annotated[ - Optional[str], + str | None, Doc( """ Name for this *path operation*. Only used internally. @@ -2172,7 +2164,7 @@ class APIRouter(routing.Router): ), ] = None, callbacks: Annotated[ - Optional[list[BaseRoute]], + list[BaseRoute] | None, Doc( """ List of *path operations* that will be used as OpenAPI callbacks. @@ -2188,7 +2180,7 @@ class APIRouter(routing.Router): ), ] = None, openapi_extra: Annotated[ - Optional[dict[str, Any]], + dict[str, Any] | None, Doc( """ Extra metadata to be included in the OpenAPI schema for this *path @@ -2313,7 +2305,7 @@ class APIRouter(routing.Router): ), ] = Default(None), status_code: Annotated[ - Optional[int], + int | None, Doc( """ The default status code to be used for the response. @@ -2326,7 +2318,7 @@ class APIRouter(routing.Router): ), ] = None, tags: Annotated[ - Optional[list[Union[str, Enum]]], + list[str | Enum] | None, Doc( """ A list of tags to be applied to the *path operation*. @@ -2339,7 +2331,7 @@ class APIRouter(routing.Router): ), ] = None, dependencies: Annotated[ - Optional[Sequence[params.Depends]], + Sequence[params.Depends] | None, Doc( """ A list of dependencies (using `Depends()`) to be applied to the @@ -2351,7 +2343,7 @@ class APIRouter(routing.Router): ), ] = None, summary: Annotated[ - Optional[str], + str | None, Doc( """ A summary for the *path operation*. @@ -2364,7 +2356,7 @@ class APIRouter(routing.Router): ), ] = None, description: Annotated[ - Optional[str], + str | None, Doc( """ A description for the *path operation*. @@ -2392,7 +2384,7 @@ class APIRouter(routing.Router): ), ] = "Successful Response", responses: Annotated[ - Optional[dict[Union[int, str], dict[str, Any]]], + dict[int | str, dict[str, Any]] | None, Doc( """ Additional responses that could be returned by this *path operation*. @@ -2402,7 +2394,7 @@ class APIRouter(routing.Router): ), ] = None, deprecated: Annotated[ - Optional[bool], + bool | None, Doc( """ Mark this *path operation* as deprecated. @@ -2412,7 +2404,7 @@ class APIRouter(routing.Router): ), ] = None, operation_id: Annotated[ - Optional[str], + str | None, Doc( """ Custom operation ID to be used by this *path operation*. @@ -2432,7 +2424,7 @@ class APIRouter(routing.Router): ), ] = None, response_model_include: Annotated[ - Optional[IncEx], + IncEx | None, Doc( """ Configuration passed to Pydantic to include only certain fields in the @@ -2444,7 +2436,7 @@ class APIRouter(routing.Router): ), ] = None, response_model_exclude: Annotated[ - Optional[IncEx], + IncEx | None, Doc( """ Configuration passed to Pydantic to exclude certain fields in the @@ -2546,7 +2538,7 @@ class APIRouter(routing.Router): ), ] = Default(JSONResponse), name: Annotated[ - Optional[str], + str | None, Doc( """ Name for this *path operation*. Only used internally. @@ -2554,7 +2546,7 @@ class APIRouter(routing.Router): ), ] = None, callbacks: Annotated[ - Optional[list[BaseRoute]], + list[BaseRoute] | None, Doc( """ List of *path operations* that will be used as OpenAPI callbacks. @@ -2570,7 +2562,7 @@ class APIRouter(routing.Router): ), ] = None, openapi_extra: Annotated[ - Optional[dict[str, Any]], + dict[str, Any] | None, Doc( """ Extra metadata to be included in the OpenAPI schema for this *path @@ -2695,7 +2687,7 @@ class APIRouter(routing.Router): ), ] = Default(None), status_code: Annotated[ - Optional[int], + int | None, Doc( """ The default status code to be used for the response. @@ -2708,7 +2700,7 @@ class APIRouter(routing.Router): ), ] = None, tags: Annotated[ - Optional[list[Union[str, Enum]]], + list[str | Enum] | None, Doc( """ A list of tags to be applied to the *path operation*. @@ -2721,7 +2713,7 @@ class APIRouter(routing.Router): ), ] = None, dependencies: Annotated[ - Optional[Sequence[params.Depends]], + Sequence[params.Depends] | None, Doc( """ A list of dependencies (using `Depends()`) to be applied to the @@ -2733,7 +2725,7 @@ class APIRouter(routing.Router): ), ] = None, summary: Annotated[ - Optional[str], + str | None, Doc( """ A summary for the *path operation*. @@ -2746,7 +2738,7 @@ class APIRouter(routing.Router): ), ] = None, description: Annotated[ - Optional[str], + str | None, Doc( """ A description for the *path operation*. @@ -2774,7 +2766,7 @@ class APIRouter(routing.Router): ), ] = "Successful Response", responses: Annotated[ - Optional[dict[Union[int, str], dict[str, Any]]], + dict[int | str, dict[str, Any]] | None, Doc( """ Additional responses that could be returned by this *path operation*. @@ -2784,7 +2776,7 @@ class APIRouter(routing.Router): ), ] = None, deprecated: Annotated[ - Optional[bool], + bool | None, Doc( """ Mark this *path operation* as deprecated. @@ -2794,7 +2786,7 @@ class APIRouter(routing.Router): ), ] = None, operation_id: Annotated[ - Optional[str], + str | None, Doc( """ Custom operation ID to be used by this *path operation*. @@ -2814,7 +2806,7 @@ class APIRouter(routing.Router): ), ] = None, response_model_include: Annotated[ - Optional[IncEx], + IncEx | None, Doc( """ Configuration passed to Pydantic to include only certain fields in the @@ -2826,7 +2818,7 @@ class APIRouter(routing.Router): ), ] = None, response_model_exclude: Annotated[ - Optional[IncEx], + IncEx | None, Doc( """ Configuration passed to Pydantic to exclude certain fields in the @@ -2928,7 +2920,7 @@ class APIRouter(routing.Router): ), ] = Default(JSONResponse), name: Annotated[ - Optional[str], + str | None, Doc( """ Name for this *path operation*. Only used internally. @@ -2936,7 +2928,7 @@ class APIRouter(routing.Router): ), ] = None, callbacks: Annotated[ - Optional[list[BaseRoute]], + list[BaseRoute] | None, Doc( """ List of *path operations* that will be used as OpenAPI callbacks. @@ -2952,7 +2944,7 @@ class APIRouter(routing.Router): ), ] = None, openapi_extra: Annotated[ - Optional[dict[str, Any]], + dict[str, Any] | None, Doc( """ Extra metadata to be included in the OpenAPI schema for this *path @@ -3072,7 +3064,7 @@ class APIRouter(routing.Router): ), ] = Default(None), status_code: Annotated[ - Optional[int], + int | None, Doc( """ The default status code to be used for the response. @@ -3085,7 +3077,7 @@ class APIRouter(routing.Router): ), ] = None, tags: Annotated[ - Optional[list[Union[str, Enum]]], + list[str | Enum] | None, Doc( """ A list of tags to be applied to the *path operation*. @@ -3098,7 +3090,7 @@ class APIRouter(routing.Router): ), ] = None, dependencies: Annotated[ - Optional[Sequence[params.Depends]], + Sequence[params.Depends] | None, Doc( """ A list of dependencies (using `Depends()`) to be applied to the @@ -3110,7 +3102,7 @@ class APIRouter(routing.Router): ), ] = None, summary: Annotated[ - Optional[str], + str | None, Doc( """ A summary for the *path operation*. @@ -3123,7 +3115,7 @@ class APIRouter(routing.Router): ), ] = None, description: Annotated[ - Optional[str], + str | None, Doc( """ A description for the *path operation*. @@ -3151,7 +3143,7 @@ class APIRouter(routing.Router): ), ] = "Successful Response", responses: Annotated[ - Optional[dict[Union[int, str], dict[str, Any]]], + dict[int | str, dict[str, Any]] | None, Doc( """ Additional responses that could be returned by this *path operation*. @@ -3161,7 +3153,7 @@ class APIRouter(routing.Router): ), ] = None, deprecated: Annotated[ - Optional[bool], + bool | None, Doc( """ Mark this *path operation* as deprecated. @@ -3171,7 +3163,7 @@ class APIRouter(routing.Router): ), ] = None, operation_id: Annotated[ - Optional[str], + str | None, Doc( """ Custom operation ID to be used by this *path operation*. @@ -3191,7 +3183,7 @@ class APIRouter(routing.Router): ), ] = None, response_model_include: Annotated[ - Optional[IncEx], + IncEx | None, Doc( """ Configuration passed to Pydantic to include only certain fields in the @@ -3203,7 +3195,7 @@ class APIRouter(routing.Router): ), ] = None, response_model_exclude: Annotated[ - Optional[IncEx], + IncEx | None, Doc( """ Configuration passed to Pydantic to exclude certain fields in the @@ -3305,7 +3297,7 @@ class APIRouter(routing.Router): ), ] = Default(JSONResponse), name: Annotated[ - Optional[str], + str | None, Doc( """ Name for this *path operation*. Only used internally. @@ -3313,7 +3305,7 @@ class APIRouter(routing.Router): ), ] = None, callbacks: Annotated[ - Optional[list[BaseRoute]], + list[BaseRoute] | None, Doc( """ List of *path operations* that will be used as OpenAPI callbacks. @@ -3329,7 +3321,7 @@ class APIRouter(routing.Router): ), ] = None, openapi_extra: Annotated[ - Optional[dict[str, Any]], + dict[str, Any] | None, Doc( """ Extra metadata to be included in the OpenAPI schema for this *path @@ -3449,7 +3441,7 @@ class APIRouter(routing.Router): ), ] = Default(None), status_code: Annotated[ - Optional[int], + int | None, Doc( """ The default status code to be used for the response. @@ -3462,7 +3454,7 @@ class APIRouter(routing.Router): ), ] = None, tags: Annotated[ - Optional[list[Union[str, Enum]]], + list[str | Enum] | None, Doc( """ A list of tags to be applied to the *path operation*. @@ -3475,7 +3467,7 @@ class APIRouter(routing.Router): ), ] = None, dependencies: Annotated[ - Optional[Sequence[params.Depends]], + Sequence[params.Depends] | None, Doc( """ A list of dependencies (using `Depends()`) to be applied to the @@ -3487,7 +3479,7 @@ class APIRouter(routing.Router): ), ] = None, summary: Annotated[ - Optional[str], + str | None, Doc( """ A summary for the *path operation*. @@ -3500,7 +3492,7 @@ class APIRouter(routing.Router): ), ] = None, description: Annotated[ - Optional[str], + str | None, Doc( """ A description for the *path operation*. @@ -3528,7 +3520,7 @@ class APIRouter(routing.Router): ), ] = "Successful Response", responses: Annotated[ - Optional[dict[Union[int, str], dict[str, Any]]], + dict[int | str, dict[str, Any]] | None, Doc( """ Additional responses that could be returned by this *path operation*. @@ -3538,7 +3530,7 @@ class APIRouter(routing.Router): ), ] = None, deprecated: Annotated[ - Optional[bool], + bool | None, Doc( """ Mark this *path operation* as deprecated. @@ -3548,7 +3540,7 @@ class APIRouter(routing.Router): ), ] = None, operation_id: Annotated[ - Optional[str], + str | None, Doc( """ Custom operation ID to be used by this *path operation*. @@ -3568,7 +3560,7 @@ class APIRouter(routing.Router): ), ] = None, response_model_include: Annotated[ - Optional[IncEx], + IncEx | None, Doc( """ Configuration passed to Pydantic to include only certain fields in the @@ -3580,7 +3572,7 @@ class APIRouter(routing.Router): ), ] = None, response_model_exclude: Annotated[ - Optional[IncEx], + IncEx | None, Doc( """ Configuration passed to Pydantic to exclude certain fields in the @@ -3682,7 +3674,7 @@ class APIRouter(routing.Router): ), ] = Default(JSONResponse), name: Annotated[ - Optional[str], + str | None, Doc( """ Name for this *path operation*. Only used internally. @@ -3690,7 +3682,7 @@ class APIRouter(routing.Router): ), ] = None, callbacks: Annotated[ - Optional[list[BaseRoute]], + list[BaseRoute] | None, Doc( """ List of *path operations* that will be used as OpenAPI callbacks. @@ -3706,7 +3698,7 @@ class APIRouter(routing.Router): ), ] = None, openapi_extra: Annotated[ - Optional[dict[str, Any]], + dict[str, Any] | None, Doc( """ Extra metadata to be included in the OpenAPI schema for this *path @@ -3831,7 +3823,7 @@ class APIRouter(routing.Router): ), ] = Default(None), status_code: Annotated[ - Optional[int], + int | None, Doc( """ The default status code to be used for the response. @@ -3844,7 +3836,7 @@ class APIRouter(routing.Router): ), ] = None, tags: Annotated[ - Optional[list[Union[str, Enum]]], + list[str | Enum] | None, Doc( """ A list of tags to be applied to the *path operation*. @@ -3857,7 +3849,7 @@ class APIRouter(routing.Router): ), ] = None, dependencies: Annotated[ - Optional[Sequence[params.Depends]], + Sequence[params.Depends] | None, Doc( """ A list of dependencies (using `Depends()`) to be applied to the @@ -3869,7 +3861,7 @@ class APIRouter(routing.Router): ), ] = None, summary: Annotated[ - Optional[str], + str | None, Doc( """ A summary for the *path operation*. @@ -3882,7 +3874,7 @@ class APIRouter(routing.Router): ), ] = None, description: Annotated[ - Optional[str], + str | None, Doc( """ A description for the *path operation*. @@ -3910,7 +3902,7 @@ class APIRouter(routing.Router): ), ] = "Successful Response", responses: Annotated[ - Optional[dict[Union[int, str], dict[str, Any]]], + dict[int | str, dict[str, Any]] | None, Doc( """ Additional responses that could be returned by this *path operation*. @@ -3920,7 +3912,7 @@ class APIRouter(routing.Router): ), ] = None, deprecated: Annotated[ - Optional[bool], + bool | None, Doc( """ Mark this *path operation* as deprecated. @@ -3930,7 +3922,7 @@ class APIRouter(routing.Router): ), ] = None, operation_id: Annotated[ - Optional[str], + str | None, Doc( """ Custom operation ID to be used by this *path operation*. @@ -3950,7 +3942,7 @@ class APIRouter(routing.Router): ), ] = None, response_model_include: Annotated[ - Optional[IncEx], + IncEx | None, Doc( """ Configuration passed to Pydantic to include only certain fields in the @@ -3962,7 +3954,7 @@ class APIRouter(routing.Router): ), ] = None, response_model_exclude: Annotated[ - Optional[IncEx], + IncEx | None, Doc( """ Configuration passed to Pydantic to exclude certain fields in the @@ -4064,7 +4056,7 @@ class APIRouter(routing.Router): ), ] = Default(JSONResponse), name: Annotated[ - Optional[str], + str | None, Doc( """ Name for this *path operation*. Only used internally. @@ -4072,7 +4064,7 @@ class APIRouter(routing.Router): ), ] = None, callbacks: Annotated[ - Optional[list[BaseRoute]], + list[BaseRoute] | None, Doc( """ List of *path operations* that will be used as OpenAPI callbacks. @@ -4088,7 +4080,7 @@ class APIRouter(routing.Router): ), ] = None, openapi_extra: Annotated[ - Optional[dict[str, Any]], + dict[str, Any] | None, Doc( """ Extra metadata to be included in the OpenAPI schema for this *path @@ -4213,7 +4205,7 @@ class APIRouter(routing.Router): ), ] = Default(None), status_code: Annotated[ - Optional[int], + int | None, Doc( """ The default status code to be used for the response. @@ -4226,7 +4218,7 @@ class APIRouter(routing.Router): ), ] = None, tags: Annotated[ - Optional[list[Union[str, Enum]]], + list[str | Enum] | None, Doc( """ A list of tags to be applied to the *path operation*. @@ -4239,7 +4231,7 @@ class APIRouter(routing.Router): ), ] = None, dependencies: Annotated[ - Optional[Sequence[params.Depends]], + Sequence[params.Depends] | None, Doc( """ A list of dependencies (using `Depends()`) to be applied to the @@ -4251,7 +4243,7 @@ class APIRouter(routing.Router): ), ] = None, summary: Annotated[ - Optional[str], + str | None, Doc( """ A summary for the *path operation*. @@ -4264,7 +4256,7 @@ class APIRouter(routing.Router): ), ] = None, description: Annotated[ - Optional[str], + str | None, Doc( """ A description for the *path operation*. @@ -4292,7 +4284,7 @@ class APIRouter(routing.Router): ), ] = "Successful Response", responses: Annotated[ - Optional[dict[Union[int, str], dict[str, Any]]], + dict[int | str, dict[str, Any]] | None, Doc( """ Additional responses that could be returned by this *path operation*. @@ -4302,7 +4294,7 @@ class APIRouter(routing.Router): ), ] = None, deprecated: Annotated[ - Optional[bool], + bool | None, Doc( """ Mark this *path operation* as deprecated. @@ -4312,7 +4304,7 @@ class APIRouter(routing.Router): ), ] = None, operation_id: Annotated[ - Optional[str], + str | None, Doc( """ Custom operation ID to be used by this *path operation*. @@ -4332,7 +4324,7 @@ class APIRouter(routing.Router): ), ] = None, response_model_include: Annotated[ - Optional[IncEx], + IncEx | None, Doc( """ Configuration passed to Pydantic to include only certain fields in the @@ -4344,7 +4336,7 @@ class APIRouter(routing.Router): ), ] = None, response_model_exclude: Annotated[ - Optional[IncEx], + IncEx | None, Doc( """ Configuration passed to Pydantic to exclude certain fields in the @@ -4446,7 +4438,7 @@ class APIRouter(routing.Router): ), ] = Default(JSONResponse), name: Annotated[ - Optional[str], + str | None, Doc( """ Name for this *path operation*. Only used internally. @@ -4454,7 +4446,7 @@ class APIRouter(routing.Router): ), ] = None, callbacks: Annotated[ - Optional[list[BaseRoute]], + list[BaseRoute] | None, Doc( """ List of *path operations* that will be used as OpenAPI callbacks. @@ -4470,7 +4462,7 @@ class APIRouter(routing.Router): ), ] = None, openapi_extra: Annotated[ - Optional[dict[str, Any]], + dict[str, Any] | None, Doc( """ Extra metadata to be included in the OpenAPI schema for this *path diff --git a/fastapi/security/api_key.py b/fastapi/security/api_key.py index 18dfb8e61..89358a913 100644 --- a/fastapi/security/api_key.py +++ b/fastapi/security/api_key.py @@ -1,4 +1,4 @@ -from typing import Annotated, Optional, Union +from typing import Annotated from annotated_doc import Doc from fastapi.openapi.models import APIKey, APIKeyIn @@ -13,8 +13,8 @@ class APIKeyBase(SecurityBase): self, location: APIKeyIn, name: str, - description: Union[str, None], - scheme_name: Union[str, None], + description: str | None, + scheme_name: str | None, auto_error: bool, ): self.auto_error = auto_error @@ -42,7 +42,7 @@ class APIKeyBase(SecurityBase): headers={"WWW-Authenticate": "APIKey"}, ) - def check_api_key(self, api_key: Optional[str]) -> Optional[str]: + def check_api_key(self, api_key: str | None) -> str | None: if not api_key: if self.auto_error: raise self.make_not_authenticated_error() @@ -90,7 +90,7 @@ class APIKeyQuery(APIKeyBase): Doc("Query parameter name."), ], scheme_name: Annotated[ - Optional[str], + str | None, Doc( """ Security scheme name. @@ -100,7 +100,7 @@ class APIKeyQuery(APIKeyBase): ), ] = None, description: Annotated[ - Optional[str], + str | None, Doc( """ Security scheme description. @@ -137,7 +137,7 @@ class APIKeyQuery(APIKeyBase): auto_error=auto_error, ) - async def __call__(self, request: Request) -> Optional[str]: + async def __call__(self, request: Request) -> str | None: api_key = request.query_params.get(self.model.name) return self.check_api_key(api_key) @@ -179,7 +179,7 @@ class APIKeyHeader(APIKeyBase): *, name: Annotated[str, Doc("Header name.")], scheme_name: Annotated[ - Optional[str], + str | None, Doc( """ Security scheme name. @@ -189,7 +189,7 @@ class APIKeyHeader(APIKeyBase): ), ] = None, description: Annotated[ - Optional[str], + str | None, Doc( """ Security scheme description. @@ -225,7 +225,7 @@ class APIKeyHeader(APIKeyBase): auto_error=auto_error, ) - async def __call__(self, request: Request) -> Optional[str]: + async def __call__(self, request: Request) -> str | None: api_key = request.headers.get(self.model.name) return self.check_api_key(api_key) @@ -267,7 +267,7 @@ class APIKeyCookie(APIKeyBase): *, name: Annotated[str, Doc("Cookie name.")], scheme_name: Annotated[ - Optional[str], + str | None, Doc( """ Security scheme name. @@ -277,7 +277,7 @@ class APIKeyCookie(APIKeyBase): ), ] = None, description: Annotated[ - Optional[str], + str | None, Doc( """ Security scheme description. @@ -313,6 +313,6 @@ class APIKeyCookie(APIKeyBase): auto_error=auto_error, ) - async def __call__(self, request: Request) -> Optional[str]: + async def __call__(self, request: Request) -> str | None: api_key = request.cookies.get(self.model.name) return self.check_api_key(api_key) diff --git a/fastapi/security/http.py b/fastapi/security/http.py index b4c3bc6d8..05299323c 100644 --- a/fastapi/security/http.py +++ b/fastapi/security/http.py @@ -1,6 +1,6 @@ import binascii from base64 import b64decode -from typing import Annotated, Optional +from typing import Annotated from annotated_doc import Doc from fastapi.exceptions import HTTPException @@ -71,8 +71,8 @@ class HTTPBase(SecurityBase): self, *, scheme: str, - scheme_name: Optional[str] = None, - description: Optional[str] = None, + scheme_name: str | None = None, + description: str | None = None, auto_error: bool = True, ): self.model: HTTPBaseModel = HTTPBaseModel( @@ -91,9 +91,7 @@ class HTTPBase(SecurityBase): headers=self.make_authenticate_headers(), ) - async def __call__( - self, request: Request - ) -> Optional[HTTPAuthorizationCredentials]: + async def __call__(self, request: Request) -> HTTPAuthorizationCredentials | None: authorization = request.headers.get("Authorization") scheme, credentials = get_authorization_scheme_param(authorization) if not (authorization and scheme and credentials): @@ -143,7 +141,7 @@ class HTTPBasic(HTTPBase): self, *, scheme_name: Annotated[ - Optional[str], + str | None, Doc( """ Security scheme name. @@ -153,7 +151,7 @@ class HTTPBasic(HTTPBase): ), ] = None, realm: Annotated[ - Optional[str], + str | None, Doc( """ HTTP Basic authentication realm. @@ -161,7 +159,7 @@ class HTTPBasic(HTTPBase): ), ] = None, description: Annotated[ - Optional[str], + str | None, Doc( """ Security scheme description. @@ -203,7 +201,7 @@ class HTTPBasic(HTTPBase): async def __call__( # type: ignore self, request: Request - ) -> Optional[HTTPBasicCredentials]: + ) -> HTTPBasicCredentials | None: authorization = request.headers.get("Authorization") scheme, param = get_authorization_scheme_param(authorization) if not authorization or scheme.lower() != "basic": @@ -256,9 +254,9 @@ class HTTPBearer(HTTPBase): def __init__( self, *, - bearerFormat: Annotated[Optional[str], Doc("Bearer token format.")] = None, + bearerFormat: Annotated[str | None, Doc("Bearer token format.")] = None, scheme_name: Annotated[ - Optional[str], + str | None, Doc( """ Security scheme name. @@ -268,7 +266,7 @@ class HTTPBearer(HTTPBase): ), ] = None, description: Annotated[ - Optional[str], + str | None, Doc( """ Security scheme description. @@ -302,9 +300,7 @@ class HTTPBearer(HTTPBase): self.scheme_name = scheme_name or self.__class__.__name__ self.auto_error = auto_error - async def __call__( - self, request: Request - ) -> Optional[HTTPAuthorizationCredentials]: + async def __call__(self, request: Request) -> HTTPAuthorizationCredentials | None: authorization = request.headers.get("Authorization") scheme, credentials = get_authorization_scheme_param(authorization) if not (authorization and scheme and credentials): @@ -362,7 +358,7 @@ class HTTPDigest(HTTPBase): self, *, scheme_name: Annotated[ - Optional[str], + str | None, Doc( """ Security scheme name. @@ -372,7 +368,7 @@ class HTTPDigest(HTTPBase): ), ] = None, description: Annotated[ - Optional[str], + str | None, Doc( """ Security scheme description. @@ -405,9 +401,7 @@ class HTTPDigest(HTTPBase): self.scheme_name = scheme_name or self.__class__.__name__ self.auto_error = auto_error - async def __call__( - self, request: Request - ) -> Optional[HTTPAuthorizationCredentials]: + async def __call__(self, request: Request) -> HTTPAuthorizationCredentials | None: authorization = request.headers.get("Authorization") scheme, credentials = get_authorization_scheme_param(authorization) if not (authorization and scheme and credentials): diff --git a/fastapi/security/oauth2.py b/fastapi/security/oauth2.py index 58ffc5c76..661043ce7 100644 --- a/fastapi/security/oauth2.py +++ b/fastapi/security/oauth2.py @@ -1,4 +1,4 @@ -from typing import Annotated, Any, Optional, Union, cast +from typing import Annotated, Any, cast from annotated_doc import Doc from fastapi.exceptions import HTTPException @@ -60,7 +60,7 @@ class OAuth2PasswordRequestForm: self, *, grant_type: Annotated[ - Union[str, None], + str | None, Form(pattern="^password$"), Doc( """ @@ -128,7 +128,7 @@ class OAuth2PasswordRequestForm: ), ] = "", client_id: Annotated[ - Union[str, None], + str | None, Form(), Doc( """ @@ -139,7 +139,7 @@ class OAuth2PasswordRequestForm: ), ] = None, client_secret: Annotated[ - Union[str, None], + str | None, Form(json_schema_extra={"format": "password"}), Doc( """ @@ -294,7 +294,7 @@ class OAuth2PasswordRequestFormStrict(OAuth2PasswordRequestForm): ), ] = "", client_id: Annotated[ - Union[str, None], + str | None, Form(), Doc( """ @@ -305,7 +305,7 @@ class OAuth2PasswordRequestFormStrict(OAuth2PasswordRequestForm): ), ] = None, client_secret: Annotated[ - Union[str, None], + str | None, Form(), Doc( """ @@ -344,7 +344,7 @@ class OAuth2(SecurityBase): self, *, flows: Annotated[ - Union[OAuthFlowsModel, dict[str, dict[str, Any]]], + OAuthFlowsModel | dict[str, dict[str, Any]], Doc( """ The dictionary of OAuth2 flows. @@ -352,7 +352,7 @@ class OAuth2(SecurityBase): ), ] = OAuthFlowsModel(), scheme_name: Annotated[ - Optional[str], + str | None, Doc( """ Security scheme name. @@ -362,7 +362,7 @@ class OAuth2(SecurityBase): ), ] = None, description: Annotated[ - Optional[str], + str | None, Doc( """ Security scheme description. @@ -420,7 +420,7 @@ class OAuth2(SecurityBase): headers={"WWW-Authenticate": "Bearer"}, ) - async def __call__(self, request: Request) -> Optional[str]: + async def __call__(self, request: Request) -> str | None: authorization = request.headers.get("Authorization") if not authorization: if self.auto_error: @@ -454,7 +454,7 @@ class OAuth2PasswordBearer(OAuth2): ), ], scheme_name: Annotated[ - Optional[str], + str | None, Doc( """ Security scheme name. @@ -464,7 +464,7 @@ class OAuth2PasswordBearer(OAuth2): ), ] = None, scopes: Annotated[ - Optional[dict[str, str]], + dict[str, str] | None, Doc( """ The OAuth2 scopes that would be required by the *path operations* that @@ -476,7 +476,7 @@ class OAuth2PasswordBearer(OAuth2): ), ] = None, description: Annotated[ - Optional[str], + str | None, Doc( """ Security scheme description. @@ -506,7 +506,7 @@ class OAuth2PasswordBearer(OAuth2): ), ] = True, refreshUrl: Annotated[ - Optional[str], + str | None, Doc( """ The URL to refresh the token and obtain a new one. @@ -533,7 +533,7 @@ class OAuth2PasswordBearer(OAuth2): auto_error=auto_error, ) - async def __call__(self, request: Request) -> Optional[str]: + async def __call__(self, request: Request) -> str | None: authorization = request.headers.get("Authorization") scheme, param = get_authorization_scheme_param(authorization) if not authorization or scheme.lower() != "bearer": @@ -562,7 +562,7 @@ class OAuth2AuthorizationCodeBearer(OAuth2): ), ], refreshUrl: Annotated[ - Optional[str], + str | None, Doc( """ The URL to refresh the token and obtain a new one. @@ -570,7 +570,7 @@ class OAuth2AuthorizationCodeBearer(OAuth2): ), ] = None, scheme_name: Annotated[ - Optional[str], + str | None, Doc( """ Security scheme name. @@ -580,7 +580,7 @@ class OAuth2AuthorizationCodeBearer(OAuth2): ), ] = None, scopes: Annotated[ - Optional[dict[str, str]], + dict[str, str] | None, Doc( """ The OAuth2 scopes that would be required by the *path operations* that @@ -589,7 +589,7 @@ class OAuth2AuthorizationCodeBearer(OAuth2): ), ] = None, description: Annotated[ - Optional[str], + str | None, Doc( """ Security scheme description. @@ -639,7 +639,7 @@ class OAuth2AuthorizationCodeBearer(OAuth2): auto_error=auto_error, ) - async def __call__(self, request: Request) -> Optional[str]: + async def __call__(self, request: Request) -> str | None: authorization = request.headers.get("Authorization") scheme, param = get_authorization_scheme_param(authorization) if not authorization or scheme.lower() != "bearer": @@ -666,7 +666,7 @@ class SecurityScopes: def __init__( self, scopes: Annotated[ - Optional[list[str]], + list[str] | None, Doc( """ This will be filled by FastAPI. diff --git a/fastapi/security/open_id_connect_url.py b/fastapi/security/open_id_connect_url.py index f4d953351..1c6fcc744 100644 --- a/fastapi/security/open_id_connect_url.py +++ b/fastapi/security/open_id_connect_url.py @@ -1,4 +1,4 @@ -from typing import Annotated, Optional +from typing import Annotated from annotated_doc import Doc from fastapi.openapi.models import OpenIdConnect as OpenIdConnectModel @@ -31,7 +31,7 @@ class OpenIdConnect(SecurityBase): ), ], scheme_name: Annotated[ - Optional[str], + str | None, Doc( """ Security scheme name. @@ -41,7 +41,7 @@ class OpenIdConnect(SecurityBase): ), ] = None, description: Annotated[ - Optional[str], + str | None, Doc( """ Security scheme description. @@ -84,7 +84,7 @@ class OpenIdConnect(SecurityBase): headers={"WWW-Authenticate": "Bearer"}, ) - async def __call__(self, request: Request) -> Optional[str]: + async def __call__(self, request: Request) -> str | None: authorization = request.headers.get("Authorization") if not authorization: if self.auto_error: diff --git a/fastapi/security/utils.py b/fastapi/security/utils.py index fd349aec7..8ee66fd38 100644 --- a/fastapi/security/utils.py +++ b/fastapi/security/utils.py @@ -1,8 +1,5 @@ -from typing import Optional - - def get_authorization_scheme_param( - authorization_header_value: Optional[str], + authorization_header_value: str | None, ) -> tuple[str, str]: if not authorization_header_value: return "", "" diff --git a/fastapi/types.py b/fastapi/types.py index 1c3a6de74..1fb86e13b 100644 --- a/fastapi/types.py +++ b/fastapi/types.py @@ -1,11 +1,12 @@ import types +from collections.abc import Callable from enum import Enum -from typing import Any, Callable, Optional, TypeVar, Union +from typing import Any, TypeVar, Union from pydantic import BaseModel from pydantic.main import IncEx as IncEx DecoratedCallable = TypeVar("DecoratedCallable", bound=Callable[..., Any]) UnionType = getattr(types, "UnionType", Union) -ModelNameMap = dict[Union[type[BaseModel], type[Enum]], str] -DependencyCacheKey = tuple[Optional[Callable[..., Any]], tuple[str, ...], str] +ModelNameMap = dict[type[BaseModel] | type[Enum], str] +DependencyCacheKey = tuple[Callable[..., Any] | None, tuple[str, ...], str] diff --git a/fastapi/utils.py b/fastapi/utils.py index 28c7cdfcc..12eaa2bf0 100644 --- a/fastapi/utils.py +++ b/fastapi/utils.py @@ -3,8 +3,7 @@ import warnings from typing import ( TYPE_CHECKING, Any, - Optional, - Union, + Literal, ) import fastapi @@ -17,7 +16,6 @@ from fastapi._compat import ( from fastapi.datastructures import DefaultPlaceholder, DefaultType from fastapi.exceptions import FastAPIDeprecationWarning, PydanticV1NotSupportedError from pydantic.fields import FieldInfo -from typing_extensions import Literal from ._compat import v2 @@ -25,7 +23,7 @@ if TYPE_CHECKING: # pragma: nocover from .routing import APIRoute -def is_body_allowed_for_status_code(status_code: Union[int, str, None]) -> bool: +def is_body_allowed_for_status_code(status_code: int | str | None) -> bool: if status_code is None: return True # Ref: https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#patterned-fields-1 @@ -60,9 +58,9 @@ _invalid_args_message = ( def create_model_field( name: str, type_: Any, - default: Optional[Any] = Undefined, - field_info: Optional[FieldInfo] = None, - alias: Optional[str] = None, + default: Any | None = Undefined, + field_info: FieldInfo | None = None, + alias: str | None = None, mode: Literal["validation", "serialization"] = "validation", ) -> ModelField: if annotation_is_pydantic_v1(type_): @@ -121,9 +119,9 @@ def deep_dict_update(main_dict: dict[Any, Any], update_dict: dict[Any, Any]) -> def get_value_or_default( - first_item: Union[DefaultPlaceholder, DefaultType], - *extra_items: Union[DefaultPlaceholder, DefaultType], -) -> Union[DefaultPlaceholder, DefaultType]: + first_item: DefaultPlaceholder | DefaultType, + *extra_items: DefaultPlaceholder | DefaultType, +) -> DefaultPlaceholder | DefaultType: """ Pass items or `DefaultPlaceholder`s by descending priority. From d06ab3f5c7c1b6229e28af37905eb51ab4b4cdb7 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 11 Feb 2026 18:41:46 +0000 Subject: [PATCH 09/20] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [skip ci] --- docs/en/docs/release-notes.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index e0ca3de72..7640bd6fa 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -11,6 +11,10 @@ hide: * ➖ Drop support for Python 3.9. PR [#14897](https://github.com/fastapi/fastapi/pull/14897) by [@tiangolo](https://github.com/tiangolo). +### Refactors + +* 🎨 Update internal types for Python 3.10. PR [#14898](https://github.com/fastapi/fastapi/pull/14898) by [@tiangolo](https://github.com/tiangolo). + ## 0.128.8 ### Docs From c9e2277d8b3b0feead4bdad97fca7cf05c9263fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Thu, 12 Feb 2026 05:19:43 -0800 Subject: [PATCH 10/20] =?UTF-8?q?=F0=9F=93=9D=20Update=20source=20examples?= =?UTF-8?q?=20and=20docs=20from=20Python=203.9=20to=203.10=20(#14900)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/advanced/additional-responses.md | 4 +- .../en/docs/advanced/advanced-dependencies.md | 8 +- docs/en/docs/advanced/async-tests.md | 8 +- docs/en/docs/advanced/behind-a-proxy.md | 12 +- docs/en/docs/advanced/custom-response.md | 32 +-- docs/en/docs/advanced/events.md | 12 +- docs/en/docs/advanced/generate-clients.md | 8 +- docs/en/docs/advanced/middleware.md | 6 +- docs/en/docs/advanced/openapi-webhooks.md | 2 +- .../path-operation-advanced-configuration.md | 14 +- .../advanced/response-change-status-code.md | 2 +- docs/en/docs/advanced/response-cookies.md | 4 +- docs/en/docs/advanced/response-directly.md | 2 +- docs/en/docs/advanced/response-headers.md | 4 +- .../docs/advanced/security/http-basic-auth.md | 6 +- docs/en/docs/advanced/settings.md | 20 +- docs/en/docs/advanced/sub-applications.md | 6 +- docs/en/docs/advanced/templates.md | 2 +- docs/en/docs/advanced/testing-events.md | 4 +- docs/en/docs/advanced/testing-websockets.md | 2 +- .../docs/advanced/using-request-directly.md | 2 +- docs/en/docs/advanced/websockets.md | 8 +- docs/en/docs/advanced/wsgi.md | 2 +- .../authentication-error-status-code.md | 2 +- docs/en/docs/how-to/conditional-openapi.md | 2 +- docs/en/docs/how-to/configure-swagger-ui.md | 6 +- docs/en/docs/how-to/custom-docs-ui-assets.md | 14 +- docs/en/docs/how-to/extending-openapi.md | 10 +- docs/en/docs/how-to/graphql.md | 2 +- docs/en/docs/python-types.md | 24 +- docs/en/docs/tutorial/background-tasks.md | 6 +- docs/en/docs/tutorial/bigger-applications.md | 26 +- docs/en/docs/tutorial/body-nested-models.md | 4 +- docs/en/docs/tutorial/cors.md | 2 +- docs/en/docs/tutorial/debugging.md | 2 +- ...pendencies-in-path-operation-decorators.md | 8 +- .../dependencies/dependencies-with-yield.md | 22 +- .../dependencies/global-dependencies.md | 2 +- docs/en/docs/tutorial/extra-models.md | 4 +- docs/en/docs/tutorial/first-steps.md | 14 +- docs/en/docs/tutorial/handling-errors.md | 16 +- docs/en/docs/tutorial/metadata.md | 12 +- docs/en/docs/tutorial/middleware.md | 4 +- .../tutorial/path-operation-configuration.md | 4 +- .../path-params-numeric-validations.md | 14 +- docs/en/docs/tutorial/path-params.md | 20 +- .../tutorial/query-params-str-validations.md | 8 +- docs/en/docs/tutorial/query-params.md | 4 +- docs/en/docs/tutorial/request-files.md | 12 +- docs/en/docs/tutorial/request-form-models.md | 4 +- .../docs/tutorial/request-forms-and-files.md | 4 +- docs/en/docs/tutorial/request-forms.md | 4 +- docs/en/docs/tutorial/response-model.md | 4 +- docs/en/docs/tutorial/response-status-code.md | 6 +- docs/en/docs/tutorial/security/first-steps.md | 6 +- .../tutorial/security/get-current-user.md | 2 +- docs/en/docs/tutorial/static-files.md | 2 +- docs/en/docs/tutorial/testing.md | 6 +- .../additional_responses/tutorial001_py310.py | 22 ++ .../additional_responses/tutorial002_py39.py | 30 --- .../additional_responses/tutorial003_py310.py | 37 +++ .../additional_responses/tutorial004_py39.py | 32 --- .../tutorial001_an_py39.py | 25 -- .../tutorial001_py39.py | 25 -- .../advanced_middleware/tutorial001_py310.py | 11 + .../advanced_middleware/tutorial002_py310.py | 13 + .../advanced_middleware/tutorial003_py310.py | 11 + .../__init__.py | 0 docs_src/app_testing/app_a_py310/main.py | 8 + docs_src/app_testing/app_a_py310/test_main.py | 11 + docs_src/app_testing/app_b_an_py39/main.py | 38 --- .../app_testing/app_b_an_py39/test_main.py | 65 ----- docs_src/app_testing/app_b_py39/main.py | 38 --- docs_src/app_testing/app_b_py39/test_main.py | 65 ----- docs_src/app_testing/tutorial001_py310.py | 18 ++ docs_src/app_testing/tutorial002_py310.py | 31 +++ docs_src/app_testing/tutorial003_py310.py | 24 ++ docs_src/app_testing/tutorial004_py310.py | 43 +++ .../app_a_py310}/__init__.py | 0 docs_src/async_tests/app_a_py310/main.py | 8 + docs_src/async_tests/app_a_py310/test_main.py | 14 + .../tutorial001_an_py310.py | 21 ++ .../background_tasks/tutorial001_py310.py | 15 ++ .../background_tasks/tutorial002_an_py39.py | 26 -- docs_src/background_tasks/tutorial002_py39.py | 26 -- .../behind_a_proxy/tutorial001_01_py310.py | 8 + docs_src/behind_a_proxy/tutorial001_py310.py | 8 + docs_src/behind_a_proxy/tutorial002_py310.py | 8 + docs_src/behind_a_proxy/tutorial003_py310.py | 14 + docs_src/behind_a_proxy/tutorial004_py310.py | 15 ++ .../internal => app_an_py310}/__init__.py | 0 .../app_an_py310/dependencies.py | 13 + .../internal}/__init__.py | 0 .../internal/admin.py | 0 .../bigger_applications/app_an_py310/main.py | 23 ++ .../app_an_py310/routers/__init__.py | 0 .../routers/items.py | 0 .../routers/users.py | 0 docs_src/body/tutorial001_py39.py | 19 -- docs_src/body/tutorial002_py39.py | 23 -- docs_src/body/tutorial003_py39.py | 19 -- docs_src/body/tutorial004_py39.py | 22 -- docs_src/body_fields/tutorial001_an_py39.py | 21 -- docs_src/body_fields/tutorial001_py39.py | 21 -- .../tutorial001_an_py39.py | 27 -- .../body_multiple_params/tutorial001_py39.py | 28 -- .../body_multiple_params/tutorial002_py39.py | 24 -- .../tutorial003_an_py39.py | 26 -- .../body_multiple_params/tutorial003_py39.py | 24 -- .../tutorial004_an_py39.py | 33 --- .../body_multiple_params/tutorial004_py39.py | 33 --- .../tutorial005_an_py39.py | 19 -- .../body_multiple_params/tutorial005_py39.py | 19 -- .../body_nested_models/tutorial001_py39.py | 20 -- .../body_nested_models/tutorial002_py39.py | 20 -- .../body_nested_models/tutorial003_py39.py | 20 -- .../body_nested_models/tutorial004_py39.py | 26 -- .../body_nested_models/tutorial005_py39.py | 26 -- .../body_nested_models/tutorial006_py39.py | 26 -- .../body_nested_models/tutorial007_py39.py | 32 --- .../body_nested_models/tutorial008_py310.py | 14 + .../body_nested_models/tutorial009_py310.py | 8 + docs_src/body_updates/tutorial001_py39.py | 34 --- docs_src/body_updates/tutorial002_py39.py | 37 --- .../conditional_openapi/tutorial001_py310.py | 16 ++ .../configure_swagger_ui/tutorial001_py310.py | 8 + .../configure_swagger_ui/tutorial002_py310.py | 8 + .../configure_swagger_ui/tutorial003_py310.py | 8 + .../tutorial001_an_py39.py | 17 -- .../cookie_param_models/tutorial001_py39.py | 17 -- .../tutorial002_an_py39.py | 19 -- .../cookie_param_models/tutorial002_py39.py | 19 -- docs_src/cookie_params/tutorial001_an_py39.py | 10 - docs_src/cookie_params/tutorial001_py39.py | 10 - docs_src/cors/tutorial001_py310.py | 24 ++ docs_src/custom_docs_ui/tutorial001_py310.py | 38 +++ docs_src/custom_docs_ui/tutorial002_py310.py | 41 +++ .../tutorial001_an_py39.py | 35 --- .../tutorial001_py39.py | 35 --- .../tutorial002_an_py39.py | 29 -- .../tutorial002_py39.py | 29 -- .../tutorial003_py39.py | 39 --- docs_src/custom_response/tutorial001_py310.py | 9 + .../custom_response/tutorial001b_py310.py | 9 + docs_src/custom_response/tutorial002_py310.py | 18 ++ docs_src/custom_response/tutorial003_py310.py | 19 ++ docs_src/custom_response/tutorial004_py310.py | 23 ++ docs_src/custom_response/tutorial005_py310.py | 9 + docs_src/custom_response/tutorial006_py310.py | 9 + .../custom_response/tutorial006b_py310.py | 9 + .../custom_response/tutorial006c_py310.py | 9 + docs_src/custom_response/tutorial007_py310.py | 14 + docs_src/custom_response/tutorial008_py310.py | 14 + docs_src/custom_response/tutorial009_py310.py | 10 + .../custom_response/tutorial009b_py310.py | 10 + .../custom_response/tutorial009c_py310.py | 19 ++ docs_src/custom_response/tutorial010_py310.py | 9 + docs_src/dataclasses_/tutorial001_py39.py | 20 -- docs_src/dataclasses_/tutorial002_py39.py | 26 -- docs_src/dataclasses_/tutorial003_py39.py | 55 ---- docs_src/debugging/tutorial001_py310.py | 15 ++ .../dependencies/tutorial001_02_an_py39.py | 24 -- docs_src/dependencies/tutorial001_an_py39.py | 21 -- docs_src/dependencies/tutorial001_py39.py | 21 -- docs_src/dependencies/tutorial002_an_py39.py | 25 -- docs_src/dependencies/tutorial002_py39.py | 25 -- docs_src/dependencies/tutorial003_an_py39.py | 25 -- docs_src/dependencies/tutorial003_py39.py | 25 -- docs_src/dependencies/tutorial004_an_py39.py | 25 -- docs_src/dependencies/tutorial004_py39.py | 25 -- docs_src/dependencies/tutorial005_an_py39.py | 25 -- docs_src/dependencies/tutorial005_py39.py | 23 -- docs_src/dependencies/tutorial006_an_py310.py | 21 ++ docs_src/dependencies/tutorial006_py310.py | 19 ++ docs_src/dependencies/tutorial007_py310.py | 6 + docs_src/dependencies/tutorial008_an_py310.py | 27 ++ docs_src/dependencies/tutorial008_py310.py | 25 ++ .../dependencies/tutorial008b_an_py310.py | 32 +++ docs_src/dependencies/tutorial008b_py310.py | 30 +++ .../dependencies/tutorial008c_an_py310.py | 29 ++ docs_src/dependencies/tutorial008c_py310.py | 27 ++ .../dependencies/tutorial008d_an_py310.py | 30 +++ docs_src/dependencies/tutorial008d_py310.py | 28 ++ .../dependencies/tutorial008e_an_py310.py | 17 ++ docs_src/dependencies/tutorial008e_py310.py | 15 ++ docs_src/dependencies/tutorial010_py310.py | 14 + docs_src/dependencies/tutorial011_an_py310.py | 23 ++ docs_src/dependencies/tutorial011_py310.py | 21 ++ docs_src/dependencies/tutorial012_an_py310.py | 27 ++ docs_src/dependencies/tutorial012_py310.py | 25 ++ .../dependency_testing/tutorial001_an_py39.py | 59 ----- .../dependency_testing/tutorial001_py39.py | 59 ----- docs_src/encoder/tutorial001_py39.py | 23 -- docs_src/events/tutorial001_py310.py | 16 ++ docs_src/events/tutorial002_py310.py | 14 + docs_src/events/tutorial003_py310.py | 28 ++ .../extending_openapi/tutorial001_py310.py | 29 ++ .../extra_data_types/tutorial001_an_py39.py | 28 -- docs_src/extra_data_types/tutorial001_py39.py | 28 -- docs_src/extra_models/tutorial001_py39.py | 43 --- docs_src/extra_models/tutorial002_py39.py | 41 --- docs_src/extra_models/tutorial003_py39.py | 35 --- docs_src/extra_models/tutorial004_py310.py | 20 ++ docs_src/extra_models/tutorial005_py310.py | 8 + docs_src/first_steps/tutorial001_py310.py | 8 + docs_src/first_steps/tutorial003_py310.py | 8 + .../generate_clients/tutorial001_py310.py | 26 ++ .../generate_clients/tutorial002_py310.py | 36 +++ .../generate_clients/tutorial003_py310.py | 42 +++ .../generate_clients/tutorial004_py310.py | 15 ++ docs_src/graphql_/tutorial001_py310.py | 25 ++ docs_src/handling_errors/tutorial001_py310.py | 12 + docs_src/handling_errors/tutorial002_py310.py | 16 ++ docs_src/handling_errors/tutorial003_py310.py | 25 ++ docs_src/handling_errors/tutorial004_py310.py | 26 ++ docs_src/handling_errors/tutorial005_py310.py | 25 ++ docs_src/handling_errors/tutorial006_py310.py | 28 ++ .../tutorial001_an_py39.py | 19 -- .../header_param_models/tutorial001_py39.py | 19 -- .../tutorial002_an_py39.py | 21 -- .../header_param_models/tutorial002_py39.py | 21 -- .../tutorial003_an_py39.py | 21 -- .../header_param_models/tutorial003_py39.py | 19 -- docs_src/header_params/tutorial001_an_py39.py | 10 - docs_src/header_params/tutorial001_py39.py | 10 - docs_src/header_params/tutorial002_an_py39.py | 14 - docs_src/header_params/tutorial002_py39.py | 12 - docs_src/header_params/tutorial003_an_py39.py | 10 - docs_src/header_params/tutorial003_py39.py | 10 - docs_src/metadata/tutorial001_1_py310.py | 38 +++ docs_src/metadata/tutorial001_py310.py | 38 +++ docs_src/metadata/tutorial002_py310.py | 8 + docs_src/metadata/tutorial003_py310.py | 8 + docs_src/metadata/tutorial004_py310.py | 28 ++ docs_src/middleware/tutorial001_py310.py | 14 + .../openapi_callbacks/tutorial001_py39.py | 53 ---- .../openapi_webhooks/tutorial001_py310.py | 25 ++ .../tutorial001_py310.py | 8 + .../tutorial002_py310.py | 24 ++ .../tutorial003_py310.py | 8 + .../tutorial004_py39.py | 30 --- .../tutorial005_py310.py | 8 + .../tutorial006_py310.py | 41 +++ ...al007_pv1_py39.py => tutorial007_py310.py} | 8 +- .../tutorial001_py39.py | 19 -- .../tutorial002_py39.py | 29 -- .../tutorial002b_py310.py | 20 ++ .../tutorial003_py39.py | 23 -- .../tutorial004_py39.py | 28 -- .../tutorial005_py39.py | 32 --- .../tutorial006_py310.py | 18 ++ docs_src/path_params/tutorial001_py310.py | 8 + docs_src/path_params/tutorial002_py310.py | 8 + docs_src/path_params/tutorial003_py310.py | 13 + docs_src/path_params/tutorial003b_py310.py | 13 + docs_src/path_params/tutorial004_py310.py | 8 + docs_src/path_params/tutorial005_py310.py | 23 ++ .../tutorial002_an_py310.py | 15 ++ .../tutorial002_py310.py | 11 + .../tutorial003_an_py310.py | 15 ++ .../tutorial003_py310.py | 11 + .../tutorial004_an_py310.py | 15 ++ .../tutorial004_py310.py | 13 + .../tutorial005_an_py310.py | 16 ++ .../tutorial005_py310.py | 15 ++ ...001_an_py39.py => tutorial006_an_py310.py} | 10 +- ...torial001_py39.py => tutorial006_py310.py} | 10 +- .../pydantic_v1_in_v2/tutorial001_an_py39.py | 9 - .../pydantic_v1_in_v2/tutorial002_an_py39.py | 18 -- .../pydantic_v1_in_v2/tutorial003_an_py39.py | 25 -- .../pydantic_v1_in_v2/tutorial004_an_py39.py | 19 -- docs_src/python_types/tutorial001_py310.py | 6 + docs_src/python_types/tutorial002_py310.py | 6 + docs_src/python_types/tutorial003_py310.py | 3 + docs_src/python_types/tutorial004_py310.py | 3 + docs_src/python_types/tutorial005_py310.py | 2 + docs_src/python_types/tutorial006_py310.py | 3 + docs_src/python_types/tutorial007_py310.py | 2 + docs_src/python_types/tutorial008_py310.py | 4 + docs_src/python_types/tutorial010_py310.py | 7 + docs_src/python_types/tutorial011_py39.py | 23 -- docs_src/python_types/tutorial012_py39.py | 8 - docs_src/python_types/tutorial013_py310.py | 5 + .../query_param_models/tutorial001_an_py39.py | 18 -- .../query_param_models/tutorial001_py39.py | 18 -- .../query_param_models/tutorial002_an_py39.py | 20 -- .../query_param_models/tutorial002_py39.py | 20 -- docs_src/query_params/tutorial001_py310.py | 10 + docs_src/query_params/tutorial002_py39.py | 12 - docs_src/query_params/tutorial003_py39.py | 17 -- docs_src/query_params/tutorial004_py39.py | 19 -- docs_src/query_params/tutorial005_py310.py | 9 + docs_src/query_params/tutorial006_py39.py | 13 - .../tutorial001_py39.py | 13 - .../tutorial002_an_py39.py | 13 - .../tutorial003_an_py39.py | 15 -- .../tutorial003_py39.py | 15 -- .../tutorial004_an_py39.py | 17 -- .../tutorial004_py39.py | 17 -- .../tutorial004_regex_an_py310.py | 17 -- ...ial002_py39.py => tutorial005_an_py310.py} | 4 +- ...torial009_py39.py => tutorial005_py310.py} | 4 +- ...al006c_py39.py => tutorial006_an_py310.py} | 4 +- ...al006c_an_py39.py => tutorial006_py310.py} | 4 +- .../tutorial007_an_py39.py | 15 -- .../tutorial007_py39.py | 15 -- .../tutorial008_an_py39.py | 22 -- .../tutorial008_py39.py | 20 -- .../tutorial009_an_py39.py | 13 - .../tutorial010_an_py39.py | 26 -- .../tutorial010_py39.py | 24 -- ...011_an_py39.py => tutorial012_an_py310.py} | 4 +- .../tutorial012_py310.py | 9 + ...ial011_py39.py => tutorial013_an_py310.py} | 4 +- .../tutorial013_py310.py | 9 + .../tutorial014_an_py39.py | 15 -- .../tutorial014_py39.py | 15 -- .../tutorial015_an_py39.py | 30 --- .../request_files/tutorial001_02_an_py39.py | 21 -- docs_src/request_files/tutorial001_02_py39.py | 21 -- .../request_files/tutorial001_03_an_py310.py | 17 ++ .../request_files/tutorial001_03_py310.py | 15 ++ .../request_files/tutorial001_an_py310.py | 15 ++ docs_src/request_files/tutorial001_py310.py | 13 + .../request_files/tutorial002_an_py310.py | 33 +++ docs_src/request_files/tutorial002_py310.py | 31 +++ .../request_files/tutorial003_an_py310.py | 39 +++ docs_src/request_files/tutorial003_py310.py | 35 +++ .../tutorial001_an_py310.py | 16 ++ .../request_form_models/tutorial001_py310.py | 14 + .../tutorial002_an_py310.py | 17 ++ .../request_form_models/tutorial002_py310.py | 15 ++ .../request_forms/tutorial001_an_py310.py | 10 + docs_src/request_forms/tutorial001_py310.py | 8 + .../tutorial001_an_py310.py | 18 ++ .../tutorial001_py310.py | 14 + .../tutorial001_py310.py | 13 + .../response_cookies/tutorial001_py310.py | 12 + .../response_cookies/tutorial002_py310.py | 9 + .../response_directly/tutorial001_py39.py | 22 -- .../response_directly/tutorial002_py310.py | 18 ++ .../response_headers/tutorial001_py310.py | 11 + .../response_headers/tutorial002_py310.py | 9 + .../response_model/tutorial001_01_py39.py | 27 -- docs_src/response_model/tutorial001_py39.py | 27 -- docs_src/response_model/tutorial002_py39.py | 19 -- .../response_model/tutorial003_01_py39.py | 21 -- .../response_model/tutorial003_02_py310.py | 11 + .../response_model/tutorial003_03_py310.py | 9 + .../response_model/tutorial003_04_py39.py | 13 - .../response_model/tutorial003_05_py39.py | 13 - docs_src/response_model/tutorial003_py39.py | 24 -- docs_src/response_model/tutorial004_py39.py | 26 -- docs_src/response_model/tutorial005_py39.py | 39 --- docs_src/response_model/tutorial006_py39.py | 39 --- .../response_status_code/tutorial001_py310.py | 8 + .../response_status_code/tutorial002_py310.py | 8 + .../tutorial001_pv1_py310.py | 29 -- .../tutorial001_pv1_py39.py | 31 --- .../schema_extra_example/tutorial001_py39.py | 32 --- .../schema_extra_example/tutorial002_py39.py | 19 -- .../tutorial003_an_py39.py | 34 --- .../schema_extra_example/tutorial003_py39.py | 31 --- .../tutorial004_an_py39.py | 43 --- .../schema_extra_example/tutorial004_py39.py | 40 --- .../tutorial005_an_py39.py | 54 ---- .../schema_extra_example/tutorial005_py39.py | 51 ---- docs_src/security/tutorial001_an_py310.py | 13 + docs_src/security/tutorial001_py310.py | 11 + docs_src/security/tutorial002_an_py39.py | 32 --- docs_src/security/tutorial002_py39.py | 32 --- docs_src/security/tutorial003_an_py39.py | 94 ------- docs_src/security/tutorial003_py39.py | 90 ------- docs_src/security/tutorial004_an_py39.py | 147 ----------- docs_src/security/tutorial004_py39.py | 141 ---------- docs_src/security/tutorial005_an_py39.py | 179 ------------- docs_src/security/tutorial005_py39.py | 177 ------------- docs_src/security/tutorial006_an_py310.py | 13 + docs_src/security/tutorial006_py310.py | 11 + docs_src/security/tutorial007_an_py310.py | 36 +++ docs_src/security/tutorial007_py310.py | 33 +++ .../tutorial001_py39.py | 28 -- .../tutorial002_py39.py | 28 -- docs_src/settings/app01_py310/__init__.py | 0 .../config_pv1.py => app01_py310/config.py} | 6 +- docs_src/settings/app01_py310/main.py | 14 + docs_src/settings/app02_an_py310/__init__.py | 0 .../config.py} | 5 +- docs_src/settings/app02_an_py310/main.py | 22 ++ docs_src/settings/app02_an_py310/test_main.py | 23 ++ docs_src/settings/app02_py310/__init__.py | 0 docs_src/settings/app02_py310/config.py | 7 + docs_src/settings/app02_py310/main.py | 21 ++ docs_src/settings/app02_py310/test_main.py | 23 ++ docs_src/settings/app03_an_py310/__init__.py | 0 docs_src/settings/app03_an_py310/config.py | 9 + docs_src/settings/app03_an_py310/main.py | 22 ++ docs_src/settings/app03_py310/__init__.py | 0 docs_src/settings/app03_py310/config.py | 9 + docs_src/settings/app03_py310/main.py | 21 ++ ...al001_pv1_py39.py => tutorial001_py310.py} | 2 +- docs_src/sql_databases/tutorial001_an_py39.py | 73 ------ docs_src/sql_databases/tutorial001_py39.py | 71 ----- docs_src/sql_databases/tutorial002_an_py39.py | 103 -------- docs_src/sql_databases/tutorial002_py39.py | 104 -------- docs_src/static_files/tutorial001_py310.py | 6 + .../sub_applications/tutorial001_py310.py | 19 ++ docs_src/templates/tutorial001_py310.py | 18 ++ .../tutorial001_py310.py | 9 + docs_src/websockets/tutorial001_py310.py | 51 ++++ docs_src/websockets/tutorial002_an_py39.py | 92 ------- docs_src/websockets/tutorial002_py39.py | 91 ------- docs_src/websockets/tutorial003_py310.py | 81 ++++++ docs_src/wsgi/tutorial001_py310.py | 23 ++ pyproject.toml | 247 ++++++++++++++++-- .../test_tutorial001.py | 2 +- .../test_tutorial002.py | 1 - .../test_tutorial003.py | 2 +- .../test_tutorial004.py | 1 - .../test_tutorial001.py | 2 - .../test_tutorial001.py | 2 +- .../test_tutorial002.py | 2 +- .../test_tutorial003.py | 2 +- .../test_async_tests/test_main_a.py | 2 +- .../test_tutorial001.py | 2 +- .../test_background_tasks/test_tutorial001.py | 2 +- .../test_background_tasks/test_tutorial002.py | 2 - .../test_behind_a_proxy/test_tutorial001.py | 2 +- .../test_tutorial001_01.py | 2 +- .../test_behind_a_proxy/test_tutorial002.py | 2 +- .../test_behind_a_proxy/test_tutorial003.py | 2 +- .../test_behind_a_proxy/test_tutorial004.py | 2 +- .../test_bigger_applications/test_main.py | 3 +- .../test_body/test_tutorial001.py | 1 - .../test_body/test_tutorial002.py | 6 +- .../test_body/test_tutorial003.py | 1 - .../test_body/test_tutorial004.py | 1 - .../test_body_fields/test_tutorial001.py | 2 - .../test_tutorial001.py | 2 - .../test_tutorial002.py | 1 - .../test_tutorial003.py | 2 - .../test_tutorial004.py | 2 - .../test_tutorial005.py | 2 - ...est_tutorial001_tutorial002_tutorial003.py | 3 - .../test_tutorial004.py | 1 - .../test_tutorial005.py | 1 - .../test_tutorial006.py | 1 - .../test_tutorial007.py | 1 - .../test_tutorial008.py | 2 +- .../test_tutorial009.py | 2 +- .../test_body_updates/test_tutorial001.py | 1 - .../test_body_updates/test_tutorial002.py | 1 - .../test_tutorial001.py | 6 +- .../test_tutorial001.py | 2 +- .../test_tutorial002.py | 2 +- .../test_tutorial003.py | 2 +- .../test_tutorial001.py | 2 - .../test_tutorial002.py | 2 - .../test_cookie_params/test_tutorial001.py | 2 - .../test_cors/test_tutorial001.py | 2 +- .../test_custom_docs_ui/test_tutorial001.py | 2 +- .../test_custom_docs_ui/test_tutorial002.py | 2 +- .../test_tutorial001.py | 2 - .../test_tutorial002.py | 2 - .../test_tutorial003.py | 1 - .../test_custom_response/test_tutorial001.py | 4 +- .../test_custom_response/test_tutorial001b.py | 2 +- ...est_tutorial002_tutorial003_tutorial004.py | 6 +- .../test_custom_response/test_tutorial005.py | 2 +- .../test_custom_response/test_tutorial006.py | 2 +- .../test_custom_response/test_tutorial006b.py | 2 +- .../test_custom_response/test_tutorial006c.py | 2 +- .../test_custom_response/test_tutorial007.py | 2 +- .../test_custom_response/test_tutorial008.py | 6 +- .../test_custom_response/test_tutorial009.py | 6 +- .../test_custom_response/test_tutorial009b.py | 6 +- .../test_custom_response/test_tutorial009c.py | 2 +- .../test_dataclasses/test_tutorial001.py | 1 - .../test_dataclasses/test_tutorial002.py | 1 - .../test_dataclasses/test_tutorial003.py | 1 - .../test_debugging/test_tutorial001.py | 2 +- .../test_tutorial001_tutorial001_02.py | 3 - ...est_tutorial002_tutorial003_tutorial004.py | 6 - .../test_dependencies/test_tutorial005.py | 2 - .../test_dependencies/test_tutorial006.py | 4 +- .../test_dependencies/test_tutorial007.py | 4 +- .../test_dependencies/test_tutorial008.py | 4 +- .../test_dependencies/test_tutorial008b.py | 4 +- .../test_dependencies/test_tutorial008c.py | 4 +- .../test_dependencies/test_tutorial008d.py | 4 +- .../test_dependencies/test_tutorial008e.py | 4 +- .../test_dependencies/test_tutorial010.py | 4 +- .../test_dependencies/test_tutorial011.py | 4 +- .../test_dependencies/test_tutorial012.py | 4 +- .../test_encoder/test_tutorial001.py | 1 - .../test_events/test_tutorial001.py | 2 +- .../test_events/test_tutorial002.py | 2 +- .../test_events/test_tutorial003.py | 2 +- .../test_tutorial001.py | 2 +- .../test_extra_data_types/test_tutorial001.py | 2 - .../test_tutorial001_tutorial002.py | 2 - .../test_extra_models/test_tutorial003.py | 1 - .../test_extra_models/test_tutorial004.py | 2 +- .../test_extra_models/test_tutorial005.py | 2 +- ...est_tutorial001_tutorial002_tutorial003.py | 4 +- .../test_generate_clients/test_tutorial001.py | 2 +- .../test_generate_clients/test_tutorial002.py | 2 +- .../test_generate_clients/test_tutorial003.py | 2 +- .../test_generate_clients/test_tutorial004.py | 6 +- .../test_graphql/test_tutorial001.py | 2 +- .../test_handling_errors/test_tutorial001.py | 2 +- .../test_handling_errors/test_tutorial002.py | 2 +- .../test_handling_errors/test_tutorial003.py | 2 +- .../test_handling_errors/test_tutorial004.py | 2 +- .../test_handling_errors/test_tutorial005.py | 2 +- .../test_handling_errors/test_tutorial006.py | 2 +- .../test_tutorial001.py | 2 - .../test_tutorial002.py | 2 - .../test_tutorial003.py | 2 - .../test_header_params/test_tutorial001.py | 2 - .../test_header_params/test_tutorial002.py | 2 - .../test_header_params/test_tutorial003.py | 2 - .../test_metadata/test_tutorial001.py | 2 +- .../test_metadata/test_tutorial001_1.py | 2 +- .../test_metadata/test_tutorial002.py | 2 +- .../test_metadata/test_tutorial003.py | 2 +- .../test_metadata/test_tutorial004.py | 2 +- .../test_middleware/test_tutorial001.py | 2 +- .../test_tutorial001.py | 1 - .../test_openapi_webhooks/test_tutorial001.py | 2 +- .../test_tutorial001.py | 2 +- .../test_tutorial002.py | 2 +- .../test_tutorial003.py | 2 +- .../test_tutorial004.py | 1 - .../test_tutorial005.py | 2 +- .../test_tutorial006.py | 2 +- .../test_tutorial007.py | 2 +- .../test_tutorial001.py | 1 - .../test_tutorial002.py | 1 - .../test_tutorial002b.py | 2 +- .../test_tutorial003_tutorial004.py | 2 - .../test_tutorial005.py | 1 - .../test_tutorial006.py | 2 +- .../test_path_params/test_tutorial001.py | 2 +- .../test_path_params/test_tutorial002.py | 2 +- .../test_path_params/test_tutorial003.py | 2 +- .../test_path_params/test_tutorial003b.py | 2 +- .../test_path_params/test_tutorial004.py | 2 +- .../test_path_params/test_tutorial005.py | 2 +- .../test_tutorial001.py | 2 - .../test_tutorial002_tutorial003.py | 8 +- .../test_tutorial004.py | 4 +- .../test_tutorial005.py | 4 +- .../test_tutorial006.py | 4 +- .../test_tutorial001_tutorial002.py | 4 +- .../test_python_types/test_tutorial003.py | 2 +- .../test_python_types/test_tutorial004.py | 2 +- .../test_python_types/test_tutorial005.py | 2 +- .../test_python_types/test_tutorial006.py | 2 +- .../test_python_types/test_tutorial007.py | 2 +- .../test_python_types/test_tutorial008.py | 2 +- .../test_python_types/test_tutorial008b.py | 2 +- .../test_tutorial009_tutorial009b.py | 3 +- .../test_python_types/test_tutorial009c.py | 2 +- .../test_python_types/test_tutorial010.py | 2 +- .../test_python_types/test_tutorial011.py | 1 - .../test_python_types/test_tutorial012.py | 7 - .../test_python_types/test_tutorial013.py | 2 +- .../test_tutorial001.py | 2 - .../test_tutorial002.py | 2 - .../test_query_params/test_tutorial001.py | 2 +- .../test_query_params/test_tutorial002.py | 1 - .../test_query_params/test_tutorial003.py | 1 - .../test_query_params/test_tutorial004.py | 1 - .../test_query_params/test_tutorial005.py | 2 +- .../test_query_params/test_tutorial006.py | 1 - .../test_tutorial001.py | 1 - .../test_tutorial002.py | 2 - .../test_tutorial003.py | 2 - .../test_tutorial004.py | 11 - .../test_tutorial005.py | 4 +- .../test_tutorial006.py | 4 +- .../test_tutorial006c.py | 2 - .../test_tutorial007.py | 2 - .../test_tutorial008.py | 2 - .../test_tutorial009.py | 2 - .../test_tutorial010.py | 2 - .../test_tutorial011.py | 2 - .../test_tutorial012.py | 4 +- .../test_tutorial013.py | 4 +- .../test_tutorial014.py | 2 - .../test_tutorial015.py | 1 - .../test_request_files/test_tutorial001.py | 4 +- .../test_request_files/test_tutorial001_02.py | 2 - .../test_request_files/test_tutorial001_03.py | 4 +- .../test_request_files/test_tutorial002.py | 4 +- .../test_request_files/test_tutorial003.py | 4 +- .../test_tutorial001.py | 4 +- .../test_tutorial002.py | 4 +- .../test_request_forms/test_tutorial001.py | 4 +- .../test_tutorial001.py | 4 +- .../test_tutorial001.py | 2 +- .../test_response_cookies/test_tutorial001.py | 2 +- .../test_response_cookies/test_tutorial002.py | 2 +- .../test_tutorial001.py | 1 - .../test_tutorial002.py | 2 +- .../test_response_headers/test_tutorial001.py | 2 +- .../test_response_headers/test_tutorial002.py | 2 +- .../test_tutorial001_tutorial001_01.py | 2 - .../test_response_model/test_tutorial002.py | 1 - .../test_response_model/test_tutorial003.py | 1 - .../test_tutorial003_01.py | 1 - .../test_tutorial003_02.py | 2 +- .../test_tutorial003_03.py | 2 +- .../test_tutorial003_04.py | 1 - .../test_tutorial003_05.py | 1 - .../test_response_model/test_tutorial004.py | 1 - .../test_response_model/test_tutorial005.py | 1 - .../test_response_model/test_tutorial006.py | 1 - .../test_tutorial001_tutorial002.py | 4 +- .../test_tutorial001.py | 1 - .../test_tutorial002.py | 1 - .../test_tutorial003.py | 2 - .../test_tutorial004.py | 2 - .../test_tutorial005.py | 2 - .../test_security/test_tutorial001.py | 4 +- .../test_security/test_tutorial002.py | 2 - .../test_security/test_tutorial003.py | 2 - .../test_security/test_tutorial004.py | 2 - .../test_security/test_tutorial005.py | 2 - .../test_security/test_tutorial006.py | 4 +- .../test_security/test_tutorial007.py | 4 +- .../test_tutorial001.py | 1 - .../test_tutorial002.py | 1 - .../test_tutorial/test_settings/test_app01.py | 2 +- .../test_tutorial/test_settings/test_app02.py | 4 +- .../test_tutorial/test_settings/test_app03.py | 4 +- .../test_settings/test_tutorial001.py | 2 +- .../test_sql_databases/test_tutorial001.py | 2 - .../test_sql_databases/test_tutorial002.py | 2 - .../test_static_files/test_tutorial001.py | 2 +- .../test_sub_applications/test_tutorial001.py | 2 +- .../test_templates/test_tutorial001.py | 2 +- .../test_tutorial/test_testing/test_main_a.py | 2 +- .../test_tutorial/test_testing/test_main_b.py | 2 - .../test_testing/test_tutorial001.py | 2 +- .../test_testing/test_tutorial002.py | 2 +- .../test_testing/test_tutorial003.py | 2 +- .../test_testing/test_tutorial004.py | 2 +- .../test_tutorial001.py | 2 - .../test_tutorial001.py | 2 +- .../test_websockets/test_tutorial001.py | 2 +- .../test_websockets/test_tutorial002.py | 2 - .../test_websockets/test_tutorial003.py | 2 +- .../test_wsgi/test_tutorial001.py | 2 +- 655 files changed, 3703 insertions(+), 5660 deletions(-) create mode 100644 docs_src/additional_responses/tutorial001_py310.py delete mode 100644 docs_src/additional_responses/tutorial002_py39.py create mode 100644 docs_src/additional_responses/tutorial003_py310.py delete mode 100644 docs_src/additional_responses/tutorial004_py39.py delete mode 100644 docs_src/additional_status_codes/tutorial001_an_py39.py delete mode 100644 docs_src/additional_status_codes/tutorial001_py39.py create mode 100644 docs_src/advanced_middleware/tutorial001_py310.py create mode 100644 docs_src/advanced_middleware/tutorial002_py310.py create mode 100644 docs_src/advanced_middleware/tutorial003_py310.py rename docs_src/app_testing/{app_b_an_py39 => app_a_py310}/__init__.py (100%) create mode 100644 docs_src/app_testing/app_a_py310/main.py create mode 100644 docs_src/app_testing/app_a_py310/test_main.py delete mode 100644 docs_src/app_testing/app_b_an_py39/main.py delete mode 100644 docs_src/app_testing/app_b_an_py39/test_main.py delete mode 100644 docs_src/app_testing/app_b_py39/main.py delete mode 100644 docs_src/app_testing/app_b_py39/test_main.py create mode 100644 docs_src/app_testing/tutorial001_py310.py create mode 100644 docs_src/app_testing/tutorial002_py310.py create mode 100644 docs_src/app_testing/tutorial003_py310.py create mode 100644 docs_src/app_testing/tutorial004_py310.py rename docs_src/{app_testing/app_b_py39 => async_tests/app_a_py310}/__init__.py (100%) create mode 100644 docs_src/async_tests/app_a_py310/main.py create mode 100644 docs_src/async_tests/app_a_py310/test_main.py create mode 100644 docs_src/authentication_error_status_code/tutorial001_an_py310.py create mode 100644 docs_src/background_tasks/tutorial001_py310.py delete mode 100644 docs_src/background_tasks/tutorial002_an_py39.py delete mode 100644 docs_src/background_tasks/tutorial002_py39.py create mode 100644 docs_src/behind_a_proxy/tutorial001_01_py310.py create mode 100644 docs_src/behind_a_proxy/tutorial001_py310.py create mode 100644 docs_src/behind_a_proxy/tutorial002_py310.py create mode 100644 docs_src/behind_a_proxy/tutorial003_py310.py create mode 100644 docs_src/behind_a_proxy/tutorial004_py310.py rename docs_src/bigger_applications/{app_py39/internal => app_an_py310}/__init__.py (100%) create mode 100644 docs_src/bigger_applications/app_an_py310/dependencies.py rename docs_src/bigger_applications/{app_py39/routers => app_an_py310/internal}/__init__.py (100%) rename docs_src/bigger_applications/{app_py39 => app_an_py310}/internal/admin.py (100%) create mode 100644 docs_src/bigger_applications/app_an_py310/main.py create mode 100644 docs_src/bigger_applications/app_an_py310/routers/__init__.py rename docs_src/bigger_applications/{app_py39 => app_an_py310}/routers/items.py (100%) rename docs_src/bigger_applications/{app_py39 => app_an_py310}/routers/users.py (100%) delete mode 100644 docs_src/body/tutorial001_py39.py delete mode 100644 docs_src/body/tutorial002_py39.py delete mode 100644 docs_src/body/tutorial003_py39.py delete mode 100644 docs_src/body/tutorial004_py39.py delete mode 100644 docs_src/body_fields/tutorial001_an_py39.py delete mode 100644 docs_src/body_fields/tutorial001_py39.py delete mode 100644 docs_src/body_multiple_params/tutorial001_an_py39.py delete mode 100644 docs_src/body_multiple_params/tutorial001_py39.py delete mode 100644 docs_src/body_multiple_params/tutorial002_py39.py delete mode 100644 docs_src/body_multiple_params/tutorial003_an_py39.py delete mode 100644 docs_src/body_multiple_params/tutorial003_py39.py delete mode 100644 docs_src/body_multiple_params/tutorial004_an_py39.py delete mode 100644 docs_src/body_multiple_params/tutorial004_py39.py delete mode 100644 docs_src/body_multiple_params/tutorial005_an_py39.py delete mode 100644 docs_src/body_multiple_params/tutorial005_py39.py delete mode 100644 docs_src/body_nested_models/tutorial001_py39.py delete mode 100644 docs_src/body_nested_models/tutorial002_py39.py delete mode 100644 docs_src/body_nested_models/tutorial003_py39.py delete mode 100644 docs_src/body_nested_models/tutorial004_py39.py delete mode 100644 docs_src/body_nested_models/tutorial005_py39.py delete mode 100644 docs_src/body_nested_models/tutorial006_py39.py delete mode 100644 docs_src/body_nested_models/tutorial007_py39.py create mode 100644 docs_src/body_nested_models/tutorial008_py310.py create mode 100644 docs_src/body_nested_models/tutorial009_py310.py delete mode 100644 docs_src/body_updates/tutorial001_py39.py delete mode 100644 docs_src/body_updates/tutorial002_py39.py create mode 100644 docs_src/conditional_openapi/tutorial001_py310.py create mode 100644 docs_src/configure_swagger_ui/tutorial001_py310.py create mode 100644 docs_src/configure_swagger_ui/tutorial002_py310.py create mode 100644 docs_src/configure_swagger_ui/tutorial003_py310.py delete mode 100644 docs_src/cookie_param_models/tutorial001_an_py39.py delete mode 100644 docs_src/cookie_param_models/tutorial001_py39.py delete mode 100644 docs_src/cookie_param_models/tutorial002_an_py39.py delete mode 100644 docs_src/cookie_param_models/tutorial002_py39.py delete mode 100644 docs_src/cookie_params/tutorial001_an_py39.py delete mode 100644 docs_src/cookie_params/tutorial001_py39.py create mode 100644 docs_src/cors/tutorial001_py310.py create mode 100644 docs_src/custom_docs_ui/tutorial001_py310.py create mode 100644 docs_src/custom_docs_ui/tutorial002_py310.py delete mode 100644 docs_src/custom_request_and_route/tutorial001_an_py39.py delete mode 100644 docs_src/custom_request_and_route/tutorial001_py39.py delete mode 100644 docs_src/custom_request_and_route/tutorial002_an_py39.py delete mode 100644 docs_src/custom_request_and_route/tutorial002_py39.py delete mode 100644 docs_src/custom_request_and_route/tutorial003_py39.py create mode 100644 docs_src/custom_response/tutorial001_py310.py create mode 100644 docs_src/custom_response/tutorial001b_py310.py create mode 100644 docs_src/custom_response/tutorial002_py310.py create mode 100644 docs_src/custom_response/tutorial003_py310.py create mode 100644 docs_src/custom_response/tutorial004_py310.py create mode 100644 docs_src/custom_response/tutorial005_py310.py create mode 100644 docs_src/custom_response/tutorial006_py310.py create mode 100644 docs_src/custom_response/tutorial006b_py310.py create mode 100644 docs_src/custom_response/tutorial006c_py310.py create mode 100644 docs_src/custom_response/tutorial007_py310.py create mode 100644 docs_src/custom_response/tutorial008_py310.py create mode 100644 docs_src/custom_response/tutorial009_py310.py create mode 100644 docs_src/custom_response/tutorial009b_py310.py create mode 100644 docs_src/custom_response/tutorial009c_py310.py create mode 100644 docs_src/custom_response/tutorial010_py310.py delete mode 100644 docs_src/dataclasses_/tutorial001_py39.py delete mode 100644 docs_src/dataclasses_/tutorial002_py39.py delete mode 100644 docs_src/dataclasses_/tutorial003_py39.py create mode 100644 docs_src/debugging/tutorial001_py310.py delete mode 100644 docs_src/dependencies/tutorial001_02_an_py39.py delete mode 100644 docs_src/dependencies/tutorial001_an_py39.py delete mode 100644 docs_src/dependencies/tutorial001_py39.py delete mode 100644 docs_src/dependencies/tutorial002_an_py39.py delete mode 100644 docs_src/dependencies/tutorial002_py39.py delete mode 100644 docs_src/dependencies/tutorial003_an_py39.py delete mode 100644 docs_src/dependencies/tutorial003_py39.py delete mode 100644 docs_src/dependencies/tutorial004_an_py39.py delete mode 100644 docs_src/dependencies/tutorial004_py39.py delete mode 100644 docs_src/dependencies/tutorial005_an_py39.py delete mode 100644 docs_src/dependencies/tutorial005_py39.py create mode 100644 docs_src/dependencies/tutorial006_an_py310.py create mode 100644 docs_src/dependencies/tutorial006_py310.py create mode 100644 docs_src/dependencies/tutorial007_py310.py create mode 100644 docs_src/dependencies/tutorial008_an_py310.py create mode 100644 docs_src/dependencies/tutorial008_py310.py create mode 100644 docs_src/dependencies/tutorial008b_an_py310.py create mode 100644 docs_src/dependencies/tutorial008b_py310.py create mode 100644 docs_src/dependencies/tutorial008c_an_py310.py create mode 100644 docs_src/dependencies/tutorial008c_py310.py create mode 100644 docs_src/dependencies/tutorial008d_an_py310.py create mode 100644 docs_src/dependencies/tutorial008d_py310.py create mode 100644 docs_src/dependencies/tutorial008e_an_py310.py create mode 100644 docs_src/dependencies/tutorial008e_py310.py create mode 100644 docs_src/dependencies/tutorial010_py310.py create mode 100644 docs_src/dependencies/tutorial011_an_py310.py create mode 100644 docs_src/dependencies/tutorial011_py310.py create mode 100644 docs_src/dependencies/tutorial012_an_py310.py create mode 100644 docs_src/dependencies/tutorial012_py310.py delete mode 100644 docs_src/dependency_testing/tutorial001_an_py39.py delete mode 100644 docs_src/dependency_testing/tutorial001_py39.py delete mode 100644 docs_src/encoder/tutorial001_py39.py create mode 100644 docs_src/events/tutorial001_py310.py create mode 100644 docs_src/events/tutorial002_py310.py create mode 100644 docs_src/events/tutorial003_py310.py create mode 100644 docs_src/extending_openapi/tutorial001_py310.py delete mode 100644 docs_src/extra_data_types/tutorial001_an_py39.py delete mode 100644 docs_src/extra_data_types/tutorial001_py39.py delete mode 100644 docs_src/extra_models/tutorial001_py39.py delete mode 100644 docs_src/extra_models/tutorial002_py39.py delete mode 100644 docs_src/extra_models/tutorial003_py39.py create mode 100644 docs_src/extra_models/tutorial004_py310.py create mode 100644 docs_src/extra_models/tutorial005_py310.py create mode 100644 docs_src/first_steps/tutorial001_py310.py create mode 100644 docs_src/first_steps/tutorial003_py310.py create mode 100644 docs_src/generate_clients/tutorial001_py310.py create mode 100644 docs_src/generate_clients/tutorial002_py310.py create mode 100644 docs_src/generate_clients/tutorial003_py310.py create mode 100644 docs_src/generate_clients/tutorial004_py310.py create mode 100644 docs_src/graphql_/tutorial001_py310.py create mode 100644 docs_src/handling_errors/tutorial001_py310.py create mode 100644 docs_src/handling_errors/tutorial002_py310.py create mode 100644 docs_src/handling_errors/tutorial003_py310.py create mode 100644 docs_src/handling_errors/tutorial004_py310.py create mode 100644 docs_src/handling_errors/tutorial005_py310.py create mode 100644 docs_src/handling_errors/tutorial006_py310.py delete mode 100644 docs_src/header_param_models/tutorial001_an_py39.py delete mode 100644 docs_src/header_param_models/tutorial001_py39.py delete mode 100644 docs_src/header_param_models/tutorial002_an_py39.py delete mode 100644 docs_src/header_param_models/tutorial002_py39.py delete mode 100644 docs_src/header_param_models/tutorial003_an_py39.py delete mode 100644 docs_src/header_param_models/tutorial003_py39.py delete mode 100644 docs_src/header_params/tutorial001_an_py39.py delete mode 100644 docs_src/header_params/tutorial001_py39.py delete mode 100644 docs_src/header_params/tutorial002_an_py39.py delete mode 100644 docs_src/header_params/tutorial002_py39.py delete mode 100644 docs_src/header_params/tutorial003_an_py39.py delete mode 100644 docs_src/header_params/tutorial003_py39.py create mode 100644 docs_src/metadata/tutorial001_1_py310.py create mode 100644 docs_src/metadata/tutorial001_py310.py create mode 100644 docs_src/metadata/tutorial002_py310.py create mode 100644 docs_src/metadata/tutorial003_py310.py create mode 100644 docs_src/metadata/tutorial004_py310.py create mode 100644 docs_src/middleware/tutorial001_py310.py delete mode 100644 docs_src/openapi_callbacks/tutorial001_py39.py create mode 100644 docs_src/openapi_webhooks/tutorial001_py310.py create mode 100644 docs_src/path_operation_advanced_configuration/tutorial001_py310.py create mode 100644 docs_src/path_operation_advanced_configuration/tutorial002_py310.py create mode 100644 docs_src/path_operation_advanced_configuration/tutorial003_py310.py delete mode 100644 docs_src/path_operation_advanced_configuration/tutorial004_py39.py create mode 100644 docs_src/path_operation_advanced_configuration/tutorial005_py310.py create mode 100644 docs_src/path_operation_advanced_configuration/tutorial006_py310.py rename docs_src/path_operation_advanced_configuration/{tutorial007_pv1_py39.py => tutorial007_py310.py} (68%) delete mode 100644 docs_src/path_operation_configuration/tutorial001_py39.py delete mode 100644 docs_src/path_operation_configuration/tutorial002_py39.py create mode 100644 docs_src/path_operation_configuration/tutorial002b_py310.py delete mode 100644 docs_src/path_operation_configuration/tutorial003_py39.py delete mode 100644 docs_src/path_operation_configuration/tutorial004_py39.py delete mode 100644 docs_src/path_operation_configuration/tutorial005_py39.py create mode 100644 docs_src/path_operation_configuration/tutorial006_py310.py create mode 100644 docs_src/path_params/tutorial001_py310.py create mode 100644 docs_src/path_params/tutorial002_py310.py create mode 100644 docs_src/path_params/tutorial003_py310.py create mode 100644 docs_src/path_params/tutorial003b_py310.py create mode 100644 docs_src/path_params/tutorial004_py310.py create mode 100644 docs_src/path_params/tutorial005_py310.py create mode 100644 docs_src/path_params_numeric_validations/tutorial002_an_py310.py create mode 100644 docs_src/path_params_numeric_validations/tutorial002_py310.py create mode 100644 docs_src/path_params_numeric_validations/tutorial003_an_py310.py create mode 100644 docs_src/path_params_numeric_validations/tutorial003_py310.py create mode 100644 docs_src/path_params_numeric_validations/tutorial004_an_py310.py create mode 100644 docs_src/path_params_numeric_validations/tutorial004_py310.py create mode 100644 docs_src/path_params_numeric_validations/tutorial005_an_py310.py create mode 100644 docs_src/path_params_numeric_validations/tutorial005_py310.py rename docs_src/path_params_numeric_validations/{tutorial001_an_py39.py => tutorial006_an_py310.py} (61%) rename docs_src/path_params_numeric_validations/{tutorial001_py39.py => tutorial006_py310.py} (53%) delete mode 100644 docs_src/pydantic_v1_in_v2/tutorial001_an_py39.py delete mode 100644 docs_src/pydantic_v1_in_v2/tutorial002_an_py39.py delete mode 100644 docs_src/pydantic_v1_in_v2/tutorial003_an_py39.py delete mode 100644 docs_src/pydantic_v1_in_v2/tutorial004_an_py39.py create mode 100644 docs_src/python_types/tutorial001_py310.py create mode 100644 docs_src/python_types/tutorial002_py310.py create mode 100644 docs_src/python_types/tutorial003_py310.py create mode 100644 docs_src/python_types/tutorial004_py310.py create mode 100644 docs_src/python_types/tutorial005_py310.py create mode 100644 docs_src/python_types/tutorial006_py310.py create mode 100644 docs_src/python_types/tutorial007_py310.py create mode 100644 docs_src/python_types/tutorial008_py310.py create mode 100644 docs_src/python_types/tutorial010_py310.py delete mode 100644 docs_src/python_types/tutorial011_py39.py delete mode 100644 docs_src/python_types/tutorial012_py39.py create mode 100644 docs_src/python_types/tutorial013_py310.py delete mode 100644 docs_src/query_param_models/tutorial001_an_py39.py delete mode 100644 docs_src/query_param_models/tutorial001_py39.py delete mode 100644 docs_src/query_param_models/tutorial002_an_py39.py delete mode 100644 docs_src/query_param_models/tutorial002_py39.py create mode 100644 docs_src/query_params/tutorial001_py310.py delete mode 100644 docs_src/query_params/tutorial002_py39.py delete mode 100644 docs_src/query_params/tutorial003_py39.py delete mode 100644 docs_src/query_params/tutorial004_py39.py create mode 100644 docs_src/query_params/tutorial005_py310.py delete mode 100644 docs_src/query_params/tutorial006_py39.py delete mode 100644 docs_src/query_params_str_validations/tutorial001_py39.py delete mode 100644 docs_src/query_params_str_validations/tutorial002_an_py39.py delete mode 100644 docs_src/query_params_str_validations/tutorial003_an_py39.py delete mode 100644 docs_src/query_params_str_validations/tutorial003_py39.py delete mode 100644 docs_src/query_params_str_validations/tutorial004_an_py39.py delete mode 100644 docs_src/query_params_str_validations/tutorial004_py39.py delete mode 100644 docs_src/query_params_str_validations/tutorial004_regex_an_py310.py rename docs_src/query_params_str_validations/{tutorial002_py39.py => tutorial005_an_py310.py} (65%) rename docs_src/query_params_str_validations/{tutorial009_py39.py => tutorial005_py310.py} (64%) rename docs_src/query_params_str_validations/{tutorial006c_py39.py => tutorial006_an_py310.py} (69%) rename docs_src/query_params_str_validations/{tutorial006c_an_py39.py => tutorial006_py310.py} (64%) delete mode 100644 docs_src/query_params_str_validations/tutorial007_an_py39.py delete mode 100644 docs_src/query_params_str_validations/tutorial007_py39.py delete mode 100644 docs_src/query_params_str_validations/tutorial008_an_py39.py delete mode 100644 docs_src/query_params_str_validations/tutorial008_py39.py delete mode 100644 docs_src/query_params_str_validations/tutorial009_an_py39.py delete mode 100644 docs_src/query_params_str_validations/tutorial010_an_py39.py delete mode 100644 docs_src/query_params_str_validations/tutorial010_py39.py rename docs_src/query_params_str_validations/{tutorial011_an_py39.py => tutorial012_an_py310.py} (52%) create mode 100644 docs_src/query_params_str_validations/tutorial012_py310.py rename docs_src/query_params_str_validations/{tutorial011_py39.py => tutorial013_an_py310.py} (56%) create mode 100644 docs_src/query_params_str_validations/tutorial013_py310.py delete mode 100644 docs_src/query_params_str_validations/tutorial014_an_py39.py delete mode 100644 docs_src/query_params_str_validations/tutorial014_py39.py delete mode 100644 docs_src/query_params_str_validations/tutorial015_an_py39.py delete mode 100644 docs_src/request_files/tutorial001_02_an_py39.py delete mode 100644 docs_src/request_files/tutorial001_02_py39.py create mode 100644 docs_src/request_files/tutorial001_03_an_py310.py create mode 100644 docs_src/request_files/tutorial001_03_py310.py create mode 100644 docs_src/request_files/tutorial001_an_py310.py create mode 100644 docs_src/request_files/tutorial001_py310.py create mode 100644 docs_src/request_files/tutorial002_an_py310.py create mode 100644 docs_src/request_files/tutorial002_py310.py create mode 100644 docs_src/request_files/tutorial003_an_py310.py create mode 100644 docs_src/request_files/tutorial003_py310.py create mode 100644 docs_src/request_form_models/tutorial001_an_py310.py create mode 100644 docs_src/request_form_models/tutorial001_py310.py create mode 100644 docs_src/request_form_models/tutorial002_an_py310.py create mode 100644 docs_src/request_form_models/tutorial002_py310.py create mode 100644 docs_src/request_forms/tutorial001_an_py310.py create mode 100644 docs_src/request_forms/tutorial001_py310.py create mode 100644 docs_src/request_forms_and_files/tutorial001_an_py310.py create mode 100644 docs_src/request_forms_and_files/tutorial001_py310.py create mode 100644 docs_src/response_change_status_code/tutorial001_py310.py create mode 100644 docs_src/response_cookies/tutorial001_py310.py create mode 100644 docs_src/response_cookies/tutorial002_py310.py delete mode 100644 docs_src/response_directly/tutorial001_py39.py create mode 100644 docs_src/response_directly/tutorial002_py310.py create mode 100644 docs_src/response_headers/tutorial001_py310.py create mode 100644 docs_src/response_headers/tutorial002_py310.py delete mode 100644 docs_src/response_model/tutorial001_01_py39.py delete mode 100644 docs_src/response_model/tutorial001_py39.py delete mode 100644 docs_src/response_model/tutorial002_py39.py delete mode 100644 docs_src/response_model/tutorial003_01_py39.py create mode 100644 docs_src/response_model/tutorial003_02_py310.py create mode 100644 docs_src/response_model/tutorial003_03_py310.py delete mode 100644 docs_src/response_model/tutorial003_04_py39.py delete mode 100644 docs_src/response_model/tutorial003_05_py39.py delete mode 100644 docs_src/response_model/tutorial003_py39.py delete mode 100644 docs_src/response_model/tutorial004_py39.py delete mode 100644 docs_src/response_model/tutorial005_py39.py delete mode 100644 docs_src/response_model/tutorial006_py39.py create mode 100644 docs_src/response_status_code/tutorial001_py310.py create mode 100644 docs_src/response_status_code/tutorial002_py310.py delete mode 100644 docs_src/schema_extra_example/tutorial001_pv1_py310.py delete mode 100644 docs_src/schema_extra_example/tutorial001_pv1_py39.py delete mode 100644 docs_src/schema_extra_example/tutorial001_py39.py delete mode 100644 docs_src/schema_extra_example/tutorial002_py39.py delete mode 100644 docs_src/schema_extra_example/tutorial003_an_py39.py delete mode 100644 docs_src/schema_extra_example/tutorial003_py39.py delete mode 100644 docs_src/schema_extra_example/tutorial004_an_py39.py delete mode 100644 docs_src/schema_extra_example/tutorial004_py39.py delete mode 100644 docs_src/schema_extra_example/tutorial005_an_py39.py delete mode 100644 docs_src/schema_extra_example/tutorial005_py39.py create mode 100644 docs_src/security/tutorial001_an_py310.py create mode 100644 docs_src/security/tutorial001_py310.py delete mode 100644 docs_src/security/tutorial002_an_py39.py delete mode 100644 docs_src/security/tutorial002_py39.py delete mode 100644 docs_src/security/tutorial003_an_py39.py delete mode 100644 docs_src/security/tutorial003_py39.py delete mode 100644 docs_src/security/tutorial004_an_py39.py delete mode 100644 docs_src/security/tutorial004_py39.py delete mode 100644 docs_src/security/tutorial005_an_py39.py delete mode 100644 docs_src/security/tutorial005_py39.py create mode 100644 docs_src/security/tutorial006_an_py310.py create mode 100644 docs_src/security/tutorial006_py310.py create mode 100644 docs_src/security/tutorial007_an_py310.py create mode 100644 docs_src/security/tutorial007_py310.py delete mode 100644 docs_src/separate_openapi_schemas/tutorial001_py39.py delete mode 100644 docs_src/separate_openapi_schemas/tutorial002_py39.py create mode 100644 docs_src/settings/app01_py310/__init__.py rename docs_src/settings/{app03_an_py39/config_pv1.py => app01_py310/config.py} (59%) create mode 100644 docs_src/settings/app01_py310/main.py create mode 100644 docs_src/settings/app02_an_py310/__init__.py rename docs_src/settings/{app03_py39/config_pv1.py => app02_an_py310/config.py} (58%) create mode 100644 docs_src/settings/app02_an_py310/main.py create mode 100644 docs_src/settings/app02_an_py310/test_main.py create mode 100644 docs_src/settings/app02_py310/__init__.py create mode 100644 docs_src/settings/app02_py310/config.py create mode 100644 docs_src/settings/app02_py310/main.py create mode 100644 docs_src/settings/app02_py310/test_main.py create mode 100644 docs_src/settings/app03_an_py310/__init__.py create mode 100644 docs_src/settings/app03_an_py310/config.py create mode 100644 docs_src/settings/app03_an_py310/main.py create mode 100644 docs_src/settings/app03_py310/__init__.py create mode 100644 docs_src/settings/app03_py310/config.py create mode 100644 docs_src/settings/app03_py310/main.py rename docs_src/settings/{tutorial001_pv1_py39.py => tutorial001_py310.py} (89%) delete mode 100644 docs_src/sql_databases/tutorial001_an_py39.py delete mode 100644 docs_src/sql_databases/tutorial001_py39.py delete mode 100644 docs_src/sql_databases/tutorial002_an_py39.py delete mode 100644 docs_src/sql_databases/tutorial002_py39.py create mode 100644 docs_src/static_files/tutorial001_py310.py create mode 100644 docs_src/sub_applications/tutorial001_py310.py create mode 100644 docs_src/templates/tutorial001_py310.py create mode 100644 docs_src/using_request_directly/tutorial001_py310.py create mode 100644 docs_src/websockets/tutorial001_py310.py delete mode 100644 docs_src/websockets/tutorial002_an_py39.py delete mode 100644 docs_src/websockets/tutorial002_py39.py create mode 100644 docs_src/websockets/tutorial003_py310.py create mode 100644 docs_src/wsgi/tutorial001_py310.py delete mode 100644 tests/test_tutorial/test_python_types/test_tutorial012.py diff --git a/docs/en/docs/advanced/additional-responses.md b/docs/en/docs/advanced/additional-responses.md index bb70753ed..6306bd1f9 100644 --- a/docs/en/docs/advanced/additional-responses.md +++ b/docs/en/docs/advanced/additional-responses.md @@ -26,7 +26,7 @@ Each of those response `dict`s can have a key `model`, containing a Pydantic mod For example, to declare another response with a status code `404` and a Pydantic model `Message`, you can write: -{* ../../docs_src/additional_responses/tutorial001_py39.py hl[18,22] *} +{* ../../docs_src/additional_responses/tutorial001_py310.py hl[18,22] *} /// note @@ -203,7 +203,7 @@ For example, you can declare a response with a status code `404` that uses a Pyd And a response with a status code `200` that uses your `response_model`, but includes a custom `example`: -{* ../../docs_src/additional_responses/tutorial003_py39.py hl[20:31] *} +{* ../../docs_src/additional_responses/tutorial003_py310.py hl[20:31] *} It will all be combined and included in your OpenAPI, and shown in the API docs: diff --git a/docs/en/docs/advanced/advanced-dependencies.md b/docs/en/docs/advanced/advanced-dependencies.md index 0d03507b7..3a23a6d1a 100644 --- a/docs/en/docs/advanced/advanced-dependencies.md +++ b/docs/en/docs/advanced/advanced-dependencies.md @@ -18,7 +18,7 @@ Not the class itself (which is already a callable), but an instance of that clas To do that, we declare a method `__call__`: -{* ../../docs_src/dependencies/tutorial011_an_py39.py hl[12] *} +{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[12] *} In this case, this `__call__` is what **FastAPI** will use to check for additional parameters and sub-dependencies, and this is what will be called to pass a value to the parameter in your *path operation function* later. @@ -26,7 +26,7 @@ In this case, this `__call__` is what **FastAPI** will use to check for addition And now, we can use `__init__` to declare the parameters of the instance that we can use to "parameterize" the dependency: -{* ../../docs_src/dependencies/tutorial011_an_py39.py hl[9] *} +{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[9] *} In this case, **FastAPI** won't ever touch or care about `__init__`, we will use it directly in our code. @@ -34,7 +34,7 @@ In this case, **FastAPI** won't ever touch or care about `__init__`, we will use We could create an instance of this class with: -{* ../../docs_src/dependencies/tutorial011_an_py39.py hl[18] *} +{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[18] *} And that way we are able to "parameterize" our dependency, that now has `"bar"` inside of it, as the attribute `checker.fixed_content`. @@ -50,7 +50,7 @@ checker(q="somequery") ...and pass whatever that returns as the value of the dependency in our *path operation function* as the parameter `fixed_content_included`: -{* ../../docs_src/dependencies/tutorial011_an_py39.py hl[22] *} +{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[22] *} /// tip diff --git a/docs/en/docs/advanced/async-tests.md b/docs/en/docs/advanced/async-tests.md index 65ddc60b2..cefb1d184 100644 --- a/docs/en/docs/advanced/async-tests.md +++ b/docs/en/docs/advanced/async-tests.md @@ -32,11 +32,11 @@ For a simple example, let's consider a file structure similar to the one describ The file `main.py` would have: -{* ../../docs_src/async_tests/app_a_py39/main.py *} +{* ../../docs_src/async_tests/app_a_py310/main.py *} The file `test_main.py` would have the tests for `main.py`, it could look like this now: -{* ../../docs_src/async_tests/app_a_py39/test_main.py *} +{* ../../docs_src/async_tests/app_a_py310/test_main.py *} ## Run it { #run-it } @@ -56,7 +56,7 @@ $ pytest The marker `@pytest.mark.anyio` tells pytest that this test function should be called asynchronously: -{* ../../docs_src/async_tests/app_a_py39/test_main.py hl[7] *} +{* ../../docs_src/async_tests/app_a_py310/test_main.py hl[7] *} /// tip @@ -66,7 +66,7 @@ Note that the test function is now `async def` instead of just `def` as before w Then we can create an `AsyncClient` with the app, and send async requests to it, using `await`. -{* ../../docs_src/async_tests/app_a_py39/test_main.py hl[9:12] *} +{* ../../docs_src/async_tests/app_a_py310/test_main.py hl[9:12] *} This is the equivalent to: diff --git a/docs/en/docs/advanced/behind-a-proxy.md b/docs/en/docs/advanced/behind-a-proxy.md index 4fef02bd1..770e9cd3c 100644 --- a/docs/en/docs/advanced/behind-a-proxy.md +++ b/docs/en/docs/advanced/behind-a-proxy.md @@ -44,7 +44,7 @@ $ fastapi run --forwarded-allow-ips="*" For example, let's say you define a *path operation* `/items/`: -{* ../../docs_src/behind_a_proxy/tutorial001_01_py39.py hl[6] *} +{* ../../docs_src/behind_a_proxy/tutorial001_01_py310.py hl[6] *} If the client tries to go to `/items`, by default, it would be redirected to `/items/`. @@ -115,7 +115,7 @@ In this case, the original path `/app` would actually be served at `/api/v1/app` Even though all your code is written assuming there's just `/app`. -{* ../../docs_src/behind_a_proxy/tutorial001_py39.py hl[6] *} +{* ../../docs_src/behind_a_proxy/tutorial001_py310.py hl[6] *} And the proxy would be **"stripping"** the **path prefix** on the fly before transmitting the request to the app server (probably Uvicorn via FastAPI CLI), keeping your application convinced that it is being served at `/app`, so that you don't have to update all your code to include the prefix `/api/v1`. @@ -193,7 +193,7 @@ You can get the current `root_path` used by your application for each request, i Here we are including it in the message just for demonstration purposes. -{* ../../docs_src/behind_a_proxy/tutorial001_py39.py hl[8] *} +{* ../../docs_src/behind_a_proxy/tutorial001_py310.py hl[8] *} Then, if you start Uvicorn with: @@ -220,7 +220,7 @@ The response would be something like: Alternatively, if you don't have a way to provide a command line option like `--root-path` or equivalent, you can set the `root_path` parameter when creating your FastAPI app: -{* ../../docs_src/behind_a_proxy/tutorial002_py39.py hl[3] *} +{* ../../docs_src/behind_a_proxy/tutorial002_py310.py hl[3] *} Passing the `root_path` to `FastAPI` would be the equivalent of passing the `--root-path` command line option to Uvicorn or Hypercorn. @@ -400,7 +400,7 @@ If you pass a custom list of `servers` and there's a `root_path` (because your A For example: -{* ../../docs_src/behind_a_proxy/tutorial003_py39.py hl[4:7] *} +{* ../../docs_src/behind_a_proxy/tutorial003_py310.py hl[4:7] *} Will generate an OpenAPI schema like: @@ -455,7 +455,7 @@ If you don't specify the `servers` parameter and `root_path` is equal to `/`, th If you don't want **FastAPI** to include an automatic server using the `root_path`, you can use the parameter `root_path_in_servers=False`: -{* ../../docs_src/behind_a_proxy/tutorial004_py39.py hl[9] *} +{* ../../docs_src/behind_a_proxy/tutorial004_py310.py hl[9] *} and then it won't include it in the OpenAPI schema. diff --git a/docs/en/docs/advanced/custom-response.md b/docs/en/docs/advanced/custom-response.md index e53409c39..8b4b3da33 100644 --- a/docs/en/docs/advanced/custom-response.md +++ b/docs/en/docs/advanced/custom-response.md @@ -30,7 +30,7 @@ This is because by default, FastAPI will inspect every item inside and make sure But if you are certain that the content that you are returning is **serializable with JSON**, you can pass it directly to the response class and avoid the extra overhead that FastAPI would have by passing your return content through the `jsonable_encoder` before passing it to the response class. -{* ../../docs_src/custom_response/tutorial001b_py39.py hl[2,7] *} +{* ../../docs_src/custom_response/tutorial001b_py310.py hl[2,7] *} /// info @@ -55,7 +55,7 @@ To return a response with HTML directly from **FastAPI**, use `HTMLResponse`. * Import `HTMLResponse`. * Pass `HTMLResponse` as the parameter `response_class` of your *path operation decorator*. -{* ../../docs_src/custom_response/tutorial002_py39.py hl[2,7] *} +{* ../../docs_src/custom_response/tutorial002_py310.py hl[2,7] *} /// info @@ -73,7 +73,7 @@ As seen in [Return a Response directly](response-directly.md){.internal-link tar The same example from above, returning an `HTMLResponse`, could look like: -{* ../../docs_src/custom_response/tutorial003_py39.py hl[2,7,19] *} +{* ../../docs_src/custom_response/tutorial003_py310.py hl[2,7,19] *} /// warning @@ -97,7 +97,7 @@ The `response_class` will then be used only to document the OpenAPI *path operat For example, it could be something like: -{* ../../docs_src/custom_response/tutorial004_py39.py hl[7,21,23] *} +{* ../../docs_src/custom_response/tutorial004_py310.py hl[7,21,23] *} In this example, the function `generate_html_response()` already generates and returns a `Response` instead of returning the HTML in a `str`. @@ -136,7 +136,7 @@ It accepts the following parameters: FastAPI (actually Starlette) will automatically include a Content-Length header. It will also include a Content-Type header, based on the `media_type` and appending a charset for text types. -{* ../../docs_src/response_directly/tutorial002_py39.py hl[1,18] *} +{* ../../docs_src/response_directly/tutorial002_py310.py hl[1,18] *} ### `HTMLResponse` { #htmlresponse } @@ -146,7 +146,7 @@ Takes some text or bytes and returns an HTML response, as you read above. Takes some text or bytes and returns a plain text response. -{* ../../docs_src/custom_response/tutorial005_py39.py hl[2,7,9] *} +{* ../../docs_src/custom_response/tutorial005_py310.py hl[2,7,9] *} ### `JSONResponse` { #jsonresponse } @@ -180,7 +180,7 @@ This requires installing `ujson` for example with `pip install ujson`. /// -{* ../../docs_src/custom_response/tutorial001_py39.py hl[2,7] *} +{* ../../docs_src/custom_response/tutorial001_py310.py hl[2,7] *} /// tip @@ -194,14 +194,14 @@ Returns an HTTP redirect. Uses a 307 status code (Temporary Redirect) by default You can return a `RedirectResponse` directly: -{* ../../docs_src/custom_response/tutorial006_py39.py hl[2,9] *} +{* ../../docs_src/custom_response/tutorial006_py310.py hl[2,9] *} --- Or you can use it in the `response_class` parameter: -{* ../../docs_src/custom_response/tutorial006b_py39.py hl[2,7,9] *} +{* ../../docs_src/custom_response/tutorial006b_py310.py hl[2,7,9] *} If you do that, then you can return the URL directly from your *path operation* function. @@ -211,13 +211,13 @@ In this case, the `status_code` used will be the default one for the `RedirectRe You can also use the `status_code` parameter combined with the `response_class` parameter: -{* ../../docs_src/custom_response/tutorial006c_py39.py hl[2,7,9] *} +{* ../../docs_src/custom_response/tutorial006c_py310.py hl[2,7,9] *} ### `StreamingResponse` { #streamingresponse } Takes an async generator or a normal generator/iterator and streams the response body. -{* ../../docs_src/custom_response/tutorial007_py39.py hl[2,14] *} +{* ../../docs_src/custom_response/tutorial007_py310.py hl[2,14] *} #### Using `StreamingResponse` with file-like objects { #using-streamingresponse-with-file-like-objects } @@ -227,7 +227,7 @@ That way, you don't have to read it all first in memory, and you can pass that g This includes many libraries to interact with cloud storage, video processing, and others. -{* ../../docs_src/custom_response/tutorial008_py39.py hl[2,10:12,14] *} +{* ../../docs_src/custom_response/tutorial008_py310.py hl[2,10:12,14] *} 1. This is the generator function. It's a "generator function" because it contains `yield` statements inside. 2. By using a `with` block, we make sure that the file-like object is closed after the generator function is done. So, after it finishes sending the response. @@ -256,11 +256,11 @@ Takes a different set of arguments to instantiate than the other response types: File responses will include appropriate `Content-Length`, `Last-Modified` and `ETag` headers. -{* ../../docs_src/custom_response/tutorial009_py39.py hl[2,10] *} +{* ../../docs_src/custom_response/tutorial009_py310.py hl[2,10] *} You can also use the `response_class` parameter: -{* ../../docs_src/custom_response/tutorial009b_py39.py hl[2,8,10] *} +{* ../../docs_src/custom_response/tutorial009b_py310.py hl[2,8,10] *} In this case, you can return the file path directly from your *path operation* function. @@ -274,7 +274,7 @@ Let's say you want it to return indented and formatted JSON, so you want to use You could create a `CustomORJSONResponse`. The main thing you have to do is create a `Response.render(content)` method that returns the content as `bytes`: -{* ../../docs_src/custom_response/tutorial009c_py39.py hl[9:14,17] *} +{* ../../docs_src/custom_response/tutorial009c_py310.py hl[9:14,17] *} Now instead of returning: @@ -300,7 +300,7 @@ The parameter that defines this is `default_response_class`. In the example below, **FastAPI** will use `ORJSONResponse` by default, in all *path operations*, instead of `JSONResponse`. -{* ../../docs_src/custom_response/tutorial010_py39.py hl[2,4] *} +{* ../../docs_src/custom_response/tutorial010_py310.py hl[2,4] *} /// tip diff --git a/docs/en/docs/advanced/events.md b/docs/en/docs/advanced/events.md index 9414b7a3f..302e96325 100644 --- a/docs/en/docs/advanced/events.md +++ b/docs/en/docs/advanced/events.md @@ -30,7 +30,7 @@ Let's start with an example and then see it in detail. We create an async function `lifespan()` with `yield` like this: -{* ../../docs_src/events/tutorial003_py39.py hl[16,19] *} +{* ../../docs_src/events/tutorial003_py310.py hl[16,19] *} Here we are simulating the expensive *startup* operation of loading the model by putting the (fake) model function in the dictionary with machine learning models before the `yield`. This code will be executed **before** the application **starts taking requests**, during the *startup*. @@ -48,7 +48,7 @@ Maybe you need to start a new version, or you just got tired of running it. 🤷 The first thing to notice, is that we are defining an async function with `yield`. This is very similar to Dependencies with `yield`. -{* ../../docs_src/events/tutorial003_py39.py hl[14:19] *} +{* ../../docs_src/events/tutorial003_py310.py hl[14:19] *} The first part of the function, before the `yield`, will be executed **before** the application starts. @@ -60,7 +60,7 @@ If you check, the function is decorated with an `@asynccontextmanager`. That converts the function into something called an "**async context manager**". -{* ../../docs_src/events/tutorial003_py39.py hl[1,13] *} +{* ../../docs_src/events/tutorial003_py310.py hl[1,13] *} A **context manager** in Python is something that you can use in a `with` statement, for example, `open()` can be used as a context manager: @@ -82,7 +82,7 @@ In our code example above, we don't use it directly, but we pass it to FastAPI f The `lifespan` parameter of the `FastAPI` app takes an **async context manager**, so we can pass our new `lifespan` async context manager to it. -{* ../../docs_src/events/tutorial003_py39.py hl[22] *} +{* ../../docs_src/events/tutorial003_py310.py hl[22] *} ## Alternative Events (deprecated) { #alternative-events-deprecated } @@ -104,7 +104,7 @@ These functions can be declared with `async def` or normal `def`. To add a function that should be run before the application starts, declare it with the event `"startup"`: -{* ../../docs_src/events/tutorial001_py39.py hl[8] *} +{* ../../docs_src/events/tutorial001_py310.py hl[8] *} In this case, the `startup` event handler function will initialize the items "database" (just a `dict`) with some values. @@ -116,7 +116,7 @@ And your application won't start receiving requests until all the `startup` even To add a function that should be run when the application is shutting down, declare it with the event `"shutdown"`: -{* ../../docs_src/events/tutorial002_py39.py hl[6] *} +{* ../../docs_src/events/tutorial002_py310.py hl[6] *} Here, the `shutdown` event handler function will write a text line `"Application shutdown"` to a file `log.txt`. diff --git a/docs/en/docs/advanced/generate-clients.md b/docs/en/docs/advanced/generate-clients.md index 2d0c2aa0c..1e6173c9a 100644 --- a/docs/en/docs/advanced/generate-clients.md +++ b/docs/en/docs/advanced/generate-clients.md @@ -40,7 +40,7 @@ Some of these solutions may also be open source or offer free tiers, so you can Let's start with a simple FastAPI application: -{* ../../docs_src/generate_clients/tutorial001_py39.py hl[7:9,12:13,16:17,21] *} +{* ../../docs_src/generate_clients/tutorial001_py310.py hl[7:9,12:13,16:17,21] *} Notice that the *path operations* define the models they use for request payload and response payload, using the models `Item` and `ResponseMessage`. @@ -98,7 +98,7 @@ In many cases, your FastAPI app will be bigger, and you will probably use tags t For example, you could have a section for **items** and another section for **users**, and they could be separated by tags: -{* ../../docs_src/generate_clients/tutorial002_py39.py hl[21,26,34] *} +{* ../../docs_src/generate_clients/tutorial002_py310.py hl[21,26,34] *} ### Generate a TypeScript Client with Tags { #generate-a-typescript-client-with-tags } @@ -145,7 +145,7 @@ For example, here it is using the first tag (you will probably have only one tag You can then pass that custom function to **FastAPI** as the `generate_unique_id_function` parameter: -{* ../../docs_src/generate_clients/tutorial003_py39.py hl[6:7,10] *} +{* ../../docs_src/generate_clients/tutorial003_py310.py hl[6:7,10] *} ### Generate a TypeScript Client with Custom Operation IDs { #generate-a-typescript-client-with-custom-operation-ids } @@ -167,7 +167,7 @@ But for the generated client, we could **modify** the OpenAPI operation IDs righ We could download the OpenAPI JSON to a file `openapi.json` and then we could **remove that prefixed tag** with a script like this: -{* ../../docs_src/generate_clients/tutorial004_py39.py *} +{* ../../docs_src/generate_clients/tutorial004_py310.py *} //// tab | Node.js diff --git a/docs/en/docs/advanced/middleware.md b/docs/en/docs/advanced/middleware.md index 765b38932..b448f5c52 100644 --- a/docs/en/docs/advanced/middleware.md +++ b/docs/en/docs/advanced/middleware.md @@ -57,13 +57,13 @@ Enforces that all incoming requests must either be `https` or `wss`. Any incoming request to `http` or `ws` will be redirected to the secure scheme instead. -{* ../../docs_src/advanced_middleware/tutorial001_py39.py hl[2,6] *} +{* ../../docs_src/advanced_middleware/tutorial001_py310.py hl[2,6] *} ## `TrustedHostMiddleware` { #trustedhostmiddleware } Enforces that all incoming requests have a correctly set `Host` header, in order to guard against HTTP Host Header attacks. -{* ../../docs_src/advanced_middleware/tutorial002_py39.py hl[2,6:8] *} +{* ../../docs_src/advanced_middleware/tutorial002_py310.py hl[2,6:8] *} The following arguments are supported: @@ -78,7 +78,7 @@ Handles GZip responses for any request that includes `"gzip"` in the `Accept-Enc The middleware will handle both standard and streaming responses. -{* ../../docs_src/advanced_middleware/tutorial003_py39.py hl[2,6] *} +{* ../../docs_src/advanced_middleware/tutorial003_py310.py hl[2,6] *} The following arguments are supported: diff --git a/docs/en/docs/advanced/openapi-webhooks.md b/docs/en/docs/advanced/openapi-webhooks.md index 59f060c03..f4f586f84 100644 --- a/docs/en/docs/advanced/openapi-webhooks.md +++ b/docs/en/docs/advanced/openapi-webhooks.md @@ -32,7 +32,7 @@ Webhooks are available in OpenAPI 3.1.0 and above, supported by FastAPI `0.99.0` When you create a **FastAPI** application, there is a `webhooks` attribute that you can use to define *webhooks*, the same way you would define *path operations*, for example with `@app.webhooks.post()`. -{* ../../docs_src/openapi_webhooks/tutorial001_py39.py hl[9:13,36:53] *} +{* ../../docs_src/openapi_webhooks/tutorial001_py310.py hl[9:13,36:53] *} The webhooks that you define will end up in the **OpenAPI** schema and the automatic **docs UI**. diff --git a/docs/en/docs/advanced/path-operation-advanced-configuration.md b/docs/en/docs/advanced/path-operation-advanced-configuration.md index 3d7bfdee5..fdc77c8a2 100644 --- a/docs/en/docs/advanced/path-operation-advanced-configuration.md +++ b/docs/en/docs/advanced/path-operation-advanced-configuration.md @@ -12,7 +12,7 @@ You can set the OpenAPI `operationId` to be used in your *path operation* with t You would have to make sure that it is unique for each operation. -{* ../../docs_src/path_operation_advanced_configuration/tutorial001_py39.py hl[6] *} +{* ../../docs_src/path_operation_advanced_configuration/tutorial001_py310.py hl[6] *} ### Using the *path operation function* name as the operationId { #using-the-path-operation-function-name-as-the-operationid } @@ -20,7 +20,7 @@ If you want to use your APIs' function names as `operationId`s, you can iterate You should do it after adding all your *path operations*. -{* ../../docs_src/path_operation_advanced_configuration/tutorial002_py39.py hl[2, 12:21, 24] *} +{* ../../docs_src/path_operation_advanced_configuration/tutorial002_py310.py hl[2, 12:21, 24] *} /// tip @@ -40,7 +40,7 @@ Even if they are in different modules (Python files). To exclude a *path operation* from the generated OpenAPI schema (and thus, from the automatic documentation systems), use the parameter `include_in_schema` and set it to `False`: -{* ../../docs_src/path_operation_advanced_configuration/tutorial003_py39.py hl[6] *} +{* ../../docs_src/path_operation_advanced_configuration/tutorial003_py310.py hl[6] *} ## Advanced description from docstring { #advanced-description-from-docstring } @@ -92,7 +92,7 @@ You can extend the OpenAPI schema for a *path operation* using the parameter `op This `openapi_extra` can be helpful, for example, to declare [OpenAPI Extensions](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#specificationExtensions): -{* ../../docs_src/path_operation_advanced_configuration/tutorial005_py39.py hl[6] *} +{* ../../docs_src/path_operation_advanced_configuration/tutorial005_py310.py hl[6] *} If you open the automatic API docs, your extension will show up at the bottom of the specific *path operation*. @@ -139,7 +139,7 @@ For example, you could decide to read and validate the request with your own cod You could do that with `openapi_extra`: -{* ../../docs_src/path_operation_advanced_configuration/tutorial006_py39.py hl[19:36, 39:40] *} +{* ../../docs_src/path_operation_advanced_configuration/tutorial006_py310.py hl[19:36, 39:40] *} In this example, we didn't declare any Pydantic model. In fact, the request body is not even parsed as JSON, it is read directly as `bytes`, and the function `magic_data_reader()` would be in charge of parsing it in some way. @@ -153,7 +153,7 @@ And you could do this even if the data type in the request is not JSON. For example, in this application we don't use FastAPI's integrated functionality to extract the JSON Schema from Pydantic models nor the automatic validation for JSON. In fact, we are declaring the request content type as YAML, not JSON: -{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py39.py hl[15:20, 22] *} +{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py310.py hl[15:20, 22] *} Nevertheless, although we are not using the default integrated functionality, we are still using a Pydantic model to manually generate the JSON Schema for the data that we want to receive in YAML. @@ -161,7 +161,7 @@ Then we use the request directly, and extract the body as `bytes`. This means th And then in our code, we parse that YAML content directly, and then we are again using the same Pydantic model to validate the YAML content: -{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py39.py hl[24:31] *} +{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py310.py hl[24:31] *} /// tip diff --git a/docs/en/docs/advanced/response-change-status-code.md b/docs/en/docs/advanced/response-change-status-code.md index d9708aa62..8aa601e7b 100644 --- a/docs/en/docs/advanced/response-change-status-code.md +++ b/docs/en/docs/advanced/response-change-status-code.md @@ -20,7 +20,7 @@ You can declare a parameter of type `Response` in your *path operation function* And then you can set the `status_code` in that *temporal* response object. -{* ../../docs_src/response_change_status_code/tutorial001_py39.py hl[1,9,12] *} +{* ../../docs_src/response_change_status_code/tutorial001_py310.py hl[1,9,12] *} And then you can return any object you need, as you normally would (a `dict`, a database model, etc). diff --git a/docs/en/docs/advanced/response-cookies.md b/docs/en/docs/advanced/response-cookies.md index 5b6fab112..cfc615d7e 100644 --- a/docs/en/docs/advanced/response-cookies.md +++ b/docs/en/docs/advanced/response-cookies.md @@ -6,7 +6,7 @@ You can declare a parameter of type `Response` in your *path operation function* And then you can set cookies in that *temporal* response object. -{* ../../docs_src/response_cookies/tutorial002_py39.py hl[1, 8:9] *} +{* ../../docs_src/response_cookies/tutorial002_py310.py hl[1, 8:9] *} And then you can return any object you need, as you normally would (a `dict`, a database model, etc). @@ -24,7 +24,7 @@ To do that, you can create a response as described in [Return a Response Directl Then set Cookies in it, and then return it: -{* ../../docs_src/response_cookies/tutorial001_py39.py hl[10:12] *} +{* ../../docs_src/response_cookies/tutorial001_py310.py hl[10:12] *} /// tip diff --git a/docs/en/docs/advanced/response-directly.md b/docs/en/docs/advanced/response-directly.md index 4374cb963..76cc50d03 100644 --- a/docs/en/docs/advanced/response-directly.md +++ b/docs/en/docs/advanced/response-directly.md @@ -54,7 +54,7 @@ Let's say that you want to return an Strawberry documentation. diff --git a/docs/en/docs/python-types.md b/docs/en/docs/python-types.md index f2ad35d71..90c32cec8 100644 --- a/docs/en/docs/python-types.md +++ b/docs/en/docs/python-types.md @@ -22,7 +22,7 @@ If you are a Python expert, and you already know everything about type hints, sk Let's start with a simple example: -{* ../../docs_src/python_types/tutorial001_py39.py *} +{* ../../docs_src/python_types/tutorial001_py310.py *} Calling this program outputs: @@ -36,7 +36,7 @@ The function does the following: * Converts the first letter of each one to upper case with `title()`. * Concatenates them with a space in the middle. -{* ../../docs_src/python_types/tutorial001_py39.py hl[2] *} +{* ../../docs_src/python_types/tutorial001_py310.py hl[2] *} ### Edit it { #edit-it } @@ -78,7 +78,7 @@ That's it. Those are the "type hints": -{* ../../docs_src/python_types/tutorial002_py39.py hl[1] *} +{* ../../docs_src/python_types/tutorial002_py310.py hl[1] *} That is not the same as declaring default values like would be with: @@ -106,7 +106,7 @@ With that, you can scroll, seeing the options, until you find the one that "ring Check this function, it already has type hints: -{* ../../docs_src/python_types/tutorial003_py39.py hl[1] *} +{* ../../docs_src/python_types/tutorial003_py310.py hl[1] *} Because the editor knows the types of the variables, you don't only get completion, you also get error checks: @@ -114,7 +114,7 @@ Because the editor knows the types of the variables, you don't only get completi Now you know that you have to fix it, convert `age` to a string with `str(age)`: -{* ../../docs_src/python_types/tutorial004_py39.py hl[2] *} +{* ../../docs_src/python_types/tutorial004_py310.py hl[2] *} ## Declaring types { #declaring-types } @@ -133,7 +133,7 @@ You can use, for example: * `bool` * `bytes` -{* ../../docs_src/python_types/tutorial005_py39.py hl[1] *} +{* ../../docs_src/python_types/tutorial005_py310.py hl[1] *} ### `typing` module { #typing-module } @@ -170,7 +170,7 @@ As the type, put `list`. As the list is a type that contains some internal types, you put them in square brackets: -{* ../../docs_src/python_types/tutorial006_py39.py hl[1] *} +{* ../../docs_src/python_types/tutorial006_py310.py hl[1] *} /// info @@ -196,7 +196,7 @@ And still, the editor knows it is a `str`, and provides support for that. You would do the same to declare `tuple`s and `set`s: -{* ../../docs_src/python_types/tutorial007_py39.py hl[1] *} +{* ../../docs_src/python_types/tutorial007_py310.py hl[1] *} This means: @@ -211,7 +211,7 @@ The first type parameter is for the keys of the `dict`. The second type parameter is for the values of the `dict`: -{* ../../docs_src/python_types/tutorial008_py39.py hl[1] *} +{* ../../docs_src/python_types/tutorial008_py310.py hl[1] *} This means: @@ -253,11 +253,11 @@ You can also declare a class as the type of a variable. Let's say you have a class `Person`, with a name: -{* ../../docs_src/python_types/tutorial010_py39.py hl[1:3] *} +{* ../../docs_src/python_types/tutorial010_py310.py hl[1:3] *} Then you can declare a variable to be of type `Person`: -{* ../../docs_src/python_types/tutorial010_py39.py hl[6] *} +{* ../../docs_src/python_types/tutorial010_py310.py hl[6] *} And then, again, you get all the editor support: @@ -299,7 +299,7 @@ Python also has a feature that allows putting **additional deprecated, but without removing it, pass the parameter `deprecated`: -{* ../../docs_src/path_operation_configuration/tutorial006_py39.py hl[16] *} +{* ../../docs_src/path_operation_configuration/tutorial006_py310.py hl[16] *} It will be clearly marked as deprecated in the interactive docs: diff --git a/docs/en/docs/tutorial/path-params-numeric-validations.md b/docs/en/docs/tutorial/path-params-numeric-validations.md index 8b1b8a839..de63a51f5 100644 --- a/docs/en/docs/tutorial/path-params-numeric-validations.md +++ b/docs/en/docs/tutorial/path-params-numeric-validations.md @@ -54,11 +54,11 @@ It doesn't matter for **FastAPI**. It will detect the parameters by their names, So, you can declare your function as: -{* ../../docs_src/path_params_numeric_validations/tutorial002_py39.py hl[7] *} +{* ../../docs_src/path_params_numeric_validations/tutorial002_py310.py hl[7] *} But keep in mind that if you use `Annotated`, you won't have this problem, it won't matter as you're not using the function parameter default values for `Query()` or `Path()`. -{* ../../docs_src/path_params_numeric_validations/tutorial002_an_py39.py *} +{* ../../docs_src/path_params_numeric_validations/tutorial002_an_py310.py *} ## Order the parameters as you need, tricks { #order-the-parameters-as-you-need-tricks } @@ -83,13 +83,13 @@ Pass `*`, as the first parameter of the function. Python won't do anything with that `*`, but it will know that all the following parameters should be called as keyword arguments (key-value pairs), also known as kwargs. Even if they don't have a default value. -{* ../../docs_src/path_params_numeric_validations/tutorial003_py39.py hl[7] *} +{* ../../docs_src/path_params_numeric_validations/tutorial003_py310.py hl[7] *} ### Better with `Annotated` { #better-with-annotated } Keep in mind that if you use `Annotated`, as you are not using function parameter default values, you won't have this problem, and you probably won't need to use `*`. -{* ../../docs_src/path_params_numeric_validations/tutorial003_an_py39.py hl[10] *} +{* ../../docs_src/path_params_numeric_validations/tutorial003_an_py310.py hl[10] *} ## Number validations: greater than or equal { #number-validations-greater-than-or-equal } @@ -97,7 +97,7 @@ With `Query` and `Path` (and others you'll see later) you can declare number con Here, with `ge=1`, `item_id` will need to be an integer number "`g`reater than or `e`qual" to `1`. -{* ../../docs_src/path_params_numeric_validations/tutorial004_an_py39.py hl[10] *} +{* ../../docs_src/path_params_numeric_validations/tutorial004_an_py310.py hl[10] *} ## Number validations: greater than and less than or equal { #number-validations-greater-than-and-less-than-or-equal } @@ -106,7 +106,7 @@ The same applies for: * `gt`: `g`reater `t`han * `le`: `l`ess than or `e`qual -{* ../../docs_src/path_params_numeric_validations/tutorial005_an_py39.py hl[10] *} +{* ../../docs_src/path_params_numeric_validations/tutorial005_an_py310.py hl[10] *} ## Number validations: floats, greater than and less than { #number-validations-floats-greater-than-and-less-than } @@ -118,7 +118,7 @@ So, `0.5` would be a valid value. But `0.0` or `0` would not. And the same for lt. -{* ../../docs_src/path_params_numeric_validations/tutorial006_an_py39.py hl[13] *} +{* ../../docs_src/path_params_numeric_validations/tutorial006_an_py310.py hl[13] *} ## Recap { #recap } diff --git a/docs/en/docs/tutorial/path-params.md b/docs/en/docs/tutorial/path-params.md index cf312f1fe..8adbbcfa1 100644 --- a/docs/en/docs/tutorial/path-params.md +++ b/docs/en/docs/tutorial/path-params.md @@ -2,7 +2,7 @@ You can declare path "parameters" or "variables" with the same syntax used by Python format strings: -{* ../../docs_src/path_params/tutorial001_py39.py hl[6:7] *} +{* ../../docs_src/path_params/tutorial001_py310.py hl[6:7] *} The value of the path parameter `item_id` will be passed to your function as the argument `item_id`. @@ -16,7 +16,7 @@ So, if you run this example and go to Item: - if x_token != fake_secret_token: - raise HTTPException(status_code=400, detail="Invalid X-Token header") - if item.id in fake_db: - raise HTTPException(status_code=409, detail="Item already exists") - fake_db[item.id] = item.model_dump() - return item diff --git a/docs_src/app_testing/app_b_an_py39/test_main.py b/docs_src/app_testing/app_b_an_py39/test_main.py deleted file mode 100644 index 4e1c51ecc..000000000 --- a/docs_src/app_testing/app_b_an_py39/test_main.py +++ /dev/null @@ -1,65 +0,0 @@ -from fastapi.testclient import TestClient - -from .main import app - -client = TestClient(app) - - -def test_read_item(): - response = client.get("/items/foo", headers={"X-Token": "coneofsilence"}) - assert response.status_code == 200 - assert response.json() == { - "id": "foo", - "title": "Foo", - "description": "There goes my hero", - } - - -def test_read_item_bad_token(): - response = client.get("/items/foo", headers={"X-Token": "hailhydra"}) - assert response.status_code == 400 - assert response.json() == {"detail": "Invalid X-Token header"} - - -def test_read_nonexistent_item(): - response = client.get("/items/baz", headers={"X-Token": "coneofsilence"}) - assert response.status_code == 404 - assert response.json() == {"detail": "Item not found"} - - -def test_create_item(): - response = client.post( - "/items/", - headers={"X-Token": "coneofsilence"}, - json={"id": "foobar", "title": "Foo Bar", "description": "The Foo Barters"}, - ) - assert response.status_code == 200 - assert response.json() == { - "id": "foobar", - "title": "Foo Bar", - "description": "The Foo Barters", - } - - -def test_create_item_bad_token(): - response = client.post( - "/items/", - headers={"X-Token": "hailhydra"}, - json={"id": "bazz", "title": "Bazz", "description": "Drop the bazz"}, - ) - assert response.status_code == 400 - assert response.json() == {"detail": "Invalid X-Token header"} - - -def test_create_existing_item(): - response = client.post( - "/items/", - headers={"X-Token": "coneofsilence"}, - json={ - "id": "foo", - "title": "The Foo ID Stealers", - "description": "There goes my stealer", - }, - ) - assert response.status_code == 409 - assert response.json() == {"detail": "Item already exists"} diff --git a/docs_src/app_testing/app_b_py39/main.py b/docs_src/app_testing/app_b_py39/main.py deleted file mode 100644 index ed38f4721..000000000 --- a/docs_src/app_testing/app_b_py39/main.py +++ /dev/null @@ -1,38 +0,0 @@ -from typing import Union - -from fastapi import FastAPI, Header, HTTPException -from pydantic import BaseModel - -fake_secret_token = "coneofsilence" - -fake_db = { - "foo": {"id": "foo", "title": "Foo", "description": "There goes my hero"}, - "bar": {"id": "bar", "title": "Bar", "description": "The bartenders"}, -} - -app = FastAPI() - - -class Item(BaseModel): - id: str - title: str - description: Union[str, None] = None - - -@app.get("/items/{item_id}", response_model=Item) -async def read_main(item_id: str, x_token: str = Header()): - if x_token != fake_secret_token: - raise HTTPException(status_code=400, detail="Invalid X-Token header") - if item_id not in fake_db: - raise HTTPException(status_code=404, detail="Item not found") - return fake_db[item_id] - - -@app.post("/items/") -async def create_item(item: Item, x_token: str = Header()) -> Item: - if x_token != fake_secret_token: - raise HTTPException(status_code=400, detail="Invalid X-Token header") - if item.id in fake_db: - raise HTTPException(status_code=409, detail="Item already exists") - fake_db[item.id] = item.model_dump() - return item diff --git a/docs_src/app_testing/app_b_py39/test_main.py b/docs_src/app_testing/app_b_py39/test_main.py deleted file mode 100644 index 4e1c51ecc..000000000 --- a/docs_src/app_testing/app_b_py39/test_main.py +++ /dev/null @@ -1,65 +0,0 @@ -from fastapi.testclient import TestClient - -from .main import app - -client = TestClient(app) - - -def test_read_item(): - response = client.get("/items/foo", headers={"X-Token": "coneofsilence"}) - assert response.status_code == 200 - assert response.json() == { - "id": "foo", - "title": "Foo", - "description": "There goes my hero", - } - - -def test_read_item_bad_token(): - response = client.get("/items/foo", headers={"X-Token": "hailhydra"}) - assert response.status_code == 400 - assert response.json() == {"detail": "Invalid X-Token header"} - - -def test_read_nonexistent_item(): - response = client.get("/items/baz", headers={"X-Token": "coneofsilence"}) - assert response.status_code == 404 - assert response.json() == {"detail": "Item not found"} - - -def test_create_item(): - response = client.post( - "/items/", - headers={"X-Token": "coneofsilence"}, - json={"id": "foobar", "title": "Foo Bar", "description": "The Foo Barters"}, - ) - assert response.status_code == 200 - assert response.json() == { - "id": "foobar", - "title": "Foo Bar", - "description": "The Foo Barters", - } - - -def test_create_item_bad_token(): - response = client.post( - "/items/", - headers={"X-Token": "hailhydra"}, - json={"id": "bazz", "title": "Bazz", "description": "Drop the bazz"}, - ) - assert response.status_code == 400 - assert response.json() == {"detail": "Invalid X-Token header"} - - -def test_create_existing_item(): - response = client.post( - "/items/", - headers={"X-Token": "coneofsilence"}, - json={ - "id": "foo", - "title": "The Foo ID Stealers", - "description": "There goes my stealer", - }, - ) - assert response.status_code == 409 - assert response.json() == {"detail": "Item already exists"} diff --git a/docs_src/app_testing/tutorial001_py310.py b/docs_src/app_testing/tutorial001_py310.py new file mode 100644 index 000000000..79a853b48 --- /dev/null +++ b/docs_src/app_testing/tutorial001_py310.py @@ -0,0 +1,18 @@ +from fastapi import FastAPI +from fastapi.testclient import TestClient + +app = FastAPI() + + +@app.get("/") +async def read_main(): + return {"msg": "Hello World"} + + +client = TestClient(app) + + +def test_read_main(): + response = client.get("/") + assert response.status_code == 200 + assert response.json() == {"msg": "Hello World"} diff --git a/docs_src/app_testing/tutorial002_py310.py b/docs_src/app_testing/tutorial002_py310.py new file mode 100644 index 000000000..71c898b3c --- /dev/null +++ b/docs_src/app_testing/tutorial002_py310.py @@ -0,0 +1,31 @@ +from fastapi import FastAPI +from fastapi.testclient import TestClient +from fastapi.websockets import WebSocket + +app = FastAPI() + + +@app.get("/") +async def read_main(): + return {"msg": "Hello World"} + + +@app.websocket("/ws") +async def websocket(websocket: WebSocket): + await websocket.accept() + await websocket.send_json({"msg": "Hello WebSocket"}) + await websocket.close() + + +def test_read_main(): + client = TestClient(app) + response = client.get("/") + assert response.status_code == 200 + assert response.json() == {"msg": "Hello World"} + + +def test_websocket(): + client = TestClient(app) + with client.websocket_connect("/ws") as websocket: + data = websocket.receive_json() + assert data == {"msg": "Hello WebSocket"} diff --git a/docs_src/app_testing/tutorial003_py310.py b/docs_src/app_testing/tutorial003_py310.py new file mode 100644 index 000000000..ca6b45ce0 --- /dev/null +++ b/docs_src/app_testing/tutorial003_py310.py @@ -0,0 +1,24 @@ +from fastapi import FastAPI +from fastapi.testclient import TestClient + +app = FastAPI() + +items = {} + + +@app.on_event("startup") +async def startup_event(): + items["foo"] = {"name": "Fighters"} + items["bar"] = {"name": "Tenders"} + + +@app.get("/items/{item_id}") +async def read_items(item_id: str): + return items[item_id] + + +def test_read_items(): + with TestClient(app) as client: + response = client.get("/items/foo") + assert response.status_code == 200 + assert response.json() == {"name": "Fighters"} diff --git a/docs_src/app_testing/tutorial004_py310.py b/docs_src/app_testing/tutorial004_py310.py new file mode 100644 index 000000000..f83ac9ae9 --- /dev/null +++ b/docs_src/app_testing/tutorial004_py310.py @@ -0,0 +1,43 @@ +from contextlib import asynccontextmanager + +from fastapi import FastAPI +from fastapi.testclient import TestClient + +items = {} + + +@asynccontextmanager +async def lifespan(app: FastAPI): + items["foo"] = {"name": "Fighters"} + items["bar"] = {"name": "Tenders"} + yield + # clean up items + items.clear() + + +app = FastAPI(lifespan=lifespan) + + +@app.get("/items/{item_id}") +async def read_items(item_id: str): + return items[item_id] + + +def test_read_items(): + # Before the lifespan starts, "items" is still empty + assert items == {} + + with TestClient(app) as client: + # Inside the "with TestClient" block, the lifespan starts and items added + assert items == {"foo": {"name": "Fighters"}, "bar": {"name": "Tenders"}} + + response = client.get("/items/foo") + assert response.status_code == 200 + assert response.json() == {"name": "Fighters"} + + # After the requests is done, the items are still there + assert items == {"foo": {"name": "Fighters"}, "bar": {"name": "Tenders"}} + + # The end of the "with TestClient" block simulates terminating the app, so + # the lifespan ends and items are cleaned up + assert items == {} diff --git a/docs_src/app_testing/app_b_py39/__init__.py b/docs_src/async_tests/app_a_py310/__init__.py similarity index 100% rename from docs_src/app_testing/app_b_py39/__init__.py rename to docs_src/async_tests/app_a_py310/__init__.py diff --git a/docs_src/async_tests/app_a_py310/main.py b/docs_src/async_tests/app_a_py310/main.py new file mode 100644 index 000000000..9594f859c --- /dev/null +++ b/docs_src/async_tests/app_a_py310/main.py @@ -0,0 +1,8 @@ +from fastapi import FastAPI + +app = FastAPI() + + +@app.get("/") +async def root(): + return {"message": "Tomato"} diff --git a/docs_src/async_tests/app_a_py310/test_main.py b/docs_src/async_tests/app_a_py310/test_main.py new file mode 100644 index 000000000..a57a31f7d --- /dev/null +++ b/docs_src/async_tests/app_a_py310/test_main.py @@ -0,0 +1,14 @@ +import pytest +from httpx import ASGITransport, AsyncClient + +from .main import app + + +@pytest.mark.anyio +async def test_root(): + async with AsyncClient( + transport=ASGITransport(app=app), base_url="http://test" + ) as ac: + response = await ac.get("/") + assert response.status_code == 200 + assert response.json() == {"message": "Tomato"} diff --git a/docs_src/authentication_error_status_code/tutorial001_an_py310.py b/docs_src/authentication_error_status_code/tutorial001_an_py310.py new file mode 100644 index 000000000..7bbc2f717 --- /dev/null +++ b/docs_src/authentication_error_status_code/tutorial001_an_py310.py @@ -0,0 +1,21 @@ +from typing import Annotated + +from fastapi import Depends, FastAPI, HTTPException, status +from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer + +app = FastAPI() + + +class HTTPBearer403(HTTPBearer): + def make_not_authenticated_error(self) -> HTTPException: + return HTTPException( + status_code=status.HTTP_403_FORBIDDEN, detail="Not authenticated" + ) + + +CredentialsDep = Annotated[HTTPAuthorizationCredentials, Depends(HTTPBearer403())] + + +@app.get("/me") +def read_me(credentials: CredentialsDep): + return {"message": "You are authenticated", "token": credentials.credentials} diff --git a/docs_src/background_tasks/tutorial001_py310.py b/docs_src/background_tasks/tutorial001_py310.py new file mode 100644 index 000000000..1720a7433 --- /dev/null +++ b/docs_src/background_tasks/tutorial001_py310.py @@ -0,0 +1,15 @@ +from fastapi import BackgroundTasks, FastAPI + +app = FastAPI() + + +def write_notification(email: str, message=""): + with open("log.txt", mode="w") as email_file: + content = f"notification for {email}: {message}" + email_file.write(content) + + +@app.post("/send-notification/{email}") +async def send_notification(email: str, background_tasks: BackgroundTasks): + background_tasks.add_task(write_notification, email, message="some notification") + return {"message": "Notification sent in the background"} diff --git a/docs_src/background_tasks/tutorial002_an_py39.py b/docs_src/background_tasks/tutorial002_an_py39.py deleted file mode 100644 index bfdd14875..000000000 --- a/docs_src/background_tasks/tutorial002_an_py39.py +++ /dev/null @@ -1,26 +0,0 @@ -from typing import Annotated, Union - -from fastapi import BackgroundTasks, Depends, FastAPI - -app = FastAPI() - - -def write_log(message: str): - with open("log.txt", mode="a") as log: - log.write(message) - - -def get_query(background_tasks: BackgroundTasks, q: Union[str, None] = None): - if q: - message = f"found query: {q}\n" - background_tasks.add_task(write_log, message) - return q - - -@app.post("/send-notification/{email}") -async def send_notification( - email: str, background_tasks: BackgroundTasks, q: Annotated[str, Depends(get_query)] -): - message = f"message to {email}\n" - background_tasks.add_task(write_log, message) - return {"message": "Message sent"} diff --git a/docs_src/background_tasks/tutorial002_py39.py b/docs_src/background_tasks/tutorial002_py39.py deleted file mode 100644 index 2e1b2f6c6..000000000 --- a/docs_src/background_tasks/tutorial002_py39.py +++ /dev/null @@ -1,26 +0,0 @@ -from typing import Union - -from fastapi import BackgroundTasks, Depends, FastAPI - -app = FastAPI() - - -def write_log(message: str): - with open("log.txt", mode="a") as log: - log.write(message) - - -def get_query(background_tasks: BackgroundTasks, q: Union[str, None] = None): - if q: - message = f"found query: {q}\n" - background_tasks.add_task(write_log, message) - return q - - -@app.post("/send-notification/{email}") -async def send_notification( - email: str, background_tasks: BackgroundTasks, q: str = Depends(get_query) -): - message = f"message to {email}\n" - background_tasks.add_task(write_log, message) - return {"message": "Message sent"} diff --git a/docs_src/behind_a_proxy/tutorial001_01_py310.py b/docs_src/behind_a_proxy/tutorial001_01_py310.py new file mode 100644 index 000000000..52b114395 --- /dev/null +++ b/docs_src/behind_a_proxy/tutorial001_01_py310.py @@ -0,0 +1,8 @@ +from fastapi import FastAPI + +app = FastAPI() + + +@app.get("/items/") +def read_items(): + return ["plumbus", "portal gun"] diff --git a/docs_src/behind_a_proxy/tutorial001_py310.py b/docs_src/behind_a_proxy/tutorial001_py310.py new file mode 100644 index 000000000..ede59ada1 --- /dev/null +++ b/docs_src/behind_a_proxy/tutorial001_py310.py @@ -0,0 +1,8 @@ +from fastapi import FastAPI, Request + +app = FastAPI() + + +@app.get("/app") +def read_main(request: Request): + return {"message": "Hello World", "root_path": request.scope.get("root_path")} diff --git a/docs_src/behind_a_proxy/tutorial002_py310.py b/docs_src/behind_a_proxy/tutorial002_py310.py new file mode 100644 index 000000000..c1600cde9 --- /dev/null +++ b/docs_src/behind_a_proxy/tutorial002_py310.py @@ -0,0 +1,8 @@ +from fastapi import FastAPI, Request + +app = FastAPI(root_path="/api/v1") + + +@app.get("/app") +def read_main(request: Request): + return {"message": "Hello World", "root_path": request.scope.get("root_path")} diff --git a/docs_src/behind_a_proxy/tutorial003_py310.py b/docs_src/behind_a_proxy/tutorial003_py310.py new file mode 100644 index 000000000..3b7d8be01 --- /dev/null +++ b/docs_src/behind_a_proxy/tutorial003_py310.py @@ -0,0 +1,14 @@ +from fastapi import FastAPI, Request + +app = FastAPI( + servers=[ + {"url": "https://stag.example.com", "description": "Staging environment"}, + {"url": "https://prod.example.com", "description": "Production environment"}, + ], + root_path="/api/v1", +) + + +@app.get("/app") +def read_main(request: Request): + return {"message": "Hello World", "root_path": request.scope.get("root_path")} diff --git a/docs_src/behind_a_proxy/tutorial004_py310.py b/docs_src/behind_a_proxy/tutorial004_py310.py new file mode 100644 index 000000000..51bd5babc --- /dev/null +++ b/docs_src/behind_a_proxy/tutorial004_py310.py @@ -0,0 +1,15 @@ +from fastapi import FastAPI, Request + +app = FastAPI( + servers=[ + {"url": "https://stag.example.com", "description": "Staging environment"}, + {"url": "https://prod.example.com", "description": "Production environment"}, + ], + root_path="/api/v1", + root_path_in_servers=False, +) + + +@app.get("/app") +def read_main(request: Request): + return {"message": "Hello World", "root_path": request.scope.get("root_path")} diff --git a/docs_src/bigger_applications/app_py39/internal/__init__.py b/docs_src/bigger_applications/app_an_py310/__init__.py similarity index 100% rename from docs_src/bigger_applications/app_py39/internal/__init__.py rename to docs_src/bigger_applications/app_an_py310/__init__.py diff --git a/docs_src/bigger_applications/app_an_py310/dependencies.py b/docs_src/bigger_applications/app_an_py310/dependencies.py new file mode 100644 index 000000000..5c7612aa0 --- /dev/null +++ b/docs_src/bigger_applications/app_an_py310/dependencies.py @@ -0,0 +1,13 @@ +from typing import Annotated + +from fastapi import Header, HTTPException + + +async def get_token_header(x_token: Annotated[str, Header()]): + if x_token != "fake-super-secret-token": + raise HTTPException(status_code=400, detail="X-Token header invalid") + + +async def get_query_token(token: str): + if token != "jessica": + raise HTTPException(status_code=400, detail="No Jessica token provided") diff --git a/docs_src/bigger_applications/app_py39/routers/__init__.py b/docs_src/bigger_applications/app_an_py310/internal/__init__.py similarity index 100% rename from docs_src/bigger_applications/app_py39/routers/__init__.py rename to docs_src/bigger_applications/app_an_py310/internal/__init__.py diff --git a/docs_src/bigger_applications/app_py39/internal/admin.py b/docs_src/bigger_applications/app_an_py310/internal/admin.py similarity index 100% rename from docs_src/bigger_applications/app_py39/internal/admin.py rename to docs_src/bigger_applications/app_an_py310/internal/admin.py diff --git a/docs_src/bigger_applications/app_an_py310/main.py b/docs_src/bigger_applications/app_an_py310/main.py new file mode 100644 index 000000000..ae544a3aa --- /dev/null +++ b/docs_src/bigger_applications/app_an_py310/main.py @@ -0,0 +1,23 @@ +from fastapi import Depends, FastAPI + +from .dependencies import get_query_token, get_token_header +from .internal import admin +from .routers import items, users + +app = FastAPI(dependencies=[Depends(get_query_token)]) + + +app.include_router(users.router) +app.include_router(items.router) +app.include_router( + admin.router, + prefix="/admin", + tags=["admin"], + dependencies=[Depends(get_token_header)], + responses={418: {"description": "I'm a teapot"}}, +) + + +@app.get("/") +async def root(): + return {"message": "Hello Bigger Applications!"} diff --git a/docs_src/bigger_applications/app_an_py310/routers/__init__.py b/docs_src/bigger_applications/app_an_py310/routers/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/docs_src/bigger_applications/app_py39/routers/items.py b/docs_src/bigger_applications/app_an_py310/routers/items.py similarity index 100% rename from docs_src/bigger_applications/app_py39/routers/items.py rename to docs_src/bigger_applications/app_an_py310/routers/items.py diff --git a/docs_src/bigger_applications/app_py39/routers/users.py b/docs_src/bigger_applications/app_an_py310/routers/users.py similarity index 100% rename from docs_src/bigger_applications/app_py39/routers/users.py rename to docs_src/bigger_applications/app_an_py310/routers/users.py diff --git a/docs_src/body/tutorial001_py39.py b/docs_src/body/tutorial001_py39.py deleted file mode 100644 index f93317274..000000000 --- a/docs_src/body/tutorial001_py39.py +++ /dev/null @@ -1,19 +0,0 @@ -from typing import Union - -from fastapi import FastAPI -from pydantic import BaseModel - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: Union[float, None] = None - - -app = FastAPI() - - -@app.post("/items/") -async def create_item(item: Item): - return item diff --git a/docs_src/body/tutorial002_py39.py b/docs_src/body/tutorial002_py39.py deleted file mode 100644 index fb212e8e7..000000000 --- a/docs_src/body/tutorial002_py39.py +++ /dev/null @@ -1,23 +0,0 @@ -from typing import Union - -from fastapi import FastAPI -from pydantic import BaseModel - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: Union[float, None] = None - - -app = FastAPI() - - -@app.post("/items/") -async def create_item(item: Item): - item_dict = item.model_dump() - if item.tax is not None: - price_with_tax = item.price + item.tax - item_dict.update({"price_with_tax": price_with_tax}) - return item_dict diff --git a/docs_src/body/tutorial003_py39.py b/docs_src/body/tutorial003_py39.py deleted file mode 100644 index 636ba2275..000000000 --- a/docs_src/body/tutorial003_py39.py +++ /dev/null @@ -1,19 +0,0 @@ -from typing import Union - -from fastapi import FastAPI -from pydantic import BaseModel - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: Union[float, None] = None - - -app = FastAPI() - - -@app.put("/items/{item_id}") -async def update_item(item_id: int, item: Item): - return {"item_id": item_id, **item.model_dump()} diff --git a/docs_src/body/tutorial004_py39.py b/docs_src/body/tutorial004_py39.py deleted file mode 100644 index 2c157abfa..000000000 --- a/docs_src/body/tutorial004_py39.py +++ /dev/null @@ -1,22 +0,0 @@ -from typing import Union - -from fastapi import FastAPI -from pydantic import BaseModel - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: Union[float, None] = None - - -app = FastAPI() - - -@app.put("/items/{item_id}") -async def update_item(item_id: int, item: Item, q: Union[str, None] = None): - result = {"item_id": item_id, **item.model_dump()} - if q: - result.update({"q": q}) - return result diff --git a/docs_src/body_fields/tutorial001_an_py39.py b/docs_src/body_fields/tutorial001_an_py39.py deleted file mode 100644 index 6ef14470c..000000000 --- a/docs_src/body_fields/tutorial001_an_py39.py +++ /dev/null @@ -1,21 +0,0 @@ -from typing import Annotated, Union - -from fastapi import Body, FastAPI -from pydantic import BaseModel, Field - -app = FastAPI() - - -class Item(BaseModel): - name: str - description: Union[str, None] = Field( - default=None, title="The description of the item", max_length=300 - ) - price: float = Field(gt=0, description="The price must be greater than zero") - tax: Union[float, None] = None - - -@app.put("/items/{item_id}") -async def update_item(item_id: int, item: Annotated[Item, Body(embed=True)]): - results = {"item_id": item_id, "item": item} - return results diff --git a/docs_src/body_fields/tutorial001_py39.py b/docs_src/body_fields/tutorial001_py39.py deleted file mode 100644 index cbeebd614..000000000 --- a/docs_src/body_fields/tutorial001_py39.py +++ /dev/null @@ -1,21 +0,0 @@ -from typing import Union - -from fastapi import Body, FastAPI -from pydantic import BaseModel, Field - -app = FastAPI() - - -class Item(BaseModel): - name: str - description: Union[str, None] = Field( - default=None, title="The description of the item", max_length=300 - ) - price: float = Field(gt=0, description="The price must be greater than zero") - tax: Union[float, None] = None - - -@app.put("/items/{item_id}") -async def update_item(item_id: int, item: Item = Body(embed=True)): - results = {"item_id": item_id, "item": item} - return results diff --git a/docs_src/body_multiple_params/tutorial001_an_py39.py b/docs_src/body_multiple_params/tutorial001_an_py39.py deleted file mode 100644 index 1c0ac3a7b..000000000 --- a/docs_src/body_multiple_params/tutorial001_an_py39.py +++ /dev/null @@ -1,27 +0,0 @@ -from typing import Annotated, Union - -from fastapi import FastAPI, Path -from pydantic import BaseModel - -app = FastAPI() - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: Union[float, None] = None - - -@app.put("/items/{item_id}") -async def update_item( - item_id: Annotated[int, Path(title="The ID of the item to get", ge=0, le=1000)], - q: Union[str, None] = None, - item: Union[Item, None] = None, -): - results = {"item_id": item_id} - if q: - results.update({"q": q}) - if item: - results.update({"item": item}) - return results diff --git a/docs_src/body_multiple_params/tutorial001_py39.py b/docs_src/body_multiple_params/tutorial001_py39.py deleted file mode 100644 index a73975b3a..000000000 --- a/docs_src/body_multiple_params/tutorial001_py39.py +++ /dev/null @@ -1,28 +0,0 @@ -from typing import Union - -from fastapi import FastAPI, Path -from pydantic import BaseModel - -app = FastAPI() - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: Union[float, None] = None - - -@app.put("/items/{item_id}") -async def update_item( - *, - item_id: int = Path(title="The ID of the item to get", ge=0, le=1000), - q: Union[str, None] = None, - item: Union[Item, None] = None, -): - results = {"item_id": item_id} - if q: - results.update({"q": q}) - if item: - results.update({"item": item}) - return results diff --git a/docs_src/body_multiple_params/tutorial002_py39.py b/docs_src/body_multiple_params/tutorial002_py39.py deleted file mode 100644 index 2d7160ae8..000000000 --- a/docs_src/body_multiple_params/tutorial002_py39.py +++ /dev/null @@ -1,24 +0,0 @@ -from typing import Union - -from fastapi import FastAPI -from pydantic import BaseModel - -app = FastAPI() - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: Union[float, None] = None - - -class User(BaseModel): - username: str - full_name: Union[str, None] = None - - -@app.put("/items/{item_id}") -async def update_item(item_id: int, item: Item, user: User): - results = {"item_id": item_id, "item": item, "user": user} - return results diff --git a/docs_src/body_multiple_params/tutorial003_an_py39.py b/docs_src/body_multiple_params/tutorial003_an_py39.py deleted file mode 100644 index 042351e0b..000000000 --- a/docs_src/body_multiple_params/tutorial003_an_py39.py +++ /dev/null @@ -1,26 +0,0 @@ -from typing import Annotated, Union - -from fastapi import Body, FastAPI -from pydantic import BaseModel - -app = FastAPI() - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: Union[float, None] = None - - -class User(BaseModel): - username: str - full_name: Union[str, None] = None - - -@app.put("/items/{item_id}") -async def update_item( - item_id: int, item: Item, user: User, importance: Annotated[int, Body()] -): - results = {"item_id": item_id, "item": item, "user": user, "importance": importance} - return results diff --git a/docs_src/body_multiple_params/tutorial003_py39.py b/docs_src/body_multiple_params/tutorial003_py39.py deleted file mode 100644 index cf344e6c5..000000000 --- a/docs_src/body_multiple_params/tutorial003_py39.py +++ /dev/null @@ -1,24 +0,0 @@ -from typing import Union - -from fastapi import Body, FastAPI -from pydantic import BaseModel - -app = FastAPI() - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: Union[float, None] = None - - -class User(BaseModel): - username: str - full_name: Union[str, None] = None - - -@app.put("/items/{item_id}") -async def update_item(item_id: int, item: Item, user: User, importance: int = Body()): - results = {"item_id": item_id, "item": item, "user": user, "importance": importance} - return results diff --git a/docs_src/body_multiple_params/tutorial004_an_py39.py b/docs_src/body_multiple_params/tutorial004_an_py39.py deleted file mode 100644 index 567427c03..000000000 --- a/docs_src/body_multiple_params/tutorial004_an_py39.py +++ /dev/null @@ -1,33 +0,0 @@ -from typing import Annotated, Union - -from fastapi import Body, FastAPI -from pydantic import BaseModel - -app = FastAPI() - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: Union[float, None] = None - - -class User(BaseModel): - username: str - full_name: Union[str, None] = None - - -@app.put("/items/{item_id}") -async def update_item( - *, - item_id: int, - item: Item, - user: User, - importance: Annotated[int, Body(gt=0)], - q: Union[str, None] = None, -): - results = {"item_id": item_id, "item": item, "user": user, "importance": importance} - if q: - results.update({"q": q}) - return results diff --git a/docs_src/body_multiple_params/tutorial004_py39.py b/docs_src/body_multiple_params/tutorial004_py39.py deleted file mode 100644 index 8ce4c7a97..000000000 --- a/docs_src/body_multiple_params/tutorial004_py39.py +++ /dev/null @@ -1,33 +0,0 @@ -from typing import Union - -from fastapi import Body, FastAPI -from pydantic import BaseModel - -app = FastAPI() - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: Union[float, None] = None - - -class User(BaseModel): - username: str - full_name: Union[str, None] = None - - -@app.put("/items/{item_id}") -async def update_item( - *, - item_id: int, - item: Item, - user: User, - importance: int = Body(gt=0), - q: Union[str, None] = None, -): - results = {"item_id": item_id, "item": item, "user": user, "importance": importance} - if q: - results.update({"q": q}) - return results diff --git a/docs_src/body_multiple_params/tutorial005_an_py39.py b/docs_src/body_multiple_params/tutorial005_an_py39.py deleted file mode 100644 index 9a52425c1..000000000 --- a/docs_src/body_multiple_params/tutorial005_an_py39.py +++ /dev/null @@ -1,19 +0,0 @@ -from typing import Annotated, Union - -from fastapi import Body, FastAPI -from pydantic import BaseModel - -app = FastAPI() - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: Union[float, None] = None - - -@app.put("/items/{item_id}") -async def update_item(item_id: int, item: Annotated[Item, Body(embed=True)]): - results = {"item_id": item_id, "item": item} - return results diff --git a/docs_src/body_multiple_params/tutorial005_py39.py b/docs_src/body_multiple_params/tutorial005_py39.py deleted file mode 100644 index 29e6e14b7..000000000 --- a/docs_src/body_multiple_params/tutorial005_py39.py +++ /dev/null @@ -1,19 +0,0 @@ -from typing import Union - -from fastapi import Body, FastAPI -from pydantic import BaseModel - -app = FastAPI() - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: Union[float, None] = None - - -@app.put("/items/{item_id}") -async def update_item(item_id: int, item: Item = Body(embed=True)): - results = {"item_id": item_id, "item": item} - return results diff --git a/docs_src/body_nested_models/tutorial001_py39.py b/docs_src/body_nested_models/tutorial001_py39.py deleted file mode 100644 index 37ef6dda5..000000000 --- a/docs_src/body_nested_models/tutorial001_py39.py +++ /dev/null @@ -1,20 +0,0 @@ -from typing import Union - -from fastapi import FastAPI -from pydantic import BaseModel - -app = FastAPI() - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: Union[float, None] = None - tags: list = [] - - -@app.put("/items/{item_id}") -async def update_item(item_id: int, item: Item): - results = {"item_id": item_id, "item": item} - return results diff --git a/docs_src/body_nested_models/tutorial002_py39.py b/docs_src/body_nested_models/tutorial002_py39.py deleted file mode 100644 index 8a93a7233..000000000 --- a/docs_src/body_nested_models/tutorial002_py39.py +++ /dev/null @@ -1,20 +0,0 @@ -from typing import Union - -from fastapi import FastAPI -from pydantic import BaseModel - -app = FastAPI() - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: Union[float, None] = None - tags: list[str] = [] - - -@app.put("/items/{item_id}") -async def update_item(item_id: int, item: Item): - results = {"item_id": item_id, "item": item} - return results diff --git a/docs_src/body_nested_models/tutorial003_py39.py b/docs_src/body_nested_models/tutorial003_py39.py deleted file mode 100644 index b590ece36..000000000 --- a/docs_src/body_nested_models/tutorial003_py39.py +++ /dev/null @@ -1,20 +0,0 @@ -from typing import Union - -from fastapi import FastAPI -from pydantic import BaseModel - -app = FastAPI() - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: Union[float, None] = None - tags: set[str] = set() - - -@app.put("/items/{item_id}") -async def update_item(item_id: int, item: Item): - results = {"item_id": item_id, "item": item} - return results diff --git a/docs_src/body_nested_models/tutorial004_py39.py b/docs_src/body_nested_models/tutorial004_py39.py deleted file mode 100644 index dc2b175fb..000000000 --- a/docs_src/body_nested_models/tutorial004_py39.py +++ /dev/null @@ -1,26 +0,0 @@ -from typing import Union - -from fastapi import FastAPI -from pydantic import BaseModel - -app = FastAPI() - - -class Image(BaseModel): - url: str - name: str - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: Union[float, None] = None - tags: set[str] = set() - image: Union[Image, None] = None - - -@app.put("/items/{item_id}") -async def update_item(item_id: int, item: Item): - results = {"item_id": item_id, "item": item} - return results diff --git a/docs_src/body_nested_models/tutorial005_py39.py b/docs_src/body_nested_models/tutorial005_py39.py deleted file mode 100644 index 47db90008..000000000 --- a/docs_src/body_nested_models/tutorial005_py39.py +++ /dev/null @@ -1,26 +0,0 @@ -from typing import Union - -from fastapi import FastAPI -from pydantic import BaseModel, HttpUrl - -app = FastAPI() - - -class Image(BaseModel): - url: HttpUrl - name: str - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: Union[float, None] = None - tags: set[str] = set() - image: Union[Image, None] = None - - -@app.put("/items/{item_id}") -async def update_item(item_id: int, item: Item): - results = {"item_id": item_id, "item": item} - return results diff --git a/docs_src/body_nested_models/tutorial006_py39.py b/docs_src/body_nested_models/tutorial006_py39.py deleted file mode 100644 index b14409703..000000000 --- a/docs_src/body_nested_models/tutorial006_py39.py +++ /dev/null @@ -1,26 +0,0 @@ -from typing import Union - -from fastapi import FastAPI -from pydantic import BaseModel, HttpUrl - -app = FastAPI() - - -class Image(BaseModel): - url: HttpUrl - name: str - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: Union[float, None] = None - tags: set[str] = set() - images: Union[list[Image], None] = None - - -@app.put("/items/{item_id}") -async def update_item(item_id: int, item: Item): - results = {"item_id": item_id, "item": item} - return results diff --git a/docs_src/body_nested_models/tutorial007_py39.py b/docs_src/body_nested_models/tutorial007_py39.py deleted file mode 100644 index 59cf01e23..000000000 --- a/docs_src/body_nested_models/tutorial007_py39.py +++ /dev/null @@ -1,32 +0,0 @@ -from typing import Union - -from fastapi import FastAPI -from pydantic import BaseModel, HttpUrl - -app = FastAPI() - - -class Image(BaseModel): - url: HttpUrl - name: str - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: Union[float, None] = None - tags: set[str] = set() - images: Union[list[Image], None] = None - - -class Offer(BaseModel): - name: str - description: Union[str, None] = None - price: float - items: list[Item] - - -@app.post("/offers/") -async def create_offer(offer: Offer): - return offer diff --git a/docs_src/body_nested_models/tutorial008_py310.py b/docs_src/body_nested_models/tutorial008_py310.py new file mode 100644 index 000000000..854a7a5a4 --- /dev/null +++ b/docs_src/body_nested_models/tutorial008_py310.py @@ -0,0 +1,14 @@ +from fastapi import FastAPI +from pydantic import BaseModel, HttpUrl + +app = FastAPI() + + +class Image(BaseModel): + url: HttpUrl + name: str + + +@app.post("/images/multiple/") +async def create_multiple_images(images: list[Image]): + return images diff --git a/docs_src/body_nested_models/tutorial009_py310.py b/docs_src/body_nested_models/tutorial009_py310.py new file mode 100644 index 000000000..59c1e5082 --- /dev/null +++ b/docs_src/body_nested_models/tutorial009_py310.py @@ -0,0 +1,8 @@ +from fastapi import FastAPI + +app = FastAPI() + + +@app.post("/index-weights/") +async def create_index_weights(weights: dict[int, float]): + return weights diff --git a/docs_src/body_updates/tutorial001_py39.py b/docs_src/body_updates/tutorial001_py39.py deleted file mode 100644 index 999bcdb82..000000000 --- a/docs_src/body_updates/tutorial001_py39.py +++ /dev/null @@ -1,34 +0,0 @@ -from typing import Union - -from fastapi import FastAPI -from fastapi.encoders import jsonable_encoder -from pydantic import BaseModel - -app = FastAPI() - - -class Item(BaseModel): - name: Union[str, None] = None - description: Union[str, None] = None - price: Union[float, None] = None - tax: float = 10.5 - tags: list[str] = [] - - -items = { - "foo": {"name": "Foo", "price": 50.2}, - "bar": {"name": "Bar", "description": "The bartenders", "price": 62, "tax": 20.2}, - "baz": {"name": "Baz", "description": None, "price": 50.2, "tax": 10.5, "tags": []}, -} - - -@app.get("/items/{item_id}", response_model=Item) -async def read_item(item_id: str): - return items[item_id] - - -@app.put("/items/{item_id}", response_model=Item) -async def update_item(item_id: str, item: Item): - update_item_encoded = jsonable_encoder(item) - items[item_id] = update_item_encoded - return update_item_encoded diff --git a/docs_src/body_updates/tutorial002_py39.py b/docs_src/body_updates/tutorial002_py39.py deleted file mode 100644 index 3714b5a55..000000000 --- a/docs_src/body_updates/tutorial002_py39.py +++ /dev/null @@ -1,37 +0,0 @@ -from typing import Union - -from fastapi import FastAPI -from fastapi.encoders import jsonable_encoder -from pydantic import BaseModel - -app = FastAPI() - - -class Item(BaseModel): - name: Union[str, None] = None - description: Union[str, None] = None - price: Union[float, None] = None - tax: float = 10.5 - tags: list[str] = [] - - -items = { - "foo": {"name": "Foo", "price": 50.2}, - "bar": {"name": "Bar", "description": "The bartenders", "price": 62, "tax": 20.2}, - "baz": {"name": "Baz", "description": None, "price": 50.2, "tax": 10.5, "tags": []}, -} - - -@app.get("/items/{item_id}", response_model=Item) -async def read_item(item_id: str): - return items[item_id] - - -@app.patch("/items/{item_id}") -async def update_item(item_id: str, item: Item) -> Item: - stored_item_data = items[item_id] - stored_item_model = Item(**stored_item_data) - update_data = item.model_dump(exclude_unset=True) - updated_item = stored_item_model.model_copy(update=update_data) - items[item_id] = jsonable_encoder(updated_item) - return updated_item diff --git a/docs_src/conditional_openapi/tutorial001_py310.py b/docs_src/conditional_openapi/tutorial001_py310.py new file mode 100644 index 000000000..eedb0d274 --- /dev/null +++ b/docs_src/conditional_openapi/tutorial001_py310.py @@ -0,0 +1,16 @@ +from fastapi import FastAPI +from pydantic_settings import BaseSettings + + +class Settings(BaseSettings): + openapi_url: str = "/openapi.json" + + +settings = Settings() + +app = FastAPI(openapi_url=settings.openapi_url) + + +@app.get("/") +def root(): + return {"message": "Hello World"} diff --git a/docs_src/configure_swagger_ui/tutorial001_py310.py b/docs_src/configure_swagger_ui/tutorial001_py310.py new file mode 100644 index 000000000..6c24ce758 --- /dev/null +++ b/docs_src/configure_swagger_ui/tutorial001_py310.py @@ -0,0 +1,8 @@ +from fastapi import FastAPI + +app = FastAPI(swagger_ui_parameters={"syntaxHighlight": False}) + + +@app.get("/users/{username}") +async def read_user(username: str): + return {"message": f"Hello {username}"} diff --git a/docs_src/configure_swagger_ui/tutorial002_py310.py b/docs_src/configure_swagger_ui/tutorial002_py310.py new file mode 100644 index 000000000..cc75c2196 --- /dev/null +++ b/docs_src/configure_swagger_ui/tutorial002_py310.py @@ -0,0 +1,8 @@ +from fastapi import FastAPI + +app = FastAPI(swagger_ui_parameters={"syntaxHighlight": {"theme": "obsidian"}}) + + +@app.get("/users/{username}") +async def read_user(username: str): + return {"message": f"Hello {username}"} diff --git a/docs_src/configure_swagger_ui/tutorial003_py310.py b/docs_src/configure_swagger_ui/tutorial003_py310.py new file mode 100644 index 000000000..b4449f5c6 --- /dev/null +++ b/docs_src/configure_swagger_ui/tutorial003_py310.py @@ -0,0 +1,8 @@ +from fastapi import FastAPI + +app = FastAPI(swagger_ui_parameters={"deepLinking": False}) + + +@app.get("/users/{username}") +async def read_user(username: str): + return {"message": f"Hello {username}"} diff --git a/docs_src/cookie_param_models/tutorial001_an_py39.py b/docs_src/cookie_param_models/tutorial001_an_py39.py deleted file mode 100644 index 3d90c2007..000000000 --- a/docs_src/cookie_param_models/tutorial001_an_py39.py +++ /dev/null @@ -1,17 +0,0 @@ -from typing import Annotated, Union - -from fastapi import Cookie, FastAPI -from pydantic import BaseModel - -app = FastAPI() - - -class Cookies(BaseModel): - session_id: str - fatebook_tracker: Union[str, None] = None - googall_tracker: Union[str, None] = None - - -@app.get("/items/") -async def read_items(cookies: Annotated[Cookies, Cookie()]): - return cookies diff --git a/docs_src/cookie_param_models/tutorial001_py39.py b/docs_src/cookie_param_models/tutorial001_py39.py deleted file mode 100644 index cc65c43e1..000000000 --- a/docs_src/cookie_param_models/tutorial001_py39.py +++ /dev/null @@ -1,17 +0,0 @@ -from typing import Union - -from fastapi import Cookie, FastAPI -from pydantic import BaseModel - -app = FastAPI() - - -class Cookies(BaseModel): - session_id: str - fatebook_tracker: Union[str, None] = None - googall_tracker: Union[str, None] = None - - -@app.get("/items/") -async def read_items(cookies: Cookies = Cookie()): - return cookies diff --git a/docs_src/cookie_param_models/tutorial002_an_py39.py b/docs_src/cookie_param_models/tutorial002_an_py39.py deleted file mode 100644 index a906ce6a1..000000000 --- a/docs_src/cookie_param_models/tutorial002_an_py39.py +++ /dev/null @@ -1,19 +0,0 @@ -from typing import Annotated, Union - -from fastapi import Cookie, FastAPI -from pydantic import BaseModel - -app = FastAPI() - - -class Cookies(BaseModel): - model_config = {"extra": "forbid"} - - session_id: str - fatebook_tracker: Union[str, None] = None - googall_tracker: Union[str, None] = None - - -@app.get("/items/") -async def read_items(cookies: Annotated[Cookies, Cookie()]): - return cookies diff --git a/docs_src/cookie_param_models/tutorial002_py39.py b/docs_src/cookie_param_models/tutorial002_py39.py deleted file mode 100644 index 9679e890f..000000000 --- a/docs_src/cookie_param_models/tutorial002_py39.py +++ /dev/null @@ -1,19 +0,0 @@ -from typing import Union - -from fastapi import Cookie, FastAPI -from pydantic import BaseModel - -app = FastAPI() - - -class Cookies(BaseModel): - model_config = {"extra": "forbid"} - - session_id: str - fatebook_tracker: Union[str, None] = None - googall_tracker: Union[str, None] = None - - -@app.get("/items/") -async def read_items(cookies: Cookies = Cookie()): - return cookies diff --git a/docs_src/cookie_params/tutorial001_an_py39.py b/docs_src/cookie_params/tutorial001_an_py39.py deleted file mode 100644 index e18d0a332..000000000 --- a/docs_src/cookie_params/tutorial001_an_py39.py +++ /dev/null @@ -1,10 +0,0 @@ -from typing import Annotated, Union - -from fastapi import Cookie, FastAPI - -app = FastAPI() - - -@app.get("/items/") -async def read_items(ads_id: Annotated[Union[str, None], Cookie()] = None): - return {"ads_id": ads_id} diff --git a/docs_src/cookie_params/tutorial001_py39.py b/docs_src/cookie_params/tutorial001_py39.py deleted file mode 100644 index c4a497fda..000000000 --- a/docs_src/cookie_params/tutorial001_py39.py +++ /dev/null @@ -1,10 +0,0 @@ -from typing import Union - -from fastapi import Cookie, FastAPI - -app = FastAPI() - - -@app.get("/items/") -async def read_items(ads_id: Union[str, None] = Cookie(default=None)): - return {"ads_id": ads_id} diff --git a/docs_src/cors/tutorial001_py310.py b/docs_src/cors/tutorial001_py310.py new file mode 100644 index 000000000..d59ab27ac --- /dev/null +++ b/docs_src/cors/tutorial001_py310.py @@ -0,0 +1,24 @@ +from fastapi import FastAPI +from fastapi.middleware.cors import CORSMiddleware + +app = FastAPI() + +origins = [ + "http://localhost.tiangolo.com", + "https://localhost.tiangolo.com", + "http://localhost", + "http://localhost:8080", +] + +app.add_middleware( + CORSMiddleware, + allow_origins=origins, + allow_credentials=True, + allow_methods=["*"], + allow_headers=["*"], +) + + +@app.get("/") +async def main(): + return {"message": "Hello World"} diff --git a/docs_src/custom_docs_ui/tutorial001_py310.py b/docs_src/custom_docs_ui/tutorial001_py310.py new file mode 100644 index 000000000..1cfcce19a --- /dev/null +++ b/docs_src/custom_docs_ui/tutorial001_py310.py @@ -0,0 +1,38 @@ +from fastapi import FastAPI +from fastapi.openapi.docs import ( + get_redoc_html, + get_swagger_ui_html, + get_swagger_ui_oauth2_redirect_html, +) + +app = FastAPI(docs_url=None, redoc_url=None) + + +@app.get("/docs", include_in_schema=False) +async def custom_swagger_ui_html(): + return get_swagger_ui_html( + openapi_url=app.openapi_url, + title=app.title + " - Swagger UI", + oauth2_redirect_url=app.swagger_ui_oauth2_redirect_url, + swagger_js_url="https://unpkg.com/swagger-ui-dist@5/swagger-ui-bundle.js", + swagger_css_url="https://unpkg.com/swagger-ui-dist@5/swagger-ui.css", + ) + + +@app.get(app.swagger_ui_oauth2_redirect_url, include_in_schema=False) +async def swagger_ui_redirect(): + return get_swagger_ui_oauth2_redirect_html() + + +@app.get("/redoc", include_in_schema=False) +async def redoc_html(): + return get_redoc_html( + openapi_url=app.openapi_url, + title=app.title + " - ReDoc", + redoc_js_url="https://unpkg.com/redoc@2/bundles/redoc.standalone.js", + ) + + +@app.get("/users/{username}") +async def read_user(username: str): + return {"message": f"Hello {username}"} diff --git a/docs_src/custom_docs_ui/tutorial002_py310.py b/docs_src/custom_docs_ui/tutorial002_py310.py new file mode 100644 index 000000000..23ea368f8 --- /dev/null +++ b/docs_src/custom_docs_ui/tutorial002_py310.py @@ -0,0 +1,41 @@ +from fastapi import FastAPI +from fastapi.openapi.docs import ( + get_redoc_html, + get_swagger_ui_html, + get_swagger_ui_oauth2_redirect_html, +) +from fastapi.staticfiles import StaticFiles + +app = FastAPI(docs_url=None, redoc_url=None) + +app.mount("/static", StaticFiles(directory="static"), name="static") + + +@app.get("/docs", include_in_schema=False) +async def custom_swagger_ui_html(): + return get_swagger_ui_html( + openapi_url=app.openapi_url, + title=app.title + " - Swagger UI", + oauth2_redirect_url=app.swagger_ui_oauth2_redirect_url, + swagger_js_url="/static/swagger-ui-bundle.js", + swagger_css_url="/static/swagger-ui.css", + ) + + +@app.get(app.swagger_ui_oauth2_redirect_url, include_in_schema=False) +async def swagger_ui_redirect(): + return get_swagger_ui_oauth2_redirect_html() + + +@app.get("/redoc", include_in_schema=False) +async def redoc_html(): + return get_redoc_html( + openapi_url=app.openapi_url, + title=app.title + " - ReDoc", + redoc_js_url="/static/redoc.standalone.js", + ) + + +@app.get("/users/{username}") +async def read_user(username: str): + return {"message": f"Hello {username}"} diff --git a/docs_src/custom_request_and_route/tutorial001_an_py39.py b/docs_src/custom_request_and_route/tutorial001_an_py39.py deleted file mode 100644 index 076727e64..000000000 --- a/docs_src/custom_request_and_route/tutorial001_an_py39.py +++ /dev/null @@ -1,35 +0,0 @@ -import gzip -from typing import Annotated, Callable - -from fastapi import Body, FastAPI, Request, Response -from fastapi.routing import APIRoute - - -class GzipRequest(Request): - async def body(self) -> bytes: - if not hasattr(self, "_body"): - body = await super().body() - if "gzip" in self.headers.getlist("Content-Encoding"): - body = gzip.decompress(body) - self._body = body - return self._body - - -class GzipRoute(APIRoute): - def get_route_handler(self) -> Callable: - original_route_handler = super().get_route_handler() - - async def custom_route_handler(request: Request) -> Response: - request = GzipRequest(request.scope, request.receive) - return await original_route_handler(request) - - return custom_route_handler - - -app = FastAPI() -app.router.route_class = GzipRoute - - -@app.post("/sum") -async def sum_numbers(numbers: Annotated[list[int], Body()]): - return {"sum": sum(numbers)} diff --git a/docs_src/custom_request_and_route/tutorial001_py39.py b/docs_src/custom_request_and_route/tutorial001_py39.py deleted file mode 100644 index 54b20b942..000000000 --- a/docs_src/custom_request_and_route/tutorial001_py39.py +++ /dev/null @@ -1,35 +0,0 @@ -import gzip -from typing import Callable - -from fastapi import Body, FastAPI, Request, Response -from fastapi.routing import APIRoute - - -class GzipRequest(Request): - async def body(self) -> bytes: - if not hasattr(self, "_body"): - body = await super().body() - if "gzip" in self.headers.getlist("Content-Encoding"): - body = gzip.decompress(body) - self._body = body - return self._body - - -class GzipRoute(APIRoute): - def get_route_handler(self) -> Callable: - original_route_handler = super().get_route_handler() - - async def custom_route_handler(request: Request) -> Response: - request = GzipRequest(request.scope, request.receive) - return await original_route_handler(request) - - return custom_route_handler - - -app = FastAPI() -app.router.route_class = GzipRoute - - -@app.post("/sum") -async def sum_numbers(numbers: list[int] = Body()): - return {"sum": sum(numbers)} diff --git a/docs_src/custom_request_and_route/tutorial002_an_py39.py b/docs_src/custom_request_and_route/tutorial002_an_py39.py deleted file mode 100644 index e7de09de4..000000000 --- a/docs_src/custom_request_and_route/tutorial002_an_py39.py +++ /dev/null @@ -1,29 +0,0 @@ -from typing import Annotated, Callable - -from fastapi import Body, FastAPI, HTTPException, Request, Response -from fastapi.exceptions import RequestValidationError -from fastapi.routing import APIRoute - - -class ValidationErrorLoggingRoute(APIRoute): - def get_route_handler(self) -> Callable: - original_route_handler = super().get_route_handler() - - async def custom_route_handler(request: Request) -> Response: - try: - return await original_route_handler(request) - except RequestValidationError as exc: - body = await request.body() - detail = {"errors": exc.errors(), "body": body.decode()} - raise HTTPException(status_code=422, detail=detail) - - return custom_route_handler - - -app = FastAPI() -app.router.route_class = ValidationErrorLoggingRoute - - -@app.post("/") -async def sum_numbers(numbers: Annotated[list[int], Body()]): - return sum(numbers) diff --git a/docs_src/custom_request_and_route/tutorial002_py39.py b/docs_src/custom_request_and_route/tutorial002_py39.py deleted file mode 100644 index c4e474828..000000000 --- a/docs_src/custom_request_and_route/tutorial002_py39.py +++ /dev/null @@ -1,29 +0,0 @@ -from typing import Callable - -from fastapi import Body, FastAPI, HTTPException, Request, Response -from fastapi.exceptions import RequestValidationError -from fastapi.routing import APIRoute - - -class ValidationErrorLoggingRoute(APIRoute): - def get_route_handler(self) -> Callable: - original_route_handler = super().get_route_handler() - - async def custom_route_handler(request: Request) -> Response: - try: - return await original_route_handler(request) - except RequestValidationError as exc: - body = await request.body() - detail = {"errors": exc.errors(), "body": body.decode()} - raise HTTPException(status_code=422, detail=detail) - - return custom_route_handler - - -app = FastAPI() -app.router.route_class = ValidationErrorLoggingRoute - - -@app.post("/") -async def sum_numbers(numbers: list[int] = Body()): - return sum(numbers) diff --git a/docs_src/custom_request_and_route/tutorial003_py39.py b/docs_src/custom_request_and_route/tutorial003_py39.py deleted file mode 100644 index aabe76068..000000000 --- a/docs_src/custom_request_and_route/tutorial003_py39.py +++ /dev/null @@ -1,39 +0,0 @@ -import time -from typing import Callable - -from fastapi import APIRouter, FastAPI, Request, Response -from fastapi.routing import APIRoute - - -class TimedRoute(APIRoute): - def get_route_handler(self) -> Callable: - original_route_handler = super().get_route_handler() - - async def custom_route_handler(request: Request) -> Response: - before = time.time() - response: Response = await original_route_handler(request) - duration = time.time() - before - response.headers["X-Response-Time"] = str(duration) - print(f"route duration: {duration}") - print(f"route response: {response}") - print(f"route response headers: {response.headers}") - return response - - return custom_route_handler - - -app = FastAPI() -router = APIRouter(route_class=TimedRoute) - - -@app.get("/") -async def not_timed(): - return {"message": "Not timed"} - - -@router.get("/timed") -async def timed(): - return {"message": "It's the time of my life"} - - -app.include_router(router) diff --git a/docs_src/custom_response/tutorial001_py310.py b/docs_src/custom_response/tutorial001_py310.py new file mode 100644 index 000000000..0f09bdf77 --- /dev/null +++ b/docs_src/custom_response/tutorial001_py310.py @@ -0,0 +1,9 @@ +from fastapi import FastAPI +from fastapi.responses import UJSONResponse + +app = FastAPI() + + +@app.get("/items/", response_class=UJSONResponse) +async def read_items(): + return [{"item_id": "Foo"}] diff --git a/docs_src/custom_response/tutorial001b_py310.py b/docs_src/custom_response/tutorial001b_py310.py new file mode 100644 index 000000000..95e6ca763 --- /dev/null +++ b/docs_src/custom_response/tutorial001b_py310.py @@ -0,0 +1,9 @@ +from fastapi import FastAPI +from fastapi.responses import ORJSONResponse + +app = FastAPI() + + +@app.get("/items/", response_class=ORJSONResponse) +async def read_items(): + return ORJSONResponse([{"item_id": "Foo"}]) diff --git a/docs_src/custom_response/tutorial002_py310.py b/docs_src/custom_response/tutorial002_py310.py new file mode 100644 index 000000000..23c495867 --- /dev/null +++ b/docs_src/custom_response/tutorial002_py310.py @@ -0,0 +1,18 @@ +from fastapi import FastAPI +from fastapi.responses import HTMLResponse + +app = FastAPI() + + +@app.get("/items/", response_class=HTMLResponse) +async def read_items(): + return """ + + + Some HTML in here + + +

Look ma! HTML!

+ + + """ diff --git a/docs_src/custom_response/tutorial003_py310.py b/docs_src/custom_response/tutorial003_py310.py new file mode 100644 index 000000000..51ad3c146 --- /dev/null +++ b/docs_src/custom_response/tutorial003_py310.py @@ -0,0 +1,19 @@ +from fastapi import FastAPI +from fastapi.responses import HTMLResponse + +app = FastAPI() + + +@app.get("/items/") +async def read_items(): + html_content = """ + + + Some HTML in here + + +

Look ma! HTML!

+ + + """ + return HTMLResponse(content=html_content, status_code=200) diff --git a/docs_src/custom_response/tutorial004_py310.py b/docs_src/custom_response/tutorial004_py310.py new file mode 100644 index 000000000..0e90f2012 --- /dev/null +++ b/docs_src/custom_response/tutorial004_py310.py @@ -0,0 +1,23 @@ +from fastapi import FastAPI +from fastapi.responses import HTMLResponse + +app = FastAPI() + + +def generate_html_response(): + html_content = """ + + + Some HTML in here + + +

Look ma! HTML!

+ + + """ + return HTMLResponse(content=html_content, status_code=200) + + +@app.get("/items/", response_class=HTMLResponse) +async def read_items(): + return generate_html_response() diff --git a/docs_src/custom_response/tutorial005_py310.py b/docs_src/custom_response/tutorial005_py310.py new file mode 100644 index 000000000..3d58f57fb --- /dev/null +++ b/docs_src/custom_response/tutorial005_py310.py @@ -0,0 +1,9 @@ +from fastapi import FastAPI +from fastapi.responses import PlainTextResponse + +app = FastAPI() + + +@app.get("/", response_class=PlainTextResponse) +async def main(): + return "Hello World" diff --git a/docs_src/custom_response/tutorial006_py310.py b/docs_src/custom_response/tutorial006_py310.py new file mode 100644 index 000000000..332f8f87f --- /dev/null +++ b/docs_src/custom_response/tutorial006_py310.py @@ -0,0 +1,9 @@ +from fastapi import FastAPI +from fastapi.responses import RedirectResponse + +app = FastAPI() + + +@app.get("/typer") +async def redirect_typer(): + return RedirectResponse("https://typer.tiangolo.com") diff --git a/docs_src/custom_response/tutorial006b_py310.py b/docs_src/custom_response/tutorial006b_py310.py new file mode 100644 index 000000000..03a7be399 --- /dev/null +++ b/docs_src/custom_response/tutorial006b_py310.py @@ -0,0 +1,9 @@ +from fastapi import FastAPI +from fastapi.responses import RedirectResponse + +app = FastAPI() + + +@app.get("/fastapi", response_class=RedirectResponse) +async def redirect_fastapi(): + return "https://fastapi.tiangolo.com" diff --git a/docs_src/custom_response/tutorial006c_py310.py b/docs_src/custom_response/tutorial006c_py310.py new file mode 100644 index 000000000..87c720364 --- /dev/null +++ b/docs_src/custom_response/tutorial006c_py310.py @@ -0,0 +1,9 @@ +from fastapi import FastAPI +from fastapi.responses import RedirectResponse + +app = FastAPI() + + +@app.get("/pydantic", response_class=RedirectResponse, status_code=302) +async def redirect_pydantic(): + return "https://docs.pydantic.dev/" diff --git a/docs_src/custom_response/tutorial007_py310.py b/docs_src/custom_response/tutorial007_py310.py new file mode 100644 index 000000000..e2a53a211 --- /dev/null +++ b/docs_src/custom_response/tutorial007_py310.py @@ -0,0 +1,14 @@ +from fastapi import FastAPI +from fastapi.responses import StreamingResponse + +app = FastAPI() + + +async def fake_video_streamer(): + for i in range(10): + yield b"some fake video bytes" + + +@app.get("/") +async def main(): + return StreamingResponse(fake_video_streamer()) diff --git a/docs_src/custom_response/tutorial008_py310.py b/docs_src/custom_response/tutorial008_py310.py new file mode 100644 index 000000000..fc071cbee --- /dev/null +++ b/docs_src/custom_response/tutorial008_py310.py @@ -0,0 +1,14 @@ +from fastapi import FastAPI +from fastapi.responses import StreamingResponse + +some_file_path = "large-video-file.mp4" +app = FastAPI() + + +@app.get("/") +def main(): + def iterfile(): # (1) + with open(some_file_path, mode="rb") as file_like: # (2) + yield from file_like # (3) + + return StreamingResponse(iterfile(), media_type="video/mp4") diff --git a/docs_src/custom_response/tutorial009_py310.py b/docs_src/custom_response/tutorial009_py310.py new file mode 100644 index 000000000..71cf50cc1 --- /dev/null +++ b/docs_src/custom_response/tutorial009_py310.py @@ -0,0 +1,10 @@ +from fastapi import FastAPI +from fastapi.responses import FileResponse + +some_file_path = "large-video-file.mp4" +app = FastAPI() + + +@app.get("/") +async def main(): + return FileResponse(some_file_path) diff --git a/docs_src/custom_response/tutorial009b_py310.py b/docs_src/custom_response/tutorial009b_py310.py new file mode 100644 index 000000000..27200ee4b --- /dev/null +++ b/docs_src/custom_response/tutorial009b_py310.py @@ -0,0 +1,10 @@ +from fastapi import FastAPI +from fastapi.responses import FileResponse + +some_file_path = "large-video-file.mp4" +app = FastAPI() + + +@app.get("/", response_class=FileResponse) +async def main(): + return some_file_path diff --git a/docs_src/custom_response/tutorial009c_py310.py b/docs_src/custom_response/tutorial009c_py310.py new file mode 100644 index 000000000..de6b6688e --- /dev/null +++ b/docs_src/custom_response/tutorial009c_py310.py @@ -0,0 +1,19 @@ +from typing import Any + +import orjson +from fastapi import FastAPI, Response + +app = FastAPI() + + +class CustomORJSONResponse(Response): + media_type = "application/json" + + def render(self, content: Any) -> bytes: + assert orjson is not None, "orjson must be installed" + return orjson.dumps(content, option=orjson.OPT_INDENT_2) + + +@app.get("/", response_class=CustomORJSONResponse) +async def main(): + return {"message": "Hello World"} diff --git a/docs_src/custom_response/tutorial010_py310.py b/docs_src/custom_response/tutorial010_py310.py new file mode 100644 index 000000000..57cb06260 --- /dev/null +++ b/docs_src/custom_response/tutorial010_py310.py @@ -0,0 +1,9 @@ +from fastapi import FastAPI +from fastapi.responses import ORJSONResponse + +app = FastAPI(default_response_class=ORJSONResponse) + + +@app.get("/items/") +async def read_items(): + return [{"item_id": "Foo"}] diff --git a/docs_src/dataclasses_/tutorial001_py39.py b/docs_src/dataclasses_/tutorial001_py39.py deleted file mode 100644 index 2954c391f..000000000 --- a/docs_src/dataclasses_/tutorial001_py39.py +++ /dev/null @@ -1,20 +0,0 @@ -from dataclasses import dataclass -from typing import Union - -from fastapi import FastAPI - - -@dataclass -class Item: - name: str - price: float - description: Union[str, None] = None - tax: Union[float, None] = None - - -app = FastAPI() - - -@app.post("/items/") -async def create_item(item: Item): - return item diff --git a/docs_src/dataclasses_/tutorial002_py39.py b/docs_src/dataclasses_/tutorial002_py39.py deleted file mode 100644 index 0c23765d8..000000000 --- a/docs_src/dataclasses_/tutorial002_py39.py +++ /dev/null @@ -1,26 +0,0 @@ -from dataclasses import dataclass, field -from typing import Union - -from fastapi import FastAPI - - -@dataclass -class Item: - name: str - price: float - tags: list[str] = field(default_factory=list) - description: Union[str, None] = None - tax: Union[float, None] = None - - -app = FastAPI() - - -@app.get("/items/next", response_model=Item) -async def read_next_item(): - return { - "name": "Island In The Moon", - "price": 12.99, - "description": "A place to be playin' and havin' fun", - "tags": ["breater"], - } diff --git a/docs_src/dataclasses_/tutorial003_py39.py b/docs_src/dataclasses_/tutorial003_py39.py deleted file mode 100644 index 991708c00..000000000 --- a/docs_src/dataclasses_/tutorial003_py39.py +++ /dev/null @@ -1,55 +0,0 @@ -from dataclasses import field # (1) -from typing import Union - -from fastapi import FastAPI -from pydantic.dataclasses import dataclass # (2) - - -@dataclass -class Item: - name: str - description: Union[str, None] = None - - -@dataclass -class Author: - name: str - items: list[Item] = field(default_factory=list) # (3) - - -app = FastAPI() - - -@app.post("/authors/{author_id}/items/", response_model=Author) # (4) -async def create_author_items(author_id: str, items: list[Item]): # (5) - return {"name": author_id, "items": items} # (6) - - -@app.get("/authors/", response_model=list[Author]) # (7) -def get_authors(): # (8) - return [ # (9) - { - "name": "Breaters", - "items": [ - { - "name": "Island In The Moon", - "description": "A place to be playin' and havin' fun", - }, - {"name": "Holy Buddies"}, - ], - }, - { - "name": "System of an Up", - "items": [ - { - "name": "Salt", - "description": "The kombucha mushroom people's favorite", - }, - {"name": "Pad Thai"}, - { - "name": "Lonely Night", - "description": "The mostests lonliest nightiest of allest", - }, - ], - }, - ] diff --git a/docs_src/debugging/tutorial001_py310.py b/docs_src/debugging/tutorial001_py310.py new file mode 100644 index 000000000..3de21d2a8 --- /dev/null +++ b/docs_src/debugging/tutorial001_py310.py @@ -0,0 +1,15 @@ +import uvicorn +from fastapi import FastAPI + +app = FastAPI() + + +@app.get("/") +def root(): + a = "a" + b = "b" + a + return {"hello world": b} + + +if __name__ == "__main__": + uvicorn.run(app, host="0.0.0.0", port=8000) diff --git a/docs_src/dependencies/tutorial001_02_an_py39.py b/docs_src/dependencies/tutorial001_02_an_py39.py deleted file mode 100644 index df969ae9c..000000000 --- a/docs_src/dependencies/tutorial001_02_an_py39.py +++ /dev/null @@ -1,24 +0,0 @@ -from typing import Annotated, Union - -from fastapi import Depends, FastAPI - -app = FastAPI() - - -async def common_parameters( - q: Union[str, None] = None, skip: int = 0, limit: int = 100 -): - return {"q": q, "skip": skip, "limit": limit} - - -CommonsDep = Annotated[dict, Depends(common_parameters)] - - -@app.get("/items/") -async def read_items(commons: CommonsDep): - return commons - - -@app.get("/users/") -async def read_users(commons: CommonsDep): - return commons diff --git a/docs_src/dependencies/tutorial001_an_py39.py b/docs_src/dependencies/tutorial001_an_py39.py deleted file mode 100644 index 5d9fe6ddf..000000000 --- a/docs_src/dependencies/tutorial001_an_py39.py +++ /dev/null @@ -1,21 +0,0 @@ -from typing import Annotated, Union - -from fastapi import Depends, FastAPI - -app = FastAPI() - - -async def common_parameters( - q: Union[str, None] = None, skip: int = 0, limit: int = 100 -): - return {"q": q, "skip": skip, "limit": limit} - - -@app.get("/items/") -async def read_items(commons: Annotated[dict, Depends(common_parameters)]): - return commons - - -@app.get("/users/") -async def read_users(commons: Annotated[dict, Depends(common_parameters)]): - return commons diff --git a/docs_src/dependencies/tutorial001_py39.py b/docs_src/dependencies/tutorial001_py39.py deleted file mode 100644 index b1275103a..000000000 --- a/docs_src/dependencies/tutorial001_py39.py +++ /dev/null @@ -1,21 +0,0 @@ -from typing import Union - -from fastapi import Depends, FastAPI - -app = FastAPI() - - -async def common_parameters( - q: Union[str, None] = None, skip: int = 0, limit: int = 100 -): - return {"q": q, "skip": skip, "limit": limit} - - -@app.get("/items/") -async def read_items(commons: dict = Depends(common_parameters)): - return commons - - -@app.get("/users/") -async def read_users(commons: dict = Depends(common_parameters)): - return commons diff --git a/docs_src/dependencies/tutorial002_an_py39.py b/docs_src/dependencies/tutorial002_an_py39.py deleted file mode 100644 index 844a23c5a..000000000 --- a/docs_src/dependencies/tutorial002_an_py39.py +++ /dev/null @@ -1,25 +0,0 @@ -from typing import Annotated, Union - -from fastapi import Depends, FastAPI - -app = FastAPI() - - -fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}] - - -class CommonQueryParams: - def __init__(self, q: Union[str, None] = None, skip: int = 0, limit: int = 100): - self.q = q - self.skip = skip - self.limit = limit - - -@app.get("/items/") -async def read_items(commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]): - response = {} - if commons.q: - response.update({"q": commons.q}) - items = fake_items_db[commons.skip : commons.skip + commons.limit] - response.update({"items": items}) - return response diff --git a/docs_src/dependencies/tutorial002_py39.py b/docs_src/dependencies/tutorial002_py39.py deleted file mode 100644 index 8e863e4fa..000000000 --- a/docs_src/dependencies/tutorial002_py39.py +++ /dev/null @@ -1,25 +0,0 @@ -from typing import Union - -from fastapi import Depends, FastAPI - -app = FastAPI() - - -fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}] - - -class CommonQueryParams: - def __init__(self, q: Union[str, None] = None, skip: int = 0, limit: int = 100): - self.q = q - self.skip = skip - self.limit = limit - - -@app.get("/items/") -async def read_items(commons: CommonQueryParams = Depends(CommonQueryParams)): - response = {} - if commons.q: - response.update({"q": commons.q}) - items = fake_items_db[commons.skip : commons.skip + commons.limit] - response.update({"items": items}) - return response diff --git a/docs_src/dependencies/tutorial003_an_py39.py b/docs_src/dependencies/tutorial003_an_py39.py deleted file mode 100644 index 9e9123ad2..000000000 --- a/docs_src/dependencies/tutorial003_an_py39.py +++ /dev/null @@ -1,25 +0,0 @@ -from typing import Annotated, Any, Union - -from fastapi import Depends, FastAPI - -app = FastAPI() - - -fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}] - - -class CommonQueryParams: - def __init__(self, q: Union[str, None] = None, skip: int = 0, limit: int = 100): - self.q = q - self.skip = skip - self.limit = limit - - -@app.get("/items/") -async def read_items(commons: Annotated[Any, Depends(CommonQueryParams)]): - response = {} - if commons.q: - response.update({"q": commons.q}) - items = fake_items_db[commons.skip : commons.skip + commons.limit] - response.update({"items": items}) - return response diff --git a/docs_src/dependencies/tutorial003_py39.py b/docs_src/dependencies/tutorial003_py39.py deleted file mode 100644 index 34614e539..000000000 --- a/docs_src/dependencies/tutorial003_py39.py +++ /dev/null @@ -1,25 +0,0 @@ -from typing import Union - -from fastapi import Depends, FastAPI - -app = FastAPI() - - -fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}] - - -class CommonQueryParams: - def __init__(self, q: Union[str, None] = None, skip: int = 0, limit: int = 100): - self.q = q - self.skip = skip - self.limit = limit - - -@app.get("/items/") -async def read_items(commons=Depends(CommonQueryParams)): - response = {} - if commons.q: - response.update({"q": commons.q}) - items = fake_items_db[commons.skip : commons.skip + commons.limit] - response.update({"items": items}) - return response diff --git a/docs_src/dependencies/tutorial004_an_py39.py b/docs_src/dependencies/tutorial004_an_py39.py deleted file mode 100644 index 74268626b..000000000 --- a/docs_src/dependencies/tutorial004_an_py39.py +++ /dev/null @@ -1,25 +0,0 @@ -from typing import Annotated, Union - -from fastapi import Depends, FastAPI - -app = FastAPI() - - -fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}] - - -class CommonQueryParams: - def __init__(self, q: Union[str, None] = None, skip: int = 0, limit: int = 100): - self.q = q - self.skip = skip - self.limit = limit - - -@app.get("/items/") -async def read_items(commons: Annotated[CommonQueryParams, Depends()]): - response = {} - if commons.q: - response.update({"q": commons.q}) - items = fake_items_db[commons.skip : commons.skip + commons.limit] - response.update({"items": items}) - return response diff --git a/docs_src/dependencies/tutorial004_py39.py b/docs_src/dependencies/tutorial004_py39.py deleted file mode 100644 index d9fe88148..000000000 --- a/docs_src/dependencies/tutorial004_py39.py +++ /dev/null @@ -1,25 +0,0 @@ -from typing import Union - -from fastapi import Depends, FastAPI - -app = FastAPI() - - -fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}] - - -class CommonQueryParams: - def __init__(self, q: Union[str, None] = None, skip: int = 0, limit: int = 100): - self.q = q - self.skip = skip - self.limit = limit - - -@app.get("/items/") -async def read_items(commons: CommonQueryParams = Depends()): - response = {} - if commons.q: - response.update({"q": commons.q}) - items = fake_items_db[commons.skip : commons.skip + commons.limit] - response.update({"items": items}) - return response diff --git a/docs_src/dependencies/tutorial005_an_py39.py b/docs_src/dependencies/tutorial005_an_py39.py deleted file mode 100644 index d5dd8dca9..000000000 --- a/docs_src/dependencies/tutorial005_an_py39.py +++ /dev/null @@ -1,25 +0,0 @@ -from typing import Annotated, Union - -from fastapi import Cookie, Depends, FastAPI - -app = FastAPI() - - -def query_extractor(q: Union[str, None] = None): - return q - - -def query_or_cookie_extractor( - q: Annotated[str, Depends(query_extractor)], - last_query: Annotated[Union[str, None], Cookie()] = None, -): - if not q: - return last_query - return q - - -@app.get("/items/") -async def read_query( - query_or_default: Annotated[str, Depends(query_or_cookie_extractor)], -): - return {"q_or_cookie": query_or_default} diff --git a/docs_src/dependencies/tutorial005_py39.py b/docs_src/dependencies/tutorial005_py39.py deleted file mode 100644 index 697332b5b..000000000 --- a/docs_src/dependencies/tutorial005_py39.py +++ /dev/null @@ -1,23 +0,0 @@ -from typing import Union - -from fastapi import Cookie, Depends, FastAPI - -app = FastAPI() - - -def query_extractor(q: Union[str, None] = None): - return q - - -def query_or_cookie_extractor( - q: str = Depends(query_extractor), - last_query: Union[str, None] = Cookie(default=None), -): - if not q: - return last_query - return q - - -@app.get("/items/") -async def read_query(query_or_default: str = Depends(query_or_cookie_extractor)): - return {"q_or_cookie": query_or_default} diff --git a/docs_src/dependencies/tutorial006_an_py310.py b/docs_src/dependencies/tutorial006_an_py310.py new file mode 100644 index 000000000..11976ed6a --- /dev/null +++ b/docs_src/dependencies/tutorial006_an_py310.py @@ -0,0 +1,21 @@ +from typing import Annotated + +from fastapi import Depends, FastAPI, Header, HTTPException + +app = FastAPI() + + +async def verify_token(x_token: Annotated[str, Header()]): + if x_token != "fake-super-secret-token": + raise HTTPException(status_code=400, detail="X-Token header invalid") + + +async def verify_key(x_key: Annotated[str, Header()]): + if x_key != "fake-super-secret-key": + raise HTTPException(status_code=400, detail="X-Key header invalid") + return x_key + + +@app.get("/items/", dependencies=[Depends(verify_token), Depends(verify_key)]) +async def read_items(): + return [{"item": "Foo"}, {"item": "Bar"}] diff --git a/docs_src/dependencies/tutorial006_py310.py b/docs_src/dependencies/tutorial006_py310.py new file mode 100644 index 000000000..9aff4154f --- /dev/null +++ b/docs_src/dependencies/tutorial006_py310.py @@ -0,0 +1,19 @@ +from fastapi import Depends, FastAPI, Header, HTTPException + +app = FastAPI() + + +async def verify_token(x_token: str = Header()): + if x_token != "fake-super-secret-token": + raise HTTPException(status_code=400, detail="X-Token header invalid") + + +async def verify_key(x_key: str = Header()): + if x_key != "fake-super-secret-key": + raise HTTPException(status_code=400, detail="X-Key header invalid") + return x_key + + +@app.get("/items/", dependencies=[Depends(verify_token), Depends(verify_key)]) +async def read_items(): + return [{"item": "Foo"}, {"item": "Bar"}] diff --git a/docs_src/dependencies/tutorial007_py310.py b/docs_src/dependencies/tutorial007_py310.py new file mode 100644 index 000000000..2e4ab4777 --- /dev/null +++ b/docs_src/dependencies/tutorial007_py310.py @@ -0,0 +1,6 @@ +async def get_db(): + db = DBSession() + try: + yield db + finally: + db.close() diff --git a/docs_src/dependencies/tutorial008_an_py310.py b/docs_src/dependencies/tutorial008_an_py310.py new file mode 100644 index 000000000..acc804c32 --- /dev/null +++ b/docs_src/dependencies/tutorial008_an_py310.py @@ -0,0 +1,27 @@ +from typing import Annotated + +from fastapi import Depends + + +async def dependency_a(): + dep_a = generate_dep_a() + try: + yield dep_a + finally: + dep_a.close() + + +async def dependency_b(dep_a: Annotated[DepA, Depends(dependency_a)]): + dep_b = generate_dep_b() + try: + yield dep_b + finally: + dep_b.close(dep_a) + + +async def dependency_c(dep_b: Annotated[DepB, Depends(dependency_b)]): + dep_c = generate_dep_c() + try: + yield dep_c + finally: + dep_c.close(dep_b) diff --git a/docs_src/dependencies/tutorial008_py310.py b/docs_src/dependencies/tutorial008_py310.py new file mode 100644 index 000000000..8472f642d --- /dev/null +++ b/docs_src/dependencies/tutorial008_py310.py @@ -0,0 +1,25 @@ +from fastapi import Depends + + +async def dependency_a(): + dep_a = generate_dep_a() + try: + yield dep_a + finally: + dep_a.close() + + +async def dependency_b(dep_a=Depends(dependency_a)): + dep_b = generate_dep_b() + try: + yield dep_b + finally: + dep_b.close(dep_a) + + +async def dependency_c(dep_b=Depends(dependency_b)): + dep_c = generate_dep_c() + try: + yield dep_c + finally: + dep_c.close(dep_b) diff --git a/docs_src/dependencies/tutorial008b_an_py310.py b/docs_src/dependencies/tutorial008b_an_py310.py new file mode 100644 index 000000000..3b8434c81 --- /dev/null +++ b/docs_src/dependencies/tutorial008b_an_py310.py @@ -0,0 +1,32 @@ +from typing import Annotated + +from fastapi import Depends, FastAPI, HTTPException + +app = FastAPI() + + +data = { + "plumbus": {"description": "Freshly pickled plumbus", "owner": "Morty"}, + "portal-gun": {"description": "Gun to create portals", "owner": "Rick"}, +} + + +class OwnerError(Exception): + pass + + +def get_username(): + try: + yield "Rick" + except OwnerError as e: + raise HTTPException(status_code=400, detail=f"Owner error: {e}") + + +@app.get("/items/{item_id}") +def get_item(item_id: str, username: Annotated[str, Depends(get_username)]): + if item_id not in data: + raise HTTPException(status_code=404, detail="Item not found") + item = data[item_id] + if item["owner"] != username: + raise OwnerError(username) + return item diff --git a/docs_src/dependencies/tutorial008b_py310.py b/docs_src/dependencies/tutorial008b_py310.py new file mode 100644 index 000000000..163e96600 --- /dev/null +++ b/docs_src/dependencies/tutorial008b_py310.py @@ -0,0 +1,30 @@ +from fastapi import Depends, FastAPI, HTTPException + +app = FastAPI() + + +data = { + "plumbus": {"description": "Freshly pickled plumbus", "owner": "Morty"}, + "portal-gun": {"description": "Gun to create portals", "owner": "Rick"}, +} + + +class OwnerError(Exception): + pass + + +def get_username(): + try: + yield "Rick" + except OwnerError as e: + raise HTTPException(status_code=400, detail=f"Owner error: {e}") + + +@app.get("/items/{item_id}") +def get_item(item_id: str, username: str = Depends(get_username)): + if item_id not in data: + raise HTTPException(status_code=404, detail="Item not found") + item = data[item_id] + if item["owner"] != username: + raise OwnerError(username) + return item diff --git a/docs_src/dependencies/tutorial008c_an_py310.py b/docs_src/dependencies/tutorial008c_an_py310.py new file mode 100644 index 000000000..da92efa9c --- /dev/null +++ b/docs_src/dependencies/tutorial008c_an_py310.py @@ -0,0 +1,29 @@ +from typing import Annotated + +from fastapi import Depends, FastAPI, HTTPException + +app = FastAPI() + + +class InternalError(Exception): + pass + + +def get_username(): + try: + yield "Rick" + except InternalError: + print("Oops, we didn't raise again, Britney 😱") + + +@app.get("/items/{item_id}") +def get_item(item_id: str, username: Annotated[str, Depends(get_username)]): + if item_id == "portal-gun": + raise InternalError( + f"The portal gun is too dangerous to be owned by {username}" + ) + if item_id != "plumbus": + raise HTTPException( + status_code=404, detail="Item not found, there's only a plumbus here" + ) + return item_id diff --git a/docs_src/dependencies/tutorial008c_py310.py b/docs_src/dependencies/tutorial008c_py310.py new file mode 100644 index 000000000..4b99a5a31 --- /dev/null +++ b/docs_src/dependencies/tutorial008c_py310.py @@ -0,0 +1,27 @@ +from fastapi import Depends, FastAPI, HTTPException + +app = FastAPI() + + +class InternalError(Exception): + pass + + +def get_username(): + try: + yield "Rick" + except InternalError: + print("Oops, we didn't raise again, Britney 😱") + + +@app.get("/items/{item_id}") +def get_item(item_id: str, username: str = Depends(get_username)): + if item_id == "portal-gun": + raise InternalError( + f"The portal gun is too dangerous to be owned by {username}" + ) + if item_id != "plumbus": + raise HTTPException( + status_code=404, detail="Item not found, there's only a plumbus here" + ) + return item_id diff --git a/docs_src/dependencies/tutorial008d_an_py310.py b/docs_src/dependencies/tutorial008d_an_py310.py new file mode 100644 index 000000000..99bd5cb91 --- /dev/null +++ b/docs_src/dependencies/tutorial008d_an_py310.py @@ -0,0 +1,30 @@ +from typing import Annotated + +from fastapi import Depends, FastAPI, HTTPException + +app = FastAPI() + + +class InternalError(Exception): + pass + + +def get_username(): + try: + yield "Rick" + except InternalError: + print("We don't swallow the internal error here, we raise again 😎") + raise + + +@app.get("/items/{item_id}") +def get_item(item_id: str, username: Annotated[str, Depends(get_username)]): + if item_id == "portal-gun": + raise InternalError( + f"The portal gun is too dangerous to be owned by {username}" + ) + if item_id != "plumbus": + raise HTTPException( + status_code=404, detail="Item not found, there's only a plumbus here" + ) + return item_id diff --git a/docs_src/dependencies/tutorial008d_py310.py b/docs_src/dependencies/tutorial008d_py310.py new file mode 100644 index 000000000..93039343d --- /dev/null +++ b/docs_src/dependencies/tutorial008d_py310.py @@ -0,0 +1,28 @@ +from fastapi import Depends, FastAPI, HTTPException + +app = FastAPI() + + +class InternalError(Exception): + pass + + +def get_username(): + try: + yield "Rick" + except InternalError: + print("We don't swallow the internal error here, we raise again 😎") + raise + + +@app.get("/items/{item_id}") +def get_item(item_id: str, username: str = Depends(get_username)): + if item_id == "portal-gun": + raise InternalError( + f"The portal gun is too dangerous to be owned by {username}" + ) + if item_id != "plumbus": + raise HTTPException( + status_code=404, detail="Item not found, there's only a plumbus here" + ) + return item_id diff --git a/docs_src/dependencies/tutorial008e_an_py310.py b/docs_src/dependencies/tutorial008e_an_py310.py new file mode 100644 index 000000000..80a44c7e2 --- /dev/null +++ b/docs_src/dependencies/tutorial008e_an_py310.py @@ -0,0 +1,17 @@ +from typing import Annotated + +from fastapi import Depends, FastAPI + +app = FastAPI() + + +def get_username(): + try: + yield "Rick" + finally: + print("Cleanup up before response is sent") + + +@app.get("/users/me") +def get_user_me(username: Annotated[str, Depends(get_username, scope="function")]): + return username diff --git a/docs_src/dependencies/tutorial008e_py310.py b/docs_src/dependencies/tutorial008e_py310.py new file mode 100644 index 000000000..1ed056e91 --- /dev/null +++ b/docs_src/dependencies/tutorial008e_py310.py @@ -0,0 +1,15 @@ +from fastapi import Depends, FastAPI + +app = FastAPI() + + +def get_username(): + try: + yield "Rick" + finally: + print("Cleanup up before response is sent") + + +@app.get("/users/me") +def get_user_me(username: str = Depends(get_username, scope="function")): + return username diff --git a/docs_src/dependencies/tutorial010_py310.py b/docs_src/dependencies/tutorial010_py310.py new file mode 100644 index 000000000..c27f1b170 --- /dev/null +++ b/docs_src/dependencies/tutorial010_py310.py @@ -0,0 +1,14 @@ +class MySuperContextManager: + def __init__(self): + self.db = DBSession() + + def __enter__(self): + return self.db + + def __exit__(self, exc_type, exc_value, traceback): + self.db.close() + + +async def get_db(): + with MySuperContextManager() as db: + yield db diff --git a/docs_src/dependencies/tutorial011_an_py310.py b/docs_src/dependencies/tutorial011_an_py310.py new file mode 100644 index 000000000..68b7434ec --- /dev/null +++ b/docs_src/dependencies/tutorial011_an_py310.py @@ -0,0 +1,23 @@ +from typing import Annotated + +from fastapi import Depends, FastAPI + +app = FastAPI() + + +class FixedContentQueryChecker: + def __init__(self, fixed_content: str): + self.fixed_content = fixed_content + + def __call__(self, q: str = ""): + if q: + return self.fixed_content in q + return False + + +checker = FixedContentQueryChecker("bar") + + +@app.get("/query-checker/") +async def read_query_check(fixed_content_included: Annotated[bool, Depends(checker)]): + return {"fixed_content_in_query": fixed_content_included} diff --git a/docs_src/dependencies/tutorial011_py310.py b/docs_src/dependencies/tutorial011_py310.py new file mode 100644 index 000000000..5d22f6823 --- /dev/null +++ b/docs_src/dependencies/tutorial011_py310.py @@ -0,0 +1,21 @@ +from fastapi import Depends, FastAPI + +app = FastAPI() + + +class FixedContentQueryChecker: + def __init__(self, fixed_content: str): + self.fixed_content = fixed_content + + def __call__(self, q: str = ""): + if q: + return self.fixed_content in q + return False + + +checker = FixedContentQueryChecker("bar") + + +@app.get("/query-checker/") +async def read_query_check(fixed_content_included: bool = Depends(checker)): + return {"fixed_content_in_query": fixed_content_included} diff --git a/docs_src/dependencies/tutorial012_an_py310.py b/docs_src/dependencies/tutorial012_an_py310.py new file mode 100644 index 000000000..6503591fc --- /dev/null +++ b/docs_src/dependencies/tutorial012_an_py310.py @@ -0,0 +1,27 @@ +from typing import Annotated + +from fastapi import Depends, FastAPI, Header, HTTPException + + +async def verify_token(x_token: Annotated[str, Header()]): + if x_token != "fake-super-secret-token": + raise HTTPException(status_code=400, detail="X-Token header invalid") + + +async def verify_key(x_key: Annotated[str, Header()]): + if x_key != "fake-super-secret-key": + raise HTTPException(status_code=400, detail="X-Key header invalid") + return x_key + + +app = FastAPI(dependencies=[Depends(verify_token), Depends(verify_key)]) + + +@app.get("/items/") +async def read_items(): + return [{"item": "Portal Gun"}, {"item": "Plumbus"}] + + +@app.get("/users/") +async def read_users(): + return [{"username": "Rick"}, {"username": "Morty"}] diff --git a/docs_src/dependencies/tutorial012_py310.py b/docs_src/dependencies/tutorial012_py310.py new file mode 100644 index 000000000..36ce6c711 --- /dev/null +++ b/docs_src/dependencies/tutorial012_py310.py @@ -0,0 +1,25 @@ +from fastapi import Depends, FastAPI, Header, HTTPException + + +async def verify_token(x_token: str = Header()): + if x_token != "fake-super-secret-token": + raise HTTPException(status_code=400, detail="X-Token header invalid") + + +async def verify_key(x_key: str = Header()): + if x_key != "fake-super-secret-key": + raise HTTPException(status_code=400, detail="X-Key header invalid") + return x_key + + +app = FastAPI(dependencies=[Depends(verify_token), Depends(verify_key)]) + + +@app.get("/items/") +async def read_items(): + return [{"item": "Portal Gun"}, {"item": "Plumbus"}] + + +@app.get("/users/") +async def read_users(): + return [{"username": "Rick"}, {"username": "Morty"}] diff --git a/docs_src/dependency_testing/tutorial001_an_py39.py b/docs_src/dependency_testing/tutorial001_an_py39.py deleted file mode 100644 index bccb0cdb1..000000000 --- a/docs_src/dependency_testing/tutorial001_an_py39.py +++ /dev/null @@ -1,59 +0,0 @@ -from typing import Annotated, Union - -from fastapi import Depends, FastAPI -from fastapi.testclient import TestClient - -app = FastAPI() - - -async def common_parameters( - q: Union[str, None] = None, skip: int = 0, limit: int = 100 -): - return {"q": q, "skip": skip, "limit": limit} - - -@app.get("/items/") -async def read_items(commons: Annotated[dict, Depends(common_parameters)]): - return {"message": "Hello Items!", "params": commons} - - -@app.get("/users/") -async def read_users(commons: Annotated[dict, Depends(common_parameters)]): - return {"message": "Hello Users!", "params": commons} - - -client = TestClient(app) - - -async def override_dependency(q: Union[str, None] = None): - return {"q": q, "skip": 5, "limit": 10} - - -app.dependency_overrides[common_parameters] = override_dependency - - -def test_override_in_items(): - response = client.get("/items/") - assert response.status_code == 200 - assert response.json() == { - "message": "Hello Items!", - "params": {"q": None, "skip": 5, "limit": 10}, - } - - -def test_override_in_items_with_q(): - response = client.get("/items/?q=foo") - assert response.status_code == 200 - assert response.json() == { - "message": "Hello Items!", - "params": {"q": "foo", "skip": 5, "limit": 10}, - } - - -def test_override_in_items_with_params(): - response = client.get("/items/?q=foo&skip=100&limit=200") - assert response.status_code == 200 - assert response.json() == { - "message": "Hello Items!", - "params": {"q": "foo", "skip": 5, "limit": 10}, - } diff --git a/docs_src/dependency_testing/tutorial001_py39.py b/docs_src/dependency_testing/tutorial001_py39.py deleted file mode 100644 index a5fe1d9bf..000000000 --- a/docs_src/dependency_testing/tutorial001_py39.py +++ /dev/null @@ -1,59 +0,0 @@ -from typing import Union - -from fastapi import Depends, FastAPI -from fastapi.testclient import TestClient - -app = FastAPI() - - -async def common_parameters( - q: Union[str, None] = None, skip: int = 0, limit: int = 100 -): - return {"q": q, "skip": skip, "limit": limit} - - -@app.get("/items/") -async def read_items(commons: dict = Depends(common_parameters)): - return {"message": "Hello Items!", "params": commons} - - -@app.get("/users/") -async def read_users(commons: dict = Depends(common_parameters)): - return {"message": "Hello Users!", "params": commons} - - -client = TestClient(app) - - -async def override_dependency(q: Union[str, None] = None): - return {"q": q, "skip": 5, "limit": 10} - - -app.dependency_overrides[common_parameters] = override_dependency - - -def test_override_in_items(): - response = client.get("/items/") - assert response.status_code == 200 - assert response.json() == { - "message": "Hello Items!", - "params": {"q": None, "skip": 5, "limit": 10}, - } - - -def test_override_in_items_with_q(): - response = client.get("/items/?q=foo") - assert response.status_code == 200 - assert response.json() == { - "message": "Hello Items!", - "params": {"q": "foo", "skip": 5, "limit": 10}, - } - - -def test_override_in_items_with_params(): - response = client.get("/items/?q=foo&skip=100&limit=200") - assert response.status_code == 200 - assert response.json() == { - "message": "Hello Items!", - "params": {"q": "foo", "skip": 5, "limit": 10}, - } diff --git a/docs_src/encoder/tutorial001_py39.py b/docs_src/encoder/tutorial001_py39.py deleted file mode 100644 index 5f7e7061e..000000000 --- a/docs_src/encoder/tutorial001_py39.py +++ /dev/null @@ -1,23 +0,0 @@ -from datetime import datetime -from typing import Union - -from fastapi import FastAPI -from fastapi.encoders import jsonable_encoder -from pydantic import BaseModel - -fake_db = {} - - -class Item(BaseModel): - title: str - timestamp: datetime - description: Union[str, None] = None - - -app = FastAPI() - - -@app.put("/items/{id}") -def update_item(id: str, item: Item): - json_compatible_item_data = jsonable_encoder(item) - fake_db[id] = json_compatible_item_data diff --git a/docs_src/events/tutorial001_py310.py b/docs_src/events/tutorial001_py310.py new file mode 100644 index 000000000..128004c9f --- /dev/null +++ b/docs_src/events/tutorial001_py310.py @@ -0,0 +1,16 @@ +from fastapi import FastAPI + +app = FastAPI() + +items = {} + + +@app.on_event("startup") +async def startup_event(): + items["foo"] = {"name": "Fighters"} + items["bar"] = {"name": "Tenders"} + + +@app.get("/items/{item_id}") +async def read_items(item_id: str): + return items[item_id] diff --git a/docs_src/events/tutorial002_py310.py b/docs_src/events/tutorial002_py310.py new file mode 100644 index 000000000..a71fea802 --- /dev/null +++ b/docs_src/events/tutorial002_py310.py @@ -0,0 +1,14 @@ +from fastapi import FastAPI + +app = FastAPI() + + +@app.on_event("shutdown") +def shutdown_event(): + with open("log.txt", mode="a") as log: + log.write("Application shutdown") + + +@app.get("/items/") +async def read_items(): + return [{"name": "Foo"}] diff --git a/docs_src/events/tutorial003_py310.py b/docs_src/events/tutorial003_py310.py new file mode 100644 index 000000000..2b650590b --- /dev/null +++ b/docs_src/events/tutorial003_py310.py @@ -0,0 +1,28 @@ +from contextlib import asynccontextmanager + +from fastapi import FastAPI + + +def fake_answer_to_everything_ml_model(x: float): + return x * 42 + + +ml_models = {} + + +@asynccontextmanager +async def lifespan(app: FastAPI): + # Load the ML model + ml_models["answer_to_everything"] = fake_answer_to_everything_ml_model + yield + # Clean up the ML models and release the resources + ml_models.clear() + + +app = FastAPI(lifespan=lifespan) + + +@app.get("/predict") +async def predict(x: float): + result = ml_models["answer_to_everything"](x) + return {"result": result} diff --git a/docs_src/extending_openapi/tutorial001_py310.py b/docs_src/extending_openapi/tutorial001_py310.py new file mode 100644 index 000000000..35e31c0e0 --- /dev/null +++ b/docs_src/extending_openapi/tutorial001_py310.py @@ -0,0 +1,29 @@ +from fastapi import FastAPI +from fastapi.openapi.utils import get_openapi + +app = FastAPI() + + +@app.get("/items/") +async def read_items(): + return [{"name": "Foo"}] + + +def custom_openapi(): + if app.openapi_schema: + return app.openapi_schema + openapi_schema = get_openapi( + title="Custom title", + version="2.5.0", + summary="This is a very custom OpenAPI schema", + description="Here's a longer description of the custom **OpenAPI** schema", + routes=app.routes, + ) + openapi_schema["info"]["x-logo"] = { + "url": "https://fastapi.tiangolo.com/img/logo-margin/logo-teal.png" + } + app.openapi_schema = openapi_schema + return app.openapi_schema + + +app.openapi = custom_openapi diff --git a/docs_src/extra_data_types/tutorial001_an_py39.py b/docs_src/extra_data_types/tutorial001_an_py39.py deleted file mode 100644 index fa3551d66..000000000 --- a/docs_src/extra_data_types/tutorial001_an_py39.py +++ /dev/null @@ -1,28 +0,0 @@ -from datetime import datetime, time, timedelta -from typing import Annotated, Union -from uuid import UUID - -from fastapi import Body, FastAPI - -app = FastAPI() - - -@app.put("/items/{item_id}") -async def read_items( - item_id: UUID, - start_datetime: Annotated[datetime, Body()], - end_datetime: Annotated[datetime, Body()], - process_after: Annotated[timedelta, Body()], - repeat_at: Annotated[Union[time, None], Body()] = None, -): - start_process = start_datetime + process_after - duration = end_datetime - start_process - return { - "item_id": item_id, - "start_datetime": start_datetime, - "end_datetime": end_datetime, - "process_after": process_after, - "repeat_at": repeat_at, - "start_process": start_process, - "duration": duration, - } diff --git a/docs_src/extra_data_types/tutorial001_py39.py b/docs_src/extra_data_types/tutorial001_py39.py deleted file mode 100644 index 71de958ff..000000000 --- a/docs_src/extra_data_types/tutorial001_py39.py +++ /dev/null @@ -1,28 +0,0 @@ -from datetime import datetime, time, timedelta -from typing import Union -from uuid import UUID - -from fastapi import Body, FastAPI - -app = FastAPI() - - -@app.put("/items/{item_id}") -async def read_items( - item_id: UUID, - start_datetime: datetime = Body(), - end_datetime: datetime = Body(), - process_after: timedelta = Body(), - repeat_at: Union[time, None] = Body(default=None), -): - start_process = start_datetime + process_after - duration = end_datetime - start_process - return { - "item_id": item_id, - "start_datetime": start_datetime, - "end_datetime": end_datetime, - "process_after": process_after, - "repeat_at": repeat_at, - "start_process": start_process, - "duration": duration, - } diff --git a/docs_src/extra_models/tutorial001_py39.py b/docs_src/extra_models/tutorial001_py39.py deleted file mode 100644 index 327ffcdf0..000000000 --- a/docs_src/extra_models/tutorial001_py39.py +++ /dev/null @@ -1,43 +0,0 @@ -from typing import Union - -from fastapi import FastAPI -from pydantic import BaseModel, EmailStr - -app = FastAPI() - - -class UserIn(BaseModel): - username: str - password: str - email: EmailStr - full_name: Union[str, None] = None - - -class UserOut(BaseModel): - username: str - email: EmailStr - full_name: Union[str, None] = None - - -class UserInDB(BaseModel): - username: str - hashed_password: str - email: EmailStr - full_name: Union[str, None] = None - - -def fake_password_hasher(raw_password: str): - return "supersecret" + raw_password - - -def fake_save_user(user_in: UserIn): - hashed_password = fake_password_hasher(user_in.password) - user_in_db = UserInDB(**user_in.model_dump(), hashed_password=hashed_password) - print("User saved! ..not really") - return user_in_db - - -@app.post("/user/", response_model=UserOut) -async def create_user(user_in: UserIn): - user_saved = fake_save_user(user_in) - return user_saved diff --git a/docs_src/extra_models/tutorial002_py39.py b/docs_src/extra_models/tutorial002_py39.py deleted file mode 100644 index 654379601..000000000 --- a/docs_src/extra_models/tutorial002_py39.py +++ /dev/null @@ -1,41 +0,0 @@ -from typing import Union - -from fastapi import FastAPI -from pydantic import BaseModel, EmailStr - -app = FastAPI() - - -class UserBase(BaseModel): - username: str - email: EmailStr - full_name: Union[str, None] = None - - -class UserIn(UserBase): - password: str - - -class UserOut(UserBase): - pass - - -class UserInDB(UserBase): - hashed_password: str - - -def fake_password_hasher(raw_password: str): - return "supersecret" + raw_password - - -def fake_save_user(user_in: UserIn): - hashed_password = fake_password_hasher(user_in.password) - user_in_db = UserInDB(**user_in.model_dump(), hashed_password=hashed_password) - print("User saved! ..not really") - return user_in_db - - -@app.post("/user/", response_model=UserOut) -async def create_user(user_in: UserIn): - user_saved = fake_save_user(user_in) - return user_saved diff --git a/docs_src/extra_models/tutorial003_py39.py b/docs_src/extra_models/tutorial003_py39.py deleted file mode 100644 index 06675cbc0..000000000 --- a/docs_src/extra_models/tutorial003_py39.py +++ /dev/null @@ -1,35 +0,0 @@ -from typing import Union - -from fastapi import FastAPI -from pydantic import BaseModel - -app = FastAPI() - - -class BaseItem(BaseModel): - description: str - type: str - - -class CarItem(BaseItem): - type: str = "car" - - -class PlaneItem(BaseItem): - type: str = "plane" - size: int - - -items = { - "item1": {"description": "All my friends drive a low rider", "type": "car"}, - "item2": { - "description": "Music is my aeroplane, it's my aeroplane", - "type": "plane", - "size": 5, - }, -} - - -@app.get("/items/{item_id}", response_model=Union[PlaneItem, CarItem]) -async def read_item(item_id: str): - return items[item_id] diff --git a/docs_src/extra_models/tutorial004_py310.py b/docs_src/extra_models/tutorial004_py310.py new file mode 100644 index 000000000..28cacde4d --- /dev/null +++ b/docs_src/extra_models/tutorial004_py310.py @@ -0,0 +1,20 @@ +from fastapi import FastAPI +from pydantic import BaseModel + +app = FastAPI() + + +class Item(BaseModel): + name: str + description: str + + +items = [ + {"name": "Foo", "description": "There comes my hero"}, + {"name": "Red", "description": "It's my aeroplane"}, +] + + +@app.get("/items/", response_model=list[Item]) +async def read_items(): + return items diff --git a/docs_src/extra_models/tutorial005_py310.py b/docs_src/extra_models/tutorial005_py310.py new file mode 100644 index 000000000..9da2a0a0f --- /dev/null +++ b/docs_src/extra_models/tutorial005_py310.py @@ -0,0 +1,8 @@ +from fastapi import FastAPI + +app = FastAPI() + + +@app.get("/keyword-weights/", response_model=dict[str, float]) +async def read_keyword_weights(): + return {"foo": 2.3, "bar": 3.4} diff --git a/docs_src/first_steps/tutorial001_py310.py b/docs_src/first_steps/tutorial001_py310.py new file mode 100644 index 000000000..ee60be1f9 --- /dev/null +++ b/docs_src/first_steps/tutorial001_py310.py @@ -0,0 +1,8 @@ +from fastapi import FastAPI + +app = FastAPI() + + +@app.get("/") +async def root(): + return {"message": "Hello World"} diff --git a/docs_src/first_steps/tutorial003_py310.py b/docs_src/first_steps/tutorial003_py310.py new file mode 100644 index 000000000..e30b827ea --- /dev/null +++ b/docs_src/first_steps/tutorial003_py310.py @@ -0,0 +1,8 @@ +from fastapi import FastAPI + +app = FastAPI() + + +@app.get("/") +def root(): + return {"message": "Hello World"} diff --git a/docs_src/generate_clients/tutorial001_py310.py b/docs_src/generate_clients/tutorial001_py310.py new file mode 100644 index 000000000..6a5ae2320 --- /dev/null +++ b/docs_src/generate_clients/tutorial001_py310.py @@ -0,0 +1,26 @@ +from fastapi import FastAPI +from pydantic import BaseModel + +app = FastAPI() + + +class Item(BaseModel): + name: str + price: float + + +class ResponseMessage(BaseModel): + message: str + + +@app.post("/items/", response_model=ResponseMessage) +async def create_item(item: Item): + return {"message": "item received"} + + +@app.get("/items/", response_model=list[Item]) +async def get_items(): + return [ + {"name": "Plumbus", "price": 3}, + {"name": "Portal Gun", "price": 9001}, + ] diff --git a/docs_src/generate_clients/tutorial002_py310.py b/docs_src/generate_clients/tutorial002_py310.py new file mode 100644 index 000000000..83309760b --- /dev/null +++ b/docs_src/generate_clients/tutorial002_py310.py @@ -0,0 +1,36 @@ +from fastapi import FastAPI +from pydantic import BaseModel + +app = FastAPI() + + +class Item(BaseModel): + name: str + price: float + + +class ResponseMessage(BaseModel): + message: str + + +class User(BaseModel): + username: str + email: str + + +@app.post("/items/", response_model=ResponseMessage, tags=["items"]) +async def create_item(item: Item): + return {"message": "Item received"} + + +@app.get("/items/", response_model=list[Item], tags=["items"]) +async def get_items(): + return [ + {"name": "Plumbus", "price": 3}, + {"name": "Portal Gun", "price": 9001}, + ] + + +@app.post("/users/", response_model=ResponseMessage, tags=["users"]) +async def create_user(user: User): + return {"message": "User received"} diff --git a/docs_src/generate_clients/tutorial003_py310.py b/docs_src/generate_clients/tutorial003_py310.py new file mode 100644 index 000000000..40722cf10 --- /dev/null +++ b/docs_src/generate_clients/tutorial003_py310.py @@ -0,0 +1,42 @@ +from fastapi import FastAPI +from fastapi.routing import APIRoute +from pydantic import BaseModel + + +def custom_generate_unique_id(route: APIRoute): + return f"{route.tags[0]}-{route.name}" + + +app = FastAPI(generate_unique_id_function=custom_generate_unique_id) + + +class Item(BaseModel): + name: str + price: float + + +class ResponseMessage(BaseModel): + message: str + + +class User(BaseModel): + username: str + email: str + + +@app.post("/items/", response_model=ResponseMessage, tags=["items"]) +async def create_item(item: Item): + return {"message": "Item received"} + + +@app.get("/items/", response_model=list[Item], tags=["items"]) +async def get_items(): + return [ + {"name": "Plumbus", "price": 3}, + {"name": "Portal Gun", "price": 9001}, + ] + + +@app.post("/users/", response_model=ResponseMessage, tags=["users"]) +async def create_user(user: User): + return {"message": "User received"} diff --git a/docs_src/generate_clients/tutorial004_py310.py b/docs_src/generate_clients/tutorial004_py310.py new file mode 100644 index 000000000..894dc7f8d --- /dev/null +++ b/docs_src/generate_clients/tutorial004_py310.py @@ -0,0 +1,15 @@ +import json +from pathlib import Path + +file_path = Path("./openapi.json") +openapi_content = json.loads(file_path.read_text()) + +for path_data in openapi_content["paths"].values(): + for operation in path_data.values(): + tag = operation["tags"][0] + operation_id = operation["operationId"] + to_remove = f"{tag}-" + new_operation_id = operation_id[len(to_remove) :] + operation["operationId"] = new_operation_id + +file_path.write_text(json.dumps(openapi_content)) diff --git a/docs_src/graphql_/tutorial001_py310.py b/docs_src/graphql_/tutorial001_py310.py new file mode 100644 index 000000000..e92b2d71c --- /dev/null +++ b/docs_src/graphql_/tutorial001_py310.py @@ -0,0 +1,25 @@ +import strawberry +from fastapi import FastAPI +from strawberry.fastapi import GraphQLRouter + + +@strawberry.type +class User: + name: str + age: int + + +@strawberry.type +class Query: + @strawberry.field + def user(self) -> User: + return User(name="Patrick", age=100) + + +schema = strawberry.Schema(query=Query) + + +graphql_app = GraphQLRouter(schema) + +app = FastAPI() +app.include_router(graphql_app, prefix="/graphql") diff --git a/docs_src/handling_errors/tutorial001_py310.py b/docs_src/handling_errors/tutorial001_py310.py new file mode 100644 index 000000000..e5f32aac2 --- /dev/null +++ b/docs_src/handling_errors/tutorial001_py310.py @@ -0,0 +1,12 @@ +from fastapi import FastAPI, HTTPException + +app = FastAPI() + +items = {"foo": "The Foo Wrestlers"} + + +@app.get("/items/{item_id}") +async def read_item(item_id: str): + if item_id not in items: + raise HTTPException(status_code=404, detail="Item not found") + return {"item": items[item_id]} diff --git a/docs_src/handling_errors/tutorial002_py310.py b/docs_src/handling_errors/tutorial002_py310.py new file mode 100644 index 000000000..e48c295c9 --- /dev/null +++ b/docs_src/handling_errors/tutorial002_py310.py @@ -0,0 +1,16 @@ +from fastapi import FastAPI, HTTPException + +app = FastAPI() + +items = {"foo": "The Foo Wrestlers"} + + +@app.get("/items-header/{item_id}") +async def read_item_header(item_id: str): + if item_id not in items: + raise HTTPException( + status_code=404, + detail="Item not found", + headers={"X-Error": "There goes my error"}, + ) + return {"item": items[item_id]} diff --git a/docs_src/handling_errors/tutorial003_py310.py b/docs_src/handling_errors/tutorial003_py310.py new file mode 100644 index 000000000..791cd6838 --- /dev/null +++ b/docs_src/handling_errors/tutorial003_py310.py @@ -0,0 +1,25 @@ +from fastapi import FastAPI, Request +from fastapi.responses import JSONResponse + + +class UnicornException(Exception): + def __init__(self, name: str): + self.name = name + + +app = FastAPI() + + +@app.exception_handler(UnicornException) +async def unicorn_exception_handler(request: Request, exc: UnicornException): + return JSONResponse( + status_code=418, + content={"message": f"Oops! {exc.name} did something. There goes a rainbow..."}, + ) + + +@app.get("/unicorns/{name}") +async def read_unicorn(name: str): + if name == "yolo": + raise UnicornException(name=name) + return {"unicorn_name": name} diff --git a/docs_src/handling_errors/tutorial004_py310.py b/docs_src/handling_errors/tutorial004_py310.py new file mode 100644 index 000000000..ae50807e9 --- /dev/null +++ b/docs_src/handling_errors/tutorial004_py310.py @@ -0,0 +1,26 @@ +from fastapi import FastAPI, HTTPException +from fastapi.exceptions import RequestValidationError +from fastapi.responses import PlainTextResponse +from starlette.exceptions import HTTPException as StarletteHTTPException + +app = FastAPI() + + +@app.exception_handler(StarletteHTTPException) +async def http_exception_handler(request, exc): + return PlainTextResponse(str(exc.detail), status_code=exc.status_code) + + +@app.exception_handler(RequestValidationError) +async def validation_exception_handler(request, exc: RequestValidationError): + message = "Validation errors:" + for error in exc.errors(): + message += f"\nField: {error['loc']}, Error: {error['msg']}" + return PlainTextResponse(message, status_code=400) + + +@app.get("/items/{item_id}") +async def read_item(item_id: int): + if item_id == 3: + raise HTTPException(status_code=418, detail="Nope! I don't like 3.") + return {"item_id": item_id} diff --git a/docs_src/handling_errors/tutorial005_py310.py b/docs_src/handling_errors/tutorial005_py310.py new file mode 100644 index 000000000..0e04fa086 --- /dev/null +++ b/docs_src/handling_errors/tutorial005_py310.py @@ -0,0 +1,25 @@ +from fastapi import FastAPI, Request +from fastapi.encoders import jsonable_encoder +from fastapi.exceptions import RequestValidationError +from fastapi.responses import JSONResponse +from pydantic import BaseModel + +app = FastAPI() + + +@app.exception_handler(RequestValidationError) +async def validation_exception_handler(request: Request, exc: RequestValidationError): + return JSONResponse( + status_code=422, + content=jsonable_encoder({"detail": exc.errors(), "body": exc.body}), + ) + + +class Item(BaseModel): + title: str + size: int + + +@app.post("/items/") +async def create_item(item: Item): + return item diff --git a/docs_src/handling_errors/tutorial006_py310.py b/docs_src/handling_errors/tutorial006_py310.py new file mode 100644 index 000000000..e05160d7e --- /dev/null +++ b/docs_src/handling_errors/tutorial006_py310.py @@ -0,0 +1,28 @@ +from fastapi import FastAPI, HTTPException +from fastapi.exception_handlers import ( + http_exception_handler, + request_validation_exception_handler, +) +from fastapi.exceptions import RequestValidationError +from starlette.exceptions import HTTPException as StarletteHTTPException + +app = FastAPI() + + +@app.exception_handler(StarletteHTTPException) +async def custom_http_exception_handler(request, exc): + print(f"OMG! An HTTP error!: {repr(exc)}") + return await http_exception_handler(request, exc) + + +@app.exception_handler(RequestValidationError) +async def validation_exception_handler(request, exc): + print(f"OMG! The client sent invalid data!: {exc}") + return await request_validation_exception_handler(request, exc) + + +@app.get("/items/{item_id}") +async def read_item(item_id: int): + if item_id == 3: + raise HTTPException(status_code=418, detail="Nope! I don't like 3.") + return {"item_id": item_id} diff --git a/docs_src/header_param_models/tutorial001_an_py39.py b/docs_src/header_param_models/tutorial001_an_py39.py deleted file mode 100644 index 51a5f94fc..000000000 --- a/docs_src/header_param_models/tutorial001_an_py39.py +++ /dev/null @@ -1,19 +0,0 @@ -from typing import Annotated, Union - -from fastapi import FastAPI, Header -from pydantic import BaseModel - -app = FastAPI() - - -class CommonHeaders(BaseModel): - host: str - save_data: bool - if_modified_since: Union[str, None] = None - traceparent: Union[str, None] = None - x_tag: list[str] = [] - - -@app.get("/items/") -async def read_items(headers: Annotated[CommonHeaders, Header()]): - return headers diff --git a/docs_src/header_param_models/tutorial001_py39.py b/docs_src/header_param_models/tutorial001_py39.py deleted file mode 100644 index 4c1137813..000000000 --- a/docs_src/header_param_models/tutorial001_py39.py +++ /dev/null @@ -1,19 +0,0 @@ -from typing import Union - -from fastapi import FastAPI, Header -from pydantic import BaseModel - -app = FastAPI() - - -class CommonHeaders(BaseModel): - host: str - save_data: bool - if_modified_since: Union[str, None] = None - traceparent: Union[str, None] = None - x_tag: list[str] = [] - - -@app.get("/items/") -async def read_items(headers: CommonHeaders = Header()): - return headers diff --git a/docs_src/header_param_models/tutorial002_an_py39.py b/docs_src/header_param_models/tutorial002_an_py39.py deleted file mode 100644 index ca5208c9d..000000000 --- a/docs_src/header_param_models/tutorial002_an_py39.py +++ /dev/null @@ -1,21 +0,0 @@ -from typing import Annotated, Union - -from fastapi import FastAPI, Header -from pydantic import BaseModel - -app = FastAPI() - - -class CommonHeaders(BaseModel): - model_config = {"extra": "forbid"} - - host: str - save_data: bool - if_modified_since: Union[str, None] = None - traceparent: Union[str, None] = None - x_tag: list[str] = [] - - -@app.get("/items/") -async def read_items(headers: Annotated[CommonHeaders, Header()]): - return headers diff --git a/docs_src/header_param_models/tutorial002_py39.py b/docs_src/header_param_models/tutorial002_py39.py deleted file mode 100644 index f8ce559a7..000000000 --- a/docs_src/header_param_models/tutorial002_py39.py +++ /dev/null @@ -1,21 +0,0 @@ -from typing import Union - -from fastapi import FastAPI, Header -from pydantic import BaseModel - -app = FastAPI() - - -class CommonHeaders(BaseModel): - model_config = {"extra": "forbid"} - - host: str - save_data: bool - if_modified_since: Union[str, None] = None - traceparent: Union[str, None] = None - x_tag: list[str] = [] - - -@app.get("/items/") -async def read_items(headers: CommonHeaders = Header()): - return headers diff --git a/docs_src/header_param_models/tutorial003_an_py39.py b/docs_src/header_param_models/tutorial003_an_py39.py deleted file mode 100644 index 8be6b01d0..000000000 --- a/docs_src/header_param_models/tutorial003_an_py39.py +++ /dev/null @@ -1,21 +0,0 @@ -from typing import Annotated, Union - -from fastapi import FastAPI, Header -from pydantic import BaseModel - -app = FastAPI() - - -class CommonHeaders(BaseModel): - host: str - save_data: bool - if_modified_since: Union[str, None] = None - traceparent: Union[str, None] = None - x_tag: list[str] = [] - - -@app.get("/items/") -async def read_items( - headers: Annotated[CommonHeaders, Header(convert_underscores=False)], -): - return headers diff --git a/docs_src/header_param_models/tutorial003_py39.py b/docs_src/header_param_models/tutorial003_py39.py deleted file mode 100644 index 848c34111..000000000 --- a/docs_src/header_param_models/tutorial003_py39.py +++ /dev/null @@ -1,19 +0,0 @@ -from typing import Union - -from fastapi import FastAPI, Header -from pydantic import BaseModel - -app = FastAPI() - - -class CommonHeaders(BaseModel): - host: str - save_data: bool - if_modified_since: Union[str, None] = None - traceparent: Union[str, None] = None - x_tag: list[str] = [] - - -@app.get("/items/") -async def read_items(headers: CommonHeaders = Header(convert_underscores=False)): - return headers diff --git a/docs_src/header_params/tutorial001_an_py39.py b/docs_src/header_params/tutorial001_an_py39.py deleted file mode 100644 index 1fbe3bb99..000000000 --- a/docs_src/header_params/tutorial001_an_py39.py +++ /dev/null @@ -1,10 +0,0 @@ -from typing import Annotated, Union - -from fastapi import FastAPI, Header - -app = FastAPI() - - -@app.get("/items/") -async def read_items(user_agent: Annotated[Union[str, None], Header()] = None): - return {"User-Agent": user_agent} diff --git a/docs_src/header_params/tutorial001_py39.py b/docs_src/header_params/tutorial001_py39.py deleted file mode 100644 index 74429c8e2..000000000 --- a/docs_src/header_params/tutorial001_py39.py +++ /dev/null @@ -1,10 +0,0 @@ -from typing import Union - -from fastapi import FastAPI, Header - -app = FastAPI() - - -@app.get("/items/") -async def read_items(user_agent: Union[str, None] = Header(default=None)): - return {"User-Agent": user_agent} diff --git a/docs_src/header_params/tutorial002_an_py39.py b/docs_src/header_params/tutorial002_an_py39.py deleted file mode 100644 index 008e4b6e1..000000000 --- a/docs_src/header_params/tutorial002_an_py39.py +++ /dev/null @@ -1,14 +0,0 @@ -from typing import Annotated, Union - -from fastapi import FastAPI, Header - -app = FastAPI() - - -@app.get("/items/") -async def read_items( - strange_header: Annotated[ - Union[str, None], Header(convert_underscores=False) - ] = None, -): - return {"strange_header": strange_header} diff --git a/docs_src/header_params/tutorial002_py39.py b/docs_src/header_params/tutorial002_py39.py deleted file mode 100644 index 0a34f17cc..000000000 --- a/docs_src/header_params/tutorial002_py39.py +++ /dev/null @@ -1,12 +0,0 @@ -from typing import Union - -from fastapi import FastAPI, Header - -app = FastAPI() - - -@app.get("/items/") -async def read_items( - strange_header: Union[str, None] = Header(default=None, convert_underscores=False), -): - return {"strange_header": strange_header} diff --git a/docs_src/header_params/tutorial003_an_py39.py b/docs_src/header_params/tutorial003_an_py39.py deleted file mode 100644 index 5aad89407..000000000 --- a/docs_src/header_params/tutorial003_an_py39.py +++ /dev/null @@ -1,10 +0,0 @@ -from typing import Annotated, Union - -from fastapi import FastAPI, Header - -app = FastAPI() - - -@app.get("/items/") -async def read_items(x_token: Annotated[Union[list[str], None], Header()] = None): - return {"X-Token values": x_token} diff --git a/docs_src/header_params/tutorial003_py39.py b/docs_src/header_params/tutorial003_py39.py deleted file mode 100644 index 34437db16..000000000 --- a/docs_src/header_params/tutorial003_py39.py +++ /dev/null @@ -1,10 +0,0 @@ -from typing import Union - -from fastapi import FastAPI, Header - -app = FastAPI() - - -@app.get("/items/") -async def read_items(x_token: Union[list[str], None] = Header(default=None)): - return {"X-Token values": x_token} diff --git a/docs_src/metadata/tutorial001_1_py310.py b/docs_src/metadata/tutorial001_1_py310.py new file mode 100644 index 000000000..419232d86 --- /dev/null +++ b/docs_src/metadata/tutorial001_1_py310.py @@ -0,0 +1,38 @@ +from fastapi import FastAPI + +description = """ +ChimichangApp API helps you do awesome stuff. 🚀 + +## Items + +You can **read items**. + +## Users + +You will be able to: + +* **Create users** (_not implemented_). +* **Read users** (_not implemented_). +""" + +app = FastAPI( + title="ChimichangApp", + description=description, + summary="Deadpool's favorite app. Nuff said.", + version="0.0.1", + terms_of_service="http://example.com/terms/", + contact={ + "name": "Deadpoolio the Amazing", + "url": "http://x-force.example.com/contact/", + "email": "dp@x-force.example.com", + }, + license_info={ + "name": "Apache 2.0", + "identifier": "Apache-2.0", + }, +) + + +@app.get("/items/") +async def read_items(): + return [{"name": "Katana"}] diff --git a/docs_src/metadata/tutorial001_py310.py b/docs_src/metadata/tutorial001_py310.py new file mode 100644 index 000000000..76656e81b --- /dev/null +++ b/docs_src/metadata/tutorial001_py310.py @@ -0,0 +1,38 @@ +from fastapi import FastAPI + +description = """ +ChimichangApp API helps you do awesome stuff. 🚀 + +## Items + +You can **read items**. + +## Users + +You will be able to: + +* **Create users** (_not implemented_). +* **Read users** (_not implemented_). +""" + +app = FastAPI( + title="ChimichangApp", + description=description, + summary="Deadpool's favorite app. Nuff said.", + version="0.0.1", + terms_of_service="http://example.com/terms/", + contact={ + "name": "Deadpoolio the Amazing", + "url": "http://x-force.example.com/contact/", + "email": "dp@x-force.example.com", + }, + license_info={ + "name": "Apache 2.0", + "url": "https://www.apache.org/licenses/LICENSE-2.0.html", + }, +) + + +@app.get("/items/") +async def read_items(): + return [{"name": "Katana"}] diff --git a/docs_src/metadata/tutorial002_py310.py b/docs_src/metadata/tutorial002_py310.py new file mode 100644 index 000000000..cf9ed7087 --- /dev/null +++ b/docs_src/metadata/tutorial002_py310.py @@ -0,0 +1,8 @@ +from fastapi import FastAPI + +app = FastAPI(openapi_url="/api/v1/openapi.json") + + +@app.get("/items/") +async def read_items(): + return [{"name": "Foo"}] diff --git a/docs_src/metadata/tutorial003_py310.py b/docs_src/metadata/tutorial003_py310.py new file mode 100644 index 000000000..ee09c7f37 --- /dev/null +++ b/docs_src/metadata/tutorial003_py310.py @@ -0,0 +1,8 @@ +from fastapi import FastAPI + +app = FastAPI(docs_url="/documentation", redoc_url=None) + + +@app.get("/items/") +async def read_items(): + return [{"name": "Foo"}] diff --git a/docs_src/metadata/tutorial004_py310.py b/docs_src/metadata/tutorial004_py310.py new file mode 100644 index 000000000..465bd659d --- /dev/null +++ b/docs_src/metadata/tutorial004_py310.py @@ -0,0 +1,28 @@ +from fastapi import FastAPI + +tags_metadata = [ + { + "name": "users", + "description": "Operations with users. The **login** logic is also here.", + }, + { + "name": "items", + "description": "Manage items. So _fancy_ they have their own docs.", + "externalDocs": { + "description": "Items external docs", + "url": "https://fastapi.tiangolo.com/", + }, + }, +] + +app = FastAPI(openapi_tags=tags_metadata) + + +@app.get("/users/", tags=["users"]) +async def get_users(): + return [{"name": "Harry"}, {"name": "Ron"}] + + +@app.get("/items/", tags=["items"]) +async def get_items(): + return [{"name": "wand"}, {"name": "flying broom"}] diff --git a/docs_src/middleware/tutorial001_py310.py b/docs_src/middleware/tutorial001_py310.py new file mode 100644 index 000000000..e65a7dade --- /dev/null +++ b/docs_src/middleware/tutorial001_py310.py @@ -0,0 +1,14 @@ +import time + +from fastapi import FastAPI, Request + +app = FastAPI() + + +@app.middleware("http") +async def add_process_time_header(request: Request, call_next): + start_time = time.perf_counter() + response = await call_next(request) + process_time = time.perf_counter() - start_time + response.headers["X-Process-Time"] = str(process_time) + return response diff --git a/docs_src/openapi_callbacks/tutorial001_py39.py b/docs_src/openapi_callbacks/tutorial001_py39.py deleted file mode 100644 index 3f1bac6e2..000000000 --- a/docs_src/openapi_callbacks/tutorial001_py39.py +++ /dev/null @@ -1,53 +0,0 @@ -from typing import Union - -from fastapi import APIRouter, FastAPI -from pydantic import BaseModel, HttpUrl - -app = FastAPI() - - -class Invoice(BaseModel): - id: str - title: Union[str, None] = None - customer: str - total: float - - -class InvoiceEvent(BaseModel): - description: str - paid: bool - - -class InvoiceEventReceived(BaseModel): - ok: bool - - -invoices_callback_router = APIRouter() - - -@invoices_callback_router.post( - "{$callback_url}/invoices/{$request.body.id}", response_model=InvoiceEventReceived -) -def invoice_notification(body: InvoiceEvent): - pass - - -@app.post("/invoices/", callbacks=invoices_callback_router.routes) -def create_invoice(invoice: Invoice, callback_url: Union[HttpUrl, None] = None): - """ - Create an invoice. - - This will (let's imagine) let the API user (some external developer) create an - invoice. - - And this path operation will: - - * Send the invoice to the client. - * Collect the money from the client. - * Send a notification back to the API user (the external developer), as a callback. - * At this point is that the API will somehow send a POST request to the - external API with the notification of the invoice event - (e.g. "payment successful"). - """ - # Send the invoice, collect the money, send the notification (the callback) - return {"msg": "Invoice received"} diff --git a/docs_src/openapi_webhooks/tutorial001_py310.py b/docs_src/openapi_webhooks/tutorial001_py310.py new file mode 100644 index 000000000..55822bb48 --- /dev/null +++ b/docs_src/openapi_webhooks/tutorial001_py310.py @@ -0,0 +1,25 @@ +from datetime import datetime + +from fastapi import FastAPI +from pydantic import BaseModel + +app = FastAPI() + + +class Subscription(BaseModel): + username: str + monthly_fee: float + start_date: datetime + + +@app.webhooks.post("new-subscription") +def new_subscription(body: Subscription): + """ + When a new user subscribes to your service we'll send you a POST request with this + data to the URL that you register for the event `new-subscription` in the dashboard. + """ + + +@app.get("/users/") +def read_users(): + return ["Rick", "Morty"] diff --git a/docs_src/path_operation_advanced_configuration/tutorial001_py310.py b/docs_src/path_operation_advanced_configuration/tutorial001_py310.py new file mode 100644 index 000000000..fafa8ffb8 --- /dev/null +++ b/docs_src/path_operation_advanced_configuration/tutorial001_py310.py @@ -0,0 +1,8 @@ +from fastapi import FastAPI + +app = FastAPI() + + +@app.get("/items/", operation_id="some_specific_id_you_define") +async def read_items(): + return [{"item_id": "Foo"}] diff --git a/docs_src/path_operation_advanced_configuration/tutorial002_py310.py b/docs_src/path_operation_advanced_configuration/tutorial002_py310.py new file mode 100644 index 000000000..3aaae9b37 --- /dev/null +++ b/docs_src/path_operation_advanced_configuration/tutorial002_py310.py @@ -0,0 +1,24 @@ +from fastapi import FastAPI +from fastapi.routing import APIRoute + +app = FastAPI() + + +@app.get("/items/") +async def read_items(): + return [{"item_id": "Foo"}] + + +def use_route_names_as_operation_ids(app: FastAPI) -> None: + """ + Simplify operation IDs so that generated API clients have simpler function + names. + + Should be called only after all routes have been added. + """ + for route in app.routes: + if isinstance(route, APIRoute): + route.operation_id = route.name # in this case, 'read_items' + + +use_route_names_as_operation_ids(app) diff --git a/docs_src/path_operation_advanced_configuration/tutorial003_py310.py b/docs_src/path_operation_advanced_configuration/tutorial003_py310.py new file mode 100644 index 000000000..dcc358e32 --- /dev/null +++ b/docs_src/path_operation_advanced_configuration/tutorial003_py310.py @@ -0,0 +1,8 @@ +from fastapi import FastAPI + +app = FastAPI() + + +@app.get("/items/", include_in_schema=False) +async def read_items(): + return [{"item_id": "Foo"}] diff --git a/docs_src/path_operation_advanced_configuration/tutorial004_py39.py b/docs_src/path_operation_advanced_configuration/tutorial004_py39.py deleted file mode 100644 index 8fabe7cb8..000000000 --- a/docs_src/path_operation_advanced_configuration/tutorial004_py39.py +++ /dev/null @@ -1,30 +0,0 @@ -from typing import Union - -from fastapi import FastAPI -from pydantic import BaseModel - -app = FastAPI() - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: Union[float, None] = None - tags: set[str] = set() - - -@app.post("/items/", summary="Create an item") -async def create_item(item: Item) -> Item: - """ - Create an item with all the information: - - - **name**: each item must have a name - - **description**: a long description - - **price**: required - - **tax**: if the item doesn't have tax, you can omit this - - **tags**: a set of unique tag strings for this item - \f - :param item: User input. - """ - return item diff --git a/docs_src/path_operation_advanced_configuration/tutorial005_py310.py b/docs_src/path_operation_advanced_configuration/tutorial005_py310.py new file mode 100644 index 000000000..5837ad835 --- /dev/null +++ b/docs_src/path_operation_advanced_configuration/tutorial005_py310.py @@ -0,0 +1,8 @@ +from fastapi import FastAPI + +app = FastAPI() + + +@app.get("/items/", openapi_extra={"x-aperture-labs-portal": "blue"}) +async def read_items(): + return [{"item_id": "portal-gun"}] diff --git a/docs_src/path_operation_advanced_configuration/tutorial006_py310.py b/docs_src/path_operation_advanced_configuration/tutorial006_py310.py new file mode 100644 index 000000000..403c3ee3f --- /dev/null +++ b/docs_src/path_operation_advanced_configuration/tutorial006_py310.py @@ -0,0 +1,41 @@ +from fastapi import FastAPI, Request + +app = FastAPI() + + +def magic_data_reader(raw_body: bytes): + return { + "size": len(raw_body), + "content": { + "name": "Maaaagic", + "price": 42, + "description": "Just kiddin', no magic here. ✨", + }, + } + + +@app.post( + "/items/", + openapi_extra={ + "requestBody": { + "content": { + "application/json": { + "schema": { + "required": ["name", "price"], + "type": "object", + "properties": { + "name": {"type": "string"}, + "price": {"type": "number"}, + "description": {"type": "string"}, + }, + } + } + }, + "required": True, + }, + }, +) +async def create_item(request: Request): + raw_body = await request.body() + data = magic_data_reader(raw_body) + return data diff --git a/docs_src/path_operation_advanced_configuration/tutorial007_pv1_py39.py b/docs_src/path_operation_advanced_configuration/tutorial007_py310.py similarity index 68% rename from docs_src/path_operation_advanced_configuration/tutorial007_pv1_py39.py rename to docs_src/path_operation_advanced_configuration/tutorial007_py310.py index 849f648e1..ff64ef792 100644 --- a/docs_src/path_operation_advanced_configuration/tutorial007_pv1_py39.py +++ b/docs_src/path_operation_advanced_configuration/tutorial007_py310.py @@ -1,6 +1,6 @@ import yaml from fastapi import FastAPI, HTTPException, Request -from pydantic.v1 import BaseModel, ValidationError +from pydantic import BaseModel, ValidationError app = FastAPI() @@ -14,7 +14,7 @@ class Item(BaseModel): "/items/", openapi_extra={ "requestBody": { - "content": {"application/x-yaml": {"schema": Item.schema()}}, + "content": {"application/x-yaml": {"schema": Item.model_json_schema()}}, "required": True, }, }, @@ -26,7 +26,7 @@ async def create_item(request: Request): except yaml.YAMLError: raise HTTPException(status_code=422, detail="Invalid YAML") try: - item = Item.parse_obj(data) + item = Item.model_validate(data) except ValidationError as e: - raise HTTPException(status_code=422, detail=e.errors()) + raise HTTPException(status_code=422, detail=e.errors(include_url=False)) return item diff --git a/docs_src/path_operation_configuration/tutorial001_py39.py b/docs_src/path_operation_configuration/tutorial001_py39.py deleted file mode 100644 index 09b318282..000000000 --- a/docs_src/path_operation_configuration/tutorial001_py39.py +++ /dev/null @@ -1,19 +0,0 @@ -from typing import Union - -from fastapi import FastAPI, status -from pydantic import BaseModel - -app = FastAPI() - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: Union[float, None] = None - tags: set[str] = set() - - -@app.post("/items/", status_code=status.HTTP_201_CREATED) -async def create_item(item: Item) -> Item: - return item diff --git a/docs_src/path_operation_configuration/tutorial002_py39.py b/docs_src/path_operation_configuration/tutorial002_py39.py deleted file mode 100644 index fca3b0de9..000000000 --- a/docs_src/path_operation_configuration/tutorial002_py39.py +++ /dev/null @@ -1,29 +0,0 @@ -from typing import Union - -from fastapi import FastAPI -from pydantic import BaseModel - -app = FastAPI() - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: Union[float, None] = None - tags: set[str] = set() - - -@app.post("/items/", tags=["items"]) -async def create_item(item: Item) -> Item: - return item - - -@app.get("/items/", tags=["items"]) -async def read_items(): - return [{"name": "Foo", "price": 42}] - - -@app.get("/users/", tags=["users"]) -async def read_users(): - return [{"username": "johndoe"}] diff --git a/docs_src/path_operation_configuration/tutorial002b_py310.py b/docs_src/path_operation_configuration/tutorial002b_py310.py new file mode 100644 index 000000000..d53b4d817 --- /dev/null +++ b/docs_src/path_operation_configuration/tutorial002b_py310.py @@ -0,0 +1,20 @@ +from enum import Enum + +from fastapi import FastAPI + +app = FastAPI() + + +class Tags(Enum): + items = "items" + users = "users" + + +@app.get("/items/", tags=[Tags.items]) +async def get_items(): + return ["Portal gun", "Plumbus"] + + +@app.get("/users/", tags=[Tags.users]) +async def read_users(): + return ["Rick", "Morty"] diff --git a/docs_src/path_operation_configuration/tutorial003_py39.py b/docs_src/path_operation_configuration/tutorial003_py39.py deleted file mode 100644 index a77fb34d8..000000000 --- a/docs_src/path_operation_configuration/tutorial003_py39.py +++ /dev/null @@ -1,23 +0,0 @@ -from typing import Union - -from fastapi import FastAPI -from pydantic import BaseModel - -app = FastAPI() - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: Union[float, None] = None - tags: set[str] = set() - - -@app.post( - "/items/", - summary="Create an item", - description="Create an item with all the information, name, description, price, tax and a set of unique tags", -) -async def create_item(item: Item) -> Item: - return item diff --git a/docs_src/path_operation_configuration/tutorial004_py39.py b/docs_src/path_operation_configuration/tutorial004_py39.py deleted file mode 100644 index 31dfbff1d..000000000 --- a/docs_src/path_operation_configuration/tutorial004_py39.py +++ /dev/null @@ -1,28 +0,0 @@ -from typing import Union - -from fastapi import FastAPI -from pydantic import BaseModel - -app = FastAPI() - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: Union[float, None] = None - tags: set[str] = set() - - -@app.post("/items/", summary="Create an item") -async def create_item(item: Item) -> Item: - """ - Create an item with all the information: - - - **name**: each item must have a name - - **description**: a long description - - **price**: required - - **tax**: if the item doesn't have tax, you can omit this - - **tags**: a set of unique tag strings for this item - """ - return item diff --git a/docs_src/path_operation_configuration/tutorial005_py39.py b/docs_src/path_operation_configuration/tutorial005_py39.py deleted file mode 100644 index 0a53a8f2d..000000000 --- a/docs_src/path_operation_configuration/tutorial005_py39.py +++ /dev/null @@ -1,32 +0,0 @@ -from typing import Union - -from fastapi import FastAPI -from pydantic import BaseModel - -app = FastAPI() - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: Union[float, None] = None - tags: set[str] = set() - - -@app.post( - "/items/", - summary="Create an item", - response_description="The created item", -) -async def create_item(item: Item) -> Item: - """ - Create an item with all the information: - - - **name**: each item must have a name - - **description**: a long description - - **price**: required - - **tax**: if the item doesn't have tax, you can omit this - - **tags**: a set of unique tag strings for this item - """ - return item diff --git a/docs_src/path_operation_configuration/tutorial006_py310.py b/docs_src/path_operation_configuration/tutorial006_py310.py new file mode 100644 index 000000000..7c1aa9b20 --- /dev/null +++ b/docs_src/path_operation_configuration/tutorial006_py310.py @@ -0,0 +1,18 @@ +from fastapi import FastAPI + +app = FastAPI() + + +@app.get("/items/", tags=["items"]) +async def read_items(): + return [{"name": "Foo", "price": 42}] + + +@app.get("/users/", tags=["users"]) +async def read_users(): + return [{"username": "johndoe"}] + + +@app.get("/elements/", tags=["items"], deprecated=True) +async def read_elements(): + return [{"item_id": "Foo"}] diff --git a/docs_src/path_params/tutorial001_py310.py b/docs_src/path_params/tutorial001_py310.py new file mode 100644 index 000000000..7bbf70e6c --- /dev/null +++ b/docs_src/path_params/tutorial001_py310.py @@ -0,0 +1,8 @@ +from fastapi import FastAPI + +app = FastAPI() + + +@app.get("/items/{item_id}") +async def read_item(item_id): + return {"item_id": item_id} diff --git a/docs_src/path_params/tutorial002_py310.py b/docs_src/path_params/tutorial002_py310.py new file mode 100644 index 000000000..8272ad70d --- /dev/null +++ b/docs_src/path_params/tutorial002_py310.py @@ -0,0 +1,8 @@ +from fastapi import FastAPI + +app = FastAPI() + + +@app.get("/items/{item_id}") +async def read_item(item_id: int): + return {"item_id": item_id} diff --git a/docs_src/path_params/tutorial003_py310.py b/docs_src/path_params/tutorial003_py310.py new file mode 100644 index 000000000..5f0aa0923 --- /dev/null +++ b/docs_src/path_params/tutorial003_py310.py @@ -0,0 +1,13 @@ +from fastapi import FastAPI + +app = FastAPI() + + +@app.get("/users/me") +async def read_user_me(): + return {"user_id": "the current user"} + + +@app.get("/users/{user_id}") +async def read_user(user_id: str): + return {"user_id": user_id} diff --git a/docs_src/path_params/tutorial003b_py310.py b/docs_src/path_params/tutorial003b_py310.py new file mode 100644 index 000000000..822d37369 --- /dev/null +++ b/docs_src/path_params/tutorial003b_py310.py @@ -0,0 +1,13 @@ +from fastapi import FastAPI + +app = FastAPI() + + +@app.get("/users") +async def read_users(): + return ["Rick", "Morty"] + + +@app.get("/users") +async def read_users2(): + return ["Bean", "Elfo"] diff --git a/docs_src/path_params/tutorial004_py310.py b/docs_src/path_params/tutorial004_py310.py new file mode 100644 index 000000000..2961e6178 --- /dev/null +++ b/docs_src/path_params/tutorial004_py310.py @@ -0,0 +1,8 @@ +from fastapi import FastAPI + +app = FastAPI() + + +@app.get("/files/{file_path:path}") +async def read_file(file_path: str): + return {"file_path": file_path} diff --git a/docs_src/path_params/tutorial005_py310.py b/docs_src/path_params/tutorial005_py310.py new file mode 100644 index 000000000..9a24a4963 --- /dev/null +++ b/docs_src/path_params/tutorial005_py310.py @@ -0,0 +1,23 @@ +from enum import Enum + +from fastapi import FastAPI + + +class ModelName(str, Enum): + alexnet = "alexnet" + resnet = "resnet" + lenet = "lenet" + + +app = FastAPI() + + +@app.get("/models/{model_name}") +async def get_model(model_name: ModelName): + if model_name is ModelName.alexnet: + return {"model_name": model_name, "message": "Deep Learning FTW!"} + + if model_name.value == "lenet": + return {"model_name": model_name, "message": "LeCNN all the images"} + + return {"model_name": model_name, "message": "Have some residuals"} diff --git a/docs_src/path_params_numeric_validations/tutorial002_an_py310.py b/docs_src/path_params_numeric_validations/tutorial002_an_py310.py new file mode 100644 index 000000000..cd882abb2 --- /dev/null +++ b/docs_src/path_params_numeric_validations/tutorial002_an_py310.py @@ -0,0 +1,15 @@ +from typing import Annotated + +from fastapi import FastAPI, Path + +app = FastAPI() + + +@app.get("/items/{item_id}") +async def read_items( + q: str, item_id: Annotated[int, Path(title="The ID of the item to get")] +): + results = {"item_id": item_id} + if q: + results.update({"q": q}) + return results diff --git a/docs_src/path_params_numeric_validations/tutorial002_py310.py b/docs_src/path_params_numeric_validations/tutorial002_py310.py new file mode 100644 index 000000000..63ac691a8 --- /dev/null +++ b/docs_src/path_params_numeric_validations/tutorial002_py310.py @@ -0,0 +1,11 @@ +from fastapi import FastAPI, Path + +app = FastAPI() + + +@app.get("/items/{item_id}") +async def read_items(q: str, item_id: int = Path(title="The ID of the item to get")): + results = {"item_id": item_id} + if q: + results.update({"q": q}) + return results diff --git a/docs_src/path_params_numeric_validations/tutorial003_an_py310.py b/docs_src/path_params_numeric_validations/tutorial003_an_py310.py new file mode 100644 index 000000000..1588556e7 --- /dev/null +++ b/docs_src/path_params_numeric_validations/tutorial003_an_py310.py @@ -0,0 +1,15 @@ +from typing import Annotated + +from fastapi import FastAPI, Path + +app = FastAPI() + + +@app.get("/items/{item_id}") +async def read_items( + item_id: Annotated[int, Path(title="The ID of the item to get")], q: str +): + results = {"item_id": item_id} + if q: + results.update({"q": q}) + return results diff --git a/docs_src/path_params_numeric_validations/tutorial003_py310.py b/docs_src/path_params_numeric_validations/tutorial003_py310.py new file mode 100644 index 000000000..8df0ffc62 --- /dev/null +++ b/docs_src/path_params_numeric_validations/tutorial003_py310.py @@ -0,0 +1,11 @@ +from fastapi import FastAPI, Path + +app = FastAPI() + + +@app.get("/items/{item_id}") +async def read_items(*, item_id: int = Path(title="The ID of the item to get"), q: str): + results = {"item_id": item_id} + if q: + results.update({"q": q}) + return results diff --git a/docs_src/path_params_numeric_validations/tutorial004_an_py310.py b/docs_src/path_params_numeric_validations/tutorial004_an_py310.py new file mode 100644 index 000000000..f67f6450e --- /dev/null +++ b/docs_src/path_params_numeric_validations/tutorial004_an_py310.py @@ -0,0 +1,15 @@ +from typing import Annotated + +from fastapi import FastAPI, Path + +app = FastAPI() + + +@app.get("/items/{item_id}") +async def read_items( + item_id: Annotated[int, Path(title="The ID of the item to get", ge=1)], q: str +): + results = {"item_id": item_id} + if q: + results.update({"q": q}) + return results diff --git a/docs_src/path_params_numeric_validations/tutorial004_py310.py b/docs_src/path_params_numeric_validations/tutorial004_py310.py new file mode 100644 index 000000000..86651d47c --- /dev/null +++ b/docs_src/path_params_numeric_validations/tutorial004_py310.py @@ -0,0 +1,13 @@ +from fastapi import FastAPI, Path + +app = FastAPI() + + +@app.get("/items/{item_id}") +async def read_items( + *, item_id: int = Path(title="The ID of the item to get", ge=1), q: str +): + results = {"item_id": item_id} + if q: + results.update({"q": q}) + return results diff --git a/docs_src/path_params_numeric_validations/tutorial005_an_py310.py b/docs_src/path_params_numeric_validations/tutorial005_an_py310.py new file mode 100644 index 000000000..571dd583c --- /dev/null +++ b/docs_src/path_params_numeric_validations/tutorial005_an_py310.py @@ -0,0 +1,16 @@ +from typing import Annotated + +from fastapi import FastAPI, Path + +app = FastAPI() + + +@app.get("/items/{item_id}") +async def read_items( + item_id: Annotated[int, Path(title="The ID of the item to get", gt=0, le=1000)], + q: str, +): + results = {"item_id": item_id} + if q: + results.update({"q": q}) + return results diff --git a/docs_src/path_params_numeric_validations/tutorial005_py310.py b/docs_src/path_params_numeric_validations/tutorial005_py310.py new file mode 100644 index 000000000..8f12f2da0 --- /dev/null +++ b/docs_src/path_params_numeric_validations/tutorial005_py310.py @@ -0,0 +1,15 @@ +from fastapi import FastAPI, Path + +app = FastAPI() + + +@app.get("/items/{item_id}") +async def read_items( + *, + item_id: int = Path(title="The ID of the item to get", gt=0, le=1000), + q: str, +): + results = {"item_id": item_id} + if q: + results.update({"q": q}) + return results diff --git a/docs_src/path_params_numeric_validations/tutorial001_an_py39.py b/docs_src/path_params_numeric_validations/tutorial006_an_py310.py similarity index 61% rename from docs_src/path_params_numeric_validations/tutorial001_an_py39.py rename to docs_src/path_params_numeric_validations/tutorial006_an_py310.py index b36315a46..426ec3776 100644 --- a/docs_src/path_params_numeric_validations/tutorial001_an_py39.py +++ b/docs_src/path_params_numeric_validations/tutorial006_an_py310.py @@ -1,4 +1,4 @@ -from typing import Annotated, Union +from typing import Annotated from fastapi import FastAPI, Path, Query @@ -7,10 +7,14 @@ app = FastAPI() @app.get("/items/{item_id}") async def read_items( - item_id: Annotated[int, Path(title="The ID of the item to get")], - q: Annotated[Union[str, None], Query(alias="item-query")] = None, + *, + item_id: Annotated[int, Path(title="The ID of the item to get", ge=0, le=1000)], + q: str, + size: Annotated[float, Query(gt=0, lt=10.5)], ): results = {"item_id": item_id} if q: results.update({"q": q}) + if size: + results.update({"size": size}) return results diff --git a/docs_src/path_params_numeric_validations/tutorial001_py39.py b/docs_src/path_params_numeric_validations/tutorial006_py310.py similarity index 53% rename from docs_src/path_params_numeric_validations/tutorial001_py39.py rename to docs_src/path_params_numeric_validations/tutorial006_py310.py index 530147028..f07629aa0 100644 --- a/docs_src/path_params_numeric_validations/tutorial001_py39.py +++ b/docs_src/path_params_numeric_validations/tutorial006_py310.py @@ -1,5 +1,3 @@ -from typing import Union - from fastapi import FastAPI, Path, Query app = FastAPI() @@ -7,10 +5,14 @@ app = FastAPI() @app.get("/items/{item_id}") async def read_items( - item_id: int = Path(title="The ID of the item to get"), - q: Union[str, None] = Query(default=None, alias="item-query"), + *, + item_id: int = Path(title="The ID of the item to get", ge=0, le=1000), + q: str, + size: float = Query(gt=0, lt=10.5), ): results = {"item_id": item_id} if q: results.update({"q": q}) + if size: + results.update({"size": size}) return results diff --git a/docs_src/pydantic_v1_in_v2/tutorial001_an_py39.py b/docs_src/pydantic_v1_in_v2/tutorial001_an_py39.py deleted file mode 100644 index 62a4b2c21..000000000 --- a/docs_src/pydantic_v1_in_v2/tutorial001_an_py39.py +++ /dev/null @@ -1,9 +0,0 @@ -from typing import Union - -from pydantic.v1 import BaseModel - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - size: float diff --git a/docs_src/pydantic_v1_in_v2/tutorial002_an_py39.py b/docs_src/pydantic_v1_in_v2/tutorial002_an_py39.py deleted file mode 100644 index 3c6a06080..000000000 --- a/docs_src/pydantic_v1_in_v2/tutorial002_an_py39.py +++ /dev/null @@ -1,18 +0,0 @@ -from typing import Union - -from fastapi import FastAPI -from pydantic.v1 import BaseModel - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - size: float - - -app = FastAPI() - - -@app.post("/items/") -async def create_item(item: Item) -> Item: - return item diff --git a/docs_src/pydantic_v1_in_v2/tutorial003_an_py39.py b/docs_src/pydantic_v1_in_v2/tutorial003_an_py39.py deleted file mode 100644 index 117d6f7a4..000000000 --- a/docs_src/pydantic_v1_in_v2/tutorial003_an_py39.py +++ /dev/null @@ -1,25 +0,0 @@ -from typing import Union - -from fastapi import FastAPI -from pydantic import BaseModel as BaseModelV2 -from pydantic.v1 import BaseModel - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - size: float - - -class ItemV2(BaseModelV2): - name: str - description: Union[str, None] = None - size: float - - -app = FastAPI() - - -@app.post("/items/", response_model=ItemV2) -async def create_item(item: Item): - return item diff --git a/docs_src/pydantic_v1_in_v2/tutorial004_an_py39.py b/docs_src/pydantic_v1_in_v2/tutorial004_an_py39.py deleted file mode 100644 index 150ab20ae..000000000 --- a/docs_src/pydantic_v1_in_v2/tutorial004_an_py39.py +++ /dev/null @@ -1,19 +0,0 @@ -from typing import Annotated, Union - -from fastapi import FastAPI -from fastapi.temp_pydantic_v1_params import Body -from pydantic.v1 import BaseModel - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - size: float - - -app = FastAPI() - - -@app.post("/items/") -async def create_item(item: Annotated[Item, Body(embed=True)]) -> Item: - return item diff --git a/docs_src/python_types/tutorial001_py310.py b/docs_src/python_types/tutorial001_py310.py new file mode 100644 index 000000000..09039435f --- /dev/null +++ b/docs_src/python_types/tutorial001_py310.py @@ -0,0 +1,6 @@ +def get_full_name(first_name, last_name): + full_name = first_name.title() + " " + last_name.title() + return full_name + + +print(get_full_name("john", "doe")) diff --git a/docs_src/python_types/tutorial002_py310.py b/docs_src/python_types/tutorial002_py310.py new file mode 100644 index 000000000..c0857a116 --- /dev/null +++ b/docs_src/python_types/tutorial002_py310.py @@ -0,0 +1,6 @@ +def get_full_name(first_name: str, last_name: str): + full_name = first_name.title() + " " + last_name.title() + return full_name + + +print(get_full_name("john", "doe")) diff --git a/docs_src/python_types/tutorial003_py310.py b/docs_src/python_types/tutorial003_py310.py new file mode 100644 index 000000000..d021d8211 --- /dev/null +++ b/docs_src/python_types/tutorial003_py310.py @@ -0,0 +1,3 @@ +def get_name_with_age(name: str, age: int): + name_with_age = name + " is this old: " + age + return name_with_age diff --git a/docs_src/python_types/tutorial004_py310.py b/docs_src/python_types/tutorial004_py310.py new file mode 100644 index 000000000..9400269e2 --- /dev/null +++ b/docs_src/python_types/tutorial004_py310.py @@ -0,0 +1,3 @@ +def get_name_with_age(name: str, age: int): + name_with_age = name + " is this old: " + str(age) + return name_with_age diff --git a/docs_src/python_types/tutorial005_py310.py b/docs_src/python_types/tutorial005_py310.py new file mode 100644 index 000000000..6c8edb0ec --- /dev/null +++ b/docs_src/python_types/tutorial005_py310.py @@ -0,0 +1,2 @@ +def get_items(item_a: str, item_b: int, item_c: float, item_d: bool, item_e: bytes): + return item_a, item_b, item_c, item_d, item_e diff --git a/docs_src/python_types/tutorial006_py310.py b/docs_src/python_types/tutorial006_py310.py new file mode 100644 index 000000000..486b67caf --- /dev/null +++ b/docs_src/python_types/tutorial006_py310.py @@ -0,0 +1,3 @@ +def process_items(items: list[str]): + for item in items: + print(item) diff --git a/docs_src/python_types/tutorial007_py310.py b/docs_src/python_types/tutorial007_py310.py new file mode 100644 index 000000000..ea96c7964 --- /dev/null +++ b/docs_src/python_types/tutorial007_py310.py @@ -0,0 +1,2 @@ +def process_items(items_t: tuple[int, int, str], items_s: set[bytes]): + return items_t, items_s diff --git a/docs_src/python_types/tutorial008_py310.py b/docs_src/python_types/tutorial008_py310.py new file mode 100644 index 000000000..a393385b0 --- /dev/null +++ b/docs_src/python_types/tutorial008_py310.py @@ -0,0 +1,4 @@ +def process_items(prices: dict[str, float]): + for item_name, item_price in prices.items(): + print(item_name) + print(item_price) diff --git a/docs_src/python_types/tutorial010_py310.py b/docs_src/python_types/tutorial010_py310.py new file mode 100644 index 000000000..468cffc2d --- /dev/null +++ b/docs_src/python_types/tutorial010_py310.py @@ -0,0 +1,7 @@ +class Person: + def __init__(self, name: str): + self.name = name + + +def get_person_name(one_person: Person): + return one_person.name diff --git a/docs_src/python_types/tutorial011_py39.py b/docs_src/python_types/tutorial011_py39.py deleted file mode 100644 index 4eb40b405..000000000 --- a/docs_src/python_types/tutorial011_py39.py +++ /dev/null @@ -1,23 +0,0 @@ -from datetime import datetime -from typing import Union - -from pydantic import BaseModel - - -class User(BaseModel): - id: int - name: str = "John Doe" - signup_ts: Union[datetime, None] = None - friends: list[int] = [] - - -external_data = { - "id": "123", - "signup_ts": "2017-06-01 12:22", - "friends": [1, "2", b"3"], -} -user = User(**external_data) -print(user) -# > User id=123 name='John Doe' signup_ts=datetime.datetime(2017, 6, 1, 12, 22) friends=[1, 2, 3] -print(user.id) -# > 123 diff --git a/docs_src/python_types/tutorial012_py39.py b/docs_src/python_types/tutorial012_py39.py deleted file mode 100644 index 74fa94c43..000000000 --- a/docs_src/python_types/tutorial012_py39.py +++ /dev/null @@ -1,8 +0,0 @@ -from typing import Optional - -from pydantic import BaseModel - - -class User(BaseModel): - name: str - age: Optional[int] diff --git a/docs_src/python_types/tutorial013_py310.py b/docs_src/python_types/tutorial013_py310.py new file mode 100644 index 000000000..65a0eaa93 --- /dev/null +++ b/docs_src/python_types/tutorial013_py310.py @@ -0,0 +1,5 @@ +from typing import Annotated + + +def say_hello(name: Annotated[str, "this is just metadata"]) -> str: + return f"Hello {name}" diff --git a/docs_src/query_param_models/tutorial001_an_py39.py b/docs_src/query_param_models/tutorial001_an_py39.py deleted file mode 100644 index 71427acae..000000000 --- a/docs_src/query_param_models/tutorial001_an_py39.py +++ /dev/null @@ -1,18 +0,0 @@ -from typing import Annotated, Literal - -from fastapi import FastAPI, Query -from pydantic import BaseModel, Field - -app = FastAPI() - - -class FilterParams(BaseModel): - limit: int = Field(100, gt=0, le=100) - offset: int = Field(0, ge=0) - order_by: Literal["created_at", "updated_at"] = "created_at" - tags: list[str] = [] - - -@app.get("/items/") -async def read_items(filter_query: Annotated[FilterParams, Query()]): - return filter_query diff --git a/docs_src/query_param_models/tutorial001_py39.py b/docs_src/query_param_models/tutorial001_py39.py deleted file mode 100644 index 3ebf9f4d7..000000000 --- a/docs_src/query_param_models/tutorial001_py39.py +++ /dev/null @@ -1,18 +0,0 @@ -from typing import Literal - -from fastapi import FastAPI, Query -from pydantic import BaseModel, Field - -app = FastAPI() - - -class FilterParams(BaseModel): - limit: int = Field(100, gt=0, le=100) - offset: int = Field(0, ge=0) - order_by: Literal["created_at", "updated_at"] = "created_at" - tags: list[str] = [] - - -@app.get("/items/") -async def read_items(filter_query: FilterParams = Query()): - return filter_query diff --git a/docs_src/query_param_models/tutorial002_an_py39.py b/docs_src/query_param_models/tutorial002_an_py39.py deleted file mode 100644 index 975956502..000000000 --- a/docs_src/query_param_models/tutorial002_an_py39.py +++ /dev/null @@ -1,20 +0,0 @@ -from typing import Annotated, Literal - -from fastapi import FastAPI, Query -from pydantic import BaseModel, Field - -app = FastAPI() - - -class FilterParams(BaseModel): - model_config = {"extra": "forbid"} - - limit: int = Field(100, gt=0, le=100) - offset: int = Field(0, ge=0) - order_by: Literal["created_at", "updated_at"] = "created_at" - tags: list[str] = [] - - -@app.get("/items/") -async def read_items(filter_query: Annotated[FilterParams, Query()]): - return filter_query diff --git a/docs_src/query_param_models/tutorial002_py39.py b/docs_src/query_param_models/tutorial002_py39.py deleted file mode 100644 index 6ec418499..000000000 --- a/docs_src/query_param_models/tutorial002_py39.py +++ /dev/null @@ -1,20 +0,0 @@ -from typing import Literal - -from fastapi import FastAPI, Query -from pydantic import BaseModel, Field - -app = FastAPI() - - -class FilterParams(BaseModel): - model_config = {"extra": "forbid"} - - limit: int = Field(100, gt=0, le=100) - offset: int = Field(0, ge=0) - order_by: Literal["created_at", "updated_at"] = "created_at" - tags: list[str] = [] - - -@app.get("/items/") -async def read_items(filter_query: FilterParams = Query()): - return filter_query diff --git a/docs_src/query_params/tutorial001_py310.py b/docs_src/query_params/tutorial001_py310.py new file mode 100644 index 000000000..74e1a1760 --- /dev/null +++ b/docs_src/query_params/tutorial001_py310.py @@ -0,0 +1,10 @@ +from fastapi import FastAPI + +app = FastAPI() + +fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}] + + +@app.get("/items/") +async def read_item(skip: int = 0, limit: int = 10): + return fake_items_db[skip : skip + limit] diff --git a/docs_src/query_params/tutorial002_py39.py b/docs_src/query_params/tutorial002_py39.py deleted file mode 100644 index 8465f45ee..000000000 --- a/docs_src/query_params/tutorial002_py39.py +++ /dev/null @@ -1,12 +0,0 @@ -from typing import Union - -from fastapi import FastAPI - -app = FastAPI() - - -@app.get("/items/{item_id}") -async def read_item(item_id: str, q: Union[str, None] = None): - if q: - return {"item_id": item_id, "q": q} - return {"item_id": item_id} diff --git a/docs_src/query_params/tutorial003_py39.py b/docs_src/query_params/tutorial003_py39.py deleted file mode 100644 index 3362715b3..000000000 --- a/docs_src/query_params/tutorial003_py39.py +++ /dev/null @@ -1,17 +0,0 @@ -from typing import Union - -from fastapi import FastAPI - -app = FastAPI() - - -@app.get("/items/{item_id}") -async def read_item(item_id: str, q: Union[str, None] = None, short: bool = False): - item = {"item_id": item_id} - if q: - item.update({"q": q}) - if not short: - item.update( - {"description": "This is an amazing item that has a long description"} - ) - return item diff --git a/docs_src/query_params/tutorial004_py39.py b/docs_src/query_params/tutorial004_py39.py deleted file mode 100644 index 049c3ae93..000000000 --- a/docs_src/query_params/tutorial004_py39.py +++ /dev/null @@ -1,19 +0,0 @@ -from typing import Union - -from fastapi import FastAPI - -app = FastAPI() - - -@app.get("/users/{user_id}/items/{item_id}") -async def read_user_item( - user_id: int, item_id: str, q: Union[str, None] = None, short: bool = False -): - item = {"item_id": item_id, "owner_id": user_id} - if q: - item.update({"q": q}) - if not short: - item.update( - {"description": "This is an amazing item that has a long description"} - ) - return item diff --git a/docs_src/query_params/tutorial005_py310.py b/docs_src/query_params/tutorial005_py310.py new file mode 100644 index 000000000..e16a40574 --- /dev/null +++ b/docs_src/query_params/tutorial005_py310.py @@ -0,0 +1,9 @@ +from fastapi import FastAPI + +app = FastAPI() + + +@app.get("/items/{item_id}") +async def read_user_item(item_id: str, needy: str): + item = {"item_id": item_id, "needy": needy} + return item diff --git a/docs_src/query_params/tutorial006_py39.py b/docs_src/query_params/tutorial006_py39.py deleted file mode 100644 index f0dbfe08f..000000000 --- a/docs_src/query_params/tutorial006_py39.py +++ /dev/null @@ -1,13 +0,0 @@ -from typing import Union - -from fastapi import FastAPI - -app = FastAPI() - - -@app.get("/items/{item_id}") -async def read_user_item( - item_id: str, needy: str, skip: int = 0, limit: Union[int, None] = None -): - item = {"item_id": item_id, "needy": needy, "skip": skip, "limit": limit} - return item diff --git a/docs_src/query_params_str_validations/tutorial001_py39.py b/docs_src/query_params_str_validations/tutorial001_py39.py deleted file mode 100644 index e38326b18..000000000 --- a/docs_src/query_params_str_validations/tutorial001_py39.py +++ /dev/null @@ -1,13 +0,0 @@ -from typing import Union - -from fastapi import FastAPI - -app = FastAPI() - - -@app.get("/items/") -async def read_items(q: Union[str, None] = None): - results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} - if q: - results.update({"q": q}) - return results diff --git a/docs_src/query_params_str_validations/tutorial002_an_py39.py b/docs_src/query_params_str_validations/tutorial002_an_py39.py deleted file mode 100644 index 2d8fc9798..000000000 --- a/docs_src/query_params_str_validations/tutorial002_an_py39.py +++ /dev/null @@ -1,13 +0,0 @@ -from typing import Annotated, Union - -from fastapi import FastAPI, Query - -app = FastAPI() - - -@app.get("/items/") -async def read_items(q: Annotated[Union[str, None], Query(max_length=50)] = None): - results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} - if q: - results.update({"q": q}) - return results diff --git a/docs_src/query_params_str_validations/tutorial003_an_py39.py b/docs_src/query_params_str_validations/tutorial003_an_py39.py deleted file mode 100644 index 3d6697793..000000000 --- a/docs_src/query_params_str_validations/tutorial003_an_py39.py +++ /dev/null @@ -1,15 +0,0 @@ -from typing import Annotated, Union - -from fastapi import FastAPI, Query - -app = FastAPI() - - -@app.get("/items/") -async def read_items( - q: Annotated[Union[str, None], Query(min_length=3, max_length=50)] = None, -): - results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} - if q: - results.update({"q": q}) - return results diff --git a/docs_src/query_params_str_validations/tutorial003_py39.py b/docs_src/query_params_str_validations/tutorial003_py39.py deleted file mode 100644 index 7d4917373..000000000 --- a/docs_src/query_params_str_validations/tutorial003_py39.py +++ /dev/null @@ -1,15 +0,0 @@ -from typing import Union - -from fastapi import FastAPI, Query - -app = FastAPI() - - -@app.get("/items/") -async def read_items( - q: Union[str, None] = Query(default=None, min_length=3, max_length=50), -): - results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} - if q: - results.update({"q": q}) - return results diff --git a/docs_src/query_params_str_validations/tutorial004_an_py39.py b/docs_src/query_params_str_validations/tutorial004_an_py39.py deleted file mode 100644 index de27097b3..000000000 --- a/docs_src/query_params_str_validations/tutorial004_an_py39.py +++ /dev/null @@ -1,17 +0,0 @@ -from typing import Annotated, Union - -from fastapi import FastAPI, Query - -app = FastAPI() - - -@app.get("/items/") -async def read_items( - q: Annotated[ - Union[str, None], Query(min_length=3, max_length=50, pattern="^fixedquery$") - ] = None, -): - results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} - if q: - results.update({"q": q}) - return results diff --git a/docs_src/query_params_str_validations/tutorial004_py39.py b/docs_src/query_params_str_validations/tutorial004_py39.py deleted file mode 100644 index 64a647a16..000000000 --- a/docs_src/query_params_str_validations/tutorial004_py39.py +++ /dev/null @@ -1,17 +0,0 @@ -from typing import Union - -from fastapi import FastAPI, Query - -app = FastAPI() - - -@app.get("/items/") -async def read_items( - q: Union[str, None] = Query( - default=None, min_length=3, max_length=50, pattern="^fixedquery$" - ), -): - results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} - if q: - results.update({"q": q}) - return results diff --git a/docs_src/query_params_str_validations/tutorial004_regex_an_py310.py b/docs_src/query_params_str_validations/tutorial004_regex_an_py310.py deleted file mode 100644 index 21e0d3eb8..000000000 --- a/docs_src/query_params_str_validations/tutorial004_regex_an_py310.py +++ /dev/null @@ -1,17 +0,0 @@ -from typing import Annotated - -from fastapi import FastAPI, Query - -app = FastAPI() - - -@app.get("/items/") -async def read_items( - q: Annotated[ - str | None, Query(min_length=3, max_length=50, regex="^fixedquery$") - ] = None, -): - results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} - if q: - results.update({"q": q}) - return results diff --git a/docs_src/query_params_str_validations/tutorial002_py39.py b/docs_src/query_params_str_validations/tutorial005_an_py310.py similarity index 65% rename from docs_src/query_params_str_validations/tutorial002_py39.py rename to docs_src/query_params_str_validations/tutorial005_an_py310.py index 17e017b7e..b1f6046b5 100644 --- a/docs_src/query_params_str_validations/tutorial002_py39.py +++ b/docs_src/query_params_str_validations/tutorial005_an_py310.py @@ -1,4 +1,4 @@ -from typing import Union +from typing import Annotated from fastapi import FastAPI, Query @@ -6,7 +6,7 @@ app = FastAPI() @app.get("/items/") -async def read_items(q: Union[str, None] = Query(default=None, max_length=50)): +async def read_items(q: Annotated[str, Query(min_length=3)] = "fixedquery"): results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} if q: results.update({"q": q}) diff --git a/docs_src/query_params_str_validations/tutorial009_py39.py b/docs_src/query_params_str_validations/tutorial005_py310.py similarity index 64% rename from docs_src/query_params_str_validations/tutorial009_py39.py rename to docs_src/query_params_str_validations/tutorial005_py310.py index 8a6bfe2d9..8ab42869e 100644 --- a/docs_src/query_params_str_validations/tutorial009_py39.py +++ b/docs_src/query_params_str_validations/tutorial005_py310.py @@ -1,12 +1,10 @@ -from typing import Union - from fastapi import FastAPI, Query app = FastAPI() @app.get("/items/") -async def read_items(q: Union[str, None] = Query(default=None, alias="item-query")): +async def read_items(q: str = Query(default="fixedquery", min_length=3)): results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} if q: results.update({"q": q}) diff --git a/docs_src/query_params_str_validations/tutorial006c_py39.py b/docs_src/query_params_str_validations/tutorial006_an_py310.py similarity index 69% rename from docs_src/query_params_str_validations/tutorial006c_py39.py rename to docs_src/query_params_str_validations/tutorial006_an_py310.py index 0a0e820da..3b4a676d2 100644 --- a/docs_src/query_params_str_validations/tutorial006c_py39.py +++ b/docs_src/query_params_str_validations/tutorial006_an_py310.py @@ -1,4 +1,4 @@ -from typing import Union +from typing import Annotated from fastapi import FastAPI, Query @@ -6,7 +6,7 @@ app = FastAPI() @app.get("/items/") -async def read_items(q: Union[str, None] = Query(min_length=3)): +async def read_items(q: Annotated[str, Query(min_length=3)]): results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} if q: results.update({"q": q}) diff --git a/docs_src/query_params_str_validations/tutorial006c_an_py39.py b/docs_src/query_params_str_validations/tutorial006_py310.py similarity index 64% rename from docs_src/query_params_str_validations/tutorial006c_an_py39.py rename to docs_src/query_params_str_validations/tutorial006_py310.py index 76a1cd49a..9a90eb64e 100644 --- a/docs_src/query_params_str_validations/tutorial006c_an_py39.py +++ b/docs_src/query_params_str_validations/tutorial006_py310.py @@ -1,12 +1,10 @@ -from typing import Annotated, Union - from fastapi import FastAPI, Query app = FastAPI() @app.get("/items/") -async def read_items(q: Annotated[Union[str, None], Query(min_length=3)]): +async def read_items(q: str = Query(min_length=3)): results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} if q: results.update({"q": q}) diff --git a/docs_src/query_params_str_validations/tutorial007_an_py39.py b/docs_src/query_params_str_validations/tutorial007_an_py39.py deleted file mode 100644 index 8d7a82c46..000000000 --- a/docs_src/query_params_str_validations/tutorial007_an_py39.py +++ /dev/null @@ -1,15 +0,0 @@ -from typing import Annotated, Union - -from fastapi import FastAPI, Query - -app = FastAPI() - - -@app.get("/items/") -async def read_items( - q: Annotated[Union[str, None], Query(title="Query string", min_length=3)] = None, -): - results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} - if q: - results.update({"q": q}) - return results diff --git a/docs_src/query_params_str_validations/tutorial007_py39.py b/docs_src/query_params_str_validations/tutorial007_py39.py deleted file mode 100644 index 27b649e14..000000000 --- a/docs_src/query_params_str_validations/tutorial007_py39.py +++ /dev/null @@ -1,15 +0,0 @@ -from typing import Union - -from fastapi import FastAPI, Query - -app = FastAPI() - - -@app.get("/items/") -async def read_items( - q: Union[str, None] = Query(default=None, title="Query string", min_length=3), -): - results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} - if q: - results.update({"q": q}) - return results diff --git a/docs_src/query_params_str_validations/tutorial008_an_py39.py b/docs_src/query_params_str_validations/tutorial008_an_py39.py deleted file mode 100644 index f3f2f2c0e..000000000 --- a/docs_src/query_params_str_validations/tutorial008_an_py39.py +++ /dev/null @@ -1,22 +0,0 @@ -from typing import Annotated, Union - -from fastapi import FastAPI, Query - -app = FastAPI() - - -@app.get("/items/") -async def read_items( - q: Annotated[ - Union[str, None], - Query( - title="Query string", - description="Query string for the items to search in the database that have a good match", - min_length=3, - ), - ] = None, -): - results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} - if q: - results.update({"q": q}) - return results diff --git a/docs_src/query_params_str_validations/tutorial008_py39.py b/docs_src/query_params_str_validations/tutorial008_py39.py deleted file mode 100644 index e3e0b50aa..000000000 --- a/docs_src/query_params_str_validations/tutorial008_py39.py +++ /dev/null @@ -1,20 +0,0 @@ -from typing import Union - -from fastapi import FastAPI, Query - -app = FastAPI() - - -@app.get("/items/") -async def read_items( - q: Union[str, None] = Query( - default=None, - title="Query string", - description="Query string for the items to search in the database that have a good match", - min_length=3, - ), -): - results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} - if q: - results.update({"q": q}) - return results diff --git a/docs_src/query_params_str_validations/tutorial009_an_py39.py b/docs_src/query_params_str_validations/tutorial009_an_py39.py deleted file mode 100644 index 70a89e613..000000000 --- a/docs_src/query_params_str_validations/tutorial009_an_py39.py +++ /dev/null @@ -1,13 +0,0 @@ -from typing import Annotated, Union - -from fastapi import FastAPI, Query - -app = FastAPI() - - -@app.get("/items/") -async def read_items(q: Annotated[Union[str, None], Query(alias="item-query")] = None): - results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} - if q: - results.update({"q": q}) - return results diff --git a/docs_src/query_params_str_validations/tutorial010_an_py39.py b/docs_src/query_params_str_validations/tutorial010_an_py39.py deleted file mode 100644 index b126c116f..000000000 --- a/docs_src/query_params_str_validations/tutorial010_an_py39.py +++ /dev/null @@ -1,26 +0,0 @@ -from typing import Annotated, Union - -from fastapi import FastAPI, Query - -app = FastAPI() - - -@app.get("/items/") -async def read_items( - q: Annotated[ - Union[str, None], - Query( - alias="item-query", - title="Query string", - description="Query string for the items to search in the database that have a good match", - min_length=3, - max_length=50, - pattern="^fixedquery$", - deprecated=True, - ), - ] = None, -): - results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} - if q: - results.update({"q": q}) - return results diff --git a/docs_src/query_params_str_validations/tutorial010_py39.py b/docs_src/query_params_str_validations/tutorial010_py39.py deleted file mode 100644 index ff29176fe..000000000 --- a/docs_src/query_params_str_validations/tutorial010_py39.py +++ /dev/null @@ -1,24 +0,0 @@ -from typing import Union - -from fastapi import FastAPI, Query - -app = FastAPI() - - -@app.get("/items/") -async def read_items( - q: Union[str, None] = Query( - default=None, - alias="item-query", - title="Query string", - description="Query string for the items to search in the database that have a good match", - min_length=3, - max_length=50, - pattern="^fixedquery$", - deprecated=True, - ), -): - results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} - if q: - results.update({"q": q}) - return results diff --git a/docs_src/query_params_str_validations/tutorial011_an_py39.py b/docs_src/query_params_str_validations/tutorial012_an_py310.py similarity index 52% rename from docs_src/query_params_str_validations/tutorial011_an_py39.py rename to docs_src/query_params_str_validations/tutorial012_an_py310.py index 416e3990d..9b5a9c2fb 100644 --- a/docs_src/query_params_str_validations/tutorial011_an_py39.py +++ b/docs_src/query_params_str_validations/tutorial012_an_py310.py @@ -1,4 +1,4 @@ -from typing import Annotated, Union +from typing import Annotated from fastapi import FastAPI, Query @@ -6,6 +6,6 @@ app = FastAPI() @app.get("/items/") -async def read_items(q: Annotated[Union[list[str], None], Query()] = None): +async def read_items(q: Annotated[list[str], Query()] = ["foo", "bar"]): query_items = {"q": q} return query_items diff --git a/docs_src/query_params_str_validations/tutorial012_py310.py b/docs_src/query_params_str_validations/tutorial012_py310.py new file mode 100644 index 000000000..070d0b04b --- /dev/null +++ b/docs_src/query_params_str_validations/tutorial012_py310.py @@ -0,0 +1,9 @@ +from fastapi import FastAPI, Query + +app = FastAPI() + + +@app.get("/items/") +async def read_items(q: list[str] = Query(default=["foo", "bar"])): + query_items = {"q": q} + return query_items diff --git a/docs_src/query_params_str_validations/tutorial011_py39.py b/docs_src/query_params_str_validations/tutorial013_an_py310.py similarity index 56% rename from docs_src/query_params_str_validations/tutorial011_py39.py rename to docs_src/query_params_str_validations/tutorial013_an_py310.py index 878f95c79..602734145 100644 --- a/docs_src/query_params_str_validations/tutorial011_py39.py +++ b/docs_src/query_params_str_validations/tutorial013_an_py310.py @@ -1,4 +1,4 @@ -from typing import Union +from typing import Annotated from fastapi import FastAPI, Query @@ -6,6 +6,6 @@ app = FastAPI() @app.get("/items/") -async def read_items(q: Union[list[str], None] = Query(default=None)): +async def read_items(q: Annotated[list, Query()] = []): query_items = {"q": q} return query_items diff --git a/docs_src/query_params_str_validations/tutorial013_py310.py b/docs_src/query_params_str_validations/tutorial013_py310.py new file mode 100644 index 000000000..0b0f44869 --- /dev/null +++ b/docs_src/query_params_str_validations/tutorial013_py310.py @@ -0,0 +1,9 @@ +from fastapi import FastAPI, Query + +app = FastAPI() + + +@app.get("/items/") +async def read_items(q: list = Query(default=[])): + query_items = {"q": q} + return query_items diff --git a/docs_src/query_params_str_validations/tutorial014_an_py39.py b/docs_src/query_params_str_validations/tutorial014_an_py39.py deleted file mode 100644 index aaf7703a5..000000000 --- a/docs_src/query_params_str_validations/tutorial014_an_py39.py +++ /dev/null @@ -1,15 +0,0 @@ -from typing import Annotated, Union - -from fastapi import FastAPI, Query - -app = FastAPI() - - -@app.get("/items/") -async def read_items( - hidden_query: Annotated[Union[str, None], Query(include_in_schema=False)] = None, -): - if hidden_query: - return {"hidden_query": hidden_query} - else: - return {"hidden_query": "Not found"} diff --git a/docs_src/query_params_str_validations/tutorial014_py39.py b/docs_src/query_params_str_validations/tutorial014_py39.py deleted file mode 100644 index 779db1c80..000000000 --- a/docs_src/query_params_str_validations/tutorial014_py39.py +++ /dev/null @@ -1,15 +0,0 @@ -from typing import Union - -from fastapi import FastAPI, Query - -app = FastAPI() - - -@app.get("/items/") -async def read_items( - hidden_query: Union[str, None] = Query(default=None, include_in_schema=False), -): - if hidden_query: - return {"hidden_query": hidden_query} - else: - return {"hidden_query": "Not found"} diff --git a/docs_src/query_params_str_validations/tutorial015_an_py39.py b/docs_src/query_params_str_validations/tutorial015_an_py39.py deleted file mode 100644 index 989b6d2c2..000000000 --- a/docs_src/query_params_str_validations/tutorial015_an_py39.py +++ /dev/null @@ -1,30 +0,0 @@ -import random -from typing import Annotated, Union - -from fastapi import FastAPI -from pydantic import AfterValidator - -app = FastAPI() - -data = { - "isbn-9781529046137": "The Hitchhiker's Guide to the Galaxy", - "imdb-tt0371724": "The Hitchhiker's Guide to the Galaxy", - "isbn-9781439512982": "Isaac Asimov: The Complete Stories, Vol. 2", -} - - -def check_valid_id(id: str): - if not id.startswith(("isbn-", "imdb-")): - raise ValueError('Invalid ID format, it must start with "isbn-" or "imdb-"') - return id - - -@app.get("/items/") -async def read_items( - id: Annotated[Union[str, None], AfterValidator(check_valid_id)] = None, -): - if id: - item = data.get(id) - else: - id, item = random.choice(list(data.items())) - return {"id": id, "name": item} diff --git a/docs_src/request_files/tutorial001_02_an_py39.py b/docs_src/request_files/tutorial001_02_an_py39.py deleted file mode 100644 index bb090ff6c..000000000 --- a/docs_src/request_files/tutorial001_02_an_py39.py +++ /dev/null @@ -1,21 +0,0 @@ -from typing import Annotated, Union - -from fastapi import FastAPI, File, UploadFile - -app = FastAPI() - - -@app.post("/files/") -async def create_file(file: Annotated[Union[bytes, None], File()] = None): - if not file: - return {"message": "No file sent"} - else: - return {"file_size": len(file)} - - -@app.post("/uploadfile/") -async def create_upload_file(file: Union[UploadFile, None] = None): - if not file: - return {"message": "No upload file sent"} - else: - return {"filename": file.filename} diff --git a/docs_src/request_files/tutorial001_02_py39.py b/docs_src/request_files/tutorial001_02_py39.py deleted file mode 100644 index ac30be2d3..000000000 --- a/docs_src/request_files/tutorial001_02_py39.py +++ /dev/null @@ -1,21 +0,0 @@ -from typing import Union - -from fastapi import FastAPI, File, UploadFile - -app = FastAPI() - - -@app.post("/files/") -async def create_file(file: Union[bytes, None] = File(default=None)): - if not file: - return {"message": "No file sent"} - else: - return {"file_size": len(file)} - - -@app.post("/uploadfile/") -async def create_upload_file(file: Union[UploadFile, None] = None): - if not file: - return {"message": "No upload file sent"} - else: - return {"filename": file.filename} diff --git a/docs_src/request_files/tutorial001_03_an_py310.py b/docs_src/request_files/tutorial001_03_an_py310.py new file mode 100644 index 000000000..93098a677 --- /dev/null +++ b/docs_src/request_files/tutorial001_03_an_py310.py @@ -0,0 +1,17 @@ +from typing import Annotated + +from fastapi import FastAPI, File, UploadFile + +app = FastAPI() + + +@app.post("/files/") +async def create_file(file: Annotated[bytes, File(description="A file read as bytes")]): + return {"file_size": len(file)} + + +@app.post("/uploadfile/") +async def create_upload_file( + file: Annotated[UploadFile, File(description="A file read as UploadFile")], +): + return {"filename": file.filename} diff --git a/docs_src/request_files/tutorial001_03_py310.py b/docs_src/request_files/tutorial001_03_py310.py new file mode 100644 index 000000000..d8005cc7d --- /dev/null +++ b/docs_src/request_files/tutorial001_03_py310.py @@ -0,0 +1,15 @@ +from fastapi import FastAPI, File, UploadFile + +app = FastAPI() + + +@app.post("/files/") +async def create_file(file: bytes = File(description="A file read as bytes")): + return {"file_size": len(file)} + + +@app.post("/uploadfile/") +async def create_upload_file( + file: UploadFile = File(description="A file read as UploadFile"), +): + return {"filename": file.filename} diff --git a/docs_src/request_files/tutorial001_an_py310.py b/docs_src/request_files/tutorial001_an_py310.py new file mode 100644 index 000000000..26a767221 --- /dev/null +++ b/docs_src/request_files/tutorial001_an_py310.py @@ -0,0 +1,15 @@ +from typing import Annotated + +from fastapi import FastAPI, File, UploadFile + +app = FastAPI() + + +@app.post("/files/") +async def create_file(file: Annotated[bytes, File()]): + return {"file_size": len(file)} + + +@app.post("/uploadfile/") +async def create_upload_file(file: UploadFile): + return {"filename": file.filename} diff --git a/docs_src/request_files/tutorial001_py310.py b/docs_src/request_files/tutorial001_py310.py new file mode 100644 index 000000000..2e0ea6391 --- /dev/null +++ b/docs_src/request_files/tutorial001_py310.py @@ -0,0 +1,13 @@ +from fastapi import FastAPI, File, UploadFile + +app = FastAPI() + + +@app.post("/files/") +async def create_file(file: bytes = File()): + return {"file_size": len(file)} + + +@app.post("/uploadfile/") +async def create_upload_file(file: UploadFile): + return {"filename": file.filename} diff --git a/docs_src/request_files/tutorial002_an_py310.py b/docs_src/request_files/tutorial002_an_py310.py new file mode 100644 index 000000000..db524ceab --- /dev/null +++ b/docs_src/request_files/tutorial002_an_py310.py @@ -0,0 +1,33 @@ +from typing import Annotated + +from fastapi import FastAPI, File, UploadFile +from fastapi.responses import HTMLResponse + +app = FastAPI() + + +@app.post("/files/") +async def create_files(files: Annotated[list[bytes], File()]): + return {"file_sizes": [len(file) for file in files]} + + +@app.post("/uploadfiles/") +async def create_upload_files(files: list[UploadFile]): + return {"filenames": [file.filename for file in files]} + + +@app.get("/") +async def main(): + content = """ + +
+ + +
+
+ + +
+ + """ + return HTMLResponse(content=content) diff --git a/docs_src/request_files/tutorial002_py310.py b/docs_src/request_files/tutorial002_py310.py new file mode 100644 index 000000000..b64cf5598 --- /dev/null +++ b/docs_src/request_files/tutorial002_py310.py @@ -0,0 +1,31 @@ +from fastapi import FastAPI, File, UploadFile +from fastapi.responses import HTMLResponse + +app = FastAPI() + + +@app.post("/files/") +async def create_files(files: list[bytes] = File()): + return {"file_sizes": [len(file) for file in files]} + + +@app.post("/uploadfiles/") +async def create_upload_files(files: list[UploadFile]): + return {"filenames": [file.filename for file in files]} + + +@app.get("/") +async def main(): + content = """ + +
+ + +
+
+ + +
+ + """ + return HTMLResponse(content=content) diff --git a/docs_src/request_files/tutorial003_an_py310.py b/docs_src/request_files/tutorial003_an_py310.py new file mode 100644 index 000000000..5a8c5dab5 --- /dev/null +++ b/docs_src/request_files/tutorial003_an_py310.py @@ -0,0 +1,39 @@ +from typing import Annotated + +from fastapi import FastAPI, File, UploadFile +from fastapi.responses import HTMLResponse + +app = FastAPI() + + +@app.post("/files/") +async def create_files( + files: Annotated[list[bytes], File(description="Multiple files as bytes")], +): + return {"file_sizes": [len(file) for file in files]} + + +@app.post("/uploadfiles/") +async def create_upload_files( + files: Annotated[ + list[UploadFile], File(description="Multiple files as UploadFile") + ], +): + return {"filenames": [file.filename for file in files]} + + +@app.get("/") +async def main(): + content = """ + +
+ + +
+
+ + +
+ + """ + return HTMLResponse(content=content) diff --git a/docs_src/request_files/tutorial003_py310.py b/docs_src/request_files/tutorial003_py310.py new file mode 100644 index 000000000..96f5e8742 --- /dev/null +++ b/docs_src/request_files/tutorial003_py310.py @@ -0,0 +1,35 @@ +from fastapi import FastAPI, File, UploadFile +from fastapi.responses import HTMLResponse + +app = FastAPI() + + +@app.post("/files/") +async def create_files( + files: list[bytes] = File(description="Multiple files as bytes"), +): + return {"file_sizes": [len(file) for file in files]} + + +@app.post("/uploadfiles/") +async def create_upload_files( + files: list[UploadFile] = File(description="Multiple files as UploadFile"), +): + return {"filenames": [file.filename for file in files]} + + +@app.get("/") +async def main(): + content = """ + +
+ + +
+
+ + +
+ + """ + return HTMLResponse(content=content) diff --git a/docs_src/request_form_models/tutorial001_an_py310.py b/docs_src/request_form_models/tutorial001_an_py310.py new file mode 100644 index 000000000..7cc81aae9 --- /dev/null +++ b/docs_src/request_form_models/tutorial001_an_py310.py @@ -0,0 +1,16 @@ +from typing import Annotated + +from fastapi import FastAPI, Form +from pydantic import BaseModel + +app = FastAPI() + + +class FormData(BaseModel): + username: str + password: str + + +@app.post("/login/") +async def login(data: Annotated[FormData, Form()]): + return data diff --git a/docs_src/request_form_models/tutorial001_py310.py b/docs_src/request_form_models/tutorial001_py310.py new file mode 100644 index 000000000..98feff0b9 --- /dev/null +++ b/docs_src/request_form_models/tutorial001_py310.py @@ -0,0 +1,14 @@ +from fastapi import FastAPI, Form +from pydantic import BaseModel + +app = FastAPI() + + +class FormData(BaseModel): + username: str + password: str + + +@app.post("/login/") +async def login(data: FormData = Form()): + return data diff --git a/docs_src/request_form_models/tutorial002_an_py310.py b/docs_src/request_form_models/tutorial002_an_py310.py new file mode 100644 index 000000000..3004e0852 --- /dev/null +++ b/docs_src/request_form_models/tutorial002_an_py310.py @@ -0,0 +1,17 @@ +from typing import Annotated + +from fastapi import FastAPI, Form +from pydantic import BaseModel + +app = FastAPI() + + +class FormData(BaseModel): + username: str + password: str + model_config = {"extra": "forbid"} + + +@app.post("/login/") +async def login(data: Annotated[FormData, Form()]): + return data diff --git a/docs_src/request_form_models/tutorial002_py310.py b/docs_src/request_form_models/tutorial002_py310.py new file mode 100644 index 000000000..59b329e8d --- /dev/null +++ b/docs_src/request_form_models/tutorial002_py310.py @@ -0,0 +1,15 @@ +from fastapi import FastAPI, Form +from pydantic import BaseModel + +app = FastAPI() + + +class FormData(BaseModel): + username: str + password: str + model_config = {"extra": "forbid"} + + +@app.post("/login/") +async def login(data: FormData = Form()): + return data diff --git a/docs_src/request_forms/tutorial001_an_py310.py b/docs_src/request_forms/tutorial001_an_py310.py new file mode 100644 index 000000000..8e9d2ea53 --- /dev/null +++ b/docs_src/request_forms/tutorial001_an_py310.py @@ -0,0 +1,10 @@ +from typing import Annotated + +from fastapi import FastAPI, Form + +app = FastAPI() + + +@app.post("/login/") +async def login(username: Annotated[str, Form()], password: Annotated[str, Form()]): + return {"username": username} diff --git a/docs_src/request_forms/tutorial001_py310.py b/docs_src/request_forms/tutorial001_py310.py new file mode 100644 index 000000000..a53770001 --- /dev/null +++ b/docs_src/request_forms/tutorial001_py310.py @@ -0,0 +1,8 @@ +from fastapi import FastAPI, Form + +app = FastAPI() + + +@app.post("/login/") +async def login(username: str = Form(), password: str = Form()): + return {"username": username} diff --git a/docs_src/request_forms_and_files/tutorial001_an_py310.py b/docs_src/request_forms_and_files/tutorial001_an_py310.py new file mode 100644 index 000000000..12cc43e50 --- /dev/null +++ b/docs_src/request_forms_and_files/tutorial001_an_py310.py @@ -0,0 +1,18 @@ +from typing import Annotated + +from fastapi import FastAPI, File, Form, UploadFile + +app = FastAPI() + + +@app.post("/files/") +async def create_file( + file: Annotated[bytes, File()], + fileb: Annotated[UploadFile, File()], + token: Annotated[str, Form()], +): + return { + "file_size": len(file), + "token": token, + "fileb_content_type": fileb.content_type, + } diff --git a/docs_src/request_forms_and_files/tutorial001_py310.py b/docs_src/request_forms_and_files/tutorial001_py310.py new file mode 100644 index 000000000..7b5224ce5 --- /dev/null +++ b/docs_src/request_forms_and_files/tutorial001_py310.py @@ -0,0 +1,14 @@ +from fastapi import FastAPI, File, Form, UploadFile + +app = FastAPI() + + +@app.post("/files/") +async def create_file( + file: bytes = File(), fileb: UploadFile = File(), token: str = Form() +): + return { + "file_size": len(file), + "token": token, + "fileb_content_type": fileb.content_type, + } diff --git a/docs_src/response_change_status_code/tutorial001_py310.py b/docs_src/response_change_status_code/tutorial001_py310.py new file mode 100644 index 000000000..197decbfb --- /dev/null +++ b/docs_src/response_change_status_code/tutorial001_py310.py @@ -0,0 +1,13 @@ +from fastapi import FastAPI, Response, status + +app = FastAPI() + +tasks = {"foo": "Listen to the Bar Fighters"} + + +@app.put("/get-or-create-task/{task_id}", status_code=200) +def get_or_create_task(task_id: str, response: Response): + if task_id not in tasks: + tasks[task_id] = "This didn't exist before" + response.status_code = status.HTTP_201_CREATED + return tasks[task_id] diff --git a/docs_src/response_cookies/tutorial001_py310.py b/docs_src/response_cookies/tutorial001_py310.py new file mode 100644 index 000000000..33f8e8f6e --- /dev/null +++ b/docs_src/response_cookies/tutorial001_py310.py @@ -0,0 +1,12 @@ +from fastapi import FastAPI +from fastapi.responses import JSONResponse + +app = FastAPI() + + +@app.post("/cookie/") +def create_cookie(): + content = {"message": "Come to the dark side, we have cookies"} + response = JSONResponse(content=content) + response.set_cookie(key="fakesession", value="fake-cookie-session-value") + return response diff --git a/docs_src/response_cookies/tutorial002_py310.py b/docs_src/response_cookies/tutorial002_py310.py new file mode 100644 index 000000000..76c06fdb9 --- /dev/null +++ b/docs_src/response_cookies/tutorial002_py310.py @@ -0,0 +1,9 @@ +from fastapi import FastAPI, Response + +app = FastAPI() + + +@app.post("/cookie-and-object/") +def create_cookie(response: Response): + response.set_cookie(key="fakesession", value="fake-cookie-session-value") + return {"message": "Come to the dark side, we have cookies"} diff --git a/docs_src/response_directly/tutorial001_py39.py b/docs_src/response_directly/tutorial001_py39.py deleted file mode 100644 index 5ab655a8a..000000000 --- a/docs_src/response_directly/tutorial001_py39.py +++ /dev/null @@ -1,22 +0,0 @@ -from datetime import datetime -from typing import Union - -from fastapi import FastAPI -from fastapi.encoders import jsonable_encoder -from fastapi.responses import JSONResponse -from pydantic import BaseModel - - -class Item(BaseModel): - title: str - timestamp: datetime - description: Union[str, None] = None - - -app = FastAPI() - - -@app.put("/items/{id}") -def update_item(id: str, item: Item): - json_compatible_item_data = jsonable_encoder(item) - return JSONResponse(content=json_compatible_item_data) diff --git a/docs_src/response_directly/tutorial002_py310.py b/docs_src/response_directly/tutorial002_py310.py new file mode 100644 index 000000000..6643da6e6 --- /dev/null +++ b/docs_src/response_directly/tutorial002_py310.py @@ -0,0 +1,18 @@ +from fastapi import FastAPI, Response + +app = FastAPI() + + +@app.get("/legacy/") +def get_legacy_data(): + data = """ + +
+ Apply shampoo here. +
+ + You'll have to use soap here. + +
+ """ + return Response(content=data, media_type="application/xml") diff --git a/docs_src/response_headers/tutorial001_py310.py b/docs_src/response_headers/tutorial001_py310.py new file mode 100644 index 000000000..2da02a470 --- /dev/null +++ b/docs_src/response_headers/tutorial001_py310.py @@ -0,0 +1,11 @@ +from fastapi import FastAPI +from fastapi.responses import JSONResponse + +app = FastAPI() + + +@app.get("/headers/") +def get_headers(): + content = {"message": "Hello World"} + headers = {"X-Cat-Dog": "alone in the world", "Content-Language": "en-US"} + return JSONResponse(content=content, headers=headers) diff --git a/docs_src/response_headers/tutorial002_py310.py b/docs_src/response_headers/tutorial002_py310.py new file mode 100644 index 000000000..d2c498305 --- /dev/null +++ b/docs_src/response_headers/tutorial002_py310.py @@ -0,0 +1,9 @@ +from fastapi import FastAPI, Response + +app = FastAPI() + + +@app.get("/headers-and-object/") +def get_headers(response: Response): + response.headers["X-Cat-Dog"] = "alone in the world" + return {"message": "Hello World"} diff --git a/docs_src/response_model/tutorial001_01_py39.py b/docs_src/response_model/tutorial001_01_py39.py deleted file mode 100644 index 16c78aa3f..000000000 --- a/docs_src/response_model/tutorial001_01_py39.py +++ /dev/null @@ -1,27 +0,0 @@ -from typing import Union - -from fastapi import FastAPI -from pydantic import BaseModel - -app = FastAPI() - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: Union[float, None] = None - tags: list[str] = [] - - -@app.post("/items/") -async def create_item(item: Item) -> Item: - return item - - -@app.get("/items/") -async def read_items() -> list[Item]: - return [ - Item(name="Portal Gun", price=42.0), - Item(name="Plumbus", price=32.0), - ] diff --git a/docs_src/response_model/tutorial001_py39.py b/docs_src/response_model/tutorial001_py39.py deleted file mode 100644 index 261e252d0..000000000 --- a/docs_src/response_model/tutorial001_py39.py +++ /dev/null @@ -1,27 +0,0 @@ -from typing import Any, Union - -from fastapi import FastAPI -from pydantic import BaseModel - -app = FastAPI() - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: Union[float, None] = None - tags: list[str] = [] - - -@app.post("/items/", response_model=Item) -async def create_item(item: Item) -> Any: - return item - - -@app.get("/items/", response_model=list[Item]) -async def read_items() -> Any: - return [ - {"name": "Portal Gun", "price": 42.0}, - {"name": "Plumbus", "price": 32.0}, - ] diff --git a/docs_src/response_model/tutorial002_py39.py b/docs_src/response_model/tutorial002_py39.py deleted file mode 100644 index a58668f9e..000000000 --- a/docs_src/response_model/tutorial002_py39.py +++ /dev/null @@ -1,19 +0,0 @@ -from typing import Union - -from fastapi import FastAPI -from pydantic import BaseModel, EmailStr - -app = FastAPI() - - -class UserIn(BaseModel): - username: str - password: str - email: EmailStr - full_name: Union[str, None] = None - - -# Don't do this in production! -@app.post("/user/") -async def create_user(user: UserIn) -> UserIn: - return user diff --git a/docs_src/response_model/tutorial003_01_py39.py b/docs_src/response_model/tutorial003_01_py39.py deleted file mode 100644 index 52694b551..000000000 --- a/docs_src/response_model/tutorial003_01_py39.py +++ /dev/null @@ -1,21 +0,0 @@ -from typing import Union - -from fastapi import FastAPI -from pydantic import BaseModel, EmailStr - -app = FastAPI() - - -class BaseUser(BaseModel): - username: str - email: EmailStr - full_name: Union[str, None] = None - - -class UserIn(BaseUser): - password: str - - -@app.post("/user/") -async def create_user(user: UserIn) -> BaseUser: - return user diff --git a/docs_src/response_model/tutorial003_02_py310.py b/docs_src/response_model/tutorial003_02_py310.py new file mode 100644 index 000000000..df6a09646 --- /dev/null +++ b/docs_src/response_model/tutorial003_02_py310.py @@ -0,0 +1,11 @@ +from fastapi import FastAPI, Response +from fastapi.responses import JSONResponse, RedirectResponse + +app = FastAPI() + + +@app.get("/portal") +async def get_portal(teleport: bool = False) -> Response: + if teleport: + return RedirectResponse(url="https://www.youtube.com/watch?v=dQw4w9WgXcQ") + return JSONResponse(content={"message": "Here's your interdimensional portal."}) diff --git a/docs_src/response_model/tutorial003_03_py310.py b/docs_src/response_model/tutorial003_03_py310.py new file mode 100644 index 000000000..0d4bd8de5 --- /dev/null +++ b/docs_src/response_model/tutorial003_03_py310.py @@ -0,0 +1,9 @@ +from fastapi import FastAPI +from fastapi.responses import RedirectResponse + +app = FastAPI() + + +@app.get("/teleport") +async def get_teleport() -> RedirectResponse: + return RedirectResponse(url="https://www.youtube.com/watch?v=dQw4w9WgXcQ") diff --git a/docs_src/response_model/tutorial003_04_py39.py b/docs_src/response_model/tutorial003_04_py39.py deleted file mode 100644 index b13a92692..000000000 --- a/docs_src/response_model/tutorial003_04_py39.py +++ /dev/null @@ -1,13 +0,0 @@ -from typing import Union - -from fastapi import FastAPI, Response -from fastapi.responses import RedirectResponse - -app = FastAPI() - - -@app.get("/portal") -async def get_portal(teleport: bool = False) -> Union[Response, dict]: - if teleport: - return RedirectResponse(url="https://www.youtube.com/watch?v=dQw4w9WgXcQ") - return {"message": "Here's your interdimensional portal."} diff --git a/docs_src/response_model/tutorial003_05_py39.py b/docs_src/response_model/tutorial003_05_py39.py deleted file mode 100644 index 0962061a6..000000000 --- a/docs_src/response_model/tutorial003_05_py39.py +++ /dev/null @@ -1,13 +0,0 @@ -from typing import Union - -from fastapi import FastAPI, Response -from fastapi.responses import RedirectResponse - -app = FastAPI() - - -@app.get("/portal", response_model=None) -async def get_portal(teleport: bool = False) -> Union[Response, dict]: - if teleport: - return RedirectResponse(url="https://www.youtube.com/watch?v=dQw4w9WgXcQ") - return {"message": "Here's your interdimensional portal."} diff --git a/docs_src/response_model/tutorial003_py39.py b/docs_src/response_model/tutorial003_py39.py deleted file mode 100644 index c42dbc707..000000000 --- a/docs_src/response_model/tutorial003_py39.py +++ /dev/null @@ -1,24 +0,0 @@ -from typing import Any, Union - -from fastapi import FastAPI -from pydantic import BaseModel, EmailStr - -app = FastAPI() - - -class UserIn(BaseModel): - username: str - password: str - email: EmailStr - full_name: Union[str, None] = None - - -class UserOut(BaseModel): - username: str - email: EmailStr - full_name: Union[str, None] = None - - -@app.post("/user/", response_model=UserOut) -async def create_user(user: UserIn) -> Any: - return user diff --git a/docs_src/response_model/tutorial004_py39.py b/docs_src/response_model/tutorial004_py39.py deleted file mode 100644 index 9463b45ec..000000000 --- a/docs_src/response_model/tutorial004_py39.py +++ /dev/null @@ -1,26 +0,0 @@ -from typing import Union - -from fastapi import FastAPI -from pydantic import BaseModel - -app = FastAPI() - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: float = 10.5 - tags: list[str] = [] - - -items = { - "foo": {"name": "Foo", "price": 50.2}, - "bar": {"name": "Bar", "description": "The bartenders", "price": 62, "tax": 20.2}, - "baz": {"name": "Baz", "description": None, "price": 50.2, "tax": 10.5, "tags": []}, -} - - -@app.get("/items/{item_id}", response_model=Item, response_model_exclude_unset=True) -async def read_item(item_id: str): - return items[item_id] diff --git a/docs_src/response_model/tutorial005_py39.py b/docs_src/response_model/tutorial005_py39.py deleted file mode 100644 index 30eb9f8e3..000000000 --- a/docs_src/response_model/tutorial005_py39.py +++ /dev/null @@ -1,39 +0,0 @@ -from typing import Union - -from fastapi import FastAPI -from pydantic import BaseModel - -app = FastAPI() - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: float = 10.5 - - -items = { - "foo": {"name": "Foo", "price": 50.2}, - "bar": {"name": "Bar", "description": "The Bar fighters", "price": 62, "tax": 20.2}, - "baz": { - "name": "Baz", - "description": "There goes my baz", - "price": 50.2, - "tax": 10.5, - }, -} - - -@app.get( - "/items/{item_id}/name", - response_model=Item, - response_model_include={"name", "description"}, -) -async def read_item_name(item_id: str): - return items[item_id] - - -@app.get("/items/{item_id}/public", response_model=Item, response_model_exclude={"tax"}) -async def read_item_public_data(item_id: str): - return items[item_id] diff --git a/docs_src/response_model/tutorial006_py39.py b/docs_src/response_model/tutorial006_py39.py deleted file mode 100644 index 3ffdb512b..000000000 --- a/docs_src/response_model/tutorial006_py39.py +++ /dev/null @@ -1,39 +0,0 @@ -from typing import Union - -from fastapi import FastAPI -from pydantic import BaseModel - -app = FastAPI() - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: float = 10.5 - - -items = { - "foo": {"name": "Foo", "price": 50.2}, - "bar": {"name": "Bar", "description": "The Bar fighters", "price": 62, "tax": 20.2}, - "baz": { - "name": "Baz", - "description": "There goes my baz", - "price": 50.2, - "tax": 10.5, - }, -} - - -@app.get( - "/items/{item_id}/name", - response_model=Item, - response_model_include=["name", "description"], -) -async def read_item_name(item_id: str): - return items[item_id] - - -@app.get("/items/{item_id}/public", response_model=Item, response_model_exclude=["tax"]) -async def read_item_public_data(item_id: str): - return items[item_id] diff --git a/docs_src/response_status_code/tutorial001_py310.py b/docs_src/response_status_code/tutorial001_py310.py new file mode 100644 index 000000000..14b6d6e67 --- /dev/null +++ b/docs_src/response_status_code/tutorial001_py310.py @@ -0,0 +1,8 @@ +from fastapi import FastAPI + +app = FastAPI() + + +@app.post("/items/", status_code=201) +async def create_item(name: str): + return {"name": name} diff --git a/docs_src/response_status_code/tutorial002_py310.py b/docs_src/response_status_code/tutorial002_py310.py new file mode 100644 index 000000000..4fcc9829d --- /dev/null +++ b/docs_src/response_status_code/tutorial002_py310.py @@ -0,0 +1,8 @@ +from fastapi import FastAPI, status + +app = FastAPI() + + +@app.post("/items/", status_code=status.HTTP_201_CREATED) +async def create_item(name: str): + return {"name": name} diff --git a/docs_src/schema_extra_example/tutorial001_pv1_py310.py b/docs_src/schema_extra_example/tutorial001_pv1_py310.py deleted file mode 100644 index b13b8a8c2..000000000 --- a/docs_src/schema_extra_example/tutorial001_pv1_py310.py +++ /dev/null @@ -1,29 +0,0 @@ -from fastapi import FastAPI -from pydantic.v1 import BaseModel - -app = FastAPI() - - -class Item(BaseModel): - name: str - description: str | None = None - price: float - tax: float | None = None - - class Config: - schema_extra = { - "examples": [ - { - "name": "Foo", - "description": "A very nice Item", - "price": 35.4, - "tax": 3.2, - } - ] - } - - -@app.put("/items/{item_id}") -async def update_item(item_id: int, item: Item): - results = {"item_id": item_id, "item": item} - return results diff --git a/docs_src/schema_extra_example/tutorial001_pv1_py39.py b/docs_src/schema_extra_example/tutorial001_pv1_py39.py deleted file mode 100644 index 3240b35d6..000000000 --- a/docs_src/schema_extra_example/tutorial001_pv1_py39.py +++ /dev/null @@ -1,31 +0,0 @@ -from typing import Union - -from fastapi import FastAPI -from pydantic.v1 import BaseModel - -app = FastAPI() - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: Union[float, None] = None - - class Config: - schema_extra = { - "examples": [ - { - "name": "Foo", - "description": "A very nice Item", - "price": 35.4, - "tax": 3.2, - } - ] - } - - -@app.put("/items/{item_id}") -async def update_item(item_id: int, item: Item): - results = {"item_id": item_id, "item": item} - return results diff --git a/docs_src/schema_extra_example/tutorial001_py39.py b/docs_src/schema_extra_example/tutorial001_py39.py deleted file mode 100644 index 32a66db3a..000000000 --- a/docs_src/schema_extra_example/tutorial001_py39.py +++ /dev/null @@ -1,32 +0,0 @@ -from typing import Union - -from fastapi import FastAPI -from pydantic import BaseModel - -app = FastAPI() - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: Union[float, None] = None - - model_config = { - "json_schema_extra": { - "examples": [ - { - "name": "Foo", - "description": "A very nice Item", - "price": 35.4, - "tax": 3.2, - } - ] - } - } - - -@app.put("/items/{item_id}") -async def update_item(item_id: int, item: Item): - results = {"item_id": item_id, "item": item} - return results diff --git a/docs_src/schema_extra_example/tutorial002_py39.py b/docs_src/schema_extra_example/tutorial002_py39.py deleted file mode 100644 index 70f06567c..000000000 --- a/docs_src/schema_extra_example/tutorial002_py39.py +++ /dev/null @@ -1,19 +0,0 @@ -from typing import Union - -from fastapi import FastAPI -from pydantic import BaseModel, Field - -app = FastAPI() - - -class Item(BaseModel): - name: str = Field(examples=["Foo"]) - description: Union[str, None] = Field(default=None, examples=["A very nice Item"]) - price: float = Field(examples=[35.4]) - tax: Union[float, None] = Field(default=None, examples=[3.2]) - - -@app.put("/items/{item_id}") -async def update_item(item_id: int, item: Item): - results = {"item_id": item_id, "item": item} - return results diff --git a/docs_src/schema_extra_example/tutorial003_an_py39.py b/docs_src/schema_extra_example/tutorial003_an_py39.py deleted file mode 100644 index 472808561..000000000 --- a/docs_src/schema_extra_example/tutorial003_an_py39.py +++ /dev/null @@ -1,34 +0,0 @@ -from typing import Annotated, Union - -from fastapi import Body, FastAPI -from pydantic import BaseModel - -app = FastAPI() - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: Union[float, None] = None - - -@app.put("/items/{item_id}") -async def update_item( - item_id: int, - item: Annotated[ - Item, - Body( - examples=[ - { - "name": "Foo", - "description": "A very nice Item", - "price": 35.4, - "tax": 3.2, - } - ], - ), - ], -): - results = {"item_id": item_id, "item": item} - return results diff --git a/docs_src/schema_extra_example/tutorial003_py39.py b/docs_src/schema_extra_example/tutorial003_py39.py deleted file mode 100644 index 385f3de8a..000000000 --- a/docs_src/schema_extra_example/tutorial003_py39.py +++ /dev/null @@ -1,31 +0,0 @@ -from typing import Union - -from fastapi import Body, FastAPI -from pydantic import BaseModel - -app = FastAPI() - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: Union[float, None] = None - - -@app.put("/items/{item_id}") -async def update_item( - item_id: int, - item: Item = Body( - examples=[ - { - "name": "Foo", - "description": "A very nice Item", - "price": 35.4, - "tax": 3.2, - } - ], - ), -): - results = {"item_id": item_id, "item": item} - return results diff --git a/docs_src/schema_extra_example/tutorial004_an_py39.py b/docs_src/schema_extra_example/tutorial004_an_py39.py deleted file mode 100644 index dc5a8fe49..000000000 --- a/docs_src/schema_extra_example/tutorial004_an_py39.py +++ /dev/null @@ -1,43 +0,0 @@ -from typing import Annotated, Union - -from fastapi import Body, FastAPI -from pydantic import BaseModel - -app = FastAPI() - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: Union[float, None] = None - - -@app.put("/items/{item_id}") -async def update_item( - *, - item_id: int, - item: Annotated[ - Item, - Body( - examples=[ - { - "name": "Foo", - "description": "A very nice Item", - "price": 35.4, - "tax": 3.2, - }, - { - "name": "Bar", - "price": "35.4", - }, - { - "name": "Baz", - "price": "thirty five point four", - }, - ], - ), - ], -): - results = {"item_id": item_id, "item": item} - return results diff --git a/docs_src/schema_extra_example/tutorial004_py39.py b/docs_src/schema_extra_example/tutorial004_py39.py deleted file mode 100644 index 75514a3e9..000000000 --- a/docs_src/schema_extra_example/tutorial004_py39.py +++ /dev/null @@ -1,40 +0,0 @@ -from typing import Union - -from fastapi import Body, FastAPI -from pydantic import BaseModel - -app = FastAPI() - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: Union[float, None] = None - - -@app.put("/items/{item_id}") -async def update_item( - *, - item_id: int, - item: Item = Body( - examples=[ - { - "name": "Foo", - "description": "A very nice Item", - "price": 35.4, - "tax": 3.2, - }, - { - "name": "Bar", - "price": "35.4", - }, - { - "name": "Baz", - "price": "thirty five point four", - }, - ], - ), -): - results = {"item_id": item_id, "item": item} - return results diff --git a/docs_src/schema_extra_example/tutorial005_an_py39.py b/docs_src/schema_extra_example/tutorial005_an_py39.py deleted file mode 100644 index edeb1affc..000000000 --- a/docs_src/schema_extra_example/tutorial005_an_py39.py +++ /dev/null @@ -1,54 +0,0 @@ -from typing import Annotated, Union - -from fastapi import Body, FastAPI -from pydantic import BaseModel - -app = FastAPI() - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: Union[float, None] = None - - -@app.put("/items/{item_id}") -async def update_item( - *, - item_id: int, - item: Annotated[ - Item, - Body( - openapi_examples={ - "normal": { - "summary": "A normal example", - "description": "A **normal** item works correctly.", - "value": { - "name": "Foo", - "description": "A very nice Item", - "price": 35.4, - "tax": 3.2, - }, - }, - "converted": { - "summary": "An example with converted data", - "description": "FastAPI can convert price `strings` to actual `numbers` automatically", - "value": { - "name": "Bar", - "price": "35.4", - }, - }, - "invalid": { - "summary": "Invalid data is rejected with an error", - "value": { - "name": "Baz", - "price": "thirty five point four", - }, - }, - }, - ), - ], -): - results = {"item_id": item_id, "item": item} - return results diff --git a/docs_src/schema_extra_example/tutorial005_py39.py b/docs_src/schema_extra_example/tutorial005_py39.py deleted file mode 100644 index b8217c27e..000000000 --- a/docs_src/schema_extra_example/tutorial005_py39.py +++ /dev/null @@ -1,51 +0,0 @@ -from typing import Union - -from fastapi import Body, FastAPI -from pydantic import BaseModel - -app = FastAPI() - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: Union[float, None] = None - - -@app.put("/items/{item_id}") -async def update_item( - *, - item_id: int, - item: Item = Body( - openapi_examples={ - "normal": { - "summary": "A normal example", - "description": "A **normal** item works correctly.", - "value": { - "name": "Foo", - "description": "A very nice Item", - "price": 35.4, - "tax": 3.2, - }, - }, - "converted": { - "summary": "An example with converted data", - "description": "FastAPI can convert price `strings` to actual `numbers` automatically", - "value": { - "name": "Bar", - "price": "35.4", - }, - }, - "invalid": { - "summary": "Invalid data is rejected with an error", - "value": { - "name": "Baz", - "price": "thirty five point four", - }, - }, - }, - ), -): - results = {"item_id": item_id, "item": item} - return results diff --git a/docs_src/security/tutorial001_an_py310.py b/docs_src/security/tutorial001_an_py310.py new file mode 100644 index 000000000..de110402e --- /dev/null +++ b/docs_src/security/tutorial001_an_py310.py @@ -0,0 +1,13 @@ +from typing import Annotated + +from fastapi import Depends, FastAPI +from fastapi.security import OAuth2PasswordBearer + +app = FastAPI() + +oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token") + + +@app.get("/items/") +async def read_items(token: Annotated[str, Depends(oauth2_scheme)]): + return {"token": token} diff --git a/docs_src/security/tutorial001_py310.py b/docs_src/security/tutorial001_py310.py new file mode 100644 index 000000000..224e59602 --- /dev/null +++ b/docs_src/security/tutorial001_py310.py @@ -0,0 +1,11 @@ +from fastapi import Depends, FastAPI +from fastapi.security import OAuth2PasswordBearer + +app = FastAPI() + +oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token") + + +@app.get("/items/") +async def read_items(token: str = Depends(oauth2_scheme)): + return {"token": token} diff --git a/docs_src/security/tutorial002_an_py39.py b/docs_src/security/tutorial002_an_py39.py deleted file mode 100644 index 7ff1c470b..000000000 --- a/docs_src/security/tutorial002_an_py39.py +++ /dev/null @@ -1,32 +0,0 @@ -from typing import Annotated, Union - -from fastapi import Depends, FastAPI -from fastapi.security import OAuth2PasswordBearer -from pydantic import BaseModel - -app = FastAPI() - -oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token") - - -class User(BaseModel): - username: str - email: Union[str, None] = None - full_name: Union[str, None] = None - disabled: Union[bool, None] = None - - -def fake_decode_token(token): - return User( - username=token + "fakedecoded", email="john@example.com", full_name="John Doe" - ) - - -async def get_current_user(token: Annotated[str, Depends(oauth2_scheme)]): - user = fake_decode_token(token) - return user - - -@app.get("/users/me") -async def read_users_me(current_user: Annotated[User, Depends(get_current_user)]): - return current_user diff --git a/docs_src/security/tutorial002_py39.py b/docs_src/security/tutorial002_py39.py deleted file mode 100644 index bfd035221..000000000 --- a/docs_src/security/tutorial002_py39.py +++ /dev/null @@ -1,32 +0,0 @@ -from typing import Union - -from fastapi import Depends, FastAPI -from fastapi.security import OAuth2PasswordBearer -from pydantic import BaseModel - -app = FastAPI() - -oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token") - - -class User(BaseModel): - username: str - email: Union[str, None] = None - full_name: Union[str, None] = None - disabled: Union[bool, None] = None - - -def fake_decode_token(token): - return User( - username=token + "fakedecoded", email="john@example.com", full_name="John Doe" - ) - - -async def get_current_user(token: str = Depends(oauth2_scheme)): - user = fake_decode_token(token) - return user - - -@app.get("/users/me") -async def read_users_me(current_user: User = Depends(get_current_user)): - return current_user diff --git a/docs_src/security/tutorial003_an_py39.py b/docs_src/security/tutorial003_an_py39.py deleted file mode 100644 index b396210c8..000000000 --- a/docs_src/security/tutorial003_an_py39.py +++ /dev/null @@ -1,94 +0,0 @@ -from typing import Annotated, Union - -from fastapi import Depends, FastAPI, HTTPException, status -from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm -from pydantic import BaseModel - -fake_users_db = { - "johndoe": { - "username": "johndoe", - "full_name": "John Doe", - "email": "johndoe@example.com", - "hashed_password": "fakehashedsecret", - "disabled": False, - }, - "alice": { - "username": "alice", - "full_name": "Alice Wonderson", - "email": "alice@example.com", - "hashed_password": "fakehashedsecret2", - "disabled": True, - }, -} - -app = FastAPI() - - -def fake_hash_password(password: str): - return "fakehashed" + password - - -oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token") - - -class User(BaseModel): - username: str - email: Union[str, None] = None - full_name: Union[str, None] = None - disabled: Union[bool, None] = None - - -class UserInDB(User): - hashed_password: str - - -def get_user(db, username: str): - if username in db: - user_dict = db[username] - return UserInDB(**user_dict) - - -def fake_decode_token(token): - # This doesn't provide any security at all - # Check the next version - user = get_user(fake_users_db, token) - return user - - -async def get_current_user(token: Annotated[str, Depends(oauth2_scheme)]): - user = fake_decode_token(token) - if not user: - raise HTTPException( - status_code=status.HTTP_401_UNAUTHORIZED, - detail="Not authenticated", - headers={"WWW-Authenticate": "Bearer"}, - ) - return user - - -async def get_current_active_user( - current_user: Annotated[User, Depends(get_current_user)], -): - if current_user.disabled: - raise HTTPException(status_code=400, detail="Inactive user") - return current_user - - -@app.post("/token") -async def login(form_data: Annotated[OAuth2PasswordRequestForm, Depends()]): - user_dict = fake_users_db.get(form_data.username) - if not user_dict: - raise HTTPException(status_code=400, detail="Incorrect username or password") - user = UserInDB(**user_dict) - hashed_password = fake_hash_password(form_data.password) - if not hashed_password == user.hashed_password: - raise HTTPException(status_code=400, detail="Incorrect username or password") - - return {"access_token": user.username, "token_type": "bearer"} - - -@app.get("/users/me") -async def read_users_me( - current_user: Annotated[User, Depends(get_current_active_user)], -): - return current_user diff --git a/docs_src/security/tutorial003_py39.py b/docs_src/security/tutorial003_py39.py deleted file mode 100644 index ce7a71b68..000000000 --- a/docs_src/security/tutorial003_py39.py +++ /dev/null @@ -1,90 +0,0 @@ -from typing import Union - -from fastapi import Depends, FastAPI, HTTPException, status -from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm -from pydantic import BaseModel - -fake_users_db = { - "johndoe": { - "username": "johndoe", - "full_name": "John Doe", - "email": "johndoe@example.com", - "hashed_password": "fakehashedsecret", - "disabled": False, - }, - "alice": { - "username": "alice", - "full_name": "Alice Wonderson", - "email": "alice@example.com", - "hashed_password": "fakehashedsecret2", - "disabled": True, - }, -} - -app = FastAPI() - - -def fake_hash_password(password: str): - return "fakehashed" + password - - -oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token") - - -class User(BaseModel): - username: str - email: Union[str, None] = None - full_name: Union[str, None] = None - disabled: Union[bool, None] = None - - -class UserInDB(User): - hashed_password: str - - -def get_user(db, username: str): - if username in db: - user_dict = db[username] - return UserInDB(**user_dict) - - -def fake_decode_token(token): - # This doesn't provide any security at all - # Check the next version - user = get_user(fake_users_db, token) - return user - - -async def get_current_user(token: str = Depends(oauth2_scheme)): - user = fake_decode_token(token) - if not user: - raise HTTPException( - status_code=status.HTTP_401_UNAUTHORIZED, - detail="Not authenticated", - headers={"WWW-Authenticate": "Bearer"}, - ) - return user - - -async def get_current_active_user(current_user: User = Depends(get_current_user)): - if current_user.disabled: - raise HTTPException(status_code=400, detail="Inactive user") - return current_user - - -@app.post("/token") -async def login(form_data: OAuth2PasswordRequestForm = Depends()): - user_dict = fake_users_db.get(form_data.username) - if not user_dict: - raise HTTPException(status_code=400, detail="Incorrect username or password") - user = UserInDB(**user_dict) - hashed_password = fake_hash_password(form_data.password) - if not hashed_password == user.hashed_password: - raise HTTPException(status_code=400, detail="Incorrect username or password") - - return {"access_token": user.username, "token_type": "bearer"} - - -@app.get("/users/me") -async def read_users_me(current_user: User = Depends(get_current_active_user)): - return current_user diff --git a/docs_src/security/tutorial004_an_py39.py b/docs_src/security/tutorial004_an_py39.py deleted file mode 100644 index 73b3d456d..000000000 --- a/docs_src/security/tutorial004_an_py39.py +++ /dev/null @@ -1,147 +0,0 @@ -from datetime import datetime, timedelta, timezone -from typing import Annotated, Union - -import jwt -from fastapi import Depends, FastAPI, HTTPException, status -from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm -from jwt.exceptions import InvalidTokenError -from pwdlib import PasswordHash -from pydantic import BaseModel - -# to get a string like this run: -# openssl rand -hex 32 -SECRET_KEY = "09d25e094faa6ca2556c818166b7a9563b93f7099f6f0f4caa6cf63b88e8d3e7" -ALGORITHM = "HS256" -ACCESS_TOKEN_EXPIRE_MINUTES = 30 - - -fake_users_db = { - "johndoe": { - "username": "johndoe", - "full_name": "John Doe", - "email": "johndoe@example.com", - "hashed_password": "$argon2id$v=19$m=65536,t=3,p=4$wagCPXjifgvUFBzq4hqe3w$CYaIb8sB+wtD+Vu/P4uod1+Qof8h+1g7bbDlBID48Rc", - "disabled": False, - } -} - - -class Token(BaseModel): - access_token: str - token_type: str - - -class TokenData(BaseModel): - username: Union[str, None] = None - - -class User(BaseModel): - username: str - email: Union[str, None] = None - full_name: Union[str, None] = None - disabled: Union[bool, None] = None - - -class UserInDB(User): - hashed_password: str - - -password_hash = PasswordHash.recommended() - -oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token") - -app = FastAPI() - - -def verify_password(plain_password, hashed_password): - return password_hash.verify(plain_password, hashed_password) - - -def get_password_hash(password): - return password_hash.hash(password) - - -def get_user(db, username: str): - if username in db: - user_dict = db[username] - return UserInDB(**user_dict) - - -def authenticate_user(fake_db, username: str, password: str): - user = get_user(fake_db, username) - if not user: - return False - if not verify_password(password, user.hashed_password): - return False - return user - - -def create_access_token(data: dict, expires_delta: Union[timedelta, None] = None): - to_encode = data.copy() - if expires_delta: - expire = datetime.now(timezone.utc) + expires_delta - else: - expire = datetime.now(timezone.utc) + timedelta(minutes=15) - to_encode.update({"exp": expire}) - encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM) - return encoded_jwt - - -async def get_current_user(token: Annotated[str, Depends(oauth2_scheme)]): - credentials_exception = HTTPException( - status_code=status.HTTP_401_UNAUTHORIZED, - detail="Could not validate credentials", - headers={"WWW-Authenticate": "Bearer"}, - ) - try: - payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM]) - username = payload.get("sub") - if username is None: - raise credentials_exception - token_data = TokenData(username=username) - except InvalidTokenError: - raise credentials_exception - user = get_user(fake_users_db, username=token_data.username) - if user is None: - raise credentials_exception - return user - - -async def get_current_active_user( - current_user: Annotated[User, Depends(get_current_user)], -): - if current_user.disabled: - raise HTTPException(status_code=400, detail="Inactive user") - return current_user - - -@app.post("/token") -async def login_for_access_token( - form_data: Annotated[OAuth2PasswordRequestForm, Depends()], -) -> Token: - user = authenticate_user(fake_users_db, form_data.username, form_data.password) - if not user: - raise HTTPException( - status_code=status.HTTP_401_UNAUTHORIZED, - detail="Incorrect username or password", - headers={"WWW-Authenticate": "Bearer"}, - ) - access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES) - access_token = create_access_token( - data={"sub": user.username}, expires_delta=access_token_expires - ) - return Token(access_token=access_token, token_type="bearer") - - -@app.get("/users/me/") -async def read_users_me( - current_user: Annotated[User, Depends(get_current_active_user)], -) -> User: - return current_user - - -@app.get("/users/me/items/") -async def read_own_items( - current_user: Annotated[User, Depends(get_current_active_user)], -): - return [{"item_id": "Foo", "owner": current_user.username}] diff --git a/docs_src/security/tutorial004_py39.py b/docs_src/security/tutorial004_py39.py deleted file mode 100644 index e67403d5d..000000000 --- a/docs_src/security/tutorial004_py39.py +++ /dev/null @@ -1,141 +0,0 @@ -from datetime import datetime, timedelta, timezone -from typing import Union - -import jwt -from fastapi import Depends, FastAPI, HTTPException, status -from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm -from jwt.exceptions import InvalidTokenError -from pwdlib import PasswordHash -from pydantic import BaseModel - -# to get a string like this run: -# openssl rand -hex 32 -SECRET_KEY = "09d25e094faa6ca2556c818166b7a9563b93f7099f6f0f4caa6cf63b88e8d3e7" -ALGORITHM = "HS256" -ACCESS_TOKEN_EXPIRE_MINUTES = 30 - - -fake_users_db = { - "johndoe": { - "username": "johndoe", - "full_name": "John Doe", - "email": "johndoe@example.com", - "hashed_password": "$argon2id$v=19$m=65536,t=3,p=4$wagCPXjifgvUFBzq4hqe3w$CYaIb8sB+wtD+Vu/P4uod1+Qof8h+1g7bbDlBID48Rc", - "disabled": False, - } -} - - -class Token(BaseModel): - access_token: str - token_type: str - - -class TokenData(BaseModel): - username: Union[str, None] = None - - -class User(BaseModel): - username: str - email: Union[str, None] = None - full_name: Union[str, None] = None - disabled: Union[bool, None] = None - - -class UserInDB(User): - hashed_password: str - - -password_hash = PasswordHash.recommended() - -oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token") - -app = FastAPI() - - -def verify_password(plain_password, hashed_password): - return password_hash.verify(plain_password, hashed_password) - - -def get_password_hash(password): - return password_hash.hash(password) - - -def get_user(db, username: str): - if username in db: - user_dict = db[username] - return UserInDB(**user_dict) - - -def authenticate_user(fake_db, username: str, password: str): - user = get_user(fake_db, username) - if not user: - return False - if not verify_password(password, user.hashed_password): - return False - return user - - -def create_access_token(data: dict, expires_delta: Union[timedelta, None] = None): - to_encode = data.copy() - if expires_delta: - expire = datetime.now(timezone.utc) + expires_delta - else: - expire = datetime.now(timezone.utc) + timedelta(minutes=15) - to_encode.update({"exp": expire}) - encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM) - return encoded_jwt - - -async def get_current_user(token: str = Depends(oauth2_scheme)): - credentials_exception = HTTPException( - status_code=status.HTTP_401_UNAUTHORIZED, - detail="Could not validate credentials", - headers={"WWW-Authenticate": "Bearer"}, - ) - try: - payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM]) - username = payload.get("sub") - if username is None: - raise credentials_exception - token_data = TokenData(username=username) - except InvalidTokenError: - raise credentials_exception - user = get_user(fake_users_db, username=token_data.username) - if user is None: - raise credentials_exception - return user - - -async def get_current_active_user(current_user: User = Depends(get_current_user)): - if current_user.disabled: - raise HTTPException(status_code=400, detail="Inactive user") - return current_user - - -@app.post("/token") -async def login_for_access_token( - form_data: OAuth2PasswordRequestForm = Depends(), -) -> Token: - user = authenticate_user(fake_users_db, form_data.username, form_data.password) - if not user: - raise HTTPException( - status_code=status.HTTP_401_UNAUTHORIZED, - detail="Incorrect username or password", - headers={"WWW-Authenticate": "Bearer"}, - ) - access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES) - access_token = create_access_token( - data={"sub": user.username}, expires_delta=access_token_expires - ) - return Token(access_token=access_token, token_type="bearer") - - -@app.get("/users/me/") -async def read_users_me(current_user: User = Depends(get_current_active_user)) -> User: - return current_user - - -@app.get("/users/me/items/") -async def read_own_items(current_user: User = Depends(get_current_active_user)): - return [{"item_id": "Foo", "owner": current_user.username}] diff --git a/docs_src/security/tutorial005_an_py39.py b/docs_src/security/tutorial005_an_py39.py deleted file mode 100644 index 1aeba688a..000000000 --- a/docs_src/security/tutorial005_an_py39.py +++ /dev/null @@ -1,179 +0,0 @@ -from datetime import datetime, timedelta, timezone -from typing import Annotated, Union - -import jwt -from fastapi import Depends, FastAPI, HTTPException, Security, status -from fastapi.security import ( - OAuth2PasswordBearer, - OAuth2PasswordRequestForm, - SecurityScopes, -) -from jwt.exceptions import InvalidTokenError -from pwdlib import PasswordHash -from pydantic import BaseModel, ValidationError - -# to get a string like this run: -# openssl rand -hex 32 -SECRET_KEY = "09d25e094faa6ca2556c818166b7a9563b93f7099f6f0f4caa6cf63b88e8d3e7" -ALGORITHM = "HS256" -ACCESS_TOKEN_EXPIRE_MINUTES = 30 - - -fake_users_db = { - "johndoe": { - "username": "johndoe", - "full_name": "John Doe", - "email": "johndoe@example.com", - "hashed_password": "$argon2id$v=19$m=65536,t=3,p=4$wagCPXjifgvUFBzq4hqe3w$CYaIb8sB+wtD+Vu/P4uod1+Qof8h+1g7bbDlBID48Rc", - "disabled": False, - }, - "alice": { - "username": "alice", - "full_name": "Alice Chains", - "email": "alicechains@example.com", - "hashed_password": "$argon2id$v=19$m=65536,t=3,p=4$g2/AV1zwopqUntPKJavBFw$BwpRGDCyUHLvHICnwijyX8ROGoiUPwNKZ7915MeYfCE", - "disabled": True, - }, -} - - -class Token(BaseModel): - access_token: str - token_type: str - - -class TokenData(BaseModel): - username: Union[str, None] = None - scopes: list[str] = [] - - -class User(BaseModel): - username: str - email: Union[str, None] = None - full_name: Union[str, None] = None - disabled: Union[bool, None] = None - - -class UserInDB(User): - hashed_password: str - - -password_hash = PasswordHash.recommended() - -oauth2_scheme = OAuth2PasswordBearer( - tokenUrl="token", - scopes={"me": "Read information about the current user.", "items": "Read items."}, -) - -app = FastAPI() - - -def verify_password(plain_password, hashed_password): - return password_hash.verify(plain_password, hashed_password) - - -def get_password_hash(password): - return password_hash.hash(password) - - -def get_user(db, username: str): - if username in db: - user_dict = db[username] - return UserInDB(**user_dict) - - -def authenticate_user(fake_db, username: str, password: str): - user = get_user(fake_db, username) - if not user: - return False - if not verify_password(password, user.hashed_password): - return False - return user - - -def create_access_token(data: dict, expires_delta: Union[timedelta, None] = None): - to_encode = data.copy() - if expires_delta: - expire = datetime.now(timezone.utc) + expires_delta - else: - expire = datetime.now(timezone.utc) + timedelta(minutes=15) - to_encode.update({"exp": expire}) - encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM) - return encoded_jwt - - -async def get_current_user( - security_scopes: SecurityScopes, token: Annotated[str, Depends(oauth2_scheme)] -): - if security_scopes.scopes: - authenticate_value = f'Bearer scope="{security_scopes.scope_str}"' - else: - authenticate_value = "Bearer" - credentials_exception = HTTPException( - status_code=status.HTTP_401_UNAUTHORIZED, - detail="Could not validate credentials", - headers={"WWW-Authenticate": authenticate_value}, - ) - try: - payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM]) - username = payload.get("sub") - if username is None: - raise credentials_exception - scope: str = payload.get("scope", "") - token_scopes = scope.split(" ") - token_data = TokenData(scopes=token_scopes, username=username) - except (InvalidTokenError, ValidationError): - raise credentials_exception - user = get_user(fake_users_db, username=token_data.username) - if user is None: - raise credentials_exception - for scope in security_scopes.scopes: - if scope not in token_data.scopes: - raise HTTPException( - status_code=status.HTTP_401_UNAUTHORIZED, - detail="Not enough permissions", - headers={"WWW-Authenticate": authenticate_value}, - ) - return user - - -async def get_current_active_user( - current_user: Annotated[User, Security(get_current_user, scopes=["me"])], -): - if current_user.disabled: - raise HTTPException(status_code=400, detail="Inactive user") - return current_user - - -@app.post("/token") -async def login_for_access_token( - form_data: Annotated[OAuth2PasswordRequestForm, Depends()], -) -> Token: - user = authenticate_user(fake_users_db, form_data.username, form_data.password) - if not user: - raise HTTPException(status_code=400, detail="Incorrect username or password") - access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES) - access_token = create_access_token( - data={"sub": user.username, "scope": " ".join(form_data.scopes)}, - expires_delta=access_token_expires, - ) - return Token(access_token=access_token, token_type="bearer") - - -@app.get("/users/me/") -async def read_users_me( - current_user: Annotated[User, Depends(get_current_active_user)], -) -> User: - return current_user - - -@app.get("/users/me/items/") -async def read_own_items( - current_user: Annotated[User, Security(get_current_active_user, scopes=["items"])], -): - return [{"item_id": "Foo", "owner": current_user.username}] - - -@app.get("/status/") -async def read_system_status(current_user: Annotated[User, Depends(get_current_user)]): - return {"status": "ok"} diff --git a/docs_src/security/tutorial005_py39.py b/docs_src/security/tutorial005_py39.py deleted file mode 100644 index 32280aa48..000000000 --- a/docs_src/security/tutorial005_py39.py +++ /dev/null @@ -1,177 +0,0 @@ -from datetime import datetime, timedelta, timezone -from typing import Union - -import jwt -from fastapi import Depends, FastAPI, HTTPException, Security, status -from fastapi.security import ( - OAuth2PasswordBearer, - OAuth2PasswordRequestForm, - SecurityScopes, -) -from jwt.exceptions import InvalidTokenError -from pwdlib import PasswordHash -from pydantic import BaseModel, ValidationError - -# to get a string like this run: -# openssl rand -hex 32 -SECRET_KEY = "09d25e094faa6ca2556c818166b7a9563b93f7099f6f0f4caa6cf63b88e8d3e7" -ALGORITHM = "HS256" -ACCESS_TOKEN_EXPIRE_MINUTES = 30 - - -fake_users_db = { - "johndoe": { - "username": "johndoe", - "full_name": "John Doe", - "email": "johndoe@example.com", - "hashed_password": "$argon2id$v=19$m=65536,t=3,p=4$wagCPXjifgvUFBzq4hqe3w$CYaIb8sB+wtD+Vu/P4uod1+Qof8h+1g7bbDlBID48Rc", - "disabled": False, - }, - "alice": { - "username": "alice", - "full_name": "Alice Chains", - "email": "alicechains@example.com", - "hashed_password": "$argon2id$v=19$m=65536,t=3,p=4$g2/AV1zwopqUntPKJavBFw$BwpRGDCyUHLvHICnwijyX8ROGoiUPwNKZ7915MeYfCE", - "disabled": True, - }, -} - - -class Token(BaseModel): - access_token: str - token_type: str - - -class TokenData(BaseModel): - username: Union[str, None] = None - scopes: list[str] = [] - - -class User(BaseModel): - username: str - email: Union[str, None] = None - full_name: Union[str, None] = None - disabled: Union[bool, None] = None - - -class UserInDB(User): - hashed_password: str - - -password_hash = PasswordHash.recommended() - -oauth2_scheme = OAuth2PasswordBearer( - tokenUrl="token", - scopes={"me": "Read information about the current user.", "items": "Read items."}, -) - -app = FastAPI() - - -def verify_password(plain_password, hashed_password): - return password_hash.verify(plain_password, hashed_password) - - -def get_password_hash(password): - return password_hash.hash(password) - - -def get_user(db, username: str): - if username in db: - user_dict = db[username] - return UserInDB(**user_dict) - - -def authenticate_user(fake_db, username: str, password: str): - user = get_user(fake_db, username) - if not user: - return False - if not verify_password(password, user.hashed_password): - return False - return user - - -def create_access_token(data: dict, expires_delta: Union[timedelta, None] = None): - to_encode = data.copy() - if expires_delta: - expire = datetime.now(timezone.utc) + expires_delta - else: - expire = datetime.now(timezone.utc) + timedelta(minutes=15) - to_encode.update({"exp": expire}) - encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM) - return encoded_jwt - - -async def get_current_user( - security_scopes: SecurityScopes, token: str = Depends(oauth2_scheme) -): - if security_scopes.scopes: - authenticate_value = f'Bearer scope="{security_scopes.scope_str}"' - else: - authenticate_value = "Bearer" - credentials_exception = HTTPException( - status_code=status.HTTP_401_UNAUTHORIZED, - detail="Could not validate credentials", - headers={"WWW-Authenticate": authenticate_value}, - ) - try: - payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM]) - username: str = payload.get("sub") - if username is None: - raise credentials_exception - scope: str = payload.get("scope", "") - token_scopes = scope.split(" ") - token_data = TokenData(scopes=token_scopes, username=username) - except (InvalidTokenError, ValidationError): - raise credentials_exception - user = get_user(fake_users_db, username=token_data.username) - if user is None: - raise credentials_exception - for scope in security_scopes.scopes: - if scope not in token_data.scopes: - raise HTTPException( - status_code=status.HTTP_401_UNAUTHORIZED, - detail="Not enough permissions", - headers={"WWW-Authenticate": authenticate_value}, - ) - return user - - -async def get_current_active_user( - current_user: User = Security(get_current_user, scopes=["me"]), -): - if current_user.disabled: - raise HTTPException(status_code=400, detail="Inactive user") - return current_user - - -@app.post("/token") -async def login_for_access_token( - form_data: OAuth2PasswordRequestForm = Depends(), -) -> Token: - user = authenticate_user(fake_users_db, form_data.username, form_data.password) - if not user: - raise HTTPException(status_code=400, detail="Incorrect username or password") - access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES) - access_token = create_access_token( - data={"sub": user.username, "scope": " ".join(form_data.scopes)}, - expires_delta=access_token_expires, - ) - return Token(access_token=access_token, token_type="bearer") - - -@app.get("/users/me/") -async def read_users_me(current_user: User = Depends(get_current_active_user)) -> User: - return current_user - - -@app.get("/users/me/items/") -async def read_own_items( - current_user: User = Security(get_current_active_user, scopes=["items"]), -): - return [{"item_id": "Foo", "owner": current_user.username}] - - -@app.get("/status/") -async def read_system_status(current_user: User = Depends(get_current_user)): - return {"status": "ok"} diff --git a/docs_src/security/tutorial006_an_py310.py b/docs_src/security/tutorial006_an_py310.py new file mode 100644 index 000000000..03c696a4b --- /dev/null +++ b/docs_src/security/tutorial006_an_py310.py @@ -0,0 +1,13 @@ +from typing import Annotated + +from fastapi import Depends, FastAPI +from fastapi.security import HTTPBasic, HTTPBasicCredentials + +app = FastAPI() + +security = HTTPBasic() + + +@app.get("/users/me") +def read_current_user(credentials: Annotated[HTTPBasicCredentials, Depends(security)]): + return {"username": credentials.username, "password": credentials.password} diff --git a/docs_src/security/tutorial006_py310.py b/docs_src/security/tutorial006_py310.py new file mode 100644 index 000000000..29121ffd6 --- /dev/null +++ b/docs_src/security/tutorial006_py310.py @@ -0,0 +1,11 @@ +from fastapi import Depends, FastAPI +from fastapi.security import HTTPBasic, HTTPBasicCredentials + +app = FastAPI() + +security = HTTPBasic() + + +@app.get("/users/me") +def read_current_user(credentials: HTTPBasicCredentials = Depends(security)): + return {"username": credentials.username, "password": credentials.password} diff --git a/docs_src/security/tutorial007_an_py310.py b/docs_src/security/tutorial007_an_py310.py new file mode 100644 index 000000000..87ef98657 --- /dev/null +++ b/docs_src/security/tutorial007_an_py310.py @@ -0,0 +1,36 @@ +import secrets +from typing import Annotated + +from fastapi import Depends, FastAPI, HTTPException, status +from fastapi.security import HTTPBasic, HTTPBasicCredentials + +app = FastAPI() + +security = HTTPBasic() + + +def get_current_username( + credentials: Annotated[HTTPBasicCredentials, Depends(security)], +): + current_username_bytes = credentials.username.encode("utf8") + correct_username_bytes = b"stanleyjobson" + is_correct_username = secrets.compare_digest( + current_username_bytes, correct_username_bytes + ) + current_password_bytes = credentials.password.encode("utf8") + correct_password_bytes = b"swordfish" + is_correct_password = secrets.compare_digest( + current_password_bytes, correct_password_bytes + ) + if not (is_correct_username and is_correct_password): + raise HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, + detail="Incorrect username or password", + headers={"WWW-Authenticate": "Basic"}, + ) + return credentials.username + + +@app.get("/users/me") +def read_current_user(username: Annotated[str, Depends(get_current_username)]): + return {"username": username} diff --git a/docs_src/security/tutorial007_py310.py b/docs_src/security/tutorial007_py310.py new file mode 100644 index 000000000..ac816eb0c --- /dev/null +++ b/docs_src/security/tutorial007_py310.py @@ -0,0 +1,33 @@ +import secrets + +from fastapi import Depends, FastAPI, HTTPException, status +from fastapi.security import HTTPBasic, HTTPBasicCredentials + +app = FastAPI() + +security = HTTPBasic() + + +def get_current_username(credentials: HTTPBasicCredentials = Depends(security)): + current_username_bytes = credentials.username.encode("utf8") + correct_username_bytes = b"stanleyjobson" + is_correct_username = secrets.compare_digest( + current_username_bytes, correct_username_bytes + ) + current_password_bytes = credentials.password.encode("utf8") + correct_password_bytes = b"swordfish" + is_correct_password = secrets.compare_digest( + current_password_bytes, correct_password_bytes + ) + if not (is_correct_username and is_correct_password): + raise HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, + detail="Incorrect username or password", + headers={"WWW-Authenticate": "Basic"}, + ) + return credentials.username + + +@app.get("/users/me") +def read_current_user(username: str = Depends(get_current_username)): + return {"username": username} diff --git a/docs_src/separate_openapi_schemas/tutorial001_py39.py b/docs_src/separate_openapi_schemas/tutorial001_py39.py deleted file mode 100644 index 63cffd1e3..000000000 --- a/docs_src/separate_openapi_schemas/tutorial001_py39.py +++ /dev/null @@ -1,28 +0,0 @@ -from typing import Optional - -from fastapi import FastAPI -from pydantic import BaseModel - - -class Item(BaseModel): - name: str - description: Optional[str] = None - - -app = FastAPI() - - -@app.post("/items/") -def create_item(item: Item): - return item - - -@app.get("/items/") -def read_items() -> list[Item]: - return [ - Item( - name="Portal Gun", - description="Device to travel through the multi-rick-verse", - ), - Item(name="Plumbus"), - ] diff --git a/docs_src/separate_openapi_schemas/tutorial002_py39.py b/docs_src/separate_openapi_schemas/tutorial002_py39.py deleted file mode 100644 index 50d997d92..000000000 --- a/docs_src/separate_openapi_schemas/tutorial002_py39.py +++ /dev/null @@ -1,28 +0,0 @@ -from typing import Optional - -from fastapi import FastAPI -from pydantic import BaseModel - - -class Item(BaseModel): - name: str - description: Optional[str] = None - - -app = FastAPI(separate_input_output_schemas=False) - - -@app.post("/items/") -def create_item(item: Item): - return item - - -@app.get("/items/") -def read_items() -> list[Item]: - return [ - Item( - name="Portal Gun", - description="Device to travel through the multi-rick-verse", - ), - Item(name="Plumbus"), - ] diff --git a/docs_src/settings/app01_py310/__init__.py b/docs_src/settings/app01_py310/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/docs_src/settings/app03_an_py39/config_pv1.py b/docs_src/settings/app01_py310/config.py similarity index 59% rename from docs_src/settings/app03_an_py39/config_pv1.py rename to docs_src/settings/app01_py310/config.py index 7ae66ef77..b31b8811d 100644 --- a/docs_src/settings/app03_an_py39/config_pv1.py +++ b/docs_src/settings/app01_py310/config.py @@ -1,4 +1,4 @@ -from pydantic.v1 import BaseSettings +from pydantic_settings import BaseSettings class Settings(BaseSettings): @@ -6,5 +6,5 @@ class Settings(BaseSettings): admin_email: str items_per_user: int = 50 - class Config: - env_file = ".env" + +settings = Settings() diff --git a/docs_src/settings/app01_py310/main.py b/docs_src/settings/app01_py310/main.py new file mode 100644 index 000000000..4a3a86ce2 --- /dev/null +++ b/docs_src/settings/app01_py310/main.py @@ -0,0 +1,14 @@ +from fastapi import FastAPI + +from .config import settings + +app = FastAPI() + + +@app.get("/info") +async def info(): + return { + "app_name": settings.app_name, + "admin_email": settings.admin_email, + "items_per_user": settings.items_per_user, + } diff --git a/docs_src/settings/app02_an_py310/__init__.py b/docs_src/settings/app02_an_py310/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/docs_src/settings/app03_py39/config_pv1.py b/docs_src/settings/app02_an_py310/config.py similarity index 58% rename from docs_src/settings/app03_py39/config_pv1.py rename to docs_src/settings/app02_an_py310/config.py index 7ae66ef77..e17b5035d 100644 --- a/docs_src/settings/app03_py39/config_pv1.py +++ b/docs_src/settings/app02_an_py310/config.py @@ -1,10 +1,7 @@ -from pydantic.v1 import BaseSettings +from pydantic_settings import BaseSettings class Settings(BaseSettings): app_name: str = "Awesome API" admin_email: str items_per_user: int = 50 - - class Config: - env_file = ".env" diff --git a/docs_src/settings/app02_an_py310/main.py b/docs_src/settings/app02_an_py310/main.py new file mode 100644 index 000000000..6d5db12a8 --- /dev/null +++ b/docs_src/settings/app02_an_py310/main.py @@ -0,0 +1,22 @@ +from functools import lru_cache +from typing import Annotated + +from fastapi import Depends, FastAPI + +from .config import Settings + +app = FastAPI() + + +@lru_cache +def get_settings(): + return Settings() + + +@app.get("/info") +async def info(settings: Annotated[Settings, Depends(get_settings)]): + return { + "app_name": settings.app_name, + "admin_email": settings.admin_email, + "items_per_user": settings.items_per_user, + } diff --git a/docs_src/settings/app02_an_py310/test_main.py b/docs_src/settings/app02_an_py310/test_main.py new file mode 100644 index 000000000..7a04d7e8e --- /dev/null +++ b/docs_src/settings/app02_an_py310/test_main.py @@ -0,0 +1,23 @@ +from fastapi.testclient import TestClient + +from .config import Settings +from .main import app, get_settings + +client = TestClient(app) + + +def get_settings_override(): + return Settings(admin_email="testing_admin@example.com") + + +app.dependency_overrides[get_settings] = get_settings_override + + +def test_app(): + response = client.get("/info") + data = response.json() + assert data == { + "app_name": "Awesome API", + "admin_email": "testing_admin@example.com", + "items_per_user": 50, + } diff --git a/docs_src/settings/app02_py310/__init__.py b/docs_src/settings/app02_py310/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/docs_src/settings/app02_py310/config.py b/docs_src/settings/app02_py310/config.py new file mode 100644 index 000000000..e17b5035d --- /dev/null +++ b/docs_src/settings/app02_py310/config.py @@ -0,0 +1,7 @@ +from pydantic_settings import BaseSettings + + +class Settings(BaseSettings): + app_name: str = "Awesome API" + admin_email: str + items_per_user: int = 50 diff --git a/docs_src/settings/app02_py310/main.py b/docs_src/settings/app02_py310/main.py new file mode 100644 index 000000000..941f82e6b --- /dev/null +++ b/docs_src/settings/app02_py310/main.py @@ -0,0 +1,21 @@ +from functools import lru_cache + +from fastapi import Depends, FastAPI + +from .config import Settings + +app = FastAPI() + + +@lru_cache +def get_settings(): + return Settings() + + +@app.get("/info") +async def info(settings: Settings = Depends(get_settings)): + return { + "app_name": settings.app_name, + "admin_email": settings.admin_email, + "items_per_user": settings.items_per_user, + } diff --git a/docs_src/settings/app02_py310/test_main.py b/docs_src/settings/app02_py310/test_main.py new file mode 100644 index 000000000..7a04d7e8e --- /dev/null +++ b/docs_src/settings/app02_py310/test_main.py @@ -0,0 +1,23 @@ +from fastapi.testclient import TestClient + +from .config import Settings +from .main import app, get_settings + +client = TestClient(app) + + +def get_settings_override(): + return Settings(admin_email="testing_admin@example.com") + + +app.dependency_overrides[get_settings] = get_settings_override + + +def test_app(): + response = client.get("/info") + data = response.json() + assert data == { + "app_name": "Awesome API", + "admin_email": "testing_admin@example.com", + "items_per_user": 50, + } diff --git a/docs_src/settings/app03_an_py310/__init__.py b/docs_src/settings/app03_an_py310/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/docs_src/settings/app03_an_py310/config.py b/docs_src/settings/app03_an_py310/config.py new file mode 100644 index 000000000..08f8f88c2 --- /dev/null +++ b/docs_src/settings/app03_an_py310/config.py @@ -0,0 +1,9 @@ +from pydantic_settings import BaseSettings, SettingsConfigDict + + +class Settings(BaseSettings): + app_name: str = "Awesome API" + admin_email: str + items_per_user: int = 50 + + model_config = SettingsConfigDict(env_file=".env") diff --git a/docs_src/settings/app03_an_py310/main.py b/docs_src/settings/app03_an_py310/main.py new file mode 100644 index 000000000..2f64b9cd1 --- /dev/null +++ b/docs_src/settings/app03_an_py310/main.py @@ -0,0 +1,22 @@ +from functools import lru_cache +from typing import Annotated + +from fastapi import Depends, FastAPI + +from . import config + +app = FastAPI() + + +@lru_cache +def get_settings(): + return config.Settings() + + +@app.get("/info") +async def info(settings: Annotated[config.Settings, Depends(get_settings)]): + return { + "app_name": settings.app_name, + "admin_email": settings.admin_email, + "items_per_user": settings.items_per_user, + } diff --git a/docs_src/settings/app03_py310/__init__.py b/docs_src/settings/app03_py310/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/docs_src/settings/app03_py310/config.py b/docs_src/settings/app03_py310/config.py new file mode 100644 index 000000000..08f8f88c2 --- /dev/null +++ b/docs_src/settings/app03_py310/config.py @@ -0,0 +1,9 @@ +from pydantic_settings import BaseSettings, SettingsConfigDict + + +class Settings(BaseSettings): + app_name: str = "Awesome API" + admin_email: str + items_per_user: int = 50 + + model_config = SettingsConfigDict(env_file=".env") diff --git a/docs_src/settings/app03_py310/main.py b/docs_src/settings/app03_py310/main.py new file mode 100644 index 000000000..ea64a5709 --- /dev/null +++ b/docs_src/settings/app03_py310/main.py @@ -0,0 +1,21 @@ +from functools import lru_cache + +from fastapi import Depends, FastAPI + +from . import config + +app = FastAPI() + + +@lru_cache +def get_settings(): + return config.Settings() + + +@app.get("/info") +async def info(settings: config.Settings = Depends(get_settings)): + return { + "app_name": settings.app_name, + "admin_email": settings.admin_email, + "items_per_user": settings.items_per_user, + } diff --git a/docs_src/settings/tutorial001_pv1_py39.py b/docs_src/settings/tutorial001_py310.py similarity index 89% rename from docs_src/settings/tutorial001_pv1_py39.py rename to docs_src/settings/tutorial001_py310.py index 20ad2bbf6..d48c4c060 100644 --- a/docs_src/settings/tutorial001_pv1_py39.py +++ b/docs_src/settings/tutorial001_py310.py @@ -1,5 +1,5 @@ from fastapi import FastAPI -from pydantic.v1 import BaseSettings +from pydantic_settings import BaseSettings class Settings(BaseSettings): diff --git a/docs_src/sql_databases/tutorial001_an_py39.py b/docs_src/sql_databases/tutorial001_an_py39.py deleted file mode 100644 index 595892746..000000000 --- a/docs_src/sql_databases/tutorial001_an_py39.py +++ /dev/null @@ -1,73 +0,0 @@ -from typing import Annotated, Union - -from fastapi import Depends, FastAPI, HTTPException, Query -from sqlmodel import Field, Session, SQLModel, create_engine, select - - -class Hero(SQLModel, table=True): - id: Union[int, None] = Field(default=None, primary_key=True) - name: str = Field(index=True) - age: Union[int, None] = Field(default=None, index=True) - secret_name: str - - -sqlite_file_name = "database.db" -sqlite_url = f"sqlite:///{sqlite_file_name}" - -connect_args = {"check_same_thread": False} -engine = create_engine(sqlite_url, connect_args=connect_args) - - -def create_db_and_tables(): - SQLModel.metadata.create_all(engine) - - -def get_session(): - with Session(engine) as session: - yield session - - -SessionDep = Annotated[Session, Depends(get_session)] - -app = FastAPI() - - -@app.on_event("startup") -def on_startup(): - create_db_and_tables() - - -@app.post("/heroes/") -def create_hero(hero: Hero, session: SessionDep) -> Hero: - session.add(hero) - session.commit() - session.refresh(hero) - return hero - - -@app.get("/heroes/") -def read_heroes( - session: SessionDep, - offset: int = 0, - limit: Annotated[int, Query(le=100)] = 100, -) -> list[Hero]: - heroes = session.exec(select(Hero).offset(offset).limit(limit)).all() - return heroes - - -@app.get("/heroes/{hero_id}") -def read_hero(hero_id: int, session: SessionDep) -> Hero: - hero = session.get(Hero, hero_id) - if not hero: - raise HTTPException(status_code=404, detail="Hero not found") - return hero - - -@app.delete("/heroes/{hero_id}") -def delete_hero(hero_id: int, session: SessionDep): - hero = session.get(Hero, hero_id) - if not hero: - raise HTTPException(status_code=404, detail="Hero not found") - session.delete(hero) - session.commit() - return {"ok": True} diff --git a/docs_src/sql_databases/tutorial001_py39.py b/docs_src/sql_databases/tutorial001_py39.py deleted file mode 100644 index 410a52d0c..000000000 --- a/docs_src/sql_databases/tutorial001_py39.py +++ /dev/null @@ -1,71 +0,0 @@ -from typing import Union - -from fastapi import Depends, FastAPI, HTTPException, Query -from sqlmodel import Field, Session, SQLModel, create_engine, select - - -class Hero(SQLModel, table=True): - id: Union[int, None] = Field(default=None, primary_key=True) - name: str = Field(index=True) - age: Union[int, None] = Field(default=None, index=True) - secret_name: str - - -sqlite_file_name = "database.db" -sqlite_url = f"sqlite:///{sqlite_file_name}" - -connect_args = {"check_same_thread": False} -engine = create_engine(sqlite_url, connect_args=connect_args) - - -def create_db_and_tables(): - SQLModel.metadata.create_all(engine) - - -def get_session(): - with Session(engine) as session: - yield session - - -app = FastAPI() - - -@app.on_event("startup") -def on_startup(): - create_db_and_tables() - - -@app.post("/heroes/") -def create_hero(hero: Hero, session: Session = Depends(get_session)) -> Hero: - session.add(hero) - session.commit() - session.refresh(hero) - return hero - - -@app.get("/heroes/") -def read_heroes( - session: Session = Depends(get_session), - offset: int = 0, - limit: int = Query(default=100, le=100), -) -> list[Hero]: - heroes = session.exec(select(Hero).offset(offset).limit(limit)).all() - return heroes - - -@app.get("/heroes/{hero_id}") -def read_hero(hero_id: int, session: Session = Depends(get_session)) -> Hero: - hero = session.get(Hero, hero_id) - if not hero: - raise HTTPException(status_code=404, detail="Hero not found") - return hero - - -@app.delete("/heroes/{hero_id}") -def delete_hero(hero_id: int, session: Session = Depends(get_session)): - hero = session.get(Hero, hero_id) - if not hero: - raise HTTPException(status_code=404, detail="Hero not found") - session.delete(hero) - session.commit() - return {"ok": True} diff --git a/docs_src/sql_databases/tutorial002_an_py39.py b/docs_src/sql_databases/tutorial002_an_py39.py deleted file mode 100644 index a8a0721ff..000000000 --- a/docs_src/sql_databases/tutorial002_an_py39.py +++ /dev/null @@ -1,103 +0,0 @@ -from typing import Annotated, Union - -from fastapi import Depends, FastAPI, HTTPException, Query -from sqlmodel import Field, Session, SQLModel, create_engine, select - - -class HeroBase(SQLModel): - name: str = Field(index=True) - age: Union[int, None] = Field(default=None, index=True) - - -class Hero(HeroBase, table=True): - id: Union[int, None] = Field(default=None, primary_key=True) - secret_name: str - - -class HeroPublic(HeroBase): - id: int - - -class HeroCreate(HeroBase): - secret_name: str - - -class HeroUpdate(HeroBase): - name: Union[str, None] = None - age: Union[int, None] = None - secret_name: Union[str, None] = None - - -sqlite_file_name = "database.db" -sqlite_url = f"sqlite:///{sqlite_file_name}" - -connect_args = {"check_same_thread": False} -engine = create_engine(sqlite_url, connect_args=connect_args) - - -def create_db_and_tables(): - SQLModel.metadata.create_all(engine) - - -def get_session(): - with Session(engine) as session: - yield session - - -SessionDep = Annotated[Session, Depends(get_session)] -app = FastAPI() - - -@app.on_event("startup") -def on_startup(): - create_db_and_tables() - - -@app.post("/heroes/", response_model=HeroPublic) -def create_hero(hero: HeroCreate, session: SessionDep): - db_hero = Hero.model_validate(hero) - session.add(db_hero) - session.commit() - session.refresh(db_hero) - return db_hero - - -@app.get("/heroes/", response_model=list[HeroPublic]) -def read_heroes( - session: SessionDep, - offset: int = 0, - limit: Annotated[int, Query(le=100)] = 100, -): - heroes = session.exec(select(Hero).offset(offset).limit(limit)).all() - return heroes - - -@app.get("/heroes/{hero_id}", response_model=HeroPublic) -def read_hero(hero_id: int, session: SessionDep): - hero = session.get(Hero, hero_id) - if not hero: - raise HTTPException(status_code=404, detail="Hero not found") - return hero - - -@app.patch("/heroes/{hero_id}", response_model=HeroPublic) -def update_hero(hero_id: int, hero: HeroUpdate, session: SessionDep): - hero_db = session.get(Hero, hero_id) - if not hero_db: - raise HTTPException(status_code=404, detail="Hero not found") - hero_data = hero.model_dump(exclude_unset=True) - hero_db.sqlmodel_update(hero_data) - session.add(hero_db) - session.commit() - session.refresh(hero_db) - return hero_db - - -@app.delete("/heroes/{hero_id}") -def delete_hero(hero_id: int, session: SessionDep): - hero = session.get(Hero, hero_id) - if not hero: - raise HTTPException(status_code=404, detail="Hero not found") - session.delete(hero) - session.commit() - return {"ok": True} diff --git a/docs_src/sql_databases/tutorial002_py39.py b/docs_src/sql_databases/tutorial002_py39.py deleted file mode 100644 index d8f5dd090..000000000 --- a/docs_src/sql_databases/tutorial002_py39.py +++ /dev/null @@ -1,104 +0,0 @@ -from typing import Union - -from fastapi import Depends, FastAPI, HTTPException, Query -from sqlmodel import Field, Session, SQLModel, create_engine, select - - -class HeroBase(SQLModel): - name: str = Field(index=True) - age: Union[int, None] = Field(default=None, index=True) - - -class Hero(HeroBase, table=True): - id: Union[int, None] = Field(default=None, primary_key=True) - secret_name: str - - -class HeroPublic(HeroBase): - id: int - - -class HeroCreate(HeroBase): - secret_name: str - - -class HeroUpdate(HeroBase): - name: Union[str, None] = None - age: Union[int, None] = None - secret_name: Union[str, None] = None - - -sqlite_file_name = "database.db" -sqlite_url = f"sqlite:///{sqlite_file_name}" - -connect_args = {"check_same_thread": False} -engine = create_engine(sqlite_url, connect_args=connect_args) - - -def create_db_and_tables(): - SQLModel.metadata.create_all(engine) - - -def get_session(): - with Session(engine) as session: - yield session - - -app = FastAPI() - - -@app.on_event("startup") -def on_startup(): - create_db_and_tables() - - -@app.post("/heroes/", response_model=HeroPublic) -def create_hero(hero: HeroCreate, session: Session = Depends(get_session)): - db_hero = Hero.model_validate(hero) - session.add(db_hero) - session.commit() - session.refresh(db_hero) - return db_hero - - -@app.get("/heroes/", response_model=list[HeroPublic]) -def read_heroes( - session: Session = Depends(get_session), - offset: int = 0, - limit: int = Query(default=100, le=100), -): - heroes = session.exec(select(Hero).offset(offset).limit(limit)).all() - return heroes - - -@app.get("/heroes/{hero_id}", response_model=HeroPublic) -def read_hero(hero_id: int, session: Session = Depends(get_session)): - hero = session.get(Hero, hero_id) - if not hero: - raise HTTPException(status_code=404, detail="Hero not found") - return hero - - -@app.patch("/heroes/{hero_id}", response_model=HeroPublic) -def update_hero( - hero_id: int, hero: HeroUpdate, session: Session = Depends(get_session) -): - hero_db = session.get(Hero, hero_id) - if not hero_db: - raise HTTPException(status_code=404, detail="Hero not found") - hero_data = hero.model_dump(exclude_unset=True) - hero_db.sqlmodel_update(hero_data) - session.add(hero_db) - session.commit() - session.refresh(hero_db) - return hero_db - - -@app.delete("/heroes/{hero_id}") -def delete_hero(hero_id: int, session: Session = Depends(get_session)): - hero = session.get(Hero, hero_id) - if not hero: - raise HTTPException(status_code=404, detail="Hero not found") - session.delete(hero) - session.commit() - return {"ok": True} diff --git a/docs_src/static_files/tutorial001_py310.py b/docs_src/static_files/tutorial001_py310.py new file mode 100644 index 000000000..460352c7e --- /dev/null +++ b/docs_src/static_files/tutorial001_py310.py @@ -0,0 +1,6 @@ +from fastapi import FastAPI +from fastapi.staticfiles import StaticFiles + +app = FastAPI() + +app.mount("/static", StaticFiles(directory="static"), name="static") diff --git a/docs_src/sub_applications/tutorial001_py310.py b/docs_src/sub_applications/tutorial001_py310.py new file mode 100644 index 000000000..57e627e80 --- /dev/null +++ b/docs_src/sub_applications/tutorial001_py310.py @@ -0,0 +1,19 @@ +from fastapi import FastAPI + +app = FastAPI() + + +@app.get("/app") +def read_main(): + return {"message": "Hello World from main app"} + + +subapi = FastAPI() + + +@subapi.get("/sub") +def read_sub(): + return {"message": "Hello World from sub API"} + + +app.mount("/subapi", subapi) diff --git a/docs_src/templates/tutorial001_py310.py b/docs_src/templates/tutorial001_py310.py new file mode 100644 index 000000000..81ccc8d4d --- /dev/null +++ b/docs_src/templates/tutorial001_py310.py @@ -0,0 +1,18 @@ +from fastapi import FastAPI, Request +from fastapi.responses import HTMLResponse +from fastapi.staticfiles import StaticFiles +from fastapi.templating import Jinja2Templates + +app = FastAPI() + +app.mount("/static", StaticFiles(directory="static"), name="static") + + +templates = Jinja2Templates(directory="templates") + + +@app.get("/items/{id}", response_class=HTMLResponse) +async def read_item(request: Request, id: str): + return templates.TemplateResponse( + request=request, name="item.html", context={"id": id} + ) diff --git a/docs_src/using_request_directly/tutorial001_py310.py b/docs_src/using_request_directly/tutorial001_py310.py new file mode 100644 index 000000000..2d7288b54 --- /dev/null +++ b/docs_src/using_request_directly/tutorial001_py310.py @@ -0,0 +1,9 @@ +from fastapi import FastAPI, Request + +app = FastAPI() + + +@app.get("/items/{item_id}") +def read_root(item_id: str, request: Request): + client_host = request.client.host + return {"client_host": client_host, "item_id": item_id} diff --git a/docs_src/websockets/tutorial001_py310.py b/docs_src/websockets/tutorial001_py310.py new file mode 100644 index 000000000..a43a2be17 --- /dev/null +++ b/docs_src/websockets/tutorial001_py310.py @@ -0,0 +1,51 @@ +from fastapi import FastAPI, WebSocket +from fastapi.responses import HTMLResponse + +app = FastAPI() + +html = """ + + + + Chat + + +

WebSocket Chat

+
+ + +
+
    +
+ + + +""" + + +@app.get("/") +async def get(): + return HTMLResponse(html) + + +@app.websocket("/ws") +async def websocket_endpoint(websocket: WebSocket): + await websocket.accept() + while True: + data = await websocket.receive_text() + await websocket.send_text(f"Message text was: {data}") diff --git a/docs_src/websockets/tutorial002_an_py39.py b/docs_src/websockets/tutorial002_an_py39.py deleted file mode 100644 index 606d355fe..000000000 --- a/docs_src/websockets/tutorial002_an_py39.py +++ /dev/null @@ -1,92 +0,0 @@ -from typing import Annotated, Union - -from fastapi import ( - Cookie, - Depends, - FastAPI, - Query, - WebSocket, - WebSocketException, - status, -) -from fastapi.responses import HTMLResponse - -app = FastAPI() - -html = """ - - - - Chat - - -

WebSocket Chat

-
- - - -
- - -
-
    -
- - - -""" - - -@app.get("/") -async def get(): - return HTMLResponse(html) - - -async def get_cookie_or_token( - websocket: WebSocket, - session: Annotated[Union[str, None], Cookie()] = None, - token: Annotated[Union[str, None], Query()] = None, -): - if session is None and token is None: - raise WebSocketException(code=status.WS_1008_POLICY_VIOLATION) - return session or token - - -@app.websocket("/items/{item_id}/ws") -async def websocket_endpoint( - *, - websocket: WebSocket, - item_id: str, - q: Union[int, None] = None, - cookie_or_token: Annotated[str, Depends(get_cookie_or_token)], -): - await websocket.accept() - while True: - data = await websocket.receive_text() - await websocket.send_text( - f"Session cookie or query token value is: {cookie_or_token}" - ) - if q is not None: - await websocket.send_text(f"Query parameter q is: {q}") - await websocket.send_text(f"Message text was: {data}, for item ID: {item_id}") diff --git a/docs_src/websockets/tutorial002_py39.py b/docs_src/websockets/tutorial002_py39.py deleted file mode 100644 index cab749e4d..000000000 --- a/docs_src/websockets/tutorial002_py39.py +++ /dev/null @@ -1,91 +0,0 @@ -from typing import Union - -from fastapi import ( - Cookie, - Depends, - FastAPI, - Query, - WebSocket, - WebSocketException, - status, -) -from fastapi.responses import HTMLResponse - -app = FastAPI() - -html = """ - - - - Chat - - -

WebSocket Chat

-
- - - -
- - -
-
    -
- - - -""" - - -@app.get("/") -async def get(): - return HTMLResponse(html) - - -async def get_cookie_or_token( - websocket: WebSocket, - session: Union[str, None] = Cookie(default=None), - token: Union[str, None] = Query(default=None), -): - if session is None and token is None: - raise WebSocketException(code=status.WS_1008_POLICY_VIOLATION) - return session or token - - -@app.websocket("/items/{item_id}/ws") -async def websocket_endpoint( - websocket: WebSocket, - item_id: str, - q: Union[int, None] = None, - cookie_or_token: str = Depends(get_cookie_or_token), -): - await websocket.accept() - while True: - data = await websocket.receive_text() - await websocket.send_text( - f"Session cookie or query token value is: {cookie_or_token}" - ) - if q is not None: - await websocket.send_text(f"Query parameter q is: {q}") - await websocket.send_text(f"Message text was: {data}, for item ID: {item_id}") diff --git a/docs_src/websockets/tutorial003_py310.py b/docs_src/websockets/tutorial003_py310.py new file mode 100644 index 000000000..316218088 --- /dev/null +++ b/docs_src/websockets/tutorial003_py310.py @@ -0,0 +1,81 @@ +from fastapi import FastAPI, WebSocket, WebSocketDisconnect +from fastapi.responses import HTMLResponse + +app = FastAPI() + +html = """ + + + + Chat + + +

WebSocket Chat

+

Your ID:

+
+ + +
+
    +
+ + + +""" + + +class ConnectionManager: + def __init__(self): + self.active_connections: list[WebSocket] = [] + + async def connect(self, websocket: WebSocket): + await websocket.accept() + self.active_connections.append(websocket) + + def disconnect(self, websocket: WebSocket): + self.active_connections.remove(websocket) + + async def send_personal_message(self, message: str, websocket: WebSocket): + await websocket.send_text(message) + + async def broadcast(self, message: str): + for connection in self.active_connections: + await connection.send_text(message) + + +manager = ConnectionManager() + + +@app.get("/") +async def get(): + return HTMLResponse(html) + + +@app.websocket("/ws/{client_id}") +async def websocket_endpoint(websocket: WebSocket, client_id: int): + await manager.connect(websocket) + try: + while True: + data = await websocket.receive_text() + await manager.send_personal_message(f"You wrote: {data}", websocket) + await manager.broadcast(f"Client #{client_id} says: {data}") + except WebSocketDisconnect: + manager.disconnect(websocket) + await manager.broadcast(f"Client #{client_id} left the chat") diff --git a/docs_src/wsgi/tutorial001_py310.py b/docs_src/wsgi/tutorial001_py310.py new file mode 100644 index 000000000..8eeceb829 --- /dev/null +++ b/docs_src/wsgi/tutorial001_py310.py @@ -0,0 +1,23 @@ +from a2wsgi import WSGIMiddleware +from fastapi import FastAPI +from flask import Flask, request +from markupsafe import escape + +flask_app = Flask(__name__) + + +@flask_app.route("/") +def flask_main(): + name = request.args.get("name", "World") + return f"Hello, {escape(name)} from Flask!" + + +app = FastAPI() + + +@app.get("/v2") +def read_main(): + return {"message": "Hello World"} + + +app.mount("/v1", WSGIMiddleware(flask_app)) diff --git a/pyproject.toml b/pyproject.toml index e1ce30507..1e6fda3b1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -285,20 +285,205 @@ omit = [ "docs_src/dependencies/tutorial014_an_py310.py", # temporary code example? # Pydantic v1 migration, no longer tested "docs_src/pydantic_v1_in_v2/tutorial001_an_py310.py", - "docs_src/pydantic_v1_in_v2/tutorial001_an_py39.py", "docs_src/pydantic_v1_in_v2/tutorial002_an_py310.py", - "docs_src/pydantic_v1_in_v2/tutorial002_an_py39.py", "docs_src/pydantic_v1_in_v2/tutorial003_an_py310.py", - "docs_src/pydantic_v1_in_v2/tutorial003_an_py39.py", "docs_src/pydantic_v1_in_v2/tutorial004_an_py310.py", - "docs_src/pydantic_v1_in_v2/tutorial004_an_py39.py", - # TODO: remove when removing this file, after updating translations, Pydantic v1 - "docs_src/schema_extra_example/tutorial001_pv1_py310.py", - "docs_src/schema_extra_example/tutorial001_pv1_py39.py", - "docs_src/path_operation_advanced_configuration/tutorial007_pv1_py39.py", - "docs_src/settings/app03_py39/config_pv1.py", - "docs_src/settings/app03_an_py39/config_pv1.py", - "docs_src/settings/tutorial001_pv1_py39.py", + # TODO: remove all the ignores below when all translations use the new Python 3.10 files + "docs_src/additional_responses/tutorial001_py39.py", + "docs_src/additional_responses/tutorial003_py39.py", + "docs_src/advanced_middleware/tutorial001_py39.py", + "docs_src/advanced_middleware/tutorial002_py39.py", + "docs_src/advanced_middleware/tutorial003_py39.py", + "docs_src/app_testing/app_a_py39/main.py", + "docs_src/app_testing/app_a_py39/test_main.py", + "docs_src/app_testing/tutorial001_py39.py", + "docs_src/app_testing/tutorial002_py39.py", + "docs_src/app_testing/tutorial003_py39.py", + "docs_src/app_testing/tutorial004_py39.py", + "docs_src/async_tests/app_a_py39/main.py", + "docs_src/async_tests/app_a_py39/test_main.py", + "docs_src/authentication_error_status_code/tutorial001_an_py39.py", + "docs_src/background_tasks/tutorial001_py39.py", + "docs_src/behind_a_proxy/tutorial001_01_py39.py", + "docs_src/behind_a_proxy/tutorial001_py39.py", + "docs_src/behind_a_proxy/tutorial002_py39.py", + "docs_src/behind_a_proxy/tutorial003_py39.py", + "docs_src/behind_a_proxy/tutorial004_py39.py", + "docs_src/bigger_applications/app_an_py39/dependencies.py", + "docs_src/bigger_applications/app_an_py39/internal/admin.py", + "docs_src/bigger_applications/app_an_py39/main.py", + "docs_src/bigger_applications/app_an_py39/routers/items.py", + "docs_src/bigger_applications/app_an_py39/routers/users.py", + "docs_src/bigger_applications/app_py39/dependencies.py", + "docs_src/bigger_applications/app_py39/main.py", + "docs_src/body_nested_models/tutorial008_py39.py", + "docs_src/body_nested_models/tutorial009_py39.py", + "docs_src/conditional_openapi/tutorial001_py39.py", + "docs_src/configure_swagger_ui/tutorial001_py39.py", + "docs_src/configure_swagger_ui/tutorial002_py39.py", + "docs_src/configure_swagger_ui/tutorial003_py39.py", + "docs_src/cors/tutorial001_py39.py", + "docs_src/custom_docs_ui/tutorial001_py39.py", + "docs_src/custom_docs_ui/tutorial002_py39.py", + "docs_src/custom_response/tutorial001_py39.py", + "docs_src/custom_response/tutorial001b_py39.py", + "docs_src/custom_response/tutorial002_py39.py", + "docs_src/custom_response/tutorial003_py39.py", + "docs_src/custom_response/tutorial004_py39.py", + "docs_src/custom_response/tutorial005_py39.py", + "docs_src/custom_response/tutorial006_py39.py", + "docs_src/custom_response/tutorial006b_py39.py", + "docs_src/custom_response/tutorial006c_py39.py", + "docs_src/custom_response/tutorial007_py39.py", + "docs_src/custom_response/tutorial008_py39.py", + "docs_src/custom_response/tutorial009_py39.py", + "docs_src/custom_response/tutorial009b_py39.py", + "docs_src/custom_response/tutorial009c_py39.py", + "docs_src/custom_response/tutorial010_py39.py", + "docs_src/debugging/tutorial001_py39.py", + "docs_src/dependencies/tutorial006_an_py39.py", + "docs_src/dependencies/tutorial006_py39.py", + "docs_src/dependencies/tutorial007_py39.py", + "docs_src/dependencies/tutorial008_py39.py", + "docs_src/dependencies/tutorial008b_an_py39.py", + "docs_src/dependencies/tutorial008b_py39.py", + "docs_src/dependencies/tutorial008c_an_py39.py", + "docs_src/dependencies/tutorial008c_py39.py", + "docs_src/dependencies/tutorial008d_an_py39.py", + "docs_src/dependencies/tutorial008d_py39.py", + "docs_src/dependencies/tutorial008e_an_py39.py", + "docs_src/dependencies/tutorial008e_py39.py", + "docs_src/dependencies/tutorial010_py39.py", + "docs_src/dependencies/tutorial011_an_py39.py", + "docs_src/dependencies/tutorial011_py39.py", + "docs_src/dependencies/tutorial012_an_py39.py", + "docs_src/dependencies/tutorial012_py39.py", + "docs_src/events/tutorial001_py39.py", + "docs_src/events/tutorial002_py39.py", + "docs_src/events/tutorial003_py39.py", + "docs_src/extending_openapi/tutorial001_py39.py", + "docs_src/extra_models/tutorial004_py39.py", + "docs_src/extra_models/tutorial005_py39.py", + "docs_src/first_steps/tutorial001_py39.py", + "docs_src/first_steps/tutorial003_py39.py", + "docs_src/generate_clients/tutorial001_py39.py", + "docs_src/generate_clients/tutorial002_py39.py", + "docs_src/generate_clients/tutorial003_py39.py", + "docs_src/generate_clients/tutorial004_py39.py", + "docs_src/graphql_/tutorial001_py39.py", + "docs_src/handling_errors/tutorial001_py39.py", + "docs_src/handling_errors/tutorial002_py39.py", + "docs_src/handling_errors/tutorial003_py39.py", + "docs_src/handling_errors/tutorial004_py39.py", + "docs_src/handling_errors/tutorial005_py39.py", + "docs_src/handling_errors/tutorial006_py39.py", + "docs_src/metadata/tutorial001_1_py39.py", + "docs_src/metadata/tutorial001_py39.py", + "docs_src/metadata/tutorial002_py39.py", + "docs_src/metadata/tutorial003_py39.py", + "docs_src/metadata/tutorial004_py39.py", + "docs_src/middleware/tutorial001_py39.py", + "docs_src/openapi_webhooks/tutorial001_py39.py", + "docs_src/path_operation_advanced_configuration/tutorial001_py39.py", + "docs_src/path_operation_advanced_configuration/tutorial002_py39.py", + "docs_src/path_operation_advanced_configuration/tutorial003_py39.py", + "docs_src/path_operation_advanced_configuration/tutorial005_py39.py", + "docs_src/path_operation_advanced_configuration/tutorial006_py39.py", + "docs_src/path_operation_advanced_configuration/tutorial007_py39.py", + "docs_src/path_operation_configuration/tutorial002b_py39.py", + "docs_src/path_operation_configuration/tutorial006_py39.py", + "docs_src/path_params/tutorial001_py39.py", + "docs_src/path_params/tutorial002_py39.py", + "docs_src/path_params/tutorial003_py39.py", + "docs_src/path_params/tutorial003b_py39.py", + "docs_src/path_params/tutorial004_py39.py", + "docs_src/path_params/tutorial005_py39.py", + "docs_src/path_params_numeric_validations/tutorial002_an_py39.py", + "docs_src/path_params_numeric_validations/tutorial002_py39.py", + "docs_src/path_params_numeric_validations/tutorial003_an_py39.py", + "docs_src/path_params_numeric_validations/tutorial003_py39.py", + "docs_src/path_params_numeric_validations/tutorial004_an_py39.py", + "docs_src/path_params_numeric_validations/tutorial004_py39.py", + "docs_src/path_params_numeric_validations/tutorial005_an_py39.py", + "docs_src/path_params_numeric_validations/tutorial005_py39.py", + "docs_src/path_params_numeric_validations/tutorial006_an_py39.py", + "docs_src/path_params_numeric_validations/tutorial006_py39.py", + "docs_src/python_types/tutorial001_py39.py", + "docs_src/python_types/tutorial002_py39.py", + "docs_src/python_types/tutorial003_py39.py", + "docs_src/python_types/tutorial004_py39.py", + "docs_src/python_types/tutorial005_py39.py", + "docs_src/python_types/tutorial006_py39.py", + "docs_src/python_types/tutorial007_py39.py", + "docs_src/python_types/tutorial008_py39.py", + "docs_src/python_types/tutorial008b_py39.py", + "docs_src/python_types/tutorial009_py39.py", + "docs_src/python_types/tutorial009b_py39.py", + "docs_src/python_types/tutorial009c_py39.py", + "docs_src/python_types/tutorial010_py39.py", + "docs_src/python_types/tutorial013_py39.py", + "docs_src/query_params/tutorial001_py39.py", + "docs_src/query_params/tutorial005_py39.py", + "docs_src/query_params_str_validations/tutorial005_an_py39.py", + "docs_src/query_params_str_validations/tutorial005_py39.py", + "docs_src/query_params_str_validations/tutorial006_an_py39.py", + "docs_src/query_params_str_validations/tutorial006_py39.py", + "docs_src/query_params_str_validations/tutorial012_an_py39.py", + "docs_src/query_params_str_validations/tutorial012_py39.py", + "docs_src/query_params_str_validations/tutorial013_an_py39.py", + "docs_src/query_params_str_validations/tutorial013_py39.py", + "docs_src/request_files/tutorial001_03_an_py39.py", + "docs_src/request_files/tutorial001_03_py39.py", + "docs_src/request_files/tutorial001_an_py39.py", + "docs_src/request_files/tutorial001_py39.py", + "docs_src/request_files/tutorial002_an_py39.py", + "docs_src/request_files/tutorial002_py39.py", + "docs_src/request_files/tutorial003_an_py39.py", + "docs_src/request_files/tutorial003_py39.py", + "docs_src/request_form_models/tutorial001_an_py39.py", + "docs_src/request_form_models/tutorial001_py39.py", + "docs_src/request_form_models/tutorial002_an_py39.py", + "docs_src/request_form_models/tutorial002_py39.py", + "docs_src/request_forms/tutorial001_an_py39.py", + "docs_src/request_forms/tutorial001_py39.py", + "docs_src/request_forms_and_files/tutorial001_an_py39.py", + "docs_src/request_forms_and_files/tutorial001_py39.py", + "docs_src/response_change_status_code/tutorial001_py39.py", + "docs_src/response_cookies/tutorial001_py39.py", + "docs_src/response_cookies/tutorial002_py39.py", + "docs_src/response_directly/tutorial002_py39.py", + "docs_src/response_headers/tutorial001_py39.py", + "docs_src/response_headers/tutorial002_py39.py", + "docs_src/response_model/tutorial003_02_py39.py", + "docs_src/response_model/tutorial003_03_py39.py", + "docs_src/response_status_code/tutorial001_py39.py", + "docs_src/response_status_code/tutorial002_py39.py", + "docs_src/security/tutorial001_an_py39.py", + "docs_src/security/tutorial001_py39.py", + "docs_src/security/tutorial006_an_py39.py", + "docs_src/security/tutorial006_py39.py", + "docs_src/security/tutorial007_an_py39.py", + "docs_src/security/tutorial007_py39.py", + "docs_src/settings/app01_py39/config.py", + "docs_src/settings/app01_py39/main.py", + "docs_src/settings/app02_an_py39/config.py", + "docs_src/settings/app02_an_py39/main.py", + "docs_src/settings/app02_an_py39/test_main.py", + "docs_src/settings/app02_py39/config.py", + "docs_src/settings/app02_py39/main.py", + "docs_src/settings/app02_py39/test_main.py", + "docs_src/settings/app03_an_py39/config.py", + "docs_src/settings/app03_an_py39/main.py", + "docs_src/settings/app03_py39/config.py", + "docs_src/settings/app03_py39/main.py", + "docs_src/settings/tutorial001_py39.py", + "docs_src/static_files/tutorial001_py39.py", + "docs_src/sub_applications/tutorial001_py39.py", + "docs_src/templates/tutorial001_py39.py", + "docs_src/using_request_directly/tutorial001_py39.py", + "docs_src/websockets/tutorial001_py39.py", + "docs_src/websockets/tutorial003_py39.py", + "docs_src/wsgi/tutorial001_py39.py", ] [tool.coverage.report] @@ -327,32 +512,42 @@ ignore = [ [tool.ruff.lint.per-file-ignores] "__init__.py" = ["F401"] -"docs_src/dependencies/tutorial007_py39.py" = ["F821"] -"docs_src/dependencies/tutorial008_py39.py" = ["F821"] -"docs_src/dependencies/tutorial009_py39.py" = ["F821"] -"docs_src/dependencies/tutorial010_py39.py" = ["F821"] +"docs_src/custom_request_and_route/tutorial002_an_py310.py" = ["B904"] +"docs_src/custom_request_and_route/tutorial002_an_py39.py" = ["B904"] +"docs_src/custom_request_and_route/tutorial002_py310.py" = ["B904"] +"docs_src/custom_request_and_route/tutorial002_py39.py" = ["B904"] +"docs_src/custom_response/tutorial007_py310.py" = ["B007"] "docs_src/custom_response/tutorial007_py39.py" = ["B007"] "docs_src/dataclasses/tutorial003_py39.py" = ["I001"] -"docs_src/path_operation_advanced_configuration/tutorial007_py39.py" = ["B904"] -"docs_src/path_operation_advanced_configuration/tutorial007_pv1_py39.py" = ["B904"] -"docs_src/custom_request_and_route/tutorial002_py39.py" = ["B904"] -"docs_src/custom_request_and_route/tutorial002_py310.py" = ["B904"] -"docs_src/custom_request_and_route/tutorial002_an_py39.py" = ["B904"] -"docs_src/custom_request_and_route/tutorial002_an_py310.py" = ["B904"] +"docs_src/dependencies/tutorial007_py310.py" = ["F821"] +"docs_src/dependencies/tutorial007_py39.py" = ["F821"] +"docs_src/dependencies/tutorial008_an_py310.py" = ["F821"] "docs_src/dependencies/tutorial008_an_py39.py" = ["F821"] +"docs_src/dependencies/tutorial008_py310.py" = ["F821"] +"docs_src/dependencies/tutorial008_py39.py" = ["F821"] +"docs_src/dependencies/tutorial008b_an_py310.py" = ["B904"] +"docs_src/dependencies/tutorial008b_an_py39.py" = ["B904"] +"docs_src/dependencies/tutorial008b_py310.py" = ["B904"] +"docs_src/dependencies/tutorial008b_py39.py" = ["B904"] +"docs_src/dependencies/tutorial009_py310.py" = ["F821"] +"docs_src/dependencies/tutorial009_py39.py" = ["F821"] +"docs_src/dependencies/tutorial010_py310.py" = ["F821"] +"docs_src/dependencies/tutorial010_py39.py" = ["F821"] +"docs_src/path_operation_advanced_configuration/tutorial007_pv1_py39.py" = ["B904"] +"docs_src/path_operation_advanced_configuration/tutorial007_py310.py" = ["B904"] +"docs_src/path_operation_advanced_configuration/tutorial007_py39.py" = ["B904"] +"docs_src/query_params_str_validations/tutorial012_an_py310.py" = ["B006"] "docs_src/query_params_str_validations/tutorial012_an_py39.py" = ["B006"] +"docs_src/query_params_str_validations/tutorial013_an_py310.py" = ["B006"] "docs_src/query_params_str_validations/tutorial013_an_py39.py" = ["B006"] -"docs_src/security/tutorial004_py39.py" = ["B904"] -"docs_src/security/tutorial004_an_py39.py" = ["B904"] "docs_src/security/tutorial004_an_py310.py" = ["B904"] +"docs_src/security/tutorial004_an_py39.py" = ["B904"] "docs_src/security/tutorial004_py310.py" = ["B904"] +"docs_src/security/tutorial004_py39.py" = ["B904"] "docs_src/security/tutorial005_an_py310.py" = ["B904"] "docs_src/security/tutorial005_an_py39.py" = ["B904"] "docs_src/security/tutorial005_py310.py" = ["B904"] "docs_src/security/tutorial005_py39.py" = ["B904"] -"docs_src/dependencies/tutorial008b_py39.py" = ["B904"] -"docs_src/dependencies/tutorial008b_an_py39.py" = ["B904"] - [tool.ruff.lint.isort] known-third-party = ["fastapi", "pydantic", "starlette"] diff --git a/tests/test_tutorial/test_additional_responses/test_tutorial001.py b/tests/test_tutorial/test_additional_responses/test_tutorial001.py index d8d9d4130..456070c9c 100644 --- a/tests/test_tutorial/test_additional_responses/test_tutorial001.py +++ b/tests/test_tutorial/test_additional_responses/test_tutorial001.py @@ -1,7 +1,7 @@ from fastapi.testclient import TestClient from inline_snapshot import snapshot -from docs_src.additional_responses.tutorial001_py39 import app +from docs_src.additional_responses.tutorial001_py310 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_additional_responses/test_tutorial002.py b/tests/test_tutorial/test_additional_responses/test_tutorial002.py index 4fae59d22..586779e44 100644 --- a/tests/test_tutorial/test_additional_responses/test_tutorial002.py +++ b/tests/test_tutorial/test_additional_responses/test_tutorial002.py @@ -12,7 +12,6 @@ from tests.utils import needs_py310 @pytest.fixture( name="client", params=[ - pytest.param("tutorial002_py39"), pytest.param("tutorial002_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_additional_responses/test_tutorial003.py b/tests/test_tutorial/test_additional_responses/test_tutorial003.py index e888819df..56eeacb60 100644 --- a/tests/test_tutorial/test_additional_responses/test_tutorial003.py +++ b/tests/test_tutorial/test_additional_responses/test_tutorial003.py @@ -1,7 +1,7 @@ from fastapi.testclient import TestClient from inline_snapshot import snapshot -from docs_src.additional_responses.tutorial003_py39 import app +from docs_src.additional_responses.tutorial003_py310 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_additional_responses/test_tutorial004.py b/tests/test_tutorial/test_additional_responses/test_tutorial004.py index 9df326a5c..fe56fbb8b 100644 --- a/tests/test_tutorial/test_additional_responses/test_tutorial004.py +++ b/tests/test_tutorial/test_additional_responses/test_tutorial004.py @@ -12,7 +12,6 @@ from tests.utils import needs_py310 @pytest.fixture( name="client", params=[ - pytest.param("tutorial004_py39"), pytest.param("tutorial004_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_additional_status_codes/test_tutorial001.py b/tests/test_tutorial/test_additional_status_codes/test_tutorial001.py index bced1f6df..f57ea2bcf 100644 --- a/tests/test_tutorial/test_additional_status_codes/test_tutorial001.py +++ b/tests/test_tutorial/test_additional_status_codes/test_tutorial001.py @@ -9,9 +9,7 @@ from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - "tutorial001_py39", pytest.param("tutorial001_py310", marks=needs_py310), - "tutorial001_an_py39", pytest.param("tutorial001_an_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_advanced_middleware/test_tutorial001.py b/tests/test_tutorial/test_advanced_middleware/test_tutorial001.py index f17391956..6231cf4cb 100644 --- a/tests/test_tutorial/test_advanced_middleware/test_tutorial001.py +++ b/tests/test_tutorial/test_advanced_middleware/test_tutorial001.py @@ -1,6 +1,6 @@ from fastapi.testclient import TestClient -from docs_src.advanced_middleware.tutorial001_py39 import app +from docs_src.advanced_middleware.tutorial001_py310 import app def test_middleware(): diff --git a/tests/test_tutorial/test_advanced_middleware/test_tutorial002.py b/tests/test_tutorial/test_advanced_middleware/test_tutorial002.py index bae915406..fa8ac41d7 100644 --- a/tests/test_tutorial/test_advanced_middleware/test_tutorial002.py +++ b/tests/test_tutorial/test_advanced_middleware/test_tutorial002.py @@ -1,6 +1,6 @@ from fastapi.testclient import TestClient -from docs_src.advanced_middleware.tutorial002_py39 import app +from docs_src.advanced_middleware.tutorial002_py310 import app def test_middleware(): diff --git a/tests/test_tutorial/test_advanced_middleware/test_tutorial003.py b/tests/test_tutorial/test_advanced_middleware/test_tutorial003.py index 66697997c..8602e1569 100644 --- a/tests/test_tutorial/test_advanced_middleware/test_tutorial003.py +++ b/tests/test_tutorial/test_advanced_middleware/test_tutorial003.py @@ -1,7 +1,7 @@ from fastapi.responses import PlainTextResponse from fastapi.testclient import TestClient -from docs_src.advanced_middleware.tutorial003_py39 import app +from docs_src.advanced_middleware.tutorial003_py310 import app @app.get("/large") diff --git a/tests/test_tutorial/test_async_tests/test_main_a.py b/tests/test_tutorial/test_async_tests/test_main_a.py index f29acaa9a..4e33692d0 100644 --- a/tests/test_tutorial/test_async_tests/test_main_a.py +++ b/tests/test_tutorial/test_async_tests/test_main_a.py @@ -1,6 +1,6 @@ import pytest -from docs_src.async_tests.app_a_py39.test_main import test_root +from docs_src.async_tests.app_a_py310.test_main import test_root @pytest.mark.anyio diff --git a/tests/test_tutorial/test_authentication_error_status_code/test_tutorial001.py b/tests/test_tutorial/test_authentication_error_status_code/test_tutorial001.py index 6f5811631..7e1588d67 100644 --- a/tests/test_tutorial/test_authentication_error_status_code/test_tutorial001.py +++ b/tests/test_tutorial/test_authentication_error_status_code/test_tutorial001.py @@ -8,7 +8,7 @@ from inline_snapshot import snapshot @pytest.fixture( name="client", params=[ - "tutorial001_an_py39", + "tutorial001_an_py310", ], ) def get_client(request: pytest.FixtureRequest): diff --git a/tests/test_tutorial/test_background_tasks/test_tutorial001.py b/tests/test_tutorial/test_background_tasks/test_tutorial001.py index c0ad27a6f..100583f77 100644 --- a/tests/test_tutorial/test_background_tasks/test_tutorial001.py +++ b/tests/test_tutorial/test_background_tasks/test_tutorial001.py @@ -3,7 +3,7 @@ from pathlib import Path from fastapi.testclient import TestClient -from docs_src.background_tasks.tutorial001_py39 import app +from docs_src.background_tasks.tutorial001_py310 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_background_tasks/test_tutorial002.py b/tests/test_tutorial/test_background_tasks/test_tutorial002.py index 288a1c244..f29402c83 100644 --- a/tests/test_tutorial/test_background_tasks/test_tutorial002.py +++ b/tests/test_tutorial/test_background_tasks/test_tutorial002.py @@ -11,9 +11,7 @@ from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - "tutorial002_py39", pytest.param("tutorial002_py310", marks=needs_py310), - "tutorial002_an_py39", pytest.param("tutorial002_an_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_behind_a_proxy/test_tutorial001.py b/tests/test_tutorial/test_behind_a_proxy/test_tutorial001.py index 31adaa56a..38ae460fb 100644 --- a/tests/test_tutorial/test_behind_a_proxy/test_tutorial001.py +++ b/tests/test_tutorial/test_behind_a_proxy/test_tutorial001.py @@ -1,7 +1,7 @@ from fastapi.testclient import TestClient from inline_snapshot import snapshot -from docs_src.behind_a_proxy.tutorial001_py39 import app +from docs_src.behind_a_proxy.tutorial001_py310 import app client = TestClient(app, root_path="/api/v1") diff --git a/tests/test_tutorial/test_behind_a_proxy/test_tutorial001_01.py b/tests/test_tutorial/test_behind_a_proxy/test_tutorial001_01.py index da4acb28c..190b33c50 100644 --- a/tests/test_tutorial/test_behind_a_proxy/test_tutorial001_01.py +++ b/tests/test_tutorial/test_behind_a_proxy/test_tutorial001_01.py @@ -1,6 +1,6 @@ from fastapi.testclient import TestClient -from docs_src.behind_a_proxy.tutorial001_01_py39 import app +from docs_src.behind_a_proxy.tutorial001_01_py310 import app client = TestClient( app, diff --git a/tests/test_tutorial/test_behind_a_proxy/test_tutorial002.py b/tests/test_tutorial/test_behind_a_proxy/test_tutorial002.py index 56e6f2f9d..c9356a513 100644 --- a/tests/test_tutorial/test_behind_a_proxy/test_tutorial002.py +++ b/tests/test_tutorial/test_behind_a_proxy/test_tutorial002.py @@ -1,7 +1,7 @@ from fastapi.testclient import TestClient from inline_snapshot import snapshot -from docs_src.behind_a_proxy.tutorial002_py39 import app +from docs_src.behind_a_proxy.tutorial002_py310 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_behind_a_proxy/test_tutorial003.py b/tests/test_tutorial/test_behind_a_proxy/test_tutorial003.py index a164bb80b..d74da5b73 100644 --- a/tests/test_tutorial/test_behind_a_proxy/test_tutorial003.py +++ b/tests/test_tutorial/test_behind_a_proxy/test_tutorial003.py @@ -1,7 +1,7 @@ from fastapi.testclient import TestClient from inline_snapshot import snapshot -from docs_src.behind_a_proxy.tutorial003_py39 import app +from docs_src.behind_a_proxy.tutorial003_py310 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_behind_a_proxy/test_tutorial004.py b/tests/test_tutorial/test_behind_a_proxy/test_tutorial004.py index 01bba9fed..f5e27c118 100644 --- a/tests/test_tutorial/test_behind_a_proxy/test_tutorial004.py +++ b/tests/test_tutorial/test_behind_a_proxy/test_tutorial004.py @@ -1,7 +1,7 @@ from fastapi.testclient import TestClient from inline_snapshot import snapshot -from docs_src.behind_a_proxy.tutorial004_py39 import app +from docs_src.behind_a_proxy.tutorial004_py310 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_bigger_applications/test_main.py b/tests/test_tutorial/test_bigger_applications/test_main.py index 18845e470..abe008d9e 100644 --- a/tests/test_tutorial/test_bigger_applications/test_main.py +++ b/tests/test_tutorial/test_bigger_applications/test_main.py @@ -8,8 +8,7 @@ from inline_snapshot import snapshot @pytest.fixture( name="client", params=[ - "app_py39.main", - "app_an_py39.main", + "app_an_py310.main", ], ) def get_client(request: pytest.FixtureRequest): diff --git a/tests/test_tutorial/test_body/test_tutorial001.py b/tests/test_tutorial/test_body/test_tutorial001.py index c1877a72e..bdabf8d68 100644 --- a/tests/test_tutorial/test_body/test_tutorial001.py +++ b/tests/test_tutorial/test_body/test_tutorial001.py @@ -11,7 +11,6 @@ from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - "tutorial001_py39", pytest.param("tutorial001_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_body/test_tutorial002.py b/tests/test_tutorial/test_body/test_tutorial002.py index 94bf213e3..f1e1236c9 100644 --- a/tests/test_tutorial/test_body/test_tutorial002.py +++ b/tests/test_tutorial/test_body/test_tutorial002.py @@ -1,5 +1,4 @@ import importlib -from typing import Union import pytest from fastapi.testclient import TestClient @@ -11,7 +10,6 @@ from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - pytest.param("tutorial002_py39"), pytest.param("tutorial002_py310", marks=needs_py310), ], ) @@ -23,7 +21,7 @@ def get_client(request: pytest.FixtureRequest): @pytest.mark.parametrize("price", ["50.5", 50.5]) -def test_post_with_tax(client: TestClient, price: Union[str, float]): +def test_post_with_tax(client: TestClient, price: str | float): response = client.post( "/items/", json={"name": "Foo", "price": price, "description": "Some Foo", "tax": 0.3}, @@ -39,7 +37,7 @@ def test_post_with_tax(client: TestClient, price: Union[str, float]): @pytest.mark.parametrize("price", ["50.5", 50.5]) -def test_post_without_tax(client: TestClient, price: Union[str, float]): +def test_post_without_tax(client: TestClient, price: str | float): response = client.post( "/items/", json={"name": "Foo", "price": price, "description": "Some Foo"} ) diff --git a/tests/test_tutorial/test_body/test_tutorial003.py b/tests/test_tutorial/test_body/test_tutorial003.py index 832c211f6..b4767cf28 100644 --- a/tests/test_tutorial/test_body/test_tutorial003.py +++ b/tests/test_tutorial/test_body/test_tutorial003.py @@ -10,7 +10,6 @@ from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - pytest.param("tutorial003_py39"), pytest.param("tutorial003_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_body/test_tutorial004.py b/tests/test_tutorial/test_body/test_tutorial004.py index 1019a168c..f0a50a64c 100644 --- a/tests/test_tutorial/test_body/test_tutorial004.py +++ b/tests/test_tutorial/test_body/test_tutorial004.py @@ -10,7 +10,6 @@ from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - pytest.param("tutorial004_py39"), pytest.param("tutorial004_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_body_fields/test_tutorial001.py b/tests/test_tutorial/test_body_fields/test_tutorial001.py index 0116dcb09..eb94d24cd 100644 --- a/tests/test_tutorial/test_body_fields/test_tutorial001.py +++ b/tests/test_tutorial/test_body_fields/test_tutorial001.py @@ -10,9 +10,7 @@ from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - "tutorial001_py39", pytest.param("tutorial001_py310", marks=needs_py310), - "tutorial001_an_py39", pytest.param("tutorial001_an_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_body_multiple_params/test_tutorial001.py b/tests/test_tutorial/test_body_multiple_params/test_tutorial001.py index 2e8ba457b..f510f1c15 100644 --- a/tests/test_tutorial/test_body_multiple_params/test_tutorial001.py +++ b/tests/test_tutorial/test_body_multiple_params/test_tutorial001.py @@ -10,9 +10,7 @@ from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - "tutorial001_py39", pytest.param("tutorial001_py310", marks=needs_py310), - "tutorial001_an_py39", pytest.param("tutorial001_an_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_body_multiple_params/test_tutorial002.py b/tests/test_tutorial/test_body_multiple_params/test_tutorial002.py index 0c94e9dd1..b23402c3c 100644 --- a/tests/test_tutorial/test_body_multiple_params/test_tutorial002.py +++ b/tests/test_tutorial/test_body_multiple_params/test_tutorial002.py @@ -10,7 +10,6 @@ from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - pytest.param("tutorial002_py39"), pytest.param("tutorial002_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_body_multiple_params/test_tutorial003.py b/tests/test_tutorial/test_body_multiple_params/test_tutorial003.py index c27f3d5ba..89fabd3ba 100644 --- a/tests/test_tutorial/test_body_multiple_params/test_tutorial003.py +++ b/tests/test_tutorial/test_body_multiple_params/test_tutorial003.py @@ -10,9 +10,7 @@ from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - "tutorial003_py39", pytest.param("tutorial003_py310", marks=needs_py310), - "tutorial003_an_py39", pytest.param("tutorial003_an_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_body_multiple_params/test_tutorial004.py b/tests/test_tutorial/test_body_multiple_params/test_tutorial004.py index 2a39f3d71..c5b4b452d 100644 --- a/tests/test_tutorial/test_body_multiple_params/test_tutorial004.py +++ b/tests/test_tutorial/test_body_multiple_params/test_tutorial004.py @@ -10,9 +10,7 @@ from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - pytest.param("tutorial004_py39"), pytest.param("tutorial004_py310", marks=needs_py310), - pytest.param("tutorial004_an_py39"), pytest.param("tutorial004_an_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_body_multiple_params/test_tutorial005.py b/tests/test_tutorial/test_body_multiple_params/test_tutorial005.py index d600e0767..b8fc98cd7 100644 --- a/tests/test_tutorial/test_body_multiple_params/test_tutorial005.py +++ b/tests/test_tutorial/test_body_multiple_params/test_tutorial005.py @@ -10,9 +10,7 @@ from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - pytest.param("tutorial005_py39"), pytest.param("tutorial005_py310", marks=needs_py310), - pytest.param("tutorial005_an_py39"), pytest.param("tutorial005_an_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_body_nested_models/test_tutorial001_tutorial002_tutorial003.py b/tests/test_tutorial/test_body_nested_models/test_tutorial001_tutorial002_tutorial003.py index 18bce279b..2e2f329f7 100644 --- a/tests/test_tutorial/test_body_nested_models/test_tutorial001_tutorial002_tutorial003.py +++ b/tests/test_tutorial/test_body_nested_models/test_tutorial001_tutorial002_tutorial003.py @@ -17,11 +17,8 @@ SET_OF_STR_SCHEMA = {"type": "array", "items": {"type": "string"}, "uniqueItems" @pytest.fixture( name="mod_name", params=[ - pytest.param("tutorial001_py39"), pytest.param("tutorial001_py310", marks=needs_py310), - pytest.param("tutorial002_py39"), pytest.param("tutorial002_py310", marks=needs_py310), - pytest.param("tutorial003_py39"), pytest.param("tutorial003_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_body_nested_models/test_tutorial004.py b/tests/test_tutorial/test_body_nested_models/test_tutorial004.py index 6a70779b6..4605a757d 100644 --- a/tests/test_tutorial/test_body_nested_models/test_tutorial004.py +++ b/tests/test_tutorial/test_body_nested_models/test_tutorial004.py @@ -11,7 +11,6 @@ from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - pytest.param("tutorial004_py39"), pytest.param("tutorial004_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_body_nested_models/test_tutorial005.py b/tests/test_tutorial/test_body_nested_models/test_tutorial005.py index 2ff3d4f22..ffa02cd65 100644 --- a/tests/test_tutorial/test_body_nested_models/test_tutorial005.py +++ b/tests/test_tutorial/test_body_nested_models/test_tutorial005.py @@ -11,7 +11,6 @@ from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - pytest.param("tutorial005_py39"), pytest.param("tutorial005_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_body_nested_models/test_tutorial006.py b/tests/test_tutorial/test_body_nested_models/test_tutorial006.py index 229216fc5..4551a72b3 100644 --- a/tests/test_tutorial/test_body_nested_models/test_tutorial006.py +++ b/tests/test_tutorial/test_body_nested_models/test_tutorial006.py @@ -11,7 +11,6 @@ from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - pytest.param("tutorial006_py39"), pytest.param("tutorial006_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_body_nested_models/test_tutorial007.py b/tests/test_tutorial/test_body_nested_models/test_tutorial007.py index 5a7763f59..5b99b41b6 100644 --- a/tests/test_tutorial/test_body_nested_models/test_tutorial007.py +++ b/tests/test_tutorial/test_body_nested_models/test_tutorial007.py @@ -10,7 +10,6 @@ from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - pytest.param("tutorial007_py39"), pytest.param("tutorial007_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_body_nested_models/test_tutorial008.py b/tests/test_tutorial/test_body_nested_models/test_tutorial008.py index 26f48f1d5..d038805bd 100644 --- a/tests/test_tutorial/test_body_nested_models/test_tutorial008.py +++ b/tests/test_tutorial/test_body_nested_models/test_tutorial008.py @@ -8,7 +8,7 @@ from inline_snapshot import snapshot @pytest.fixture( name="client", params=[ - pytest.param("tutorial008_py39"), + pytest.param("tutorial008_py310"), ], ) def get_client(request: pytest.FixtureRequest): diff --git a/tests/test_tutorial/test_body_nested_models/test_tutorial009.py b/tests/test_tutorial/test_body_nested_models/test_tutorial009.py index 492dcecd2..a747e2a64 100644 --- a/tests/test_tutorial/test_body_nested_models/test_tutorial009.py +++ b/tests/test_tutorial/test_body_nested_models/test_tutorial009.py @@ -8,7 +8,7 @@ from inline_snapshot import snapshot @pytest.fixture( name="client", params=[ - "tutorial009_py39", + "tutorial009_py310", ], ) def get_client(request: pytest.FixtureRequest): diff --git a/tests/test_tutorial/test_body_updates/test_tutorial001.py b/tests/test_tutorial/test_body_updates/test_tutorial001.py index feb07b859..ba8d7baf3 100644 --- a/tests/test_tutorial/test_body_updates/test_tutorial001.py +++ b/tests/test_tutorial/test_body_updates/test_tutorial001.py @@ -10,7 +10,6 @@ from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - "tutorial001_py39", pytest.param("tutorial001_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_body_updates/test_tutorial002.py b/tests/test_tutorial/test_body_updates/test_tutorial002.py index a34d08b52..cf0ee7ada 100644 --- a/tests/test_tutorial/test_body_updates/test_tutorial002.py +++ b/tests/test_tutorial/test_body_updates/test_tutorial002.py @@ -10,7 +10,6 @@ from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - pytest.param("tutorial002_py39"), pytest.param("tutorial002_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_conditional_openapi/test_tutorial001.py b/tests/test_tutorial/test_conditional_openapi/test_tutorial001.py index 644b82ad9..a7aa9dbe2 100644 --- a/tests/test_tutorial/test_conditional_openapi/test_tutorial001.py +++ b/tests/test_tutorial/test_conditional_openapi/test_tutorial001.py @@ -5,11 +5,11 @@ from inline_snapshot import snapshot def get_client() -> TestClient: - from docs_src.conditional_openapi import tutorial001_py39 + from docs_src.conditional_openapi import tutorial001_py310 - importlib.reload(tutorial001_py39) + importlib.reload(tutorial001_py310) - client = TestClient(tutorial001_py39.app) + client = TestClient(tutorial001_py310.app) return client diff --git a/tests/test_tutorial/test_configure_swagger_ui/test_tutorial001.py b/tests/test_tutorial/test_configure_swagger_ui/test_tutorial001.py index 1fa9419a7..e2f1fbf90 100644 --- a/tests/test_tutorial/test_configure_swagger_ui/test_tutorial001.py +++ b/tests/test_tutorial/test_configure_swagger_ui/test_tutorial001.py @@ -1,6 +1,6 @@ from fastapi.testclient import TestClient -from docs_src.configure_swagger_ui.tutorial001_py39 import app +from docs_src.configure_swagger_ui.tutorial001_py310 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_configure_swagger_ui/test_tutorial002.py b/tests/test_tutorial/test_configure_swagger_ui/test_tutorial002.py index c218cc858..ce1cb4bac 100644 --- a/tests/test_tutorial/test_configure_swagger_ui/test_tutorial002.py +++ b/tests/test_tutorial/test_configure_swagger_ui/test_tutorial002.py @@ -1,6 +1,6 @@ from fastapi.testclient import TestClient -from docs_src.configure_swagger_ui.tutorial002_py39 import app +from docs_src.configure_swagger_ui.tutorial002_py310 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_configure_swagger_ui/test_tutorial003.py b/tests/test_tutorial/test_configure_swagger_ui/test_tutorial003.py index 8b7368549..6f28e7734 100644 --- a/tests/test_tutorial/test_configure_swagger_ui/test_tutorial003.py +++ b/tests/test_tutorial/test_configure_swagger_ui/test_tutorial003.py @@ -1,6 +1,6 @@ from fastapi.testclient import TestClient -from docs_src.configure_swagger_ui.tutorial003_py39 import app +from docs_src.configure_swagger_ui.tutorial003_py310 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_cookie_param_models/test_tutorial001.py b/tests/test_tutorial/test_cookie_param_models/test_tutorial001.py index f391c569a..c4de7ad45 100644 --- a/tests/test_tutorial/test_cookie_param_models/test_tutorial001.py +++ b/tests/test_tutorial/test_cookie_param_models/test_tutorial001.py @@ -10,9 +10,7 @@ from tests.utils import needs_py310 @pytest.fixture( name="client", params=[ - "tutorial001_py39", pytest.param("tutorial001_py310", marks=needs_py310), - "tutorial001_an_py39", pytest.param("tutorial001_an_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_cookie_param_models/test_tutorial002.py b/tests/test_tutorial/test_cookie_param_models/test_tutorial002.py index 6583045dc..37be0f1dd 100644 --- a/tests/test_tutorial/test_cookie_param_models/test_tutorial002.py +++ b/tests/test_tutorial/test_cookie_param_models/test_tutorial002.py @@ -10,9 +10,7 @@ from tests.utils import needs_py310 @pytest.fixture( name="client", params=[ - pytest.param("tutorial002_py39"), pytest.param("tutorial002_py310", marks=[needs_py310]), - pytest.param("tutorial002_an_py39"), pytest.param("tutorial002_an_py310", marks=[needs_py310]), ], ) diff --git a/tests/test_tutorial/test_cookie_params/test_tutorial001.py b/tests/test_tutorial/test_cookie_params/test_tutorial001.py index 4d7adf0d6..db0765ea5 100644 --- a/tests/test_tutorial/test_cookie_params/test_tutorial001.py +++ b/tests/test_tutorial/test_cookie_params/test_tutorial001.py @@ -11,9 +11,7 @@ from ...utils import needs_py310 @pytest.fixture( name="mod", params=[ - "tutorial001_py39", pytest.param("tutorial001_py310", marks=needs_py310), - "tutorial001_an_py39", pytest.param("tutorial001_an_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_cors/test_tutorial001.py b/tests/test_tutorial/test_cors/test_tutorial001.py index 6a733693a..428378cd4 100644 --- a/tests/test_tutorial/test_cors/test_tutorial001.py +++ b/tests/test_tutorial/test_cors/test_tutorial001.py @@ -1,6 +1,6 @@ from fastapi.testclient import TestClient -from docs_src.cors.tutorial001_py39 import app +from docs_src.cors.tutorial001_py310 import app def test_cors(): diff --git a/tests/test_tutorial/test_custom_docs_ui/test_tutorial001.py b/tests/test_tutorial/test_custom_docs_ui/test_tutorial001.py index 1816e5d97..f7eb7fd97 100644 --- a/tests/test_tutorial/test_custom_docs_ui/test_tutorial001.py +++ b/tests/test_tutorial/test_custom_docs_ui/test_tutorial001.py @@ -10,7 +10,7 @@ def client(): static_dir: Path = Path(os.getcwd()) / "static" print(static_dir) static_dir.mkdir(exist_ok=True) - from docs_src.custom_docs_ui.tutorial001_py39 import app + from docs_src.custom_docs_ui.tutorial001_py310 import app with TestClient(app) as client: yield client diff --git a/tests/test_tutorial/test_custom_docs_ui/test_tutorial002.py b/tests/test_tutorial/test_custom_docs_ui/test_tutorial002.py index e8b7eb7aa..28945d838 100644 --- a/tests/test_tutorial/test_custom_docs_ui/test_tutorial002.py +++ b/tests/test_tutorial/test_custom_docs_ui/test_tutorial002.py @@ -10,7 +10,7 @@ def client(): static_dir: Path = Path(os.getcwd()) / "static" print(static_dir) static_dir.mkdir(exist_ok=True) - from docs_src.custom_docs_ui.tutorial002_py39 import app + from docs_src.custom_docs_ui.tutorial002_py310 import app with TestClient(app) as client: yield client diff --git a/tests/test_tutorial/test_custom_request_and_route/test_tutorial001.py b/tests/test_tutorial/test_custom_request_and_route/test_tutorial001.py index b4ea53784..39d3bd406 100644 --- a/tests/test_tutorial/test_custom_request_and_route/test_tutorial001.py +++ b/tests/test_tutorial/test_custom_request_and_route/test_tutorial001.py @@ -12,9 +12,7 @@ from tests.utils import needs_py310 @pytest.fixture( name="client", params=[ - pytest.param("tutorial001_py39"), pytest.param("tutorial001_py310", marks=needs_py310), - pytest.param("tutorial001_an_py39"), pytest.param("tutorial001_an_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_custom_request_and_route/test_tutorial002.py b/tests/test_tutorial/test_custom_request_and_route/test_tutorial002.py index a9c7ae638..746d6c9d2 100644 --- a/tests/test_tutorial/test_custom_request_and_route/test_tutorial002.py +++ b/tests/test_tutorial/test_custom_request_and_route/test_tutorial002.py @@ -10,9 +10,7 @@ from tests.utils import needs_py310 @pytest.fixture( name="client", params=[ - pytest.param("tutorial002_py39"), pytest.param("tutorial002_py310", marks=needs_py310), - pytest.param("tutorial002_an_py39"), pytest.param("tutorial002_an_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_custom_request_and_route/test_tutorial003.py b/tests/test_tutorial/test_custom_request_and_route/test_tutorial003.py index 6cad7bd3f..c11ea1259 100644 --- a/tests/test_tutorial/test_custom_request_and_route/test_tutorial003.py +++ b/tests/test_tutorial/test_custom_request_and_route/test_tutorial003.py @@ -9,7 +9,6 @@ from tests.utils import needs_py310 @pytest.fixture( name="client", params=[ - pytest.param("tutorial003_py39"), pytest.param("tutorial003_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_custom_response/test_tutorial001.py b/tests/test_tutorial/test_custom_response/test_tutorial001.py index 20244bef4..a5fe4c8f4 100644 --- a/tests/test_tutorial/test_custom_response/test_tutorial001.py +++ b/tests/test_tutorial/test_custom_response/test_tutorial001.py @@ -8,8 +8,8 @@ from inline_snapshot import snapshot @pytest.fixture( name="client", params=[ - pytest.param("tutorial001_py39"), - pytest.param("tutorial010_py39"), + pytest.param("tutorial001_py310"), + pytest.param("tutorial010_py310"), ], ) def get_client(request: pytest.FixtureRequest): diff --git a/tests/test_tutorial/test_custom_response/test_tutorial001b.py b/tests/test_tutorial/test_custom_response/test_tutorial001b.py index 746801df1..32437db86 100644 --- a/tests/test_tutorial/test_custom_response/test_tutorial001b.py +++ b/tests/test_tutorial/test_custom_response/test_tutorial001b.py @@ -1,7 +1,7 @@ from fastapi.testclient import TestClient from inline_snapshot import snapshot -from docs_src.custom_response.tutorial001b_py39 import app +from docs_src.custom_response.tutorial001b_py310 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_custom_response/test_tutorial002_tutorial003_tutorial004.py b/tests/test_tutorial/test_custom_response/test_tutorial002_tutorial003_tutorial004.py index 68e046ac5..42fd85583 100644 --- a/tests/test_tutorial/test_custom_response/test_tutorial002_tutorial003_tutorial004.py +++ b/tests/test_tutorial/test_custom_response/test_tutorial002_tutorial003_tutorial004.py @@ -8,9 +8,9 @@ from inline_snapshot import Is, snapshot @pytest.fixture( name="mod_name", params=[ - pytest.param("tutorial002_py39"), - pytest.param("tutorial003_py39"), - pytest.param("tutorial004_py39"), + pytest.param("tutorial002_py310"), + pytest.param("tutorial003_py310"), + pytest.param("tutorial004_py310"), ], ) def get_mod_name(request: pytest.FixtureRequest) -> str: diff --git a/tests/test_tutorial/test_custom_response/test_tutorial005.py b/tests/test_tutorial/test_custom_response/test_tutorial005.py index b4919af6c..297e48822 100644 --- a/tests/test_tutorial/test_custom_response/test_tutorial005.py +++ b/tests/test_tutorial/test_custom_response/test_tutorial005.py @@ -1,7 +1,7 @@ from fastapi.testclient import TestClient from inline_snapshot import snapshot -from docs_src.custom_response.tutorial005_py39 import app +from docs_src.custom_response.tutorial005_py310 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_custom_response/test_tutorial006.py b/tests/test_tutorial/test_custom_response/test_tutorial006.py index ea2d366aa..4365090c2 100644 --- a/tests/test_tutorial/test_custom_response/test_tutorial006.py +++ b/tests/test_tutorial/test_custom_response/test_tutorial006.py @@ -1,7 +1,7 @@ from fastapi.testclient import TestClient from inline_snapshot import snapshot -from docs_src.custom_response.tutorial006_py39 import app +from docs_src.custom_response.tutorial006_py310 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_custom_response/test_tutorial006b.py b/tests/test_tutorial/test_custom_response/test_tutorial006b.py index 133a591b1..a77618847 100644 --- a/tests/test_tutorial/test_custom_response/test_tutorial006b.py +++ b/tests/test_tutorial/test_custom_response/test_tutorial006b.py @@ -1,7 +1,7 @@ from fastapi.testclient import TestClient from inline_snapshot import snapshot -from docs_src.custom_response.tutorial006b_py39 import app +from docs_src.custom_response.tutorial006b_py310 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_custom_response/test_tutorial006c.py b/tests/test_tutorial/test_custom_response/test_tutorial006c.py index 5b17d815d..f29bda2c2 100644 --- a/tests/test_tutorial/test_custom_response/test_tutorial006c.py +++ b/tests/test_tutorial/test_custom_response/test_tutorial006c.py @@ -1,7 +1,7 @@ from fastapi.testclient import TestClient from inline_snapshot import snapshot -from docs_src.custom_response.tutorial006c_py39 import app +from docs_src.custom_response.tutorial006c_py310 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_custom_response/test_tutorial007.py b/tests/test_tutorial/test_custom_response/test_tutorial007.py index a62476ec1..5f2e233f8 100644 --- a/tests/test_tutorial/test_custom_response/test_tutorial007.py +++ b/tests/test_tutorial/test_custom_response/test_tutorial007.py @@ -1,6 +1,6 @@ from fastapi.testclient import TestClient -from docs_src.custom_response.tutorial007_py39 import app +from docs_src.custom_response.tutorial007_py310 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_custom_response/test_tutorial008.py b/tests/test_tutorial/test_custom_response/test_tutorial008.py index d9fe61f53..1be7c1a62 100644 --- a/tests/test_tutorial/test_custom_response/test_tutorial008.py +++ b/tests/test_tutorial/test_custom_response/test_tutorial008.py @@ -2,15 +2,15 @@ from pathlib import Path from fastapi.testclient import TestClient -from docs_src.custom_response import tutorial008_py39 -from docs_src.custom_response.tutorial008_py39 import app +from docs_src.custom_response import tutorial008_py310 +from docs_src.custom_response.tutorial008_py310 import app client = TestClient(app) def test_get(tmp_path: Path): file_path: Path = tmp_path / "large-video-file.mp4" - tutorial008_py39.some_file_path = str(file_path) + tutorial008_py310.some_file_path = str(file_path) test_content = b"Fake video bytes" file_path.write_bytes(test_content) response = client.get("/") diff --git a/tests/test_tutorial/test_custom_response/test_tutorial009.py b/tests/test_tutorial/test_custom_response/test_tutorial009.py index cb6a514be..a6564d551 100644 --- a/tests/test_tutorial/test_custom_response/test_tutorial009.py +++ b/tests/test_tutorial/test_custom_response/test_tutorial009.py @@ -2,15 +2,15 @@ from pathlib import Path from fastapi.testclient import TestClient -from docs_src.custom_response import tutorial009_py39 -from docs_src.custom_response.tutorial009_py39 import app +from docs_src.custom_response import tutorial009_py310 +from docs_src.custom_response.tutorial009_py310 import app client = TestClient(app) def test_get(tmp_path: Path): file_path: Path = tmp_path / "large-video-file.mp4" - tutorial009_py39.some_file_path = str(file_path) + tutorial009_py310.some_file_path = str(file_path) test_content = b"Fake video bytes" file_path.write_bytes(test_content) response = client.get("/") diff --git a/tests/test_tutorial/test_custom_response/test_tutorial009b.py b/tests/test_tutorial/test_custom_response/test_tutorial009b.py index 9918bdb1a..05ac62f3d 100644 --- a/tests/test_tutorial/test_custom_response/test_tutorial009b.py +++ b/tests/test_tutorial/test_custom_response/test_tutorial009b.py @@ -2,15 +2,15 @@ from pathlib import Path from fastapi.testclient import TestClient -from docs_src.custom_response import tutorial009b_py39 -from docs_src.custom_response.tutorial009b_py39 import app +from docs_src.custom_response import tutorial009b_py310 +from docs_src.custom_response.tutorial009b_py310 import app client = TestClient(app) def test_get(tmp_path: Path): file_path: Path = tmp_path / "large-video-file.mp4" - tutorial009b_py39.some_file_path = str(file_path) + tutorial009b_py310.some_file_path = str(file_path) test_content = b"Fake video bytes" file_path.write_bytes(test_content) response = client.get("/") diff --git a/tests/test_tutorial/test_custom_response/test_tutorial009c.py b/tests/test_tutorial/test_custom_response/test_tutorial009c.py index efc3a6b4a..7a1b71307 100644 --- a/tests/test_tutorial/test_custom_response/test_tutorial009c.py +++ b/tests/test_tutorial/test_custom_response/test_tutorial009c.py @@ -1,6 +1,6 @@ from fastapi.testclient import TestClient -from docs_src.custom_response.tutorial009c_py39 import app +from docs_src.custom_response.tutorial009c_py310 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_dataclasses/test_tutorial001.py b/tests/test_tutorial/test_dataclasses/test_tutorial001.py index a3d2cf515..62de135dc 100644 --- a/tests/test_tutorial/test_dataclasses/test_tutorial001.py +++ b/tests/test_tutorial/test_dataclasses/test_tutorial001.py @@ -10,7 +10,6 @@ from tests.utils import needs_py310 @pytest.fixture( name="client", params=[ - pytest.param("tutorial001_py39"), pytest.param("tutorial001_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_dataclasses/test_tutorial002.py b/tests/test_tutorial/test_dataclasses/test_tutorial002.py index 210d743bb..f6607c8e0 100644 --- a/tests/test_tutorial/test_dataclasses/test_tutorial002.py +++ b/tests/test_tutorial/test_dataclasses/test_tutorial002.py @@ -10,7 +10,6 @@ from tests.utils import needs_py310 @pytest.fixture( name="client", params=[ - pytest.param("tutorial002_py39"), pytest.param("tutorial002_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_dataclasses/test_tutorial003.py b/tests/test_tutorial/test_dataclasses/test_tutorial003.py index e023271bc..5a35e5c4a 100644 --- a/tests/test_tutorial/test_dataclasses/test_tutorial003.py +++ b/tests/test_tutorial/test_dataclasses/test_tutorial003.py @@ -10,7 +10,6 @@ from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - pytest.param("tutorial003_py39"), pytest.param("tutorial003_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_debugging/test_tutorial001.py b/tests/test_tutorial/test_debugging/test_tutorial001.py index 1a0ca6cad..fbf2bfa02 100644 --- a/tests/test_tutorial/test_debugging/test_tutorial001.py +++ b/tests/test_tutorial/test_debugging/test_tutorial001.py @@ -7,7 +7,7 @@ import pytest from fastapi.testclient import TestClient from inline_snapshot import snapshot -MOD_NAME = "docs_src.debugging.tutorial001_py39" +MOD_NAME = "docs_src.debugging.tutorial001_py310" @pytest.fixture(name="client") diff --git a/tests/test_tutorial/test_dependencies/test_tutorial001_tutorial001_02.py b/tests/test_tutorial/test_dependencies/test_tutorial001_tutorial001_02.py index 74f4a8f3a..11e732e6d 100644 --- a/tests/test_tutorial/test_dependencies/test_tutorial001_tutorial001_02.py +++ b/tests/test_tutorial/test_dependencies/test_tutorial001_tutorial001_02.py @@ -10,11 +10,8 @@ from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - pytest.param("tutorial001_py39"), pytest.param("tutorial001_py310", marks=needs_py310), - pytest.param("tutorial001_an_py39"), pytest.param("tutorial001_an_py310", marks=needs_py310), - pytest.param("tutorial001_02_an_py39"), pytest.param("tutorial001_02_an_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_dependencies/test_tutorial002_tutorial003_tutorial004.py b/tests/test_tutorial/test_dependencies/test_tutorial002_tutorial003_tutorial004.py index 6e1cea5a0..a9ddf8a52 100644 --- a/tests/test_tutorial/test_dependencies/test_tutorial002_tutorial003_tutorial004.py +++ b/tests/test_tutorial/test_dependencies/test_tutorial002_tutorial003_tutorial004.py @@ -10,17 +10,11 @@ from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - pytest.param("tutorial002_py39"), pytest.param("tutorial002_py310", marks=needs_py310), - pytest.param("tutorial002_an_py39"), pytest.param("tutorial002_an_py310", marks=needs_py310), - pytest.param("tutorial003_py39"), pytest.param("tutorial003_py310", marks=needs_py310), - pytest.param("tutorial003_an_py39"), pytest.param("tutorial003_an_py310", marks=needs_py310), - pytest.param("tutorial004_py39"), pytest.param("tutorial004_py310", marks=needs_py310), - pytest.param("tutorial004_an_py39"), pytest.param("tutorial004_an_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_dependencies/test_tutorial005.py b/tests/test_tutorial/test_dependencies/test_tutorial005.py index 31054744a..3cd083b35 100644 --- a/tests/test_tutorial/test_dependencies/test_tutorial005.py +++ b/tests/test_tutorial/test_dependencies/test_tutorial005.py @@ -10,9 +10,7 @@ from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - pytest.param("tutorial005_py39"), pytest.param("tutorial005_py310", marks=needs_py310), - pytest.param("tutorial005_an_py39"), pytest.param("tutorial005_an_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_dependencies/test_tutorial006.py b/tests/test_tutorial/test_dependencies/test_tutorial006.py index 8d6cfa2d6..f6e6f8368 100644 --- a/tests/test_tutorial/test_dependencies/test_tutorial006.py +++ b/tests/test_tutorial/test_dependencies/test_tutorial006.py @@ -8,8 +8,8 @@ from inline_snapshot import snapshot @pytest.fixture( name="client", params=[ - pytest.param("tutorial006_py39"), - pytest.param("tutorial006_an_py39"), + pytest.param("tutorial006_py310"), + pytest.param("tutorial006_an_py310"), ], ) def get_client(request: pytest.FixtureRequest): diff --git a/tests/test_tutorial/test_dependencies/test_tutorial007.py b/tests/test_tutorial/test_dependencies/test_tutorial007.py index 3e188abcf..c98485611 100644 --- a/tests/test_tutorial/test_dependencies/test_tutorial007.py +++ b/tests/test_tutorial/test_dependencies/test_tutorial007.py @@ -2,7 +2,7 @@ import asyncio from contextlib import asynccontextmanager from unittest.mock import Mock, patch -from docs_src.dependencies.tutorial007_py39 import get_db +from docs_src.dependencies.tutorial007_py310 import get_db def test_get_db(): # Just for coverage @@ -14,7 +14,7 @@ def test_get_db(): # Just for coverage dbsession_moock = Mock() with patch( - "docs_src.dependencies.tutorial007_py39.DBSession", + "docs_src.dependencies.tutorial007_py310.DBSession", return_value=dbsession_moock, create=True, ): diff --git a/tests/test_tutorial/test_dependencies/test_tutorial008.py b/tests/test_tutorial/test_dependencies/test_tutorial008.py index 5a2d226bf..e23ac0ac5 100644 --- a/tests/test_tutorial/test_dependencies/test_tutorial008.py +++ b/tests/test_tutorial/test_dependencies/test_tutorial008.py @@ -12,9 +12,9 @@ from fastapi.testclient import TestClient @pytest.fixture( name="module", params=[ - "tutorial008_py39", + "tutorial008_py310", pytest.param( - "tutorial008_an_py39", + "tutorial008_an_py310", marks=pytest.mark.xfail( sys.version_info < (3, 14), reason="Fails with `NameError: name 'DepA' is not defined`", diff --git a/tests/test_tutorial/test_dependencies/test_tutorial008b.py b/tests/test_tutorial/test_dependencies/test_tutorial008b.py index 91e00b370..d2493d0cc 100644 --- a/tests/test_tutorial/test_dependencies/test_tutorial008b.py +++ b/tests/test_tutorial/test_dependencies/test_tutorial008b.py @@ -7,8 +7,8 @@ from fastapi.testclient import TestClient @pytest.fixture( name="client", params=[ - pytest.param("tutorial008b_py39"), - pytest.param("tutorial008b_an_py39"), + pytest.param("tutorial008b_py310"), + pytest.param("tutorial008b_an_py310"), ], ) def get_client(request: pytest.FixtureRequest): diff --git a/tests/test_tutorial/test_dependencies/test_tutorial008c.py b/tests/test_tutorial/test_dependencies/test_tutorial008c.py index aede6f8d2..b7713c73b 100644 --- a/tests/test_tutorial/test_dependencies/test_tutorial008c.py +++ b/tests/test_tutorial/test_dependencies/test_tutorial008c.py @@ -9,8 +9,8 @@ from fastapi.testclient import TestClient @pytest.fixture( name="mod", params=[ - pytest.param("tutorial008c_py39"), - pytest.param("tutorial008c_an_py39"), + pytest.param("tutorial008c_py310"), + pytest.param("tutorial008c_an_py310"), ], ) def get_mod(request: pytest.FixtureRequest): diff --git a/tests/test_tutorial/test_dependencies/test_tutorial008d.py b/tests/test_tutorial/test_dependencies/test_tutorial008d.py index 5477f8b95..e831c055e 100644 --- a/tests/test_tutorial/test_dependencies/test_tutorial008d.py +++ b/tests/test_tutorial/test_dependencies/test_tutorial008d.py @@ -8,8 +8,8 @@ from fastapi.testclient import TestClient @pytest.fixture( name="mod", params=[ - pytest.param("tutorial008d_py39"), - pytest.param("tutorial008d_an_py39"), + pytest.param("tutorial008d_py310"), + pytest.param("tutorial008d_an_py310"), ], ) def get_mod(request: pytest.FixtureRequest): diff --git a/tests/test_tutorial/test_dependencies/test_tutorial008e.py b/tests/test_tutorial/test_dependencies/test_tutorial008e.py index c433157ea..18eba9f77 100644 --- a/tests/test_tutorial/test_dependencies/test_tutorial008e.py +++ b/tests/test_tutorial/test_dependencies/test_tutorial008e.py @@ -7,8 +7,8 @@ from fastapi.testclient import TestClient @pytest.fixture( name="client", params=[ - pytest.param("tutorial008e_py39"), - pytest.param("tutorial008e_an_py39"), + pytest.param("tutorial008e_py310"), + pytest.param("tutorial008e_an_py310"), ], ) def get_client(request: pytest.FixtureRequest): diff --git a/tests/test_tutorial/test_dependencies/test_tutorial010.py b/tests/test_tutorial/test_dependencies/test_tutorial010.py index 6d3815ada..954d09f20 100644 --- a/tests/test_tutorial/test_dependencies/test_tutorial010.py +++ b/tests/test_tutorial/test_dependencies/test_tutorial010.py @@ -4,7 +4,7 @@ from unittest.mock import Mock, patch from fastapi import Depends, FastAPI from fastapi.testclient import TestClient -from docs_src.dependencies.tutorial010_py39 import get_db +from docs_src.dependencies.tutorial010_py310 import get_db def test_get_db(): @@ -19,7 +19,7 @@ def test_get_db(): dbsession_mock = Mock() with patch( - "docs_src.dependencies.tutorial010_py39.DBSession", + "docs_src.dependencies.tutorial010_py310.DBSession", return_value=dbsession_mock, create=True, ): diff --git a/tests/test_tutorial/test_dependencies/test_tutorial011.py b/tests/test_tutorial/test_dependencies/test_tutorial011.py index 383422a7e..16167fd2e 100644 --- a/tests/test_tutorial/test_dependencies/test_tutorial011.py +++ b/tests/test_tutorial/test_dependencies/test_tutorial011.py @@ -8,8 +8,8 @@ from inline_snapshot import snapshot @pytest.fixture( name="client", params=[ - "tutorial011_py39", - pytest.param("tutorial011_an_py39"), + "tutorial011_py310", + pytest.param("tutorial011_an_py310"), ], ) def get_client(request: pytest.FixtureRequest): diff --git a/tests/test_tutorial/test_dependencies/test_tutorial012.py b/tests/test_tutorial/test_dependencies/test_tutorial012.py index a15688924..e0148e052 100644 --- a/tests/test_tutorial/test_dependencies/test_tutorial012.py +++ b/tests/test_tutorial/test_dependencies/test_tutorial012.py @@ -8,8 +8,8 @@ from inline_snapshot import snapshot @pytest.fixture( name="client", params=[ - pytest.param("tutorial012_py39"), - pytest.param("tutorial012_an_py39"), + pytest.param("tutorial012_py310"), + pytest.param("tutorial012_an_py310"), ], ) def get_client(request: pytest.FixtureRequest): diff --git a/tests/test_tutorial/test_encoder/test_tutorial001.py b/tests/test_tutorial/test_encoder/test_tutorial001.py index a3d672333..e8c1f3c73 100644 --- a/tests/test_tutorial/test_encoder/test_tutorial001.py +++ b/tests/test_tutorial/test_encoder/test_tutorial001.py @@ -11,7 +11,6 @@ from ...utils import needs_py310 @pytest.fixture( name="mod", params=[ - pytest.param("tutorial001_py39"), pytest.param("tutorial001_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_events/test_tutorial001.py b/tests/test_tutorial/test_events/test_tutorial001.py index 63215c00d..e392cdcc9 100644 --- a/tests/test_tutorial/test_events/test_tutorial001.py +++ b/tests/test_tutorial/test_events/test_tutorial001.py @@ -7,7 +7,7 @@ from inline_snapshot import snapshot @pytest.fixture(name="app", scope="module") def get_app(): with pytest.warns(DeprecationWarning): - from docs_src.events.tutorial001_py39 import app + from docs_src.events.tutorial001_py310 import app yield app diff --git a/tests/test_tutorial/test_events/test_tutorial002.py b/tests/test_tutorial/test_events/test_tutorial002.py index f98d8921f..47af7a952 100644 --- a/tests/test_tutorial/test_events/test_tutorial002.py +++ b/tests/test_tutorial/test_events/test_tutorial002.py @@ -7,7 +7,7 @@ from inline_snapshot import snapshot @pytest.fixture(name="app", scope="module") def get_app(): with pytest.warns(DeprecationWarning): - from docs_src.events.tutorial002_py39 import app + from docs_src.events.tutorial002_py310 import app yield app diff --git a/tests/test_tutorial/test_events/test_tutorial003.py b/tests/test_tutorial/test_events/test_tutorial003.py index 4fc848e11..3da0b2ca5 100644 --- a/tests/test_tutorial/test_events/test_tutorial003.py +++ b/tests/test_tutorial/test_events/test_tutorial003.py @@ -1,7 +1,7 @@ from fastapi.testclient import TestClient from inline_snapshot import snapshot -from docs_src.events.tutorial003_py39 import ( +from docs_src.events.tutorial003_py310 import ( app, fake_answer_to_everything_ml_model, ml_models, diff --git a/tests/test_tutorial/test_extending_openapi/test_tutorial001.py b/tests/test_tutorial/test_extending_openapi/test_tutorial001.py index bc10c888c..06c56565f 100644 --- a/tests/test_tutorial/test_extending_openapi/test_tutorial001.py +++ b/tests/test_tutorial/test_extending_openapi/test_tutorial001.py @@ -1,7 +1,7 @@ from fastapi.testclient import TestClient from inline_snapshot import snapshot -from docs_src.extending_openapi.tutorial001_py39 import app +from docs_src.extending_openapi.tutorial001_py310 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_extra_data_types/test_tutorial001.py b/tests/test_tutorial/test_extra_data_types/test_tutorial001.py index 28fe68f28..2e7f0e522 100644 --- a/tests/test_tutorial/test_extra_data_types/test_tutorial001.py +++ b/tests/test_tutorial/test_extra_data_types/test_tutorial001.py @@ -10,9 +10,7 @@ from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - pytest.param("tutorial001_py39"), pytest.param("tutorial001_py310", marks=needs_py310), - pytest.param("tutorial001_an_py39"), pytest.param("tutorial001_an_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_extra_models/test_tutorial001_tutorial002.py b/tests/test_tutorial/test_extra_models/test_tutorial001_tutorial002.py index 4248878b5..4fcb7ff78 100644 --- a/tests/test_tutorial/test_extra_models/test_tutorial001_tutorial002.py +++ b/tests/test_tutorial/test_extra_models/test_tutorial001_tutorial002.py @@ -11,9 +11,7 @@ from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - pytest.param("tutorial001_py39"), pytest.param("tutorial001_py310", marks=needs_py310), - pytest.param("tutorial002_py39"), pytest.param("tutorial002_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_extra_models/test_tutorial003.py b/tests/test_tutorial/test_extra_models/test_tutorial003.py index 38e874158..2a2cf8afa 100644 --- a/tests/test_tutorial/test_extra_models/test_tutorial003.py +++ b/tests/test_tutorial/test_extra_models/test_tutorial003.py @@ -10,7 +10,6 @@ from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - pytest.param("tutorial003_py39"), pytest.param("tutorial003_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_extra_models/test_tutorial004.py b/tests/test_tutorial/test_extra_models/test_tutorial004.py index c64371e3b..3ded20959 100644 --- a/tests/test_tutorial/test_extra_models/test_tutorial004.py +++ b/tests/test_tutorial/test_extra_models/test_tutorial004.py @@ -8,7 +8,7 @@ from inline_snapshot import snapshot @pytest.fixture( name="client", params=[ - pytest.param("tutorial004_py39"), + pytest.param("tutorial004_py310"), ], ) def get_client(request: pytest.FixtureRequest): diff --git a/tests/test_tutorial/test_extra_models/test_tutorial005.py b/tests/test_tutorial/test_extra_models/test_tutorial005.py index 43b8bae8e..265b76832 100644 --- a/tests/test_tutorial/test_extra_models/test_tutorial005.py +++ b/tests/test_tutorial/test_extra_models/test_tutorial005.py @@ -8,7 +8,7 @@ from inline_snapshot import snapshot @pytest.fixture( name="client", params=[ - pytest.param("tutorial005_py39"), + pytest.param("tutorial005_py310"), ], ) def get_client(request: pytest.FixtureRequest): diff --git a/tests/test_tutorial/test_first_steps/test_tutorial001_tutorial002_tutorial003.py b/tests/test_tutorial/test_first_steps/test_tutorial001_tutorial002_tutorial003.py index 5457ad132..30eab21e9 100644 --- a/tests/test_tutorial/test_first_steps/test_tutorial001_tutorial002_tutorial003.py +++ b/tests/test_tutorial/test_first_steps/test_tutorial001_tutorial002_tutorial003.py @@ -8,8 +8,8 @@ from inline_snapshot import snapshot @pytest.fixture( name="client", params=[ - "tutorial001_py39", - "tutorial003_py39", + "tutorial001_py310", + "tutorial003_py310", ], ) def get_client(request: pytest.FixtureRequest): diff --git a/tests/test_tutorial/test_generate_clients/test_tutorial001.py b/tests/test_tutorial/test_generate_clients/test_tutorial001.py index 62799d259..40ed3eeea 100644 --- a/tests/test_tutorial/test_generate_clients/test_tutorial001.py +++ b/tests/test_tutorial/test_generate_clients/test_tutorial001.py @@ -8,7 +8,7 @@ from inline_snapshot import snapshot @pytest.fixture( name="client", params=[ - pytest.param("tutorial001_py39"), + pytest.param("tutorial001_py310"), ], ) def get_client(request: pytest.FixtureRequest): diff --git a/tests/test_tutorial/test_generate_clients/test_tutorial002.py b/tests/test_tutorial/test_generate_clients/test_tutorial002.py index f64f5f866..6557b8c27 100644 --- a/tests/test_tutorial/test_generate_clients/test_tutorial002.py +++ b/tests/test_tutorial/test_generate_clients/test_tutorial002.py @@ -1,7 +1,7 @@ from fastapi.testclient import TestClient from inline_snapshot import snapshot -from docs_src.generate_clients.tutorial002_py39 import app +from docs_src.generate_clients.tutorial002_py310 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_generate_clients/test_tutorial003.py b/tests/test_tutorial/test_generate_clients/test_tutorial003.py index 34ede6194..cded241ae 100644 --- a/tests/test_tutorial/test_generate_clients/test_tutorial003.py +++ b/tests/test_tutorial/test_generate_clients/test_tutorial003.py @@ -1,7 +1,7 @@ from fastapi.testclient import TestClient from inline_snapshot import snapshot -from docs_src.generate_clients.tutorial003_py39 import app +from docs_src.generate_clients.tutorial003_py310 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_generate_clients/test_tutorial004.py b/tests/test_tutorial/test_generate_clients/test_tutorial004.py index d04bfbfe8..1d71de869 100644 --- a/tests/test_tutorial/test_generate_clients/test_tutorial004.py +++ b/tests/test_tutorial/test_generate_clients/test_tutorial004.py @@ -5,16 +5,16 @@ from unittest.mock import patch from inline_snapshot import snapshot -from docs_src.generate_clients import tutorial003_py39 +from docs_src.generate_clients import tutorial003_py310 def test_remove_tags(tmp_path: pathlib.Path): tmp_file = tmp_path / "openapi.json" - openapi_json = tutorial003_py39.app.openapi() + openapi_json = tutorial003_py310.app.openapi() tmp_file.write_text(json.dumps(openapi_json)) with patch("pathlib.Path", return_value=tmp_file): - importlib.import_module("docs_src.generate_clients.tutorial004_py39") + importlib.import_module("docs_src.generate_clients.tutorial004_py310") modified_openapi = json.loads(tmp_file.read_text()) assert modified_openapi == snapshot( diff --git a/tests/test_tutorial/test_graphql/test_tutorial001.py b/tests/test_tutorial/test_graphql/test_tutorial001.py index cc3be6a19..c93347081 100644 --- a/tests/test_tutorial/test_graphql/test_tutorial001.py +++ b/tests/test_tutorial/test_graphql/test_tutorial001.py @@ -10,7 +10,7 @@ warnings.filterwarnings( category=DeprecationWarning, ) -from docs_src.graphql_.tutorial001_py39 import app # noqa: E402 +from docs_src.graphql_.tutorial001_py310 import app # noqa: E402 @pytest.fixture(name="client") diff --git a/tests/test_tutorial/test_handling_errors/test_tutorial001.py b/tests/test_tutorial/test_handling_errors/test_tutorial001.py index 8283cdc73..001a02a0f 100644 --- a/tests/test_tutorial/test_handling_errors/test_tutorial001.py +++ b/tests/test_tutorial/test_handling_errors/test_tutorial001.py @@ -1,7 +1,7 @@ from fastapi.testclient import TestClient from inline_snapshot import snapshot -from docs_src.handling_errors.tutorial001_py39 import app +from docs_src.handling_errors.tutorial001_py310 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_handling_errors/test_tutorial002.py b/tests/test_tutorial/test_handling_errors/test_tutorial002.py index c437693d3..0e7321ee7 100644 --- a/tests/test_tutorial/test_handling_errors/test_tutorial002.py +++ b/tests/test_tutorial/test_handling_errors/test_tutorial002.py @@ -1,7 +1,7 @@ from fastapi.testclient import TestClient from inline_snapshot import snapshot -from docs_src.handling_errors.tutorial002_py39 import app +from docs_src.handling_errors.tutorial002_py310 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_handling_errors/test_tutorial003.py b/tests/test_tutorial/test_handling_errors/test_tutorial003.py index 959729e53..cc11985be 100644 --- a/tests/test_tutorial/test_handling_errors/test_tutorial003.py +++ b/tests/test_tutorial/test_handling_errors/test_tutorial003.py @@ -1,7 +1,7 @@ from fastapi.testclient import TestClient from inline_snapshot import snapshot -from docs_src.handling_errors.tutorial003_py39 import app +from docs_src.handling_errors.tutorial003_py310 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_handling_errors/test_tutorial004.py b/tests/test_tutorial/test_handling_errors/test_tutorial004.py index 16165bb3d..5471cb0d8 100644 --- a/tests/test_tutorial/test_handling_errors/test_tutorial004.py +++ b/tests/test_tutorial/test_handling_errors/test_tutorial004.py @@ -1,7 +1,7 @@ from fastapi.testclient import TestClient from inline_snapshot import snapshot -from docs_src.handling_errors.tutorial004_py39 import app +from docs_src.handling_errors.tutorial004_py310 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_handling_errors/test_tutorial005.py b/tests/test_tutorial/test_handling_errors/test_tutorial005.py index af924a9f7..c04b510c3 100644 --- a/tests/test_tutorial/test_handling_errors/test_tutorial005.py +++ b/tests/test_tutorial/test_handling_errors/test_tutorial005.py @@ -1,7 +1,7 @@ from fastapi.testclient import TestClient from inline_snapshot import snapshot -from docs_src.handling_errors.tutorial005_py39 import app +from docs_src.handling_errors.tutorial005_py310 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_handling_errors/test_tutorial006.py b/tests/test_tutorial/test_handling_errors/test_tutorial006.py index 4c069d81e..666e44f3a 100644 --- a/tests/test_tutorial/test_handling_errors/test_tutorial006.py +++ b/tests/test_tutorial/test_handling_errors/test_tutorial006.py @@ -1,7 +1,7 @@ from fastapi.testclient import TestClient from inline_snapshot import snapshot -from docs_src.handling_errors.tutorial006_py39 import app +from docs_src.handling_errors.tutorial006_py310 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_header_param_models/test_tutorial001.py b/tests/test_tutorial/test_header_param_models/test_tutorial001.py index 2d14c698e..8391bd119 100644 --- a/tests/test_tutorial/test_header_param_models/test_tutorial001.py +++ b/tests/test_tutorial/test_header_param_models/test_tutorial001.py @@ -10,9 +10,7 @@ from tests.utils import needs_py310 @pytest.fixture( name="client", params=[ - pytest.param("tutorial001_py39"), pytest.param("tutorial001_py310", marks=needs_py310), - pytest.param("tutorial001_an_py39"), pytest.param("tutorial001_an_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_header_param_models/test_tutorial002.py b/tests/test_tutorial/test_header_param_models/test_tutorial002.py index 478ac8408..3d66dca08 100644 --- a/tests/test_tutorial/test_header_param_models/test_tutorial002.py +++ b/tests/test_tutorial/test_header_param_models/test_tutorial002.py @@ -10,9 +10,7 @@ from tests.utils import needs_py310 @pytest.fixture( name="client", params=[ - pytest.param("tutorial002_py39"), pytest.param("tutorial002_py310", marks=[needs_py310]), - pytest.param("tutorial002_an_py39"), pytest.param("tutorial002_an_py310", marks=[needs_py310]), ], ) diff --git a/tests/test_tutorial/test_header_param_models/test_tutorial003.py b/tests/test_tutorial/test_header_param_models/test_tutorial003.py index 00636c2b5..7d0da24fd 100644 --- a/tests/test_tutorial/test_header_param_models/test_tutorial003.py +++ b/tests/test_tutorial/test_header_param_models/test_tutorial003.py @@ -10,9 +10,7 @@ from tests.utils import needs_py310 @pytest.fixture( name="client", params=[ - pytest.param("tutorial003_py39"), pytest.param("tutorial003_py310", marks=needs_py310), - pytest.param("tutorial003_an_py39"), pytest.param("tutorial003_an_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_header_params/test_tutorial001.py b/tests/test_tutorial/test_header_params/test_tutorial001.py index 2e97a8322..900d35adc 100644 --- a/tests/test_tutorial/test_header_params/test_tutorial001.py +++ b/tests/test_tutorial/test_header_params/test_tutorial001.py @@ -10,9 +10,7 @@ from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - pytest.param("tutorial001_py39"), pytest.param("tutorial001_py310", marks=needs_py310), - pytest.param("tutorial001_an_py39"), pytest.param("tutorial001_an_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_header_params/test_tutorial002.py b/tests/test_tutorial/test_header_params/test_tutorial002.py index ba86c55bf..c756eae71 100644 --- a/tests/test_tutorial/test_header_params/test_tutorial002.py +++ b/tests/test_tutorial/test_header_params/test_tutorial002.py @@ -10,9 +10,7 @@ from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - pytest.param("tutorial002_py39"), pytest.param("tutorial002_py310", marks=needs_py310), - pytest.param("tutorial002_an_py39"), pytest.param("tutorial002_an_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_header_params/test_tutorial003.py b/tests/test_tutorial/test_header_params/test_tutorial003.py index 30e5133c0..1f71322b6 100644 --- a/tests/test_tutorial/test_header_params/test_tutorial003.py +++ b/tests/test_tutorial/test_header_params/test_tutorial003.py @@ -10,9 +10,7 @@ from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - pytest.param("tutorial003_py39"), pytest.param("tutorial003_py310", marks=needs_py310), - pytest.param("tutorial003_an_py39"), pytest.param("tutorial003_an_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_metadata/test_tutorial001.py b/tests/test_tutorial/test_metadata/test_tutorial001.py index ba3c09ce4..ce0c1643a 100644 --- a/tests/test_tutorial/test_metadata/test_tutorial001.py +++ b/tests/test_tutorial/test_metadata/test_tutorial001.py @@ -1,7 +1,7 @@ from fastapi.testclient import TestClient from inline_snapshot import snapshot -from docs_src.metadata.tutorial001_py39 import app +from docs_src.metadata.tutorial001_py310 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_metadata/test_tutorial001_1.py b/tests/test_tutorial/test_metadata/test_tutorial001_1.py index 933954973..ba9ba9dcb 100644 --- a/tests/test_tutorial/test_metadata/test_tutorial001_1.py +++ b/tests/test_tutorial/test_metadata/test_tutorial001_1.py @@ -1,7 +1,7 @@ from fastapi.testclient import TestClient from inline_snapshot import snapshot -from docs_src.metadata.tutorial001_1_py39 import app +from docs_src.metadata.tutorial001_1_py310 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_metadata/test_tutorial002.py b/tests/test_tutorial/test_metadata/test_tutorial002.py index 5a252475e..979a6a7b8 100644 --- a/tests/test_tutorial/test_metadata/test_tutorial002.py +++ b/tests/test_tutorial/test_metadata/test_tutorial002.py @@ -1,7 +1,7 @@ from fastapi.testclient import TestClient from inline_snapshot import snapshot -from docs_src.metadata.tutorial002_py39 import app +from docs_src.metadata.tutorial002_py310 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_metadata/test_tutorial003.py b/tests/test_tutorial/test_metadata/test_tutorial003.py index 778781e66..ee2978028 100644 --- a/tests/test_tutorial/test_metadata/test_tutorial003.py +++ b/tests/test_tutorial/test_metadata/test_tutorial003.py @@ -1,7 +1,7 @@ from fastapi.testclient import TestClient from inline_snapshot import snapshot -from docs_src.metadata.tutorial003_py39 import app +from docs_src.metadata.tutorial003_py310 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_metadata/test_tutorial004.py b/tests/test_tutorial/test_metadata/test_tutorial004.py index 5c309a830..ef0533d50 100644 --- a/tests/test_tutorial/test_metadata/test_tutorial004.py +++ b/tests/test_tutorial/test_metadata/test_tutorial004.py @@ -1,7 +1,7 @@ from fastapi.testclient import TestClient from inline_snapshot import snapshot -from docs_src.metadata.tutorial004_py39 import app +from docs_src.metadata.tutorial004_py310 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_middleware/test_tutorial001.py b/tests/test_tutorial/test_middleware/test_tutorial001.py index 18047f343..1fa1e5a50 100644 --- a/tests/test_tutorial/test_middleware/test_tutorial001.py +++ b/tests/test_tutorial/test_middleware/test_tutorial001.py @@ -1,7 +1,7 @@ from fastapi.testclient import TestClient from inline_snapshot import snapshot -from docs_src.middleware.tutorial001_py39 import app +from docs_src.middleware.tutorial001_py310 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_openapi_callbacks/test_tutorial001.py b/tests/test_tutorial/test_openapi_callbacks/test_tutorial001.py index 1e937d0c9..62374ef27 100644 --- a/tests/test_tutorial/test_openapi_callbacks/test_tutorial001.py +++ b/tests/test_tutorial/test_openapi_callbacks/test_tutorial001.py @@ -11,7 +11,6 @@ from tests.utils import needs_py310 @pytest.fixture( name="mod", params=[ - pytest.param("tutorial001_py39"), pytest.param("tutorial001_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_openapi_webhooks/test_tutorial001.py b/tests/test_tutorial/test_openapi_webhooks/test_tutorial001.py index 0482c94bf..696a2bed5 100644 --- a/tests/test_tutorial/test_openapi_webhooks/test_tutorial001.py +++ b/tests/test_tutorial/test_openapi_webhooks/test_tutorial001.py @@ -1,7 +1,7 @@ from fastapi.testclient import TestClient from inline_snapshot import snapshot -from docs_src.openapi_webhooks.tutorial001_py39 import app +from docs_src.openapi_webhooks.tutorial001_py310 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial001.py b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial001.py index 3a4f64824..ecda8a315 100644 --- a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial001.py +++ b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial001.py @@ -1,7 +1,7 @@ from fastapi.testclient import TestClient from inline_snapshot import snapshot -from docs_src.path_operation_advanced_configuration.tutorial001_py39 import app +from docs_src.path_operation_advanced_configuration.tutorial001_py310 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial002.py b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial002.py index c26c36030..c5067e233 100644 --- a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial002.py +++ b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial002.py @@ -1,7 +1,7 @@ from fastapi.testclient import TestClient from inline_snapshot import snapshot -from docs_src.path_operation_advanced_configuration.tutorial002_py39 import app +from docs_src.path_operation_advanced_configuration.tutorial002_py310 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial003.py b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial003.py index f060647b2..36fe21678 100644 --- a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial003.py +++ b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial003.py @@ -1,7 +1,7 @@ from fastapi.testclient import TestClient from inline_snapshot import snapshot -from docs_src.path_operation_advanced_configuration.tutorial003_py39 import app +from docs_src.path_operation_advanced_configuration.tutorial003_py310 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial004.py b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial004.py index bf7934544..894cd9749 100644 --- a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial004.py +++ b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial004.py @@ -10,7 +10,6 @@ from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - pytest.param("tutorial004_py39"), pytest.param("tutorial004_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial005.py b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial005.py index 779e54f9e..f129ec6f4 100644 --- a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial005.py +++ b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial005.py @@ -1,7 +1,7 @@ from fastapi.testclient import TestClient from inline_snapshot import snapshot -from docs_src.path_operation_advanced_configuration.tutorial005_py39 import app +from docs_src.path_operation_advanced_configuration.tutorial005_py310 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial006.py b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial006.py index d63b5f912..f3bf2b5bf 100644 --- a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial006.py +++ b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial006.py @@ -1,7 +1,7 @@ from fastapi.testclient import TestClient from inline_snapshot import snapshot -from docs_src.path_operation_advanced_configuration.tutorial006_py39 import app +from docs_src.path_operation_advanced_configuration.tutorial006_py310 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial007.py b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial007.py index ec0c91bda..ad06e6c05 100644 --- a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial007.py +++ b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial007.py @@ -8,7 +8,7 @@ from inline_snapshot import snapshot @pytest.fixture( name="client", params=[ - pytest.param("tutorial007_py39"), + pytest.param("tutorial007_py310"), ], ) def get_client(request: pytest.FixtureRequest): diff --git a/tests/test_tutorial/test_path_operation_configurations/test_tutorial001.py b/tests/test_tutorial/test_path_operation_configurations/test_tutorial001.py index 500cb057c..1b81b6f86 100644 --- a/tests/test_tutorial/test_path_operation_configurations/test_tutorial001.py +++ b/tests/test_tutorial/test_path_operation_configurations/test_tutorial001.py @@ -11,7 +11,6 @@ from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - pytest.param("tutorial001_py39"), pytest.param("tutorial001_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_path_operation_configurations/test_tutorial002.py b/tests/test_tutorial/test_path_operation_configurations/test_tutorial002.py index 1cc560cb9..675f3b1ae 100644 --- a/tests/test_tutorial/test_path_operation_configurations/test_tutorial002.py +++ b/tests/test_tutorial/test_path_operation_configurations/test_tutorial002.py @@ -11,7 +11,6 @@ from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - pytest.param("tutorial002_py39"), pytest.param("tutorial002_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_path_operation_configurations/test_tutorial002b.py b/tests/test_tutorial/test_path_operation_configurations/test_tutorial002b.py index 98319645c..f9a5ff760 100644 --- a/tests/test_tutorial/test_path_operation_configurations/test_tutorial002b.py +++ b/tests/test_tutorial/test_path_operation_configurations/test_tutorial002b.py @@ -1,7 +1,7 @@ from fastapi.testclient import TestClient from inline_snapshot import snapshot -from docs_src.path_operation_configuration.tutorial002b_py39 import app +from docs_src.path_operation_configuration.tutorial002b_py310 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_path_operation_configurations/test_tutorial003_tutorial004.py b/tests/test_tutorial/test_path_operation_configurations/test_tutorial003_tutorial004.py index c13a3c38c..6d1afecc8 100644 --- a/tests/test_tutorial/test_path_operation_configurations/test_tutorial003_tutorial004.py +++ b/tests/test_tutorial/test_path_operation_configurations/test_tutorial003_tutorial004.py @@ -25,9 +25,7 @@ DESCRIPTIONS = { @pytest.fixture( name="mod_name", params=[ - pytest.param("tutorial003_py39"), pytest.param("tutorial003_py310", marks=needs_py310), - pytest.param("tutorial004_py39"), pytest.param("tutorial004_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_path_operation_configurations/test_tutorial005.py b/tests/test_tutorial/test_path_operation_configurations/test_tutorial005.py index 07152755f..b186c0a68 100644 --- a/tests/test_tutorial/test_path_operation_configurations/test_tutorial005.py +++ b/tests/test_tutorial/test_path_operation_configurations/test_tutorial005.py @@ -10,7 +10,6 @@ from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - pytest.param("tutorial005_py39"), pytest.param("tutorial005_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_path_operation_configurations/test_tutorial006.py b/tests/test_tutorial/test_path_operation_configurations/test_tutorial006.py index 5f56ab929..27a93f563 100644 --- a/tests/test_tutorial/test_path_operation_configurations/test_tutorial006.py +++ b/tests/test_tutorial/test_path_operation_configurations/test_tutorial006.py @@ -2,7 +2,7 @@ import pytest from fastapi.testclient import TestClient from inline_snapshot import snapshot -from docs_src.path_operation_configuration.tutorial006_py39 import app +from docs_src.path_operation_configuration.tutorial006_py310 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_path_params/test_tutorial001.py b/tests/test_tutorial/test_path_params/test_tutorial001.py index ec598832b..75c47c855 100644 --- a/tests/test_tutorial/test_path_params/test_tutorial001.py +++ b/tests/test_tutorial/test_path_params/test_tutorial001.py @@ -2,7 +2,7 @@ import pytest from fastapi.testclient import TestClient from inline_snapshot import snapshot -from docs_src.path_params.tutorial001_py39 import app +from docs_src.path_params.tutorial001_py310 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_path_params/test_tutorial002.py b/tests/test_tutorial/test_path_params/test_tutorial002.py index 8384ec8ef..416c70558 100644 --- a/tests/test_tutorial/test_path_params/test_tutorial002.py +++ b/tests/test_tutorial/test_path_params/test_tutorial002.py @@ -1,7 +1,7 @@ from fastapi.testclient import TestClient from inline_snapshot import snapshot -from docs_src.path_params.tutorial002_py39 import app +from docs_src.path_params.tutorial002_py310 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_path_params/test_tutorial003.py b/tests/test_tutorial/test_path_params/test_tutorial003.py index 432ccde49..2c07ebbc8 100644 --- a/tests/test_tutorial/test_path_params/test_tutorial003.py +++ b/tests/test_tutorial/test_path_params/test_tutorial003.py @@ -2,7 +2,7 @@ import pytest from fastapi.testclient import TestClient from inline_snapshot import snapshot -from docs_src.path_params.tutorial003_py39 import app +from docs_src.path_params.tutorial003_py310 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_path_params/test_tutorial003b.py b/tests/test_tutorial/test_path_params/test_tutorial003b.py index 1cf39eca9..debf98503 100644 --- a/tests/test_tutorial/test_path_params/test_tutorial003b.py +++ b/tests/test_tutorial/test_path_params/test_tutorial003b.py @@ -3,7 +3,7 @@ import asyncio from fastapi.testclient import TestClient from inline_snapshot import snapshot -from docs_src.path_params.tutorial003b_py39 import app, read_users2 +from docs_src.path_params.tutorial003b_py310 import app, read_users2 client = TestClient(app) diff --git a/tests/test_tutorial/test_path_params/test_tutorial004.py b/tests/test_tutorial/test_path_params/test_tutorial004.py index b691e821d..2f2a72e64 100644 --- a/tests/test_tutorial/test_path_params/test_tutorial004.py +++ b/tests/test_tutorial/test_path_params/test_tutorial004.py @@ -1,7 +1,7 @@ from fastapi.testclient import TestClient from inline_snapshot import snapshot -from docs_src.path_params.tutorial004_py39 import app +from docs_src.path_params.tutorial004_py310 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_path_params/test_tutorial005.py b/tests/test_tutorial/test_path_params/test_tutorial005.py index c60fee3f0..bf54b59a9 100644 --- a/tests/test_tutorial/test_path_params/test_tutorial005.py +++ b/tests/test_tutorial/test_path_params/test_tutorial005.py @@ -1,7 +1,7 @@ from fastapi.testclient import TestClient from inline_snapshot import snapshot -from docs_src.path_params.tutorial005_py39 import app +from docs_src.path_params.tutorial005_py310 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_path_params_numeric_validations/test_tutorial001.py b/tests/test_tutorial/test_path_params_numeric_validations/test_tutorial001.py index b43de7032..868b0ea78 100644 --- a/tests/test_tutorial/test_path_params_numeric_validations/test_tutorial001.py +++ b/tests/test_tutorial/test_path_params_numeric_validations/test_tutorial001.py @@ -10,9 +10,7 @@ from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - pytest.param("tutorial001_py39"), pytest.param("tutorial001_py310", marks=needs_py310), - pytest.param("tutorial001_an_py39"), pytest.param("tutorial001_an_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_path_params_numeric_validations/test_tutorial002_tutorial003.py b/tests/test_tutorial/test_path_params_numeric_validations/test_tutorial002_tutorial003.py index 1bb2a3ea8..55d5b418c 100644 --- a/tests/test_tutorial/test_path_params_numeric_validations/test_tutorial002_tutorial003.py +++ b/tests/test_tutorial/test_path_params_numeric_validations/test_tutorial002_tutorial003.py @@ -8,10 +8,10 @@ from inline_snapshot import snapshot @pytest.fixture( name="client", params=[ - pytest.param("tutorial002_py39"), - pytest.param("tutorial002_an_py39"), - pytest.param("tutorial003_py39"), - pytest.param("tutorial003_an_py39"), + pytest.param("tutorial002_py310"), + pytest.param("tutorial002_an_py310"), + pytest.param("tutorial003_py310"), + pytest.param("tutorial003_an_py310"), ], ) def get_client(request: pytest.FixtureRequest) -> TestClient: diff --git a/tests/test_tutorial/test_path_params_numeric_validations/test_tutorial004.py b/tests/test_tutorial/test_path_params_numeric_validations/test_tutorial004.py index 37c16d295..7b1272fa1 100644 --- a/tests/test_tutorial/test_path_params_numeric_validations/test_tutorial004.py +++ b/tests/test_tutorial/test_path_params_numeric_validations/test_tutorial004.py @@ -8,8 +8,8 @@ from inline_snapshot import snapshot @pytest.fixture( name="client", params=[ - pytest.param("tutorial004_py39"), - pytest.param("tutorial004_an_py39"), + pytest.param("tutorial004_py310"), + pytest.param("tutorial004_an_py310"), ], ) def get_client(request: pytest.FixtureRequest) -> TestClient: diff --git a/tests/test_tutorial/test_path_params_numeric_validations/test_tutorial005.py b/tests/test_tutorial/test_path_params_numeric_validations/test_tutorial005.py index 0afc9dcbc..d2c9b6077 100644 --- a/tests/test_tutorial/test_path_params_numeric_validations/test_tutorial005.py +++ b/tests/test_tutorial/test_path_params_numeric_validations/test_tutorial005.py @@ -8,8 +8,8 @@ from inline_snapshot import snapshot @pytest.fixture( name="client", params=[ - pytest.param("tutorial005_py39"), - pytest.param("tutorial005_an_py39"), + pytest.param("tutorial005_py310"), + pytest.param("tutorial005_an_py310"), ], ) def get_client(request: pytest.FixtureRequest) -> TestClient: diff --git a/tests/test_tutorial/test_path_params_numeric_validations/test_tutorial006.py b/tests/test_tutorial/test_path_params_numeric_validations/test_tutorial006.py index e0a9694c1..9fb1f8b3b 100644 --- a/tests/test_tutorial/test_path_params_numeric_validations/test_tutorial006.py +++ b/tests/test_tutorial/test_path_params_numeric_validations/test_tutorial006.py @@ -8,8 +8,8 @@ from inline_snapshot import snapshot @pytest.fixture( name="client", params=[ - pytest.param("tutorial006_py39"), - pytest.param("tutorial006_an_py39"), + pytest.param("tutorial006_py310"), + pytest.param("tutorial006_an_py310"), ], ) def get_client(request: pytest.FixtureRequest) -> TestClient: diff --git a/tests/test_tutorial/test_python_types/test_tutorial001_tutorial002.py b/tests/test_tutorial/test_python_types/test_tutorial001_tutorial002.py index ccb096857..d7bf599fe 100644 --- a/tests/test_tutorial/test_python_types/test_tutorial001_tutorial002.py +++ b/tests/test_tutorial/test_python_types/test_tutorial001_tutorial002.py @@ -7,8 +7,8 @@ import pytest @pytest.mark.parametrize( "module_name", [ - "tutorial001_py39", - "tutorial002_py39", + "tutorial001_py310", + "tutorial002_py310", ], ) def test_run_module(module_name: str): diff --git a/tests/test_tutorial/test_python_types/test_tutorial003.py b/tests/test_tutorial/test_python_types/test_tutorial003.py index 34d264917..20b1e7101 100644 --- a/tests/test_tutorial/test_python_types/test_tutorial003.py +++ b/tests/test_tutorial/test_python_types/test_tutorial003.py @@ -1,6 +1,6 @@ import pytest -from docs_src.python_types.tutorial003_py39 import get_name_with_age +from docs_src.python_types.tutorial003_py310 import get_name_with_age def test_get_name_with_age_pass_int(): diff --git a/tests/test_tutorial/test_python_types/test_tutorial004.py b/tests/test_tutorial/test_python_types/test_tutorial004.py index 24af32883..0b16c0cb4 100644 --- a/tests/test_tutorial/test_python_types/test_tutorial004.py +++ b/tests/test_tutorial/test_python_types/test_tutorial004.py @@ -1,4 +1,4 @@ -from docs_src.python_types.tutorial004_py39 import get_name_with_age +from docs_src.python_types.tutorial004_py310 import get_name_with_age def test_get_name_with_age_pass_int(): diff --git a/tests/test_tutorial/test_python_types/test_tutorial005.py b/tests/test_tutorial/test_python_types/test_tutorial005.py index 6d67ec471..b5c847523 100644 --- a/tests/test_tutorial/test_python_types/test_tutorial005.py +++ b/tests/test_tutorial/test_python_types/test_tutorial005.py @@ -1,4 +1,4 @@ -from docs_src.python_types.tutorial005_py39 import get_items +from docs_src.python_types.tutorial005_py310 import get_items def test_get_items(): diff --git a/tests/test_tutorial/test_python_types/test_tutorial006.py b/tests/test_tutorial/test_python_types/test_tutorial006.py index 50976926e..fbe929a76 100644 --- a/tests/test_tutorial/test_python_types/test_tutorial006.py +++ b/tests/test_tutorial/test_python_types/test_tutorial006.py @@ -1,6 +1,6 @@ from unittest.mock import patch -from docs_src.python_types.tutorial006_py39 import process_items +from docs_src.python_types.tutorial006_py310 import process_items def test_process_items(): diff --git a/tests/test_tutorial/test_python_types/test_tutorial007.py b/tests/test_tutorial/test_python_types/test_tutorial007.py index c04529465..b664d2784 100644 --- a/tests/test_tutorial/test_python_types/test_tutorial007.py +++ b/tests/test_tutorial/test_python_types/test_tutorial007.py @@ -1,4 +1,4 @@ -from docs_src.python_types.tutorial007_py39 import process_items +from docs_src.python_types.tutorial007_py310 import process_items def test_process_items(): diff --git a/tests/test_tutorial/test_python_types/test_tutorial008.py b/tests/test_tutorial/test_python_types/test_tutorial008.py index 33cf6cbfb..74a4e9cac 100644 --- a/tests/test_tutorial/test_python_types/test_tutorial008.py +++ b/tests/test_tutorial/test_python_types/test_tutorial008.py @@ -1,6 +1,6 @@ from unittest.mock import patch -from docs_src.python_types.tutorial008_py39 import process_items +from docs_src.python_types.tutorial008_py310 import process_items def test_process_items(): diff --git a/tests/test_tutorial/test_python_types/test_tutorial008b.py b/tests/test_tutorial/test_python_types/test_tutorial008b.py index 1ef0d4ea1..60d7e51c1 100644 --- a/tests/test_tutorial/test_python_types/test_tutorial008b.py +++ b/tests/test_tutorial/test_python_types/test_tutorial008b.py @@ -10,7 +10,7 @@ from ...utils import needs_py310 @pytest.fixture( name="module", params=[ - pytest.param("tutorial008b_py39"), + pytest.param("tutorial008b_py310"), pytest.param("tutorial008b_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_python_types/test_tutorial009_tutorial009b.py b/tests/test_tutorial/test_python_types/test_tutorial009_tutorial009b.py index 34046c5c4..eec51b1be 100644 --- a/tests/test_tutorial/test_python_types/test_tutorial009_tutorial009b.py +++ b/tests/test_tutorial/test_python_types/test_tutorial009_tutorial009b.py @@ -10,9 +10,8 @@ from ...utils import needs_py310 @pytest.fixture( name="module", params=[ - pytest.param("tutorial009_py39"), + pytest.param("tutorial009_py310"), pytest.param("tutorial009_py310", marks=needs_py310), - pytest.param("tutorial009b_py39"), ], ) def get_module(request: pytest.FixtureRequest): diff --git a/tests/test_tutorial/test_python_types/test_tutorial009c.py b/tests/test_tutorial/test_python_types/test_tutorial009c.py index 7bd404911..17c4b9e0c 100644 --- a/tests/test_tutorial/test_python_types/test_tutorial009c.py +++ b/tests/test_tutorial/test_python_types/test_tutorial009c.py @@ -11,7 +11,7 @@ from ...utils import needs_py310 @pytest.fixture( name="module", params=[ - pytest.param("tutorial009c_py39"), + pytest.param("tutorial009c_py310"), pytest.param("tutorial009c_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_python_types/test_tutorial010.py b/tests/test_tutorial/test_python_types/test_tutorial010.py index 9e4d2e36b..8525e6d84 100644 --- a/tests/test_tutorial/test_python_types/test_tutorial010.py +++ b/tests/test_tutorial/test_python_types/test_tutorial010.py @@ -1,4 +1,4 @@ -from docs_src.python_types.tutorial010_py39 import Person, get_person_name +from docs_src.python_types.tutorial010_py310 import Person, get_person_name def test_get_person_name(): diff --git a/tests/test_tutorial/test_python_types/test_tutorial011.py b/tests/test_tutorial/test_python_types/test_tutorial011.py index a05751b97..3761eb924 100644 --- a/tests/test_tutorial/test_python_types/test_tutorial011.py +++ b/tests/test_tutorial/test_python_types/test_tutorial011.py @@ -9,7 +9,6 @@ from ...utils import needs_py310 @pytest.mark.parametrize( "module_name", [ - pytest.param("tutorial011_py39"), pytest.param("tutorial011_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_python_types/test_tutorial012.py b/tests/test_tutorial/test_python_types/test_tutorial012.py deleted file mode 100644 index e57804820..000000000 --- a/tests/test_tutorial/test_python_types/test_tutorial012.py +++ /dev/null @@ -1,7 +0,0 @@ -from docs_src.python_types.tutorial012_py39 import User - - -def test_user(): - user = User(name="John Doe", age=30) - assert user.name == "John Doe" - assert user.age == 30 diff --git a/tests/test_tutorial/test_python_types/test_tutorial013.py b/tests/test_tutorial/test_python_types/test_tutorial013.py index 5602ef76f..d8669b485 100644 --- a/tests/test_tutorial/test_python_types/test_tutorial013.py +++ b/tests/test_tutorial/test_python_types/test_tutorial013.py @@ -1,4 +1,4 @@ -from docs_src.python_types.tutorial013_py39 import say_hello +from docs_src.python_types.tutorial013_py310 import say_hello def test_say_hello(): diff --git a/tests/test_tutorial/test_query_param_models/test_tutorial001.py b/tests/test_tutorial/test_query_param_models/test_tutorial001.py index 38b767154..75d1b9762 100644 --- a/tests/test_tutorial/test_query_param_models/test_tutorial001.py +++ b/tests/test_tutorial/test_query_param_models/test_tutorial001.py @@ -10,9 +10,7 @@ from tests.utils import needs_py310 @pytest.fixture( name="client", params=[ - pytest.param("tutorial001_py39"), pytest.param("tutorial001_py310", marks=needs_py310), - pytest.param("tutorial001_an_py39"), pytest.param("tutorial001_an_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_query_param_models/test_tutorial002.py b/tests/test_tutorial/test_query_param_models/test_tutorial002.py index b173a2df4..da2b6608a 100644 --- a/tests/test_tutorial/test_query_param_models/test_tutorial002.py +++ b/tests/test_tutorial/test_query_param_models/test_tutorial002.py @@ -10,9 +10,7 @@ from tests.utils import needs_py310 @pytest.fixture( name="client", params=[ - pytest.param("tutorial002_py39"), pytest.param("tutorial002_py310", marks=[needs_py310]), - pytest.param("tutorial002_an_py39"), pytest.param("tutorial002_an_py310", marks=[needs_py310]), ], ) diff --git a/tests/test_tutorial/test_query_params/test_tutorial001.py b/tests/test_tutorial/test_query_params/test_tutorial001.py index 40ada0e8e..d68702587 100644 --- a/tests/test_tutorial/test_query_params/test_tutorial001.py +++ b/tests/test_tutorial/test_query_params/test_tutorial001.py @@ -8,7 +8,7 @@ from inline_snapshot import snapshot @pytest.fixture( name="client", params=[ - pytest.param("tutorial001_py39"), + pytest.param("tutorial001_py310"), ], ) def get_client(request: pytest.FixtureRequest): diff --git a/tests/test_tutorial/test_query_params/test_tutorial002.py b/tests/test_tutorial/test_query_params/test_tutorial002.py index 1da308a7e..9be507fba 100644 --- a/tests/test_tutorial/test_query_params/test_tutorial002.py +++ b/tests/test_tutorial/test_query_params/test_tutorial002.py @@ -10,7 +10,6 @@ from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - pytest.param("tutorial002_py39"), pytest.param("tutorial002_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_query_params/test_tutorial003.py b/tests/test_tutorial/test_query_params/test_tutorial003.py index 9bb58ff9f..2951f1adf 100644 --- a/tests/test_tutorial/test_query_params/test_tutorial003.py +++ b/tests/test_tutorial/test_query_params/test_tutorial003.py @@ -10,7 +10,6 @@ from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - pytest.param("tutorial003_py39"), pytest.param("tutorial003_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_query_params/test_tutorial004.py b/tests/test_tutorial/test_query_params/test_tutorial004.py index 20aadb3ac..9786f861f 100644 --- a/tests/test_tutorial/test_query_params/test_tutorial004.py +++ b/tests/test_tutorial/test_query_params/test_tutorial004.py @@ -10,7 +10,6 @@ from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - pytest.param("tutorial004_py39"), pytest.param("tutorial004_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_query_params/test_tutorial005.py b/tests/test_tutorial/test_query_params/test_tutorial005.py index e023fe6d8..b21e97f0b 100644 --- a/tests/test_tutorial/test_query_params/test_tutorial005.py +++ b/tests/test_tutorial/test_query_params/test_tutorial005.py @@ -1,7 +1,7 @@ from fastapi.testclient import TestClient from inline_snapshot import snapshot -from docs_src.query_params.tutorial005_py39 import app +from docs_src.query_params.tutorial005_py310 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_query_params/test_tutorial006.py b/tests/test_tutorial/test_query_params/test_tutorial006.py index b28e12655..a27f2bbb0 100644 --- a/tests/test_tutorial/test_query_params/test_tutorial006.py +++ b/tests/test_tutorial/test_query_params/test_tutorial006.py @@ -10,7 +10,6 @@ from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - pytest.param("tutorial006_py39"), pytest.param("tutorial006_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial001.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial001.py index ed73b7329..1eb424e4f 100644 --- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial001.py +++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial001.py @@ -10,7 +10,6 @@ from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - pytest.param("tutorial001_py39"), pytest.param("tutorial001_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial002.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial002.py index 3eac1f2b3..feb59f169 100644 --- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial002.py +++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial002.py @@ -10,9 +10,7 @@ from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - pytest.param("tutorial002_py39"), pytest.param("tutorial002_py310", marks=needs_py310), - pytest.param("tutorial002_an_py39"), pytest.param("tutorial002_an_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial003.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial003.py index 59d5160ac..4e1ef1da7 100644 --- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial003.py +++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial003.py @@ -10,9 +10,7 @@ from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - pytest.param("tutorial003_py39"), pytest.param("tutorial003_py310", marks=needs_py310), - pytest.param("tutorial003_an_py39"), pytest.param("tutorial003_an_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial004.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial004.py index abf08c932..9c2d442c8 100644 --- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial004.py +++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial004.py @@ -10,19 +10,8 @@ from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - pytest.param("tutorial004_py39"), pytest.param("tutorial004_py310", marks=needs_py310), - pytest.param("tutorial004_an_py39"), pytest.param("tutorial004_an_py310", marks=needs_py310), - pytest.param( - "tutorial004_regex_an_py310", - marks=( - needs_py310, - pytest.mark.filterwarnings( - "ignore:`regex` has been deprecated, please use `pattern` instead:fastapi.exceptions.FastAPIDeprecationWarning" - ), - ), - ), ], ) def get_client(request: pytest.FixtureRequest): diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial005.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial005.py index 7b5368abc..61f07631b 100644 --- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial005.py +++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial005.py @@ -8,8 +8,8 @@ from inline_snapshot import snapshot @pytest.fixture( name="client", params=[ - pytest.param("tutorial005_py39"), - pytest.param("tutorial005_an_py39"), + pytest.param("tutorial005_py310"), + pytest.param("tutorial005_an_py310"), ], ) def get_client(request: pytest.FixtureRequest): diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial006.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial006.py index 2c1df2c08..18ee8dbdc 100644 --- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial006.py +++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial006.py @@ -8,8 +8,8 @@ from inline_snapshot import snapshot @pytest.fixture( name="client", params=[ - pytest.param("tutorial006_py39"), - pytest.param("tutorial006_an_py39"), + pytest.param("tutorial006_py310"), + pytest.param("tutorial006_an_py310"), ], ) def get_client(request: pytest.FixtureRequest): diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial006c.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial006c.py index 3df9efa83..74c10b885 100644 --- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial006c.py +++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial006c.py @@ -10,9 +10,7 @@ from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - pytest.param("tutorial006c_py39"), pytest.param("tutorial006c_py310", marks=needs_py310), - pytest.param("tutorial006c_an_py39"), pytest.param("tutorial006c_an_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial007.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial007.py index 874002b17..3a23ce4a4 100644 --- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial007.py +++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial007.py @@ -10,9 +10,7 @@ from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - pytest.param("tutorial007_py39"), pytest.param("tutorial007_py310", marks=needs_py310), - pytest.param("tutorial007_an_py39"), pytest.param("tutorial007_an_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial008.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial008.py index b9613a17b..430d1bc18 100644 --- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial008.py +++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial008.py @@ -10,9 +10,7 @@ from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - pytest.param("tutorial008_py39"), pytest.param("tutorial008_py310", marks=needs_py310), - pytest.param("tutorial008_an_py39"), pytest.param("tutorial008_an_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial009.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial009.py index d749d85f7..a81e1c40e 100644 --- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial009.py +++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial009.py @@ -10,9 +10,7 @@ from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - pytest.param("tutorial009_py39"), pytest.param("tutorial009_py310", marks=needs_py310), - pytest.param("tutorial009_an_py39"), pytest.param("tutorial009_an_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial010.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial010.py index efe9f1fa6..bb8fbfcee 100644 --- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial010.py +++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial010.py @@ -11,9 +11,7 @@ from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - pytest.param("tutorial010_py39"), pytest.param("tutorial010_py310", marks=needs_py310), - pytest.param("tutorial010_an_py39"), pytest.param("tutorial010_an_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial011.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial011.py index c25357fdd..8d558efec 100644 --- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial011.py +++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial011.py @@ -10,9 +10,7 @@ from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - pytest.param("tutorial011_py39"), pytest.param("tutorial011_py310", marks=needs_py310), - pytest.param("tutorial011_an_py39"), pytest.param("tutorial011_an_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial012.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial012.py index c3d01e90e..5aae7fcc6 100644 --- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial012.py +++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial012.py @@ -8,8 +8,8 @@ from inline_snapshot import snapshot @pytest.fixture( name="client", params=[ - pytest.param("tutorial012_py39"), - pytest.param("tutorial012_an_py39"), + pytest.param("tutorial012_py310"), + pytest.param("tutorial012_an_py310"), ], ) def get_client(request: pytest.FixtureRequest): diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial013.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial013.py index 74efa4695..29d49a5b7 100644 --- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial013.py +++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial013.py @@ -8,8 +8,8 @@ from inline_snapshot import snapshot @pytest.fixture( name="client", params=[ - "tutorial013_py39", - "tutorial013_an_py39", + "tutorial013_py310", + "tutorial013_an_py310", ], ) def get_client(request: pytest.FixtureRequest): diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial014.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial014.py index 6dff18b78..683e39795 100644 --- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial014.py +++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial014.py @@ -10,9 +10,7 @@ from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - pytest.param("tutorial014_py39"), pytest.param("tutorial014_py310", marks=needs_py310), - pytest.param("tutorial014_an_py39"), pytest.param("tutorial014_an_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial015.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial015.py index 32a990e74..01d7c983a 100644 --- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial015.py +++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial015.py @@ -11,7 +11,6 @@ from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - pytest.param("tutorial015_an_py39"), pytest.param("tutorial015_an_py310", marks=[needs_py310]), ], ) diff --git a/tests/test_tutorial/test_request_files/test_tutorial001.py b/tests/test_tutorial/test_request_files/test_tutorial001.py index fd5c3b055..4d3c35d65 100644 --- a/tests/test_tutorial/test_request_files/test_tutorial001.py +++ b/tests/test_tutorial/test_request_files/test_tutorial001.py @@ -8,8 +8,8 @@ from inline_snapshot import snapshot @pytest.fixture( name="client", params=[ - "tutorial001_py39", - "tutorial001_an_py39", + "tutorial001_py310", + "tutorial001_an_py310", ], ) def get_client(request: pytest.FixtureRequest): diff --git a/tests/test_tutorial/test_request_files/test_tutorial001_02.py b/tests/test_tutorial/test_request_files/test_tutorial001_02.py index feeb5363e..f199b992a 100644 --- a/tests/test_tutorial/test_request_files/test_tutorial001_02.py +++ b/tests/test_tutorial/test_request_files/test_tutorial001_02.py @@ -11,9 +11,7 @@ from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - pytest.param("tutorial001_02_py39"), pytest.param("tutorial001_02_py310", marks=needs_py310), - pytest.param("tutorial001_02_an_py39"), pytest.param("tutorial001_02_an_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_request_files/test_tutorial001_03.py b/tests/test_tutorial/test_request_files/test_tutorial001_03.py index 5ef8df178..ce22c1b5c 100644 --- a/tests/test_tutorial/test_request_files/test_tutorial001_03.py +++ b/tests/test_tutorial/test_request_files/test_tutorial001_03.py @@ -8,8 +8,8 @@ from inline_snapshot import snapshot @pytest.fixture( name="client", params=[ - "tutorial001_03_py39", - "tutorial001_03_an_py39", + "tutorial001_03_py310", + "tutorial001_03_an_py310", ], ) def get_client(request: pytest.FixtureRequest): diff --git a/tests/test_tutorial/test_request_files/test_tutorial002.py b/tests/test_tutorial/test_request_files/test_tutorial002.py index 52655fd63..ebf76b3a0 100644 --- a/tests/test_tutorial/test_request_files/test_tutorial002.py +++ b/tests/test_tutorial/test_request_files/test_tutorial002.py @@ -9,8 +9,8 @@ from inline_snapshot import snapshot @pytest.fixture( name="app", params=[ - "tutorial002_py39", - "tutorial002_an_py39", + "tutorial002_py310", + "tutorial002_an_py310", ], ) def get_app(request: pytest.FixtureRequest): diff --git a/tests/test_tutorial/test_request_files/test_tutorial003.py b/tests/test_tutorial/test_request_files/test_tutorial003.py index a1425ba33..f11658d27 100644 --- a/tests/test_tutorial/test_request_files/test_tutorial003.py +++ b/tests/test_tutorial/test_request_files/test_tutorial003.py @@ -9,8 +9,8 @@ from inline_snapshot import snapshot @pytest.fixture( name="app", params=[ - "tutorial003_py39", - "tutorial003_an_py39", + "tutorial003_py310", + "tutorial003_an_py310", ], ) def get_app(request: pytest.FixtureRequest): diff --git a/tests/test_tutorial/test_request_form_models/test_tutorial001.py b/tests/test_tutorial/test_request_form_models/test_tutorial001.py index 68fa074dc..3122e97e8 100644 --- a/tests/test_tutorial/test_request_form_models/test_tutorial001.py +++ b/tests/test_tutorial/test_request_form_models/test_tutorial001.py @@ -8,8 +8,8 @@ from inline_snapshot import snapshot @pytest.fixture( name="client", params=[ - "tutorial001_py39", - "tutorial001_an_py39", + "tutorial001_py310", + "tutorial001_an_py310", ], ) def get_client(request: pytest.FixtureRequest): diff --git a/tests/test_tutorial/test_request_form_models/test_tutorial002.py b/tests/test_tutorial/test_request_form_models/test_tutorial002.py index ed5ae109a..e5dc6e486 100644 --- a/tests/test_tutorial/test_request_form_models/test_tutorial002.py +++ b/tests/test_tutorial/test_request_form_models/test_tutorial002.py @@ -8,8 +8,8 @@ from inline_snapshot import snapshot @pytest.fixture( name="client", params=[ - "tutorial002_py39", - "tutorial002_an_py39", + "tutorial002_py310", + "tutorial002_an_py310", ], ) def get_client(request: pytest.FixtureRequest): diff --git a/tests/test_tutorial/test_request_forms/test_tutorial001.py b/tests/test_tutorial/test_request_forms/test_tutorial001.py index d1596f137..ff3421aac 100644 --- a/tests/test_tutorial/test_request_forms/test_tutorial001.py +++ b/tests/test_tutorial/test_request_forms/test_tutorial001.py @@ -8,8 +8,8 @@ from inline_snapshot import snapshot @pytest.fixture( name="client", params=[ - "tutorial001_py39", - "tutorial001_an_py39", + "tutorial001_py310", + "tutorial001_an_py310", ], ) def get_client(request: pytest.FixtureRequest): diff --git a/tests/test_tutorial/test_request_forms_and_files/test_tutorial001.py b/tests/test_tutorial/test_request_forms_and_files/test_tutorial001.py index 6e9165c42..e2462e040 100644 --- a/tests/test_tutorial/test_request_forms_and_files/test_tutorial001.py +++ b/tests/test_tutorial/test_request_forms_and_files/test_tutorial001.py @@ -9,8 +9,8 @@ from inline_snapshot import snapshot @pytest.fixture( name="app", params=[ - "tutorial001_py39", - "tutorial001_an_py39", + "tutorial001_py310", + "tutorial001_an_py310", ], ) def get_app(request: pytest.FixtureRequest): diff --git a/tests/test_tutorial/test_response_change_status_code/test_tutorial001.py b/tests/test_tutorial/test_response_change_status_code/test_tutorial001.py index 05d5ca619..d046bd266 100644 --- a/tests/test_tutorial/test_response_change_status_code/test_tutorial001.py +++ b/tests/test_tutorial/test_response_change_status_code/test_tutorial001.py @@ -1,6 +1,6 @@ from fastapi.testclient import TestClient -from docs_src.response_change_status_code.tutorial001_py39 import app +from docs_src.response_change_status_code.tutorial001_py310 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_response_cookies/test_tutorial001.py b/tests/test_tutorial/test_response_cookies/test_tutorial001.py index 6b931c8bd..106898339 100644 --- a/tests/test_tutorial/test_response_cookies/test_tutorial001.py +++ b/tests/test_tutorial/test_response_cookies/test_tutorial001.py @@ -1,6 +1,6 @@ from fastapi.testclient import TestClient -from docs_src.response_cookies.tutorial001_py39 import app +from docs_src.response_cookies.tutorial001_py310 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_response_cookies/test_tutorial002.py b/tests/test_tutorial/test_response_cookies/test_tutorial002.py index 3ee5f500c..66812e480 100644 --- a/tests/test_tutorial/test_response_cookies/test_tutorial002.py +++ b/tests/test_tutorial/test_response_cookies/test_tutorial002.py @@ -1,6 +1,6 @@ from fastapi.testclient import TestClient -from docs_src.response_cookies.tutorial002_py39 import app +from docs_src.response_cookies.tutorial002_py310 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_response_directly/test_tutorial001.py b/tests/test_tutorial/test_response_directly/test_tutorial001.py index 2b034f1c9..54406684d 100644 --- a/tests/test_tutorial/test_response_directly/test_tutorial001.py +++ b/tests/test_tutorial/test_response_directly/test_tutorial001.py @@ -10,7 +10,6 @@ from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - pytest.param("tutorial001_py39"), pytest.param("tutorial001_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_response_directly/test_tutorial002.py b/tests/test_tutorial/test_response_directly/test_tutorial002.py index 047e82c14..7dcb8d292 100644 --- a/tests/test_tutorial/test_response_directly/test_tutorial002.py +++ b/tests/test_tutorial/test_response_directly/test_tutorial002.py @@ -8,7 +8,7 @@ from inline_snapshot import snapshot @pytest.fixture( name="client", params=[ - pytest.param("tutorial002_py39"), + pytest.param("tutorial002_py310"), ], ) def get_client(request: pytest.FixtureRequest): diff --git a/tests/test_tutorial/test_response_headers/test_tutorial001.py b/tests/test_tutorial/test_response_headers/test_tutorial001.py index 6232aad23..ea182246f 100644 --- a/tests/test_tutorial/test_response_headers/test_tutorial001.py +++ b/tests/test_tutorial/test_response_headers/test_tutorial001.py @@ -1,6 +1,6 @@ from fastapi.testclient import TestClient -from docs_src.response_headers.tutorial001_py39 import app +from docs_src.response_headers.tutorial001_py310 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_response_headers/test_tutorial002.py b/tests/test_tutorial/test_response_headers/test_tutorial002.py index 2ac2226cb..9b90459cb 100644 --- a/tests/test_tutorial/test_response_headers/test_tutorial002.py +++ b/tests/test_tutorial/test_response_headers/test_tutorial002.py @@ -1,6 +1,6 @@ from fastapi.testclient import TestClient -from docs_src.response_headers.tutorial002_py39 import app +from docs_src.response_headers.tutorial002_py310 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_response_model/test_tutorial001_tutorial001_01.py b/tests/test_tutorial/test_response_model/test_tutorial001_tutorial001_01.py index 914f53783..bbdcc6820 100644 --- a/tests/test_tutorial/test_response_model/test_tutorial001_tutorial001_01.py +++ b/tests/test_tutorial/test_response_model/test_tutorial001_tutorial001_01.py @@ -10,9 +10,7 @@ from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - pytest.param("tutorial001_py39"), pytest.param("tutorial001_py310", marks=needs_py310), - pytest.param("tutorial001_01_py39"), pytest.param("tutorial001_01_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_response_model/test_tutorial002.py b/tests/test_tutorial/test_response_model/test_tutorial002.py index 10a4e37cd..31b465990 100644 --- a/tests/test_tutorial/test_response_model/test_tutorial002.py +++ b/tests/test_tutorial/test_response_model/test_tutorial002.py @@ -10,7 +10,6 @@ from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - pytest.param("tutorial002_py39"), pytest.param("tutorial002_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_response_model/test_tutorial003.py b/tests/test_tutorial/test_response_model/test_tutorial003.py index a1477b7df..8178c8196 100644 --- a/tests/test_tutorial/test_response_model/test_tutorial003.py +++ b/tests/test_tutorial/test_response_model/test_tutorial003.py @@ -10,7 +10,6 @@ from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - pytest.param("tutorial003_py39"), pytest.param("tutorial003_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_response_model/test_tutorial003_01.py b/tests/test_tutorial/test_response_model/test_tutorial003_01.py index a60a14ae8..1a0c4f260 100644 --- a/tests/test_tutorial/test_response_model/test_tutorial003_01.py +++ b/tests/test_tutorial/test_response_model/test_tutorial003_01.py @@ -10,7 +10,6 @@ from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - pytest.param("tutorial003_01_py39"), pytest.param("tutorial003_01_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_response_model/test_tutorial003_02.py b/tests/test_tutorial/test_response_model/test_tutorial003_02.py index 460c88251..a28c56be9 100644 --- a/tests/test_tutorial/test_response_model/test_tutorial003_02.py +++ b/tests/test_tutorial/test_response_model/test_tutorial003_02.py @@ -1,7 +1,7 @@ from fastapi.testclient import TestClient from inline_snapshot import snapshot -from docs_src.response_model.tutorial003_02_py39 import app +from docs_src.response_model.tutorial003_02_py310 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_response_model/test_tutorial003_03.py b/tests/test_tutorial/test_response_model/test_tutorial003_03.py index c83d78c4f..65e747022 100644 --- a/tests/test_tutorial/test_response_model/test_tutorial003_03.py +++ b/tests/test_tutorial/test_response_model/test_tutorial003_03.py @@ -1,7 +1,7 @@ from fastapi.testclient import TestClient from inline_snapshot import snapshot -from docs_src.response_model.tutorial003_03_py39 import app +from docs_src.response_model.tutorial003_03_py310 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_response_model/test_tutorial003_04.py b/tests/test_tutorial/test_response_model/test_tutorial003_04.py index 145af126f..44f2e504e 100644 --- a/tests/test_tutorial/test_response_model/test_tutorial003_04.py +++ b/tests/test_tutorial/test_response_model/test_tutorial003_04.py @@ -9,7 +9,6 @@ from ...utils import needs_py310 @pytest.mark.parametrize( "module_name", [ - pytest.param("tutorial003_04_py39"), pytest.param("tutorial003_04_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_response_model/test_tutorial003_05.py b/tests/test_tutorial/test_response_model/test_tutorial003_05.py index 187b6491f..0f0e94fda 100644 --- a/tests/test_tutorial/test_response_model/test_tutorial003_05.py +++ b/tests/test_tutorial/test_response_model/test_tutorial003_05.py @@ -10,7 +10,6 @@ from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - pytest.param("tutorial003_05_py39"), pytest.param("tutorial003_05_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_response_model/test_tutorial004.py b/tests/test_tutorial/test_response_model/test_tutorial004.py index d40bce261..e7c0e79f2 100644 --- a/tests/test_tutorial/test_response_model/test_tutorial004.py +++ b/tests/test_tutorial/test_response_model/test_tutorial004.py @@ -10,7 +10,6 @@ from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - pytest.param("tutorial004_py39"), pytest.param("tutorial004_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_response_model/test_tutorial005.py b/tests/test_tutorial/test_response_model/test_tutorial005.py index 55b2334d4..75c8fc0ac 100644 --- a/tests/test_tutorial/test_response_model/test_tutorial005.py +++ b/tests/test_tutorial/test_response_model/test_tutorial005.py @@ -10,7 +10,6 @@ from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - pytest.param("tutorial005_py39"), pytest.param("tutorial005_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_response_model/test_tutorial006.py b/tests/test_tutorial/test_response_model/test_tutorial006.py index 5d6f542b5..f80ce1b28 100644 --- a/tests/test_tutorial/test_response_model/test_tutorial006.py +++ b/tests/test_tutorial/test_response_model/test_tutorial006.py @@ -10,7 +10,6 @@ from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - pytest.param("tutorial006_py39"), pytest.param("tutorial006_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_response_status_code/test_tutorial001_tutorial002.py b/tests/test_tutorial/test_response_status_code/test_tutorial001_tutorial002.py index 7199ceed6..69c32f92e 100644 --- a/tests/test_tutorial/test_response_status_code/test_tutorial001_tutorial002.py +++ b/tests/test_tutorial/test_response_status_code/test_tutorial001_tutorial002.py @@ -8,8 +8,8 @@ from inline_snapshot import snapshot @pytest.fixture( name="client", params=[ - pytest.param("tutorial001_py39"), - pytest.param("tutorial002_py39"), + pytest.param("tutorial001_py310"), + pytest.param("tutorial002_py310"), ], ) def get_client(request: pytest.FixtureRequest): diff --git a/tests/test_tutorial/test_schema_extra_example/test_tutorial001.py b/tests/test_tutorial/test_schema_extra_example/test_tutorial001.py index f19346a3a..126dfbe7d 100644 --- a/tests/test_tutorial/test_schema_extra_example/test_tutorial001.py +++ b/tests/test_tutorial/test_schema_extra_example/test_tutorial001.py @@ -10,7 +10,6 @@ from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - pytest.param("tutorial001_py39"), pytest.param("tutorial001_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_schema_extra_example/test_tutorial002.py b/tests/test_tutorial/test_schema_extra_example/test_tutorial002.py index 8313cb14f..cac3337a2 100644 --- a/tests/test_tutorial/test_schema_extra_example/test_tutorial002.py +++ b/tests/test_tutorial/test_schema_extra_example/test_tutorial002.py @@ -10,7 +10,6 @@ from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - pytest.param("tutorial002_py39"), pytest.param("tutorial002_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_schema_extra_example/test_tutorial003.py b/tests/test_tutorial/test_schema_extra_example/test_tutorial003.py index 3c45a64bc..1ccca4da8 100644 --- a/tests/test_tutorial/test_schema_extra_example/test_tutorial003.py +++ b/tests/test_tutorial/test_schema_extra_example/test_tutorial003.py @@ -10,9 +10,7 @@ from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - pytest.param("tutorial003_py39"), pytest.param("tutorial003_py310", marks=needs_py310), - pytest.param("tutorial003_an_py39"), pytest.param("tutorial003_an_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_schema_extra_example/test_tutorial004.py b/tests/test_tutorial/test_schema_extra_example/test_tutorial004.py index 4b8e15fa1..cffd27066 100644 --- a/tests/test_tutorial/test_schema_extra_example/test_tutorial004.py +++ b/tests/test_tutorial/test_schema_extra_example/test_tutorial004.py @@ -10,9 +10,7 @@ from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - pytest.param("tutorial004_py39"), pytest.param("tutorial004_py310", marks=needs_py310), - pytest.param("tutorial004_an_py39"), pytest.param("tutorial004_an_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_schema_extra_example/test_tutorial005.py b/tests/test_tutorial/test_schema_extra_example/test_tutorial005.py index 7f8e36df2..0bc17a00e 100644 --- a/tests/test_tutorial/test_schema_extra_example/test_tutorial005.py +++ b/tests/test_tutorial/test_schema_extra_example/test_tutorial005.py @@ -10,9 +10,7 @@ from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - pytest.param("tutorial005_py39"), pytest.param("tutorial005_py310", marks=needs_py310), - pytest.param("tutorial005_an_py39"), pytest.param("tutorial005_an_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_security/test_tutorial001.py b/tests/test_tutorial/test_security/test_tutorial001.py index 5742b51bf..c1a15ae00 100644 --- a/tests/test_tutorial/test_security/test_tutorial001.py +++ b/tests/test_tutorial/test_security/test_tutorial001.py @@ -8,8 +8,8 @@ from inline_snapshot import snapshot @pytest.fixture( name="client", params=[ - pytest.param("tutorial001_py39"), - pytest.param("tutorial001_an_py39"), + pytest.param("tutorial001_py310"), + pytest.param("tutorial001_an_py310"), ], ) def get_client(request: pytest.FixtureRequest): diff --git a/tests/test_tutorial/test_security/test_tutorial002.py b/tests/test_tutorial/test_security/test_tutorial002.py index 1e8c6e018..4d1202c32 100644 --- a/tests/test_tutorial/test_security/test_tutorial002.py +++ b/tests/test_tutorial/test_security/test_tutorial002.py @@ -10,9 +10,7 @@ from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - pytest.param("tutorial002_py39"), pytest.param("tutorial002_py310", marks=needs_py310), - pytest.param("tutorial002_an_py39"), pytest.param("tutorial002_an_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_security/test_tutorial003.py b/tests/test_tutorial/test_security/test_tutorial003.py index acd910c71..45f4e57bb 100644 --- a/tests/test_tutorial/test_security/test_tutorial003.py +++ b/tests/test_tutorial/test_security/test_tutorial003.py @@ -10,9 +10,7 @@ from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - pytest.param("tutorial003_py39"), pytest.param("tutorial003_py310", marks=needs_py310), - pytest.param("tutorial003_an_py39"), pytest.param("tutorial003_an_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_security/test_tutorial004.py b/tests/test_tutorial/test_security/test_tutorial004.py index e842c92a1..e52a029bd 100644 --- a/tests/test_tutorial/test_security/test_tutorial004.py +++ b/tests/test_tutorial/test_security/test_tutorial004.py @@ -12,9 +12,7 @@ from ...utils import needs_py310 @pytest.fixture( name="mod", params=[ - pytest.param("tutorial004_py39"), pytest.param("tutorial004_py310", marks=needs_py310), - pytest.param("tutorial004_an_py39"), pytest.param("tutorial004_an_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_security/test_tutorial005.py b/tests/test_tutorial/test_security/test_tutorial005.py index 76b08860f..c6e0e78e0 100644 --- a/tests/test_tutorial/test_security/test_tutorial005.py +++ b/tests/test_tutorial/test_security/test_tutorial005.py @@ -11,9 +11,7 @@ from ...utils import needs_py310 @pytest.fixture( name="mod", params=[ - pytest.param("tutorial005_py39"), pytest.param("tutorial005_py310", marks=needs_py310), - pytest.param("tutorial005_an_py39"), pytest.param("tutorial005_an_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_security/test_tutorial006.py b/tests/test_tutorial/test_security/test_tutorial006.py index 1c96f62ae..671946d97 100644 --- a/tests/test_tutorial/test_security/test_tutorial006.py +++ b/tests/test_tutorial/test_security/test_tutorial006.py @@ -9,8 +9,8 @@ from inline_snapshot import snapshot @pytest.fixture( name="client", params=[ - pytest.param("tutorial006_py39"), - pytest.param("tutorial006_an_py39"), + pytest.param("tutorial006_py310"), + pytest.param("tutorial006_an_py310"), ], ) def get_client(request: pytest.FixtureRequest): diff --git a/tests/test_tutorial/test_security/test_tutorial007.py b/tests/test_tutorial/test_security/test_tutorial007.py index 24667422f..e73545753 100644 --- a/tests/test_tutorial/test_security/test_tutorial007.py +++ b/tests/test_tutorial/test_security/test_tutorial007.py @@ -9,8 +9,8 @@ from inline_snapshot import snapshot @pytest.fixture( name="client", params=[ - pytest.param("tutorial007_py39"), - pytest.param("tutorial007_an_py39"), + pytest.param("tutorial007_py310"), + pytest.param("tutorial007_an_py310"), ], ) def get_client(request: pytest.FixtureRequest): diff --git a/tests/test_tutorial/test_separate_openapi_schemas/test_tutorial001.py b/tests/test_tutorial/test_separate_openapi_schemas/test_tutorial001.py index 0be3b59f9..653b20c7d 100644 --- a/tests/test_tutorial/test_separate_openapi_schemas/test_tutorial001.py +++ b/tests/test_tutorial/test_separate_openapi_schemas/test_tutorial001.py @@ -10,7 +10,6 @@ from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - pytest.param("tutorial001_py39"), pytest.param("tutorial001_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_separate_openapi_schemas/test_tutorial002.py b/tests/test_tutorial/test_separate_openapi_schemas/test_tutorial002.py index 87c63f69e..0ef706a4d 100644 --- a/tests/test_tutorial/test_separate_openapi_schemas/test_tutorial002.py +++ b/tests/test_tutorial/test_separate_openapi_schemas/test_tutorial002.py @@ -10,7 +10,6 @@ from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - pytest.param("tutorial002_py39"), pytest.param("tutorial002_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_settings/test_app01.py b/tests/test_tutorial/test_settings/test_app01.py index 52b9b1e62..da27308e8 100644 --- a/tests/test_tutorial/test_settings/test_app01.py +++ b/tests/test_tutorial/test_settings/test_app01.py @@ -12,7 +12,7 @@ from pytest import MonkeyPatch @pytest.fixture( name="mod_name", params=[ - pytest.param("app01_py39"), + pytest.param("app01_py310"), ], ) def get_mod_name(request: pytest.FixtureRequest): diff --git a/tests/test_tutorial/test_settings/test_app02.py b/tests/test_tutorial/test_settings/test_app02.py index 9cbed4fd1..20594ebb7 100644 --- a/tests/test_tutorial/test_settings/test_app02.py +++ b/tests/test_tutorial/test_settings/test_app02.py @@ -8,8 +8,8 @@ from pytest import MonkeyPatch @pytest.fixture( name="mod_path", params=[ - pytest.param("app02_py39"), - pytest.param("app02_an_py39"), + pytest.param("app02_py310"), + pytest.param("app02_an_py310"), ], ) def get_mod_path(request: pytest.FixtureRequest): diff --git a/tests/test_tutorial/test_settings/test_app03.py b/tests/test_tutorial/test_settings/test_app03.py index 72de49796..f4539c96d 100644 --- a/tests/test_tutorial/test_settings/test_app03.py +++ b/tests/test_tutorial/test_settings/test_app03.py @@ -9,8 +9,8 @@ from pytest import MonkeyPatch @pytest.fixture( name="mod_path", params=[ - pytest.param("app03_py39"), - pytest.param("app03_an_py39"), + pytest.param("app03_py310"), + pytest.param("app03_an_py310"), ], ) def get_mod_path(request: pytest.FixtureRequest): diff --git a/tests/test_tutorial/test_settings/test_tutorial001.py b/tests/test_tutorial/test_settings/test_tutorial001.py index f4576a0d2..8857c35df 100644 --- a/tests/test_tutorial/test_settings/test_tutorial001.py +++ b/tests/test_tutorial/test_settings/test_tutorial001.py @@ -5,7 +5,7 @@ from fastapi.testclient import TestClient from pytest import MonkeyPatch -@pytest.fixture(name="app", params=[pytest.param("tutorial001_py39")]) +@pytest.fixture(name="app", params=[pytest.param("tutorial001_py310")]) def get_app(request: pytest.FixtureRequest, monkeypatch: MonkeyPatch): monkeypatch.setenv("ADMIN_EMAIL", "admin@example.com") mod = importlib.import_module(f"docs_src.settings.{request.param}") diff --git a/tests/test_tutorial/test_sql_databases/test_tutorial001.py b/tests/test_tutorial/test_sql_databases/test_tutorial001.py index aec20e42e..3407ec758 100644 --- a/tests/test_tutorial/test_sql_databases/test_tutorial001.py +++ b/tests/test_tutorial/test_sql_databases/test_tutorial001.py @@ -22,9 +22,7 @@ def clear_sqlmodel(): @pytest.fixture( name="client", params=[ - pytest.param("tutorial001_py39"), pytest.param("tutorial001_py310", marks=needs_py310), - pytest.param("tutorial001_an_py39"), pytest.param("tutorial001_an_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_sql_databases/test_tutorial002.py b/tests/test_tutorial/test_sql_databases/test_tutorial002.py index 4ea7d5f64..51a36b6c7 100644 --- a/tests/test_tutorial/test_sql_databases/test_tutorial002.py +++ b/tests/test_tutorial/test_sql_databases/test_tutorial002.py @@ -22,9 +22,7 @@ def clear_sqlmodel(): @pytest.fixture( name="client", params=[ - pytest.param("tutorial002_py39"), pytest.param("tutorial002_py310", marks=needs_py310), - pytest.param("tutorial002_an_py39"), pytest.param("tutorial002_an_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_static_files/test_tutorial001.py b/tests/test_tutorial/test_static_files/test_tutorial001.py index dd93fee79..1d57310f3 100644 --- a/tests/test_tutorial/test_static_files/test_tutorial001.py +++ b/tests/test_tutorial/test_static_files/test_tutorial001.py @@ -12,7 +12,7 @@ def client(): static_dir.mkdir(exist_ok=True) sample_file = static_dir / "sample.txt" sample_file.write_text("This is a sample static file.") - from docs_src.static_files.tutorial001_py39 import app + from docs_src.static_files.tutorial001_py310 import app with TestClient(app) as client: yield client diff --git a/tests/test_tutorial/test_sub_applications/test_tutorial001.py b/tests/test_tutorial/test_sub_applications/test_tutorial001.py index a8fb3dc36..63fb68fb2 100644 --- a/tests/test_tutorial/test_sub_applications/test_tutorial001.py +++ b/tests/test_tutorial/test_sub_applications/test_tutorial001.py @@ -1,7 +1,7 @@ from fastapi.testclient import TestClient from inline_snapshot import snapshot -from docs_src.sub_applications.tutorial001_py39 import app +from docs_src.sub_applications.tutorial001_py310 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_templates/test_tutorial001.py b/tests/test_tutorial/test_templates/test_tutorial001.py index 818508037..04bc3fce8 100644 --- a/tests/test_tutorial/test_templates/test_tutorial001.py +++ b/tests/test_tutorial/test_templates/test_tutorial001.py @@ -11,7 +11,7 @@ def test_main(): shutil.rmtree("./templates") shutil.copytree("./docs_src/templates/templates/", "./templates") shutil.copytree("./docs_src/templates/static/", "./static") - from docs_src.templates.tutorial001_py39 import app + from docs_src.templates.tutorial001_py310 import app client = TestClient(app) response = client.get("/items/foo") diff --git a/tests/test_tutorial/test_testing/test_main_a.py b/tests/test_tutorial/test_testing/test_main_a.py index 528488805..d071d5309 100644 --- a/tests/test_tutorial/test_testing/test_main_a.py +++ b/tests/test_tutorial/test_testing/test_main_a.py @@ -1,6 +1,6 @@ from inline_snapshot import snapshot -from docs_src.app_testing.app_a_py39.test_main import client, test_read_main +from docs_src.app_testing.app_a_py310.test_main import client, test_read_main def test_main(): diff --git a/tests/test_tutorial/test_testing/test_main_b.py b/tests/test_tutorial/test_testing/test_main_b.py index 3d679cd5a..2d042fd69 100644 --- a/tests/test_tutorial/test_testing/test_main_b.py +++ b/tests/test_tutorial/test_testing/test_main_b.py @@ -9,9 +9,7 @@ from ...utils import needs_py310 @pytest.fixture( name="test_module", params=[ - "app_b_py39.test_main", pytest.param("app_b_py310.test_main", marks=needs_py310), - "app_b_an_py39.test_main", pytest.param("app_b_an_py310.test_main", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_testing/test_tutorial001.py b/tests/test_tutorial/test_testing/test_tutorial001.py index 2b501d36a..b9bb182b7 100644 --- a/tests/test_tutorial/test_testing/test_tutorial001.py +++ b/tests/test_tutorial/test_testing/test_tutorial001.py @@ -1,6 +1,6 @@ from inline_snapshot import snapshot -from docs_src.app_testing.tutorial001_py39 import client, test_read_main +from docs_src.app_testing.tutorial001_py310 import client, test_read_main def test_main(): diff --git a/tests/test_tutorial/test_testing/test_tutorial002.py b/tests/test_tutorial/test_testing/test_tutorial002.py index cc9b5ba27..840248dc3 100644 --- a/tests/test_tutorial/test_testing/test_tutorial002.py +++ b/tests/test_tutorial/test_testing/test_tutorial002.py @@ -1,4 +1,4 @@ -from docs_src.app_testing.tutorial002_py39 import test_read_main, test_websocket +from docs_src.app_testing.tutorial002_py310 import test_read_main, test_websocket def test_main(): diff --git a/tests/test_tutorial/test_testing/test_tutorial003.py b/tests/test_tutorial/test_testing/test_tutorial003.py index 4faa820e9..196fc4555 100644 --- a/tests/test_tutorial/test_testing/test_tutorial003.py +++ b/tests/test_tutorial/test_testing/test_tutorial003.py @@ -3,5 +3,5 @@ import pytest def test_main(): with pytest.warns(DeprecationWarning): - from docs_src.app_testing.tutorial003_py39 import test_read_items + from docs_src.app_testing.tutorial003_py310 import test_read_items test_read_items() diff --git a/tests/test_tutorial/test_testing/test_tutorial004.py b/tests/test_tutorial/test_testing/test_tutorial004.py index c95214ffe..d5de1bb60 100644 --- a/tests/test_tutorial/test_testing/test_tutorial004.py +++ b/tests/test_tutorial/test_testing/test_tutorial004.py @@ -1,4 +1,4 @@ -from docs_src.app_testing.tutorial004_py39 import test_read_items +from docs_src.app_testing.tutorial004_py310 import test_read_items def test_main(): diff --git a/tests/test_tutorial/test_testing_dependencies/test_tutorial001.py b/tests/test_tutorial/test_testing_dependencies/test_tutorial001.py index 6e9656bf5..81491276e 100644 --- a/tests/test_tutorial/test_testing_dependencies/test_tutorial001.py +++ b/tests/test_tutorial/test_testing_dependencies/test_tutorial001.py @@ -9,9 +9,7 @@ from ...utils import needs_py310 @pytest.fixture( name="test_module", params=[ - pytest.param("tutorial001_py39"), pytest.param("tutorial001_py310", marks=needs_py310), - pytest.param("tutorial001_an_py39"), pytest.param("tutorial001_an_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_using_request_directly/test_tutorial001.py b/tests/test_tutorial/test_using_request_directly/test_tutorial001.py index cb8ae8b05..4145177e4 100644 --- a/tests/test_tutorial/test_using_request_directly/test_tutorial001.py +++ b/tests/test_tutorial/test_using_request_directly/test_tutorial001.py @@ -1,7 +1,7 @@ from fastapi.testclient import TestClient from inline_snapshot import snapshot -from docs_src.using_request_directly.tutorial001_py39 import app +from docs_src.using_request_directly.tutorial001_py310 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_websockets/test_tutorial001.py b/tests/test_tutorial/test_websockets/test_tutorial001.py index 4f8368db2..6f3bf1429 100644 --- a/tests/test_tutorial/test_websockets/test_tutorial001.py +++ b/tests/test_tutorial/test_websockets/test_tutorial001.py @@ -2,7 +2,7 @@ import pytest from fastapi.testclient import TestClient from fastapi.websockets import WebSocketDisconnect -from docs_src.websockets.tutorial001_py39 import app +from docs_src.websockets.tutorial001_py310 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_websockets/test_tutorial002.py b/tests/test_tutorial/test_websockets/test_tutorial002.py index ebf1fc8e8..0509b0d0d 100644 --- a/tests/test_tutorial/test_websockets/test_tutorial002.py +++ b/tests/test_tutorial/test_websockets/test_tutorial002.py @@ -11,9 +11,7 @@ from ...utils import needs_py310 @pytest.fixture( name="app", params=[ - pytest.param("tutorial002_py39"), pytest.param("tutorial002_py310", marks=needs_py310), - pytest.param("tutorial002_an_py39"), pytest.param("tutorial002_an_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_websockets/test_tutorial003.py b/tests/test_tutorial/test_websockets/test_tutorial003.py index 0be1fc81d..781146371 100644 --- a/tests/test_tutorial/test_websockets/test_tutorial003.py +++ b/tests/test_tutorial/test_websockets/test_tutorial003.py @@ -8,7 +8,7 @@ from fastapi.testclient import TestClient @pytest.fixture( name="mod", params=[ - pytest.param("tutorial003_py39"), + pytest.param("tutorial003_py310"), ], ) def get_mod(request: pytest.FixtureRequest): diff --git a/tests/test_tutorial/test_wsgi/test_tutorial001.py b/tests/test_tutorial/test_wsgi/test_tutorial001.py index 9fe8c2a4b..9bcd56dfc 100644 --- a/tests/test_tutorial/test_wsgi/test_tutorial001.py +++ b/tests/test_tutorial/test_wsgi/test_tutorial001.py @@ -1,6 +1,6 @@ from fastapi.testclient import TestClient -from docs_src.wsgi.tutorial001_py39 import app +from docs_src.wsgi.tutorial001_py310 import app client = TestClient(app) From 0e460654af7101866b7d0f22735ef6337fe13d0c Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 12 Feb 2026 13:20:10 +0000 Subject: [PATCH 11/20] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [skip ci] --- docs/en/docs/release-notes.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 7640bd6fa..52cc3836a 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -15,6 +15,10 @@ hide: * 🎨 Update internal types for Python 3.10. PR [#14898](https://github.com/fastapi/fastapi/pull/14898) by [@tiangolo](https://github.com/tiangolo). +### Docs + +* 📝 Update source examples and docs from Python 3.9 to 3.10. PR [#14900](https://github.com/fastapi/fastapi/pull/14900) by [@tiangolo](https://github.com/tiangolo). + ## 0.128.8 ### Docs From c82a3d8a13af58e092ba95ffb4b8a64b9ca82726 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Thu, 12 Feb 2026 05:24:28 -0800 Subject: [PATCH 12/20] =?UTF-8?q?=F0=9F=93=9D=20Update=20highlights=20in?= =?UTF-8?q?=20webhooks=20docs=20(#14905)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/advanced/openapi-webhooks.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/docs/advanced/openapi-webhooks.md b/docs/en/docs/advanced/openapi-webhooks.md index f4f586f84..d9b73ea4a 100644 --- a/docs/en/docs/advanced/openapi-webhooks.md +++ b/docs/en/docs/advanced/openapi-webhooks.md @@ -32,7 +32,7 @@ Webhooks are available in OpenAPI 3.1.0 and above, supported by FastAPI `0.99.0` When you create a **FastAPI** application, there is a `webhooks` attribute that you can use to define *webhooks*, the same way you would define *path operations*, for example with `@app.webhooks.post()`. -{* ../../docs_src/openapi_webhooks/tutorial001_py310.py hl[9:13,36:53] *} +{* ../../docs_src/openapi_webhooks/tutorial001_py310.py hl[9:12,15:20] *} The webhooks that you define will end up in the **OpenAPI** schema and the automatic **docs UI**. From 109cc8aff126b60971ec27d68d32b8713f0ec72a Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 12 Feb 2026 13:24:54 +0000 Subject: [PATCH 13/20] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [skip ci] --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 52cc3836a..e3804c6e3 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -17,6 +17,7 @@ hide: ### Docs +* 📝 Update highlights in webhooks docs. PR [#14905](https://github.com/fastapi/fastapi/pull/14905) by [@tiangolo](https://github.com/tiangolo). * 📝 Update source examples and docs from Python 3.9 to 3.10. PR [#14900](https://github.com/fastapi/fastapi/pull/14900) by [@tiangolo](https://github.com/tiangolo). ## 0.128.8 From 31d9750aceaff347bd55be37880b7f36bc26c1b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Thu, 12 Feb 2026 05:31:33 -0800 Subject: [PATCH 14/20] =?UTF-8?q?=F0=9F=94=A8=20Update=20docs.py=20scripts?= =?UTF-8?q?=20to=20migrate=20Python=203.9=20to=20Python=203.10=20(#14906)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- scripts/docs.py | 211 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 206 insertions(+), 5 deletions(-) diff --git a/scripts/docs.py b/scripts/docs.py index 3cf62f084..23d74aaf4 100644 --- a/scripts/docs.py +++ b/scripts/docs.py @@ -8,7 +8,7 @@ from html.parser import HTMLParser from http.server import HTTPServer, SimpleHTTPRequestHandler from multiprocessing import Pool from pathlib import Path -from typing import Any, Optional, Union +from typing import Any import mkdocs.utils import typer @@ -103,7 +103,7 @@ def get_lang_paths() -> list[Path]: return sorted(docs_path.iterdir()) -def lang_callback(lang: Optional[str]) -> Union[str, None]: +def lang_callback(lang: str | None) -> str | None: if lang is None: return None lang = lang.lower() @@ -412,6 +412,13 @@ def langs_json(): @app.command() def generate_docs_src_versions_for_file(file_path: Path) -> None: target_versions = ["py39", "py310"] + full_path_str = str(file_path) + for target_version in target_versions: + if f"_{target_version}" in full_path_str: + logging.info( + f"Skipping {file_path}, already a version file for {target_version}" + ) + return base_content = file_path.read_text(encoding="utf-8") previous_content = {base_content} for target_version in target_versions: @@ -438,13 +445,207 @@ def generate_docs_src_versions_for_file(file_path: Path) -> None: if content_format in previous_content: continue previous_content.add(content_format) - version_file = file_path.with_name( - file_path.name.replace(".py", f"_{target_version}.py") - ) + # Determine where the version label should go: in the parent directory + # name or in the file name, matching the source structure. + label_in_parent = False + for v in target_versions: + if f"_{v}" in file_path.parent.name: + label_in_parent = True + break + if label_in_parent: + parent_name = file_path.parent.name + for v in target_versions: + parent_name = parent_name.replace(f"_{v}", "") + new_parent = file_path.parent.parent / f"{parent_name}_{target_version}" + new_parent.mkdir(parents=True, exist_ok=True) + version_file = new_parent / file_path.name + else: + base_name = file_path.stem + for v in target_versions: + if base_name.endswith(f"_{v}"): + base_name = base_name[: -len(f"_{v}")] + break + version_file = file_path.with_name(f"{base_name}_{target_version}.py") logging.info(f"Writing to {version_file}") version_file.write_text(content_format, encoding="utf-8") +@app.command() +def generate_docs_src_versions() -> None: + """ + Generate Python version-specific files for all .py files in docs_src. + """ + docs_src_path = Path("docs_src") + for py_file in sorted(docs_src_path.rglob("*.py")): + generate_docs_src_versions_for_file(py_file) + + +@app.command() +def copy_py39_to_py310() -> None: + """ + For each docs_src file/directory with a _py39 label that has no _py310 + counterpart, copy it with the _py310 label. + """ + docs_src_path = Path("docs_src") + # Handle directory-level labels (e.g. app_b_an_py39/) + for dir_path in sorted(docs_src_path.rglob("*_py39")): + if not dir_path.is_dir(): + continue + py310_dir = dir_path.parent / dir_path.name.replace("_py39", "_py310") + if py310_dir.exists(): + continue + logging.info(f"Copying directory {dir_path} -> {py310_dir}") + shutil.copytree(dir_path, py310_dir) + # Handle file-level labels (e.g. tutorial001_py39.py) + for file_path in sorted(docs_src_path.rglob("*_py39.py")): + if not file_path.is_file(): + continue + # Skip files inside _py39 directories (already handled above) + if "_py39" in file_path.parent.name: + continue + py310_file = file_path.with_name( + file_path.name.replace("_py39.py", "_py310.py") + ) + if py310_file.exists(): + continue + logging.info(f"Copying file {file_path} -> {py310_file}") + shutil.copy2(file_path, py310_file) + + +@app.command() +def update_docs_includes_py39_to_py310() -> None: + """ + Update .md files in docs/en/ to replace _py39 includes with _py310 versions. + + For each include line referencing a _py39 file or directory in docs_src, replace + the _py39 label with _py310. + """ + include_pattern = re.compile(r"\{[^}]*docs_src/[^}]*_py39[^}]*\.py[^}]*\}") + count = 0 + for md_file in sorted(en_docs_path.rglob("*.md")): + content = md_file.read_text(encoding="utf-8") + if "_py39" not in content: + continue + new_content = include_pattern.sub( + lambda m: m.group(0).replace("_py39", "_py310"), content + ) + if new_content != content: + md_file.write_text(new_content, encoding="utf-8") + count += 1 + logging.info(f"Updated includes in {md_file}") + print(f"Updated {count} file(s) ✅") + + +@app.command() +def remove_unused_docs_src() -> None: + """ + Delete .py files in docs_src that are not included in any .md file under docs/. + """ + docs_src_path = Path("docs_src") + # Collect all docs .md content referencing docs_src + all_docs_content = "" + for md_file in docs_path.rglob("*.md"): + all_docs_content += md_file.read_text(encoding="utf-8") + # Build a set of directory-based package roots (e.g. docs_src/bigger_applications/app_py39) + # where at least one file is referenced in docs. All files in these directories + # should be kept since they may be internally imported by the referenced files. + used_package_dirs: set[Path] = set() + for py_file in docs_src_path.rglob("*.py"): + if py_file.name == "__init__.py": + continue + rel_path = str(py_file) + if rel_path in all_docs_content: + # Walk up from the file's parent to find the package root + # (a subdirectory under docs_src//) + parts = py_file.relative_to(docs_src_path).parts + if len(parts) > 2: + # File is inside a sub-package like docs_src/topic/app_xxx/... + package_root = docs_src_path / parts[0] / parts[1] + used_package_dirs.add(package_root) + removed = 0 + for py_file in sorted(docs_src_path.rglob("*.py")): + if py_file.name == "__init__.py": + continue + # Build the relative path as it appears in includes (e.g. docs_src/first_steps/tutorial001.py) + rel_path = str(py_file) + if rel_path in all_docs_content: + continue + # If this file is inside a directory-based package where any sibling is + # referenced, keep it (it's likely imported internally). + parts = py_file.relative_to(docs_src_path).parts + if len(parts) > 2: + package_root = docs_src_path / parts[0] / parts[1] + if package_root in used_package_dirs: + continue + # Check if the _an counterpart (or non-_an counterpart) is referenced. + # If either variant is included, keep both. + # Handle both file-level _an (tutorial001_an.py) and directory-level _an + # (app_an/main.py) + counterpart_found = False + full_path_str = str(py_file) + if "_an" in py_file.stem: + # This is an _an file, check if the non-_an version is referenced + counterpart = full_path_str.replace( + f"/{py_file.stem}", f"/{py_file.stem.replace('_an', '', 1)}" + ) + if counterpart in all_docs_content: + counterpart_found = True + else: + # This is a non-_an file, check if there's an _an version referenced + # Insert _an before any version suffix or at the end of the stem + stem = py_file.stem + for suffix in ("_py39", "_py310"): + if suffix in stem: + an_stem = stem.replace(suffix, f"_an{suffix}", 1) + break + else: + an_stem = f"{stem}_an" + counterpart = full_path_str.replace(f"/{stem}.", f"/{an_stem}.") + if counterpart in all_docs_content: + counterpart_found = True + # Also check directory-level _an counterparts + if not counterpart_found: + parent_name = py_file.parent.name + if "_an" in parent_name: + counterpart_parent = parent_name.replace("_an", "", 1) + counterpart_dir = str(py_file).replace( + f"/{parent_name}/", f"/{counterpart_parent}/" + ) + if counterpart_dir in all_docs_content: + counterpart_found = True + else: + # Try inserting _an into parent directory name + for suffix in ("_py39", "_py310"): + if suffix in parent_name: + an_parent = parent_name.replace(suffix, f"_an{suffix}", 1) + break + else: + an_parent = f"{parent_name}_an" + counterpart_dir = str(py_file).replace( + f"/{parent_name}/", f"/{an_parent}/" + ) + if counterpart_dir in all_docs_content: + counterpart_found = True + if counterpart_found: + continue + logging.info(f"Removing unused file: {py_file}") + py_file.unlink() + removed += 1 + # Clean up directories that are empty or only contain __init__.py / __pycache__ + for dir_path in sorted(docs_src_path.rglob("*"), reverse=True): + if not dir_path.is_dir(): + continue + remaining = [ + f + for f in dir_path.iterdir() + if f.name != "__pycache__" and f.name != "__init__.py" + ] + if not remaining: + logging.info(f"Removing empty/init-only directory: {dir_path}") + shutil.rmtree(dir_path) + print(f"Removed {removed} unused file(s) ✅") + + @app.command() def add_permalinks_page(path: Path, update_existing: bool = False): """ From b7ce02ae86ee466380d2db09be008cfe83a1ca35 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 12 Feb 2026 13:32:02 +0000 Subject: [PATCH 15/20] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [skip ci] --- docs/en/docs/release-notes.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index e3804c6e3..a428a4d86 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -20,6 +20,10 @@ hide: * 📝 Update highlights in webhooks docs. PR [#14905](https://github.com/fastapi/fastapi/pull/14905) by [@tiangolo](https://github.com/tiangolo). * 📝 Update source examples and docs from Python 3.9 to 3.10. PR [#14900](https://github.com/fastapi/fastapi/pull/14900) by [@tiangolo](https://github.com/tiangolo). +### Internal + +* 🔨 Update docs.py scripts to migrate Python 3.9 to Python 3.10. PR [#14906](https://github.com/fastapi/fastapi/pull/14906) by [@tiangolo](https://github.com/tiangolo). + ## 0.128.8 ### Docs From a2e51363c721ee6fccb148bff95ca328b4efdfed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Thu, 12 Feb 2026 14:52:27 +0100 Subject: [PATCH 16/20] =?UTF-8?q?=F0=9F=94=96=20Release=20version=200.129.?= =?UTF-8?q?0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 2 ++ fastapi/__init__.py | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index a428a4d86..e85ed4b3e 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -7,6 +7,8 @@ hide: ## Latest Changes +## 0.129.0 + ### Breaking Changes * ➖ Drop support for Python 3.9. PR [#14897](https://github.com/fastapi/fastapi/pull/14897) by [@tiangolo](https://github.com/tiangolo). diff --git a/fastapi/__init__.py b/fastapi/__init__.py index 9931216ee..de5a0be38 100644 --- a/fastapi/__init__.py +++ b/fastapi/__init__.py @@ -1,6 +1,6 @@ """FastAPI framework, high performance, easy to learn, fast to code, ready for production""" -__version__ = "0.128.8" +__version__ = "0.129.0" from starlette import status as status From d11f820ac38bdea38e50c9ede001a6c9b57eac6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Thu, 12 Feb 2026 10:10:35 -0800 Subject: [PATCH 17/20] =?UTF-8?q?=F0=9F=93=9D=20Update=20docs=20for=20JWT?= =?UTF-8?q?=20to=20prevent=20timing=20attacks=20(#14908)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/tutorial/security/oauth2-jwt.md | 12 ++++++++---- docs_src/security/tutorial004_an_py310.py | 3 +++ docs_src/security/tutorial004_py310.py | 3 +++ docs_src/security/tutorial005_an_py310.py | 3 +++ docs_src/security/tutorial005_py310.py | 3 +++ 5 files changed, 20 insertions(+), 4 deletions(-) diff --git a/docs/en/docs/tutorial/security/oauth2-jwt.md b/docs/en/docs/tutorial/security/oauth2-jwt.md index 95baf871c..26894ab28 100644 --- a/docs/en/docs/tutorial/security/oauth2-jwt.md +++ b/docs/en/docs/tutorial/security/oauth2-jwt.md @@ -116,7 +116,11 @@ And another utility to verify if a received password matches the hash stored. And another one to authenticate and return a user. -{* ../../docs_src/security/tutorial004_an_py310.py hl[8,49,56:57,60:61,70:76] *} +{* ../../docs_src/security/tutorial004_an_py310.py hl[8,49,51,58:59,62:63,72:79] *} + +When `authenticate_user` is called with a username that doesn't exist in the database, we still run `verify_password` against a dummy hash. + +This ensures the endpoint takes roughly the same amount of time to respond whether the username is valid or not, preventing **timing attacks** that could be used to enumerate existing usernames. /// note @@ -152,7 +156,7 @@ Define a Pydantic Model that will be used in the token endpoint for the response Create a utility function to generate a new access token. -{* ../../docs_src/security/tutorial004_an_py310.py hl[4,7,13:15,29:31,79:87] *} +{* ../../docs_src/security/tutorial004_an_py310.py hl[4,7,13:15,29:31,82:90] *} ## Update the dependencies { #update-the-dependencies } @@ -162,7 +166,7 @@ Decode the received token, verify it, and return the current user. If the token is invalid, return an HTTP error right away. -{* ../../docs_src/security/tutorial004_an_py310.py hl[90:107] *} +{* ../../docs_src/security/tutorial004_an_py310.py hl[93:110] *} ## Update the `/token` *path operation* { #update-the-token-path-operation } @@ -170,7 +174,7 @@ Create a `timedelta` with the expiration time of the token. Create a real JWT access token and return it. -{* ../../docs_src/security/tutorial004_an_py310.py hl[118:133] *} +{* ../../docs_src/security/tutorial004_an_py310.py hl[121:136] *} ### Technical details about the JWT "subject" `sub` { #technical-details-about-the-jwt-subject-sub } diff --git a/docs_src/security/tutorial004_an_py310.py b/docs_src/security/tutorial004_an_py310.py index 368c743bf..685cb034e 100644 --- a/docs_src/security/tutorial004_an_py310.py +++ b/docs_src/security/tutorial004_an_py310.py @@ -48,6 +48,8 @@ class UserInDB(User): password_hash = PasswordHash.recommended() +DUMMY_HASH = password_hash.hash("dummypassword") + oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token") app = FastAPI() @@ -70,6 +72,7 @@ def get_user(db, username: str): def authenticate_user(fake_db, username: str, password: str): user = get_user(fake_db, username) if not user: + verify_password(password, DUMMY_HASH) return False if not verify_password(password, user.hashed_password): return False diff --git a/docs_src/security/tutorial004_py310.py b/docs_src/security/tutorial004_py310.py index 8d0785b40..dc7f1c9e2 100644 --- a/docs_src/security/tutorial004_py310.py +++ b/docs_src/security/tutorial004_py310.py @@ -47,6 +47,8 @@ class UserInDB(User): password_hash = PasswordHash.recommended() +DUMMY_HASH = password_hash.hash("dummypassword") + oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token") app = FastAPI() @@ -69,6 +71,7 @@ def get_user(db, username: str): def authenticate_user(fake_db, username: str, password: str): user = get_user(fake_db, username) if not user: + verify_password(password, DUMMY_HASH) return False if not verify_password(password, user.hashed_password): return False diff --git a/docs_src/security/tutorial005_an_py310.py b/docs_src/security/tutorial005_an_py310.py index fef0ab71c..9911723db 100644 --- a/docs_src/security/tutorial005_an_py310.py +++ b/docs_src/security/tutorial005_an_py310.py @@ -60,6 +60,8 @@ class UserInDB(User): password_hash = PasswordHash.recommended() +DUMMY_HASH = password_hash.hash("dummypassword") + oauth2_scheme = OAuth2PasswordBearer( tokenUrl="token", scopes={"me": "Read information about the current user.", "items": "Read items."}, @@ -85,6 +87,7 @@ def get_user(db, username: str): def authenticate_user(fake_db, username: str, password: str): user = get_user(fake_db, username) if not user: + verify_password(password, DUMMY_HASH) return False if not verify_password(password, user.hashed_password): return False diff --git a/docs_src/security/tutorial005_py310.py b/docs_src/security/tutorial005_py310.py index 412fbf798..710cdac32 100644 --- a/docs_src/security/tutorial005_py310.py +++ b/docs_src/security/tutorial005_py310.py @@ -59,6 +59,8 @@ class UserInDB(User): password_hash = PasswordHash.recommended() +DUMMY_HASH = password_hash.hash("dummypassword") + oauth2_scheme = OAuth2PasswordBearer( tokenUrl="token", scopes={"me": "Read information about the current user.", "items": "Read items."}, @@ -84,6 +86,7 @@ def get_user(db, username: str): def authenticate_user(fake_db, username: str, password: str): user = get_user(fake_db, username) if not user: + verify_password(password, DUMMY_HASH) return False if not verify_password(password, user.hashed_password): return False From c206f19b5d39fe9fbf90b67229290b41f8fabeec Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 12 Feb 2026 18:10:57 +0000 Subject: [PATCH 18/20] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [skip ci] --- docs/en/docs/release-notes.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index e85ed4b3e..d8bc3a26f 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -7,6 +7,10 @@ hide: ## Latest Changes +### Docs + +* 📝 Update docs for JWT to prevent timing attacks. PR [#14908](https://github.com/fastapi/fastapi/pull/14908) by [@tiangolo](https://github.com/tiangolo). + ## 0.129.0 ### Breaking Changes From 55a9eee13a7c228b358bd110976b3aeab3185fe2 Mon Sep 17 00:00:00 2001 From: Motov Yurii <109919500+YuriiMotov@users.noreply.github.com> Date: Thu, 12 Feb 2026 20:57:34 +0100 Subject: [PATCH 19/20] =?UTF-8?q?=F0=9F=8C=90=20Update=20translations=20fo?= =?UTF-8?q?r=20ru=20(update-outdated)=20(#14909)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Update all * Reflect latest changes in `docs/en/docs/tutorial/security/oauth2-jwt.md` --- docs/ru/docs/advanced/additional-responses.md | 4 +- .../ru/docs/advanced/advanced-dependencies.md | 8 +- .../ru/docs/advanced/advanced-python-types.md | 61 ++++++ docs/ru/docs/advanced/async-tests.md | 10 +- docs/ru/docs/advanced/behind-a-proxy.md | 22 +- docs/ru/docs/advanced/custom-response.md | 36 ++-- docs/ru/docs/advanced/dataclasses.md | 2 +- docs/ru/docs/advanced/events.md | 12 +- docs/ru/docs/advanced/generate-clients.md | 12 +- docs/ru/docs/advanced/middleware.md | 6 +- docs/ru/docs/advanced/openapi-webhooks.md | 6 +- .../path-operation-advanced-configuration.md | 16 +- .../advanced/response-change-status-code.md | 2 +- docs/ru/docs/advanced/response-cookies.md | 4 +- docs/ru/docs/advanced/response-directly.md | 2 +- docs/ru/docs/advanced/response-headers.md | 4 +- .../docs/advanced/security/http-basic-auth.md | 6 +- docs/ru/docs/advanced/settings.md | 20 +- docs/ru/docs/advanced/sub-applications.md | 6 +- docs/ru/docs/advanced/templates.md | 2 +- docs/ru/docs/advanced/testing-events.md | 4 +- docs/ru/docs/advanced/testing-websockets.md | 2 +- .../docs/advanced/using-request-directly.md | 2 +- docs/ru/docs/advanced/websockets.md | 8 +- docs/ru/docs/advanced/wsgi.md | 2 +- docs/ru/docs/alternatives.md | 12 +- docs/ru/docs/async.md | 12 +- docs/ru/docs/benchmarks.md | 10 +- docs/ru/docs/deployment/concepts.md | 10 +- docs/ru/docs/deployment/docker.md | 20 +- docs/ru/docs/deployment/https.md | 2 +- docs/ru/docs/deployment/index.md | 2 +- docs/ru/docs/deployment/versions.md | 4 +- docs/ru/docs/environment-variables.md | 2 +- docs/ru/docs/fastapi-cli.md | 2 +- docs/ru/docs/features.md | 24 +-- docs/ru/docs/history-design-future.md | 8 +- .../authentication-error-status-code.md | 2 +- docs/ru/docs/how-to/conditional-openapi.md | 6 +- docs/ru/docs/how-to/configure-swagger-ui.md | 6 +- docs/ru/docs/how-to/custom-docs-ui-assets.md | 14 +- docs/ru/docs/how-to/extending-openapi.md | 12 +- docs/ru/docs/how-to/graphql.md | 2 +- docs/ru/docs/how-to/index.md | 6 +- docs/ru/docs/index.md | 12 +- docs/ru/docs/project-generation.md | 2 +- docs/ru/docs/python-types.md | 190 ++++-------------- docs/ru/docs/tutorial/background-tasks.md | 10 +- docs/ru/docs/tutorial/bigger-applications.md | 26 +-- docs/ru/docs/tutorial/body-multiple-params.md | 8 +- docs/ru/docs/tutorial/body-nested-models.md | 4 +- docs/ru/docs/tutorial/body.md | 6 +- docs/ru/docs/tutorial/cookie-param-models.md | 8 +- docs/ru/docs/tutorial/cookie-params.md | 6 +- docs/ru/docs/tutorial/cors.md | 4 +- docs/ru/docs/tutorial/debugging.md | 8 +- .../dependencies/classes-as-dependencies.md | 28 +-- ...pendencies-in-path-operation-decorators.md | 12 +- .../dependencies/dependencies-with-yield.md | 24 +-- .../dependencies/global-dependencies.md | 4 +- docs/ru/docs/tutorial/dependencies/index.md | 2 +- .../tutorial/dependencies/sub-dependencies.md | 6 +- docs/ru/docs/tutorial/encoder.md | 4 +- docs/ru/docs/tutorial/extra-models.md | 8 +- docs/ru/docs/tutorial/first-steps.md | 16 +- docs/ru/docs/tutorial/handling-errors.md | 20 +- docs/ru/docs/tutorial/metadata.md | 12 +- docs/ru/docs/tutorial/middleware.md | 32 ++- .../tutorial/path-operation-configuration.md | 10 +- .../path-params-numeric-validations.md | 16 +- docs/ru/docs/tutorial/path-params.md | 30 +-- docs/ru/docs/tutorial/query-param-models.md | 2 +- .../tutorial/query-params-str-validations.md | 42 +--- docs/ru/docs/tutorial/query-params.md | 8 +- docs/ru/docs/tutorial/request-files.md | 14 +- docs/ru/docs/tutorial/request-form-models.md | 4 +- .../docs/tutorial/request-forms-and-files.md | 4 +- docs/ru/docs/tutorial/request-forms.md | 10 +- docs/ru/docs/tutorial/response-model.md | 6 +- docs/ru/docs/tutorial/response-status-code.md | 10 +- docs/ru/docs/tutorial/schema-extra-example.md | 2 +- docs/ru/docs/tutorial/security/first-steps.md | 6 +- .../tutorial/security/get-current-user.md | 2 +- docs/ru/docs/tutorial/security/index.md | 84 ++++---- docs/ru/docs/tutorial/security/oauth2-jwt.md | 28 ++- .../docs/tutorial/security/simple-oauth2.md | 2 +- docs/ru/docs/tutorial/sql-databases.md | 6 +- docs/ru/docs/tutorial/static-files.md | 2 +- docs/ru/docs/tutorial/testing.md | 10 +- docs/ru/docs/virtual-environments.md | 4 +- 90 files changed, 549 insertions(+), 620 deletions(-) create mode 100644 docs/ru/docs/advanced/advanced-python-types.md diff --git a/docs/ru/docs/advanced/additional-responses.md b/docs/ru/docs/advanced/additional-responses.md index fca4f072d..ca36ba20e 100644 --- a/docs/ru/docs/advanced/additional-responses.md +++ b/docs/ru/docs/advanced/additional-responses.md @@ -26,7 +26,7 @@ Например, чтобы объявить ещё один ответ со статус-кодом `404` и Pydantic-моделью `Message`, можно написать: -{* ../../docs_src/additional_responses/tutorial001_py39.py hl[18,22] *} +{* ../../docs_src/additional_responses/tutorial001_py310.py hl[18,22] *} /// note | Примечание @@ -203,7 +203,7 @@ А также ответ со статус-кодом `200`, который использует ваш `response_model`, но включает пользовательский `example`: -{* ../../docs_src/additional_responses/tutorial003_py39.py hl[20:31] *} +{* ../../docs_src/additional_responses/tutorial003_py310.py hl[20:31] *} Всё это будет объединено и включено в ваш OpenAPI и отображено в документации API: diff --git a/docs/ru/docs/advanced/advanced-dependencies.md b/docs/ru/docs/advanced/advanced-dependencies.md index fb2643cd5..686a0cf91 100644 --- a/docs/ru/docs/advanced/advanced-dependencies.md +++ b/docs/ru/docs/advanced/advanced-dependencies.md @@ -18,7 +18,7 @@ Для этого объявляем метод `__call__`: -{* ../../docs_src/dependencies/tutorial011_an_py39.py hl[12] *} +{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[12] *} В этом случае именно `__call__` **FastAPI** использует для проверки дополнительных параметров и подзависимостей, и именно он будет вызван, чтобы позже передать значение параметру в вашей *функции-обработчике пути*. @@ -26,7 +26,7 @@ Теперь мы можем использовать `__init__`, чтобы объявить параметры экземпляра, с помощью которых будем «параметризовать» зависимость: -{* ../../docs_src/dependencies/tutorial011_an_py39.py hl[9] *} +{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[9] *} В этом случае **FastAPI** вовсе не трогает `__init__` и не зависит от него — мы используем его напрямую в нашем коде. @@ -34,7 +34,7 @@ Мы можем создать экземпляр этого класса так: -{* ../../docs_src/dependencies/tutorial011_an_py39.py hl[18] *} +{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[18] *} Так мы «параметризуем» нашу зависимость: теперь внутри неё хранится "bar" в атрибуте `checker.fixed_content`. @@ -50,7 +50,7 @@ checker(q="somequery") …и передаст возвращённое значение как значение зависимости в параметр `fixed_content_included` нашей *функции-обработчика пути*: -{* ../../docs_src/dependencies/tutorial011_an_py39.py hl[22] *} +{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[22] *} /// tip | Совет diff --git a/docs/ru/docs/advanced/advanced-python-types.md b/docs/ru/docs/advanced/advanced-python-types.md new file mode 100644 index 000000000..62dcf8c4f --- /dev/null +++ b/docs/ru/docs/advanced/advanced-python-types.md @@ -0,0 +1,61 @@ +# Продвинутые типы Python { #advanced-python-types } + +Ниже несколько дополнительных идей, которые могут быть полезны при работе с типами Python. + +## Использование `Union` или `Optional` { #using-union-or-optional } + +Если по какой-то причине ваш код не может использовать `|`, например, если это не аннотация типов, а что-то вроде `response_model=`, вместо вертикальной черты (`|`) можно использовать `Union` из `typing`. + +Например, вы можете объявить, что значение может быть `str` или `None`: + +```python +from typing import Union + + +def say_hi(name: Union[str, None]): + print(f"Hi {name}!") +``` + +В `typing` также есть сокращение, чтобы объявить, что значение может быть `None`, — `Optional`. + +Вот совет с моей очень субъективной точки зрения: + +- 🚨 Избегайте использования `Optional[SomeType]` +- Вместо этого ✨ используйте **`Union[SomeType, None]`** ✨. + +Оба варианта эквивалентны и под капотом это одно и то же, но я бы рекомендовал `Union` вместо `Optional`, потому что слово «optional» может наводить на мысль, что значение необязательное, тогда как на самом деле это означает «значение может быть `None`», даже если оно не является необязательным и по-прежнему требуется. + +По-моему, `Union[SomeType, None]` более явно передаёт смысл. + +Речь только о словах и названиях. Но эти слова могут влиять на то, как вы и ваша команда думаете о коде. + +В качестве примера возьмём такую функцию: + +```python +from typing import Optional + + +def say_hi(name: Optional[str]): + print(f"Hey {name}!") +``` + +Параметр `name` объявлен как `Optional[str]`, но он не является необязательным: вы не можете вызвать функцию без этого параметра: + +```Python +say_hi() # О нет, это вызывает ошибку! 😱 +``` + +Параметр `name` по-прежнему обязателен (не «optional»), так как у него нет значения по умолчанию. При этом `name` принимает `None` в качестве значения: + +```Python +say_hi(name=None) # Это работает, None допустим 🎉 +``` + +Хорошая новость: в большинстве случаев вы сможете просто использовать `|` для объявления объединений типов: + +```python +def say_hi(name: str | None): + print(f"Hey {name}!") +``` + +Так что обычно вам не о чем переживать из‑за названий вроде `Optional` и `Union`. 😎 diff --git a/docs/ru/docs/advanced/async-tests.md b/docs/ru/docs/advanced/async-tests.md index e68970406..52939c255 100644 --- a/docs/ru/docs/advanced/async-tests.md +++ b/docs/ru/docs/advanced/async-tests.md @@ -32,11 +32,11 @@ Файл `main.py`: -{* ../../docs_src/async_tests/app_a_py39/main.py *} +{* ../../docs_src/async_tests/app_a_py310/main.py *} Файл `test_main.py` содержит тесты для `main.py`, теперь он может выглядеть так: -{* ../../docs_src/async_tests/app_a_py39/test_main.py *} +{* ../../docs_src/async_tests/app_a_py310/test_main.py *} ## Запуск тестов { #run-it } @@ -56,7 +56,7 @@ $ pytest Маркер `@pytest.mark.anyio` говорит pytest, что тестовая функция должна быть вызвана асинхронно: -{* ../../docs_src/async_tests/app_a_py39/test_main.py hl[7] *} +{* ../../docs_src/async_tests/app_a_py310/test_main.py hl[7] *} /// tip | Подсказка @@ -66,7 +66,7 @@ $ pytest Затем мы можем создать `AsyncClient` со ссылкой на приложение и посылать асинхронные запросы, используя `await`. -{* ../../docs_src/async_tests/app_a_py39/test_main.py hl[9:12] *} +{* ../../docs_src/async_tests/app_a_py310/test_main.py hl[9:12] *} Это эквивалентно следующему: @@ -94,6 +94,6 @@ response = client.get('/') /// tip | Подсказка -Если вы столкнулись с `RuntimeError: Task attached to a different loop` при вызове асинхронных функций в ваших тестах (например, при использовании
MongoDB's MotorClient), то не забывайте инициализировать объекты, которым нужен цикл событий (event loop), только внутри асинхронных функций, например, в `'@app.on_event("startup")` callback. +Если вы столкнулись с `RuntimeError: Task attached to a different loop` при вызове асинхронных функций в ваших тестах (например, при использовании MongoDB's MotorClient), то не забывайте инициализировать объекты, которым нужен цикл событий (event loop), только внутри асинхронных функций, например, в `@app.on_event("startup")` callback. /// diff --git a/docs/ru/docs/advanced/behind-a-proxy.md b/docs/ru/docs/advanced/behind-a-proxy.md index f78da01a0..ec75ed369 100644 --- a/docs/ru/docs/advanced/behind-a-proxy.md +++ b/docs/ru/docs/advanced/behind-a-proxy.md @@ -44,7 +44,7 @@ $ fastapi run --forwarded-allow-ips="*" Например, вы объявили операцию пути `/items/`: -{* ../../docs_src/behind_a_proxy/tutorial001_01_py39.py hl[6] *} +{* ../../docs_src/behind_a_proxy/tutorial001_01_py310.py hl[6] *} Если клиент обратится к `/items`, по умолчанию произойдёт редирект на `/items/`. @@ -115,7 +115,7 @@ sequenceDiagram Хотя весь ваш код написан с расчётом, что путь один — `/app`. -{* ../../docs_src/behind_a_proxy/tutorial001_py39.py hl[6] *} +{* ../../docs_src/behind_a_proxy/tutorial001_py310.py hl[6] *} Прокси будет «обрезать» префикс пути на лету перед передачей запроса на сервер приложения (скорее всего Uvicorn, запущенный через FastAPI CLI), поддерживая у вашего приложения иллюзию, что его обслуживают по `/app`, чтобы вам не пришлось менять весь код и добавлять префикс `/api/v1`. @@ -193,7 +193,7 @@ $ fastapi run main.py --forwarded-allow-ips="*" --root-path /api/v1 Здесь мы добавляем его в сообщение лишь для демонстрации. -{* ../../docs_src/behind_a_proxy/tutorial001_py39.py hl[8] *} +{* ../../docs_src/behind_a_proxy/tutorial001_py310.py hl[8] *} Затем, если вы запустите Uvicorn так: @@ -220,7 +220,7 @@ $ fastapi run main.py --forwarded-allow-ips="*" --root-path /api/v1 Если нет возможности передать опцию командной строки `--root-path` (или аналог), вы можете указать параметр `root_path` при создании приложения FastAPI: -{* ../../docs_src/behind_a_proxy/tutorial002_py39.py hl[3] *} +{* ../../docs_src/behind_a_proxy/tutorial002_py310.py hl[3] *} Передача `root_path` в `FastAPI` эквивалентна опции командной строки `--root-path` для Uvicorn или Hypercorn. @@ -241,17 +241,17 @@ $ fastapi run main.py --forwarded-allow-ips="*" --root-path /api/v1 Uvicorn ожидает, что прокси обратится к нему по `http://127.0.0.1:8000/app`, а уже задача прокси — добавить сверху префикс `/api/v1`. -## О прокси с урезанным префиксом пути { #about-proxies-with-a-stripped-path-prefix } +## О прокси с функцией удаления префикса пути { #about-proxies-with-a-stripped-path-prefix } -Помните, что прокси с урезанным префиксом пути — лишь один из вариантов настройки. +Помните, что прокси с функцией удаления префикса пути — лишь один из вариантов настройки. -Во многих случаях по умолчанию прокси будет без урезанного префикса пути. +Во многих случаях по умолчанию прокси будет без функции удаления префикса пути. -В таком случае (без урезанного префикса) прокси слушает, например, по адресу `https://myawesomeapp.com`, и если браузер идёт на `https://myawesomeapp.com/api/v1/app`, а ваш сервер (например, Uvicorn) слушает на `http://127.0.0.1:8000`, то прокси (без урезанного префикса) обратится к Uvicorn по тому же пути: `http://127.0.0.1:8000/api/v1/app`. +В таком случае (без функции удаления префикса пути) прокси слушает, например, по адресу `https://myawesomeapp.com`, и если браузер идёт на `https://myawesomeapp.com/api/v1/app`, а ваш сервер (например, Uvicorn) слушает на `http://127.0.0.1:8000`, то прокси (без урезанного префикса) обратится к Uvicorn по тому же пути: `http://127.0.0.1:8000/api/v1/app`. ## Локальное тестирование с Traefik { #testing-locally-with-traefik } -Вы можете легко поэкспериментировать локально с урезанным префиксом пути, используя Traefik. +Вы можете легко поэкспериментировать локально с функцией удаления префикса пути, используя Traefik. Скачайте Traefik — это один бинарный файл; распакуйте архив и запустите его прямо из терминала. @@ -400,7 +400,7 @@ $ fastapi run main.py --forwarded-allow-ips="*" --root-path /api/v1 Например: -{* ../../docs_src/behind_a_proxy/tutorial003_py39.py hl[4:7] *} +{* ../../docs_src/behind_a_proxy/tutorial003_py310.py hl[4:7] *} Будет сгенерирована схема OpenAPI примерно такая: @@ -455,7 +455,7 @@ $ fastapi run main.py --forwarded-allow-ips="*" --root-path /api/v1 Если вы не хотите, чтобы FastAPI добавлял автоматический сервер, используя `root_path`, укажите параметр `root_path_in_servers=False`: -{* ../../docs_src/behind_a_proxy/tutorial004_py39.py hl[9] *} +{* ../../docs_src/behind_a_proxy/tutorial004_py310.py hl[9] *} и тогда этот сервер не будет добавлен в схему OpenAPI. diff --git a/docs/ru/docs/advanced/custom-response.md b/docs/ru/docs/advanced/custom-response.md index 49550b49f..b9f91373d 100644 --- a/docs/ru/docs/advanced/custom-response.md +++ b/docs/ru/docs/advanced/custom-response.md @@ -30,7 +30,7 @@ Но если вы уверены, что содержимое, которое вы возвращаете, **сериализуемо в JSON**, вы можете передать его напрямую в класс ответа и избежать дополнительных накладных расходов, которые FastAPI понёс бы, пропуская возвращаемое содержимое через `jsonable_encoder` перед передачей в класс ответа. -{* ../../docs_src/custom_response/tutorial001b_py39.py hl[2,7] *} +{* ../../docs_src/custom_response/tutorial001b_py310.py hl[2,7] *} /// info | Информация @@ -55,7 +55,7 @@ - Импортируйте `HTMLResponse`. - Передайте `HTMLResponse` в параметр `response_class` вашего декоратора операции пути. -{* ../../docs_src/custom_response/tutorial002_py39.py hl[2,7] *} +{* ../../docs_src/custom_response/tutorial002_py310.py hl[2,7] *} /// info | Информация @@ -73,17 +73,17 @@ Тот же пример сверху, возвращающий `HTMLResponse`, может выглядеть так: -{* ../../docs_src/custom_response/tutorial003_py39.py hl[2,7,19] *} +{* ../../docs_src/custom_response/tutorial003_py310.py hl[2,7,19] *} /// warning | Предупреждение -`Response`, возвращённый напрямую вашей функцией-обработчиком пути, не будет задокументирован в OpenAPI (например, `Content-Type` нне будет задокументирова) и не будет виден в автоматически сгенерированной интерактивной документации. +`Response`, возвращённый напрямую вашей функцией-обработчиком пути, не будет задокументирован в OpenAPI (например, `Content-Type` не будет задокументирован) и не будет виден в автоматически сгенерированной интерактивной документации. /// /// info | Информация -Разумеется, фактические заголовок `Content-Type`, статус-код и т.д. возьмутся из объекта `Response`, который вы вернули. +Разумеется, фактический заголовок `Content-Type`, статус-код и т.д. возьмутся из объекта `Response`, который вы вернули. /// @@ -97,7 +97,7 @@ Например, это может быть что-то вроде: -{* ../../docs_src/custom_response/tutorial004_py39.py hl[7,21,23] *} +{* ../../docs_src/custom_response/tutorial004_py310.py hl[7,21,23] *} В этом примере функция `generate_html_response()` уже генерирует и возвращает `Response` вместо возврата HTML в `str`. @@ -136,7 +136,7 @@ FastAPI (фактически Starlette) автоматически добавит заголовок Content-Length. Также будет добавлен заголовок Content-Type, основанный на `media_type` и с добавлением charset для текстовых типов. -{* ../../docs_src/response_directly/tutorial002_py39.py hl[1,18] *} +{* ../../docs_src/response_directly/tutorial002_py310.py hl[1,18] *} ### `HTMLResponse` { #htmlresponse } @@ -146,7 +146,7 @@ FastAPI (фактически Starlette) автоматически добави Принимает текст или байты и возвращает ответ в виде простого текста. -{* ../../docs_src/custom_response/tutorial005_py39.py hl[2,7,9] *} +{* ../../docs_src/custom_response/tutorial005_py310.py hl[2,7,9] *} ### `JSONResponse` { #jsonresponse } @@ -180,7 +180,7 @@ FastAPI (фактически Starlette) автоматически добави /// -{* ../../docs_src/custom_response/tutorial001_py39.py hl[2,7] *} +{* ../../docs_src/custom_response/tutorial001_py310.py hl[2,7] *} /// tip | Совет @@ -194,13 +194,13 @@ FastAPI (фактически Starlette) автоматически добави Вы можете вернуть `RedirectResponse` напрямую: -{* ../../docs_src/custom_response/tutorial006_py39.py hl[2,9] *} +{* ../../docs_src/custom_response/tutorial006_py310.py hl[2,9] *} --- Или можно использовать его в параметре `response_class`: -{* ../../docs_src/custom_response/tutorial006b_py39.py hl[2,7,9] *} +{* ../../docs_src/custom_response/tutorial006b_py310.py hl[2,7,9] *} Если вы сделаете так, то сможете возвращать URL напрямую из своей функции-обработчика пути. @@ -210,13 +210,13 @@ FastAPI (фактически Starlette) автоматически добави Также вы можете использовать параметр `status_code` в сочетании с параметром `response_class`: -{* ../../docs_src/custom_response/tutorial006c_py39.py hl[2,7,9] *} +{* ../../docs_src/custom_response/tutorial006c_py310.py hl[2,7,9] *} ### `StreamingResponse` { #streamingresponse } Принимает асинхронный генератор или обычный генератор/итератор и отправляет тело ответа потоково. -{* ../../docs_src/custom_response/tutorial007_py39.py hl[2,14] *} +{* ../../docs_src/custom_response/tutorial007_py310.py hl[2,14] *} #### Использование `StreamingResponse` с файлоподобными объектами { #using-streamingresponse-with-file-like-objects } @@ -226,7 +226,7 @@ FastAPI (фактически Starlette) автоматически добави Это включает многие библиотеки для работы с облачным хранилищем, обработки видео и т.д. -{* ../../docs_src/custom_response/tutorial008_py39.py hl[2,10:12,14] *} +{* ../../docs_src/custom_response/tutorial008_py310.py hl[2,10:12,14] *} 1. Это функция-генератор. Она является «функцией-генератором», потому что содержит оператор(ы) `yield` внутри. 2. Используя блок `with`, мы гарантируем, что файлоподобный объект будет закрыт после завершения работы функции-генератора. То есть после того, как она закончит отправку ответа. @@ -255,11 +255,11 @@ FastAPI (фактически Starlette) автоматически добави Файловые ответы будут содержать соответствующие заголовки `Content-Length`, `Last-Modified` и `ETag`. -{* ../../docs_src/custom_response/tutorial009_py39.py hl[2,10] *} +{* ../../docs_src/custom_response/tutorial009_py310.py hl[2,10] *} Вы также можете использовать параметр `response_class`: -{* ../../docs_src/custom_response/tutorial009b_py39.py hl[2,8,10] *} +{* ../../docs_src/custom_response/tutorial009b_py310.py hl[2,8,10] *} В этом случае вы можете возвращать путь к файлу напрямую из своей функции-обработчика пути. @@ -273,7 +273,7 @@ FastAPI (фактически Starlette) автоматически добави Вы могли бы создать `CustomORJSONResponse`. Главное, что вам нужно сделать — реализовать метод `Response.render(content)`, который возвращает содержимое как `bytes`: -{* ../../docs_src/custom_response/tutorial009c_py39.py hl[9:14,17] *} +{* ../../docs_src/custom_response/tutorial009c_py310.py hl[9:14,17] *} Теперь вместо того, чтобы возвращать: @@ -299,7 +299,7 @@ FastAPI (фактически Starlette) автоматически добави В примере ниже **FastAPI** будет использовать `ORJSONResponse` по умолчанию во всех операциях пути вместо `JSONResponse`. -{* ../../docs_src/custom_response/tutorial010_py39.py hl[2,4] *} +{* ../../docs_src/custom_response/tutorial010_py310.py hl[2,4] *} /// tip | Совет diff --git a/docs/ru/docs/advanced/dataclasses.md b/docs/ru/docs/advanced/dataclasses.md index b3ced37c1..87a5763c1 100644 --- a/docs/ru/docs/advanced/dataclasses.md +++ b/docs/ru/docs/advanced/dataclasses.md @@ -64,7 +64,7 @@ FastAPI построен поверх **Pydantic**, и я показывал в 6. Здесь мы возвращаем словарь, содержащий `items`, который является списком dataclass. - FastAPI по-прежнему способен сериализовать данные в JSON. + FastAPI по-прежнему способен сериализовать данные в JSON. 7. Здесь `response_model` использует аннотацию типа — список dataclass `Author`. diff --git a/docs/ru/docs/advanced/events.md b/docs/ru/docs/advanced/events.md index db73d9094..bcb5b000a 100644 --- a/docs/ru/docs/advanced/events.md +++ b/docs/ru/docs/advanced/events.md @@ -30,7 +30,7 @@ Мы создаём асинхронную функцию `lifespan()` с `yield` примерно так: -{* ../../docs_src/events/tutorial003_py39.py hl[16,19] *} +{* ../../docs_src/events/tutorial003_py310.py hl[16,19] *} Здесь мы симулируем дорогую операцию startup по загрузке модели, помещая (фиктивную) функцию модели в словарь с моделями Машинного обучения до `yield`. Этот код будет выполнен до того, как приложение начнет принимать запросы, во время startup. @@ -48,7 +48,7 @@ Первое, на что стоит обратить внимание, — мы определяем асинхронную функцию с `yield`. Это очень похоже на Зависимости с `yield`. -{* ../../docs_src/events/tutorial003_py39.py hl[14:19] *} +{* ../../docs_src/events/tutorial003_py310.py hl[14:19] *} Первая часть функции, до `yield`, будет выполнена до запуска приложения. @@ -60,7 +60,7 @@ Это превращает функцию в «асинхронный менеджер контекста». -{* ../../docs_src/events/tutorial003_py39.py hl[1,13] *} +{* ../../docs_src/events/tutorial003_py310.py hl[1,13] *} Менеджер контекста в Python — это то, что можно использовать в операторе `with`. Например, `open()` можно использовать как менеджер контекста: @@ -82,7 +82,7 @@ async with lifespan(app): Параметр `lifespan` приложения `FastAPI` принимает асинхронный менеджер контекста, поэтому мы можем передать ему наш новый асинхронный менеджер контекста `lifespan`. -{* ../../docs_src/events/tutorial003_py39.py hl[22] *} +{* ../../docs_src/events/tutorial003_py310.py hl[22] *} ## Альтернативные события (устаревшие) { #alternative-events-deprecated } @@ -104,7 +104,7 @@ async with lifespan(app): Чтобы добавить функцию, которую нужно запустить до старта приложения, объявите её как обработчик события `"startup"`: -{* ../../docs_src/events/tutorial001_py39.py hl[8] *} +{* ../../docs_src/events/tutorial001_py310.py hl[8] *} В этом случае функция-обработчик события `startup` инициализирует «базу данных» items (это просто `dict`) некоторыми значениями. @@ -116,7 +116,7 @@ async with lifespan(app): Чтобы добавить функцию, которую нужно запустить при завершении работы приложения, объявите её как обработчик события `"shutdown"`: -{* ../../docs_src/events/tutorial002_py39.py hl[6] *} +{* ../../docs_src/events/tutorial002_py310.py hl[6] *} Здесь функция-обработчик события `shutdown` запишет строку текста `"Application shutdown"` в файл `log.txt`. diff --git a/docs/ru/docs/advanced/generate-clients.md b/docs/ru/docs/advanced/generate-clients.md index 00bdd31fe..4eb098a88 100644 --- a/docs/ru/docs/advanced/generate-clients.md +++ b/docs/ru/docs/advanced/generate-clients.md @@ -2,7 +2,7 @@ Поскольку **FastAPI** основан на спецификации **OpenAPI**, его API можно описать в стандартном формате, понятном множеству инструментов. -Это упрощает генерацию актуальной **документации**, клиентских библиотек (**SDKs**) на разных языках, а также **тестирования** или **воркфлоу автоматизации**, которые остаются синхронизированными с вашим кодом. +Это упрощает генерацию актуальной **документации**, клиентских библиотек (**SDKs**) на разных языках, а также **тестирования** или **воркфлоу автоматизации**, которые остаются синхронизированными с вашим кодом. В этом руководстве вы узнаете, как сгенерировать **TypeScript SDK** для вашего бэкенда на FastAPI. @@ -40,7 +40,7 @@ FastAPI автоматически генерирует спецификации Начнём с простого приложения FastAPI: -{* ../../docs_src/generate_clients/tutorial001_py39.py hl[7:9,12:13,16:17,21] *} +{* ../../docs_src/generate_clients/tutorial001_py310.py hl[7:9,12:13,16:17,21] *} Обратите внимание, что *операции пути (обработчики пути)* определяют модели, которые они используют для полезной нагрузки запроса и полезной нагрузки ответа, с помощью моделей `Item` и `ResponseMessage`. @@ -98,7 +98,7 @@ npx @hey-api/openapi-ts -i http://localhost:8000/openapi.json -o src/client Например, у вас может быть раздел для **items** и другой раздел для **users**, и они могут быть разделены тегами: -{* ../../docs_src/generate_clients/tutorial002_py39.py hl[21,26,34] *} +{* ../../docs_src/generate_clients/tutorial002_py310.py hl[21,26,34] *} ### Генерация TypeScript‑клиента с тегами { #generate-a-typescript-client-with-tags } @@ -145,7 +145,7 @@ FastAPI использует **уникальный ID** для каждой *о Затем вы можете передать эту пользовательскую функцию в **FastAPI** через параметр `generate_unique_id_function`: -{* ../../docs_src/generate_clients/tutorial003_py39.py hl[6:7,10] *} +{* ../../docs_src/generate_clients/tutorial003_py310.py hl[6:7,10] *} ### Генерация TypeScript‑клиента с пользовательскими ID операций { #generate-a-typescript-client-with-custom-operation-ids } @@ -157,7 +157,7 @@ FastAPI использует **уникальный ID** для каждой *о ### Предобработка спецификации OpenAPI для генератора клиента { #preprocess-the-openapi-specification-for-the-client-generator } -Сгенерированном коде всё ещё есть **дублирующаяся информация**. +В сгенерированном коде всё ещё есть **дублирующаяся информация**. Мы уже знаем, что этот метод относится к **items**, потому что это слово есть в `ItemsService` (взято из тега), но при этом имя тега всё ещё добавлено префиксом к имени метода. 😕 @@ -167,7 +167,7 @@ FastAPI использует **уникальный ID** для каждой *о Мы можем скачать OpenAPI JSON в файл `openapi.json`, а затем **убрать этот префикс‑тег** таким скриптом: -{* ../../docs_src/generate_clients/tutorial004_py39.py *} +{* ../../docs_src/generate_clients/tutorial004_py310.py *} //// tab | Node.js diff --git a/docs/ru/docs/advanced/middleware.md b/docs/ru/docs/advanced/middleware.md index 5ebe01078..034feae7e 100644 --- a/docs/ru/docs/advanced/middleware.md +++ b/docs/ru/docs/advanced/middleware.md @@ -57,13 +57,13 @@ app.add_middleware(UnicornMiddleware, some_config="rainbow") Любой входящий запрос по `http` или `ws` будет перенаправлен на безопасную схему. -{* ../../docs_src/advanced_middleware/tutorial001_py39.py hl[2,6] *} +{* ../../docs_src/advanced_middleware/tutorial001_py310.py hl[2,6] *} ## `TrustedHostMiddleware` { #trustedhostmiddleware } Гарантирует, что во всех входящих запросах корректно установлен `Host`‑заголовок, чтобы защититься от атак на HTTP‑заголовок Host. -{* ../../docs_src/advanced_middleware/tutorial002_py39.py hl[2,6:8] *} +{* ../../docs_src/advanced_middleware/tutorial002_py310.py hl[2,6:8] *} Поддерживаются следующие аргументы: @@ -78,7 +78,7 @@ app.add_middleware(UnicornMiddleware, some_config="rainbow") Это middleware обрабатывает как обычные, так и потоковые ответы. -{* ../../docs_src/advanced_middleware/tutorial003_py39.py hl[2,6] *} +{* ../../docs_src/advanced_middleware/tutorial003_py310.py hl[2,6] *} Поддерживаются следующие аргументы: diff --git a/docs/ru/docs/advanced/openapi-webhooks.md b/docs/ru/docs/advanced/openapi-webhooks.md index 3a2b9fff7..b477075c1 100644 --- a/docs/ru/docs/advanced/openapi-webhooks.md +++ b/docs/ru/docs/advanced/openapi-webhooks.md @@ -16,9 +16,9 @@ Вся логика регистрации URL-адресов для вебхуков и код, который реально отправляет эти запросы, целиком на вашей стороне. Вы пишете это так, как вам нужно, в своем собственном коде. -## Документирование вебхуков с помощью FastAPI и OpenAPI { #documenting-webhooks-with-fastapi-and-openapi } +## Документирование вебхуков с помощью **FastAPI** и OpenAPI { #documenting-webhooks-with-fastapi-and-openapi } -С FastAPI, используя OpenAPI, вы можете определить имена этих вебхуков, типы HTTP-операций, которые ваше приложение может отправлять (например, `POST`, `PUT` и т.д.), а также тела запросов, которые ваше приложение будет отправлять. +С **FastAPI**, используя OpenAPI, вы можете определить имена этих вебхуков, типы HTTP-операций, которые ваше приложение может отправлять (например, `POST`, `PUT` и т.д.), а также тела запросов, которые ваше приложение будет отправлять. Это значительно упростит вашим пользователям реализацию их API для приема ваших вебхук-запросов; возможно, они даже смогут автоматически сгенерировать часть кода своего API. @@ -32,7 +32,7 @@ При создании приложения на **FastAPI** есть атрибут `webhooks`, с помощью которого можно объявлять вебхуки так же, как вы объявляете операции пути (обработчики пути), например с `@app.webhooks.post()`. -{* ../../docs_src/openapi_webhooks/tutorial001_py39.py hl[9:13,36:53] *} +{* ../../docs_src/openapi_webhooks/tutorial001_py310.py hl[9:12,15:20] *} Определенные вами вебхуки попадут в схему **OpenAPI** и в автоматический **интерфейс документации**. diff --git a/docs/ru/docs/advanced/path-operation-advanced-configuration.md b/docs/ru/docs/advanced/path-operation-advanced-configuration.md index 86d3a5b63..b8c879bf6 100644 --- a/docs/ru/docs/advanced/path-operation-advanced-configuration.md +++ b/docs/ru/docs/advanced/path-operation-advanced-configuration.md @@ -12,7 +12,7 @@ Нужно убедиться, что он уникален для каждой операции. -{* ../../docs_src/path_operation_advanced_configuration/tutorial001_py39.py hl[6] *} +{* ../../docs_src/path_operation_advanced_configuration/tutorial001_py310.py hl[6] *} ### Использование имени *функции-обработчика пути* как operationId { #using-the-path-operation-function-name-as-the-operationid } @@ -20,7 +20,7 @@ Делать это следует после добавления всех *операций пути*. -{* ../../docs_src/path_operation_advanced_configuration/tutorial002_py39.py hl[2, 12:21, 24] *} +{* ../../docs_src/path_operation_advanced_configuration/tutorial002_py310.py hl[2, 12:21, 24] *} /// tip | Совет @@ -40,7 +40,7 @@ Чтобы исключить *операцию пути* из генерируемой схемы OpenAPI (а значит, и из автоматических систем документации), используйте параметр `include_in_schema` и установите его в `False`: -{* ../../docs_src/path_operation_advanced_configuration/tutorial003_py39.py hl[6] *} +{* ../../docs_src/path_operation_advanced_configuration/tutorial003_py310.py hl[6] *} ## Расширенное описание из docstring { #advanced-description-from-docstring } @@ -92,7 +92,7 @@ `openapi_extra` может пригодиться, например, чтобы объявить [Расширения OpenAPI](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#specificationExtensions): -{* ../../docs_src/path_operation_advanced_configuration/tutorial005_py39.py hl[6] *} +{* ../../docs_src/path_operation_advanced_configuration/tutorial005_py310.py hl[6] *} Если вы откроете автоматическую документацию API, ваше расширение появится внизу страницы конкретной *операции пути*. @@ -139,9 +139,9 @@ Это можно сделать с помощью `openapi_extra`: -{* ../../docs_src/path_operation_advanced_configuration/tutorial006_py39.py hl[19:36, 39:40] *} +{* ../../docs_src/path_operation_advanced_configuration/tutorial006_py310.py hl[19:36, 39:40] *} -В этом примере мы не объявляли никакую Pydantic-модель. Фактически тело запроса даже не распарсено как JSON, оно читается напрямую как `bytes`, а функция `magic_data_reader()` будет отвечать за его парсинг каким-то способом. +В этом примере мы не объявляли никакую Pydantic-модель. Фактически тело запроса даже не распарсено как JSON, оно читается напрямую как `bytes`, а функция `magic_data_reader()` будет отвечать за его парсинг каким-то способом. Тем не менее, мы можем объявить ожидаемую схему для тела запроса. @@ -153,7 +153,7 @@ Например, в этом приложении мы не используем встроенную функциональность FastAPI для извлечения JSON Schema из моделей Pydantic, равно как и автоматическую валидацию JSON. Мы объявляем тип содержимого HTTP-запроса как YAML, а не JSON: -{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py39.py hl[15:20, 22] *} +{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py310.py hl[15:20, 22] *} Тем не менее, хотя мы не используем встроенную функциональность по умолчанию, мы всё равно используем Pydantic-модель, чтобы вручную сгенерировать JSON Schema для данных, которые мы хотим получить в YAML. @@ -161,7 +161,7 @@ А затем в нашем коде мы напрямую парсим это содержимое YAML и снова используем ту же Pydantic-модель, чтобы валидировать YAML-содержимое: -{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py39.py hl[24:31] *} +{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py310.py hl[24:31] *} /// tip | Совет diff --git a/docs/ru/docs/advanced/response-change-status-code.md b/docs/ru/docs/advanced/response-change-status-code.md index 85d9050ff..273862bae 100644 --- a/docs/ru/docs/advanced/response-change-status-code.md +++ b/docs/ru/docs/advanced/response-change-status-code.md @@ -20,7 +20,7 @@ И затем вы можете установить `status_code` в этом *временном* объекте ответа. -{* ../../docs_src/response_change_status_code/tutorial001_py39.py hl[1,9,12] *} +{* ../../docs_src/response_change_status_code/tutorial001_py310.py hl[1,9,12] *} После этого вы можете вернуть любой объект, который вам нужен, как обычно (`dict`, модель базы данных и т.д.). diff --git a/docs/ru/docs/advanced/response-cookies.md b/docs/ru/docs/advanced/response-cookies.md index 2872d6c0a..d3662ef8e 100644 --- a/docs/ru/docs/advanced/response-cookies.md +++ b/docs/ru/docs/advanced/response-cookies.md @@ -6,7 +6,7 @@ Затем установить cookies в этом временном объекте ответа. -{* ../../docs_src/response_cookies/tutorial002_py39.py hl[1, 8:9] *} +{* ../../docs_src/response_cookies/tutorial002_py310.py hl[1, 8:9] *} После этого можно вернуть любой объект, как и раньше (например, `dict`, объект модели базы данных и так далее). @@ -24,7 +24,7 @@ Затем установите cookies и верните этот объект: -{* ../../docs_src/response_cookies/tutorial001_py39.py hl[10:12] *} +{* ../../docs_src/response_cookies/tutorial001_py310.py hl[10:12] *} /// tip | Совет diff --git a/docs/ru/docs/advanced/response-directly.md b/docs/ru/docs/advanced/response-directly.md index b45281071..60facdd85 100644 --- a/docs/ru/docs/advanced/response-directly.md +++ b/docs/ru/docs/advanced/response-directly.md @@ -54,7 +54,7 @@ Вы можете поместить ваш XML-контент в строку, поместить её в `Response` и вернуть: -{* ../../docs_src/response_directly/tutorial002_py39.py hl[1,18] *} +{* ../../docs_src/response_directly/tutorial002_py310.py hl[1,18] *} ## Примечания { #notes } diff --git a/docs/ru/docs/advanced/response-headers.md b/docs/ru/docs/advanced/response-headers.md index 8f24f05b0..dc821983b 100644 --- a/docs/ru/docs/advanced/response-headers.md +++ b/docs/ru/docs/advanced/response-headers.md @@ -6,7 +6,7 @@ А затем вы можете устанавливать HTTP-заголовки в этом *временном* объекте ответа. -{* ../../docs_src/response_headers/tutorial002_py39.py hl[1, 7:8] *} +{* ../../docs_src/response_headers/tutorial002_py310.py hl[1, 7:8] *} После этого вы можете вернуть любой нужный объект, как обычно (например, `dict`, модель из базы данных и т.д.). @@ -22,7 +22,7 @@ Создайте ответ, как описано в [Вернуть Response напрямую](response-directly.md){.internal-link target=_blank}, и передайте заголовки как дополнительный параметр: -{* ../../docs_src/response_headers/tutorial001_py39.py hl[10:12] *} +{* ../../docs_src/response_headers/tutorial001_py310.py hl[10:12] *} /// note | Технические детали diff --git a/docs/ru/docs/advanced/security/http-basic-auth.md b/docs/ru/docs/advanced/security/http-basic-auth.md index 41e62d4bf..a6bfb7c54 100644 --- a/docs/ru/docs/advanced/security/http-basic-auth.md +++ b/docs/ru/docs/advanced/security/http-basic-auth.md @@ -20,7 +20,7 @@ * Она возвращает объект типа `HTTPBasicCredentials`: * Он содержит отправленные `username` и `password`. -{* ../../docs_src/security/tutorial006_an_py39.py hl[4,8,12] *} +{* ../../docs_src/security/tutorial006_an_py310.py hl[4,8,12] *} Когда вы впервые откроете URL (или нажмёте кнопку «Execute» в документации), браузер попросит ввести имя пользователя и пароль: @@ -40,7 +40,7 @@ Затем можно использовать `secrets.compare_digest()`, чтобы убедиться, что `credentials.username` равен `"stanleyjobson"`, а `credentials.password` — `"swordfish"`. -{* ../../docs_src/security/tutorial007_an_py39.py hl[1,12:24] *} +{* ../../docs_src/security/tutorial007_an_py310.py hl[1,12:24] *} Это было бы похоже на: @@ -104,4 +104,4 @@ Pythonу придётся сравнить весь общий префикс `s После того как обнаружено, что учётные данные некорректны, верните `HTTPException` со статус-кодом ответа 401 (тем же, что и при отсутствии учётных данных) и добавьте HTTP-заголовок `WWW-Authenticate`, чтобы браузер снова показал окно входа: -{* ../../docs_src/security/tutorial007_an_py39.py hl[26:30] *} +{* ../../docs_src/security/tutorial007_an_py310.py hl[26:30] *} diff --git a/docs/ru/docs/advanced/settings.md b/docs/ru/docs/advanced/settings.md index 8408faebf..15537e2b4 100644 --- a/docs/ru/docs/advanced/settings.md +++ b/docs/ru/docs/advanced/settings.md @@ -54,7 +54,7 @@ $ pip install "fastapi[all]" Вы можете использовать все те же возможности валидации и инструменты, что и для Pydantic‑моделей, например разные типы данных и дополнительную валидацию через `Field()`. -{* ../../docs_src/settings/tutorial001_py39.py hl[2,5:8,11] *} +{* ../../docs_src/settings/tutorial001_py310.py hl[2,5:8,11] *} /// tip | Совет @@ -70,7 +70,7 @@ $ pip install "fastapi[all]" Затем вы можете использовать новый объект `settings` в вашем приложении: -{* ../../docs_src/settings/tutorial001_py39.py hl[18:20] *} +{* ../../docs_src/settings/tutorial001_py310.py hl[18:20] *} ### Запуск сервера { #run-the-server } @@ -104,11 +104,11 @@ $ ADMIN_EMAIL="deadpool@example.com" APP_NAME="ChimichangApp" fastapi run main.p Например, у вас может быть файл `config.py` со следующим содержимым: -{* ../../docs_src/settings/app01_py39/config.py *} +{* ../../docs_src/settings/app01_py310/config.py *} А затем использовать его в файле `main.py`: -{* ../../docs_src/settings/app01_py39/main.py hl[3,11:13] *} +{* ../../docs_src/settings/app01_py310/main.py hl[3,11:13] *} /// tip | Совет @@ -126,7 +126,7 @@ $ ADMIN_EMAIL="deadpool@example.com" APP_NAME="ChimichangApp" fastapi run main.p Продолжая предыдущий пример, ваш файл `config.py` может выглядеть так: -{* ../../docs_src/settings/app02_an_py39/config.py hl[10] *} +{* ../../docs_src/settings/app02_an_py310/config.py hl[10] *} Обратите внимание, что теперь мы не создаем экземпляр по умолчанию `settings = Settings()`. @@ -134,7 +134,7 @@ $ ADMIN_EMAIL="deadpool@example.com" APP_NAME="ChimichangApp" fastapi run main.p Теперь мы создаем зависимость, которая возвращает новый `config.Settings()`. -{* ../../docs_src/settings/app02_an_py39/main.py hl[6,12:13] *} +{* ../../docs_src/settings/app02_an_py310/main.py hl[6,12:13] *} /// tip | Совет @@ -146,13 +146,13 @@ $ ADMIN_EMAIL="deadpool@example.com" APP_NAME="ChimichangApp" fastapi run main.p Затем мы можем запросить ее в *функции-обработчике пути* как зависимость и использовать там, где нужно. -{* ../../docs_src/settings/app02_an_py39/main.py hl[17,19:21] *} +{* ../../docs_src/settings/app02_an_py310/main.py hl[17,19:21] *} ### Настройки и тестирование { #settings-and-testing } Далее будет очень просто предоставить другой объект настроек во время тестирования, создав переопределение зависимости для `get_settings`: -{* ../../docs_src/settings/app02_an_py39/test_main.py hl[9:10,13,21] *} +{* ../../docs_src/settings/app02_an_py310/test_main.py hl[9:10,13,21] *} В переопределении зависимости мы задаем новое значение `admin_email` при создании нового объекта `Settings`, а затем возвращаем этот новый объект. @@ -193,7 +193,7 @@ APP_NAME="ChimichangApp" Затем обновите ваш `config.py` так: -{* ../../docs_src/settings/app03_an_py39/config.py hl[9] *} +{* ../../docs_src/settings/app03_an_py310/config.py hl[9] *} /// tip | Совет @@ -226,7 +226,7 @@ def get_settings(): Но так как мы используем декоратор `@lru_cache` сверху, объект `Settings` будет создан только один раз — при первом вызове. ✔️ -{* ../../docs_src/settings/app03_an_py39/main.py hl[1,11] *} +{* ../../docs_src/settings/app03_an_py310/main.py hl[1,11] *} Затем при любых последующих вызовах `get_settings()` в зависимостях для следующих запросов, вместо выполнения внутреннего кода `get_settings()` и создания нового объекта `Settings`, будет возвращаться тот же объект, что был возвращен при первом вызове, снова и снова. diff --git a/docs/ru/docs/advanced/sub-applications.md b/docs/ru/docs/advanced/sub-applications.md index fa5a683f4..4fd5649ce 100644 --- a/docs/ru/docs/advanced/sub-applications.md +++ b/docs/ru/docs/advanced/sub-applications.md @@ -10,7 +10,7 @@ Сначала создайте основное, верхнего уровня, приложение **FastAPI** и его *операции пути*: -{* ../../docs_src/sub_applications/tutorial001_py39.py hl[3, 6:8] *} +{* ../../docs_src/sub_applications/tutorial001_py310.py hl[3, 6:8] *} ### Подприложение { #sub-application } @@ -18,7 +18,7 @@ Это подприложение — обычное стандартное приложение FastAPI, но именно оно будет «смонтировано»: -{* ../../docs_src/sub_applications/tutorial001_py39.py hl[11, 14:16] *} +{* ../../docs_src/sub_applications/tutorial001_py310.py hl[11, 14:16] *} ### Смонтируйте подприложение { #mount-the-sub-application } @@ -26,7 +26,7 @@ В этом случае оно будет смонтировано по пути `/subapi`: -{* ../../docs_src/sub_applications/tutorial001_py39.py hl[11, 19] *} +{* ../../docs_src/sub_applications/tutorial001_py310.py hl[11, 19] *} ### Проверьте автоматическую документацию API { #check-the-automatic-api-docs } diff --git a/docs/ru/docs/advanced/templates.md b/docs/ru/docs/advanced/templates.md index 460e2e466..68adcb515 100644 --- a/docs/ru/docs/advanced/templates.md +++ b/docs/ru/docs/advanced/templates.md @@ -27,7 +27,7 @@ $ pip install jinja2 - Объявите параметр `Request` в *операции пути*, которая будет возвращать шаблон. - Используйте созданный `templates`, чтобы отрендерить и вернуть `TemplateResponse`; передайте имя шаблона, объект `request` и словарь «context» с парами ключ-значение для использования внутри шаблона Jinja2. -{* ../../docs_src/templates/tutorial001_py39.py hl[4,11,15:18] *} +{* ../../docs_src/templates/tutorial001_py310.py hl[4,11,15:18] *} /// note | Примечание diff --git a/docs/ru/docs/advanced/testing-events.md b/docs/ru/docs/advanced/testing-events.md index 82caea845..452342cdd 100644 --- a/docs/ru/docs/advanced/testing-events.md +++ b/docs/ru/docs/advanced/testing-events.md @@ -2,11 +2,11 @@ Если вам нужно, чтобы `lifespan` выполнялся в ваших тестах, вы можете использовать `TestClient` вместе с оператором `with`: -{* ../../docs_src/app_testing/tutorial004_py39.py hl[9:15,18,27:28,30:32,41:43] *} +{* ../../docs_src/app_testing/tutorial004_py310.py hl[9:15,18,27:28,30:32,41:43] *} Вы можете узнать больше подробностей в статье [Запуск lifespan в тестах на официальном сайте документации Starlette.](https://www.starlette.dev/lifespan/#running-lifespan-in-tests) Для устаревших событий `startup` и `shutdown` вы можете использовать `TestClient` следующим образом: -{* ../../docs_src/app_testing/tutorial003_py39.py hl[9:12,20:24] *} +{* ../../docs_src/app_testing/tutorial003_py310.py hl[9:12,20:24] *} diff --git a/docs/ru/docs/advanced/testing-websockets.md b/docs/ru/docs/advanced/testing-websockets.md index b6626679e..f6fa6a04b 100644 --- a/docs/ru/docs/advanced/testing-websockets.md +++ b/docs/ru/docs/advanced/testing-websockets.md @@ -4,7 +4,7 @@ Для этого используйте `TestClient` с менеджером контекста `with`, подключаясь к WebSocket: -{* ../../docs_src/app_testing/tutorial002_py39.py hl[27:31] *} +{* ../../docs_src/app_testing/tutorial002_py310.py hl[27:31] *} /// note | Примечание diff --git a/docs/ru/docs/advanced/using-request-directly.md b/docs/ru/docs/advanced/using-request-directly.md index cdf500c0e..0c091cded 100644 --- a/docs/ru/docs/advanced/using-request-directly.md +++ b/docs/ru/docs/advanced/using-request-directly.md @@ -29,7 +29,7 @@ Для этого нужно обратиться к запросу напрямую. -{* ../../docs_src/using_request_directly/tutorial001_py39.py hl[1,7:8] *} +{* ../../docs_src/using_request_directly/tutorial001_py310.py hl[1,7:8] *} Если объявить параметр *функции-обработчика пути* с типом `Request`, **FastAPI** поймёт, что нужно передать объект `Request` в этот параметр. diff --git a/docs/ru/docs/advanced/websockets.md b/docs/ru/docs/advanced/websockets.md index fa5e4738e..446cc2505 100644 --- a/docs/ru/docs/advanced/websockets.md +++ b/docs/ru/docs/advanced/websockets.md @@ -38,13 +38,13 @@ $ pip install websockets Для примера нам нужен наиболее простой способ, который позволит сосредоточиться на серверной части веб‑сокетов и получить рабочий код: -{* ../../docs_src/websockets/tutorial001_py39.py hl[2,6:38,41:43] *} +{* ../../docs_src/websockets/tutorial001_py310.py hl[2,6:38,41:43] *} ## Создание `websocket` { #create-a-websocket } Создайте `websocket` в своем **FastAPI** приложении: -{* ../../docs_src/websockets/tutorial001_py39.py hl[1,46:47] *} +{* ../../docs_src/websockets/tutorial001_py310.py hl[1,46:47] *} /// note | Технические детали @@ -58,7 +58,7 @@ $ pip install websockets Через эндпоинт веб-сокета вы можете получать и отправлять сообщения. -{* ../../docs_src/websockets/tutorial001_py39.py hl[48:52] *} +{* ../../docs_src/websockets/tutorial001_py310.py hl[48:52] *} Вы можете получать и отправлять двоичные, текстовые и JSON данные. @@ -154,7 +154,7 @@ $ fastapi dev main.py Если веб-сокет соединение закрыто, то `await websocket.receive_text()` вызовет исключение `WebSocketDisconnect`, которое можно поймать и обработать как в этом примере: -{* ../../docs_src/websockets/tutorial003_py39.py hl[79:81] *} +{* ../../docs_src/websockets/tutorial003_py310.py hl[79:81] *} Чтобы воспроизвести пример: diff --git a/docs/ru/docs/advanced/wsgi.md b/docs/ru/docs/advanced/wsgi.md index 41d3a169c..aa630c228 100644 --- a/docs/ru/docs/advanced/wsgi.md +++ b/docs/ru/docs/advanced/wsgi.md @@ -18,7 +18,7 @@ После этого смонтируйте его на путь. -{* ../../docs_src/wsgi/tutorial001_py39.py hl[1,3,23] *} +{* ../../docs_src/wsgi/tutorial001_py310.py hl[1,3,23] *} /// note | Примечание diff --git a/docs/ru/docs/alternatives.md b/docs/ru/docs/alternatives.md index 17b54aad2..1f713c3f3 100644 --- a/docs/ru/docs/alternatives.md +++ b/docs/ru/docs/alternatives.md @@ -137,7 +137,7 @@ def read_url(): ### Marshmallow { #marshmallow } -Одна из основных возможностей, нужных системам API, — «сериализация» данных, то есть преобразование данных из кода (Python) во что-то, что можно отправить по сети. Например, преобразование объекта с данными из базы в JSON-объект. Преобразование объектов `datetime` в строки и т. п. +Одна из основных возможностей, нужных системам API, — «сериализация» данных, то есть преобразование данных из кода (Python) во что-то, что можно отправить по сети. Например, преобразование объекта с данными из базы в JSON-объект. Преобразование объектов `datetime` в строки и т. п. Ещё одна важная возможность, востребованная API, — валидация данных: убеждаться, что данные валидны с учётом заданных параметров. Например, что какое-то поле — `int`, а не произвольная строка. Это особенно полезно для входящих данных. @@ -145,7 +145,7 @@ def read_url(): Именно для этих возможностей и был создан Marshmallow. Это отличная библиотека, я много ей пользовался раньше. -Но она появилась до того, как в Python появились аннотации типов. Поэтому для определения каждой схемы нужно использовать специальные утилиты и классы, предоставляемые Marshmallow. +Но она появилась до того, как в Python появились аннотации типов. Поэтому для определения каждой схемы нужно использовать специальные утилиты и классы, предоставляемые Marshmallow. /// check | Вдохновило **FastAPI** на @@ -155,7 +155,7 @@ def read_url(): ### Webargs { #webargs } -Ещё одна важная возможность для API — парсинг данных из входящих HTTP-запросов. +Ещё одна важная возможность для API — парсинг данных из входящих HTTP-запросов. Webargs — это инструмент, созданный для этого поверх нескольких фреймворков, включая Flask. @@ -245,7 +245,7 @@ Flask-apispec был создан теми же разработчиками, ч В нём встроена система внедрения зависимостей, вдохновлённая Angular 2. Требуется предварительная регистрация «инжектируемых» компонентов (как и во всех известных мне системах внедрения зависимостей), что добавляет многословности и повторяемости кода. -Поскольку параметры описываются с помощью типов TypeScript (аналог аннотаций типов в Python), поддержка редактора весьма хороша. +Поскольку параметры описываются с помощью типов TypeScript (аналог аннотаций типов в Python), поддержка редактора кода весьма хороша. Но так как данные о типах TypeScript не сохраняются после компиляции в JavaScript, он не может полагаться на типы для одновременного определения валидации, сериализации и документации. Из‑за этого и некоторых проектных решений для получения валидации, сериализации и автоматической генерации схем приходится добавлять декораторы во многих местах. В итоге это становится довольно многословным. @@ -359,7 +359,7 @@ Hug вдохновил **FastAPI** объявлять параметр `response В нём были автоматические валидация данных, сериализация данных и генерация схемы OpenAPI на основе тех же аннотаций типов в нескольких местах. -Определение схемы тела запроса не использовало те же аннотации типов Python, как в Pydantic, — это было ближе к Marshmallow, поэтому поддержка редактора была бы хуже, но всё равно APIStar оставался лучшим доступным вариантом. +Определение схемы тела запроса не использовало те же аннотации типов Python, как в Pydantic, — это было ближе к Marshmallow, поэтому поддержка редактора кода была бы хуже, но всё равно APIStar оставался лучшим доступным вариантом. На тот момент у него были лучшие показатели в бенчмарках (его превосходил только Starlette). @@ -419,7 +419,7 @@ Pydantic — это библиотека для определения вали ### Starlette { #starlette } -Starlette — это лёгкий ASGI фреймворк/набор инструментов, идеально подходящий для создания высокопроизводительных asyncio‑сервисов. +Starlette — это лёгкий ASGI фреймворк/набор инструментов, идеально подходящий для создания высокопроизводительных asyncio‑сервисов. Он очень простой и интуитивный. Спроектирован так, чтобы его было легко расширять, и чтобы компоненты были модульными. diff --git a/docs/ru/docs/async.md b/docs/ru/docs/async.md index 15d4e108a..bff32aaf4 100644 --- a/docs/ru/docs/async.md +++ b/docs/ru/docs/async.md @@ -4,7 +4,7 @@ ## Нет времени? { #in-a-hurry } -TL;DR: +TL;DR: Если вы используете сторонние библиотеки, которые нужно вызывать с `await`, например: @@ -68,13 +68,13 @@ def results(): Асинхронный код значит, что в языке 💬 есть способ сказать компьютеру/программе 🤖, что в некоторый момент кода ему 🤖 придётся подождать, пока *что-то ещё* где-то в другом месте завершится. Назовём это *что-то ещё* «медленный файл» 📝. -И пока мы ждём завершения работы с «медленныи файлом» 📝, компьютер может заняться другой работой. +И пока мы ждём завершения работы с «медленным файлом» 📝, компьютер может заняться другой работой. Затем компьютер/программа 🤖 будет возвращаться каждый раз, когда появится возможность (пока снова где-то идёт ожидание), или когда 🤖 завершит всю текущую работу. И он 🤖 проверит, не завершилась ли какая-либо из задач, которых он ждал, и сделает то, что нужно. Далее он 🤖 возьмёт первую завершившуюся задачу (скажем, наш «медленный файл» 📝) и продолжит делать с ней то, что требуется. -Это «ожидание чего-то ещё» обычно относится к операциям I/O, которые относительно «медленные» (по сравнению со скоростью процессора и оперативной памяти), например ожидание: +Это «ожидание чего-то ещё» обычно относится к операциям I/O, которые относительно «медленные» (по сравнению со скоростью процессора и оперативной памяти), например ожидание: * отправки данных клиентом по сети * получения клиентом данных, отправленных вашей программой по сети @@ -85,7 +85,7 @@ def results(): * возврата результатов запроса к базе данных * и т.д. -Поскольку основное время выполнения уходит на ожидание операций I/O, их называют операциями, «ограниченными вводом-выводом» (I/O bound). +Поскольку основное время выполнения уходит на ожидание операций I/O, их называют операциями, «ограниченными вводом-выводом» (I/O bound). Это называется «асинхронным», потому что компьютеру/программе не нужно «синхронизироваться» с медленной задачей, простаивая и выжидая точный момент её завершения, чтобы забрать результат и продолжить работу. @@ -277,7 +277,7 @@ def results(): В этом сценарии каждый уборщик (включая вас) был бы процессором, выполняющим свою часть работы. -И так как основное время выполнения уходит на реальную работу (а не ожидание), а работу в компьютере выполняет CPU, такие задачи называют «ограниченными процессором» (CPU bound). +И так как основное время выполнения уходит на реальную работу (а не ожидание), а работу в компьютере выполняет CPU, такие задачи называют «ограниченными процессором» (CPU bound). --- @@ -417,7 +417,7 @@ Starlette (и **FastAPI**) основаны на I/O. +Если вы пришли из другого async-фреймворка, который работает иначе, и привыкли объявлять тривиальные *функции-обработчики пути*, выполняющие только вычисления, через простой `def` ради крошечной выгоды в производительности (около 100 наносекунд), обратите внимание: в **FastAPI** эффект будет противоположным. В таких случаях лучше использовать `async def`, если только ваши *функции-обработчики пути* не используют код, выполняющий блокирующий I/O. Тем не менее, в обоих случаях велика вероятность, что **FastAPI** [всё равно будет быстрее](index.md#performance){.internal-link target=_blank} (или как минимум сопоставим) с вашим предыдущим фреймворком. diff --git a/docs/ru/docs/benchmarks.md b/docs/ru/docs/benchmarks.md index 612b39f70..c8cacae5f 100644 --- a/docs/ru/docs/benchmarks.md +++ b/docs/ru/docs/benchmarks.md @@ -16,19 +16,19 @@ * **Uvicorn**: ASGI-сервер * **Starlette**: (использует Uvicorn) веб-микрофреймворк - * **FastAPI**: (использует Starlette) API-микрофреймворк с рядом дополнительных возможностей для создания API, включая валидацию данных и т. п. + * **FastAPI**: (использует Starlette) API-микрофреймворк с рядом дополнительных возможностей для создания API, включая валидацию данных и т.п. * **Uvicorn**: * Будет иметь наилучшую производительность, так как помимо самого сервера у него немного дополнительного кода. * Вы не будете писать приложение непосредственно на Uvicorn. Это означало бы, что Ваш код должен включать как минимум весь код, предоставляемый Starlette (или **FastAPI**). И если Вы так сделаете, то в конечном итоге Ваше приложение будет иметь те же накладные расходы, что и при использовании фреймворка, минимизирующего код Вашего приложения и Ваши ошибки. - * Если Вы сравниваете Uvicorn, сравнивайте его с Daphne, Hypercorn, uWSGI и т. д. — серверами приложений. + * Если Вы сравниваете Uvicorn, сравнивайте его с Daphne, Hypercorn, uWSGI и т.д. — серверами приложений. * **Starlette**: * Будет на следующем месте по производительности после Uvicorn. Фактически Starlette запускается под управлением Uvicorn, поэтому он может быть только «медленнее» Uvicorn из‑за выполнения большего объёма кода. - * Зато он предоставляет Вам инструменты для создания простых веб‑приложений с маршрутизацией по путям и т. п. - * Если Вы сравниваете Starlette, сравнивайте его с Sanic, Flask, Django и т. д. — веб‑фреймворками (или микрофреймворками). + * Зато он предоставляет Вам инструменты для создания простых веб‑приложений с маршрутизацией по путям и т.п. + * Если Вы сравниваете Starlette, сравнивайте его с Sanic, Flask, Django и т.д. — веб‑фреймворками (или микрофреймворками). * **FastAPI**: * Точно так же, как Starlette использует Uvicorn и не может быть быстрее него, **FastAPI** использует Starlette, поэтому не может быть быстрее его. * FastAPI предоставляет больше возможностей поверх Starlette — те, которые почти всегда нужны при создании API, такие как валидация и сериализация данных. В довесок Вы ещё и получаете автоматическую документацию (автоматическая документация даже не увеличивает накладные расходы при работе приложения, так как она создаётся при запуске). - * Если бы Вы не использовали FastAPI, а использовали Starlette напрямую (или другой инструмент вроде Sanic, Flask, Responder и т. д.), Вам пришлось бы самостоятельно реализовать валидацию и сериализацию данных. То есть, в итоге, Ваше приложение имело бы такие же накладные расходы, как если бы оно было создано с использованием FastAPI. И во многих случаях валидация и сериализация данных представляют собой самый большой объём кода, написанного в приложениях. + * Если бы Вы не использовали FastAPI, а использовали Starlette напрямую (или другой инструмент вроде Sanic, Flask, Responder и т.д.), Вам пришлось бы самостоятельно реализовать валидацию и сериализацию данных. То есть, в итоге, Ваше приложение имело бы такие же накладные расходы, как если бы оно было создано с использованием FastAPI. И во многих случаях валидация и сериализация данных представляют собой самый большой объём кода, написанного в приложениях. * Таким образом, используя FastAPI, Вы экономите время разработки, уменьшаете количество ошибок, строк кода и, вероятно, получите ту же производительность (или лучше), как и если бы не использовали его (поскольку Вам пришлось бы реализовать все его возможности в своём коде). * Если Вы сравниваете FastAPI, сравнивайте его с фреймворком веб‑приложений (или набором инструментов), который обеспечивает валидацию данных, сериализацию и документацию, такими как Flask-apispec, NestJS, Molten и им подобные. Фреймворки с интегрированной автоматической валидацией данных, сериализацией и документацией. diff --git a/docs/ru/docs/deployment/concepts.md b/docs/ru/docs/deployment/concepts.md index 207d1604d..173dbb962 100644 --- a/docs/ru/docs/deployment/concepts.md +++ b/docs/ru/docs/deployment/concepts.md @@ -27,13 +27,13 @@ В [предыдущей главе про HTTPS](https.md){.internal-link target=_blank} мы разобрались, как HTTPS обеспечивает шифрование для вашего API. -Также мы увидели, что HTTPS обычно обеспечивает компонент, **внешний** по отношению к серверу вашего приложения — **TLS Termination Proxy**. +Также мы увидели, что HTTPS обычно обеспечивает компонент, **внешний** по отношению к серверу вашего приложения — **прокси-сервер TSL-терминации**. И должен быть компонент, отвечающий за **обновление HTTPS‑сертификатов** — это может быть тот же самый компонент или отдельный. ### Примеры инструментов для HTTPS { #example-tools-for-https } -Некоторые инструменты, которые можно использовать как TLS Termination Proxy: +Некоторые инструменты, которые можно использовать как прокси-сервер TSL-терминации: * Traefik * Автоматически обновляет сертификаты ✨ @@ -47,7 +47,7 @@ * С внешним компонентом (например, cert-manager) для обновления сертификатов * Обрабатывается внутри облачного провайдера как часть его услуг (см. ниже 👇) -Другой вариант — использовать **облачный сервис**, который возьмёт на себя больше задач, включая настройку HTTPS. Там могут быть ограничения или дополнительная стоимость и т.п., но в таком случае вам не придётся самим настраивать TLS Termination Proxy. +Другой вариант — использовать **облачный сервис**, который возьмёт на себя больше задач, включая настройку HTTPS. Там могут быть ограничения или дополнительная стоимость и т.п., но в таком случае вам не придётся самим настраивать прокси-сервер TSL-терминации. В следующих главах я покажу конкретные примеры. @@ -214,7 +214,7 @@ Процесс‑менеджер, вероятно, будет тем, кто слушает **порт** на IP. И он будет передавать всю коммуникацию воркер‑процессам. -Эти воркеры будут запускать ваше приложение, выполнять основные вычисления для получения **запроса** и возврата **ответа**, и загружать всё, что вы кладёте в переменные, в RAM. +Эти воркеры будут запускать ваше приложение, выполнять основные вычисления для получения **HTTP‑запроса** и возврата **HTTP‑ответа**, и загружать всё, что вы кладёте в переменные, в RAM. @@ -289,7 +289,7 @@ Ваш сервер(а) — это **ресурс**, который ваши программы могут потреблять или **использовать**: время вычислений на CPU и доступную оперативную память (RAM). -Какую долю системных ресурсов вы хотите потреблять/использовать? Можно подумать «немного», но на практике вы, скорее всего, захотите потреблять **максимум без падений**. +Какую долю системных ресурсов вы хотите потреблять/использовать? Можно подумать «немного», но на практике вы, вероятно, захотите потреблять **максимум без падений**. Если вы платите за 3 сервера, но используете лишь малую часть их RAM и CPU, вы, вероятно, **тратите деньги впустую** 💸 и **электроэнергию серверов** 🌎 и т.п. diff --git a/docs/ru/docs/deployment/docker.md b/docs/ru/docs/deployment/docker.md index 9e8562be7..791057fe5 100644 --- a/docs/ru/docs/deployment/docker.md +++ b/docs/ru/docs/deployment/docker.md @@ -14,7 +14,7 @@ Предпросмотр Dockerfile 👀 ```Dockerfile -FROM python:3.9 +FROM python:3.14 WORKDIR /code @@ -166,7 +166,7 @@ def read_item(item_id: int, q: str | None = None): ```{ .dockerfile .annotate } # (1)! -FROM python:3.9 +FROM python:3.14 # (2)! WORKDIR /code @@ -273,9 +273,9 @@ CMD fastapi run app/main.py --port 80 └── requirements.txt ``` -#### За прокси-сервером TLS терминации { #behind-a-tls-termination-proxy } +#### За прокси-сервером TSL-терминации { #behind-a-tls-termination-proxy } -Если вы запускаете контейнер за прокси-сервером завершения TLS (балансировщиком нагрузки), таким как Nginx или Traefik, добавьте опцию `--proxy-headers`. Это сообщит Uvicorn (через FastAPI CLI), что приложение работает за HTTPS и можно доверять соответствующим заголовкам. +Если вы запускаете контейнер за прокси-сервером TSL-терминации (балансировщиком нагрузки), таким как Nginx или Traefik, добавьте опцию `--proxy-headers`. Это сообщит Uvicorn (через FastAPI CLI), что приложение работает за HTTPS и можно доверять соответствующим заголовкам. ```Dockerfile CMD ["fastapi", "run", "app/main.py", "--proxy-headers", "--port", "80"] @@ -390,7 +390,7 @@ $ docker run -d --name mycontainer -p 80:80 myimage Тогда в `Dockerfile` нужно изменить пути копирования: ```{ .dockerfile .annotate hl_lines="10 13" } -FROM python:3.9 +FROM python:3.14 WORKDIR /code @@ -454,7 +454,7 @@ CMD ["fastapi", "run", "main.py", "--port", "80"] ## Репликация — количество процессов { #replication-number-of-processes } -Если у вас есть кластер машин с **Kubernetes**, Docker Swarm Mode, Nomad или другой похожей системой для управления распределёнными контейнерами на нескольких машинах, скорее всего вы будете **управлять репликацией** на **уровне кластера**, а не использовать **менеджер процессов** (например, Uvicorn с воркерами) в каждом контейнере. +Если у вас есть кластер машин с **Kubernetes**, Docker Swarm Mode, Nomad или другой похожей системой для управления распределёнными контейнерами на нескольких машинах, скорее всего вы будете **управлять репликацией** на **уровне кластера**, а не использовать **менеджер процессов** (например, Uvicorn с воркерами) в каждом контейнере. Одна из таких систем управления распределёнными контейнерами, как Kubernetes, обычно имеет встроенный способ управлять **репликацией контейнеров**, поддерживая **балансировку нагрузки** для входящих запросов — всё это на **уровне кластера**. @@ -462,17 +462,17 @@ CMD ["fastapi", "run", "main.py", "--port", "80"] ### Балансировщик нагрузки { #load-balancer } -При использовании контейнеров обычно есть компонент, **слушающий главный порт**. Это может быть другой контейнер — **прокси завершения TLS** для обработки **HTTPS** или похожий инструмент. +При использовании контейнеров обычно есть компонент, **слушающий главный порт**. Это может быть другой контейнер — **прокси-сервер TSL-терминации** для обработки **HTTPS** или похожий инструмент. Поскольку этот компонент принимает **нагрузку** запросов и распределяет её между воркерами **сбалансированно**, его часто называют **балансировщиком нагрузки**. /// tip | Подсказка -Тот же компонент **прокси завершения TLS**, который обрабатывает HTTPS, скорее всего также будет **балансировщиком нагрузки**. +Тот же компонент **прокси-сервер TSL-терминации**, который обрабатывает HTTPS, скорее всего также будет **балансировщиком нагрузки**. /// -При работе с контейнерами система, которую вы используете для запуска и управления ими, уже имеет внутренние средства для передачи **сетевого взаимодействия** (например, HTTP-запросов) от **балансировщика нагрузки** (который также может быть **прокси завершения TLS**) к контейнеру(-ам) с вашим приложением. +При работе с контейнерами система, которую вы используете для запуска и управления ими, уже имеет внутренние средства для передачи **сетевого взаимодействия** (например, HTTP-запросов) от **балансировщика нагрузки** (который также может быть **прокси-сервером TSL-терминации**) к контейнеру(-ам) с вашим приложением. ### Один балансировщик — несколько контейнеров-воркеров { #one-load-balancer-multiple-worker-containers } @@ -499,7 +499,7 @@ CMD ["fastapi", "run", "main.py", "--port", "80"] В таких случаях вы можете использовать опцию командной строки `--workers`, чтобы указать нужное количество воркеров: ```{ .dockerfile .annotate } -FROM python:3.9 +FROM python:3.14 WORKDIR /code diff --git a/docs/ru/docs/deployment/https.md b/docs/ru/docs/deployment/https.md index 05a03255e..ffeccfd7d 100644 --- a/docs/ru/docs/deployment/https.md +++ b/docs/ru/docs/deployment/https.md @@ -65,7 +65,7 @@ Чаще всего всё начинается с **приобретения** **имени домена**. Затем вы настраиваете его на DNS‑сервере (возможно, у того же облачного провайдера). -Скорее всего, вы получите облачный сервер (виртуальную машину) или что-то подобное, и у него будет постоянный **публичный IP-адрес**. +Скорее всего, вы получите облачный сервер (виртуальную машину) или что-то подобное, и у него будет постоянный **публичный IP-адрес**. На DNS‑сервере(ах) вы настроите запись («`A record`» - запись типа A), указывающую, что **ваш домен** должен указывать на публичный **IP‑адрес вашего сервера**. diff --git a/docs/ru/docs/deployment/index.md b/docs/ru/docs/deployment/index.md index ffb77641d..7e735593b 100644 --- a/docs/ru/docs/deployment/index.md +++ b/docs/ru/docs/deployment/index.md @@ -18,6 +18,6 @@ Например, мы, команда, стоящая за FastAPI, создали **FastAPI Cloud**, чтобы сделать развёртывание приложений FastAPI в облаке как можно более простым и прямолинейным, с тем же удобством для разработчика, что и при работе с FastAPI. -В этом блоке я покажу вам некоторые из основных концепций, которые вы, вероятно, должны иметь в виду при развертывании приложения **FastAPI** (хотя большинство из них применимо к любому другому типу веб-приложений). +Я покажу вам некоторые из основных концепций, которые вы, вероятно, должны иметь в виду при развертывании приложения **FastAPI** (хотя большинство из них применимо к любому другому типу веб-приложений). В последующих разделах вы узнаете больше деталей и методов, необходимых для этого. ✨ diff --git a/docs/ru/docs/deployment/versions.md b/docs/ru/docs/deployment/versions.md index 58d5aa110..4195d689f 100644 --- a/docs/ru/docs/deployment/versions.md +++ b/docs/ru/docs/deployment/versions.md @@ -1,12 +1,12 @@ # О версиях FastAPI { #about-fastapi-versions } -**FastAPI** уже используется в продакшене во многих приложениях и системах. Покрытие тестами поддерживается на уровне 100%. Но его разработка всё ещё движется быстрыми темпами. +**FastAPI** уже используется в продакшн во многих приложениях и системах. Покрытие тестами поддерживается на уровне 100%. Но его разработка всё ещё движется быстрыми темпами. Часто добавляются новые функции, регулярно исправляются баги, код продолжает постоянно совершенствоваться. По указанным причинам текущие версии до сих пор `0.x.x`. Это говорит о том, что каждая версия может содержать обратно несовместимые изменения, следуя Семантическому версионированию. -Уже сейчас вы можете создавать приложения в продакшене, используя **FastAPI** (и скорее всего так и делаете), главное убедиться в том, что вы используете версию, которая корректно работает с вашим кодом. +Уже сейчас вы можете создавать приложения в продакшн, используя **FastAPI** (и скорее всего так и делаете), главное убедиться в том, что вы используете версию, которая корректно работает с вашим кодом. ## Закрепите вашу версию `fastapi` { #pin-your-fastapi-version } diff --git a/docs/ru/docs/environment-variables.md b/docs/ru/docs/environment-variables.md index 6291b79d2..759127420 100644 --- a/docs/ru/docs/environment-variables.md +++ b/docs/ru/docs/environment-variables.md @@ -161,7 +161,7 @@ Hello World from Python Эти переменные окружения могут работать только с **текстовыми строками**, поскольку они являются внешними по отношению к Python и должны быть совместимы с другими программами и остальной системой (и даже с различными операционными системами, такими как Linux, Windows, macOS). -Это означает, что **любое значение**, считанное в Python из переменной окружения, **будет `str`**, и любое преобразование к другому типу или любая проверка должны быть выполнены в коде. +Это означает, что **любое значение**, считанное в Python из переменной окружения, **будет `str`**, и любое преобразование к другому типу или любая валидация должны быть выполнены в коде. Подробнее об использовании переменных окружения для работы с **настройками приложения** вы узнаете в [Расширенное руководство пользователя - Настройки и переменные среды](./advanced/settings.md){.internal-link target=_blank}. diff --git a/docs/ru/docs/fastapi-cli.md b/docs/ru/docs/fastapi-cli.md index 72cf55e7b..a46e0053e 100644 --- a/docs/ru/docs/fastapi-cli.md +++ b/docs/ru/docs/fastapi-cli.md @@ -52,7 +52,7 @@ FastAPI CLI берет путь к вашей Python-программе (нап Для работы в режиме продакшн вместо `fastapi dev` нужно использовать `fastapi run`. 🚀 -Внутри **FastAPI CLI** используется Uvicorn, высокопроизводительный, готовый к работе в продакшне ASGI-сервер. 😎 +Внутри **FastAPI CLI** используется Uvicorn, высокопроизводительный, готовый к работе в продакшн ASGI-сервер. 😎 ## `fastapi dev` { #fastapi-dev } diff --git a/docs/ru/docs/features.md b/docs/ru/docs/features.md index 703ff951e..0bc3dbb2d 100644 --- a/docs/ru/docs/features.md +++ b/docs/ru/docs/features.md @@ -6,7 +6,7 @@ ### Основано на открытых стандартах { #based-on-open-standards } -* OpenAPI для создания API, включая объявления операций пути, параметров, тел запросов, безопасности и т. д. +* OpenAPI для создания API, включая объявления операций пути, параметров, тел запросов, безопасности и т.д. * Автоматическая документация моделей данных с помощью JSON Schema (так как сама спецификация OpenAPI основана на JSON Schema). * Разработан вокруг этих стандартов, после тщательного их изучения. Это не дополнительная надстройка поверх. * Это также позволяет использовать автоматическую **генерацию клиентского кода** на многих языках. @@ -107,7 +107,7 @@ FastAPI имеет продуманные значения **по умолчан * Объекты JSON (`dict`). * Массив JSON (`list`) с определёнными типами элементов. * Строковые (`str`) поля с ограничением минимальной и максимальной длины. - * Числа (`int`, `float`) с минимальными и максимальными значениями и т. п. + * Числа (`int`, `float`) с минимальными и максимальными значениями и т.п. * Проверка для более экзотических типов, таких как: * URL. @@ -126,24 +126,24 @@ FastAPI имеет продуманные значения **по умолчан * HTTP Basic. * **OAuth2** (также с **токенами JWT**). Ознакомьтесь с руководством [OAuth2 с JWT](tutorial/security/oauth2-jwt.md){.internal-link target=_blank}. * Ключи API в: - * Заголовках. + * HTTP-заголовках. * Параметрах запросов. * Cookies и т.п. Вдобавок все функции безопасности от Starlette (включая **сессионные cookies**). -Все инструменты и компоненты спроектированы для многократного использования и легко интегрируются с вашими системами, хранилищами данных, реляционными и NoSQL базами данных и т. д. +Все инструменты и компоненты спроектированы для многократного использования и легко интегрируются с вашими системами, хранилищами данных, реляционными и NoSQL базами данных и т.д. ### Внедрение зависимостей { #dependency-injection } -FastAPI включает в себя чрезвычайно простую в использовании, но чрезвычайно мощную систему Внедрения зависимостей. +FastAPI включает в себя чрезвычайно простую в использовании, но чрезвычайно мощную систему Внедрения зависимостей. * Даже зависимости могут иметь зависимости, создавая иерархию или **«граф» зависимостей**. * Всё **автоматически обрабатывается** фреймворком. * Все зависимости могут запрашивать данные из запросов и **дополнять операции пути** ограничениями и автоматической документацией. * **Автоматическая проверка** даже для параметров *операций пути*, определённых в зависимостях. -* Поддержка сложных систем аутентификации пользователей, **соединений с базами данных** и т. д. -* **Никаких компромиссов** с базами данных, интерфейсами и т. д. Но при этом — лёгкая интеграция со всеми ними. +* Поддержка сложных систем аутентификации пользователей, **соединений с базами данных** и т.д. +* **Никаких компромиссов** с базами данных, интерфейсами и т.д. Но при этом — лёгкая интеграция со всеми ними. ### Нет ограничений на "Плагины" { #unlimited-plug-ins } @@ -153,8 +153,8 @@ FastAPI включает в себя чрезвычайно простую в и ### Проверен { #tested } -* 100% покрытие тестами. -* 100% аннотирование типов в кодовой базе. +* 100% покрытие тестами. +* 100% аннотирование типов в кодовой базе. * Используется в продакшн‑приложениях. ## Возможности Starlette { #starlette-features } @@ -179,7 +179,7 @@ FastAPI включает в себя чрезвычайно простую в и **FastAPI** полностью совместим с (и основан на) Pydantic. Поэтому любой дополнительный код Pydantic, который у вас есть, также будет работать. -Включая внешние библиотеки, также основанные на Pydantic, такие как ORM’ы, ODM’ы для баз данных. +Включая внешние библиотеки, также основанные на Pydantic, такие как ORM’ы, ODM’ы для баз данных. Это также означает, что во многих случаях вы можете передавать тот же объект, который получили из запроса, **непосредственно в базу данных**, так как всё проверяется автоматически. @@ -190,10 +190,10 @@ FastAPI включает в себя чрезвычайно простую в и * **Никакой нервотрёпки**: * Не нужно изучать новые схемы в микроязыках. * Если вы знаете типы в Python, вы знаете, как использовать Pydantic. -* Прекрасно сочетается с вашим **IDE/linter/мозгом**: +* Прекрасно сочетается с вашим **IDE/линтер/мозгом**: * Потому что структуры данных pydantic — это всего лишь экземпляры классов, определённых вами; автозавершение, проверка кода, mypy и ваша интуиция — всё будет работать с вашими валидированными данными. * Валидация **сложных структур**: - * Использование иерархических моделей Pydantic; `List`, `Dict` и т. п. из модуля `typing` (входит в стандартную библиотеку Python). + * Использование иерархических моделей Pydantic; `List`, `Dict` и т.п. из модуля `typing` (входит в стандартную библиотеку Python). * Валидаторы позволяют чётко и легко определять, проверять и документировать сложные схемы данных в виде JSON Schema. * У вас могут быть глубоко **вложенные объекты JSON**, и все они будут проверены и аннотированы. * **Расширяемость**: diff --git a/docs/ru/docs/history-design-future.md b/docs/ru/docs/history-design-future.md index 9cdd53376..e2395fe8b 100644 --- a/docs/ru/docs/history-design-future.md +++ b/docs/ru/docs/history-design-future.md @@ -30,7 +30,7 @@ ## Исследования { #investigation } -Благодаря опыту использования существующих альтернатив, мы с коллегами изучили их основные идеи и скомбинировали собранные знания наилучшим образом. +Используя все существовавшие ранее альтернативы, я получил возможность у каждой из них чему-то научиться, позаимствовать идеи и объединить их наилучшим образом для себя и для команд разработчиков, с которыми я работал. Например, стало ясно, что необходимо брать за основу стандартные аннотации типов Python. @@ -44,13 +44,13 @@ Я проверил несколько идей на самых популярных редакторах кода: PyCharm, VS Code, редакторы на базе Jedi. -Данные по редакторам я взял из опроса Python-разработчиков, который охватывает около 80% пользователей. +Согласно последнему опросу Python-разработчиков, который охватывает около 80% пользователей. Это означает, что **FastAPI** был специально проверен на редакторах, используемых 80% Python-разработчиками. И поскольку большинство других редакторов, как правило, работают аналогичным образом, все его преимущества должны работать практически для всех редакторов. Таким образом, я смог найти наилучшие способы сократить дублирование кода, обеспечить повсеместное автозавершение, проверку типов и ошибок и т.д. -И все это, чтобы все пользователи могли получать наилучший опыт разработки. +И все это, чтобы все разработчики могли получать наилучший опыт разработки. ## Зависимости { #requirements } @@ -58,7 +58,7 @@ По моим предложениям был изменён код этого фреймворка, чтобы сделать его полностью совместимым с JSON Schema, поддержать различные способы определения ограничений и улучшить поддержку в редакторах кода (проверки типов, автозавершение) на основе тестов в нескольких редакторах. -В то же время, я принимал участие в разработке **Starlette**, ещё один из основных компонентов FastAPI. +Во время разработки я также внес вклад в **Starlette**, другую ключевую зависимость. ## Разработка { #development } diff --git a/docs/ru/docs/how-to/authentication-error-status-code.md b/docs/ru/docs/how-to/authentication-error-status-code.md index 5675cecc5..596563c54 100644 --- a/docs/ru/docs/how-to/authentication-error-status-code.md +++ b/docs/ru/docs/how-to/authentication-error-status-code.md @@ -8,7 +8,7 @@ Например, вы можете создать подкласс `HTTPBearer`, который будет возвращать ошибку `403 Forbidden` вместо стандартной `401 Unauthorized`: -{* ../../docs_src/authentication_error_status_code/tutorial001_an_py39.py hl[9:13] *} +{* ../../docs_src/authentication_error_status_code/tutorial001_an_py310.py hl[9:13] *} /// tip | Совет diff --git a/docs/ru/docs/how-to/conditional-openapi.md b/docs/ru/docs/how-to/conditional-openapi.md index d0845b91e..6efa30608 100644 --- a/docs/ru/docs/how-to/conditional-openapi.md +++ b/docs/ru/docs/how-to/conditional-openapi.md @@ -4,9 +4,9 @@ ## О безопасности, API и документации { #about-security-apis-and-docs } -Скрытие пользовательских интерфейсов документации в продакшн *не должно* быть способом защиты вашего API. +Скрытие пользовательских интерфейсов документации в продакшн не должно быть способом защиты вашего API. -Это не добавляет дополнительной безопасности вашему API, *операции пути* (обработчики пути) всё равно будут доступны по своим путям. +Это не добавляет дополнительной безопасности вашему API, операции пути (обработчики пути) всё равно будут доступны по своим путям. Если в вашем коде есть уязвимость, она всё равно останется. @@ -29,7 +29,7 @@ Например: -{* ../../docs_src/conditional_openapi/tutorial001_py39.py hl[6,11] *} +{* ../../docs_src/conditional_openapi/tutorial001_py310.py hl[6,11] *} Здесь мы объявляем настройку `openapi_url` с тем же значением по умолчанию — `"/openapi.json"`. diff --git a/docs/ru/docs/how-to/configure-swagger-ui.md b/docs/ru/docs/how-to/configure-swagger-ui.md index b3b1c1ba6..f4f2a0e54 100644 --- a/docs/ru/docs/how-to/configure-swagger-ui.md +++ b/docs/ru/docs/how-to/configure-swagger-ui.md @@ -18,7 +18,7 @@ FastAPI преобразует эти настройки в **JSON**, чтобы Но вы можете отключить её, установив `syntaxHighlight` в `False`: -{* ../../docs_src/configure_swagger_ui/tutorial001_py39.py hl[3] *} +{* ../../docs_src/configure_swagger_ui/tutorial001_py310.py hl[3] *} …и после этого Swagger UI больше не будет показывать подсветку синтаксиса: @@ -28,7 +28,7 @@ FastAPI преобразует эти настройки в **JSON**, чтобы Аналогично вы можете задать тему подсветки синтаксиса с ключом "syntaxHighlight.theme" (обратите внимание, что посередине стоит точка): -{* ../../docs_src/configure_swagger_ui/tutorial002_py39.py hl[3] *} +{* ../../docs_src/configure_swagger_ui/tutorial002_py310.py hl[3] *} Эта настройка изменит цветовую тему подсветки синтаксиса: @@ -46,7 +46,7 @@ FastAPI включает некоторые параметры конфигур Например, чтобы отключить `deepLinking`, можно передать такие настройки в `swagger_ui_parameters`: -{* ../../docs_src/configure_swagger_ui/tutorial003_py39.py hl[3] *} +{* ../../docs_src/configure_swagger_ui/tutorial003_py310.py hl[3] *} ## Другие параметры Swagger UI { #other-swagger-ui-parameters } diff --git a/docs/ru/docs/how-to/custom-docs-ui-assets.md b/docs/ru/docs/how-to/custom-docs-ui-assets.md index f524911e6..e3c31b32c 100644 --- a/docs/ru/docs/how-to/custom-docs-ui-assets.md +++ b/docs/ru/docs/how-to/custom-docs-ui-assets.md @@ -18,7 +18,7 @@ Чтобы отключить её, установите их URL в значение `None` при создании вашего приложения `FastAPI`: -{* ../../docs_src/custom_docs_ui/tutorial001_py39.py hl[8] *} +{* ../../docs_src/custom_docs_ui/tutorial001_py310.py hl[8] *} ### Подключить пользовательскую документацию { #include-the-custom-docs } @@ -34,7 +34,7 @@ Аналогично и для ReDoc... -{* ../../docs_src/custom_docs_ui/tutorial001_py39.py hl[2:6,11:19,22:24,27:33] *} +{* ../../docs_src/custom_docs_ui/tutorial001_py310.py hl[2:6,11:19,22:24,27:33] *} /// tip | Совет @@ -50,7 +50,7 @@ Swagger UI сделает это за вас «за кулисами», но д Чтобы убедиться, что всё работает, создайте *операцию пути*: -{* ../../docs_src/custom_docs_ui/tutorial001_py39.py hl[36:38] *} +{* ../../docs_src/custom_docs_ui/tutorial001_py310.py hl[36:38] *} ### Тестирование { #test-it } @@ -118,7 +118,7 @@ Swagger UI сделает это за вас «за кулисами», но д * Импортируйте `StaticFiles`. * Смонтируйте экземпляр `StaticFiles()` в определённый путь. -{* ../../docs_src/custom_docs_ui/tutorial002_py39.py hl[7,11] *} +{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[7,11] *} ### Протестируйте статические файлы { #test-the-static-files } @@ -144,7 +144,7 @@ Swagger UI сделает это за вас «за кулисами», но д Чтобы отключить её, установите их URL в значение `None` при создании вашего приложения `FastAPI`: -{* ../../docs_src/custom_docs_ui/tutorial002_py39.py hl[9] *} +{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[9] *} ### Подключить пользовательскую документацию со статическими файлами { #include-the-custom-docs-for-static-files } @@ -160,7 +160,7 @@ Swagger UI сделает это за вас «за кулисами», но д Аналогично и для ReDoc... -{* ../../docs_src/custom_docs_ui/tutorial002_py39.py hl[2:6,14:22,25:27,30:36] *} +{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[2:6,14:22,25:27,30:36] *} /// tip | Совет @@ -176,7 +176,7 @@ Swagger UI сделает это за вас «за кулисами», но д Чтобы убедиться, что всё работает, создайте *операцию пути*: -{* ../../docs_src/custom_docs_ui/tutorial002_py39.py hl[39:41] *} +{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[39:41] *} ### Тестирование UI со статическими файлами { #test-static-files-ui } diff --git a/docs/ru/docs/how-to/extending-openapi.md b/docs/ru/docs/how-to/extending-openapi.md index 1d69cbdb3..197a1790a 100644 --- a/docs/ru/docs/how-to/extending-openapi.md +++ b/docs/ru/docs/how-to/extending-openapi.md @@ -24,7 +24,7 @@ * `version`: Версия вашего API, например `2.5.0`. * `openapi_version`: Версия используемой спецификации OpenAPI. По умолчанию — последняя: `3.1.0`. * `summary`: Краткое описание API. -* `description`: Описание вашего API; может включать Markdown и будет отображается в документации. +* `description`: Описание вашего API; может включать Markdown и будет отображаться в документации. * `routes`: Список маршрутов — это каждая зарегистрированная *операция пути*. Берутся из `app.routes`. /// info | Информация @@ -43,19 +43,19 @@ Сначала напишите приложение **FastAPI** как обычно: -{* ../../docs_src/extending_openapi/tutorial001_py39.py hl[1,4,7:9] *} +{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[1,4,7:9] *} ### Сгенерируйте схему OpenAPI { #generate-the-openapi-schema } Затем используйте ту же вспомогательную функцию для генерации схемы OpenAPI внутри функции `custom_openapi()`: -{* ../../docs_src/extending_openapi/tutorial001_py39.py hl[2,15:21] *} +{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[2,15:21] *} ### Измените схему OpenAPI { #modify-the-openapi-schema } Теперь можно добавить расширение ReDoc, добавив кастомный `x-logo` в «объект» `info` в схеме OpenAPI: -{* ../../docs_src/extending_openapi/tutorial001_py39.py hl[22:24] *} +{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[22:24] *} ### Кэшируйте схему OpenAPI { #cache-the-openapi-schema } @@ -65,13 +65,13 @@ Она будет создана один раз, а затем тот же кэшированный вариант будет использоваться для последующих запросов. -{* ../../docs_src/extending_openapi/tutorial001_py39.py hl[13:14,25:26] *} +{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[13:14,25:26] *} ### Переопределите метод { #override-the-method } Теперь вы можете заменить метод `.openapi()` на вашу новую функцию. -{* ../../docs_src/extending_openapi/tutorial001_py39.py hl[29] *} +{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[29] *} ### Проверьте { #check-it } diff --git a/docs/ru/docs/how-to/graphql.md b/docs/ru/docs/how-to/graphql.md index 50c321e7d..9e28d6182 100644 --- a/docs/ru/docs/how-to/graphql.md +++ b/docs/ru/docs/how-to/graphql.md @@ -35,7 +35,7 @@ Вот небольшой пример того, как можно интегрировать Strawberry с FastAPI: -{* ../../docs_src/graphql_/tutorial001_py39.py hl[3,22,25] *} +{* ../../docs_src/graphql_/tutorial001_py310.py hl[3,22,25] *} Подробнее о Strawberry можно узнать в документации Strawberry. diff --git a/docs/ru/docs/how-to/index.md b/docs/ru/docs/how-to/index.md index 228c125dd..75e7fff26 100644 --- a/docs/ru/docs/how-to/index.md +++ b/docs/ru/docs/how-to/index.md @@ -1,13 +1,13 @@ # Как сделать — Рецепты { #how-to-recipes } -Здесь вы найдете разные рецепты и руководства «как сделать» по различным темам. +Здесь вы найдете разные рецепты и руководства «как сделать» по **различным темам**. -Большинство из этих идей более-менее независимы, и в большинстве случаев вам стоит изучать их только если они напрямую относятся к вашему проекту. +Большинство из этих идей более-менее **независимы**, и в большинстве случаев вам стоит изучать их только если они напрямую относятся к **вашему проекту**. Если что-то кажется интересным и полезным для вашего проекта, смело изучайте; в противном случае, вероятно, можно просто пропустить. /// tip | Совет -Если вы хотите изучить FastAPI структурированно (рекомендуется), вместо этого читайте [Учебник — Руководство пользователя](../tutorial/index.md){.internal-link target=_blank} по главам. +Если вы хотите **изучить FastAPI** структурированно (рекомендуется), вместо этого читайте [Учебник — Руководство пользователя](../tutorial/index.md){.internal-link target=_blank} по главам. /// diff --git a/docs/ru/docs/index.md b/docs/ru/docs/index.md index b1a0c9a2e..877014a08 100644 --- a/docs/ru/docs/index.md +++ b/docs/ru/docs/index.md @@ -40,7 +40,7 @@ FastAPI — это современный, быстрый (высокопрои * **Скорость**: Очень высокая производительность, на уровне **NodeJS** и **Go** (благодаря Starlette и Pydantic). [Один из самых быстрых доступных фреймворков Python](#performance). * **Быстрота разработки**: Увеличьте скорость разработки фич примерно на 200–300%. * * **Меньше ошибок**: Сократите примерно на 40% количество ошибок, вызванных человеком (разработчиком). * -* **Интуитивность**: Отличная поддержка редактора кода. Автозавершение везде. Меньше времени на отладку. +* **Интуитивность**: Отличная поддержка редактора кода. Автозавершение везде. Меньше времени на отладку. * **Простота**: Разработан так, чтобы его было легко использовать и осваивать. Меньше времени на чтение документации. * **Краткость**: Минимизируйте дублирование кода. Несколько возможностей из каждого объявления параметров. Меньше ошибок. * **Надежность**: Получите код, готовый к продакшн. С автоматической интерактивной документацией. @@ -127,7 +127,7 @@ FastAPI — это современный, быстрый (высокопрои -Если вы создаёте приложение CLI для использования в терминале вместо веб-API, посмотрите **Typer**. +Если вы создаёте приложение CLI для использования в терминале вместо веб-API, посмотрите **Typer**. **Typer** — младший брат FastAPI. И он задуман как **FastAPI для CLI**. ⌨️ 🚀 @@ -368,7 +368,7 @@ item: Item * Валидацию данных: * Автоматические и понятные ошибки, когда данные некорректны. * Валидацию даже для глубоко вложенных объектов JSON. -* Преобразование входных данных: из сети в данные и типы Python. Чтение из: +* Преобразование входных данных: из сети в данные и типы Python. Чтение из: * JSON. * Параметров пути. * Параметров запроса. @@ -376,7 +376,7 @@ item: Item * HTTP-заголовков. * Форм. * Файлов. -* Преобразование выходных данных: из данных и типов Python в данные сети (например, JSON): +* Преобразование выходных данных: из данных и типов Python в данные сети (например, JSON): * Преобразование типов Python (`str`, `int`, `float`, `bool`, `list` и т.д.). * Объекты `datetime`. * Объекты `UUID`. @@ -439,7 +439,7 @@ item: Item * Объявление **параметров** из других источников: **HTTP-заголовки**, **cookies**, **поля формы** и **файлы**. * Как задать **ограничения валидации** вроде `maximum_length` или `regex`. -* Очень мощную и простую в использовании систему **внедрения зависимостей**. +* Очень мощную и простую в использовании систему **внедрения зависимостей**. * Безопасность и аутентификацию, включая поддержку **OAuth2** с **JWT токенами** и **HTTP Basic** аутентификацию. * Более продвинутые (но столь же простые) приёмы объявления **глубоко вложенных JSON-моделей** (спасибо Pydantic). * Интеграцию **GraphQL** с Strawberry и другими библиотеками. @@ -524,7 +524,7 @@ FastAPI зависит от Pydantic и Starlette. * httpx — обязателен, если вы хотите использовать `TestClient`. * jinja2 — обязателен, если вы хотите использовать конфигурацию шаблонов по умолчанию. -* python-multipart - обязателен, если вы хотите поддерживать «парсинг» форм через `request.form()`. +* python-multipart - обязателен, если вы хотите поддерживать «парсинг» форм через `request.form()`. Используется FastAPI: diff --git a/docs/ru/docs/project-generation.md b/docs/ru/docs/project-generation.md index dbedf76fe..8155457e3 100644 --- a/docs/ru/docs/project-generation.md +++ b/docs/ru/docs/project-generation.md @@ -18,7 +18,7 @@ - 🤖 Автоматически сгенерированный фронтенд‑клиент. - 🧪 [Playwright](https://playwright.dev) для End‑to‑End тестирования. - 🦇 Поддержка тёмной темы. -- 🐋 [Docker Compose](https://www.docker.com) для разработки и продакшна. +- 🐋 [Docker Compose](https://www.docker.com) для разработки и продакшн. - 🔒 Безопасное хэширование паролей по умолчанию. - 🔑 Аутентификация по JWT‑токенам. - 📫 Восстановление пароля по электронной почте. diff --git a/docs/ru/docs/python-types.md b/docs/ru/docs/python-types.md index ae4a1e2b7..95153c388 100644 --- a/docs/ru/docs/python-types.md +++ b/docs/ru/docs/python-types.md @@ -2,7 +2,7 @@ Python поддерживает необязательные «подсказки типов» (их также называют «аннотациями типов»). -Эти **«подсказки типов»** или аннотации — это специальный синтаксис, позволяющий объявлять тип переменной. +Эти **«подсказки типов»** или аннотации — это специальный синтаксис, позволяющий объявлять тип переменной. Объявляя типы для ваших переменных, редакторы кода и инструменты смогут лучше вас поддерживать. @@ -22,7 +22,7 @@ Python поддерживает необязательные «подсказк Давайте начнем с простого примера: -{* ../../docs_src/python_types/tutorial001_py39.py *} +{* ../../docs_src/python_types/tutorial001_py310.py *} Вызов этой программы выводит: @@ -34,9 +34,9 @@ John Doe * Принимает `first_name` и `last_name`. * Преобразует первую букву каждого значения в верхний регистр с помощью `title()`. -* Соединяет их пробелом посередине. +* Соединяет их пробелом посередине. -{* ../../docs_src/python_types/tutorial001_py39.py hl[2] *} +{* ../../docs_src/python_types/tutorial001_py310.py hl[2] *} ### Отредактируем пример { #edit-it } @@ -78,7 +78,7 @@ John Doe Это и есть «подсказки типов»: -{* ../../docs_src/python_types/tutorial002_py39.py hl[1] *} +{* ../../docs_src/python_types/tutorial002_py310.py hl[1] *} Это не то же самое, что объявление значений по умолчанию, как, например: @@ -106,7 +106,7 @@ John Doe Посмотрите на эту функцию — у неё уже есть подсказки типов: -{* ../../docs_src/python_types/tutorial003_py39.py hl[1] *} +{* ../../docs_src/python_types/tutorial003_py310.py hl[1] *} Так как редактор кода знает типы переменных, вы получаете не только автозавершение, но и проверки ошибок: @@ -114,7 +114,7 @@ John Doe Теперь вы знаете, что нужно исправить — преобразовать `age` в строку с помощью `str(age)`: -{* ../../docs_src/python_types/tutorial004_py39.py hl[2] *} +{* ../../docs_src/python_types/tutorial004_py310.py hl[2] *} ## Объявление типов { #declaring-types } @@ -133,29 +133,32 @@ John Doe * `bool` * `bytes` -{* ../../docs_src/python_types/tutorial005_py39.py hl[1] *} +{* ../../docs_src/python_types/tutorial005_py310.py hl[1] *} -### Generic-типы с параметрами типов { #generic-types-with-type-parameters } +### Модуль `typing` { #typing-module } -Есть структуры данных, которые могут содержать другие значения, например, `dict`, `list`, `set` и `tuple`. И внутренние значения тоже могут иметь свой тип. +Для некоторых дополнительных сценариев может понадобиться импортировать что-то из стандартного модуля `typing`. Например, когда вы хотите объявить, что что-то имеет «любой тип», можно использовать `Any` из `typing`: -Такие типы, которые содержат внутренние типы, называют «**generic**»-типами. И их можно объявлять, в том числе с указанием внутренних типов. +```python +from typing import Any -Чтобы объявлять эти типы и их внутренние типы, вы можете использовать стандартный модуль Python `typing`. Он существует специально для поддержки подсказок типов. -#### Новые версии Python { #newer-versions-of-python } +def some_function(data: Any): + print(data) +``` -Синтаксис с использованием `typing` **совместим** со всеми версиями, от Python 3.6 до самых новых, включая Python 3.9, Python 3.10 и т.д. +### Generic-типы { #generic-types } -По мере развития Python **новые версии** получают улучшенную поддержку этих аннотаций типов, и во многих случаях вам даже не нужно импортировать и использовать модуль `typing`, чтобы объявлять аннотации типов. +Некоторые типы могут принимать «параметры типов» в квадратных скобках, чтобы определить их внутренние типы. Например, «список строк» объявляется как `list[str]`. -Если вы можете выбрать более свежую версию Python для проекта, вы получите дополнительную простоту. +Такие типы, которые принимают параметры типов, называются **Generic-типами** или **Generics**. -Во всей документации есть примеры, совместимые с каждой версией Python (когда есть различия). +Вы можете использовать те же встроенные типы как generics (с квадратными скобками и типами внутри): -Например, «**Python 3.6+**» означает совместимость с Python 3.6 и выше (включая 3.7, 3.8, 3.9, 3.10 и т.д.). А «**Python 3.9+**» — совместимость с Python 3.9 и выше (включая 3.10 и т.п.). - -Если вы можете использовать **последние версии Python**, используйте примеры для самой новой версии — у них будет **самый лучший и простой синтаксис**, например, «**Python 3.10+**». +* `list` +* `tuple` +* `set` +* `dict` #### List { #list } @@ -167,7 +170,7 @@ John Doe Так как список — это тип, содержащий внутренние типы, укажите их в квадратных скобках: -{* ../../docs_src/python_types/tutorial006_py39.py hl[1] *} +{* ../../docs_src/python_types/tutorial006_py310.py hl[1] *} /// info | Информация @@ -193,7 +196,7 @@ John Doe Аналогично вы бы объявили `tuple` и `set`: -{* ../../docs_src/python_types/tutorial007_py39.py hl[1] *} +{* ../../docs_src/python_types/tutorial007_py310.py hl[1] *} Это означает: @@ -208,7 +211,7 @@ John Doe Второй параметр типа — для значений `dict`: -{* ../../docs_src/python_types/tutorial008_py39.py hl[1] *} +{* ../../docs_src/python_types/tutorial008_py310.py hl[1] *} Это означает: @@ -220,44 +223,20 @@ John Doe Вы можете объявить, что переменная может быть **одним из нескольких типов**, например, `int` или `str`. -В Python 3.6 и выше (включая Python 3.10) вы можете использовать тип `Union` из `typing` и перечислить в квадратных скобках все допустимые типы. +Чтобы это определить, используйте вертикальную черту (`|`) для разделения обоих типов. -В Python 3.10 также появился **новый синтаксис**, где допустимые типы можно указать через вертикальную черту (`|`). - -//// tab | Python 3.10+ +Это называется «объединение» (union), потому что переменная может быть чем угодно из объединения этих двух множеств типов. ```Python hl_lines="1" {!> ../../docs_src/python_types/tutorial008b_py310.py!} ``` -//// - -//// tab | Python 3.9+ - -```Python hl_lines="1 4" -{!> ../../docs_src/python_types/tutorial008b_py39.py!} -``` - -//// - -В обоих случаях это означает, что `item` может быть `int` или `str`. +Это означает, что `item` может быть `int` или `str`. #### Возможно `None` { #possibly-none } Вы можете объявить, что значение может иметь определённый тип, например `str`, но также может быть и `None`. -В Python 3.6 и выше (включая Python 3.10) это можно объявить, импортировав и используя `Optional` из модуля `typing`. - -```Python hl_lines="1 4" -{!../../docs_src/python_types/tutorial009_py39.py!} -``` - -Использование `Optional[str]` вместо просто `str` позволит редактору кода помочь вам обнаружить ошибки, когда вы предполагаете, что значение всегда `str`, хотя на самом деле оно может быть и `None`. - -`Optional[Something]` — это на самом деле сокращение для `Union[Something, None]`, они эквивалентны. - -Это также означает, что в Python 3.10 вы можете использовать `Something | None`: - //// tab | Python 3.10+ ```Python hl_lines="1" @@ -266,96 +245,7 @@ John Doe //// -//// tab | Python 3.9+ - -```Python hl_lines="1 4" -{!> ../../docs_src/python_types/tutorial009_py39.py!} -``` - -//// - -//// tab | Python 3.9+ альтернативный вариант - -```Python hl_lines="1 4" -{!> ../../docs_src/python_types/tutorial009b_py39.py!} -``` - -//// - -#### Использовать `Union` или `Optional` { #using-union-or-optional } - -Если вы используете версию Python ниже 3.10, вот совет с моей весьма **субъективной** точки зрения: - -* 🚨 Избегайте использования `Optional[SomeType]` -* Вместо этого ✨ **используйте `Union[SomeType, None]`** ✨. - -Оба варианта эквивалентны и внутри одинаковы, но я бы рекомендовал `Union` вместо `Optional`, потому что слово «**optional**» («необязательный») может навести на мысль, что значение необязательное, хотя на самом деле оно означает «может быть `None`», даже если параметр не является необязательным и всё ещё обязателен. - -Мне кажется, `Union[SomeType, None]` более явно выражает смысл. - -Речь только о словах и названиях. Но эти слова могут влиять на то, как вы и ваши коллеги думаете о коде. - -В качестве примера возьмём эту функцию: - -{* ../../docs_src/python_types/tutorial009c_py39.py hl[1,4] *} - -Параметр `name` определён как `Optional[str]`, но он **не необязательный** — вы не можете вызвать функцию без этого параметра: - -```Python -say_hi() # О нет, это вызывает ошибку! 😱 -``` - -Параметр `name` всё ещё **обязателен** (не *optional*), потому что у него нет значения по умолчанию. При этом `name` принимает `None` как значение: - -```Python -say_hi(name=None) # Это работает, None допустим 🎉 -``` - -Хорошая новость: как только вы перейдёте на Python 3.10, об этом можно не переживать — вы сможете просто использовать `|` для объединения типов: - -{* ../../docs_src/python_types/tutorial009c_py310.py hl[1,4] *} - -И тогда вам не придётся задумываться о названиях вроде `Optional` и `Union`. 😎 - -#### Generic-типы { #generic-types } - -Типы, которые принимают параметры типов в квадратных скобках, называются **Generic-типами** или **Generics**, например: - -//// tab | Python 3.10+ - -Вы можете использовать те же встроенные типы как generics (с квадратными скобками и типами внутри): - -* `list` -* `tuple` -* `set` -* `dict` - -И, как и в предыдущих версиях Python, из модуля `typing`: - -* `Union` -* `Optional` -* ...и другие. - -В Python 3.10, как альтернативу generics `Union` и `Optional`, можно использовать вертикальную черту (`|`) для объявления объединений типов — это гораздо лучше и проще. - -//// - -//// tab | Python 3.9+ - -Вы можете использовать те же встроенные типы как generics (с квадратными скобками и типами внутри): - -* `list` -* `tuple` -* `set` -* `dict` - -И generics из модуля `typing`: - -* `Union` -* `Optional` -* ...и другие. - -//// +Использование `str | None` вместо просто `str` позволит редактору кода помочь вам обнаружить ошибки, когда вы предполагаете, что значение всегда `str`, хотя на самом деле оно может быть и `None`. ### Классы как типы { #classes-as-types } @@ -363,11 +253,11 @@ say_hi(name=None) # Это работает, None допустим 🎉 Допустим, у вас есть класс `Person` с именем: -{* ../../docs_src/python_types/tutorial010_py39.py hl[1:3] *} +{* ../../docs_src/python_types/tutorial010_py310.py hl[1:3] *} Тогда вы можете объявить переменную типа `Person`: -{* ../../docs_src/python_types/tutorial010_py39.py hl[6] *} +{* ../../docs_src/python_types/tutorial010_py310.py hl[6] *} И снова вы получите полную поддержку редактора кода: @@ -401,21 +291,15 @@ say_hi(name=None) # Это работает, None допустим 🎉 **FastAPI** целиком основан на Pydantic. -Вы увидите намного больше всего этого на практике в [Руководстве пользователя](tutorial/index.md){.internal-link target=_blank}. - -/// tip | Совет - -У Pydantic есть особое поведение, когда вы используете `Optional` или `Union[Something, None]` без значения по умолчанию. Подробнее читайте в документации Pydantic: Required Optional fields. - -/// +Вы увидите намного больше всего этого на практике в [Учебник - Руководство пользователя](tutorial/index.md){.internal-link target=_blank}. ## Подсказки типов с аннотациями метаданных { #type-hints-with-metadata-annotations } -В Python также есть возможность добавлять **дополнительные метаданные** к подсказкам типов с помощью `Annotated`. +В Python также есть возможность добавлять **дополнительные метаданные** к подсказкам типов с помощью `Annotated`. -Начиная с Python 3.9, `Annotated` входит в стандартную библиотеку, поэтому вы можете импортировать его из `typing`. +Вы можете импортировать `Annotated` из `typing`. -{* ../../docs_src/python_types/tutorial013_py39.py hl[1,4] *} +{* ../../docs_src/python_types/tutorial013_py310.py hl[1,4] *} Сам Python ничего не делает с `Annotated`. А для редакторов кода и других инструментов тип по-прежнему `str`. @@ -453,7 +337,7 @@ say_hi(name=None) # Это работает, None допустим 🎉 * **Документирования** API с использованием OpenAPI: * что затем используется пользовательскими интерфейсами автоматической интерактивной документации. -Всё это может звучать абстрактно. Не волнуйтесь. Вы увидите всё это в действии в [Руководстве пользователя](tutorial/index.md){.internal-link target=_blank}. +Всё это может звучать абстрактно. Не волнуйтесь. Вы увидите всё это в действии в [Учебник - Руководство пользователя](tutorial/index.md){.internal-link target=_blank}. Важно то, что, используя стандартные типы Python в одном месте (вместо добавления дополнительных классов, декораторов и т.д.), **FastAPI** сделает за вас большую часть работы. diff --git a/docs/ru/docs/tutorial/background-tasks.md b/docs/ru/docs/tutorial/background-tasks.md index 8d7b7442f..9fa7a8502 100644 --- a/docs/ru/docs/tutorial/background-tasks.md +++ b/docs/ru/docs/tutorial/background-tasks.md @@ -15,7 +15,7 @@ Сначала импортируйте `BackgroundTasks` и объявите параметр в вашей функции‑обработчике пути с типом `BackgroundTasks`: -{* ../../docs_src/background_tasks/tutorial001_py39.py hl[1,13] *} +{* ../../docs_src/background_tasks/tutorial001_py310.py hl[1,13] *} **FastAPI** создаст объект типа `BackgroundTasks` для вас и передаст его через этот параметр. @@ -31,13 +31,13 @@ Так как операция записи не использует `async` и `await`, мы определим функцию как обычную `def`: -{* ../../docs_src/background_tasks/tutorial001_py39.py hl[6:9] *} +{* ../../docs_src/background_tasks/tutorial001_py310.py hl[6:9] *} ## Добавление фоновой задачи { #add-the-background-task } Внутри вашей функции‑обработчика пути передайте функцию задачи объекту фоновых задач методом `.add_task()`: -{* ../../docs_src/background_tasks/tutorial001_py39.py hl[14] *} +{* ../../docs_src/background_tasks/tutorial001_py310.py hl[14] *} `.add_task()` принимает следующие аргументы: @@ -47,7 +47,7 @@ ## Встраивание зависимостей { #dependency-injection } -Использование `BackgroundTasks` также работает с системой встраивания зависимостей, вы можете объявить параметр типа `BackgroundTasks` на нескольких уровнях: в функции‑обработчике пути, в зависимости (dependable), в подзависимости и т. д. +Использование `BackgroundTasks` также работает с системой встраивания зависимостей, вы можете объявить параметр типа `BackgroundTasks` на нескольких уровнях: в функции‑обработчике пути, в зависимости (dependable), в подзависимости и т.д. **FastAPI** знает, что делать в каждом случае и как переиспользовать один и тот же объект, так чтобы все фоновые задачи были объединены и затем выполнены в фоне: @@ -73,7 +73,7 @@ ## Предостережение { #caveat } -Если вам нужно выполнять тяжелые вычисления в фоне, и при этом они не обязательно должны запускаться тем же процессом (например, вам не нужно делиться памятью, переменными и т. п.), вам могут подойти более мощные инструменты, такие как Celery. +Если вам нужно выполнять тяжелые вычисления в фоне, и при этом они не обязательно должны запускаться тем же процессом (например, вам не нужно делиться памятью, переменными и т.п.), вам могут подойти более мощные инструменты, такие как Celery. Они обычно требуют более сложной конфигурации, менеджера очереди сообщений/заданий (например, RabbitMQ или Redis), но позволяют запускать фоновые задачи в нескольких процессах и, что особенно важно, на нескольких серверах. diff --git a/docs/ru/docs/tutorial/bigger-applications.md b/docs/ru/docs/tutorial/bigger-applications.md index 76304523c..3fb36d5a2 100644 --- a/docs/ru/docs/tutorial/bigger-applications.md +++ b/docs/ru/docs/tutorial/bigger-applications.md @@ -85,7 +85,7 @@ from app.routers import items Точно так же, как и в случае с классом `FastAPI`, вам нужно импортировать и создать его «экземпляр»: -{* ../../docs_src/bigger_applications/app_an_py39/routers/users.py hl[1,3] title["app/routers/users.py"] *} +{* ../../docs_src/bigger_applications/app_an_py310/routers/users.py hl[1,3] title["app/routers/users.py"] *} ### *Операции пути* с `APIRouter` { #path-operations-with-apirouter } @@ -93,7 +93,7 @@ from app.routers import items Используйте его так же, как вы использовали бы класс `FastAPI`: -{* ../../docs_src/bigger_applications/app_an_py39/routers/users.py hl[6,11,16] title["app/routers/users.py"] *} +{* ../../docs_src/bigger_applications/app_an_py310/routers/users.py hl[6,11,16] title["app/routers/users.py"] *} Вы можете думать об `APIRouter` как об «мини-классе `FastAPI`». @@ -117,7 +117,7 @@ from app.routers import items Теперь мы воспользуемся простой зависимостью, чтобы прочитать кастомный HTTP-заголовок `X-Token`: -{* ../../docs_src/bigger_applications/app_an_py39/dependencies.py hl[3,6:8] title["app/dependencies.py"] *} +{* ../../docs_src/bigger_applications/app_an_py310/dependencies.py hl[3,6:8] title["app/dependencies.py"] *} /// tip | Подсказка @@ -149,7 +149,7 @@ from app.routers import items Таким образом, вместо того чтобы добавлять всё это в каждую *операцию пути*, мы можем добавить это в `APIRouter`. -{* ../../docs_src/bigger_applications/app_an_py39/routers/items.py hl[5:10,16,21] title["app/routers/items.py"] *} +{* ../../docs_src/bigger_applications/app_an_py310/routers/items.py hl[5:10,16,21] title["app/routers/items.py"] *} Так как путь каждой *операции пути* должен начинаться с `/`, как здесь: @@ -208,7 +208,7 @@ async def read_item(item_id: str): Поэтому мы используем относительный импорт с `..` для зависимостей: -{* ../../docs_src/bigger_applications/app_an_py39/routers/items.py hl[3] title["app/routers/items.py"] *} +{* ../../docs_src/bigger_applications/app_an_py310/routers/items.py hl[3] title["app/routers/items.py"] *} #### Как работает относительный импорт { #how-relative-imports-work } @@ -279,7 +279,7 @@ from ...dependencies import get_token_header Но мы всё равно можем добавить _ещё_ `tags`, которые будут применяться к конкретной *операции пути*, а также дополнительные `responses`, специфичные для этой *операции пути*: -{* ../../docs_src/bigger_applications/app_an_py39/routers/items.py hl[30:31] title["app/routers/items.py"] *} +{* ../../docs_src/bigger_applications/app_an_py310/routers/items.py hl[30:31] title["app/routers/items.py"] *} /// tip | Подсказка @@ -305,13 +305,13 @@ from ...dependencies import get_token_header И мы даже можем объявить [глобальные зависимости](dependencies/global-dependencies.md){.internal-link target=_blank}, которые будут объединены с зависимостями для каждого `APIRouter`: -{* ../../docs_src/bigger_applications/app_an_py39/main.py hl[1,3,7] title["app/main.py"] *} +{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[1,3,7] title["app/main.py"] *} ### Импорт `APIRouter` { #import-the-apirouter } Теперь мы импортируем другие подмодули, содержащие `APIRouter`: -{* ../../docs_src/bigger_applications/app_an_py39/main.py hl[4:5] title["app/main.py"] *} +{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[4:5] title["app/main.py"] *} Так как файлы `app/routers/users.py` и `app/routers/items.py` являются подмодулями, входящими в один и тот же Python-пакет `app`, мы можем использовать одну точку `.` для импорта через «относительные импорты». @@ -374,13 +374,13 @@ from .routers.users import router Поэтому, чтобы иметь возможность использовать обе в одном файле, мы импортируем подмодули напрямую: -{* ../../docs_src/bigger_applications/app_an_py39/main.py hl[5] title["app/main.py"] *} +{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[5] title["app/main.py"] *} ### Подключение `APIRouter` для `users` и `items` { #include-the-apirouters-for-users-and-items } Теперь давайте подключим `router` из подмодулей `users` и `items`: -{* ../../docs_src/bigger_applications/app_an_py39/main.py hl[10:11] title["app/main.py"] *} +{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[10:11] title["app/main.py"] *} /// info | Примечание @@ -420,13 +420,13 @@ from .routers.users import router Для этого примера всё будет очень просто. Но допустим, что поскольку он используется совместно с другими проектами в организации, мы не можем модифицировать его и добавить `prefix`, `dependencies`, `tags` и т.д. непосредственно в `APIRouter`: -{* ../../docs_src/bigger_applications/app_an_py39/internal/admin.py hl[3] title["app/internal/admin.py"] *} +{* ../../docs_src/bigger_applications/app_an_py310/internal/admin.py hl[3] title["app/internal/admin.py"] *} Но мы всё равно хотим задать пользовательский `prefix` при подключении `APIRouter`, чтобы все его *операции пути* начинались с `/admin`, хотим защитить его с помощью `dependencies`, которые у нас уже есть для этого проекта, и хотим включить `tags` и `responses`. Мы можем объявить всё это, не изменяя исходный `APIRouter`, передав эти параметры в `app.include_router()`: -{* ../../docs_src/bigger_applications/app_an_py39/main.py hl[14:17] title["app/main.py"] *} +{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[14:17] title["app/main.py"] *} Таким образом исходный `APIRouter` не будет модифицирован, и мы сможем использовать файл `app/internal/admin.py` сразу в нескольких проектах организации. @@ -447,7 +447,7 @@ from .routers.users import router Здесь мы делаем это... просто чтобы показать, что можем 🤷: -{* ../../docs_src/bigger_applications/app_an_py39/main.py hl[21:23] title["app/main.py"] *} +{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[21:23] title["app/main.py"] *} и это будет работать корректно вместе со всеми другими *операциями пути*, добавленными через `app.include_router()`. diff --git a/docs/ru/docs/tutorial/body-multiple-params.md b/docs/ru/docs/tutorial/body-multiple-params.md index 9d9400494..ddd9c6fdd 100644 --- a/docs/ru/docs/tutorial/body-multiple-params.md +++ b/docs/ru/docs/tutorial/body-multiple-params.md @@ -52,7 +52,7 @@ } ``` -/// note | Внимание +/// note | Заметка Обратите внимание, что хотя параметр `item` был объявлен таким же способом, как и раньше, теперь предполагается, что он находится внутри тела с ключом `item`. @@ -104,12 +104,6 @@ q: str | None = None ``` -Или в Python 3.9: - -```Python -q: Union[str, None] = None -``` - Например: {* ../../docs_src/body_multiple_params/tutorial004_an_py310.py hl[28] *} diff --git a/docs/ru/docs/tutorial/body-nested-models.md b/docs/ru/docs/tutorial/body-nested-models.md index 4c914b97f..6610b209c 100644 --- a/docs/ru/docs/tutorial/body-nested-models.md +++ b/docs/ru/docs/tutorial/body-nested-models.md @@ -163,7 +163,7 @@ images: list[Image] например так: -{* ../../docs_src/body_nested_models/tutorial008_py39.py hl[13] *} +{* ../../docs_src/body_nested_models/tutorial008_py310.py hl[13] *} ## Поддержка редактора кода везде { #editor-support-everywhere } @@ -193,7 +193,7 @@ images: list[Image] В этом случае вы принимаете любой `dict`, пока у него есть ключи типа `int` со значениями типа `float`: -{* ../../docs_src/body_nested_models/tutorial009_py39.py hl[7] *} +{* ../../docs_src/body_nested_models/tutorial009_py310.py hl[7] *} /// tip | Совет diff --git a/docs/ru/docs/tutorial/body.md b/docs/ru/docs/tutorial/body.md index 537d7ebc9..3e55607da 100644 --- a/docs/ru/docs/tutorial/body.md +++ b/docs/ru/docs/tutorial/body.md @@ -72,7 +72,7 @@ * Проведёт валидацию данных. * Если данные некорректны, вернёт понятную и наглядную ошибку, указывающую, где именно и что было некорректно. * Передаст полученные данные в параметр `item`. - * Поскольку внутри функции вы объявили его с типом `Item`, у вас будет поддержка со стороны редактора кода (автозавершение и т. п.) для всех атрибутов и их типов. + * Поскольку внутри функции вы объявили его с типом `Item`, у вас будет поддержка со стороны редактора кода (автозавершение и т.п.) для всех атрибутов и их типов. * Сгенерирует определения JSON Schema для вашей модели; вы можете использовать их и в других местах, если это имеет смысл для вашего проекта. * Эти схемы будут частью сгенерированной схемы OpenAPI и будут использоваться автоматической документацией UIs. @@ -148,14 +148,14 @@ JSON Schema ваших моделей будет частью сгенериро Параметры функции будут распознаны следующим образом: * Если параметр также объявлен в **пути**, он будет использоваться как path-параметр. -* Если параметр имеет **скалярный тип** (например, `int`, `float`, `str`, `bool` и т. п.), он будет интерпретирован как параметр **запроса**. +* Если параметр имеет **скалярный тип** (например, `int`, `float`, `str`, `bool` и т.п.), он будет интерпретирован как параметр **запроса**. * Если параметр объявлен как тип **модели Pydantic**, он будет интерпретирован как **тело** запроса. /// note | Заметка FastAPI понимает, что значение `q` не является обязательным из-за значения по умолчанию `= None`. -Аннотации типов `str | None` (Python 3.10+) или `Union` в `Union[str, None]` (Python 3.9+) не используются FastAPI для определения обязательности; он узнает, что параметр не обязателен, потому что у него есть значение по умолчанию `= None`. +Аннотация типов `str | None` не используется FastAPI для определения обязательности; он узнает, что параметр не обязателен, потому что у него есть значение по умолчанию `= None`. Но добавление аннотаций типов позволит вашему редактору кода лучше вас поддерживать и обнаруживать ошибки. diff --git a/docs/ru/docs/tutorial/cookie-param-models.md b/docs/ru/docs/tutorial/cookie-param-models.md index 182813afd..9b34cf030 100644 --- a/docs/ru/docs/tutorial/cookie-param-models.md +++ b/docs/ru/docs/tutorial/cookie-param-models.md @@ -46,7 +46,7 @@ В некоторых случаях (не особо часто встречающихся) вам может понадобиться **ограничить** cookies, которые вы хотите получать. -Теперь ваш API сам решает, принимать ли cookies. 🤪🍪 +Теперь у вашего API есть возможность контролировать своё согласие на использование cookie. 🤪🍪 Вы можете сконфигурировать Pydantic-модель так, чтобы запретить (`forbid`) любые дополнительные (`extra`) поля: @@ -54,9 +54,9 @@ Если клиент попробует отправить **дополнительные cookies**, то в ответ он получит **ошибку**. -Бедные баннеры cookies, они всеми силами пытаются получить ваше согласие — и всё ради того, чтобы API его отклонил. 🍪 +Бедные баннеры cookies, они всеми силами пытаются получить ваше согласие — и всё ради того, чтобы API его отклонил. 🍪 -Например, если клиент попытается отправить cookie `santa_tracker` со значением `good-list-please`, то в ответ он получит **ошибку**, сообщающую ему, что cookie `santa_tracker` не разрешён: +Например, если клиент попытается отправить cookie `santa_tracker` со значением `good-list-please`, то в ответ он получит **ошибку**, сообщающую ему, что `santa_tracker` cookie не разрешён: ```json { @@ -73,4 +73,4 @@ ## Заключение { #summary } -Вы можете использовать **Pydantic-модели** для объявления **cookies** в **FastAPI**. 😎 +Вы можете использовать **Pydantic-модели** для объявления **cookies** в **FastAPI**. 😎 diff --git a/docs/ru/docs/tutorial/cookie-params.md b/docs/ru/docs/tutorial/cookie-params.md index 2d2eff8d7..8dad3873e 100644 --- a/docs/ru/docs/tutorial/cookie-params.md +++ b/docs/ru/docs/tutorial/cookie-params.md @@ -32,11 +32,11 @@ /// info | Дополнительная информация -Имейте в виду, что, поскольку браузеры обрабатывают cookies особым образом и «за кулисами», они не позволяют JavaScript просто так получать к ним доступ. +Имейте в виду, что, поскольку **браузеры обрабатывают cookies** особым образом и «за кулисами», они **не** позволяют **JavaScript** просто так получать к ним доступ. -Если вы откроете интерфейс документации API на `/docs`, вы сможете увидеть документацию по cookies для ваших операций пути. +Если вы откроете **интерфейс документации API** на `/docs`, вы сможете увидеть **документацию** по cookies для ваших *операции пути*. -Но даже если вы заполните данные и нажмёте «Execute», поскольку UI документации работает с JavaScript, cookies отправлены не будут, и вы увидите сообщение об ошибке, как будто вы не указали никаких значений. +Но даже если вы **заполните данные** и нажмёте «Execute», поскольку UI документации работает с **JavaScript**, cookies отправлены не будут, и вы увидите сообщение об **ошибке**, как будто вы не указали никаких значений. /// diff --git a/docs/ru/docs/tutorial/cors.md b/docs/ru/docs/tutorial/cors.md index d09a31e2c..feaa15968 100644 --- a/docs/ru/docs/tutorial/cors.md +++ b/docs/ru/docs/tutorial/cors.md @@ -46,7 +46,7 @@ * Отдельных HTTP-методов (`POST`, `PUT`) или всех вместе, используя `"*"`. * Отдельных HTTP-заголовков или всех вместе, используя `"*"`. -{* ../../docs_src/cors/tutorial001_py39.py hl[2,6:11,13:19] *} +{* ../../docs_src/cors/tutorial001_py310.py hl[2,6:11,13:19] *} `CORSMiddleware` использует "запрещающие" значения по умолчанию, поэтому вам нужно явным образом разрешить использование отдельных источников, методов или заголовков, чтобы браузеры могли использовать их в кросс-доменном контексте. @@ -77,7 +77,7 @@ ## Больше информации { #more-info } -Для получения более подробной информации о CORS обратитесь к документации CORS от Mozilla. +Для получения более подробной информации о CORS обратитесь к документации CORS от Mozilla. /// note | Технические детали diff --git a/docs/ru/docs/tutorial/debugging.md b/docs/ru/docs/tutorial/debugging.md index 51955835e..483fe8086 100644 --- a/docs/ru/docs/tutorial/debugging.md +++ b/docs/ru/docs/tutorial/debugging.md @@ -6,7 +6,7 @@ В вашем FastAPI приложении, импортируйте и вызовите `uvicorn` напрямую: -{* ../../docs_src/debugging/tutorial001_py39.py hl[1,15] *} +{* ../../docs_src/debugging/tutorial001_py310.py hl[1,15] *} ### Описание `__name__ == "__main__"` { #about-name-main } @@ -42,7 +42,7 @@ $ python myapp.py то встроенная переменная `__name__`, автоматически создаваемая Python в вашем файле, будет иметь значение строкового типа `"__main__"`. -Тогда выполнится условие и эта часть кода: +Тогда эта часть кода: ```Python uvicorn.run(app, host="0.0.0.0", port=8000) @@ -59,7 +59,7 @@ $ python myapp.py ```Python from myapp import app -# Some more code +# Еще немного кода ``` то автоматическая создаваемая внутри файла `myapp.py` переменная `__name__` будет иметь значение отличающееся от `"__main__"`. @@ -99,7 +99,7 @@ from myapp import app --- -Если используете Pycharm, вы можете выполнить следующие шаги: +Если используете PyCharm, вы можете выполнить следующие шаги: * Открыть "Run" меню. * Выбрать опцию "Debug...". diff --git a/docs/ru/docs/tutorial/dependencies/classes-as-dependencies.md b/docs/ru/docs/tutorial/dependencies/classes-as-dependencies.md index a38e885d4..9a3171e9f 100644 --- a/docs/ru/docs/tutorial/dependencies/classes-as-dependencies.md +++ b/docs/ru/docs/tutorial/dependencies/classes-as-dependencies.md @@ -4,7 +4,7 @@ ## `dict` из предыдущего примера { #a-dict-from-the-previous-example } -В предыдущем примере мы возвращали `dict` из нашей зависимости: +В предыдущем примере мы возвращали `dict` из нашей зависимости («dependable»): {* ../../docs_src/dependencies/tutorial001_an_py310.py hl[9] *} @@ -67,7 +67,7 @@ fluffy = Cat(name="Mr Fluffy") Это относится и к вызываемым объектам без параметров. Работа с ними происходит точно так же, как и для *функций-обработчиков пути* без параметров. -Теперь мы можем изменить зависимость `common_parameters`, указанную выше, на класс `CommonQueryParams`: +Теперь мы можем изменить зависимость («dependable») `common_parameters`, указанную выше, на класс `CommonQueryParams`: {* ../../docs_src/dependencies/tutorial002_an_py310.py hl[11:15] *} @@ -101,7 +101,7 @@ fluffy = Cat(name="Mr Fluffy") Обратите внимание, что в приведенном выше коде мы два раза пишем `CommonQueryParams`: -//// tab | Python 3.9+ +//// tab | Python 3.10+ ```Python commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)] @@ -109,7 +109,7 @@ commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)] //// -//// tab | Python 3.9+ non-Annotated +//// tab | Python 3.10+ без Annotated /// tip | Подсказка @@ -137,7 +137,7 @@ commons: CommonQueryParams = Depends(CommonQueryParams) В этом случае первый `CommonQueryParams`, в: -//// tab | Python 3.9+ +//// tab | Python 3.10+ ```Python commons: Annotated[CommonQueryParams, ... @@ -145,7 +145,7 @@ commons: Annotated[CommonQueryParams, ... //// -//// tab | Python 3.9+ non-Annotated +//// tab | Python 3.10+ без Annotated /// tip | Подсказка @@ -163,7 +163,7 @@ commons: CommonQueryParams ... На самом деле можно написать просто: -//// tab | Python 3.9+ +//// tab | Python 3.10+ ```Python commons: Annotated[Any, Depends(CommonQueryParams)] @@ -171,7 +171,7 @@ commons: Annotated[Any, Depends(CommonQueryParams)] //// -//// tab | Python 3.9+ non-Annotated +//// tab | Python 3.10+ без Annotated /// tip | Подсказка @@ -197,7 +197,7 @@ commons = Depends(CommonQueryParams) Но вы видите, что здесь мы имеем некоторое повторение кода, дважды написав `CommonQueryParams`: -//// tab | Python 3.9+ +//// tab | Python 3.10+ ```Python commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)] @@ -205,7 +205,7 @@ commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)] //// -//// tab | Python 3.9+ non-Annotated +//// tab | Python 3.10+ без Annotated /// tip | Подсказка @@ -225,7 +225,7 @@ commons: CommonQueryParams = Depends(CommonQueryParams) Вместо того чтобы писать: -//// tab | Python 3.9+ +//// tab | Python 3.10+ ```Python commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)] @@ -233,7 +233,7 @@ commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)] //// -//// tab | Python 3.9+ non-Annotated +//// tab | Python 3.10+ без Annotated /// tip | Подсказка @@ -249,7 +249,7 @@ commons: CommonQueryParams = Depends(CommonQueryParams) ...следует написать: -//// tab | Python 3.9+ +//// tab | Python 3.10+ ```Python commons: Annotated[CommonQueryParams, Depends()] @@ -257,7 +257,7 @@ commons: Annotated[CommonQueryParams, Depends()] //// -//// tab | Python 3.9+ non-Annotated +//// tab | Python 3.10+ без Annotated /// tip | Подсказка diff --git a/docs/ru/docs/tutorial/dependencies/dependencies-in-path-operation-decorators.md b/docs/ru/docs/tutorial/dependencies/dependencies-in-path-operation-decorators.md index ef5664448..4cfc4e699 100644 --- a/docs/ru/docs/tutorial/dependencies/dependencies-in-path-operation-decorators.md +++ b/docs/ru/docs/tutorial/dependencies/dependencies-in-path-operation-decorators.md @@ -14,7 +14,7 @@ Это должен быть `list` состоящий из `Depends()`: -{* ../../docs_src/dependencies/tutorial006_an_py39.py hl[19] *} +{* ../../docs_src/dependencies/tutorial006_an_py310.py hl[19] *} Зависимости из dependencies выполнятся так же, как и обычные зависимости. Но их значения (если они были) не будут переданы в *функцию операции пути*. @@ -30,7 +30,7 @@ /// info | Примечание -В этом примере мы используем выдуманные пользовательские заголовки `X-Key` и `X-Token`. +В этом примере мы используем выдуманные пользовательские HTTP-заголовки `X-Key` и `X-Token`. Но в реальных проектах, при внедрении системы безопасности, вы получите больше пользы используя интегрированные [средства защиты (следующая глава)](../security/index.md){.internal-link target=_blank}. @@ -42,15 +42,15 @@ ### Требования к зависимостям { #dependency-requirements } -Они могут объявлять требования к запросу (например заголовки) или другие подзависимости: +Они могут объявлять требования к запросу (например HTTP-заголовки) или другие подзависимости: -{* ../../docs_src/dependencies/tutorial006_an_py39.py hl[8,13] *} +{* ../../docs_src/dependencies/tutorial006_an_py310.py hl[8,13] *} ### Вызов исключений { #raise-exceptions } Зависимости из dependencies могут вызывать исключения с помощью `raise`, как и обычные зависимости: -{* ../../docs_src/dependencies/tutorial006_an_py39.py hl[10,15] *} +{* ../../docs_src/dependencies/tutorial006_an_py310.py hl[10,15] *} ### Возвращаемые значения { #return-values } @@ -58,7 +58,7 @@ Таким образом, вы можете переиспользовать обычную зависимость (возвращающую значение), которую вы уже используете где-то в другом месте, и хотя значение не будет использоваться, зависимость будет выполнена: -{* ../../docs_src/dependencies/tutorial006_an_py39.py hl[11,16] *} +{* ../../docs_src/dependencies/tutorial006_an_py310.py hl[11,16] *} ## Зависимости для группы *операций путей* { #dependencies-for-a-group-of-path-operations } diff --git a/docs/ru/docs/tutorial/dependencies/dependencies-with-yield.md b/docs/ru/docs/tutorial/dependencies/dependencies-with-yield.md index dc202db61..03a7c083c 100644 --- a/docs/ru/docs/tutorial/dependencies/dependencies-with-yield.md +++ b/docs/ru/docs/tutorial/dependencies/dependencies-with-yield.md @@ -1,6 +1,6 @@ # Зависимости с yield { #dependencies-with-yield } -FastAPI поддерживает зависимости, которые выполняют некоторые дополнительные шаги после завершения. +FastAPI поддерживает зависимости, которые выполняют некоторые дополнительные шаги после завершения. Для этого используйте `yield` вместо `return`, а дополнительные шаги (код) напишите после него. @@ -29,15 +29,15 @@ FastAPI поддерживает зависимости, которые выпо Перед созданием ответа будет выполнен только код до и включая оператор `yield`: -{* ../../docs_src/dependencies/tutorial007_py39.py hl[2:4] *} +{* ../../docs_src/dependencies/tutorial007_py310.py hl[2:4] *} Значение, полученное из `yield`, внедряется в *операции пути* и другие зависимости: -{* ../../docs_src/dependencies/tutorial007_py39.py hl[4] *} +{* ../../docs_src/dependencies/tutorial007_py310.py hl[4] *} Код, следующий за оператором `yield`, выполняется после ответа: -{* ../../docs_src/dependencies/tutorial007_py39.py hl[5:6] *} +{* ../../docs_src/dependencies/tutorial007_py310.py hl[5:6] *} /// tip | Подсказка @@ -57,7 +57,7 @@ FastAPI поддерживает зависимости, которые выпо Точно так же можно использовать `finally`, чтобы убедиться, что обязательные шаги при выходе выполнены независимо от того, было ли исключение или нет. -{* ../../docs_src/dependencies/tutorial007_py39.py hl[3,5] *} +{* ../../docs_src/dependencies/tutorial007_py310.py hl[3,5] *} ## Подзависимости с `yield` { #sub-dependencies-with-yield } @@ -67,7 +67,7 @@ FastAPI поддерживает зависимости, которые выпо Например, `dependency_c` может зависеть от `dependency_b`, а `dependency_b` — от `dependency_a`: -{* ../../docs_src/dependencies/tutorial008_an_py39.py hl[6,14,22] *} +{* ../../docs_src/dependencies/tutorial008_an_py310.py hl[6,14,22] *} И все они могут использовать `yield`. @@ -75,7 +75,7 @@ FastAPI поддерживает зависимости, которые выпо И, в свою очередь, `dependency_b` нуждается в том, чтобы значение из `dependency_a` (здесь `dep_a`) было доступно для её кода выхода. -{* ../../docs_src/dependencies/tutorial008_an_py39.py hl[18:19,26:27] *} +{* ../../docs_src/dependencies/tutorial008_an_py310.py hl[18:19,26:27] *} Точно так же можно иметь часть зависимостей с `yield`, часть — с `return`, и какие-то из них могут зависеть друг от друга. @@ -109,7 +109,7 @@ FastAPI поддерживает зависимости, которые выпо /// -{* ../../docs_src/dependencies/tutorial008b_an_py39.py hl[18:22,31] *} +{* ../../docs_src/dependencies/tutorial008b_an_py310.py hl[18:22,31] *} Если вы хотите перехватывать исключения и формировать на их основе пользовательский ответ, создайте [Пользовательский обработчик исключений](../handling-errors.md#install-custom-exception-handlers){.internal-link target=_blank}. @@ -117,7 +117,7 @@ FastAPI поддерживает зависимости, которые выпо Если вы ловите исключение с помощью `except` в зависимости с `yield` и не вызываете его снова (или не вызываете новое исключение), FastAPI не сможет заметить, что было исключение — так же, как это происходит в обычном Python: -{* ../../docs_src/dependencies/tutorial008c_an_py39.py hl[15:16] *} +{* ../../docs_src/dependencies/tutorial008c_an_py310.py hl[15:16] *} В этом случае клиент получит *HTTP 500 Internal Server Error*, как и должно быть, поскольку мы не вызываем `HTTPException` или что-то подобное, но на сервере **не будет никаких логов** или других указаний на то, какая была ошибка. 😱 @@ -127,7 +127,7 @@ FastAPI поддерживает зависимости, которые выпо Вы можете повторно вызвать то же самое исключение с помощью `raise`: -{* ../../docs_src/dependencies/tutorial008d_an_py39.py hl[17] *} +{* ../../docs_src/dependencies/tutorial008d_an_py310.py hl[17] *} Теперь клиент получит тот же *HTTP 500 Internal Server Error*, но на сервере в логах будет наше пользовательское `InternalError`. 😎 @@ -190,7 +190,7 @@ participant tasks as Background tasks Но если вы знаете, что не будете использовать зависимость после возврата из *функции-обработчика пути*, вы можете использовать `Depends(scope="function")`, чтобы сообщить FastAPI, что он должен закрыть зависимость после возврата из *функции-обработчика пути*, но **до того**, как **ответ будет отправлен**. -{* ../../docs_src/dependencies/tutorial008e_an_py39.py hl[12,16] *} +{* ../../docs_src/dependencies/tutorial008e_an_py310.py hl[12,16] *} `Depends()` принимает параметр `scope`, который может быть: @@ -269,7 +269,7 @@ with open("./somefile.txt") as f: Их также можно использовать внутри зависимостей **FastAPI** с `yield`, применяя операторы `with` или `async with` внутри функции зависимости: -{* ../../docs_src/dependencies/tutorial010_py39.py hl[1:9,13] *} +{* ../../docs_src/dependencies/tutorial010_py310.py hl[1:9,13] *} /// tip | Подсказка diff --git a/docs/ru/docs/tutorial/dependencies/global-dependencies.md b/docs/ru/docs/tutorial/dependencies/global-dependencies.md index 2347c6dd8..f488322a9 100644 --- a/docs/ru/docs/tutorial/dependencies/global-dependencies.md +++ b/docs/ru/docs/tutorial/dependencies/global-dependencies.md @@ -6,10 +6,10 @@ В этом случае они будут применяться ко всем *операциям пути* в приложении: -{* ../../docs_src/dependencies/tutorial012_an_py39.py hl[17] *} +{* ../../docs_src/dependencies/tutorial012_an_py310.py hl[17] *} Все способы [добавления `dependencies` (зависимостей) в *декораторах операций пути*](dependencies-in-path-operation-decorators.md){.internal-link target=_blank} по-прежнему применимы, но в данном случае зависимости применяются ко всем *операциям пути* приложения. ## Зависимости для групп *операций пути* { #dependencies-for-groups-of-path-operations } -Позднее, читая о том, как структурировать более крупные [приложения, содержащие много файлов](../../tutorial/bigger-applications.md){.internal-link target=_blank}, вы узнаете, как объявить один параметр `dependencies` для целой группы *операций пути*. +Позднее, читая о том, как структурировать более крупные приложения ([приложения, содержащие много файлов](../../tutorial/bigger-applications.md){.internal-link target=_blank}), возможно, состоящие из нескольких файлов, вы узнаете, как объявить один параметр `dependencies` для целой группы *операций пути*. diff --git a/docs/ru/docs/tutorial/dependencies/index.md b/docs/ru/docs/tutorial/dependencies/index.md index 98b0d59c6..29f735ab6 100644 --- a/docs/ru/docs/tutorial/dependencies/index.md +++ b/docs/ru/docs/tutorial/dependencies/index.md @@ -1,6 +1,6 @@ # Зависимости { #dependencies } -**FastAPI** имеет очень мощную, но интуитивную систему **Инъекция зависимостей**. +**FastAPI** имеет очень мощную, но интуитивную систему **Инъекция зависимостей**. Она спроектирована так, чтобы быть очень простой в использовании и облегчать любому разработчику интеграцию других компонентов с **FastAPI**. diff --git a/docs/ru/docs/tutorial/dependencies/sub-dependencies.md b/docs/ru/docs/tutorial/dependencies/sub-dependencies.md index da31a6682..3c71defd8 100644 --- a/docs/ru/docs/tutorial/dependencies/sub-dependencies.md +++ b/docs/ru/docs/tutorial/dependencies/sub-dependencies.md @@ -58,11 +58,11 @@ query_extractor --> query_or_cookie_extractor --> read_query Если одна из ваших зависимостей объявлена несколько раз для одной и той же *функции операции пути*, например, несколько зависимостей имеют общую подзависимость, **FastAPI** будет знать, что вызывать эту подзависимость нужно только один раз за запрос. -При этом возвращаемое значение будет сохранено в "кэш" и будет передано всем "зависимым" функциям, которые нуждаются в нем внутри этого конкретного запроса, вместо того, чтобы вызывать зависимость несколько раз для одного и того же запроса. +При этом возвращаемое значение будет сохранено в «кэш» и будет передано всем "зависимым" функциям, которые нуждаются в нем внутри этого конкретного запроса, вместо того, чтобы вызывать зависимость несколько раз для одного и того же запроса. В расширенном сценарии, когда вы знаете, что вам нужно, чтобы зависимость вызывалась на каждом шаге (возможно, несколько раз) в одном и том же запросе, вместо использования "кэшированного" значения, вы можете установить параметр `use_cache=False` при использовании `Depends`: -//// tab | Python 3.9+ +//// tab | Python 3.10+ ```Python hl_lines="1" async def needy_dependency(fresh_value: Annotated[str, Depends(get_value, use_cache=False)]): @@ -71,7 +71,7 @@ async def needy_dependency(fresh_value: Annotated[str, Depends(get_value, use_ca //// -//// tab | Python 3.9+ без Annotated +//// tab | Python 3.10+ без Annotated /// tip | Подсказка diff --git a/docs/ru/docs/tutorial/encoder.md b/docs/ru/docs/tutorial/encoder.md index 16981f79d..28e2a49c0 100644 --- a/docs/ru/docs/tutorial/encoder.md +++ b/docs/ru/docs/tutorial/encoder.md @@ -10,9 +10,9 @@ Представим, что у вас есть база данных `fake_db`, которая принимает только JSON-совместимые данные. -Например, он не принимает объекты `datetime`, так как они не совместимы с JSON. +Например, она не принимает объекты `datetime`, так как они не совместимы с JSON. -В таком случае объект `datetime` следует преобразовать в строку соответствующую формату ISO. +В таком случае объект `datetime` следует преобразовать в строку, соответствующую формату ISO. Точно так же эта база данных не может принять Pydantic-модель (объект с атрибутами), а только `dict`. diff --git a/docs/ru/docs/tutorial/extra-models.md b/docs/ru/docs/tutorial/extra-models.md index 03156f2b4..f9b63ca70 100644 --- a/docs/ru/docs/tutorial/extra-models.md +++ b/docs/ru/docs/tutorial/extra-models.md @@ -190,9 +190,9 @@ some_variable: PlaneItem | CarItem Таким же образом вы можете объявлять HTTP-ответы, возвращающие списки объектов. -Для этого используйте стандартный `typing.List` в Python (или просто `list` в Python 3.9 и выше): +Для этого используйте стандартный `list` в Python: -{* ../../docs_src/extra_models/tutorial004_py39.py hl[18] *} +{* ../../docs_src/extra_models/tutorial004_py310.py hl[18] *} ## Ответ с произвольным `dict` { #response-with-arbitrary-dict } @@ -200,9 +200,9 @@ some_variable: PlaneItem | CarItem Это полезно, если вы заранее не знаете корректных названий полей/атрибутов (которые будут нужны при использовании Pydantic-модели). -В этом случае вы можете использовать `typing.Dict` (или просто `dict` в Python 3.9 и выше): +В этом случае вы можете использовать `dict`: -{* ../../docs_src/extra_models/tutorial005_py39.py hl[6] *} +{* ../../docs_src/extra_models/tutorial005_py310.py hl[6] *} ## Резюме { #recap } diff --git a/docs/ru/docs/tutorial/first-steps.md b/docs/ru/docs/tutorial/first-steps.md index 798c03d51..cee264ff4 100644 --- a/docs/ru/docs/tutorial/first-steps.md +++ b/docs/ru/docs/tutorial/first-steps.md @@ -2,7 +2,7 @@ Самый простой файл FastAPI может выглядеть так: -{* ../../docs_src/first_steps/tutorial001_py39.py *} +{* ../../docs_src/first_steps/tutorial001_py310.py *} Скопируйте это в файл `main.py`. @@ -183,7 +183,7 @@ Deploying to FastAPI Cloud... ### Шаг 1: импортируйте `FastAPI` { #step-1-import-fastapi } -{* ../../docs_src/first_steps/tutorial001_py39.py hl[1] *} +{* ../../docs_src/first_steps/tutorial001_py310.py hl[1] *} `FastAPI` — это класс на Python, который предоставляет всю функциональность для вашего API. @@ -197,7 +197,7 @@ Deploying to FastAPI Cloud... ### Шаг 2: создайте экземпляр `FastAPI` { #step-2-create-a-fastapi-instance } -{* ../../docs_src/first_steps/tutorial001_py39.py hl[3] *} +{* ../../docs_src/first_steps/tutorial001_py310.py hl[3] *} Здесь переменная `app` будет экземпляром класса `FastAPI`. @@ -266,12 +266,12 @@ https://example.com/items/foo #### Определите *декоратор операции пути (path operation decorator)* { #define-a-path-operation-decorator } -{* ../../docs_src/first_steps/tutorial001_py39.py hl[6] *} +{* ../../docs_src/first_steps/tutorial001_py310.py hl[6] *} `@app.get("/")` сообщает **FastAPI**, что функция прямо под ним отвечает за обработку запросов, поступающих: * по пути `/` -* с использованием get операции +* с использованием get операции /// info | Информация о `@decorator` @@ -320,7 +320,7 @@ https://example.com/items/foo * **операция**: `get`. * **функция**: функция ниже «декоратора» (ниже `@app.get("/")`). -{* ../../docs_src/first_steps/tutorial001_py39.py hl[7] *} +{* ../../docs_src/first_steps/tutorial001_py310.py hl[7] *} Это функция на Python. @@ -332,7 +332,7 @@ https://example.com/items/foo Вы также можете определить её как обычную функцию вместо `async def`: -{* ../../docs_src/first_steps/tutorial003_py39.py hl[7] *} +{* ../../docs_src/first_steps/tutorial003_py310.py hl[7] *} /// note | Примечание @@ -342,7 +342,7 @@ https://example.com/items/foo ### Шаг 5: верните содержимое { #step-5-return-the-content } -{* ../../docs_src/first_steps/tutorial001_py39.py hl[8] *} +{* ../../docs_src/first_steps/tutorial001_py310.py hl[8] *} Вы можете вернуть `dict`, `list`, отдельные значения `str`, `int` и т.д. diff --git a/docs/ru/docs/tutorial/handling-errors.md b/docs/ru/docs/tutorial/handling-errors.md index 2e00d7075..fbd82cf28 100644 --- a/docs/ru/docs/tutorial/handling-errors.md +++ b/docs/ru/docs/tutorial/handling-errors.md @@ -11,7 +11,7 @@ * Элемент, к которому клиент пытался получить доступ, не существует. * и т.д. -В таких случаях обычно возвращается **HTTP-код статуса ответа** в диапазоне **400** (от 400 до 499). +В таких случаях обычно возвращают **HTTP статус-код** в диапазоне **400** (от 400 до 499). Они похожи на двухсотые HTTP статус-коды (от 200 до 299), которые означают, что запрос обработан успешно. @@ -25,7 +25,7 @@ ### Импортируйте `HTTPException` { #import-httpexception } -{* ../../docs_src/handling_errors/tutorial001_py39.py hl[1] *} +{* ../../docs_src/handling_errors/tutorial001_py310.py hl[1] *} ### Вызовите `HTTPException` в своем коде { #raise-an-httpexception-in-your-code } @@ -39,7 +39,7 @@ В данном примере, когда клиент запрашивает элемент по несуществующему ID, возникает исключение со статус-кодом `404`: -{* ../../docs_src/handling_errors/tutorial001_py39.py hl[11] *} +{* ../../docs_src/handling_errors/tutorial001_py310.py hl[11] *} ### Возвращаемый ответ { #the-resulting-response } @@ -71,13 +71,13 @@ ## Добавление пользовательских заголовков { #add-custom-headers } -В некоторых ситуациях полезно иметь возможность добавлять пользовательские заголовки к ошибке HTTP. Например, для некоторых типов безопасности. +В некоторых ситуациях полезно иметь возможность добавлять пользовательские HTTP-заголовки к ошибке HTTP. Например, для некоторых типов безопасности. Скорее всего, вам не потребуется использовать его непосредственно в коде. Но в случае, если это необходимо для продвинутого сценария, можно добавить пользовательские заголовки: -{* ../../docs_src/handling_errors/tutorial002_py39.py hl[14] *} +{* ../../docs_src/handling_errors/tutorial002_py310.py hl[14] *} ## Установка пользовательских обработчиков исключений { #install-custom-exception-handlers } @@ -89,7 +89,7 @@ Можно добавить собственный обработчик исключений с помощью `@app.exception_handler()`: -{* ../../docs_src/handling_errors/tutorial003_py39.py hl[5:7,13:18,24] *} +{* ../../docs_src/handling_errors/tutorial003_py310.py hl[5:7,13:18,24] *} Здесь, если запросить `/unicorns/yolo`, то *операция пути* вызовет `UnicornException`. @@ -127,7 +127,7 @@ Обработчик исключения получит объект `Request` и исключение. -{* ../../docs_src/handling_errors/tutorial004_py39.py hl[2,14:19] *} +{* ../../docs_src/handling_errors/tutorial004_py310.py hl[2,14:19] *} Теперь, если перейти к `/items/foo`, то вместо стандартной JSON-ошибки с: @@ -159,7 +159,7 @@ Field: ('path', 'item_id'), Error: Input should be a valid integer, unable to pa Например, для этих ошибок можно вернуть обычный текстовый ответ вместо JSON: -{* ../../docs_src/handling_errors/tutorial004_py39.py hl[3:4,9:11,25] *} +{* ../../docs_src/handling_errors/tutorial004_py310.py hl[3:4,9:11,25] *} /// note | Технические детали @@ -183,7 +183,7 @@ Field: ('path', 'item_id'), Error: Input should be a valid integer, unable to pa Вы можете использовать его при разработке приложения для регистрации тела и его отладки, возврата пользователю и т.д. -{* ../../docs_src/handling_errors/tutorial005_py39.py hl[14] *} +{* ../../docs_src/handling_errors/tutorial005_py310.py hl[14] *} Теперь попробуйте отправить недействительный элемент, например: @@ -239,6 +239,6 @@ from starlette.exceptions import HTTPException as StarletteHTTPException Если вы хотите использовать исключение вместе с теми же обработчиками исключений по умолчанию из **FastAPI**, вы можете импортировать и повторно использовать обработчики исключений по умолчанию из `fastapi.exception_handlers`: -{* ../../docs_src/handling_errors/tutorial006_py39.py hl[2:5,15,21] *} +{* ../../docs_src/handling_errors/tutorial006_py310.py hl[2:5,15,21] *} В этом примере вы просто `выводите в терминал` ошибку с очень выразительным сообщением, но идея вам понятна. Вы можете использовать исключение, а затем просто повторно использовать стандартные обработчики исключений. diff --git a/docs/ru/docs/tutorial/metadata.md b/docs/ru/docs/tutorial/metadata.md index e4fe5fb54..221655aa5 100644 --- a/docs/ru/docs/tutorial/metadata.md +++ b/docs/ru/docs/tutorial/metadata.md @@ -18,7 +18,7 @@ Вы можете задать их следующим образом: -{* ../../docs_src/metadata/tutorial001_py39.py hl[3:16, 19:32] *} +{* ../../docs_src/metadata/tutorial001_py310.py hl[3:16, 19:32] *} /// tip | Подсказка @@ -36,7 +36,7 @@ К примеру: -{* ../../docs_src/metadata/tutorial001_1_py39.py hl[31] *} +{* ../../docs_src/metadata/tutorial001_1_py310.py hl[31] *} ## Метаданные для тегов { #metadata-for-tags } @@ -58,7 +58,7 @@ Создайте метаданные для ваших тегов и передайте их в параметре `openapi_tags`: -{* ../../docs_src/metadata/tutorial004_py39.py hl[3:16,18] *} +{* ../../docs_src/metadata/tutorial004_py310.py hl[3:16,18] *} Помните, что вы можете использовать Markdown внутри описания, к примеру "login" будет отображен жирным шрифтом (**login**) и "fancy" будет отображаться курсивом (_fancy_). @@ -72,7 +72,7 @@ Используйте параметр `tags` с вашими *операциями пути* (и `APIRouter`ами), чтобы присвоить им различные теги: -{* ../../docs_src/metadata/tutorial004_py39.py hl[21,26] *} +{* ../../docs_src/metadata/tutorial004_py310.py hl[21,26] *} /// info | Дополнительная информация @@ -100,7 +100,7 @@ К примеру, чтобы задать её отображение по адресу `/api/v1/openapi.json`: -{* ../../docs_src/metadata/tutorial002_py39.py hl[3] *} +{* ../../docs_src/metadata/tutorial002_py310.py hl[3] *} Если вы хотите отключить схему OpenAPI полностью, вы можете задать `openapi_url=None`, это также отключит пользовательские интерфейсы документации, которые её используют. @@ -117,4 +117,4 @@ К примеру, чтобы задать отображение Swagger UI по адресу `/documentation` и отключить ReDoc: -{* ../../docs_src/metadata/tutorial003_py39.py hl[3] *} +{* ../../docs_src/metadata/tutorial003_py310.py hl[3] *} diff --git a/docs/ru/docs/tutorial/middleware.md b/docs/ru/docs/tutorial/middleware.md index a83d3c011..734545cd8 100644 --- a/docs/ru/docs/tutorial/middleware.md +++ b/docs/ru/docs/tutorial/middleware.md @@ -1,10 +1,8 @@ # Middleware (Промежуточный слой) { #middleware } -Вы можете добавить промежуточный слой (middleware) в **FastAPI** приложение. - -"Middleware" это функция, которая выполняется с каждым запросом до его обработки какой-либо конкретной *операцией пути*. -А также с каждым ответом перед его возвращением. +Вы можете добавить middleware (промежуточный слой) в **FastAPI** приложение. +"Middleware" - это функция, которая выполняется с каждым **запросом** до его обработки какой-либо конкретной *операцией пути*. А также с каждым **ответом** перед его возвращением. * Она принимает каждый поступающий **запрос**. * Может что-то сделать с этим **запросом** или выполнить любой нужный код. @@ -23,23 +21,23 @@ ## Создание middleware { #create-a-middleware } -Для создания middleware используйте декоратор `@app.middleware("http")`. +Для создания middleware используйте декоратор `@app.middleware("http")` поверх функции. Функция middleware получает: -* `request` (объект запроса). +* `request`. * Функцию `call_next`, которая получает `request` в качестве параметра. * Эта функция передаёт `request` соответствующей *операции пути*. - * Затем она возвращает ответ `response`, сгенерированный *операцией пути*. -* Также имеется возможность видоизменить `response`, перед тем как его вернуть. + * Затем она возвращает `response`, сгенерированный соответствующей *операцией пути*. +* Также имеется возможность видоизменить `response` перед тем как его вернуть. -{* ../../docs_src/middleware/tutorial001_py39.py hl[8:9,11,14] *} +{* ../../docs_src/middleware/tutorial001_py310.py hl[8:9,11,14] *} -/// tip | Примечание +/// tip | Совет -Имейте в виду, что можно добавлять свои собственные заголовки при помощи префикса 'X-'. +Имейте в виду, что можно добавлять проприетарные HTTP-заголовки с префиксом `X-`. -Если же вы хотите добавить собственные заголовки, которые клиент сможет увидеть в браузере, то вам потребуется добавить их в настройки CORS ([CORS (Cross-Origin Resource Sharing)](cors.md){.internal-link target=_blank}), используя параметр `expose_headers`, см. документацию Starlette's CORS docs. +Но если вы хотите, чтобы клиент в браузере мог видеть ваши пользовательские заголовки, необходимо добавить их в настройки CORS ([CORS (Cross-Origin Resource Sharing)](cors.md){.internal-link target=_blank}), используя параметр `expose_headers`, описанный в документации по CORS Starlette. /// @@ -53,17 +51,17 @@ ### До и после `response` { #before-and-after-the-response } -Вы можете добавить код, использующий `request` до передачи его какой-либо *операции пути*. +Вы можете добавить код, использующий `request`, до передачи его какой-либо *операции пути*. А также после формирования `response`, до того, как вы его вернёте. Например, вы можете добавить собственный заголовок `X-Process-Time`, содержащий время в секундах, необходимое для обработки запроса и генерации ответа: -{* ../../docs_src/middleware/tutorial001_py39.py hl[10,12:13] *} +{* ../../docs_src/middleware/tutorial001_py310.py hl[10,12:13] *} -/// tip | Примечание +/// tip | Совет -Мы используем `time.perf_counter()` вместо `time.time()` для обеспечения большей точности наших примеров. 🤓 +Мы используем `time.perf_counter()` вместо `time.time()` для обеспечения большей точности в таких случаях. 🤓 /// @@ -94,4 +92,4 @@ app.add_middleware(MiddlewareB) О других middleware вы можете узнать больше в разделе [Advanced User Guide: Advanced Middleware](../advanced/middleware.md){.internal-link target=_blank}. -В следующем разделе вы можете прочитать, как настроить CORS с помощью middleware. +В следующем разделе вы можете прочитать, как настроить CORS с помощью middleware. diff --git a/docs/ru/docs/tutorial/path-operation-configuration.md b/docs/ru/docs/tutorial/path-operation-configuration.md index 112a1efca..31531c67f 100644 --- a/docs/ru/docs/tutorial/path-operation-configuration.md +++ b/docs/ru/docs/tutorial/path-operation-configuration.md @@ -4,7 +4,7 @@ /// warning | Внимание -Помните, что эти параметры передаются непосредственно *декоратору операций пути*, а не вашей *функции-обработчику операций пути*. +Помните, что эти параметры передаются непосредственно *декоратору операций пути*, а не вашей *функции-обработчику пути*. /// @@ -46,7 +46,7 @@ **FastAPI** поддерживает это так же, как и в случае с обычными строками: -{* ../../docs_src/path_operation_configuration/tutorial002b_py39.py hl[1,8:10,13,18] *} +{* ../../docs_src/path_operation_configuration/tutorial002b_py310.py hl[1,8:10,13,18] *} ## Краткое и развёрнутое содержание { #summary-and-description } @@ -56,7 +56,7 @@ ## Описание из строк документации { #description-from-docstring } -Так как описания обычно длинные и содержат много строк, вы можете объявить описание *операции пути* в функции строки документации и **FastAPI** прочитает её отсюда. +Так как описания обычно длинные и содержат много строк, вы можете объявить описание *операции пути* в строке документации функции, и **FastAPI** прочитает её оттуда. Вы можете использовать Markdown в строке документации, и он будет интерпретирован и отображён корректно (с учетом отступа в строке документации). @@ -90,9 +90,9 @@ OpenAPI указывает, что каждой *операции пути* не ## Обозначение *операции пути* как устаревшей { #deprecate-a-path-operation } -Если вам необходимо пометить *операцию пути* как устаревшую, при этом не удаляя её, передайте параметр `deprecated`: +Если вам необходимо пометить *операцию пути* как устаревшую, при этом не удаляя её, передайте параметр `deprecated`: -{* ../../docs_src/path_operation_configuration/tutorial006_py39.py hl[16] *} +{* ../../docs_src/path_operation_configuration/tutorial006_py310.py hl[16] *} Он будет четко помечен как устаревший в интерактивной документации: diff --git a/docs/ru/docs/tutorial/path-params-numeric-validations.md b/docs/ru/docs/tutorial/path-params-numeric-validations.md index f0fe78805..6c1148b60 100644 --- a/docs/ru/docs/tutorial/path-params-numeric-validations.md +++ b/docs/ru/docs/tutorial/path-params-numeric-validations.md @@ -44,7 +44,7 @@ Path-параметр всегда является обязательным, п И если вам больше ничего не нужно указывать для этого параметра, то нет необходимости использовать `Query`. -Но вам по-прежнему нужно использовать `Path` для path-параметра `item_id`. И если по какой-либо причине вы не хотите использовать `Annotated`, то могут возникнуть небольшие сложности. +Но вам по-прежнему нужно использовать `Path` для path-параметра `item_id`. И по какой-либо причине вы не хотите использовать `Annotated`. Если вы поместите параметр со значением по умолчанию перед другим параметром, у которого нет значения по умолчанию, то Python укажет на ошибку. @@ -54,11 +54,11 @@ Path-параметр всегда является обязательным, п Поэтому вы можете определить функцию так: -{* ../../docs_src/path_params_numeric_validations/tutorial002_py39.py hl[7] *} +{* ../../docs_src/path_params_numeric_validations/tutorial002_py310.py hl[7] *} Но имейте в виду, что если вы используете `Annotated`, вы не столкнётесь с этой проблемой, так как вы не используете значения по умолчанию параметров функции для `Query()` или `Path()`. -{* ../../docs_src/path_params_numeric_validations/tutorial002_an_py39.py *} +{* ../../docs_src/path_params_numeric_validations/tutorial002_an_py310.py *} ## Задайте нужный вам порядок параметров, полезные приёмы { #order-the-parameters-as-you-need-tricks } @@ -83,13 +83,13 @@ Path-параметр всегда является обязательным, п Python не будет ничего делать с `*`, но он будет знать, что все следующие параметры являются именованными аргументами (парами ключ-значение), также известными как kwargs, даже если у них нет значений по умолчанию. -{* ../../docs_src/path_params_numeric_validations/tutorial003_py39.py hl[7] *} +{* ../../docs_src/path_params_numeric_validations/tutorial003_py310.py hl[7] *} ### Лучше с `Annotated` { #better-with-annotated } Имейте в виду, что если вы используете `Annotated`, то, поскольку вы не используете значений по умолчанию для параметров функции, у вас не возникнет подобной проблемы и вам, вероятно, не придётся использовать `*`. -{* ../../docs_src/path_params_numeric_validations/tutorial003_an_py39.py hl[10] *} +{* ../../docs_src/path_params_numeric_validations/tutorial003_an_py310.py hl[10] *} ## Валидация числовых данных: больше или равно { #number-validations-greater-than-or-equal } @@ -97,7 +97,7 @@ Python не будет ничего делать с `*`, но он будет з В этом примере при указании `ge=1`, параметр `item_id` должен быть целым числом "`g`reater than or `e`qual" — больше или равно `1`. -{* ../../docs_src/path_params_numeric_validations/tutorial004_an_py39.py hl[10] *} +{* ../../docs_src/path_params_numeric_validations/tutorial004_an_py310.py hl[10] *} ## Валидация числовых данных: больше и меньше или равно { #number-validations-greater-than-and-less-than-or-equal } @@ -106,7 +106,7 @@ Python не будет ничего делать с `*`, но он будет з * `gt`: больше (`g`reater `t`han) * `le`: меньше или равно (`l`ess than or `e`qual) -{* ../../docs_src/path_params_numeric_validations/tutorial005_an_py39.py hl[10] *} +{* ../../docs_src/path_params_numeric_validations/tutorial005_an_py310.py hl[10] *} ## Валидация числовых данных: числа с плавающей точкой, больше и меньше { #number-validations-floats-greater-than-and-less-than } @@ -118,7 +118,7 @@ Python не будет ничего делать с `*`, но он будет з То же самое справедливо и для lt. -{* ../../docs_src/path_params_numeric_validations/tutorial006_an_py39.py hl[13] *} +{* ../../docs_src/path_params_numeric_validations/tutorial006_an_py310.py hl[13] *} ## Резюме { #recap } diff --git a/docs/ru/docs/tutorial/path-params.md b/docs/ru/docs/tutorial/path-params.md index 83a7ed3ff..729569748 100644 --- a/docs/ru/docs/tutorial/path-params.md +++ b/docs/ru/docs/tutorial/path-params.md @@ -2,7 +2,7 @@ Вы можете определить "параметры" или "переменные" пути, используя синтаксис форматированных строк Python: -{* ../../docs_src/path_params/tutorial001_py39.py hl[6:7] *} +{* ../../docs_src/path_params/tutorial001_py310.py hl[6:7] *} Значение параметра пути `item_id` будет передано в функцию в качестве аргумента `item_id`. @@ -16,7 +16,7 @@ Вы можете объявить тип параметра пути в функции, используя стандартные аннотации типов Python: -{* ../../docs_src/path_params/tutorial002_py39.py hl[7] *} +{* ../../docs_src/path_params/tutorial002_py310.py hl[7] *} Здесь, `item_id` объявлен типом `int`. @@ -26,7 +26,7 @@ /// -## Преобразование данных { #data-conversion } +## Преобразование данных { #data-conversion } Если запустите этот пример и перейдёте по адресу: http://127.0.0.1:8000/items/3, то увидите ответ: @@ -38,7 +38,7 @@ Обратите внимание на значение `3`, которое получила (и вернула) функция. Это целочисленный Python `int`, а не строка `"3"`. -Используя такое объявление типов, **FastAPI** выполняет автоматический "парсинг" запросов. +Используя такое объявление типов, **FastAPI** выполняет автоматический HTTP-запрос "парсинг". /// @@ -118,13 +118,13 @@ Поскольку *операции пути* выполняются в порядке их объявления, необходимо, чтобы путь для `/users/me` был объявлен раньше, чем путь для `/users/{user_id}`: -{* ../../docs_src/path_params/tutorial003_py39.py hl[6,11] *} +{* ../../docs_src/path_params/tutorial003_py310.py hl[6,11] *} Иначе путь для `/users/{user_id}` также будет соответствовать `/users/me`, "подразумевая", что он получает параметр `user_id` со значением `"me"`. Аналогично, вы не можете переопределить операцию с путем: -{* ../../docs_src/path_params/tutorial003b_py39.py hl[6,11] *} +{* ../../docs_src/path_params/tutorial003b_py310.py hl[6,11] *} Первый будет выполняться всегда, так как путь совпадает первым. @@ -140,11 +140,11 @@ Затем создайте атрибуты класса с фиксированными допустимыми значениями: -{* ../../docs_src/path_params/tutorial005_py39.py hl[1,6:9] *} +{* ../../docs_src/path_params/tutorial005_py310.py hl[1,6:9] *} /// tip | Подсказка -Если интересно, то "AlexNet", "ResNet" и "LeNet" - это названия моделей Машинного обучения. +Если интересно, то "AlexNet", "ResNet" и "LeNet" - это названия моделей Машинного обучения. /// @@ -152,7 +152,7 @@ Определите *параметр пути*, используя в аннотации типа класс перечисления (`ModelName`), созданный ранее: -{* ../../docs_src/path_params/tutorial005_py39.py hl[16] *} +{* ../../docs_src/path_params/tutorial005_py310.py hl[16] *} ### Проверьте документацию { #check-the-docs } @@ -168,13 +168,13 @@ Вы можете сравнить это значение с *элементом перечисления* класса `ModelName`: -{* ../../docs_src/path_params/tutorial005_py39.py hl[17] *} +{* ../../docs_src/path_params/tutorial005_py310.py hl[17] *} #### Получение *значения перечисления* { #get-the-enumeration-value } Можно получить фактическое значение (в данном случае - `str`) с помощью `model_name.value` или в общем случае `your_enum_member.value`: -{* ../../docs_src/path_params/tutorial005_py39.py hl[20] *} +{* ../../docs_src/path_params/tutorial005_py310.py hl[20] *} /// tip | Подсказка @@ -188,8 +188,8 @@ Они будут преобразованы в соответствующие значения (в данном случае - строки) перед их возвратом клиенту: -{* ../../docs_src/path_params/tutorial005_py39.py hl[18,21,23] *} -Вы отправите клиенту такой JSON-ответ: +{* ../../docs_src/path_params/tutorial005_py310.py hl[18,21,23] *} +На стороне клиента вы получите такой JSON-ответ: ```JSON { @@ -226,7 +226,7 @@ OpenAPI не поддерживает способов объявления *п Можете использовать так: -{* ../../docs_src/path_params/tutorial004_py39.py hl[6] *} +{* ../../docs_src/path_params/tutorial004_py310.py hl[6] *} /// tip | Подсказка @@ -241,7 +241,7 @@ OpenAPI не поддерживает способов объявления *п Используя **FastAPI** вместе со стандартными объявлениями типов Python (короткими и интуитивно понятными), вы получаете: * Поддержку редактора кода (проверку ошибок, автозавершение и т.п.) -* "Парсинг" данных +* "Парсинг" данных * Валидацию данных * Аннотации API и автоматическую документацию diff --git a/docs/ru/docs/tutorial/query-param-models.md b/docs/ru/docs/tutorial/query-param-models.md index 5ad7f1d99..7f29740ac 100644 --- a/docs/ru/docs/tutorial/query-param-models.md +++ b/docs/ru/docs/tutorial/query-param-models.md @@ -6,7 +6,7 @@ /// note | Заметка -Этот функционал доступен с версии `0.115.0`. 🤓 +Это поддерживается начиная с версии FastAPI `0.115.0`. 🤓 /// diff --git a/docs/ru/docs/tutorial/query-params-str-validations.md b/docs/ru/docs/tutorial/query-params-str-validations.md index 2bc2fb22c..43cbcad03 100644 --- a/docs/ru/docs/tutorial/query-params-str-validations.md +++ b/docs/ru/docs/tutorial/query-params-str-validations.md @@ -47,40 +47,16 @@ FastAPI поймёт, что значение `q` не обязательно, У нас была такая аннотация типа: -//// tab | Python 3.10+ - ```Python q: str | None = None ``` -//// - -//// tab | Python 3.9+ - -```Python -q: Union[str, None] = None -``` - -//// - Мы «обернём» это в `Annotated`, и получится: -//// tab | Python 3.10+ - ```Python q: Annotated[str | None] = None ``` -//// - -//// tab | Python 3.9+ - -```Python -q: Annotated[Union[str, None]] = None -``` - -//// - Обе версии означают одно и то же: `q` — параметр, который может быть `str` или `None`, и по умолчанию равен `None`. А теперь к самому интересному. 🎉 @@ -109,7 +85,7 @@ q: Annotated[Union[str, None]] = None ## Альтернатива (устаревшее): `Query` как значение по умолчанию { #alternative-old-query-as-the-default-value } -В предыдущих версиях FastAPI (до 0.95.0) требовалось использовать `Query` как значение по умолчанию для параметра вместо помещения его в `Annotated`. Скорее всего вы ещё встретите такой код, поэтому поясню. +В предыдущих версиях FastAPI (до 0.95.0) требовалось использовать `Query` как значение по умолчанию для параметра вместо помещения его в `Annotated`. Скорее всего вы ещё встретите такой код, поэтому поясню. /// tip | Подсказка @@ -191,7 +167,7 @@ q: str = Query(default="rick") ## Регулярные выражения { #add-regular-expressions } -Вы можете определить регулярное выражение `pattern`, которому должен соответствовать параметр: +Вы можете определить регулярное выражение `pattern`, которому должен соответствовать параметр: {* ../../docs_src/query_params_str_validations/tutorial004_an_py310.py hl[11] *} @@ -211,7 +187,7 @@ q: str = Query(default="rick") Допустим, вы хотите объявить, что query-параметр `q` должен иметь `min_length` равный `3` и значение по умолчанию `"fixedquery"`: -{* ../../docs_src/query_params_str_validations/tutorial005_an_py39.py hl[9] *} +{* ../../docs_src/query_params_str_validations/tutorial005_an_py310.py hl[9] *} /// note | Примечание @@ -241,7 +217,7 @@ q: Annotated[str | None, Query(min_length=3)] = None Поэтому, когда вам нужно объявить значение как обязательное при использовании `Query`, просто не указывайте значение по умолчанию: -{* ../../docs_src/query_params_str_validations/tutorial006_an_py39.py hl[9] *} +{* ../../docs_src/query_params_str_validations/tutorial006_an_py310.py hl[9] *} ### Обязательный, но может быть `None` { #required-can-be-none } @@ -292,7 +268,7 @@ http://localhost:8000/items/?q=foo&q=bar Можно также определить значение по умолчанию как `list`, если ничего не передано: -{* ../../docs_src/query_params_str_validations/tutorial012_an_py39.py hl[9] *} +{* ../../docs_src/query_params_str_validations/tutorial012_an_py310.py hl[9] *} Если вы перейдёте по адресу: @@ -315,7 +291,7 @@ http://localhost:8000/items/ Можно использовать `list` напрямую вместо `list[str]`: -{* ../../docs_src/query_params_str_validations/tutorial013_an_py39.py hl[9] *} +{* ../../docs_src/query_params_str_validations/tutorial013_an_py310.py hl[9] *} /// note | Примечание @@ -371,7 +347,7 @@ http://127.0.0.1:8000/items/?item-query=foobaritems Предположим, этот параметр вам больше не нравится. -Его нужно оставить на какое‑то время, так как клиенты его используют, но вы хотите, чтобы в документации он явно отображался как устаревший. +Его нужно оставить на какое‑то время, так как клиенты его используют, но вы хотите, чтобы в документации он явно отображался как устаревший. Тогда передайте параметр `deprecated=True` в `Query`: @@ -401,7 +377,7 @@ http://127.0.0.1:8000/items/?item-query=foobaritems /// -Например, эта кастомная проверка убеждается, что ID элемента начинается с `isbn-` для номера книги ISBN или с `imdb-` для ID URL фильма на IMDB: +Например, эта кастомная проверка убеждается, что ID элемента начинается с `isbn-` для номера книги ISBN или с `imdb-` для ID URL фильма на IMDB: {* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py hl[5,16:19,24] *} @@ -435,7 +411,7 @@ http://127.0.0.1:8000/items/?item-query=foobaritems #### Случайный элемент { #a-random-item } -С помощью `data.items()` мы получаем итерируемый объект с кортежами, содержащими ключ и значение для каждого элемента словаря. +С помощью `data.items()` мы получаем итерируемый объект с кортежами, содержащими ключ и значение для каждого элемента словаря. Мы превращаем этот итерируемый объект в обычный `list` через `list(data.items())`. diff --git a/docs/ru/docs/tutorial/query-params.md b/docs/ru/docs/tutorial/query-params.md index be1c0e46e..cbacb129c 100644 --- a/docs/ru/docs/tutorial/query-params.md +++ b/docs/ru/docs/tutorial/query-params.md @@ -2,7 +2,7 @@ Когда вы объявляете параметры функции, которые не являются параметрами пути, они автоматически интерпретируются как "query"-параметры. -{* ../../docs_src/query_params/tutorial001_py39.py hl[9] *} +{* ../../docs_src/query_params/tutorial001_py310.py hl[9] *} Query-параметры представляют из себя набор пар ключ-значение, которые идут после знака `?` в URL-адресе, разделенные символами `&`. @@ -24,7 +24,7 @@ http://127.0.0.1:8000/items/?skip=0&limit=10 Все те же правила, которые применяются к path-параметрам, также применяются и query-параметрам: * Поддержка от редактора кода (очевидно) -* "Парсинг" данных +* "Парсинг" данных * Проверка на соответствие данных (Валидация) * Автоматическая документация @@ -121,13 +121,13 @@ http://127.0.0.1:8000/items/foo?short=yes ## Обязательные query-параметры { #required-query-parameters } -Когда вы объявляете значение по умолчанию для параметра, который не является path-параметром (в этом разделе, мы пока что познакомились только с path-параметрами), то он не является обязательным. +Когда вы объявляете значение по умолчанию для параметра, который не является path-параметром (в этом разделе мы пока что рассмотрели только query-параметры), то он не является обязательным. Если вы не хотите задавать конкретное значение, но хотите сделать параметр необязательным, вы можете установить значение по умолчанию равным `None`. Но если вы хотите сделать query-параметр обязательным, вы можете просто не указывать значение по умолчанию: -{* ../../docs_src/query_params/tutorial005_py39.py hl[6:7] *} +{* ../../docs_src/query_params/tutorial005_py310.py hl[6:7] *} Здесь параметр запроса `needy` является обязательным параметром с типом данных `str`. diff --git a/docs/ru/docs/tutorial/request-files.md b/docs/ru/docs/tutorial/request-files.md index 9cfbd53df..41922333f 100644 --- a/docs/ru/docs/tutorial/request-files.md +++ b/docs/ru/docs/tutorial/request-files.md @@ -20,13 +20,13 @@ $ pip install python-multipart Импортируйте `File` и `UploadFile` из модуля `fastapi`: -{* ../../docs_src/request_files/tutorial001_an_py39.py hl[3] *} +{* ../../docs_src/request_files/tutorial001_an_py310.py hl[3] *} ## Определите параметры `File` { #define-file-parameters } Создайте параметры `File` так же, как вы это делаете для `Body` или `Form`: -{* ../../docs_src/request_files/tutorial001_an_py39.py hl[9] *} +{* ../../docs_src/request_files/tutorial001_an_py310.py hl[9] *} /// info | Дополнительная информация @@ -54,7 +54,7 @@ $ pip install python-multipart Определите параметр файла с типом `UploadFile`: -{* ../../docs_src/request_files/tutorial001_an_py39.py hl[14] *} +{* ../../docs_src/request_files/tutorial001_an_py310.py hl[14] *} Использование `UploadFile` имеет ряд преимуществ перед `bytes`: @@ -122,7 +122,7 @@ contents = myfile.file.read() Но когда форма включает файлы, она кодируется как multipart/form-data. Если вы используете `File`, **FastAPI** будет знать, что ему нужно получить файлы из нужной части тела. -Если вы хотите узнать больше об этих кодировках и полях форм, перейдите по ссылке MDN web docs for POST. +Если вы хотите узнать больше об этих кодировках и полях форм, перейдите по ссылке MDN web docs for POST. /// @@ -144,7 +144,7 @@ contents = myfile.file.read() Вы также можете использовать `File()` вместе с `UploadFile`, например, для установки дополнительных метаданных: -{* ../../docs_src/request_files/tutorial001_03_an_py39.py hl[9,15] *} +{* ../../docs_src/request_files/tutorial001_03_an_py310.py hl[9,15] *} ## Загрузка нескольких файлов { #multiple-file-uploads } @@ -154,7 +154,7 @@ contents = myfile.file.read() Для этого необходимо объявить список `bytes` или `UploadFile`: -{* ../../docs_src/request_files/tutorial002_an_py39.py hl[10,15] *} +{* ../../docs_src/request_files/tutorial002_an_py310.py hl[10,15] *} Вы получите, как и было объявлено, список `list` из `bytes` или `UploadFile`. @@ -170,7 +170,7 @@ contents = myfile.file.read() Так же, как и раньше, вы можете использовать `File()` для задания дополнительных параметров, даже для `UploadFile`: -{* ../../docs_src/request_files/tutorial003_an_py39.py hl[11,18:20] *} +{* ../../docs_src/request_files/tutorial003_an_py310.py hl[11,18:20] *} ## Резюме { #recap } diff --git a/docs/ru/docs/tutorial/request-form-models.md b/docs/ru/docs/tutorial/request-form-models.md index f8c58356c..f4411a27b 100644 --- a/docs/ru/docs/tutorial/request-form-models.md +++ b/docs/ru/docs/tutorial/request-form-models.md @@ -24,7 +24,7 @@ $ pip install python-multipart Вам просто нужно объявить **Pydantic-модель** с полями, которые вы хотите получить как **поля формы**, а затем объявить параметр как `Form`: -{* ../../docs_src/request_form_models/tutorial001_an_py39.py hl[9:11,15] *} +{* ../../docs_src/request_form_models/tutorial001_an_py310.py hl[9:11,15] *} **FastAPI** **извлечёт** данные для **каждого поля** из **данных формы** в запросе и выдаст вам объявленную Pydantic-модель. @@ -48,7 +48,7 @@ $ pip install python-multipart Вы можете сконфигурировать Pydantic-модель так, чтобы запретить (`forbid`) все дополнительные (`extra`) поля: -{* ../../docs_src/request_form_models/tutorial002_an_py39.py hl[12] *} +{* ../../docs_src/request_form_models/tutorial002_an_py310.py hl[12] *} Если клиент попробует отправить дополнительные данные, то в ответ он получит **ошибку**. diff --git a/docs/ru/docs/tutorial/request-forms-and-files.md b/docs/ru/docs/tutorial/request-forms-and-files.md index 691dc75ba..10836d74f 100644 --- a/docs/ru/docs/tutorial/request-forms-and-files.md +++ b/docs/ru/docs/tutorial/request-forms-and-files.md @@ -16,13 +16,13 @@ $ pip install python-multipart ## Импортируйте `File` и `Form` { #import-file-and-form } -{* ../../docs_src/request_forms_and_files/tutorial001_an_py39.py hl[3] *} +{* ../../docs_src/request_forms_and_files/tutorial001_an_py310.py hl[3] *} ## Определите параметры `File` и `Form` { #define-file-and-form-parameters } Создайте параметры файла и формы таким же образом, как для `Body` или `Query`: -{* ../../docs_src/request_forms_and_files/tutorial001_an_py39.py hl[10:12] *} +{* ../../docs_src/request_forms_and_files/tutorial001_an_py310.py hl[10:12] *} Файлы и поля формы будут загружены в виде данных формы, и вы получите файлы и поля формы. diff --git a/docs/ru/docs/tutorial/request-forms.md b/docs/ru/docs/tutorial/request-forms.md index e257652b6..01f71ac2f 100644 --- a/docs/ru/docs/tutorial/request-forms.md +++ b/docs/ru/docs/tutorial/request-forms.md @@ -18,17 +18,17 @@ $ pip install python-multipart Импортируйте `Form` из `fastapi`: -{* ../../docs_src/request_forms/tutorial001_an_py39.py hl[3] *} +{* ../../docs_src/request_forms/tutorial001_an_py310.py hl[3] *} ## Определение параметров `Form` { #define-form-parameters } Создайте параметры формы так же, как это делается для `Body` или `Query`: -{* ../../docs_src/request_forms/tutorial001_an_py39.py hl[9] *} +{* ../../docs_src/request_forms/tutorial001_an_py310.py hl[9] *} -Например, в одном из способов использования спецификации OAuth2 (называемом «потоком пароля») требуется отправить `username` и `password` в виде полей формы. +Например, в одном из способов использования спецификации OAuth2 (называемом «password flow» - аутентификация по паролю) требуется отправить `username` и `password` в виде полей формы. -spec требует, чтобы поля были строго названы `username` и `password` и отправлялись как поля формы, а не JSON. +спецификация требует, чтобы поля были строго названы `username` и `password` и отправлялись как поля формы, а не JSON. С помощью `Form` вы можете объявить те же настройки, что и с `Body` (и `Query`, `Path`, `Cookie`), включая валидацию, примеры, псевдоним (например, `user-name` вместо `username`) и т.д. @@ -56,7 +56,7 @@ $ pip install python-multipart Но когда форма содержит файлы, она кодируется как `multipart/form-data`. О работе с файлами вы прочтёте в следующей главе. -Если вы хотите узнать больше про эти кодировки и поля формы, обратитесь к MDN веб-документации для `POST`. +Если вы хотите узнать больше про эти кодировки и поля формы, обратитесь к MDN веб-документации для `POST`. /// diff --git a/docs/ru/docs/tutorial/response-model.md b/docs/ru/docs/tutorial/response-model.md index 22a811cd5..cd99ce28c 100644 --- a/docs/ru/docs/tutorial/response-model.md +++ b/docs/ru/docs/tutorial/response-model.md @@ -183,7 +183,7 @@ FastAPI делает несколько вещей внутри вместе с Самый распространённый случай — [возвращать Response напрямую, как описано далее в разделах документации для продвинутых](../advanced/response-directly.md){.internal-link target=_blank}. -{* ../../docs_src/response_model/tutorial003_02_py39.py hl[8,10:11] *} +{* ../../docs_src/response_model/tutorial003_02_py310.py hl[8,10:11] *} Этот простой случай обрабатывается FastAPI автоматически, потому что аннотация возвращаемого типа — это класс (или подкласс) `Response`. @@ -193,7 +193,7 @@ FastAPI делает несколько вещей внутри вместе с Вы также можете использовать подкласс `Response` в аннотации типа: -{* ../../docs_src/response_model/tutorial003_03_py39.py hl[8:9] *} +{* ../../docs_src/response_model/tutorial003_03_py310.py hl[8:9] *} Это тоже сработает, так как `RedirectResponse` — подкласс `Response`, и FastAPI автоматически обработает этот простой случай. @@ -201,7 +201,7 @@ FastAPI делает несколько вещей внутри вместе с Но когда вы возвращаете произвольный объект, не являющийся валидным типом Pydantic (например, объект базы данных), и аннотируете его таким образом в функции, FastAPI попытается создать модель ответа Pydantic из этой аннотации типа и потерпит неудачу. -То же произойдёт, если у вас будет что-то вроде union разных типов, где один или несколько не являются валидными типами Pydantic, например, это приведёт к ошибке 💥: +То же произойдёт, если у вас будет что-то вроде union разных типов, где один или несколько не являются валидными типами Pydantic, например, это приведёт к ошибке 💥: {* ../../docs_src/response_model/tutorial003_04_py310.py hl[8] *} diff --git a/docs/ru/docs/tutorial/response-status-code.md b/docs/ru/docs/tutorial/response-status-code.md index 30f642b64..13d982e80 100644 --- a/docs/ru/docs/tutorial/response-status-code.md +++ b/docs/ru/docs/tutorial/response-status-code.md @@ -8,7 +8,7 @@ * `@app.delete()` * и других. -{* ../../docs_src/response_status_code/tutorial001_py39.py hl[6] *} +{* ../../docs_src/response_status_code/tutorial001_py310.py hl[6] *} /// note | Примечание @@ -66,7 +66,7 @@ FastAPI знает об этом и создаст документацию Open /// tip | Подсказка -Чтобы узнать больше о HTTP кодах статуса и о том, для чего каждый из них предназначен, ознакомьтесь с MDN документацией об HTTP статус-кодах. +Чтобы узнать больше о HTTP кодах статуса и о том, для чего каждый из них предназначен, ознакомьтесь с MDN документацией об HTTP статус-кодах. /// @@ -74,7 +74,7 @@ FastAPI знает об этом и создаст документацию Open Рассмотрим предыдущий пример еще раз: -{* ../../docs_src/response_status_code/tutorial001_py39.py hl[6] *} +{* ../../docs_src/response_status_code/tutorial001_py310.py hl[6] *} `201` – это код статуса "Создано". @@ -82,7 +82,7 @@ FastAPI знает об этом и создаст документацию Open Для удобства вы можете использовать переменные из `fastapi.status`. -{* ../../docs_src/response_status_code/tutorial002_py39.py hl[1,6] *} +{* ../../docs_src/response_status_code/tutorial002_py310.py hl[1,6] *} Они содержат те же числовые значения, но позволяют использовать автозавершение редактора кода для выбора кода статуса: @@ -90,7 +90,7 @@ FastAPI знает об этом и создаст документацию Open /// note | Технические детали -Вы также можете использовать `from starlette import status` вместо `from fastapi import status`. +Вы также можете использовать `from starlette import status`. **FastAPI** позволяет использовать как `starlette.status`, так и `fastapi.status` исключительно для удобства разработчиков. Но поставляется fastapi.status непосредственно из Starlette. diff --git a/docs/ru/docs/tutorial/schema-extra-example.md b/docs/ru/docs/tutorial/schema-extra-example.md index e4a97c880..c7381aae2 100644 --- a/docs/ru/docs/tutorial/schema-extra-example.md +++ b/docs/ru/docs/tutorial/schema-extra-example.md @@ -74,7 +74,7 @@ OpenAPI 3.1.0 (используется начиная с FastAPI 0.99.0) доб Когда вы делаете это, примеры становятся частью внутренней **JSON Schema** для данных тела запроса. -Тем не менее, на момент написания этого Swagger UI, инструмент, отвечающий за отображение UI документации, не поддерживает показ нескольких примеров для данных в **JSON Schema**. Но ниже есть обходной путь. +Тем не менее, на момент написания этого Swagger UI, инструмент, отвечающий за отображение UI документации, не поддерживает показ нескольких примеров для данных в **JSON Schema**. Но ниже есть обходной путь. ### Специфические для OpenAPI `examples` { #openapi-specific-examples } diff --git a/docs/ru/docs/tutorial/security/first-steps.md b/docs/ru/docs/tutorial/security/first-steps.md index 983e85e66..9b9673b84 100644 --- a/docs/ru/docs/tutorial/security/first-steps.md +++ b/docs/ru/docs/tutorial/security/first-steps.md @@ -20,7 +20,7 @@ Скопируйте пример в файл `main.py`: -{* ../../docs_src/security/tutorial001_an_py39.py *} +{* ../../docs_src/security/tutorial001_an_py310.py *} ## Запуск { #run-it } @@ -132,7 +132,7 @@ OAuth2 был спроектирован так, чтобы бэкенд или При создании экземпляра класса `OAuth2PasswordBearer` мы передаем параметр `tokenUrl`. Этот параметр содержит URL, который клиент (фронтенд, работающий в браузере пользователя) будет использовать для отправки `username` и `password`, чтобы получить токен. -{* ../../docs_src/security/tutorial001_an_py39.py hl[8] *} +{* ../../docs_src/security/tutorial001_an_py310.py hl[8] *} /// tip | Подсказка @@ -170,7 +170,7 @@ oauth2_scheme(some, parameters) Теперь вы можете передать `oauth2_scheme` как зависимость с `Depends`. -{* ../../docs_src/security/tutorial001_an_py39.py hl[12] *} +{* ../../docs_src/security/tutorial001_an_py310.py hl[12] *} Эта зависимость предоставит `str`, который будет присвоен параметру `token` *функции-обработчика пути*. diff --git a/docs/ru/docs/tutorial/security/get-current-user.md b/docs/ru/docs/tutorial/security/get-current-user.md index c6bc07cc1..8388b672c 100644 --- a/docs/ru/docs/tutorial/security/get-current-user.md +++ b/docs/ru/docs/tutorial/security/get-current-user.md @@ -2,7 +2,7 @@ В предыдущей главе система безопасности (основанная на системе внедрения зависимостей) передавала *функции-обработчику пути* `token` типа `str`: -{* ../../docs_src/security/tutorial001_an_py39.py hl[12] *} +{* ../../docs_src/security/tutorial001_an_py310.py hl[12] *} Но это всё ещё не слишком полезно. diff --git a/docs/ru/docs/tutorial/security/index.md b/docs/ru/docs/tutorial/security/index.md index ebac013b6..bd8da824b 100644 --- a/docs/ru/docs/tutorial/security/index.md +++ b/docs/ru/docs/tutorial/security/index.md @@ -1,56 +1,56 @@ -# Настройка авторизации { #security } +# Безопасность { #security } Существует множество способов обеспечения безопасности, аутентификации и авторизации. -Обычно эта тема является достаточно сложной и трудной. +Обычно эта тема является достаточно сложной и «трудной». -Во многих фреймворках и системах только работа с определением доступов к приложению и аутентификацией требует значительных затрат усилий и написания множества кода (во многих случаях его объём может составлять более 50% от всего написанного кода). +Во многих фреймворках и системах только работа с безопасностью и аутентификацией требует значительных затрат усилий и написания множества кода (во многих случаях его объём может составлять 50% или более от всего написанного кода). -**FastAPI** предоставляет несколько инструментов, которые помогут вам настроить **Авторизацию** легко, быстро, стандартным способом, без необходимости изучать все её тонкости. +**FastAPI** предоставляет несколько инструментов, которые помогут вам работать с **безопасностью** легко, быстро, стандартным способом, без необходимости изучать и разбираться во всех спецификациях по безопасности. -Но сначала давайте рассмотрим некоторые небольшие концепции. +Но сначала давайте рассмотрим несколько небольших концепций. -## Куда-то торопишься? { #in-a-hurry } +## Нет времени? { #in-a-hurry } -Если вам не нужна информация о каких-либо из следующих терминов и вам просто нужно добавить защиту с аутентификацией на основе логина и пароля *прямо сейчас*, переходите к следующим главам. +Если вам не важны какие-либо из этих терминов и вам просто нужно добавить защиту с аутентификацией на основе имени пользователя и пароля прямо сейчас, переходите к следующим главам. ## OAuth2 { #oauth2 } -OAuth2 - это протокол, который определяет несколько способов обработки аутентификации и авторизации. +OAuth2 - это спецификация, которая определяет несколько способов обработки аутентификации и авторизации. -Он довольно обширен и охватывает несколько сложных вариантов использования. +Это довольно обширная спецификация, охватывающая несколько сложных вариантов использования. -OAuth2 включает в себя способы аутентификации с использованием "третьей стороны". +Она включает способы аутентификации с использованием «третьей стороны». -Это то, что используют под собой все кнопки "вход с помощью Facebook, Google, X (Twitter), GitHub" на страницах авторизации. +Именно это используется во всех системах с кнопками «войти с помощью Facebook, Google, X (Twitter), GitHub». ### OAuth 1 { #oauth-1 } -Ранее использовался протокол OAuth 1, который сильно отличается от OAuth2 и является более сложным, поскольку он включал прямые описания того, как шифровать сообщение. +Ранее использовался OAuth 1, который сильно отличается от OAuth2 и является более сложным, поскольку он включал прямые спецификации того, как шифровать обмен данными. В настоящее время он не очень популярен и не используется. -OAuth2 не указывает, как шифровать сообщение, он ожидает, что ваше приложение будет обслуживаться по протоколу HTTPS. +OAuth2 не указывает, как шифровать обмен данными, он ожидает, что ваше приложение будет обслуживаться по протоколу HTTPS. /// tip | Подсказка -В разделе **Развертывание** вы увидите как настроить протокол HTTPS бесплатно, используя Traefik и Let's Encrypt. +В разделе о **развертывании** вы увидите, как настроить HTTPS бесплатно, используя Traefik и Let's Encrypt. /// ## OpenID Connect { #openid-connect } -OpenID Connect - это еще один протокол, основанный на **OAuth2**. +OpenID Connect — это ещё одна спецификация, основанная на **OAuth2**. -Он просто расширяет OAuth2, уточняя некоторые вещи, не имеющие однозначного определения в OAuth2, в попытке сделать его более совместимым. +Она просто расширяет OAuth2, уточняя некоторые вещи, которые относительно неоднозначны в OAuth2, стараясь сделать его более совместимым. -Например, для входа в Google используется OpenID Connect (который под собой использует OAuth2). +Например, для входа в Google используется OpenID Connect (который под капотом использует OAuth2). Но вход в Facebook не поддерживает OpenID Connect. У него есть собственная вариация OAuth2. -### OpenID (не "OpenID Connect") { #openid-not-openid-connect } +### OpenID (не «OpenID Connect») { #openid-not-openid-connect } -Также ранее использовался стандарт "OpenID", который пытался решить ту же проблему, что и **OpenID Connect**, но не был основан на OAuth2. +Также ранее использовалась спецификация «OpenID», которая пыталась решить ту же задачу, что и **OpenID Connect**, но не была основана на OAuth2. Таким образом, это была полноценная дополнительная система. @@ -62,45 +62,45 @@ OpenAPI (ранее известный как Swagger) - это открытая **FastAPI** основан на **OpenAPI**. -Это то, что делает возможным наличие множества автоматических интерактивных интерфейсов документирования, сгенерированного кода и т.д. +Это то, что делает возможными несколько автоматических интерактивных интерфейсов документации, генерацию кода и т.д. -В OpenAPI есть способ использовать несколько "схем" безопасности. +В OpenAPI есть способ определить несколько «схем» безопасности. -Таким образом, вы можете воспользоваться преимуществами Всех этих стандартных инструментов, включая интерактивные системы документирования. +Используя их, вы можете воспользоваться преимуществами всех этих инструментов, основанных на стандартах, включая интерактивные системы документирования. -OpenAPI может использовать следующие схемы авторизации: +OpenAPI определяет следующие схемы безопасности: -* `apiKey`: уникальный идентификатор для приложения, который может быть получен из: - * Параметров запроса. - * Заголовка. - * Cookies. -* `http`: стандартные системы аутентификации по протоколу HTTP, включая: - * `bearer`: заголовок `Authorization` со значением `Bearer {уникальный токен}`. Это унаследовано от OAuth2. - * Базовая аутентификация по протоколу HTTP. +* `apiKey`: специфичный для приложения ключ, который может поступать из: + * параметра запроса. + * HTTP-заголовка. + * cookie. +* `http`: стандартные системы аутентификации по HTTP, включая: + * `bearer`: HTTP-заголовок `Authorization` со значением `Bearer ` плюс токен. Это унаследовано от OAuth2. + * Базовая аутентификация по HTTP. * HTTP Digest и т.д. -* `oauth2`: все способы обеспечения безопасности OAuth2 называемые "потоки" (англ. "flows"). - * Некоторые из этих "потоков" подходят для реализации аутентификации через сторонний сервис использующий OAuth 2.0 (например, Google, Facebook, X (Twitter), GitHub и т.д.): +* `oauth2`: все способы OAuth2 для обеспечения безопасности (называются «потоками»). + * Несколько из этих «потоков» подходят для построения провайдера аутентификации OAuth 2.0 (например, Google, Facebook, X (Twitter), GitHub и т.д.): * `implicit` * `clientCredentials` * `authorizationCode` - * Но есть один конкретный "поток", который может быть идеально использован для обработки аутентификации непосредственно в том же приложении: - * `password`: в некоторых следующих главах будут рассмотрены примеры этого. -* `openIdConnect`: способ определить, как автоматически обнаруживать данные аутентификации OAuth2. - * Это автоматическое обнаружение определено в спецификации OpenID Connect. + * Но есть один конкретный «поток», который можно идеально использовать для обработки аутентификации непосредственно в этом же приложении: + * `password`: в некоторых следующих главах будут приведены примеры. +* `openIdConnect`: имеет способ определить, как автоматически обнаруживать данные аутентификации OAuth2. + * Именно это автоматическое обнаружение определено в спецификации OpenID Connect. /// tip | Подсказка -Интеграция сторонних сервисов для аутентификации/авторизации таких как Google, Facebook, X (Twitter), GitHub и т.д. осуществляется достаточно легко. +Интеграция сторонних провайдеров аутентификации/авторизации, таких как Google, Facebook, X (Twitter), GitHub и т.д., также возможна и относительно проста. -Самой сложной проблемой является создание такого провайдера аутентификации/авторизации, но **FastAPI** предоставляет вам инструменты, позволяющие легко это сделать, выполняя при этом всю тяжелую работу за вас. +Самой сложной задачей является создание такого провайдера аутентификации/авторизации, но **FastAPI** предоставляет вам инструменты, позволяющие легко это сделать, выполняя при этом всю тяжёлую работу за вас. /// -## Преимущества **FastAPI** { #fastapi-utilities } +## Инструменты **FastAPI** { #fastapi-utilities } -Fast API предоставляет несколько инструментов для каждой из этих схем безопасности в модуле `fastapi.security`, которые упрощают использование этих механизмов безопасности. +FastAPI предоставляет несколько инструментов для каждой из этих схем безопасности в модуле `fastapi.security`, которые упрощают использование этих механизмов безопасности. -В следующих главах вы увидите, как обезопасить свой API, используя инструменты, предоставляемые **FastAPI**. +В следующих главах вы увидите, как добавить безопасность в ваш API, используя инструменты, предоставляемые **FastAPI**. -И вы также увидите, как он автоматически интегрируется в систему интерактивной документации. +И вы также увидите, как это автоматически интегрируется в систему интерактивной документации. diff --git a/docs/ru/docs/tutorial/security/oauth2-jwt.md b/docs/ru/docs/tutorial/security/oauth2-jwt.md index 803491f53..7838b07df 100644 --- a/docs/ru/docs/tutorial/security/oauth2-jwt.md +++ b/docs/ru/docs/tutorial/security/oauth2-jwt.md @@ -1,10 +1,10 @@ # OAuth2 с паролем (и хешированием), Bearer с JWT-токенами { #oauth2-with-password-and-hashing-bearer-with-jwt-tokens } -Теперь, когда у нас определен процесс обеспечения безопасности, давайте сделаем приложение действительно безопасным, используя токены JWT и безопасное хеширование паролей. +Теперь, когда у нас определен процесс обеспечения безопасности, давайте сделаем приложение действительно безопасным, используя токены JWT и безопасное хеширование паролей. Этот код можно реально использовать в своем приложении, сохранять хэши паролей в базе данных и т.д. -Мы продолжим разбираться, начиная с того места, на котором остановились в предыдущей главе. +Мы продолжим разбираться, начиная с того места, на котором остановились в предыдущей главе, и расширим его. ## Про JWT { #about-jwt } @@ -43,9 +43,11 @@ $ pip install pyjwt /// info | Дополнительная информация + Если вы планируете использовать алгоритмы цифровой подписи, такие как RSA или ECDSA, вам следует установить зависимость библиотеки криптографии `pyjwt[crypto]`. Подробнее об этом можно прочитать в документации по установке PyJWT. + /// ## Хеширование паролей { #password-hashing } @@ -83,11 +85,13 @@ $ pip install "pwdlib[argon2]" /// tip | Подсказка + С помощью `pwdlib` можно даже настроить его на чтение паролей, созданных **Django**, плагином безопасности **Flask** или многими другими библиотеками. Таким образом, вы сможете, например, совместно использовать одни и те же данные из приложения Django в базе данных с приложением FastAPI. Или постепенно мигрировать Django-приложение, используя ту же базу данных. При этом пользователи смогут одновременно входить в систему как из приложения Django, так и из приложения **FastAPI**. + /// ## Хеширование и проверка паролей { #hash-and-verify-the-passwords } @@ -97,11 +101,13 @@ $ pip install "pwdlib[argon2]" Создайте экземпляр PasswordHash с рекомендованными настройками — он будет использоваться для хэширования и проверки паролей. /// tip | Подсказка + pwdlib также поддерживает алгоритм хеширования bcrypt, но не включает устаревшие алгоритмы — для работы с устаревшими хэшами рекомендуется использовать библиотеку passlib. Например, вы можете использовать ее для чтения и проверки паролей, сгенерированных другой системой (например, Django), но хэшировать все новые пароли другим алгоритмом, например Argon2 или Bcrypt. И при этом быть совместимым со всеми этими системами. + /// Создайте служебную функцию для хэширования пароля, поступающего от пользователя. @@ -110,10 +116,16 @@ pwdlib также поддерживает алгоритм хешировани И еще одну — для аутентификации и возврата пользователя. -{* ../../docs_src/security/tutorial004_an_py310.py hl[8,49,56:57,60:61,70:76] *} +{* ../../docs_src/security/tutorial004_an_py310.py hl[8,49,51,58:59,62:63,72:79] *} + +Когда `authenticate_user` вызывается с именем пользователя, которого нет в базе данных, мы все равно запускаем `verify_password` с использованием фиктивного хэша. + +Это гарантирует, что эндпоинт отвечает примерно за одно и то же время вне зависимости от того, существует имя пользователя или нет, предотвращая тайминговые атаки (атака по времени), с помощью которых можно было бы перечислять существующие имена пользователей. /// note | Технические детали + Если проверить новую (фальшивую) базу данных `fake_users_db`, то можно увидеть, как теперь выглядит хэшированный пароль: `"$argon2id$v=19$m=65536,t=3,p=4$wagCPXjifgvUFBzq4hqe3w$CYaIb8sB+wtD+Vu/P4uod1+Qof8h+1g7bbDlBID48Rc"`. + /// ## Работа с JWT токенами { #handle-jwt-tokens } @@ -144,7 +156,7 @@ $ openssl rand -hex 32 Создайте служебную функцию для генерации нового токена доступа. -{* ../../docs_src/security/tutorial004_an_py310.py hl[4,7,13:15,29:31,79:87] *} +{* ../../docs_src/security/tutorial004_an_py310.py hl[4,7,13:15,29:31,82:90] *} ## Обновление зависимостей { #update-the-dependencies } @@ -154,7 +166,7 @@ $ openssl rand -hex 32 Если токен недействителен, то сразу же верните HTTP-ошибку. -{* ../../docs_src/security/tutorial004_an_py310.py hl[90:107] *} +{* ../../docs_src/security/tutorial004_an_py310.py hl[93:110] *} ## Обновление *операции пути* `/token` { #update-the-token-path-operation } @@ -162,7 +174,7 @@ $ openssl rand -hex 32 Создайте реальный токен доступа JWT и верните его -{* ../../docs_src/security/tutorial004_an_py310.py hl[118:133] *} +{* ../../docs_src/security/tutorial004_an_py310.py hl[121:136] *} ### Технические подробности о JWT ключе `sub` { #technical-details-about-the-jwt-subject-sub } @@ -202,7 +214,9 @@ Username: `johndoe` Password: `secret` /// check | Проверка + Обратите внимание, что нигде в коде не используется открытый текст пароля "`secret`", мы используем только его хэшированную версию. + /// @@ -225,7 +239,9 @@ Password: `secret` /// note | Техническая информация + Обратите внимание на HTTP-заголовок `Authorization`, значение которого начинается с `Bearer `. + /// ## Продвинутое использование `scopes` { #advanced-usage-with-scopes } diff --git a/docs/ru/docs/tutorial/security/simple-oauth2.md b/docs/ru/docs/tutorial/security/simple-oauth2.md index 36ff32c8e..4b86a4013 100644 --- a/docs/ru/docs/tutorial/security/simple-oauth2.md +++ b/docs/ru/docs/tutorial/security/simple-oauth2.md @@ -236,7 +236,7 @@ UserInDB( -Если щёлкнуть на значке замка и выйти из системы, а затем попытаться выполнить ту же операцию ещё раз, будет выдана ошибка HTTP 401: +Если щёлкнуть на значке замка и выйти из системы, а затем попробовать выполнить ту же операцию ещё раз, будет выдана ошибка HTTP 401: ```JSON { diff --git a/docs/ru/docs/tutorial/sql-databases.md b/docs/ru/docs/tutorial/sql-databases.md index 1d0346533..ed67739cc 100644 --- a/docs/ru/docs/tutorial/sql-databases.md +++ b/docs/ru/docs/tutorial/sql-databases.md @@ -8,7 +8,7 @@ /// tip | Подсказка -Вы можете использовать любую другую библиотеку для работы с SQL или NoSQL базами данных (иногда их называют "ORMs"), FastAPI ничего не навязывает. 😎 +Вы можете использовать любую другую библиотеку для работы с SQL или NoSQL базами данных (иногда их называют "ORMs"), FastAPI ничего не навязывает. 😎 /// @@ -344,7 +344,7 @@ $ fastapi dev main.py -Если вы перейдёте в UI API `/docs`, вы увидите, что он обновился: теперь при создании героя он не ожидает получить `id` от клиента и т. д. +Если вы перейдёте в UI API `/docs`, вы увидите, что он обновился: теперь при создании героя он не ожидает получить `id` от клиента и т.д.
@@ -354,4 +354,4 @@ $ fastapi dev main.py Вы можете использовать **SQLModel** для взаимодействия с SQL базой данных и упростить код с помощью *моделей данных* и *моделей-таблиц*. -Гораздо больше вы можете узнать в документации **SQLModel**, там есть более подробный мини-туториал по использованию SQLModel с **FastAPI**. 🚀 +Гораздо больше вы можете узнать в документации **SQLModel**, там есть более подробное мини-руководство по использованию SQLModel с **FastAPI**. 🚀 diff --git a/docs/ru/docs/tutorial/static-files.md b/docs/ru/docs/tutorial/static-files.md index f40cfe9b0..3b0cab831 100644 --- a/docs/ru/docs/tutorial/static-files.md +++ b/docs/ru/docs/tutorial/static-files.md @@ -7,7 +7,7 @@ * Импортируйте `StaticFiles`. * "Примонтируйте" экземпляр `StaticFiles()` к определённому пути. -{* ../../docs_src/static_files/tutorial001_py39.py hl[2,6] *} +{* ../../docs_src/static_files/tutorial001_py310.py hl[2,6] *} /// note | Технические детали diff --git a/docs/ru/docs/tutorial/testing.md b/docs/ru/docs/tutorial/testing.md index ab58429c5..6dd2fe579 100644 --- a/docs/ru/docs/tutorial/testing.md +++ b/docs/ru/docs/tutorial/testing.md @@ -30,7 +30,7 @@ $ pip install httpx Напишите простое утверждение с `assert` дабы проверить истинность Python-выражения (это тоже стандарт `pytest`). -{* ../../docs_src/app_testing/tutorial001_py39.py hl[2,12,15:18] *} +{* ../../docs_src/app_testing/tutorial001_py310.py hl[2,12,15:18] *} /// tip | Подсказка @@ -76,7 +76,7 @@ $ pip install httpx В файле `main.py` находится Ваше приложение **FastAPI**: -{* ../../docs_src/app_testing/app_a_py39/main.py *} +{* ../../docs_src/app_testing/app_a_py310/main.py *} ### Файл тестов { #testing-file } @@ -92,7 +92,7 @@ $ pip install httpx Так как оба файла находятся в одной директории, для импорта объекта приложения из файла `main` в файл `test_main` Вы можете использовать относительный импорт: -{* ../../docs_src/app_testing/app_a_py39/test_main.py hl[3] *} +{* ../../docs_src/app_testing/app_a_py310/test_main.py hl[3] *} ...и писать дальше тесты, как и раньше. @@ -119,7 +119,7 @@ $ pip install httpx Ещё есть операция `POST`, и она может вернуть несколько ошибок. -Обе *операции пути* требуют наличия в запросе заголовка `X-Token`. +Обе *операции пути* требуют наличия в запросе HTTP-заголовка `X-Token`. {* ../../docs_src/app_testing/app_b_an_py310/main.py *} @@ -139,7 +139,7 @@ $ pip install httpx * Передаёте *path*-параметры или *query*-параметры, вписав их непосредственно в строку URL. * Передаёте JSON в теле запроса, передав Python-объект (например: `dict`) через именованный параметр `json`. * Если же Вам необходимо отправить *форму с данными* вместо JSON, то используйте параметр `data` вместо `json`. -* Для передачи *заголовков*, передайте объект `dict` через параметр `headers`. +* Для передачи *HTTP-заголовков*, передайте объект `dict` через параметр `headers`. * Для передачи *cookies* также передайте `dict`, но через параметр `cookies`. Для получения дополнительной информации о передаче данных на бэкенд с помощью `httpx` или `TestClient` ознакомьтесь с документацией HTTPX. diff --git a/docs/ru/docs/virtual-environments.md b/docs/ru/docs/virtual-environments.md index 43136298a..f931cc3c8 100644 --- a/docs/ru/docs/virtual-environments.md +++ b/docs/ru/docs/virtual-environments.md @@ -53,7 +53,7 @@ $ cd awesome-project ## Создание виртуального окружения { #create-a-virtual-environment } -Когда вы начинаете работать над Python‑проектом **впервые**, создайте виртуальное окружение **внутри вашего проекта**. +Когда вы начинаете работать над Python‑проектом **впервые**, создайте виртуальное окружение **внутри вашего проекта**. /// tip | Подсказка @@ -166,7 +166,7 @@ $ source .venv/Scripts/activate Каждый раз, когда вы устанавливаете **новый пакет** в это окружение, **активируйте** окружение снова. -Это гарантирует, что если вы используете **программу терминала (CLI)**, установленную этим пакетом, вы будете использовать именно ту, что из вашего виртуального окружения, а не какую‑то глобально установленную, возможно другой версии, чем вам нужна. +Это гарантирует, что если вы используете **программу терминала (CLI)**, установленную этим пакетом, вы будете использовать именно ту, что из вашего виртуального окружения, а не какую‑то глобально установленную, возможно другой версии, чем вам нужна. /// From 6fa573ce0bc16fe445f93db413d20146dd9ff35d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 12 Feb 2026 19:58:08 +0000 Subject: [PATCH 20/20] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [skip ci] --- docs/en/docs/release-notes.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index d8bc3a26f..dfa4eb489 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -11,6 +11,10 @@ hide: * 📝 Update docs for JWT to prevent timing attacks. PR [#14908](https://github.com/fastapi/fastapi/pull/14908) by [@tiangolo](https://github.com/tiangolo). +### Translations + +* 🌐 Update translations for ru (update-outdated). PR [#14909](https://github.com/fastapi/fastapi/pull/14909) by [@YuriiMotov](https://github.com/YuriiMotov). + ## 0.129.0 ### Breaking Changes