dbos 0.6.1__py3-none-any.whl → 0.7.0__py3-none-any.whl

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.

Potentially problematic release.


This version of dbos might be problematic. Click here for more details.

dbos/system_database.py CHANGED
@@ -1,12 +1,11 @@
1
1
  import datetime
2
2
  import os
3
- import select
4
3
  import threading
5
4
  import time
6
5
  from enum import Enum
7
6
  from typing import Any, Dict, List, Literal, Optional, Sequence, Set, TypedDict, cast
8
7
 
9
- import psycopg2
8
+ import psycopg
10
9
  import sqlalchemy as sa
11
10
  import sqlalchemy.dialects.postgresql as pg
12
11
  from alembic import command
@@ -14,11 +13,7 @@ from alembic.config import Config
14
13
  from sqlalchemy.exc import DBAPIError
15
14
 
16
15
  import dbos.utils as utils
17
- from dbos.error import (
18
- DBOSDuplicateWorkflowEventError,
19
- DBOSNonExistentWorkflowError,
20
- DBOSWorkflowConflictIDError,
21
- )
16
+ from dbos.error import DBOSNonExistentWorkflowError, DBOSWorkflowConflictIDError
22
17
 
23
18
  from .dbos_config import ConfigFile
24
19
  from .logger import dbos_logger
@@ -33,10 +28,11 @@ class WorkflowStatusString(Enum):
33
28
  ERROR = "ERROR"
34
29
  RETRIES_EXCEEDED = "RETRIES_EXCEEDED"
35
30
  CANCELLED = "CANCELLED"
31
+ ENQUEUED = "ENQUEUED"
36
32
 
37
33
 
38
34
  WorkflowStatuses = Literal[
39
- "PENDING", "SUCCESS", "ERROR", "RETRIES_EXCEEDED", "CANCELLED"
35
+ "PENDING", "SUCCESS", "ERROR", "RETRIES_EXCEEDED", "CANCELLED", "ENQUEUED"
40
36
  ]
41
37
 
42
38
 
@@ -61,6 +57,7 @@ class WorkflowStatusInternal(TypedDict):
61
57
  authenticated_user: Optional[str]
62
58
  assumed_role: Optional[str]
63
59
  authenticated_roles: Optional[str] # JSON list of roles.
60
+ queue_name: Optional[str]
64
61
 
65
62
 
66
63
  class RecordedResult(TypedDict):
@@ -154,7 +151,7 @@ class SystemDatabase:
154
151
 
155
152
  # If the system database does not already exist, create it
156
153
  postgres_db_url = sa.URL.create(
157
- "postgresql",
154
+ "postgresql+psycopg",
158
155
  username=config["database"]["username"],
159
156
  password=config["database"]["password"],
160
157
  host=config["database"]["hostname"],
@@ -172,7 +169,7 @@ class SystemDatabase:
172
169
  engine.dispose()
173
170
 
174
171
  system_db_url = sa.URL.create(
175
- "postgresql",
172
+ "postgresql+psycopg",
176
173
  username=config["database"]["username"],
177
174
  password=config["database"]["password"],
178
175
  host=config["database"]["hostname"],
@@ -196,7 +193,7 @@ class SystemDatabase:
196
193
  )
197
194
  command.upgrade(alembic_cfg, "head")
198
195
 
199
- self.notification_conn: Optional[psycopg2.extensions.connection] = None
196
+ self.notification_conn: Optional[psycopg.connection.Connection] = None
200
197
  self.notifications_map: Dict[str, threading.Condition] = {}
201
198
  self.workflow_events_map: Dict[str, threading.Condition] = {}
202
199
 
@@ -247,6 +244,7 @@ class SystemDatabase:
247
244
  authenticated_user=status["authenticated_user"],
248
245
  authenticated_roles=status["authenticated_roles"],
249
246
  assumed_role=status["assumed_role"],
247
+ queue_name=status["queue_name"],
250
248
  )
251
249
  if replace:
252
250
  cmd = cmd.on_conflict_do_update(
@@ -320,6 +318,7 @@ class SystemDatabase:
320
318
  SystemSchema.workflow_status.c.authenticated_user,
321
319
  SystemSchema.workflow_status.c.authenticated_roles,
322
320
  SystemSchema.workflow_status.c.assumed_role,
321
+ SystemSchema.workflow_status.c.queue_name,
323
322
  ).where(SystemSchema.workflow_status.c.workflow_uuid == workflow_uuid)
324
323
  ).fetchone()
325
324
  if row is None:
@@ -340,6 +339,7 @@ class SystemDatabase:
340
339
  "authenticated_user": row[6],
341
340
  "authenticated_roles": row[7],
342
341
  "assumed_role": row[8],
342
+ "queue_name": row[9],
343
343
  }
344
344
  return status
345
345
 
@@ -379,6 +379,7 @@ class SystemDatabase:
379
379
  SystemSchema.workflow_status.c.authenticated_user,
380
380
  SystemSchema.workflow_status.c.authenticated_roles,
381
381
  SystemSchema.workflow_status.c.assumed_role,
382
+ SystemSchema.workflow_status.c.queue_name,
382
383
  ).where(SystemSchema.workflow_status.c.workflow_uuid == workflow_uuid)
383
384
  ).fetchone()
384
385
  if row is None:
@@ -399,6 +400,7 @@ class SystemDatabase:
399
400
  "authenticated_user": row[7],
400
401
  "authenticated_roles": row[8],
401
402
  "assumed_role": row[9],
403
+ "queue_name": row[10],
402
404
  }
403
405
  return status
404
406
 
@@ -565,11 +567,9 @@ class SystemDatabase:
565
567
  with self.engine.begin() as c:
566
568
  c.execute(sql)
567
569
  except DBAPIError as dbapi_error:
568
- if dbapi_error.orig.pgcode == "23505": # type: ignore
570
+ if dbapi_error.orig.sqlstate == "23505": # type: ignore
569
571
  raise DBOSWorkflowConflictIDError(result["workflow_uuid"])
570
- raise dbapi_error
571
- except Exception as e:
572
- raise e
572
+ raise
573
573
 
574
574
  def check_operation_execution(
575
575
  self, workflow_uuid: str, function_id: int, conn: Optional[sa.Connection] = None
@@ -623,11 +623,9 @@ class SystemDatabase:
623
623
  )
624
624
  except DBAPIError as dbapi_error:
625
625
  # Foreign key violation
626
- if dbapi_error.orig.pgcode == "23503": # type: ignore
626
+ if dbapi_error.orig.sqlstate == "23503": # type: ignore
627
627
  raise DBOSNonExistentWorkflowError(destination_uuid)
628
- raise dbapi_error
629
- except Exception as e:
630
- raise e
628
+ raise
631
629
  output: OperationResultInternal = {
632
630
  "workflow_uuid": workflow_uuid,
633
631
  "function_id": function_id,
@@ -729,69 +727,59 @@ class SystemDatabase:
729
727
  return message
730
728
 
731
729
  def _notification_listener(self) -> None:
732
- notification_cursor: Optional[psycopg2.extensions.cursor] = None
733
730
  while self._run_background_processes:
734
731
  try:
735
- # Listen to notifications
736
- self.notification_conn = psycopg2.connect(
737
- self.engine.url.render_as_string(hide_password=False)
732
+ # since we're using the psycopg connection directly, we need a url without the "+pycopg" suffix
733
+ url = sa.URL.create(
734
+ "postgresql", **self.engine.url.translate_connect_args()
738
735
  )
739
- self.notification_conn.set_isolation_level(
740
- psycopg2.extensions.ISOLATION_LEVEL_AUTOCOMMIT
736
+ # Listen to notifications
737
+ self.notification_conn = psycopg.connect(
738
+ url.render_as_string(hide_password=False), autocommit=True
741
739
  )
742
- notification_cursor = self.notification_conn.cursor()
743
740
 
744
- notification_cursor.execute("LISTEN dbos_notifications_channel")
745
- notification_cursor.execute("LISTEN dbos_workflow_events_channel")
741
+ self.notification_conn.execute("LISTEN dbos_notifications_channel")
742
+ self.notification_conn.execute("LISTEN dbos_workflow_events_channel")
743
+
746
744
  while self._run_background_processes:
747
- if select.select([self.notification_conn], [], [], 60) == (
748
- [],
749
- [],
750
- [],
751
- ):
752
- continue
753
- else:
754
- self.notification_conn.poll()
755
- while self.notification_conn.notifies:
756
- notify = self.notification_conn.notifies.pop(0)
757
- channel = notify.channel
758
- dbos_logger.debug(
759
- f"Received notification on channel: {channel}, payload: {notify.payload}"
760
- )
761
- if channel == "dbos_notifications_channel":
762
- if (
763
- notify.payload
764
- and notify.payload in self.notifications_map
765
- ):
766
- condition = self.notifications_map[notify.payload]
767
- condition.acquire()
768
- condition.notify_all()
769
- condition.release()
770
- dbos_logger.debug(
771
- f"Signaled notifications condition for {notify.payload}"
772
- )
773
- elif channel == "dbos_workflow_events_channel":
774
- if (
775
- notify.payload
776
- and notify.payload in self.workflow_events_map
777
- ):
778
- condition = self.workflow_events_map[notify.payload]
779
- condition.acquire()
780
- condition.notify_all()
781
- condition.release()
782
- dbos_logger.debug(
783
- f"Signaled workflow_events condition for {notify.payload}"
784
- )
785
- else:
786
- dbos_logger.error(f"Unknown channel: {channel}")
745
+ gen = self.notification_conn.notifies(timeout=60)
746
+ for notify in gen:
747
+ channel = notify.channel
748
+ dbos_logger.debug(
749
+ f"Received notification on channel: {channel}, payload: {notify.payload}"
750
+ )
751
+ if channel == "dbos_notifications_channel":
752
+ if (
753
+ notify.payload
754
+ and notify.payload in self.notifications_map
755
+ ):
756
+ condition = self.notifications_map[notify.payload]
757
+ condition.acquire()
758
+ condition.notify_all()
759
+ condition.release()
760
+ dbos_logger.debug(
761
+ f"Signaled notifications condition for {notify.payload}"
762
+ )
763
+ elif channel == "dbos_workflow_events_channel":
764
+ if (
765
+ notify.payload
766
+ and notify.payload in self.workflow_events_map
767
+ ):
768
+ condition = self.workflow_events_map[notify.payload]
769
+ condition.acquire()
770
+ condition.notify_all()
771
+ condition.release()
772
+ dbos_logger.debug(
773
+ f"Signaled workflow_events condition for {notify.payload}"
774
+ )
775
+ else:
776
+ dbos_logger.error(f"Unknown channel: {channel}")
787
777
  except Exception as e:
788
778
  if self._run_background_processes:
789
779
  dbos_logger.error(f"Notification listener error: {e}")
790
780
  time.sleep(1)
791
781
  # Then the loop will try to reconnect and restart the listener
792
782
  finally:
793
- if notification_cursor is not None:
794
- notification_cursor.close()
795
783
  if self.notification_conn is not None:
796
784
  self.notification_conn.close()
797
785
 
@@ -839,20 +827,18 @@ class SystemDatabase:
839
827
  if recorded_output is not None:
840
828
  return # Already sent before
841
829
 
842
- try:
843
- c.execute(
844
- pg.insert(SystemSchema.workflow_events).values(
845
- workflow_uuid=workflow_uuid,
846
- key=key,
847
- value=utils.serialize(message),
848
- )
830
+ c.execute(
831
+ pg.insert(SystemSchema.workflow_events)
832
+ .values(
833
+ workflow_uuid=workflow_uuid,
834
+ key=key,
835
+ value=utils.serialize(message),
849
836
  )
850
- except DBAPIError as dbapi_error:
851
- if dbapi_error.orig.pgcode == "23505": # type: ignore
852
- raise DBOSDuplicateWorkflowEventError(workflow_uuid, key)
853
- raise dbapi_error
854
- except Exception as e:
855
- raise e
837
+ .on_conflict_do_update(
838
+ index_elements=["workflow_uuid", "key"],
839
+ set_={"value": utils.serialize(message)},
840
+ )
841
+ )
856
842
  output: OperationResultInternal = {
857
843
  "workflow_uuid": workflow_uuid,
858
844
  "function_id": function_id,
@@ -1026,3 +1012,50 @@ class SystemDatabase:
1026
1012
  len(self._workflow_status_buffer) == 0
1027
1013
  and len(self._workflow_inputs_buffer) == 0
1028
1014
  )
1015
+
1016
+ def enqueue(self, workflow_id: str, queue_name: str) -> None:
1017
+ with self.engine.begin() as c:
1018
+ c.execute(
1019
+ pg.insert(SystemSchema.job_queue)
1020
+ .values(
1021
+ workflow_uuid=workflow_id,
1022
+ queue_name=queue_name,
1023
+ )
1024
+ .on_conflict_do_nothing()
1025
+ )
1026
+
1027
+ def start_queued_workflows(
1028
+ self, queue_name: str, concurrency: Optional[int]
1029
+ ) -> List[str]:
1030
+ with self.engine.begin() as c:
1031
+ query = sa.select(SystemSchema.job_queue.c.workflow_uuid).where(
1032
+ SystemSchema.job_queue.c.queue_name == queue_name
1033
+ )
1034
+ if concurrency is not None:
1035
+ query = query.order_by(
1036
+ SystemSchema.job_queue.c.created_at_epoch_ms.asc()
1037
+ ).limit(concurrency)
1038
+ rows = c.execute(query).fetchall()
1039
+ dequeued_ids: List[str] = [row[0] for row in rows]
1040
+ ret_ids = []
1041
+ for id in dequeued_ids:
1042
+ result = c.execute(
1043
+ SystemSchema.workflow_status.update()
1044
+ .where(SystemSchema.workflow_status.c.workflow_uuid == id)
1045
+ .where(
1046
+ SystemSchema.workflow_status.c.status
1047
+ == WorkflowStatusString.ENQUEUED.value
1048
+ )
1049
+ .values(status=WorkflowStatusString.PENDING.value)
1050
+ )
1051
+ if result.rowcount > 0:
1052
+ ret_ids.append(id)
1053
+ return ret_ids
1054
+
1055
+ def remove_from_queue(self, workflow_id: str) -> None:
1056
+ with self.engine.begin() as c:
1057
+ c.execute(
1058
+ sa.delete(SystemSchema.job_queue).where(
1059
+ SystemSchema.job_queue.c.workflow_uuid == workflow_id
1060
+ )
1061
+ )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: dbos
3
- Version: 0.6.1
3
+ Version: 0.7.0
4
4
  Summary: Ultra-lightweight durable execution in Python
5
5
  Author-Email: "DBOS, Inc." <contact@dbos.dev>
6
6
  License: MIT
@@ -8,7 +8,6 @@ Requires-Python: >=3.9
8
8
  Requires-Dist: pyyaml>=6.0.2
9
9
  Requires-Dist: jsonschema>=4.23.0
10
10
  Requires-Dist: alembic>=1.13.2
11
- Requires-Dist: psycopg2-binary>=2.9.9
12
11
  Requires-Dist: typing-extensions>=4.12.2; python_version < "3.10"
13
12
  Requires-Dist: typer>=0.12.3
14
13
  Requires-Dist: jsonpickle>=3.2.2
@@ -19,6 +18,7 @@ Requires-Dist: python-dateutil>=2.9.0.post0
19
18
  Requires-Dist: fastapi[standard]>=0.112.1
20
19
  Requires-Dist: psutil>=6.0.0
21
20
  Requires-Dist: tomlkit>=0.13.2
21
+ Requires-Dist: psycopg>=3.2.1
22
22
  Description-Content-Type: text/markdown
23
23
 
24
24
 
@@ -1,38 +1,40 @@
1
- dbos-0.6.1.dist-info/METADATA,sha256=3WgP4NAQT1ZNQbEkLV9hupdBqevptUrwS2k6WpJ6dss,5016
2
- dbos-0.6.1.dist-info/WHEEL,sha256=rSwsxJWe3vzyR5HCwjWXQruDgschpei4h_giTm0dJVE,90
3
- dbos-0.6.1.dist-info/entry_points.txt,sha256=3PmOPbM4FYxEmggRRdJw0oAsiBzKR8U0yx7bmwUmMOM,39
4
- dbos-0.6.1.dist-info/licenses/LICENSE,sha256=VGZit_a5-kdw9WT6fY5jxAWVwGQzgLFyPWrcVVUhVNU,1067
5
- dbos/__init__.py,sha256=heuB3bqRXlVdfea9sKHBIVKSqFP6UuwhQecQfV4hyas,642
1
+ dbos-0.7.0.dist-info/METADATA,sha256=l5ADRiFrTFSL2RzqUeXd6R8_CI9guOA5D_Zu75-Wexg,5008
2
+ dbos-0.7.0.dist-info/WHEEL,sha256=Vza3XR51HW1KmFP0iIMUVYIvz0uQuKJpIXKYOBGQyFQ,90
3
+ dbos-0.7.0.dist-info/entry_points.txt,sha256=z6GcVANQV7Uw_82H9Ob2axJX6V3imftyZsljdh-M1HU,54
4
+ dbos-0.7.0.dist-info/licenses/LICENSE,sha256=VGZit_a5-kdw9WT6fY5jxAWVwGQzgLFyPWrcVVUhVNU,1067
5
+ dbos/__init__.py,sha256=jjlBFzSAzO2e-LD5IKJw7bRqZjrxpF5Sn-_JUJJptHU,680
6
6
  dbos/admin_sever.py,sha256=Qg5T3YRrbPW05PR_99yAaxgo1ugQrAp_uTeTqSfjm_k,3397
7
- dbos/application_database.py,sha256=1K3kE96BgGi_QWOd2heXluyNTwFAwlUVuAR6JKKUqf0,5659
7
+ dbos/application_database.py,sha256=knFK8We8y6WrIpnFCKvFq5hvSuFQqUuJqOqDpSVMCPI,5521
8
8
  dbos/cli.py,sha256=z5dXbbnGWzSC3E1rfS8Lp1_OIImzcDKM7jP-iu_Q4aI,8602
9
- dbos/context.py,sha256=NVMGyvAa2RIiBVspvDz-8MBk_BQyGyYdPdorgO-GSng,16407
10
- dbos/core.py,sha256=jeqO8DABPAUrFlJXOfRfFDSnA8BGwiPnMa1JNbGuYLs,28584
9
+ dbos/context.py,sha256=1Xp0i-ZP72Vj6eMdHuyfXi9RHnoT2w4MZ2Kx1CrKnQ8,16559
10
+ dbos/core.py,sha256=LnQRHLjfpdlzlRkElduay8nObNMyRNC8SJSZEzqei7o,29161
11
11
  dbos/dbos-config.schema.json,sha256=azpfmoDZg7WfSy3kvIsk9iEiKB_-VZt03VEOoXJAkqE,5331
12
- dbos/dbos.py,sha256=wzL51K7bY3J8grHXi0k0F0N09vFVBYWKwI0DGxyN4MY,29730
13
- dbos/dbos_config.py,sha256=ih_TD_1zTKhPKxk8TPdEIp3ihu82R06SGKg-s4rHxws,5344
12
+ dbos/dbos.py,sha256=RtDcvKe4sm1TlnCGU4cyex-UI7hMMlhgzmOl1NuRLo4,29294
13
+ dbos/dbos_config.py,sha256=NJVze2GkKgYUmcPP31Unb-QpsA0TzImEeQGJgVq6W6k,5352
14
14
  dbos/decorators.py,sha256=lbPefsLK6Cya4cb7TrOcLglOpGT3pc6qjZdsQKlfZLg,629
15
- dbos/error.py,sha256=DDhB0VHmoZE_CP51ICdFMZSL2gmVS3Dm0aPNWncci94,3876
16
- dbos/fastapi.py,sha256=s7LnwwYVpJm_QZZwBW5um8NV2Q2Qx85uVZqGcKlSZAo,1881
15
+ dbos/error.py,sha256=c2y7d3Cbb-ZOO-M9txcCxuyPE1bdnwKrJnXgJXYb-pQ,3437
16
+ dbos/fastapi.py,sha256=gx9hlpxYOiwbuhSlbY9bn5C-F_FsCbrJvkX9ZAvDG6U,3418
17
17
  dbos/flask.py,sha256=azr4geMEGuuTBCyxIZmgDmmP-6s_pTIF-lGyp9Q4IB8,2430
18
- dbos/kafka.py,sha256=FtngQHBu2TKfyDF7GFsKJAawFQJiOFxgKEUlNNxrdrw,3055
18
+ dbos/kafka.py,sha256=LH3hbNapnkjLcuXNUtdGU0398JafWb-t0GwUl3LOzkc,3645
19
19
  dbos/kafka_message.py,sha256=NYvOXNG3Qn7bghn1pv3fg4Pbs86ILZGcK4IB-MLUNu0,409
20
20
  dbos/logger.py,sha256=D-aFSZUCHBP34J1IZ5YNkTrJW-rDiH3py_v9jLU4Yrk,3565
21
21
  dbos/migrations/env.py,sha256=38SIGVbmn_VV2x2u1aHLcPOoWgZ84eCymf3g_NljmbU,1626
22
22
  dbos/migrations/script.py.mako,sha256=MEqL-2qATlST9TAOeYgscMn1uy6HUS9NFvDgl93dMj8,635
23
23
  dbos/migrations/versions/5c361fc04708_added_system_tables.py,sha256=QMgFMb0aLgC25YicsvPSr6AHRCA6Zd66hyaRUhwKzrQ,6404
24
24
  dbos/migrations/versions/a3b18ad34abe_added_triggers.py,sha256=Rv0ZsZYZ_WdgGEULYsPfnp4YzaO5L198gDTgYY39AVA,2022
25
+ dbos/migrations/versions/eab0cc1d9a14_job_queue.py,sha256=_9-FCW-zOpCQfblTS_yRLtFiUaWlC1tM4BoKBTDeH9k,1395
25
26
  dbos/py.typed,sha256=QfzXT1Ktfk3Rj84akygc7_42z0lRpCq0Ilh8OXI6Zas,44
26
- dbos/recovery.py,sha256=xfwQFWNuD8DXg5HD5_-3tG7Neo9j-x1lrqiwtn5FSh8,2015
27
+ dbos/queue.py,sha256=5unMPX1ThoVWfXOR2IUSeIjgATgcX_YmZS3Fz1Uoc7o,1228
28
+ dbos/recovery.py,sha256=zqtO_ExGoIErLMVnbneU3VeHLVWvhV4jnfqssAVlQQk,2016
27
29
  dbos/registrations.py,sha256=gMI-u05tv5bpvyddQGtoUgCsqARx51aOY7p0JXPafQo,6539
28
30
  dbos/request.py,sha256=-FIwtknayvRl6OjvqO4V2GySVzSdP1Ft3cc9ZBS-PLY,928
29
31
  dbos/roles.py,sha256=7Lh7uwUq1dpa6TXCOHre4mPTd5qmXzK_QPkvYR52DXg,2285
30
32
  dbos/scheduler/croniter.py,sha256=hbhgfsHBqclUS8VeLnJ9PSE9Z54z6mi4nnrr1aUXn0k,47561
31
- dbos/scheduler/scheduler.py,sha256=uO4_9jmWW2rLv1ODL3lc1cE_37ZaVTgnvmFx_FAlN50,1472
33
+ dbos/scheduler/scheduler.py,sha256=Sz4EIpAtur7so2YajTic64GrTpa4qPw8QxXn0M34v80,1360
32
34
  dbos/schemas/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
33
35
  dbos/schemas/application_database.py,sha256=q_Wr2XbiZNBYFkOtu7uKavo1T_cSOBblxKGHThYGGsY,962
34
- dbos/schemas/system_database.py,sha256=5V3vqnEzry0Hn7ZbVS9Gs_dJKia8uX8p7mGC82Ru8rk,4303
35
- dbos/system_database.py,sha256=BZ8yE79FH9NZhEt8AAYNXy0-wMcKLBAq8VPdZbfidR4,40564
36
+ dbos/schemas/system_database.py,sha256=ed4c1UntsD-cqXD0ekM4jvcYYEViavDh_G6c0pVDe7k,4938
37
+ dbos/system_database.py,sha256=VSGFSPubbMokGYsZfRb6cQPltLfjoWM-Re_2Gj9qkRc,41844
36
38
  dbos/templates/hello/README.md,sha256=GhxhBj42wjTt1fWEtwNriHbJuKb66Vzu89G4pxNHw2g,930
37
39
  dbos/templates/hello/__package/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
38
40
  dbos/templates/hello/__package/main.py,sha256=eI0SS9Nwj-fldtiuSzIlIG6dC91GXXwdRsoHxv6S_WI,2719
@@ -46,4 +48,4 @@ dbos/templates/hello/start_postgres_docker.py,sha256=lQVLlYO5YkhGPEgPqwGc7Y8uDKs
46
48
  dbos/tracer.py,sha256=GaXDhdKKF_IQp5SAMipGXiDVwteRKjNbrXyYCH1mor0,2520
47
49
  dbos/utils.py,sha256=hWj9iWDrby2cVEhb0pG-IdnrxLqP64NhkaWUXiLc8bA,402
48
50
  version/__init__.py,sha256=L4sNxecRuqdtSFdpUGX3TtBi9KL3k7YsZVIvv-fv9-A,1678
49
- dbos-0.6.1.dist-info/RECORD,,
51
+ dbos-0.7.0.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: pdm-backend (2.3.3)
2
+ Generator: pdm-backend (2.4.1)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
@@ -1,3 +1,5 @@
1
1
  [console_scripts]
2
2
  dbos = dbos.cli:app
3
3
 
4
+ [gui_scripts]
5
+