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

@@ -36,7 +36,12 @@ class DogSchool(Application):
36
36
 
37
37
  def get_dog(self, dog_id: UUID) -> Dict[str, Any]:
38
38
  dog = self.repository.get(dog_id, projector_func=project_dog)
39
- return {"name": dog.name, "tricks": tuple([t.name for t in dog.tricks])}
39
+ return {
40
+ "name": dog.name,
41
+ "tricks": tuple([t.name for t in dog.tricks]),
42
+ "created_on": dog.created_on,
43
+ "modified_on": dog.modified_on,
44
+ }
40
45
 
41
46
  def construct_mapper(self) -> Mapper:
42
47
  return self.factory.mapper(
@@ -5,33 +5,31 @@ from functools import singledispatch
5
5
  from typing import Any, Callable, Dict, Iterable, Optional, Tuple, TypeVar
6
6
  from uuid import UUID, uuid4
7
7
 
8
- from pydantic import BaseModel
8
+ from pydantic import BaseModel, ConfigDict
9
9
 
10
10
  from eventsourcing.utils import get_topic
11
11
 
12
12
 
13
13
  class DomainEvent(BaseModel):
14
+ model_config = ConfigDict(frozen=True, extra="forbid")
15
+
14
16
  originator_id: UUID
15
17
  originator_version: int
16
18
  timestamp: datetime
17
19
 
18
- class Config:
19
- frozen = True
20
-
21
20
 
22
21
  def create_timestamp() -> datetime:
23
22
  return datetime.now(tz=timezone.utc)
24
23
 
25
24
 
26
25
  class Aggregate(BaseModel):
26
+ model_config = ConfigDict(frozen=True, extra="forbid")
27
+
27
28
  id: UUID
28
29
  version: int
29
30
  created_on: datetime
30
31
  modified_on: datetime
31
32
 
32
- class Config:
33
- frozen = True
34
-
35
33
 
36
34
  class Snapshot(DomainEvent):
37
35
  topic: str
@@ -1,5 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
+ from datetime import datetime
3
4
  from unittest import TestCase
4
5
 
5
6
  from eventsourcing.examples.aggregate7.application import DogSchool
@@ -20,6 +21,8 @@ class TestDogSchool(TestCase):
20
21
  dog = school.get_dog(dog_id)
21
22
  self.assertEqual(dog["name"], "Fido")
22
23
  self.assertEqual(dog["tricks"], ("roll over", "play dead"))
24
+ self.assertIsInstance(dog["created_on"], datetime)
25
+ self.assertIsInstance(dog["modified_on"], datetime)
23
26
 
24
27
  # Select notifications.
25
28
  notifications = school.notification_log.select(start=1, limit=10)
@@ -30,9 +33,13 @@ class TestDogSchool(TestCase):
30
33
  dog = school.get_dog(dog_id)
31
34
  self.assertEqual(dog["name"], "Fido")
32
35
  self.assertEqual(dog["tricks"], ("roll over", "play dead"))
36
+ self.assertIsInstance(dog["created_on"], datetime)
37
+ self.assertIsInstance(dog["modified_on"], datetime)
33
38
 
34
39
  # Continue with snapshotted aggregate.
35
40
  school.add_trick(dog_id, "fetch ball")
36
41
  dog = school.get_dog(dog_id)
37
42
  self.assertEqual(dog["name"], "Fido")
38
43
  self.assertEqual(dog["tricks"], ("roll over", "play dead", "fetch ball"))
44
+ self.assertIsInstance(dog["created_on"], datetime)
45
+ self.assertIsInstance(dog["modified_on"], datetime)
@@ -7,33 +7,31 @@ from functools import singledispatch
7
7
  from typing import Any, Callable, Dict, Iterable, List, Optional, Tuple, TypeVar
8
8
  from uuid import UUID, uuid4
9
9
 
10
- from pydantic import BaseModel
10
+ from pydantic import BaseModel, ConfigDict
11
11
 
12
12
  from eventsourcing.utils import get_topic
13
13
 
14
14
 
15
15
  class DomainEvent(BaseModel):
16
+ model_config = ConfigDict(frozen=True, extra="forbid")
17
+
16
18
  originator_id: UUID
17
19
  originator_version: int
18
20
  timestamp: datetime
19
21
 
20
- class Config:
21
- frozen = True
22
-
23
22
 
24
23
  def create_timestamp() -> datetime:
25
24
  return datetime.now(tz=timezone.utc)
26
25
 
27
26
 
28
27
  class Aggregate(BaseModel):
28
+ model_config = ConfigDict(frozen=True, extra="forbid")
29
+
29
30
  id: UUID
30
31
  version: int
31
32
  created_on: datetime
32
33
  modified_on: datetime
33
34
 
34
- class Config:
35
- frozen = True
36
-
37
35
  def hold_event(self, event: DomainEvent) -> None:
38
36
  all_pending_events[id(self)].append(event)
39
37
 
@@ -1,10 +1,10 @@
1
1
  from __future__ import annotations
2
2
 
3
- from datetime import datetime # noqa: TCH003
4
- from typing import List
5
- from uuid import UUID # noqa: TCH003
3
+ from datetime import datetime
4
+ from typing import Any, List
5
+ from uuid import UUID
6
6
 
7
- from pydantic import BaseModel, Extra
7
+ from pydantic import BaseModel, ConfigDict, TypeAdapter
8
8
 
9
9
  from eventsourcing.domain import (
10
10
  Aggregate as BaseAggregate,
@@ -16,25 +16,23 @@ from eventsourcing.domain import (
16
16
 
17
17
 
18
18
  class DomainEvent(BaseModel):
19
+ model_config = ConfigDict(frozen=True, extra="forbid")
20
+
19
21
  originator_id: UUID
20
22
  originator_version: int
21
23
  timestamp: datetime
22
24
 
23
- class Config:
24
- frozen = True
25
25
 
26
-
27
- class Aggregate(BaseAggregate):
28
- class Event(DomainEvent, CanMutateAggregate):
29
- pass
30
-
31
- class Created(Event, CanInitAggregate):
32
- originator_topic: str
26
+ datetime_adapter = TypeAdapter(datetime)
33
27
 
34
28
 
35
29
  class SnapshotState(BaseModel):
36
- class Config:
37
- extra = Extra.allow
30
+ model_config = ConfigDict(frozen=True, extra="allow")
31
+
32
+ def __init__(self, **kwargs: Any) -> None:
33
+ for key in ["_created_on", "_modified_on"]:
34
+ kwargs[key] = datetime_adapter.validate_python(kwargs[key])
35
+ super().__init__(**kwargs)
38
36
 
39
37
 
40
38
  class AggregateSnapshot(DomainEvent, CanSnapshotAggregate):
@@ -42,18 +40,26 @@ class AggregateSnapshot(DomainEvent, CanSnapshotAggregate):
42
40
  state: SnapshotState
43
41
 
44
42
 
43
+ class Aggregate(BaseAggregate):
44
+ class Event(DomainEvent, CanMutateAggregate):
45
+ pass
46
+
47
+ class Created(Event, CanInitAggregate):
48
+ originator_topic: str
49
+
50
+
45
51
  class Trick(BaseModel):
46
52
  name: str
47
53
 
48
54
 
49
- class DogState(SnapshotState):
55
+ class DogSnapshotState(SnapshotState):
50
56
  name: str
51
57
  tricks: List[Trick]
52
58
 
53
59
 
54
60
  class Dog(Aggregate):
55
61
  class Snapshot(AggregateSnapshot):
56
- state: DogState
62
+ state: DogSnapshotState
57
63
 
58
64
  @event("Registered")
59
65
  def __init__(self, name: str) -> None:
@@ -1,5 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
+ from datetime import datetime
3
4
  from unittest import TestCase
4
5
 
5
6
  from eventsourcing.examples.aggregate8.application import DogSchool
@@ -19,6 +20,8 @@ class TestDogSchool(TestCase):
19
20
  dog = school.get_dog(dog_id)
20
21
  self.assertEqual(dog["name"], "Fido")
21
22
  self.assertEqual(dog["tricks"], ("roll over", "play dead"))
23
+ self.assertIsInstance(dog["created_on"], datetime)
24
+ self.assertIsInstance(dog["modified_on"], datetime)
22
25
 
23
26
  # Select notifications.
24
27
  notifications = school.notification_log.select(start=1, limit=10)
@@ -29,9 +32,13 @@ class TestDogSchool(TestCase):
29
32
  dog = school.get_dog(dog_id)
30
33
  self.assertEqual(dog["name"], "Fido")
31
34
  self.assertEqual(dog["tricks"], ("roll over", "play dead"))
35
+ self.assertIsInstance(dog["created_on"], datetime)
36
+ self.assertIsInstance(dog["modified_on"], datetime)
32
37
 
33
38
  # Continue with snapshotted aggregate.
34
39
  school.add_trick(dog_id, "fetch ball")
35
40
  dog = school.get_dog(dog_id)
36
41
  self.assertEqual(dog["name"], "Fido")
37
42
  self.assertEqual(dog["tricks"], ("roll over", "play dead", "fetch ball"))
43
+ self.assertIsInstance(dog["created_on"], datetime)
44
+ self.assertIsInstance(dog["modified_on"], datetime)
eventsourcing/postgres.py CHANGED
@@ -9,7 +9,6 @@ import psycopg.errors
9
9
  import psycopg_pool
10
10
  from psycopg import Connection, Cursor
11
11
  from psycopg.rows import DictRow, dict_row
12
- from typing_extensions import Self
13
12
 
14
13
  from eventsourcing.persistence import (
15
14
  AggregateRecorder,
@@ -34,6 +33,8 @@ from eventsourcing.utils import Environment, resolve_topic, retry, strtobool
34
33
  if TYPE_CHECKING: # pragma: nocover
35
34
  from uuid import UUID
36
35
 
36
+ from typing_extensions import Self
37
+
37
38
  logging.getLogger("psycopg.pool").setLevel(logging.CRITICAL)
38
39
  logging.getLogger("psycopg").setLevel(logging.CRITICAL)
39
40
 
eventsourcing/system.py CHANGED
@@ -8,6 +8,7 @@ from queue import Full, Queue
8
8
  from threading import Event, Lock, RLock, Thread
9
9
  from types import FrameType, ModuleType
10
10
  from typing import (
11
+ TYPE_CHECKING,
11
12
  Any,
12
13
  ClassVar,
13
14
  Dict,
@@ -22,7 +23,8 @@ from typing import (
22
23
  cast,
23
24
  )
24
25
 
25
- from typing_extensions import Self
26
+ if TYPE_CHECKING: # pragma: nocover
27
+ from typing_extensions import Self
26
28
 
27
29
  from eventsourcing.application import (
28
30
  Application,
@@ -232,6 +232,7 @@ class TestPostgresDatastore(TestCase):
232
232
  user="eventsourcing",
233
233
  password="wrong", # noqa: S106
234
234
  pool_size=1,
235
+ connect_timeout=3,
235
236
  ) as datastore:
236
237
 
237
238
  conn: Connection
@@ -261,7 +262,7 @@ class TestPostgresDatastore(TestCase):
261
262
  password="",
262
263
  pool_size=1,
263
264
  get_password_func=get_password_func,
264
- connect_timeout=10,
265
+ connect_timeout=3,
265
266
  ) as datastore, datastore.get_connection() as conn, conn.cursor() as curs:
266
267
  # Create a connection, and check it works (this test depends on psycopg
267
268
  # retrying attempt to connect, should call "get password" twice).
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: eventsourcing
3
- Version: 9.3.2
3
+ Version: 9.3.3
4
4
  Summary: Event sourcing in Python
5
5
  Home-page: https://github.com/pyeventsourcing/eventsourcing
6
6
  License: BSD 3-Clause
@@ -25,15 +25,10 @@ Classifier: Programming Language :: Python :: 3.12
25
25
  Classifier: Programming Language :: Python :: 3.13
26
26
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
27
27
  Provides-Extra: crypto
28
- Provides-Extra: docs
29
28
  Provides-Extra: postgres
30
- Requires-Dist: Sphinx ; extra == "docs"
31
29
  Requires-Dist: backports.zoneinfo ; python_version < "3.9"
32
- Requires-Dist: orjson ; extra == "docs"
33
- Requires-Dist: psycopg[c,pool] (<=3.2.1) ; (python_full_version <= "3.12.999999") and (extra == "postgres")
34
- Requires-Dist: pycryptodome (>=3.20,<3.21) ; extra == "crypto"
35
- Requires-Dist: pydantic ; extra == "docs"
36
- Requires-Dist: sphinx_rtd_theme ; extra == "docs"
30
+ Requires-Dist: psycopg[c,pool] (<=3.2.99999) ; extra == "postgres"
31
+ Requires-Dist: pycryptodome (>=3.21,<3.22) ; extra == "crypto"
37
32
  Requires-Dist: typing_extensions
38
33
  Project-URL: Repository, https://github.com/pyeventsourcing/eventsourcing
39
34
  Description-Content-Type: text/markdown
@@ -34,22 +34,22 @@ eventsourcing/examples/aggregate6a/application.py,sha256=KK8PjIhlMuxKmV4Gjr6tLSW
34
34
  eventsourcing/examples/aggregate6a/domainmodel.py,sha256=LaktSGm8sa4xIDyXQAyRkjH8m_HhVt3GHbQw8vfZkUQ,3627
35
35
  eventsourcing/examples/aggregate6a/test_application.py,sha256=s8tyZqGWwLQXpD9FSEe1h5MZT3v5_zJc17Vzw133_lw,1673
36
36
  eventsourcing/examples/aggregate7/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
37
- eventsourcing/examples/aggregate7/application.py,sha256=cOJ3nYKRTOCO3gA3M-CmlR0Gu-lW8Agmq5epy5uVf90,1395
38
- eventsourcing/examples/aggregate7/domainmodel.py,sha256=pImr-nOg8uR1SjfF0Ou1R19eLjrsZ9-Xpbhbkci7izk,3261
37
+ eventsourcing/examples/aggregate7/application.py,sha256=vZTXSWH39OoSiwgwcyrE9SHuw-cvbjMEjSrsu9pHiBs,1516
38
+ eventsourcing/examples/aggregate7/domainmodel.py,sha256=WXO3uVEUWp7klxq6__yX48fDJiXMMd8YzJpJsVG1fdI,3311
39
39
  eventsourcing/examples/aggregate7/persistence.py,sha256=zb2yJc4iVqkOc9iGLeqLCgo1E-kRRIoBYNvOBhUOfKg,1874
40
- eventsourcing/examples/aggregate7/test_application.py,sha256=tWRTrRdIL81AlEyO-j2LHTF3l-6yWqXFTOj8Dnk2Nt4,1366
40
+ eventsourcing/examples/aggregate7/test_application.py,sha256=QjbnycufzOelwN5EqUxe-8Q-8rx8Cz5VkuHUYI05fMM,1753
41
41
  eventsourcing/examples/aggregate7/test_compression_and_encryption.py,sha256=s9EGEdQ_m4xpt6tyPBhXeGQO9JAx1IpckjHE7vtmBbo,1634
42
42
  eventsourcing/examples/aggregate7/test_snapshotting_intervals.py,sha256=_poDWDfHXciTgFfA2IRcR_JVonFedWcV4afaRIto5Ho,2190
43
43
  eventsourcing/examples/aggregate7a/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
44
44
  eventsourcing/examples/aggregate7a/application.py,sha256=dRa5XGu29Ka31qbSY8VBfKPekvQnzWELE6_gM2Xht-E,1748
45
- eventsourcing/examples/aggregate7a/domainmodel.py,sha256=l0mdBGedAOljbSYAxVbh6Po2nbbAKp_vhVGs915MYFA,4016
45
+ eventsourcing/examples/aggregate7a/domainmodel.py,sha256=D56CLAgCEh1hWDSbiALz-7sQpLVQbU2N-6C-dZ4KX74,4066
46
46
  eventsourcing/examples/aggregate7a/test_application.py,sha256=06ViRUVfIE74OLEj7N3rYmVhLO7V5sbCCaS8ozLBIH4,1741
47
47
  eventsourcing/examples/aggregate7a/test_compression_and_encryption.py,sha256=h3pxOUMHMCUMWx36vN2pqg4Mrwry_KCpJfMYYkA64o8,1636
48
48
  eventsourcing/examples/aggregate8/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
49
49
  eventsourcing/examples/aggregate8/application.py,sha256=b4MQb7wFzzk29cHe8ZuVQuwFXn2kskEmLojzqO4EKsw,1357
50
- eventsourcing/examples/aggregate8/domainmodel.py,sha256=Nnc62RyMy_wukqPLxnRo2vJOqxho2XVAgagWfT-Vuq0,1276
50
+ eventsourcing/examples/aggregate8/domainmodel.py,sha256=t-FmjMcI0tkJUqzS_OvSs7IFbPTj6hcx9I33WudH6Ec,1564
51
51
  eventsourcing/examples/aggregate8/persistence.py,sha256=zb2yJc4iVqkOc9iGLeqLCgo1E-kRRIoBYNvOBhUOfKg,1874
52
- eventsourcing/examples/aggregate8/test_application.py,sha256=tbd77pTSpUopE_CENZAt31vCZOYs8E0Ot3WnFRQrhhw,1268
52
+ eventsourcing/examples/aggregate8/test_application.py,sha256=zhla6hWQuuhLaiukUYUcOsL7-BWFru6zqKOxLODDLsA,1655
53
53
  eventsourcing/examples/aggregate8/test_compression_and_encryption.py,sha256=UWGnTSIlRu-FbXWQ0rX1YOQuDkMj9NCCssoQES23i-w,1509
54
54
  eventsourcing/examples/aggregate8/test_snapshotting_intervals.py,sha256=w_HAY_RirHqHtSQ1Z-muqqUz75RTYYBLeFGCB8ELhbI,1261
55
55
  eventsourcing/examples/bankaccounts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -90,10 +90,10 @@ eventsourcing/examples/test_parking_lot.py,sha256=Tlm8KYlMoZFBi20mX-_BSAPPJfeKDg
90
90
  eventsourcing/interface.py,sha256=KzDWLeIkREf-TAFl5AFHtKJwJFA-IthqMKClFkUFqdc,4676
91
91
  eventsourcing/persistence.py,sha256=TJseAtsWwdC33XLvcoyHdgwTv6s6KsvQS8XLKIq472s,37672
92
92
  eventsourcing/popo.py,sha256=AApSGneHuXa8yHOWdDfsFTMVDI-9ivEpuKTX1BSOXr8,6547
93
- eventsourcing/postgres.py,sha256=ZsDw36JJbR9O3_FeYSkA_NVab7N0fg4FrmWkVN4h3Lo,29767
93
+ eventsourcing/postgres.py,sha256=NatfdA-YQQPB1qWsQg23Uhyy6R-hcGNOJHJ1bKmFuKQ,29772
94
94
  eventsourcing/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
95
95
  eventsourcing/sqlite.py,sha256=jz7SZk26Gcsjw88KL1xnr4-1tStTW16f1NR6TjMsZnQ,18466
96
- eventsourcing/system.py,sha256=Fyho27C44MckwC3OD9opw7an1Thz20QsD7PnRymnYik,45501
96
+ eventsourcing/system.py,sha256=il05rAzPtKaxragIktMBOEyWGhz16VK0F7cEBlsl4_Q,45561
97
97
  eventsourcing/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
98
98
  eventsourcing/tests/application.py,sha256=wBanhWzAZvL3fYxCFe5cloN-Up7uLw6KcdRQ2dhKVAg,17586
99
99
  eventsourcing/tests/application_tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -128,7 +128,7 @@ eventsourcing/tests/persistence_tests/test_infrastructure_factory.py,sha256=xcDd
128
128
  eventsourcing/tests/persistence_tests/test_mapper.py,sha256=3GWdhLzFrld8-h7pPfsYdNzIn1YNTa_L6iHb-dCg5zk,3806
129
129
  eventsourcing/tests/persistence_tests/test_noninterleaving_notification_ids.py,sha256=O8t9AT1SJ0mwrkh9hyDvQr_bpO-n3RA-PO4S9RVdzhY,2130
130
130
  eventsourcing/tests/persistence_tests/test_popo.py,sha256=7KIb72i2VF566N14IyEhM21P7eX3o8UmOLQKkaFAH84,3366
131
- eventsourcing/tests/persistence_tests/test_postgres.py,sha256=6mxPWJCAFWB0GIgVLEDXVpxY_mPVlm4ZunU22V3VvUA,41185
131
+ eventsourcing/tests/persistence_tests/test_postgres.py,sha256=GnveTnyttrPHNZzFQZVTQfkKHjYsKKEh8Y770VZIRvE,41215
132
132
  eventsourcing/tests/persistence_tests/test_sqlite.py,sha256=dABEY6r0AIjGkgbBBk6f7MgfvQz9JkXgpOPEq8xvei0,11744
133
133
  eventsourcing/tests/persistence_tests/test_transcoder.py,sha256=IU1phRrGpyB0KzKFxivtDzDBP2Vn609nrwU52yk9YKM,1251
134
134
  eventsourcing/tests/postgres_utils.py,sha256=xymcGYasUXeZTBenkHz-ykD8HtrFjVM1Z7-qRrH6OQk,1364
@@ -138,8 +138,8 @@ eventsourcing/tests/system_tests/test_system.py,sha256=IRmLBovJ5Ha4KWNVg8efM-0OV
138
138
  eventsourcing/tests/utils_tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
139
139
  eventsourcing/tests/utils_tests/test_utils.py,sha256=8HcTk_0_lXyoT307fEmd2utwmOUS_joToUPGFeFnKW8,6486
140
140
  eventsourcing/utils.py,sha256=PIWDvoGiKCXsNbR5DirkoJ_svopg80SoH37bqxOcjkU,8247
141
- eventsourcing-9.3.2.dist-info/AUTHORS,sha256=8aHOM4UbNZcKlD-cHpFRcM6RWyCqtwtxRev6DeUgVRs,137
142
- eventsourcing-9.3.2.dist-info/LICENSE,sha256=bSE_F-T6cQPmMY5LuJC27km_pGB1XCVuUFx1uY0Nueg,1512
143
- eventsourcing-9.3.2.dist-info/METADATA,sha256=QFafd2jcyxKW5UCb_N5-8M-iZBJKU8YPdk5fOCJYcsQ,9968
144
- eventsourcing-9.3.2.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
145
- eventsourcing-9.3.2.dist-info/RECORD,,
141
+ eventsourcing-9.3.3.dist-info/AUTHORS,sha256=8aHOM4UbNZcKlD-cHpFRcM6RWyCqtwtxRev6DeUgVRs,137
142
+ eventsourcing-9.3.3.dist-info/LICENSE,sha256=bSE_F-T6cQPmMY5LuJC27km_pGB1XCVuUFx1uY0Nueg,1512
143
+ eventsourcing-9.3.3.dist-info/METADATA,sha256=imKTn-0_ySg-VoB4VpJ7a3FNtB2RSsclUbk8m9bArMw,9734
144
+ eventsourcing-9.3.3.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
145
+ eventsourcing-9.3.3.dist-info/RECORD,,