eventsourcing 9.4.0b2__py3-none-any.whl → 9.4.0b4__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/application.py +53 -104
- eventsourcing/cipher.py +3 -8
- eventsourcing/compressor.py +2 -6
- eventsourcing/cryptography.py +3 -8
- eventsourcing/dispatch.py +2 -2
- eventsourcing/domain.py +361 -384
- eventsourcing/interface.py +10 -24
- eventsourcing/persistence.py +91 -212
- eventsourcing/popo.py +2 -2
- eventsourcing/postgres.py +7 -10
- eventsourcing/projection.py +19 -41
- eventsourcing/sqlite.py +4 -7
- eventsourcing/system.py +89 -156
- eventsourcing/tests/__init__.py +3 -0
- eventsourcing/tests/application.py +14 -10
- eventsourcing/tests/domain.py +14 -34
- eventsourcing/tests/persistence.py +21 -18
- eventsourcing/utils.py +11 -17
- {eventsourcing-9.4.0b2.dist-info → eventsourcing-9.4.0b4.dist-info}/METADATA +1 -1
- eventsourcing-9.4.0b4.dist-info/RECORD +26 -0
- eventsourcing-9.4.0b2.dist-info/RECORD +0 -26
- {eventsourcing-9.4.0b2.dist-info → eventsourcing-9.4.0b4.dist-info}/AUTHORS +0 -0
- {eventsourcing-9.4.0b2.dist-info → eventsourcing-9.4.0b4.dist-info}/LICENSE +0 -0
- {eventsourcing-9.4.0b2.dist-info → eventsourcing-9.4.0b4.dist-info}/WHEEL +0 -0
eventsourcing/popo.py
CHANGED
|
@@ -235,7 +235,7 @@ class POPOProcessRecorder(
|
|
|
235
235
|
self, stored_events: list[StoredEvent], **kwargs: Any
|
|
236
236
|
) -> None:
|
|
237
237
|
super()._assert_uniqueness(stored_events, **kwargs)
|
|
238
|
-
t: Tracking | None = kwargs.get("tracking"
|
|
238
|
+
t: Tracking | None = kwargs.get("tracking")
|
|
239
239
|
if t:
|
|
240
240
|
self._assert_tracking_uniqueness(t)
|
|
241
241
|
|
|
@@ -243,7 +243,7 @@ class POPOProcessRecorder(
|
|
|
243
243
|
self, stored_events: list[StoredEvent], **kwargs: Any
|
|
244
244
|
) -> Sequence[int] | None:
|
|
245
245
|
notification_ids = super()._update_table(stored_events, **kwargs)
|
|
246
|
-
t: Tracking | None = kwargs.get("tracking"
|
|
246
|
+
t: Tracking | None = kwargs.get("tracking")
|
|
247
247
|
if t:
|
|
248
248
|
self._insert_tracking(t)
|
|
249
249
|
return notification_ids
|
eventsourcing/postgres.py
CHANGED
|
@@ -75,7 +75,7 @@ class ConnectionPool(psycopg_pool.ConnectionPool[Any]):
|
|
|
75
75
|
|
|
76
76
|
|
|
77
77
|
class PostgresDatastore:
|
|
78
|
-
def __init__(
|
|
78
|
+
def __init__( # noqa: PLR0913
|
|
79
79
|
self,
|
|
80
80
|
dbname: str,
|
|
81
81
|
host: str,
|
|
@@ -440,11 +440,9 @@ class PostgresApplicationRecorder(PostgresAggregateRecorder, ApplicationRecorder
|
|
|
440
440
|
*,
|
|
441
441
|
inclusive_of_start: bool = True,
|
|
442
442
|
) -> list[Notification]:
|
|
443
|
-
"""
|
|
444
|
-
Returns a list of event notifications
|
|
443
|
+
"""Returns a list of event notifications
|
|
445
444
|
from 'start', limited by 'limit'.
|
|
446
445
|
"""
|
|
447
|
-
|
|
448
446
|
params: list[int | str | Sequence[str]] = []
|
|
449
447
|
statement = SQL("SELECT * FROM {0}.{1}").format(
|
|
450
448
|
Identifier(self.datastore.schema),
|
|
@@ -501,9 +499,7 @@ class PostgresApplicationRecorder(PostgresAggregateRecorder, ApplicationRecorder
|
|
|
501
499
|
|
|
502
500
|
@retry((InterfaceError, OperationalError), max_attempts=10, wait=0.2)
|
|
503
501
|
def max_notification_id(self) -> int | None:
|
|
504
|
-
"""
|
|
505
|
-
Returns the maximum notification ID.
|
|
506
|
-
"""
|
|
502
|
+
"""Returns the maximum notification ID."""
|
|
507
503
|
with self.datastore.get_connection() as conn, conn.cursor() as curs:
|
|
508
504
|
curs.execute(self.max_notification_id_statement)
|
|
509
505
|
fetchone = curs.fetchone()
|
|
@@ -553,7 +549,7 @@ class PostgresApplicationRecorder(PostgresAggregateRecorder, ApplicationRecorder
|
|
|
553
549
|
notification_ids.append(row["notification_id"])
|
|
554
550
|
if len(notification_ids) != len(stored_events):
|
|
555
551
|
msg = "Couldn't get all notification IDs "
|
|
556
|
-
msg += f"(got {len(notification_ids)}, expected {len(stored_events)}"
|
|
552
|
+
msg += f"(got {len(notification_ids)}, expected {len(stored_events)})"
|
|
557
553
|
raise ProgrammingError(msg)
|
|
558
554
|
return notification_ids
|
|
559
555
|
|
|
@@ -730,7 +726,7 @@ class PostgresProcessRecorder(
|
|
|
730
726
|
stored_events: list[StoredEvent],
|
|
731
727
|
**kwargs: Any,
|
|
732
728
|
) -> None:
|
|
733
|
-
tracking: Tracking | None = kwargs.get("tracking"
|
|
729
|
+
tracking: Tracking | None = kwargs.get("tracking")
|
|
734
730
|
if tracking is not None:
|
|
735
731
|
self._insert_tracking(curs, tracking=tracking)
|
|
736
732
|
super()._insert_events(curs, stored_events, **kwargs)
|
|
@@ -974,7 +970,8 @@ class PostgresFactory(InfrastructureFactory[PostgresTrackingRecorder]):
|
|
|
974
970
|
tracking_recorder_class = resolve_topic(tracking_recorder_topic)
|
|
975
971
|
else:
|
|
976
972
|
tracking_recorder_class = cast(
|
|
977
|
-
type[TPostgresTrackingRecorder],
|
|
973
|
+
"type[TPostgresTrackingRecorder]",
|
|
974
|
+
type(self).tracking_recorder_class,
|
|
978
975
|
)
|
|
979
976
|
assert tracking_recorder_class is not None
|
|
980
977
|
assert issubclass(tracking_recorder_class, PostgresTrackingRecorder)
|
eventsourcing/projection.py
CHANGED
|
@@ -29,8 +29,7 @@ if TYPE_CHECKING:
|
|
|
29
29
|
|
|
30
30
|
|
|
31
31
|
class ApplicationSubscription(Iterator[tuple[DomainEventProtocol, Tracking]]):
|
|
32
|
-
"""
|
|
33
|
-
An iterator that yields all domain events recorded in an application
|
|
32
|
+
"""An iterator that yields all domain events recorded in an application
|
|
34
33
|
sequence that have notification IDs greater than a given value. The iterator
|
|
35
34
|
will block when all recorded domain events have been yielded, and then
|
|
36
35
|
continue when new events are recorded. Domain events are returned along
|
|
@@ -52,30 +51,23 @@ class ApplicationSubscription(Iterator[tuple[DomainEventProtocol, Tracking]]):
|
|
|
52
51
|
self.subscription = self.recorder.subscribe(gt=gt, topics=topics)
|
|
53
52
|
|
|
54
53
|
def stop(self) -> None:
|
|
55
|
-
"""
|
|
56
|
-
Stops the stored event subscription.
|
|
57
|
-
"""
|
|
54
|
+
"""Stops the stored event subscription."""
|
|
58
55
|
self.subscription.stop()
|
|
59
56
|
|
|
60
57
|
def __enter__(self) -> Self:
|
|
61
|
-
"""
|
|
62
|
-
Calls __enter__ on the stored event subscription.
|
|
63
|
-
"""
|
|
58
|
+
"""Calls __enter__ on the stored event subscription."""
|
|
64
59
|
self.subscription.__enter__()
|
|
65
60
|
return self
|
|
66
61
|
|
|
67
62
|
def __exit__(self, *args: object, **kwargs: Any) -> None:
|
|
68
|
-
"""
|
|
69
|
-
Calls __exit__ on the stored event subscription.
|
|
70
|
-
"""
|
|
63
|
+
"""Calls __exit__ on the stored event subscription."""
|
|
71
64
|
self.subscription.__exit__(*args, **kwargs)
|
|
72
65
|
|
|
73
66
|
def __iter__(self) -> Self:
|
|
74
67
|
return self
|
|
75
68
|
|
|
76
69
|
def __next__(self) -> tuple[DomainEventProtocol, Tracking]:
|
|
77
|
-
"""
|
|
78
|
-
Returns the next stored event from the stored event subscription.
|
|
70
|
+
"""Returns the next stored event from the stored event subscription.
|
|
79
71
|
Constructs a tracking object that identifies the position of
|
|
80
72
|
the event in the application sequence, and reconstructs a domain
|
|
81
73
|
event object from the stored event object.
|
|
@@ -86,10 +78,9 @@ class ApplicationSubscription(Iterator[tuple[DomainEventProtocol, Tracking]]):
|
|
|
86
78
|
return domain_event, tracking
|
|
87
79
|
|
|
88
80
|
def __del__(self) -> None:
|
|
89
|
-
"""
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
self.stop()
|
|
81
|
+
"""Stops the stored event subscription."""
|
|
82
|
+
with contextlib.suppress(AttributeError):
|
|
83
|
+
self.stop()
|
|
93
84
|
|
|
94
85
|
|
|
95
86
|
class Projection(ABC, Generic[TTrackingRecorder]):
|
|
@@ -120,9 +111,7 @@ class Projection(ABC, Generic[TTrackingRecorder]):
|
|
|
120
111
|
def process_event(
|
|
121
112
|
self, domain_event: DomainEventProtocol, tracking: Tracking
|
|
122
113
|
) -> None:
|
|
123
|
-
"""
|
|
124
|
-
Process a domain event and track it.
|
|
125
|
-
"""
|
|
114
|
+
"""Process a domain event and track it."""
|
|
126
115
|
|
|
127
116
|
|
|
128
117
|
TApplication = TypeVar("TApplication", bound=Application)
|
|
@@ -137,8 +126,7 @@ class ProjectionRunner(Generic[TApplication, TTrackingRecorder]):
|
|
|
137
126
|
view_class: type[TTrackingRecorder],
|
|
138
127
|
env: EnvType | None = None,
|
|
139
128
|
):
|
|
140
|
-
"""
|
|
141
|
-
Constructs application from given application class with given environment.
|
|
129
|
+
"""Constructs application from given application class with given environment.
|
|
142
130
|
Also constructs a materialised view from given class using an infrastructure
|
|
143
131
|
factory constructed with an environment named after the projection. Also
|
|
144
132
|
constructs a projection with the constructed materialised view object.
|
|
@@ -194,9 +182,7 @@ class ProjectionRunner(Generic[TApplication, TTrackingRecorder]):
|
|
|
194
182
|
return self._is_interrupted
|
|
195
183
|
|
|
196
184
|
def _construct_env(self, name: str, env: EnvType | None = None) -> Environment:
|
|
197
|
-
"""
|
|
198
|
-
Constructs environment from which projection will be configured.
|
|
199
|
-
"""
|
|
185
|
+
"""Constructs environment from which projection will be configured."""
|
|
200
186
|
_env: dict[str, str] = {}
|
|
201
187
|
_env.update(os.environ)
|
|
202
188
|
if env is not None:
|
|
@@ -204,9 +190,7 @@ class ProjectionRunner(Generic[TApplication, TTrackingRecorder]):
|
|
|
204
190
|
return Environment(name, _env)
|
|
205
191
|
|
|
206
192
|
def stop(self) -> None:
|
|
207
|
-
"""
|
|
208
|
-
Sets the "interrupted" event.
|
|
209
|
-
"""
|
|
193
|
+
"""Sets the "interrupted" event."""
|
|
210
194
|
self._has_called_stop = True
|
|
211
195
|
self._is_interrupted.set()
|
|
212
196
|
|
|
@@ -215,8 +199,8 @@ class ProjectionRunner(Generic[TApplication, TTrackingRecorder]):
|
|
|
215
199
|
subscription: ApplicationSubscription,
|
|
216
200
|
is_stopping: Event,
|
|
217
201
|
) -> None:
|
|
218
|
-
"""
|
|
219
|
-
|
|
202
|
+
"""Stops the application subscription, which
|
|
203
|
+
will stop the event-processing thread.
|
|
220
204
|
"""
|
|
221
205
|
try:
|
|
222
206
|
is_stopping.wait()
|
|
@@ -238,7 +222,7 @@ class ProjectionRunner(Generic[TApplication, TTrackingRecorder]):
|
|
|
238
222
|
except BaseException as e:
|
|
239
223
|
_runner = runner() # get reference from weakref
|
|
240
224
|
if _runner is not None:
|
|
241
|
-
_runner._thread_error = e
|
|
225
|
+
_runner._thread_error = e # noqa: SLF001
|
|
242
226
|
else:
|
|
243
227
|
msg = "ProjectionRunner was deleted before error could be assigned:\n"
|
|
244
228
|
msg += format_exc()
|
|
@@ -251,8 +235,7 @@ class ProjectionRunner(Generic[TApplication, TTrackingRecorder]):
|
|
|
251
235
|
is_stopping.set()
|
|
252
236
|
|
|
253
237
|
def run_forever(self, timeout: float | None = None) -> None:
|
|
254
|
-
"""
|
|
255
|
-
Blocks until timeout, or until the runner is stopped or errors. Re-raises
|
|
238
|
+
"""Blocks until timeout, or until the runner is stopped or errors. Re-raises
|
|
256
239
|
any error otherwise exits normally
|
|
257
240
|
"""
|
|
258
241
|
if (
|
|
@@ -264,8 +247,7 @@ class ProjectionRunner(Generic[TApplication, TTrackingRecorder]):
|
|
|
264
247
|
raise error
|
|
265
248
|
|
|
266
249
|
def wait(self, notification_id: int | None, timeout: float = 1.0) -> None:
|
|
267
|
-
"""
|
|
268
|
-
Blocks until timeout, or until the materialised view has recorded a tracking
|
|
250
|
+
"""Blocks until timeout, or until the materialised view has recorded a tracking
|
|
269
251
|
object that is greater than or equal to the given notification ID.
|
|
270
252
|
"""
|
|
271
253
|
try:
|
|
@@ -293,9 +275,7 @@ class ProjectionRunner(Generic[TApplication, TTrackingRecorder]):
|
|
|
293
275
|
exc_val: BaseException | None,
|
|
294
276
|
exc_tb: TracebackType | None,
|
|
295
277
|
) -> None:
|
|
296
|
-
"""
|
|
297
|
-
Calls stop() and waits for the event-processing thread to exit.
|
|
298
|
-
"""
|
|
278
|
+
"""Calls stop() and waits for the event-processing thread to exit."""
|
|
299
279
|
self.stop()
|
|
300
280
|
self._stop_thread.join()
|
|
301
281
|
self._processing_thread.join()
|
|
@@ -305,8 +285,6 @@ class ProjectionRunner(Generic[TApplication, TTrackingRecorder]):
|
|
|
305
285
|
raise error
|
|
306
286
|
|
|
307
287
|
def __del__(self) -> None:
|
|
308
|
-
"""
|
|
309
|
-
Calls stop().
|
|
310
|
-
"""
|
|
288
|
+
"""Calls stop()."""
|
|
311
289
|
with contextlib.suppress(AttributeError):
|
|
312
290
|
self.stop()
|
eventsourcing/sqlite.py
CHANGED
|
@@ -412,8 +412,7 @@ class SQLiteApplicationRecorder(
|
|
|
412
412
|
*,
|
|
413
413
|
inclusive_of_start: bool = True,
|
|
414
414
|
) -> list[Notification]:
|
|
415
|
-
"""
|
|
416
|
-
Returns a list of event notifications
|
|
415
|
+
"""Returns a list of event notifications
|
|
417
416
|
from 'start', limited by 'limit'.
|
|
418
417
|
"""
|
|
419
418
|
params: list[int | str] = []
|
|
@@ -443,7 +442,7 @@ class SQLiteApplicationRecorder(
|
|
|
443
442
|
else:
|
|
444
443
|
statement += "AND "
|
|
445
444
|
params += list(topics)
|
|
446
|
-
statement += "topic IN (
|
|
445
|
+
statement += f"topic IN ({','.join('?' * len(topics))}) "
|
|
447
446
|
|
|
448
447
|
params.append(limit)
|
|
449
448
|
statement += "ORDER BY rowid LIMIT ?"
|
|
@@ -462,9 +461,7 @@ class SQLiteApplicationRecorder(
|
|
|
462
461
|
]
|
|
463
462
|
|
|
464
463
|
def max_notification_id(self) -> int:
|
|
465
|
-
"""
|
|
466
|
-
Returns the maximum notification ID.
|
|
467
|
-
"""
|
|
464
|
+
"""Returns the maximum notification ID."""
|
|
468
465
|
with self.datastore.transaction(commit=False) as c:
|
|
469
466
|
return self._max_notification_id(c)
|
|
470
467
|
|
|
@@ -561,7 +558,7 @@ class SQLiteProcessRecorder(
|
|
|
561
558
|
**kwargs: Any,
|
|
562
559
|
) -> Sequence[int] | None:
|
|
563
560
|
returning = super()._insert_events(c, stored_events, **kwargs)
|
|
564
|
-
tracking: Tracking | None = kwargs.get("tracking"
|
|
561
|
+
tracking: Tracking | None = kwargs.get("tracking")
|
|
565
562
|
if tracking is not None:
|
|
566
563
|
self._insert_tracking(c, tracking)
|
|
567
564
|
return returning
|