dbos 0.26.0a9__tar.gz → 0.26.0a11__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 (100) hide show
  1. {dbos-0.26.0a9 → dbos-0.26.0a11}/PKG-INFO +1 -1
  2. {dbos-0.26.0a9 → dbos-0.26.0a11}/dbos/_client.py +123 -2
  3. {dbos-0.26.0a9 → dbos-0.26.0a11}/dbos/_dbos.py +3 -3
  4. {dbos-0.26.0a9 → dbos-0.26.0a11}/dbos/_sys_db.py +4 -2
  5. {dbos-0.26.0a9 → dbos-0.26.0a11}/pyproject.toml +1 -1
  6. {dbos-0.26.0a9 → dbos-0.26.0a11}/tests/test_workflow_introspection.py +36 -0
  7. {dbos-0.26.0a9 → dbos-0.26.0a11}/LICENSE +0 -0
  8. {dbos-0.26.0a9 → dbos-0.26.0a11}/README.md +0 -0
  9. {dbos-0.26.0a9 → dbos-0.26.0a11}/dbos/__init__.py +0 -0
  10. {dbos-0.26.0a9 → dbos-0.26.0a11}/dbos/__main__.py +0 -0
  11. {dbos-0.26.0a9 → dbos-0.26.0a11}/dbos/_admin_server.py +0 -0
  12. {dbos-0.26.0a9 → dbos-0.26.0a11}/dbos/_app_db.py +0 -0
  13. {dbos-0.26.0a9 → dbos-0.26.0a11}/dbos/_classproperty.py +0 -0
  14. {dbos-0.26.0a9 → dbos-0.26.0a11}/dbos/_conductor/conductor.py +0 -0
  15. {dbos-0.26.0a9 → dbos-0.26.0a11}/dbos/_conductor/protocol.py +0 -0
  16. {dbos-0.26.0a9 → dbos-0.26.0a11}/dbos/_context.py +0 -0
  17. {dbos-0.26.0a9 → dbos-0.26.0a11}/dbos/_core.py +0 -0
  18. {dbos-0.26.0a9 → dbos-0.26.0a11}/dbos/_croniter.py +0 -0
  19. {dbos-0.26.0a9 → dbos-0.26.0a11}/dbos/_dbos_config.py +0 -0
  20. {dbos-0.26.0a9 → dbos-0.26.0a11}/dbos/_debug.py +0 -0
  21. {dbos-0.26.0a9 → dbos-0.26.0a11}/dbos/_docker_pg_helper.py +0 -0
  22. {dbos-0.26.0a9 → dbos-0.26.0a11}/dbos/_error.py +0 -0
  23. {dbos-0.26.0a9 → dbos-0.26.0a11}/dbos/_fastapi.py +0 -0
  24. {dbos-0.26.0a9 → dbos-0.26.0a11}/dbos/_flask.py +0 -0
  25. {dbos-0.26.0a9 → dbos-0.26.0a11}/dbos/_kafka.py +0 -0
  26. {dbos-0.26.0a9 → dbos-0.26.0a11}/dbos/_kafka_message.py +0 -0
  27. {dbos-0.26.0a9 → dbos-0.26.0a11}/dbos/_logger.py +0 -0
  28. {dbos-0.26.0a9 → dbos-0.26.0a11}/dbos/_migrations/env.py +0 -0
  29. {dbos-0.26.0a9 → dbos-0.26.0a11}/dbos/_migrations/script.py.mako +0 -0
  30. {dbos-0.26.0a9 → dbos-0.26.0a11}/dbos/_migrations/versions/04ca4f231047_workflow_queues_executor_id.py +0 -0
  31. {dbos-0.26.0a9 → dbos-0.26.0a11}/dbos/_migrations/versions/50f3227f0b4b_fix_job_queue.py +0 -0
  32. {dbos-0.26.0a9 → dbos-0.26.0a11}/dbos/_migrations/versions/5c361fc04708_added_system_tables.py +0 -0
  33. {dbos-0.26.0a9 → dbos-0.26.0a11}/dbos/_migrations/versions/a3b18ad34abe_added_triggers.py +0 -0
  34. {dbos-0.26.0a9 → dbos-0.26.0a11}/dbos/_migrations/versions/d76646551a6b_job_queue_limiter.py +0 -0
  35. {dbos-0.26.0a9 → dbos-0.26.0a11}/dbos/_migrations/versions/d76646551a6c_workflow_queue.py +0 -0
  36. {dbos-0.26.0a9 → dbos-0.26.0a11}/dbos/_migrations/versions/eab0cc1d9a14_job_queue.py +0 -0
  37. {dbos-0.26.0a9 → dbos-0.26.0a11}/dbos/_migrations/versions/f4b9b32ba814_functionname_childid_op_outputs.py +0 -0
  38. {dbos-0.26.0a9 → dbos-0.26.0a11}/dbos/_outcome.py +0 -0
  39. {dbos-0.26.0a9 → dbos-0.26.0a11}/dbos/_queue.py +0 -0
  40. {dbos-0.26.0a9 → dbos-0.26.0a11}/dbos/_recovery.py +0 -0
  41. {dbos-0.26.0a9 → dbos-0.26.0a11}/dbos/_registrations.py +0 -0
  42. {dbos-0.26.0a9 → dbos-0.26.0a11}/dbos/_request.py +0 -0
  43. {dbos-0.26.0a9 → dbos-0.26.0a11}/dbos/_roles.py +0 -0
  44. {dbos-0.26.0a9 → dbos-0.26.0a11}/dbos/_scheduler.py +0 -0
  45. {dbos-0.26.0a9 → dbos-0.26.0a11}/dbos/_schemas/__init__.py +0 -0
  46. {dbos-0.26.0a9 → dbos-0.26.0a11}/dbos/_schemas/application_database.py +0 -0
  47. {dbos-0.26.0a9 → dbos-0.26.0a11}/dbos/_schemas/system_database.py +0 -0
  48. {dbos-0.26.0a9 → dbos-0.26.0a11}/dbos/_serialization.py +0 -0
  49. {dbos-0.26.0a9 → dbos-0.26.0a11}/dbos/_templates/dbos-db-starter/README.md +0 -0
  50. {dbos-0.26.0a9 → dbos-0.26.0a11}/dbos/_templates/dbos-db-starter/__package/__init__.py +0 -0
  51. {dbos-0.26.0a9 → dbos-0.26.0a11}/dbos/_templates/dbos-db-starter/__package/main.py +0 -0
  52. {dbos-0.26.0a9 → dbos-0.26.0a11}/dbos/_templates/dbos-db-starter/__package/schema.py +0 -0
  53. {dbos-0.26.0a9 → dbos-0.26.0a11}/dbos/_templates/dbos-db-starter/alembic.ini +0 -0
  54. {dbos-0.26.0a9 → dbos-0.26.0a11}/dbos/_templates/dbos-db-starter/dbos-config.yaml.dbos +0 -0
  55. {dbos-0.26.0a9 → dbos-0.26.0a11}/dbos/_templates/dbos-db-starter/migrations/env.py.dbos +0 -0
  56. {dbos-0.26.0a9 → dbos-0.26.0a11}/dbos/_templates/dbos-db-starter/migrations/script.py.mako +0 -0
  57. {dbos-0.26.0a9 → dbos-0.26.0a11}/dbos/_templates/dbos-db-starter/migrations/versions/2024_07_31_180642_init.py +0 -0
  58. {dbos-0.26.0a9 → dbos-0.26.0a11}/dbos/_templates/dbos-db-starter/start_postgres_docker.py +0 -0
  59. {dbos-0.26.0a9 → dbos-0.26.0a11}/dbos/_tracer.py +0 -0
  60. {dbos-0.26.0a9 → dbos-0.26.0a11}/dbos/_utils.py +0 -0
  61. {dbos-0.26.0a9 → dbos-0.26.0a11}/dbos/_workflow_commands.py +0 -0
  62. {dbos-0.26.0a9 → dbos-0.26.0a11}/dbos/cli/_github_init.py +0 -0
  63. {dbos-0.26.0a9 → dbos-0.26.0a11}/dbos/cli/_template_init.py +0 -0
  64. {dbos-0.26.0a9 → dbos-0.26.0a11}/dbos/cli/cli.py +0 -0
  65. {dbos-0.26.0a9 → dbos-0.26.0a11}/dbos/dbos-config.schema.json +0 -0
  66. {dbos-0.26.0a9 → dbos-0.26.0a11}/dbos/py.typed +0 -0
  67. {dbos-0.26.0a9 → dbos-0.26.0a11}/tests/__init__.py +0 -0
  68. {dbos-0.26.0a9 → dbos-0.26.0a11}/tests/atexit_no_ctor.py +0 -0
  69. {dbos-0.26.0a9 → dbos-0.26.0a11}/tests/atexit_no_launch.py +0 -0
  70. {dbos-0.26.0a9 → dbos-0.26.0a11}/tests/classdefs.py +0 -0
  71. {dbos-0.26.0a9 → dbos-0.26.0a11}/tests/client_collateral.py +0 -0
  72. {dbos-0.26.0a9 → dbos-0.26.0a11}/tests/client_worker.py +0 -0
  73. {dbos-0.26.0a9 → dbos-0.26.0a11}/tests/conftest.py +0 -0
  74. {dbos-0.26.0a9 → dbos-0.26.0a11}/tests/more_classdefs.py +0 -0
  75. {dbos-0.26.0a9 → dbos-0.26.0a11}/tests/queuedworkflow.py +0 -0
  76. {dbos-0.26.0a9 → dbos-0.26.0a11}/tests/test_admin_server.py +0 -0
  77. {dbos-0.26.0a9 → dbos-0.26.0a11}/tests/test_async.py +0 -0
  78. {dbos-0.26.0a9 → dbos-0.26.0a11}/tests/test_classdecorators.py +0 -0
  79. {dbos-0.26.0a9 → dbos-0.26.0a11}/tests/test_client.py +0 -0
  80. {dbos-0.26.0a9 → dbos-0.26.0a11}/tests/test_concurrency.py +0 -0
  81. {dbos-0.26.0a9 → dbos-0.26.0a11}/tests/test_config.py +0 -0
  82. {dbos-0.26.0a9 → dbos-0.26.0a11}/tests/test_croniter.py +0 -0
  83. {dbos-0.26.0a9 → dbos-0.26.0a11}/tests/test_dbos.py +0 -0
  84. {dbos-0.26.0a9 → dbos-0.26.0a11}/tests/test_debug.py +0 -0
  85. {dbos-0.26.0a9 → dbos-0.26.0a11}/tests/test_docker_secrets.py +0 -0
  86. {dbos-0.26.0a9 → dbos-0.26.0a11}/tests/test_failures.py +0 -0
  87. {dbos-0.26.0a9 → dbos-0.26.0a11}/tests/test_fastapi.py +0 -0
  88. {dbos-0.26.0a9 → dbos-0.26.0a11}/tests/test_fastapi_roles.py +0 -0
  89. {dbos-0.26.0a9 → dbos-0.26.0a11}/tests/test_flask.py +0 -0
  90. {dbos-0.26.0a9 → dbos-0.26.0a11}/tests/test_kafka.py +0 -0
  91. {dbos-0.26.0a9 → dbos-0.26.0a11}/tests/test_outcome.py +0 -0
  92. {dbos-0.26.0a9 → dbos-0.26.0a11}/tests/test_package.py +0 -0
  93. {dbos-0.26.0a9 → dbos-0.26.0a11}/tests/test_queue.py +0 -0
  94. {dbos-0.26.0a9 → dbos-0.26.0a11}/tests/test_scheduler.py +0 -0
  95. {dbos-0.26.0a9 → dbos-0.26.0a11}/tests/test_schema_migration.py +0 -0
  96. {dbos-0.26.0a9 → dbos-0.26.0a11}/tests/test_singleton.py +0 -0
  97. {dbos-0.26.0a9 → dbos-0.26.0a11}/tests/test_spans.py +0 -0
  98. {dbos-0.26.0a9 → dbos-0.26.0a11}/tests/test_sqlalchemy.py +0 -0
  99. {dbos-0.26.0a9 → dbos-0.26.0a11}/tests/test_workflow_management.py +0 -0
  100. {dbos-0.26.0a9 → dbos-0.26.0a11}/version/__init__.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: dbos
3
- Version: 0.26.0a9
3
+ Version: 0.26.0a11
4
4
  Summary: Ultra-lightweight durable execution in Python
5
5
  Author-Email: "DBOS, Inc." <contact@dbos.dev>
6
6
  License: MIT
@@ -1,7 +1,7 @@
1
1
  import asyncio
2
2
  import sys
3
3
  import uuid
4
- from typing import Any, Generic, Optional, TypedDict, TypeVar
4
+ from typing import Any, Generic, List, Optional, TypedDict, TypeVar
5
5
 
6
6
  if sys.version_info < (3, 11):
7
7
  from typing_extensions import NotRequired
@@ -15,7 +15,12 @@ from dbos._error import DBOSNonExistentWorkflowError
15
15
  from dbos._registrations import DEFAULT_MAX_RECOVERY_ATTEMPTS
16
16
  from dbos._serialization import WorkflowInputs
17
17
  from dbos._sys_db import SystemDatabase, WorkflowStatusInternal, WorkflowStatusString
18
- from dbos._workflow_commands import WorkflowStatus, get_workflow
18
+ from dbos._workflow_commands import (
19
+ WorkflowStatus,
20
+ get_workflow,
21
+ list_queued_workflows,
22
+ list_workflows,
23
+ )
19
24
 
20
25
  R = TypeVar("R", covariant=True) # A generic type for workflow return values
21
26
 
@@ -202,3 +207,119 @@ class DBOSClient:
202
207
  return await asyncio.to_thread(
203
208
  self.get_event, workflow_id, key, timeout_seconds
204
209
  )
210
+
211
+ def cancel_workflow(self, workflow_id: str) -> None:
212
+ self._sys_db.cancel_workflow(workflow_id)
213
+
214
+ async def cancel_workflow_async(self, workflow_id: str) -> None:
215
+ await asyncio.to_thread(self.cancel_workflow, workflow_id)
216
+
217
+ def resume_workflow(self, workflow_id: str) -> None:
218
+ self._sys_db.resume_workflow(workflow_id)
219
+
220
+ async def resume_workflow_async(self, workflow_id: str) -> None:
221
+ await asyncio.to_thread(self.resume_workflow, workflow_id)
222
+
223
+ def list_workflows(
224
+ self,
225
+ *,
226
+ workflow_ids: Optional[List[str]] = None,
227
+ status: Optional[str] = None,
228
+ start_time: Optional[str] = None,
229
+ end_time: Optional[str] = None,
230
+ name: Optional[str] = None,
231
+ app_version: Optional[str] = None,
232
+ user: Optional[str] = None,
233
+ limit: Optional[int] = None,
234
+ offset: Optional[int] = None,
235
+ sort_desc: bool = False,
236
+ ) -> List[WorkflowStatus]:
237
+ return list_workflows(
238
+ self._sys_db,
239
+ workflow_ids=workflow_ids,
240
+ status=status,
241
+ start_time=start_time,
242
+ end_time=end_time,
243
+ name=name,
244
+ app_version=app_version,
245
+ user=user,
246
+ limit=limit,
247
+ offset=offset,
248
+ sort_desc=sort_desc,
249
+ )
250
+
251
+ async def list_workflows_async(
252
+ self,
253
+ *,
254
+ workflow_ids: Optional[List[str]] = None,
255
+ status: Optional[str] = None,
256
+ start_time: Optional[str] = None,
257
+ end_time: Optional[str] = None,
258
+ name: Optional[str] = None,
259
+ app_version: Optional[str] = None,
260
+ user: Optional[str] = None,
261
+ limit: Optional[int] = None,
262
+ offset: Optional[int] = None,
263
+ sort_desc: bool = False,
264
+ ) -> List[WorkflowStatus]:
265
+ return await asyncio.to_thread(
266
+ self.list_workflows,
267
+ workflow_ids=workflow_ids,
268
+ status=status,
269
+ start_time=start_time,
270
+ end_time=end_time,
271
+ name=name,
272
+ app_version=app_version,
273
+ user=user,
274
+ limit=limit,
275
+ offset=offset,
276
+ sort_desc=sort_desc,
277
+ )
278
+
279
+ def list_queued_workflows(
280
+ self,
281
+ *,
282
+ queue_name: Optional[str] = None,
283
+ status: Optional[str] = None,
284
+ start_time: Optional[str] = None,
285
+ end_time: Optional[str] = None,
286
+ name: Optional[str] = None,
287
+ limit: Optional[int] = None,
288
+ offset: Optional[int] = None,
289
+ sort_desc: bool = False,
290
+ ) -> List[WorkflowStatus]:
291
+ return list_queued_workflows(
292
+ self._sys_db,
293
+ queue_name=queue_name,
294
+ status=status,
295
+ start_time=start_time,
296
+ end_time=end_time,
297
+ name=name,
298
+ limit=limit,
299
+ offset=offset,
300
+ sort_desc=sort_desc,
301
+ )
302
+
303
+ async def list_queued_workflows_async(
304
+ self,
305
+ *,
306
+ queue_name: Optional[str] = None,
307
+ status: Optional[str] = None,
308
+ start_time: Optional[str] = None,
309
+ end_time: Optional[str] = None,
310
+ name: Optional[str] = None,
311
+ limit: Optional[int] = None,
312
+ offset: Optional[int] = None,
313
+ sort_desc: bool = False,
314
+ ) -> List[WorkflowStatus]:
315
+ return await asyncio.to_thread(
316
+ self.list_queued_workflows,
317
+ queue_name=queue_name,
318
+ status=status,
319
+ start_time=start_time,
320
+ end_time=end_time,
321
+ name=name,
322
+ limit=limit,
323
+ offset=offset,
324
+ sort_desc=sort_desc,
325
+ )
@@ -1061,11 +1061,11 @@ class DBOS:
1061
1061
 
1062
1062
  @classproperty
1063
1063
  def step_id(cls) -> int:
1064
- """Return the step ID for the current context. This is a unique identifier of the current step within the workflow."""
1064
+ """Return the step ID for the currently executing step. This is a unique identifier of the current step within the workflow."""
1065
1065
  ctx = assert_current_dbos_context()
1066
1066
  assert (
1067
- ctx.is_within_workflow()
1068
- ), "step_id is only available within a DBOS workflow."
1067
+ ctx.is_step() or ctx.is_transaction()
1068
+ ), "step_id is only available within a DBOS step."
1069
1069
  return ctx.function_id
1070
1070
 
1071
1071
  @classproperty
@@ -1569,7 +1569,9 @@ class SystemDatabase:
1569
1569
 
1570
1570
  def call_function_as_step(self, fn: Callable[[], T], function_name: str) -> T:
1571
1571
  ctx = get_local_dbos_context()
1572
- if ctx and ctx.is_within_workflow():
1572
+ if ctx and ctx.is_transaction():
1573
+ raise Exception(f"Invalid call to `{function_name}` inside a transaction")
1574
+ if ctx and ctx.is_workflow():
1573
1575
  ctx.function_id += 1
1574
1576
  res = self.check_operation_execution(
1575
1577
  ctx.workflow_id, ctx.function_id, function_name
@@ -1587,7 +1589,7 @@ class SystemDatabase:
1587
1589
  f"Recorded output and error are both None for {function_name}"
1588
1590
  )
1589
1591
  result = fn()
1590
- if ctx and ctx.is_within_workflow():
1592
+ if ctx and ctx.is_workflow():
1591
1593
  self.record_operation_result(
1592
1594
  {
1593
1595
  "workflow_uuid": ctx.workflow_id,
@@ -28,7 +28,7 @@ dependencies = [
28
28
  ]
29
29
  requires-python = ">=3.9"
30
30
  readme = "README.md"
31
- version = "0.26.0a9"
31
+ version = "0.26.0a11"
32
32
 
33
33
  [project.license]
34
34
  text = "MIT"
@@ -990,3 +990,39 @@ def test_list_workflows_as_step(dbos: DBOS) -> None:
990
990
  workflow_event.set()
991
991
  assert handle.get_result() == 1
992
992
  assert handle_two.get_result() == 1
993
+
994
+
995
+ def test_call_as_step_within_step(
996
+ dbos: DBOS, sys_db: SystemDatabase, app_db: ApplicationDatabase
997
+ ) -> None:
998
+ # If we call any util functions within a step, it should be called directly without checkpointing
999
+
1000
+ @DBOS.step()
1001
+ def getStatus(workflow_id: str) -> str:
1002
+ status = DBOS.get_workflow_status(workflow_id)
1003
+ assert status is not None
1004
+ return status.status
1005
+
1006
+ @DBOS.workflow()
1007
+ def getStatusWorkflow() -> str:
1008
+ return getStatus(DBOS.workflow_id)
1009
+
1010
+ @DBOS.transaction()
1011
+ def transactionStatus() -> None:
1012
+ DBOS.get_workflow_status(DBOS.workflow_id)
1013
+
1014
+ wfid = str(uuid.uuid4())
1015
+ with SetWorkflowID(wfid):
1016
+ status = getStatusWorkflow()
1017
+ assert status == WorkflowStatusString.PENDING.value
1018
+
1019
+ steps = _workflow_commands.list_workflow_steps(sys_db, app_db, wfid)
1020
+
1021
+ assert len(steps) == 1
1022
+ assert steps[0]["function_name"] == getStatus.__qualname__
1023
+
1024
+ with pytest.raises(Exception) as exc_info:
1025
+ transactionStatus()
1026
+ assert "Invalid call to `DBOS.getStatus` inside a transaction" in str(
1027
+ exc_info.value
1028
+ )
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
File without changes