cadwyn 3.15.10__py3-none-any.whl → 4.1.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.

Potentially problematic release.


This version of cadwyn might be problematic. Click here for more details.

cadwyn/_utils.py CHANGED
@@ -1,13 +1,7 @@
1
- import functools
2
- import importlib
3
- import inspect
4
- import sys
5
- from collections.abc import Callable, Collection
6
- from pathlib import Path
7
- from types import ModuleType
1
+ from collections.abc import Callable
8
2
  from typing import Any, Generic, TypeVar, Union
9
3
 
10
- from cadwyn.exceptions import CadwynError, ModuleIsNotVersionedError
4
+ from pydantic._internal._decorators import unwrap_wrapped_function
11
5
 
12
6
  Sentinel: Any = object()
13
7
  UnionType = type(int | str) | type(Union[int, str])
@@ -41,102 +35,8 @@ def same_definition_as_in(t: _T) -> Callable[[Callable], _T]:
41
35
  return decorator
42
36
 
43
37
 
44
- @functools.cache
45
- def get_another_version_of_cls(
46
- cls_from_old_version: type[Any], new_version_dir: Path, version_dirs: frozenset[Path] | tuple[Path, ...]
47
- ):
48
- # version_dir = /home/myuser/package/companies/v2021_01_01
49
- module_from_old_version = sys.modules[cls_from_old_version.__module__]
50
- try:
51
- module = get_another_version_of_module(module_from_old_version, new_version_dir, version_dirs)
52
- except ModuleIsNotVersionedError:
53
- return cls_from_old_version
54
- return getattr(module, cls_from_old_version.__name__)
55
-
56
-
57
- def get_another_version_of_module(
58
- module_from_old_version: ModuleType,
59
- new_version_dir: Path,
60
- version_dirs: frozenset[Path] | tuple[Path, ...],
61
- ):
62
- new_model_module_python_path = get_pythonpath_to_another_version_of_module(
63
- module_from_old_version,
64
- new_version_dir,
65
- version_dirs,
66
- )
67
- return importlib.import_module(new_model_module_python_path)
68
-
69
-
70
- def get_pythonpath_to_another_version_of_module(
71
- module_from_old_version: ModuleType,
72
- new_version_dir: Path,
73
- version_dirs: frozenset[Path] | tuple[Path, ...],
74
- ) -> str:
75
- # ['package', 'companies', 'head', 'schemas']
76
- # ^^^^^^
77
- # index = 2
78
- index_of_base_schema_dir = get_index_of_head_schema_dir_in_module_python_path(
79
- module_from_old_version,
80
- new_version_dir,
81
- version_dirs,
82
- )
83
-
84
- # ['package', 'companies', 'head', 'schemas']
85
- model_split_python_path = module_from_old_version.__name__.split(".")
86
- # ['package', 'companies', 'v2021_01_01', 'schemas']
87
- model_split_python_path[index_of_base_schema_dir] = new_version_dir.name
88
- # package.companies.v2021_01_01.schemas
89
- return ".".join(model_split_python_path)
90
-
91
-
92
- @functools.cache
93
- def get_index_of_head_schema_dir_in_module_python_path(
94
- module_from_old_version: ModuleType,
95
- parallel_dir: Path,
96
- version_dirs: frozenset[Path] = frozenset(),
97
- ) -> int:
98
- """If version_dirs have been passed, we will check if the module is versioned and raise an exception if it isn't"""
99
- file = inspect.getsourcefile(module_from_old_version)
100
- # Impossible to cover
101
- if file is None: # pragma: no cover
102
- raise CadwynError(
103
- f"Model {module_from_old_version} is not defined in a file. It is likely because it's a compiled module "
104
- "which Cadwyn couldn't migrate to an older version. "
105
- "If you are seeing this error -- you've encountered a bug in Cadwyn.",
106
- )
107
- # /home/myuser/package/companies/head/__init__.py
108
- file = Path(file)
109
- _validate_that_module_is_versioned(file, version_dirs)
110
- is_package = file.name == "__init__.py"
111
- if is_package:
112
- # /home/myuser/package/companies/head/
113
- file = file.parent
114
- # /home/myuser/package/companies
115
- root_dir = parallel_dir.parent
116
- # head/schemas
117
- relative_file = file.relative_to(root_dir).with_suffix("")
118
- # ['head', 'schemas']
119
- relative_file_parts = relative_file.parts
120
- # package.companies.head.schemas.payables
121
- module_python_path = module_from_old_version.__name__
122
- # ['package', 'companies', 'head', 'schemas']
123
- module_split_python_path = module_python_path.split(".")
124
-
125
- index = len(module_split_python_path) - len(relative_file_parts) - int(is_package)
126
-
127
- # When we are in latest/__init__.py, we have this special case
128
- if len(relative_file_parts) == 1 and is_package:
129
- index += 1
130
- return index
131
-
132
-
133
- def _validate_that_module_is_versioned(file: Path, version_dirs: Collection[Path]):
134
- if not version_dirs:
135
- return
136
- for version_dir in version_dirs:
137
- try:
138
- file.relative_to(version_dir)
139
- return
140
- except ValueError:
141
- pass
142
- raise ModuleIsNotVersionedError(f"Module {file} is not versioned.")
38
+ def fully_unwrap_decorator(func: Callable, is_pydantic_v1_style_validator: Any):
39
+ func = unwrap_wrapped_function(func)
40
+ if is_pydantic_v1_style_validator and func.__closure__:
41
+ func = func.__closure__[0].cell_contents
42
+ return unwrap_wrapped_function(func)
cadwyn/applications.py CHANGED
@@ -4,7 +4,6 @@ from collections.abc import Callable, Coroutine, Sequence
4
4
  from datetime import date
5
5
  from logging import getLogger
6
6
  from pathlib import Path
7
- from types import ModuleType
8
7
  from typing import Any, cast
9
8
 
10
9
  from fastapi import APIRouter, FastAPI, HTTPException, routing
@@ -24,7 +23,7 @@ from starlette.requests import Request
24
23
  from starlette.responses import JSONResponse, Response
25
24
  from starlette.routing import BaseRoute, Route
26
25
  from starlette.types import Lifespan
27
- from typing_extensions import Self, deprecated
26
+ from typing_extensions import Self
28
27
 
29
28
  from cadwyn.middleware import HeaderVersioningMiddleware, _get_api_version_dependency
30
29
  from cadwyn.route_generation import generate_versioned_routers
@@ -95,9 +94,6 @@ class Cadwyn(FastAPI):
95
94
  ) -> None:
96
95
  self.versions = versions
97
96
  # TODO: Remove argument entirely in any major version.
98
- latest_schemas_package = extra.pop("latest_schemas_package", None) or self.versions.head_schemas_package
99
- self.versions.head_schemas_package = latest_schemas_package
100
- self._latest_schemas_package = cast(ModuleType, latest_schemas_package)
101
97
  self._dependency_overrides_provider = FakeDependencyOverridesProvider({})
102
98
 
103
99
  super().__init__(
@@ -175,9 +171,10 @@ class Cadwyn(FastAPI):
175
171
 
176
172
  @property
177
173
  def dependency_overrides(self) -> dict[Callable[..., Any], Callable[..., Any]]:
174
+ # TODO: Remove this approach as it is no longer necessary
178
175
  # 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.
176
+ # because it takes a deepcopy of the router and self.versions.head_schemas_package was a module
177
+ # which couldn't be copied.
181
178
  return self._dependency_overrides_provider.dependency_overrides
182
179
 
183
180
  @dependency_overrides.setter
@@ -187,16 +184,6 @@ class Cadwyn(FastAPI):
187
184
  ) -> None:
188
185
  self._dependency_overrides_provider.dependency_overrides = value
189
186
 
190
- @property # pragma: no cover
191
- @deprecated("It is going to be deleted in the future. Use VersionBundle.head_schemas_package instead")
192
- def latest_schemas_package(self):
193
- return self._latest_schemas_package
194
-
195
- @latest_schemas_package.setter # pragma: no cover
196
- @deprecated("It is going to be deleted in the future. Use VersionBundle.head_schemas_package instead")
197
- def latest_schemas_package(self, value: ModuleType | None):
198
- self._latest_schemas_package = value
199
-
200
187
  def _add_openapi_endpoints(self, unversioned_router: APIRouter):
201
188
  if self.openapi_url is not None:
202
189
  unversioned_router.add_route(
@@ -233,10 +220,7 @@ class Cadwyn(FastAPI):
233
220
  root_router = APIRouter(dependency_overrides_provider=self._dependency_overrides_provider)
234
221
  for router in routers:
235
222
  root_router.include_router(router)
236
- router_versions = generate_versioned_routers(
237
- root_router,
238
- versions=self.versions,
239
- )
223
+ router_versions = generate_versioned_routers(root_router, versions=self.versions)
240
224
  for version, router in router_versions.items():
241
225
  self.add_header_versioned_routers(router, header_value=version.isoformat())
242
226
 
@@ -358,16 +342,3 @@ class Cadwyn(FastAPI):
358
342
  self.router.routes.extend(added_routes)
359
343
 
360
344
  return added_routes
361
-
362
- @deprecated("Use builtin FastAPI methods such as include_router instead")
363
- def add_unversioned_routers(self, *routers: APIRouter):
364
- for router in routers:
365
- self.include_router(router)
366
-
367
- @deprecated("Use builtin FastAPI methods such as add_api_route instead")
368
- def add_unversioned_routes(self, *routes: Route):
369
- router = APIRouter(routes=list(routes))
370
- self.include_router(router)
371
-
372
- @deprecated("It no longer does anything")
373
- def enrich_swagger(self): ...
cadwyn/exceptions.py CHANGED
@@ -5,6 +5,10 @@ from typing import Any
5
5
  from fastapi.routing import APIRoute
6
6
 
7
7
 
8
+ class CadwynRenderError(Exception):
9
+ pass
10
+
11
+
8
12
  class CadwynError(Exception):
9
13
  pass
10
14
 
@@ -26,15 +30,15 @@ class LintingError(CadwynError):
26
30
  pass
27
31
 
28
32
 
29
- class CodeGenerationError(CadwynError):
33
+ class SchemaGenerationError(CadwynError):
30
34
  pass
31
35
 
32
36
 
33
- class ModuleIsNotAvailableAsTextError(CodeGenerationError):
37
+ class ModuleIsNotAvailableAsTextError(SchemaGenerationError):
34
38
  pass
35
39
 
36
40
 
37
- class InvalidGenerationInstructionError(CodeGenerationError):
41
+ class InvalidGenerationInstructionError(SchemaGenerationError):
38
42
  pass
39
43
 
40
44
 
@@ -70,3 +74,7 @@ class CadwynStructureError(CadwynError):
70
74
 
71
75
  class ModuleIsNotVersionedError(ValueError):
72
76
  pass
77
+
78
+
79
+ class ImportFromStringError(CadwynError):
80
+ pass
cadwyn/middleware.py CHANGED
@@ -64,11 +64,11 @@ class HeaderVersioningMiddleware(BaseHTTPMiddleware):
64
64
  request=request,
65
65
  dependant=self.version_header_validation_dependant,
66
66
  async_exit_stack=async_exit_stack,
67
- embed_body_fields=False,
68
67
  )
69
- if solved_result.errors:
70
- return self.default_response_class(status_code=422, content=_normalize_errors(solved_result.errors))
71
- api_version = cast(date, solved_result.values[self.api_version_header_name.replace("-", "_")])
68
+ values, errors, *_ = solved_result
69
+ if errors:
70
+ return self.default_response_class(status_code=422, content=_normalize_errors(errors))
71
+ api_version = cast(date, values[self.api_version_header_name.replace("-", "_")])
72
72
  self.api_version_var.set(api_version)
73
73
 
74
74
  response = await call_next(request)