cadwyn 3.15.1__py3-none-any.whl → 3.15.3__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.
Potentially problematic release.
This version of cadwyn might be problematic. Click here for more details.
- cadwyn/applications.py +108 -13
- cadwyn/routing.py +37 -5
- {cadwyn-3.15.1.dist-info → cadwyn-3.15.3.dist-info}/METADATA +1 -1
- {cadwyn-3.15.1.dist-info → cadwyn-3.15.3.dist-info}/RECORD +7 -7
- {cadwyn-3.15.1.dist-info → cadwyn-3.15.3.dist-info}/LICENSE +0 -0
- {cadwyn-3.15.1.dist-info → cadwyn-3.15.3.dist-info}/WHEEL +0 -0
- {cadwyn-3.15.1.dist-info → cadwyn-3.15.3.dist-info}/entry_points.txt +0 -0
cadwyn/applications.py
CHANGED
|
@@ -24,6 +24,7 @@ from starlette.routing import BaseRoute, Route
|
|
|
24
24
|
from starlette.types import Lifespan
|
|
25
25
|
from typing_extensions import Self, deprecated
|
|
26
26
|
|
|
27
|
+
from cadwyn._utils import same_definition_as_in
|
|
27
28
|
from cadwyn.middleware import HeaderVersioningMiddleware, _get_api_version_dependency
|
|
28
29
|
from cadwyn.route_generation import generate_versioned_routers
|
|
29
30
|
from cadwyn.routing import _RootHeaderAPIRouter
|
|
@@ -58,8 +59,13 @@ class Cadwyn(FastAPI):
|
|
|
58
59
|
swagger_ui_oauth2_redirect_url: str | None = "/docs/oauth2-redirect",
|
|
59
60
|
swagger_ui_init_oauth: dict[str, Any] | None = None,
|
|
60
61
|
middleware: Sequence[Middleware] | None = None,
|
|
61
|
-
exception_handlers:
|
|
62
|
-
|
|
62
|
+
exception_handlers: (
|
|
63
|
+
dict[
|
|
64
|
+
int | type[Exception],
|
|
65
|
+
Callable[[Request, Any], Coroutine[Any, Any, Response]],
|
|
66
|
+
]
|
|
67
|
+
| None
|
|
68
|
+
) = None,
|
|
63
69
|
on_startup: Sequence[Callable[[], Any]] | None = None,
|
|
64
70
|
on_shutdown: Sequence[Callable[[], Any]] | None = None,
|
|
65
71
|
lifespan: Lifespan[Self] | None = None,
|
|
@@ -75,7 +81,9 @@ class Cadwyn(FastAPI):
|
|
|
75
81
|
deprecated: bool | None = None,
|
|
76
82
|
include_in_schema: bool = True,
|
|
77
83
|
swagger_ui_parameters: dict[str, Any] | None = None,
|
|
78
|
-
generate_unique_id_function: Callable[[routing.APIRoute], str] = Default(
|
|
84
|
+
generate_unique_id_function: Callable[[routing.APIRoute], str] = Default( # noqa: B008
|
|
85
|
+
generate_unique_id
|
|
86
|
+
),
|
|
79
87
|
separate_input_output_schemas: bool = True,
|
|
80
88
|
**extra: Any,
|
|
81
89
|
) -> None:
|
|
@@ -143,8 +151,6 @@ class Cadwyn(FastAPI):
|
|
|
143
151
|
api_version_var=self.versions.api_version_var,
|
|
144
152
|
)
|
|
145
153
|
|
|
146
|
-
self.add_event_handler("startup", self.enrich_swagger)
|
|
147
|
-
|
|
148
154
|
self.docs_url = docs_url
|
|
149
155
|
self.redoc_url = redoc_url
|
|
150
156
|
self.openapi_url = openapi_url
|
|
@@ -229,7 +235,7 @@ class Cadwyn(FastAPI):
|
|
|
229
235
|
terms_of_service=self.terms_of_service,
|
|
230
236
|
contact=self.contact,
|
|
231
237
|
license_info=self.license_info,
|
|
232
|
-
routes=self.router.
|
|
238
|
+
routes=self.router.unversioned_routes,
|
|
233
239
|
tags=self.openapi_tags,
|
|
234
240
|
servers=self.servers,
|
|
235
241
|
)
|
|
@@ -317,29 +323,118 @@ class Cadwyn(FastAPI):
|
|
|
317
323
|
except ValueError as e:
|
|
318
324
|
raise ValueError("header_value should be in ISO 8601 format") from e
|
|
319
325
|
|
|
326
|
+
added_routes: list[BaseRoute] = []
|
|
320
327
|
if header_value_as_dt not in self.router.versioned_routers: # pragma: no branch
|
|
321
328
|
self.router.versioned_routers[header_value_as_dt] = APIRouter(**self._kwargs_to_router)
|
|
322
|
-
if self.openapi_url is not None: # pragma: no branch
|
|
323
|
-
self.router.versioned_routers[header_value_as_dt].add_route(
|
|
324
|
-
path=self.openapi_url,
|
|
325
|
-
endpoint=self.openapi_jsons,
|
|
326
|
-
include_in_schema=False,
|
|
327
|
-
)
|
|
328
329
|
|
|
329
|
-
|
|
330
|
+
versioned_router = self.router.versioned_routers[header_value_as_dt]
|
|
331
|
+
if self.openapi_url is not None: # pragma: no branch
|
|
332
|
+
versioned_router.add_route(
|
|
333
|
+
path=self.openapi_url,
|
|
334
|
+
endpoint=self.openapi_jsons,
|
|
335
|
+
include_in_schema=False,
|
|
336
|
+
)
|
|
337
|
+
added_routes.append(versioned_router.routes[-1])
|
|
338
|
+
|
|
339
|
+
added_route_count = 0
|
|
330
340
|
for router in (first_router, *other_routers):
|
|
331
341
|
self.router.versioned_routers[header_value_as_dt].include_router(
|
|
332
342
|
router,
|
|
333
343
|
dependencies=[Depends(_get_api_version_dependency(self.router.api_version_header_name, header_value))],
|
|
334
344
|
)
|
|
345
|
+
added_route_count += len(router.routes)
|
|
346
|
+
|
|
347
|
+
added_routes.extend(versioned_router.routes[-added_route_count:])
|
|
348
|
+
self.router.routes.extend(added_routes)
|
|
335
349
|
|
|
350
|
+
self.enrich_swagger()
|
|
336
351
|
return added_routes
|
|
337
352
|
|
|
338
353
|
def add_unversioned_routers(self, *routers: APIRouter):
|
|
339
354
|
for router in routers:
|
|
340
355
|
self.router.include_router(router)
|
|
356
|
+
self.enrich_swagger()
|
|
341
357
|
|
|
342
358
|
@deprecated("Use add add_unversioned_routers instead")
|
|
343
359
|
def add_unversioned_routes(self, *routes: Route):
|
|
344
360
|
router = APIRouter(routes=list(routes))
|
|
345
361
|
self.include_router(router)
|
|
362
|
+
self.enrich_swagger()
|
|
363
|
+
|
|
364
|
+
@same_definition_as_in(FastAPI.include_router)
|
|
365
|
+
def include_router(self, *args: Any, **kwargs: Any):
|
|
366
|
+
route = super().include_router(*args, **kwargs)
|
|
367
|
+
self.enrich_swagger()
|
|
368
|
+
return route
|
|
369
|
+
|
|
370
|
+
@same_definition_as_in(FastAPI.post)
|
|
371
|
+
def post(self, *args: Any, **kwargs: Any):
|
|
372
|
+
route = super().post(*args, **kwargs)
|
|
373
|
+
self.enrich_swagger()
|
|
374
|
+
return route
|
|
375
|
+
|
|
376
|
+
@same_definition_as_in(FastAPI.get)
|
|
377
|
+
def get(self, *args: Any, **kwargs: Any):
|
|
378
|
+
route = super().get(*args, **kwargs)
|
|
379
|
+
self.enrich_swagger()
|
|
380
|
+
return route
|
|
381
|
+
|
|
382
|
+
@same_definition_as_in(FastAPI.patch)
|
|
383
|
+
def patch(self, *args: Any, **kwargs: Any):
|
|
384
|
+
route = super().patch(*args, **kwargs)
|
|
385
|
+
self.enrich_swagger()
|
|
386
|
+
return route
|
|
387
|
+
|
|
388
|
+
@same_definition_as_in(FastAPI.delete)
|
|
389
|
+
def delete(self, *args: Any, **kwargs: Any):
|
|
390
|
+
route = super().delete(*args, **kwargs)
|
|
391
|
+
self.enrich_swagger()
|
|
392
|
+
return route
|
|
393
|
+
|
|
394
|
+
@same_definition_as_in(FastAPI.put)
|
|
395
|
+
def put(self, *args: Any, **kwargs: Any):
|
|
396
|
+
route = super().put(*args, **kwargs)
|
|
397
|
+
self.enrich_swagger()
|
|
398
|
+
return route
|
|
399
|
+
|
|
400
|
+
@same_definition_as_in(FastAPI.trace)
|
|
401
|
+
def trace(self, *args: Any, **kwargs: Any): # pragma: no cover
|
|
402
|
+
route = super().trace(*args, **kwargs)
|
|
403
|
+
self.enrich_swagger()
|
|
404
|
+
return route
|
|
405
|
+
|
|
406
|
+
@same_definition_as_in(FastAPI.options)
|
|
407
|
+
def options(self, *args: Any, **kwargs: Any):
|
|
408
|
+
route = super().options(*args, **kwargs)
|
|
409
|
+
self.enrich_swagger()
|
|
410
|
+
return route
|
|
411
|
+
|
|
412
|
+
@same_definition_as_in(FastAPI.head)
|
|
413
|
+
def head(self, *args: Any, **kwargs: Any):
|
|
414
|
+
route = super().head(*args, **kwargs)
|
|
415
|
+
self.enrich_swagger()
|
|
416
|
+
return route
|
|
417
|
+
|
|
418
|
+
@same_definition_as_in(FastAPI.add_api_route)
|
|
419
|
+
def add_api_route(self, *args: Any, **kwargs: Any):
|
|
420
|
+
route = super().add_api_route(*args, **kwargs)
|
|
421
|
+
self.enrich_swagger()
|
|
422
|
+
return route
|
|
423
|
+
|
|
424
|
+
@same_definition_as_in(FastAPI.api_route)
|
|
425
|
+
def api_route(self, *args: Any, **kwargs: Any):
|
|
426
|
+
route = super().api_route(*args, **kwargs)
|
|
427
|
+
self.enrich_swagger()
|
|
428
|
+
return route
|
|
429
|
+
|
|
430
|
+
@same_definition_as_in(FastAPI.add_api_websocket_route)
|
|
431
|
+
def add_api_websocket_route(self, *args: Any, **kwargs: Any): # pragma: no cover
|
|
432
|
+
route = super().add_api_websocket_route(*args, **kwargs)
|
|
433
|
+
self.enrich_swagger()
|
|
434
|
+
return route
|
|
435
|
+
|
|
436
|
+
@same_definition_as_in(FastAPI.websocket)
|
|
437
|
+
def websocket(self, *args: Any, **kwargs: Any): # pragma: no cover
|
|
438
|
+
route = super().websocket(*args, **kwargs)
|
|
439
|
+
self.enrich_swagger()
|
|
440
|
+
return route
|
cadwyn/routing.py
CHANGED
|
@@ -9,10 +9,15 @@ from typing import Any
|
|
|
9
9
|
from fastapi.routing import APIRouter
|
|
10
10
|
from starlette.datastructures import URL
|
|
11
11
|
from starlette.responses import RedirectResponse
|
|
12
|
-
from starlette.routing import BaseRoute, Match
|
|
12
|
+
from starlette.routing import BaseRoute, Match, Route
|
|
13
13
|
from starlette.types import Receive, Scope, Send
|
|
14
14
|
|
|
15
|
-
from .
|
|
15
|
+
from cadwyn._utils import same_definition_as_in
|
|
16
|
+
|
|
17
|
+
from .route_generation import (
|
|
18
|
+
InternalRepresentationOf,
|
|
19
|
+
generate_versioned_routers,
|
|
20
|
+
)
|
|
16
21
|
|
|
17
22
|
# TODO: Remove this in a major version. This is only here for backwards compatibility
|
|
18
23
|
__all__ = ["InternalRepresentationOf", "generate_versioned_routers"]
|
|
@@ -46,6 +51,7 @@ class _RootHeaderAPIRouter(APIRouter):
|
|
|
46
51
|
self.versioned_routers: dict[date, APIRouter] = {}
|
|
47
52
|
self.api_version_header_name = api_version_header_name.lower()
|
|
48
53
|
self.api_version_var = api_version_var
|
|
54
|
+
self.unversioned_routes: list[Route] = []
|
|
49
55
|
|
|
50
56
|
@cached_property
|
|
51
57
|
def sorted_versions(self):
|
|
@@ -68,13 +74,19 @@ class _RootHeaderAPIRouter(APIRouter):
|
|
|
68
74
|
# then the request version is older that the oldest route we have
|
|
69
75
|
_logger.info(
|
|
70
76
|
"Request version is older than the oldest version. No route can match this version",
|
|
71
|
-
extra={
|
|
77
|
+
extra={
|
|
78
|
+
"oldest_version": self.min_routes_version.isoformat(),
|
|
79
|
+
"request_version": request_version,
|
|
80
|
+
},
|
|
72
81
|
)
|
|
73
82
|
return []
|
|
74
83
|
version_chosen = self.find_closest_date_but_not_new(request_header_value)
|
|
75
84
|
_logger.info(
|
|
76
85
|
"Partial match. The endpoint with a lower version was selected for the API call",
|
|
77
|
-
extra={
|
|
86
|
+
extra={
|
|
87
|
+
"version_chosen": version_chosen,
|
|
88
|
+
"request_version": request_version,
|
|
89
|
+
},
|
|
78
90
|
)
|
|
79
91
|
return self.versioned_routers[version_chosen].routes
|
|
80
92
|
|
|
@@ -94,13 +106,33 @@ class _RootHeaderAPIRouter(APIRouter):
|
|
|
94
106
|
# if header_value is None, then it's an unversioned request and we need to use the unversioned routes
|
|
95
107
|
# if there will be a value, we search for the most suitable version
|
|
96
108
|
if not header_value:
|
|
97
|
-
routes = self.
|
|
109
|
+
routes = self.unversioned_routes
|
|
98
110
|
elif header_value in self.versioned_routers:
|
|
99
111
|
routes = self.versioned_routers[header_value].routes
|
|
100
112
|
else:
|
|
101
113
|
routes = self.pick_version(request_header_value=header_value)
|
|
102
114
|
await self.process_request(scope=scope, receive=receive, send=send, routes=routes)
|
|
103
115
|
|
|
116
|
+
@same_definition_as_in(APIRouter.add_api_route)
|
|
117
|
+
def add_api_route(self, *args: Any, **kwargs: Any):
|
|
118
|
+
super().add_api_route(*args, **kwargs)
|
|
119
|
+
self.unversioned_routes.append(self.routes[-1])
|
|
120
|
+
|
|
121
|
+
@same_definition_as_in(APIRouter.add_route)
|
|
122
|
+
def add_route(self, *args: Any, **kwargs: Any):
|
|
123
|
+
super().add_route(*args, **kwargs)
|
|
124
|
+
self.unversioned_routes.append(self.routes[-1])
|
|
125
|
+
|
|
126
|
+
@same_definition_as_in(APIRouter.add_api_websocket_route)
|
|
127
|
+
def add_api_websocket_route(self, *args: Any, **kwargs: Any): # pragma: no cover
|
|
128
|
+
super().add_api_websocket_route(*args, **kwargs)
|
|
129
|
+
self.unversioned_routes.append(self.routes[-1])
|
|
130
|
+
|
|
131
|
+
@same_definition_as_in(APIRouter.add_websocket_route)
|
|
132
|
+
def add_websocket_route(self, *args: Any, **kwargs: Any): # pragma: no cover
|
|
133
|
+
super().add_websocket_route(*args, **kwargs)
|
|
134
|
+
self.unversioned_routes.append(self.routes[-1])
|
|
135
|
+
|
|
104
136
|
async def process_request(self, scope: Scope, receive: Receive, send: Send, routes: Sequence[BaseRoute]) -> None:
|
|
105
137
|
"""
|
|
106
138
|
its a copy-paste from starlette.routing.Router
|
|
@@ -4,7 +4,7 @@ cadwyn/_asts.py,sha256=OF1qQKPqTbgYhH1tYF-MB8CCU0r6YITZpMFegzmk0Ic,10118
|
|
|
4
4
|
cadwyn/_compat.py,sha256=yAPmfGl2vVEYXlNHHPMoa2JkEJCVPjbP_Uz0WOIVOp4,5494
|
|
5
5
|
cadwyn/_package_utils.py,sha256=trxTYLmppv-10SKhScfyDQJh21rsQGFoLaOtHycKKR0,1443
|
|
6
6
|
cadwyn/_utils.py,sha256=BFsfZBpdoL5RMAaT1V1cXJVpTZCmwksQ-Le2MTHivGI,4841
|
|
7
|
-
cadwyn/applications.py,sha256=
|
|
7
|
+
cadwyn/applications.py,sha256=3J_MLmwItVnGbIrqtiO7jwKoXIYkZJ2MYBX-hNRWaS8,17591
|
|
8
8
|
cadwyn/codegen/README.md,sha256=hc7AE87LsEsvbh-wX1H10JEWh-8bLHoe-1CkY3h00FI,879
|
|
9
9
|
cadwyn/codegen/__init__.py,sha256=JgddDjxMTjSfVrMXHwNu1ODgdn2QfPWpccrRKquBV6k,355
|
|
10
10
|
cadwyn/codegen/_common.py,sha256=FTI4fqpUFGBMACVlPiDMHTWhqwW_-zQNa_4Qh7m-hCA,5877
|
|
@@ -20,7 +20,7 @@ cadwyn/main.py,sha256=kt2Vn7TIA4ZnD_xrgz57TOjUk-4zVP8SV8nuTZBEaaU,218
|
|
|
20
20
|
cadwyn/middleware.py,sha256=8cuBri_yRkl0goe6G0MLwtL04WGbW9Infah3wy9hUVM,3372
|
|
21
21
|
cadwyn/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
22
22
|
cadwyn/route_generation.py,sha256=nn_PWDa2WQOF-z3IOYBfG9K8po0tHm2C_Q0sRJRr5Ck,39843
|
|
23
|
-
cadwyn/routing.py,sha256=
|
|
23
|
+
cadwyn/routing.py,sha256=3rxo4jzdL4rD5EntSAW9ZPWvYfD8AEy8olRum7iSE8A,7411
|
|
24
24
|
cadwyn/static/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
25
25
|
cadwyn/static/docs.html,sha256=WNm5ANJVy51TcIUFOaqKf1Z8eF86CC85TTHPxACtkzw,3455
|
|
26
26
|
cadwyn/structure/__init__.py,sha256=HjaNd6H4m4Cia42-dCO7A7sLWuVII7oldjaCabhbs_o,697
|
|
@@ -31,8 +31,8 @@ cadwyn/structure/enums.py,sha256=iMokxA2QYJ61SzyB-Pmuq3y7KL7-e6TsnjLVUaVZQnw,954
|
|
|
31
31
|
cadwyn/structure/modules.py,sha256=1FK-lLm-zOTXEvn-QtyBH38aDRht5PDQiZrOPCsBlM4,1268
|
|
32
32
|
cadwyn/structure/schemas.py,sha256=0ylArAkUw626VkUOJSulOwJs7CS6lrGBRECEG5HFD4Q,8897
|
|
33
33
|
cadwyn/structure/versions.py,sha256=PuXYze89tWvLsOOiuAQtYRi-p1ue2FPfBWWR2bl8hLg,37236
|
|
34
|
-
cadwyn-3.15.
|
|
35
|
-
cadwyn-3.15.
|
|
36
|
-
cadwyn-3.15.
|
|
37
|
-
cadwyn-3.15.
|
|
38
|
-
cadwyn-3.15.
|
|
34
|
+
cadwyn-3.15.3.dist-info/LICENSE,sha256=KeCWewiDQYpmSnzF-p_0YpoWiyDcUPaCuG8OWQs4ig4,1072
|
|
35
|
+
cadwyn-3.15.3.dist-info/METADATA,sha256=0Pb2wYzcfzNUs3RLWRFqhAiYzLLQ0-49iK1ie0vMfjg,4397
|
|
36
|
+
cadwyn-3.15.3.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
|
|
37
|
+
cadwyn-3.15.3.dist-info/entry_points.txt,sha256=eO05hLn9GoRzzpwT9GONPmXKsonjuMNssM2D2WHWKGk,46
|
|
38
|
+
cadwyn-3.15.3.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|