django-lambda-tasks 0.4.3__tar.gz → 0.4.5__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (101) hide show
  1. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/.kiro/steering/product.md +8 -1
  2. django_lambda_tasks-0.4.3/README.md → django_lambda_tasks-0.4.5/PKG-INFO +37 -0
  3. django_lambda_tasks-0.4.3/PKG-INFO → django_lambda_tasks-0.4.5/README.md +25 -12
  4. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/lambda_tasks/decorators.py +13 -9
  5. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/lambda_tasks/settings.py +4 -1
  6. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/pyproject.toml +1 -1
  7. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/tests/test_decorator.py +12 -2
  8. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/tests/test_decorators.py +14 -5
  9. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/tests/test_deferred_enqueue.py +3 -3
  10. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/tests/test_models.py +10 -5
  11. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/.github/workflows/ci.yml +0 -0
  12. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/.github/workflows/release.yml +0 -0
  13. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/.gitignore +0 -0
  14. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/.kiro/specs/async-local-execution/.config.kiro +0 -0
  15. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/.kiro/specs/async-local-execution/design.md +0 -0
  16. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/.kiro/specs/async-local-execution/requirements.md +0 -0
  17. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/.kiro/specs/async-local-execution/tasks.md +0 -0
  18. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/.kiro/specs/deferred-task-enqueue/.config.kiro +0 -0
  19. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/.kiro/specs/deferred-task-enqueue/design.md +0 -0
  20. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/.kiro/specs/deferred-task-enqueue/requirements.md +0 -0
  21. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/.kiro/specs/deferred-task-enqueue/tasks.md +0 -0
  22. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/.kiro/specs/eager-mode-example-app/.config.kiro +0 -0
  23. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/.kiro/specs/eager-mode-example-app/design.md +0 -0
  24. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/.kiro/specs/eager-mode-example-app/requirements.md +0 -0
  25. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/.kiro/specs/eager-mode-example-app/tasks.md +0 -0
  26. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/.kiro/specs/ignore-errors-decorator-option/.config.kiro +0 -0
  27. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/.kiro/specs/ignore-errors-decorator-option/design.md +0 -0
  28. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/.kiro/specs/ignore-errors-decorator-option/requirements.md +0 -0
  29. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/.kiro/specs/ignore-errors-decorator-option/tasks.md +0 -0
  30. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/.kiro/specs/import-string-task-resolution/.config.kiro +0 -0
  31. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/.kiro/specs/import-string-task-resolution/design.md +0 -0
  32. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/.kiro/specs/import-string-task-resolution/requirements.md +0 -0
  33. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/.kiro/specs/import-string-task-resolution/tasks.md +0 -0
  34. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/.kiro/specs/retry-delay/.config.kiro +0 -0
  35. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/.kiro/specs/retry-delay/design.md +0 -0
  36. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/.kiro/specs/retry-delay/requirements.md +0 -0
  37. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/.kiro/specs/retry-delay/tasks.md +0 -0
  38. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/.kiro/specs/rse-background-tasks/.config.kiro +0 -0
  39. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/.kiro/specs/rse-background-tasks/design.md +0 -0
  40. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/.kiro/specs/rse-background-tasks/requirements.md +0 -0
  41. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/.kiro/specs/rse-background-tasks/tasks.md +0 -0
  42. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/.kiro/specs/rse-background-tasks-bugfix/.config.kiro +0 -0
  43. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/.kiro/specs/rse-background-tasks-bugfix/bugfix.md +0 -0
  44. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/.kiro/specs/rse-background-tasks-bugfix/design.md +0 -0
  45. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/.kiro/specs/rse-background-tasks-bugfix/tasks.md +0 -0
  46. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/.kiro/specs/singleton-task/.config.kiro +0 -0
  47. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/.kiro/specs/singleton-task/design.md +0 -0
  48. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/.kiro/specs/singleton-task/requirements.md +0 -0
  49. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/.kiro/specs/singleton-task/tasks.md +0 -0
  50. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/.kiro/specs/ssm-environment-loader/.config.kiro +0 -0
  51. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/.kiro/specs/ssm-environment-loader/design.md +0 -0
  52. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/.kiro/specs/ssm-environment-loader/requirements.md +0 -0
  53. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/.kiro/specs/ssm-environment-loader/tasks.md +0 -0
  54. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/.kiro/specs/task-retry/.config.kiro +0 -0
  55. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/.kiro/specs/task-retry/design.md +0 -0
  56. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/.kiro/specs/task-retry/requirements.md +0 -0
  57. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/.kiro/specs/task-retry/tasks.md +0 -0
  58. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/.kiro/steering/structure.md +0 -0
  59. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/.kiro/steering/tech.md +0 -0
  60. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/.pre-commit-config.yaml +0 -0
  61. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/.vscode/settings.json +0 -0
  62. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/example/README.md +0 -0
  63. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/example/example_app/__init__.py +0 -0
  64. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/example/example_app/apps.py +0 -0
  65. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/example/example_app/tasks.py +0 -0
  66. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/example/example_app/urls.py +0 -0
  67. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/example/example_app/views.py +0 -0
  68. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/example/example_project/__init__.py +0 -0
  69. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/example/example_project/settings.py +0 -0
  70. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/example/example_project/urls.py +0 -0
  71. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/example/example_project/wsgi.py +0 -0
  72. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/example/manage.py +0 -0
  73. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/lambda_tasks/__init__.py +0 -0
  74. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/lambda_tasks/admin.py +0 -0
  75. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/lambda_tasks/apps.py +0 -0
  76. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/lambda_tasks/environment_loader.py +0 -0
  77. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/lambda_tasks/handler.py +0 -0
  78. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/lambda_tasks/local_executor.py +0 -0
  79. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/lambda_tasks/logging.py +0 -0
  80. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/lambda_tasks/migrations/0001_initial.py +0 -0
  81. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/lambda_tasks/migrations/0002_alter_taskrecord_status.py +0 -0
  82. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/lambda_tasks/migrations/__init__.py +0 -0
  83. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/lambda_tasks/models.py +0 -0
  84. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/lambda_tasks/secret_loader.py +0 -0
  85. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/lambda_tasks/tasks.py +0 -0
  86. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/lambda_tasks/timeouts.py +0 -0
  87. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/tests/conftest.py +0 -0
  88. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/tests/settings.py +0 -0
  89. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/tests/test_admin.py +0 -0
  90. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/tests/test_environment_loader.py +0 -0
  91. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/tests/test_handler.py +0 -0
  92. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/tests/test_kwargs_only.py +0 -0
  93. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/tests/test_local_executor.py +0 -0
  94. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/tests/test_logging.py +0 -0
  95. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/tests/test_memory_limit.py +0 -0
  96. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/tests/test_secret_loader.py +0 -0
  97. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/tests/test_serializer.py +0 -0
  98. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/tests/test_settings.py +0 -0
  99. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/tests/test_tasks.py +0 -0
  100. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/tests/test_timeout_validation.py +0 -0
  101. {django_lambda_tasks-0.4.3 → django_lambda_tasks-0.4.5}/tests/test_timeouts.py +0 -0
@@ -39,7 +39,14 @@ def my_task(*, user_id: int, action: str) -> None:
39
39
 
40
40
  ## Enqueuing
41
41
 
42
- `execute_on_commit()` uses the decorator `delay` value. There are no per-call overrides.
42
+ `execute_on_commit()` uses the decorator `delay` value by default. Pass `_delay=<seconds>` at call time to override the delay for that specific enqueue:
43
+
44
+ ```python
45
+ my_task.execute_on_commit(user_id=1, action="x") # uses decorator delay
46
+ my_task.execute_on_commit(user_id=1, action="x", _delay=60) # overrides with 60s
47
+ ```
48
+
49
+ The `_delay` override is validated against the same range `[0, 900]` as the decorator `delay`. It only affects the SQS `DelaySeconds` — it has no effect in eager or async-local mode.
43
50
 
44
51
  ## ignore_errors
45
52
 
@@ -1,3 +1,15 @@
1
+ Metadata-Version: 2.4
2
+ Name: django-lambda-tasks
3
+ Version: 0.4.5
4
+ Summary: Run async tasks in a lambda function
5
+ Requires-Python: >=3.10
6
+ Requires-Dist: awslambdaric
7
+ Requires-Dist: boto3
8
+ Requires-Dist: django
9
+ Requires-Dist: pydantic
10
+ Requires-Dist: redis
11
+ Description-Content-Type: text/markdown
12
+
1
13
  # Django Lambda Tasks
2
14
 
3
15
  A Django library for offloading work to AWS Lambda outside of the request-response cycle. Tasks are defined with a decorator, enqueued to SQS on transaction commit, and executed by a Lambda handler that AWS invokes with SQS message batches. Task results, status, and metadata are persisted in the Django database.
@@ -59,6 +71,13 @@ def register(request):
59
71
  return HttpResponse("Registered")
60
72
  ```
61
73
 
74
+ You can override the delay for a specific enqueue by passing `_delay`:
75
+
76
+ ```python
77
+ # Delay this particular invocation by 60 seconds instead of the decorator default
78
+ send_welcome_email.execute_on_commit(user_id=user.id, template="welcome", _delay=60)
79
+ ```
80
+
62
81
  ### 3. Configure AWS
63
82
 
64
83
  See [AWS Lambda and SQS setup](#aws-lambda-and-sqs-setup) for queue and Lambda configuration.
@@ -208,6 +227,24 @@ def my_task(*, arg: str) -> None:
208
227
  | `retry_delay` | `int` | `0` | Base delay in seconds when enqueuing a retry. Jitter (1–5s) is always added; result capped at 900. Requires `retry_on` to be non-empty. |
209
228
  | `singleton` | `bool` | `False` | Prevent concurrent execution via a Redis lock (see [Singleton tasks](#singleton-tasks)). |
210
229
 
230
+ ### Per-call delay override
231
+
232
+ The `delay` decorator parameter sets the default SQS `DelaySeconds` for all invocations of a task. To override it for a specific call, pass `_delay` to `execute_on_commit()` or `serialize()`:
233
+
234
+ ```python
235
+ @lambda_task(delay=0)
236
+ def notify_user(*, user_id: int) -> None:
237
+ ...
238
+
239
+ # Uses the decorator default (0 seconds)
240
+ notify_user.execute_on_commit(user_id=1)
241
+
242
+ # Override: delay this specific invocation by 120 seconds
243
+ notify_user.execute_on_commit(user_id=1, _delay=120)
244
+ ```
245
+
246
+ `_delay` is validated against the same `[0, 900]` range as the decorator `delay`. It only affects the SQS `DelaySeconds` — it has no effect in eager or async-local mode.
247
+
211
248
  ---
212
249
 
213
250
  ## Serializing a task invocation
@@ -1,15 +1,3 @@
1
- Metadata-Version: 2.4
2
- Name: django-lambda-tasks
3
- Version: 0.4.3
4
- Summary: Run async tasks in a lambda function
5
- Requires-Python: >=3.10
6
- Requires-Dist: awslambdaric
7
- Requires-Dist: boto3
8
- Requires-Dist: django
9
- Requires-Dist: pydantic
10
- Requires-Dist: redis
11
- Description-Content-Type: text/markdown
12
-
13
1
  # Django Lambda Tasks
14
2
 
15
3
  A Django library for offloading work to AWS Lambda outside of the request-response cycle. Tasks are defined with a decorator, enqueued to SQS on transaction commit, and executed by a Lambda handler that AWS invokes with SQS message batches. Task results, status, and metadata are persisted in the Django database.
@@ -71,6 +59,13 @@ def register(request):
71
59
  return HttpResponse("Registered")
72
60
  ```
73
61
 
62
+ You can override the delay for a specific enqueue by passing `_delay`:
63
+
64
+ ```python
65
+ # Delay this particular invocation by 60 seconds instead of the decorator default
66
+ send_welcome_email.execute_on_commit(user_id=user.id, template="welcome", _delay=60)
67
+ ```
68
+
74
69
  ### 3. Configure AWS
75
70
 
76
71
  See [AWS Lambda and SQS setup](#aws-lambda-and-sqs-setup) for queue and Lambda configuration.
@@ -220,6 +215,24 @@ def my_task(*, arg: str) -> None:
220
215
  | `retry_delay` | `int` | `0` | Base delay in seconds when enqueuing a retry. Jitter (1–5s) is always added; result capped at 900. Requires `retry_on` to be non-empty. |
221
216
  | `singleton` | `bool` | `False` | Prevent concurrent execution via a Redis lock (see [Singleton tasks](#singleton-tasks)). |
222
217
 
218
+ ### Per-call delay override
219
+
220
+ The `delay` decorator parameter sets the default SQS `DelaySeconds` for all invocations of a task. To override it for a specific call, pass `_delay` to `execute_on_commit()` or `serialize()`:
221
+
222
+ ```python
223
+ @lambda_task(delay=0)
224
+ def notify_user(*, user_id: int) -> None:
225
+ ...
226
+
227
+ # Uses the decorator default (0 seconds)
228
+ notify_user.execute_on_commit(user_id=1)
229
+
230
+ # Override: delay this specific invocation by 120 seconds
231
+ notify_user.execute_on_commit(user_id=1, _delay=120)
232
+ ```
233
+
234
+ `_delay` is validated against the same `[0, 900]` range as the decorator `delay`. It only affects the SQS `DelaySeconds` — it has no effect in eager or async-local mode.
235
+
223
236
  ---
224
237
 
225
238
  ## Serializing a task invocation
@@ -19,7 +19,7 @@ import pydantic
19
19
  from redis.exceptions import LockError
20
20
 
21
21
  from lambda_tasks.models import SQSLambdaTask, SQSLambdaTaskMessage
22
- from lambda_tasks.settings import MAX_TIMEOUT, LambdaTasksSettings
22
+ from lambda_tasks.settings import MAX_DELAY, MAX_TIMEOUT, LambdaTasksSettings
23
23
 
24
24
 
25
25
  def _build_kwargs_model(func: types.FunctionType) -> type[pydantic.BaseModel]:
@@ -154,13 +154,17 @@ class LambdaTaskWrapper:
154
154
  def _build_task(self, *, kwargs: dict[str, Any]) -> SQSLambdaTask:
155
155
  """Pop overrides, validate kwargs, and build a SQSLambdaTask.
156
156
 
157
- Mutates *kwargs* in-place (pops ``_n_retries``).
157
+ Mutates *kwargs* in-place (pops ``_n_retries``, ``_delay``).
158
158
  Returns ``SQSLambdaTask``.
159
159
 
160
160
  Raises:
161
161
  pydantic.ValidationError: if the remaining kwargs fail type validation.
162
+ ValueError: if ``_delay`` is outside the allowed range [0, 900].
162
163
  """
163
164
  n_retries = kwargs.pop("_n_retries", 0)
165
+ delay = kwargs.pop("_delay", self._delay)
166
+
167
+ self._validate_delay(delay=delay)
164
168
 
165
169
  self._kwargs_model.model_validate(kwargs)
166
170
 
@@ -172,7 +176,7 @@ class LambdaTaskWrapper:
172
176
 
173
177
  return SQSLambdaTask(
174
178
  message=message,
175
- delay=self._delay,
179
+ delay=delay,
176
180
  queue=self._queue,
177
181
  )
178
182
 
@@ -253,9 +257,9 @@ class LambdaTaskWrapper:
253
257
 
254
258
  @staticmethod
255
259
  def _validate_delay(*, delay: int) -> None:
256
- """Raise ValueError if delay is outside the allowed range [0, 900]."""
257
- if delay < 0 or delay > 900:
258
- raise ValueError(f"delay ({delay}) must be in the range [0, 900].")
260
+ """Raise ValueError if delay is outside the allowed range [0, MAX_DELAY]."""
261
+ if delay < 0 or delay > MAX_DELAY:
262
+ raise ValueError(f"delay ({delay}) must be in the range [0, {MAX_DELAY}].")
259
263
 
260
264
  @staticmethod
261
265
  def _validate_retry_delay(
@@ -263,10 +267,10 @@ class LambdaTaskWrapper:
263
267
  retry_delay: int,
264
268
  retry_on: tuple[type[BaseException], ...],
265
269
  ) -> None:
266
- """Raise ValueError if retry_delay is outside [0, 900], or TypeError if retry_delay != 0 and retry_on is empty."""
267
- if retry_delay < 0 or retry_delay > 900:
270
+ """Raise ValueError if retry_delay is outside [0, MAX_DELAY], or TypeError if retry_delay != 0 and retry_on is empty."""
271
+ if retry_delay < 0 or retry_delay > MAX_DELAY:
268
272
  raise ValueError(
269
- f"retry_delay ({retry_delay}) must be in the range [0, 900]."
273
+ f"retry_delay ({retry_delay}) must be in the range [0, {MAX_DELAY}]."
270
274
  )
271
275
 
272
276
  if retry_delay != 0 and not retry_on:
@@ -1,7 +1,10 @@
1
+ from typing import Final
2
+
1
3
  from django.conf import settings as django_settings
2
4
  from django.core.exceptions import ImproperlyConfigured
3
5
 
4
- MAX_TIMEOUT = 900
6
+ MAX_DELAY: Final = 900
7
+ MAX_TIMEOUT: Final = 900
5
8
 
6
9
 
7
10
  class LambdaTasksSettings:
@@ -7,7 +7,7 @@ packages = ["lambda_tasks"]
7
7
 
8
8
  [project]
9
9
  name = "django-lambda-tasks"
10
- version = "0.4.3"
10
+ version = "0.4.5"
11
11
  description = "Run async tasks in a lambda function"
12
12
  readme = "README.md"
13
13
  requires-python = ">=3.10"
@@ -82,13 +82,23 @@ class TestLambdaTaskWrapperOnCommit:
82
82
 
83
83
  def test_on_commit_accepts_delay_override(self):
84
84
  wrapper = LambdaTaskWrapper(sample_task)
85
- with pytest.raises(pydantic.ValidationError):
85
+ captured: list = []
86
+ with patch(
87
+ "lambda_tasks.models.transaction.on_commit",
88
+ side_effect=lambda cb: captured.append(cb),
89
+ ):
86
90
  wrapper.execute_on_commit(x=1, _delay=10)
91
+ assert captured[0].__self__.delay == 10
87
92
 
88
93
  def test_on_commit_accepts_delay_and_task_kwargs(self):
89
94
  wrapper = LambdaTaskWrapper(sample_task)
90
- with pytest.raises(pydantic.ValidationError):
95
+ captured: list = []
96
+ with patch(
97
+ "lambda_tasks.models.transaction.on_commit",
98
+ side_effect=lambda cb: captured.append(cb),
99
+ ):
91
100
  wrapper.execute_on_commit(x=1, y="test", _delay=5)
101
+ assert captured[0].__self__.delay == 5
92
102
 
93
103
 
94
104
  # ---------------------------------------------------------------------------
@@ -251,21 +251,30 @@ def test_queue_property_defaults_to_default():
251
251
  # ---------------------------------------------------------------------------
252
252
 
253
253
 
254
- def test_passing_delay_kwarg_to_execute_on_commit_raises_validation_error():
255
- """Passing _delay to execute_on_commit raises pydantic.ValidationError. Requirement 4.1, 4.2"""
254
+ def test_passing_delay_kwarg_to_execute_on_commit_overrides_decorator_delay():
255
+ """Passing _delay to _build_task overrides the decorator delay. Requirement 4.1, 4.2"""
256
256
  wrapper = LambdaTaskWrapper(_make_func(), delay=10)
257
- with pytest.raises(pydantic.ValidationError):
258
- wrapper._build_task(kwargs={"x": 1, "_delay": 5})
257
+ task = wrapper._build_task(kwargs={"x": 1, "_delay": 5})
258
+ assert task.delay == 5
259
259
 
260
260
 
261
261
  def test_build_task_uses_decorator_delay_not_call_time_override():
262
- """_build_task uses the decorator delay, not a call-time override. Requirement 4.3"""
262
+ """_build_task uses the decorator delay when no _delay override is given. Requirement 4.3"""
263
263
  decorator_delay = 42
264
264
  wrapper = LambdaTaskWrapper(_make_func(), delay=decorator_delay)
265
265
  task = wrapper._build_task(kwargs={"x": 1})
266
266
  assert task.delay == decorator_delay
267
267
 
268
268
 
269
+ def test_build_task_delay_override_validates_range():
270
+ """_delay outside [0, 900] raises ValueError."""
271
+ wrapper = LambdaTaskWrapper(_make_func(), delay=10)
272
+ with pytest.raises(ValueError):
273
+ wrapper._build_task(kwargs={"x": 1, "_delay": -1})
274
+ with pytest.raises(ValueError):
275
+ wrapper._build_task(kwargs={"x": 1, "_delay": 901})
276
+
277
+
269
278
  # ---------------------------------------------------------------------------
270
279
  # Unit tests: lambda_task forwarding retry_delay (Requirements 1.1, 1.2)
271
280
  # ---------------------------------------------------------------------------
@@ -44,9 +44,9 @@ def test_to_json_uses_decorator_defaults_for_delay_and_queue():
44
44
 
45
45
 
46
46
  def test_to_json_uses_call_site_override_for_delay():
47
- """_delay at call site is no longer supported — it raises pydantic.ValidationError."""
48
- with pytest.raises(ValidationError):
49
- _wrapper.serialize(x=1, _delay=30)
47
+ """_delay at call site overrides the decorator default."""
48
+ result = _wrapper.serialize(x=1, _delay=30)
49
+ assert result["delay"] == 30
50
50
 
51
51
 
52
52
  def test_to_json_task_name_matches_module_qualname():
@@ -1649,17 +1649,22 @@ def test_normal_execute_on_commit_uses_decorator_delay(settings, decorator_delay
1649
1649
  assert mock_client.send_message.call_args.kwargs["DelaySeconds"] == decorator_delay
1650
1650
 
1651
1651
 
1652
- def test_passing_delay_to_execute_on_commit_raises_validation_error():
1653
- """Passing _delay to execute_on_commit raises ValidationError (extra='forbid' on kwargs model).
1652
+ def test_passing_delay_to_execute_on_commit_overrides_decorator_delay():
1653
+ """Passing _delay to execute_on_commit overrides the decorator delay.
1654
1654
  Validates: Requirements 4.1, 4.2"""
1655
- from pydantic import ValidationError
1655
+ from unittest.mock import patch
1656
1656
 
1657
- @lambda_task
1657
+ @lambda_task(delay=10)
1658
1658
  def _task_simple(*, x: int) -> None:
1659
1659
  pass
1660
1660
 
1661
- with pytest.raises(ValidationError):
1661
+ captured: list = []
1662
+ with patch(
1663
+ "lambda_tasks.models.transaction.on_commit",
1664
+ side_effect=lambda cb: captured.append(cb),
1665
+ ):
1662
1666
  _task_simple.execute_on_commit(x=1, _delay=5)
1667
+ assert captured[0].__self__.delay == 5
1663
1668
 
1664
1669
 
1665
1670
  # ---------------------------------------------------------------------------