eventsourcing 9.4.4__py3-none-any.whl → 9.4.6__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.

@@ -8,14 +8,15 @@ from abc import ABC, abstractmethod
8
8
  from collections.abc import Iterator, Sequence
9
9
  from threading import Event, Thread
10
10
  from traceback import format_exc
11
- from typing import TYPE_CHECKING, Any, ClassVar, Generic, TypeVar
11
+ from typing import TYPE_CHECKING, Any, Generic, TypeVar
12
12
  from warnings import warn
13
13
 
14
14
  from eventsourcing.application import Application, ProcessingEvent
15
15
  from eventsourcing.dispatch import singledispatchmethod
16
- from eventsourcing.domain import DomainEventProtocol
16
+ from eventsourcing.domain import DomainEventProtocol, TAggregateID
17
17
  from eventsourcing.persistence import (
18
18
  InfrastructureFactory,
19
+ Mapper,
19
20
  ProcessRecorder,
20
21
  Tracking,
21
22
  TrackingRecorder,
@@ -30,7 +31,9 @@ if TYPE_CHECKING:
30
31
  from typing_extensions import Self
31
32
 
32
33
 
33
- class ApplicationSubscription(Iterator[tuple[DomainEventProtocol, Tracking]]):
34
+ class ApplicationSubscription(
35
+ Iterator[tuple[DomainEventProtocol[TAggregateID], Tracking]]
36
+ ):
34
37
  """An iterator that yields all domain events recorded in an application
35
38
  sequence that have notification IDs greater than a given value. The iterator
36
39
  will block when all recorded domain events have been yielded, and then
@@ -40,7 +43,7 @@ class ApplicationSubscription(Iterator[tuple[DomainEventProtocol, Tracking]]):
40
43
 
41
44
  def __init__(
42
45
  self,
43
- app: Application,
46
+ app: Application[TAggregateID],
44
47
  gt: int | None = None,
45
48
  topics: Sequence[str] = (),
46
49
  ):
@@ -49,7 +52,7 @@ class ApplicationSubscription(Iterator[tuple[DomainEventProtocol, Tracking]]):
49
52
  """
50
53
  self.name = app.name
51
54
  self.recorder = app.recorder
52
- self.mapper = app.mapper
55
+ self.mapper: Mapper[TAggregateID] = app.mapper
53
56
  self.subscription = self.recorder.subscribe(gt=gt, topics=topics)
54
57
 
55
58
  def stop(self) -> None:
@@ -68,7 +71,7 @@ class ApplicationSubscription(Iterator[tuple[DomainEventProtocol, Tracking]]):
68
71
  def __iter__(self) -> Self:
69
72
  return self
70
73
 
71
- def __next__(self) -> tuple[DomainEventProtocol, Tracking]:
74
+ def __next__(self) -> tuple[DomainEventProtocol[TAggregateID], Tracking]:
72
75
  """Returns the next stored event from subscription to the application's
73
76
  recorder. Constructs a tracking object that identifies the position of
74
77
  the event in the application sequence. Constructs a domain event object
@@ -116,18 +119,18 @@ class Projection(ABC, Generic[TTrackingRecorder]):
116
119
  @singledispatchmethod
117
120
  @abstractmethod
118
121
  def process_event(
119
- self, domain_event: DomainEventProtocol, tracking: Tracking
122
+ self, domain_event: DomainEventProtocol[TAggregateID], tracking: Tracking
120
123
  ) -> None:
121
124
  """Process a domain event and track it."""
122
125
 
123
126
 
124
- class EventSourcedProjection(Application, ABC):
127
+ class EventSourcedProjection(Application[TAggregateID], ABC):
125
128
  """Extends the :py:class:`~eventsourcing.application.Application` class
126
129
  by using a process recorder as its application recorder, and by
127
130
  processing domain events through its :py:func:`policy` method.
128
131
  """
129
132
 
130
- topics: ClassVar[Sequence[str]] = ()
133
+ topics: Sequence[str] = ()
131
134
 
132
135
  def __init__(self, env: EnvType | None = None) -> None:
133
136
  super().__init__(env)
@@ -141,7 +144,7 @@ class EventSourcedProjection(Application, ABC):
141
144
  return self.factory.process_recorder()
142
145
 
143
146
  def process_event(
144
- self, domain_event: DomainEventProtocol, tracking: Tracking
147
+ self, domain_event: DomainEventProtocol[TAggregateID], tracking: Tracking
145
148
  ) -> None:
146
149
  """Calls :func:`~eventsourcing.system.Follower.policy` method with the given
147
150
  domain event and a new :class:`~eventsourcing.application.ProcessingEvent`
@@ -158,7 +161,7 @@ class EventSourcedProjection(Application, ABC):
158
161
  the recordings are passed in a call to
159
162
  :py:func:`~eventsourcing.application.Application._notify`.
160
163
  """
161
- processing_event = ProcessingEvent(tracking=tracking)
164
+ processing_event = ProcessingEvent[TAggregateID](tracking=tracking)
162
165
  self.policy(domain_event, processing_event)
163
166
  recordings = self._record(processing_event)
164
167
  self._take_snapshots(processing_event)
@@ -168,8 +171,8 @@ class EventSourcedProjection(Application, ABC):
168
171
  @singledispatchmethod
169
172
  def policy(
170
173
  self,
171
- domain_event: DomainEventProtocol,
172
- processing_event: ProcessingEvent,
174
+ domain_event: DomainEventProtocol[TAggregateID],
175
+ processing_event: ProcessingEvent[TAggregateID],
173
176
  ) -> None:
174
177
  """Abstract domain event processing policy method. Must be
175
178
  implemented by event processing applications. When
@@ -183,9 +186,9 @@ class EventSourcedProjection(Application, ABC):
183
186
  """
184
187
 
185
188
 
186
- TApplication = TypeVar("TApplication", bound=Application)
189
+ TApplication = TypeVar("TApplication", bound=Application[Any])
187
190
  TEventSourcedProjection = TypeVar(
188
- "TEventSourcedProjection", bound=EventSourcedProjection
191
+ "TEventSourcedProjection", bound=EventSourcedProjection[Any]
189
192
  )
190
193
 
191
194
 
@@ -193,7 +196,7 @@ class BaseProjectionRunner(Generic[TApplication]):
193
196
  def __init__(
194
197
  self,
195
198
  *,
196
- projection: EventSourcedProjection | Projection[Any],
199
+ projection: EventSourcedProjection[Any] | Projection[Any],
197
200
  application_class: type[TApplication],
198
201
  tracking_recorder: TrackingRecorder,
199
202
  topics: Sequence[str],
@@ -258,7 +261,7 @@ class BaseProjectionRunner(Generic[TApplication]):
258
261
 
259
262
  @staticmethod
260
263
  def _stop_subscription_when_stopping(
261
- subscription: ApplicationSubscription,
264
+ subscription: ApplicationSubscription[TAggregateID],
262
265
  is_stopping: Event,
263
266
  ) -> None:
264
267
  """Stops the application subscription, which
@@ -272,10 +275,12 @@ class BaseProjectionRunner(Generic[TApplication]):
272
275
 
273
276
  @staticmethod
274
277
  def _process_events_loop(
275
- subscription: ApplicationSubscription,
276
- projection: EventSourcedProjection | Projection[Any],
278
+ subscription: ApplicationSubscription[TAggregateID],
279
+ projection: EventSourcedProjection[Any] | Projection[Any],
277
280
  is_stopping: Event,
278
- runner: weakref.ReferenceType[ProjectionRunner[Application, TrackingRecorder]],
281
+ runner: weakref.ReferenceType[
282
+ ProjectionRunner[Application[Any], TrackingRecorder]
283
+ ],
279
284
  ) -> None:
280
285
  """Iterates over the subscription and calls process_event()."""
281
286
  try:
eventsourcing/sqlite.py CHANGED
@@ -29,7 +29,7 @@ from eventsourcing.persistence import (
29
29
  Tracking,
30
30
  TrackingRecorder,
31
31
  )
32
- from eventsourcing.utils import Environment, resolve_topic, strtobool
32
+ from eventsourcing.utils import Environment, EnvType, resolve_topic, strtobool
33
33
 
34
34
  if TYPE_CHECKING:
35
35
  from collections.abc import Iterator, Sequence
@@ -300,7 +300,7 @@ class SQLiteAggregateRecorder(SQLiteRecorder, AggregateRecorder):
300
300
  return statements
301
301
 
302
302
  def insert_events(
303
- self, stored_events: list[StoredEvent], **kwargs: Any
303
+ self, stored_events: Sequence[StoredEvent], **kwargs: Any
304
304
  ) -> Sequence[int] | None:
305
305
  with self.datastore.transaction(commit=True) as c:
306
306
  return self._insert_events(c, stored_events, **kwargs)
@@ -308,12 +308,16 @@ class SQLiteAggregateRecorder(SQLiteRecorder, AggregateRecorder):
308
308
  def _insert_events(
309
309
  self,
310
310
  c: SQLiteCursor,
311
- stored_events: list[StoredEvent],
311
+ stored_events: Sequence[StoredEvent],
312
312
  **_: Any,
313
313
  ) -> Sequence[int] | None:
314
314
  params = [
315
315
  (
316
- s.originator_id.hex,
316
+ (
317
+ s.originator_id.hex
318
+ if isinstance(s.originator_id, UUID)
319
+ else s.originator_id
320
+ ),
317
321
  s.originator_version,
318
322
  s.topic,
319
323
  s.state,
@@ -325,15 +329,17 @@ class SQLiteAggregateRecorder(SQLiteRecorder, AggregateRecorder):
325
329
 
326
330
  def select_events(
327
331
  self,
328
- originator_id: UUID,
332
+ originator_id: UUID | str,
329
333
  *,
330
334
  gt: int | None = None,
331
335
  lte: int | None = None,
332
336
  desc: bool = False,
333
337
  limit: int | None = None,
334
- ) -> list[StoredEvent]:
338
+ ) -> Sequence[StoredEvent]:
335
339
  statement = self.select_events_statement
336
- params: list[Any] = [originator_id.hex]
340
+ params: list[Any] = [
341
+ originator_id.hex if isinstance(originator_id, UUID) else originator_id
342
+ ]
337
343
  if gt is not None:
338
344
  statement += "AND originator_version>? "
339
345
  params.append(gt)
@@ -352,7 +358,7 @@ class SQLiteAggregateRecorder(SQLiteRecorder, AggregateRecorder):
352
358
  c.execute(statement, params)
353
359
  return [
354
360
  StoredEvent(
355
- originator_id=UUID(row["originator_id"]),
361
+ originator_id=row["originator_id"],
356
362
  originator_version=row["originator_version"],
357
363
  topic=row["topic"],
358
364
  state=row["state"],
@@ -391,18 +397,22 @@ class SQLiteApplicationRecorder(
391
397
  def _insert_events(
392
398
  self,
393
399
  c: SQLiteCursor,
394
- stored_events: list[StoredEvent],
400
+ stored_events: Sequence[StoredEvent],
395
401
  **_: Any,
396
402
  ) -> Sequence[int] | None:
397
403
  returning = []
398
- for stored_event in stored_events:
404
+ for s in stored_events:
399
405
  c.execute(
400
406
  self.insert_events_statement,
401
407
  (
402
- stored_event.originator_id.hex,
403
- stored_event.originator_version,
404
- stored_event.topic,
405
- stored_event.state,
408
+ (
409
+ s.originator_id.hex
410
+ if isinstance(s.originator_id, UUID)
411
+ else s.originator_id
412
+ ),
413
+ s.originator_version,
414
+ s.topic,
415
+ s.state,
406
416
  ),
407
417
  )
408
418
  returning.append(c.lastrowid)
@@ -416,7 +426,7 @@ class SQLiteApplicationRecorder(
416
426
  topics: Sequence[str] = (),
417
427
  *,
418
428
  inclusive_of_start: bool = True,
419
- ) -> list[Notification]:
429
+ ) -> Sequence[Notification]:
420
430
  """Returns a list of event notifications
421
431
  from 'start', limited by 'limit'.
422
432
  """
@@ -457,7 +467,7 @@ class SQLiteApplicationRecorder(
457
467
  return [
458
468
  Notification(
459
469
  id=row["rowid"],
460
- originator_id=UUID(row["originator_id"]),
470
+ originator_id=row["originator_id"],
461
471
  originator_version=row["originator_version"],
462
472
  topic=row["topic"],
463
473
  state=row["state"],
@@ -650,7 +660,7 @@ class SQLiteProcessRecorder(
650
660
  def _insert_events(
651
661
  self,
652
662
  c: SQLiteCursor,
653
- stored_events: list[StoredEvent],
663
+ stored_events: Sequence[StoredEvent],
654
664
  **kwargs: Any,
655
665
  ) -> Sequence[int] | None:
656
666
  returning = super()._insert_events(c, stored_events, **kwargs)
@@ -671,7 +681,7 @@ class SQLiteFactory(InfrastructureFactory[SQLiteTrackingRecorder]):
671
681
  tracking_recorder_class = SQLiteTrackingRecorder
672
682
  process_recorder_class = SQLiteProcessRecorder
673
683
 
674
- def __init__(self, env: Environment):
684
+ def __init__(self, env: Environment | EnvType | None):
675
685
  super().__init__(env)
676
686
  db_name = self.env.get(self.SQLITE_DBNAME)
677
687
  if not db_name: