cadwyn 3.15.4__tar.gz → 3.15.6__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.

Files changed (37) hide show
  1. {cadwyn-3.15.4 → cadwyn-3.15.6}/PKG-INFO +1 -1
  2. {cadwyn-3.15.4 → cadwyn-3.15.6}/cadwyn/__init__.py +3 -1
  3. {cadwyn-3.15.4 → cadwyn-3.15.6}/cadwyn/applications.py +22 -1
  4. {cadwyn-3.15.4 → cadwyn-3.15.6}/cadwyn/route_generation.py +17 -21
  5. {cadwyn-3.15.4 → cadwyn-3.15.6}/cadwyn/structure/versions.py +4 -3
  6. {cadwyn-3.15.4 → cadwyn-3.15.6}/pyproject.toml +3 -2
  7. {cadwyn-3.15.4 → cadwyn-3.15.6}/LICENSE +0 -0
  8. {cadwyn-3.15.4 → cadwyn-3.15.6}/README.md +0 -0
  9. {cadwyn-3.15.4 → cadwyn-3.15.6}/cadwyn/__main__.py +0 -0
  10. {cadwyn-3.15.4 → cadwyn-3.15.6}/cadwyn/_asts.py +0 -0
  11. {cadwyn-3.15.4 → cadwyn-3.15.6}/cadwyn/_compat.py +0 -0
  12. {cadwyn-3.15.4 → cadwyn-3.15.6}/cadwyn/_package_utils.py +0 -0
  13. {cadwyn-3.15.4 → cadwyn-3.15.6}/cadwyn/_utils.py +0 -0
  14. {cadwyn-3.15.4 → cadwyn-3.15.6}/cadwyn/codegen/README.md +0 -0
  15. {cadwyn-3.15.4 → cadwyn-3.15.6}/cadwyn/codegen/__init__.py +0 -0
  16. {cadwyn-3.15.4 → cadwyn-3.15.6}/cadwyn/codegen/_common.py +0 -0
  17. {cadwyn-3.15.4 → cadwyn-3.15.6}/cadwyn/codegen/_main.py +0 -0
  18. {cadwyn-3.15.4 → cadwyn-3.15.6}/cadwyn/codegen/_plugins/__init__.py +0 -0
  19. {cadwyn-3.15.4 → cadwyn-3.15.6}/cadwyn/codegen/_plugins/class_migrations.py +0 -0
  20. {cadwyn-3.15.4 → cadwyn-3.15.6}/cadwyn/codegen/_plugins/class_rebuilding.py +0 -0
  21. {cadwyn-3.15.4 → cadwyn-3.15.6}/cadwyn/codegen/_plugins/class_renaming.py +0 -0
  22. {cadwyn-3.15.4 → cadwyn-3.15.6}/cadwyn/codegen/_plugins/import_auto_adding.py +0 -0
  23. {cadwyn-3.15.4 → cadwyn-3.15.6}/cadwyn/codegen/_plugins/module_migrations.py +0 -0
  24. {cadwyn-3.15.4 → cadwyn-3.15.6}/cadwyn/exceptions.py +0 -0
  25. {cadwyn-3.15.4 → cadwyn-3.15.6}/cadwyn/main.py +0 -0
  26. {cadwyn-3.15.4 → cadwyn-3.15.6}/cadwyn/middleware.py +0 -0
  27. {cadwyn-3.15.4 → cadwyn-3.15.6}/cadwyn/py.typed +0 -0
  28. {cadwyn-3.15.4 → cadwyn-3.15.6}/cadwyn/routing.py +0 -0
  29. {cadwyn-3.15.4 → cadwyn-3.15.6}/cadwyn/static/__init__.py +0 -0
  30. {cadwyn-3.15.4 → cadwyn-3.15.6}/cadwyn/static/docs.html +0 -0
  31. {cadwyn-3.15.4 → cadwyn-3.15.6}/cadwyn/structure/__init__.py +0 -0
  32. {cadwyn-3.15.4 → cadwyn-3.15.6}/cadwyn/structure/common.py +0 -0
  33. {cadwyn-3.15.4 → cadwyn-3.15.6}/cadwyn/structure/data.py +0 -0
  34. {cadwyn-3.15.4 → cadwyn-3.15.6}/cadwyn/structure/endpoints.py +0 -0
  35. {cadwyn-3.15.4 → cadwyn-3.15.6}/cadwyn/structure/enums.py +0 -0
  36. {cadwyn-3.15.4 → cadwyn-3.15.6}/cadwyn/structure/modules.py +0 -0
  37. {cadwyn-3.15.4 → cadwyn-3.15.6}/cadwyn/structure/schemas.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: cadwyn
3
- Version: 3.15.4
3
+ Version: 3.15.6
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
@@ -7,7 +7,7 @@ from .route_generation import (
7
7
  VersionedAPIRouter,
8
8
  generate_versioned_routers,
9
9
  )
10
- from .structure import VersionBundle
10
+ from .structure import HeadVersion, Version, VersionBundle
11
11
 
12
12
  __version__ = importlib.metadata.version("cadwyn")
13
13
  __all__ = [
@@ -15,6 +15,8 @@ __all__ = [
15
15
  "VersionedAPIRouter",
16
16
  "generate_code_for_versioned_packages",
17
17
  "VersionBundle",
18
+ "HeadVersion",
19
+ "Version",
18
20
  "generate_versioned_routers",
19
21
  "InternalRepresentationOf",
20
22
  ]
@@ -1,3 +1,4 @@
1
+ import dataclasses
1
2
  import datetime
2
3
  from collections.abc import Callable, Coroutine, Sequence
3
4
  from datetime import date
@@ -34,6 +35,11 @@ CURR_DIR = Path(__file__).resolve()
34
35
  logger = getLogger(__name__)
35
36
 
36
37
 
38
+ @dataclasses.dataclass(slots=True)
39
+ class FakeDependencyOverridesProvider:
40
+ dependency_overrides: dict[Callable[..., Any], Callable[..., Any]]
41
+
42
+
37
43
  class Cadwyn(FastAPI):
38
44
  _templates = Jinja2Templates(directory=CURR_DIR.parent / "static")
39
45
 
@@ -92,6 +98,7 @@ class Cadwyn(FastAPI):
92
98
  latest_schemas_package = extra.pop("latest_schemas_package", None) or self.versions.head_schemas_package
93
99
  self.versions.head_schemas_package = latest_schemas_package
94
100
  self._latest_schemas_package = cast(ModuleType, latest_schemas_package)
101
+ self._dependency_overrides_provider = FakeDependencyOverridesProvider({})
95
102
 
96
103
  super().__init__(
97
104
  debug=debug,
@@ -166,6 +173,20 @@ class Cadwyn(FastAPI):
166
173
  default_response_class=default_response_class,
167
174
  )
168
175
 
176
+ @property
177
+ def dependency_overrides(self) -> dict[Callable[..., Any], Callable[..., Any]]:
178
+ # This is only necessary because we cannot send self to versioned router generator
179
+ # because it takes a deepcopy of the router and self.versions.head_schemas_package is a module
180
+ # which cannot be copied.
181
+ return self._dependency_overrides_provider.dependency_overrides
182
+
183
+ @dependency_overrides.setter
184
+ def dependency_overrides( # pyright: ignore[reportIncompatibleVariableOverride]
185
+ self,
186
+ value: dict[Callable[..., Any], Callable[..., Any]],
187
+ ) -> None:
188
+ self._dependency_overrides_provider.dependency_overrides = value
189
+
169
190
  @property # pragma: no cover
170
191
  @deprecated("It is going to be deleted in the future. Use VersionBundle.head_schemas_package instead")
171
192
  def latest_schemas_package(self):
@@ -209,7 +230,7 @@ class Cadwyn(FastAPI):
209
230
  )
210
231
 
211
232
  def generate_and_include_versioned_routers(self, *routers: APIRouter) -> None:
212
- root_router = APIRouter()
233
+ root_router = APIRouter(dependency_overrides_provider=self._dependency_overrides_provider)
213
234
  for router in routers:
214
235
  root_router.include_router(router)
215
236
  router_versions = generate_versioned_routers(
@@ -12,6 +12,7 @@ from enum import Enum
12
12
  from pathlib import Path
13
13
  from types import GenericAlias, MappingProxyType, ModuleType
14
14
  from typing import (
15
+ TYPE_CHECKING,
15
16
  Annotated,
16
17
  Any,
17
18
  Generic,
@@ -28,23 +29,18 @@ import fastapi.params
28
29
  import fastapi.routing
29
30
  import fastapi.security.base
30
31
  import fastapi.utils
31
- from fastapi import APIRouter
32
+ from fastapi import (
33
+ APIRouter,
34
+ Request, # noqa: F401 # We import Request for libraries like svcs that expect it to be in globals
35
+ Response, # noqa: F401 # We import Request for libraries like svcs that expect it to be in globals
36
+ )
32
37
  from fastapi._compat import ModelField as FastAPIModelField
33
38
  from fastapi._compat import create_body_model
34
- from fastapi.dependencies.models import Dependant
35
- from fastapi.dependencies.utils import (
36
- get_body_field,
37
- get_dependant,
38
- get_parameterless_sub_dependant,
39
- )
40
39
  from fastapi.params import Depends
41
40
  from fastapi.routing import APIRoute
42
41
  from issubclass import issubclass as lenient_issubclass
43
42
  from pydantic import BaseModel
44
- from starlette.routing import (
45
- BaseRoute,
46
- request_response,
47
- )
43
+ from starlette.routing import BaseRoute
48
44
  from typing_extensions import Self, assert_never, deprecated
49
45
 
50
46
  from cadwyn._compat import get_annotation_from_model_field, model_fields, rebuild_fastapi_body_param
@@ -68,6 +64,9 @@ from cadwyn.structure.endpoints import (
68
64
  )
69
65
  from cadwyn.structure.versions import _CADWYN_REQUEST_PARAM_NAME, _CADWYN_RESPONSE_PARAM_NAME, VersionChange
70
66
 
67
+ if TYPE_CHECKING:
68
+ from fastapi.dependencies.models import Dependant
69
+
71
70
  _T = TypeVar("_T", bound=Callable[..., Any])
72
71
  _R = TypeVar("_R", bound=fastapi.routing.APIRouter)
73
72
  # This is a hack we do because we can't guarantee how the user will use the router.
@@ -308,7 +307,7 @@ class _EndpointTransformer(Generic[_R]):
308
307
 
309
308
  def _replace_internal_representation_with_the_versioned_schema(
310
309
  self,
311
- copy_of_dependant: Dependant,
310
+ copy_of_dependant: "Dependant",
312
311
  schema_to_internal_request_body_representation: dict[type[BaseModel], type[BaseModel]],
313
312
  ):
314
313
  body_param: FastAPIModelField = copy_of_dependant.body_params[0]
@@ -658,15 +657,12 @@ def _modify_callable(
658
657
 
659
658
 
660
659
  def _remake_endpoint_dependencies(route: fastapi.routing.APIRoute):
661
- route.dependant = get_dependant(path=route.path_format, call=route.endpoint)
660
+ # Unlike get_dependant, APIRoute is the public API of FastAPI and it's (almost) guaranteed to be stable.
661
+
662
+ route_copy = fastapi.routing.APIRoute(route.path, route.endpoint, dependencies=route.dependencies)
663
+ route.dependant = route_copy.dependant
664
+ route.body_field = route_copy.body_field
662
665
  _add_request_and_response_params(route)
663
- route.body_field = get_body_field(dependant=route.dependant, name=route.unique_id)
664
- for depends in route.dependencies[::-1]:
665
- route.dependant.dependencies.insert(
666
- 0,
667
- get_parameterless_sub_dependant(depends=depends, path=route.path_format),
668
- )
669
- route.app = request_response(route.get_route_handler())
670
666
 
671
667
 
672
668
  def _add_request_and_response_params(route: APIRoute):
@@ -681,7 +677,7 @@ def _add_data_migrations_to_route(
681
677
  head_route: Any,
682
678
  template_body_field: type[BaseModel] | None,
683
679
  template_body_field_name: str | None,
684
- dependant_for_request_migrations: Dependant,
680
+ dependant_for_request_migrations: "Dependant",
685
681
  versions: VersionBundle,
686
682
  ):
687
683
  if not (route.dependant.request_param_name and route.dependant.response_param_name): # pragma: no cover
@@ -285,6 +285,8 @@ class VersionBundle:
285
285
  raise CadwynStructureError(
286
286
  "Versions are not sorted correctly. Please sort them in descending order.",
287
287
  )
288
+ if not self.versions:
289
+ raise CadwynStructureError("You must define at least one non-head version in a VersionBundle.")
288
290
  if self.versions[-1].version_changes:
289
291
  raise CadwynStructureError(
290
292
  f'The first version "{self.versions[-1].value}" cannot have any version changes. '
@@ -325,7 +327,7 @@ class VersionBundle:
325
327
  raise CadwynStructureError(
326
328
  f'The head schemas package must be a package. "{head_schemas_package.__name__}" is not a package.',
327
329
  )
328
- elif head_schemas_package.__name__.endswith(".head"):
330
+ elif head_schemas_package.__name__.endswith(".head") or head_schemas_package.__name__ == "head":
329
331
  return "head"
330
332
  elif head_schemas_package.__name__.endswith(".latest"):
331
333
  warnings.warn(
@@ -463,7 +465,6 @@ class VersionBundle:
463
465
  request.scope["headers"] = tuple((key.encode(), value.encode()) for key, value in request_info.headers.items())
464
466
  del request._headers
465
467
  # Remember this: if len(body_params) == 1, then route.body_schema == route.dependant.body_params[0]
466
-
467
468
  dependencies, errors, _, _, _ = await solve_dependencies(
468
469
  request=request,
469
470
  response=response,
@@ -803,7 +804,7 @@ async def _get_body(
803
804
  ) from e
804
805
  except HTTPException:
805
806
  raise
806
- except Exception as e: # noqa: BLE001
807
+ except Exception as e:
807
808
  raise HTTPException(status_code=400, detail="There was an error parsing the body") from e
808
809
  return body
809
810
 
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "cadwyn"
3
- version = "3.15.4"
3
+ version = "3.15.6"
4
4
  description = "Production-ready community-driven modern Stripe-like API versioning in FastAPI"
5
5
  authors = ["Stanislav Zmiev <zmievsa@gmail.com>"]
6
6
  license = "MIT"
@@ -68,7 +68,6 @@ cli = ["typer"]
68
68
  pytest = ">=7.2.1"
69
69
  pytest-cov = ">=4.0.0"
70
70
  uvicorn = "*"
71
- devtools = "*"
72
71
  pdbpp = "^0.10.3"
73
72
  httpx = "*"
74
73
  pytest-fixture-classes = ">=1.0.3"
@@ -78,6 +77,8 @@ mkdocs-material = ">=9.3.1"
78
77
  python-multipart = ">=0.0.6"
79
78
  mkdocs-simple-hooks = ">=0.1.5"
80
79
  pytest-sugar = "^1.0.0"
80
+ better-devtools = "^0.13.3"
81
+ svcs = "^24.1.0"
81
82
 
82
83
  [tool.poetry.scripts]
83
84
  cadwyn = "cadwyn.__main__:app"
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