dynamicforms-fastapi-viewsets 0.6.4__tar.gz → 0.7.0__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.
Files changed (53) hide show
  1. {dynamicforms_fastapi_viewsets-0.6.4 → dynamicforms_fastapi_viewsets-0.7.0}/PKG-INFO +1 -1
  2. dynamicforms_fastapi_viewsets-0.7.0/fastapi_viewsets/__init__.py +1 -0
  3. {dynamicforms_fastapi_viewsets-0.6.4 → dynamicforms_fastapi_viewsets-0.7.0}/fastapi_viewsets/decorators/build_schema.py +9 -6
  4. {dynamicforms_fastapi_viewsets-0.6.4 → dynamicforms_fastapi_viewsets-0.7.0}/fastapi_viewsets/decorators/route_viewset.py +6 -4
  5. {dynamicforms_fastapi_viewsets-0.6.4 → dynamicforms_fastapi_viewsets-0.7.0}/fastapi_viewsets/middleware/__init__.py +26 -0
  6. dynamicforms_fastapi_viewsets-0.6.4/fastapi_viewsets/__init__.py +0 -1
  7. {dynamicforms_fastapi_viewsets-0.6.4 → dynamicforms_fastapi_viewsets-0.7.0}/.gitignore +0 -0
  8. {dynamicforms_fastapi_viewsets-0.6.4 → dynamicforms_fastapi_viewsets-0.7.0}/LICENSE +0 -0
  9. {dynamicforms_fastapi_viewsets-0.6.4 → dynamicforms_fastapi_viewsets-0.7.0}/README.md +0 -0
  10. {dynamicforms_fastapi_viewsets-0.6.4 → dynamicforms_fastapi_viewsets-0.7.0}/fastapi_viewsets/action_configuration.py +0 -0
  11. {dynamicforms_fastapi_viewsets-0.6.4 → dynamicforms_fastapi_viewsets-0.7.0}/fastapi_viewsets/backends/__init__.py +0 -0
  12. {dynamicforms_fastapi_viewsets-0.6.4 → dynamicforms_fastapi_viewsets-0.7.0}/fastapi_viewsets/backends/django_orm.py +0 -0
  13. {dynamicforms_fastapi_viewsets-0.6.4 → dynamicforms_fastapi_viewsets-0.7.0}/fastapi_viewsets/collection_viewset.py +0 -0
  14. {dynamicforms_fastapi_viewsets-0.6.4 → dynamicforms_fastapi_viewsets-0.7.0}/fastapi_viewsets/conf.py +0 -0
  15. {dynamicforms_fastapi_viewsets-0.6.4 → dynamicforms_fastapi_viewsets-0.7.0}/fastapi_viewsets/context/__init__.py +0 -0
  16. {dynamicforms_fastapi_viewsets-0.6.4 → dynamicforms_fastapi_viewsets-0.7.0}/fastapi_viewsets/context/auth/__init__.py +0 -0
  17. {dynamicforms_fastapi_viewsets-0.6.4 → dynamicforms_fastapi_viewsets-0.7.0}/fastapi_viewsets/context/auth/django.py +0 -0
  18. {dynamicforms_fastapi_viewsets-0.6.4 → dynamicforms_fastapi_viewsets-0.7.0}/fastapi_viewsets/context/auth/jwt.py +0 -0
  19. {dynamicforms_fastapi_viewsets-0.6.4 → dynamicforms_fastapi_viewsets-0.7.0}/fastapi_viewsets/context/auth/static.py +0 -0
  20. {dynamicforms_fastapi_viewsets-0.6.4 → dynamicforms_fastapi_viewsets-0.7.0}/fastapi_viewsets/cursor.py +0 -0
  21. {dynamicforms_fastapi_viewsets-0.6.4 → dynamicforms_fastapi_viewsets-0.7.0}/fastapi_viewsets/decorators/__init__.py +0 -0
  22. {dynamicforms_fastapi_viewsets-0.6.4 → dynamicforms_fastapi_viewsets-0.7.0}/fastapi_viewsets/decorators/celery_viewset/__init__.py +0 -0
  23. {dynamicforms_fastapi_viewsets-0.6.4 → dynamicforms_fastapi_viewsets-0.7.0}/fastapi_viewsets/decorators/celery_viewset/client.py +0 -0
  24. {dynamicforms_fastapi_viewsets-0.6.4 → dynamicforms_fastapi_viewsets-0.7.0}/fastapi_viewsets/decorators/celery_viewset/result_reader.py +0 -0
  25. {dynamicforms_fastapi_viewsets-0.6.4 → dynamicforms_fastapi_viewsets-0.7.0}/fastapi_viewsets/decorators/celery_viewset/server.py +0 -0
  26. {dynamicforms_fastapi_viewsets-0.6.4 → dynamicforms_fastapi_viewsets-0.7.0}/fastapi_viewsets/decorators/conftest.py +0 -0
  27. {dynamicforms_fastapi_viewsets-0.6.4 → dynamicforms_fastapi_viewsets-0.7.0}/fastapi_viewsets/decorators/lifecycle_runner.py +0 -0
  28. {dynamicforms_fastapi_viewsets-0.6.4 → dynamicforms_fastapi_viewsets-0.7.0}/fastapi_viewsets/decorators/primary_key_model_helper.py +0 -0
  29. {dynamicforms_fastapi_viewsets-0.6.4 → dynamicforms_fastapi_viewsets-0.7.0}/fastapi_viewsets/endpoint_docs.py +0 -0
  30. {dynamicforms_fastapi_viewsets-0.6.4 → dynamicforms_fastapi_viewsets-0.7.0}/fastapi_viewsets/exceptions.py +0 -0
  31. {dynamicforms_fastapi_viewsets-0.6.4 → dynamicforms_fastapi_viewsets-0.7.0}/fastapi_viewsets/filters/__init__.py +0 -0
  32. {dynamicforms_fastapi_viewsets-0.6.4 → dynamicforms_fastapi_viewsets-0.7.0}/fastapi_viewsets/filters/base.py +0 -0
  33. {dynamicforms_fastapi_viewsets-0.6.4 → dynamicforms_fastapi_viewsets-0.7.0}/fastapi_viewsets/filters/declaration.py +0 -0
  34. {dynamicforms_fastapi_viewsets-0.6.4 → dynamicforms_fastapi_viewsets-0.7.0}/fastapi_viewsets/filters/operators.py +0 -0
  35. {dynamicforms_fastapi_viewsets-0.6.4 → dynamicforms_fastapi_viewsets-0.7.0}/fastapi_viewsets/filters/registry.py +0 -0
  36. {dynamicforms_fastapi_viewsets-0.6.4 → dynamicforms_fastapi_viewsets-0.7.0}/fastapi_viewsets/list_query.py +0 -0
  37. {dynamicforms_fastapi_viewsets-0.6.4 → dynamicforms_fastapi_viewsets-0.7.0}/fastapi_viewsets/list_shapes.py +0 -0
  38. {dynamicforms_fastapi_viewsets-0.6.4 → dynamicforms_fastapi_viewsets-0.7.0}/fastapi_viewsets/middleware/auth/__init__.py +0 -0
  39. {dynamicforms_fastapi_viewsets-0.6.4 → dynamicforms_fastapi_viewsets-0.7.0}/fastapi_viewsets/middleware/auth/authorization.py +0 -0
  40. {dynamicforms_fastapi_viewsets-0.6.4 → dynamicforms_fastapi_viewsets-0.7.0}/fastapi_viewsets/middleware/rate_limiter.py +0 -0
  41. {dynamicforms_fastapi_viewsets-0.6.4 → dynamicforms_fastapi_viewsets-0.7.0}/fastapi_viewsets/mixins.py +0 -0
  42. {dynamicforms_fastapi_viewsets-0.6.4 → dynamicforms_fastapi_viewsets-0.7.0}/fastapi_viewsets/mux_ws/__init__.py +0 -0
  43. {dynamicforms_fastapi_viewsets-0.6.4 → dynamicforms_fastapi_viewsets-0.7.0}/fastapi_viewsets/mux_ws/asgi.py +0 -0
  44. {dynamicforms_fastapi_viewsets-0.6.4 → dynamicforms_fastapi_viewsets-0.7.0}/fastapi_viewsets/mux_ws/protocol.py +0 -0
  45. {dynamicforms_fastapi_viewsets-0.6.4 → dynamicforms_fastapi_viewsets-0.7.0}/fastapi_viewsets/mux_ws/registry.py +0 -0
  46. {dynamicforms_fastapi_viewsets-0.6.4 → dynamicforms_fastapi_viewsets-0.7.0}/fastapi_viewsets/mux_ws/server.py +0 -0
  47. {dynamicforms_fastapi_viewsets-0.6.4 → dynamicforms_fastapi_viewsets-0.7.0}/fastapi_viewsets/mux_ws/transports.py +0 -0
  48. {dynamicforms_fastapi_viewsets-0.6.4 → dynamicforms_fastapi_viewsets-0.7.0}/fastapi_viewsets/py.typed +0 -0
  49. {dynamicforms_fastapi_viewsets-0.6.4 → dynamicforms_fastapi_viewsets-0.7.0}/fastapi_viewsets/response_classes.py +0 -0
  50. {dynamicforms_fastapi_viewsets-0.6.4 → dynamicforms_fastapi_viewsets-0.7.0}/fastapi_viewsets/save_state/__init__.py +0 -0
  51. {dynamicforms_fastapi_viewsets-0.6.4 → dynamicforms_fastapi_viewsets-0.7.0}/fastapi_viewsets/save_state/save_state.py +0 -0
  52. {dynamicforms_fastapi_viewsets-0.6.4 → dynamicforms_fastapi_viewsets-0.7.0}/fastapi_viewsets/save_state/serialize_state.py +0 -0
  53. {dynamicforms_fastapi_viewsets-0.6.4 → dynamicforms_fastapi_viewsets-0.7.0}/pyproject.toml +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: dynamicforms-fastapi-viewsets
3
- Version: 0.6.4
3
+ Version: 0.7.0
4
4
  Summary: Django REST Framework-style viewsets for FastAPI, with optional Celery-backed async execution and a Vue/TypeScript client counterpart.
5
5
  Project-URL: Homepage, https://github.com/dynamicforms/fastapi-viewsets
6
6
  Project-URL: Repository, https://github.com/dynamicforms/fastapi-viewsets
@@ -0,0 +1 @@
1
+ __version__ = "0.7.0"
@@ -94,12 +94,15 @@ def build_schema(cls, base_path: str = "", default_tags=None, get_wrapper=None,
94
94
  and attaches them to the class. Idempotent: if already called, returns immediately.
95
95
  If get_wrapper is None, only __router is built (no FastAPI app, no endpoint wrapping).
96
96
 
97
- disable_response_model: pass True when command middleware is configured (see
98
- fastapi_viewsets/middleware.py and route_viewset.py) - middleware can change the shape of what's
99
- actually served (e.g. strip an internal-only field via ViewSetResult.body), so FastAPI must not
100
- coerce/re-validate the endpoint's return value against the ORIGINAL method's declared return
101
- type, which would silently undo those changes (missing fields reappear with their model
102
- defaults).
97
+ disable_response_model: pass True when a configured command middleware declares
98
+ modifies_response_shape=True (see Middleware.modifies_response_shape and
99
+ any_modifies_response_shape() in fastapi_viewsets/middleware/__init__.py, and route_viewset.py) -
100
+ such a middleware can change the shape of what's actually served (e.g. strip an internal-only
101
+ field via ViewSetResult.body), so FastAPI must not coerce/re-validate the endpoint's return value
102
+ against the ORIGINAL method's declared return type, which would silently undo those changes
103
+ (missing fields reappear with their model defaults). Middleware that doesn't declare this (the
104
+ default) leaves the endpoint's declared return type in place, both in the OpenAPI docs and for
105
+ FastAPI's own response validation.
103
106
  """
104
107
  if hasattr(cls, "__router") and (get_wrapper is None or getattr(cls, "__router_full", False)):
105
108
  return
@@ -21,7 +21,7 @@ from fastapi_viewsets.endpoint_docs import (
21
21
  register_tag,
22
22
  viewset_description,
23
23
  )
24
- from fastapi_viewsets.middleware import Middleware
24
+ from fastapi_viewsets.middleware import any_modifies_response_shape, Middleware
25
25
  from fastapi_viewsets.mixins import FilterParam
26
26
  from fastapi_viewsets.mux_ws import register_viewset, resolve_register_muxws, resolve_register_rest
27
27
 
@@ -342,14 +342,16 @@ def route_viewset(
342
342
  return wrapper, new_return_annotation
343
343
 
344
344
  # Command middleware (see fastapi_viewsets/middleware.py) can reshape the response body via
345
- # ViewSetResult - if any is configured, the endpoint's declared return type can no longer
346
- # be trusted as the actual response_model, same reasoning as the old finalize_response hook.
345
+ # ViewSetResult - only middleware that actually declares modifies_response_shape=True
346
+ # untrusts the endpoint's declared return type as the response_model (same reasoning as the
347
+ # old finalize_response hook); typical middleware (auth, rate limiting, sessions) only adds
348
+ # headers/cookies and leaves the declared model - and therefore the OpenAPI docs - in place.
347
349
  build_schema(
348
350
  cls,
349
351
  base_path,
350
352
  default_tags,
351
353
  get_wrapper,
352
- disable_response_model=bool(settings.viewsets_command_middleware),
354
+ disable_response_model=any_modifies_response_shape(settings.viewsets_command_middleware),
353
355
  )
354
356
 
355
357
  muxws_routes = []
@@ -57,6 +57,20 @@ class Middleware(ABC):
57
57
  concrete example) - a bare function would need extra indirection (closures, partials) for that.
58
58
  """
59
59
 
60
+ modifies_response_shape: bool = False
61
+ """
62
+ Whether this middleware can change the shape of ViewSetResult.body (strip/rename/restructure
63
+ fields, not just add side-channel headers/cookies or a status code) - see
64
+ `any_modifies_response_shape()` below. False by default: typical middleware (auth, rate
65
+ limiting, sessions) only inspects the result or attaches headers/cookies, so the endpoint's
66
+ declared return type stays a trustworthy response_model. Override to True on a middleware whose
67
+ __call__ actually reassigns `result.body` to something that no longer matches the original
68
+ return annotation - otherwise FastAPI's response_model validation will coerce the reshaped body
69
+ back towards the original model (e.g. reintroducing a stripped field with its default value).
70
+ A plain function middleware declares this the same way, by setting the attribute on the
71
+ function object: `my_middleware.modifies_response_shape = True`.
72
+ """
73
+
60
74
  def config_from(self, context: Context) -> Any:
61
75
  """
62
76
  This middleware's own @action_configuration value for the current call (see
@@ -104,6 +118,18 @@ class Middleware(ABC):
104
118
  raise NotImplementedError
105
119
 
106
120
 
121
+ def any_modifies_response_shape(middlewares: list) -> bool:
122
+ """
123
+ Whether any entry in `middlewares` (a mix of Middleware instances and/or plain functions, as
124
+ settings.viewsets_command_middleware holds) declares modifies_response_shape=True. A bare
125
+ function that never set the attribute is treated as False, same default as the Middleware
126
+ class - see Middleware.modifies_response_shape above. Used by route_viewset/build_schema to
127
+ decide whether an endpoint's declared response_model can still be trusted for OpenAPI docs and
128
+ FastAPI's own response validation.
129
+ """
130
+ return any(getattr(middleware, "modifies_response_shape", False) for middleware in middlewares)
131
+
132
+
107
133
  async def run_command_chain(
108
134
  middlewares: list[CommandMiddleware],
109
135
  request: "Request | None",
@@ -1 +0,0 @@
1
- __version__ = "0.6.4"