cadwyn 5.3.2__tar.gz → 5.4.1__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 (161) hide show
  1. {cadwyn-5.3.2 → cadwyn-5.4.1}/.pre-commit-config.yaml +17 -9
  2. {cadwyn-5.3.2 → cadwyn-5.4.1}/CHANGELOG.md +20 -0
  3. {cadwyn-5.3.2 → cadwyn-5.4.1}/PKG-INFO +8 -9
  4. {cadwyn-5.3.2 → cadwyn-5.4.1}/README.md +5 -7
  5. {cadwyn-5.3.2 → cadwyn-5.4.1}/cadwyn/__main__.py +1 -1
  6. {cadwyn-5.3.2 → cadwyn-5.4.1}/cadwyn/_asts.py +1 -1
  7. {cadwyn-5.3.2 → cadwyn-5.4.1}/cadwyn/applications.py +2 -2
  8. {cadwyn-5.3.2 → cadwyn-5.4.1}/cadwyn/changelogs.py +5 -5
  9. {cadwyn-5.3.2 → cadwyn-5.4.1}/cadwyn/route_generation.py +2 -2
  10. {cadwyn-5.3.2 → cadwyn-5.4.1}/cadwyn/schema_generation.py +32 -29
  11. {cadwyn-5.3.2 → cadwyn-5.4.1}/cadwyn/structure/data.py +2 -2
  12. {cadwyn-5.3.2 → cadwyn-5.4.1}/cadwyn/structure/schemas.py +2 -2
  13. {cadwyn-5.3.2 → cadwyn-5.4.1}/cadwyn/structure/versions.py +1 -1
  14. {cadwyn-5.3.2 → cadwyn-5.4.1}/docs/concepts/version_changes.md +25 -0
  15. {cadwyn-5.3.2 → cadwyn-5.4.1}/docs/how_to/change_openapi_schemas/remove_field.md +2 -1
  16. cadwyn-5.4.1/docs/img/logos/cadwyn_icon_transparent.svg +1 -0
  17. cadwyn-5.4.1/docs/img/logos/cadwyn_transparent.svg +1 -0
  18. cadwyn-5.4.1/docs/img/logos/cadwyn_with_background.svg +1 -0
  19. {cadwyn-5.3.2 → cadwyn-5.4.1}/docs/index.md +0 -6
  20. cadwyn-5.4.1/docs/stylesheets/extra.css +12 -0
  21. {cadwyn-5.3.2 → cadwyn-5.4.1}/mkdocs.yml +7 -0
  22. {cadwyn-5.3.2 → cadwyn-5.4.1}/pyproject.toml +4 -3
  23. {cadwyn-5.3.2 → cadwyn-5.4.1}/ruff.toml +21 -13
  24. {cadwyn-5.3.2 → cadwyn-5.4.1}/tests/conftest.py +1 -1
  25. {cadwyn-5.3.2 → cadwyn-5.4.1}/tests/test_applications.py +14 -12
  26. {cadwyn-5.3.2 → cadwyn-5.4.1}/tests/test_cli.py +0 -15
  27. {cadwyn-5.3.2 → cadwyn-5.4.1}/tests/test_render.py +4 -2
  28. {cadwyn-5.3.2 → cadwyn-5.4.1}/tests/test_router_generation.py +11 -11
  29. cadwyn-5.4.1/uv.lock +1792 -0
  30. cadwyn-5.3.2/docs/img/sponsor_logos/monite.png +0 -0
  31. cadwyn-5.3.2/uv.lock +0 -1737
  32. {cadwyn-5.3.2 → cadwyn-5.4.1}/.github/CODE_OF_CONDUCT.md +0 -0
  33. {cadwyn-5.3.2 → cadwyn-5.4.1}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  34. {cadwyn-5.3.2 → cadwyn-5.4.1}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  35. {cadwyn-5.3.2 → cadwyn-5.4.1}/.github/actions/setup-python-uv/action.yaml +0 -0
  36. {cadwyn-5.3.2 → cadwyn-5.4.1}/.github/workflows/ci.yaml +0 -0
  37. {cadwyn-5.3.2 → cadwyn-5.4.1}/.github/workflows/daily_tests.yaml +0 -0
  38. {cadwyn-5.3.2 → cadwyn-5.4.1}/.github/workflows/publish_docs.yaml +0 -0
  39. {cadwyn-5.3.2 → cadwyn-5.4.1}/.github/workflows/release.yaml +0 -0
  40. {cadwyn-5.3.2 → cadwyn-5.4.1}/.gitignore +0 -0
  41. {cadwyn-5.3.2 → cadwyn-5.4.1}/LICENSE +0 -0
  42. {cadwyn-5.3.2 → cadwyn-5.4.1}/Makefile +0 -0
  43. {cadwyn-5.3.2 → cadwyn-5.4.1}/cadwyn/__init__.py +0 -0
  44. {cadwyn-5.3.2 → cadwyn-5.4.1}/cadwyn/_importer.py +0 -0
  45. {cadwyn-5.3.2 → cadwyn-5.4.1}/cadwyn/_internal/__init__.py +0 -0
  46. {cadwyn-5.3.2 → cadwyn-5.4.1}/cadwyn/_internal/context_vars.py +0 -0
  47. {cadwyn-5.3.2 → cadwyn-5.4.1}/cadwyn/_render.py +0 -0
  48. {cadwyn-5.3.2 → cadwyn-5.4.1}/cadwyn/_utils.py +0 -0
  49. {cadwyn-5.3.2 → cadwyn-5.4.1}/cadwyn/dependencies.py +0 -0
  50. {cadwyn-5.3.2 → cadwyn-5.4.1}/cadwyn/exceptions.py +0 -0
  51. {cadwyn-5.3.2 → cadwyn-5.4.1}/cadwyn/middleware.py +0 -0
  52. {cadwyn-5.3.2 → cadwyn-5.4.1}/cadwyn/py.typed +0 -0
  53. {cadwyn-5.3.2 → cadwyn-5.4.1}/cadwyn/routing.py +0 -0
  54. {cadwyn-5.3.2 → cadwyn-5.4.1}/cadwyn/static/__init__.py +0 -0
  55. {cadwyn-5.3.2 → cadwyn-5.4.1}/cadwyn/static/docs.html +0 -0
  56. {cadwyn-5.3.2 → cadwyn-5.4.1}/cadwyn/structure/__init__.py +0 -0
  57. {cadwyn-5.3.2 → cadwyn-5.4.1}/cadwyn/structure/common.py +0 -0
  58. {cadwyn-5.3.2 → cadwyn-5.4.1}/cadwyn/structure/endpoints.py +0 -0
  59. {cadwyn-5.3.2 → cadwyn-5.4.1}/cadwyn/structure/enums.py +0 -0
  60. {cadwyn-5.3.2 → cadwyn-5.4.1}/docs/CNAME +0 -0
  61. {cadwyn-5.3.2 → cadwyn-5.4.1}/docs/__init__.py +0 -0
  62. {cadwyn-5.3.2 → cadwyn-5.4.1}/docs/concepts/api_version_parameter.md +0 -0
  63. {cadwyn-5.3.2 → cadwyn-5.4.1}/docs/concepts/beware_of_data_versioning.md +0 -0
  64. {cadwyn-5.3.2 → cadwyn-5.4.1}/docs/concepts/changelogs.md +0 -0
  65. {cadwyn-5.3.2 → cadwyn-5.4.1}/docs/concepts/cli.md +0 -0
  66. {cadwyn-5.3.2 → cadwyn-5.4.1}/docs/concepts/endpoint_migrations.md +0 -0
  67. {cadwyn-5.3.2 → cadwyn-5.4.1}/docs/concepts/enum_migrations.md +0 -0
  68. {cadwyn-5.3.2 → cadwyn-5.4.1}/docs/concepts/index.md +0 -0
  69. {cadwyn-5.3.2 → cadwyn-5.4.1}/docs/concepts/main_app.md +0 -0
  70. {cadwyn-5.3.2 → cadwyn-5.4.1}/docs/concepts/methodology.md +0 -0
  71. {cadwyn-5.3.2 → cadwyn-5.4.1}/docs/concepts/schema_generation.md +0 -0
  72. {cadwyn-5.3.2 → cadwyn-5.4.1}/docs/concepts/schema_migrations.md +0 -0
  73. {cadwyn-5.3.2 → cadwyn-5.4.1}/docs/concepts/testing.md +0 -0
  74. {cadwyn-5.3.2 → cadwyn-5.4.1}/docs/home/CONTRIBUTING.md +0 -0
  75. {cadwyn-5.3.2 → cadwyn-5.4.1}/docs/how_to/change_business_logic/index.md +0 -0
  76. {cadwyn-5.3.2 → cadwyn-5.4.1}/docs/how_to/change_endpoints/index.md +0 -0
  77. {cadwyn-5.3.2 → cadwyn-5.4.1}/docs/how_to/change_openapi_schemas/add_field.md +0 -0
  78. {cadwyn-5.3.2 → cadwyn-5.4.1}/docs/how_to/change_openapi_schemas/change_field_type.md +0 -0
  79. {cadwyn-5.3.2 → cadwyn-5.4.1}/docs/how_to/change_openapi_schemas/change_schema_without_endpoint.md +0 -0
  80. {cadwyn-5.3.2 → cadwyn-5.4.1}/docs/how_to/change_openapi_schemas/changing_constraints.md +0 -0
  81. {cadwyn-5.3.2 → cadwyn-5.4.1}/docs/how_to/change_openapi_schemas/rename_a_field_in_schema.md +0 -0
  82. {cadwyn-5.3.2 → cadwyn-5.4.1}/docs/how_to/index.md +0 -0
  83. {cadwyn-5.3.2 → cadwyn-5.4.1}/docs/how_to/version_with_paths_and_numbers_instead_of_headers_and_dates.md +0 -0
  84. {cadwyn-5.3.2 → cadwyn-5.4.1}/docs/img/dashboard_with_one_version.png +0 -0
  85. {cadwyn-5.3.2 → cadwyn-5.4.1}/docs/img/dashboard_with_two_versions.png +0 -0
  86. {cadwyn-5.3.2 → cadwyn-5.4.1}/docs/img/get_users_endpoint_from_prior_version.png +0 -0
  87. {cadwyn-5.3.2 → cadwyn-5.4.1}/docs/img/simplified_migration_model.png +0 -0
  88. {cadwyn-5.3.2 → cadwyn-5.4.1}/docs/img/unversioned_dashboard.png +0 -0
  89. {cadwyn-5.3.2 → cadwyn-5.4.1}/docs/plugin.py +0 -0
  90. {cadwyn-5.3.2 → cadwyn-5.4.1}/docs/quickstart/setup.md +0 -0
  91. {cadwyn-5.3.2 → cadwyn-5.4.1}/docs/quickstart/tutorial.md +0 -0
  92. {cadwyn-5.3.2 → cadwyn-5.4.1}/docs/theory/how_to_build_versioning_framework.md +0 -0
  93. {cadwyn-5.3.2 → cadwyn-5.4.1}/docs/theory/how_we_got_here.md +0 -0
  94. {cadwyn-5.3.2 → cadwyn-5.4.1}/docs/theory/literature.md +0 -0
  95. {cadwyn-5.3.2 → cadwyn-5.4.1}/docs_src/__init__.py +0 -0
  96. {cadwyn-5.3.2 → cadwyn-5.4.1}/docs_src/how_to/__init__.py +0 -0
  97. {cadwyn-5.3.2 → cadwyn-5.4.1}/docs_src/how_to/change_openapi_schemas/__init__.py +0 -0
  98. {cadwyn-5.3.2 → cadwyn-5.4.1}/docs_src/how_to/change_openapi_schemas/change_schema_without_endpoint/__init__.py +0 -0
  99. {cadwyn-5.3.2 → cadwyn-5.4.1}/docs_src/how_to/change_openapi_schemas/change_schema_without_endpoint/block001.py +0 -0
  100. {cadwyn-5.3.2 → cadwyn-5.4.1}/docs_src/how_to/change_openapi_schemas/change_schema_without_endpoint/block002.py +0 -0
  101. {cadwyn-5.3.2 → cadwyn-5.4.1}/docs_src/how_to/change_openapi_schemas/change_schema_without_endpoint/tests/__init__.py +0 -0
  102. {cadwyn-5.3.2 → cadwyn-5.4.1}/docs_src/how_to/change_openapi_schemas/change_schema_without_endpoint/tests/test_block001.py +0 -0
  103. {cadwyn-5.3.2 → cadwyn-5.4.1}/docs_src/how_to/change_openapi_schemas/change_schema_without_endpoint/tests/test_block002.py +0 -0
  104. {cadwyn-5.3.2 → cadwyn-5.4.1}/docs_src/how_to/version_with_path_and_numbers_instead_of_headers_and_dates/__init__.py +0 -0
  105. {cadwyn-5.3.2 → cadwyn-5.4.1}/docs_src/how_to/version_with_path_and_numbers_instead_of_headers_and_dates/block001.py +0 -0
  106. {cadwyn-5.3.2 → cadwyn-5.4.1}/docs_src/how_to/version_with_path_and_numbers_instead_of_headers_and_dates/tests/__init__.py +0 -0
  107. {cadwyn-5.3.2 → cadwyn-5.4.1}/docs_src/how_to/version_with_path_and_numbers_instead_of_headers_and_dates/tests/test_block_001.py +0 -0
  108. {cadwyn-5.3.2 → cadwyn-5.4.1}/docs_src/quickstart/__init__.py +0 -0
  109. {cadwyn-5.3.2 → cadwyn-5.4.1}/docs_src/quickstart/setup/__init__.py +0 -0
  110. {cadwyn-5.3.2 → cadwyn-5.4.1}/docs_src/quickstart/setup/block001.sh +0 -0
  111. {cadwyn-5.3.2 → cadwyn-5.4.1}/docs_src/quickstart/setup/block002.py +0 -0
  112. {cadwyn-5.3.2 → cadwyn-5.4.1}/docs_src/quickstart/setup/tests/__init__.py +0 -0
  113. {cadwyn-5.3.2 → cadwyn-5.4.1}/docs_src/quickstart/setup/tests/test_block002.py +0 -0
  114. {cadwyn-5.3.2 → cadwyn-5.4.1}/docs_src/quickstart/tutorial/__init__.py +0 -0
  115. {cadwyn-5.3.2 → cadwyn-5.4.1}/docs_src/quickstart/tutorial/block001.py +0 -0
  116. {cadwyn-5.3.2 → cadwyn-5.4.1}/docs_src/quickstart/tutorial/block002.py +0 -0
  117. {cadwyn-5.3.2 → cadwyn-5.4.1}/docs_src/quickstart/tutorial/block003.py +0 -0
  118. {cadwyn-5.3.2 → cadwyn-5.4.1}/docs_src/quickstart/tutorial/tests/__init__.py +0 -0
  119. {cadwyn-5.3.2 → cadwyn-5.4.1}/docs_src/quickstart/tutorial/tests/test_block001.py +0 -0
  120. {cadwyn-5.3.2 → cadwyn-5.4.1}/docs_src/quickstart/tutorial/tests/test_block002.py +0 -0
  121. {cadwyn-5.3.2 → cadwyn-5.4.1}/docs_src/quickstart/tutorial/tests/test_block003.py +0 -0
  122. {cadwyn-5.3.2 → cadwyn-5.4.1}/docs_src/ruff.toml +0 -0
  123. {cadwyn-5.3.2 → cadwyn-5.4.1}/scripts/fix_links.py +0 -0
  124. {cadwyn-5.3.2 → cadwyn-5.4.1}/scripts/split_md.py +0 -0
  125. {cadwyn-5.3.2 → cadwyn-5.4.1}/tests/__init__.py +0 -0
  126. {cadwyn-5.3.2 → cadwyn-5.4.1}/tests/_data/__init__.py +0 -0
  127. {cadwyn-5.3.2 → cadwyn-5.4.1}/tests/_data/unversioned_schema_dir/__init__.py +0 -0
  128. {cadwyn-5.3.2 → cadwyn-5.4.1}/tests/_data/unversioned_schema_dir/unversioned_schemas.py +0 -0
  129. {cadwyn-5.3.2 → cadwyn-5.4.1}/tests/_data/unversioned_schemas.py +0 -0
  130. {cadwyn-5.3.2 → cadwyn-5.4.1}/tests/_resources/__init__.py +0 -0
  131. {cadwyn-5.3.2 → cadwyn-5.4.1}/tests/_resources/app_for_testing_routing.py +0 -0
  132. {cadwyn-5.3.2 → cadwyn-5.4.1}/tests/_resources/render/__init__.py +0 -0
  133. {cadwyn-5.3.2 → cadwyn-5.4.1}/tests/_resources/render/classes.py +0 -0
  134. {cadwyn-5.3.2 → cadwyn-5.4.1}/tests/_resources/render/complex/__init__.py +0 -0
  135. {cadwyn-5.3.2 → cadwyn-5.4.1}/tests/_resources/render/complex/classes.py +0 -0
  136. {cadwyn-5.3.2 → cadwyn-5.4.1}/tests/_resources/render/complex/versions.py +0 -0
  137. {cadwyn-5.3.2 → cadwyn-5.4.1}/tests/_resources/render/versions.py +0 -0
  138. {cadwyn-5.3.2 → cadwyn-5.4.1}/tests/_resources/utils.py +0 -0
  139. {cadwyn-5.3.2 → cadwyn-5.4.1}/tests/_resources/versioned_app/__init__.py +0 -0
  140. {cadwyn-5.3.2 → cadwyn-5.4.1}/tests/_resources/versioned_app/app.py +0 -0
  141. {cadwyn-5.3.2 → cadwyn-5.4.1}/tests/_resources/versioned_app/v2021_01_01.py +0 -0
  142. {cadwyn-5.3.2 → cadwyn-5.4.1}/tests/_resources/versioned_app/v2022_01_02.py +0 -0
  143. {cadwyn-5.3.2 → cadwyn-5.4.1}/tests/_resources/versioned_app/webhooks.py +0 -0
  144. {cadwyn-5.3.2 → cadwyn-5.4.1}/tests/test_auth_dependencies.py +0 -0
  145. {cadwyn-5.3.2 → cadwyn-5.4.1}/tests/test_changelog.py +0 -0
  146. {cadwyn-5.3.2 → cadwyn-5.4.1}/tests/test_data_migrations.py +0 -0
  147. {cadwyn-5.3.2 → cadwyn-5.4.1}/tests/test_router_generation_with_from_future_annotations.py +0 -0
  148. {cadwyn-5.3.2 → cadwyn-5.4.1}/tests/test_routing.py +0 -0
  149. {cadwyn-5.3.2 → cadwyn-5.4.1}/tests/test_schema_generation/__init__.py +0 -0
  150. {cadwyn-5.3.2 → cadwyn-5.4.1}/tests/test_schema_generation/test_enum.py +0 -0
  151. {cadwyn-5.3.2 → cadwyn-5.4.1}/tests/test_schema_generation/test_schema.py +0 -0
  152. {cadwyn-5.3.2 → cadwyn-5.4.1}/tests/test_schema_generation/test_schema_field.py +0 -0
  153. {cadwyn-5.3.2 → cadwyn-5.4.1}/tests/test_schema_generation/test_schema_validator.py +0 -0
  154. {cadwyn-5.3.2 → cadwyn-5.4.1}/tests/test_schema_generation/test_schema_with_future_annotations.py +0 -0
  155. {cadwyn-5.3.2 → cadwyn-5.4.1}/tests/test_structure.py +0 -0
  156. {cadwyn-5.3.2 → cadwyn-5.4.1}/tests/tutorial/__init__.py +0 -0
  157. {cadwyn-5.3.2 → cadwyn-5.4.1}/tests/tutorial/main.py +0 -0
  158. {cadwyn-5.3.2 → cadwyn-5.4.1}/tests/tutorial/test_example.py +0 -0
  159. {cadwyn-5.3.2 → cadwyn-5.4.1}/tests/versioning_styles/__init__.py +0 -0
  160. {cadwyn-5.3.2 → cadwyn-5.4.1}/tests/versioning_styles/test_versioning_formats.py +0 -0
  161. {cadwyn-5.3.2 → cadwyn-5.4.1}/tox.ini +0 -0
@@ -1,12 +1,13 @@
1
1
  default_language_version:
2
- python: python3.10
2
+ python: python3
3
3
  repos:
4
4
  - repo: https://github.com/pre-commit/pre-commit-hooks
5
5
  rev: v5.0.0
6
6
  hooks:
7
7
  - id: check-added-large-files
8
8
  - id: check-yaml
9
- args: ["--unsafe"]
9
+ args:
10
+ - '--unsafe'
10
11
  - id: check-toml
11
12
  - id: end-of-file-fixer
12
13
  - id: trailing-whitespace
@@ -18,27 +19,34 @@ repos:
18
19
  - id: python-check-blanket-noqa
19
20
 
20
21
  - repo: https://github.com/astral-sh/ruff-pre-commit
21
- rev: v0.8.1
22
+ rev: v0.11.10
22
23
  hooks:
23
24
  - id: ruff
24
- args: [--fix, --exit-non-zero-on-fix]
25
+ args:
26
+ - '--fix'
27
+ - '--exit-non-zero-on-fix'
25
28
  - id: ruff-format
26
29
 
27
30
  - repo: https://github.com/adamchainz/blacken-docs
28
- rev: "1.19.1" # replace with latest tag on GitHub
31
+ rev: 1.19.1 # replace with latest tag on GitHub
29
32
  hooks:
30
33
  - id: blacken-docs
31
34
  additional_dependencies:
32
35
  - black==22.12.0
33
- args: ["--line-length=80", "--target-version=py310", "--skip-errors"]
36
+ args:
37
+ - '--line-length=80'
38
+ - '--target-version=py310'
39
+ - '--skip-errors'
34
40
 
35
41
  - repo: https://github.com/igorshubovych/markdownlint-cli
36
- rev: v0.43.0
42
+ rev: v0.44.0
37
43
  hooks:
38
44
  - id: markdownlint
39
- args: ["--disable", "MD013"]
45
+ args:
46
+ - '--disable'
47
+ - MD013
40
48
 
41
49
  - repo: https://github.com/astral-sh/uv-pre-commit
42
- rev: 0.6.5
50
+ rev: 0.7.5
43
51
  hooks:
44
52
  - id: uv-lock
@@ -5,6 +5,26 @@ Please follow [the Keep a Changelog standard](https://keepachangelog.com/en/1.0.
5
5
 
6
6
  ## [Unreleased]
7
7
 
8
+ ## [5.4.1]
9
+
10
+ ### Fixed
11
+
12
+ * Fixed import error in python 3.9 when using typing_extensions==3.14.0
13
+
14
+ ## [5.4.0]
15
+
16
+ ### Added
17
+
18
+ - `typing_inspection` dependency from pydantic team for complex isinstance checks that must be the same between `typing` and `typing_extensions`
19
+ - Support for `pydantic>=2.12.0` FieldInfo refactoring from https://github.com/pydantic/pydantic/pull/11898
20
+
21
+
22
+ ## [5.3.3]
23
+
24
+ ### Fixed
25
+
26
+ * Fixed pypi badge link in README
27
+
8
28
  ## [5.3.2]
9
29
 
10
30
  ### Fixed
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cadwyn
3
- Version: 5.3.2
3
+ Version: 5.4.1
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
@@ -37,9 +37,10 @@ Requires-Python: >=3.9
37
37
  Requires-Dist: backports-strenum<2,>=1.3.1; python_version < '3.11'
38
38
  Requires-Dist: fastapi>=0.112.4
39
39
  Requires-Dist: jinja2>=3.1.2
40
- Requires-Dist: pydantic>=2.0.0
40
+ Requires-Dist: pydantic>=2.11.0
41
41
  Requires-Dist: starlette>=0.30.0
42
42
  Requires-Dist: typing-extensions>=4.8.0
43
+ Requires-Dist: typing-inspection>=0.4.0
43
44
  Provides-Extra: standard
44
45
  Requires-Dist: fastapi[standard]>=0.112.3; extra == 'standard'
45
46
  Requires-Dist: typer>=0.7.0; extra == 'standard'
@@ -59,7 +60,7 @@ Production-ready community-driven modern [Stripe-like](https://stripe.com/blog/a
59
60
  <img src="https://img.shields.io/codecov/c/github/zmievsa/cadwyn?color=%2334D058&logo=codecov" alt="Coverage">
60
61
  </a>
61
62
  <a href="https://pypi.org/project/cadwyn/" target="_blank">
62
- <img alt="PyPI" src="https://img.shields.io/pypi/v/cadwyn?color=%2334D058&logo=pypi&label=PyPI package" alt="Package version">
63
+ <img alt="PyPI" src="https://img.shields.io/pypi/v/cadwyn?color=%2334D058&logo=pypi&label=PyPI" alt="Package version">
63
64
  </a>
64
65
  <a href="https://pypi.org/project/cadwyn/" target="_blank">
65
66
  <img src="https://img.shields.io/pypi/pyversions/cadwyn?color=%2334D058&logo=python" alt="Supported Python versions">
@@ -71,12 +72,12 @@ Production-ready community-driven modern [Stripe-like](https://stripe.com/blog/a
71
72
 
72
73
  ## Who is this for?
73
74
 
74
- Cadwyn allows you to maintain the implementation just for your newest API version and get all the older versions generated automatically. You keep API versioning encapsulated in small and independent "version change" modules while your business logic stays simple and knows nothing about versioning.
75
+ 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.
75
76
 
76
- Its [approach](https://docs.cadwyn.dev/theory/how_we_got_here/#ii-migration-based-response-building) will be useful if you want to:
77
+ This [approach](https://docs.cadwyn.dev/theory/how_we_got_here/#ii-migration-based-response-building) may be useful if you want to:
77
78
 
78
79
  1. Support many API versions for a long time
79
- 2. Effortlessly backport features and bugfixes to older API versions
80
+ 2. Have features and bugfixes automatically backported to older API versions
80
81
 
81
82
  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.
82
83
 
@@ -86,6 +87,4 @@ The [documentation](https://docs.cadwyn.dev) has everything you need to succeed.
86
87
 
87
88
  ## Sponsors
88
89
 
89
- 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!
90
-
91
- [![Monite](https://docs.cadwyn.dev/img/sponsor_logos/monite.png)](https://docs.monite.com/)
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!
@@ -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 package" alt="Package version">
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 maintain the implementation just for your newest API version and get all the older versions generated automatically. You keep API versioning encapsulated in small and independent "version change" modules while your business logic stays simple and knows nothing about versioning.
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
- Its [approach](https://docs.cadwyn.dev/theory/how_we_got_here/#ii-migration-based-response-building) will be useful if you want to:
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. Effortlessly backport features and bugfixes to older API versions
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
 
@@ -39,6 +39,4 @@ The [documentation](https://docs.cadwyn.dev) has everything you need to succeed.
39
39
 
40
40
  ## Sponsors
41
41
 
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
- [![Monite](https://docs.cadwyn.dev/img/sponsor_logos/monite.png)](https://docs.monite.com/)
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!
@@ -36,7 +36,7 @@ def version_callback(value: bool):
36
36
  def output_code(code: str, raw: bool):
37
37
  if raw:
38
38
  typer.echo(code)
39
- else:
39
+ else: # pragma: no cover
40
40
  _CONSOLE.print(Syntax(code, "python", line_numbers=True))
41
41
 
42
42
 
@@ -22,7 +22,7 @@ NoneType = type(None)
22
22
 
23
23
 
24
24
  # A parent type of typing._GenericAlias
25
- _BaseGenericAlias = cast(type, type(List[int])).mro()[1] # noqa: UP006
25
+ _BaseGenericAlias = cast("type", type(List[int])).mro()[1] # noqa: UP006
26
26
 
27
27
  # type(list[int]) and type(List[int]) are different which is why we have to do this.
28
28
  # Please note that this problem is much wider than just lists which is why we use typing._BaseGenericAlias
@@ -400,7 +400,7 @@ class Cadwyn(FastAPI):
400
400
  init_oauth=self.swagger_ui_init_oauth,
401
401
  swagger_ui_parameters=self.swagger_ui_parameters,
402
402
  )
403
- return self._render_docs_dashboard(req, cast(str, self.docs_url))
403
+ return self._render_docs_dashboard(req, cast("str", self.docs_url))
404
404
 
405
405
  async def redoc_dashboard(self, req: Request) -> Response:
406
406
  version = req.query_params.get("version")
@@ -410,7 +410,7 @@ class Cadwyn(FastAPI):
410
410
  openapi_url = root_path + f"{self.openapi_url}?version={version}"
411
411
  return get_redoc_html(openapi_url=openapi_url, title=f"{self.title} - ReDoc")
412
412
 
413
- return self._render_docs_dashboard(req, docs_url=cast(str, self.redoc_url))
413
+ return self._render_docs_dashboard(req, docs_url=cast("str", self.redoc_url))
414
414
 
415
415
  def _extract_root_path(self, req: Request):
416
416
  return req.scope.get("root_path", "").rstrip("/")
@@ -93,7 +93,7 @@ def _generate_changelog(versions: VersionBundle, router: _RootCadwynAPIRouter) -
93
93
  generator_from_newer_version,
94
94
  generator_from_older_version,
95
95
  schemas_from_older_version,
96
- cast(list[APIRoute], routes_from_newer_version),
96
+ cast("list[APIRoute]", routes_from_newer_version),
97
97
  )
98
98
  if changelog_entry is not None: # pragma: no branch # This should never happen
99
99
  version_change_changelog.instructions.append(CadwynVersionChangeInstruction(changelog_entry))
@@ -321,18 +321,18 @@ def _convert_version_change_instruction_to_changelog_entry( # noqa: C901
321
321
  if isinstance(instruction, EndpointDidntExistInstruction):
322
322
  return CadwynEndpointWasAddedChangelogEntry(
323
323
  path=instruction.endpoint_path,
324
- methods=cast(Any, instruction.endpoint_methods),
324
+ methods=cast("Any", instruction.endpoint_methods),
325
325
  )
326
326
  elif isinstance(instruction, EndpointExistedInstruction):
327
327
  return CadwynEndpointWasRemovedChangelogEntry(
328
328
  path=instruction.endpoint_path,
329
- methods=cast(Any, instruction.endpoint_methods),
329
+ methods=cast("Any", instruction.endpoint_methods),
330
330
  )
331
331
  elif isinstance(instruction, EndpointHadInstruction):
332
332
  if instruction.attributes.include_in_schema is not Sentinel:
333
333
  return CadwynEndpointWasRemovedChangelogEntry(
334
334
  path=instruction.endpoint_path,
335
- methods=cast(Any, instruction.endpoint_methods),
335
+ methods=cast("Any", instruction.endpoint_methods),
336
336
  )
337
337
 
338
338
  renaming_map = {"operation_id": "operationId"}
@@ -379,7 +379,7 @@ def _convert_version_change_instruction_to_changelog_entry( # noqa: C901
379
379
  attribute_changes.append(CadwynEndpointAttributeChange(name="responses", new_value=changed_responses))
380
380
  return CadwynEndpointHadChangelogEntry(
381
381
  path=instruction.endpoint_path,
382
- methods=cast(Any, instruction.endpoint_methods),
382
+ methods=cast("Any", instruction.endpoint_methods),
383
383
  changes=attribute_changes,
384
384
  )
385
385
 
@@ -78,7 +78,7 @@ def generate_versioned_routers(
78
78
  webhooks: Union[_WR, None] = None,
79
79
  ) -> GeneratedRouters[_R, _WR]:
80
80
  if webhooks is None:
81
- webhooks = cast(_WR, APIRouter())
81
+ webhooks = cast("_WR", APIRouter())
82
82
  return _EndpointTransformer(router, versions, webhooks).transform()
83
83
 
84
84
 
@@ -167,7 +167,7 @@ class _EndpointTransformer(Generic[_R, _WR]):
167
167
 
168
168
  # We know they are APIRoutes because of the check at the very beginning of the top loop.
169
169
  # I.e. Because head_route is an APIRoute, both routes are APIRoutes too
170
- older_route = cast(APIRoute, older_route)
170
+ older_route = cast("APIRoute", older_route)
171
171
  # Wait.. Why do we need this code again?
172
172
  if older_route.body_field is not None and _route_has_a_simple_body_schema(older_route):
173
173
  if hasattr(older_route.body_field.type_, "__cadwyn_original_model__"):
@@ -11,14 +11,20 @@ from collections.abc import Callable, Sequence
11
11
  from datetime import date
12
12
  from enum import Enum
13
13
  from functools import cache
14
- from typing import TYPE_CHECKING, Annotated, Generic, Union, cast
14
+ from typing import (
15
+ TYPE_CHECKING,
16
+ Annotated,
17
+ Generic,
18
+ Union,
19
+ _BaseGenericAlias, # pyright: ignore[reportAttributeAccessIssue]
20
+ cast,
21
+ )
15
22
 
16
23
  import fastapi.params
17
24
  import fastapi.security.base
18
25
  import fastapi.utils
19
26
  import pydantic
20
27
  import pydantic._internal._decorators
21
- import typing_extensions
22
28
  from fastapi import Response
23
29
  from fastapi.dependencies.utils import is_async_gen_callable, is_coroutine_callable, is_gen_callable
24
30
  from fastapi.routing import APIRoute
@@ -32,12 +38,12 @@ from pydantic._internal._decorators import (
32
38
  RootValidatorDecoratorInfo,
33
39
  ValidatorDecoratorInfo,
34
40
  )
41
+ from pydantic._internal._known_annotated_metadata import collect_known_metadata
35
42
  from pydantic._internal._typing_extra import try_eval_type as pydantic_try_eval_type
36
43
  from pydantic.fields import ComputedFieldInfo, FieldInfo
37
44
  from typing_extensions import (
38
45
  Any,
39
46
  Doc,
40
- NewType,
41
47
  Self,
42
48
  TypeAlias,
43
49
  TypeAliasType,
@@ -80,11 +86,6 @@ if TYPE_CHECKING:
80
86
  from cadwyn.structure.versions import HeadVersion, Version, VersionBundle
81
87
 
82
88
 
83
- if sys.version_info >= (3, 10):
84
- from typing import _BaseGenericAlias # pyright: ignore[reportAttributeAccessIssue]
85
- else:
86
- from typing_extensions import _BaseGenericAlias # pyright: ignore[reportAttributeAccessIssue]
87
-
88
89
  _Call = TypeVar("_Call", bound=Callable[..., Any])
89
90
 
90
91
  _FieldName: TypeAlias = str
@@ -153,16 +154,12 @@ class PydanticFieldWrapper:
153
154
  )
154
155
 
155
156
 
156
- def _extract_passed_field_attributes(field_info: FieldInfo):
157
- attributes = {
158
- attr_name: field_info._attributes_set[attr_name]
159
- for attr_name in _all_field_arg_names
160
- if attr_name in field_info._attributes_set
157
+ def _extract_passed_field_attributes(field_info: FieldInfo) -> dict[str, object]:
158
+ return {
159
+ k: v
160
+ for k, v in (field_info._attributes_set | collect_known_metadata(field_info.metadata)[0]).items()
161
+ if k in _all_field_arg_names and not (k == "frozen" and v is None)
161
162
  }
162
- # PydanticV2 always adds frozen to _attributes_set but we don't want it if it wasn't explicitly set
163
- if attributes.get("frozen", ...) is None:
164
- attributes.pop("frozen")
165
- return attributes
166
163
 
167
164
 
168
165
  @dataclasses.dataclass(**DATACLASS_SLOTS)
@@ -265,7 +262,7 @@ def _wrap_pydantic_model(model: type[_T_PYDANTIC_MODEL]) -> "_PydanticModelWrapp
265
262
  # For example, when "from __future__ import annotations" is used in the file with the schema
266
263
  if model is not BaseModel:
267
264
  model.model_rebuild(raise_errors=False)
268
- model = cast(type[_T_PYDANTIC_MODEL], model)
265
+ model = cast("type[_T_PYDANTIC_MODEL]", model)
269
266
 
270
267
  decorators = _get_model_decorators(model)
271
268
  validators = {}
@@ -345,7 +342,7 @@ def _wrap_pydantic_model(model: type[_T_PYDANTIC_MODEL]) -> "_PydanticModelWrapp
345
342
  def _get_field_and_validator_names_from_model(cls: type) -> tuple[set[_FieldName], set[str]]:
346
343
  fields = cls.model_fields
347
344
  source = inspect.getsource(cls)
348
- cls_ast = cast(ast.ClassDef, ast.parse(textwrap.dedent(source)).body[0])
345
+ cls_ast = cast("ast.ClassDef", ast.parse(textwrap.dedent(source)).body[0])
349
346
  validator_names = (
350
347
  _get_validator_info_or_none(node)
351
348
  for node in cls_ast.body
@@ -468,7 +465,7 @@ class _PydanticModelWrapper(Generic[_T_PYDANTIC_MODEL]):
468
465
  fields = {name: field.generate_field_copy(generator) for name, field in self.fields.items()}
469
466
  model_copy = type(self.cls)(
470
467
  self.name,
471
- tuple(generator[cast(type[BaseModel], base)] for base in self.cls.__bases__),
468
+ tuple(generator[cast("type[BaseModel]", base)] for base in self.cls.__bases__),
472
469
  self.other_attributes
473
470
  | per_field_validators
474
471
  | root_validators
@@ -514,7 +511,7 @@ class _CallableWrapper:
514
511
  return hash(self._original_callable)
515
512
 
516
513
  def __eq__(self, value: object) -> bool:
517
- return self._original_callable == value # pyright: ignore[reportUnnecessaryComparison]
514
+ return self._original_callable == value
518
515
 
519
516
 
520
517
  class _AsyncCallableWrapper(_CallableWrapper):
@@ -587,9 +584,11 @@ class _AnnotationTransformer:
587
584
  self._remake_endpoint_dependencies(route)
588
585
 
589
586
  def _change_version_of_a_non_container_annotation(self, annotation: Any) -> Any:
590
- if isinstance(annotation, (_BaseGenericAlias, types.GenericAlias)):
587
+ from typing_inspection.typing_objects import is_any, is_newtype, is_typealiastype
588
+
589
+ if isinstance(annotation, (types.GenericAlias, _BaseGenericAlias)):
591
590
  return get_origin(annotation)[tuple(self.change_version_of_annotation(arg) for arg in get_args(annotation))]
592
- elif isinstance(annotation, TypeAliasType):
591
+ elif is_typealiastype(annotation):
593
592
  if (
594
593
  annotation.__module__ is not None and (annotation.__module__.startswith("pydantic."))
595
594
  ) or annotation.__name__ in _PYDANTIC_ALL_EXPORTED_NAMES:
@@ -616,7 +615,7 @@ class _AnnotationTransformer:
616
615
  return getitem(
617
616
  tuple(self.change_version_of_annotation(a) for a in get_args(annotation)),
618
617
  )
619
- elif annotation is typing.Any or annotation is typing_extensions.Any or isinstance(annotation, NewType):
618
+ elif is_any(annotation) or is_newtype(annotation):
620
619
  return annotation
621
620
  elif isinstance(annotation, type):
622
621
  return self._change_version_of_type(annotation)
@@ -776,7 +775,7 @@ class SchemaGenerator:
776
775
  wrapper = self._get_wrapper_for_model(model)
777
776
  model_copy = wrapper.generate_model_copy(self)
778
777
  self.concrete_models[model] = model_copy
779
- return cast(type[_T_ANY_MODEL], model_copy)
778
+ return cast("type[_T_ANY_MODEL]", model_copy)
780
779
 
781
780
  @overload
782
781
  def _get_wrapper_for_model(self, model: type[BaseModel]) -> "_PydanticModelWrapper[BaseModel]": ...
@@ -865,7 +864,7 @@ def _apply_alter_schema_instructions(
865
864
  elif isinstance(alter_schema_instruction, ValidatorExistedInstruction):
866
865
  validator_name = get_name_of_function_wrapped_in_pydantic_validator(alter_schema_instruction.validator)
867
866
  raw_validator = cast(
868
- pydantic._internal._decorators.PydanticDescriptorProxy, alter_schema_instruction.validator
867
+ "pydantic._internal._decorators.PydanticDescriptorProxy", alter_schema_instruction.validator
869
868
  )
870
869
  schema_info.validators[validator_name] = _wrap_validator(
871
870
  raw_validator.wrapped,
@@ -1041,15 +1040,19 @@ def _delete_field_attributes(
1041
1040
  annotation: Any,
1042
1041
  ) -> None:
1043
1042
  for attr_name in alter_schema_instruction.attributes:
1043
+ deleted = False
1044
+
1044
1045
  if attr_name in field.passed_field_attributes:
1045
1046
  field.delete_attribute(name=attr_name)
1046
- elif get_origin(annotation) == Annotated and any( # pragma: no branch
1047
+ deleted = True
1048
+ if get_origin(annotation) == Annotated and any( # pragma: no branch
1047
1049
  hasattr(sub_ann, attr_name) for sub_ann in get_args(annotation)
1048
1050
  ):
1049
1051
  for sub_ann in get_args(annotation):
1050
1052
  if hasattr(sub_ann, attr_name):
1051
1053
  object.__setattr__(sub_ann, attr_name, None)
1052
- else:
1054
+ deleted = True
1055
+ if not deleted:
1053
1056
  raise InvalidGenerationInstructionError(
1054
1057
  f'You tried to delete the attribute "{attr_name}" of field "{alter_schema_instruction.name}" '
1055
1058
  f'from "{model.name}" in "{version_change_name}" '
@@ -1100,7 +1103,7 @@ class _EnumWrapper(Generic[_T_ENUM]):
1100
1103
  for attr_name, attr in initialization_namespace.items():
1101
1104
  enum_dict[attr_name] = attr
1102
1105
  enum_dict["__doc__"] = self.cls.__doc__
1103
- model_copy = cast(type[_T_ENUM], type(self.name, self.cls.__bases__, enum_dict))
1106
+ model_copy = cast("type[_T_ENUM]", type(self.name, self.cls.__bases__, enum_dict))
1104
1107
  model_copy.__cadwyn_original_model__ = self.cls # pyright: ignore[reportAttributeAccessIssue]
1105
1108
  return model_copy
1106
1109
 
@@ -140,7 +140,7 @@ def convert_request_to_next_version_for(
140
140
  if isinstance(schema_or_path, str):
141
141
  return _AlterRequestByPathInstruction(
142
142
  path=schema_or_path,
143
- methods=set(cast(list, methods_or_second_schema)),
143
+ methods=set(cast("list", methods_or_second_schema)),
144
144
  transformer=transformer,
145
145
  )
146
146
  else:
@@ -214,7 +214,7 @@ def convert_response_to_previous_version_for(
214
214
  # The validation above checks that methods is not None
215
215
  return _AlterResponseByPathInstruction(
216
216
  path=schema_or_path,
217
- methods=set(cast(list, methods_or_second_schema)),
217
+ methods=set(cast("list", methods_or_second_schema)),
218
218
  transformer=transformer,
219
219
  migrate_http_errors=migrate_http_errors,
220
220
  )
@@ -246,7 +246,7 @@ class AlterFieldInstructionFactory:
246
246
  info: Union[FieldInfo, Any, None] = None,
247
247
  ) -> FieldExistedAsInstruction:
248
248
  if info is None:
249
- info = cast(FieldInfo, Field())
249
+ info = cast("FieldInfo", Field())
250
250
  info.annotation = type
251
251
  return FieldExistedAsInstruction(is_hidden_from_changelog=False, schema=self.schema, name=self.name, field=info)
252
252
 
@@ -317,7 +317,7 @@ class AlterSchemaInstructionFactory:
317
317
  def validator(
318
318
  self, func: "Union[Callable[..., Any], classmethod[Any, Any, Any], PydanticDescriptorProxy]", /
319
319
  ) -> AlterValidatorInstructionFactory:
320
- func = cast(Union[Callable[..., Any], PydanticDescriptorProxy], unwrap_wrapped_function(func))
320
+ func = cast("Union[Callable[..., Any], PydanticDescriptorProxy]", unwrap_wrapped_function(func))
321
321
 
322
322
  if not isinstance(func, PydanticDescriptorProxy):
323
323
  if hasattr(func, "__self__"):
@@ -620,7 +620,7 @@ class VersionBundle:
620
620
  detail = response_info.body
621
621
  if detail is None:
622
622
  detail = http.HTTPStatus(response_info.status_code).phrase
623
- raised_exception.detail = cast(str, detail)
623
+ raised_exception.detail = cast("str", detail)
624
624
  raised_exception.headers = dict(response_info.headers)
625
625
  raised_exception.status_code = response_info.status_code
626
626
 
@@ -408,6 +408,31 @@ print(BulkCreateUsersRequestBody is BulkCreateUsersResponseBody) # False
408
408
 
409
409
  or to specify migrations using [endpoint path](#path-based-migration-specification) instead of a schema.
410
410
 
411
+ ## Dependency re-execution warning
412
+
413
+ Notice that whenever a request comes to Cadwyn, we first validate it against the request's version of the schema, then we migrate it to the latest version, and then validate again to prevent migrations from creating invalid requests.
414
+
415
+ This means that if you have a dependency that is executed during the request validation, **it will be executed twice**. For example, if you have a dependency that checks whether a user exists in the database, it will be executed twice. This is not a problem if the dependency is idempotent but it is a problem if it is not.
416
+
417
+ To solve this problem, you can use the `cadwyn.current_dependency_solver` dependency which tell you whether your dependency is getting called before or after the request is migrated. 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"`.
418
+
419
+ ```python
420
+ from cadwyn import current_dependency_solver
421
+
422
+
423
+ def my_dependency(
424
+ dependency_solver: Annotated[
425
+ Literal["fastapi", "cadwyn"], Depends(current_dependency_solver)
426
+ ]
427
+ ):
428
+ if dependency_solver == "fastapi": # Before migration
429
+ ...
430
+ else: # After migration
431
+ ...
432
+ ```
433
+
434
+ but the majority of your dependencies will not need this as most dependencies should not have side effects or network calls within them.
435
+
411
436
  ## Version changes with side effects
412
437
 
413
438
  Sometimes you will use API versioning to handle a breaking change in your **business logic**, not in the schemas themselves. In such cases, it is tempting to add a version check and just follow the new business logic such as:
@@ -83,7 +83,8 @@ Let's say that we had a nullable `middle_name` field but we decided that it does
83
83
  schema(BaseUser)
84
84
  .field("middle_name")
85
85
  .existed_as(
86
- type=str | None, description="User's Middle Name", default=None
86
+ type=str | None,
87
+ info=Field(description="User's Middle Name", default=None),
87
88
  ),
88
89
  )
89
90
  ```
@@ -0,0 +1 @@
1
+ <svg clip-rule="evenodd" fill-rule="evenodd" height="104.996mm" image-rendering="optimizeQuality" shape-rendering="geometricPrecision" text-rendering="geometricPrecision" viewBox="0 0 2410.37 2560.05" width="108.373mm" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><linearGradient id="a" gradientUnits="objectBoundingBox" x1="50%" x2="50%" y1="100%" y2="0%"><stop offset="0" stop-color="#5a1ee2"/><stop offset="1" stop-color="#9f52ee"/></linearGradient><linearGradient id="b" gradientUnits="userSpaceOnUse" x1="1279.45" x2="1826.35" y1="1276.73" y2="1018.32"><stop offset="0" stop-color="#8740ea"/><stop offset="1" stop-color="#e791ff"/></linearGradient><path d="m0 0h2410.38v2560.05h-2410.38z" fill="none"/><g fill-rule="nonzero"><path d="m1246.08 741.76c-188.54 0-359.22 76.41-482.76 199.96-123.54 123.54-199.96 294.22-199.96 482.76s76.41 359.23 199.96 482.77c123.54 123.54 294.22 199.96 482.76 199.96s359.23-76.41 482.77-199.96c19.07-19.07 37.03-39.27 53.75-60.49 9.08-11.53 25.65-13.82 37.52-5.19l88.47 64.28c6.22 4.52 9.92 10.68 11 18.29s-.78 14.56-5.51 20.62c-21.48 27.55-44.64 53.74-69.31 78.41-153.22 153.22-364.9 247.99-598.68 247.99-233.79 0-445.46-94.77-598.68-247.99s-247.99-364.9-247.99-598.68c0-233.79 94.77-445.46 247.99-598.68s364.89-247.99 598.68-247.99c233.02 0 444.07 94.16 597.18 246.5l-141.94 91.37c-120.79-108.14-280.33-173.91-455.23-173.91z" fill="url(#a)"/><path d="m609.17 397.48 169.83 432.05-50.81 19.85-169.83-432.05z" fill="#974ced"/><path d="m1241.57 1320.13 556.05-431.46 66.61 86.25-556.05 431.47z" fill="url(#b)"/><path d="m463.33 1349.37 993.64 598.21-56.35 93.51-993.64-598.21z" fill="url(#a)"/><path d="m1407.66 1977.15c97.66-120.17 197.41-214.12 299.23-281.82 102.94-68.46 208.08-110.16 315.38-125.11l7.48 54.01c-99.04 13.8-196.64 52.66-292.75 116.58-97.25 64.66-192.95 154.92-287.06 270.72l-42.27-34.38z" fill="#884bd4"/></g><path d="m583.76 288.89c65.46 0 118.52 53.06 118.52 118.52s-53.06 118.52-118.52 118.52-118.52-53.06-118.52-118.52 53.06-118.52 118.52-118.52z" fill="#974ced"/><path d="m1830.93 669.87c144.66 0 261.92 117.27 261.92 261.92 0 144.66-117.27 261.92-261.92 261.92-144.66 0-261.92-117.27-261.92-261.92 0-144.66 117.27-261.92 261.92-261.92z" fill="#e791ff"/><path d="m1428.79 1846.58c81.61 0 147.76 66.16 147.76 147.76 0 81.61-66.16 147.76-147.76 147.76-81.61 0-147.76-66.16-147.76-147.76 0-81.61 66.16-147.76 147.76-147.76z" fill="#e791ff"/><path d="m2026.01 1484.86c62.06 0 112.36 50.31 112.36 112.36 0 62.06-50.31 112.36-112.36 112.36-62.06 0-112.36-50.31-112.36-112.36 0-62.06 50.31-112.36 112.36-112.36z" fill="#e791ff"/><path d="m435.16 1232.96c90.11 0 163.16 73.05 163.16 163.16s-73.05 163.16-163.16 163.16-163.16-73.05-163.16-163.16 73.05-163.16 163.16-163.16z" fill="#e791ff"/><path d="m1274.87 1267.83c52.7 0 95.43 42.73 95.43 95.43s-42.73 95.43-95.43 95.43-95.43-42.73-95.43-95.43 42.73-95.43 95.43-95.43z" fill="#8740ea"/></svg>
@@ -0,0 +1 @@
1
+ <svg clip-rule="evenodd" fill-rule="evenodd" height="104.996mm" image-rendering="optimizeQuality" shape-rendering="geometricPrecision" text-rendering="geometricPrecision" viewBox="0 0 14313.61 3866.19" width="108.373mm" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><linearGradient id="a" gradientUnits="objectBoundingBox" x1="50%" x2="50%" y1="100%" y2="0%"><stop offset="0" stop-color="#5a1ee2"/><stop offset="1" stop-color="#9f52ee"/></linearGradient><linearGradient id="b" gradientUnits="userSpaceOnUse" x1="1903.41" x2="2936.67" y1="1866.35" y2="1378.14"><stop offset="0" stop-color="#8740ea"/><stop offset="1" stop-color="#e791ff"/></linearGradient><g fill-rule="nonzero"><path d="m1840.35 855.62c-356.21 0-678.69 144.37-912.09 377.78-233.41 233.41-377.78 555.88-377.78 912.09s144.37 678.7 377.78 912.11 555.88 377.78 912.09 377.78 678.7-144.37 912.11-377.78c36.04-36.04 69.97-74.2 101.55-114.28 17.16-21.78 48.47-26.11 70.9-9.81l167.14 121.44c11.75 8.54 18.75 20.18 20.77 34.56 2.03 14.38-1.48 27.51-10.41 38.96-40.59 52.05-84.34 101.53-130.95 148.14-289.49 289.49-689.41 468.54-1131.11 468.54-441.71 0-841.61-179.05-1131.1-468.54s-468.54-689.41-468.54-1131.11c0-441.71 179.05-841.61 468.54-1131.1s689.39-468.54 1131.1-468.54c440.25 0 839 177.9 1128.26 465.72l-268.17 172.62c-228.21-204.31-529.64-328.58-860.09-328.58z" fill="url(#a)"/><path d="m637.02 205.17 320.87 816.28-95.99 37.5-320.86-816.28z" fill="#974ced"/><path d="m1831.83 1948.35 1050.57-815.18 125.85 162.96-1050.57 815.18z" fill="url(#b)"/><path d="m361.5 2003.59 1877.3 1130.22-106.48 176.67-1877.3-1130.22z" fill="url(#a)"/><path d="m2145.63 3189.67c184.51-227.04 372.98-404.54 565.34-532.45 194.49-129.34 393.12-208.13 595.86-236.38l14.13 102.04c-187.12 26.07-371.51 99.5-553.11 220.25-183.73 122.16-364.54 292.69-542.36 511.49z" fill="#884bd4"/></g><path d="m589.03 0c123.67 0 223.92 100.25 223.92 223.92s-100.25 223.92-223.92 223.92-223.92-100.25-223.92-223.92 100.25-223.92 223.92-223.92z" fill="#974ced"/><g fill="#e791ff"><path d="m2945.33 719.79c273.31 0 494.86 221.55 494.86 494.86s-221.55 494.86-494.86 494.86-494.86-221.55-494.86-494.86 221.55-494.86 494.86-494.86z"/><path d="m2185.56 2942.97c154.18 0 279.17 124.99 279.17 279.17s-124.99 279.17-279.17 279.17-279.17-124.99-279.17-279.17 124.99-279.17 279.17-279.17z"/><path d="m3313.89 2259.57c117.25 0 212.29 95.05 212.29 212.29 0 117.25-95.05 212.29-212.29 212.29-117.25 0-212.29-95.05-212.29-212.29 0-117.25 95.05-212.29 212.29-212.29z"/><path d="m308.26 1783.66c170.25 0 308.26 138.01 308.26 308.26s-138.01 308.26-308.26 308.26-308.26-138.01-308.26-308.26 138.01-308.26 308.26-308.26z"/></g><path d="m1894.75 1849.54c99.57 0 180.29 80.72 180.29 180.29s-80.72 180.29-180.29 180.29-180.29-80.72-180.29-180.29 80.72-180.29 180.29-180.29z" fill="#8740ea"/><path d="m4640.58 3233.75c173.84 0 329.7-59.95 443.61-155.86v125.89h341.69v-1519.65h-341.69v125.89c-113.9-95.91-269.76-155.86-443.61-155.86-452.6 0-785.31 344.7-785.31 791.3 0 443.61 332.71 788.3 785.31 788.3zm0-338.7c-263.77 0-443.61-191.83-443.61-449.6 0-260.77 179.84-452.6 443.61-452.6s443.61 191.83 443.61 452.6c0 257.78-179.84 449.6-443.61 449.6zm1182.6-452.6c0 446.6 332.71 791.3 785.31 791.3 173.84 0 329.7-59.95 443.61-155.86v125.89h341.69v-2098.14h-341.69v704.38c-113.9-95.91-269.76-155.86-443.61-155.86-452.6 0-785.31 344.7-785.31 788.3zm338.7 0c0-260.77 179.84-449.6 446.61-449.6 266.76 0 443.61 188.83 443.61 449.6s-179.84 452.6-443.61 452.6-446.61-191.83-446.61-452.6zm2903.08 155.86 287.74 605.46h257.78l725.35-1519.65h-374.66l-482.57 1001.11-284.75-608.46h-260.76l-284.75 608.46-479.58-1001.11h-377.67l728.35 1519.65h254.78zm3382.65-914.19h-377.67l-479.57 1013.1-479.58-1013.1h-377.67l668.41 1405.75-368.67 776.31h374.66l1040.08-2182.06zm735.99 761.32c0-275.75 143.88-452.6 395.65-452.6 251.78 0 392.65 177.05 392.65 452.6v758.33h341.7v-758.33c0-461.59-290.75-791.3-734.35-791.3-164.86 0-296.73 53.95-395.65 134.88v-104.91h-338.7v1519.65h338.7v-758.33z" fill="#fff" fill-rule="nonzero"/></svg>
@@ -0,0 +1 @@
1
+ <svg clip-rule="evenodd" fill-rule="evenodd" height="104.996mm" image-rendering="optimizeQuality" shape-rendering="geometricPrecision" text-rendering="geometricPrecision" viewBox="0 0 13833 4217.33" width="108.373mm" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><linearGradient id="a" gradientUnits="objectBoundingBox" x1="50%" x2="50%" y1="100%" y2="0%"><stop offset="0" stop-color="#5a1ee2"/><stop offset="1" stop-color="#9f52ee"/></linearGradient><linearGradient id="b" gradientUnits="userSpaceOnUse" x1="2346.93" x2="3249.83" y1="2002.05" y2="1575.43"><stop offset="0" stop-color="#8740ea"/><stop offset="1" stop-color="#e791ff"/></linearGradient><path d="m0-.01h13833.01v4217.33h-13833.01z" fill="#060320"/><g fill-rule="nonzero"><path d="m2291.83 1118.85c-311.27 0-593.06 126.16-797.01 330.11-203.96 203.96-330.11 485.75-330.11 797.01 0 311.27 126.16 593.06 330.11 797.02 203.96 203.96 485.75 330.11 797.01 330.11 311.27 0 593.06-126.16 797.02-330.11 31.49-31.49 61.14-64.84 88.74-99.86 15-19.03 42.35-22.82 61.95-8.57l146.05 106.12c10.27 7.46 16.39 17.63 18.15 30.2 1.78 12.57-1.29 24.04-9.09 34.04-35.47 45.48-73.7 88.72-114.43 129.45-252.96 252.96-602.43 409.42-988.4 409.42s-735.43-156.46-988.39-409.42-409.42-602.43-409.42-988.4 156.46-735.43 409.42-988.39 602.41-409.42 988.39-409.42c384.7 0 733.14 155.45 985.91 406.96l-234.34 150.84c-199.42-178.53-462.81-287.12-751.57-287.12z" fill="url(#a)"/><path d="m1240.33 550.46 280.38 713.29-83.87 32.77-280.39-713.29z" fill="#974ced"/><path d="m2284.39 2073.71 918.01-712.33 109.97 142.39-918.01 712.33z" fill="url(#b)"/><path d="m999.57 2121.97 1640.44 987.62-93.04 154.38-1640.45-987.62z" fill="url(#a)"/><path d="m2558.6 3158.4c161.23-198.39 325.92-353.5 494.01-465.27 169.95-113.02 343.52-181.87 520.68-206.56l12.34 89.16c-163.51 22.78-324.64 86.94-483.32 192.46-160.55 106.75-318.55 255.76-473.93 446.95l-69.78-56.75z" fill="#884bd4"/></g><path d="m1198.39 371.18c108.07 0 195.67 87.6 195.67 195.67s-87.6 195.67-195.67 195.67-195.67-87.6-195.67-195.67 87.6-195.67 195.67-195.67z" fill="#974ced"/><g fill="#e791ff"><path d="m3257.39 1000.15c238.82 0 432.42 193.6 432.42 432.42s-193.6 432.42-432.42 432.42-432.42-193.6-432.42-432.42 193.6-432.42 432.42-432.42z"/><path d="m2593.49 2942.83c134.73 0 243.95 109.22 243.95 243.95s-109.22 243.95-243.95 243.95-243.95-109.22-243.95-243.95 109.22-243.95 243.95-243.95z"/><path d="m3579.46 2345.65c102.45 0 185.51 83.05 185.51 185.51 0 102.45-83.05 185.51-185.51 185.51-102.45 0-185.51-83.05-185.51-185.51 0-102.45 83.05-185.51 185.51-185.51z"/><path d="m953.04 1929.79c148.77 0 269.36 120.6 269.36 269.36 0 148.77-120.6 269.36-269.36 269.36-148.77 0-269.36-120.6-269.36-269.36 0-148.77 120.6-269.36 269.36-269.36z"/></g><path d="m2339.37 1987.36c87.01 0 157.55 70.54 157.55 157.55s-70.54 157.55-157.55 157.55-157.55-70.54-157.55-157.55 70.54-157.55 157.55-157.55z" fill="#8740ea"/><path d="m4738.75 3196.92c151.91 0 288.11-52.39 387.63-136.2v110.01h298.58v-1327.91h-298.58v110.01c-99.53-83.81-235.73-136.2-387.63-136.2-395.49 0-686.22 301.21-686.22 691.46 0 387.63 290.73 688.84 686.22 688.84zm0-295.96c-230.49 0-387.63-167.62-387.63-392.88 0-227.87 157.15-395.49 387.63-395.49 230.49 0 387.63 167.62 387.63 395.49 0 225.25-157.15 392.88-387.63 392.88zm1033.39-395.49c0 390.25 290.73 691.46 686.22 691.46 151.91 0 288.11-52.39 387.63-136.2v110.01h298.58v-1833.41h-298.58v615.5c-99.53-83.81-235.73-136.2-387.63-136.2-395.49 0-686.22 301.21-686.22 688.84zm295.96 0c0-227.87 157.15-392.88 390.26-392.88 233.1 0 387.63 165.01 387.63 392.88s-157.15 395.49-387.63 395.49c-230.49 0-390.26-167.62-390.26-395.49zm2536.8 136.2 251.44 529.07h225.25l633.83-1327.91h-327.39l-421.69 874.8-248.82-531.69h-227.86l-248.82 531.69-419.07-874.8h-330.02l636.45 1327.91h222.64l254.05-529.07zm2955.86-798.85h-330.02l-419.06 885.28-419.07-885.28h-330.02l584.08 1228.38-322.16 678.37h327.39l908.85-1906.75zm643.13 665.26c0-240.96 125.72-395.49 345.73-395.49s343.11 154.71 343.11 395.49v662.65h298.59v-662.65c0-403.35-254.06-691.46-641.7-691.46-144.06 0-259.3 47.14-345.73 117.86v-91.67h-295.96v1327.91h295.96v-662.65z" fill="#fff" fill-rule="nonzero"/></svg>
@@ -36,9 +36,3 @@ Whether you are a newbie in API versioning, a pro looking for a sophisticated to
36
36
  ## Get started
37
37
 
38
38
  It is recommended to read the [quickstart tutorial](https://docs.cadwyn.dev/quickstart/setup/) first to get your feet wet with Cadwyn's approach
39
-
40
- ## Sponsors
41
-
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
- [![Monite](./img/sponsor_logos/monite.png)](https://docs.monite.com/)
@@ -0,0 +1,12 @@
1
+ .md-header__button.md-logo {
2
+ margin-top: 0
3
+ margin-bottom: 0;
4
+ padding-top: 0;
5
+ padding-bottom: 0;
6
+ }
7
+
8
+ .md-header__button.md-logo img,
9
+ .md-header__button.md-logo svg {
10
+ height: 2.4rem;
11
+ width: 2.4rem;
12
+ }
@@ -11,6 +11,9 @@ plugins:
11
11
  hooks:
12
12
  on_pre_build: "docs.plugin:on_pre_build"
13
13
 
14
+ extra_css:
15
+ - stylesheets/extra.css
16
+
14
17
  markdown_extensions:
15
18
  toc:
16
19
  permalink: true
@@ -41,8 +44,12 @@ markdown_extensions:
41
44
  md_in_html: null
42
45
  mdx_include:
43
46
  markdown_include_variants:
47
+
44
48
  theme:
45
49
  name: "material"
50
+ logo: img/logos/cadwyn_icon_transparent.svg
51
+ favicon: img/logos/cadwyn_icon_transparent.svg
52
+
46
53
  features:
47
54
  - content.code.annotate
48
55
  - content.code.copy