cadwyn 4.4.1__tar.gz → 4.4.3__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 (134) hide show
  1. {cadwyn-4.4.1 → cadwyn-4.4.3}/CHANGELOG.md +18 -0
  2. {cadwyn-4.4.1 → cadwyn-4.4.3}/Makefile +1 -1
  3. {cadwyn-4.4.1 → cadwyn-4.4.3}/PKG-INFO +2 -1
  4. {cadwyn-4.4.1 → cadwyn-4.4.3}/cadwyn/route_generation.py +26 -6
  5. {cadwyn-4.4.1 → cadwyn-4.4.3}/cadwyn/schema_generation.py +20 -7
  6. {cadwyn-4.4.1 → cadwyn-4.4.3}/pyproject.toml +12 -11
  7. cadwyn-4.4.3/tests/test_auth_dependencies.py +67 -0
  8. {cadwyn-4.4.1 → cadwyn-4.4.3}/uv.lock +50 -50
  9. {cadwyn-4.4.1 → cadwyn-4.4.3}/.github/CODE_OF_CONDUCT.md +0 -0
  10. {cadwyn-4.4.1 → cadwyn-4.4.3}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  11. {cadwyn-4.4.1 → cadwyn-4.4.3}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  12. {cadwyn-4.4.1 → cadwyn-4.4.3}/.github/actions/setup-python-uv/action.yaml +0 -0
  13. {cadwyn-4.4.1 → cadwyn-4.4.3}/.github/workflows/ci.yaml +0 -0
  14. {cadwyn-4.4.1 → cadwyn-4.4.3}/.github/workflows/daily_tests.yaml +0 -0
  15. {cadwyn-4.4.1 → cadwyn-4.4.3}/.github/workflows/publish_docs.yaml +0 -0
  16. {cadwyn-4.4.1 → cadwyn-4.4.3}/.github/workflows/release.yaml +0 -0
  17. {cadwyn-4.4.1 → cadwyn-4.4.3}/.github/workflows/validate_links.yaml +0 -0
  18. {cadwyn-4.4.1 → cadwyn-4.4.3}/.gitignore +0 -0
  19. {cadwyn-4.4.1 → cadwyn-4.4.3}/.pre-commit-config.yaml +0 -0
  20. {cadwyn-4.4.1 → cadwyn-4.4.3}/LICENSE +0 -0
  21. {cadwyn-4.4.1 → cadwyn-4.4.3}/README.md +0 -0
  22. {cadwyn-4.4.1 → cadwyn-4.4.3}/cadwyn/__init__.py +0 -0
  23. {cadwyn-4.4.1 → cadwyn-4.4.3}/cadwyn/__main__.py +0 -0
  24. {cadwyn-4.4.1 → cadwyn-4.4.3}/cadwyn/_asts.py +0 -0
  25. {cadwyn-4.4.1 → cadwyn-4.4.3}/cadwyn/_importer.py +0 -0
  26. {cadwyn-4.4.1 → cadwyn-4.4.3}/cadwyn/_render.py +0 -0
  27. {cadwyn-4.4.1 → cadwyn-4.4.3}/cadwyn/_utils.py +0 -0
  28. {cadwyn-4.4.1 → cadwyn-4.4.3}/cadwyn/applications.py +0 -0
  29. {cadwyn-4.4.1 → cadwyn-4.4.3}/cadwyn/changelogs.py +0 -0
  30. {cadwyn-4.4.1 → cadwyn-4.4.3}/cadwyn/exceptions.py +0 -0
  31. {cadwyn-4.4.1 → cadwyn-4.4.3}/cadwyn/middleware.py +0 -0
  32. {cadwyn-4.4.1 → cadwyn-4.4.3}/cadwyn/py.typed +0 -0
  33. {cadwyn-4.4.1 → cadwyn-4.4.3}/cadwyn/routing.py +0 -0
  34. {cadwyn-4.4.1 → cadwyn-4.4.3}/cadwyn/static/__init__.py +0 -0
  35. {cadwyn-4.4.1 → cadwyn-4.4.3}/cadwyn/static/docs.html +0 -0
  36. {cadwyn-4.4.1 → cadwyn-4.4.3}/cadwyn/structure/__init__.py +0 -0
  37. {cadwyn-4.4.1 → cadwyn-4.4.3}/cadwyn/structure/common.py +0 -0
  38. {cadwyn-4.4.1 → cadwyn-4.4.3}/cadwyn/structure/data.py +0 -0
  39. {cadwyn-4.4.1 → cadwyn-4.4.3}/cadwyn/structure/endpoints.py +0 -0
  40. {cadwyn-4.4.1 → cadwyn-4.4.3}/cadwyn/structure/enums.py +0 -0
  41. {cadwyn-4.4.1 → cadwyn-4.4.3}/cadwyn/structure/schemas.py +0 -0
  42. {cadwyn-4.4.1 → cadwyn-4.4.3}/cadwyn/structure/versions.py +0 -0
  43. {cadwyn-4.4.1 → cadwyn-4.4.3}/docs/CNAME +0 -0
  44. {cadwyn-4.4.1 → cadwyn-4.4.3}/docs/__init__.py +0 -0
  45. {cadwyn-4.4.1 → cadwyn-4.4.3}/docs/concepts/api_version_header_and_context_variables.md +0 -0
  46. {cadwyn-4.4.1 → cadwyn-4.4.3}/docs/concepts/beware_of_data_versioning.md +0 -0
  47. {cadwyn-4.4.1 → cadwyn-4.4.3}/docs/concepts/changelogs.md +0 -0
  48. {cadwyn-4.4.1 → cadwyn-4.4.3}/docs/concepts/cli.md +0 -0
  49. {cadwyn-4.4.1 → cadwyn-4.4.3}/docs/concepts/endpoint_migrations.md +0 -0
  50. {cadwyn-4.4.1 → cadwyn-4.4.3}/docs/concepts/enum_migrations.md +0 -0
  51. {cadwyn-4.4.1 → cadwyn-4.4.3}/docs/concepts/index.md +0 -0
  52. {cadwyn-4.4.1 → cadwyn-4.4.3}/docs/concepts/main_app.md +0 -0
  53. {cadwyn-4.4.1 → cadwyn-4.4.3}/docs/concepts/methodology.md +0 -0
  54. {cadwyn-4.4.1 → cadwyn-4.4.3}/docs/concepts/schema_generation.md +0 -0
  55. {cadwyn-4.4.1 → cadwyn-4.4.3}/docs/concepts/schema_migrations.md +0 -0
  56. {cadwyn-4.4.1 → cadwyn-4.4.3}/docs/concepts/testing.md +0 -0
  57. {cadwyn-4.4.1 → cadwyn-4.4.3}/docs/concepts/version_changes.md +0 -0
  58. {cadwyn-4.4.1 → cadwyn-4.4.3}/docs/home/CONTRIBUTING.md +0 -0
  59. {cadwyn-4.4.1 → cadwyn-4.4.3}/docs/how_to/change_business_logic/index.md +0 -0
  60. {cadwyn-4.4.1 → cadwyn-4.4.3}/docs/how_to/change_endpoints/index.md +0 -0
  61. {cadwyn-4.4.1 → cadwyn-4.4.3}/docs/how_to/change_openapi_schemas/add_field.md +0 -0
  62. {cadwyn-4.4.1 → cadwyn-4.4.3}/docs/how_to/change_openapi_schemas/change_field_type.md +0 -0
  63. {cadwyn-4.4.1 → cadwyn-4.4.3}/docs/how_to/change_openapi_schemas/changing_constraints.md +0 -0
  64. {cadwyn-4.4.1 → cadwyn-4.4.3}/docs/how_to/change_openapi_schemas/remove_field.md +0 -0
  65. {cadwyn-4.4.1 → cadwyn-4.4.3}/docs/how_to/change_openapi_schemas/rename_a_field_in_schema.md +0 -0
  66. {cadwyn-4.4.1 → cadwyn-4.4.3}/docs/how_to/index.md +0 -0
  67. {cadwyn-4.4.1 → cadwyn-4.4.3}/docs/img/dashboard_with_one_version.png +0 -0
  68. {cadwyn-4.4.1 → cadwyn-4.4.3}/docs/img/dashboard_with_two_versions.png +0 -0
  69. {cadwyn-4.4.1 → cadwyn-4.4.3}/docs/img/get_users_endpoint_from_prior_version.png +0 -0
  70. {cadwyn-4.4.1 → cadwyn-4.4.3}/docs/img/simplified_migration_model.png +0 -0
  71. {cadwyn-4.4.1 → cadwyn-4.4.3}/docs/img/sponsor_logos/monite.png +0 -0
  72. {cadwyn-4.4.1 → cadwyn-4.4.3}/docs/img/unversioned_dashboard.png +0 -0
  73. {cadwyn-4.4.1 → cadwyn-4.4.3}/docs/index.md +0 -0
  74. {cadwyn-4.4.1 → cadwyn-4.4.3}/docs/plugin.py +0 -0
  75. {cadwyn-4.4.1 → cadwyn-4.4.3}/docs/quickstart/setup.md +0 -0
  76. {cadwyn-4.4.1 → cadwyn-4.4.3}/docs/quickstart/tutorial.md +0 -0
  77. {cadwyn-4.4.1 → cadwyn-4.4.3}/docs/theory/how_to_build_versioning_framework.md +0 -0
  78. {cadwyn-4.4.1 → cadwyn-4.4.3}/docs/theory/how_we_got_here.md +0 -0
  79. {cadwyn-4.4.1 → cadwyn-4.4.3}/docs/theory/literature.md +0 -0
  80. {cadwyn-4.4.1 → cadwyn-4.4.3}/docs_src/__init__.py +0 -0
  81. {cadwyn-4.4.1 → cadwyn-4.4.3}/docs_src/quickstart/__init__.py +0 -0
  82. {cadwyn-4.4.1 → cadwyn-4.4.3}/docs_src/quickstart/setup/__init__.py +0 -0
  83. {cadwyn-4.4.1 → cadwyn-4.4.3}/docs_src/quickstart/setup/block001.sh +0 -0
  84. {cadwyn-4.4.1 → cadwyn-4.4.3}/docs_src/quickstart/setup/block002.py +0 -0
  85. {cadwyn-4.4.1 → cadwyn-4.4.3}/docs_src/quickstart/setup/tests/__init__.py +0 -0
  86. {cadwyn-4.4.1 → cadwyn-4.4.3}/docs_src/quickstart/setup/tests/test_block002.py +0 -0
  87. {cadwyn-4.4.1 → cadwyn-4.4.3}/docs_src/quickstart/tutorial/__init__.py +0 -0
  88. {cadwyn-4.4.1 → cadwyn-4.4.3}/docs_src/quickstart/tutorial/block001.py +0 -0
  89. {cadwyn-4.4.1 → cadwyn-4.4.3}/docs_src/quickstart/tutorial/block002.py +0 -0
  90. {cadwyn-4.4.1 → cadwyn-4.4.3}/docs_src/quickstart/tutorial/block003.py +0 -0
  91. {cadwyn-4.4.1 → cadwyn-4.4.3}/docs_src/quickstart/tutorial/tests/__init__.py +0 -0
  92. {cadwyn-4.4.1 → cadwyn-4.4.3}/docs_src/quickstart/tutorial/tests/test_block001.py +0 -0
  93. {cadwyn-4.4.1 → cadwyn-4.4.3}/docs_src/quickstart/tutorial/tests/test_block002.py +0 -0
  94. {cadwyn-4.4.1 → cadwyn-4.4.3}/docs_src/quickstart/tutorial/tests/test_block003.py +0 -0
  95. {cadwyn-4.4.1 → cadwyn-4.4.3}/mkdocs.yml +0 -0
  96. {cadwyn-4.4.1 → cadwyn-4.4.3}/ruff.toml +0 -0
  97. {cadwyn-4.4.1 → cadwyn-4.4.3}/scripts/fix_links.py +0 -0
  98. {cadwyn-4.4.1 → cadwyn-4.4.3}/scripts/split_md.py +0 -0
  99. {cadwyn-4.4.1 → cadwyn-4.4.3}/tests/__init__.py +0 -0
  100. {cadwyn-4.4.1 → cadwyn-4.4.3}/tests/_data/__init__.py +0 -0
  101. {cadwyn-4.4.1 → cadwyn-4.4.3}/tests/_data/unversioned_schema_dir/__init__.py +0 -0
  102. {cadwyn-4.4.1 → cadwyn-4.4.3}/tests/_data/unversioned_schema_dir/unversioned_schemas.py +0 -0
  103. {cadwyn-4.4.1 → cadwyn-4.4.3}/tests/_data/unversioned_schemas.py +0 -0
  104. {cadwyn-4.4.1 → cadwyn-4.4.3}/tests/_resources/__init__.py +0 -0
  105. {cadwyn-4.4.1 → cadwyn-4.4.3}/tests/_resources/app_for_testing_routing.py +0 -0
  106. {cadwyn-4.4.1 → cadwyn-4.4.3}/tests/_resources/render/__init__.py +0 -0
  107. {cadwyn-4.4.1 → cadwyn-4.4.3}/tests/_resources/render/classes.py +0 -0
  108. {cadwyn-4.4.1 → cadwyn-4.4.3}/tests/_resources/render/complex/__init__.py +0 -0
  109. {cadwyn-4.4.1 → cadwyn-4.4.3}/tests/_resources/render/complex/classes.py +0 -0
  110. {cadwyn-4.4.1 → cadwyn-4.4.3}/tests/_resources/render/complex/versions.py +0 -0
  111. {cadwyn-4.4.1 → cadwyn-4.4.3}/tests/_resources/render/versions.py +0 -0
  112. {cadwyn-4.4.1 → cadwyn-4.4.3}/tests/_resources/utils.py +0 -0
  113. {cadwyn-4.4.1 → cadwyn-4.4.3}/tests/_resources/versioned_app/__init__.py +0 -0
  114. {cadwyn-4.4.1 → cadwyn-4.4.3}/tests/_resources/versioned_app/app.py +0 -0
  115. {cadwyn-4.4.1 → cadwyn-4.4.3}/tests/_resources/versioned_app/v2021_01_01.py +0 -0
  116. {cadwyn-4.4.1 → cadwyn-4.4.3}/tests/_resources/versioned_app/v2022_01_02.py +0 -0
  117. {cadwyn-4.4.1 → cadwyn-4.4.3}/tests/_resources/versioned_app/webhooks.py +0 -0
  118. {cadwyn-4.4.1 → cadwyn-4.4.3}/tests/conftest.py +0 -0
  119. {cadwyn-4.4.1 → cadwyn-4.4.3}/tests/test_applications.py +0 -0
  120. {cadwyn-4.4.1 → cadwyn-4.4.3}/tests/test_changelog.py +0 -0
  121. {cadwyn-4.4.1 → cadwyn-4.4.3}/tests/test_cli.py +0 -0
  122. {cadwyn-4.4.1 → cadwyn-4.4.3}/tests/test_data_migrations.py +0 -0
  123. {cadwyn-4.4.1 → cadwyn-4.4.3}/tests/test_render.py +0 -0
  124. {cadwyn-4.4.1 → cadwyn-4.4.3}/tests/test_router_generation.py +0 -0
  125. {cadwyn-4.4.1 → cadwyn-4.4.3}/tests/test_routing.py +0 -0
  126. {cadwyn-4.4.1 → cadwyn-4.4.3}/tests/test_schema_generation/__init__.py +0 -0
  127. {cadwyn-4.4.1 → cadwyn-4.4.3}/tests/test_schema_generation/test_enum.py +0 -0
  128. {cadwyn-4.4.1 → cadwyn-4.4.3}/tests/test_schema_generation/test_schema.py +0 -0
  129. {cadwyn-4.4.1 → cadwyn-4.4.3}/tests/test_schema_generation/test_schema_field.py +0 -0
  130. {cadwyn-4.4.1 → cadwyn-4.4.3}/tests/test_schema_generation/test_schema_validator.py +0 -0
  131. {cadwyn-4.4.1 → cadwyn-4.4.3}/tests/test_structure.py +0 -0
  132. {cadwyn-4.4.1 → cadwyn-4.4.3}/tests/tutorial/__init__.py +0 -0
  133. {cadwyn-4.4.1 → cadwyn-4.4.3}/tests/tutorial/main.py +0 -0
  134. {cadwyn-4.4.1 → cadwyn-4.4.3}/tests/tutorial/test_example.py +0 -0
@@ -5,6 +5,24 @@ Please follow [the Keep a Changelog standard](https://keepachangelog.com/en/1.0.
5
5
 
6
6
  ## [Unreleased]
7
7
 
8
+ ## [4.4.3]
9
+
10
+ ### Changed
11
+
12
+ * Bumped package versions
13
+
14
+ ## [4.4.2]
15
+
16
+ ### Fixed
17
+
18
+ * Non-function (object instances) dependencies not supporting dependency overrides in testing
19
+
20
+ ## [4.4.1]
21
+
22
+ ### Added
23
+
24
+ * Python 3.13 to CI
25
+
8
26
  ## [4.4.0]
9
27
 
10
28
  ### Added
@@ -11,4 +11,4 @@ test:
11
11
  rm -r coverage; \
12
12
  uv run coverage run --source=. -m pytest .; \
13
13
  uv run coverage combine; \
14
- uv run coverage report --fail-under=100;
14
+ uv run coverage report --fail-under=100 --show-missing;
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: cadwyn
3
- Version: 4.4.1
3
+ Version: 4.4.3
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
@@ -23,6 +23,7 @@ Classifier: Programming Language :: Python :: 3
23
23
  Classifier: Programming Language :: Python :: 3.10
24
24
  Classifier: Programming Language :: Python :: 3.11
25
25
  Classifier: Programming Language :: Python :: 3.12
26
+ Classifier: Programming Language :: Python :: 3.13
26
27
  Classifier: Topic :: Internet
27
28
  Classifier: Topic :: Internet :: WWW/HTTP
28
29
  Classifier: Topic :: Internet :: WWW/HTTP :: HTTP Servers
@@ -1,7 +1,7 @@
1
1
  import re
2
2
  from collections import defaultdict
3
3
  from collections.abc import Callable, Sequence
4
- from copy import deepcopy
4
+ from copy import copy, deepcopy
5
5
  from dataclasses import dataclass
6
6
  from typing import (
7
7
  TYPE_CHECKING,
@@ -49,6 +49,7 @@ if TYPE_CHECKING:
49
49
  _Call = TypeVar("_Call", bound=Callable[..., Any])
50
50
  _R = TypeVar("_R", bound=APIRouter)
51
51
  _WR = TypeVar("_WR", bound=APIRouter, default=APIRouter)
52
+ _RouteT = TypeVar("_RouteT", bound=BaseRoute)
52
53
  # This is a hack we do because we can't guarantee how the user will use the router.
53
54
  _DELETED_ROUTE_TAG = "_CADWYN_DELETED_ROUTE"
54
55
 
@@ -90,6 +91,25 @@ class VersionedAPIRouter(fastapi.routing.APIRouter):
90
91
  return endpoint
91
92
 
92
93
 
94
+ def copy_router(router: _R) -> _R:
95
+ router = copy(router)
96
+ router.routes = [copy_route(r) for r in router.routes]
97
+ return router
98
+
99
+
100
+ def copy_route(route: _RouteT) -> _RouteT:
101
+ if not isinstance(route, APIRoute):
102
+ return copy(route)
103
+
104
+ # This is slightly wasteful in terms of resources but it makes it easy for us
105
+ # to make sure that new versions of FastAPI are going to be supported even if
106
+ # APIRoute gets new attributes.
107
+ new_route = deepcopy(route)
108
+ new_route.dependant = copy(route.dependant)
109
+ new_route.dependencies = copy(route.dependencies)
110
+ return new_route
111
+
112
+
93
113
  class _EndpointTransformer(Generic[_R, _WR]):
94
114
  def __init__(self, parent_router: _R, versions: VersionBundle, webhooks: _WR) -> None:
95
115
  super().__init__()
@@ -103,8 +123,8 @@ class _EndpointTransformer(Generic[_R, _WR]):
103
123
  ]
104
124
 
105
125
  def transform(self) -> GeneratedRouters[_R, _WR]:
106
- router = deepcopy(self.parent_router)
107
- webhook_router = deepcopy(self.parent_webhooks_router)
126
+ router = copy_router(self.parent_router)
127
+ webhook_router = copy_router(self.parent_webhooks_router)
108
128
  routers: dict[VersionDate, _R] = {}
109
129
  webhook_routers: dict[VersionDate, _WR] = {}
110
130
 
@@ -117,8 +137,8 @@ class _EndpointTransformer(Generic[_R, _WR]):
117
137
  routers[version.value] = router
118
138
  webhook_routers[version.value] = webhook_router
119
139
  # Applying changes for the next version
120
- router = deepcopy(router)
121
- webhook_router = deepcopy(webhook_router)
140
+ router = copy_router(router)
141
+ webhook_router = copy_router(webhook_router)
122
142
  self._apply_endpoint_changes_to_router(router.routes + webhook_router.routes, version)
123
143
 
124
144
  if self.routes_that_never_existed:
@@ -134,7 +154,7 @@ class _EndpointTransformer(Generic[_R, _WR]):
134
154
  if not isinstance(head_route, APIRoute):
135
155
  continue
136
156
  _add_request_and_response_params(head_route)
137
- copy_of_dependant = deepcopy(head_route.dependant)
157
+ copy_of_dependant = copy(head_route.dependant)
138
158
 
139
159
  for older_router in list(routers.values()):
140
160
  older_route = older_router.routes[route_index]
@@ -367,6 +367,10 @@ class _PydanticModelWrapper(Generic[_T_PYDANTIC_MODEL]):
367
367
  return model_copy
368
368
 
369
369
 
370
+ def is_regular_function(call: Callable):
371
+ return isinstance(call, types.FunctionType | types.MethodType)
372
+
373
+
370
374
  class _CallableWrapper:
371
375
  """__eq__ and __hash__ are needed to make sure that dependency overrides work correctly.
372
376
  They are based on putting dependencies (functions) as keys for the dictionary so if we want to be able to
@@ -376,6 +380,8 @@ class _CallableWrapper:
376
380
  def __init__(self, original_callable: Callable) -> None:
377
381
  super().__init__()
378
382
  self._original_callable = original_callable
383
+ if not is_regular_function(original_callable):
384
+ original_callable = original_callable.__call__
379
385
  functools.update_wrapper(self, original_callable)
380
386
 
381
387
  @property
@@ -458,6 +464,12 @@ class _AnnotationTransformer:
458
464
  def _change_version_of_a_non_container_annotation(self, annotation: Any) -> Any:
459
465
  if isinstance(annotation, _BaseGenericAlias | types.GenericAlias):
460
466
  return get_origin(annotation)[tuple(self.change_version_of_annotation(arg) for arg in get_args(annotation))]
467
+ elif isinstance(annotation, fastapi.params.Security):
468
+ return fastapi.params.Security(
469
+ self.change_version_of_annotation(annotation.dependency),
470
+ scopes=annotation.scopes,
471
+ use_cache=annotation.use_cache,
472
+ )
461
473
  elif isinstance(annotation, fastapi.params.Depends):
462
474
  return fastapi.params.Depends(
463
475
  self.change_version_of_annotation(annotation.dependency),
@@ -475,7 +487,7 @@ class _AnnotationTransformer:
475
487
  elif callable(annotation):
476
488
  if type(annotation).__module__.startswith(
477
489
  ("fastapi.", "pydantic.", "pydantic_core.", "starlette.")
478
- ) or isinstance(annotation, fastapi.params.Security | fastapi.security.base.SecurityBase):
490
+ ) or isinstance(annotation, fastapi.security.base.SecurityBase):
479
491
  return annotation
480
492
 
481
493
  def modifier(annotation: Any):
@@ -568,8 +580,12 @@ class _AnnotationTransformer:
568
580
  def _copy_function_through_class_based_wrapper(cls, call: Any):
569
581
  """Separate from copy_endpoint because endpoints MUST be functions in FastAPI, they cannot be cls instances"""
570
582
  call = cls._unwrap_callable(call)
571
-
572
- if inspect.iscoroutinefunction(call):
583
+ if not is_regular_function(call):
584
+ # This means that the callable is actually an instance of a regular class
585
+ actual_call = call.__call__
586
+ else:
587
+ actual_call = call
588
+ if inspect.iscoroutinefunction(actual_call):
573
589
  return _AsyncCallableWrapper(call)
574
590
  else:
575
591
  return _CallableWrapper(call)
@@ -578,9 +594,6 @@ class _AnnotationTransformer:
578
594
  def _unwrap_callable(call: Any) -> Any:
579
595
  while hasattr(call, "_original_callable"):
580
596
  call = call._original_callable
581
- if not isinstance(call, types.FunctionType | types.MethodType):
582
- # This means that the callable is actually an instance of a regular class
583
- call = call.__call__
584
597
 
585
598
  return call
586
599
 
@@ -618,7 +631,7 @@ class SchemaGenerator:
618
631
  wrapper = self._get_wrapper_for_model(model)
619
632
  model_copy = wrapper.generate_model_copy(self)
620
633
  self.concrete_models[model] = model_copy
621
- return model_copy
634
+ return cast(type[_T_ANY_MODEL], model_copy)
622
635
 
623
636
  @overload
624
637
  def _get_wrapper_for_model(self, model: type[BaseModel]) -> "_PydanticModelWrapper[BaseModel]": ...
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "cadwyn"
3
- version = "4.4.1"
3
+ version = "4.4.3"
4
4
  description = "Production-ready community-driven modern Stripe-like API versioning in FastAPI"
5
5
  authors = [{ name = "Stanislav Zmiev", email = "zmievsa@gmail.com" }]
6
6
  license = "MIT"
@@ -31,6 +31,7 @@ classifiers = [
31
31
  "Programming Language :: Python :: 3.10",
32
32
  "Programming Language :: Python :: 3.11",
33
33
  "Programming Language :: Python :: 3.12",
34
+ "Programming Language :: Python :: 3.13",
34
35
  "Topic :: Internet",
35
36
  "Topic :: Software Development :: Libraries :: Application Frameworks",
36
37
  "Topic :: Software Development :: Libraries :: Python Modules",
@@ -57,24 +58,16 @@ dependencies = [
57
58
  "typing-extensions>=4.8.0",
58
59
  ]
59
60
 
61
+
60
62
  [project.optional-dependencies]
61
63
  standard = ["fastapi[standard]>=0.112.3", "typer>=0.7.0"]
62
64
 
63
- [project.urls]
64
- "Source code" = "https://github.com/zmievsa/cadwyn"
65
- Documentation = "https://docs.cadwyn.dev"
66
-
67
-
68
- [project.scripts]
69
- cadwyn = "cadwyn.__main__:app"
70
-
71
65
  [tool.uv]
72
66
  dev-dependencies = [
73
67
  "pdbpp ~=0.10.3",
74
68
  "python-multipart >=0.0.6",
75
69
  "better-devtools ~=0.13.3",
76
70
  "pytest-sugar ~=1.0.0",
77
-
78
71
  # tests
79
72
  "svcs ~=24.1.0",
80
73
  "httpx >=0.26.0",
@@ -83,7 +76,6 @@ dev-dependencies = [
83
76
  "pytest-cov >=4.0.0",
84
77
  "dirty-equals >=0.6.0",
85
78
  "uvicorn ~=0.23.0",
86
-
87
79
  # docs
88
80
  "mkdocs >=1.5.2",
89
81
  "mkdocs-material >=9.3.1",
@@ -92,6 +84,15 @@ dev-dependencies = [
92
84
  "mike >=2.1.2, <3",
93
85
  ]
94
86
 
87
+ [project.urls]
88
+ "Source code" = "https://github.com/zmievsa/cadwyn"
89
+ Documentation = "https://docs.cadwyn.dev"
90
+
91
+
92
+ [project.scripts]
93
+ cadwyn = "cadwyn.__main__:app"
94
+
95
+
95
96
  [tool.coverage.run]
96
97
  data_file = "coverage/coverage"
97
98
  parallel = true
@@ -0,0 +1,67 @@
1
+ from typing import NoReturn
2
+
3
+ import pytest
4
+ from fastapi import APIRouter, HTTPException, Security
5
+ from fastapi.testclient import TestClient
6
+
7
+ from cadwyn.applications import Cadwyn
8
+ from cadwyn.structure.versions import Version, VersionBundle
9
+
10
+
11
+ class ScarySecurity:
12
+ """It's IMPORTANT that we use an instance of a class instead of a function because it can be properly copied.
13
+
14
+ It's an edge case.
15
+ """
16
+
17
+ async def __call__(self) -> NoReturn:
18
+ raise HTTPException(status_code=401, detail="Unauthorized")
19
+
20
+
21
+ scary_security = ScarySecurity()
22
+
23
+
24
+ @pytest.fixture
25
+ def cadwyn_app():
26
+ router = APIRouter()
27
+
28
+ @router.get("/hello")
29
+ async def world(user=Security(scary_security)):
30
+ return {"hello": "world", "user": user}
31
+
32
+ app = Cadwyn(versions=VersionBundle(Version("2023-11-16")))
33
+ app.include_router(router)
34
+ app.generate_and_include_versioned_routers(router)
35
+
36
+ return app
37
+
38
+
39
+ @pytest.fixture
40
+ def user_client(cadwyn_app: Cadwyn):
41
+ with TestClient(app=cadwyn_app, base_url="http://test") as ac:
42
+ yield ac
43
+
44
+
45
+ @pytest.fixture
46
+ def _override_auth_dependency(cadwyn_app: Cadwyn) -> None:
47
+ cadwyn_app.dependency_overrides[scary_security] = lambda: {"id": 123}
48
+
49
+
50
+ def test__no_dependency_overrides_with_unversioned_routes(user_client: TestClient):
51
+ response = user_client.get("/hello")
52
+ assert response.status_code == 401, response.json()
53
+
54
+
55
+ def test__no_dependency_overrides_with_versioned_routes(user_client: TestClient):
56
+ response = user_client.get("/hello", headers={"x-api-version": "2023-11-16"})
57
+ assert response.status_code == 401, response.json()
58
+
59
+
60
+ def test__dependency_overrides_with_unversioned_routes(user_client: TestClient, _override_auth_dependency: None):
61
+ response = user_client.get("/hello")
62
+ assert response.status_code == 200, response.json()
63
+
64
+
65
+ def test__dependency_overrides_with_versioned_routes(user_client: TestClient, _override_auth_dependency: None):
66
+ response = user_client.get("/hello", headers={"x-api-version": "2023-11-16"})
67
+ assert response.status_code == 200, response.json()
@@ -84,7 +84,7 @@ wheels = [
84
84
 
85
85
  [[package]]
86
86
  name = "cadwyn"
87
- version = "4.4.1"
87
+ version = "4.4.2"
88
88
  source = { editable = "." }
89
89
  dependencies = [
90
90
  { name = "backports-strenum", marker = "python_full_version < '3.11'" },
@@ -391,16 +391,16 @@ wheels = [
391
391
 
392
392
  [[package]]
393
393
  name = "fastapi"
394
- version = "0.115.3"
394
+ version = "0.115.4"
395
395
  source = { registry = "https://pypi.org/simple" }
396
396
  dependencies = [
397
397
  { name = "pydantic" },
398
398
  { name = "starlette" },
399
399
  { name = "typing-extensions" },
400
400
  ]
401
- sdist = { url = "https://files.pythonhosted.org/packages/a9/ce/b64ce344d7b13c0768dc5b131a69d52f57202eb85839408a7637ca0dd7e2/fastapi-0.115.3.tar.gz", hash = "sha256:c091c6a35599c036d676fa24bd4a6e19fa30058d93d950216cdc672881f6f7db", size = 300453 }
401
+ sdist = { url = "https://files.pythonhosted.org/packages/a9/db/5781f19bd30745885e0737ff3fdd4e63e7bc691710f9da691128bb0dc73b/fastapi-0.115.4.tar.gz", hash = "sha256:db653475586b091cb8b2fec2ac54a680ac6a158e07406e1abae31679e8826349", size = 300737 }
402
402
  wheels = [
403
- { url = "https://files.pythonhosted.org/packages/57/95/4c5b79e7ca1f7b372d16a32cad7c9cc6c3c899200bed8f45739f4415cfae/fastapi-0.115.3-py3-none-any.whl", hash = "sha256:8035e8f9a2b0aa89cea03b6c77721178ed5358e1aea4cd8570d9466895c0638c", size = 94647 },
403
+ { url = "https://files.pythonhosted.org/packages/99/f6/af0d1f58f86002be0cf1e2665cdd6f7a4a71cdc8a7a9438cdc9e3b5375fe/fastapi-0.115.4-py3-none-any.whl", hash = "sha256:0b504a063ffb3cf96a5e27dc1bc32c80ca743a2528574f9cdc77daa2d31b4742", size = 94732 },
404
404
  ]
405
405
 
406
406
  [package.optional-dependencies]
@@ -747,7 +747,7 @@ wheels = [
747
747
 
748
748
  [[package]]
749
749
  name = "mkdocs-material"
750
- version = "9.5.42"
750
+ version = "9.5.43"
751
751
  source = { registry = "https://pypi.org/simple" }
752
752
  dependencies = [
753
753
  { name = "babel" },
@@ -762,9 +762,9 @@ dependencies = [
762
762
  { name = "regex" },
763
763
  { name = "requests" },
764
764
  ]
765
- sdist = { url = "https://files.pythonhosted.org/packages/f9/33/b3343ed975fbbd6798b8d8a7c4f1bf8489cc321fc8fd426eba3d87b0242e/mkdocs_material-9.5.42.tar.gz", hash = "sha256:92779b5e9b5934540c574c11647131d217dc540dce72b05feeda088c8eb1b8f2", size = 3963891 }
765
+ sdist = { url = "https://files.pythonhosted.org/packages/0f/81/88039be572a6b063a3ebc99421cf523b56e3560c0baccd7e0c45569469b1/mkdocs_material-9.5.43.tar.gz", hash = "sha256:83be7ff30b65a1e4930dfa4ab911e75780a3afc9583d162692e434581cb46979", size = 3962873 }
766
766
  wheels = [
767
- { url = "https://files.pythonhosted.org/packages/55/55/ad3e6a60ac1e8e76025543c49c1f24ecd80fb38e8a57000403bf2f0a4293/mkdocs_material-9.5.42-py3-none-any.whl", hash = "sha256:452a7c5d21284b373f36b981a2cbebfff59263feebeede1bc28652e9c5bbe316", size = 8672619 },
767
+ { url = "https://files.pythonhosted.org/packages/6d/22/af8d23818887a39613f821672346776d585c2544938be2561e6e0374cb2d/mkdocs_material-9.5.43-py3-none-any.whl", hash = "sha256:4aae0664c456fd12837a3192e0225c17960ba8bf55d7f0a7daef7e4b0b914a34", size = 8672197 },
768
768
  ]
769
769
 
770
770
  [[package]]
@@ -939,15 +939,15 @@ wheels = [
939
939
 
940
940
  [[package]]
941
941
  name = "pymdown-extensions"
942
- version = "10.11.2"
942
+ version = "10.12"
943
943
  source = { registry = "https://pypi.org/simple" }
944
944
  dependencies = [
945
945
  { name = "markdown" },
946
946
  { name = "pyyaml" },
947
947
  ]
948
- sdist = { url = "https://files.pythonhosted.org/packages/f4/71/2730a20e9e3752393d78998347f8b1085ef9c417646ea9befbeef221e3c4/pymdown_extensions-10.11.2.tar.gz", hash = "sha256:bc8847ecc9e784a098efd35e20cba772bc5a1b529dfcef9dc1972db9021a1049", size = 830241 }
948
+ sdist = { url = "https://files.pythonhosted.org/packages/d8/0b/32f05854cfd432e9286bb41a870e0d1a926b72df5f5cdb6dec962b2e369e/pymdown_extensions-10.12.tar.gz", hash = "sha256:b0ee1e0b2bef1071a47891ab17003bfe5bf824a398e13f49f8ed653b699369a7", size = 840790 }
949
949
  wheels = [
950
- { url = "https://files.pythonhosted.org/packages/c2/35/c0edf199257ef0a7d407d29cd51c4e70d1dad4370a5f44deb65a7a5475e2/pymdown_extensions-10.11.2-py3-none-any.whl", hash = "sha256:41cdde0a77290e480cf53892f5c5e50921a7ee3e5cd60ba91bf19837b33badcf", size = 259044 },
950
+ { url = "https://files.pythonhosted.org/packages/53/32/95a164ddf533bd676cbbe878e36e89b4ade3efde8dd61d0148c90cbbe57e/pymdown_extensions-10.12-py3-none-any.whl", hash = "sha256:49f81412242d3527b8b4967b990df395c89563043bc51a3d2d7d500e52123b77", size = 263448 },
951
951
  ]
952
952
 
953
953
  [[package]]
@@ -990,15 +990,15 @@ wheels = [
990
990
 
991
991
  [[package]]
992
992
  name = "pytest-cov"
993
- version = "5.0.0"
993
+ version = "6.0.0"
994
994
  source = { registry = "https://pypi.org/simple" }
995
995
  dependencies = [
996
996
  { name = "coverage", extra = ["toml"] },
997
997
  { name = "pytest" },
998
998
  ]
999
- sdist = { url = "https://files.pythonhosted.org/packages/74/67/00efc8d11b630c56f15f4ad9c7f9223f1e5ec275aaae3fa9118c6a223ad2/pytest-cov-5.0.0.tar.gz", hash = "sha256:5837b58e9f6ebd335b0f8060eecce69b662415b16dc503883a02f45dfeb14857", size = 63042 }
999
+ sdist = { url = "https://files.pythonhosted.org/packages/be/45/9b538de8cef30e17c7b45ef42f538a94889ed6a16f2387a6c89e73220651/pytest-cov-6.0.0.tar.gz", hash = "sha256:fde0b595ca248bb8e2d76f020b465f3b107c9632e6a1d1705f17834c89dcadc0", size = 66945 }
1000
1000
  wheels = [
1001
- { url = "https://files.pythonhosted.org/packages/78/3a/af5b4fa5961d9a1e6237b530eb87dd04aea6eb83da09d2a4073d81b54ccf/pytest_cov-5.0.0-py3-none-any.whl", hash = "sha256:4f0764a1219df53214206bf1feea4633c3b558a2925c8b59f144f682861ce652", size = 21990 },
1001
+ { url = "https://files.pythonhosted.org/packages/36/3b/48e79f2cd6a61dbbd4807b4ed46cb564b4fd50a76166b1c4ea5c1d9e2371/pytest_cov-6.0.0-py3-none-any.whl", hash = "sha256:eee6f1b9e61008bd34975a4d5bab25801eb31898b032dd55addc93e96fcaaa35", size = 22949 },
1002
1002
  ]
1003
1003
 
1004
1004
  [[package]]
@@ -1051,11 +1051,11 @@ wheels = [
1051
1051
 
1052
1052
  [[package]]
1053
1053
  name = "python-multipart"
1054
- version = "0.0.12"
1054
+ version = "0.0.17"
1055
1055
  source = { registry = "https://pypi.org/simple" }
1056
- sdist = { url = "https://files.pythonhosted.org/packages/16/6e/7ecfe1366b9270f7f475c76fcfa28812493a6a1abd489b2433851a444f4f/python_multipart-0.0.12.tar.gz", hash = "sha256:045e1f98d719c1ce085ed7f7e1ef9d8ccc8c02ba02b5566d5f7521410ced58cb", size = 35713 }
1056
+ sdist = { url = "https://files.pythonhosted.org/packages/40/22/edea41c2d4a22e666c0c7db7acdcbf7bc8c1c1f7d3b3ca246ec982fec612/python_multipart-0.0.17.tar.gz", hash = "sha256:41330d831cae6e2f22902704ead2826ea038d0419530eadff3ea80175aec5538", size = 36452 }
1057
1057
  wheels = [
1058
- { url = "https://files.pythonhosted.org/packages/f5/0b/c316262244abea7481f95f1e91d7575f3dfcf6455d56d1ffe9839c582eb1/python_multipart-0.0.12-py3-none-any.whl", hash = "sha256:43dcf96cf65888a9cd3423544dd0d75ac10f7aa0c3c28a175bbcd00c9ce1aebf", size = 23246 },
1058
+ { url = "https://files.pythonhosted.org/packages/b4/fb/275137a799169392f1fa88fff2be92f16eee38e982720a8aaadefc4a36b2/python_multipart-0.0.17-py3-none-any.whl", hash = "sha256:15dc4f487e0a9476cc1201261188ee0940165cffc94429b6fc565c4d3045cb5d", size = 24453 },
1059
1059
  ]
1060
1060
 
1061
1061
  [[package]]
@@ -1209,16 +1209,16 @@ wheels = [
1209
1209
 
1210
1210
  [[package]]
1211
1211
  name = "rich"
1212
- version = "13.9.3"
1212
+ version = "13.9.4"
1213
1213
  source = { registry = "https://pypi.org/simple" }
1214
1214
  dependencies = [
1215
1215
  { name = "markdown-it-py" },
1216
1216
  { name = "pygments" },
1217
1217
  { name = "typing-extensions", marker = "python_full_version < '3.11'" },
1218
1218
  ]
1219
- sdist = { url = "https://files.pythonhosted.org/packages/d9/e9/cf9ef5245d835065e6673781dbd4b8911d352fb770d56cf0879cf11b7ee1/rich-13.9.3.tar.gz", hash = "sha256:bc1e01b899537598cf02579d2b9f4a415104d3fc439313a7a2c165d76557a08e", size = 222889 }
1219
+ sdist = { url = "https://files.pythonhosted.org/packages/ab/3a/0316b28d0761c6734d6bc14e770d85506c986c85ffb239e688eeaab2c2bc/rich-13.9.4.tar.gz", hash = "sha256:439594978a49a09530cff7ebc4b5c7103ef57baf48d5ea3184f21d9a2befa098", size = 223149 }
1220
1220
  wheels = [
1221
- { url = "https://files.pythonhosted.org/packages/9a/e2/10e9819cf4a20bd8ea2f5dabafc2e6bf4a78d6a0965daeb60a4b34d1c11f/rich-13.9.3-py3-none-any.whl", hash = "sha256:9836f5096eb2172c9e77df411c1b009bace4193d6a481d534fea75ebba758283", size = 242157 },
1221
+ { url = "https://files.pythonhosted.org/packages/19/71/39c7c0d87f8d4e6c020a393182060eaefeeae6c01dab6a84ec346f2567df/rich-13.9.4-py3-none-any.whl", hash = "sha256:6049d5e6ec054bf2779ab3358186963bac2ea89175919d699e378b99738c2a90", size = 242424 },
1222
1222
  ]
1223
1223
 
1224
1224
  [[package]]
@@ -1250,14 +1250,14 @@ wheels = [
1250
1250
 
1251
1251
  [[package]]
1252
1252
  name = "starlette"
1253
- version = "0.41.0"
1253
+ version = "0.41.2"
1254
1254
  source = { registry = "https://pypi.org/simple" }
1255
1255
  dependencies = [
1256
1256
  { name = "anyio" },
1257
1257
  ]
1258
- sdist = { url = "https://files.pythonhosted.org/packages/78/53/c3a36690a923706e7ac841f649c64f5108889ab1ec44218dac45771f252a/starlette-0.41.0.tar.gz", hash = "sha256:39cbd8768b107d68bfe1ff1672b38a2c38b49777de46d2a592841d58e3bf7c2a", size = 2573755 }
1258
+ sdist = { url = "https://files.pythonhosted.org/packages/3e/da/1fb4bdb72ae12b834becd7e1e7e47001d32f91ec0ce8d7bc1b618d9f0bd9/starlette-0.41.2.tar.gz", hash = "sha256:9834fd799d1a87fd346deb76158668cfa0b0d56f85caefe8268e2d97c3468b62", size = 2573867 }
1259
1259
  wheels = [
1260
- { url = "https://files.pythonhosted.org/packages/35/c6/a4443bfabf5629129512ca0e07866c4c3c094079ba4e9b2551006927253c/starlette-0.41.0-py3-none-any.whl", hash = "sha256:a0193a3c413ebc9c78bff1c3546a45bb8c8bcb4a84cae8747d650a65bd37210a", size = 73216 },
1260
+ { url = "https://files.pythonhosted.org/packages/54/43/f185bfd0ca1d213beb4293bed51d92254df23d8ceaf6c0e17146d508a776/starlette-0.41.2-py3-none-any.whl", hash = "sha256:fbc189474b4731cf30fcef52f18a8d070e3f3b46c6a04c97579e85e6ffca942d", size = 73259 },
1261
1261
  ]
1262
1262
 
1263
1263
  [[package]]
@@ -1391,34 +1391,34 @@ wheels = [
1391
1391
 
1392
1392
  [[package]]
1393
1393
  name = "watchdog"
1394
- version = "5.0.3"
1395
- source = { registry = "https://pypi.org/simple" }
1396
- sdist = { url = "https://files.pythonhosted.org/packages/a2/48/a86139aaeab2db0a2482676f64798d8ac4d2dbb457523f50ab37bf02ce2c/watchdog-5.0.3.tar.gz", hash = "sha256:108f42a7f0345042a854d4d0ad0834b741d421330d5f575b81cb27b883500176", size = 129556 }
1397
- wheels = [
1398
- { url = "https://files.pythonhosted.org/packages/05/2b/dd2081aab6fc9e785c2eee7146d3c6de58e607f4e70049d715cd170cbf77/watchdog-5.0.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:85527b882f3facda0579bce9d743ff7f10c3e1e0db0a0d0e28170a7d0e5ce2ea", size = 96652 },
1399
- { url = "https://files.pythonhosted.org/packages/9e/4f/f643c0a720d16ef7316aea06a79b96e229e59df4e0d83bec5e12713c1f29/watchdog-5.0.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:53adf73dcdc0ef04f7735066b4a57a4cd3e49ef135daae41d77395f0b5b692cb", size = 88651 },
1400
- { url = "https://files.pythonhosted.org/packages/2b/72/acb22067d1f18161914c9b1087c703d63638131a9fde78090da290663407/watchdog-5.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e25adddab85f674acac303cf1f5835951345a56c5f7f582987d266679979c75b", size = 89289 },
1401
- { url = "https://files.pythonhosted.org/packages/70/34/946f08602f8b8e6af45bc725e4a8013975a34883ab5570bd0d827a4c9829/watchdog-5.0.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:f01f4a3565a387080dc49bdd1fefe4ecc77f894991b88ef927edbfa45eb10818", size = 96650 },
1402
- { url = "https://files.pythonhosted.org/packages/96/2b/b84e35d49e8b0bad77e5d086fc1e2c6c833bbfe74d53144cfe8b26117eff/watchdog-5.0.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:91b522adc25614cdeaf91f7897800b82c13b4b8ac68a42ca959f992f6990c490", size = 88653 },
1403
- { url = "https://files.pythonhosted.org/packages/d5/3f/41b5d77c10f450b79921c17b7d0b416616048867bfe63acaa072a619a0cb/watchdog-5.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d52db5beb5e476e6853da2e2d24dbbbed6797b449c8bf7ea118a4ee0d2c9040e", size = 89286 },
1404
- { url = "https://files.pythonhosted.org/packages/1c/9b/8b206a928c188fdeb7b12e1c795199534cd44bdef223b8470129016009dd/watchdog-5.0.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:94d11b07c64f63f49876e0ab8042ae034674c8653bfcdaa8c4b32e71cfff87e8", size = 96739 },
1405
- { url = "https://files.pythonhosted.org/packages/e1/26/129ca9cd0f8016672f37000010c2fedc0b86816e894ebdc0af9bb04a6439/watchdog-5.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:349c9488e1d85d0a58e8cb14222d2c51cbc801ce11ac3936ab4c3af986536926", size = 88708 },
1406
- { url = "https://files.pythonhosted.org/packages/8f/b3/5e10ec32f0c429cdb55b1369066d6e83faf9985b3a53a4e37bb5c5e29aa0/watchdog-5.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:53a3f10b62c2d569e260f96e8d966463dec1a50fa4f1b22aec69e3f91025060e", size = 89309 },
1407
- { url = "https://files.pythonhosted.org/packages/54/c4/49af4ab00bcfb688e9962eace2edda07a2cf89b9699ea536da48e8585cff/watchdog-5.0.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:950f531ec6e03696a2414b6308f5c6ff9dab7821a768c9d5788b1314e9a46ca7", size = 96740 },
1408
- { url = "https://files.pythonhosted.org/packages/96/a4/b24de77cc9ae424c1687c9d4fb15aa560d7d7b28ba559aca72f781d0202b/watchdog-5.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ae6deb336cba5d71476caa029ceb6e88047fc1dc74b62b7c4012639c0b563906", size = 88711 },
1409
- { url = "https://files.pythonhosted.org/packages/a4/71/3f2e9fe8403386b99d788868955b3a790f7a09721501a7e1eb58f514ffaa/watchdog-5.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1021223c08ba8d2d38d71ec1704496471ffd7be42cfb26b87cd5059323a389a1", size = 89319 },
1410
- { url = "https://files.pythonhosted.org/packages/a2/d6/1d1ca81c75d903eca3fdb7061d93845485b58a5ba182d146843b88fc51c2/watchdog-5.0.3-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:90a67d7857adb1d985aca232cc9905dd5bc4803ed85cfcdcfcf707e52049eda7", size = 88172 },
1411
- { url = "https://files.pythonhosted.org/packages/47/bb/d5e0abcfd6d729029a24766682e062526db8b59e9ae0c94aff509e0fd2b9/watchdog-5.0.3-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:720ef9d3a4f9ca575a780af283c8fd3a0674b307651c1976714745090da5a9e8", size = 88644 },
1412
- { url = "https://files.pythonhosted.org/packages/60/33/7cb71c9df9a77b6927ee5f48d25e1de5562ce0fa7e0c56dcf2b0472e64a2/watchdog-5.0.3-py3-none-manylinux2014_aarch64.whl", hash = "sha256:dd021efa85970bd4824acacbb922066159d0f9e546389a4743d56919b6758b91", size = 79335 },
1413
- { url = "https://files.pythonhosted.org/packages/f6/91/320bc1496cf951a3cf93a7ffd18a581f0792c304be963d943e0e608c2919/watchdog-5.0.3-py3-none-manylinux2014_armv7l.whl", hash = "sha256:78864cc8f23dbee55be34cc1494632a7ba30263951b5b2e8fc8286b95845f82c", size = 79334 },
1414
- { url = "https://files.pythonhosted.org/packages/8b/2c/567c5e042ed667d3544c43d48a65cf853450a2d2a9089d9523a65f195e94/watchdog-5.0.3-py3-none-manylinux2014_i686.whl", hash = "sha256:1e9679245e3ea6498494b3028b90c7b25dbb2abe65c7d07423ecfc2d6218ff7c", size = 79333 },
1415
- { url = "https://files.pythonhosted.org/packages/c3/f0/64059fe162ef3274662e67bbdea6c45b3cd53e846d5bd1365fcdc3dc1d15/watchdog-5.0.3-py3-none-manylinux2014_ppc64.whl", hash = "sha256:9413384f26b5d050b6978e6fcd0c1e7f0539be7a4f1a885061473c5deaa57221", size = 79334 },
1416
- { url = "https://files.pythonhosted.org/packages/f6/d9/19b7d02965be2801e2d0f6f4bde23e4ae172620071b65430fa0c2f8441ac/watchdog-5.0.3-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:294b7a598974b8e2c6123d19ef15de9abcd282b0fbbdbc4d23dfa812959a9e05", size = 79333 },
1417
- { url = "https://files.pythonhosted.org/packages/cb/a1/5393ac6d0b095d3a44946b09258e9b5f22cb2fb67bcfa419dd868478826c/watchdog-5.0.3-py3-none-manylinux2014_s390x.whl", hash = "sha256:26dd201857d702bdf9d78c273cafcab5871dd29343748524695cecffa44a8d97", size = 79332 },
1418
- { url = "https://files.pythonhosted.org/packages/a0/58/edec25190b6403caf4426dd418234f2358a106634b7d6aa4aec6939b104f/watchdog-5.0.3-py3-none-manylinux2014_x86_64.whl", hash = "sha256:0f9332243355643d567697c3e3fa07330a1d1abf981611654a1f2bf2175612b7", size = 79334 },
1419
- { url = "https://files.pythonhosted.org/packages/97/69/cfb2d17ba8aabc73be2e2d03c8c319b1f32053a02c4b571852983aa24ff2/watchdog-5.0.3-py3-none-win32.whl", hash = "sha256:c66f80ee5b602a9c7ab66e3c9f36026590a0902db3aea414d59a2f55188c1f49", size = 79320 },
1420
- { url = "https://files.pythonhosted.org/packages/91/b4/2b5b59358dadfa2c8676322f955b6c22cde4937602f40490e2f7403e548e/watchdog-5.0.3-py3-none-win_amd64.whl", hash = "sha256:f00b4cf737f568be9665563347a910f8bdc76f88c2970121c86243c8cfdf90e9", size = 79325 },
1421
- { url = "https://files.pythonhosted.org/packages/38/b8/0aa69337651b3005f161f7f494e59188a1d8d94171666900d26d29d10f69/watchdog-5.0.3-py3-none-win_ia64.whl", hash = "sha256:49f4d36cb315c25ea0d946e018c01bb028048023b9e103d3d3943f58e109dd45", size = 79324 },
1394
+ version = "6.0.0"
1395
+ source = { registry = "https://pypi.org/simple" }
1396
+ sdist = { url = "https://files.pythonhosted.org/packages/db/7d/7f3d619e951c88ed75c6037b246ddcf2d322812ee8ea189be89511721d54/watchdog-6.0.0.tar.gz", hash = "sha256:9ddf7c82fda3ae8e24decda1338ede66e1c99883db93711d8fb941eaa2d8c282", size = 131220 }
1397
+ wheels = [
1398
+ { url = "https://files.pythonhosted.org/packages/0c/56/90994d789c61df619bfc5ce2ecdabd5eeff564e1eb47512bd01b5e019569/watchdog-6.0.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d1cdb490583ebd691c012b3d6dae011000fe42edb7a82ece80965b42abd61f26", size = 96390 },
1399
+ { url = "https://files.pythonhosted.org/packages/55/46/9a67ee697342ddf3c6daa97e3a587a56d6c4052f881ed926a849fcf7371c/watchdog-6.0.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bc64ab3bdb6a04d69d4023b29422170b74681784ffb9463ed4870cf2f3e66112", size = 88389 },
1400
+ { url = "https://files.pythonhosted.org/packages/44/65/91b0985747c52064d8701e1075eb96f8c40a79df889e59a399453adfb882/watchdog-6.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c897ac1b55c5a1461e16dae288d22bb2e412ba9807df8397a635d88f671d36c3", size = 89020 },
1401
+ { url = "https://files.pythonhosted.org/packages/e0/24/d9be5cd6642a6aa68352ded4b4b10fb0d7889cb7f45814fb92cecd35f101/watchdog-6.0.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6eb11feb5a0d452ee41f824e271ca311a09e250441c262ca2fd7ebcf2461a06c", size = 96393 },
1402
+ { url = "https://files.pythonhosted.org/packages/63/7a/6013b0d8dbc56adca7fdd4f0beed381c59f6752341b12fa0886fa7afc78b/watchdog-6.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ef810fbf7b781a5a593894e4f439773830bdecb885e6880d957d5b9382a960d2", size = 88392 },
1403
+ { url = "https://files.pythonhosted.org/packages/d1/40/b75381494851556de56281e053700e46bff5b37bf4c7267e858640af5a7f/watchdog-6.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:afd0fe1b2270917c5e23c2a65ce50c2a4abb63daafb0d419fde368e272a76b7c", size = 89019 },
1404
+ { url = "https://files.pythonhosted.org/packages/39/ea/3930d07dafc9e286ed356a679aa02d777c06e9bfd1164fa7c19c288a5483/watchdog-6.0.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:bdd4e6f14b8b18c334febb9c4425a878a2ac20efd1e0b231978e7b150f92a948", size = 96471 },
1405
+ { url = "https://files.pythonhosted.org/packages/12/87/48361531f70b1f87928b045df868a9fd4e253d9ae087fa4cf3f7113be363/watchdog-6.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c7c15dda13c4eb00d6fb6fc508b3c0ed88b9d5d374056b239c4ad1611125c860", size = 88449 },
1406
+ { url = "https://files.pythonhosted.org/packages/5b/7e/8f322f5e600812e6f9a31b75d242631068ca8f4ef0582dd3ae6e72daecc8/watchdog-6.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6f10cb2d5902447c7d0da897e2c6768bca89174d0c6e1e30abec5421af97a5b0", size = 89054 },
1407
+ { url = "https://files.pythonhosted.org/packages/68/98/b0345cabdce2041a01293ba483333582891a3bd5769b08eceb0d406056ef/watchdog-6.0.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:490ab2ef84f11129844c23fb14ecf30ef3d8a6abafd3754a6f75ca1e6654136c", size = 96480 },
1408
+ { url = "https://files.pythonhosted.org/packages/85/83/cdf13902c626b28eedef7ec4f10745c52aad8a8fe7eb04ed7b1f111ca20e/watchdog-6.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:76aae96b00ae814b181bb25b1b98076d5fc84e8a53cd8885a318b42b6d3a5134", size = 88451 },
1409
+ { url = "https://files.pythonhosted.org/packages/fe/c4/225c87bae08c8b9ec99030cd48ae9c4eca050a59bf5c2255853e18c87b50/watchdog-6.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a175f755fc2279e0b7312c0035d52e27211a5bc39719dd529625b1930917345b", size = 89057 },
1410
+ { url = "https://files.pythonhosted.org/packages/30/ad/d17b5d42e28a8b91f8ed01cb949da092827afb9995d4559fd448d0472763/watchdog-6.0.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:c7ac31a19f4545dd92fc25d200694098f42c9a8e391bc00bdd362c5736dbf881", size = 87902 },
1411
+ { url = "https://files.pythonhosted.org/packages/5c/ca/c3649991d140ff6ab67bfc85ab42b165ead119c9e12211e08089d763ece5/watchdog-6.0.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:9513f27a1a582d9808cf21a07dae516f0fab1cf2d7683a742c498b93eedabb11", size = 88380 },
1412
+ { url = "https://files.pythonhosted.org/packages/a9/c7/ca4bf3e518cb57a686b2feb4f55a1892fd9a3dd13f470fca14e00f80ea36/watchdog-6.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:7607498efa04a3542ae3e05e64da8202e58159aa1fa4acddf7678d34a35d4f13", size = 79079 },
1413
+ { url = "https://files.pythonhosted.org/packages/5c/51/d46dc9332f9a647593c947b4b88e2381c8dfc0942d15b8edc0310fa4abb1/watchdog-6.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:9041567ee8953024c83343288ccc458fd0a2d811d6a0fd68c4c22609e3490379", size = 79078 },
1414
+ { url = "https://files.pythonhosted.org/packages/d4/57/04edbf5e169cd318d5f07b4766fee38e825d64b6913ca157ca32d1a42267/watchdog-6.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:82dc3e3143c7e38ec49d61af98d6558288c415eac98486a5c581726e0737c00e", size = 79076 },
1415
+ { url = "https://files.pythonhosted.org/packages/ab/cc/da8422b300e13cb187d2203f20b9253e91058aaf7db65b74142013478e66/watchdog-6.0.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:212ac9b8bf1161dc91bd09c048048a95ca3a4c4f5e5d4a7d1b1a7d5752a7f96f", size = 79077 },
1416
+ { url = "https://files.pythonhosted.org/packages/2c/3b/b8964e04ae1a025c44ba8e4291f86e97fac443bca31de8bd98d3263d2fcf/watchdog-6.0.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:e3df4cbb9a450c6d49318f6d14f4bbc80d763fa587ba46ec86f99f9e6876bb26", size = 79078 },
1417
+ { url = "https://files.pythonhosted.org/packages/62/ae/a696eb424bedff7407801c257d4b1afda455fe40821a2be430e173660e81/watchdog-6.0.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:2cce7cfc2008eb51feb6aab51251fd79b85d9894e98ba847408f662b3395ca3c", size = 79077 },
1418
+ { url = "https://files.pythonhosted.org/packages/b5/e8/dbf020b4d98251a9860752a094d09a65e1b436ad181faf929983f697048f/watchdog-6.0.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:20ffe5b202af80ab4266dcd3e91aae72bf2da48c0d33bdb15c66658e685e94e2", size = 79078 },
1419
+ { url = "https://files.pythonhosted.org/packages/07/f6/d0e5b343768e8bcb4cda79f0f2f55051bf26177ecd5651f84c07567461cf/watchdog-6.0.0-py3-none-win32.whl", hash = "sha256:07df1fdd701c5d4c8e55ef6cf55b8f0120fe1aef7ef39a1c6fc6bc2e606d517a", size = 79065 },
1420
+ { url = "https://files.pythonhosted.org/packages/db/d9/c495884c6e548fce18a8f40568ff120bc3a4b7b99813081c8ac0c936fa64/watchdog-6.0.0-py3-none-win_amd64.whl", hash = "sha256:cbafb470cf848d93b5d013e2ecb245d4aa1c8fd0504e863ccefa32445359d680", size = 79070 },
1421
+ { url = "https://files.pythonhosted.org/packages/33/e8/e40370e6d74ddba47f002a32919d91310d6074130fe4e17dabcafc15cbf1/watchdog-6.0.0-py3-none-win_ia64.whl", hash = "sha256:a1914259fa9e1454315171103c6a30961236f508b9b623eae470268bbcc6a22f", size = 79067 },
1422
1422
  ]
1423
1423
 
1424
1424
  [[package]]
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes