dbos 1.15.0a8__tar.gz → 1.15.0a9__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 (99) hide show
  1. {dbos-1.15.0a8 → dbos-1.15.0a9}/PKG-INFO +1 -1
  2. {dbos-1.15.0a8 → dbos-1.15.0a9}/dbos/_dbos.py +29 -1
  3. {dbos-1.15.0a8 → dbos-1.15.0a9}/dbos/_sys_db.py +26 -0
  4. {dbos-1.15.0a8 → dbos-1.15.0a9}/pyproject.toml +1 -1
  5. {dbos-1.15.0a8 → dbos-1.15.0a9}/tests/test_async.py +40 -0
  6. {dbos-1.15.0a8 → dbos-1.15.0a9}/tests/test_dbos.py +49 -0
  7. {dbos-1.15.0a8 → dbos-1.15.0a9}/LICENSE +0 -0
  8. {dbos-1.15.0a8 → dbos-1.15.0a9}/README.md +0 -0
  9. {dbos-1.15.0a8 → dbos-1.15.0a9}/dbos/__init__.py +0 -0
  10. {dbos-1.15.0a8 → dbos-1.15.0a9}/dbos/__main__.py +0 -0
  11. {dbos-1.15.0a8 → dbos-1.15.0a9}/dbos/_admin_server.py +0 -0
  12. {dbos-1.15.0a8 → dbos-1.15.0a9}/dbos/_app_db.py +0 -0
  13. {dbos-1.15.0a8 → dbos-1.15.0a9}/dbos/_classproperty.py +0 -0
  14. {dbos-1.15.0a8 → dbos-1.15.0a9}/dbos/_client.py +0 -0
  15. {dbos-1.15.0a8 → dbos-1.15.0a9}/dbos/_conductor/conductor.py +0 -0
  16. {dbos-1.15.0a8 → dbos-1.15.0a9}/dbos/_conductor/protocol.py +0 -0
  17. {dbos-1.15.0a8 → dbos-1.15.0a9}/dbos/_context.py +0 -0
  18. {dbos-1.15.0a8 → dbos-1.15.0a9}/dbos/_core.py +0 -0
  19. {dbos-1.15.0a8 → dbos-1.15.0a9}/dbos/_croniter.py +0 -0
  20. {dbos-1.15.0a8 → dbos-1.15.0a9}/dbos/_dbos_config.py +0 -0
  21. {dbos-1.15.0a8 → dbos-1.15.0a9}/dbos/_debouncer.py +0 -0
  22. {dbos-1.15.0a8 → dbos-1.15.0a9}/dbos/_debug.py +0 -0
  23. {dbos-1.15.0a8 → dbos-1.15.0a9}/dbos/_docker_pg_helper.py +0 -0
  24. {dbos-1.15.0a8 → dbos-1.15.0a9}/dbos/_error.py +0 -0
  25. {dbos-1.15.0a8 → dbos-1.15.0a9}/dbos/_event_loop.py +0 -0
  26. {dbos-1.15.0a8 → dbos-1.15.0a9}/dbos/_fastapi.py +0 -0
  27. {dbos-1.15.0a8 → dbos-1.15.0a9}/dbos/_flask.py +0 -0
  28. {dbos-1.15.0a8 → dbos-1.15.0a9}/dbos/_kafka.py +0 -0
  29. {dbos-1.15.0a8 → dbos-1.15.0a9}/dbos/_kafka_message.py +0 -0
  30. {dbos-1.15.0a8 → dbos-1.15.0a9}/dbos/_logger.py +0 -0
  31. {dbos-1.15.0a8 → dbos-1.15.0a9}/dbos/_migration.py +0 -0
  32. {dbos-1.15.0a8 → dbos-1.15.0a9}/dbos/_outcome.py +0 -0
  33. {dbos-1.15.0a8 → dbos-1.15.0a9}/dbos/_queue.py +0 -0
  34. {dbos-1.15.0a8 → dbos-1.15.0a9}/dbos/_recovery.py +0 -0
  35. {dbos-1.15.0a8 → dbos-1.15.0a9}/dbos/_registrations.py +0 -0
  36. {dbos-1.15.0a8 → dbos-1.15.0a9}/dbos/_roles.py +0 -0
  37. {dbos-1.15.0a8 → dbos-1.15.0a9}/dbos/_scheduler.py +0 -0
  38. {dbos-1.15.0a8 → dbos-1.15.0a9}/dbos/_schemas/__init__.py +0 -0
  39. {dbos-1.15.0a8 → dbos-1.15.0a9}/dbos/_schemas/application_database.py +0 -0
  40. {dbos-1.15.0a8 → dbos-1.15.0a9}/dbos/_schemas/system_database.py +0 -0
  41. {dbos-1.15.0a8 → dbos-1.15.0a9}/dbos/_serialization.py +0 -0
  42. {dbos-1.15.0a8 → dbos-1.15.0a9}/dbos/_sys_db_postgres.py +0 -0
  43. {dbos-1.15.0a8 → dbos-1.15.0a9}/dbos/_sys_db_sqlite.py +0 -0
  44. {dbos-1.15.0a8 → dbos-1.15.0a9}/dbos/_templates/dbos-db-starter/README.md +0 -0
  45. {dbos-1.15.0a8 → dbos-1.15.0a9}/dbos/_templates/dbos-db-starter/__package/__init__.py +0 -0
  46. {dbos-1.15.0a8 → dbos-1.15.0a9}/dbos/_templates/dbos-db-starter/__package/main.py.dbos +0 -0
  47. {dbos-1.15.0a8 → dbos-1.15.0a9}/dbos/_templates/dbos-db-starter/__package/schema.py +0 -0
  48. {dbos-1.15.0a8 → dbos-1.15.0a9}/dbos/_templates/dbos-db-starter/dbos-config.yaml.dbos +0 -0
  49. {dbos-1.15.0a8 → dbos-1.15.0a9}/dbos/_templates/dbos-db-starter/migrations/create_table.py.dbos +0 -0
  50. {dbos-1.15.0a8 → dbos-1.15.0a9}/dbos/_templates/dbos-db-starter/start_postgres_docker.py +0 -0
  51. {dbos-1.15.0a8 → dbos-1.15.0a9}/dbos/_tracer.py +0 -0
  52. {dbos-1.15.0a8 → dbos-1.15.0a9}/dbos/_utils.py +0 -0
  53. {dbos-1.15.0a8 → dbos-1.15.0a9}/dbos/_workflow_commands.py +0 -0
  54. {dbos-1.15.0a8 → dbos-1.15.0a9}/dbos/cli/_github_init.py +0 -0
  55. {dbos-1.15.0a8 → dbos-1.15.0a9}/dbos/cli/_template_init.py +0 -0
  56. {dbos-1.15.0a8 → dbos-1.15.0a9}/dbos/cli/cli.py +0 -0
  57. {dbos-1.15.0a8 → dbos-1.15.0a9}/dbos/cli/migration.py +0 -0
  58. {dbos-1.15.0a8 → dbos-1.15.0a9}/dbos/dbos-config.schema.json +0 -0
  59. {dbos-1.15.0a8 → dbos-1.15.0a9}/dbos/py.typed +0 -0
  60. {dbos-1.15.0a8 → dbos-1.15.0a9}/tests/__init__.py +0 -0
  61. {dbos-1.15.0a8 → dbos-1.15.0a9}/tests/atexit_no_ctor.py +0 -0
  62. {dbos-1.15.0a8 → dbos-1.15.0a9}/tests/atexit_no_launch.py +0 -0
  63. {dbos-1.15.0a8 → dbos-1.15.0a9}/tests/classdefs.py +0 -0
  64. {dbos-1.15.0a8 → dbos-1.15.0a9}/tests/client_collateral.py +0 -0
  65. {dbos-1.15.0a8 → dbos-1.15.0a9}/tests/client_worker.py +0 -0
  66. {dbos-1.15.0a8 → dbos-1.15.0a9}/tests/conftest.py +0 -0
  67. {dbos-1.15.0a8 → dbos-1.15.0a9}/tests/dupname_classdefs1.py +0 -0
  68. {dbos-1.15.0a8 → dbos-1.15.0a9}/tests/dupname_classdefsa.py +0 -0
  69. {dbos-1.15.0a8 → dbos-1.15.0a9}/tests/more_classdefs.py +0 -0
  70. {dbos-1.15.0a8 → dbos-1.15.0a9}/tests/queuedworkflow.py +0 -0
  71. {dbos-1.15.0a8 → dbos-1.15.0a9}/tests/script_without_fastapi.py +0 -0
  72. {dbos-1.15.0a8 → dbos-1.15.0a9}/tests/test_admin_server.py +0 -0
  73. {dbos-1.15.0a8 → dbos-1.15.0a9}/tests/test_async_workflow_management.py +0 -0
  74. {dbos-1.15.0a8 → dbos-1.15.0a9}/tests/test_classdecorators.py +0 -0
  75. {dbos-1.15.0a8 → dbos-1.15.0a9}/tests/test_cli.py +0 -0
  76. {dbos-1.15.0a8 → dbos-1.15.0a9}/tests/test_client.py +0 -0
  77. {dbos-1.15.0a8 → dbos-1.15.0a9}/tests/test_concurrency.py +0 -0
  78. {dbos-1.15.0a8 → dbos-1.15.0a9}/tests/test_config.py +0 -0
  79. {dbos-1.15.0a8 → dbos-1.15.0a9}/tests/test_croniter.py +0 -0
  80. {dbos-1.15.0a8 → dbos-1.15.0a9}/tests/test_debouncer.py +0 -0
  81. {dbos-1.15.0a8 → dbos-1.15.0a9}/tests/test_debug.py +0 -0
  82. {dbos-1.15.0a8 → dbos-1.15.0a9}/tests/test_docker_secrets.py +0 -0
  83. {dbos-1.15.0a8 → dbos-1.15.0a9}/tests/test_failures.py +0 -0
  84. {dbos-1.15.0a8 → dbos-1.15.0a9}/tests/test_fastapi.py +0 -0
  85. {dbos-1.15.0a8 → dbos-1.15.0a9}/tests/test_fastapi_roles.py +0 -0
  86. {dbos-1.15.0a8 → dbos-1.15.0a9}/tests/test_flask.py +0 -0
  87. {dbos-1.15.0a8 → dbos-1.15.0a9}/tests/test_kafka.py +0 -0
  88. {dbos-1.15.0a8 → dbos-1.15.0a9}/tests/test_outcome.py +0 -0
  89. {dbos-1.15.0a8 → dbos-1.15.0a9}/tests/test_package.py +0 -0
  90. {dbos-1.15.0a8 → dbos-1.15.0a9}/tests/test_queue.py +0 -0
  91. {dbos-1.15.0a8 → dbos-1.15.0a9}/tests/test_scheduler.py +0 -0
  92. {dbos-1.15.0a8 → dbos-1.15.0a9}/tests/test_schema_migration.py +0 -0
  93. {dbos-1.15.0a8 → dbos-1.15.0a9}/tests/test_singleton.py +0 -0
  94. {dbos-1.15.0a8 → dbos-1.15.0a9}/tests/test_spans.py +0 -0
  95. {dbos-1.15.0a8 → dbos-1.15.0a9}/tests/test_sqlalchemy.py +0 -0
  96. {dbos-1.15.0a8 → dbos-1.15.0a9}/tests/test_streaming.py +0 -0
  97. {dbos-1.15.0a8 → dbos-1.15.0a9}/tests/test_workflow_introspection.py +0 -0
  98. {dbos-1.15.0a8 → dbos-1.15.0a9}/tests/test_workflow_management.py +0 -0
  99. {dbos-1.15.0a8 → dbos-1.15.0a9}/version/__init__.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: dbos
3
- Version: 1.15.0a8
3
+ Version: 1.15.0a9
4
4
  Summary: Ultra-lightweight durable execution in Python
5
5
  Author-Email: "DBOS, Inc." <contact@dbos.dev>
6
6
  License: MIT
@@ -16,6 +16,7 @@ from typing import (
16
16
  AsyncGenerator,
17
17
  Callable,
18
18
  Coroutine,
19
+ Dict,
19
20
  Generator,
20
21
  Generic,
21
22
  List,
@@ -974,6 +975,33 @@ class DBOS:
974
975
  lambda: DBOS.get_event(workflow_id, key, timeout_seconds)
975
976
  )
976
977
 
978
+ @classmethod
979
+ def get_all_events(cls, workflow_id: str) -> Dict[str, Any]:
980
+ """
981
+ Get all events currently present for a workflow ID.
982
+ Args:
983
+ workflow_id: The workflow ID for which to get events
984
+ Returns:
985
+ A dictionary mapping event keys to their deserialized values
986
+ """
987
+
988
+ def fn() -> Dict[str, Any]:
989
+ return _get_dbos_instance()._sys_db.get_all_events(workflow_id)
990
+
991
+ return _get_dbos_instance()._sys_db.call_function_as_step(fn, "DBOS.get_events")
992
+
993
+ @classmethod
994
+ async def get_all_events_async(cls, workflow_id: str) -> Dict[str, Any]:
995
+ """
996
+ Get all events currently present for a workflow ID.
997
+ Args:
998
+ workflow_id: The workflow ID for which to get events
999
+ Returns:
1000
+ A dictionary mapping event keys to their deserialized values
1001
+ """
1002
+ await cls._configure_asyncio_thread_pool()
1003
+ return await asyncio.to_thread(cls.get_all_events, workflow_id)
1004
+
977
1005
  @classmethod
978
1006
  def _execute_workflow_id(cls, workflow_id: str) -> WorkflowHandle[Any]:
979
1007
  """Execute a workflow by ID (for recovery)."""
@@ -1225,7 +1253,7 @@ class DBOS:
1225
1253
  async def list_workflow_steps_async(cls, workflow_id: str) -> List[StepInfo]:
1226
1254
  await cls._configure_asyncio_thread_pool()
1227
1255
  return await asyncio.to_thread(cls.list_workflow_steps, workflow_id)
1228
-
1256
+
1229
1257
  @classproperty
1230
1258
  def application_version(cls) -> str:
1231
1259
  return GlobalParams.app_version
@@ -1567,6 +1567,32 @@ class SystemDatabase(ABC):
1567
1567
  }
1568
1568
  self._record_operation_result_txn(output, conn=c)
1569
1569
 
1570
+ def get_all_events(self, workflow_id: str) -> Dict[str, Any]:
1571
+ """
1572
+ Get all events currently present for a workflow ID.
1573
+
1574
+ Args:
1575
+ workflow_id: The workflow UUID to get events for
1576
+
1577
+ Returns:
1578
+ A dictionary mapping event keys to their deserialized values
1579
+ """
1580
+ with self.engine.begin() as c:
1581
+ rows = c.execute(
1582
+ sa.select(
1583
+ SystemSchema.workflow_events.c.key,
1584
+ SystemSchema.workflow_events.c.value,
1585
+ ).where(SystemSchema.workflow_events.c.workflow_uuid == workflow_id)
1586
+ ).fetchall()
1587
+
1588
+ events: Dict[str, Any] = {}
1589
+ for row in rows:
1590
+ key = row[0]
1591
+ value = _serialization.deserialize(row[1])
1592
+ events[key] = value
1593
+
1594
+ return events
1595
+
1570
1596
  @db_retry()
1571
1597
  def get_event(
1572
1598
  self,
@@ -34,7 +34,7 @@ classifiers = [
34
34
  "Topic :: Software Development :: Libraries :: Python Modules",
35
35
  "Framework :: AsyncIO",
36
36
  ]
37
- version = "1.15.0a8"
37
+ version = "1.15.0a9"
38
38
 
39
39
  [project.license]
40
40
  text = "MIT"
@@ -606,3 +606,43 @@ async def test_workflow_with_task_cancellation(dbos: DBOS) -> None:
606
606
  # Verify the workflow completes despite the task cancellation
607
607
  handle: WorkflowHandleAsync[str] = await DBOS.retrieve_workflow_async(wfid)
608
608
  assert await handle.get_result() == "completed"
609
+
610
+
611
+ @pytest.mark.asyncio
612
+ async def test_get_events_async(dbos: DBOS) -> None:
613
+ """Test the async version of get_events function that retrieves all events for a workflow."""
614
+
615
+ @DBOS.workflow()
616
+ async def async_events_workflow() -> str:
617
+ # Set multiple events using async methods
618
+ await DBOS.set_event_async("event1", "value1")
619
+ await DBOS.set_event_async("event2", {"nested": "data", "count": 42})
620
+ await DBOS.set_event_async("event3", [1, 2, 3, 4, 5])
621
+ return "completed"
622
+
623
+ # Execute the workflow
624
+ handle = await DBOS.start_workflow_async(async_events_workflow)
625
+ result = await handle.get_result()
626
+ assert result == "completed"
627
+
628
+ # Get all events for the workflow using async method
629
+ events = await DBOS.get_all_events_async(handle.workflow_id)
630
+
631
+ # Verify all events are present with correct values
632
+ assert len(events) == 3
633
+ assert events["event1"] == "value1"
634
+ assert events["event2"] == {"nested": "data", "count": 42}
635
+ assert events["event3"] == [1, 2, 3, 4, 5]
636
+
637
+ # Test with a workflow that has no events
638
+ @DBOS.workflow()
639
+ async def no_events_workflow() -> str:
640
+ await DBOS.sleep_async(0.01)
641
+ return "no events"
642
+
643
+ handle2 = await DBOS.start_workflow_async(no_events_workflow)
644
+ await handle2.get_result()
645
+
646
+ # Should return empty dict for workflow with no events
647
+ events2 = await DBOS.get_all_events_async(handle2.workflow_id)
648
+ assert events2 == {}
@@ -1890,3 +1890,52 @@ def test_custom_engine(
1890
1890
  steps = client.list_workflow_steps(handle.workflow_id)
1891
1891
  assert len(steps) == 3
1892
1892
  assert "setEvent" in steps[0]["function_name"]
1893
+
1894
+
1895
+ def test_get_events(dbos: DBOS) -> None:
1896
+
1897
+ @DBOS.workflow()
1898
+ def events_workflow() -> str:
1899
+ # Set multiple events
1900
+ DBOS.set_event("event1", "value1")
1901
+ DBOS.set_event("event2", {"nested": "data", "count": 42})
1902
+ DBOS.set_event("event3", [1, 2, 3, 4, 5])
1903
+ return "completed"
1904
+
1905
+ # Execute the workflow
1906
+ handle = DBOS.start_workflow(events_workflow)
1907
+ result = handle.get_result()
1908
+ assert result == "completed"
1909
+
1910
+ # Get events, verify they are present with correct values
1911
+ def get_events() -> None:
1912
+ events = DBOS.get_all_events(handle.workflow_id)
1913
+
1914
+ assert len(events) == 3
1915
+ assert events["event1"] == "value1"
1916
+ assert events["event2"] == {"nested": "data", "count": 42}
1917
+ assert events["event3"] == [1, 2, 3, 4, 5]
1918
+
1919
+ # Verify it works
1920
+ get_events()
1921
+
1922
+ # Run it as a workflow, verify it still works
1923
+ get_events_workflow = DBOS.workflow()(get_events)
1924
+ wfid = str(uuid.uuid4())
1925
+ with SetWorkflowID(wfid):
1926
+ get_events_workflow()
1927
+ steps = DBOS.list_workflow_steps(wfid)
1928
+ assert len(steps) == 1
1929
+ assert steps[0]["function_name"] == "DBOS.get_events"
1930
+
1931
+ # Test with a workflow that has no events
1932
+ @DBOS.workflow()
1933
+ def no_events_workflow() -> str:
1934
+ return "no events"
1935
+
1936
+ handle2 = DBOS.start_workflow(no_events_workflow)
1937
+ handle2.get_result()
1938
+
1939
+ # Should return empty dict for workflow with no events
1940
+ events2 = DBOS.get_all_events(handle2.workflow_id)
1941
+ assert events2 == {}
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
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