cadwyn 5.4.1__tar.gz → 5.4.2__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-5.4.1 → cadwyn-5.4.2}/CHANGELOG.md +6 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/PKG-INFO +1 -1
- {cadwyn-5.4.1 → cadwyn-5.4.2}/cadwyn/schema_generation.py +25 -9
- {cadwyn-5.4.1 → cadwyn-5.4.2}/docs/home/CONTRIBUTING.md +1 -1
- {cadwyn-5.4.1 → cadwyn-5.4.2}/docs/index.md +4 -4
- cadwyn-5.4.2/docs/theory/how_to_build_versioning_framework.md +24 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/docs/theory/literature.md +1 -1
- {cadwyn-5.4.1 → cadwyn-5.4.2}/pyproject.toml +1 -1
- {cadwyn-5.4.1 → cadwyn-5.4.2}/tests/test_schema_generation/test_schema_field.py +46 -1
- {cadwyn-5.4.1 → cadwyn-5.4.2}/uv.lock +1 -1
- cadwyn-5.4.1/docs/theory/how_to_build_versioning_framework.md +0 -23
- {cadwyn-5.4.1 → cadwyn-5.4.2}/.github/CODE_OF_CONDUCT.md +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/.github/actions/setup-python-uv/action.yaml +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/.github/workflows/ci.yaml +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/.github/workflows/daily_tests.yaml +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/.github/workflows/publish_docs.yaml +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/.github/workflows/release.yaml +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/.gitignore +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/.pre-commit-config.yaml +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/LICENSE +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/Makefile +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/README.md +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/cadwyn/__init__.py +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/cadwyn/__main__.py +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/cadwyn/_asts.py +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/cadwyn/_importer.py +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/cadwyn/_internal/__init__.py +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/cadwyn/_internal/context_vars.py +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/cadwyn/_render.py +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/cadwyn/_utils.py +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/cadwyn/applications.py +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/cadwyn/changelogs.py +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/cadwyn/dependencies.py +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/cadwyn/exceptions.py +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/cadwyn/middleware.py +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/cadwyn/py.typed +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/cadwyn/route_generation.py +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/cadwyn/routing.py +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/cadwyn/static/__init__.py +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/cadwyn/static/docs.html +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/cadwyn/structure/__init__.py +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/cadwyn/structure/common.py +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/cadwyn/structure/data.py +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/cadwyn/structure/endpoints.py +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/cadwyn/structure/enums.py +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/cadwyn/structure/schemas.py +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/cadwyn/structure/versions.py +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/docs/CNAME +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/docs/__init__.py +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/docs/concepts/api_version_parameter.md +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/docs/concepts/beware_of_data_versioning.md +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/docs/concepts/changelogs.md +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/docs/concepts/cli.md +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/docs/concepts/endpoint_migrations.md +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/docs/concepts/enum_migrations.md +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/docs/concepts/index.md +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/docs/concepts/main_app.md +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/docs/concepts/methodology.md +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/docs/concepts/schema_generation.md +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/docs/concepts/schema_migrations.md +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/docs/concepts/testing.md +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/docs/concepts/version_changes.md +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/docs/how_to/change_business_logic/index.md +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/docs/how_to/change_endpoints/index.md +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/docs/how_to/change_openapi_schemas/add_field.md +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/docs/how_to/change_openapi_schemas/change_field_type.md +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/docs/how_to/change_openapi_schemas/change_schema_without_endpoint.md +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/docs/how_to/change_openapi_schemas/changing_constraints.md +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/docs/how_to/change_openapi_schemas/remove_field.md +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/docs/how_to/change_openapi_schemas/rename_a_field_in_schema.md +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/docs/how_to/index.md +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/docs/how_to/version_with_paths_and_numbers_instead_of_headers_and_dates.md +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/docs/img/dashboard_with_one_version.png +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/docs/img/dashboard_with_two_versions.png +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/docs/img/get_users_endpoint_from_prior_version.png +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/docs/img/logos/cadwyn_icon_transparent.svg +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/docs/img/logos/cadwyn_transparent.svg +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/docs/img/logos/cadwyn_with_background.svg +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/docs/img/simplified_migration_model.png +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/docs/img/unversioned_dashboard.png +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/docs/plugin.py +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/docs/quickstart/setup.md +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/docs/quickstart/tutorial.md +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/docs/stylesheets/extra.css +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/docs/theory/how_we_got_here.md +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/docs_src/__init__.py +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/docs_src/how_to/__init__.py +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/docs_src/how_to/change_openapi_schemas/__init__.py +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/docs_src/how_to/change_openapi_schemas/change_schema_without_endpoint/__init__.py +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/docs_src/how_to/change_openapi_schemas/change_schema_without_endpoint/block001.py +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/docs_src/how_to/change_openapi_schemas/change_schema_without_endpoint/block002.py +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/docs_src/how_to/change_openapi_schemas/change_schema_without_endpoint/tests/__init__.py +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/docs_src/how_to/change_openapi_schemas/change_schema_without_endpoint/tests/test_block001.py +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/docs_src/how_to/change_openapi_schemas/change_schema_without_endpoint/tests/test_block002.py +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/docs_src/how_to/version_with_path_and_numbers_instead_of_headers_and_dates/__init__.py +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/docs_src/how_to/version_with_path_and_numbers_instead_of_headers_and_dates/block001.py +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/docs_src/how_to/version_with_path_and_numbers_instead_of_headers_and_dates/tests/__init__.py +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/docs_src/how_to/version_with_path_and_numbers_instead_of_headers_and_dates/tests/test_block_001.py +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/docs_src/quickstart/__init__.py +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/docs_src/quickstart/setup/__init__.py +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/docs_src/quickstart/setup/block001.sh +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/docs_src/quickstart/setup/block002.py +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/docs_src/quickstart/setup/tests/__init__.py +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/docs_src/quickstart/setup/tests/test_block002.py +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/docs_src/quickstart/tutorial/__init__.py +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/docs_src/quickstart/tutorial/block001.py +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/docs_src/quickstart/tutorial/block002.py +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/docs_src/quickstart/tutorial/block003.py +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/docs_src/quickstart/tutorial/tests/__init__.py +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/docs_src/quickstart/tutorial/tests/test_block001.py +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/docs_src/quickstart/tutorial/tests/test_block002.py +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/docs_src/quickstart/tutorial/tests/test_block003.py +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/docs_src/ruff.toml +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/mkdocs.yml +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/ruff.toml +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/scripts/fix_links.py +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/scripts/split_md.py +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/tests/__init__.py +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/tests/_data/__init__.py +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/tests/_data/unversioned_schema_dir/__init__.py +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/tests/_data/unversioned_schema_dir/unversioned_schemas.py +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/tests/_data/unversioned_schemas.py +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/tests/_resources/__init__.py +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/tests/_resources/app_for_testing_routing.py +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/tests/_resources/render/__init__.py +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/tests/_resources/render/classes.py +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/tests/_resources/render/complex/__init__.py +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/tests/_resources/render/complex/classes.py +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/tests/_resources/render/complex/versions.py +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/tests/_resources/render/versions.py +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/tests/_resources/utils.py +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/tests/_resources/versioned_app/__init__.py +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/tests/_resources/versioned_app/app.py +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/tests/_resources/versioned_app/v2021_01_01.py +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/tests/_resources/versioned_app/v2022_01_02.py +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/tests/_resources/versioned_app/webhooks.py +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/tests/conftest.py +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/tests/test_applications.py +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/tests/test_auth_dependencies.py +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/tests/test_changelog.py +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/tests/test_cli.py +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/tests/test_data_migrations.py +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/tests/test_render.py +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/tests/test_router_generation.py +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/tests/test_router_generation_with_from_future_annotations.py +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/tests/test_routing.py +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/tests/test_schema_generation/__init__.py +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/tests/test_schema_generation/test_enum.py +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/tests/test_schema_generation/test_schema.py +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/tests/test_schema_generation/test_schema_validator.py +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/tests/test_schema_generation/test_schema_with_future_annotations.py +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/tests/test_structure.py +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/tests/tutorial/__init__.py +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/tests/tutorial/main.py +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/tests/tutorial/test_example.py +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/tests/versioning_styles/__init__.py +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/tests/versioning_styles/test_versioning_formats.py +0 -0
- {cadwyn-5.4.1 → cadwyn-5.4.2}/tox.ini +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cadwyn
|
|
3
|
-
Version: 5.4.
|
|
3
|
+
Version: 5.4.2
|
|
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
|
|
@@ -236,6 +236,11 @@ def _wrap_validator(func: Callable, is_pydantic_v1_style_validator: Any, decorat
|
|
|
236
236
|
func = func.__func__
|
|
237
237
|
kwargs = dataclasses.asdict(decorator_info)
|
|
238
238
|
decorator_fields = kwargs.pop("fields", None)
|
|
239
|
+
|
|
240
|
+
# wrapped_property is not accepted by computed_field()
|
|
241
|
+
if isinstance(decorator_info, ComputedFieldInfo):
|
|
242
|
+
kwargs.pop("wrapped_property", None)
|
|
243
|
+
|
|
239
244
|
actual_decorator = PYDANTIC_DECORATOR_TYPE_TO_DECORATOR_MAP[type(decorator_info)]
|
|
240
245
|
if is_pydantic_v1_style_validator:
|
|
241
246
|
# There's an inconsistency in their interfaces so we gotta resort to this
|
|
@@ -1061,19 +1066,30 @@ def _delete_field_attributes(
|
|
|
1061
1066
|
|
|
1062
1067
|
|
|
1063
1068
|
def _delete_field_from_model(model: _PydanticModelWrapper, field_name: str, version_change_name: str):
|
|
1064
|
-
if field_name
|
|
1069
|
+
if field_name in model.fields:
|
|
1070
|
+
model.fields.pop(field_name)
|
|
1071
|
+
model.annotations.pop(field_name)
|
|
1072
|
+
for validator_name, validator in model.validators.copy().items():
|
|
1073
|
+
if isinstance(validator, _PerFieldValidatorWrapper) and field_name in validator.fields:
|
|
1074
|
+
validator.fields.remove(field_name)
|
|
1075
|
+
# TODO: This behavior doesn't feel natural
|
|
1076
|
+
if not validator.fields:
|
|
1077
|
+
model.validators[validator_name].is_deleted = True
|
|
1078
|
+
|
|
1079
|
+
elif (
|
|
1080
|
+
field_name in model.validators
|
|
1081
|
+
and isinstance(model.validators[field_name], _ValidatorWrapper)
|
|
1082
|
+
and hasattr(model.validators[field_name], "decorator")
|
|
1083
|
+
and model.validators[field_name].decorator == pydantic.computed_field
|
|
1084
|
+
):
|
|
1085
|
+
validator = model.validators[field_name]
|
|
1086
|
+
model.validators[field_name].is_deleted = True
|
|
1087
|
+
model.annotations.pop(field_name, None)
|
|
1088
|
+
else:
|
|
1065
1089
|
raise InvalidGenerationInstructionError(
|
|
1066
1090
|
f'You tried to delete a field "{field_name}" from "{model.name}" '
|
|
1067
1091
|
f'in "{version_change_name}" but it doesn\'t have such a field.',
|
|
1068
1092
|
)
|
|
1069
|
-
model.fields.pop(field_name)
|
|
1070
|
-
model.annotations.pop(field_name)
|
|
1071
|
-
for validator_name, validator in model.validators.copy().items():
|
|
1072
|
-
if isinstance(validator, _PerFieldValidatorWrapper) and field_name in validator.fields:
|
|
1073
|
-
validator.fields.remove(field_name)
|
|
1074
|
-
# TODO: This behavior doesn't feel natural
|
|
1075
|
-
if not validator.fields:
|
|
1076
|
-
model.validators[validator_name].is_deleted = True
|
|
1077
1093
|
|
|
1078
1094
|
|
|
1079
1095
|
class _DummyEnum(Enum):
|
|
@@ -66,7 +66,7 @@ Then you can serve the documentation with `mkdocs serve`
|
|
|
66
66
|
|
|
67
67
|
We welcome contributions that enhance / improve the content of the docs. Feel free to add examples, clarify text, restructure the docs, etc., but make sure to follow these guidelines:
|
|
68
68
|
|
|
69
|
-
* Write text in idiomatic
|
|
69
|
+
* Write text in idiomatic English, using simple language
|
|
70
70
|
* Opt for [Oxford commas](https://en.wikipedia.org/wiki/Serial_comma) when listing a series of terms
|
|
71
71
|
* Keep examples simple and self contained
|
|
72
72
|
* Provide links where applicable
|
|
@@ -12,7 +12,7 @@ Production-ready community-driven modern [Stripe-like](https://stripe.com/blog/a
|
|
|
12
12
|
<img src="https://img.shields.io/codecov/c/github/zmievsa/cadwyn?color=%2334D058&logo=codecov" alt="Coverage">
|
|
13
13
|
</a>
|
|
14
14
|
<a href="https://pypi.org/project/cadwyn/" target="_blank">
|
|
15
|
-
<img alt="PyPI" src="https://img.shields.io/pypi/v/cadwyn?color=%2334D058&logo=pypi&label=PyPI
|
|
15
|
+
<img alt="PyPI" src="https://img.shields.io/pypi/v/cadwyn?color=%2334D058&logo=pypi&label=PyPI" alt="Package version">
|
|
16
16
|
</a>
|
|
17
17
|
<a href="https://pypi.org/project/cadwyn/" target="_blank">
|
|
18
18
|
<img src="https://img.shields.io/pypi/pyversions/cadwyn?color=%2334D058&logo=python" alt="Supported Python versions">
|
|
@@ -24,12 +24,12 @@ Production-ready community-driven modern [Stripe-like](https://stripe.com/blog/a
|
|
|
24
24
|
|
|
25
25
|
## Who is this for?
|
|
26
26
|
|
|
27
|
-
Cadwyn allows you to
|
|
27
|
+
Cadwyn allows you to maintain the implementation just for your newest API version and get all the older versions generated automatically. You keep API backward compatibility encapsulated in small and independent "version change" modules while your business logic stays simple and knows nothing about versioning.
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
This [approach](https://docs.cadwyn.dev/theory/how_we_got_here/#ii-migration-based-response-building) may be useful if you want to:
|
|
30
30
|
|
|
31
31
|
1. Support many API versions for a long time
|
|
32
|
-
2.
|
|
32
|
+
2. Have features and bugfixes automatically backported to older API versions
|
|
33
33
|
|
|
34
34
|
Whether you are a newbie in API versioning, a pro looking for a sophisticated tool, an experimenter looking to build a similar framework, or even someone who just wants to learn about all approaches to API versioning -- Cadwyn has the functionality, theory, and documentation to cover all the mentioned use cases.
|
|
35
35
|
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# How to build a versioning framework
|
|
2
|
+
|
|
3
|
+
## Questions to ask yourself when rating your framework
|
|
4
|
+
|
|
5
|
+
### How easy is it to create a version?
|
|
6
|
+
|
|
7
|
+
If it is too easy, it is probably a trap. The framework is probably hiding too much complexity from you and will shoot you in the back later. For example, early on we tried a simple "copy the entire business logic into a separate directory" approach which made it so simple to add new versions. We added too many of them in the end, thus it got hellishly hard to maintain or get rid of these versions.
|
|
8
|
+
|
|
9
|
+
### How easy is it to delete an old version?
|
|
10
|
+
|
|
11
|
+
Your framework must be able to let you clean up versions as simply as possible and cheaply whenever you need to. For example, if your framework tries to minimize the amount of code duplication in your repository by having new routes include old routes within them and new business logic inherit from classes from old business logic, then deleting an old version is going to be painful; oftentimes even dangerous as versions can quickly start interacting with each other in all sorts of ways, turning a single small application into a set of interconnected applications.
|
|
12
|
+
|
|
13
|
+
### How easy is it to see the differences between versions?
|
|
14
|
+
|
|
15
|
+
The easier it is, the better off our users are.
|
|
16
|
+
|
|
17
|
+
### What exactly do you need to duplicate to create a new version?
|
|
18
|
+
|
|
19
|
+
The less we duplicate and maintain by hand, the easier it is to support. However, the less we duplicate, the more chance there is to break the old versions with new releases.
|
|
20
|
+
|
|
21
|
+
### How easy is it to notice accidental data versioning?
|
|
22
|
+
|
|
23
|
+
Data versioning is an incredibly big issue when versioning your API.
|
|
24
|
+
So if your framework makes it hard to version data -- it's really good!
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Literature
|
|
2
2
|
|
|
3
|
-
During Cadwyn's development, I went through countless resources on API Versioning. The following are the most unique and effective ones I
|
|
3
|
+
During Cadwyn's development, I went through countless resources on API Versioning. The following are the most unique and effective ones I managed to find.
|
|
4
4
|
|
|
5
5
|
## Cadwyn-like API Versioning
|
|
6
6
|
|
|
@@ -3,7 +3,7 @@ from enum import Enum, auto
|
|
|
3
3
|
from typing import Annotated, Any, Literal, Union
|
|
4
4
|
|
|
5
5
|
import pytest
|
|
6
|
-
from pydantic import BaseModel, Field, StringConstraints, ValidationError, conint, constr
|
|
6
|
+
from pydantic import BaseModel, Field, StringConstraints, ValidationError, computed_field, conint, constr
|
|
7
7
|
from pydantic.fields import FieldInfo
|
|
8
8
|
|
|
9
9
|
from cadwyn.exceptions import (
|
|
@@ -762,3 +762,48 @@ def test__schema_field_had__nonexistent_field__should_raise_error(create_runtime
|
|
|
762
762
|
),
|
|
763
763
|
):
|
|
764
764
|
create_runtime_schemas(version_change(schema(SchemaWithOneStrField).field("boo").had(type=int)))
|
|
765
|
+
|
|
766
|
+
|
|
767
|
+
def test__schema_with_computed_field__should_be_recreated_in_older_version(
|
|
768
|
+
create_runtime_schemas: CreateRuntimeSchemas,
|
|
769
|
+
):
|
|
770
|
+
class SchemaWithComputedField(BaseModel):
|
|
771
|
+
image_file_key: str = Field(exclude=True)
|
|
772
|
+
|
|
773
|
+
@computed_field
|
|
774
|
+
@property
|
|
775
|
+
def image_url(self) -> str:
|
|
776
|
+
return f"https://example.com/{self.image_file_key}"
|
|
777
|
+
|
|
778
|
+
schemas = create_runtime_schemas(version_change())
|
|
779
|
+
|
|
780
|
+
latest_model = schemas["2001-01-01"][SchemaWithComputedField]
|
|
781
|
+
old_model = schemas["2000-01-01"][SchemaWithComputedField]
|
|
782
|
+
|
|
783
|
+
latest_instance = latest_model(image_file_key="test.jpg")
|
|
784
|
+
old_instance = old_model(image_file_key="test.jpg")
|
|
785
|
+
|
|
786
|
+
assert latest_instance.image_url == "https://example.com/test.jpg"
|
|
787
|
+
assert old_instance.image_url == "https://example.com/test.jpg"
|
|
788
|
+
|
|
789
|
+
|
|
790
|
+
def test__schema_with_computed_field__remove_computed_field(create_runtime_schemas: CreateRuntimeSchemas):
|
|
791
|
+
class SchemaWithComputedField(BaseModel):
|
|
792
|
+
image_file_key: str = Field(exclude=True)
|
|
793
|
+
|
|
794
|
+
@computed_field
|
|
795
|
+
@property
|
|
796
|
+
def image_url(self) -> str:
|
|
797
|
+
return f"https://example.com/{self.image_file_key}"
|
|
798
|
+
|
|
799
|
+
schemas = create_runtime_schemas(version_change(schema(SchemaWithComputedField).field("image_url").didnt_exist))
|
|
800
|
+
|
|
801
|
+
latest_model = schemas["2001-01-01"][SchemaWithComputedField]
|
|
802
|
+
latest_instance = latest_model(image_file_key="test.jpg")
|
|
803
|
+
assert latest_instance.image_url == "https://example.com/test.jpg"
|
|
804
|
+
|
|
805
|
+
old_model = schemas["2000-01-01"][SchemaWithComputedField]
|
|
806
|
+
old_instance = old_model(image_file_key="test.jpg")
|
|
807
|
+
|
|
808
|
+
assert not hasattr(old_instance, "image_url")
|
|
809
|
+
assert "image_url" not in old_instance.model_dump()
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
# How to build a versioning framework
|
|
2
|
-
|
|
3
|
-
## Questions to ask yourself when rating your framework
|
|
4
|
-
|
|
5
|
-
### How easy it is to create a version?
|
|
6
|
-
|
|
7
|
-
If it is too easy: it is probably a trap. The framework is probably hiding too much complexity from you and will shoot you in the back later. For example, early on we have tried a simple "copy entire business logic into a separate directory" approach which made it so simple to add new versions that we added too many of them -- at the end, maintaining and getting rid of these versions has gotten hellishly hard.
|
|
8
|
-
|
|
9
|
-
### How easy is it to delete an old version?
|
|
10
|
-
|
|
11
|
-
Your framework must make it as simple as possible to make sure that you can clean up versions cheaply whenever you need to. For example, if your framework tries to minimize the amount of code duplication in your repository by having new routes include old routes within them and new business logic inherit from classes from old business logic, then deleting an old version is going to be painful; oftentimes even dangerous as versions can quickly start interacting with each other in all sorts of ways, turning a single small application into a set of interconnected applications.
|
|
12
|
-
|
|
13
|
-
### How easy is it to see the differences between versions?
|
|
14
|
-
|
|
15
|
-
The easier it is -- the better off our users are.
|
|
16
|
-
|
|
17
|
-
### What exactly do you need to duplicate to create a new version?
|
|
18
|
-
|
|
19
|
-
The less we duplicate and maintain by hand -- the easier it is to support. However, the less we duplicate -- the more chance there is to break the old versions with new releases.
|
|
20
|
-
|
|
21
|
-
### How easy is it to notice accidental data versioning?
|
|
22
|
-
|
|
23
|
-
Data versioning is an incredibly big problem when versioning your API so if your framework makes it hard to version data -- it's really good!
|
|
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
|
|
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
|
|
File without changes
|
{cadwyn-5.4.1 → cadwyn-5.4.2}/docs/how_to/change_openapi_schemas/change_schema_without_endpoint.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{cadwyn-5.4.1 → cadwyn-5.4.2}/docs/how_to/change_openapi_schemas/rename_a_field_in_schema.md
RENAMED
|
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
|
|
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
|
|
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
|
{cadwyn-5.4.1 → cadwyn-5.4.2}/tests/test_schema_generation/test_schema_with_future_annotations.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|