eventsourcing 9.4.0a1__py3-none-any.whl → 9.4.0a2__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/__init__.py CHANGED
@@ -1 +0,0 @@
1
- __version__ = "9.3.0dev0"
@@ -25,7 +25,7 @@ from typing import (
25
25
  )
26
26
  from warnings import warn
27
27
 
28
- from typing_extensions import Self, deprecated
28
+ from typing_extensions import deprecated
29
29
 
30
30
  from eventsourcing.domain import (
31
31
  Aggregate,
@@ -57,7 +57,7 @@ from eventsourcing.persistence import (
57
57
  )
58
58
  from eventsourcing.utils import Environment, EnvType, strtobool
59
59
 
60
- if TYPE_CHECKING: # pragma: no cover
60
+ if TYPE_CHECKING:
61
61
  from uuid import UUID
62
62
 
63
63
  ProjectorFunction = Callable[
@@ -903,21 +903,6 @@ class Application:
903
903
  need to take action when new domain events have been saved.
904
904
  """
905
905
 
906
- def subscribe(self, gt: int | None = None) -> ApplicationSubscription:
907
- """
908
- Returns an iterator that yields all domain events recorded in an application
909
- sequence that have notification IDs greater than a given value. The iterator
910
- will block when all recorded domain events have been yielded, and then
911
- continue when new events are recorded. Domain events are returned along
912
- with tracking objects that identify the position in the application sequence.
913
- """
914
- return ApplicationSubscription(
915
- name=self.name,
916
- recorder=self.recorder,
917
- mapper=self.mapper,
918
- gt=gt,
919
- )
920
-
921
906
  def close(self) -> None:
922
907
  self.closing.set()
923
908
  self.factory.close()
@@ -1042,36 +1027,3 @@ class EventSourcedLog(Generic[TDomainEvent]):
1042
1027
  limit=limit,
1043
1028
  ),
1044
1029
  )
1045
-
1046
-
1047
- class ApplicationSubscription:
1048
- def __init__(
1049
- self,
1050
- name: str,
1051
- recorder: ApplicationRecorder,
1052
- mapper: Mapper,
1053
- gt: int | None = None,
1054
- ):
1055
- self.name = name
1056
- self.recorder = recorder
1057
- self.mapper = mapper
1058
- self.subscription = self.recorder.subscribe(gt=gt)
1059
-
1060
- def __enter__(self) -> Self:
1061
- self.subscription.__enter__()
1062
- return self
1063
-
1064
- def __exit__(self, *args: object, **kwargs: Any) -> None:
1065
- self.subscription.__exit__(*args, **kwargs)
1066
-
1067
- def __iter__(self) -> Self:
1068
- return self
1069
-
1070
- def __next__(self) -> Tuple[DomainEventProtocol, Tracking]:
1071
- notification = next(self.subscription)
1072
- tracking = Tracking(self.name, notification.id)
1073
- domain_event = self.mapper.to_domain_event(notification)
1074
- return domain_event, tracking
1075
-
1076
- def __del__(self) -> None:
1077
- self.subscription.stop()
eventsourcing/cipher.py CHANGED
@@ -10,13 +10,14 @@ from Crypto.Cipher.AES import key_size
10
10
 
11
11
  from eventsourcing.persistence import Cipher
12
12
 
13
- if TYPE_CHECKING: # pragma: no cover
13
+ if TYPE_CHECKING:
14
14
  from eventsourcing.utils import Environment
15
15
 
16
16
 
17
17
  class AESCipher(Cipher):
18
18
  """
19
- Cipher strategy that uses AES cipher in GCM mode.
19
+ Cipher strategy that uses AES cipher (in GCM mode)
20
+ from the Python pycryptodome package.
20
21
  """
21
22
 
22
23
  CIPHER_KEY = "CIPHER_KEY"
@@ -71,6 +72,7 @@ class AESCipher(Cipher):
71
72
 
72
73
  # Return ciphertext.
73
74
  return nonce + tag + encrypted
75
+ # return nonce + tag + encrypted
74
76
 
75
77
  def construct_cipher(self, nonce: bytes) -> GcmMode:
76
78
  cipher = AES.new(
@@ -0,0 +1,96 @@
1
+ from __future__ import annotations
2
+
3
+ import os
4
+ from base64 import b64decode, b64encode
5
+ from typing import TYPE_CHECKING
6
+
7
+ from cryptography.exceptions import InvalidTag
8
+ from cryptography.hazmat.primitives.ciphers.aead import AESGCM
9
+
10
+ from eventsourcing.persistence import Cipher
11
+
12
+ if TYPE_CHECKING:
13
+ from eventsourcing.utils import Environment
14
+
15
+
16
+ class AESCipher(Cipher):
17
+ """
18
+ Cipher strategy that uses AES cipher (in GCM mode)
19
+ from the Python cryptography package.
20
+ """
21
+
22
+ CIPHER_KEY = "CIPHER_KEY"
23
+ KEY_SIZES = (16, 24, 32)
24
+
25
+ @staticmethod
26
+ def create_key(num_bytes: int) -> str:
27
+ """
28
+ Creates AES cipher key, with length num_bytes.
29
+
30
+ :param num_bytes: An int value, either 16, 24, or 32.
31
+
32
+ """
33
+ AESCipher.check_key_size(num_bytes)
34
+ key = AESGCM.generate_key(num_bytes * 8)
35
+ return b64encode(key).decode("utf8")
36
+
37
+ @staticmethod
38
+ def check_key_size(num_bytes: int) -> None:
39
+ if num_bytes not in AESCipher.KEY_SIZES:
40
+ msg = f"Invalid key size: {num_bytes} not in {AESCipher.KEY_SIZES}"
41
+ raise ValueError(msg)
42
+
43
+ @staticmethod
44
+ def random_bytes(num_bytes: int) -> bytes:
45
+ return os.urandom(num_bytes)
46
+
47
+ def __init__(self, environment: Environment):
48
+ """
49
+ Initialises AES cipher with ``cipher_key``.
50
+
51
+ :param str cipher_key: 16, 24, or 32 bytes encoded as base64
52
+ """
53
+ cipher_key = environment.get(self.CIPHER_KEY)
54
+ if not cipher_key:
55
+ msg = f"'{self.CIPHER_KEY}' not in env"
56
+ raise OSError(msg)
57
+ key = b64decode(cipher_key.encode("utf8"))
58
+ AESCipher.check_key_size(len(key))
59
+ self.key = key
60
+
61
+ def encrypt(self, plaintext: bytes) -> bytes:
62
+ """Return ciphertext for given plaintext."""
63
+
64
+ # Construct AES-GCM cipher, with 96-bit nonce.
65
+ aesgcm = AESGCM(self.key)
66
+ nonce = AESCipher.random_bytes(12)
67
+ res = aesgcm.encrypt(nonce, plaintext, None)
68
+ # Put tag at the front for compatibility with eventsourcing.crypto.AESCipher.
69
+ tag = res[-16:]
70
+ encrypted = res[:-16]
71
+ return nonce + tag + encrypted
72
+
73
+ def decrypt(self, ciphertext: bytes) -> bytes:
74
+ """Return plaintext for given ciphertext."""
75
+
76
+ # Split out the nonce, tag, and encrypted data.
77
+ nonce = ciphertext[:12]
78
+ if len(nonce) != 12:
79
+ msg = "Damaged cipher text: invalid nonce length"
80
+ raise ValueError(msg)
81
+
82
+ # Expect tag at the front.
83
+ tag = ciphertext[12:28]
84
+ if len(tag) != 16:
85
+ msg = "Damaged cipher text: invalid tag length"
86
+ raise ValueError(msg)
87
+ encrypted = ciphertext[28:]
88
+
89
+ aesgcm = AESGCM(self.key)
90
+ try:
91
+ plaintext = aesgcm.decrypt(nonce, encrypted + tag, None)
92
+ except InvalidTag as e:
93
+ msg = "Invalid cipher tag"
94
+ raise ValueError(msg) from e
95
+ # Decrypt and verify.
96
+ return plaintext
eventsourcing/domain.py CHANGED
@@ -410,7 +410,7 @@ def _spec_filter_kwargs_for_method_params(method: Callable[..., Any]) -> set[str
410
410
  return set(method_signature.parameters)
411
411
 
412
412
 
413
- if TYPE_CHECKING: # pragma: no cover
413
+ if TYPE_CHECKING:
414
414
  EventSpecType = Union[str, Type[CanMutateAggregate]]
415
415
 
416
416
  CommandMethod = Callable[..., None]
@@ -1552,12 +1552,6 @@ class VersionError(OriginatorVersionError):
1552
1552
 
1553
1553
 
1554
1554
  class SnapshotProtocol(DomainEventProtocol, Protocol):
1555
- @property
1556
- def topic(self) -> str:
1557
- """
1558
- Snapshots have a read-only 'topic'.
1559
- """
1560
-
1561
1555
  @property
1562
1556
  def state(self) -> Dict[str, Any]:
1563
1557
  """
@@ -37,7 +37,7 @@ from eventsourcing.utils import (
37
37
  strtobool,
38
38
  )
39
39
 
40
- if TYPE_CHECKING: # pragma: no cover
40
+ if TYPE_CHECKING:
41
41
  from typing_extensions import Self
42
42
 
43
43
 
eventsourcing/popo.py CHANGED
@@ -19,7 +19,7 @@ from eventsourcing.persistence import (
19
19
  )
20
20
  from eventsourcing.utils import resolve_topic, reversed_keys
21
21
 
22
- if TYPE_CHECKING: # pragma: no cover
22
+ if TYPE_CHECKING:
23
23
  from uuid import UUID
24
24
 
25
25
 
eventsourcing/postgres.py CHANGED
@@ -35,7 +35,7 @@ from eventsourcing.persistence import (
35
35
  )
36
36
  from eventsourcing.utils import Environment, resolve_topic, retry, strtobool
37
37
 
38
- if TYPE_CHECKING: # pragma: no cover
38
+ if TYPE_CHECKING:
39
39
  from uuid import UUID
40
40
 
41
41
  from typing_extensions import Self
@@ -5,11 +5,12 @@ 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 TYPE_CHECKING, Any, Dict, Generic, Type, TypeVar
8
+ from typing import TYPE_CHECKING, Any, Dict, Generic, Iterator, Tuple, Type, TypeVar
9
9
  from warnings import warn
10
10
 
11
11
  from eventsourcing.application import Application
12
12
  from eventsourcing.dispatch import singledispatchmethod
13
+ from eventsourcing.domain import DomainEventProtocol
13
14
  from eventsourcing.persistence import (
14
15
  InfrastructureFactory,
15
16
  Tracking,
@@ -19,11 +20,50 @@ from eventsourcing.persistence import (
19
20
  )
20
21
  from eventsourcing.utils import Environment, EnvType
21
22
 
22
- if TYPE_CHECKING: # pragma: no cover
23
+ if TYPE_CHECKING:
23
24
  from typing_extensions import Self
24
25
 
25
- from eventsourcing.application import ApplicationSubscription
26
- from eventsourcing.domain import DomainEventProtocol
26
+
27
+ class ApplicationSubscription(Iterator[Tuple[DomainEventProtocol, Tracking]]):
28
+ """
29
+ An iterator that yields all domain events recorded in an application
30
+ sequence that have notification IDs greater than a given value. The iterator
31
+ will block when all recorded domain events have been yielded, and then
32
+ continue when new events are recorded. Domain events are returned along
33
+ with tracking objects that identify the position in the application sequence.
34
+ """
35
+
36
+ def __init__(
37
+ self,
38
+ app: Application,
39
+ gt: int | None = None,
40
+ ):
41
+ self.name = app.name
42
+ self.recorder = app.recorder
43
+ self.mapper = app.mapper
44
+ self.subscription = self.recorder.subscribe(gt=gt)
45
+
46
+ def __enter__(self) -> Self:
47
+ self.subscription.__enter__()
48
+ return self
49
+
50
+ def __exit__(self, *args: object, **kwargs: Any) -> None:
51
+ self.subscription.__exit__(*args, **kwargs)
52
+
53
+ def __iter__(self) -> Self:
54
+ return self
55
+
56
+ def __next__(self) -> Tuple[DomainEventProtocol, Tracking]:
57
+ notification = next(self.subscription)
58
+ tracking = Tracking(self.name, notification.id)
59
+ domain_event = self.mapper.to_domain_event(notification)
60
+ return domain_event, tracking
61
+
62
+ def __del__(self) -> None:
63
+ self.stop()
64
+
65
+ def stop(self) -> None:
66
+ self.subscription.stop()
27
67
 
28
68
 
29
69
  class Projection(ABC, Generic[TTrackingRecorder]):
@@ -46,6 +86,8 @@ class Projection(ABC, Generic[TTrackingRecorder]):
46
86
 
47
87
 
48
88
  TProjection = TypeVar("TProjection", bound=Projection[Any])
89
+
90
+
49
91
  TApplication = TypeVar("TApplication", bound=Application)
50
92
 
51
93
 
@@ -70,8 +112,9 @@ class ProjectionRunner(Generic[TApplication, TTrackingRecorder]):
70
112
  self.projection_factory.tracking_recorder(tracking_recorder_class)
71
113
  )
72
114
 
73
- self.subscription = self.app.subscribe(
74
- gt=self.tracking_recorder.max_tracking_id(self.app.name)
115
+ self.subscription = ApplicationSubscription(
116
+ app=self.app,
117
+ gt=self.tracking_recorder.max_tracking_id(self.app.name),
75
118
  )
76
119
  self.projection = projection_class(
77
120
  tracking_recorder=self.tracking_recorder,
@@ -100,7 +143,7 @@ class ProjectionRunner(Generic[TApplication, TTrackingRecorder]):
100
143
  return Environment(name, _env)
101
144
 
102
145
  def stop(self) -> None:
103
- self.subscription.subscription.stop()
146
+ self.subscription.stop()
104
147
 
105
148
  @staticmethod
106
149
  def _process_events_loop(
eventsourcing/sqlite.py CHANGED
@@ -31,7 +31,7 @@ from eventsourcing.persistence import (
31
31
  )
32
32
  from eventsourcing.utils import Environment, resolve_topic, strtobool
33
33
 
34
- if TYPE_CHECKING: # pragma: no cover
34
+ if TYPE_CHECKING:
35
35
  from types import TracebackType
36
36
 
37
37
  SQLITE3_DEFAULT_LOCK_TIMEOUT = 5
eventsourcing/system.py CHANGED
@@ -23,7 +23,7 @@ from typing import (
23
23
  cast,
24
24
  )
25
25
 
26
- if TYPE_CHECKING: # pragma: no cover
26
+ if TYPE_CHECKING:
27
27
  from typing_extensions import Self
28
28
 
29
29
  from eventsourcing.application import (
@@ -20,7 +20,6 @@ from eventsourcing.persistence import (
20
20
  InfrastructureFactory,
21
21
  IntegrityError,
22
22
  JSONTranscoder,
23
- Tracking,
24
23
  Transcoding,
25
24
  )
26
25
  from eventsourcing.tests.domain import BankAccount, EmailAddress
@@ -490,43 +489,3 @@ class ApplicationTestCase(TestCase):
490
489
  self.assertEqual(
491
490
  "'log' is deprecated, use 'notifications' instead", w[-1].message.args[0]
492
491
  )
493
-
494
- def test_catchup_subscription(self):
495
- app = Application()
496
-
497
- max_notification_id = app.recorder.max_notification_id()
498
-
499
- aggregate = Aggregate()
500
- aggregate.trigger_event(Aggregate.Event)
501
- aggregate.trigger_event(Aggregate.Event)
502
- aggregate.trigger_event(Aggregate.Event)
503
- app.save(aggregate)
504
-
505
- subscription = app.subscribe(gt=max_notification_id)
506
-
507
- # Catch up.
508
- for domain_event, tracking in subscription:
509
- self.assertIsInstance(domain_event, Aggregate.Event)
510
- self.assertIsInstance(tracking, Tracking)
511
- self.assertEqual(tracking.application_name, app.name)
512
- if max_notification_id is not None:
513
- self.assertGreater(tracking.notification_id, max_notification_id)
514
- if tracking.notification_id == app.recorder.max_notification_id():
515
- break
516
-
517
- max_notification_id = app.recorder.max_notification_id()
518
-
519
- aggregate.trigger_event(Aggregate.Event)
520
- aggregate.trigger_event(Aggregate.Event)
521
- aggregate.trigger_event(Aggregate.Event)
522
- app.save(aggregate)
523
-
524
- # Continue.
525
- for domain_event, tracking in subscription:
526
- self.assertIsInstance(domain_event, Aggregate.Event)
527
- self.assertIsInstance(tracking, Tracking)
528
- self.assertEqual(tracking.application_name, app.name)
529
- if max_notification_id is not None:
530
- self.assertGreater(tracking.notification_id, max_notification_id)
531
- if tracking.notification_id == app.recorder.max_notification_id():
532
- break
eventsourcing/utils.py CHANGED
@@ -22,7 +22,7 @@ from typing import (
22
22
  overload,
23
23
  )
24
24
 
25
- if TYPE_CHECKING: # pragma: no cover
25
+ if TYPE_CHECKING:
26
26
  from types import FunctionType, WrapperDescriptorType
27
27
 
28
28
 
@@ -1,13 +1,13 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: eventsourcing
3
- Version: 9.4.0a1
3
+ Version: 9.4.0a2
4
4
  Summary: Event sourcing in Python
5
5
  Home-page: https://github.com/pyeventsourcing/eventsourcing
6
6
  License: BSD 3-Clause
7
7
  Keywords: event sourcing,event store,domain driven design,domain-driven design,ddd,cqrs,cqs
8
8
  Author: John Bywater
9
9
  Author-email: john.bywater@appropriatesoftware.net
10
- Requires-Python: >=3.8,<4.0
10
+ Requires-Python: >=3.8, !=2.7.*, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, !=3.6.*, !=3.7.*
11
11
  Classifier: Development Status :: 3 - Alpha
12
12
  Classifier: Intended Audience :: Developers
13
13
  Classifier: Intended Audience :: Education
@@ -18,22 +18,24 @@ Classifier: Operating System :: OS Independent
18
18
  Classifier: Programming Language :: Python
19
19
  Classifier: Programming Language :: Python :: 3
20
20
  Classifier: Programming Language :: Python :: 3.8
21
- Classifier: Programming Language :: Python :: 3.9
22
21
  Classifier: Programming Language :: Python :: 3.10
23
22
  Classifier: Programming Language :: Python :: 3.11
24
23
  Classifier: Programming Language :: Python :: 3.12
25
24
  Classifier: Programming Language :: Python :: 3.13
25
+ Classifier: Programming Language :: Python :: 3.9
26
26
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
27
27
  Provides-Extra: crypto
28
+ Provides-Extra: cryptography
28
29
  Provides-Extra: postgres
29
30
  Requires-Dist: backports.zoneinfo ; python_version < "3.9"
30
- Requires-Dist: psycopg[c,pool] (<=3.2.99999) ; extra == "postgres"
31
- Requires-Dist: pycryptodome (>=3.21,<3.22) ; extra == "crypto"
31
+ Requires-Dist: cryptography (>=44.0,<44.1) ; extra == "cryptography"
32
+ Requires-Dist: psycopg[pool] (<=3.2.99999) ; extra == "postgres"
33
+ Requires-Dist: pycryptodome (>=3.22,<3.23) ; extra == "crypto"
32
34
  Requires-Dist: typing_extensions
33
35
  Project-URL: Repository, https://github.com/pyeventsourcing/eventsourcing
34
36
  Description-Content-Type: text/markdown
35
37
 
36
- [![Build Status](https://github.com/pyeventsourcing/eventsourcing/actions/workflows/runtests.yaml/badge.svg?branch=main)](https://github.com/pyeventsourcing/eventsourcing/tree/main)
38
+ [![Build Status](https://github.com/pyeventsourcing/eventsourcing/actions/workflows/runtests.yaml/badge.svg)](https://github.com/pyeventsourcing/eventsourcing)
37
39
  [![Coverage Status](https://coveralls.io/repos/github/pyeventsourcing/eventsourcing/badge.svg?branch=main)](https://coveralls.io/github/pyeventsourcing/eventsourcing?branch=main)
38
40
  [![Documentation Status](https://readthedocs.org/projects/eventsourcing/badge/?version=stable)](https://eventsourcing.readthedocs.io/en/stable/)
39
41
  [![Latest Release](https://badge.fury.io/py/eventsourcing.svg)](https://pypi.org/project/eventsourcing/)
@@ -0,0 +1,26 @@
1
+ eventsourcing/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ eventsourcing/application.py,sha256=eV_R00f5z7u6E5ou2-QpLJnJ2LzjGMxG1WP6Qm_mVfk,36214
3
+ eventsourcing/cipher.py,sha256=AjgOlOv9FF6xyXiFnHwcK6NX5IJ3nPHFL5GzIyWozyg,3265
4
+ eventsourcing/compressor.py,sha256=IdvrJUB9B2td871oifInv4lGXmHwYL9d69MbHHCr7uI,421
5
+ eventsourcing/cryptography.py,sha256=ZsQFyeyMZysADqKy38ECV71j6EMMSbo3VQO7oRnC1h0,2994
6
+ eventsourcing/dispatch.py,sha256=yYSpT-jqc6l_wTdqEnfPJJfvsZN2Ta8g2anrVPWIcqQ,1412
7
+ eventsourcing/domain.py,sha256=pNetJA4uKf1chgfNFKWv1Fke3_V5g0ygRv63WT7nsUc,58208
8
+ eventsourcing/interface.py,sha256=LIFI9AZhoVWUAq4YjKosGCpinf51jmVLqw1Ii4npSHo,5079
9
+ eventsourcing/persistence.py,sha256=h5laiUP4mc6Ur1PoDnNBLXRcl8V-2-ife_hYktlCmmM,45732
10
+ eventsourcing/popo.py,sha256=4q4-l8iuEueqvYzGMzyFEiZaT8dm_PJNosmGwzRt1oo,9393
11
+ eventsourcing/postgres.py,sha256=h4ETgjzZtj9a-otJkMfzHZSxD_hOUWyVTIVuESVI7y0,36138
12
+ eventsourcing/projection.py,sha256=6UNNF_iVYR3nmOfoysgvhtjwYnEBTvsHkQM2gzXPTbQ,6489
13
+ eventsourcing/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
14
+ eventsourcing/sqlite.py,sha256=3bezfl3H9I366NnIwLpn4cz_L3fk0pHNiOSO_Hrq6Xw,21909
15
+ eventsourcing/system.py,sha256=7cM3FBdvr64ZK_xItks1MW2yg1o0OZ1vtKtznFFB_4g,47114
16
+ eventsourcing/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
17
+ eventsourcing/tests/application.py,sha256=Q_NFgRSRWovMcyQOZ8U1AoiIsnEHf_zCpHcP0ADaYvs,17369
18
+ eventsourcing/tests/domain.py,sha256=lHSlY6jIoSeqlcPSbrrozEPUJGvJ8bgPrznlmzTxn2w,3254
19
+ eventsourcing/tests/persistence.py,sha256=uink4W_CjeAlaSfzqRBuaDH2fYKAlZ1rvL7lhyUobp8,55553
20
+ eventsourcing/tests/postgres_utils.py,sha256=xymcGYasUXeZTBenkHz-ykD8HtrFjVM1Z7-qRrH6OQk,1364
21
+ eventsourcing/utils.py,sha256=QPlHhltgEcL80RWcPJ_PTygzDwhfIowUS3Z5taw0_cA,8228
22
+ eventsourcing-9.4.0a2.dist-info/AUTHORS,sha256=8aHOM4UbNZcKlD-cHpFRcM6RWyCqtwtxRev6DeUgVRs,137
23
+ eventsourcing-9.4.0a2.dist-info/LICENSE,sha256=CQEQzcZO8AWXL5i3hIo4yVKrYjh2FBz6hCM7kpXWpw4,1512
24
+ eventsourcing-9.4.0a2.dist-info/METADATA,sha256=NE7vnBA04-Huk9ZpUL8f3E-W2_BJhFm4V_uX7ZLvX_o,9874
25
+ eventsourcing-9.4.0a2.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
26
+ eventsourcing-9.4.0a2.dist-info/RECORD,,
@@ -1,25 +0,0 @@
1
- eventsourcing/__init__.py,sha256=st2H3shrhTk5rqoUeZHUW8XD9iOX9tGGtQFWr2HGYmo,26
2
- eventsourcing/application.py,sha256=YuZEE7le3GX3kVBje16stGziSIoUt6pUEBdlCDwkXf8,37847
3
- eventsourcing/cipher.py,sha256=S43YMycOCoEnzvWSanClv_MzMwDU5nBu5RU72G8BpYA,3201
4
- eventsourcing/compressor.py,sha256=IdvrJUB9B2td871oifInv4lGXmHwYL9d69MbHHCr7uI,421
5
- eventsourcing/dispatch.py,sha256=yYSpT-jqc6l_wTdqEnfPJJfvsZN2Ta8g2anrVPWIcqQ,1412
6
- eventsourcing/domain.py,sha256=b25jDhgP0aWsSEXXOxzN7plLi0TmDpoW7iZ5UHLTd8w,58339
7
- eventsourcing/interface.py,sha256=LIFI9AZhoVWUAq4YjKosGCpinf51jmVLqw1Ii4npSHo,5079
8
- eventsourcing/persistence.py,sha256=q4iJ_mFWiHgWVuJHYScXZQPvVMIdl-FvRlBruYH9SKE,45752
9
- eventsourcing/popo.py,sha256=FQmD7zJXoIyt3t-4RFADQ7UAhGWo1c7Cp0AkTQUjIW8,9413
10
- eventsourcing/postgres.py,sha256=tOCHY1xCMzEwDZ_JOMtWS5C8OXsbCrBOYaX-fz1oxA4,36158
11
- eventsourcing/projection.py,sha256=I1YrhMt5TyLdZru4ojtppo1W1r8fTrFZJ3VB61lzk-s,5158
12
- eventsourcing/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
13
- eventsourcing/sqlite.py,sha256=pbiuBU8x1J5uJqjqB1P9LshzDQqINYaZ-oBaYYNvo2s,21929
14
- eventsourcing/system.py,sha256=8FaI7LlwiAQGP2dULFbDwby30eUpnAePcOdmqGlm4EQ,47134
15
- eventsourcing/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
16
- eventsourcing/tests/application.py,sha256=s7GA3FEi6IV_wHk2lNZKJ25A1T3PkkfJo4AVVW6-cnc,19009
17
- eventsourcing/tests/domain.py,sha256=lHSlY6jIoSeqlcPSbrrozEPUJGvJ8bgPrznlmzTxn2w,3254
18
- eventsourcing/tests/persistence.py,sha256=uink4W_CjeAlaSfzqRBuaDH2fYKAlZ1rvL7lhyUobp8,55553
19
- eventsourcing/tests/postgres_utils.py,sha256=xymcGYasUXeZTBenkHz-ykD8HtrFjVM1Z7-qRrH6OQk,1364
20
- eventsourcing/utils.py,sha256=cGS_R5gZt9mp9Sj4qzXwJKvDkVvRUcFyQbUQfNLoy4M,8248
21
- eventsourcing-9.4.0a1.dist-info/AUTHORS,sha256=8aHOM4UbNZcKlD-cHpFRcM6RWyCqtwtxRev6DeUgVRs,137
22
- eventsourcing-9.4.0a1.dist-info/LICENSE,sha256=CQEQzcZO8AWXL5i3hIo4yVKrYjh2FBz6hCM7kpXWpw4,1512
23
- eventsourcing-9.4.0a1.dist-info/METADATA,sha256=HvyZX_hguCQdfvYovDJLfkgm2YMTNl3nDmCX_21Q0e8,9724
24
- eventsourcing-9.4.0a1.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
25
- eventsourcing-9.4.0a1.dist-info/RECORD,,