cadwyn 3.11.1__py3-none-any.whl → 3.12.1__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/__main__.py CHANGED
@@ -115,8 +115,7 @@ def _get_version_bundle(possibly_version_bundle: Any) -> VersionBundle:
115
115
  @app.callback()
116
116
  def main(
117
117
  version: bool = typer.Option(None, "-V", "--version", callback=version_callback, is_eager=True),
118
- ):
119
- ...
118
+ ): ...
120
119
 
121
120
 
122
121
  if __name__ == "__main__":
cadwyn/applications.py CHANGED
@@ -19,6 +19,7 @@ from starlette.routing import BaseRoute, Route
19
19
  from starlette.types import Lifespan
20
20
  from typing_extensions import Self, deprecated
21
21
 
22
+ from cadwyn._utils import same_definition_as_in
22
23
  from cadwyn.middleware import HeaderVersioningMiddleware, _get_api_version_dependency
23
24
  from cadwyn.route_generation import generate_versioned_routers
24
25
  from cadwyn.routing import _RootHeaderAPIRouter
@@ -117,26 +118,34 @@ class Cadwyn(FastAPI):
117
118
  separate_input_output_schemas=separate_input_output_schemas,
118
119
  **extra,
119
120
  )
121
+ self._kwargs_to_router: dict[str, Any] = {
122
+ "routes": routes,
123
+ "redirect_slashes": redirect_slashes,
124
+ "dependency_overrides_provider": self,
125
+ "on_startup": on_startup,
126
+ "on_shutdown": on_shutdown,
127
+ "lifespan": lifespan,
128
+ "default_response_class": default_response_class,
129
+ "dependencies": dependencies,
130
+ "callbacks": callbacks,
131
+ "deprecated": deprecated,
132
+ "include_in_schema": include_in_schema,
133
+ "responses": responses,
134
+ "generate_unique_id_function": generate_unique_id_function,
135
+ }
120
136
  self.router: _RootHeaderAPIRouter = _RootHeaderAPIRouter( # pyright: ignore[reportIncompatibleVariableOverride]
121
- routes=self.routes,
122
- on_startup=on_startup,
123
- on_shutdown=on_shutdown,
124
- default_response_class=default_response_class,
125
- dependencies=dependencies,
126
- callbacks=callbacks,
127
- deprecated=deprecated,
128
- responses=responses,
137
+ **self._kwargs_to_router,
129
138
  api_version_header_name=api_version_header_name,
130
139
  api_version_var=self.versions.api_version_var,
131
- lifespan=lifespan,
132
140
  )
141
+
133
142
  self.docs_url = docs_url
134
143
  self.redoc_url = redoc_url
135
144
  self.openapi_url = openapi_url
136
145
  self.redoc_url = redoc_url
137
146
  self.swaggers = {}
138
147
 
139
- unversioned_router = APIRouter(routes=routes)
148
+ unversioned_router = APIRouter(**self._kwargs_to_router)
140
149
  self._add_openapi_endpoints(unversioned_router)
141
150
  self.add_unversioned_routers(unversioned_router)
142
151
  self.add_middleware(
@@ -202,14 +211,14 @@ class Cadwyn(FastAPI):
202
211
  terms_of_service=self.terms_of_service,
203
212
  contact=self.contact,
204
213
  license_info=self.license_info,
205
- routes=self.router.unversioned_routes,
214
+ routes=self.router.routes,
206
215
  tags=self.openapi_tags,
207
216
  servers=self.servers,
208
217
  )
209
218
  if unversioned_routes_openapi["paths"]:
210
219
  self.swaggers["unversioned"] = unversioned_routes_openapi
211
220
 
212
- for header_value, routes in self.router.versioned_routes.items():
221
+ for header_value, router in self.router.versioned_routers.items():
213
222
  header_value_str = header_value.isoformat()
214
223
  openapi = get_openapi(
215
224
  title=self.title,
@@ -219,7 +228,7 @@ class Cadwyn(FastAPI):
219
228
  terms_of_service=self.terms_of_service,
220
229
  contact=self.contact,
221
230
  license_info=self.license_info,
222
- routes=routes,
231
+ routes=router.routes,
223
232
  tags=self.openapi_tags,
224
233
  servers=self.servers,
225
234
  )
@@ -272,33 +281,109 @@ class Cadwyn(FastAPI):
272
281
  except ValueError as e:
273
282
  raise ValueError("header_value should be in ISO 8601 format") from e
274
283
 
275
- if header_value_as_dt not in self.router.versioned_routes: # pragma: no branch
276
- self.router.versioned_routes[header_value_as_dt] = []
284
+ if header_value_as_dt not in self.router.versioned_routers: # pragma: no branch
285
+ self.router.versioned_routers[header_value_as_dt] = APIRouter(**self._kwargs_to_router)
277
286
  if self.openapi_url is not None: # pragma: no branch
278
- self.router.versioned_routes[header_value_as_dt].append(
279
- Route(path=self.openapi_url, endpoint=self.openapi_jsons, include_in_schema=False)
287
+ self.router.versioned_routers[header_value_as_dt].add_route(
288
+ path=self.openapi_url,
289
+ endpoint=self.openapi_jsons,
290
+ include_in_schema=False,
280
291
  )
281
292
 
282
293
  added_routes: list[BaseRoute] = []
283
294
  for router in (first_router, *other_routers):
284
- added_route_count = len(router.routes)
285
-
286
- self.include_router(
295
+ self.router.versioned_routers[header_value_as_dt].include_router(
287
296
  router,
288
297
  dependencies=[Depends(_get_api_version_dependency(self.router.api_version_header_name, header_value))],
289
298
  )
290
- added_routes.extend(self.routes[len(self.routes) - added_route_count :])
291
- for route in added_routes:
292
- self.router.versioned_routes[header_value_as_dt].append(route)
293
299
 
294
300
  self.enrich_swagger()
295
301
  return added_routes
296
302
 
303
+ @same_definition_as_in(FastAPI.include_router)
304
+ def include_router(self, *args: Any, **kwargs: Any):
305
+ route = super().include_router(*args, **kwargs)
306
+ self.enrich_swagger()
307
+ return route
308
+
309
+ @same_definition_as_in(FastAPI.post)
310
+ def post(self, *args: Any, **kwargs: Any):
311
+ route = super().post(*args, **kwargs)
312
+ self.enrich_swagger()
313
+ return route
314
+
315
+ @same_definition_as_in(FastAPI.get)
316
+ def get(self, *args: Any, **kwargs: Any):
317
+ route = super().get(*args, **kwargs)
318
+ self.enrich_swagger()
319
+ return route
320
+
321
+ @same_definition_as_in(FastAPI.patch)
322
+ def patch(self, *args: Any, **kwargs: Any):
323
+ route = super().patch(*args, **kwargs)
324
+ self.enrich_swagger()
325
+ return route
326
+
327
+ @same_definition_as_in(FastAPI.delete)
328
+ def delete(self, *args: Any, **kwargs: Any):
329
+ route = super().delete(*args, **kwargs)
330
+ self.enrich_swagger()
331
+ return route
332
+
333
+ @same_definition_as_in(FastAPI.put)
334
+ def put(self, *args: Any, **kwargs: Any):
335
+ route = super().put(*args, **kwargs)
336
+ self.enrich_swagger()
337
+ return route
338
+
339
+ @same_definition_as_in(FastAPI.trace)
340
+ def trace(self, *args: Any, **kwargs: Any): # pragma: no cover
341
+ route = super().trace(*args, **kwargs)
342
+ self.enrich_swagger()
343
+ return route
344
+
345
+ @same_definition_as_in(FastAPI.options)
346
+ def options(self, *args: Any, **kwargs: Any):
347
+ route = super().options(*args, **kwargs)
348
+ self.enrich_swagger()
349
+ return route
350
+
351
+ @same_definition_as_in(FastAPI.head)
352
+ def head(self, *args: Any, **kwargs: Any):
353
+ route = super().head(*args, **kwargs)
354
+ self.enrich_swagger()
355
+ return route
356
+
357
+ @same_definition_as_in(FastAPI.add_api_route)
358
+ def add_api_route(self, *args: Any, **kwargs: Any):
359
+ route = super().add_api_route(*args, **kwargs)
360
+ self.enrich_swagger()
361
+ return route
362
+
363
+ @same_definition_as_in(FastAPI.api_route)
364
+ def api_route(self, *args: Any, **kwargs: Any):
365
+ route = super().api_route(*args, **kwargs)
366
+ self.enrich_swagger()
367
+ return route
368
+
369
+ @same_definition_as_in(FastAPI.add_api_websocket_route)
370
+ def add_api_websocket_route(self, *args: Any, **kwargs: Any): # pragma: no cover
371
+ route = super().add_api_websocket_route(*args, **kwargs)
372
+ self.enrich_swagger()
373
+ return route
374
+
375
+ @same_definition_as_in(FastAPI.websocket)
376
+ def websocket(self, *args: Any, **kwargs: Any): # pragma: no cover
377
+ route = super().websocket(*args, **kwargs)
378
+ self.enrich_swagger()
379
+ return route
380
+
297
381
  def add_unversioned_routers(self, *routers: APIRouter):
298
382
  for router in routers:
299
- self.include_router(router)
300
- self.router.unversioned_routes.extend(router.routes)
383
+ self.router.include_router(router)
301
384
  self.enrich_swagger()
302
385
 
386
+ @deprecated("Use add add_unversioned_routers instead")
303
387
  def add_unversioned_routes(self, *routes: Route):
304
- self.router.unversioned_routes.extend(routes)
388
+ router = APIRouter(routes=list(routes))
389
+ self.include_router(router)
cadwyn/codegen/_main.py CHANGED
@@ -53,8 +53,7 @@ def generate_code_for_versioned_packages(
53
53
  codegen_plugins: Sequence[CodegenPlugin] = DEFAULT_CODEGEN_PLUGINS,
54
54
  migration_plugins: Sequence[MigrationPlugin] = DEFAULT_CODEGEN_MIGRATION_PLUGINS,
55
55
  extra_context: dict[str, Any] | None = None,
56
- ):
57
- ...
56
+ ): ...
58
57
 
59
58
 
60
59
  @overload
@@ -70,8 +69,7 @@ def generate_code_for_versioned_packages(
70
69
  codegen_plugins: Sequence[CodegenPlugin] = DEFAULT_CODEGEN_PLUGINS,
71
70
  migration_plugins: Sequence[MigrationPlugin] = DEFAULT_CODEGEN_MIGRATION_PLUGINS,
72
71
  extra_context: dict[str, Any] | None = None,
73
- ):
74
- ...
72
+ ): ...
75
73
 
76
74
 
77
75
  def generate_code_for_versioned_packages(
@@ -95,8 +95,7 @@ class InternalRepresentationOf:
95
95
  def generate_versioned_routers(
96
96
  router: _R,
97
97
  versions: VersionBundle,
98
- ) -> dict[VersionDate, _R]:
99
- ...
98
+ ) -> dict[VersionDate, _R]: ...
100
99
 
101
100
 
102
101
  @overload
@@ -105,8 +104,7 @@ def generate_versioned_routers(
105
104
  router: _R,
106
105
  versions: VersionBundle,
107
106
  latest_schemas_package: ModuleType | None,
108
- ) -> dict[VersionDate, _R]:
109
- ...
107
+ ) -> dict[VersionDate, _R]: ...
110
108
 
111
109
 
112
110
  def generate_versioned_routers(
cadwyn/routing.py CHANGED
@@ -1,5 +1,4 @@
1
1
  import bisect
2
- from collections import OrderedDict
3
2
  from collections.abc import Sequence
4
3
  from contextvars import ContextVar
5
4
  from datetime import date
@@ -44,48 +43,40 @@ class _RootHeaderAPIRouter(APIRouter):
44
43
  **kwargs: Any,
45
44
  ):
46
45
  super().__init__(*args, **kwargs)
47
- self.versioned_routes: dict[date, list[BaseRoute]] = {}
48
- self.unversioned_routes: list[BaseRoute] = []
46
+ self.versioned_routers: dict[date, APIRouter] = {}
49
47
  self.api_version_header_name = api_version_header_name.lower()
50
48
  self.api_version_var = api_version_var
51
49
 
52
50
  @cached_property
53
- def sorted_versioned_routes(self):
54
- sorted_routes = sorted(self.versioned_routes.items())
55
- return OrderedDict(sorted_routes)
51
+ def sorted_versions(self):
52
+ return sorted(self.versioned_routers.keys())
56
53
 
57
54
  @cached_property
58
55
  def min_routes_version(self):
59
- return min(self.sorted_versioned_routes.keys())
56
+ return min(self.sorted_versions)
60
57
 
61
- def find_closest_date_but_not_new(self, request_version: date):
62
- routes = list(self.sorted_versioned_routes.keys())
63
- index = bisect.bisect_left(routes, request_version)
58
+ def find_closest_date_but_not_new(self, request_version: date) -> date:
59
+ index = bisect.bisect_left(self.sorted_versions, request_version)
64
60
  # as bisect_left returns the index where to insert item x in list a, assuming a is sorted
65
61
  # we need to get the previous item and that will be a match
66
- return routes[index - 1]
62
+ return self.sorted_versions[index - 1]
67
63
 
68
- def pick_version(
69
- self,
70
- request_header_value: date,
71
- ) -> list[BaseRoute]:
72
- routes = []
64
+ def pick_version(self, request_header_value: date) -> list[BaseRoute]:
73
65
  request_version = request_header_value.isoformat()
74
66
 
75
67
  if self.min_routes_version > request_header_value:
76
68
  # then the request version is older that the oldest route we have
77
69
  _logger.info(
78
- f"Request version {request_version} "
79
- f"is older than the oldest "
80
- f"version {self.min_routes_version.isoformat()} ",
70
+ "Request version is older than the oldest version. No route can match this version",
71
+ extra={"oldest_version": self.min_routes_version.isoformat(), "request_version": request_version},
81
72
  )
82
- return routes
73
+ return []
83
74
  version_chosen = self.find_closest_date_but_not_new(request_header_value)
84
75
  _logger.info(
85
- f"Partial match. The endpoint with {version_chosen} "
86
- f"version was selected for API call version {request_version}",
76
+ "Partial match. The endpoint with a lower version was selected for the API call",
77
+ extra={"version_chosen": version_chosen, "request_version": request_version},
87
78
  )
88
- return self.versioned_routes[version_chosen]
79
+ return self.versioned_routers[version_chosen].routes
89
80
 
90
81
  async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None:
91
82
  """
@@ -103,9 +94,9 @@ class _RootHeaderAPIRouter(APIRouter):
103
94
  # if header_value is None, then it's an unversioned request and we need to use the unversioned routes
104
95
  # if there will be a value, we search for the most suitable version
105
96
  if not header_value:
106
- routes = self.unversioned_routes
107
- elif header_value in self.versioned_routes:
108
- routes = self.versioned_routes[header_value]
97
+ routes = self.routes
98
+ elif header_value in self.versioned_routers:
99
+ routes = self.versioned_routers[header_value].routes
109
100
  else:
110
101
  routes = self.pick_version(request_header_value=header_value)
111
102
  await self.process_request(scope=scope, receive=receive, send=send, routes=routes)
cadwyn/structure/data.py CHANGED
@@ -109,13 +109,11 @@ class AlterRequestByPathInstruction(_BaseAlterRequestInstruction):
109
109
  @overload
110
110
  def convert_request_to_next_version_for(
111
111
  first_schema: type, /, *additional_schemas: type
112
- ) -> "type[staticmethod[_P, None]]":
113
- ...
112
+ ) -> "type[staticmethod[_P, None]]": ...
114
113
 
115
114
 
116
115
  @overload
117
- def convert_request_to_next_version_for(path: str, methods: list[str], /) -> "type[staticmethod[_P, None]]":
118
- ...
116
+ def convert_request_to_next_version_for(path: str, methods: list[str], /) -> "type[staticmethod[_P, None]]": ...
119
117
 
120
118
 
121
119
  def convert_request_to_next_version_for(
@@ -174,8 +172,7 @@ def convert_response_to_previous_version_for(
174
172
  /,
175
173
  *schemas: type,
176
174
  migrate_http_errors: bool = False,
177
- ) -> "type[staticmethod[_P, None]]":
178
- ...
175
+ ) -> "type[staticmethod[_P, None]]": ...
179
176
 
180
177
 
181
178
  @overload
@@ -185,8 +182,7 @@ def convert_response_to_previous_version_for(
185
182
  /,
186
183
  *,
187
184
  migrate_http_errors: bool = False,
188
- ) -> "type[staticmethod[_P, None]]":
189
- ...
185
+ ) -> "type[staticmethod[_P, None]]": ...
190
186
 
191
187
 
192
188
  def convert_response_to_previous_version_for(
@@ -20,7 +20,7 @@ from fastapi.concurrency import run_in_threadpool
20
20
  from fastapi.dependencies.models import Dependant
21
21
  from fastapi.dependencies.utils import solve_dependencies
22
22
  from fastapi.exceptions import RequestValidationError
23
- from fastapi.responses import FileResponse, StreamingResponse
23
+ from fastapi.responses import FileResponse, JSONResponse, StreamingResponse
24
24
  from fastapi.routing import APIRoute, _prepare_response_content
25
25
  from pydantic import BaseModel
26
26
  from starlette._utils import is_async_callable
@@ -74,9 +74,9 @@ class VersionChange:
74
74
  alter_enum_instructions: ClassVar[list[AlterEnumSubInstruction]] = Sentinel
75
75
  alter_module_instructions: ClassVar[list[AlterModuleInstruction]] = Sentinel
76
76
  alter_endpoint_instructions: ClassVar[list[AlterEndpointSubInstruction]] = Sentinel
77
- alter_request_by_schema_instructions: ClassVar[
78
- dict[type[BaseModel], list[AlterRequestBySchemaInstruction]]
79
- ] = Sentinel
77
+ alter_request_by_schema_instructions: ClassVar[dict[type[BaseModel], list[AlterRequestBySchemaInstruction]]] = (
78
+ Sentinel
79
+ )
80
80
  alter_request_by_path_instructions: ClassVar[dict[str, list[AlterRequestByPathInstruction]]] = Sentinel
81
81
  alter_response_by_schema_instructions: ClassVar[dict[type, list[AlterResponseBySchemaInstruction]]] = Sentinel
82
82
  alter_response_by_path_instructions: ClassVar[dict[str, list[AlterResponseByPathInstruction]]] = Sentinel
@@ -245,8 +245,7 @@ class VersionBundle:
245
245
  *other_versions: Version,
246
246
  api_version_var: APIVersionVarType | None = None,
247
247
  head_schemas_package: ModuleType | None = None,
248
- ) -> None:
249
- ...
248
+ ) -> None: ...
250
249
 
251
250
  @overload
252
251
  @deprecated("Pass head_version_package instead of latest_schemas_package.")
@@ -257,8 +256,7 @@ class VersionBundle:
257
256
  *other_versions: Version,
258
257
  api_version_var: APIVersionVarType | None = None,
259
258
  latest_schemas_package: ModuleType | None = None,
260
- ) -> None:
261
- ...
259
+ ) -> None: ...
262
260
 
263
261
  def __init__(
264
262
  self,
@@ -620,7 +618,10 @@ class VersionBundle:
620
618
  if isinstance(response_or_response_body, StreamingResponse | FileResponse):
621
619
  body = None
622
620
  elif response_or_response_body.body:
623
- body = json.loads(response_or_response_body.body)
621
+ if isinstance(response_or_response_body, JSONResponse) or raised_exception is not None:
622
+ body = json.loads(response_or_response_body.body)
623
+ else:
624
+ body = response_or_response_body.body.decode(response_or_response_body.charset)
624
625
  else:
625
626
  body = None
626
627
  # TODO (https://github.com/zmievsa/cadwyn/issues/51): Only do this if there are migrations
@@ -666,16 +667,25 @@ class VersionBundle:
666
667
  # that do not have it. We don't support it too.
667
668
  if response_info.body is not None and hasattr(response_info._response, "body"):
668
669
  # TODO (https://github.com/zmievsa/cadwyn/issues/51): Only do this if there are migrations
669
- response_info._response.body = json.dumps(response_info.body).encode()
670
+ if isinstance(response_info.body, str):
671
+ response_info._response.body = response_info.body.encode(response_info._response.charset)
672
+ else:
673
+ response_info._response.body = json.dumps(
674
+ response_info.body,
675
+ ensure_ascii=False,
676
+ allow_nan=False,
677
+ indent=None,
678
+ separators=(",", ":"),
679
+ ).encode("utf-8")
680
+ # It makes sense to re-calculate content length because the previously calculated one
681
+ # might slightly differ. If it differs -- uvicorn will break.
682
+ response_info.headers["content-length"] = str(len(response_info._response.body))
670
683
 
671
684
  if raised_exception is not None and response_info.status_code >= 400:
672
685
  if isinstance(response_info.body, dict) and "detail" in response_info.body:
673
686
  detail = response_info.body["detail"]
674
687
  else:
675
688
  detail = response_info.body
676
- # It makes more sense to re-calculate content length because the previously calculated one
677
- # might slightly differ.
678
- del response_info.headers["content-length"]
679
689
 
680
690
  raise HTTPException(
681
691
  status_code=response_info.status_code,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: cadwyn
3
- Version: 3.11.1
3
+ Version: 3.12.1
4
4
  Summary: Production-ready community-driven modern Stripe-like API versioning in FastAPI
5
5
  Home-page: https://github.com/zmievsa/cadwyn
6
6
  License: MIT
@@ -1,14 +1,14 @@
1
1
  cadwyn/__init__.py,sha256=XgF-CtZo-fPk5730sKlY2fAmPsTQRIsFbrfNFeUZyFY,495
2
- cadwyn/__main__.py,sha256=TMxAEvgN1MFc1TkkKmsS-jFMBAW8lVos4wUZ9stp6WU,4343
2
+ cadwyn/__main__.py,sha256=q7oNhnJ_hNRib3o6cAo4QC0cME0prVi-6P0G14tRdkw,4339
3
3
  cadwyn/_asts.py,sha256=S-x9fVKTENZZxwWfabm0PbztcHyX2MJkI6Cwv5XgVrI,10138
4
4
  cadwyn/_compat.py,sha256=6QwtzbXn53mIhEFfEizmFjd-f894oLsM6ITxqq2rCpc,5408
5
5
  cadwyn/_package_utils.py,sha256=trxTYLmppv-10SKhScfyDQJh21rsQGFoLaOtHycKKR0,1443
6
6
  cadwyn/_utils.py,sha256=BFsfZBpdoL5RMAaT1V1cXJVpTZCmwksQ-Le2MTHivGI,4841
7
- cadwyn/applications.py,sha256=sz4x_GoD3s1snm3M1Wgx22mdAICQXciVd9rhGWZk0II,12826
7
+ cadwyn/applications.py,sha256=MAVsgYojgQO4PrUETVMAsp49k6baW4h4LtS6z12gTZs,15767
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
11
- cadwyn/codegen/_main.py,sha256=8VdMhbQyNDyeZaxKV-2sUW_Sl5X-Lu92rHdINAHaTn0,10491
11
+ cadwyn/codegen/_main.py,sha256=1mpXq_1AuZaAOeGjrCVMhcK7zhjmmlO82Q3ehoOOAfM,10483
12
12
  cadwyn/codegen/_plugins/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
13
13
  cadwyn/codegen/_plugins/class_migrations.py,sha256=kHZ-RMRTARZ4l70fxHMtul_204Ute2_yQmEej7wMwwo,20119
14
14
  cadwyn/codegen/_plugins/class_rebuilding.py,sha256=zNlB_VxoEAtdC5Ydiqa7pu6Ka-pKnpPQk_dvovaK0QI,3623
@@ -19,20 +19,20 @@ cadwyn/exceptions.py,sha256=gsb1vszQ2VsnfTBM5B8AYmXwCW0yvA8pJ1GhNkGzgyE,1440
19
19
  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
- cadwyn/route_generation.py,sha256=7nHe_IP7Uz1rXmnItJsQ2yIuqe3lRgtOr8_MP_6Vg8c,35704
23
- cadwyn/routing.py,sha256=nswSMfpGMYk-TSbNY6NmH7NuWM0GoWwK_McTzPiKluk,6392
22
+ cadwyn/route_generation.py,sha256=veFSg4xlInZaJzlcO6gr3wfUCbU0_TFeU3e-9HTiqLY,35696
23
+ cadwyn/routing.py,sha256=ObH4-ETYPQjm3bMVCNzGttEKv1LL9q2sbi9eJD4W3lY,6250
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
27
27
  cadwyn/structure/common.py,sha256=6Z4nI97XPWTCinn6np73m-rLPyYNrz2fWXKJlqjsiaQ,269
28
- cadwyn/structure/data.py,sha256=F7jqlRohpLJrgJxkxs2gTkO77q6BJ6pCbt6wJIo3TRk,7128
28
+ cadwyn/structure/data.py,sha256=161UO_Y669-dKdSvBx5zHT7SorppApT_VXUtideFyjs,7112
29
29
  cadwyn/structure/endpoints.py,sha256=VngfAydGBwekhV2tBOtNDPVgl3X1IgYxUCw--VZ5cQY,5627
30
30
  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
- cadwyn/structure/versions.py,sha256=SjrVqwWFIgUQEazaIW8xXjwMhgJSdSNakbAyfHSArwA,36188
34
- cadwyn-3.11.1.dist-info/LICENSE,sha256=KeCWewiDQYpmSnzF-p_0YpoWiyDcUPaCuG8OWQs4ig4,1072
35
- cadwyn-3.11.1.dist-info/METADATA,sha256=9rFmG2uT2s12T37R84gM0mTOsGdpFrFypJ1AAiI3nZM,4360
36
- cadwyn-3.11.1.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
37
- cadwyn-3.11.1.dist-info/entry_points.txt,sha256=eO05hLn9GoRzzpwT9GONPmXKsonjuMNssM2D2WHWKGk,46
38
- cadwyn-3.11.1.dist-info/RECORD,,
33
+ cadwyn/structure/versions.py,sha256=qSUOs0-jmWuOMaDMac_EBPtuaJktdChGLuUabjopQPc,36902
34
+ cadwyn-3.12.1.dist-info/LICENSE,sha256=KeCWewiDQYpmSnzF-p_0YpoWiyDcUPaCuG8OWQs4ig4,1072
35
+ cadwyn-3.12.1.dist-info/METADATA,sha256=V7wUTcOuVwl67QOKynW5LBZw1inrKSxwp6XFdqfuGC8,4360
36
+ cadwyn-3.12.1.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
37
+ cadwyn-3.12.1.dist-info/entry_points.txt,sha256=eO05hLn9GoRzzpwT9GONPmXKsonjuMNssM2D2WHWKGk,46
38
+ cadwyn-3.12.1.dist-info/RECORD,,