eventsourcing 9.4.0a2__py3-none-any.whl → 9.4.0a4__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.
Potentially problematic release.
This version of eventsourcing might be problematic. Click here for more details.
- eventsourcing/persistence.py +14 -4
- eventsourcing/popo.py +10 -4
- eventsourcing/postgres.py +10 -4
- eventsourcing/projection.py +20 -5
- eventsourcing/sqlite.py +3 -1
- eventsourcing/tests/persistence.py +39 -0
- {eventsourcing-9.4.0a2.dist-info → eventsourcing-9.4.0a4.dist-info}/METADATA +2 -2
- {eventsourcing-9.4.0a2.dist-info → eventsourcing-9.4.0a4.dist-info}/RECORD +11 -11
- {eventsourcing-9.4.0a2.dist-info → eventsourcing-9.4.0a4.dist-info}/AUTHORS +0 -0
- {eventsourcing-9.4.0a2.dist-info → eventsourcing-9.4.0a4.dist-info}/LICENSE +0 -0
- {eventsourcing-9.4.0a2.dist-info → eventsourcing-9.4.0a4.dist-info}/WHEEL +0 -0
eventsourcing/persistence.py
CHANGED
|
@@ -486,7 +486,9 @@ class ApplicationRecorder(AggregateRecorder):
|
|
|
486
486
|
"""
|
|
487
487
|
|
|
488
488
|
@abstractmethod
|
|
489
|
-
def subscribe(
|
|
489
|
+
def subscribe(
|
|
490
|
+
self, gt: int | None = None, topics: Sequence[str] = ()
|
|
491
|
+
) -> Subscription[ApplicationRecorder]:
|
|
490
492
|
"""
|
|
491
493
|
Returns an iterator of Notification objects representing events from an
|
|
492
494
|
application sequence.
|
|
@@ -1311,10 +1313,14 @@ TApplicationRecorder_co = TypeVar(
|
|
|
1311
1313
|
|
|
1312
1314
|
class Subscription(Iterator[Notification], Generic[TApplicationRecorder_co]):
|
|
1313
1315
|
def __init__(
|
|
1314
|
-
self,
|
|
1316
|
+
self,
|
|
1317
|
+
recorder: TApplicationRecorder_co,
|
|
1318
|
+
gt: int | None = None,
|
|
1319
|
+
topics: Sequence[str] = (),
|
|
1315
1320
|
) -> None:
|
|
1316
1321
|
self._recorder = recorder
|
|
1317
1322
|
self._last_notification_id = gt
|
|
1323
|
+
self._topics = topics
|
|
1318
1324
|
self._has_been_entered = False
|
|
1319
1325
|
self._has_been_stopped = False
|
|
1320
1326
|
|
|
@@ -1349,9 +1355,12 @@ class Subscription(Iterator[Notification], Generic[TApplicationRecorder_co]):
|
|
|
1349
1355
|
|
|
1350
1356
|
class ListenNotifySubscription(Subscription[TApplicationRecorder_co]):
|
|
1351
1357
|
def __init__(
|
|
1352
|
-
self,
|
|
1358
|
+
self,
|
|
1359
|
+
recorder: TApplicationRecorder_co,
|
|
1360
|
+
gt: int | None = None,
|
|
1361
|
+
topics: Sequence[str] = (),
|
|
1353
1362
|
) -> None:
|
|
1354
|
-
super().__init__(recorder=recorder, gt=gt)
|
|
1363
|
+
super().__init__(recorder=recorder, gt=gt, topics=topics)
|
|
1355
1364
|
self._select_limit = 500
|
|
1356
1365
|
self._notifications: List[Notification] = []
|
|
1357
1366
|
self._notifications_index: int = 0
|
|
@@ -1410,6 +1419,7 @@ class ListenNotifySubscription(Subscription[TApplicationRecorder_co]):
|
|
|
1410
1419
|
notifications = self._recorder.select_notifications(
|
|
1411
1420
|
start=self._last_notification_id or 0,
|
|
1412
1421
|
limit=self._select_limit,
|
|
1422
|
+
topics=self._topics,
|
|
1413
1423
|
inclusive_of_start=False,
|
|
1414
1424
|
)
|
|
1415
1425
|
if len(notifications) > 0:
|
eventsourcing/popo.py
CHANGED
|
@@ -14,6 +14,7 @@ from eventsourcing.persistence import (
|
|
|
14
14
|
Notification,
|
|
15
15
|
ProcessRecorder,
|
|
16
16
|
StoredEvent,
|
|
17
|
+
Subscription,
|
|
17
18
|
Tracking,
|
|
18
19
|
TrackingRecorder,
|
|
19
20
|
)
|
|
@@ -155,8 +156,10 @@ class POPOApplicationRecorder(POPOAggregateRecorder, ApplicationRecorder):
|
|
|
155
156
|
with self._database_lock:
|
|
156
157
|
return len(self._stored_events) or None
|
|
157
158
|
|
|
158
|
-
def subscribe(
|
|
159
|
-
|
|
159
|
+
def subscribe(
|
|
160
|
+
self, gt: int | None = None, topics: Sequence[str] = ()
|
|
161
|
+
) -> Subscription[ApplicationRecorder]:
|
|
162
|
+
return POPOSubscription(recorder=self, gt=gt, topics=topics)
|
|
160
163
|
|
|
161
164
|
def listen(self, event: Event) -> None:
|
|
162
165
|
self._listeners.add(event)
|
|
@@ -172,10 +175,13 @@ class POPOApplicationRecorder(POPOAggregateRecorder, ApplicationRecorder):
|
|
|
172
175
|
|
|
173
176
|
class POPOSubscription(ListenNotifySubscription[POPOApplicationRecorder]):
|
|
174
177
|
def __init__(
|
|
175
|
-
self,
|
|
178
|
+
self,
|
|
179
|
+
recorder: POPOApplicationRecorder,
|
|
180
|
+
gt: int | None = None,
|
|
181
|
+
topics: Sequence[str] = (),
|
|
176
182
|
) -> None:
|
|
177
183
|
assert isinstance(recorder, POPOApplicationRecorder)
|
|
178
|
-
super().__init__(recorder=recorder, gt=gt)
|
|
184
|
+
super().__init__(recorder=recorder, gt=gt, topics=topics)
|
|
179
185
|
self._recorder.listen(self._has_been_notified)
|
|
180
186
|
|
|
181
187
|
def stop(self) -> None:
|
eventsourcing/postgres.py
CHANGED
|
@@ -30,6 +30,7 @@ from eventsourcing.persistence import (
|
|
|
30
30
|
ProcessRecorder,
|
|
31
31
|
ProgrammingError,
|
|
32
32
|
StoredEvent,
|
|
33
|
+
Subscription,
|
|
33
34
|
Tracking,
|
|
34
35
|
TrackingRecorder,
|
|
35
36
|
)
|
|
@@ -524,16 +525,21 @@ class PostgresApplicationRecorder(PostgresAggregateRecorder, ApplicationRecorder
|
|
|
524
525
|
raise ProgrammingError(msg)
|
|
525
526
|
return notification_ids
|
|
526
527
|
|
|
527
|
-
def subscribe(
|
|
528
|
-
|
|
528
|
+
def subscribe(
|
|
529
|
+
self, gt: int | None = None, topics: Sequence[str] = ()
|
|
530
|
+
) -> Subscription[ApplicationRecorder]:
|
|
531
|
+
return PostgresSubscription(recorder=self, gt=gt, topics=topics)
|
|
529
532
|
|
|
530
533
|
|
|
531
534
|
class PostgresSubscription(ListenNotifySubscription[PostgresApplicationRecorder]):
|
|
532
535
|
def __init__(
|
|
533
|
-
self,
|
|
536
|
+
self,
|
|
537
|
+
recorder: PostgresApplicationRecorder,
|
|
538
|
+
gt: int | None = None,
|
|
539
|
+
topics: Sequence[str] = (),
|
|
534
540
|
) -> None:
|
|
535
541
|
assert isinstance(recorder, PostgresApplicationRecorder)
|
|
536
|
-
super().__init__(recorder=recorder, gt=gt)
|
|
542
|
+
super().__init__(recorder=recorder, gt=gt, topics=topics)
|
|
537
543
|
self._listen_thread = Thread(target=self._listen)
|
|
538
544
|
self._listen_thread.start()
|
|
539
545
|
|
eventsourcing/projection.py
CHANGED
|
@@ -5,7 +5,17 @@ import weakref
|
|
|
5
5
|
from abc import ABC, abstractmethod
|
|
6
6
|
from threading import Event, Thread
|
|
7
7
|
from traceback import format_exc
|
|
8
|
-
from typing import
|
|
8
|
+
from typing import (
|
|
9
|
+
TYPE_CHECKING,
|
|
10
|
+
Any,
|
|
11
|
+
Dict,
|
|
12
|
+
Generic,
|
|
13
|
+
Iterator,
|
|
14
|
+
Sequence,
|
|
15
|
+
Tuple,
|
|
16
|
+
Type,
|
|
17
|
+
TypeVar,
|
|
18
|
+
)
|
|
9
19
|
from warnings import warn
|
|
10
20
|
|
|
11
21
|
from eventsourcing.application import Application
|
|
@@ -37,11 +47,12 @@ class ApplicationSubscription(Iterator[Tuple[DomainEventProtocol, Tracking]]):
|
|
|
37
47
|
self,
|
|
38
48
|
app: Application,
|
|
39
49
|
gt: int | None = None,
|
|
50
|
+
topics: Sequence[str] = (),
|
|
40
51
|
):
|
|
41
52
|
self.name = app.name
|
|
42
53
|
self.recorder = app.recorder
|
|
43
54
|
self.mapper = app.mapper
|
|
44
|
-
self.subscription = self.recorder.subscribe(gt=gt)
|
|
55
|
+
self.subscription = self.recorder.subscribe(gt=gt, topics=topics)
|
|
45
56
|
|
|
46
57
|
def __enter__(self) -> Self:
|
|
47
58
|
self.subscription.__enter__()
|
|
@@ -68,6 +79,9 @@ class ApplicationSubscription(Iterator[Tuple[DomainEventProtocol, Tracking]]):
|
|
|
68
79
|
|
|
69
80
|
class Projection(ABC, Generic[TTrackingRecorder]):
|
|
70
81
|
name: str = ""
|
|
82
|
+
"""Name of projection, used to pick prefixed environment variables."""
|
|
83
|
+
topics: Sequence[str] = ()
|
|
84
|
+
"""Event topics, used to filter events in database."""
|
|
71
85
|
|
|
72
86
|
def __init__(
|
|
73
87
|
self,
|
|
@@ -112,12 +126,13 @@ class ProjectionRunner(Generic[TApplication, TTrackingRecorder]):
|
|
|
112
126
|
self.projection_factory.tracking_recorder(tracking_recorder_class)
|
|
113
127
|
)
|
|
114
128
|
|
|
129
|
+
self.projection = projection_class(
|
|
130
|
+
tracking_recorder=self.tracking_recorder,
|
|
131
|
+
)
|
|
115
132
|
self.subscription = ApplicationSubscription(
|
|
116
133
|
app=self.app,
|
|
117
134
|
gt=self.tracking_recorder.max_tracking_id(self.app.name),
|
|
118
|
-
|
|
119
|
-
self.projection = projection_class(
|
|
120
|
-
tracking_recorder=self.tracking_recorder,
|
|
135
|
+
topics=self.projection.topics,
|
|
121
136
|
)
|
|
122
137
|
self._has_error = Event()
|
|
123
138
|
self.thread_error: BaseException | None = None
|
eventsourcing/sqlite.py
CHANGED
|
@@ -471,7 +471,9 @@ class SQLiteApplicationRecorder(
|
|
|
471
471
|
c.execute(self.select_max_notification_id_statement)
|
|
472
472
|
return c.fetchone()[0]
|
|
473
473
|
|
|
474
|
-
def subscribe(
|
|
474
|
+
def subscribe(
|
|
475
|
+
self, gt: int | None = None, topics: Sequence[str] = ()
|
|
476
|
+
) -> Subscription[ApplicationRecorder]:
|
|
475
477
|
msg = f"The {type(self).__qualname__} recorder does not support subscriptions"
|
|
476
478
|
raise NotImplementedError(msg)
|
|
477
479
|
|
|
@@ -707,6 +707,45 @@ class ApplicationRecorderTestCase(TestCase, ABC):
|
|
|
707
707
|
stored_event3.originator_id, notifications[0].originator_id
|
|
708
708
|
)
|
|
709
709
|
|
|
710
|
+
# Start a subscription, call stop() during iteration.
|
|
711
|
+
with recorder.subscribe(gt=None) as subscription:
|
|
712
|
+
|
|
713
|
+
# Receive events from the subscription.
|
|
714
|
+
for i, _ in enumerate(subscription):
|
|
715
|
+
subscription.stop()
|
|
716
|
+
# Shouldn't get here twice...
|
|
717
|
+
self.assertLess(i, 1, "Got here twice")
|
|
718
|
+
|
|
719
|
+
# Start a subscription, call stop() before iteration.
|
|
720
|
+
subscription = recorder.subscribe(gt=None)
|
|
721
|
+
with subscription:
|
|
722
|
+
subscription.stop()
|
|
723
|
+
# Receive events from the subscription.
|
|
724
|
+
for _ in subscription:
|
|
725
|
+
# Shouldn't get here...
|
|
726
|
+
self.fail("Got here")
|
|
727
|
+
|
|
728
|
+
# Start a subscription, call stop() before entering context manager.
|
|
729
|
+
subscription = recorder.subscribe(gt=None)
|
|
730
|
+
subscription.stop()
|
|
731
|
+
with subscription:
|
|
732
|
+
# Receive events from the subscription.
|
|
733
|
+
for _ in subscription:
|
|
734
|
+
# Shouldn't get here...
|
|
735
|
+
self.fail("Got here")
|
|
736
|
+
|
|
737
|
+
# Start a subscription with topics.
|
|
738
|
+
subscription = recorder.subscribe(gt=None, topics=["topic3"])
|
|
739
|
+
with subscription:
|
|
740
|
+
for notification in subscription:
|
|
741
|
+
self.assertEqual(notification.topic, "topic3")
|
|
742
|
+
if (
|
|
743
|
+
notification.originator_id == stored_event3.originator_id
|
|
744
|
+
and notification.originator_version
|
|
745
|
+
== stored_event3.originator_version
|
|
746
|
+
):
|
|
747
|
+
break
|
|
748
|
+
|
|
710
749
|
def close_db_connection(self, *args: Any) -> None:
|
|
711
750
|
""""""
|
|
712
751
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: eventsourcing
|
|
3
|
-
Version: 9.4.
|
|
3
|
+
Version: 9.4.0a4
|
|
4
4
|
Summary: Event sourcing in Python
|
|
5
5
|
Home-page: https://github.com/pyeventsourcing/eventsourcing
|
|
6
6
|
License: BSD 3-Clause
|
|
@@ -35,7 +35,7 @@ Requires-Dist: typing_extensions
|
|
|
35
35
|
Project-URL: Repository, https://github.com/pyeventsourcing/eventsourcing
|
|
36
36
|
Description-Content-Type: text/markdown
|
|
37
37
|
|
|
38
|
-
[](https://github.com/pyeventsourcing/eventsourcing)
|
|
38
|
+
[](https://github.com/pyeventsourcing/eventsourcing)
|
|
39
39
|
[](https://coveralls.io/github/pyeventsourcing/eventsourcing?branch=main)
|
|
40
40
|
[](https://eventsourcing.readthedocs.io/en/stable/)
|
|
41
41
|
[](https://pypi.org/project/eventsourcing/)
|
|
@@ -6,21 +6,21 @@ eventsourcing/cryptography.py,sha256=ZsQFyeyMZysADqKy38ECV71j6EMMSbo3VQO7oRnC1h0
|
|
|
6
6
|
eventsourcing/dispatch.py,sha256=yYSpT-jqc6l_wTdqEnfPJJfvsZN2Ta8g2anrVPWIcqQ,1412
|
|
7
7
|
eventsourcing/domain.py,sha256=pNetJA4uKf1chgfNFKWv1Fke3_V5g0ygRv63WT7nsUc,58208
|
|
8
8
|
eventsourcing/interface.py,sha256=LIFI9AZhoVWUAq4YjKosGCpinf51jmVLqw1Ii4npSHo,5079
|
|
9
|
-
eventsourcing/persistence.py,sha256=
|
|
10
|
-
eventsourcing/popo.py,sha256=
|
|
11
|
-
eventsourcing/postgres.py,sha256=
|
|
12
|
-
eventsourcing/projection.py,sha256=
|
|
9
|
+
eventsourcing/persistence.py,sha256=sfGq8BV1cnmrTy1OLoWXIObArgUD9wPHcEeM0KwZ5p8,45962
|
|
10
|
+
eventsourcing/popo.py,sha256=wBXoSVg53nVOsZVzKkrCOrXxzWe2HH1mC4aEV97rDdk,9565
|
|
11
|
+
eventsourcing/postgres.py,sha256=wu5b3Kvr4NO9yegCLAkIMDrjpkTVNisCXlFmCb74tAE,36306
|
|
12
|
+
eventsourcing/projection.py,sha256=xkMsl_VTfxtb4SOH3NwHjPRUN1L0ShFMdlp8pUEkjwE,6799
|
|
13
13
|
eventsourcing/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
14
|
-
eventsourcing/sqlite.py,sha256=
|
|
14
|
+
eventsourcing/sqlite.py,sha256=_zY-08IosW1idOnPPRg9rh0C3AyHT6yqwAv4WCOw-dg,21951
|
|
15
15
|
eventsourcing/system.py,sha256=7cM3FBdvr64ZK_xItks1MW2yg1o0OZ1vtKtznFFB_4g,47114
|
|
16
16
|
eventsourcing/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
17
17
|
eventsourcing/tests/application.py,sha256=Q_NFgRSRWovMcyQOZ8U1AoiIsnEHf_zCpHcP0ADaYvs,17369
|
|
18
18
|
eventsourcing/tests/domain.py,sha256=lHSlY6jIoSeqlcPSbrrozEPUJGvJ8bgPrznlmzTxn2w,3254
|
|
19
|
-
eventsourcing/tests/persistence.py,sha256=
|
|
19
|
+
eventsourcing/tests/persistence.py,sha256=M1EZPs8DhAOW8N_GSnALPcmz-pNVCJDx73pHaEJa138,57108
|
|
20
20
|
eventsourcing/tests/postgres_utils.py,sha256=xymcGYasUXeZTBenkHz-ykD8HtrFjVM1Z7-qRrH6OQk,1364
|
|
21
21
|
eventsourcing/utils.py,sha256=QPlHhltgEcL80RWcPJ_PTygzDwhfIowUS3Z5taw0_cA,8228
|
|
22
|
-
eventsourcing-9.4.
|
|
23
|
-
eventsourcing-9.4.
|
|
24
|
-
eventsourcing-9.4.
|
|
25
|
-
eventsourcing-9.4.
|
|
26
|
-
eventsourcing-9.4.
|
|
22
|
+
eventsourcing-9.4.0a4.dist-info/AUTHORS,sha256=8aHOM4UbNZcKlD-cHpFRcM6RWyCqtwtxRev6DeUgVRs,137
|
|
23
|
+
eventsourcing-9.4.0a4.dist-info/LICENSE,sha256=CQEQzcZO8AWXL5i3hIo4yVKrYjh2FBz6hCM7kpXWpw4,1512
|
|
24
|
+
eventsourcing-9.4.0a4.dist-info/METADATA,sha256=5ZcTr1zycsekzuQOt2W24DYp1j2VtwAtbB9msJJC-S8,9885
|
|
25
|
+
eventsourcing-9.4.0a4.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
|
26
|
+
eventsourcing-9.4.0a4.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|