cadwyn 3.11.1__tar.gz → 3.12.1__tar.gz
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-3.11.1 → cadwyn-3.12.1}/PKG-INFO +1 -1
- {cadwyn-3.11.1 → cadwyn-3.12.1}/cadwyn/__main__.py +1 -2
- {cadwyn-3.11.1 → cadwyn-3.12.1}/cadwyn/applications.py +111 -26
- {cadwyn-3.11.1 → cadwyn-3.12.1}/cadwyn/codegen/_main.py +2 -4
- {cadwyn-3.11.1 → cadwyn-3.12.1}/cadwyn/route_generation.py +2 -4
- {cadwyn-3.11.1 → cadwyn-3.12.1}/cadwyn/routing.py +17 -26
- {cadwyn-3.11.1 → cadwyn-3.12.1}/cadwyn/structure/data.py +4 -8
- {cadwyn-3.11.1 → cadwyn-3.12.1}/cadwyn/structure/versions.py +23 -13
- cadwyn-3.12.1/pyproject.toml +137 -0
- cadwyn-3.11.1/pyproject.toml +0 -246
- {cadwyn-3.11.1 → cadwyn-3.12.1}/LICENSE +0 -0
- {cadwyn-3.11.1 → cadwyn-3.12.1}/README.md +0 -0
- {cadwyn-3.11.1 → cadwyn-3.12.1}/cadwyn/__init__.py +0 -0
- {cadwyn-3.11.1 → cadwyn-3.12.1}/cadwyn/_asts.py +0 -0
- {cadwyn-3.11.1 → cadwyn-3.12.1}/cadwyn/_compat.py +0 -0
- {cadwyn-3.11.1 → cadwyn-3.12.1}/cadwyn/_package_utils.py +0 -0
- {cadwyn-3.11.1 → cadwyn-3.12.1}/cadwyn/_utils.py +0 -0
- {cadwyn-3.11.1 → cadwyn-3.12.1}/cadwyn/codegen/README.md +0 -0
- {cadwyn-3.11.1 → cadwyn-3.12.1}/cadwyn/codegen/__init__.py +0 -0
- {cadwyn-3.11.1 → cadwyn-3.12.1}/cadwyn/codegen/_common.py +0 -0
- {cadwyn-3.11.1 → cadwyn-3.12.1}/cadwyn/codegen/_plugins/__init__.py +0 -0
- {cadwyn-3.11.1 → cadwyn-3.12.1}/cadwyn/codegen/_plugins/class_migrations.py +0 -0
- {cadwyn-3.11.1 → cadwyn-3.12.1}/cadwyn/codegen/_plugins/class_rebuilding.py +0 -0
- {cadwyn-3.11.1 → cadwyn-3.12.1}/cadwyn/codegen/_plugins/class_renaming.py +0 -0
- {cadwyn-3.11.1 → cadwyn-3.12.1}/cadwyn/codegen/_plugins/import_auto_adding.py +0 -0
- {cadwyn-3.11.1 → cadwyn-3.12.1}/cadwyn/codegen/_plugins/module_migrations.py +0 -0
- {cadwyn-3.11.1 → cadwyn-3.12.1}/cadwyn/exceptions.py +0 -0
- {cadwyn-3.11.1 → cadwyn-3.12.1}/cadwyn/main.py +0 -0
- {cadwyn-3.11.1 → cadwyn-3.12.1}/cadwyn/middleware.py +0 -0
- {cadwyn-3.11.1 → cadwyn-3.12.1}/cadwyn/py.typed +0 -0
- {cadwyn-3.11.1 → cadwyn-3.12.1}/cadwyn/static/__init__.py +0 -0
- {cadwyn-3.11.1 → cadwyn-3.12.1}/cadwyn/static/docs.html +0 -0
- {cadwyn-3.11.1 → cadwyn-3.12.1}/cadwyn/structure/__init__.py +0 -0
- {cadwyn-3.11.1 → cadwyn-3.12.1}/cadwyn/structure/common.py +0 -0
- {cadwyn-3.11.1 → cadwyn-3.12.1}/cadwyn/structure/endpoints.py +0 -0
- {cadwyn-3.11.1 → cadwyn-3.12.1}/cadwyn/structure/enums.py +0 -0
- {cadwyn-3.11.1 → cadwyn-3.12.1}/cadwyn/structure/modules.py +0 -0
- {cadwyn-3.11.1 → cadwyn-3.12.1}/cadwyn/structure/schemas.py +0 -0
|
@@ -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__":
|
|
@@ -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
|
-
|
|
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(
|
|
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.
|
|
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,
|
|
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.
|
|
276
|
-
self.router.
|
|
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.
|
|
279
|
-
|
|
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
|
-
|
|
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
|
-
|
|
388
|
+
router = APIRouter(routes=list(routes))
|
|
389
|
+
self.include_router(router)
|
|
@@ -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(
|
|
@@ -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.
|
|
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
|
|
54
|
-
|
|
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.
|
|
56
|
+
return min(self.sorted_versions)
|
|
60
57
|
|
|
61
|
-
def find_closest_date_but_not_new(self, request_version: date):
|
|
62
|
-
|
|
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
|
|
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
|
-
|
|
79
|
-
|
|
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
|
|
73
|
+
return []
|
|
83
74
|
version_chosen = self.find_closest_date_but_not_new(request_header_value)
|
|
84
75
|
_logger.info(
|
|
85
|
-
|
|
86
|
-
|
|
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.
|
|
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.
|
|
107
|
-
elif header_value in self.
|
|
108
|
-
routes = self.
|
|
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)
|
|
@@ -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
|
-
|
|
79
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
[tool.poetry]
|
|
2
|
+
name = "cadwyn"
|
|
3
|
+
version = "3.12.1"
|
|
4
|
+
description = "Production-ready community-driven modern Stripe-like API versioning in FastAPI"
|
|
5
|
+
authors = ["Stanislav Zmiev <zmievsa@gmail.com>"]
|
|
6
|
+
license = "MIT"
|
|
7
|
+
readme = "README.md"
|
|
8
|
+
repository = "https://github.com/zmievsa/cadwyn"
|
|
9
|
+
documentation = "https://docs.cadwyn.dev"
|
|
10
|
+
keywords = [
|
|
11
|
+
"python",
|
|
12
|
+
"api",
|
|
13
|
+
"json-schema",
|
|
14
|
+
"stripe",
|
|
15
|
+
"versioning",
|
|
16
|
+
"code-generation",
|
|
17
|
+
"hints",
|
|
18
|
+
"api-versioning",
|
|
19
|
+
"pydantic",
|
|
20
|
+
"fastapi",
|
|
21
|
+
"python310",
|
|
22
|
+
"python311",
|
|
23
|
+
"python312",
|
|
24
|
+
]
|
|
25
|
+
classifiers = [
|
|
26
|
+
"Intended Audience :: Information Technology",
|
|
27
|
+
"Intended Audience :: System Administrators",
|
|
28
|
+
"Operating System :: OS Independent",
|
|
29
|
+
"Programming Language :: Python",
|
|
30
|
+
"Programming Language :: Python :: 3",
|
|
31
|
+
"Programming Language :: Python :: 3.10",
|
|
32
|
+
"Programming Language :: Python :: 3.11",
|
|
33
|
+
"Programming Language :: Python :: 3.12",
|
|
34
|
+
"Topic :: Internet",
|
|
35
|
+
"Topic :: Software Development :: Libraries :: Application Frameworks",
|
|
36
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
37
|
+
"Topic :: Software Development :: Libraries",
|
|
38
|
+
"Topic :: Software Development",
|
|
39
|
+
"Typing :: Typed",
|
|
40
|
+
"Development Status :: 5 - Production/Stable",
|
|
41
|
+
"Environment :: Web Environment",
|
|
42
|
+
"Framework :: AsyncIO",
|
|
43
|
+
"Framework :: FastAPI",
|
|
44
|
+
"Framework :: Pydantic",
|
|
45
|
+
"Intended Audience :: Developers",
|
|
46
|
+
"License :: OSI Approved :: MIT License",
|
|
47
|
+
"Topic :: Internet :: WWW/HTTP :: HTTP Servers",
|
|
48
|
+
"Topic :: Internet :: WWW/HTTP",
|
|
49
|
+
]
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
[tool.poetry.dependencies]
|
|
53
|
+
python = "^3.10"
|
|
54
|
+
typing-extensions = "*"
|
|
55
|
+
fastapi = ">=0.110.0"
|
|
56
|
+
starlette = ">=0.36.3"
|
|
57
|
+
pydantic = ">=1.0.0"
|
|
58
|
+
typer = {version = ">=0.7.0", optional = true}
|
|
59
|
+
better-ast-comments = "~1.2.1"
|
|
60
|
+
jinja2 = ">=3.1.2"
|
|
61
|
+
|
|
62
|
+
[tool.poetry.extras]
|
|
63
|
+
cli = ["typer"]
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
[tool.poetry.group.dev.dependencies]
|
|
67
|
+
pytest = ">=7.2.1"
|
|
68
|
+
pytest-cov = ">=4.0.0"
|
|
69
|
+
uvicorn = "*"
|
|
70
|
+
devtools = "*"
|
|
71
|
+
pdbpp = "^0.10.3"
|
|
72
|
+
httpx = "*"
|
|
73
|
+
pytest-fixture-classes = ">=1.0.3"
|
|
74
|
+
dirty-equals = ">=0.6.0"
|
|
75
|
+
mkdocs = ">=1.5.2"
|
|
76
|
+
mkdocs-material = ">=9.3.1"
|
|
77
|
+
python-multipart = ">=0.0.6"
|
|
78
|
+
mkdocs-simple-hooks = ">=0.1.5"
|
|
79
|
+
pytest-sugar = "^1.0.0"
|
|
80
|
+
|
|
81
|
+
[tool.poetry.scripts]
|
|
82
|
+
cadwyn = "cadwyn.__main__:app"
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
[tool.pytest.ini_options]
|
|
86
|
+
asyncio_mode = "auto"
|
|
87
|
+
|
|
88
|
+
[tool.coverage.report]
|
|
89
|
+
skip_covered = true
|
|
90
|
+
skip_empty = true
|
|
91
|
+
# Taken from https://coverage.readthedocs.io/en/7.1.0/excluding.html#advanced-exclusion
|
|
92
|
+
exclude_lines = [
|
|
93
|
+
"pragma: no cover",
|
|
94
|
+
"assert_never\\(",
|
|
95
|
+
"if self.debug:",
|
|
96
|
+
"if settings.DEBUG",
|
|
97
|
+
"raise AssertionError",
|
|
98
|
+
"raise NotImplementedError",
|
|
99
|
+
"if False:",
|
|
100
|
+
"assert_never",
|
|
101
|
+
"if 0:",
|
|
102
|
+
"class .*\\bProtocol\\):",
|
|
103
|
+
"if __name__ == .__main__.:",
|
|
104
|
+
"if TYPE_CHECKING:",
|
|
105
|
+
"@(abc\\.)?abstractmethod",
|
|
106
|
+
"@(typing\\.)?overload",
|
|
107
|
+
"__rich_repr__",
|
|
108
|
+
"__repr__",
|
|
109
|
+
]
|
|
110
|
+
omit = ["./docs/plugin.py", "./site/plugin.py", "./tests/_data/_temp/**/*", "tests/tutorial/data/**/*", "scripts/*.py"]
|
|
111
|
+
|
|
112
|
+
[tool.pyright]
|
|
113
|
+
reportMissingImports = true
|
|
114
|
+
strictListInference = true
|
|
115
|
+
strictDictionaryInference = true
|
|
116
|
+
strictSetInference = true
|
|
117
|
+
reportPropertyTypeMismatch = true
|
|
118
|
+
reportImportCycles = true
|
|
119
|
+
reportUntypedFunctionDecorator = "warning"
|
|
120
|
+
reportUntypedClassDecorator = "warning"
|
|
121
|
+
reportUntypedBaseClass = "warning"
|
|
122
|
+
reportDeprecated = "warning"
|
|
123
|
+
reportInvalidTypeVarUse = true
|
|
124
|
+
reportUnnecessaryCast = true
|
|
125
|
+
reportUnnecessaryComparison = true
|
|
126
|
+
reportUnnecessaryContains = true
|
|
127
|
+
reportAssertAlwaysTrue = true
|
|
128
|
+
reportUnsupportedDunderAll = true
|
|
129
|
+
reportUnnecessaryTypeIgnoreComment = true
|
|
130
|
+
reportMissingSuperCall = true
|
|
131
|
+
reportFunctionMemberAccess = false
|
|
132
|
+
reportCircularImports = true
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
[build-system]
|
|
136
|
+
requires = ["poetry-core>=1.0.0"]
|
|
137
|
+
build-backend = "poetry.core.masonry.api"
|
cadwyn-3.11.1/pyproject.toml
DELETED
|
@@ -1,246 +0,0 @@
|
|
|
1
|
-
[tool.poetry]
|
|
2
|
-
name = "cadwyn"
|
|
3
|
-
version = "3.11.1"
|
|
4
|
-
description = "Production-ready community-driven modern Stripe-like API versioning in FastAPI"
|
|
5
|
-
authors = ["Stanislav Zmiev <zmievsa@gmail.com>"]
|
|
6
|
-
license = "MIT"
|
|
7
|
-
readme = "README.md"
|
|
8
|
-
repository = "https://github.com/zmievsa/cadwyn"
|
|
9
|
-
documentation = "https://docs.cadwyn.dev"
|
|
10
|
-
keywords = [
|
|
11
|
-
"python",
|
|
12
|
-
"api",
|
|
13
|
-
"json-schema",
|
|
14
|
-
"stripe",
|
|
15
|
-
"versioning",
|
|
16
|
-
"code-generation",
|
|
17
|
-
"hints",
|
|
18
|
-
"api-versioning",
|
|
19
|
-
"pydantic",
|
|
20
|
-
"fastapi",
|
|
21
|
-
"python310",
|
|
22
|
-
"python311",
|
|
23
|
-
"python312",
|
|
24
|
-
]
|
|
25
|
-
classifiers = [
|
|
26
|
-
"Intended Audience :: Information Technology",
|
|
27
|
-
"Intended Audience :: System Administrators",
|
|
28
|
-
"Operating System :: OS Independent",
|
|
29
|
-
"Programming Language :: Python",
|
|
30
|
-
"Programming Language :: Python :: 3",
|
|
31
|
-
"Programming Language :: Python :: 3.10",
|
|
32
|
-
"Programming Language :: Python :: 3.11",
|
|
33
|
-
"Programming Language :: Python :: 3.12",
|
|
34
|
-
"Topic :: Internet",
|
|
35
|
-
"Topic :: Software Development :: Libraries :: Application Frameworks",
|
|
36
|
-
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
37
|
-
"Topic :: Software Development :: Libraries",
|
|
38
|
-
"Topic :: Software Development",
|
|
39
|
-
"Typing :: Typed",
|
|
40
|
-
"Development Status :: 5 - Production/Stable",
|
|
41
|
-
"Environment :: Web Environment",
|
|
42
|
-
"Framework :: AsyncIO",
|
|
43
|
-
"Framework :: FastAPI",
|
|
44
|
-
"Framework :: Pydantic",
|
|
45
|
-
"Intended Audience :: Developers",
|
|
46
|
-
"License :: OSI Approved :: MIT License",
|
|
47
|
-
"Topic :: Internet :: WWW/HTTP :: HTTP Servers",
|
|
48
|
-
"Topic :: Internet :: WWW/HTTP",
|
|
49
|
-
]
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
[tool.poetry.dependencies]
|
|
53
|
-
python = "^3.10"
|
|
54
|
-
typing-extensions = "*"
|
|
55
|
-
fastapi = ">=0.110.0"
|
|
56
|
-
starlette = ">=0.36.3"
|
|
57
|
-
pydantic = ">=1.0.0"
|
|
58
|
-
typer = {version = ">=0.7.0", optional = true}
|
|
59
|
-
better-ast-comments = "~1.2.1"
|
|
60
|
-
jinja2 = ">=3.1.2"
|
|
61
|
-
|
|
62
|
-
[tool.poetry.extras]
|
|
63
|
-
cli = ["typer"]
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
[tool.poetry.group.dev.dependencies]
|
|
67
|
-
ruff = "*"
|
|
68
|
-
pytest = ">=7.2.1"
|
|
69
|
-
pytest-cov = ">=4.0.0"
|
|
70
|
-
uvicorn = "*"
|
|
71
|
-
devtools = "*"
|
|
72
|
-
pdbpp = "^0.10.3"
|
|
73
|
-
httpx = "*"
|
|
74
|
-
pytest-fixture-classes = ">=1.0.3"
|
|
75
|
-
pre-commit = ">=3.4.0"
|
|
76
|
-
dirty-equals = ">=0.6.0"
|
|
77
|
-
mkdocs = ">=1.5.2"
|
|
78
|
-
mkdocs-material = ">=9.3.1"
|
|
79
|
-
python-multipart = ">=0.0.6"
|
|
80
|
-
mkdocs-simple-hooks = ">=0.1.5"
|
|
81
|
-
pytest-sugar = "^1.0.0"
|
|
82
|
-
|
|
83
|
-
[tool.poetry.scripts]
|
|
84
|
-
cadwyn = "cadwyn.__main__:app"
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
[tool.pytest.ini_options]
|
|
88
|
-
asyncio_mode = "auto"
|
|
89
|
-
|
|
90
|
-
[tool.coverage.report]
|
|
91
|
-
skip_covered = true
|
|
92
|
-
skip_empty = true
|
|
93
|
-
# Taken from https://coverage.readthedocs.io/en/7.1.0/excluding.html#advanced-exclusion
|
|
94
|
-
exclude_lines = [
|
|
95
|
-
"pragma: no cover",
|
|
96
|
-
"assert_never\\(",
|
|
97
|
-
"if self.debug:",
|
|
98
|
-
"if settings.DEBUG",
|
|
99
|
-
"raise AssertionError",
|
|
100
|
-
"raise NotImplementedError",
|
|
101
|
-
"if False:",
|
|
102
|
-
"assert_never",
|
|
103
|
-
"if 0:",
|
|
104
|
-
"class .*\\bProtocol\\):",
|
|
105
|
-
"if __name__ == .__main__.:",
|
|
106
|
-
"if TYPE_CHECKING:",
|
|
107
|
-
"@(abc\\.)?abstractmethod",
|
|
108
|
-
"@(typing\\.)?overload",
|
|
109
|
-
"__rich_repr__",
|
|
110
|
-
"__repr__",
|
|
111
|
-
]
|
|
112
|
-
omit = ["./docs/plugin.py", "./site/plugin.py", "./tests/_data/_temp/**/*", "tests/tutorial/data/**/*", "scripts/*.py"]
|
|
113
|
-
|
|
114
|
-
[tool.pyright]
|
|
115
|
-
reportMissingImports = true
|
|
116
|
-
strictListInference = true
|
|
117
|
-
strictDictionaryInference = true
|
|
118
|
-
strictSetInference = true
|
|
119
|
-
reportPropertyTypeMismatch = true
|
|
120
|
-
reportImportCycles = true
|
|
121
|
-
reportUntypedFunctionDecorator = "warning"
|
|
122
|
-
reportUntypedClassDecorator = "warning"
|
|
123
|
-
reportUntypedBaseClass = "warning"
|
|
124
|
-
reportDeprecated = "warning"
|
|
125
|
-
reportInvalidTypeVarUse = true
|
|
126
|
-
reportUnnecessaryCast = true
|
|
127
|
-
reportUnnecessaryComparison = true
|
|
128
|
-
reportUnnecessaryContains = true
|
|
129
|
-
reportAssertAlwaysTrue = true
|
|
130
|
-
reportUnsupportedDunderAll = true
|
|
131
|
-
reportUnnecessaryTypeIgnoreComment = true
|
|
132
|
-
reportMissingSuperCall = true
|
|
133
|
-
reportFunctionMemberAccess = false
|
|
134
|
-
reportCircularImports = true
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
[tool.ruff]
|
|
138
|
-
target-version = "py310"
|
|
139
|
-
line-length = 120
|
|
140
|
-
extend-exclude = ["scripts/*.py"]
|
|
141
|
-
|
|
142
|
-
[tool.ruff.lint]
|
|
143
|
-
select = [
|
|
144
|
-
"F", # pyflakes
|
|
145
|
-
"E", # pycodestyle errors
|
|
146
|
-
"W", # pycodestyle warnings
|
|
147
|
-
"C90", # mccabe
|
|
148
|
-
"I", # isort
|
|
149
|
-
"N", # pep8-naming
|
|
150
|
-
"UP", # pyupgrade
|
|
151
|
-
"YTT", # flake8-2020
|
|
152
|
-
"S", # flake8-bandit
|
|
153
|
-
"BLE", # flake8-blind-except
|
|
154
|
-
"FBT003", # flake8-boolean-trap
|
|
155
|
-
"B", # flake8-bugbear
|
|
156
|
-
"COM", # flake8-commas
|
|
157
|
-
"C4", # flake8-comprehensions
|
|
158
|
-
"T10", # flake8-debugger
|
|
159
|
-
"ISC", # flake8-implicit-str-concat
|
|
160
|
-
"G010", # Logging statement uses warn instead of warning
|
|
161
|
-
"G201", # Logging .exception(...) should be used instead of .error(..., exc_info=True)
|
|
162
|
-
"G202", # Logging statement has redundant exc_info
|
|
163
|
-
"INP", # flake8-no-pep420
|
|
164
|
-
"PIE", # flake8-pie
|
|
165
|
-
"T20", # flake8-print
|
|
166
|
-
"PYI", # flake8-pyi
|
|
167
|
-
"PT", # flake8-pytest-style
|
|
168
|
-
"Q", # flake8-quotes
|
|
169
|
-
"RSE", # flake8-raise
|
|
170
|
-
"RET", # flake8-return
|
|
171
|
-
"SIM", # flake8-simplify
|
|
172
|
-
"TCH", # flake8-type-checking
|
|
173
|
-
"ARG", # flake8-unused-arguments
|
|
174
|
-
"PTH", # flake8-use-pathlib
|
|
175
|
-
"ERA", # flake8-eradicate
|
|
176
|
-
"PGH", # pygrep-hooks
|
|
177
|
-
"PLC0414", # Import alias does not rename original package
|
|
178
|
-
"PLE", # Error
|
|
179
|
-
"PLW", # Warning
|
|
180
|
-
"TRY", # tryceratops
|
|
181
|
-
"FLY", # flynt
|
|
182
|
-
"RUF", # ruff-specific rules
|
|
183
|
-
"ANN001", # missing type annotation for arguments
|
|
184
|
-
"ANN002", # missing type annotation for *args
|
|
185
|
-
"ANN003", # missing type annotation for **kwargs
|
|
186
|
-
]
|
|
187
|
-
unfixable = [
|
|
188
|
-
"ERA001", # eradicate: found commented out code (can be dangerous if fixed automatically)
|
|
189
|
-
]
|
|
190
|
-
ignore = [
|
|
191
|
-
"D203", # 1 blank line required before class docstring
|
|
192
|
-
"ARG002", # Unused method argument
|
|
193
|
-
"TRY003", # Avoid specifying long messages outside the exception class
|
|
194
|
-
"TRY300", # Consider moving statement into the else clause
|
|
195
|
-
"ARG001", # Unused first argument
|
|
196
|
-
"PT019", # Fixture without value is injected as parameter, use @pytest.mark.usefixtures instead
|
|
197
|
-
"SIM108", # Use ternary operator instead of if-else block (ternaries lie to coverage)
|
|
198
|
-
"RET505", # Unnecessary `else` after `return` statement
|
|
199
|
-
"N805", # First argument of a method should be named `self`
|
|
200
|
-
"UP007", # Use `X | Y` for type annotations (we need this for testing and our runtime logic)
|
|
201
|
-
|
|
202
|
-
# The following rules are recommended to be ignored by ruff when using ruff format
|
|
203
|
-
"ISC001", # Checks for implicitly concatenated strings on a single line
|
|
204
|
-
"ISC002", # Checks for implicitly concatenated strings that span multiple lines
|
|
205
|
-
"W191", # Checks for indentation that uses tabs
|
|
206
|
-
"E111", # Checks for indentation with a non-multiple of 4 spaces
|
|
207
|
-
"E114", # Checks for indentation of comments with a non-multiple of 4 spaces
|
|
208
|
-
"E117", # Checks for over-indented code
|
|
209
|
-
"D206", # Checks for docstrings that are indented with tabs
|
|
210
|
-
"D300", # Checks for docstrings that use '''single quotes''' instead of """double quotes"""
|
|
211
|
-
"Q000", # Checks for inline strings that use single quotes or double quotes
|
|
212
|
-
"Q001", # Checks for multiline strings that use single quotes or double quotes
|
|
213
|
-
"Q002", # Checks for docstrings that use single quotes or double quotes
|
|
214
|
-
"Q003", # Checks for strings that include escaped quotes
|
|
215
|
-
"COM812", # Checks for the absence of trailing commas
|
|
216
|
-
"COM819", # Checks for the presence of prohibited trailing commas
|
|
217
|
-
"RET506", # Unnecessary `elif` after `raise` statement
|
|
218
|
-
]
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
[tool.ruff.lint.per-file-ignores]
|
|
222
|
-
"tests/*" = [
|
|
223
|
-
"S", # ignore bandit security issues in tests
|
|
224
|
-
"B018", # ignore useless expressions in tests
|
|
225
|
-
"PT012", # ignore complex with pytest.raises clauses
|
|
226
|
-
"RUF012", # ignore mutable class attributes ClassVar typehint requirement
|
|
227
|
-
"ANN001", # Missing type annotation for function argument
|
|
228
|
-
"ANN002", # Missing type annotation for *args
|
|
229
|
-
"ANN003", # Missing type annotation for **kwargs
|
|
230
|
-
"PGH003", # Use specific rule codes when ignoring type issues
|
|
231
|
-
"B008", # Do not perform function call in argument defaults
|
|
232
|
-
]
|
|
233
|
-
"cadwyn/_utils.py" = [
|
|
234
|
-
"ERA001", # Found commented-out code (it's not actually commented out. It's just comments)
|
|
235
|
-
]
|
|
236
|
-
|
|
237
|
-
[tool.ruff.lint.mccabe]
|
|
238
|
-
max-complexity = 14
|
|
239
|
-
|
|
240
|
-
[tool.ruff.format]
|
|
241
|
-
quote-style = "double"
|
|
242
|
-
indent-style = "space"
|
|
243
|
-
|
|
244
|
-
[build-system]
|
|
245
|
-
requires = ["poetry-core>=1.0.0"]
|
|
246
|
-
build-backend = "poetry.core.masonry.api"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|