cadwyn 5.4.3__tar.gz → 5.4.5__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 (163) hide show
  1. {cadwyn-5.4.3 → cadwyn-5.4.5}/CHANGELOG.md +14 -8
  2. {cadwyn-5.4.3 → cadwyn-5.4.5}/PKG-INFO +1 -24
  3. {cadwyn-5.4.3 → cadwyn-5.4.5}/README.md +0 -23
  4. {cadwyn-5.4.3 → cadwyn-5.4.5}/cadwyn/changelogs.py +13 -9
  5. {cadwyn-5.4.3 → cadwyn-5.4.5}/cadwyn/schema_generation.py +29 -8
  6. {cadwyn-5.4.3 → cadwyn-5.4.5}/cadwyn/structure/endpoints.py +1 -1
  7. {cadwyn-5.4.3 → cadwyn-5.4.5}/cadwyn/structure/versions.py +1 -1
  8. {cadwyn-5.4.3 → cadwyn-5.4.5}/docs/concepts/api_version_parameter.md +6 -6
  9. cadwyn-5.4.5/docs/concepts/beware_of_data_versioning.md +9 -0
  10. {cadwyn-5.4.3 → cadwyn-5.4.5}/docs/concepts/changelogs.md +3 -3
  11. {cadwyn-5.4.3 → cadwyn-5.4.5}/docs/concepts/cli.md +2 -2
  12. {cadwyn-5.4.3 → cadwyn-5.4.5}/docs/concepts/endpoint_migrations.md +9 -9
  13. {cadwyn-5.4.3 → cadwyn-5.4.5}/docs/concepts/enum_migrations.md +2 -2
  14. {cadwyn-5.4.3 → cadwyn-5.4.5}/docs/concepts/index.md +2 -2
  15. {cadwyn-5.4.3 → cadwyn-5.4.5}/docs/concepts/main_app.md +4 -4
  16. {cadwyn-5.4.3 → cadwyn-5.4.5}/docs/concepts/methodology.md +2 -2
  17. {cadwyn-5.4.3 → cadwyn-5.4.5}/docs/concepts/schema_generation.md +5 -4
  18. {cadwyn-5.4.3 → cadwyn-5.4.5}/docs/concepts/schema_migrations.md +12 -13
  19. cadwyn-5.4.5/docs/concepts/testing.md +35 -0
  20. {cadwyn-5.4.3 → cadwyn-5.4.5}/docs/concepts/version_changes.md +79 -73
  21. {cadwyn-5.4.3 → cadwyn-5.4.5}/docs/home/CONTRIBUTING.md +0 -1
  22. {cadwyn-5.4.3 → cadwyn-5.4.5}/docs/how_to/change_openapi_schemas/add_field.md +1 -1
  23. {cadwyn-5.4.3 → cadwyn-5.4.5}/docs/how_to/change_openapi_schemas/change_schema_without_endpoint.md +1 -1
  24. {cadwyn-5.4.3 → cadwyn-5.4.5}/docs/how_to/change_openapi_schemas/changing_constraints.md +1 -1
  25. {cadwyn-5.4.3 → cadwyn-5.4.5}/docs/how_to/change_openapi_schemas/remove_field.md +1 -1
  26. {cadwyn-5.4.3 → cadwyn-5.4.5}/docs/quickstart/tutorial.md +5 -5
  27. {cadwyn-5.4.3 → cadwyn-5.4.5}/docs/theory/how_to_build_versioning_framework.md +1 -1
  28. {cadwyn-5.4.3 → cadwyn-5.4.5}/pyproject.toml +1 -1
  29. {cadwyn-5.4.3 → cadwyn-5.4.5}/tests/test_router_generation.py +3 -3
  30. {cadwyn-5.4.3 → cadwyn-5.4.5}/tests/test_schema_generation/test_schema_field.py +79 -1
  31. cadwyn-5.4.5/uv.lock +2151 -0
  32. cadwyn-5.4.3/.all-contributorsrc +0 -4
  33. cadwyn-5.4.3/docs/concepts/beware_of_data_versioning.md +0 -9
  34. cadwyn-5.4.3/docs/concepts/testing.md +0 -35
  35. cadwyn-5.4.3/uv.lock +0 -1792
  36. {cadwyn-5.4.3 → cadwyn-5.4.5}/.github/CODE_OF_CONDUCT.md +0 -0
  37. {cadwyn-5.4.3 → cadwyn-5.4.5}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  38. {cadwyn-5.4.3 → cadwyn-5.4.5}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  39. {cadwyn-5.4.3 → cadwyn-5.4.5}/.github/actions/setup-python-uv/action.yaml +0 -0
  40. {cadwyn-5.4.3 → cadwyn-5.4.5}/.github/workflows/ci.yaml +0 -0
  41. {cadwyn-5.4.3 → cadwyn-5.4.5}/.github/workflows/daily_tests.yaml +0 -0
  42. {cadwyn-5.4.3 → cadwyn-5.4.5}/.github/workflows/publish_docs.yaml +0 -0
  43. {cadwyn-5.4.3 → cadwyn-5.4.5}/.github/workflows/release.yaml +0 -0
  44. {cadwyn-5.4.3 → cadwyn-5.4.5}/.gitignore +0 -0
  45. {cadwyn-5.4.3 → cadwyn-5.4.5}/.pre-commit-config.yaml +0 -0
  46. {cadwyn-5.4.3 → cadwyn-5.4.5}/LICENSE +0 -0
  47. {cadwyn-5.4.3 → cadwyn-5.4.5}/Makefile +0 -0
  48. {cadwyn-5.4.3 → cadwyn-5.4.5}/cadwyn/__init__.py +0 -0
  49. {cadwyn-5.4.3 → cadwyn-5.4.5}/cadwyn/__main__.py +0 -0
  50. {cadwyn-5.4.3 → cadwyn-5.4.5}/cadwyn/_asts.py +0 -0
  51. {cadwyn-5.4.3 → cadwyn-5.4.5}/cadwyn/_importer.py +0 -0
  52. {cadwyn-5.4.3 → cadwyn-5.4.5}/cadwyn/_internal/__init__.py +0 -0
  53. {cadwyn-5.4.3 → cadwyn-5.4.5}/cadwyn/_internal/context_vars.py +0 -0
  54. {cadwyn-5.4.3 → cadwyn-5.4.5}/cadwyn/_render.py +0 -0
  55. {cadwyn-5.4.3 → cadwyn-5.4.5}/cadwyn/_utils.py +0 -0
  56. {cadwyn-5.4.3 → cadwyn-5.4.5}/cadwyn/applications.py +0 -0
  57. {cadwyn-5.4.3 → cadwyn-5.4.5}/cadwyn/dependencies.py +0 -0
  58. {cadwyn-5.4.3 → cadwyn-5.4.5}/cadwyn/exceptions.py +0 -0
  59. {cadwyn-5.4.3 → cadwyn-5.4.5}/cadwyn/middleware.py +0 -0
  60. {cadwyn-5.4.3 → cadwyn-5.4.5}/cadwyn/py.typed +0 -0
  61. {cadwyn-5.4.3 → cadwyn-5.4.5}/cadwyn/route_generation.py +0 -0
  62. {cadwyn-5.4.3 → cadwyn-5.4.5}/cadwyn/routing.py +0 -0
  63. {cadwyn-5.4.3 → cadwyn-5.4.5}/cadwyn/static/__init__.py +0 -0
  64. {cadwyn-5.4.3 → cadwyn-5.4.5}/cadwyn/static/docs.html +0 -0
  65. {cadwyn-5.4.3 → cadwyn-5.4.5}/cadwyn/structure/__init__.py +0 -0
  66. {cadwyn-5.4.3 → cadwyn-5.4.5}/cadwyn/structure/common.py +0 -0
  67. {cadwyn-5.4.3 → cadwyn-5.4.5}/cadwyn/structure/data.py +0 -0
  68. {cadwyn-5.4.3 → cadwyn-5.4.5}/cadwyn/structure/enums.py +0 -0
  69. {cadwyn-5.4.3 → cadwyn-5.4.5}/cadwyn/structure/schemas.py +0 -0
  70. {cadwyn-5.4.3 → cadwyn-5.4.5}/docs/CNAME +0 -0
  71. {cadwyn-5.4.3 → cadwyn-5.4.5}/docs/__init__.py +0 -0
  72. {cadwyn-5.4.3 → cadwyn-5.4.5}/docs/how_to/change_business_logic/index.md +0 -0
  73. {cadwyn-5.4.3 → cadwyn-5.4.5}/docs/how_to/change_endpoints/index.md +0 -0
  74. {cadwyn-5.4.3 → cadwyn-5.4.5}/docs/how_to/change_openapi_schemas/change_field_type.md +0 -0
  75. {cadwyn-5.4.3 → cadwyn-5.4.5}/docs/how_to/change_openapi_schemas/rename_a_field_in_schema.md +0 -0
  76. {cadwyn-5.4.3 → cadwyn-5.4.5}/docs/how_to/index.md +0 -0
  77. {cadwyn-5.4.3 → cadwyn-5.4.5}/docs/how_to/version_with_paths_and_numbers_instead_of_headers_and_dates.md +0 -0
  78. {cadwyn-5.4.3 → cadwyn-5.4.5}/docs/img/dashboard_with_one_version.png +0 -0
  79. {cadwyn-5.4.3 → cadwyn-5.4.5}/docs/img/dashboard_with_two_versions.png +0 -0
  80. {cadwyn-5.4.3 → cadwyn-5.4.5}/docs/img/get_users_endpoint_from_prior_version.png +0 -0
  81. {cadwyn-5.4.3 → cadwyn-5.4.5}/docs/img/logos/cadwyn_icon_transparent.svg +0 -0
  82. {cadwyn-5.4.3 → cadwyn-5.4.5}/docs/img/logos/cadwyn_transparent.svg +0 -0
  83. {cadwyn-5.4.3 → cadwyn-5.4.5}/docs/img/logos/cadwyn_with_background.svg +0 -0
  84. {cadwyn-5.4.3 → cadwyn-5.4.5}/docs/img/simplified_migration_model.png +0 -0
  85. {cadwyn-5.4.3 → cadwyn-5.4.5}/docs/img/unversioned_dashboard.png +0 -0
  86. {cadwyn-5.4.3 → cadwyn-5.4.5}/docs/index.md +0 -0
  87. {cadwyn-5.4.3 → cadwyn-5.4.5}/docs/plugin.py +0 -0
  88. {cadwyn-5.4.3 → cadwyn-5.4.5}/docs/quickstart/setup.md +0 -0
  89. {cadwyn-5.4.3 → cadwyn-5.4.5}/docs/stylesheets/extra.css +0 -0
  90. {cadwyn-5.4.3 → cadwyn-5.4.5}/docs/theory/how_we_got_here.md +0 -0
  91. {cadwyn-5.4.3 → cadwyn-5.4.5}/docs/theory/literature.md +0 -0
  92. {cadwyn-5.4.3 → cadwyn-5.4.5}/docs_src/__init__.py +0 -0
  93. {cadwyn-5.4.3 → cadwyn-5.4.5}/docs_src/how_to/__init__.py +0 -0
  94. {cadwyn-5.4.3 → cadwyn-5.4.5}/docs_src/how_to/change_openapi_schemas/__init__.py +0 -0
  95. {cadwyn-5.4.3 → cadwyn-5.4.5}/docs_src/how_to/change_openapi_schemas/change_schema_without_endpoint/__init__.py +0 -0
  96. {cadwyn-5.4.3 → cadwyn-5.4.5}/docs_src/how_to/change_openapi_schemas/change_schema_without_endpoint/block001.py +0 -0
  97. {cadwyn-5.4.3 → cadwyn-5.4.5}/docs_src/how_to/change_openapi_schemas/change_schema_without_endpoint/block002.py +0 -0
  98. {cadwyn-5.4.3 → cadwyn-5.4.5}/docs_src/how_to/change_openapi_schemas/change_schema_without_endpoint/tests/__init__.py +0 -0
  99. {cadwyn-5.4.3 → cadwyn-5.4.5}/docs_src/how_to/change_openapi_schemas/change_schema_without_endpoint/tests/test_block001.py +0 -0
  100. {cadwyn-5.4.3 → cadwyn-5.4.5}/docs_src/how_to/change_openapi_schemas/change_schema_without_endpoint/tests/test_block002.py +0 -0
  101. {cadwyn-5.4.3 → cadwyn-5.4.5}/docs_src/how_to/version_with_path_and_numbers_instead_of_headers_and_dates/__init__.py +0 -0
  102. {cadwyn-5.4.3 → cadwyn-5.4.5}/docs_src/how_to/version_with_path_and_numbers_instead_of_headers_and_dates/block001.py +0 -0
  103. {cadwyn-5.4.3 → cadwyn-5.4.5}/docs_src/how_to/version_with_path_and_numbers_instead_of_headers_and_dates/tests/__init__.py +0 -0
  104. {cadwyn-5.4.3 → cadwyn-5.4.5}/docs_src/how_to/version_with_path_and_numbers_instead_of_headers_and_dates/tests/test_block_001.py +0 -0
  105. {cadwyn-5.4.3 → cadwyn-5.4.5}/docs_src/quickstart/__init__.py +0 -0
  106. {cadwyn-5.4.3 → cadwyn-5.4.5}/docs_src/quickstart/setup/__init__.py +0 -0
  107. {cadwyn-5.4.3 → cadwyn-5.4.5}/docs_src/quickstart/setup/block001.sh +0 -0
  108. {cadwyn-5.4.3 → cadwyn-5.4.5}/docs_src/quickstart/setup/block002.py +0 -0
  109. {cadwyn-5.4.3 → cadwyn-5.4.5}/docs_src/quickstart/setup/tests/__init__.py +0 -0
  110. {cadwyn-5.4.3 → cadwyn-5.4.5}/docs_src/quickstart/setup/tests/test_block002.py +0 -0
  111. {cadwyn-5.4.3 → cadwyn-5.4.5}/docs_src/quickstart/tutorial/__init__.py +0 -0
  112. {cadwyn-5.4.3 → cadwyn-5.4.5}/docs_src/quickstart/tutorial/block001.py +0 -0
  113. {cadwyn-5.4.3 → cadwyn-5.4.5}/docs_src/quickstart/tutorial/block002.py +0 -0
  114. {cadwyn-5.4.3 → cadwyn-5.4.5}/docs_src/quickstart/tutorial/block003.py +0 -0
  115. {cadwyn-5.4.3 → cadwyn-5.4.5}/docs_src/quickstart/tutorial/tests/__init__.py +0 -0
  116. {cadwyn-5.4.3 → cadwyn-5.4.5}/docs_src/quickstart/tutorial/tests/test_block001.py +0 -0
  117. {cadwyn-5.4.3 → cadwyn-5.4.5}/docs_src/quickstart/tutorial/tests/test_block002.py +0 -0
  118. {cadwyn-5.4.3 → cadwyn-5.4.5}/docs_src/quickstart/tutorial/tests/test_block003.py +0 -0
  119. {cadwyn-5.4.3 → cadwyn-5.4.5}/docs_src/ruff.toml +0 -0
  120. {cadwyn-5.4.3 → cadwyn-5.4.5}/mkdocs.yml +0 -0
  121. {cadwyn-5.4.3 → cadwyn-5.4.5}/ruff.toml +0 -0
  122. {cadwyn-5.4.3 → cadwyn-5.4.5}/scripts/fix_links.py +0 -0
  123. {cadwyn-5.4.3 → cadwyn-5.4.5}/scripts/split_md.py +0 -0
  124. {cadwyn-5.4.3 → cadwyn-5.4.5}/tests/__init__.py +0 -0
  125. {cadwyn-5.4.3 → cadwyn-5.4.5}/tests/_data/__init__.py +0 -0
  126. {cadwyn-5.4.3 → cadwyn-5.4.5}/tests/_data/unversioned_schema_dir/__init__.py +0 -0
  127. {cadwyn-5.4.3 → cadwyn-5.4.5}/tests/_data/unversioned_schema_dir/unversioned_schemas.py +0 -0
  128. {cadwyn-5.4.3 → cadwyn-5.4.5}/tests/_data/unversioned_schemas.py +0 -0
  129. {cadwyn-5.4.3 → cadwyn-5.4.5}/tests/_resources/__init__.py +0 -0
  130. {cadwyn-5.4.3 → cadwyn-5.4.5}/tests/_resources/app_for_testing_routing.py +0 -0
  131. {cadwyn-5.4.3 → cadwyn-5.4.5}/tests/_resources/render/__init__.py +0 -0
  132. {cadwyn-5.4.3 → cadwyn-5.4.5}/tests/_resources/render/classes.py +0 -0
  133. {cadwyn-5.4.3 → cadwyn-5.4.5}/tests/_resources/render/complex/__init__.py +0 -0
  134. {cadwyn-5.4.3 → cadwyn-5.4.5}/tests/_resources/render/complex/classes.py +0 -0
  135. {cadwyn-5.4.3 → cadwyn-5.4.5}/tests/_resources/render/complex/versions.py +0 -0
  136. {cadwyn-5.4.3 → cadwyn-5.4.5}/tests/_resources/render/versions.py +0 -0
  137. {cadwyn-5.4.3 → cadwyn-5.4.5}/tests/_resources/utils.py +0 -0
  138. {cadwyn-5.4.3 → cadwyn-5.4.5}/tests/_resources/versioned_app/__init__.py +0 -0
  139. {cadwyn-5.4.3 → cadwyn-5.4.5}/tests/_resources/versioned_app/app.py +0 -0
  140. {cadwyn-5.4.3 → cadwyn-5.4.5}/tests/_resources/versioned_app/v2021_01_01.py +0 -0
  141. {cadwyn-5.4.3 → cadwyn-5.4.5}/tests/_resources/versioned_app/v2022_01_02.py +0 -0
  142. {cadwyn-5.4.3 → cadwyn-5.4.5}/tests/_resources/versioned_app/webhooks.py +0 -0
  143. {cadwyn-5.4.3 → cadwyn-5.4.5}/tests/conftest.py +0 -0
  144. {cadwyn-5.4.3 → cadwyn-5.4.5}/tests/test_applications.py +0 -0
  145. {cadwyn-5.4.3 → cadwyn-5.4.5}/tests/test_auth_dependencies.py +0 -0
  146. {cadwyn-5.4.3 → cadwyn-5.4.5}/tests/test_changelog.py +0 -0
  147. {cadwyn-5.4.3 → cadwyn-5.4.5}/tests/test_cli.py +0 -0
  148. {cadwyn-5.4.3 → cadwyn-5.4.5}/tests/test_data_migrations.py +0 -0
  149. {cadwyn-5.4.3 → cadwyn-5.4.5}/tests/test_render.py +0 -0
  150. {cadwyn-5.4.3 → cadwyn-5.4.5}/tests/test_router_generation_with_from_future_annotations.py +0 -0
  151. {cadwyn-5.4.3 → cadwyn-5.4.5}/tests/test_routing.py +0 -0
  152. {cadwyn-5.4.3 → cadwyn-5.4.5}/tests/test_schema_generation/__init__.py +0 -0
  153. {cadwyn-5.4.3 → cadwyn-5.4.5}/tests/test_schema_generation/test_enum.py +0 -0
  154. {cadwyn-5.4.3 → cadwyn-5.4.5}/tests/test_schema_generation/test_schema.py +0 -0
  155. {cadwyn-5.4.3 → cadwyn-5.4.5}/tests/test_schema_generation/test_schema_validator.py +0 -0
  156. {cadwyn-5.4.3 → cadwyn-5.4.5}/tests/test_schema_generation/test_schema_with_future_annotations.py +0 -0
  157. {cadwyn-5.4.3 → cadwyn-5.4.5}/tests/test_structure.py +0 -0
  158. {cadwyn-5.4.3 → cadwyn-5.4.5}/tests/tutorial/__init__.py +0 -0
  159. {cadwyn-5.4.3 → cadwyn-5.4.5}/tests/tutorial/main.py +0 -0
  160. {cadwyn-5.4.3 → cadwyn-5.4.5}/tests/tutorial/test_example.py +0 -0
  161. {cadwyn-5.4.3 → cadwyn-5.4.5}/tests/versioning_styles/__init__.py +0 -0
  162. {cadwyn-5.4.3 → cadwyn-5.4.5}/tests/versioning_styles/test_versioning_formats.py +0 -0
  163. {cadwyn-5.4.3 → cadwyn-5.4.5}/tox.ini +0 -0
@@ -5,6 +5,12 @@ Please follow [the Keep a Changelog standard](https://keepachangelog.com/en/1.0.
5
5
 
6
6
  ## [Unreleased]
7
7
 
8
+ ## [5.4.4]
9
+
10
+ ### Fixed
11
+
12
+ * Fixed KeyError when versioning Pydantic models containing ClassVar annotations
13
+
8
14
  ## [5.4.3]
9
15
 
10
16
  ### Fixed
@@ -86,17 +92,17 @@ Please follow [the Keep a Changelog standard](https://keepachangelog.com/en/1.0.
86
92
  * `__doc__` attribute is now copied from the original enum to the generated enum
87
93
  * Python 3.12 type aliases and their typing_extensions backports are now supported (including `pydantic.JsonValue` and other `typing_extensions.TypeAliasType` instances)
88
94
  * The bug when solve_dependencies error on the migration of a request to the latest version responds with a non-json serializable error and cadwyn showed a failed to serialize error instead of the actual error
89
- * Updated minimum fastapi version to 0.112.4 because embed_body_fields was added in 0.112.4
95
+ * Updated minimum FastAPI version to 0.112.4 because embed_body_fields was added in 0.112.4
90
96
 
91
97
  ## [5.1.2]
92
98
 
93
99
  ### Fixed
94
100
 
95
- * Generators not being called when fastapi validates the initial request
101
+ * Generators not being called when FastAPI validates the initial request
96
102
 
97
103
  ### Added
98
104
 
99
- * `cadwyn.current_dependency_solver` function to check whether cadwyn or fastapi is currently solving dependencies. It can be used as a dependency for versioned endpoints like so: `current_dependency_solver: Annotated[Literal["fastapi", "cadwyn"], Depends(current_dependency_solver)]`. If your dependency has side effects, you would likely want to only run it once per request. If you want to run it once we migrated the request to the latest version, you should only run it when `current_dependency_solver` is `"cadwyn"`. If you want your dependency to run at the very beginning of handling the request, you should only run it when `current_dependency_solver` is `"fastapi"`.
105
+ * `cadwyn.current_dependency_solver` function to check whether cadwyn or FastAPI is currently solving dependencies. It can be used as a dependency for versioned endpoints like so: `current_dependency_solver: Annotated[Literal["fastapi", "cadwyn"], Depends(current_dependency_solver)]`. If your dependency has side effects, you would likely want to only run it once per request. If you want to run it once we migrated the request to the latest version, you should only run it when `current_dependency_solver` is `"cadwyn"`. If you want your dependency to run at the very beginning of handling the request, you should only run it when `current_dependency_solver` is `"fastapi"`.
100
106
 
101
107
  ## [5.1.1]
102
108
 
@@ -303,7 +309,7 @@ Versions 3.x.x are still supported in terms of bug and security fixes but all th
303
309
 
304
310
  ### Changed
305
311
 
306
- * `Cadwyn.enrich_swagger` is now completely unnecessary: openapi is now generated at runtime. It also now does not do anything, is deprecated, and will be removed in a future version
312
+ * `Cadwyn.enrich_swagger` is now completely unnecessary: OpenAPI is now generated at runtime. It also now does not do anything, is deprecated, and will be removed in a future version
307
313
 
308
314
  ### Fixed
309
315
 
@@ -324,7 +330,7 @@ Versions 3.x.x are still supported in terms of bug and security fixes but all th
324
330
 
325
331
  ### Fixed
326
332
 
327
- * Openapi not being generated when lifespan was used
333
+ * OpenAPI not being generated when lifespan was used
328
334
 
329
335
  ## [3.15.1]
330
336
 
@@ -449,7 +455,7 @@ Versions 3.x.x are still supported in terms of bug and security fixes but all th
449
455
 
450
456
  ### Fixed
451
457
 
452
- * When a class-based dependency from **fastapi** was used (anything security related), FastAPI had hardcoded `isinstance` checks for it which it used to enrich swagger with functionality. But when the dependencies were wrapped into our function wrappers, these checks stopped passing, thus breaking this functionality in swagger. Now we ignore all dependencies that FastAPI creates. This also introduces a hard-to-solve bug: if fastapi's class-based security dependency was subclassed and then `__call__` was overridden with new dependencies that are versioned -- we will not migrate them from version to version. I hope this is an extremely rare use case though. In fact, such use case breaks Liskov Substitution Principle and doesn't make much sense because security classes already include `request` parameter which means that no extra dependencies or parameters are necessary.
458
+ * When a class-based dependency from **fastapi** was used (anything security related), FastAPI had hardcoded `isinstance` checks for it which it used to enrich swagger with functionality. But when the dependencies were wrapped into our function wrappers, these checks stopped passing, thus breaking this functionality in swagger. Now we ignore all dependencies that FastAPI creates. This also introduces a hard-to-solve bug: if FastAPI's class-based security dependency was subclassed and then `__call__` was overridden with new dependencies that are versioned -- we will not migrate them from version to version. I hope this is an extremely rare use case though. In fact, such use case breaks Liskov Substitution Principle and doesn't make much sense because security classes already include `request` parameter which means that no extra dependencies or parameters are necessary.
453
459
 
454
460
  ## [3.6.5]
455
461
 
@@ -707,13 +713,13 @@ Versions 3.x.x are still supported in terms of bug and security fixes but all th
707
713
 
708
714
  ### Fixed
709
715
 
710
- * Custom body fields created by fastapi caused an exception. Now they are ignored
716
+ * Custom body fields created by FastAPI caused an exception. Now they are ignored
711
717
 
712
718
  ## [2.0.2]
713
719
 
714
720
  ### Added
715
721
 
716
- * A link to openapi discussion on enum expansion into docs/recipes
722
+ * A link to OpenAPI discussion on enum expansion into docs/recipes
717
723
  * A link to intercom's API versioning article into docs/theory
718
724
 
719
725
  ## [2.0.1]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cadwyn
3
- Version: 5.4.3
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 -->
@@ -40,26 +40,3 @@ The [documentation](https://docs.cadwyn.dev) has everything you need to succeed.
40
40
  ## Sponsors
41
41
 
42
42
  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!
43
-
44
- ## Contributors
45
-
46
- <details>
47
-
48
- <summary>Thanks goes to these wonderful people:</summary>
49
- <a href="https://allcontributors.org/docs/en/emoji-key">Emoji Key </a>
50
-
51
- <!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
52
- <!-- prettier-ignore-start -->
53
- <!-- markdownlint-disable -->
54
-
55
- <!-- markdownlint-restore -->
56
- <!-- prettier-ignore-end -->
57
-
58
- <!-- ALL-CONTRIBUTORS-LIST:END -->
59
-
60
- This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification.
61
- Contributions are welcome!
62
-
63
- </details>
64
-
65
- <!-- contributors-end -->
@@ -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):
@@ -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/fastapi do any comparisons.
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
- return get_origin(annotation)[tuple(self.change_version_of_annotation(arg) for arg in get_args(annotation))]
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
- field = PydanticFieldWrapper(
952
- alter_schema_instruction.field, alter_schema_instruction.field.annotation, alter_schema_instruction.name
953
- )
954
- model.fields[alter_schema_instruction.name] = field
955
- model.annotations[alter_schema_instruction.name] = alter_schema_instruction.field.annotation
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}" '
@@ -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
- # Fastapi API routes also have "endpoint" and "dependency_overrides_provider" fields.
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
@@ -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 fastapi
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
@@ -63,7 +63,7 @@ app = Cadwyn(
63
63
  )
64
64
  ```
65
65
 
66
- In which case only dates will be accepted as valid versions.
66
+ In the example above only dates will be accepted as valid versions.
67
67
 
68
68
  You can also use an arbitrary string:
69
69
 
@@ -80,21 +80,21 @@ app = Cadwyn(
80
80
  )
81
81
  ```
82
82
 
83
- In which case any string will be accepted as a valid version. Notice how they do not have to be sortable or even ordered. Cadwyn will assume that their actual order is the same as the order of the versions in the `VersionBundle`.
83
+ In the example above any string will be accepted as a valid version. Arbitrary strings can be used, Cadwyn will not sort them. Cadwyn will assume their actual order matches the order of the versions in the `VersionBundle`.
84
84
 
85
85
  ### API Version waterfalling
86
86
 
87
87
  For historical reasons, date-based routing also supports waterfalling the requests to the closest earlier version of the API if the request date parameter doesn't match any of the versions exactly.
88
88
 
89
- If the app has two versions: 2022-01-02 and 2022-01-05, and the request date parameter is 2022-01-03, then the request will be routed to 2022-01-02 version as it the closest version, but lower than the request date parameter.
89
+ If the app has two versions: 2022-01-02 and 2022-01-05, and the request date parameter is 2022-01-03, then the request will be routed to the 2022-01-02 version, as it is the closest version, but lower than the request date parameter.
90
90
 
91
- Exact match is always preferred over partial match and a request will never be matched to the higher versioned route.
91
+ An exact match is always preferred to a partial match and a request will never be matched to the higher-versioned route.
92
92
 
93
- We implement routing like this because Cadwyn was born in a microservice architecture and it is extremely convenient to have waterfalling there. For example, imagine that you have two Cadwyn services: Payables and Receivables, each defining its own API versions. Payables service might contain 10 versions while receivables service might contain only 2 versions because it didn't need as many breaking changes. If a client requests a version that does not exist in receivables -- we will just waterfall to some earlier version, making receivables behavior consistent even if API keeps getting new versions.
93
+ We implement routing like this because Cadwyn was born in a microservice architecture and it is extremely convenient to have waterfalling there. For example, imagine that you have two Cadwyn services: Payables and Receivables, each defining its own API versions. Payables service might contain 10 versions while Receivables service might contain only 2 versions because it didn't need as many breaking changes. If a client requests a version that does not exist in Receivables, we will just waterfall to some earlier version, making Receivables behavior consistent even if API keeps getting new versions.
94
94
 
95
95
  ## API Version Parameter Title and Description
96
96
 
97
- You can pass a title and/or a description to `Cadwyn` constructor. They are equivalent to passing `title` and `description` to `fastapi.Path` or `fastapi.Header` constructors.
97
+ You can pass a title and/or a description to the `Cadwyn` constructor. It is equivalent to passing `title` and `description` to `fastapi.Path` or `fastapi.Header` constructors.
98
98
 
99
99
  ```python
100
100
  app = Cadwyn(
@@ -0,0 +1,9 @@
1
+ # Beware of data versioning
2
+
3
+ Oftentimes you will want to introduce a breaking change where one of the following is true:
4
+
5
+ * Old data cannot be automatically converted to the structure of the new response
6
+ * New response cannot be automatically migrated to an older response
7
+ * Old request cannot be automatically converted to the HEAD request
8
+
9
+ This means that you are not versioning your API, you are versioning your **data**. This cannot be solved by an API versioning framework. It also makes it incredibly hard to version as you now cannot guarantee compatibility between versions. Avoid this at all costs -- all your API versions must be compatible between each other. Data versioning is not a result of a complicated use case, it is a result of **errors** when divising a new version. I am yet to meet a single case where data versioning is the right way to solve an API versioning problem.
@@ -27,11 +27,11 @@ class CompletelyHiddenVersionChange(VersionChange):
27
27
 
28
28
  ## Customizing changelog endpoint
29
29
 
30
- Just pass the `changelog_url` argument to `Cadwyn` and a `GET` to this url will start returning the changelog for all versions based on the contents of your `VersionBundle`.
30
+ The changelog endpoint name can be customized by specifying a new name via the `changelog_url` argument to the `Cadwyn()` constructor. Accessing this url via the `GET` request will return the changelog for all versions based on the content of your `VersionBundle`.
31
31
 
32
- If you want to hide the changelog endpoint, pass `include_changelog_url_in_schema=False` to `Cadwyn`.
32
+ If you want to hide the changelog endpoint, pass `include_changelog_url_in_schema=False` to `Cadwyn()`.
33
33
 
34
- If you want to delete the changelog endpoint, pass `changelog_url=None` to `Cadwyn`.
34
+ If you want to delete the changelog endpoint, pass `changelog_url=None` to `Cadwyn()`.
35
35
 
36
36
  ## Changelog structure and entry types
37
37
 
@@ -1,7 +1,7 @@
1
1
  # CLI
2
2
 
3
- Cadwyn has an optional CLI interface that can be installed with `pip install 'cadwyn[standard]'`.
4
- You can run `cadwyn --version` to check current version of Cadwyn.
3
+ Cadwyn has an optional CLI that can be installed with `pip install 'cadwyn[standard]'`.
4
+ You can run `cadwyn --version` to check the current version of Cadwyn.
5
5
 
6
6
  Its main purpose is [rendering generated schemas](./schema_generation.md#rendering-schemas).
7
7
 
@@ -1,8 +1,8 @@
1
1
  # Endpoint migrations
2
2
 
3
- Note that the `endpoint(...)` constructor contains a second argument that describes the methods of the endpoints you would like to edit. If you have two routes for a single endpoint and you put both of their methods into the instruction -- both of them are going to be changed as you would expect.
3
+ Note that the `endpoint(...)` constructor contains a second argument that describes the methods of the endpoints you would like to edit. If you have two routes for a single endpoint and you put both of their methods into the instruction -- as expected, both of them will be changed.
4
4
 
5
- ## Defining endpoints that didn't exist in new versions
5
+ ## Defining endpoints that didn't exist for new versions
6
6
 
7
7
  If you had an endpoint in an old version **but want to delete it in a new version**, you must still define it as usual with all your other endpoints but mark it as deleted.
8
8
 
@@ -43,7 +43,7 @@ class MyChange(VersionChange):
43
43
 
44
44
  ## Changing endpoint attributes
45
45
 
46
- If you want to change any attribute of your endpoint in a new version, you can return the attribute's value in all older versions like so:
46
+ If you want to change any attribute of your endpoint in a new version, you can return the attribute's value in all older versions like this:
47
47
 
48
48
  ```python
49
49
  from cadwyn import VersionChange, endpoint
@@ -64,11 +64,11 @@ However, you only need to have a migration if it is a breaking change for your u
64
64
 
65
65
  Note that changing endpoint `dependencies` is only going to affect the initial validation. So Cadwyn will take your altered dependencies and run them on each request to the endpoint but ultimately your endpoint code is always going to use the HEAD version of your dependencies. So be careful.
66
66
 
67
- Note also that if some of your dependencies were added at app/router level -- they **are** going to be overwritten by this instruction. Most of the time it is rather safe, however, as all the necessary dependencies will still run on HEAD version.
67
+ Also note that if some of your dependencies were added at app/router level, they **are** going to be overwritten by this instruction. Most of the time it is rather safe, however, as all the necessary dependencies will still run on HEAD version.
68
68
 
69
69
  ## Dealing with endpoint duplicates
70
70
 
71
- Sometimes, when you're doing some advanced changes in between versions, you will need to rewrite your endpoint function entirely. So essentially you'd have the following structure:
71
+ Sometimes, when you're doing some advanced changes in between versions, you need to rewrite your endpoint function entirely. So essentially you'd have the following structure:
72
72
 
73
73
  ```python
74
74
  from fastapi.params import Param
@@ -92,7 +92,7 @@ def get_users_by_name(user_name: Annotated[str, Param()]):
92
92
  """Do some logic with user_name"""
93
93
  ```
94
94
 
95
- As you see, these two functions have the same methods and paths. And when you have many versions, you can have even more functions like these two. So how do we ask cadwyn to restore only one of them and delete the other one?
95
+ As you see, these two functions have the same parameters and path decorators. And when you have many versions, you can have even more functions like these two. So how do we ask cadwyn to restore only one of them and delete the other one?
96
96
 
97
97
  ```python
98
98
  from cadwyn import VersionChange, endpoint
@@ -104,8 +104,8 @@ class UseParamsInsteadOfHeadersForUserNameFiltering(VersionChange):
104
104
  "because using headers is a bad API practice in such scenarios."
105
105
  )
106
106
  instructions_to_migrate_to_previous_version = (
107
- # We need to specify the name, otherwise, we will encounter an exception due to having two identical endpoints
108
- # with the same path and method
107
+ # We need to specify the name, otherwise, we will encounter an exception due to
108
+ # having two identical endpoints with the same parameters and path decorators
109
109
  endpoint(
110
110
  "/users",
111
111
  ["GET"],
@@ -117,4 +117,4 @@ class UseParamsInsteadOfHeadersForUserNameFiltering(VersionChange):
117
117
  )
118
118
  ```
119
119
 
120
- So by using a more concrete `func_name`, we are capable to distinguish between different functions that affect the same routes.
120
+ So by using a more concrete `func_name`, we are able to distinguish between different functions that affect the same routes.
@@ -1,10 +1,10 @@
1
1
  # Enum migrations
2
2
 
3
- All of the following instructions affect only openapi schemas and their initial validation. All of your incoming requests will still be converted into your HEAD schemas.
3
+ All of the following instructions affect only OpenAPI schemas and their initial validation. All of your incoming requests will still be converted into your HEAD schemas.
4
4
 
5
5
  ## Adding enum members
6
6
 
7
- Note that adding enum members **can** be a breaking change unlike adding optional fields to a schema. For example, if I return a list of entities, each of which has some type, and I add a new type -- then my client's code is likely to break.
7
+ Note that adding enum members **can** be a breaking change unlike adding optional fields to a schema. For example, if I return a list of entities, each of which has some type, and I add a new type, then my client's code is likely to break.
8
8
 
9
9
  So I suggest adding enum members in new versions as well.
10
10
 
@@ -1,8 +1,8 @@
1
1
  # Concepts
2
2
 
3
- This section covers the entirety of features and their rationale in Cadwyn. It can also be used as a reference documentation until we have a proper one. First, let's talk about the reasons for using Cadwyn at all.
3
+ This section covers the entirety of features and their rationale in Cadwyn. It can also be used as reference documentation until we have a proper one. First, let's talk about the reasons for using Cadwyn at all.
4
4
 
5
- Cadwyn aims to be the most accurate and sophisticated API Versioning model out there. First of all, you maintain **zero** duplicated code yourself. Usually, in API versioning you [would need to](../theory/how_we_got_here.md) duplicate and maintain at least some layer of your application. It could be the database, business logic, schemas, and endpoints. Cadwyn allows you to duplicate none of that. Internally, it duplicates endpoints and schemas at runtime but none of it becomes your tech debt, none of it becomes your code to support. If you test rigorously, then only [some small subset of your tests](./testing.md) will need to be duplicated when existing functionality is changed between versions.
5
+ Cadwyn aims to be the most accurate and sophisticated API Versioning model out there. First of all, you maintain **zero** duplicated code yourself. Usually, in API versioning you [would need to](../theory/how_we_got_here.md) duplicate and maintain at least some layer of your application. It could be the database, business logic, schemas, and endpoints. With Cadwyn you avoid duplicating any of that. Internally, it duplicates endpoints and schemas at runtime but none of it becomes your tech debt, none of it becomes your code to support. If you test rigorously, then only [some small subset of your tests](./testing.md) will need to be duplicated when existing functionality is changed between versions.
6
6
 
7
7
  You define your database, business logic, routes, and schemas only once. Then, whenever you release a new API version, you use Cadwyn's [version change DSL](./version_changes.md#version-changes) to describe how to convert your app to the previous version. So your business logic and database stay intact and always represent the latest version while the version changes make sure that your clients can continue using the previous versions without ever needing to update their code.
8
8
 
@@ -1,11 +1,11 @@
1
1
  # Main App
2
2
 
3
- Cadwyn's standard usage is done with a single customized FastAPI app: `cadwyn.Cadwyn`. It accepts all the same arguments as `FastAPI` three more keyword-only arguments:
3
+ Cadwyn's standard usage involves a single customized FastAPI app: `cadwyn.Cadwyn`. It accepts all the same arguments as `FastAPI` does and two more keyword-only arguments:
4
4
 
5
5
  * Required `versions: VersionBundle` describes [all versions](./version_changes.md#versionbundle) within your application
6
6
  * Optional `api_version_parameter_name: str = "x_api_version"` is the parameter that Cadwyn will use for [routing](#routing) to different API versions of your app
7
7
 
8
- After you have defined a main app, you can add versioned API routers to it using `Cadwyn.generate_and_include_versioned_routers(*routers)`
8
+ After you have defined the main app, you can add versioned API routers to it using `Cadwyn.generate_and_include_versioned_routers(*routers)`
9
9
 
10
10
  ```python
11
11
  from cadwyn import VersionedAPIRouter, Cadwyn
@@ -33,9 +33,9 @@ That's it! `generate_and_include_versioned_routers` will generate all versions o
33
33
 
34
34
  ## Routing
35
35
 
36
- Cadwyn is built on header-based routing. First, we route requests to the appropriate API version based on the version header (`x-api-version` by default). Then we route by the appropriate url path and method. Currently, Cadwyn only works with ISO date-based versions (such as `2022-11-16`). If the user sends an incorrect API version, Cadwyn picks up the closest lower applicable version. For example, `2022-11-16` in request can be matched by `2022-11-15` and `2000-01-01` but cannot be matched by `2022-11-17`.
36
+ Cadwyn is built on header-based routing. First, we route requests to the appropriate API version based on the version header (`x-api-version` by default). Then we route by the appropriate url path and method. Currently, Cadwyn only works with ISO date-based versions (such as `2022-11-16`). If the user sends a date that does not have an exact match, Cadwyn picks up the closest lower applicable version. For example, `2022-11-16` in request can be matched by `2022-11-15` and `2000-01-01` but cannot be matched by `2022-11-17`.
37
37
 
38
- However, header-based routing is only the standard way to use Cadwyn. If you want to use any other sort of routing, you can use Cadwyn directly through `cadwyn.generate_versioned_routers` or subclass `cadwyn.Cadwyn` to use a different router and middleware. Just remember to update the `VersionBundle.api_version_var` variable each time you route some request to a version. This variable allows Cadwyn to do [side effects](./version_changes.md#version-changes-with-side-effects) and [data migrations](./version_changes.md#data-migrations).
38
+ However, header-based routing is the default way to use Cadwyn. If you want to use any other form of routing, you can use Cadwyn directly through `cadwyn.generate_versioned_routers` or subclass `cadwyn.Cadwyn` to use a different router and middleware. Just remember to update the `VersionBundle.api_version_var` variable each time you route some request to a version. This variable allows Cadwyn to do [side effects](./version_changes.md#version-changes-with-side-effects) and [data migrations](./version_changes.md#data-migrations).
39
39
 
40
40
  ### VersionedAPIRouter
41
41
 
@@ -2,12 +2,12 @@
2
2
 
3
3
  Cadwyn implements a methodology that is based on the following set of principles:
4
4
 
5
- * Each version is made up of "version changes" or "compatibility gates" which describe **independent atomic** differences between it and previous version
5
+ * Each version consists of "version changes" or "compatibility gates" which describe **independent, atomic** differences from the previous version
6
6
  * We make a new version if and only if we have breaking changes
7
7
  * Versions must have little to no effect on the business logic
8
8
  * Versions **must always** be compatible in terms of data
9
9
  * Creating new versions is avoided at all costs
10
- * Any backwards compatible features must be backported to all compatible versions
10
+ * Any backward-compatible features must be backported to all compatible versions
11
11
 
12
12
  These rules give us an ability to have a large number of self-documenting versions while encapsulating their complexity in small version change classes, providing a consistent and stable experience to our users.
13
13
 
@@ -4,13 +4,13 @@ Cadwyn automatically generates versioned schemas and everything related to them
4
4
 
5
5
  ## Rendering schemas
6
6
 
7
- When you have many versions and many schemas, it is quite hard to know what validators, fields, and other attributes are defined on each schema in any concrete version. To combat this problem, we have a way to **render** the generated pydantic models and enums to code using the command-line interface.
7
+ When you have many versions and schemas, it is quite challenging to know what validators, fields, and other attributes are defined on each schema in any specific version. To address this issue, there is a way to **render** the generated pydantic models and enums as code using the command-line interface.
8
8
 
9
- **NOTICE** that `cadwyn render` does not promise to render correct schemas. It is going to be a very close approximation which should be enough for the cases where humans check the schemas by hand. However, it is not yet ready to be used for full blown code generation. For example, it doesn't handle schema renamings in class `__bases__` yet.
9
+ **NOTICE** that `cadwyn render` does not guarantee rendering correct schemas. It is going to be a close enough approximation for manual validation. However, it is not yet ready to be used for production code generation. For example, it doesn't handle schema renamings in class `__bases__` yet.
10
10
 
11
11
  ### Rendering a module
12
12
 
13
- Here's how you would render the entire module with your schemas:
13
+ Here's a way to render the entire module with the schemas:
14
14
 
15
15
  ```bash
16
16
  cadwyn render module data.schemas --app=main:app --version=2024-05-26
@@ -20,7 +20,7 @@ This command will print to stdout what the schemas would look like in version 20
20
20
 
21
21
  ### Rendering a single model
22
22
 
23
- Here's how you would render a single pydantic model or enum with your schemas:
23
+ Here's a way to render a single pydantic model or enum with the schemas:
24
24
 
25
25
  ```bash
26
26
  cadwyn render model data.schemas:UserCreateRequest --app=main:app --version=2024-05-26
@@ -34,6 +34,7 @@ Cadwyn is capable of generating versioned schemas from its version changes even
34
34
 
35
35
  ```python
36
36
  import cadwyn
37
+ from cadwyn.schema_generation import generate_versioned_models
37
38
  from my_versions import version_bundle, MyVersionedSchema
38
39
 
39
40
  schema_generators = generate_versioned_models(version_bundle)