cadwyn 5.0.0a1__py3-none-any.whl → 5.1.0a1__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/_asts.py CHANGED
@@ -2,10 +2,11 @@ import ast
2
2
  import inspect
3
3
  from collections.abc import Callable
4
4
  from enum import Enum, auto
5
- from types import GenericAlias, LambdaType, NoneType
5
+ from types import GenericAlias, LambdaType
6
6
  from typing import ( # noqa: UP035
7
7
  Any,
8
8
  List,
9
+ Union,
9
10
  cast,
10
11
  get_args,
11
12
  get_origin,
@@ -17,6 +18,7 @@ from cadwyn._utils import PlainRepr, UnionType
17
18
  from cadwyn.exceptions import InvalidGenerationInstructionError
18
19
 
19
20
  _LambdaFunctionName = (lambda: None).__name__ # pragma: no branch
21
+ NoneType = type(None)
20
22
 
21
23
 
22
24
  # A parent type of typing._GenericAlias
@@ -25,17 +27,18 @@ _BaseGenericAlias = cast(type, type(List[int])).mro()[1] # noqa: UP006
25
27
  # type(list[int]) and type(List[int]) are different which is why we have to do this.
26
28
  # Please note that this problem is much wider than just lists which is why we use typing._BaseGenericAlias
27
29
  # instead of typing._GenericAlias.
28
- GenericAliasUnion = GenericAlias | _BaseGenericAlias
30
+ GenericAliasUnion = Union[GenericAlias, _BaseGenericAlias]
31
+ GenericAliasUnionArgs = get_args(GenericAliasUnion)
29
32
 
30
33
 
31
34
  def get_fancy_repr(value: Any) -> Any:
32
35
  if isinstance(value, annotated_types.GroupedMetadata) and hasattr(type(value), "__dataclass_fields__"):
33
36
  return transform_grouped_metadata(value)
34
- if isinstance(value, list | tuple | set | frozenset):
37
+ if isinstance(value, (list, tuple, set, frozenset)):
35
38
  return transform_collection(value)
36
39
  if isinstance(value, dict):
37
40
  return transform_dict(value)
38
- if isinstance(value, GenericAliasUnion):
41
+ if isinstance(value, GenericAliasUnionArgs):
39
42
  return transform_generic_alias(value)
40
43
  if value is None or value is NoneType:
41
44
  return transform_none(value)
@@ -46,7 +49,7 @@ def get_fancy_repr(value: Any) -> Any:
46
49
  if isinstance(value, auto): # pragma: no cover # it works but we no longer use auto
47
50
  return transform_auto(value)
48
51
  if isinstance(value, UnionType):
49
- return transform_union(value)
52
+ return transform_union(value) # pragma: no cover
50
53
  if isinstance(value, LambdaType) and _LambdaFunctionName == value.__name__:
51
54
  return transform_lambda(value)
52
55
  if inspect.isfunction(value):
@@ -72,7 +75,7 @@ def transform_grouped_metadata(value: "annotated_types.GroupedMetadata"):
72
75
  )
73
76
 
74
77
 
75
- def transform_collection(value: list | tuple | set | frozenset) -> Any:
78
+ def transform_collection(value: Union[list, tuple, set, frozenset]) -> Any:
76
79
  return PlainRepr(value.__class__(map(get_fancy_repr, value)))
77
80
 
78
81
 
@@ -102,7 +105,7 @@ def transform_auto(_: auto) -> Any: # pragma: no cover # it works but we no lon
102
105
  return PlainRepr("auto()")
103
106
 
104
107
 
105
- def transform_union(value: UnionType) -> Any:
108
+ def transform_union(value: UnionType) -> Any: # pragma: no cover
106
109
  return "typing.Union[" + (", ".join(get_fancy_repr(a) for a in get_args(value))) + "]"
107
110
 
108
111
 
cadwyn/_render.py CHANGED
@@ -2,7 +2,7 @@ import ast
2
2
  import inspect
3
3
  import textwrap
4
4
  from enum import Enum
5
- from typing import TYPE_CHECKING
5
+ from typing import TYPE_CHECKING, Union
6
6
 
7
7
  import typer
8
8
  from issubclass import issubclass as lenient_issubclass
@@ -30,7 +30,7 @@ def render_module_by_path(module_path: str, app_path: str, version: str):
30
30
  attributes_to_alter = [
31
31
  name
32
32
  for name, value in module.__dict__.items()
33
- if lenient_issubclass(value, Enum | BaseModel) and value.__module__ == module.__name__
33
+ if lenient_issubclass(value, (Enum, BaseModel)) and value.__module__ == module.__name__
34
34
  ]
35
35
 
36
36
  try:
@@ -53,12 +53,12 @@ def render_module_by_path(module_path: str, app_path: str, version: str):
53
53
 
54
54
  def render_model_by_path(model_path: str, app_path: str, version: str) -> str:
55
55
  # cadwyn render model schemas:MySchema --app=run:app --version=2000-01-01
56
- model: type[BaseModel | Enum] = import_attribute_from_string(model_path)
56
+ model: type[Union[BaseModel, Enum]] = import_attribute_from_string(model_path)
57
57
  app: Cadwyn = import_attribute_from_string(app_path)
58
58
  return render_model(model, app.versions, version)
59
59
 
60
60
 
61
- def render_model(model: type[BaseModel | Enum], versions: VersionBundle, version: str) -> str:
61
+ def render_model(model: type[Union[BaseModel, Enum]], versions: VersionBundle, version: str) -> str:
62
62
  try:
63
63
  original_cls_node = ast.parse(textwrap.dedent(inspect.getsource(model))).body[0]
64
64
  except (OSError, SyntaxError, ValueError): # pragma: no cover
@@ -71,7 +71,7 @@ def render_model(model: type[BaseModel | Enum], versions: VersionBundle, version
71
71
 
72
72
 
73
73
  def _render_model_from_ast(
74
- model_ast: ast.ClassDef, model: type[BaseModel | Enum], versions: VersionBundle, version: str
74
+ model_ast: ast.ClassDef, model: type[Union[BaseModel, Enum]], versions: VersionBundle, version: str
75
75
  ):
76
76
  versioned_models = generate_versioned_models(versions)
77
77
  generator = versioned_models[version]
@@ -97,7 +97,7 @@ def _render_enum_model(wrapper: _EnumWrapper, original_cls_node: ast.ClassDef):
97
97
  ]
98
98
 
99
99
  old_body = [
100
- n for n in original_cls_node.body if not isinstance(n, ast.AnnAssign | ast.Assign | ast.Pass | ast.Constant)
100
+ n for n in original_cls_node.body if not isinstance(n, (ast.AnnAssign, ast.Assign, ast.Pass, ast.Constant))
101
101
  ]
102
102
  docstring = pop_docstring_from_cls_body(old_body)
103
103
 
@@ -130,7 +130,7 @@ def _render_pydantic_model(wrapper: _PydanticModelWrapper, original_cls_node: as
130
130
  n
131
131
  for n in original_cls_node.body
132
132
  if not (
133
- isinstance(n, ast.AnnAssign | ast.Assign | ast.Pass | ast.Constant)
133
+ isinstance(n, (ast.AnnAssign, ast.Assign, ast.Pass, ast.Constant))
134
134
  or (isinstance(n, ast.FunctionDef) and n.name in wrapper.validators)
135
135
  )
136
136
  ]
cadwyn/_utils.py CHANGED
@@ -1,10 +1,11 @@
1
+ import sys
1
2
  from collections.abc import Callable
2
3
  from typing import TYPE_CHECKING, Any, Generic, TypeVar, Union
3
4
 
4
5
  from pydantic._internal._decorators import unwrap_wrapped_function
5
6
 
6
7
  Sentinel: Any = object()
7
- UnionType = type(int | str) | type(Union[int, str])
8
+
8
9
  _T = TypeVar("_T", bound=Callable)
9
10
 
10
11
 
@@ -12,6 +13,28 @@ _P_T = TypeVar("_P_T")
12
13
  _P_R = TypeVar("_P_R")
13
14
 
14
15
 
16
+ if sys.version_info >= (3, 10):
17
+ UnionType = type(int | str) | type(Union[int, str])
18
+ DATACLASS_SLOTS: dict[str, Any] = {"slots": True}
19
+ ZIP_STRICT_TRUE: dict[str, Any] = {"strict": True}
20
+ ZIP_STRICT_FALSE: dict[str, Any] = {"strict": False}
21
+ DATACLASS_KW_ONLY: dict[str, Any] = {"kw_only": True}
22
+ else:
23
+ UnionType = type(Union[int, str])
24
+ DATACLASS_SLOTS: dict[str, Any] = {}
25
+ DATACLASS_KW_ONLY: dict[str, Any] = {}
26
+ ZIP_STRICT_TRUE: dict[str, Any] = {}
27
+ ZIP_STRICT_FALSE: dict[str, Any] = {}
28
+
29
+
30
+ def get_name_of_function_wrapped_in_pydantic_validator(func: Any) -> str:
31
+ if hasattr(func, "wrapped"):
32
+ return get_name_of_function_wrapped_in_pydantic_validator(func.wrapped)
33
+ if hasattr(func, "__func__"):
34
+ return get_name_of_function_wrapped_in_pydantic_validator(func.__func__)
35
+ return func.__name__
36
+
37
+
15
38
  class classproperty(Generic[_P_T, _P_R]): # noqa: N801
16
39
  def __init__(self, func: Callable[[_P_T], _P_R]) -> None:
17
40
  super().__init__()
@@ -49,7 +72,7 @@ if TYPE_CHECKING:
49
72
 
50
73
  else:
51
74
 
52
- def lenient_issubclass(cls: type, other: T | tuple[T, ...]) -> bool:
75
+ def lenient_issubclass(cls: type, other: Union[T, tuple[T, ...]]) -> bool:
53
76
  try:
54
77
  return issubclass(cls, other)
55
78
  except TypeError: # pragma: no cover
cadwyn/applications.py CHANGED
@@ -4,7 +4,7 @@ from collections.abc import Awaitable, Callable, Coroutine, Sequence
4
4
  from datetime import date
5
5
  from logging import getLogger
6
6
  from pathlib import Path
7
- from typing import TYPE_CHECKING, Annotated, Any, cast
7
+ from typing import TYPE_CHECKING, Annotated, Any, Union, cast
8
8
 
9
9
  import fastapi
10
10
  from fastapi import APIRouter, FastAPI, HTTPException, routing
@@ -26,7 +26,7 @@ from starlette.routing import BaseRoute, Route
26
26
  from starlette.types import Lifespan
27
27
  from typing_extensions import Self, assert_never, deprecated
28
28
 
29
- from cadwyn._utils import same_definition_as_in
29
+ from cadwyn._utils import DATACLASS_SLOTS, same_definition_as_in
30
30
  from cadwyn.changelogs import CadwynChangelogResource, _generate_changelog
31
31
  from cadwyn.exceptions import CadwynStructureError
32
32
  from cadwyn.middleware import (
@@ -48,7 +48,7 @@ CURR_DIR = Path(__file__).resolve()
48
48
  logger = getLogger(__name__)
49
49
 
50
50
 
51
- @dataclasses.dataclass(slots=True)
51
+ @dataclasses.dataclass(**DATACLASS_SLOTS)
52
52
  class FakeDependencyOverridesProvider:
53
53
  dependency_overrides: dict[Callable[..., Any], Callable[..., Any]]
54
54
 
@@ -61,7 +61,7 @@ class Cadwyn(FastAPI):
61
61
  *,
62
62
  versions: VersionBundle,
63
63
  api_version_header_name: Annotated[
64
- str | None,
64
+ Union[str, None],
65
65
  deprecated(
66
66
  "api_version_header_name is deprecated and will be removed in the future. "
67
67
  "Use api_version_parameter_name instead."
@@ -70,49 +70,51 @@ class Cadwyn(FastAPI):
70
70
  api_version_location: APIVersionLocation = "custom_header",
71
71
  api_version_format: APIVersionFormat = "date",
72
72
  api_version_parameter_name: str = "x-api-version",
73
- api_version_default_value: str | None | Callable[[Request], Awaitable[str]] = None,
73
+ api_version_default_value: Union[str, None, Callable[[Request], Awaitable[str]]] = None,
74
74
  versioning_middleware_class: type[VersionPickingMiddleware] = VersionPickingMiddleware,
75
- changelog_url: str | None = "/changelog",
75
+ changelog_url: Union[str, None] = "/changelog",
76
76
  include_changelog_url_in_schema: bool = True,
77
77
  debug: bool = False,
78
78
  title: str = "FastAPI",
79
- summary: str | None = None,
79
+ summary: Union[str, None] = None,
80
80
  description: str = "",
81
81
  version: str = "0.1.0",
82
- openapi_url: str | None = "/openapi.json",
83
- openapi_tags: list[dict[str, Any]] | None = None,
84
- servers: list[dict[str, str | Any]] | None = None,
85
- dependencies: Sequence[Depends] | None = None,
82
+ openapi_url: Union[str, None] = "/openapi.json",
83
+ openapi_tags: Union[list[dict[str, Any]], None] = None,
84
+ servers: Union[list[dict[str, Union[str, Any]]], None] = None,
85
+ dependencies: Union[Sequence[Depends], None] = None,
86
86
  default_response_class: type[Response] = JSONResponse,
87
87
  redirect_slashes: bool = True,
88
- routes: list[BaseRoute] | None = None,
89
- docs_url: str | None = "/docs",
90
- redoc_url: str | None = "/redoc",
91
- swagger_ui_oauth2_redirect_url: str | None = "/docs/oauth2-redirect",
92
- swagger_ui_init_oauth: dict[str, Any] | None = None,
93
- middleware: Sequence[Middleware] | None = None,
88
+ routes: Union[list[BaseRoute], None] = None,
89
+ docs_url: Union[str, None] = "/docs",
90
+ redoc_url: Union[str, None] = "/redoc",
91
+ swagger_ui_oauth2_redirect_url: Union[str, None] = "/docs/oauth2-redirect",
92
+ swagger_ui_init_oauth: Union[dict[str, Any], None] = None,
93
+ middleware: Union[Sequence[Middleware], None] = None,
94
94
  exception_handlers: (
95
- dict[
96
- int | type[Exception],
97
- Callable[[Request, Any], Coroutine[Any, Any, Response]],
95
+ Union[
96
+ dict[
97
+ Union[int, type[Exception]],
98
+ Callable[[Request, Any], Coroutine[Any, Any, Response]],
99
+ ],
100
+ None,
98
101
  ]
99
- | None
100
102
  ) = None,
101
- on_startup: Sequence[Callable[[], Any]] | None = None,
102
- on_shutdown: Sequence[Callable[[], Any]] | None = None,
103
- lifespan: Lifespan[Self] | None = None,
104
- terms_of_service: str | None = None,
105
- contact: dict[str, str | Any] | None = None,
106
- license_info: dict[str, str | Any] | None = None,
103
+ on_startup: Union[Sequence[Callable[[], Any]], None] = None,
104
+ on_shutdown: Union[Sequence[Callable[[], Any]], None] = None,
105
+ lifespan: Union[Lifespan[Self], None] = None,
106
+ terms_of_service: Union[str, None] = None,
107
+ contact: Union[dict[str, Union[str, Any]], None] = None,
108
+ license_info: Union[dict[str, Union[str, Any]], None] = None,
107
109
  openapi_prefix: str = "",
108
110
  root_path: str = "",
109
111
  root_path_in_servers: bool = True,
110
- responses: dict[int | str, dict[str, Any]] | None = None,
111
- callbacks: list[BaseRoute] | None = None,
112
- webhooks: APIRouter | None = None,
113
- deprecated: bool | None = None,
112
+ responses: Union[dict[Union[int, str], dict[str, Any]], None] = None,
113
+ callbacks: Union[list[BaseRoute], None] = None,
114
+ webhooks: Union[APIRouter, None] = None,
115
+ deprecated: Union[bool, None] = None,
114
116
  include_in_schema: bool = True,
115
- swagger_ui_parameters: dict[str, Any] | None = None,
117
+ swagger_ui_parameters: Union[dict[str, Any], None] = None,
116
118
  generate_unique_id_function: Callable[[routing.APIRoute], str] = Default( # noqa: B008
117
119
  generate_unique_id
118
120
  ),