dynamicforms-fastapi-viewsets 0.11.0__tar.gz → 0.11.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.
Files changed (68) hide show
  1. {dynamicforms_fastapi_viewsets-0.11.0 → dynamicforms_fastapi_viewsets-0.11.1}/PKG-INFO +1 -1
  2. dynamicforms_fastapi_viewsets-0.11.1/fastapi_viewsets/__init__.py +1 -0
  3. {dynamicforms_fastapi_viewsets-0.11.0 → dynamicforms_fastapi_viewsets-0.11.1}/fastapi_viewsets/decorators/celery_viewset/server.py +23 -4
  4. {dynamicforms_fastapi_viewsets-0.11.0 → dynamicforms_fastapi_viewsets-0.11.1}/fastapi_viewsets/middleware/__init__.py +3 -1
  5. dynamicforms_fastapi_viewsets-0.11.0/fastapi_viewsets/__init__.py +0 -1
  6. {dynamicforms_fastapi_viewsets-0.11.0 → dynamicforms_fastapi_viewsets-0.11.1}/.gitignore +0 -0
  7. {dynamicforms_fastapi_viewsets-0.11.0 → dynamicforms_fastapi_viewsets-0.11.1}/LICENSE +0 -0
  8. {dynamicforms_fastapi_viewsets-0.11.0 → dynamicforms_fastapi_viewsets-0.11.1}/README.md +0 -0
  9. {dynamicforms_fastapi_viewsets-0.11.0 → dynamicforms_fastapi_viewsets-0.11.1}/fastapi_viewsets/action_configuration.py +0 -0
  10. {dynamicforms_fastapi_viewsets-0.11.0 → dynamicforms_fastapi_viewsets-0.11.1}/fastapi_viewsets/backends/__init__.py +0 -0
  11. {dynamicforms_fastapi_viewsets-0.11.0 → dynamicforms_fastapi_viewsets-0.11.1}/fastapi_viewsets/backends/django_orm.py +0 -0
  12. {dynamicforms_fastapi_viewsets-0.11.0 → dynamicforms_fastapi_viewsets-0.11.1}/fastapi_viewsets/collection_viewset.py +0 -0
  13. {dynamicforms_fastapi_viewsets-0.11.0 → dynamicforms_fastapi_viewsets-0.11.1}/fastapi_viewsets/conf.py +0 -0
  14. {dynamicforms_fastapi_viewsets-0.11.0 → dynamicforms_fastapi_viewsets-0.11.1}/fastapi_viewsets/context/__init__.py +0 -0
  15. {dynamicforms_fastapi_viewsets-0.11.0 → dynamicforms_fastapi_viewsets-0.11.1}/fastapi_viewsets/context/auth/__init__.py +0 -0
  16. {dynamicforms_fastapi_viewsets-0.11.0 → dynamicforms_fastapi_viewsets-0.11.1}/fastapi_viewsets/context/auth/django.py +0 -0
  17. {dynamicforms_fastapi_viewsets-0.11.0 → dynamicforms_fastapi_viewsets-0.11.1}/fastapi_viewsets/context/auth/jwt.py +0 -0
  18. {dynamicforms_fastapi_viewsets-0.11.0 → dynamicforms_fastapi_viewsets-0.11.1}/fastapi_viewsets/context/auth/static.py +0 -0
  19. {dynamicforms_fastapi_viewsets-0.11.0 → dynamicforms_fastapi_viewsets-0.11.1}/fastapi_viewsets/cursor.py +0 -0
  20. {dynamicforms_fastapi_viewsets-0.11.0 → dynamicforms_fastapi_viewsets-0.11.1}/fastapi_viewsets/decorators/__init__.py +0 -0
  21. {dynamicforms_fastapi_viewsets-0.11.0 → dynamicforms_fastapi_viewsets-0.11.1}/fastapi_viewsets/decorators/build_schema.py +0 -0
  22. {dynamicforms_fastapi_viewsets-0.11.0 → dynamicforms_fastapi_viewsets-0.11.1}/fastapi_viewsets/decorators/celery_viewset/__init__.py +0 -0
  23. {dynamicforms_fastapi_viewsets-0.11.0 → dynamicforms_fastapi_viewsets-0.11.1}/fastapi_viewsets/decorators/celery_viewset/client.py +0 -0
  24. {dynamicforms_fastapi_viewsets-0.11.0 → dynamicforms_fastapi_viewsets-0.11.1}/fastapi_viewsets/decorators/celery_viewset/payload.py +0 -0
  25. {dynamicforms_fastapi_viewsets-0.11.0 → dynamicforms_fastapi_viewsets-0.11.1}/fastapi_viewsets/decorators/celery_viewset/result_reader.py +0 -0
  26. {dynamicforms_fastapi_viewsets-0.11.0 → dynamicforms_fastapi_viewsets-0.11.1}/fastapi_viewsets/decorators/conftest.py +0 -0
  27. {dynamicforms_fastapi_viewsets-0.11.0 → dynamicforms_fastapi_viewsets-0.11.1}/fastapi_viewsets/decorators/lifecycle_runner.py +0 -0
  28. {dynamicforms_fastapi_viewsets-0.11.0 → dynamicforms_fastapi_viewsets-0.11.1}/fastapi_viewsets/decorators/primary_key_model_helper.py +0 -0
  29. {dynamicforms_fastapi_viewsets-0.11.0 → dynamicforms_fastapi_viewsets-0.11.1}/fastapi_viewsets/decorators/route_viewset.py +0 -0
  30. {dynamicforms_fastapi_viewsets-0.11.0 → dynamicforms_fastapi_viewsets-0.11.1}/fastapi_viewsets/endpoint_docs.py +0 -0
  31. {dynamicforms_fastapi_viewsets-0.11.0 → dynamicforms_fastapi_viewsets-0.11.1}/fastapi_viewsets/events/__init__.py +0 -0
  32. {dynamicforms_fastapi_viewsets-0.11.0 → dynamicforms_fastapi_viewsets-0.11.1}/fastapi_viewsets/events/authorizers.py +0 -0
  33. {dynamicforms_fastapi_viewsets-0.11.0 → dynamicforms_fastapi_viewsets-0.11.1}/fastapi_viewsets/events/changes.py +0 -0
  34. {dynamicforms_fastapi_viewsets-0.11.0 → dynamicforms_fastapi_viewsets-0.11.1}/fastapi_viewsets/events/conftest.py +0 -0
  35. {dynamicforms_fastapi_viewsets-0.11.0 → dynamicforms_fastapi_viewsets-0.11.1}/fastapi_viewsets/events/delivery.py +0 -0
  36. {dynamicforms_fastapi_viewsets-0.11.0 → dynamicforms_fastapi_viewsets-0.11.1}/fastapi_viewsets/events/event.py +0 -0
  37. {dynamicforms_fastapi_viewsets-0.11.0 → dynamicforms_fastapi_viewsets-0.11.1}/fastapi_viewsets/events/lifecycle.py +0 -0
  38. {dynamicforms_fastapi_viewsets-0.11.0 → dynamicforms_fastapi_viewsets-0.11.1}/fastapi_viewsets/events/redis.py +0 -0
  39. {dynamicforms_fastapi_viewsets-0.11.0 → dynamicforms_fastapi_viewsets-0.11.1}/fastapi_viewsets/events/sources.py +0 -0
  40. {dynamicforms_fastapi_viewsets-0.11.0 → dynamicforms_fastapi_viewsets-0.11.1}/fastapi_viewsets/events/store.py +0 -0
  41. {dynamicforms_fastapi_viewsets-0.11.0 → dynamicforms_fastapi_viewsets-0.11.1}/fastapi_viewsets/events/topics.py +0 -0
  42. {dynamicforms_fastapi_viewsets-0.11.0 → dynamicforms_fastapi_viewsets-0.11.1}/fastapi_viewsets/events/viewset.py +0 -0
  43. {dynamicforms_fastapi_viewsets-0.11.0 → dynamicforms_fastapi_viewsets-0.11.1}/fastapi_viewsets/exceptions.py +0 -0
  44. {dynamicforms_fastapi_viewsets-0.11.0 → dynamicforms_fastapi_viewsets-0.11.1}/fastapi_viewsets/filters/__init__.py +0 -0
  45. {dynamicforms_fastapi_viewsets-0.11.0 → dynamicforms_fastapi_viewsets-0.11.1}/fastapi_viewsets/filters/base.py +0 -0
  46. {dynamicforms_fastapi_viewsets-0.11.0 → dynamicforms_fastapi_viewsets-0.11.1}/fastapi_viewsets/filters/declaration.py +0 -0
  47. {dynamicforms_fastapi_viewsets-0.11.0 → dynamicforms_fastapi_viewsets-0.11.1}/fastapi_viewsets/filters/operators.py +0 -0
  48. {dynamicforms_fastapi_viewsets-0.11.0 → dynamicforms_fastapi_viewsets-0.11.1}/fastapi_viewsets/filters/registry.py +0 -0
  49. {dynamicforms_fastapi_viewsets-0.11.0 → dynamicforms_fastapi_viewsets-0.11.1}/fastapi_viewsets/list_query.py +0 -0
  50. {dynamicforms_fastapi_viewsets-0.11.0 → dynamicforms_fastapi_viewsets-0.11.1}/fastapi_viewsets/list_shapes.py +0 -0
  51. {dynamicforms_fastapi_viewsets-0.11.0 → dynamicforms_fastapi_viewsets-0.11.1}/fastapi_viewsets/middleware/auth/__init__.py +0 -0
  52. {dynamicforms_fastapi_viewsets-0.11.0 → dynamicforms_fastapi_viewsets-0.11.1}/fastapi_viewsets/middleware/auth/authorization.py +0 -0
  53. {dynamicforms_fastapi_viewsets-0.11.0 → dynamicforms_fastapi_viewsets-0.11.1}/fastapi_viewsets/middleware/idempotency.py +0 -0
  54. {dynamicforms_fastapi_viewsets-0.11.0 → dynamicforms_fastapi_viewsets-0.11.1}/fastapi_viewsets/middleware/rate_limiter.py +0 -0
  55. {dynamicforms_fastapi_viewsets-0.11.0 → dynamicforms_fastapi_viewsets-0.11.1}/fastapi_viewsets/mixins.py +0 -0
  56. {dynamicforms_fastapi_viewsets-0.11.0 → dynamicforms_fastapi_viewsets-0.11.1}/fastapi_viewsets/mux_ws/__init__.py +0 -0
  57. {dynamicforms_fastapi_viewsets-0.11.0 → dynamicforms_fastapi_viewsets-0.11.1}/fastapi_viewsets/mux_ws/asgi.py +0 -0
  58. {dynamicforms_fastapi_viewsets-0.11.0 → dynamicforms_fastapi_viewsets-0.11.1}/fastapi_viewsets/mux_ws/protocol.py +0 -0
  59. {dynamicforms_fastapi_viewsets-0.11.0 → dynamicforms_fastapi_viewsets-0.11.1}/fastapi_viewsets/mux_ws/registry.py +0 -0
  60. {dynamicforms_fastapi_viewsets-0.11.0 → dynamicforms_fastapi_viewsets-0.11.1}/fastapi_viewsets/mux_ws/server.py +0 -0
  61. {dynamicforms_fastapi_viewsets-0.11.0 → dynamicforms_fastapi_viewsets-0.11.1}/fastapi_viewsets/mux_ws/transports.py +0 -0
  62. {dynamicforms_fastapi_viewsets-0.11.0 → dynamicforms_fastapi_viewsets-0.11.1}/fastapi_viewsets/py.typed +0 -0
  63. {dynamicforms_fastapi_viewsets-0.11.0 → dynamicforms_fastapi_viewsets-0.11.1}/fastapi_viewsets/response_classes.py +0 -0
  64. {dynamicforms_fastapi_viewsets-0.11.0 → dynamicforms_fastapi_viewsets-0.11.1}/fastapi_viewsets/routing.py +0 -0
  65. {dynamicforms_fastapi_viewsets-0.11.0 → dynamicforms_fastapi_viewsets-0.11.1}/fastapi_viewsets/save_state/__init__.py +0 -0
  66. {dynamicforms_fastapi_viewsets-0.11.0 → dynamicforms_fastapi_viewsets-0.11.1}/fastapi_viewsets/save_state/save_state.py +0 -0
  67. {dynamicforms_fastapi_viewsets-0.11.0 → dynamicforms_fastapi_viewsets-0.11.1}/fastapi_viewsets/save_state/serialize_state.py +0 -0
  68. {dynamicforms_fastapi_viewsets-0.11.0 → dynamicforms_fastapi_viewsets-0.11.1}/pyproject.toml +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: dynamicforms-fastapi-viewsets
3
- Version: 0.11.0
3
+ Version: 0.11.1
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.11.1"
@@ -200,16 +200,21 @@ class _Run:
200
200
  One execution in this process. Maps the exceptions the executor raises into it to this
201
201
  package's: a soft time limit and the gevent pool's hard time limit (`gevent.Timeout`) to
202
202
  `ActionInterruptedError`, any other celery, billiard or kombu exception to `ActionFailedError`, and
203
- the `asyncio.CancelledError` of an execution an interruption cancelled to that interruption.
203
+ the `asyncio.CancelledError` of an execution an interruption cancelled to that interruption, or
204
+ to the `SystemExit` / `KeyboardInterrupt` of a process exit.
204
205
  """
205
206
 
206
207
  def __init__(self, task: str):
207
208
  self.task = task
208
- self.interruption: ActionInterruptedError | None = None
209
+ self.interruption: BaseException | None = None
209
210
  self._interrupting: BaseException | None = None
210
211
 
211
212
  def interrupted(self, error: BaseException) -> None:
212
213
  """Records `error`, which interrupted the loop while the execution was suspended."""
214
+ if isinstance(error, (KeyboardInterrupt, SystemExit)):
215
+ self.interruption = error
216
+ self._interrupting = error
217
+ return
213
218
  translated = self.translate(error)
214
219
  if isinstance(translated, ActionInterruptedError):
215
220
  self.interruption = translated
@@ -286,6 +291,13 @@ def _event_loop() -> asyncio.AbstractEventLoop:
286
291
  return loop
287
292
 
288
293
 
294
+ def _supervised() -> bool:
295
+ """Whether this process is a pool child that billiard started, whose supervisor outlives it."""
296
+ from billiard.process import current_process
297
+
298
+ return getattr(current_process(), "_parent_pid", None) is not None
299
+
300
+
289
301
  _started_pid: int | None = None
290
302
  _started_loops: "weakref.WeakSet[asyncio.AbstractEventLoop]" = weakref.WeakSet()
291
303
  _started_lock = threading.Lock()
@@ -564,7 +576,8 @@ def celery_viewset_server(
564
576
  one as `ActionFailedError`. The
565
577
  worker's supervisor reports what ends an execution from outside it (a hard time limit, a
566
578
  termination, a lost process) and a call that never runs (revoked, expired, unknown, rejected)
567
- to the caller and to `Middleware.on_transition()`.
579
+ to the caller and to `Middleware.on_transition()`; a process no supervisor outlives (any pool but
580
+ `prefork`) reports its own exit as `interrupted` with reason `terminated`.
568
581
  """
569
582
  if redis_client is None:
570
583
  raise ValueError("redis_client is required for celery_viewset_server")
@@ -641,6 +654,10 @@ def celery_viewset_server(
641
654
  translated error, or a process exit as it is. An `HTTPException` the action raised is its
642
655
  answer and is not re-raised.
643
656
 
657
+ A process exit is reported as `interrupted` with reason `terminated` where no supervisor
658
+ outlives the process (any process but a prefork pool child); a prefork pool child's
659
+ supervisor reports it.
660
+
644
661
  The gevent pool's hard time limit is reported here as the supervisor reports another
645
662
  pool's, as `interrupted` with reason `time_limit`, and its `gevent.Timeout` is re-raised
646
663
  as it is: the pool handles the time limit only when that exception reaches it."""
@@ -678,7 +695,9 @@ def celery_viewset_server(
678
695
  pushed.status_code,
679
696
  pushed.detail,
680
697
  )
681
- if correlation_id and result_queue_key:
698
+ if process_exit and not _supervised():
699
+ _report("interrupted", task_name, call, lambda _t: pushed)
700
+ elif correlation_id and result_queue_key:
682
701
  push_payload(redis_client, result_queue_key, error_payload(correlation_id, task_name, pushed))
683
702
  if process_exit:
684
703
  raise caught
@@ -253,7 +253,9 @@ class Middleware(ABC):
253
253
  action itself sees `asyncio.CancelledError` in the latter case. An execution the executor
254
254
  ends from outside (a hard time limit, a termination, a lost process) ends its process:
255
255
  `call_next()` raises `SystemExit` where the process is stopped with SIGTERM and has time to
256
- unwind, and nothing at all where it is killed. `on_transition()` reports it either way. In a
256
+ unwind, whether the action was running or suspended at an `await`, and nothing at all where it
257
+ is killed. `on_transition()` reports it either way: the supervisor of a prefork pool child, or
258
+ the exiting process itself where no supervisor outlives it. In a
257
259
  gevent pool a hard time limit ends the execution only and reaches `call_next()` as
258
260
  `ActionInterruptedError`.
259
261
  """
@@ -1 +0,0 @@
1
- __version__ = "0.11.0"