fastapi 0.128.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- fastapi/__init__.py +25 -0
- fastapi/__main__.py +3 -0
- fastapi/_compat/__init__.py +41 -0
- fastapi/_compat/shared.py +206 -0
- fastapi/_compat/v2.py +568 -0
- fastapi/applications.py +4669 -0
- fastapi/background.py +60 -0
- fastapi/cli.py +13 -0
- fastapi/concurrency.py +41 -0
- fastapi/datastructures.py +183 -0
- fastapi/dependencies/__init__.py +0 -0
- fastapi/dependencies/models.py +193 -0
- fastapi/dependencies/utils.py +1021 -0
- fastapi/encoders.py +346 -0
- fastapi/exception_handlers.py +34 -0
- fastapi/exceptions.py +246 -0
- fastapi/logger.py +3 -0
- fastapi/middleware/__init__.py +1 -0
- fastapi/middleware/asyncexitstack.py +18 -0
- fastapi/middleware/cors.py +1 -0
- fastapi/middleware/gzip.py +1 -0
- fastapi/middleware/httpsredirect.py +3 -0
- fastapi/middleware/trustedhost.py +3 -0
- fastapi/middleware/wsgi.py +1 -0
- fastapi/openapi/__init__.py +0 -0
- fastapi/openapi/constants.py +3 -0
- fastapi/openapi/docs.py +344 -0
- fastapi/openapi/models.py +438 -0
- fastapi/openapi/utils.py +567 -0
- fastapi/param_functions.py +2369 -0
- fastapi/params.py +755 -0
- fastapi/py.typed +0 -0
- fastapi/requests.py +2 -0
- fastapi/responses.py +48 -0
- fastapi/routing.py +4508 -0
- fastapi/security/__init__.py +15 -0
- fastapi/security/api_key.py +318 -0
- fastapi/security/base.py +6 -0
- fastapi/security/http.py +423 -0
- fastapi/security/oauth2.py +663 -0
- fastapi/security/open_id_connect_url.py +94 -0
- fastapi/security/utils.py +10 -0
- fastapi/staticfiles.py +1 -0
- fastapi/templating.py +1 -0
- fastapi/testclient.py +1 -0
- fastapi/types.py +11 -0
- fastapi/utils.py +164 -0
- fastapi/websockets.py +3 -0
- fastapi-0.128.0.dist-info/METADATA +645 -0
- fastapi-0.128.0.dist-info/RECORD +53 -0
- fastapi-0.128.0.dist-info/WHEEL +4 -0
- fastapi-0.128.0.dist-info/entry_points.txt +5 -0
- fastapi-0.128.0.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
from typing import Annotated, Optional
|
|
2
|
+
|
|
3
|
+
from annotated_doc import Doc
|
|
4
|
+
from fastapi.openapi.models import OpenIdConnect as OpenIdConnectModel
|
|
5
|
+
from fastapi.security.base import SecurityBase
|
|
6
|
+
from starlette.exceptions import HTTPException
|
|
7
|
+
from starlette.requests import Request
|
|
8
|
+
from starlette.status import HTTP_401_UNAUTHORIZED
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class OpenIdConnect(SecurityBase):
|
|
12
|
+
"""
|
|
13
|
+
OpenID Connect authentication class. An instance of it would be used as a
|
|
14
|
+
dependency.
|
|
15
|
+
|
|
16
|
+
**Warning**: this is only a stub to connect the components with OpenAPI in FastAPI,
|
|
17
|
+
but it doesn't implement the full OpenIdConnect scheme, for example, it doesn't use
|
|
18
|
+
the OpenIDConnect URL. You would need to to subclass it and implement it in your
|
|
19
|
+
code.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
def __init__(
|
|
23
|
+
self,
|
|
24
|
+
*,
|
|
25
|
+
openIdConnectUrl: Annotated[
|
|
26
|
+
str,
|
|
27
|
+
Doc(
|
|
28
|
+
"""
|
|
29
|
+
The OpenID Connect URL.
|
|
30
|
+
"""
|
|
31
|
+
),
|
|
32
|
+
],
|
|
33
|
+
scheme_name: Annotated[
|
|
34
|
+
Optional[str],
|
|
35
|
+
Doc(
|
|
36
|
+
"""
|
|
37
|
+
Security scheme name.
|
|
38
|
+
|
|
39
|
+
It will be included in the generated OpenAPI (e.g. visible at `/docs`).
|
|
40
|
+
"""
|
|
41
|
+
),
|
|
42
|
+
] = None,
|
|
43
|
+
description: Annotated[
|
|
44
|
+
Optional[str],
|
|
45
|
+
Doc(
|
|
46
|
+
"""
|
|
47
|
+
Security scheme description.
|
|
48
|
+
|
|
49
|
+
It will be included in the generated OpenAPI (e.g. visible at `/docs`).
|
|
50
|
+
"""
|
|
51
|
+
),
|
|
52
|
+
] = None,
|
|
53
|
+
auto_error: Annotated[
|
|
54
|
+
bool,
|
|
55
|
+
Doc(
|
|
56
|
+
"""
|
|
57
|
+
By default, if no HTTP Authorization header is provided, required for
|
|
58
|
+
OpenID Connect authentication, it will automatically cancel the request
|
|
59
|
+
and send the client an error.
|
|
60
|
+
|
|
61
|
+
If `auto_error` is set to `False`, when the HTTP Authorization header
|
|
62
|
+
is not available, instead of erroring out, the dependency result will
|
|
63
|
+
be `None`.
|
|
64
|
+
|
|
65
|
+
This is useful when you want to have optional authentication.
|
|
66
|
+
|
|
67
|
+
It is also useful when you want to have authentication that can be
|
|
68
|
+
provided in one of multiple optional ways (for example, with OpenID
|
|
69
|
+
Connect or in a cookie).
|
|
70
|
+
"""
|
|
71
|
+
),
|
|
72
|
+
] = True,
|
|
73
|
+
):
|
|
74
|
+
self.model = OpenIdConnectModel(
|
|
75
|
+
openIdConnectUrl=openIdConnectUrl, description=description
|
|
76
|
+
)
|
|
77
|
+
self.scheme_name = scheme_name or self.__class__.__name__
|
|
78
|
+
self.auto_error = auto_error
|
|
79
|
+
|
|
80
|
+
def make_not_authenticated_error(self) -> HTTPException:
|
|
81
|
+
return HTTPException(
|
|
82
|
+
status_code=HTTP_401_UNAUTHORIZED,
|
|
83
|
+
detail="Not authenticated",
|
|
84
|
+
headers={"WWW-Authenticate": "Bearer"},
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
async def __call__(self, request: Request) -> Optional[str]:
|
|
88
|
+
authorization = request.headers.get("Authorization")
|
|
89
|
+
if not authorization:
|
|
90
|
+
if self.auto_error:
|
|
91
|
+
raise self.make_not_authenticated_error()
|
|
92
|
+
else:
|
|
93
|
+
return None
|
|
94
|
+
return authorization
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
from typing import Optional
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def get_authorization_scheme_param(
|
|
5
|
+
authorization_header_value: Optional[str],
|
|
6
|
+
) -> tuple[str, str]:
|
|
7
|
+
if not authorization_header_value:
|
|
8
|
+
return "", ""
|
|
9
|
+
scheme, _, param = authorization_header_value.partition(" ")
|
|
10
|
+
return scheme, param
|
fastapi/staticfiles.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from starlette.staticfiles import StaticFiles as StaticFiles # noqa
|
fastapi/templating.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from starlette.templating import Jinja2Templates as Jinja2Templates # noqa
|
fastapi/testclient.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from starlette.testclient import TestClient as TestClient # noqa
|
fastapi/types.py
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import types
|
|
2
|
+
from enum import Enum
|
|
3
|
+
from typing import Any, Callable, Optional, TypeVar, Union
|
|
4
|
+
|
|
5
|
+
from pydantic import BaseModel
|
|
6
|
+
|
|
7
|
+
DecoratedCallable = TypeVar("DecoratedCallable", bound=Callable[..., Any])
|
|
8
|
+
UnionType = getattr(types, "UnionType", Union)
|
|
9
|
+
ModelNameMap = dict[Union[type[BaseModel], type[Enum]], str]
|
|
10
|
+
IncEx = Union[set[int], set[str], dict[int, Any], dict[str, Any]]
|
|
11
|
+
DependencyCacheKey = tuple[Optional[Callable[..., Any]], tuple[str, ...], str]
|
fastapi/utils.py
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import re
|
|
2
|
+
import warnings
|
|
3
|
+
from collections.abc import MutableMapping
|
|
4
|
+
from typing import (
|
|
5
|
+
TYPE_CHECKING,
|
|
6
|
+
Any,
|
|
7
|
+
Optional,
|
|
8
|
+
Union,
|
|
9
|
+
)
|
|
10
|
+
from weakref import WeakKeyDictionary
|
|
11
|
+
|
|
12
|
+
import fastapi
|
|
13
|
+
from fastapi._compat import (
|
|
14
|
+
BaseConfig,
|
|
15
|
+
ModelField,
|
|
16
|
+
PydanticSchemaGenerationError,
|
|
17
|
+
Undefined,
|
|
18
|
+
UndefinedType,
|
|
19
|
+
Validator,
|
|
20
|
+
annotation_is_pydantic_v1,
|
|
21
|
+
)
|
|
22
|
+
from fastapi.datastructures import DefaultPlaceholder, DefaultType
|
|
23
|
+
from fastapi.exceptions import FastAPIDeprecationWarning, PydanticV1NotSupportedError
|
|
24
|
+
from pydantic import BaseModel
|
|
25
|
+
from pydantic.fields import FieldInfo
|
|
26
|
+
from typing_extensions import Literal
|
|
27
|
+
|
|
28
|
+
from ._compat import v2
|
|
29
|
+
|
|
30
|
+
if TYPE_CHECKING: # pragma: nocover
|
|
31
|
+
from .routing import APIRoute
|
|
32
|
+
|
|
33
|
+
# Cache for `create_cloned_field`
|
|
34
|
+
_CLONED_TYPES_CACHE: MutableMapping[type[BaseModel], type[BaseModel]] = (
|
|
35
|
+
WeakKeyDictionary()
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def is_body_allowed_for_status_code(status_code: Union[int, str, None]) -> bool:
|
|
40
|
+
if status_code is None:
|
|
41
|
+
return True
|
|
42
|
+
# Ref: https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#patterned-fields-1
|
|
43
|
+
if status_code in {
|
|
44
|
+
"default",
|
|
45
|
+
"1XX",
|
|
46
|
+
"2XX",
|
|
47
|
+
"3XX",
|
|
48
|
+
"4XX",
|
|
49
|
+
"5XX",
|
|
50
|
+
}:
|
|
51
|
+
return True
|
|
52
|
+
current_status_code = int(status_code)
|
|
53
|
+
return not (current_status_code < 200 or current_status_code in {204, 205, 304})
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def get_path_param_names(path: str) -> set[str]:
|
|
57
|
+
return set(re.findall("{(.*?)}", path))
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
_invalid_args_message = (
|
|
61
|
+
"Invalid args for response field! Hint: "
|
|
62
|
+
"check that {type_} is a valid Pydantic field type. "
|
|
63
|
+
"If you are using a return type annotation that is not a valid Pydantic "
|
|
64
|
+
"field (e.g. Union[Response, dict, None]) you can disable generating the "
|
|
65
|
+
"response model from the type annotation with the path operation decorator "
|
|
66
|
+
"parameter response_model=None. Read more: "
|
|
67
|
+
"https://fastapi.tiangolo.com/tutorial/response-model/"
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def create_model_field(
|
|
72
|
+
name: str,
|
|
73
|
+
type_: Any,
|
|
74
|
+
class_validators: Optional[dict[str, Validator]] = None,
|
|
75
|
+
default: Optional[Any] = Undefined,
|
|
76
|
+
required: Union[bool, UndefinedType] = Undefined,
|
|
77
|
+
model_config: Union[type[BaseConfig], None] = None,
|
|
78
|
+
field_info: Optional[FieldInfo] = None,
|
|
79
|
+
alias: Optional[str] = None,
|
|
80
|
+
mode: Literal["validation", "serialization"] = "validation",
|
|
81
|
+
version: Literal["1", "auto"] = "auto",
|
|
82
|
+
) -> ModelField:
|
|
83
|
+
if annotation_is_pydantic_v1(type_):
|
|
84
|
+
raise PydanticV1NotSupportedError(
|
|
85
|
+
"pydantic.v1 models are no longer supported by FastAPI."
|
|
86
|
+
f" Please update the response model {type_!r}."
|
|
87
|
+
)
|
|
88
|
+
class_validators = class_validators or {}
|
|
89
|
+
|
|
90
|
+
field_info = field_info or FieldInfo(annotation=type_, default=default, alias=alias)
|
|
91
|
+
kwargs = {"mode": mode, "name": name, "field_info": field_info}
|
|
92
|
+
try:
|
|
93
|
+
return v2.ModelField(**kwargs) # type: ignore[return-value,arg-type]
|
|
94
|
+
except PydanticSchemaGenerationError:
|
|
95
|
+
raise fastapi.exceptions.FastAPIError(
|
|
96
|
+
_invalid_args_message.format(type_=type_)
|
|
97
|
+
) from None
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def create_cloned_field(
|
|
101
|
+
field: ModelField,
|
|
102
|
+
*,
|
|
103
|
+
cloned_types: Optional[MutableMapping[type[BaseModel], type[BaseModel]]] = None,
|
|
104
|
+
) -> ModelField:
|
|
105
|
+
return field
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def generate_operation_id_for_path(
|
|
109
|
+
*, name: str, path: str, method: str
|
|
110
|
+
) -> str: # pragma: nocover
|
|
111
|
+
warnings.warn(
|
|
112
|
+
message="fastapi.utils.generate_operation_id_for_path() was deprecated, "
|
|
113
|
+
"it is not used internally, and will be removed soon",
|
|
114
|
+
category=FastAPIDeprecationWarning,
|
|
115
|
+
stacklevel=2,
|
|
116
|
+
)
|
|
117
|
+
operation_id = f"{name}{path}"
|
|
118
|
+
operation_id = re.sub(r"\W", "_", operation_id)
|
|
119
|
+
operation_id = f"{operation_id}_{method.lower()}"
|
|
120
|
+
return operation_id
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def generate_unique_id(route: "APIRoute") -> str:
|
|
124
|
+
operation_id = f"{route.name}{route.path_format}"
|
|
125
|
+
operation_id = re.sub(r"\W", "_", operation_id)
|
|
126
|
+
assert route.methods
|
|
127
|
+
operation_id = f"{operation_id}_{list(route.methods)[0].lower()}"
|
|
128
|
+
return operation_id
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def deep_dict_update(main_dict: dict[Any, Any], update_dict: dict[Any, Any]) -> None:
|
|
132
|
+
for key, value in update_dict.items():
|
|
133
|
+
if (
|
|
134
|
+
key in main_dict
|
|
135
|
+
and isinstance(main_dict[key], dict)
|
|
136
|
+
and isinstance(value, dict)
|
|
137
|
+
):
|
|
138
|
+
deep_dict_update(main_dict[key], value)
|
|
139
|
+
elif (
|
|
140
|
+
key in main_dict
|
|
141
|
+
and isinstance(main_dict[key], list)
|
|
142
|
+
and isinstance(update_dict[key], list)
|
|
143
|
+
):
|
|
144
|
+
main_dict[key] = main_dict[key] + update_dict[key]
|
|
145
|
+
else:
|
|
146
|
+
main_dict[key] = value
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
def get_value_or_default(
|
|
150
|
+
first_item: Union[DefaultPlaceholder, DefaultType],
|
|
151
|
+
*extra_items: Union[DefaultPlaceholder, DefaultType],
|
|
152
|
+
) -> Union[DefaultPlaceholder, DefaultType]:
|
|
153
|
+
"""
|
|
154
|
+
Pass items or `DefaultPlaceholder`s by descending priority.
|
|
155
|
+
|
|
156
|
+
The first one to _not_ be a `DefaultPlaceholder` will be returned.
|
|
157
|
+
|
|
158
|
+
Otherwise, the first item (a `DefaultPlaceholder`) will be returned.
|
|
159
|
+
"""
|
|
160
|
+
items = (first_item,) + extra_items
|
|
161
|
+
for item in items:
|
|
162
|
+
if not isinstance(item, DefaultPlaceholder):
|
|
163
|
+
return item
|
|
164
|
+
return first_item
|
fastapi/websockets.py
ADDED