prefect-client 2.20.4__py3-none-any.whl → 3.0.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.
Files changed (288) hide show
  1. prefect/__init__.py +74 -110
  2. prefect/_internal/compatibility/deprecated.py +6 -115
  3. prefect/_internal/compatibility/experimental.py +4 -79
  4. prefect/_internal/compatibility/migration.py +166 -0
  5. prefect/_internal/concurrency/__init__.py +2 -2
  6. prefect/_internal/concurrency/api.py +1 -35
  7. prefect/_internal/concurrency/calls.py +0 -6
  8. prefect/_internal/concurrency/cancellation.py +0 -3
  9. prefect/_internal/concurrency/event_loop.py +0 -20
  10. prefect/_internal/concurrency/inspection.py +3 -3
  11. prefect/_internal/concurrency/primitives.py +1 -0
  12. prefect/_internal/concurrency/services.py +23 -0
  13. prefect/_internal/concurrency/threads.py +35 -0
  14. prefect/_internal/concurrency/waiters.py +0 -28
  15. prefect/_internal/integrations.py +7 -0
  16. prefect/_internal/pydantic/__init__.py +0 -45
  17. prefect/_internal/pydantic/annotations/pendulum.py +2 -2
  18. prefect/_internal/pydantic/v1_schema.py +21 -22
  19. prefect/_internal/pydantic/v2_schema.py +0 -2
  20. prefect/_internal/pydantic/v2_validated_func.py +18 -23
  21. prefect/_internal/pytz.py +1 -1
  22. prefect/_internal/retries.py +61 -0
  23. prefect/_internal/schemas/bases.py +45 -177
  24. prefect/_internal/schemas/fields.py +1 -43
  25. prefect/_internal/schemas/validators.py +47 -233
  26. prefect/agent.py +3 -695
  27. prefect/artifacts.py +173 -14
  28. prefect/automations.py +39 -4
  29. prefect/blocks/abstract.py +1 -1
  30. prefect/blocks/core.py +405 -153
  31. prefect/blocks/fields.py +2 -57
  32. prefect/blocks/notifications.py +43 -28
  33. prefect/blocks/redis.py +168 -0
  34. prefect/blocks/system.py +67 -20
  35. prefect/blocks/webhook.py +2 -9
  36. prefect/cache_policies.py +239 -0
  37. prefect/client/__init__.py +4 -0
  38. prefect/client/base.py +33 -27
  39. prefect/client/cloud.py +65 -20
  40. prefect/client/collections.py +1 -1
  41. prefect/client/orchestration.py +650 -442
  42. prefect/client/schemas/actions.py +115 -100
  43. prefect/client/schemas/filters.py +46 -52
  44. prefect/client/schemas/objects.py +228 -178
  45. prefect/client/schemas/responses.py +18 -36
  46. prefect/client/schemas/schedules.py +55 -36
  47. prefect/client/schemas/sorting.py +2 -0
  48. prefect/client/subscriptions.py +8 -7
  49. prefect/client/types/flexible_schedule_list.py +11 -0
  50. prefect/client/utilities.py +9 -6
  51. prefect/concurrency/asyncio.py +60 -11
  52. prefect/concurrency/context.py +24 -0
  53. prefect/concurrency/events.py +2 -2
  54. prefect/concurrency/services.py +46 -16
  55. prefect/concurrency/sync.py +51 -7
  56. prefect/concurrency/v1/asyncio.py +143 -0
  57. prefect/concurrency/v1/context.py +27 -0
  58. prefect/concurrency/v1/events.py +61 -0
  59. prefect/concurrency/v1/services.py +116 -0
  60. prefect/concurrency/v1/sync.py +92 -0
  61. prefect/context.py +246 -149
  62. prefect/deployments/__init__.py +33 -18
  63. prefect/deployments/base.py +10 -15
  64. prefect/deployments/deployments.py +2 -1048
  65. prefect/deployments/flow_runs.py +178 -0
  66. prefect/deployments/runner.py +72 -173
  67. prefect/deployments/schedules.py +31 -25
  68. prefect/deployments/steps/__init__.py +0 -1
  69. prefect/deployments/steps/core.py +7 -0
  70. prefect/deployments/steps/pull.py +15 -21
  71. prefect/deployments/steps/utility.py +2 -1
  72. prefect/docker/__init__.py +20 -0
  73. prefect/docker/docker_image.py +82 -0
  74. prefect/engine.py +15 -2475
  75. prefect/events/actions.py +17 -23
  76. prefect/events/cli/automations.py +20 -7
  77. prefect/events/clients.py +142 -80
  78. prefect/events/filters.py +14 -18
  79. prefect/events/related.py +74 -75
  80. prefect/events/schemas/__init__.py +0 -5
  81. prefect/events/schemas/automations.py +55 -46
  82. prefect/events/schemas/deployment_triggers.py +7 -197
  83. prefect/events/schemas/events.py +46 -65
  84. prefect/events/schemas/labelling.py +10 -14
  85. prefect/events/utilities.py +4 -5
  86. prefect/events/worker.py +23 -8
  87. prefect/exceptions.py +15 -0
  88. prefect/filesystems.py +30 -529
  89. prefect/flow_engine.py +827 -0
  90. prefect/flow_runs.py +379 -7
  91. prefect/flows.py +470 -360
  92. prefect/futures.py +382 -331
  93. prefect/infrastructure/__init__.py +5 -26
  94. prefect/infrastructure/base.py +3 -320
  95. prefect/infrastructure/provisioners/__init__.py +5 -3
  96. prefect/infrastructure/provisioners/cloud_run.py +13 -8
  97. prefect/infrastructure/provisioners/container_instance.py +14 -9
  98. prefect/infrastructure/provisioners/ecs.py +10 -8
  99. prefect/infrastructure/provisioners/modal.py +8 -5
  100. prefect/input/__init__.py +4 -0
  101. prefect/input/actions.py +2 -4
  102. prefect/input/run_input.py +9 -9
  103. prefect/logging/formatters.py +2 -4
  104. prefect/logging/handlers.py +9 -14
  105. prefect/logging/loggers.py +5 -5
  106. prefect/main.py +72 -0
  107. prefect/plugins.py +2 -64
  108. prefect/profiles.toml +16 -2
  109. prefect/records/__init__.py +1 -0
  110. prefect/records/base.py +223 -0
  111. prefect/records/filesystem.py +207 -0
  112. prefect/records/memory.py +178 -0
  113. prefect/records/result_store.py +64 -0
  114. prefect/results.py +577 -504
  115. prefect/runner/runner.py +117 -47
  116. prefect/runner/server.py +32 -34
  117. prefect/runner/storage.py +3 -12
  118. prefect/runner/submit.py +2 -10
  119. prefect/runner/utils.py +2 -2
  120. prefect/runtime/__init__.py +1 -0
  121. prefect/runtime/deployment.py +1 -0
  122. prefect/runtime/flow_run.py +40 -5
  123. prefect/runtime/task_run.py +1 -0
  124. prefect/serializers.py +28 -39
  125. prefect/server/api/collections_data/views/aggregate-worker-metadata.json +5 -14
  126. prefect/settings.py +209 -332
  127. prefect/states.py +160 -63
  128. prefect/task_engine.py +1478 -57
  129. prefect/task_runners.py +383 -287
  130. prefect/task_runs.py +240 -0
  131. prefect/task_worker.py +463 -0
  132. prefect/tasks.py +684 -374
  133. prefect/transactions.py +410 -0
  134. prefect/types/__init__.py +72 -86
  135. prefect/types/entrypoint.py +13 -0
  136. prefect/utilities/annotations.py +4 -3
  137. prefect/utilities/asyncutils.py +227 -148
  138. prefect/utilities/callables.py +137 -45
  139. prefect/utilities/collections.py +134 -86
  140. prefect/utilities/dispatch.py +27 -14
  141. prefect/utilities/dockerutils.py +11 -4
  142. prefect/utilities/engine.py +186 -32
  143. prefect/utilities/filesystem.py +4 -5
  144. prefect/utilities/importtools.py +26 -27
  145. prefect/utilities/pydantic.py +128 -38
  146. prefect/utilities/schema_tools/hydration.py +18 -1
  147. prefect/utilities/schema_tools/validation.py +30 -0
  148. prefect/utilities/services.py +35 -9
  149. prefect/utilities/templating.py +12 -2
  150. prefect/utilities/timeout.py +20 -5
  151. prefect/utilities/urls.py +195 -0
  152. prefect/utilities/visualization.py +1 -0
  153. prefect/variables.py +78 -59
  154. prefect/workers/__init__.py +0 -1
  155. prefect/workers/base.py +237 -244
  156. prefect/workers/block.py +5 -226
  157. prefect/workers/cloud.py +6 -0
  158. prefect/workers/process.py +265 -12
  159. prefect/workers/server.py +29 -11
  160. {prefect_client-2.20.4.dist-info → prefect_client-3.0.0.dist-info}/METADATA +28 -24
  161. prefect_client-3.0.0.dist-info/RECORD +201 -0
  162. {prefect_client-2.20.4.dist-info → prefect_client-3.0.0.dist-info}/WHEEL +1 -1
  163. prefect/_internal/pydantic/_base_model.py +0 -51
  164. prefect/_internal/pydantic/_compat.py +0 -82
  165. prefect/_internal/pydantic/_flags.py +0 -20
  166. prefect/_internal/pydantic/_types.py +0 -8
  167. prefect/_internal/pydantic/utilities/config_dict.py +0 -72
  168. prefect/_internal/pydantic/utilities/field_validator.py +0 -150
  169. prefect/_internal/pydantic/utilities/model_construct.py +0 -56
  170. prefect/_internal/pydantic/utilities/model_copy.py +0 -55
  171. prefect/_internal/pydantic/utilities/model_dump.py +0 -136
  172. prefect/_internal/pydantic/utilities/model_dump_json.py +0 -112
  173. prefect/_internal/pydantic/utilities/model_fields.py +0 -50
  174. prefect/_internal/pydantic/utilities/model_fields_set.py +0 -29
  175. prefect/_internal/pydantic/utilities/model_json_schema.py +0 -82
  176. prefect/_internal/pydantic/utilities/model_rebuild.py +0 -80
  177. prefect/_internal/pydantic/utilities/model_validate.py +0 -75
  178. prefect/_internal/pydantic/utilities/model_validate_json.py +0 -68
  179. prefect/_internal/pydantic/utilities/model_validator.py +0 -87
  180. prefect/_internal/pydantic/utilities/type_adapter.py +0 -71
  181. prefect/_vendor/fastapi/__init__.py +0 -25
  182. prefect/_vendor/fastapi/applications.py +0 -946
  183. prefect/_vendor/fastapi/background.py +0 -3
  184. prefect/_vendor/fastapi/concurrency.py +0 -44
  185. prefect/_vendor/fastapi/datastructures.py +0 -58
  186. prefect/_vendor/fastapi/dependencies/__init__.py +0 -0
  187. prefect/_vendor/fastapi/dependencies/models.py +0 -64
  188. prefect/_vendor/fastapi/dependencies/utils.py +0 -877
  189. prefect/_vendor/fastapi/encoders.py +0 -177
  190. prefect/_vendor/fastapi/exception_handlers.py +0 -40
  191. prefect/_vendor/fastapi/exceptions.py +0 -46
  192. prefect/_vendor/fastapi/logger.py +0 -3
  193. prefect/_vendor/fastapi/middleware/__init__.py +0 -1
  194. prefect/_vendor/fastapi/middleware/asyncexitstack.py +0 -25
  195. prefect/_vendor/fastapi/middleware/cors.py +0 -3
  196. prefect/_vendor/fastapi/middleware/gzip.py +0 -3
  197. prefect/_vendor/fastapi/middleware/httpsredirect.py +0 -3
  198. prefect/_vendor/fastapi/middleware/trustedhost.py +0 -3
  199. prefect/_vendor/fastapi/middleware/wsgi.py +0 -3
  200. prefect/_vendor/fastapi/openapi/__init__.py +0 -0
  201. prefect/_vendor/fastapi/openapi/constants.py +0 -2
  202. prefect/_vendor/fastapi/openapi/docs.py +0 -203
  203. prefect/_vendor/fastapi/openapi/models.py +0 -480
  204. prefect/_vendor/fastapi/openapi/utils.py +0 -485
  205. prefect/_vendor/fastapi/param_functions.py +0 -340
  206. prefect/_vendor/fastapi/params.py +0 -453
  207. prefect/_vendor/fastapi/py.typed +0 -0
  208. prefect/_vendor/fastapi/requests.py +0 -4
  209. prefect/_vendor/fastapi/responses.py +0 -40
  210. prefect/_vendor/fastapi/routing.py +0 -1331
  211. prefect/_vendor/fastapi/security/__init__.py +0 -15
  212. prefect/_vendor/fastapi/security/api_key.py +0 -98
  213. prefect/_vendor/fastapi/security/base.py +0 -6
  214. prefect/_vendor/fastapi/security/http.py +0 -172
  215. prefect/_vendor/fastapi/security/oauth2.py +0 -227
  216. prefect/_vendor/fastapi/security/open_id_connect_url.py +0 -34
  217. prefect/_vendor/fastapi/security/utils.py +0 -10
  218. prefect/_vendor/fastapi/staticfiles.py +0 -1
  219. prefect/_vendor/fastapi/templating.py +0 -3
  220. prefect/_vendor/fastapi/testclient.py +0 -1
  221. prefect/_vendor/fastapi/types.py +0 -3
  222. prefect/_vendor/fastapi/utils.py +0 -235
  223. prefect/_vendor/fastapi/websockets.py +0 -7
  224. prefect/_vendor/starlette/__init__.py +0 -1
  225. prefect/_vendor/starlette/_compat.py +0 -28
  226. prefect/_vendor/starlette/_exception_handler.py +0 -80
  227. prefect/_vendor/starlette/_utils.py +0 -88
  228. prefect/_vendor/starlette/applications.py +0 -261
  229. prefect/_vendor/starlette/authentication.py +0 -159
  230. prefect/_vendor/starlette/background.py +0 -43
  231. prefect/_vendor/starlette/concurrency.py +0 -59
  232. prefect/_vendor/starlette/config.py +0 -151
  233. prefect/_vendor/starlette/convertors.py +0 -87
  234. prefect/_vendor/starlette/datastructures.py +0 -707
  235. prefect/_vendor/starlette/endpoints.py +0 -130
  236. prefect/_vendor/starlette/exceptions.py +0 -60
  237. prefect/_vendor/starlette/formparsers.py +0 -276
  238. prefect/_vendor/starlette/middleware/__init__.py +0 -17
  239. prefect/_vendor/starlette/middleware/authentication.py +0 -52
  240. prefect/_vendor/starlette/middleware/base.py +0 -220
  241. prefect/_vendor/starlette/middleware/cors.py +0 -176
  242. prefect/_vendor/starlette/middleware/errors.py +0 -265
  243. prefect/_vendor/starlette/middleware/exceptions.py +0 -74
  244. prefect/_vendor/starlette/middleware/gzip.py +0 -113
  245. prefect/_vendor/starlette/middleware/httpsredirect.py +0 -19
  246. prefect/_vendor/starlette/middleware/sessions.py +0 -82
  247. prefect/_vendor/starlette/middleware/trustedhost.py +0 -64
  248. prefect/_vendor/starlette/middleware/wsgi.py +0 -147
  249. prefect/_vendor/starlette/py.typed +0 -0
  250. prefect/_vendor/starlette/requests.py +0 -328
  251. prefect/_vendor/starlette/responses.py +0 -347
  252. prefect/_vendor/starlette/routing.py +0 -933
  253. prefect/_vendor/starlette/schemas.py +0 -154
  254. prefect/_vendor/starlette/staticfiles.py +0 -248
  255. prefect/_vendor/starlette/status.py +0 -199
  256. prefect/_vendor/starlette/templating.py +0 -231
  257. prefect/_vendor/starlette/testclient.py +0 -804
  258. prefect/_vendor/starlette/types.py +0 -30
  259. prefect/_vendor/starlette/websockets.py +0 -193
  260. prefect/blocks/kubernetes.py +0 -119
  261. prefect/deprecated/__init__.py +0 -0
  262. prefect/deprecated/data_documents.py +0 -350
  263. prefect/deprecated/packaging/__init__.py +0 -12
  264. prefect/deprecated/packaging/base.py +0 -96
  265. prefect/deprecated/packaging/docker.py +0 -146
  266. prefect/deprecated/packaging/file.py +0 -92
  267. prefect/deprecated/packaging/orion.py +0 -80
  268. prefect/deprecated/packaging/serializers.py +0 -171
  269. prefect/events/instrument.py +0 -135
  270. prefect/infrastructure/container.py +0 -824
  271. prefect/infrastructure/kubernetes.py +0 -920
  272. prefect/infrastructure/process.py +0 -289
  273. prefect/manifests.py +0 -20
  274. prefect/new_flow_engine.py +0 -449
  275. prefect/new_task_engine.py +0 -423
  276. prefect/pydantic/__init__.py +0 -76
  277. prefect/pydantic/main.py +0 -39
  278. prefect/software/__init__.py +0 -2
  279. prefect/software/base.py +0 -50
  280. prefect/software/conda.py +0 -199
  281. prefect/software/pip.py +0 -122
  282. prefect/software/python.py +0 -52
  283. prefect/task_server.py +0 -322
  284. prefect_client-2.20.4.dist-info/RECORD +0 -294
  285. /prefect/{_internal/pydantic/utilities → client/types}/__init__.py +0 -0
  286. /prefect/{_vendor → concurrency/v1}/__init__.py +0 -0
  287. {prefect_client-2.20.4.dist-info → prefect_client-3.0.0.dist-info}/LICENSE +0 -0
  288. {prefect_client-2.20.4.dist-info → prefect_client-3.0.0.dist-info}/top_level.txt +0 -0
@@ -1,1331 +0,0 @@
1
- import asyncio
2
- import dataclasses
3
- import email.message
4
- import inspect
5
- import json
6
- from contextlib import AsyncExitStack
7
- from enum import Enum, IntEnum
8
- from typing import (
9
- Any,
10
- Callable,
11
- Coroutine,
12
- Dict,
13
- List,
14
- Optional,
15
- Sequence,
16
- Set,
17
- Tuple,
18
- Type,
19
- Union,
20
- )
21
-
22
- from prefect._vendor.fastapi import params
23
- from prefect._vendor.fastapi.datastructures import Default, DefaultPlaceholder
24
- from prefect._vendor.fastapi.dependencies.models import Dependant
25
- from prefect._vendor.fastapi.dependencies.utils import (
26
- get_body_field,
27
- get_dependant,
28
- get_parameterless_sub_dependant,
29
- get_typed_return_annotation,
30
- solve_dependencies,
31
- )
32
- from prefect._vendor.fastapi.encoders import DictIntStrAny, SetIntStr, jsonable_encoder
33
- from prefect._vendor.fastapi.exceptions import (
34
- FastAPIError,
35
- RequestValidationError,
36
- WebSocketRequestValidationError,
37
- )
38
- from prefect._vendor.fastapi.types import DecoratedCallable
39
- from prefect._vendor.fastapi.utils import (
40
- create_cloned_field,
41
- create_response_field,
42
- generate_unique_id,
43
- get_value_or_default,
44
- is_body_allowed_for_status_code,
45
- )
46
-
47
- from prefect._internal.pydantic import HAS_PYDANTIC_V2
48
-
49
- if HAS_PYDANTIC_V2:
50
- from pydantic.v1 import BaseModel
51
- from pydantic.v1.error_wrappers import ErrorWrapper, ValidationError
52
- from pydantic.v1.fields import ModelField, Undefined
53
- from pydantic.v1.utils import lenient_issubclass
54
- else:
55
- from pydantic import BaseModel
56
- from pydantic.error_wrappers import ErrorWrapper, ValidationError
57
- from pydantic.fields import ModelField, Undefined
58
- from pydantic.utils import lenient_issubclass
59
-
60
- from prefect._vendor.starlette import routing
61
- from prefect._vendor.starlette.concurrency import run_in_threadpool
62
- from prefect._vendor.starlette.exceptions import HTTPException
63
- from prefect._vendor.starlette.requests import Request
64
- from prefect._vendor.starlette.responses import JSONResponse, Response
65
- from prefect._vendor.starlette.routing import (
66
- BaseRoute,
67
- Match,
68
- compile_path,
69
- get_name,
70
- request_response,
71
- websocket_session,
72
- )
73
- from prefect._vendor.starlette.routing import Mount as Mount # noqa
74
- from prefect._vendor.starlette.types import ASGIApp, Lifespan, Scope
75
- from prefect._vendor.starlette.websockets import WebSocket
76
-
77
-
78
- def _prepare_response_content(
79
- res: Any,
80
- *,
81
- exclude_unset: bool,
82
- exclude_defaults: bool = False,
83
- exclude_none: bool = False,
84
- ) -> Any:
85
- if isinstance(res, BaseModel):
86
- read_with_orm_mode = getattr(res.__config__, "read_with_orm_mode", None)
87
- if read_with_orm_mode:
88
- # Let from_orm extract the data from this model instead of converting
89
- # it now to a dict.
90
- # Otherwise there's no way to extract lazy data that requires attribute
91
- # access instead of dict iteration, e.g. lazy relationships.
92
- return res
93
- return res.dict(
94
- by_alias=True,
95
- exclude_unset=exclude_unset,
96
- exclude_defaults=exclude_defaults,
97
- exclude_none=exclude_none,
98
- )
99
- elif isinstance(res, list):
100
- return [
101
- _prepare_response_content(
102
- item,
103
- exclude_unset=exclude_unset,
104
- exclude_defaults=exclude_defaults,
105
- exclude_none=exclude_none,
106
- )
107
- for item in res
108
- ]
109
- elif isinstance(res, dict):
110
- return {
111
- k: _prepare_response_content(
112
- v,
113
- exclude_unset=exclude_unset,
114
- exclude_defaults=exclude_defaults,
115
- exclude_none=exclude_none,
116
- )
117
- for k, v in res.items()
118
- }
119
- elif dataclasses.is_dataclass(res):
120
- return dataclasses.asdict(res)
121
- return res
122
-
123
-
124
- async def serialize_response(
125
- *,
126
- field: Optional[ModelField] = None,
127
- response_content: Any,
128
- include: Optional[Union[SetIntStr, DictIntStrAny]] = None,
129
- exclude: Optional[Union[SetIntStr, DictIntStrAny]] = None,
130
- by_alias: bool = True,
131
- exclude_unset: bool = False,
132
- exclude_defaults: bool = False,
133
- exclude_none: bool = False,
134
- is_coroutine: bool = True,
135
- ) -> Any:
136
- if field:
137
- errors = []
138
- response_content = _prepare_response_content(
139
- response_content,
140
- exclude_unset=exclude_unset,
141
- exclude_defaults=exclude_defaults,
142
- exclude_none=exclude_none,
143
- )
144
- if is_coroutine:
145
- value, errors_ = field.validate(response_content, {}, loc=("response",))
146
- else:
147
- value, errors_ = await run_in_threadpool(
148
- field.validate, response_content, {}, loc=("response",)
149
- )
150
- if isinstance(errors_, ErrorWrapper):
151
- errors.append(errors_)
152
- elif isinstance(errors_, list):
153
- errors.extend(errors_)
154
- if errors:
155
- raise ValidationError(errors, field.type_)
156
- return jsonable_encoder(
157
- value,
158
- include=include,
159
- exclude=exclude,
160
- by_alias=by_alias,
161
- exclude_unset=exclude_unset,
162
- exclude_defaults=exclude_defaults,
163
- exclude_none=exclude_none,
164
- )
165
- else:
166
- return jsonable_encoder(response_content)
167
-
168
-
169
- async def run_endpoint_function(
170
- *, dependant: Dependant, values: Dict[str, Any], is_coroutine: bool
171
- ) -> Any:
172
- # Only called by get_request_handler. Has been split into its own function to
173
- # facilitate profiling endpoints, since inner functions are harder to profile.
174
- assert dependant.call is not None, "dependant.call must be a function"
175
-
176
- if is_coroutine:
177
- return await dependant.call(**values)
178
- else:
179
- return await run_in_threadpool(dependant.call, **values)
180
-
181
-
182
- def get_request_handler(
183
- dependant: Dependant,
184
- body_field: Optional[ModelField] = None,
185
- status_code: Optional[int] = None,
186
- response_class: Union[Type[Response], DefaultPlaceholder] = Default(JSONResponse),
187
- response_field: Optional[ModelField] = None,
188
- response_model_include: Optional[Union[SetIntStr, DictIntStrAny]] = None,
189
- response_model_exclude: Optional[Union[SetIntStr, DictIntStrAny]] = None,
190
- response_model_by_alias: bool = True,
191
- response_model_exclude_unset: bool = False,
192
- response_model_exclude_defaults: bool = False,
193
- response_model_exclude_none: bool = False,
194
- dependency_overrides_provider: Optional[Any] = None,
195
- ) -> Callable[[Request], Coroutine[Any, Any, Response]]:
196
- assert dependant.call is not None, "dependant.call must be a function"
197
- is_coroutine = asyncio.iscoroutinefunction(dependant.call)
198
- is_body_form = body_field and isinstance(body_field.field_info, params.Form)
199
- if isinstance(response_class, DefaultPlaceholder):
200
- actual_response_class: Type[Response] = response_class.value
201
- else:
202
- actual_response_class = response_class
203
-
204
- async def app(request: Request) -> Response:
205
- try:
206
- body: Any = None
207
- if body_field:
208
- if is_body_form:
209
- body = await request.form()
210
- stack = request.scope.get("fastapi_astack")
211
- assert isinstance(stack, AsyncExitStack)
212
- stack.push_async_callback(body.close)
213
- else:
214
- body_bytes = await request.body()
215
- if body_bytes:
216
- json_body: Any = Undefined
217
- content_type_value = request.headers.get("content-type")
218
- if not content_type_value:
219
- json_body = await request.json()
220
- else:
221
- message = email.message.Message()
222
- message["content-type"] = content_type_value
223
- if message.get_content_maintype() == "application":
224
- subtype = message.get_content_subtype()
225
- if subtype == "json" or subtype.endswith("+json"):
226
- json_body = await request.json()
227
- if json_body != Undefined:
228
- body = json_body
229
- else:
230
- body = body_bytes
231
- except json.JSONDecodeError as e:
232
- raise RequestValidationError(
233
- [ErrorWrapper(e, ("body", e.pos))], body=e.doc
234
- ) from e
235
- except HTTPException:
236
- raise
237
- except Exception as e:
238
- raise HTTPException(
239
- status_code=400, detail="There was an error parsing the body"
240
- ) from e
241
- solved_result = await solve_dependencies(
242
- request=request,
243
- dependant=dependant,
244
- body=body,
245
- dependency_overrides_provider=dependency_overrides_provider,
246
- )
247
- values, errors, background_tasks, sub_response, _ = solved_result
248
- if errors:
249
- raise RequestValidationError(errors, body=body)
250
- else:
251
- raw_response = await run_endpoint_function(
252
- dependant=dependant, values=values, is_coroutine=is_coroutine
253
- )
254
-
255
- if isinstance(raw_response, Response):
256
- if raw_response.background is None:
257
- raw_response.background = background_tasks
258
- return raw_response
259
- response_args: Dict[str, Any] = {"background": background_tasks}
260
- # If status_code was set, use it, otherwise use the default from the
261
- # response class, in the case of redirect it's 307
262
- current_status_code = (
263
- status_code if status_code else sub_response.status_code
264
- )
265
- if current_status_code is not None:
266
- response_args["status_code"] = current_status_code
267
- if sub_response.status_code:
268
- response_args["status_code"] = sub_response.status_code
269
- content = await serialize_response(
270
- field=response_field,
271
- response_content=raw_response,
272
- include=response_model_include,
273
- exclude=response_model_exclude,
274
- by_alias=response_model_by_alias,
275
- exclude_unset=response_model_exclude_unset,
276
- exclude_defaults=response_model_exclude_defaults,
277
- exclude_none=response_model_exclude_none,
278
- is_coroutine=is_coroutine,
279
- )
280
- response = actual_response_class(content, **response_args)
281
- if not is_body_allowed_for_status_code(response.status_code):
282
- response.body = b""
283
- response.headers.raw.extend(sub_response.headers.raw)
284
- return response
285
-
286
- return app
287
-
288
-
289
- def get_websocket_app(
290
- dependant: Dependant, dependency_overrides_provider: Optional[Any] = None
291
- ) -> Callable[[WebSocket], Coroutine[Any, Any, Any]]:
292
- async def app(websocket: WebSocket) -> None:
293
- solved_result = await solve_dependencies(
294
- request=websocket,
295
- dependant=dependant,
296
- dependency_overrides_provider=dependency_overrides_provider,
297
- )
298
- values, errors, _, _2, _3 = solved_result
299
- if errors:
300
- raise WebSocketRequestValidationError(errors)
301
- assert dependant.call is not None, "dependant.call must be a function"
302
- await dependant.call(**values)
303
-
304
- return app
305
-
306
-
307
- class APIWebSocketRoute(routing.WebSocketRoute):
308
- def __init__(
309
- self,
310
- path: str,
311
- endpoint: Callable[..., Any],
312
- *,
313
- name: Optional[str] = None,
314
- dependencies: Optional[Sequence[params.Depends]] = None,
315
- dependency_overrides_provider: Optional[Any] = None,
316
- ) -> None:
317
- self.path = path
318
- self.endpoint = endpoint
319
- self.name = get_name(endpoint) if name is None else name
320
- self.dependencies = list(dependencies or [])
321
- self.path_regex, self.path_format, self.param_convertors = compile_path(path)
322
- self.dependant = get_dependant(path=self.path_format, call=self.endpoint)
323
- for depends in self.dependencies[::-1]:
324
- self.dependant.dependencies.insert(
325
- 0,
326
- get_parameterless_sub_dependant(depends=depends, path=self.path_format),
327
- )
328
-
329
- self.app = websocket_session(
330
- get_websocket_app(
331
- dependant=self.dependant,
332
- dependency_overrides_provider=dependency_overrides_provider,
333
- )
334
- )
335
-
336
- def matches(self, scope: Scope) -> Tuple[Match, Scope]:
337
- match, child_scope = super().matches(scope)
338
- if match != Match.NONE:
339
- child_scope["route"] = self
340
- return match, child_scope
341
-
342
-
343
- class APIRoute(routing.Route):
344
- def __init__(
345
- self,
346
- path: str,
347
- endpoint: Callable[..., Any],
348
- *,
349
- response_model: Any = Default(None),
350
- status_code: Optional[int] = None,
351
- tags: Optional[List[Union[str, Enum]]] = None,
352
- dependencies: Optional[Sequence[params.Depends]] = None,
353
- summary: Optional[str] = None,
354
- description: Optional[str] = None,
355
- response_description: str = "Successful Response",
356
- responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None,
357
- deprecated: Optional[bool] = None,
358
- name: Optional[str] = None,
359
- methods: Optional[Union[Set[str], List[str]]] = None,
360
- operation_id: Optional[str] = None,
361
- response_model_include: Optional[Union[SetIntStr, DictIntStrAny]] = None,
362
- response_model_exclude: Optional[Union[SetIntStr, DictIntStrAny]] = None,
363
- response_model_by_alias: bool = True,
364
- response_model_exclude_unset: bool = False,
365
- response_model_exclude_defaults: bool = False,
366
- response_model_exclude_none: bool = False,
367
- include_in_schema: bool = True,
368
- response_class: Union[Type[Response], DefaultPlaceholder] = Default(
369
- JSONResponse
370
- ),
371
- dependency_overrides_provider: Optional[Any] = None,
372
- callbacks: Optional[List[BaseRoute]] = None,
373
- openapi_extra: Optional[Dict[str, Any]] = None,
374
- generate_unique_id_function: Union[
375
- Callable[["APIRoute"], str], DefaultPlaceholder
376
- ] = Default(generate_unique_id),
377
- ) -> None:
378
- self.path = path
379
- self.endpoint = endpoint
380
- if isinstance(response_model, DefaultPlaceholder):
381
- return_annotation = get_typed_return_annotation(endpoint)
382
- if lenient_issubclass(return_annotation, Response):
383
- response_model = None
384
- else:
385
- response_model = return_annotation
386
- self.response_model = response_model
387
- self.summary = summary
388
- self.response_description = response_description
389
- self.deprecated = deprecated
390
- self.operation_id = operation_id
391
- self.response_model_include = response_model_include
392
- self.response_model_exclude = response_model_exclude
393
- self.response_model_by_alias = response_model_by_alias
394
- self.response_model_exclude_unset = response_model_exclude_unset
395
- self.response_model_exclude_defaults = response_model_exclude_defaults
396
- self.response_model_exclude_none = response_model_exclude_none
397
- self.include_in_schema = include_in_schema
398
- self.response_class = response_class
399
- self.dependency_overrides_provider = dependency_overrides_provider
400
- self.callbacks = callbacks
401
- self.openapi_extra = openapi_extra
402
- self.generate_unique_id_function = generate_unique_id_function
403
- self.tags = tags or []
404
- self.responses = responses or {}
405
- self.name = get_name(endpoint) if name is None else name
406
- self.path_regex, self.path_format, self.param_convertors = compile_path(path)
407
- if methods is None:
408
- methods = ["GET"]
409
- self.methods: Set[str] = {method.upper() for method in methods}
410
- if isinstance(generate_unique_id_function, DefaultPlaceholder):
411
- current_generate_unique_id: Callable[
412
- ["APIRoute"], str
413
- ] = generate_unique_id_function.value
414
- else:
415
- current_generate_unique_id = generate_unique_id_function
416
- self.unique_id = self.operation_id or current_generate_unique_id(self)
417
- # normalize enums e.g. http.HTTPStatus
418
- if isinstance(status_code, IntEnum):
419
- status_code = int(status_code)
420
- self.status_code = status_code
421
- if self.response_model:
422
- assert is_body_allowed_for_status_code(
423
- status_code
424
- ), f"Status code {status_code} must not have a response body"
425
- response_name = "Response_" + self.unique_id
426
- self.response_field = create_response_field(
427
- name=response_name, type_=self.response_model
428
- )
429
- # Create a clone of the field, so that a Pydantic submodel is not returned
430
- # as is just because it's an instance of a subclass of a more limited class
431
- # e.g. UserInDB (containing hashed_password) could be a subclass of User
432
- # that doesn't have the hashed_password. But because it's a subclass, it
433
- # would pass the validation and be returned as is.
434
- # By being a new field, no inheritance will be passed as is. A new model
435
- # will be always created.
436
- self.secure_cloned_response_field: Optional[
437
- ModelField
438
- ] = create_cloned_field(self.response_field)
439
- else:
440
- self.response_field = None # type: ignore
441
- self.secure_cloned_response_field = None
442
- self.dependencies = list(dependencies or [])
443
- self.description = description or inspect.cleandoc(self.endpoint.__doc__ or "")
444
- # if a "form feed" character (page break) is found in the description text,
445
- # truncate description text to the content preceding the first "form feed"
446
- self.description = self.description.split("\f")[0].strip()
447
- response_fields = {}
448
- for additional_status_code, response in self.responses.items():
449
- assert isinstance(response, dict), "An additional response must be a dict"
450
- model = response.get("model")
451
- if model:
452
- assert is_body_allowed_for_status_code(
453
- additional_status_code
454
- ), f"Status code {additional_status_code} must not have a response body"
455
- response_name = f"Response_{additional_status_code}_{self.unique_id}"
456
- response_field = create_response_field(name=response_name, type_=model)
457
- response_fields[additional_status_code] = response_field
458
- if response_fields:
459
- self.response_fields: Dict[Union[int, str], ModelField] = response_fields
460
- else:
461
- self.response_fields = {}
462
-
463
- assert callable(endpoint), "An endpoint must be a callable"
464
- self.dependant = get_dependant(path=self.path_format, call=self.endpoint)
465
- for depends in self.dependencies[::-1]:
466
- self.dependant.dependencies.insert(
467
- 0,
468
- get_parameterless_sub_dependant(depends=depends, path=self.path_format),
469
- )
470
- self.body_field = get_body_field(dependant=self.dependant, name=self.unique_id)
471
- self.app = request_response(self.get_route_handler())
472
-
473
- def get_route_handler(self) -> Callable[[Request], Coroutine[Any, Any, Response]]:
474
- return get_request_handler(
475
- dependant=self.dependant,
476
- body_field=self.body_field,
477
- status_code=self.status_code,
478
- response_class=self.response_class,
479
- response_field=self.secure_cloned_response_field,
480
- response_model_include=self.response_model_include,
481
- response_model_exclude=self.response_model_exclude,
482
- response_model_by_alias=self.response_model_by_alias,
483
- response_model_exclude_unset=self.response_model_exclude_unset,
484
- response_model_exclude_defaults=self.response_model_exclude_defaults,
485
- response_model_exclude_none=self.response_model_exclude_none,
486
- dependency_overrides_provider=self.dependency_overrides_provider,
487
- )
488
-
489
- def matches(self, scope: Scope) -> Tuple[Match, Scope]:
490
- match, child_scope = super().matches(scope)
491
- if match != Match.NONE:
492
- child_scope["route"] = self
493
- return match, child_scope
494
-
495
-
496
- class APIRouter(routing.Router):
497
- def __init__(
498
- self,
499
- *,
500
- prefix: str = "",
501
- tags: Optional[List[Union[str, Enum]]] = None,
502
- dependencies: Optional[Sequence[params.Depends]] = None,
503
- default_response_class: Type[Response] = Default(JSONResponse),
504
- responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None,
505
- callbacks: Optional[List[BaseRoute]] = None,
506
- routes: Optional[List[routing.BaseRoute]] = None,
507
- redirect_slashes: bool = True,
508
- default: Optional[ASGIApp] = None,
509
- dependency_overrides_provider: Optional[Any] = None,
510
- route_class: Type[APIRoute] = APIRoute,
511
- on_startup: Optional[Sequence[Callable[[], Any]]] = None,
512
- on_shutdown: Optional[Sequence[Callable[[], Any]]] = None,
513
- # the generic to Lifespan[AppType] is the type of the top level application
514
- # which the router cannot know statically, so we use typing.Any
515
- lifespan: Optional[Lifespan[Any]] = None,
516
- deprecated: Optional[bool] = None,
517
- include_in_schema: bool = True,
518
- generate_unique_id_function: Callable[[APIRoute], str] = Default(
519
- generate_unique_id
520
- ),
521
- ) -> None:
522
- super().__init__(
523
- routes=routes,
524
- redirect_slashes=redirect_slashes,
525
- default=default,
526
- on_startup=on_startup,
527
- on_shutdown=on_shutdown,
528
- lifespan=lifespan,
529
- )
530
- if prefix:
531
- assert prefix.startswith("/"), "A path prefix must start with '/'"
532
- assert not prefix.endswith(
533
- "/"
534
- ), "A path prefix must not end with '/', as the routes will start with '/'"
535
- self.prefix = prefix
536
- self.tags: List[Union[str, Enum]] = tags or []
537
- self.dependencies = list(dependencies or [])
538
- self.deprecated = deprecated
539
- self.include_in_schema = include_in_schema
540
- self.responses = responses or {}
541
- self.callbacks = callbacks or []
542
- self.dependency_overrides_provider = dependency_overrides_provider
543
- self.route_class = route_class
544
- self.default_response_class = default_response_class
545
- self.generate_unique_id_function = generate_unique_id_function
546
-
547
- def route(
548
- self,
549
- path: str,
550
- methods: Optional[List[str]] = None,
551
- name: Optional[str] = None,
552
- include_in_schema: bool = True,
553
- ) -> Callable[[DecoratedCallable], DecoratedCallable]:
554
- def decorator(func: DecoratedCallable) -> DecoratedCallable:
555
- self.add_route(
556
- path,
557
- func,
558
- methods=methods,
559
- name=name,
560
- include_in_schema=include_in_schema,
561
- )
562
- return func
563
-
564
- return decorator
565
-
566
- def add_api_route(
567
- self,
568
- path: str,
569
- endpoint: Callable[..., Any],
570
- *,
571
- response_model: Any = Default(None),
572
- status_code: Optional[int] = None,
573
- tags: Optional[List[Union[str, Enum]]] = None,
574
- dependencies: Optional[Sequence[params.Depends]] = None,
575
- summary: Optional[str] = None,
576
- description: Optional[str] = None,
577
- response_description: str = "Successful Response",
578
- responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None,
579
- deprecated: Optional[bool] = None,
580
- methods: Optional[Union[Set[str], List[str]]] = None,
581
- operation_id: Optional[str] = None,
582
- response_model_include: Optional[Union[SetIntStr, DictIntStrAny]] = None,
583
- response_model_exclude: Optional[Union[SetIntStr, DictIntStrAny]] = None,
584
- response_model_by_alias: bool = True,
585
- response_model_exclude_unset: bool = False,
586
- response_model_exclude_defaults: bool = False,
587
- response_model_exclude_none: bool = False,
588
- include_in_schema: bool = True,
589
- response_class: Union[Type[Response], DefaultPlaceholder] = Default(
590
- JSONResponse
591
- ),
592
- name: Optional[str] = None,
593
- route_class_override: Optional[Type[APIRoute]] = None,
594
- callbacks: Optional[List[BaseRoute]] = None,
595
- openapi_extra: Optional[Dict[str, Any]] = None,
596
- generate_unique_id_function: Union[
597
- Callable[[APIRoute], str], DefaultPlaceholder
598
- ] = Default(generate_unique_id),
599
- ) -> None:
600
- route_class = route_class_override or self.route_class
601
- responses = responses or {}
602
- combined_responses = {**self.responses, **responses}
603
- current_response_class = get_value_or_default(
604
- response_class, self.default_response_class
605
- )
606
- current_tags = self.tags.copy()
607
- if tags:
608
- current_tags.extend(tags)
609
- current_dependencies = self.dependencies.copy()
610
- if dependencies:
611
- current_dependencies.extend(dependencies)
612
- current_callbacks = self.callbacks.copy()
613
- if callbacks:
614
- current_callbacks.extend(callbacks)
615
- current_generate_unique_id = get_value_or_default(
616
- generate_unique_id_function, self.generate_unique_id_function
617
- )
618
- route = route_class(
619
- self.prefix + path,
620
- endpoint=endpoint,
621
- response_model=response_model,
622
- status_code=status_code,
623
- tags=current_tags,
624
- dependencies=current_dependencies,
625
- summary=summary,
626
- description=description,
627
- response_description=response_description,
628
- responses=combined_responses,
629
- deprecated=deprecated or self.deprecated,
630
- methods=methods,
631
- operation_id=operation_id,
632
- response_model_include=response_model_include,
633
- response_model_exclude=response_model_exclude,
634
- response_model_by_alias=response_model_by_alias,
635
- response_model_exclude_unset=response_model_exclude_unset,
636
- response_model_exclude_defaults=response_model_exclude_defaults,
637
- response_model_exclude_none=response_model_exclude_none,
638
- include_in_schema=include_in_schema and self.include_in_schema,
639
- response_class=current_response_class,
640
- name=name,
641
- dependency_overrides_provider=self.dependency_overrides_provider,
642
- callbacks=current_callbacks,
643
- openapi_extra=openapi_extra,
644
- generate_unique_id_function=current_generate_unique_id,
645
- )
646
- self.routes.append(route)
647
-
648
- def api_route(
649
- self,
650
- path: str,
651
- *,
652
- response_model: Any = Default(None),
653
- status_code: Optional[int] = None,
654
- tags: Optional[List[Union[str, Enum]]] = None,
655
- dependencies: Optional[Sequence[params.Depends]] = None,
656
- summary: Optional[str] = None,
657
- description: Optional[str] = None,
658
- response_description: str = "Successful Response",
659
- responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None,
660
- deprecated: Optional[bool] = None,
661
- methods: Optional[List[str]] = None,
662
- operation_id: Optional[str] = None,
663
- response_model_include: Optional[Union[SetIntStr, DictIntStrAny]] = None,
664
- response_model_exclude: Optional[Union[SetIntStr, DictIntStrAny]] = None,
665
- response_model_by_alias: bool = True,
666
- response_model_exclude_unset: bool = False,
667
- response_model_exclude_defaults: bool = False,
668
- response_model_exclude_none: bool = False,
669
- include_in_schema: bool = True,
670
- response_class: Type[Response] = Default(JSONResponse),
671
- name: Optional[str] = None,
672
- callbacks: Optional[List[BaseRoute]] = None,
673
- openapi_extra: Optional[Dict[str, Any]] = None,
674
- generate_unique_id_function: Callable[[APIRoute], str] = Default(
675
- generate_unique_id
676
- ),
677
- ) -> Callable[[DecoratedCallable], DecoratedCallable]:
678
- def decorator(func: DecoratedCallable) -> DecoratedCallable:
679
- self.add_api_route(
680
- path,
681
- func,
682
- response_model=response_model,
683
- status_code=status_code,
684
- tags=tags,
685
- dependencies=dependencies,
686
- summary=summary,
687
- description=description,
688
- response_description=response_description,
689
- responses=responses,
690
- deprecated=deprecated,
691
- methods=methods,
692
- operation_id=operation_id,
693
- response_model_include=response_model_include,
694
- response_model_exclude=response_model_exclude,
695
- response_model_by_alias=response_model_by_alias,
696
- response_model_exclude_unset=response_model_exclude_unset,
697
- response_model_exclude_defaults=response_model_exclude_defaults,
698
- response_model_exclude_none=response_model_exclude_none,
699
- include_in_schema=include_in_schema,
700
- response_class=response_class,
701
- name=name,
702
- callbacks=callbacks,
703
- openapi_extra=openapi_extra,
704
- generate_unique_id_function=generate_unique_id_function,
705
- )
706
- return func
707
-
708
- return decorator
709
-
710
- def add_api_websocket_route(
711
- self,
712
- path: str,
713
- endpoint: Callable[..., Any],
714
- name: Optional[str] = None,
715
- *,
716
- dependencies: Optional[Sequence[params.Depends]] = None,
717
- ) -> None:
718
- current_dependencies = self.dependencies.copy()
719
- if dependencies:
720
- current_dependencies.extend(dependencies)
721
-
722
- route = APIWebSocketRoute(
723
- self.prefix + path,
724
- endpoint=endpoint,
725
- name=name,
726
- dependencies=current_dependencies,
727
- dependency_overrides_provider=self.dependency_overrides_provider,
728
- )
729
- self.routes.append(route)
730
-
731
- def websocket(
732
- self,
733
- path: str,
734
- name: Optional[str] = None,
735
- *,
736
- dependencies: Optional[Sequence[params.Depends]] = None,
737
- ) -> Callable[[DecoratedCallable], DecoratedCallable]:
738
- def decorator(func: DecoratedCallable) -> DecoratedCallable:
739
- self.add_api_websocket_route(
740
- path, func, name=name, dependencies=dependencies
741
- )
742
- return func
743
-
744
- return decorator
745
-
746
- def websocket_route(
747
- self, path: str, name: Union[str, None] = None
748
- ) -> Callable[[DecoratedCallable], DecoratedCallable]:
749
- def decorator(func: DecoratedCallable) -> DecoratedCallable:
750
- self.add_websocket_route(path, func, name=name)
751
- return func
752
-
753
- return decorator
754
-
755
- def include_router(
756
- self,
757
- router: "APIRouter",
758
- *,
759
- prefix: str = "",
760
- tags: Optional[List[Union[str, Enum]]] = None,
761
- dependencies: Optional[Sequence[params.Depends]] = None,
762
- default_response_class: Type[Response] = Default(JSONResponse),
763
- responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None,
764
- callbacks: Optional[List[BaseRoute]] = None,
765
- deprecated: Optional[bool] = None,
766
- include_in_schema: bool = True,
767
- generate_unique_id_function: Callable[[APIRoute], str] = Default(
768
- generate_unique_id
769
- ),
770
- ) -> None:
771
- if prefix:
772
- assert prefix.startswith("/"), "A path prefix must start with '/'"
773
- assert not prefix.endswith(
774
- "/"
775
- ), "A path prefix must not end with '/', as the routes will start with '/'"
776
- else:
777
- for r in router.routes:
778
- path = getattr(r, "path") # noqa: B009
779
- name = getattr(r, "name", "unknown")
780
- if path is not None and not path:
781
- raise FastAPIError(
782
- f"Prefix and path cannot be both empty (path operation: {name})"
783
- )
784
- if responses is None:
785
- responses = {}
786
- for route in router.routes:
787
- if isinstance(route, APIRoute):
788
- combined_responses = {**responses, **route.responses}
789
- use_response_class = get_value_or_default(
790
- route.response_class,
791
- router.default_response_class,
792
- default_response_class,
793
- self.default_response_class,
794
- )
795
- current_tags = []
796
- if tags:
797
- current_tags.extend(tags)
798
- if route.tags:
799
- current_tags.extend(route.tags)
800
- current_dependencies: List[params.Depends] = []
801
- if dependencies:
802
- current_dependencies.extend(dependencies)
803
- if route.dependencies:
804
- current_dependencies.extend(route.dependencies)
805
- current_callbacks = []
806
- if callbacks:
807
- current_callbacks.extend(callbacks)
808
- if route.callbacks:
809
- current_callbacks.extend(route.callbacks)
810
- current_generate_unique_id = get_value_or_default(
811
- route.generate_unique_id_function,
812
- router.generate_unique_id_function,
813
- generate_unique_id_function,
814
- self.generate_unique_id_function,
815
- )
816
- self.add_api_route(
817
- prefix + route.path,
818
- route.endpoint,
819
- response_model=route.response_model,
820
- status_code=route.status_code,
821
- tags=current_tags,
822
- dependencies=current_dependencies,
823
- summary=route.summary,
824
- description=route.description,
825
- response_description=route.response_description,
826
- responses=combined_responses,
827
- deprecated=route.deprecated or deprecated or self.deprecated,
828
- methods=route.methods,
829
- operation_id=route.operation_id,
830
- response_model_include=route.response_model_include,
831
- response_model_exclude=route.response_model_exclude,
832
- response_model_by_alias=route.response_model_by_alias,
833
- response_model_exclude_unset=route.response_model_exclude_unset,
834
- response_model_exclude_defaults=route.response_model_exclude_defaults,
835
- response_model_exclude_none=route.response_model_exclude_none,
836
- include_in_schema=route.include_in_schema
837
- and self.include_in_schema
838
- and include_in_schema,
839
- response_class=use_response_class,
840
- name=route.name,
841
- route_class_override=type(route),
842
- callbacks=current_callbacks,
843
- openapi_extra=route.openapi_extra,
844
- generate_unique_id_function=current_generate_unique_id,
845
- )
846
- elif isinstance(route, routing.Route):
847
- methods = list(route.methods or [])
848
- self.add_route(
849
- prefix + route.path,
850
- route.endpoint,
851
- methods=methods,
852
- include_in_schema=route.include_in_schema,
853
- name=route.name,
854
- )
855
- elif isinstance(route, APIWebSocketRoute):
856
- current_dependencies = []
857
- if dependencies:
858
- current_dependencies.extend(dependencies)
859
- if route.dependencies:
860
- current_dependencies.extend(route.dependencies)
861
- self.add_api_websocket_route(
862
- prefix + route.path,
863
- route.endpoint,
864
- dependencies=current_dependencies,
865
- name=route.name,
866
- )
867
- elif isinstance(route, routing.WebSocketRoute):
868
- self.add_websocket_route(
869
- prefix + route.path, route.endpoint, name=route.name
870
- )
871
- for handler in router.on_startup:
872
- self.add_event_handler("startup", handler)
873
- for handler in router.on_shutdown:
874
- self.add_event_handler("shutdown", handler)
875
-
876
- def get(
877
- self,
878
- path: str,
879
- *,
880
- response_model: Any = Default(None),
881
- status_code: Optional[int] = None,
882
- tags: Optional[List[Union[str, Enum]]] = None,
883
- dependencies: Optional[Sequence[params.Depends]] = None,
884
- summary: Optional[str] = None,
885
- description: Optional[str] = None,
886
- response_description: str = "Successful Response",
887
- responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None,
888
- deprecated: Optional[bool] = None,
889
- operation_id: Optional[str] = None,
890
- response_model_include: Optional[Union[SetIntStr, DictIntStrAny]] = None,
891
- response_model_exclude: Optional[Union[SetIntStr, DictIntStrAny]] = None,
892
- response_model_by_alias: bool = True,
893
- response_model_exclude_unset: bool = False,
894
- response_model_exclude_defaults: bool = False,
895
- response_model_exclude_none: bool = False,
896
- include_in_schema: bool = True,
897
- response_class: Type[Response] = Default(JSONResponse),
898
- name: Optional[str] = None,
899
- callbacks: Optional[List[BaseRoute]] = None,
900
- openapi_extra: Optional[Dict[str, Any]] = None,
901
- generate_unique_id_function: Callable[[APIRoute], str] = Default(
902
- generate_unique_id
903
- ),
904
- ) -> Callable[[DecoratedCallable], DecoratedCallable]:
905
- return self.api_route(
906
- path=path,
907
- response_model=response_model,
908
- status_code=status_code,
909
- tags=tags,
910
- dependencies=dependencies,
911
- summary=summary,
912
- description=description,
913
- response_description=response_description,
914
- responses=responses,
915
- deprecated=deprecated,
916
- methods=["GET"],
917
- operation_id=operation_id,
918
- response_model_include=response_model_include,
919
- response_model_exclude=response_model_exclude,
920
- response_model_by_alias=response_model_by_alias,
921
- response_model_exclude_unset=response_model_exclude_unset,
922
- response_model_exclude_defaults=response_model_exclude_defaults,
923
- response_model_exclude_none=response_model_exclude_none,
924
- include_in_schema=include_in_schema,
925
- response_class=response_class,
926
- name=name,
927
- callbacks=callbacks,
928
- openapi_extra=openapi_extra,
929
- generate_unique_id_function=generate_unique_id_function,
930
- )
931
-
932
- def put(
933
- self,
934
- path: str,
935
- *,
936
- response_model: Any = Default(None),
937
- status_code: Optional[int] = None,
938
- tags: Optional[List[Union[str, Enum]]] = None,
939
- dependencies: Optional[Sequence[params.Depends]] = None,
940
- summary: Optional[str] = None,
941
- description: Optional[str] = None,
942
- response_description: str = "Successful Response",
943
- responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None,
944
- deprecated: Optional[bool] = None,
945
- operation_id: Optional[str] = None,
946
- response_model_include: Optional[Union[SetIntStr, DictIntStrAny]] = None,
947
- response_model_exclude: Optional[Union[SetIntStr, DictIntStrAny]] = None,
948
- response_model_by_alias: bool = True,
949
- response_model_exclude_unset: bool = False,
950
- response_model_exclude_defaults: bool = False,
951
- response_model_exclude_none: bool = False,
952
- include_in_schema: bool = True,
953
- response_class: Type[Response] = Default(JSONResponse),
954
- name: Optional[str] = None,
955
- callbacks: Optional[List[BaseRoute]] = None,
956
- openapi_extra: Optional[Dict[str, Any]] = None,
957
- generate_unique_id_function: Callable[[APIRoute], str] = Default(
958
- generate_unique_id
959
- ),
960
- ) -> Callable[[DecoratedCallable], DecoratedCallable]:
961
- return self.api_route(
962
- path=path,
963
- response_model=response_model,
964
- status_code=status_code,
965
- tags=tags,
966
- dependencies=dependencies,
967
- summary=summary,
968
- description=description,
969
- response_description=response_description,
970
- responses=responses,
971
- deprecated=deprecated,
972
- methods=["PUT"],
973
- operation_id=operation_id,
974
- response_model_include=response_model_include,
975
- response_model_exclude=response_model_exclude,
976
- response_model_by_alias=response_model_by_alias,
977
- response_model_exclude_unset=response_model_exclude_unset,
978
- response_model_exclude_defaults=response_model_exclude_defaults,
979
- response_model_exclude_none=response_model_exclude_none,
980
- include_in_schema=include_in_schema,
981
- response_class=response_class,
982
- name=name,
983
- callbacks=callbacks,
984
- openapi_extra=openapi_extra,
985
- generate_unique_id_function=generate_unique_id_function,
986
- )
987
-
988
- def post(
989
- self,
990
- path: str,
991
- *,
992
- response_model: Any = Default(None),
993
- status_code: Optional[int] = None,
994
- tags: Optional[List[Union[str, Enum]]] = None,
995
- dependencies: Optional[Sequence[params.Depends]] = None,
996
- summary: Optional[str] = None,
997
- description: Optional[str] = None,
998
- response_description: str = "Successful Response",
999
- responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None,
1000
- deprecated: Optional[bool] = None,
1001
- operation_id: Optional[str] = None,
1002
- response_model_include: Optional[Union[SetIntStr, DictIntStrAny]] = None,
1003
- response_model_exclude: Optional[Union[SetIntStr, DictIntStrAny]] = None,
1004
- response_model_by_alias: bool = True,
1005
- response_model_exclude_unset: bool = False,
1006
- response_model_exclude_defaults: bool = False,
1007
- response_model_exclude_none: bool = False,
1008
- include_in_schema: bool = True,
1009
- response_class: Type[Response] = Default(JSONResponse),
1010
- name: Optional[str] = None,
1011
- callbacks: Optional[List[BaseRoute]] = None,
1012
- openapi_extra: Optional[Dict[str, Any]] = None,
1013
- generate_unique_id_function: Callable[[APIRoute], str] = Default(
1014
- generate_unique_id
1015
- ),
1016
- ) -> Callable[[DecoratedCallable], DecoratedCallable]:
1017
- return self.api_route(
1018
- path=path,
1019
- response_model=response_model,
1020
- status_code=status_code,
1021
- tags=tags,
1022
- dependencies=dependencies,
1023
- summary=summary,
1024
- description=description,
1025
- response_description=response_description,
1026
- responses=responses,
1027
- deprecated=deprecated,
1028
- methods=["POST"],
1029
- operation_id=operation_id,
1030
- response_model_include=response_model_include,
1031
- response_model_exclude=response_model_exclude,
1032
- response_model_by_alias=response_model_by_alias,
1033
- response_model_exclude_unset=response_model_exclude_unset,
1034
- response_model_exclude_defaults=response_model_exclude_defaults,
1035
- response_model_exclude_none=response_model_exclude_none,
1036
- include_in_schema=include_in_schema,
1037
- response_class=response_class,
1038
- name=name,
1039
- callbacks=callbacks,
1040
- openapi_extra=openapi_extra,
1041
- generate_unique_id_function=generate_unique_id_function,
1042
- )
1043
-
1044
- def delete(
1045
- self,
1046
- path: str,
1047
- *,
1048
- response_model: Any = Default(None),
1049
- status_code: Optional[int] = None,
1050
- tags: Optional[List[Union[str, Enum]]] = None,
1051
- dependencies: Optional[Sequence[params.Depends]] = None,
1052
- summary: Optional[str] = None,
1053
- description: Optional[str] = None,
1054
- response_description: str = "Successful Response",
1055
- responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None,
1056
- deprecated: Optional[bool] = None,
1057
- operation_id: Optional[str] = None,
1058
- response_model_include: Optional[Union[SetIntStr, DictIntStrAny]] = None,
1059
- response_model_exclude: Optional[Union[SetIntStr, DictIntStrAny]] = None,
1060
- response_model_by_alias: bool = True,
1061
- response_model_exclude_unset: bool = False,
1062
- response_model_exclude_defaults: bool = False,
1063
- response_model_exclude_none: bool = False,
1064
- include_in_schema: bool = True,
1065
- response_class: Type[Response] = Default(JSONResponse),
1066
- name: Optional[str] = None,
1067
- callbacks: Optional[List[BaseRoute]] = None,
1068
- openapi_extra: Optional[Dict[str, Any]] = None,
1069
- generate_unique_id_function: Callable[[APIRoute], str] = Default(
1070
- generate_unique_id
1071
- ),
1072
- ) -> Callable[[DecoratedCallable], DecoratedCallable]:
1073
- return self.api_route(
1074
- path=path,
1075
- response_model=response_model,
1076
- status_code=status_code,
1077
- tags=tags,
1078
- dependencies=dependencies,
1079
- summary=summary,
1080
- description=description,
1081
- response_description=response_description,
1082
- responses=responses,
1083
- deprecated=deprecated,
1084
- methods=["DELETE"],
1085
- operation_id=operation_id,
1086
- response_model_include=response_model_include,
1087
- response_model_exclude=response_model_exclude,
1088
- response_model_by_alias=response_model_by_alias,
1089
- response_model_exclude_unset=response_model_exclude_unset,
1090
- response_model_exclude_defaults=response_model_exclude_defaults,
1091
- response_model_exclude_none=response_model_exclude_none,
1092
- include_in_schema=include_in_schema,
1093
- response_class=response_class,
1094
- name=name,
1095
- callbacks=callbacks,
1096
- openapi_extra=openapi_extra,
1097
- generate_unique_id_function=generate_unique_id_function,
1098
- )
1099
-
1100
- def options(
1101
- self,
1102
- path: str,
1103
- *,
1104
- response_model: Any = Default(None),
1105
- status_code: Optional[int] = None,
1106
- tags: Optional[List[Union[str, Enum]]] = None,
1107
- dependencies: Optional[Sequence[params.Depends]] = None,
1108
- summary: Optional[str] = None,
1109
- description: Optional[str] = None,
1110
- response_description: str = "Successful Response",
1111
- responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None,
1112
- deprecated: Optional[bool] = None,
1113
- operation_id: Optional[str] = None,
1114
- response_model_include: Optional[Union[SetIntStr, DictIntStrAny]] = None,
1115
- response_model_exclude: Optional[Union[SetIntStr, DictIntStrAny]] = None,
1116
- response_model_by_alias: bool = True,
1117
- response_model_exclude_unset: bool = False,
1118
- response_model_exclude_defaults: bool = False,
1119
- response_model_exclude_none: bool = False,
1120
- include_in_schema: bool = True,
1121
- response_class: Type[Response] = Default(JSONResponse),
1122
- name: Optional[str] = None,
1123
- callbacks: Optional[List[BaseRoute]] = None,
1124
- openapi_extra: Optional[Dict[str, Any]] = None,
1125
- generate_unique_id_function: Callable[[APIRoute], str] = Default(
1126
- generate_unique_id
1127
- ),
1128
- ) -> Callable[[DecoratedCallable], DecoratedCallable]:
1129
- return self.api_route(
1130
- path=path,
1131
- response_model=response_model,
1132
- status_code=status_code,
1133
- tags=tags,
1134
- dependencies=dependencies,
1135
- summary=summary,
1136
- description=description,
1137
- response_description=response_description,
1138
- responses=responses,
1139
- deprecated=deprecated,
1140
- methods=["OPTIONS"],
1141
- operation_id=operation_id,
1142
- response_model_include=response_model_include,
1143
- response_model_exclude=response_model_exclude,
1144
- response_model_by_alias=response_model_by_alias,
1145
- response_model_exclude_unset=response_model_exclude_unset,
1146
- response_model_exclude_defaults=response_model_exclude_defaults,
1147
- response_model_exclude_none=response_model_exclude_none,
1148
- include_in_schema=include_in_schema,
1149
- response_class=response_class,
1150
- name=name,
1151
- callbacks=callbacks,
1152
- openapi_extra=openapi_extra,
1153
- generate_unique_id_function=generate_unique_id_function,
1154
- )
1155
-
1156
- def head(
1157
- self,
1158
- path: str,
1159
- *,
1160
- response_model: Any = Default(None),
1161
- status_code: Optional[int] = None,
1162
- tags: Optional[List[Union[str, Enum]]] = None,
1163
- dependencies: Optional[Sequence[params.Depends]] = None,
1164
- summary: Optional[str] = None,
1165
- description: Optional[str] = None,
1166
- response_description: str = "Successful Response",
1167
- responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None,
1168
- deprecated: Optional[bool] = None,
1169
- operation_id: Optional[str] = None,
1170
- response_model_include: Optional[Union[SetIntStr, DictIntStrAny]] = None,
1171
- response_model_exclude: Optional[Union[SetIntStr, DictIntStrAny]] = None,
1172
- response_model_by_alias: bool = True,
1173
- response_model_exclude_unset: bool = False,
1174
- response_model_exclude_defaults: bool = False,
1175
- response_model_exclude_none: bool = False,
1176
- include_in_schema: bool = True,
1177
- response_class: Type[Response] = Default(JSONResponse),
1178
- name: Optional[str] = None,
1179
- callbacks: Optional[List[BaseRoute]] = None,
1180
- openapi_extra: Optional[Dict[str, Any]] = None,
1181
- generate_unique_id_function: Callable[[APIRoute], str] = Default(
1182
- generate_unique_id
1183
- ),
1184
- ) -> Callable[[DecoratedCallable], DecoratedCallable]:
1185
- return self.api_route(
1186
- path=path,
1187
- response_model=response_model,
1188
- status_code=status_code,
1189
- tags=tags,
1190
- dependencies=dependencies,
1191
- summary=summary,
1192
- description=description,
1193
- response_description=response_description,
1194
- responses=responses,
1195
- deprecated=deprecated,
1196
- methods=["HEAD"],
1197
- operation_id=operation_id,
1198
- response_model_include=response_model_include,
1199
- response_model_exclude=response_model_exclude,
1200
- response_model_by_alias=response_model_by_alias,
1201
- response_model_exclude_unset=response_model_exclude_unset,
1202
- response_model_exclude_defaults=response_model_exclude_defaults,
1203
- response_model_exclude_none=response_model_exclude_none,
1204
- include_in_schema=include_in_schema,
1205
- response_class=response_class,
1206
- name=name,
1207
- callbacks=callbacks,
1208
- openapi_extra=openapi_extra,
1209
- generate_unique_id_function=generate_unique_id_function,
1210
- )
1211
-
1212
- def patch(
1213
- self,
1214
- path: str,
1215
- *,
1216
- response_model: Any = Default(None),
1217
- status_code: Optional[int] = None,
1218
- tags: Optional[List[Union[str, Enum]]] = None,
1219
- dependencies: Optional[Sequence[params.Depends]] = None,
1220
- summary: Optional[str] = None,
1221
- description: Optional[str] = None,
1222
- response_description: str = "Successful Response",
1223
- responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None,
1224
- deprecated: Optional[bool] = None,
1225
- operation_id: Optional[str] = None,
1226
- response_model_include: Optional[Union[SetIntStr, DictIntStrAny]] = None,
1227
- response_model_exclude: Optional[Union[SetIntStr, DictIntStrAny]] = None,
1228
- response_model_by_alias: bool = True,
1229
- response_model_exclude_unset: bool = False,
1230
- response_model_exclude_defaults: bool = False,
1231
- response_model_exclude_none: bool = False,
1232
- include_in_schema: bool = True,
1233
- response_class: Type[Response] = Default(JSONResponse),
1234
- name: Optional[str] = None,
1235
- callbacks: Optional[List[BaseRoute]] = None,
1236
- openapi_extra: Optional[Dict[str, Any]] = None,
1237
- generate_unique_id_function: Callable[[APIRoute], str] = Default(
1238
- generate_unique_id
1239
- ),
1240
- ) -> Callable[[DecoratedCallable], DecoratedCallable]:
1241
- return self.api_route(
1242
- path=path,
1243
- response_model=response_model,
1244
- status_code=status_code,
1245
- tags=tags,
1246
- dependencies=dependencies,
1247
- summary=summary,
1248
- description=description,
1249
- response_description=response_description,
1250
- responses=responses,
1251
- deprecated=deprecated,
1252
- methods=["PATCH"],
1253
- operation_id=operation_id,
1254
- response_model_include=response_model_include,
1255
- response_model_exclude=response_model_exclude,
1256
- response_model_by_alias=response_model_by_alias,
1257
- response_model_exclude_unset=response_model_exclude_unset,
1258
- response_model_exclude_defaults=response_model_exclude_defaults,
1259
- response_model_exclude_none=response_model_exclude_none,
1260
- include_in_schema=include_in_schema,
1261
- response_class=response_class,
1262
- name=name,
1263
- callbacks=callbacks,
1264
- openapi_extra=openapi_extra,
1265
- generate_unique_id_function=generate_unique_id_function,
1266
- )
1267
-
1268
- def trace(
1269
- self,
1270
- path: str,
1271
- *,
1272
- response_model: Any = Default(None),
1273
- status_code: Optional[int] = None,
1274
- tags: Optional[List[Union[str, Enum]]] = None,
1275
- dependencies: Optional[Sequence[params.Depends]] = None,
1276
- summary: Optional[str] = None,
1277
- description: Optional[str] = None,
1278
- response_description: str = "Successful Response",
1279
- responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None,
1280
- deprecated: Optional[bool] = None,
1281
- operation_id: Optional[str] = None,
1282
- response_model_include: Optional[Union[SetIntStr, DictIntStrAny]] = None,
1283
- response_model_exclude: Optional[Union[SetIntStr, DictIntStrAny]] = None,
1284
- response_model_by_alias: bool = True,
1285
- response_model_exclude_unset: bool = False,
1286
- response_model_exclude_defaults: bool = False,
1287
- response_model_exclude_none: bool = False,
1288
- include_in_schema: bool = True,
1289
- response_class: Type[Response] = Default(JSONResponse),
1290
- name: Optional[str] = None,
1291
- callbacks: Optional[List[BaseRoute]] = None,
1292
- openapi_extra: Optional[Dict[str, Any]] = None,
1293
- generate_unique_id_function: Callable[[APIRoute], str] = Default(
1294
- generate_unique_id
1295
- ),
1296
- ) -> Callable[[DecoratedCallable], DecoratedCallable]:
1297
- return self.api_route(
1298
- path=path,
1299
- response_model=response_model,
1300
- status_code=status_code,
1301
- tags=tags,
1302
- dependencies=dependencies,
1303
- summary=summary,
1304
- description=description,
1305
- response_description=response_description,
1306
- responses=responses,
1307
- deprecated=deprecated,
1308
- methods=["TRACE"],
1309
- operation_id=operation_id,
1310
- response_model_include=response_model_include,
1311
- response_model_exclude=response_model_exclude,
1312
- response_model_by_alias=response_model_by_alias,
1313
- response_model_exclude_unset=response_model_exclude_unset,
1314
- response_model_exclude_defaults=response_model_exclude_defaults,
1315
- response_model_exclude_none=response_model_exclude_none,
1316
- include_in_schema=include_in_schema,
1317
- response_class=response_class,
1318
- name=name,
1319
- callbacks=callbacks,
1320
- openapi_extra=openapi_extra,
1321
- generate_unique_id_function=generate_unique_id_function,
1322
- )
1323
-
1324
- def on_event(
1325
- self, event_type: str
1326
- ) -> Callable[[DecoratedCallable], DecoratedCallable]:
1327
- def decorator(func: DecoratedCallable) -> DecoratedCallable:
1328
- self.add_event_handler(event_type, func)
1329
- return func
1330
-
1331
- return decorator