eventbus-lite 1.0.0__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.
- eventbus_lite-1.0.0/PKG-INFO +443 -0
- eventbus_lite-1.0.0/README.MD +408 -0
- eventbus_lite-1.0.0/eventbus/__init__.py +67 -0
- eventbus_lite-1.0.0/eventbus/bus.py +565 -0
- eventbus_lite-1.0.0/eventbus/event.py +117 -0
- eventbus_lite-1.0.0/eventbus/exceptions.py +72 -0
- eventbus_lite-1.0.0/eventbus/matcher.py +141 -0
- eventbus_lite-1.0.0/eventbus/subscriber.py +46 -0
- eventbus_lite-1.0.0/eventbus_lite.egg-info/PKG-INFO +443 -0
- eventbus_lite-1.0.0/eventbus_lite.egg-info/SOURCES.txt +41 -0
- eventbus_lite-1.0.0/eventbus_lite.egg-info/dependency_links.txt +1 -0
- eventbus_lite-1.0.0/eventbus_lite.egg-info/requires.txt +16 -0
- eventbus_lite-1.0.0/eventbus_lite.egg-info/top_level.txt +1 -0
- eventbus_lite-1.0.0/pyproject.toml +63 -0
- eventbus_lite-1.0.0/setup.cfg +4 -0
- eventbus_lite-1.0.0/tests/test_callable_objects.py +59 -0
- eventbus_lite-1.0.0/tests/test_cancel.py +37 -0
- eventbus_lite-1.0.0/tests/test_context_manager.py +19 -0
- eventbus_lite-1.0.0/tests/test_dead_references.py +75 -0
- eventbus_lite-1.0.0/tests/test_decorator.py +34 -0
- eventbus_lite-1.0.0/tests/test_dispatch_cache.py +53 -0
- eventbus_lite-1.0.0/tests/test_duplicates.py +20 -0
- eventbus_lite-1.0.0/tests/test_error_event.py +72 -0
- eventbus_lite-1.0.0/tests/test_exceptions.py +58 -0
- eventbus_lite-1.0.0/tests/test_gc.py +27 -0
- eventbus_lite-1.0.0/tests/test_invalid_input.py +21 -0
- eventbus_lite-1.0.0/tests/test_locking.py +24 -0
- eventbus_lite-1.0.0/tests/test_matcher.py +25 -0
- eventbus_lite-1.0.0/tests/test_memory_leaks.py +29 -0
- eventbus_lite-1.0.0/tests/test_multiple_patterns.py +66 -0
- eventbus_lite-1.0.0/tests/test_once.py +36 -0
- eventbus_lite-1.0.0/tests/test_pattern_cache.py +70 -0
- eventbus_lite-1.0.0/tests/test_priority.py +33 -0
- eventbus_lite-1.0.0/tests/test_recursive_publish.py +89 -0
- eventbus_lite-1.0.0/tests/test_reentrancy.py +40 -0
- eventbus_lite-1.0.0/tests/test_stable_order.py +51 -0
- eventbus_lite-1.0.0/tests/test_stop_propagation.py +37 -0
- eventbus_lite-1.0.0/tests/test_stress.py +84 -0
- eventbus_lite-1.0.0/tests/test_strict_mode.py +16 -0
- eventbus_lite-1.0.0/tests/test_subscribe.py +42 -0
- eventbus_lite-1.0.0/tests/test_thread_safety.py +30 -0
- eventbus_lite-1.0.0/tests/test_unsubscribe.py +29 -0
- eventbus_lite-1.0.0/tests/test_weakref.py +53 -0
|
@@ -0,0 +1,443 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: eventbus-lite
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Lightweight thread-safe synchronous event bus for Python
|
|
5
|
+
Author: kupriyanovde
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/kupriyanovde/eventbus
|
|
8
|
+
Project-URL: Repository, https://github.com/kupriyanovde/eventbus
|
|
9
|
+
Project-URL: Issues, https://github.com/kupriyanovde/eventbus/issues
|
|
10
|
+
Keywords: eventbus,events,pubsub,observer,messaging,architecture,synchronous
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
20
|
+
Requires-Python: >=3.10
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
Provides-Extra: dev
|
|
23
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
24
|
+
Requires-Dist: pytest-cov>=4.0; extra == "dev"
|
|
25
|
+
Requires-Dist: black>=23.0; extra == "dev"
|
|
26
|
+
Requires-Dist: flake8>=6.0; extra == "dev"
|
|
27
|
+
Requires-Dist: mypy>=1.0; extra == "dev"
|
|
28
|
+
Requires-Dist: pre-commit>=3.0; extra == "dev"
|
|
29
|
+
Provides-Extra: test
|
|
30
|
+
Requires-Dist: pytest>=7.0; extra == "test"
|
|
31
|
+
Requires-Dist: pytest-cov>=4.0; extra == "test"
|
|
32
|
+
Provides-Extra: docs
|
|
33
|
+
Requires-Dist: sphinx>=6.0; extra == "docs"
|
|
34
|
+
Requires-Dist: sphinx-rtd-theme>=1.3; extra == "docs"
|
|
35
|
+
|
|
36
|
+
# EventBus
|
|
37
|
+
|
|
38
|
+
Лёгкая потокобезопасная шина событий (publish/subscribe) для Python.
|
|
39
|
+
|
|
40
|
+
## Возможности
|
|
41
|
+
|
|
42
|
+
* синхронная обработка событий;
|
|
43
|
+
* потокобезопасность;
|
|
44
|
+
* приоритеты обработчиков;
|
|
45
|
+
* стабильный порядок вызова;
|
|
46
|
+
* одноразовые подписки (`once`);
|
|
47
|
+
* декораторы регистрации;
|
|
48
|
+
* временные подписки через контекстный менеджер;
|
|
49
|
+
* поддержка шаблонов `*` и `**`;
|
|
50
|
+
* отмена события;
|
|
51
|
+
* остановка распространения события;
|
|
52
|
+
* слабые ссылки на методы и вызываемые объекты;
|
|
53
|
+
* автоматическое удаление уничтоженных подписчиков;
|
|
54
|
+
* кэширование маршрутизации событий;
|
|
55
|
+
* генерация событий об ошибках;
|
|
56
|
+
* строгий режим обработки исключений;
|
|
57
|
+
* отсутствие внешних зависимостей.
|
|
58
|
+
|
|
59
|
+
Поддерживаемые версии Python:
|
|
60
|
+
|
|
61
|
+
* Python 3.10+
|
|
62
|
+
* Python 3.11
|
|
63
|
+
* Python 3.12
|
|
64
|
+
* Python 3.13
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
# Установка
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
pip install eventbus
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
# Быстрый старт
|
|
77
|
+
|
|
78
|
+
```python
|
|
79
|
+
from eventbus import EventBus
|
|
80
|
+
|
|
81
|
+
bus = EventBus()
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def handler(event):
|
|
85
|
+
print(event.type)
|
|
86
|
+
print(event.data)
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
bus.subscribe(
|
|
90
|
+
"system/start",
|
|
91
|
+
handler
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
bus.publish(
|
|
95
|
+
"system/start",
|
|
96
|
+
version="1.0"
|
|
97
|
+
)
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Результат:
|
|
101
|
+
|
|
102
|
+
```text
|
|
103
|
+
system/start
|
|
104
|
+
{'version': '1.0'}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
# Объект Event
|
|
110
|
+
|
|
111
|
+
Каждое событие представлено экземпляром класса `Event`.
|
|
112
|
+
|
|
113
|
+
```python
|
|
114
|
+
event.type
|
|
115
|
+
event.data
|
|
116
|
+
event.source
|
|
117
|
+
event.timestamp
|
|
118
|
+
event.result
|
|
119
|
+
event.cancelled
|
|
120
|
+
event.propagation_stopped
|
|
121
|
+
event.exception
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
# Подписка
|
|
127
|
+
|
|
128
|
+
```python
|
|
129
|
+
bus.subscribe(
|
|
130
|
+
"system/start",
|
|
131
|
+
handler
|
|
132
|
+
)
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
# Публикация
|
|
138
|
+
|
|
139
|
+
```python
|
|
140
|
+
event = bus.publish(
|
|
141
|
+
"system/start",
|
|
142
|
+
value=123
|
|
143
|
+
)
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
Метод `publish()` возвращает объект `Event`.
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
# Приоритеты
|
|
151
|
+
|
|
152
|
+
Обработчики вызываются в порядке возрастания приоритета.
|
|
153
|
+
|
|
154
|
+
```python
|
|
155
|
+
bus.subscribe(
|
|
156
|
+
"test",
|
|
157
|
+
first_handler,
|
|
158
|
+
priority=100
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
bus.subscribe(
|
|
162
|
+
"test",
|
|
163
|
+
second_handler,
|
|
164
|
+
priority=200
|
|
165
|
+
)
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
Сначала будет вызван `first_handler`.
|
|
169
|
+
|
|
170
|
+
---
|
|
171
|
+
|
|
172
|
+
# Стабильный порядок
|
|
173
|
+
|
|
174
|
+
Если приоритеты одинаковы, обработчики вызываются в порядке регистрации.
|
|
175
|
+
|
|
176
|
+
```python
|
|
177
|
+
bus.subscribe("test", h1)
|
|
178
|
+
bus.subscribe("test", h2)
|
|
179
|
+
bus.subscribe("test", h3)
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
Порядок вызова:
|
|
183
|
+
|
|
184
|
+
```text
|
|
185
|
+
h1
|
|
186
|
+
h2
|
|
187
|
+
h3
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
---
|
|
191
|
+
|
|
192
|
+
# Одноразовые обработчики
|
|
193
|
+
|
|
194
|
+
```python
|
|
195
|
+
bus.subscribe(
|
|
196
|
+
"system/start",
|
|
197
|
+
handler,
|
|
198
|
+
once=True
|
|
199
|
+
)
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
После первого вызова обработчик будет автоматически удалён.
|
|
203
|
+
|
|
204
|
+
---
|
|
205
|
+
|
|
206
|
+
# Декораторы
|
|
207
|
+
|
|
208
|
+
## on()
|
|
209
|
+
|
|
210
|
+
```python
|
|
211
|
+
@bus.on("system/start")
|
|
212
|
+
def on_start(event):
|
|
213
|
+
print("started")
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
## once()
|
|
217
|
+
|
|
218
|
+
```python
|
|
219
|
+
@bus.once("system/start")
|
|
220
|
+
def initialize(event):
|
|
221
|
+
print("called once")
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
---
|
|
225
|
+
|
|
226
|
+
# Удаление подписки
|
|
227
|
+
|
|
228
|
+
```python
|
|
229
|
+
bus.unsubscribe(
|
|
230
|
+
"system/start",
|
|
231
|
+
handler
|
|
232
|
+
)
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
---
|
|
236
|
+
|
|
237
|
+
# Контекстный менеджер
|
|
238
|
+
|
|
239
|
+
```python
|
|
240
|
+
with bus.subscription(
|
|
241
|
+
"system/start",
|
|
242
|
+
handler
|
|
243
|
+
):
|
|
244
|
+
bus.publish("system/start")
|
|
245
|
+
|
|
246
|
+
# подписка автоматически удалена
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
---
|
|
250
|
+
|
|
251
|
+
# Шаблоны
|
|
252
|
+
|
|
253
|
+
## Точное совпадение
|
|
254
|
+
|
|
255
|
+
```python
|
|
256
|
+
system/start
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
---
|
|
260
|
+
|
|
261
|
+
## *
|
|
262
|
+
|
|
263
|
+
Один сегмент.
|
|
264
|
+
|
|
265
|
+
```python
|
|
266
|
+
system/*
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
Подходит для:
|
|
270
|
+
|
|
271
|
+
```text
|
|
272
|
+
system/start
|
|
273
|
+
system/stop
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
---
|
|
277
|
+
|
|
278
|
+
## **
|
|
279
|
+
|
|
280
|
+
Любое количество сегментов.
|
|
281
|
+
|
|
282
|
+
```python
|
|
283
|
+
system/**
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
Подходит для:
|
|
287
|
+
|
|
288
|
+
```text
|
|
289
|
+
system
|
|
290
|
+
system/start
|
|
291
|
+
system/core/start
|
|
292
|
+
system/core/network/start
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
---
|
|
296
|
+
|
|
297
|
+
# Отмена события
|
|
298
|
+
|
|
299
|
+
```python
|
|
300
|
+
def handler(event):
|
|
301
|
+
event.cancel("denied")
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
После вызова:
|
|
305
|
+
|
|
306
|
+
```python
|
|
307
|
+
event.cancelled == True
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
Оставшиеся обработчики вызваны не будут.
|
|
311
|
+
|
|
312
|
+
Результат доступен через:
|
|
313
|
+
|
|
314
|
+
```python
|
|
315
|
+
event.result
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
---
|
|
319
|
+
|
|
320
|
+
# Остановка распространения
|
|
321
|
+
|
|
322
|
+
```python
|
|
323
|
+
def handler(event):
|
|
324
|
+
event.stop_propagation()
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
Оставшиеся обработчики не вызываются, однако событие не считается отменённым.
|
|
328
|
+
|
|
329
|
+
```python
|
|
330
|
+
event.cancelled == False
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
---
|
|
334
|
+
|
|
335
|
+
# Исключения
|
|
336
|
+
|
|
337
|
+
По умолчанию исключения внутри обработчиков не прерывают работу EventBus.
|
|
338
|
+
|
|
339
|
+
```python
|
|
340
|
+
def handler(event):
|
|
341
|
+
raise RuntimeError()
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
Исключение сохраняется:
|
|
345
|
+
|
|
346
|
+
```python
|
|
347
|
+
event.exception
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
Также автоматически публикуется событие:
|
|
351
|
+
|
|
352
|
+
```text
|
|
353
|
+
system/error/event
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
---
|
|
357
|
+
|
|
358
|
+
# Строгий режим
|
|
359
|
+
|
|
360
|
+
```python
|
|
361
|
+
bus = EventBus(strict=True)
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
В этом режиме исключение приводит к возбуждению:
|
|
365
|
+
|
|
366
|
+
```python
|
|
367
|
+
EventDispatchError
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
---
|
|
371
|
+
|
|
372
|
+
# Слабые ссылки
|
|
373
|
+
|
|
374
|
+
Методы объектов и вызываемые экземпляры хранятся через слабые ссылки.
|
|
375
|
+
|
|
376
|
+
Если объект уничтожен сборщиком мусора, подписка удаляется автоматически.
|
|
377
|
+
|
|
378
|
+
```python
|
|
379
|
+
class Receiver:
|
|
380
|
+
|
|
381
|
+
def on_event(self, event):
|
|
382
|
+
pass
|
|
383
|
+
|
|
384
|
+
|
|
385
|
+
receiver = Receiver()
|
|
386
|
+
|
|
387
|
+
bus.subscribe(
|
|
388
|
+
"test",
|
|
389
|
+
receiver.on_event
|
|
390
|
+
)
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
---
|
|
394
|
+
|
|
395
|
+
# Потокобезопасность
|
|
396
|
+
|
|
397
|
+
Все операции регистрации, удаления подписчиков и публикации событий являются потокобезопасными.
|
|
398
|
+
|
|
399
|
+
```python
|
|
400
|
+
from threading import Thread
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
Один экземпляр `EventBus` может безопасно использоваться несколькими потоками одновременно.
|
|
404
|
+
|
|
405
|
+
---
|
|
406
|
+
|
|
407
|
+
# Исключения библиотеки
|
|
408
|
+
|
|
409
|
+
## EventBusError
|
|
410
|
+
|
|
411
|
+
Базовый класс всех исключений.
|
|
412
|
+
|
|
413
|
+
## InvalidPatternError
|
|
414
|
+
|
|
415
|
+
Некорректный шаблон события.
|
|
416
|
+
|
|
417
|
+
## InvalidHandlerError
|
|
418
|
+
|
|
419
|
+
Переданный объект не является вызываемым.
|
|
420
|
+
|
|
421
|
+
## DuplicateSubscriptionError
|
|
422
|
+
|
|
423
|
+
Ошибка повторной регистрации.
|
|
424
|
+
|
|
425
|
+
## EventDispatchError
|
|
426
|
+
|
|
427
|
+
Ошибка обработки события.
|
|
428
|
+
|
|
429
|
+
---
|
|
430
|
+
|
|
431
|
+
# Тестирование
|
|
432
|
+
|
|
433
|
+
Проект покрыт тестами.
|
|
434
|
+
|
|
435
|
+
```bash
|
|
436
|
+
pytest
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
---
|
|
440
|
+
|
|
441
|
+
# Лицензия
|
|
442
|
+
|
|
443
|
+
MIT License
|