loom-core 0.1.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.
- loom_core-0.1.0.dist-info/METADATA +342 -0
- loom_core-0.1.0.dist-info/RECORD +50 -0
- loom_core-0.1.0.dist-info/WHEEL +5 -0
- loom_core-0.1.0.dist-info/entry_points.txt +2 -0
- loom_core-0.1.0.dist-info/licenses/LICENSE +21 -0
- loom_core-0.1.0.dist-info/top_level.txt +1 -0
- src/__init__.py +45 -0
- src/cli/__init__.py +5 -0
- src/cli/cli.py +246 -0
- src/common/activity.py +30 -0
- src/common/config.py +9 -0
- src/common/errors.py +64 -0
- src/common/workflow.py +56 -0
- src/core/__init__.py +0 -0
- src/core/compiled.py +41 -0
- src/core/context.py +256 -0
- src/core/engine.py +106 -0
- src/core/handle.py +166 -0
- src/core/logger.py +60 -0
- src/core/runner.py +53 -0
- src/core/state.py +96 -0
- src/core/worker.py +147 -0
- src/core/workflow.py +168 -0
- src/database/__init__.py +0 -0
- src/database/db.py +716 -0
- src/decorators/__init__.py +0 -0
- src/decorators/activity.py +126 -0
- src/decorators/workflow.py +46 -0
- src/lib/progress.py +109 -0
- src/lib/utils.py +25 -0
- src/migrations/down/001_setup_pragma.sql +5 -0
- src/migrations/down/002_create_workflows.sql +3 -0
- src/migrations/down/003.create_events.sql +3 -0
- src/migrations/down/004.create_tasks.sql +3 -0
- src/migrations/down/005.create_indexes.sql +5 -0
- src/migrations/down/006_auto_update_triggers.sql +4 -0
- src/migrations/down/007_create_logs.sql +1 -0
- src/migrations/up/001_setup_pragma.sql +11 -0
- src/migrations/up/002_create_workflows.sql +15 -0
- src/migrations/up/003_create_events.sql +13 -0
- src/migrations/up/004_create_tasks.sql +23 -0
- src/migrations/up/005_create_indexes.sql +11 -0
- src/migrations/up/006_auto_update_triggers.sql +19 -0
- src/migrations/up/007_create_logs.sql +10 -0
- src/schemas/__init__.py +0 -0
- src/schemas/activity.py +13 -0
- src/schemas/database.py +17 -0
- src/schemas/events.py +70 -0
- src/schemas/tasks.py +58 -0
- src/schemas/workflow.py +33 -0
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: loom-core
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Durable workflow orchestration engine for Python
|
|
5
|
+
Home-page: https://github.com/satadeep3927/loom
|
|
6
|
+
Author: Satadeep Dasgupta
|
|
7
|
+
Author-email: Satadeep Dasgupta <satadeep.dasgupta@brainiuminfotech.com>
|
|
8
|
+
License: MIT
|
|
9
|
+
Project-URL: Homepage, https://github.com/satadeep3927/loom
|
|
10
|
+
Project-URL: Documentation, https://github.com/satadeep3927/loom/blob/main/README.md
|
|
11
|
+
Project-URL: Repository, https://github.com/satadeep3927/loom
|
|
12
|
+
Project-URL: Issues, https://github.com/satadeep3927/loom/issues
|
|
13
|
+
Keywords: workflow,orchestration,durable,event-sourcing,temporal
|
|
14
|
+
Classifier: Development Status :: 3 - Alpha
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
|
|
17
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
18
|
+
Classifier: Programming Language :: Python :: 3
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Framework :: AsyncIO
|
|
21
|
+
Requires-Python: >=3.12
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
License-File: LICENSE
|
|
24
|
+
Requires-Dist: aiosqlite>=0.19.0
|
|
25
|
+
Requires-Dist: click>=8.0.0
|
|
26
|
+
Requires-Dist: rich>=13.0.0
|
|
27
|
+
Provides-Extra: dev
|
|
28
|
+
Requires-Dist: pytest>=7.0.0; extra == "dev"
|
|
29
|
+
Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
|
|
30
|
+
Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
|
|
31
|
+
Requires-Dist: mypy>=1.0.0; extra == "dev"
|
|
32
|
+
Requires-Dist: black>=23.0.0; extra == "dev"
|
|
33
|
+
Requires-Dist: isort>=5.12.0; extra == "dev"
|
|
34
|
+
Requires-Dist: ruff>=0.1.0; extra == "dev"
|
|
35
|
+
Dynamic: author
|
|
36
|
+
Dynamic: home-page
|
|
37
|
+
Dynamic: license-file
|
|
38
|
+
Dynamic: requires-python
|
|
39
|
+
|
|
40
|
+
# Loom - Durable Workflow Orchestration
|
|
41
|
+
|
|
42
|
+
[](https://www.python.org/downloads/)
|
|
43
|
+
[](https://opensource.org/licenses/MIT)
|
|
44
|
+
[](https://pypi.org/project/loom-core/)
|
|
45
|
+
|
|
46
|
+
A Python-based durable workflow orchestration engine inspired by [Temporal](https://temporal.io/) and [Durable Task Framework](https://github.com/Azure/durabletask). Loom provides event-sourced, deterministic workflow execution with automatic recovery and replay capabilities.
|
|
47
|
+
|
|
48
|
+
## Features
|
|
49
|
+
|
|
50
|
+
- **Event Sourcing**: All workflow state changes persisted as immutable events
|
|
51
|
+
- **Deterministic Replay**: Workflows reconstruct from event history for recovery
|
|
52
|
+
- **Type Safe**: Full generic typing support with `Workflow[InputT, StateT]`
|
|
53
|
+
- **Async First**: Built on asyncio for high-performance concurrent execution
|
|
54
|
+
- **Durable Execution**: Workflows survive process crashes and auto-recover
|
|
55
|
+
- **Beautiful CLI**: Rich console interface with progress tracking
|
|
56
|
+
- **Well Tested**: Comprehensive test suite with pytest
|
|
57
|
+
|
|
58
|
+
## Quick Start
|
|
59
|
+
|
|
60
|
+
### Installation
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
pip install loom-core
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Or install from source:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
git clone https://github.com/yourusername/loom.git
|
|
70
|
+
cd loom
|
|
71
|
+
pip install -e .
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Define a Workflow
|
|
75
|
+
|
|
76
|
+
```python
|
|
77
|
+
import asyncio
|
|
78
|
+
from typing import TypedDict
|
|
79
|
+
import loom
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
# Define your data types
|
|
83
|
+
class OrderInput(TypedDict):
|
|
84
|
+
order_id: str
|
|
85
|
+
customer_email: str
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
class OrderState(TypedDict):
|
|
89
|
+
payment_confirmed: bool
|
|
90
|
+
email_sent: bool
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
# Define activities (side effects)
|
|
94
|
+
@loom.activity(name="process_payment", retry_count=3, timeout_seconds=30)
|
|
95
|
+
async def process_payment(order_id: str) -> bool:
|
|
96
|
+
# Call payment API
|
|
97
|
+
return True
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
@loom.activity(name="send_email", retry_count=2)
|
|
101
|
+
async def send_confirmation_email(email: str, order_id: str) -> None:
|
|
102
|
+
# Send email via service
|
|
103
|
+
pass
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
# Define workflow
|
|
107
|
+
@loom.workflow(name="OrderProcessing", version="1.0.0")
|
|
108
|
+
class OrderWorkflow(loom.Workflow[OrderInput, OrderState]):
|
|
109
|
+
|
|
110
|
+
@loom.step(name="process_payment")
|
|
111
|
+
async def payment_step(self, ctx: loom.WorkflowContext[OrderInput, OrderState]):
|
|
112
|
+
success = await ctx.activity(process_payment, ctx.input["order_id"])
|
|
113
|
+
await ctx.state.set("payment_confirmed", success)
|
|
114
|
+
ctx.logger.info(f"Payment processed: {success}")
|
|
115
|
+
|
|
116
|
+
@loom.step(name="send_confirmation")
|
|
117
|
+
async def notification_step(self, ctx: loom.WorkflowContext[OrderInput, OrderState]):
|
|
118
|
+
if ctx.state["payment_confirmed"]:
|
|
119
|
+
await ctx.activity(
|
|
120
|
+
send_confirmation_email,
|
|
121
|
+
ctx.input["customer_email"],
|
|
122
|
+
ctx.input["order_id"]
|
|
123
|
+
)
|
|
124
|
+
await ctx.state.set("email_sent", True)
|
|
125
|
+
ctx.logger.info("Confirmation email sent")
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
**Note**: For state updates, use:
|
|
129
|
+
- `await ctx.state.set("key", value)` for single values
|
|
130
|
+
- `await ctx.state.update(key=lambda _: asyncio.sleep(0, value))` for batch updates (requires awaitable)
|
|
131
|
+
|
|
132
|
+
See [STATE_MANAGEMENT.md](STATE_MANAGEMENT.md) for detailed examples.
|
|
133
|
+
|
|
134
|
+
### Start a Workflow
|
|
135
|
+
|
|
136
|
+
```python
|
|
137
|
+
async def main():
|
|
138
|
+
db = loom.Database()
|
|
139
|
+
async with db:
|
|
140
|
+
# Initialize database
|
|
141
|
+
await db.migrate_up()
|
|
142
|
+
|
|
143
|
+
# Start workflow
|
|
144
|
+
handle = await db.start_workflow(
|
|
145
|
+
OrderWorkflow,
|
|
146
|
+
workflow_input=OrderInput(
|
|
147
|
+
order_id="ORD-12345",
|
|
148
|
+
customer_email="customer@example.com"
|
|
149
|
+
),
|
|
150
|
+
initial_state=OrderState(
|
|
151
|
+
payment_confirmed=False,
|
|
152
|
+
email_sent=False
|
|
153
|
+
),
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
print(f"Workflow started: {handle.workflow_id}")
|
|
157
|
+
|
|
158
|
+
# Execute workflow tasks
|
|
159
|
+
while True:
|
|
160
|
+
task_executed = await loom.run_once()
|
|
161
|
+
if not task_executed:
|
|
162
|
+
break
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
if __name__ == "__main__":
|
|
166
|
+
asyncio.run(main())
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### Run the Worker
|
|
170
|
+
|
|
171
|
+
```bash
|
|
172
|
+
# Initialize database
|
|
173
|
+
loom init
|
|
174
|
+
|
|
175
|
+
# Start worker with 4 concurrent task processors
|
|
176
|
+
loom worker
|
|
177
|
+
|
|
178
|
+
# Custom configuration
|
|
179
|
+
loom worker --workers 8 --poll-interval 1.0
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
## CLI Commands
|
|
183
|
+
|
|
184
|
+
```bash
|
|
185
|
+
# Initialize database
|
|
186
|
+
loom init
|
|
187
|
+
|
|
188
|
+
# Start distributed worker
|
|
189
|
+
loom worker [--workers 4] [--poll-interval 0.5]
|
|
190
|
+
|
|
191
|
+
# List workflows
|
|
192
|
+
loom list [--limit 50] [--status RUNNING]
|
|
193
|
+
|
|
194
|
+
# Inspect workflow details
|
|
195
|
+
loom inspect <workflow-id> [--events]
|
|
196
|
+
|
|
197
|
+
# Show database statistics
|
|
198
|
+
loom stats
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
## 🏗️ Architecture
|
|
202
|
+
|
|
203
|
+
### Core Components
|
|
204
|
+
|
|
205
|
+
```
|
|
206
|
+
┌─────────────────────────────────────────────────────────┐
|
|
207
|
+
│ Workflow │
|
|
208
|
+
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
|
|
209
|
+
│ │ Step 1 │→ │ Step 2 │→ │ Step 3 │ │
|
|
210
|
+
│ └──────────┘ └──────────┘ └──────────┘ │
|
|
211
|
+
└─────────────────────────────────────────────────────────┘
|
|
212
|
+
↓
|
|
213
|
+
┌─────────────────────────────────────────────────────────┐
|
|
214
|
+
│ WorkflowContext │
|
|
215
|
+
│ • State Management (StateProxy) │
|
|
216
|
+
│ • Activity Execution │
|
|
217
|
+
│ • Event Replay & Cursor │
|
|
218
|
+
│ • Logger (replay-safe) │
|
|
219
|
+
└─────────────────────────────────────────────────────────┘
|
|
220
|
+
↓
|
|
221
|
+
┌─────────────────────────────────────────────────────────┐
|
|
222
|
+
│ Engine │
|
|
223
|
+
│ • replay_until_block() - Step execution │
|
|
224
|
+
│ • replay_activity() - Activity retry │
|
|
225
|
+
│ • Event matching & determinism │
|
|
226
|
+
└─────────────────────────────────────────────────────────┘
|
|
227
|
+
↓
|
|
228
|
+
┌─────────────────────────────────────────────────────────┐
|
|
229
|
+
│ Database (SQLite) │
|
|
230
|
+
│ • workflows • events • tasks • logs │
|
|
231
|
+
└─────────────────────────────────────────────────────────┘
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
### Event Types
|
|
235
|
+
|
|
236
|
+
- `WORKFLOW_STARTED` - Workflow initialization
|
|
237
|
+
- `WORKFLOW_COMPLETED` - Successful completion
|
|
238
|
+
- `WORKFLOW_FAILED` - Fatal error occurred
|
|
239
|
+
- `STATE_SET` - Single state key updated
|
|
240
|
+
- `STATE_UPDATE` - Batch state update
|
|
241
|
+
- `ACTIVITY_SCHEDULED` - Activity queued for execution
|
|
242
|
+
- `ACTIVITY_COMPLETED` - Activity finished successfully
|
|
243
|
+
- `ACTIVITY_FAILED` - Activity permanently failed
|
|
244
|
+
- `TIMER_FIRED` - Sleep/delay completed
|
|
245
|
+
- `SIGNAL_RECEIVED` - External signal received
|
|
246
|
+
|
|
247
|
+
## 📚 Documentation
|
|
248
|
+
|
|
249
|
+
See [`.copilot-instructions.md`](.copilot-instructions.md) for comprehensive development guidelines including:
|
|
250
|
+
|
|
251
|
+
- Event sourcing patterns
|
|
252
|
+
- Deterministic execution rules
|
|
253
|
+
- Activity best practices
|
|
254
|
+
- Testing strategies
|
|
255
|
+
- Common pitfalls to avoid
|
|
256
|
+
|
|
257
|
+
## 🧪 Testing
|
|
258
|
+
|
|
259
|
+
```bash
|
|
260
|
+
# Run all tests
|
|
261
|
+
pytest
|
|
262
|
+
|
|
263
|
+
# Run with coverage
|
|
264
|
+
pytest --cov=src --cov-report=html
|
|
265
|
+
|
|
266
|
+
# Run specific test file
|
|
267
|
+
pytest tests/test_workflow.py
|
|
268
|
+
|
|
269
|
+
# Verbose output
|
|
270
|
+
pytest -v
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
## Project Structure
|
|
274
|
+
|
|
275
|
+
```
|
|
276
|
+
loom/
|
|
277
|
+
├── src/
|
|
278
|
+
│ ├── common/ # Shared utilities
|
|
279
|
+
│ ├── core/ # Core engine (context, engine, runner, worker)
|
|
280
|
+
│ ├── database/ # Database layer
|
|
281
|
+
│ ├── decorators/ # @workflow, @step, @activity
|
|
282
|
+
│ ├── lib/ # Utilities and progress tracking
|
|
283
|
+
│ ├── migrations/ # Database migrations
|
|
284
|
+
│ └── schemas/ # Type definitions
|
|
285
|
+
├── tests/ # Test suite
|
|
286
|
+
├── examples/ # Example workflows
|
|
287
|
+
├── loom.py # Main package interface
|
|
288
|
+
└── pyproject.toml # Package configuration
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
## Configuration
|
|
292
|
+
|
|
293
|
+
Loom uses SQLite by default for simplicity. For production:
|
|
294
|
+
|
|
295
|
+
- Consider PostgreSQL/MySQL for scalability
|
|
296
|
+
- Implement connection pooling
|
|
297
|
+
- Add monitoring and alerting
|
|
298
|
+
- Deploy multiple workers for high availability
|
|
299
|
+
|
|
300
|
+
## Contributing
|
|
301
|
+
|
|
302
|
+
Contributions welcome! Please ensure:
|
|
303
|
+
|
|
304
|
+
1. Tests pass: `pytest`
|
|
305
|
+
2. Code formatted: `black .`
|
|
306
|
+
3. Type checking: `mypy .`
|
|
307
|
+
4. Linting: `ruff check .`
|
|
308
|
+
|
|
309
|
+
## License
|
|
310
|
+
|
|
311
|
+
MIT License - see LICENSE file for details
|
|
312
|
+
|
|
313
|
+
## Acknowledgments
|
|
314
|
+
|
|
315
|
+
Inspired by:
|
|
316
|
+
- [Temporal](https://temporal.io/) - The workflow orchestration platform
|
|
317
|
+
- [Durable Task Framework](https://github.com/Azure/durabletask) - Microsoft's durable task library
|
|
318
|
+
- [Cadence](https://cadenceworkflow.io/) - Uber's workflow platform
|
|
319
|
+
|
|
320
|
+
---
|
|
321
|
+
|
|
322
|
+
**Built withpy src`
|
|
323
|
+
4. Linting: `ruff check src`
|
|
324
|
+
|
|
325
|
+
## 📝 License
|
|
326
|
+
|
|
327
|
+
MIT License - see LICENSE file for details
|
|
328
|
+
|
|
329
|
+
## 🙏 Acknowledgments
|
|
330
|
+
|
|
331
|
+
Inspired by:
|
|
332
|
+
- [Temporal](https://temporal.io/) - The workflow orchestration platform
|
|
333
|
+
- [Durable Task Framework](https://github.com/Azure/durabletask) - Microsoft's durable task library
|
|
334
|
+
- [Cadence](https://cadenceworkflow.io/) - Uber's workflow platform
|
|
335
|
+
|
|
336
|
+
## 📧 Contact
|
|
337
|
+
|
|
338
|
+
For questions and support, please open an issue on GitHub.
|
|
339
|
+
|
|
340
|
+
---
|
|
341
|
+
|
|
342
|
+
**Built with ❤️ using Python 3.12+**
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
loom_core-0.1.0.dist-info/licenses/LICENSE,sha256=8EpC-clAYRUfJQ92T3iQEIIWYjx2A3Kfk28zOd8lh7I,1095
|
|
2
|
+
src/__init__.py,sha256=BESUSbebsjCFRkELNqdCJ3USyVbnoomCl6IRmsdOfLI,1294
|
|
3
|
+
src/cli/__init__.py,sha256=BI8VfSIB5MF4_D9GxHFJwynNEvosDHReVGvsliS99ho,73
|
|
4
|
+
src/cli/cli.py,sha256=cykYs_CKkJWck4auqDxxns9bgPkVznuN9HWsVgfHAmM,7673
|
|
5
|
+
src/common/activity.py,sha256=DXAKEJw5IgvUNJj8yr3Vu0UfxnBZW_KkKcBt70TnpyU,1078
|
|
6
|
+
src/common/config.py,sha256=NZHW07CzpWCaLv77nhULycmD7_QMHdF-3AsrxDFid4A,273
|
|
7
|
+
src/common/errors.py,sha256=jc7_XS8dUPS8fg5pb7kJaTuIR1e6eKBZyZtbsHW3lgM,1712
|
|
8
|
+
src/common/workflow.py,sha256=YfiS0FBhzEBp71t6YKsqM7aNvklvFatb_h3RbgAormQ,1945
|
|
9
|
+
src/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
10
|
+
src/core/compiled.py,sha256=Y2NQDMZVLee65ILgJoK2Ny_OcR1T4LJnOQWQcyg0Z7U,1178
|
|
11
|
+
src/core/context.py,sha256=rVWWSOaAmdVOzKKFh9TwpJVX-4Rm0h7bC76ipEcqVBw,9219
|
|
12
|
+
src/core/engine.py,sha256=rZHl15Qa36zvv0r7XDi2f0NGzXoO6X3uHrKaA-jlax4,4202
|
|
13
|
+
src/core/handle.py,sha256=beOVmJit-gSrk7II4c2KuSubmr5OIPls82_vJ-pI04U,5532
|
|
14
|
+
src/core/logger.py,sha256=4ej95IdHOdBh-y7PQoRFz_H22PJYDXvAioBoId8mOhg,1729
|
|
15
|
+
src/core/runner.py,sha256=pYITY35Q88ItZA4EuSWmNE5sgxL0tExXrm9j5vSaz6o,1718
|
|
16
|
+
src/core/state.py,sha256=jdFzSPanATeiWAkQewwcSDjjVseOyMRUdDfsc-a34mQ,2996
|
|
17
|
+
src/core/worker.py,sha256=jpTtvM1rIToVkG4SwJu1W9Q-eL3bw8b3N8KsxxrRovA,5322
|
|
18
|
+
src/core/workflow.py,sha256=E_A2rI6iaW3liZmVy3X98oxSeBDXMGiQnRZRq3Cp3BA,5755
|
|
19
|
+
src/database/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
20
|
+
src/database/db.py,sha256=BtZTNtZ6cXpfvrtdmW8Xb47zoC2NXvVoWVmUILow2eA,23535
|
|
21
|
+
src/decorators/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
22
|
+
src/decorators/activity.py,sha256=xt7oeYOKJxhKIEcwWsSVA26c_jk4yQB1PHtbcg3tCFI,4824
|
|
23
|
+
src/decorators/workflow.py,sha256=rBpbnpLfDTTAWdgiERpUPIgNUJpnYJKvBZPmzx-ECcc,1516
|
|
24
|
+
src/lib/progress.py,sha256=Es-BKYVI5xOsC-K6wBi5kUbloYIlh5X_V8sLkU7W9IU,3354
|
|
25
|
+
src/lib/utils.py,sha256=aL4VR-_JXbNLYsJYyFL__JQRAq6NQzBYetvHqMGIgYY,809
|
|
26
|
+
src/migrations/down/001_setup_pragma.sql,sha256=NGUGhNmJaroGe_APkLmp6p4q6-zVEYGKHJE4wJixfgs,280
|
|
27
|
+
src/migrations/down/002_create_workflows.sql,sha256=rQcF30tXrBJbbGkOIlJlVMBJ7SZNQHtJpMjgNmo_-hE,58
|
|
28
|
+
src/migrations/down/003.create_events.sql,sha256=5fpnS9yA6gp5z-dOeg7f-klblJPugrwZ6jgwNrQAGLw,52
|
|
29
|
+
src/migrations/down/004.create_tasks.sql,sha256=vFSGPYQLyWdk7sNTk5jrrq3fHZsw1trcPZAd_eL9kVc,50
|
|
30
|
+
src/migrations/down/005.create_indexes.sql,sha256=aDFXwWWwkyjpGqG9zZHTsQ4XyAhrNxDwjivYpVRf458,148
|
|
31
|
+
src/migrations/down/006_auto_update_triggers.sql,sha256=1lEFZsuYANADENOM6baHSA4ljqiovOSstQXIzw80hUc,108
|
|
32
|
+
src/migrations/down/007_create_logs.sql,sha256=LziyAbGM5OFDa2skhk5XhSeC3yzSOaP3Kh_a2gSAEQQ,26
|
|
33
|
+
src/migrations/up/001_setup_pragma.sql,sha256=MAm4ghbC1CXs9OcAryvL-LnwMy00Igb_Ax5Ik2w0YGE,317
|
|
34
|
+
src/migrations/up/002_create_workflows.sql,sha256=2gSUk4EF7dk3mTz6MHHQ-MA6-A8tvbpI30YzgQ9zLCA,530
|
|
35
|
+
src/migrations/up/003_create_events.sql,sha256=3b5uDBjuNkPom4NWUDlV0Xml4tj7BkHBoksJooC1pFk,388
|
|
36
|
+
src/migrations/up/004_create_tasks.sql,sha256=xLGGDFgb0DrrBkiYUOdQ80z019v5MZE7HoA_6MLpCJg,794
|
|
37
|
+
src/migrations/up/005_create_indexes.sql,sha256=1nZVwoyHJdV7YgwXCOZdWFyV0UCZI_jpjsxHyNO9u90,323
|
|
38
|
+
src/migrations/up/006_auto_update_triggers.sql,sha256=hnsbGu6n5XMFKgVha2A_rw9IVRw9zB3Zw73PGOc2R3Y,447
|
|
39
|
+
src/migrations/up/007_create_logs.sql,sha256=IV7vy9U1mGnN4nAZqLwTCyII9Qeeqzx-b1_sSsk1PO4,345
|
|
40
|
+
src/schemas/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
41
|
+
src/schemas/activity.py,sha256=0sYvmmsVhDFFPyOHkVm0tajVaAAzoq5wY6-K03nPSos,266
|
|
42
|
+
src/schemas/database.py,sha256=v9JXHWx4G_r1-SJcrCJkcnaI7Zbic-ZxtHnd7ezXrF8,282
|
|
43
|
+
src/schemas/events.py,sha256=Gz-R836nVXNSsp4Y54idhKs_WTvzFPmx5KlA8PunP28,2216
|
|
44
|
+
src/schemas/tasks.py,sha256=DJbLInggIGxI-CfP1kSyK79Bz83e3sZyEKh6C2HE8q4,1341
|
|
45
|
+
src/schemas/workflow.py,sha256=F1cNEJRuEWLjPhGinEZE2T6vwchDC8RuTHmxEIaH6Ls,671
|
|
46
|
+
loom_core-0.1.0.dist-info/METADATA,sha256=xMFFZyf9gfKbwMCCyhKKOq3uxZePKTCJweptoqgpiao,11944
|
|
47
|
+
loom_core-0.1.0.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
48
|
+
loom_core-0.1.0.dist-info/entry_points.txt,sha256=CgWbuziOoZ90zDBfSlj8mpMOu3scxAzYN10vnYWn9Gk,41
|
|
49
|
+
loom_core-0.1.0.dist-info/top_level.txt,sha256=74rtVfumQlgAPzR5_2CgYN24MB0XARCg0t-gzk6gTrM,4
|
|
50
|
+
loom_core-0.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Loom Contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
src
|
src/__init__.py
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"""Loom - Durable workflow orchestration engine for Python.
|
|
2
|
+
|
|
3
|
+
This module provides the main API for creating and managing durable workflows.
|
|
4
|
+
|
|
5
|
+
Example:
|
|
6
|
+
>>> import loom
|
|
7
|
+
>>>
|
|
8
|
+
>>> @loom.activity(name="greet", retry_count=3)
|
|
9
|
+
>>> async def greet(name: str) -> str:
|
|
10
|
+
... return f"Hello, {name}!"
|
|
11
|
+
>>>
|
|
12
|
+
>>> @loom.workflow(name="GreetingWorkflow", version="1.0.0")
|
|
13
|
+
>>> class GreetingWorkflow(loom.Workflow[dict, dict]):
|
|
14
|
+
... @loom.step(name="greet_step")
|
|
15
|
+
... async def greet_step(self, ctx):
|
|
16
|
+
... result = await ctx.activity(greet, ctx.input["name"])
|
|
17
|
+
... await ctx.state.set("result", result)
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
from src.core.context import WorkflowContext
|
|
21
|
+
from src.core.runner import run_once
|
|
22
|
+
from src.core.worker import WorkflowWorker, start_worker
|
|
23
|
+
from src.core.workflow import Workflow
|
|
24
|
+
from src.database.db import Database
|
|
25
|
+
from src.decorators.activity import activity
|
|
26
|
+
from src.decorators.workflow import step, workflow
|
|
27
|
+
|
|
28
|
+
__version__ = "0.1.0"
|
|
29
|
+
|
|
30
|
+
__all__ = [
|
|
31
|
+
# Decorators
|
|
32
|
+
"activity",
|
|
33
|
+
"workflow",
|
|
34
|
+
"step",
|
|
35
|
+
# Core classes
|
|
36
|
+
"Workflow",
|
|
37
|
+
"WorkflowContext",
|
|
38
|
+
"Database",
|
|
39
|
+
"WorkflowWorker",
|
|
40
|
+
# Functions
|
|
41
|
+
"start_worker",
|
|
42
|
+
"run_once",
|
|
43
|
+
# Version
|
|
44
|
+
"__version__",
|
|
45
|
+
]
|