Compare commits
25 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
36c2667768 | ||
|
|
d8185efb6e | ||
|
|
fc51d7e3c7 | ||
|
|
b98c65cb36 | ||
|
|
ba99214417 | ||
|
|
6f5aa81c07 | ||
|
|
73dcc40f09 | ||
|
|
33493ce694 | ||
|
|
01e570c56d | ||
|
|
ca03379b65 | ||
|
|
8cf2fa0fe4 | ||
|
|
99a2ec981b | ||
|
|
6fb951bae2 | ||
|
|
13cef7a21a | ||
|
|
e9ce31e96b | ||
|
|
1560879a84 | ||
|
|
ac93277d3b | ||
|
|
71d51a9953 | ||
|
|
81bab77617 | ||
|
|
781984b226 | ||
|
|
480620372a | ||
|
|
b04d07c933 | ||
|
|
46335068d2 | ||
|
|
4f89886b00 | ||
|
|
1c25e2d8dc |
4
.github/workflows/build-docs.yml
vendored
@@ -28,6 +28,8 @@ jobs:
|
||||
- docs/**
|
||||
- docs_src/**
|
||||
- requirements-docs.txt
|
||||
- .github/workflows/build-docs.yml
|
||||
- .github/workflows/deploy-docs.yml
|
||||
langs:
|
||||
needs:
|
||||
- changes
|
||||
@@ -55,6 +57,8 @@ jobs:
|
||||
pip install git+https://${{ secrets.FASTAPI_MKDOCS_MATERIAL_INSIDERS }}@github.com/squidfunk/mkdocs-material-insiders.git
|
||||
pip install git+https://${{ secrets.FASTAPI_MKDOCS_MATERIAL_INSIDERS }}@github.com/pawamoy-insiders/griffe-typing-deprecated.git
|
||||
pip install git+https://${{ secrets.FASTAPI_MKDOCS_MATERIAL_INSIDERS }}@github.com/pawamoy-insiders/mkdocstrings-python.git
|
||||
- name: Verify README
|
||||
run: python ./scripts/docs.py verify-readme
|
||||
- name: Export Language Codes
|
||||
id: show-langs
|
||||
run: |
|
||||
|
||||
7
.github/workflows/latest-changes.yml
vendored
@@ -34,9 +34,12 @@ jobs:
|
||||
if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.debug_enabled == 'true' }}
|
||||
with:
|
||||
limit-access-to-actor: true
|
||||
- uses: docker://tiangolo/latest-changes:0.0.3
|
||||
- uses: docker://tiangolo/latest-changes:0.2.0
|
||||
# - uses: tiangolo/latest-changes@main
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
latest_changes_file: docs/en/docs/release-notes.md
|
||||
latest_changes_header: '## Latest Changes\n\n'
|
||||
latest_changes_header: '## Latest Changes'
|
||||
end_regex: '^## '
|
||||
debug_logs: true
|
||||
label_header_prefix: '### '
|
||||
|
||||
4
.github/workflows/test.yml
vendored
@@ -29,7 +29,7 @@ jobs:
|
||||
id: cache
|
||||
with:
|
||||
path: ${{ env.pythonLocation }}
|
||||
key: ${{ runner.os }}-python-${{ env.pythonLocation }}-pydantic-v2-${{ hashFiles('pyproject.toml', 'requirements-tests.txt', 'requirements-docs-tests.txt') }}-test-v06
|
||||
key: ${{ runner.os }}-python-${{ env.pythonLocation }}-pydantic-v2-${{ hashFiles('pyproject.toml', 'requirements-tests.txt', 'requirements-docs-tests.txt') }}-test-v07
|
||||
- name: Install Dependencies
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
run: pip install -r requirements-tests.txt
|
||||
@@ -62,7 +62,7 @@ jobs:
|
||||
id: cache
|
||||
with:
|
||||
path: ${{ env.pythonLocation }}
|
||||
key: ${{ runner.os }}-python-${{ env.pythonLocation }}-${{ matrix.pydantic-version }}-${{ hashFiles('pyproject.toml', 'requirements-tests.txt', 'requirements-docs-tests.txt') }}-test-v06
|
||||
key: ${{ runner.os }}-python-${{ env.pythonLocation }}-${{ matrix.pydantic-version }}-${{ hashFiles('pyproject.toml', 'requirements-tests.txt', 'requirements-docs-tests.txt') }}-test-v07
|
||||
- name: Install Dependencies
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
run: pip install -r requirements-tests.txt
|
||||
|
||||
@@ -48,9 +48,11 @@ The key features are:
|
||||
|
||||
<a href="https://cryptapi.io/" target="_blank" title="CryptAPI: Your easy to use, secure and privacy oriented payment gateway."><img src="https://fastapi.tiangolo.com/img/sponsors/cryptapi.svg"></a>
|
||||
<a href="https://platform.sh/try-it-now/?utm_source=fastapi-signup&utm_medium=banner&utm_campaign=FastAPI-signup-June-2023" target="_blank" title="Build, run and scale your apps on a modern, reliable, and secure PaaS."><img src="https://fastapi.tiangolo.com/img/sponsors/platform-sh.png"></a>
|
||||
<a href="https://www.buildwithfern.com/?utm_source=tiangolo&utm_medium=website&utm_campaign=main-badge" target="_blank" title="Fern | SDKs and API docs"><img src="https://fastapi.tiangolo.com/img/sponsors/fern.svg"></a>
|
||||
<a href="https://www.porter.run" target="_blank" title="Deploy FastAPI on AWS with a few clicks"><img src="https://fastapi.tiangolo.com/img/sponsors/porter.png"></a>
|
||||
<a href="https://bump.sh/fastapi?utm_source=fastapi&utm_medium=referral&utm_campaign=sponsor" target="_blank" title="Automate FastAPI documentation generation with Bump.sh"><img src="https://fastapi.tiangolo.com/img/sponsors/bump-sh.svg"></a>
|
||||
<a href="https://reflex.dev" target="_blank" title="Reflex"><img src="https://fastapi.tiangolo.com/img/sponsors/reflex.png"></a>
|
||||
<a href="https://github.com/scalar/scalar/?utm_source=fastapi&utm_medium=website&utm_campaign=main-badge" target="_blank" title="Scalar: Beautiful Open-Source API References from Swagger/OpenAPI files"><img src="https://fastapi.tiangolo.com/img/sponsors/scalar.svg"></a>
|
||||
<a href="https://www.propelauth.com/?utm_source=fastapi&utm_campaign=1223&utm_medium=mainbadge" target="_blank" title="Auth, user management and more for your B2B product"><img src="https://fastapi.tiangolo.com/img/sponsors/propelauth.png"></a>
|
||||
<a href="https://www.deta.sh/?ref=fastapi" target="_blank" title="The launchpad for all your (team's) ideas"><img src="https://fastapi.tiangolo.com/img/sponsors/deta.svg"></a>
|
||||
<a href="https://training.talkpython.fm/fastapi-courses" target="_blank" title="FastAPI video courses on demand from people you trust"><img src="https://fastapi.tiangolo.com/img/sponsors/talkpython.png"></a>
|
||||
<a href="https://testdriven.io/courses/tdd-fastapi/" target="_blank" title="Learn to build high-quality web apps with best practices"><img src="https://fastapi.tiangolo.com/img/sponsors/testdriven.svg"></a>
|
||||
@@ -59,6 +61,7 @@ The key features are:
|
||||
<a href="https://databento.com/" target="_blank" title="Pay as you go for market data"><img src="https://fastapi.tiangolo.com/img/sponsors/databento.svg"></a>
|
||||
<a href="https://speakeasyapi.dev?utm_source=fastapi+repo&utm_medium=github+sponsorship" target="_blank" title="SDKs for your API | Speakeasy"><img src="https://fastapi.tiangolo.com/img/sponsors/speakeasy.png"></a>
|
||||
<a href="https://www.svix.com/" target="_blank" title="Svix - Webhooks as a service"><img src="https://fastapi.tiangolo.com/img/sponsors/svix.svg"></a>
|
||||
<a href="https://www.codacy.com/?utm_source=github&utm_medium=sponsors&utm_id=pioneers" target="_blank" title="Take code reviews from hours to minutes"><img src="https://fastapi.tiangolo.com/img/sponsors/codacy.png"></a>
|
||||
|
||||
<!-- /sponsors -->
|
||||
|
||||
|
||||
@@ -5,15 +5,21 @@ gold:
|
||||
- url: https://platform.sh/try-it-now/?utm_source=fastapi-signup&utm_medium=banner&utm_campaign=FastAPI-signup-June-2023
|
||||
title: "Build, run and scale your apps on a modern, reliable, and secure PaaS."
|
||||
img: https://fastapi.tiangolo.com/img/sponsors/platform-sh.png
|
||||
- url: https://www.buildwithfern.com/?utm_source=tiangolo&utm_medium=website&utm_campaign=main-badge
|
||||
title: Fern | SDKs and API docs
|
||||
img: https://fastapi.tiangolo.com/img/sponsors/fern.svg
|
||||
- url: https://www.porter.run
|
||||
title: Deploy FastAPI on AWS with a few clicks
|
||||
img: https://fastapi.tiangolo.com/img/sponsors/porter.png
|
||||
- url: https://bump.sh/fastapi?utm_source=fastapi&utm_medium=referral&utm_campaign=sponsor
|
||||
title: Automate FastAPI documentation generation with Bump.sh
|
||||
img: https://fastapi.tiangolo.com/img/sponsors/bump-sh.svg
|
||||
- url: https://reflex.dev
|
||||
title: Reflex
|
||||
img: https://fastapi.tiangolo.com/img/sponsors/reflex.png
|
||||
- url: https://github.com/scalar/scalar/?utm_source=fastapi&utm_medium=website&utm_campaign=main-badge
|
||||
title: "Scalar: Beautiful Open-Source API References from Swagger/OpenAPI files"
|
||||
img: https://fastapi.tiangolo.com/img/sponsors/scalar.svg
|
||||
- url: https://www.propelauth.com/?utm_source=fastapi&utm_campaign=1223&utm_medium=mainbadge
|
||||
title: Auth, user management and more for your B2B product
|
||||
img: https://fastapi.tiangolo.com/img/sponsors/propelauth.png
|
||||
silver:
|
||||
- url: https://www.deta.sh/?ref=fastapi
|
||||
title: The launchpad for all your (team's) ideas
|
||||
@@ -39,6 +45,9 @@ silver:
|
||||
- url: https://www.svix.com/
|
||||
title: Svix - Webhooks as a service
|
||||
img: https://fastapi.tiangolo.com/img/sponsors/svix.svg
|
||||
- url: https://www.codacy.com/?utm_source=github&utm_medium=sponsors&utm_id=pioneers
|
||||
title: Take code reviews from hours to minutes
|
||||
img: https://fastapi.tiangolo.com/img/sponsors/codacy.png
|
||||
bronze:
|
||||
- url: https://www.exoflare.com/open-source/?utm_source=FastAPI&utm_campaign=open_source
|
||||
title: Biosecurity risk assessments made easy.
|
||||
|
||||
@@ -21,3 +21,5 @@ logins:
|
||||
- fern-api
|
||||
- ndimares
|
||||
- svixhq
|
||||
- Alek99
|
||||
- codacy
|
||||
|
||||
@@ -20,10 +20,9 @@ Some of them also ✨ [**sponsor FastAPI**](../help-fastapi.md#sponsor-the-autho
|
||||
|
||||
And it shows their true commitment to FastAPI and its **community** (you), as they not only want to provide you a **good service** but also want to make sure you have a **good and healthy framework**, FastAPI. 🙇
|
||||
|
||||
You might want to try their services and follow their guides:
|
||||
For example, you might want to try <a href="https://speakeasyapi.dev/?utm_source=fastapi+repo&utm_medium=github+sponsorship" class="external-link" target="_blank">Speakeasy</a>.
|
||||
|
||||
* <a href="https://www.buildwithfern.com/?utm_source=tiangolo&utm_medium=website&utm_campaign=docs-generate-clients" class="external-link" target="_blank">Fern</a>
|
||||
* <a href="https://speakeasyapi.dev/?utm_source=fastapi+repo&utm_medium=github+sponsorship" class="external-link" target="_blank">Speakeasy</a>
|
||||
There are also several other companies offering similar services that you can search and find online. 🤓
|
||||
|
||||
## Generate a TypeScript Frontend Client
|
||||
|
||||
@@ -88,7 +87,7 @@ It could look like this:
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"generate-client": "openapi --input http://localhost:8000/openapi.json --output ./src/client --client axios"
|
||||
"generate-client": "openapi --input http://localhost:8000/openapi.json --output ./src/client --client axios --useOptions --useUnionTypes"
|
||||
},
|
||||
"author": "",
|
||||
"license": "",
|
||||
@@ -107,7 +106,7 @@ After having that NPM `generate-client` script there, you can run it with:
|
||||
$ npm run generate-client
|
||||
|
||||
frontend-app@1.0.0 generate-client /home/user/code/frontend-app
|
||||
> openapi --input http://localhost:8000/openapi.json --output ./src/client --client axios
|
||||
> openapi --input http://localhost:8000/openapi.json --output ./src/client --client axios --useOptions --useUnionTypes
|
||||
```
|
||||
|
||||
</div>
|
||||
@@ -247,7 +246,7 @@ Now as the end result is in a file `openapi.json`, you would modify the `package
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"generate-client": "openapi --input ./openapi.json --output ./src/client --client axios"
|
||||
"generate-client": "openapi --input ./openapi.json --output ./src/client --client axios --useOptions --useUnionTypes"
|
||||
},
|
||||
"author": "",
|
||||
"license": "",
|
||||
|
||||
@@ -119,8 +119,6 @@ That's why when talking about version 2.0 it's common to say "Swagger", and for
|
||||
|
||||
These two were chosen for being fairly popular and stable, but doing a quick search, you could find dozens of additional alternative user interfaces for OpenAPI (that you can use with **FastAPI**).
|
||||
|
||||
For example, you could try <a href="https://www.buildwithfern.com/?utm_source=tiangolo&utm_medium=website&utm_campaign=docs-alternatives" class="external-link" target="_blank">Fern</a> which is also a FastAPI sponsor. 😎🎉
|
||||
|
||||
### Flask REST frameworks
|
||||
|
||||
There are several Flask REST frameworks, but after investing the time and work into investigating them, I found that many are discontinued or abandoned, with several standing issues that made them unfit.
|
||||
|
||||
BIN
docs/en/docs/img/sponsors/codacy.png
Normal file
|
After Width: | Height: | Size: 30 KiB |
BIN
docs/en/docs/img/sponsors/propelauth-banner.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
docs/en/docs/img/sponsors/propelauth.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
docs/en/docs/img/sponsors/reflex-banner.png
Normal file
|
After Width: | Height: | Size: 8.0 KiB |
BIN
docs/en/docs/img/sponsors/reflex.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
1
docs/en/docs/img/sponsors/scalar-banner.svg
Normal file
|
After Width: | Height: | Size: 6.4 KiB |
1
docs/en/docs/img/sponsors/scalar.svg
Normal file
|
After Width: | Height: | Size: 36 KiB |
@@ -7,13 +7,37 @@ hide:
|
||||
|
||||
## Latest Changes
|
||||
|
||||
## 0.105.0
|
||||
|
||||
### Features
|
||||
|
||||
* ✨ Add support for multiple Annotated annotations, e.g. `Annotated[str, Field(), Query()]`. PR [#10773](https://github.com/tiangolo/fastapi/pull/10773) by [@tiangolo](https://github.com/tiangolo).
|
||||
|
||||
### Refactors
|
||||
|
||||
* 🔥 Remove unused NoneType. PR [#10774](https://github.com/tiangolo/fastapi/pull/10774) by [@tiangolo](https://github.com/tiangolo).
|
||||
|
||||
### Docs
|
||||
|
||||
* 📝 Tweak default suggested configs for generating clients. PR [#10736](https://github.com/tiangolo/fastapi/pull/10736) by [@tiangolo](https://github.com/tiangolo).
|
||||
|
||||
### Internal
|
||||
|
||||
* 🔧 Update sponsors, add Scalar. PR [#10728](https://github.com/tiangolo/fastapi/pull/10728) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 🔧 Update sponsors, add PropelAuth. PR [#10760](https://github.com/tiangolo/fastapi/pull/10760) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 👷 Update build docs, verify README on CI. PR [#10750](https://github.com/tiangolo/fastapi/pull/10750) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 🔧 Update sponsors, remove Fern. PR [#10729](https://github.com/tiangolo/fastapi/pull/10729) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 🔧 Update sponsors, add Codacy. PR [#10677](https://github.com/tiangolo/fastapi/pull/10677) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 🔧 Update sponsors, add Reflex. PR [#10676](https://github.com/tiangolo/fastapi/pull/10676) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 📝 Update release notes, move and check latest-changes. PR [#10588](https://github.com/tiangolo/fastapi/pull/10588) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 👷 Upgrade latest-changes GitHub Action. PR [#10587](https://github.com/tiangolo/fastapi/pull/10587) by [@tiangolo](https://github.com/tiangolo).
|
||||
|
||||
## 0.104.1
|
||||
|
||||
### Fixes
|
||||
|
||||
* 📌 Pin Swagger UI version to 5.9.0 temporarily to handle a bug crashing it in 5.9.1. PR [#10529](https://github.com/tiangolo/fastapi/pull/10529) by [@alejandraklachquin](https://github.com/alejandraklachquin).
|
||||
* This is not really a bug in FastAPI but in Swagger UI, nevertheless pinning the version will work while a soulution is found on the [Swagger UI side](https://github.com/swagger-api/swagger-ui/issues/9337).
|
||||
* This is not really a bug in FastAPI but in Swagger UI, nevertheless pinning the version will work while a solution is found on the [Swagger UI side](https://github.com/swagger-api/swagger-ui/issues/9337).
|
||||
|
||||
### Docs
|
||||
|
||||
|
||||
@@ -34,12 +34,6 @@
|
||||
<img class="sponsor-image" src="/img/sponsors/platform-sh-banner.png" />
|
||||
</a>
|
||||
</div>
|
||||
<div class="item">
|
||||
<a title="Fern | SDKs and API docs" style="display: block; position: relative;" href="https://www.buildwithfern.com/?utm_source=tiangolo&utm_medium=website&utm_campaign=top-banner" target="_blank">
|
||||
<span class="sponsor-badge">sponsor</span>
|
||||
<img class="sponsor-image" src="/img/sponsors/fern-banner.svg" />
|
||||
</a>
|
||||
</div>
|
||||
<div class="item">
|
||||
<a title="Deploy FastAPI on AWS with a few clicks" style="display: block; position: relative;" href="https://www.porter.run" target="_blank">
|
||||
<span class="sponsor-badge">sponsor</span>
|
||||
@@ -52,6 +46,24 @@
|
||||
<img class="sponsor-image" src="/img/sponsors/bump-sh-banner.svg" />
|
||||
</a>
|
||||
</div>
|
||||
<div class="item">
|
||||
<a title="Reflex" style="display: block; position: relative;" href="https://reflex.dev" target="_blank">
|
||||
<span class="sponsor-badge">sponsor</span>
|
||||
<img class="sponsor-image" src="/img/sponsors/reflex-banner.png" />
|
||||
</a>
|
||||
</div>
|
||||
<div class="item">
|
||||
<a title="Scalar: Beautiful Open-Source API References from Swagger/OpenAPI files" style="display: block; position: relative;" href="https://github.com/scalar/scalar/?utm_source=fastapi&utm_medium=website&utm_campaign=top-banner" target="_blank">
|
||||
<span class="sponsor-badge">sponsor</span>
|
||||
<img class="sponsor-image" src="/img/sponsors/scalar-banner.svg" />
|
||||
</a>
|
||||
</div>
|
||||
<div class="item">
|
||||
<a title="Auth, user management and more for your B2B product" style="display: block; position: relative;" href="https://www.propelauth.com/?utm_source=fastapi&utm_campaign=1223&utm_medium=topbanner" target="_blank">
|
||||
<span class="sponsor-badge">sponsor</span>
|
||||
<img class="sponsor-image" src="/img/sponsors/propelauth-banner.png" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"""FastAPI framework, high performance, easy to learn, fast to code, ready for production"""
|
||||
|
||||
__version__ = "0.104.1"
|
||||
__version__ = "0.105.0"
|
||||
|
||||
from starlette import status as status
|
||||
|
||||
|
||||
@@ -249,7 +249,12 @@ if PYDANTIC_V2:
|
||||
return is_bytes_sequence_annotation(field.type_)
|
||||
|
||||
def copy_field_info(*, field_info: FieldInfo, annotation: Any) -> FieldInfo:
|
||||
return type(field_info).from_annotation(annotation)
|
||||
cls = type(field_info)
|
||||
merged_field_info = cls.from_annotation(annotation)
|
||||
new_field_info = copy(field_info)
|
||||
new_field_info.metadata = merged_field_info.metadata
|
||||
new_field_info.annotation = merged_field_info.annotation
|
||||
return new_field_info
|
||||
|
||||
def serialize_sequence_value(*, field: ModelField, value: Any) -> Sequence[Any]:
|
||||
origin_type = (
|
||||
|
||||
@@ -325,10 +325,11 @@ def analyze_param(
|
||||
field_info = None
|
||||
depends = None
|
||||
type_annotation: Any = Any
|
||||
if (
|
||||
annotation is not inspect.Signature.empty
|
||||
and get_origin(annotation) is Annotated
|
||||
):
|
||||
use_annotation: Any = Any
|
||||
if annotation is not inspect.Signature.empty:
|
||||
use_annotation = annotation
|
||||
type_annotation = annotation
|
||||
if get_origin(use_annotation) is Annotated:
|
||||
annotated_args = get_args(annotation)
|
||||
type_annotation = annotated_args[0]
|
||||
fastapi_annotations = [
|
||||
@@ -336,14 +337,21 @@ def analyze_param(
|
||||
for arg in annotated_args[1:]
|
||||
if isinstance(arg, (FieldInfo, params.Depends))
|
||||
]
|
||||
assert (
|
||||
len(fastapi_annotations) <= 1
|
||||
), f"Cannot specify multiple `Annotated` FastAPI arguments for {param_name!r}"
|
||||
fastapi_annotation = next(iter(fastapi_annotations), None)
|
||||
fastapi_specific_annotations = [
|
||||
arg
|
||||
for arg in fastapi_annotations
|
||||
if isinstance(arg, (params.Param, params.Body, params.Depends))
|
||||
]
|
||||
if fastapi_specific_annotations:
|
||||
fastapi_annotation: Union[
|
||||
FieldInfo, params.Depends, None
|
||||
] = fastapi_specific_annotations[-1]
|
||||
else:
|
||||
fastapi_annotation = None
|
||||
if isinstance(fastapi_annotation, FieldInfo):
|
||||
# Copy `field_info` because we mutate `field_info.default` below.
|
||||
field_info = copy_field_info(
|
||||
field_info=fastapi_annotation, annotation=annotation
|
||||
field_info=fastapi_annotation, annotation=use_annotation
|
||||
)
|
||||
assert field_info.default is Undefined or field_info.default is Required, (
|
||||
f"`{field_info.__class__.__name__}` default value cannot be set in"
|
||||
@@ -356,8 +364,6 @@ def analyze_param(
|
||||
field_info.default = Required
|
||||
elif isinstance(fastapi_annotation, params.Depends):
|
||||
depends = fastapi_annotation
|
||||
elif annotation is not inspect.Signature.empty:
|
||||
type_annotation = annotation
|
||||
|
||||
if isinstance(value, params.Depends):
|
||||
assert depends is None, (
|
||||
@@ -402,15 +408,15 @@ def analyze_param(
|
||||
# We might check here that `default_value is Required`, but the fact is that the same
|
||||
# parameter might sometimes be a path parameter and sometimes not. See
|
||||
# `tests/test_infer_param_optionality.py` for an example.
|
||||
field_info = params.Path(annotation=type_annotation)
|
||||
field_info = params.Path(annotation=use_annotation)
|
||||
elif is_uploadfile_or_nonable_uploadfile_annotation(
|
||||
type_annotation
|
||||
) or is_uploadfile_sequence_annotation(type_annotation):
|
||||
field_info = params.File(annotation=type_annotation, default=default_value)
|
||||
field_info = params.File(annotation=use_annotation, default=default_value)
|
||||
elif not field_annotation_is_scalar(annotation=type_annotation):
|
||||
field_info = params.Body(annotation=type_annotation, default=default_value)
|
||||
field_info = params.Body(annotation=use_annotation, default=default_value)
|
||||
else:
|
||||
field_info = params.Query(annotation=type_annotation, default=default_value)
|
||||
field_info = params.Query(annotation=use_annotation, default=default_value)
|
||||
|
||||
field = None
|
||||
if field_info is not None:
|
||||
@@ -424,8 +430,8 @@ def analyze_param(
|
||||
and getattr(field_info, "in_", None) is None
|
||||
):
|
||||
field_info.in_ = params.ParamTypes.query
|
||||
use_annotation = get_annotation_from_field_info(
|
||||
type_annotation,
|
||||
use_annotation_from_field_info = get_annotation_from_field_info(
|
||||
use_annotation,
|
||||
field_info,
|
||||
param_name,
|
||||
)
|
||||
@@ -436,7 +442,7 @@ def analyze_param(
|
||||
field_info.alias = alias
|
||||
field = create_response_field(
|
||||
name=param_name,
|
||||
type_=use_annotation,
|
||||
type_=use_annotation_from_field_info,
|
||||
default=field_info.default,
|
||||
alias=alias,
|
||||
required=field_info.default in (Required, Undefined),
|
||||
@@ -466,16 +472,17 @@ def is_body_param(*, param_field: ModelField, is_path_param: bool) -> bool:
|
||||
|
||||
|
||||
def add_param_to_fields(*, field: ModelField, dependant: Dependant) -> None:
|
||||
field_info = cast(params.Param, field.field_info)
|
||||
if field_info.in_ == params.ParamTypes.path:
|
||||
field_info = field.field_info
|
||||
field_info_in = getattr(field_info, "in_", None)
|
||||
if field_info_in == params.ParamTypes.path:
|
||||
dependant.path_params.append(field)
|
||||
elif field_info.in_ == params.ParamTypes.query:
|
||||
elif field_info_in == params.ParamTypes.query:
|
||||
dependant.query_params.append(field)
|
||||
elif field_info.in_ == params.ParamTypes.header:
|
||||
elif field_info_in == params.ParamTypes.header:
|
||||
dependant.header_params.append(field)
|
||||
else:
|
||||
assert (
|
||||
field_info.in_ == params.ParamTypes.cookie
|
||||
field_info_in == params.ParamTypes.cookie
|
||||
), f"non-body parameters must be in path, query, header or cookie: {field.name}"
|
||||
dependant.cookie_params.append(field)
|
||||
|
||||
|
||||
@@ -6,6 +6,5 @@ from pydantic import BaseModel
|
||||
|
||||
DecoratedCallable = TypeVar("DecoratedCallable", bound=Callable[..., Any])
|
||||
UnionType = getattr(types, "UnionType", Union)
|
||||
NoneType = getattr(types, "UnionType", None)
|
||||
ModelNameMap = Dict[Union[Type[BaseModel], Type[Enum]], str]
|
||||
IncEx = Union[Set[int], Set[str], Dict[int, Any], Dict[str, Any]]
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import pytest
|
||||
from fastapi import Depends, FastAPI, Path
|
||||
from fastapi.param_functions import Query
|
||||
from fastapi.testclient import TestClient
|
||||
from fastapi.utils import PYDANTIC_V2
|
||||
from typing_extensions import Annotated
|
||||
|
||||
app = FastAPI()
|
||||
@@ -28,18 +30,13 @@ def test_no_annotated_defaults():
|
||||
pass # pragma: nocover
|
||||
|
||||
|
||||
def test_no_multiple_annotations():
|
||||
def test_multiple_annotations():
|
||||
async def dep():
|
||||
pass # pragma: nocover
|
||||
|
||||
with pytest.raises(
|
||||
AssertionError,
|
||||
match="Cannot specify multiple `Annotated` FastAPI arguments for 'foo'",
|
||||
):
|
||||
|
||||
@app.get("/")
|
||||
async def get(foo: Annotated[int, Query(min_length=1), Query()]):
|
||||
pass # pragma: nocover
|
||||
@app.get("/multi-query")
|
||||
async def get(foo: Annotated[int, Query(gt=2), Query(lt=10)]):
|
||||
return foo
|
||||
|
||||
with pytest.raises(
|
||||
AssertionError,
|
||||
@@ -64,3 +61,15 @@ def test_no_multiple_annotations():
|
||||
@app.get("/")
|
||||
async def get3(foo: Annotated[int, Query(min_length=1)] = Depends(dep)):
|
||||
pass # pragma: nocover
|
||||
|
||||
client = TestClient(app)
|
||||
response = client.get("/multi-query", params={"foo": "5"})
|
||||
assert response.status_code == 200
|
||||
assert response.json() == 5
|
||||
|
||||
response = client.get("/multi-query", params={"foo": "123"})
|
||||
assert response.status_code == 422
|
||||
|
||||
if PYDANTIC_V2:
|
||||
response = client.get("/multi-query", params={"foo": "1"})
|
||||
assert response.status_code == 422
|
||||
|
||||
@@ -57,7 +57,7 @@ foo_is_short = {
|
||||
{
|
||||
"ctx": {"min_length": 1},
|
||||
"loc": ["query", "foo"],
|
||||
"msg": "String should have at least 1 characters",
|
||||
"msg": "String should have at least 1 character",
|
||||
"type": "string_too_short",
|
||||
"input": "",
|
||||
"url": match_pydantic_error_url("string_too_short"),
|
||||
|
||||