pyworkflow-engine 0.1.7__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.
Files changed (196) hide show
  1. dashboard/backend/app/__init__.py +1 -0
  2. dashboard/backend/app/config.py +32 -0
  3. dashboard/backend/app/controllers/__init__.py +6 -0
  4. dashboard/backend/app/controllers/run_controller.py +86 -0
  5. dashboard/backend/app/controllers/workflow_controller.py +33 -0
  6. dashboard/backend/app/dependencies/__init__.py +5 -0
  7. dashboard/backend/app/dependencies/storage.py +50 -0
  8. dashboard/backend/app/repositories/__init__.py +6 -0
  9. dashboard/backend/app/repositories/run_repository.py +80 -0
  10. dashboard/backend/app/repositories/workflow_repository.py +27 -0
  11. dashboard/backend/app/rest/__init__.py +8 -0
  12. dashboard/backend/app/rest/v1/__init__.py +12 -0
  13. dashboard/backend/app/rest/v1/health.py +33 -0
  14. dashboard/backend/app/rest/v1/runs.py +133 -0
  15. dashboard/backend/app/rest/v1/workflows.py +41 -0
  16. dashboard/backend/app/schemas/__init__.py +23 -0
  17. dashboard/backend/app/schemas/common.py +16 -0
  18. dashboard/backend/app/schemas/event.py +24 -0
  19. dashboard/backend/app/schemas/hook.py +25 -0
  20. dashboard/backend/app/schemas/run.py +54 -0
  21. dashboard/backend/app/schemas/step.py +28 -0
  22. dashboard/backend/app/schemas/workflow.py +31 -0
  23. dashboard/backend/app/server.py +87 -0
  24. dashboard/backend/app/services/__init__.py +6 -0
  25. dashboard/backend/app/services/run_service.py +240 -0
  26. dashboard/backend/app/services/workflow_service.py +155 -0
  27. dashboard/backend/main.py +18 -0
  28. docs/concepts/cancellation.mdx +362 -0
  29. docs/concepts/continue-as-new.mdx +434 -0
  30. docs/concepts/events.mdx +266 -0
  31. docs/concepts/fault-tolerance.mdx +370 -0
  32. docs/concepts/hooks.mdx +552 -0
  33. docs/concepts/limitations.mdx +167 -0
  34. docs/concepts/schedules.mdx +775 -0
  35. docs/concepts/sleep.mdx +312 -0
  36. docs/concepts/steps.mdx +301 -0
  37. docs/concepts/workflows.mdx +255 -0
  38. docs/guides/cli.mdx +942 -0
  39. docs/guides/configuration.mdx +560 -0
  40. docs/introduction.mdx +155 -0
  41. docs/quickstart.mdx +279 -0
  42. examples/__init__.py +1 -0
  43. examples/celery/__init__.py +1 -0
  44. examples/celery/durable/docker-compose.yml +55 -0
  45. examples/celery/durable/pyworkflow.config.yaml +12 -0
  46. examples/celery/durable/workflows/__init__.py +122 -0
  47. examples/celery/durable/workflows/basic.py +87 -0
  48. examples/celery/durable/workflows/batch_processing.py +102 -0
  49. examples/celery/durable/workflows/cancellation.py +273 -0
  50. examples/celery/durable/workflows/child_workflow_patterns.py +240 -0
  51. examples/celery/durable/workflows/child_workflows.py +202 -0
  52. examples/celery/durable/workflows/continue_as_new.py +260 -0
  53. examples/celery/durable/workflows/fault_tolerance.py +210 -0
  54. examples/celery/durable/workflows/hooks.py +211 -0
  55. examples/celery/durable/workflows/idempotency.py +112 -0
  56. examples/celery/durable/workflows/long_running.py +99 -0
  57. examples/celery/durable/workflows/retries.py +101 -0
  58. examples/celery/durable/workflows/schedules.py +209 -0
  59. examples/celery/transient/01_basic_workflow.py +91 -0
  60. examples/celery/transient/02_fault_tolerance.py +257 -0
  61. examples/celery/transient/__init__.py +20 -0
  62. examples/celery/transient/pyworkflow.config.yaml +25 -0
  63. examples/local/__init__.py +1 -0
  64. examples/local/durable/01_basic_workflow.py +94 -0
  65. examples/local/durable/02_file_storage.py +132 -0
  66. examples/local/durable/03_retries.py +169 -0
  67. examples/local/durable/04_long_running.py +119 -0
  68. examples/local/durable/05_event_log.py +145 -0
  69. examples/local/durable/06_idempotency.py +148 -0
  70. examples/local/durable/07_hooks.py +334 -0
  71. examples/local/durable/08_cancellation.py +233 -0
  72. examples/local/durable/09_child_workflows.py +198 -0
  73. examples/local/durable/10_child_workflow_patterns.py +265 -0
  74. examples/local/durable/11_continue_as_new.py +249 -0
  75. examples/local/durable/12_schedules.py +198 -0
  76. examples/local/durable/__init__.py +1 -0
  77. examples/local/transient/01_quick_tasks.py +87 -0
  78. examples/local/transient/02_retries.py +130 -0
  79. examples/local/transient/03_sleep.py +141 -0
  80. examples/local/transient/__init__.py +1 -0
  81. pyworkflow/__init__.py +256 -0
  82. pyworkflow/aws/__init__.py +68 -0
  83. pyworkflow/aws/context.py +234 -0
  84. pyworkflow/aws/handler.py +184 -0
  85. pyworkflow/aws/testing.py +310 -0
  86. pyworkflow/celery/__init__.py +41 -0
  87. pyworkflow/celery/app.py +198 -0
  88. pyworkflow/celery/scheduler.py +315 -0
  89. pyworkflow/celery/tasks.py +1746 -0
  90. pyworkflow/cli/__init__.py +132 -0
  91. pyworkflow/cli/__main__.py +6 -0
  92. pyworkflow/cli/commands/__init__.py +1 -0
  93. pyworkflow/cli/commands/hooks.py +640 -0
  94. pyworkflow/cli/commands/quickstart.py +495 -0
  95. pyworkflow/cli/commands/runs.py +773 -0
  96. pyworkflow/cli/commands/scheduler.py +130 -0
  97. pyworkflow/cli/commands/schedules.py +794 -0
  98. pyworkflow/cli/commands/setup.py +703 -0
  99. pyworkflow/cli/commands/worker.py +413 -0
  100. pyworkflow/cli/commands/workflows.py +1257 -0
  101. pyworkflow/cli/output/__init__.py +1 -0
  102. pyworkflow/cli/output/formatters.py +321 -0
  103. pyworkflow/cli/output/styles.py +121 -0
  104. pyworkflow/cli/utils/__init__.py +1 -0
  105. pyworkflow/cli/utils/async_helpers.py +30 -0
  106. pyworkflow/cli/utils/config.py +130 -0
  107. pyworkflow/cli/utils/config_generator.py +344 -0
  108. pyworkflow/cli/utils/discovery.py +53 -0
  109. pyworkflow/cli/utils/docker_manager.py +651 -0
  110. pyworkflow/cli/utils/interactive.py +364 -0
  111. pyworkflow/cli/utils/storage.py +115 -0
  112. pyworkflow/config.py +329 -0
  113. pyworkflow/context/__init__.py +63 -0
  114. pyworkflow/context/aws.py +230 -0
  115. pyworkflow/context/base.py +416 -0
  116. pyworkflow/context/local.py +930 -0
  117. pyworkflow/context/mock.py +381 -0
  118. pyworkflow/core/__init__.py +0 -0
  119. pyworkflow/core/exceptions.py +353 -0
  120. pyworkflow/core/registry.py +313 -0
  121. pyworkflow/core/scheduled.py +328 -0
  122. pyworkflow/core/step.py +494 -0
  123. pyworkflow/core/workflow.py +294 -0
  124. pyworkflow/discovery.py +248 -0
  125. pyworkflow/engine/__init__.py +0 -0
  126. pyworkflow/engine/events.py +879 -0
  127. pyworkflow/engine/executor.py +682 -0
  128. pyworkflow/engine/replay.py +273 -0
  129. pyworkflow/observability/__init__.py +19 -0
  130. pyworkflow/observability/logging.py +234 -0
  131. pyworkflow/primitives/__init__.py +33 -0
  132. pyworkflow/primitives/child_handle.py +174 -0
  133. pyworkflow/primitives/child_workflow.py +372 -0
  134. pyworkflow/primitives/continue_as_new.py +101 -0
  135. pyworkflow/primitives/define_hook.py +150 -0
  136. pyworkflow/primitives/hooks.py +97 -0
  137. pyworkflow/primitives/resume_hook.py +210 -0
  138. pyworkflow/primitives/schedule.py +545 -0
  139. pyworkflow/primitives/shield.py +96 -0
  140. pyworkflow/primitives/sleep.py +100 -0
  141. pyworkflow/runtime/__init__.py +21 -0
  142. pyworkflow/runtime/base.py +179 -0
  143. pyworkflow/runtime/celery.py +310 -0
  144. pyworkflow/runtime/factory.py +101 -0
  145. pyworkflow/runtime/local.py +706 -0
  146. pyworkflow/scheduler/__init__.py +9 -0
  147. pyworkflow/scheduler/local.py +248 -0
  148. pyworkflow/serialization/__init__.py +0 -0
  149. pyworkflow/serialization/decoder.py +146 -0
  150. pyworkflow/serialization/encoder.py +162 -0
  151. pyworkflow/storage/__init__.py +54 -0
  152. pyworkflow/storage/base.py +612 -0
  153. pyworkflow/storage/config.py +185 -0
  154. pyworkflow/storage/dynamodb.py +1315 -0
  155. pyworkflow/storage/file.py +827 -0
  156. pyworkflow/storage/memory.py +549 -0
  157. pyworkflow/storage/postgres.py +1161 -0
  158. pyworkflow/storage/schemas.py +486 -0
  159. pyworkflow/storage/sqlite.py +1136 -0
  160. pyworkflow/utils/__init__.py +0 -0
  161. pyworkflow/utils/duration.py +177 -0
  162. pyworkflow/utils/schedule.py +391 -0
  163. pyworkflow_engine-0.1.7.dist-info/METADATA +687 -0
  164. pyworkflow_engine-0.1.7.dist-info/RECORD +196 -0
  165. pyworkflow_engine-0.1.7.dist-info/WHEEL +5 -0
  166. pyworkflow_engine-0.1.7.dist-info/entry_points.txt +2 -0
  167. pyworkflow_engine-0.1.7.dist-info/licenses/LICENSE +21 -0
  168. pyworkflow_engine-0.1.7.dist-info/top_level.txt +5 -0
  169. tests/examples/__init__.py +0 -0
  170. tests/integration/__init__.py +0 -0
  171. tests/integration/test_cancellation.py +330 -0
  172. tests/integration/test_child_workflows.py +439 -0
  173. tests/integration/test_continue_as_new.py +428 -0
  174. tests/integration/test_dynamodb_storage.py +1146 -0
  175. tests/integration/test_fault_tolerance.py +369 -0
  176. tests/integration/test_schedule_storage.py +484 -0
  177. tests/unit/__init__.py +0 -0
  178. tests/unit/backends/__init__.py +1 -0
  179. tests/unit/backends/test_dynamodb_storage.py +1554 -0
  180. tests/unit/backends/test_postgres_storage.py +1281 -0
  181. tests/unit/backends/test_sqlite_storage.py +1460 -0
  182. tests/unit/conftest.py +41 -0
  183. tests/unit/test_cancellation.py +364 -0
  184. tests/unit/test_child_workflows.py +680 -0
  185. tests/unit/test_continue_as_new.py +441 -0
  186. tests/unit/test_event_limits.py +316 -0
  187. tests/unit/test_executor.py +320 -0
  188. tests/unit/test_fault_tolerance.py +334 -0
  189. tests/unit/test_hooks.py +495 -0
  190. tests/unit/test_registry.py +261 -0
  191. tests/unit/test_replay.py +420 -0
  192. tests/unit/test_schedule_schemas.py +285 -0
  193. tests/unit/test_schedule_utils.py +286 -0
  194. tests/unit/test_scheduled_workflow.py +274 -0
  195. tests/unit/test_step.py +353 -0
  196. tests/unit/test_workflow.py +243 -0
@@ -0,0 +1,185 @@
1
+ """
2
+ Unified storage backend configuration utilities.
3
+
4
+ This module provides functions to serialize storage backends to configuration
5
+ dicts and recreate storage backends from configuration dicts. This is used
6
+ for passing storage configuration to Celery tasks and other cross-process
7
+ communication.
8
+ """
9
+
10
+ from typing import Any
11
+
12
+ from pyworkflow.storage.base import StorageBackend
13
+
14
+
15
+ def storage_to_config(storage: StorageBackend | None) -> dict[str, Any] | None:
16
+ """
17
+ Serialize storage backend to configuration dict.
18
+
19
+ Args:
20
+ storage: Storage backend instance
21
+
22
+ Returns:
23
+ Configuration dict or None if storage is None
24
+
25
+ Example:
26
+ >>> from pyworkflow.storage.file import FileStorageBackend
27
+ >>> storage = FileStorageBackend(base_path="./data")
28
+ >>> config = storage_to_config(storage)
29
+ >>> config
30
+ {'type': 'file', 'base_path': './data'}
31
+ """
32
+ if storage is None:
33
+ return None
34
+
35
+ # Use class name to avoid import cycles
36
+ class_name = storage.__class__.__name__
37
+
38
+ if class_name == "FileStorageBackend":
39
+ return {
40
+ "type": "file",
41
+ "base_path": str(getattr(storage, "base_path", "./workflow_data")),
42
+ }
43
+ elif class_name == "InMemoryStorageBackend":
44
+ return {"type": "memory"}
45
+ elif class_name == "SQLiteStorageBackend":
46
+ return {
47
+ "type": "sqlite",
48
+ "base_path": str(getattr(storage, "db_path", "./pyworkflow_data/pyworkflow.db")),
49
+ }
50
+ elif class_name == "RedisStorageBackend":
51
+ return {
52
+ "type": "redis",
53
+ "host": getattr(storage, "host", "localhost"),
54
+ "port": getattr(storage, "port", 6379),
55
+ "db": getattr(storage, "db", 0),
56
+ }
57
+ elif class_name == "PostgresStorageBackend":
58
+ config: dict[str, Any] = {"type": "postgres"}
59
+ dsn = getattr(storage, "dsn", None)
60
+ if dsn:
61
+ config["dsn"] = dsn
62
+ else:
63
+ config["host"] = getattr(storage, "host", "localhost")
64
+ config["port"] = getattr(storage, "port", 5432)
65
+ config["user"] = getattr(storage, "user", "pyworkflow")
66
+ config["password"] = getattr(storage, "password", "")
67
+ config["database"] = getattr(storage, "database", "pyworkflow")
68
+ return config
69
+ elif class_name == "DynamoDBStorageBackend":
70
+ return {
71
+ "type": "dynamodb",
72
+ "table_name": getattr(storage, "table_name", "pyworkflow"),
73
+ "region": getattr(storage, "region", "us-east-1"),
74
+ "endpoint_url": getattr(storage, "endpoint_url", None),
75
+ }
76
+ else:
77
+ # Unknown backend - return minimal config
78
+ return {"type": "unknown"}
79
+
80
+
81
+ def config_to_storage(config: dict[str, Any] | None = None) -> StorageBackend:
82
+ """
83
+ Create storage backend from configuration dict.
84
+
85
+ Args:
86
+ config: Configuration dict with 'type' and backend-specific params.
87
+ If None, returns default FileStorageBackend.
88
+
89
+ Returns:
90
+ Storage backend instance
91
+
92
+ Raises:
93
+ ValueError: If storage type is unknown
94
+
95
+ Example:
96
+ >>> config = {"type": "file", "base_path": "./data"}
97
+ >>> storage = config_to_storage(config)
98
+ >>> isinstance(storage, FileStorageBackend)
99
+ True
100
+ """
101
+ if not config:
102
+ from pyworkflow.storage.file import FileStorageBackend
103
+
104
+ return FileStorageBackend()
105
+
106
+ storage_type = config.get("type", "file")
107
+
108
+ if storage_type == "file":
109
+ from pyworkflow.storage.file import FileStorageBackend
110
+
111
+ base_path = config.get("base_path") or "./workflow_data"
112
+ return FileStorageBackend(base_path=base_path)
113
+
114
+ elif storage_type == "memory":
115
+ from pyworkflow.storage.memory import InMemoryStorageBackend
116
+
117
+ return InMemoryStorageBackend()
118
+
119
+ elif storage_type == "sqlite":
120
+ try:
121
+ from pyworkflow.storage.sqlite import SQLiteStorageBackend
122
+ except ImportError:
123
+ raise ValueError(
124
+ "SQLite storage backend is not available. "
125
+ "Python was compiled without SQLite support (_sqlite3 module missing). "
126
+ "Please use 'file' or 'memory' storage instead, or rebuild Python with SQLite support."
127
+ )
128
+
129
+ db_path = config.get("base_path") or "./pyworkflow_data/pyworkflow.db"
130
+ return SQLiteStorageBackend(db_path=db_path)
131
+
132
+ elif storage_type == "redis":
133
+ try:
134
+ from pyworkflow.storage.redis import RedisStorageBackend
135
+ except ImportError:
136
+ raise ValueError(
137
+ "Redis storage backend is not yet implemented. "
138
+ "Use 'file', 'sqlite', or 'postgres' storage. "
139
+ "Redis support is planned for a future release. "
140
+ "Note: Redis can still be used as a Celery broker with 'pip install pyworkflow[redis]'."
141
+ )
142
+
143
+ return RedisStorageBackend(
144
+ host=config.get("host", "localhost"),
145
+ port=config.get("port", 6379),
146
+ db=config.get("db", 0),
147
+ )
148
+
149
+ elif storage_type == "postgres":
150
+ try:
151
+ from pyworkflow.storage.postgres import PostgresStorageBackend
152
+ except ImportError:
153
+ raise ValueError(
154
+ "PostgreSQL storage backend is not available. Install asyncpg: pip install asyncpg"
155
+ )
156
+
157
+ # Support both DSN and individual parameters
158
+ if "dsn" in config:
159
+ return PostgresStorageBackend(dsn=config["dsn"])
160
+ else:
161
+ return PostgresStorageBackend(
162
+ host=config.get("host", "localhost"),
163
+ port=config.get("port", 5432),
164
+ user=config.get("user", "pyworkflow"),
165
+ password=config.get("password", ""),
166
+ database=config.get("database", "pyworkflow"),
167
+ )
168
+
169
+ elif storage_type == "dynamodb":
170
+ try:
171
+ from pyworkflow.storage.dynamodb import DynamoDBStorageBackend
172
+ except ImportError:
173
+ raise ValueError(
174
+ "DynamoDB storage backend is not available. "
175
+ "Please install the required dependencies with: pip install 'pyworkflow[dynamodb]'"
176
+ )
177
+
178
+ return DynamoDBStorageBackend(
179
+ table_name=config.get("table_name", "pyworkflow"),
180
+ region=config.get("region", "us-east-1"),
181
+ endpoint_url=config.get("endpoint_url"),
182
+ )
183
+
184
+ else:
185
+ raise ValueError(f"Unknown storage type: {storage_type}")