vega-framework 0.1.28__py3-none-any.whl → 0.1.30__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.
- vega/cli/commands/generate.py +114 -0
- vega/cli/commands/init.py +6 -0
- vega/cli/commands/web.py +9 -0
- vega/cli/main.py +18 -1
- vega/cli/templates/__init__.py +6 -0
- vega/cli/templates/components.py +34 -0
- vega/cli/templates/domain/event.py.j2 +23 -0
- vega/cli/templates/domain/event_handler.py.j2 +22 -0
- vega/cli/templates/domain/repository_interface.py.j2 +1 -1
- vega/cli/templates/project/events_init.py.j2 +32 -0
- vega/discovery/__init__.py +2 -1
- vega/discovery/events.py +86 -0
- vega/events/README.md +564 -0
- vega/events/SYNTAX_GUIDE.md +360 -0
- vega/events/__init__.py +30 -0
- vega/events/bus.py +382 -0
- vega/events/decorators.py +181 -0
- vega/events/event.py +156 -0
- vega/events/middleware.py +259 -0
- vega/patterns/interactor.py +47 -1
- {vega_framework-0.1.28.dist-info → vega_framework-0.1.30.dist-info}/METADATA +1 -1
- {vega_framework-0.1.28.dist-info → vega_framework-0.1.30.dist-info}/RECORD +25 -14
- {vega_framework-0.1.28.dist-info → vega_framework-0.1.30.dist-info}/WHEEL +0 -0
- {vega_framework-0.1.28.dist-info → vega_framework-0.1.30.dist-info}/entry_points.txt +0 -0
- {vega_framework-0.1.28.dist-info → vega_framework-0.1.30.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,360 @@
|
|
1
|
+
# Event Publishing Syntax Guide
|
2
|
+
|
3
|
+
Vega Events offers **three different syntaxes** for publishing events, from verbose to ultra-clean. Choose the one that best fits your use case!
|
4
|
+
|
5
|
+
---
|
6
|
+
|
7
|
+
## 📊 Syntax Comparison
|
8
|
+
|
9
|
+
### ❌ Verbose Syntax (Not Recommended)
|
10
|
+
|
11
|
+
```python
|
12
|
+
from vega.events import get_event_bus
|
13
|
+
|
14
|
+
# Create event
|
15
|
+
event = UserCreated(user_id="123", email="test@test.com", name="Test")
|
16
|
+
|
17
|
+
# Get bus and publish
|
18
|
+
bus = get_event_bus()
|
19
|
+
await bus.publish(event)
|
20
|
+
```
|
21
|
+
|
22
|
+
**When to use**: Almost never. Only when you need a custom event bus.
|
23
|
+
|
24
|
+
---
|
25
|
+
|
26
|
+
### ✅ Simple Syntax (Recommended Default)
|
27
|
+
|
28
|
+
```python
|
29
|
+
# Create event
|
30
|
+
event = UserCreated(user_id="123", email="test@test.com", name="Test")
|
31
|
+
|
32
|
+
# Publish
|
33
|
+
await event.publish()
|
34
|
+
```
|
35
|
+
|
36
|
+
**When to use**:
|
37
|
+
- Default choice for most scenarios
|
38
|
+
- When you need to inspect/modify the event before publishing
|
39
|
+
- When publishing conditionally
|
40
|
+
- When you want explicit control
|
41
|
+
|
42
|
+
**Advantages**:
|
43
|
+
- Clean and intuitive
|
44
|
+
- No need to import `get_event_bus()`
|
45
|
+
- Event can be inspected before publishing
|
46
|
+
- Can add metadata before publishing
|
47
|
+
|
48
|
+
---
|
49
|
+
|
50
|
+
### 🌟 Ultra-Clean Syntax (Auto-Publish)
|
51
|
+
|
52
|
+
**Step 1: Enable auto-publish on event class**
|
53
|
+
|
54
|
+
```python
|
55
|
+
from dataclasses import dataclass
|
56
|
+
from vega.events import Event
|
57
|
+
|
58
|
+
@dataclass(frozen=True)
|
59
|
+
class UserCreated(Event, auto_publish=True): # ← Enable auto-publish
|
60
|
+
user_id: str
|
61
|
+
email: str
|
62
|
+
name: str
|
63
|
+
|
64
|
+
def __post_init__(self):
|
65
|
+
super().__init__()
|
66
|
+
```
|
67
|
+
|
68
|
+
**Step 2: Just await the constructor!**
|
69
|
+
|
70
|
+
```python
|
71
|
+
# Event is automatically published when instantiated!
|
72
|
+
await UserCreated(user_id="123", email="test@test.com", name="Test")
|
73
|
+
```
|
74
|
+
|
75
|
+
**When to use**:
|
76
|
+
- In workflows where the event should ALWAYS be published immediately
|
77
|
+
- For fire-and-forget events
|
78
|
+
- In Interactor/Mediator patterns (similar to how they work)
|
79
|
+
- When you want the cleanest possible syntax
|
80
|
+
|
81
|
+
**Advantages**:
|
82
|
+
- Cleanest syntax - just like Interactors!
|
83
|
+
- No `.publish()` call needed
|
84
|
+
- Perfect for event-driven workflows
|
85
|
+
- Enforces immediate publishing
|
86
|
+
|
87
|
+
**Limitations**:
|
88
|
+
- Cannot inspect/modify event before publishing
|
89
|
+
- Cannot publish conditionally (event is always published)
|
90
|
+
- Event instance is not accessible (returns coroutine)
|
91
|
+
|
92
|
+
---
|
93
|
+
|
94
|
+
## 🎯 Detailed Examples
|
95
|
+
|
96
|
+
### Example 1: Simple Syntax with Conditional Publishing
|
97
|
+
|
98
|
+
```python
|
99
|
+
from vega.events import Event
|
100
|
+
from dataclasses import dataclass
|
101
|
+
|
102
|
+
@dataclass(frozen=True)
|
103
|
+
class OrderPlaced(Event):
|
104
|
+
order_id: str
|
105
|
+
amount: float
|
106
|
+
customer_email: str
|
107
|
+
|
108
|
+
def __post_init__(self):
|
109
|
+
super().__init__()
|
110
|
+
|
111
|
+
|
112
|
+
async def place_order(order_id: str, amount: float, customer_email: str):
|
113
|
+
"""Place an order and optionally publish event"""
|
114
|
+
|
115
|
+
# Create order...
|
116
|
+
order = save_order(order_id, amount, customer_email)
|
117
|
+
|
118
|
+
# Create event
|
119
|
+
event = OrderPlaced(
|
120
|
+
order_id=order.id,
|
121
|
+
amount=order.amount,
|
122
|
+
customer_email=order.customer_email
|
123
|
+
)
|
124
|
+
|
125
|
+
# Add metadata
|
126
|
+
event.add_metadata('source', 'web_app')
|
127
|
+
event.add_metadata('user_id', get_current_user_id())
|
128
|
+
|
129
|
+
# Publish conditionally
|
130
|
+
if order.amount > 100: # Only publish for large orders
|
131
|
+
await event.publish()
|
132
|
+
|
133
|
+
return order
|
134
|
+
```
|
135
|
+
|
136
|
+
### Example 2: Auto-Publish in Workflows
|
137
|
+
|
138
|
+
```python
|
139
|
+
from vega.events import Event
|
140
|
+
from dataclasses import dataclass
|
141
|
+
|
142
|
+
# Enable auto-publish for workflow events
|
143
|
+
@dataclass(frozen=True)
|
144
|
+
class PaymentProcessed(Event, auto_publish=True):
|
145
|
+
payment_id: str
|
146
|
+
order_id: str
|
147
|
+
amount: float
|
148
|
+
|
149
|
+
def __post_init__(self):
|
150
|
+
super().__init__()
|
151
|
+
|
152
|
+
@dataclass(frozen=True)
|
153
|
+
class OrderShipped(Event, auto_publish=True):
|
154
|
+
order_id: str
|
155
|
+
tracking_number: str
|
156
|
+
|
157
|
+
def __post_init__(self):
|
158
|
+
super().__init__()
|
159
|
+
|
160
|
+
|
161
|
+
async def complete_order_workflow(order_id: str, amount: float):
|
162
|
+
"""Complete order processing workflow"""
|
163
|
+
|
164
|
+
# Process payment - auto-publishes!
|
165
|
+
await PaymentProcessed(
|
166
|
+
payment_id=generate_payment_id(),
|
167
|
+
order_id=order_id,
|
168
|
+
amount=amount
|
169
|
+
)
|
170
|
+
|
171
|
+
# Ship order - auto-publishes!
|
172
|
+
await OrderShipped(
|
173
|
+
order_id=order_id,
|
174
|
+
tracking_number=generate_tracking_number()
|
175
|
+
)
|
176
|
+
|
177
|
+
# Clean, sequential workflow!
|
178
|
+
```
|
179
|
+
|
180
|
+
### Example 3: Mixed Approach
|
181
|
+
|
182
|
+
```python
|
183
|
+
from vega.events import Event
|
184
|
+
from dataclasses import dataclass
|
185
|
+
|
186
|
+
# Manual publish for main events
|
187
|
+
@dataclass(frozen=True)
|
188
|
+
class UserRegistered(Event):
|
189
|
+
user_id: str
|
190
|
+
email: str
|
191
|
+
|
192
|
+
def __post_init__(self):
|
193
|
+
super().__init__()
|
194
|
+
|
195
|
+
# Auto-publish for side-effect events
|
196
|
+
@dataclass(frozen=True)
|
197
|
+
class WelcomeEmailSent(Event, auto_publish=True):
|
198
|
+
user_id: str
|
199
|
+
email: str
|
200
|
+
|
201
|
+
def __post_init__(self):
|
202
|
+
super().__init__()
|
203
|
+
|
204
|
+
|
205
|
+
async def register_user(email: str, password: str):
|
206
|
+
"""Register new user"""
|
207
|
+
|
208
|
+
# Create user...
|
209
|
+
user = create_user(email, password)
|
210
|
+
|
211
|
+
# Main event - manual publish with metadata
|
212
|
+
event = UserRegistered(user_id=user.id, email=user.email)
|
213
|
+
event.add_metadata('registration_source', 'web')
|
214
|
+
await event.publish()
|
215
|
+
|
216
|
+
# Side-effect event - auto-publish
|
217
|
+
await WelcomeEmailSent(user_id=user.id, email=user.email)
|
218
|
+
|
219
|
+
return user
|
220
|
+
```
|
221
|
+
|
222
|
+
### Example 4: Integration with Interactors
|
223
|
+
|
224
|
+
```python
|
225
|
+
from vega.patterns import Interactor
|
226
|
+
from vega.di import bind
|
227
|
+
from vega.events import Event
|
228
|
+
from dataclasses import dataclass
|
229
|
+
|
230
|
+
# Auto-publish for Interactor events
|
231
|
+
@dataclass(frozen=True)
|
232
|
+
class UserCreated(Event, auto_publish=True):
|
233
|
+
user_id: str
|
234
|
+
email: str
|
235
|
+
name: str
|
236
|
+
|
237
|
+
def __post_init__(self):
|
238
|
+
super().__init__()
|
239
|
+
|
240
|
+
|
241
|
+
class CreateUser(Interactor[User]):
|
242
|
+
"""Create a new user"""
|
243
|
+
|
244
|
+
def __init__(self, name: str, email: str):
|
245
|
+
self.name = name
|
246
|
+
self.email = email
|
247
|
+
|
248
|
+
@bind
|
249
|
+
async def call(self, repository: UserRepository) -> User:
|
250
|
+
# Domain logic
|
251
|
+
user = User(name=self.name, email=self.email)
|
252
|
+
user = await repository.save(user)
|
253
|
+
|
254
|
+
# Publish event - auto-publishes!
|
255
|
+
await UserCreated(
|
256
|
+
user_id=user.id,
|
257
|
+
email=user.email,
|
258
|
+
name=user.name
|
259
|
+
)
|
260
|
+
|
261
|
+
return user
|
262
|
+
|
263
|
+
|
264
|
+
# Usage - both use similar syntax!
|
265
|
+
user = await CreateUser(name="John", email="john@example.com")
|
266
|
+
```
|
267
|
+
|
268
|
+
---
|
269
|
+
|
270
|
+
## 🤔 Decision Guide
|
271
|
+
|
272
|
+
Use this flowchart to decide which syntax to use:
|
273
|
+
|
274
|
+
```
|
275
|
+
Do you need a custom event bus?
|
276
|
+
├─ YES → Use: bus.publish(event)
|
277
|
+
└─ NO
|
278
|
+
↓
|
279
|
+
Do you need to modify the event before publishing?
|
280
|
+
├─ YES → Use: event.publish()
|
281
|
+
└─ NO
|
282
|
+
↓
|
283
|
+
Do you need conditional publishing?
|
284
|
+
├─ YES → Use: event.publish()
|
285
|
+
└─ NO
|
286
|
+
↓
|
287
|
+
Is this a workflow/always-publish scenario?
|
288
|
+
├─ YES → Use: auto_publish=True
|
289
|
+
└─ NO → Use: event.publish() (default)
|
290
|
+
```
|
291
|
+
|
292
|
+
---
|
293
|
+
|
294
|
+
## ⚡ Performance Notes
|
295
|
+
|
296
|
+
All three syntaxes have identical performance:
|
297
|
+
- Auto-publish uses metaclass (zero runtime overhead)
|
298
|
+
- `.publish()` calls the same underlying bus
|
299
|
+
- `bus.publish()` is the same method
|
300
|
+
|
301
|
+
**Choose based on code clarity, not performance!**
|
302
|
+
|
303
|
+
---
|
304
|
+
|
305
|
+
## 🎨 Best Practices
|
306
|
+
|
307
|
+
### ✅ DO
|
308
|
+
|
309
|
+
```python
|
310
|
+
# Use auto-publish for workflow events
|
311
|
+
@dataclass(frozen=True)
|
312
|
+
class StepCompleted(Event, auto_publish=True):
|
313
|
+
...
|
314
|
+
|
315
|
+
# Use manual publish for events that need metadata
|
316
|
+
event = UserCreated(...)
|
317
|
+
event.add_metadata('source', 'api')
|
318
|
+
await event.publish()
|
319
|
+
|
320
|
+
# Use consistent style within a module
|
321
|
+
```
|
322
|
+
|
323
|
+
### ❌ DON'T
|
324
|
+
|
325
|
+
```python
|
326
|
+
# Don't mix styles unnecessarily
|
327
|
+
await UserCreated(...) # auto-publish
|
328
|
+
await event.publish() # manual publish
|
329
|
+
# Pick one approach per event type!
|
330
|
+
|
331
|
+
# Don't use auto-publish if you need the event object
|
332
|
+
event = UserCreated(...) # Won't work with auto_publish=True!
|
333
|
+
# auto_publish returns a coroutine, not the event
|
334
|
+
|
335
|
+
# Don't use verbose syntax unless absolutely necessary
|
336
|
+
bus = get_event_bus()
|
337
|
+
await bus.publish(event) # Prefer: await event.publish()
|
338
|
+
```
|
339
|
+
|
340
|
+
---
|
341
|
+
|
342
|
+
## 📚 Summary
|
343
|
+
|
344
|
+
| Syntax | Code | Use Case |
|
345
|
+
|--------|------|----------|
|
346
|
+
| **Verbose** | `await bus.publish(event)` | Custom event bus |
|
347
|
+
| **Simple** | `await event.publish()` | Default choice ✅ |
|
348
|
+
| **Auto-Publish** | `await EventName(...)` | Workflows, always-publish 🌟 |
|
349
|
+
|
350
|
+
**Recommendation**: Start with **Simple syntax** as default, use **Auto-Publish** for workflow events.
|
351
|
+
|
352
|
+
---
|
353
|
+
|
354
|
+
## 🔗 See Also
|
355
|
+
|
356
|
+
- [README.md](README.md) - Full event system documentation
|
357
|
+
- [EVENT_BUS_SUMMARY.md](../../EVENT_BUS_SUMMARY.md) - Implementation summary
|
358
|
+
- [Examples](../../examples/events/) - Working examples
|
359
|
+
- [auto_publish_example.py](../../examples/events/auto_publish_example.py) - Auto-publish demo
|
360
|
+
- [simple_syntax_example.py](../../examples/events/simple_syntax_example.py) - Simple syntax demo
|
vega/events/__init__.py
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
"""Event system for domain events and event-driven architecture"""
|
2
|
+
from vega.events.event import Event, PublishableEventMeta
|
3
|
+
from vega.events.bus import EventBus, get_event_bus, set_event_bus
|
4
|
+
from vega.events.decorators import subscribe, event_handler, trigger
|
5
|
+
from vega.events.middleware import (
|
6
|
+
EventMiddleware,
|
7
|
+
LoggingEventMiddleware,
|
8
|
+
MetricsEventMiddleware,
|
9
|
+
ValidationEventMiddleware,
|
10
|
+
EnrichmentEventMiddleware,
|
11
|
+
)
|
12
|
+
|
13
|
+
__all__ = [
|
14
|
+
# Core
|
15
|
+
'Event',
|
16
|
+
'PublishableEventMeta',
|
17
|
+
'EventBus',
|
18
|
+
'get_event_bus',
|
19
|
+
'set_event_bus',
|
20
|
+
# Decorators
|
21
|
+
'subscribe',
|
22
|
+
'event_handler',
|
23
|
+
'trigger',
|
24
|
+
# Middleware
|
25
|
+
'EventMiddleware',
|
26
|
+
'LoggingEventMiddleware',
|
27
|
+
'MetricsEventMiddleware',
|
28
|
+
'ValidationEventMiddleware',
|
29
|
+
'EnrichmentEventMiddleware',
|
30
|
+
]
|