cadwyn 5.4.3__py3-none-any.whl → 5.4.5__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/changelogs.py +13 -9
- cadwyn/schema_generation.py +29 -8
- cadwyn/structure/endpoints.py +1 -1
- cadwyn/structure/versions.py +1 -1
- {cadwyn-5.4.3.dist-info → cadwyn-5.4.5.dist-info}/METADATA +1 -24
- {cadwyn-5.4.3.dist-info → cadwyn-5.4.5.dist-info}/RECORD +9 -9
- {cadwyn-5.4.3.dist-info → cadwyn-5.4.5.dist-info}/WHEEL +0 -0
- {cadwyn-5.4.3.dist-info → cadwyn-5.4.5.dist-info}/entry_points.txt +0 -0
- {cadwyn-5.4.3.dist-info → cadwyn-5.4.5.dist-info}/licenses/LICENSE +0 -0
cadwyn/changelogs.py
CHANGED
|
@@ -2,14 +2,8 @@ import copy
|
|
|
2
2
|
import sys
|
|
3
3
|
from enum import auto
|
|
4
4
|
from logging import getLogger
|
|
5
|
-
from typing import Any, Literal, TypeVar, Union, cast, get_args
|
|
5
|
+
from typing import TYPE_CHECKING, Any, Literal, TypeVar, Union, cast, get_args
|
|
6
6
|
|
|
7
|
-
from fastapi._compat import (
|
|
8
|
-
GenerateJsonSchema,
|
|
9
|
-
ModelField,
|
|
10
|
-
get_compat_model_name_map,
|
|
11
|
-
get_definitions,
|
|
12
|
-
)
|
|
13
7
|
from fastapi.openapi.constants import REF_TEMPLATE
|
|
14
8
|
from fastapi.openapi.utils import (
|
|
15
9
|
get_fields_from_routes,
|
|
@@ -41,6 +35,9 @@ from .structure.schemas import (
|
|
|
41
35
|
ValidatorExistedInstruction,
|
|
42
36
|
)
|
|
43
37
|
|
|
38
|
+
if TYPE_CHECKING:
|
|
39
|
+
from fastapi._compat import ModelField
|
|
40
|
+
|
|
44
41
|
if sys.version_info >= (3, 11): # pragma: no cover
|
|
45
42
|
from enum import StrEnum
|
|
46
43
|
else: # pragma: no cover
|
|
@@ -120,7 +117,7 @@ def _get_affected_model_names(
|
|
|
120
117
|
FieldDidntHaveInstruction,
|
|
121
118
|
],
|
|
122
119
|
generator_from_newer_version: SchemaGenerator,
|
|
123
|
-
schemas_from_last_version: list[ModelField],
|
|
120
|
+
schemas_from_last_version: "list[ModelField]",
|
|
124
121
|
):
|
|
125
122
|
changed_model = generator_from_newer_version._get_wrapper_for_model(instruction.schema)
|
|
126
123
|
annotations = [model.field_info.annotation for model in schemas_from_last_version]
|
|
@@ -156,6 +153,13 @@ def _get_all_pydantic_models_from_generic(annotation: Any) -> list[type[BaseMode
|
|
|
156
153
|
|
|
157
154
|
|
|
158
155
|
def _get_openapi_representation_of_a_field(model: type[BaseModel], field_name: str) -> dict:
|
|
156
|
+
from fastapi._compat import (
|
|
157
|
+
GenerateJsonSchema,
|
|
158
|
+
ModelField,
|
|
159
|
+
get_compat_model_name_map,
|
|
160
|
+
get_definitions,
|
|
161
|
+
)
|
|
162
|
+
|
|
159
163
|
class CadwynDummyModelForRepresentation(BaseModel):
|
|
160
164
|
my_field: model
|
|
161
165
|
|
|
@@ -315,7 +319,7 @@ def _convert_version_change_instruction_to_changelog_entry( # noqa: C901
|
|
|
315
319
|
version_change: type[VersionChange],
|
|
316
320
|
generator_from_newer_version: SchemaGenerator,
|
|
317
321
|
generator_from_older_version: SchemaGenerator,
|
|
318
|
-
schemas_from_older_version: list[ModelField],
|
|
322
|
+
schemas_from_older_version: "list[ModelField]",
|
|
319
323
|
routes_from_newer_version: list[APIRoute],
|
|
320
324
|
):
|
|
321
325
|
if isinstance(instruction, EndpointDidntExistInstruction):
|
cadwyn/schema_generation.py
CHANGED
|
@@ -14,6 +14,7 @@ from functools import cache
|
|
|
14
14
|
from typing import (
|
|
15
15
|
TYPE_CHECKING,
|
|
16
16
|
Annotated,
|
|
17
|
+
ClassVar,
|
|
17
18
|
Generic,
|
|
18
19
|
Union,
|
|
19
20
|
_BaseGenericAlias, # pyright: ignore[reportAttributeAccessIssue]
|
|
@@ -41,6 +42,7 @@ from pydantic._internal._decorators import (
|
|
|
41
42
|
from pydantic._internal._known_annotated_metadata import collect_known_metadata
|
|
42
43
|
from pydantic._internal._typing_extra import try_eval_type as pydantic_try_eval_type
|
|
43
44
|
from pydantic.fields import ComputedFieldInfo, FieldInfo
|
|
45
|
+
from pydantic_core import PydanticUndefined
|
|
44
46
|
from typing_extensions import (
|
|
45
47
|
Any,
|
|
46
48
|
Doc,
|
|
@@ -316,7 +318,7 @@ def _wrap_pydantic_model(model: type[_T_PYDANTIC_MODEL]) -> "_PydanticModelWrapp
|
|
|
316
318
|
field_name,
|
|
317
319
|
)
|
|
318
320
|
for field_name in model.__annotations__
|
|
319
|
-
if field_name in defined_fields
|
|
321
|
+
if field_name in defined_fields and field_name in model.model_fields
|
|
320
322
|
}
|
|
321
323
|
|
|
322
324
|
main_attributes = fields | validators
|
|
@@ -539,7 +541,7 @@ class _AsyncGeneratorCallableWrapper(_CallableWrapper):
|
|
|
539
541
|
class _AnnotationTransformer:
|
|
540
542
|
def __init__(self, generator: "SchemaGenerator") -> None:
|
|
541
543
|
# This cache is not here for speeding things up. It's for preventing the creation of copies of the same object
|
|
542
|
-
# because such copies could produce weird behaviors at runtime, especially if you/
|
|
544
|
+
# because such copies could produce weird behaviors at runtime, especially if you/FastAPI do any comparisons.
|
|
543
545
|
# It's defined here and not on the method because of this: https://youtu.be/sVjtp6tGo0g
|
|
544
546
|
self.generator = generator
|
|
545
547
|
# TODO: Rewrite this to memoize
|
|
@@ -592,7 +594,12 @@ class _AnnotationTransformer:
|
|
|
592
594
|
from typing_inspection.typing_objects import is_any, is_newtype, is_typealiastype
|
|
593
595
|
|
|
594
596
|
if isinstance(annotation, (types.GenericAlias, _BaseGenericAlias)):
|
|
595
|
-
|
|
597
|
+
origin = get_origin(annotation)
|
|
598
|
+
args = get_args(annotation)
|
|
599
|
+
# Classvar does not support generic tuple arguments
|
|
600
|
+
if origin is ClassVar:
|
|
601
|
+
return ClassVar[self.change_version_of_annotation(args[0])]
|
|
602
|
+
return origin[tuple(self.change_version_of_annotation(arg) for arg in get_args(annotation))]
|
|
596
603
|
elif is_typealiastype(annotation):
|
|
597
604
|
if (
|
|
598
605
|
annotation.__module__ is not None and (annotation.__module__.startswith("pydantic."))
|
|
@@ -948,11 +955,20 @@ def _add_field_to_model(
|
|
|
948
955
|
f'in "{version_change_name}" but there is already a field with that name.',
|
|
949
956
|
)
|
|
950
957
|
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
958
|
+
# Special handling for ClassVar fields
|
|
959
|
+
if get_origin(alter_schema_instruction.field.annotation) is ClassVar:
|
|
960
|
+
# ClassVar fields should not be in model.fields, only in annotations and other_attributes
|
|
961
|
+
model.annotations[alter_schema_instruction.name] = alter_schema_instruction.field.annotation
|
|
962
|
+
# Set the actual ClassVar value in other_attributes
|
|
963
|
+
if alter_schema_instruction.field.default is not PydanticUndefined:
|
|
964
|
+
model.other_attributes[alter_schema_instruction.name] = alter_schema_instruction.field.default
|
|
965
|
+
else:
|
|
966
|
+
# Regular field handling
|
|
967
|
+
field = PydanticFieldWrapper(
|
|
968
|
+
alter_schema_instruction.field, alter_schema_instruction.field.annotation, alter_schema_instruction.name
|
|
969
|
+
)
|
|
970
|
+
model.fields[alter_schema_instruction.name] = field
|
|
971
|
+
model.annotations[alter_schema_instruction.name] = alter_schema_instruction.field.annotation
|
|
956
972
|
|
|
957
973
|
|
|
958
974
|
def _change_field_in_model(
|
|
@@ -1085,6 +1101,11 @@ def _delete_field_from_model(model: _PydanticModelWrapper, field_name: str, vers
|
|
|
1085
1101
|
validator = model.validators[field_name]
|
|
1086
1102
|
model.validators[field_name].is_deleted = True
|
|
1087
1103
|
model.annotations.pop(field_name, None)
|
|
1104
|
+
elif field_name in model.annotations and get_origin(model.annotations[field_name]) is ClassVar:
|
|
1105
|
+
# Handle ClassVar fields - they exist in annotations but not in model.fields
|
|
1106
|
+
model.annotations.pop(field_name)
|
|
1107
|
+
# Also remove the attribute from other_attributes if it exists there
|
|
1108
|
+
model.other_attributes.pop(field_name, None)
|
|
1088
1109
|
else:
|
|
1089
1110
|
raise InvalidGenerationInstructionError(
|
|
1090
1111
|
f'You tried to delete a field "{field_name}" from "{model.name}" '
|
cadwyn/structure/endpoints.py
CHANGED
|
@@ -18,7 +18,7 @@ HTTP_METHODS = {"GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS", "HEAD"}
|
|
|
18
18
|
|
|
19
19
|
@dataclass(**DATACLASS_SLOTS)
|
|
20
20
|
class EndpointAttributesPayload:
|
|
21
|
-
#
|
|
21
|
+
# FastAPI API routes also have "endpoint" and "dependency_overrides_provider" fields.
|
|
22
22
|
# We do not use them because:
|
|
23
23
|
# 1. "endpoint" must not change -- otherwise this versioning is doomed
|
|
24
24
|
# 2. "dependency_overrides_provider" is taken from router's attributes
|
cadwyn/structure/versions.py
CHANGED
|
@@ -694,7 +694,7 @@ class VersionBundle:
|
|
|
694
694
|
# We use this instead of `.body()` to automatically guess body type and load the correct body, even if it's a form
|
|
695
695
|
async def _get_body(
|
|
696
696
|
request: FastapiRequest, body_field: Union[ModelField, None], exit_stack: AsyncExitStack
|
|
697
|
-
): # pragma: no cover # This is from
|
|
697
|
+
): # pragma: no cover # This is from FastAPI
|
|
698
698
|
is_body_form = body_field and isinstance(body_field.field_info, params.Form)
|
|
699
699
|
try:
|
|
700
700
|
body: Any = None
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cadwyn
|
|
3
|
-
Version: 5.4.
|
|
3
|
+
Version: 5.4.5
|
|
4
4
|
Summary: Production-ready community-driven modern Stripe-like API versioning in FastAPI
|
|
5
5
|
Project-URL: Source code, https://github.com/zmievsa/cadwyn
|
|
6
6
|
Project-URL: Documentation, https://docs.cadwyn.dev
|
|
@@ -88,26 +88,3 @@ The [documentation](https://docs.cadwyn.dev) has everything you need to succeed.
|
|
|
88
88
|
## Sponsors
|
|
89
89
|
|
|
90
90
|
These are our gorgeous sponsors. They are using Cadwyn and are sponsoring it through various means. Contact [me](https://github.com/zmievsa) if you would like to become one, too!
|
|
91
|
-
|
|
92
|
-
## Contributors
|
|
93
|
-
|
|
94
|
-
<details>
|
|
95
|
-
|
|
96
|
-
<summary>Thanks goes to these wonderful people:</summary>
|
|
97
|
-
<a href="https://allcontributors.org/docs/en/emoji-key">Emoji Key </a>
|
|
98
|
-
|
|
99
|
-
<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
|
|
100
|
-
<!-- prettier-ignore-start -->
|
|
101
|
-
<!-- markdownlint-disable -->
|
|
102
|
-
|
|
103
|
-
<!-- markdownlint-restore -->
|
|
104
|
-
<!-- prettier-ignore-end -->
|
|
105
|
-
|
|
106
|
-
<!-- ALL-CONTRIBUTORS-LIST:END -->
|
|
107
|
-
|
|
108
|
-
This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification.
|
|
109
|
-
Contributions are welcome!
|
|
110
|
-
|
|
111
|
-
</details>
|
|
112
|
-
|
|
113
|
-
<!-- contributors-end -->
|
|
@@ -5,14 +5,14 @@ cadwyn/_importer.py,sha256=QV6HqODCG9K2oL4Vc15fAqL2-plMvUWw_cgaj4Ln4C8,1075
|
|
|
5
5
|
cadwyn/_render.py,sha256=VAY2Twd_MfKaC8_X22AMIQd72_UHy87icdAbKL8hd90,5526
|
|
6
6
|
cadwyn/_utils.py,sha256=q_mTtMKTNTDzqCza67XST-jaPSfuTgnFLmOe0dlGeYY,2295
|
|
7
7
|
cadwyn/applications.py,sha256=FALDl4v_8dJWdrpHEuvG34C_vfnKKh01rAOiyg5wVak,21200
|
|
8
|
-
cadwyn/changelogs.py,sha256=
|
|
8
|
+
cadwyn/changelogs.py,sha256=gJnK2Rtl2svVZYQ_J2F6kkfzdmXNgsKmI3MzuXS9dKQ,19738
|
|
9
9
|
cadwyn/dependencies.py,sha256=phUJ4Fy3UTegpOfDfHMjxsvASWo-1NQgwqphNnPdoVQ,241
|
|
10
10
|
cadwyn/exceptions.py,sha256=8D1G7ewLrMF5jq7leald1g0ulcH9zQl8ufEK3b7HHAE,1749
|
|
11
11
|
cadwyn/middleware.py,sha256=4Ziq1ysnc8j5KmeZpsr9VJKllEFC8uYwXnG01I2FPR4,4853
|
|
12
12
|
cadwyn/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
13
13
|
cadwyn/route_generation.py,sha256=conoTBtsOtjyiV2NdUxwGQX-h1zLyIjDQjD5bT2YSgg,27185
|
|
14
14
|
cadwyn/routing.py,sha256=Ii6Qbgm9lGks1IAk-kDuIu_dX3FXsA77KSfGOFmLbgc,7604
|
|
15
|
-
cadwyn/schema_generation.py,sha256=
|
|
15
|
+
cadwyn/schema_generation.py,sha256=Q0Ma_2XA5plPcZ7sxNK1jZxubGDNcc-XMka3TkvFgEI,48848
|
|
16
16
|
cadwyn/_internal/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
17
17
|
cadwyn/_internal/context_vars.py,sha256=VcM8eAoSlvrIMFQhjZmjflV5o1yrPSEZZGkwOK4OSf4,378
|
|
18
18
|
cadwyn/static/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -20,12 +20,12 @@ cadwyn/static/docs.html,sha256=WNm5ANJVy51TcIUFOaqKf1Z8eF86CC85TTHPxACtkzw,3455
|
|
|
20
20
|
cadwyn/structure/__init__.py,sha256=Wgvjdq3vfl9Yhe-BkcFGAMi_Co11YOfTmJQqgF5Gzx4,655
|
|
21
21
|
cadwyn/structure/common.py,sha256=YuyfYMxkJcj2c5SFh9teBoEC2xLO5_2QjPzYjwdZcTs,478
|
|
22
22
|
cadwyn/structure/data.py,sha256=eb4HlGTu3V_G5vJuQ4GLEaGd4LmPmFX3L8CXwJKzfOE,7795
|
|
23
|
-
cadwyn/structure/endpoints.py,sha256=
|
|
23
|
+
cadwyn/structure/endpoints.py,sha256=OYNaZ76VidtSutQfteFMba5nNIXtEjwCAvgpy3fRBT4,6246
|
|
24
24
|
cadwyn/structure/enums.py,sha256=4FCc9aniLE3VuWAVIacrNP_FWxTIUm9JkeeHA_zZdwQ,1254
|
|
25
25
|
cadwyn/structure/schemas.py,sha256=kuQJg60VpWHZkSPvrbvd9pe-Zetq8as5YYrERsG3IE8,10785
|
|
26
|
-
cadwyn/structure/versions.py,sha256=
|
|
27
|
-
cadwyn-5.4.
|
|
28
|
-
cadwyn-5.4.
|
|
29
|
-
cadwyn-5.4.
|
|
30
|
-
cadwyn-5.4.
|
|
31
|
-
cadwyn-5.4.
|
|
26
|
+
cadwyn/structure/versions.py,sha256=3ZDKewBHHWmAwhOQbIR5p17ANzqglMDTvYUGKTAqXyk,34710
|
|
27
|
+
cadwyn-5.4.5.dist-info/METADATA,sha256=mgh_IMJ36E6I5rV8cyGSUR3e2QrEbYyUskWpimCbFLo,4504
|
|
28
|
+
cadwyn-5.4.5.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
29
|
+
cadwyn-5.4.5.dist-info/entry_points.txt,sha256=mGX8wl-Xfhpr5M93SUmkykaqinUaYAvW9rtDSX54gx0,47
|
|
30
|
+
cadwyn-5.4.5.dist-info/licenses/LICENSE,sha256=KeCWewiDQYpmSnzF-p_0YpoWiyDcUPaCuG8OWQs4ig4,1072
|
|
31
|
+
cadwyn-5.4.5.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|