dbos 0.20.0a3__tar.gz → 0.20.0a5__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.

Potentially problematic release.


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

Files changed (89) hide show
  1. {dbos-0.20.0a3 → dbos-0.20.0a5}/PKG-INFO +1 -1
  2. {dbos-0.20.0a3 → dbos-0.20.0a5}/dbos/_core.py +21 -1
  3. {dbos-0.20.0a3 → dbos-0.20.0a5}/dbos/_fastapi.py +10 -9
  4. {dbos-0.20.0a3 → dbos-0.20.0a5}/pyproject.toml +1 -1
  5. {dbos-0.20.0a3 → dbos-0.20.0a5}/tests/conftest.py +1 -9
  6. {dbos-0.20.0a3 → dbos-0.20.0a5}/tests/test_fastapi.py +76 -2
  7. {dbos-0.20.0a3 → dbos-0.20.0a5}/LICENSE +0 -0
  8. {dbos-0.20.0a3 → dbos-0.20.0a5}/README.md +0 -0
  9. {dbos-0.20.0a3 → dbos-0.20.0a5}/dbos/__init__.py +0 -0
  10. {dbos-0.20.0a3 → dbos-0.20.0a5}/dbos/_admin_server.py +0 -0
  11. {dbos-0.20.0a3 → dbos-0.20.0a5}/dbos/_app_db.py +0 -0
  12. {dbos-0.20.0a3 → dbos-0.20.0a5}/dbos/_classproperty.py +0 -0
  13. {dbos-0.20.0a3 → dbos-0.20.0a5}/dbos/_cloudutils/authentication.py +0 -0
  14. {dbos-0.20.0a3 → dbos-0.20.0a5}/dbos/_cloudutils/cloudutils.py +0 -0
  15. {dbos-0.20.0a3 → dbos-0.20.0a5}/dbos/_cloudutils/databases.py +0 -0
  16. {dbos-0.20.0a3 → dbos-0.20.0a5}/dbos/_context.py +0 -0
  17. {dbos-0.20.0a3 → dbos-0.20.0a5}/dbos/_croniter.py +0 -0
  18. {dbos-0.20.0a3 → dbos-0.20.0a5}/dbos/_db_wizard.py +0 -0
  19. {dbos-0.20.0a3 → dbos-0.20.0a5}/dbos/_dbos.py +0 -0
  20. {dbos-0.20.0a3 → dbos-0.20.0a5}/dbos/_dbos_config.py +0 -0
  21. {dbos-0.20.0a3 → dbos-0.20.0a5}/dbos/_error.py +0 -0
  22. {dbos-0.20.0a3 → dbos-0.20.0a5}/dbos/_flask.py +0 -0
  23. {dbos-0.20.0a3 → dbos-0.20.0a5}/dbos/_kafka.py +0 -0
  24. {dbos-0.20.0a3 → dbos-0.20.0a5}/dbos/_kafka_message.py +0 -0
  25. {dbos-0.20.0a3 → dbos-0.20.0a5}/dbos/_logger.py +0 -0
  26. {dbos-0.20.0a3 → dbos-0.20.0a5}/dbos/_migrations/env.py +0 -0
  27. {dbos-0.20.0a3 → dbos-0.20.0a5}/dbos/_migrations/script.py.mako +0 -0
  28. {dbos-0.20.0a3 → dbos-0.20.0a5}/dbos/_migrations/versions/04ca4f231047_workflow_queues_executor_id.py +0 -0
  29. {dbos-0.20.0a3 → dbos-0.20.0a5}/dbos/_migrations/versions/50f3227f0b4b_fix_job_queue.py +0 -0
  30. {dbos-0.20.0a3 → dbos-0.20.0a5}/dbos/_migrations/versions/5c361fc04708_added_system_tables.py +0 -0
  31. {dbos-0.20.0a3 → dbos-0.20.0a5}/dbos/_migrations/versions/a3b18ad34abe_added_triggers.py +0 -0
  32. {dbos-0.20.0a3 → dbos-0.20.0a5}/dbos/_migrations/versions/d76646551a6b_job_queue_limiter.py +0 -0
  33. {dbos-0.20.0a3 → dbos-0.20.0a5}/dbos/_migrations/versions/d76646551a6c_workflow_queue.py +0 -0
  34. {dbos-0.20.0a3 → dbos-0.20.0a5}/dbos/_migrations/versions/eab0cc1d9a14_job_queue.py +0 -0
  35. {dbos-0.20.0a3 → dbos-0.20.0a5}/dbos/_outcome.py +0 -0
  36. {dbos-0.20.0a3 → dbos-0.20.0a5}/dbos/_queue.py +0 -0
  37. {dbos-0.20.0a3 → dbos-0.20.0a5}/dbos/_recovery.py +0 -0
  38. {dbos-0.20.0a3 → dbos-0.20.0a5}/dbos/_registrations.py +0 -0
  39. {dbos-0.20.0a3 → dbos-0.20.0a5}/dbos/_request.py +0 -0
  40. {dbos-0.20.0a3 → dbos-0.20.0a5}/dbos/_roles.py +0 -0
  41. {dbos-0.20.0a3 → dbos-0.20.0a5}/dbos/_scheduler.py +0 -0
  42. {dbos-0.20.0a3 → dbos-0.20.0a5}/dbos/_schemas/__init__.py +0 -0
  43. {dbos-0.20.0a3 → dbos-0.20.0a5}/dbos/_schemas/application_database.py +0 -0
  44. {dbos-0.20.0a3 → dbos-0.20.0a5}/dbos/_schemas/system_database.py +0 -0
  45. {dbos-0.20.0a3 → dbos-0.20.0a5}/dbos/_serialization.py +0 -0
  46. {dbos-0.20.0a3 → dbos-0.20.0a5}/dbos/_sys_db.py +0 -0
  47. {dbos-0.20.0a3 → dbos-0.20.0a5}/dbos/_templates/dbos-db-starter/README.md +0 -0
  48. {dbos-0.20.0a3 → dbos-0.20.0a5}/dbos/_templates/dbos-db-starter/__package/__init__.py +0 -0
  49. {dbos-0.20.0a3 → dbos-0.20.0a5}/dbos/_templates/dbos-db-starter/__package/main.py +0 -0
  50. {dbos-0.20.0a3 → dbos-0.20.0a5}/dbos/_templates/dbos-db-starter/__package/schema.py +0 -0
  51. {dbos-0.20.0a3 → dbos-0.20.0a5}/dbos/_templates/dbos-db-starter/alembic.ini +0 -0
  52. {dbos-0.20.0a3 → dbos-0.20.0a5}/dbos/_templates/dbos-db-starter/dbos-config.yaml.dbos +0 -0
  53. {dbos-0.20.0a3 → dbos-0.20.0a5}/dbos/_templates/dbos-db-starter/migrations/env.py.dbos +0 -0
  54. {dbos-0.20.0a3 → dbos-0.20.0a5}/dbos/_templates/dbos-db-starter/migrations/script.py.mako +0 -0
  55. {dbos-0.20.0a3 → dbos-0.20.0a5}/dbos/_templates/dbos-db-starter/migrations/versions/2024_07_31_180642_init.py +0 -0
  56. {dbos-0.20.0a3 → dbos-0.20.0a5}/dbos/_templates/dbos-db-starter/start_postgres_docker.py +0 -0
  57. {dbos-0.20.0a3 → dbos-0.20.0a5}/dbos/_tracer.py +0 -0
  58. {dbos-0.20.0a3 → dbos-0.20.0a5}/dbos/_workflow_commands.py +0 -0
  59. {dbos-0.20.0a3 → dbos-0.20.0a5}/dbos/cli/_github_init.py +0 -0
  60. {dbos-0.20.0a3 → dbos-0.20.0a5}/dbos/cli/_template_init.py +0 -0
  61. {dbos-0.20.0a3 → dbos-0.20.0a5}/dbos/cli/cli.py +0 -0
  62. {dbos-0.20.0a3 → dbos-0.20.0a5}/dbos/dbos-config.schema.json +0 -0
  63. {dbos-0.20.0a3 → dbos-0.20.0a5}/dbos/py.typed +0 -0
  64. {dbos-0.20.0a3 → dbos-0.20.0a5}/tests/__init__.py +0 -0
  65. {dbos-0.20.0a3 → dbos-0.20.0a5}/tests/atexit_no_ctor.py +0 -0
  66. {dbos-0.20.0a3 → dbos-0.20.0a5}/tests/atexit_no_launch.py +0 -0
  67. {dbos-0.20.0a3 → dbos-0.20.0a5}/tests/classdefs.py +0 -0
  68. {dbos-0.20.0a3 → dbos-0.20.0a5}/tests/more_classdefs.py +0 -0
  69. {dbos-0.20.0a3 → dbos-0.20.0a5}/tests/queuedworkflow.py +0 -0
  70. {dbos-0.20.0a3 → dbos-0.20.0a5}/tests/test_admin_server.py +0 -0
  71. {dbos-0.20.0a3 → dbos-0.20.0a5}/tests/test_async.py +0 -0
  72. {dbos-0.20.0a3 → dbos-0.20.0a5}/tests/test_classdecorators.py +0 -0
  73. {dbos-0.20.0a3 → dbos-0.20.0a5}/tests/test_concurrency.py +0 -0
  74. {dbos-0.20.0a3 → dbos-0.20.0a5}/tests/test_config.py +0 -0
  75. {dbos-0.20.0a3 → dbos-0.20.0a5}/tests/test_croniter.py +0 -0
  76. {dbos-0.20.0a3 → dbos-0.20.0a5}/tests/test_dbos.py +0 -0
  77. {dbos-0.20.0a3 → dbos-0.20.0a5}/tests/test_failures.py +0 -0
  78. {dbos-0.20.0a3 → dbos-0.20.0a5}/tests/test_fastapi_roles.py +0 -0
  79. {dbos-0.20.0a3 → dbos-0.20.0a5}/tests/test_flask.py +0 -0
  80. {dbos-0.20.0a3 → dbos-0.20.0a5}/tests/test_kafka.py +0 -0
  81. {dbos-0.20.0a3 → dbos-0.20.0a5}/tests/test_outcome.py +0 -0
  82. {dbos-0.20.0a3 → dbos-0.20.0a5}/tests/test_package.py +0 -0
  83. {dbos-0.20.0a3 → dbos-0.20.0a5}/tests/test_queue.py +0 -0
  84. {dbos-0.20.0a3 → dbos-0.20.0a5}/tests/test_scheduler.py +0 -0
  85. {dbos-0.20.0a3 → dbos-0.20.0a5}/tests/test_schema_migration.py +0 -0
  86. {dbos-0.20.0a3 → dbos-0.20.0a5}/tests/test_singleton.py +0 -0
  87. {dbos-0.20.0a3 → dbos-0.20.0a5}/tests/test_spans.py +0 -0
  88. {dbos-0.20.0a3 → dbos-0.20.0a5}/tests/test_workflow_cmds.py +0 -0
  89. {dbos-0.20.0a3 → dbos-0.20.0a5}/version/__init__.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: dbos
3
- Version: 0.20.0a3
3
+ Version: 0.20.0a5
4
4
  Summary: Ultra-lightweight durable execution in Python
5
5
  Author-Email: "DBOS, Inc." <contact@dbos.dev>
6
6
  License: MIT
@@ -488,6 +488,22 @@ def start_workflow(
488
488
  return WorkflowHandleFuture(new_wf_id, future, dbos)
489
489
 
490
490
 
491
+ if sys.version_info < (3, 12):
492
+
493
+ def _mark_coroutine(func: Callable[P, R]) -> Callable[P, R]:
494
+ @wraps(func)
495
+ async def async_wrapper(*args: Any, **kwargs: Any) -> R:
496
+ return await func(*args, **kwargs) # type: ignore
497
+
498
+ return async_wrapper # type: ignore
499
+
500
+ else:
501
+
502
+ def _mark_coroutine(func: Callable[P, R]) -> Callable[P, R]:
503
+ inspect.markcoroutinefunction(func)
504
+ return func
505
+
506
+
491
507
  def workflow_wrapper(
492
508
  dbosreg: "DBOSRegistry",
493
509
  func: Callable[P, R],
@@ -548,7 +564,7 @@ def workflow_wrapper(
548
564
  )
549
565
  return outcome() # type: ignore
550
566
 
551
- return wrapper
567
+ return _mark_coroutine(wrapper) if inspect.iscoroutinefunction(func) else wrapper
552
568
 
553
569
 
554
570
  def decorate_workflow(
@@ -838,6 +854,10 @@ def decorate_step(
838
854
  assert tempwf
839
855
  return tempwf(*args, **kwargs)
840
856
 
857
+ wrapper = (
858
+ _mark_coroutine(wrapper) if inspect.iscoroutinefunction(func) else wrapper # type: ignore
859
+ )
860
+
841
861
  def temp_wf_sync(*args: Any, **kwargs: Any) -> Any:
842
862
  return wrapper(*args, **kwargs)
843
863
 
@@ -1,10 +1,10 @@
1
1
  import uuid
2
- from typing import Any, Callable, cast
2
+ from typing import Any, Callable, MutableMapping, cast
3
3
 
4
4
  from fastapi import FastAPI
5
5
  from fastapi import Request as FastAPIRequest
6
6
  from fastapi.responses import JSONResponse
7
- from starlette.types import ASGIApp, Message, Receive, Scope, Send
7
+ from starlette.types import ASGIApp, Receive, Scope, Send
8
8
 
9
9
  from . import DBOS
10
10
  from ._context import (
@@ -61,15 +61,16 @@ class LifespanMiddleware:
61
61
 
62
62
  async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None:
63
63
  if scope["type"] == "lifespan":
64
- while True:
65
- message = await receive()
66
- if message["type"] == "lifespan.startup":
64
+
65
+ async def wrapped_send(message: MutableMapping[str, Any]) -> None:
66
+ if message["type"] == "lifespan.startup.complete":
67
67
  self.dbos._launch()
68
- await send({"type": "lifespan.startup.complete"})
69
- elif message["type"] == "lifespan.shutdown":
68
+ elif message["type"] == "lifespan.shutdown.complete":
70
69
  self.dbos._destroy()
71
- await send({"type": "lifespan.shutdown.complete"})
72
- break
70
+ await send(message)
71
+
72
+ # Call the original app with our wrapped functions
73
+ await self.app(scope, receive, wrapped_send)
73
74
  else:
74
75
  await self.app(scope, receive, send)
75
76
 
@@ -27,7 +27,7 @@ dependencies = [
27
27
  ]
28
28
  requires-python = ">=3.9"
29
29
  readme = "README.md"
30
- version = "0.20.0a3"
30
+ version = "0.20.0a5"
31
31
 
32
32
  [project.license]
33
33
  text = "MIT"
@@ -118,15 +118,7 @@ def dbos_fastapi(
118
118
  ) -> Generator[Tuple[DBOS, FastAPI], Any, None]:
119
119
  DBOS.destroy()
120
120
  app = FastAPI()
121
-
122
- # ignore the on_event deprecation warnings
123
- with warnings.catch_warnings():
124
- warnings.filterwarnings(
125
- "ignore",
126
- category=DeprecationWarning,
127
- message=r"\s*on_event is deprecated, use lifespan event handlers instead\.",
128
- )
129
- dbos = DBOS(fastapi=app, config=config)
121
+ dbos = DBOS(fastapi=app, config=config)
130
122
 
131
123
  # This is for test convenience.
132
124
  # Usually fastapi itself does launch, but we are not completing the fastapi lifecycle
@@ -1,14 +1,18 @@
1
+ import asyncio
1
2
  import logging
2
3
  import uuid
3
- from typing import Tuple
4
+ from contextlib import asynccontextmanager
5
+ from typing import Any, Tuple
4
6
 
7
+ import httpx
5
8
  import pytest
6
9
  import sqlalchemy as sa
10
+ import uvicorn
7
11
  from fastapi import FastAPI
8
12
  from fastapi.testclient import TestClient
9
13
 
10
14
  # Public API
11
- from dbos import DBOS
15
+ from dbos import DBOS, ConfigFile
12
16
 
13
17
  # Private API because this is a unit test
14
18
  from dbos._context import assert_current_dbos_context
@@ -157,3 +161,73 @@ def test_endpoint_recovery(dbos_fastapi: Tuple[DBOS, FastAPI]) -> None:
157
161
  workflow_handles = DBOS.recover_pending_workflows()
158
162
  assert len(workflow_handles) == 1
159
163
  assert workflow_handles[0].get_result() == ("a", wfuuid)
164
+
165
+
166
+ @pytest.mark.asyncio
167
+ async def test_custom_lifespan(
168
+ config: ConfigFile, cleanup_test_databases: None
169
+ ) -> None:
170
+ resource = None
171
+ port = 8000
172
+
173
+ @asynccontextmanager
174
+ async def lifespan(app: FastAPI) -> Any:
175
+ nonlocal resource
176
+ resource = 1
177
+ yield
178
+ resource = None
179
+
180
+ app = FastAPI(lifespan=lifespan)
181
+
182
+ DBOS.destroy()
183
+ DBOS(fastapi=app, config=config)
184
+
185
+ @app.get("/")
186
+ @DBOS.workflow()
187
+ async def resource_workflow() -> Any:
188
+ return {"resource": resource}
189
+
190
+ uvicorn_config = uvicorn.Config(
191
+ app=app, host="127.0.0.1", port=port, log_level="error"
192
+ )
193
+ server = uvicorn.Server(config=uvicorn_config)
194
+
195
+ # Run server in background task
196
+ server_task = asyncio.create_task(server.serve())
197
+ await asyncio.sleep(0.2) # Give server time to start
198
+
199
+ async with httpx.AsyncClient() as client:
200
+ r = await client.get(f"http://127.0.0.1:{port}")
201
+ assert r.json()["resource"] == 1
202
+
203
+ server.should_exit = True
204
+ await server_task
205
+ assert resource is None
206
+
207
+
208
+ def test_stacked_decorators_wf(dbos_fastapi: Tuple[DBOS, FastAPI]) -> None:
209
+ dbos, app = dbos_fastapi
210
+ client = TestClient(app)
211
+
212
+ @app.get("/endpoint/{var1}/{var2}")
213
+ @DBOS.workflow()
214
+ async def test_endpoint(var1: str, var2: str) -> str:
215
+ return f"{var1}, {var2}!"
216
+
217
+ response = client.get("/endpoint/plums/deify")
218
+ assert response.status_code == 200
219
+ assert response.text == '"plums, deify!"'
220
+
221
+
222
+ def test_stacked_decorators_step(dbos_fastapi: Tuple[DBOS, FastAPI]) -> None:
223
+ dbos, app = dbos_fastapi
224
+ client = TestClient(app)
225
+
226
+ @app.get("/endpoint/{var1}/{var2}")
227
+ @DBOS.step()
228
+ async def test_endpoint(var1: str, var2: str) -> str:
229
+ return f"{var1}, {var2}!"
230
+
231
+ response = client.get("/endpoint/plums/deify")
232
+ assert response.status_code == 200
233
+ assert response.text == '"plums, deify!"'
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