eventsourcing 9.3.0b1__tar.gz → 9.3.1__tar.gz
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-9.3.1/AUTHORS +10 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/PKG-INFO +6 -5
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/application.py +8 -1
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/examples/aggregate4/domainmodel.py +14 -28
- eventsourcing-9.3.1/eventsourcing/examples/contentmanagementsystem/test_system.py +180 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/examples/searchablecontent/test_application.py +4 -5
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/examples/searchablecontent/test_recorder.py +4 -5
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/examples/searchabletimestamps/test_searchabletimestamps.py +8 -5
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/postgres.py +28 -22
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/system.py +10 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/tests/docs_tests/test_docs.py +10 -10
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/tests/domain_tests/test_aggregate.py +27 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/tests/persistence.py +3 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/tests/persistence_tests/test_postgres.py +104 -106
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/tests/system_tests/test_runner.py +17 -17
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/tests/system_tests/test_system.py +1 -4
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/pyproject.toml +22 -40
- eventsourcing-9.3.0b1/eventsourcing/examples/contentmanagementsystem/test_system.py +0 -174
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/LICENSE +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/README.md +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/__init__.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/cipher.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/compressor.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/dispatch.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/domain.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/examples/__init__.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/examples/aggregate1/__init__.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/examples/aggregate1/application.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/examples/aggregate1/domainmodel.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/examples/aggregate1/test_application.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/examples/aggregate2/__init__.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/examples/aggregate2/application.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/examples/aggregate2/domainmodel.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/examples/aggregate2/test_application.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/examples/aggregate3/__init__.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/examples/aggregate3/application.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/examples/aggregate3/domainmodel.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/examples/aggregate3/test_application.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/examples/aggregate4/__init__.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/examples/aggregate4/application.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/examples/aggregate4/test_application.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/examples/aggregate5/__init__.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/examples/aggregate5/application.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/examples/aggregate5/domainmodel.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/examples/aggregate5/test_application.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/examples/aggregate6/__init__.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/examples/aggregate6/application.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/examples/aggregate6/domainmodel.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/examples/aggregate6/test_application.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/examples/aggregate6a/__init__.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/examples/aggregate6a/application.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/examples/aggregate6a/domainmodel.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/examples/aggregate6a/test_application.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/examples/aggregate7/__init__.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/examples/aggregate7/application.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/examples/aggregate7/domainmodel.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/examples/aggregate7/persistence.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/examples/aggregate7/test_application.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/examples/aggregate7/test_compression_and_encryption.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/examples/aggregate7/test_snapshotting_intervals.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/examples/aggregate7a/__init__.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/examples/aggregate7a/application.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/examples/aggregate7a/domainmodel.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/examples/aggregate7a/test_application.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/examples/aggregate7a/test_compression_and_encryption.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/examples/aggregate8/__init__.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/examples/aggregate8/application.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/examples/aggregate8/domainmodel.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/examples/aggregate8/persistence.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/examples/aggregate8/test_application.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/examples/aggregate8/test_compression_and_encryption.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/examples/aggregate8/test_snapshotting_intervals.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/examples/bankaccounts/__init__.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/examples/bankaccounts/application.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/examples/bankaccounts/domainmodel.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/examples/bankaccounts/test.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/examples/cargoshipping/__init__.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/examples/cargoshipping/application.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/examples/cargoshipping/domainmodel.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/examples/cargoshipping/interface.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/examples/cargoshipping/test.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/examples/contentmanagement/__init__.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/examples/contentmanagement/application.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/examples/contentmanagement/domainmodel.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/examples/contentmanagement/test.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/examples/contentmanagement/utils.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/examples/contentmanagementsystem/__init__.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/examples/contentmanagementsystem/application.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/examples/contentmanagementsystem/postgres.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/examples/contentmanagementsystem/sqlite.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/examples/contentmanagementsystem/system.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/examples/searchablecontent/__init__.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/examples/searchablecontent/application.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/examples/searchablecontent/persistence.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/examples/searchablecontent/postgres.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/examples/searchablecontent/sqlite.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/examples/searchabletimestamps/__init__.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/examples/searchabletimestamps/application.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/examples/searchabletimestamps/persistence.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/examples/searchabletimestamps/postgres.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/examples/searchabletimestamps/sqlite.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/examples/test_invoice.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/examples/test_parking_lot.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/interface.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/persistence.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/popo.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/py.typed +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/sqlite.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/tests/__init__.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/tests/application.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/tests/application_tests/__init__.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/tests/application_tests/test_application_with_automatic_snapshotting.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/tests/application_tests/test_application_with_popo.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/tests/application_tests/test_application_with_postgres.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/tests/application_tests/test_application_with_sqlite.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/tests/application_tests/test_cache.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/tests/application_tests/test_event_sourced_log.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/tests/application_tests/test_notificationlog.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/tests/application_tests/test_notificationlogreader.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/tests/application_tests/test_processapplication.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/tests/application_tests/test_processingpolicy.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/tests/application_tests/test_repository.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/tests/application_tests/test_snapshotting.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/tests/application_tests/test_upcasting.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/tests/docs_tests/__init__.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/tests/domain.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/tests/domain_tests/__init__.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/tests/domain_tests/test_aggregate_decorators.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/tests/domain_tests/test_domainevent.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/tests/interface_tests/__init__.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/tests/interface_tests/test_remotenotificationlog.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/tests/persistence_tests/__init__.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/tests/persistence_tests/test_aes.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/tests/persistence_tests/test_connection_pool.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/tests/persistence_tests/test_eventstore.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/tests/persistence_tests/test_infrastructure_factory.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/tests/persistence_tests/test_mapper.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/tests/persistence_tests/test_noninterleaving_notification_ids.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/tests/persistence_tests/test_popo.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/tests/persistence_tests/test_sqlite.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/tests/persistence_tests/test_transcoder.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/tests/postgres_utils.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/tests/system_tests/__init__.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/tests/utils_tests/__init__.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/tests/utils_tests/test_utils.py +0 -0
- {eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: eventsourcing
|
|
3
|
-
Version: 9.3.
|
|
3
|
+
Version: 9.3.1
|
|
4
4
|
Summary: Event sourcing in Python
|
|
5
5
|
Home-page: https://github.com/pyeventsourcing/eventsourcing
|
|
6
6
|
License: BSD 3-Clause
|
|
@@ -8,7 +8,7 @@ Keywords: event sourcing,event store,domain driven design,domain-driven design,d
|
|
|
8
8
|
Author: John Bywater
|
|
9
9
|
Author-email: john.bywater@appropriatesoftware.net
|
|
10
10
|
Requires-Python: >=3.8,<4.0
|
|
11
|
-
Classifier: Development Status ::
|
|
11
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
12
12
|
Classifier: Intended Audience :: Developers
|
|
13
13
|
Classifier: Intended Audience :: Education
|
|
14
14
|
Classifier: Intended Audience :: Science/Research
|
|
@@ -22,6 +22,7 @@ Classifier: Programming Language :: Python :: 3.9
|
|
|
22
22
|
Classifier: Programming Language :: Python :: 3.10
|
|
23
23
|
Classifier: Programming Language :: Python :: 3.11
|
|
24
24
|
Classifier: Programming Language :: Python :: 3.12
|
|
25
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
25
26
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
26
27
|
Provides-Extra: crypto
|
|
27
28
|
Provides-Extra: docs
|
|
@@ -29,11 +30,11 @@ Provides-Extra: postgres
|
|
|
29
30
|
Requires-Dist: Sphinx ; extra == "docs"
|
|
30
31
|
Requires-Dist: backports.zoneinfo ; python_version < "3.9"
|
|
31
32
|
Requires-Dist: orjson ; extra == "docs"
|
|
32
|
-
Requires-Dist: psycopg[c,pool] (<=3.
|
|
33
|
-
Requires-Dist: pycryptodome (
|
|
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"
|
|
34
35
|
Requires-Dist: pydantic ; extra == "docs"
|
|
35
36
|
Requires-Dist: sphinx_rtd_theme ; extra == "docs"
|
|
36
|
-
Requires-Dist: typing_extensions
|
|
37
|
+
Requires-Dist: typing_extensions
|
|
37
38
|
Project-URL: Repository, https://github.com/pyeventsourcing/eventsourcing
|
|
38
39
|
Description-Content-Type: text/markdown
|
|
39
40
|
|
|
@@ -25,6 +25,8 @@ from typing import (
|
|
|
25
25
|
)
|
|
26
26
|
from warnings import warn
|
|
27
27
|
|
|
28
|
+
from typing_extensions import deprecated
|
|
29
|
+
|
|
28
30
|
from eventsourcing.domain import (
|
|
29
31
|
Aggregate,
|
|
30
32
|
CanMutateProtocol,
|
|
@@ -908,7 +910,12 @@ class Application:
|
|
|
908
910
|
TApplication = TypeVar("TApplication", bound=Application)
|
|
909
911
|
|
|
910
912
|
|
|
911
|
-
|
|
913
|
+
@deprecated("AggregateNotFound is deprecated, use AggregateNotFoundError instead")
|
|
914
|
+
class AggregateNotFound(EventSourcingError): # noqa: N818
|
|
915
|
+
pass
|
|
916
|
+
|
|
917
|
+
|
|
918
|
+
class AggregateNotFoundError(AggregateNotFound):
|
|
912
919
|
"""
|
|
913
920
|
Raised when an :class:`~eventsourcing.domain.Aggregate`
|
|
914
921
|
object is not found in a :class:`Repository`.
|
{eventsourcing-9.3.0b1 → eventsourcing-9.3.1}/eventsourcing/examples/aggregate4/domainmodel.py
RENAMED
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
import contextlib
|
|
4
|
-
from collections import defaultdict
|
|
5
3
|
from dataclasses import dataclass
|
|
6
4
|
from datetime import datetime, timezone
|
|
7
|
-
from typing import Any,
|
|
5
|
+
from typing import Any, Iterable, List, Type, TypeVar, cast
|
|
8
6
|
from uuid import UUID, uuid4
|
|
9
7
|
|
|
10
8
|
from eventsourcing.dispatch import singledispatchmethod
|
|
@@ -29,6 +27,7 @@ class Aggregate:
|
|
|
29
27
|
id: UUID
|
|
30
28
|
version: int
|
|
31
29
|
created_on: datetime
|
|
30
|
+
_pending_events: List[DomainEvent]
|
|
32
31
|
|
|
33
32
|
def __init__(self, event: DomainEvent):
|
|
34
33
|
self.id = event.originator_id
|
|
@@ -47,15 +46,15 @@ class Aggregate:
|
|
|
47
46
|
timestamp=event_class.create_timestamp(),
|
|
48
47
|
)
|
|
49
48
|
new_event = event_class(**kwargs)
|
|
50
|
-
self.
|
|
51
|
-
self.
|
|
49
|
+
self._apply(new_event)
|
|
50
|
+
self._pending_events.append(new_event)
|
|
52
51
|
|
|
53
52
|
@singledispatchmethod
|
|
54
|
-
def
|
|
53
|
+
def _apply(self, event: DomainEvent) -> None:
|
|
55
54
|
"""Applies event to aggregate."""
|
|
56
55
|
|
|
57
56
|
def collect_events(self) -> List[DomainEvent]:
|
|
58
|
-
events, self.
|
|
57
|
+
events, self._pending_events = self._pending_events, []
|
|
59
58
|
return events
|
|
60
59
|
|
|
61
60
|
@classmethod
|
|
@@ -64,25 +63,12 @@ class Aggregate:
|
|
|
64
63
|
_: TAggregate | None,
|
|
65
64
|
events: Iterable[DomainEvent],
|
|
66
65
|
) -> TAggregate | None:
|
|
67
|
-
aggregate = object.__new__(cls)
|
|
66
|
+
aggregate: TAggregate = object.__new__(cls)
|
|
67
|
+
aggregate._pending_events = []
|
|
68
68
|
for event in events:
|
|
69
|
-
aggregate.
|
|
69
|
+
aggregate._apply(event)
|
|
70
70
|
return aggregate
|
|
71
71
|
|
|
72
|
-
@property
|
|
73
|
-
def pending_events(self) -> List[DomainEvent]:
|
|
74
|
-
return type(self).__pending_events[id(self)]
|
|
75
|
-
|
|
76
|
-
@pending_events.setter
|
|
77
|
-
def pending_events(self, pending_events: List[DomainEvent]) -> None:
|
|
78
|
-
type(self).__pending_events[id(self)] = pending_events
|
|
79
|
-
|
|
80
|
-
__pending_events: ClassVar[Dict[int, List[DomainEvent]]] = defaultdict(list)
|
|
81
|
-
|
|
82
|
-
def __del__(self) -> None:
|
|
83
|
-
with contextlib.suppress(KeyError):
|
|
84
|
-
type(self).__pending_events.pop(id(self))
|
|
85
|
-
|
|
86
72
|
|
|
87
73
|
class Dog(Aggregate):
|
|
88
74
|
@dataclass(frozen=True)
|
|
@@ -102,27 +88,27 @@ class Dog(Aggregate):
|
|
|
102
88
|
name=name,
|
|
103
89
|
)
|
|
104
90
|
dog = cast(Dog, cls.projector(None, [event]))
|
|
105
|
-
dog.
|
|
91
|
+
dog._pending_events.append(event)
|
|
106
92
|
return dog
|
|
107
93
|
|
|
108
94
|
def add_trick(self, trick: str) -> None:
|
|
109
95
|
self.trigger_event(self.TrickAdded, trick=trick)
|
|
110
96
|
|
|
111
97
|
@singledispatchmethod
|
|
112
|
-
def
|
|
98
|
+
def _apply(self, event: DomainEvent) -> None:
|
|
113
99
|
"""Applies event to aggregate."""
|
|
114
100
|
|
|
115
|
-
@
|
|
101
|
+
@_apply.register(Registered)
|
|
116
102
|
def _(self, event: Registered) -> None:
|
|
117
103
|
super().__init__(event)
|
|
118
104
|
self.name = event.name
|
|
119
105
|
self.tricks: List[str] = []
|
|
120
106
|
|
|
121
|
-
@
|
|
107
|
+
@_apply.register(TrickAdded)
|
|
122
108
|
def _(self, event: TrickAdded) -> None:
|
|
123
109
|
self.tricks.append(event.trick)
|
|
124
110
|
self.version = event.originator_version
|
|
125
111
|
|
|
126
|
-
@
|
|
112
|
+
@_apply.register(Snapshot)
|
|
127
113
|
def _(self, event: Snapshot) -> None:
|
|
128
114
|
self.__dict__.update(event.state)
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import ClassVar, Dict
|
|
4
|
+
from unittest import TestCase
|
|
5
|
+
from uuid import uuid4
|
|
6
|
+
|
|
7
|
+
from eventsourcing.examples.contentmanagement.application import (
|
|
8
|
+
ContentManagementApplication,
|
|
9
|
+
)
|
|
10
|
+
from eventsourcing.examples.contentmanagement.domainmodel import user_id_cvar
|
|
11
|
+
from eventsourcing.examples.contentmanagementsystem.application import (
|
|
12
|
+
SearchIndexApplication,
|
|
13
|
+
)
|
|
14
|
+
from eventsourcing.examples.contentmanagementsystem.system import (
|
|
15
|
+
ContentManagementSystem,
|
|
16
|
+
)
|
|
17
|
+
from eventsourcing.postgres import PostgresDatastore
|
|
18
|
+
from eventsourcing.system import SingleThreadedRunner
|
|
19
|
+
from eventsourcing.tests.postgres_utils import drop_postgres_table
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class ContentManagementSystemTestCase(TestCase):
|
|
23
|
+
env: ClassVar[Dict[str, str]] = {}
|
|
24
|
+
|
|
25
|
+
def test_system(self) -> None:
|
|
26
|
+
with SingleThreadedRunner(
|
|
27
|
+
system=ContentManagementSystem(), env=self.env
|
|
28
|
+
) as runner:
|
|
29
|
+
|
|
30
|
+
content_management_app = runner.get(ContentManagementApplication)
|
|
31
|
+
search_index_app = runner.get(SearchIndexApplication)
|
|
32
|
+
|
|
33
|
+
# Set user_id context variable.
|
|
34
|
+
user_id = uuid4()
|
|
35
|
+
user_id_cvar.set(user_id)
|
|
36
|
+
|
|
37
|
+
# Create empty pages.
|
|
38
|
+
content_management_app.create_page(title="Animals", slug="animals")
|
|
39
|
+
content_management_app.create_page(title="Plants", slug="plants")
|
|
40
|
+
content_management_app.create_page(title="Minerals", slug="minerals")
|
|
41
|
+
|
|
42
|
+
# Search, expect no results.
|
|
43
|
+
self.assertEqual(0, len(search_index_app.search("cat")))
|
|
44
|
+
self.assertEqual(0, len(search_index_app.search("rose")))
|
|
45
|
+
self.assertEqual(0, len(search_index_app.search("calcium")))
|
|
46
|
+
|
|
47
|
+
# Update the pages.
|
|
48
|
+
content_management_app.update_body(slug="animals", body="cat")
|
|
49
|
+
content_management_app.update_body(slug="plants", body="rose")
|
|
50
|
+
content_management_app.update_body(slug="minerals", body="calcium")
|
|
51
|
+
|
|
52
|
+
# Search for single words.
|
|
53
|
+
page_ids = search_index_app.search("cat")
|
|
54
|
+
self.assertEqual(1, len(page_ids))
|
|
55
|
+
page = content_management_app.get_page_by_id(page_ids[0])
|
|
56
|
+
self.assertEqual(page["slug"], "animals")
|
|
57
|
+
self.assertEqual(page["body"], "cat")
|
|
58
|
+
|
|
59
|
+
page_ids = search_index_app.search("rose")
|
|
60
|
+
self.assertEqual(1, len(page_ids))
|
|
61
|
+
page = content_management_app.get_page_by_id(page_ids[0])
|
|
62
|
+
self.assertEqual(page["slug"], "plants")
|
|
63
|
+
self.assertEqual(page["body"], "rose")
|
|
64
|
+
|
|
65
|
+
page_ids = search_index_app.search("calcium")
|
|
66
|
+
self.assertEqual(1, len(page_ids))
|
|
67
|
+
page = content_management_app.get_page_by_id(page_ids[0])
|
|
68
|
+
self.assertEqual(page["slug"], "minerals")
|
|
69
|
+
self.assertEqual(page["body"], "calcium")
|
|
70
|
+
|
|
71
|
+
self.assertEqual(len(search_index_app.search("dog")), 0)
|
|
72
|
+
self.assertEqual(len(search_index_app.search("bluebell")), 0)
|
|
73
|
+
self.assertEqual(len(search_index_app.search("zinc")), 0)
|
|
74
|
+
|
|
75
|
+
# Update the pages again.
|
|
76
|
+
content_management_app.update_body(slug="animals", body="cat dog zebra")
|
|
77
|
+
content_management_app.update_body(
|
|
78
|
+
slug="plants", body="bluebell rose jasmine"
|
|
79
|
+
)
|
|
80
|
+
content_management_app.update_body(
|
|
81
|
+
slug="minerals", body="iron zinc calcium"
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
# Search for single words.
|
|
85
|
+
page_ids = search_index_app.search("cat")
|
|
86
|
+
self.assertEqual(1, len(page_ids))
|
|
87
|
+
page = content_management_app.get_page_by_id(page_ids[0])
|
|
88
|
+
self.assertEqual(page["slug"], "animals")
|
|
89
|
+
self.assertEqual(page["body"], "cat dog zebra")
|
|
90
|
+
|
|
91
|
+
page_ids = search_index_app.search("rose")
|
|
92
|
+
self.assertEqual(1, len(page_ids))
|
|
93
|
+
page = content_management_app.get_page_by_id(page_ids[0])
|
|
94
|
+
self.assertEqual(page["slug"], "plants")
|
|
95
|
+
self.assertEqual(page["body"], "bluebell rose jasmine")
|
|
96
|
+
|
|
97
|
+
page_ids = search_index_app.search("calcium")
|
|
98
|
+
self.assertEqual(1, len(page_ids))
|
|
99
|
+
page = content_management_app.get_page_by_id(page_ids[0])
|
|
100
|
+
self.assertEqual(page["slug"], "minerals")
|
|
101
|
+
self.assertEqual(page["body"], "iron zinc calcium")
|
|
102
|
+
|
|
103
|
+
page_ids = search_index_app.search("dog")
|
|
104
|
+
self.assertEqual(1, len(page_ids))
|
|
105
|
+
page = content_management_app.get_page_by_id(page_ids[0])
|
|
106
|
+
self.assertEqual(page["slug"], "animals")
|
|
107
|
+
self.assertEqual(page["body"], "cat dog zebra")
|
|
108
|
+
|
|
109
|
+
page_ids = search_index_app.search("bluebell")
|
|
110
|
+
self.assertEqual(1, len(page_ids))
|
|
111
|
+
page = content_management_app.get_page_by_id(page_ids[0])
|
|
112
|
+
self.assertEqual(page["slug"], "plants")
|
|
113
|
+
self.assertEqual(page["body"], "bluebell rose jasmine")
|
|
114
|
+
|
|
115
|
+
page_ids = search_index_app.search("zinc")
|
|
116
|
+
self.assertEqual(1, len(page_ids))
|
|
117
|
+
page = content_management_app.get_page_by_id(page_ids[0])
|
|
118
|
+
self.assertEqual(page["slug"], "minerals")
|
|
119
|
+
self.assertEqual(page["body"], "iron zinc calcium")
|
|
120
|
+
|
|
121
|
+
# Search for multiple words in same page.
|
|
122
|
+
page_ids = search_index_app.search("dog cat")
|
|
123
|
+
self.assertEqual(1, len(page_ids))
|
|
124
|
+
page = content_management_app.get_page_by_id(page_ids[0])
|
|
125
|
+
self.assertEqual(page["slug"], "animals")
|
|
126
|
+
self.assertEqual(page["body"], "cat dog zebra")
|
|
127
|
+
|
|
128
|
+
# Search for multiple words in same page, expect no results.
|
|
129
|
+
page_ids = search_index_app.search("rose zebra")
|
|
130
|
+
self.assertEqual(0, len(page_ids))
|
|
131
|
+
|
|
132
|
+
# Search for alternative words, expect two results.
|
|
133
|
+
page_ids = search_index_app.search("rose OR zebra")
|
|
134
|
+
pages = [
|
|
135
|
+
content_management_app.get_page_by_id(page_id) for page_id in page_ids
|
|
136
|
+
]
|
|
137
|
+
self.assertEqual(2, len(pages))
|
|
138
|
+
self.assertEqual(["animals", "plants"], sorted(p["slug"] for p in pages))
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
class TestWithSQLite(ContentManagementSystemTestCase):
|
|
142
|
+
env: ClassVar[Dict[str, str]] = {
|
|
143
|
+
"PERSISTENCE_MODULE": "eventsourcing.examples.contentmanagementsystem.sqlite",
|
|
144
|
+
"SQLITE_DBNAME": ":memory:",
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
class TestWithPostgres(ContentManagementSystemTestCase):
|
|
149
|
+
env: ClassVar[Dict[str, str]] = {
|
|
150
|
+
"PERSISTENCE_MODULE": "eventsourcing.examples.contentmanagementsystem.postgres",
|
|
151
|
+
"POSTGRES_DBNAME": "eventsourcing",
|
|
152
|
+
"POSTGRES_HOST": "127.0.0.1",
|
|
153
|
+
"POSTGRES_PORT": "5432",
|
|
154
|
+
"POSTGRES_USER": "eventsourcing",
|
|
155
|
+
"POSTGRES_PASSWORD": "eventsourcing",
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
def setUp(self) -> None:
|
|
159
|
+
super().setUp()
|
|
160
|
+
self.drop_tables()
|
|
161
|
+
|
|
162
|
+
def tearDown(self) -> None:
|
|
163
|
+
self.drop_tables()
|
|
164
|
+
super().tearDown()
|
|
165
|
+
|
|
166
|
+
def drop_tables(self) -> None:
|
|
167
|
+
with PostgresDatastore(
|
|
168
|
+
self.env["POSTGRES_DBNAME"],
|
|
169
|
+
self.env["POSTGRES_HOST"],
|
|
170
|
+
self.env["POSTGRES_PORT"],
|
|
171
|
+
self.env["POSTGRES_USER"],
|
|
172
|
+
self.env["POSTGRES_PASSWORD"],
|
|
173
|
+
) as datastore:
|
|
174
|
+
drop_postgres_table(datastore, "public.contentmanagementapplication_events")
|
|
175
|
+
drop_postgres_table(datastore, "public.pages_projection_example")
|
|
176
|
+
drop_postgres_table(datastore, "public.searchindexapplication_events")
|
|
177
|
+
drop_postgres_table(datastore, "public.searchindexapplication_tracking")
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
del ContentManagementSystemTestCase
|
|
@@ -96,16 +96,15 @@ class TestWithPostgres(SearchableContentApplicationTestCase):
|
|
|
96
96
|
super().tearDown()
|
|
97
97
|
|
|
98
98
|
def drop_tables(self) -> None:
|
|
99
|
-
|
|
99
|
+
with PostgresDatastore(
|
|
100
100
|
os.environ["POSTGRES_DBNAME"],
|
|
101
101
|
os.environ["POSTGRES_HOST"],
|
|
102
102
|
os.environ["POSTGRES_PORT"],
|
|
103
103
|
os.environ["POSTGRES_USER"],
|
|
104
104
|
os.environ["POSTGRES_PASSWORD"],
|
|
105
|
-
)
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
db.close()
|
|
105
|
+
) as datastore:
|
|
106
|
+
drop_postgres_table(datastore, "public.searchablecontentapplication_events")
|
|
107
|
+
drop_postgres_table(datastore, "public.pages_projection_example")
|
|
109
108
|
|
|
110
109
|
|
|
111
110
|
del SearchableContentApplicationTestCase
|
|
@@ -54,16 +54,15 @@ class TestWithPostgres(SearchableContentRecorderTestCase):
|
|
|
54
54
|
super().tearDown()
|
|
55
55
|
|
|
56
56
|
def drop_tables(self) -> None:
|
|
57
|
-
|
|
57
|
+
with PostgresDatastore(
|
|
58
58
|
os.environ["POSTGRES_DBNAME"],
|
|
59
59
|
os.environ["POSTGRES_HOST"],
|
|
60
60
|
os.environ["POSTGRES_PORT"],
|
|
61
61
|
os.environ["POSTGRES_USER"],
|
|
62
62
|
os.environ["POSTGRES_PASSWORD"],
|
|
63
|
-
)
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
db.close()
|
|
63
|
+
) as datastore:
|
|
64
|
+
drop_postgres_table(datastore, "public.searchablecontentapplication_events")
|
|
65
|
+
drop_postgres_table(datastore, "public.pages_projection_example")
|
|
67
66
|
|
|
68
67
|
|
|
69
68
|
del SearchableContentRecorderTestCase
|
|
@@ -76,16 +76,19 @@ class WithPostgreSQL(SearchableTimestampsTestCase):
|
|
|
76
76
|
super().tearDown()
|
|
77
77
|
|
|
78
78
|
def drop_tables(self) -> None:
|
|
79
|
-
|
|
79
|
+
with PostgresDatastore(
|
|
80
80
|
os.environ["POSTGRES_DBNAME"],
|
|
81
81
|
os.environ["POSTGRES_HOST"],
|
|
82
82
|
os.environ["POSTGRES_PORT"],
|
|
83
83
|
os.environ["POSTGRES_USER"],
|
|
84
84
|
os.environ["POSTGRES_PASSWORD"],
|
|
85
|
-
)
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
85
|
+
) as datastore:
|
|
86
|
+
drop_postgres_table(
|
|
87
|
+
datastore, "public.searchabletimestampsapplication_events"
|
|
88
|
+
)
|
|
89
|
+
drop_postgres_table(
|
|
90
|
+
datastore, "public.searchabletimestampsapplication_timestamps"
|
|
91
|
+
)
|
|
89
92
|
|
|
90
93
|
|
|
91
94
|
del SearchableTimestampsTestCase
|
|
@@ -2,13 +2,14 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
import logging
|
|
4
4
|
from contextlib import contextmanager
|
|
5
|
-
from typing import TYPE_CHECKING, Any, Callable,
|
|
5
|
+
from typing import TYPE_CHECKING, Any, Callable, Iterator, List, Sequence
|
|
6
6
|
|
|
7
7
|
import psycopg
|
|
8
8
|
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
|
|
12
13
|
|
|
13
14
|
from eventsourcing.persistence import (
|
|
14
15
|
AggregateRecorder,
|
|
@@ -62,11 +63,11 @@ class PostgresDatastore:
|
|
|
62
63
|
user: str,
|
|
63
64
|
password: str,
|
|
64
65
|
*,
|
|
65
|
-
connect_timeout: int =
|
|
66
|
+
connect_timeout: int = 30,
|
|
66
67
|
idle_in_transaction_session_timeout: int = 0,
|
|
67
68
|
pool_size: int = 2,
|
|
68
69
|
max_overflow: int = 2,
|
|
69
|
-
|
|
70
|
+
max_waiting: int = 0,
|
|
70
71
|
conn_max_age: float = 60 * 60.0,
|
|
71
72
|
pre_ping: bool = False,
|
|
72
73
|
lock_timeout: int = 0,
|
|
@@ -79,7 +80,6 @@ class PostgresDatastore:
|
|
|
79
80
|
self.pool_open_timeout = pool_open_timeout
|
|
80
81
|
|
|
81
82
|
check = ConnectionPool.check_connection if pre_ping else None
|
|
82
|
-
kwargs: Dict[str, Any] = {"check": check}
|
|
83
83
|
self.pool = ConnectionPool(
|
|
84
84
|
get_password_func=get_password_func,
|
|
85
85
|
connection_class=Connection[DictRow],
|
|
@@ -96,9 +96,9 @@ class PostgresDatastore:
|
|
|
96
96
|
open=False,
|
|
97
97
|
configure=self.after_connect,
|
|
98
98
|
timeout=connect_timeout,
|
|
99
|
-
max_waiting=
|
|
99
|
+
max_waiting=max_waiting,
|
|
100
100
|
max_lifetime=conn_max_age,
|
|
101
|
-
|
|
101
|
+
check=check,
|
|
102
102
|
)
|
|
103
103
|
self.lock_timeout = lock_timeout
|
|
104
104
|
self.schema = schema.strip()
|
|
@@ -156,6 +156,12 @@ class PostgresDatastore:
|
|
|
156
156
|
def __del__(self) -> None:
|
|
157
157
|
self.close()
|
|
158
158
|
|
|
159
|
+
def __enter__(self) -> Self:
|
|
160
|
+
return self
|
|
161
|
+
|
|
162
|
+
def __exit__(self, *args: object, **kwargs: Any) -> None:
|
|
163
|
+
self.close()
|
|
164
|
+
|
|
159
165
|
|
|
160
166
|
class PostgresAggregateRecorder(AggregateRecorder):
|
|
161
167
|
def __init__(
|
|
@@ -558,10 +564,10 @@ class Factory(InfrastructureFactory):
|
|
|
558
564
|
POSTGRES_CONNECT_TIMEOUT = "POSTGRES_CONNECT_TIMEOUT"
|
|
559
565
|
POSTGRES_CONN_MAX_AGE = "POSTGRES_CONN_MAX_AGE"
|
|
560
566
|
POSTGRES_PRE_PING = "POSTGRES_PRE_PING"
|
|
561
|
-
|
|
567
|
+
POSTGRES_MAX_WAITING = "POSTGRES_MAX_WAITING"
|
|
562
568
|
POSTGRES_LOCK_TIMEOUT = "POSTGRES_LOCK_TIMEOUT"
|
|
563
569
|
POSTGRES_POOL_SIZE = "POSTGRES_POOL_SIZE"
|
|
564
|
-
|
|
570
|
+
POSTGRES_MAX_OVERFLOW = "POSTGRES_MAX_OVERFLOW"
|
|
565
571
|
POSTGRES_IDLE_IN_TRANSACTION_SESSION_TIMEOUT = (
|
|
566
572
|
"POSTGRES_IDLE_IN_TRANSACTION_SESSION_TIMEOUT"
|
|
567
573
|
)
|
|
@@ -618,7 +624,7 @@ class Factory(InfrastructureFactory):
|
|
|
618
624
|
get_password_func = resolve_topic(get_password_topic)
|
|
619
625
|
password = ""
|
|
620
626
|
|
|
621
|
-
connect_timeout =
|
|
627
|
+
connect_timeout = 30
|
|
622
628
|
connect_timeout_str = self.env.get(self.POSTGRES_CONNECT_TIMEOUT)
|
|
623
629
|
if connect_timeout_str:
|
|
624
630
|
try:
|
|
@@ -664,30 +670,30 @@ class Factory(InfrastructureFactory):
|
|
|
664
670
|
raise OSError(msg) from None
|
|
665
671
|
|
|
666
672
|
pool_max_overflow = 10
|
|
667
|
-
pool_max_overflow_str = self.env.get(self.
|
|
673
|
+
pool_max_overflow_str = self.env.get(self.POSTGRES_MAX_OVERFLOW)
|
|
668
674
|
if pool_max_overflow_str:
|
|
669
675
|
try:
|
|
670
676
|
pool_max_overflow = int(pool_max_overflow_str)
|
|
671
677
|
except ValueError:
|
|
672
678
|
msg = (
|
|
673
679
|
"Postgres environment value for key "
|
|
674
|
-
f"'{self.
|
|
680
|
+
f"'{self.POSTGRES_MAX_OVERFLOW}' is invalid. "
|
|
675
681
|
"If set, an integer or empty string is expected: "
|
|
676
682
|
f"'{pool_max_overflow_str}'"
|
|
677
683
|
)
|
|
678
684
|
raise OSError(msg) from None
|
|
679
685
|
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
if
|
|
686
|
+
max_waiting = 0
|
|
687
|
+
max_waiting_str = self.env.get(self.POSTGRES_MAX_WAITING)
|
|
688
|
+
if max_waiting_str:
|
|
683
689
|
try:
|
|
684
|
-
|
|
690
|
+
max_waiting = int(max_waiting_str)
|
|
685
691
|
except ValueError:
|
|
686
692
|
msg = (
|
|
687
693
|
"Postgres environment value for key "
|
|
688
|
-
f"'{self.
|
|
689
|
-
"If set,
|
|
690
|
-
f"'{
|
|
694
|
+
f"'{self.POSTGRES_MAX_WAITING}' is invalid. "
|
|
695
|
+
"If set, an integer or empty string is expected: "
|
|
696
|
+
f"'{max_waiting_str}'"
|
|
691
697
|
)
|
|
692
698
|
raise OSError(msg) from None
|
|
693
699
|
|
|
@@ -733,13 +739,16 @@ class Factory(InfrastructureFactory):
|
|
|
733
739
|
idle_in_transaction_session_timeout=idle_in_transaction_session_timeout,
|
|
734
740
|
pool_size=pool_size,
|
|
735
741
|
max_overflow=pool_max_overflow,
|
|
736
|
-
|
|
742
|
+
max_waiting=max_waiting,
|
|
737
743
|
conn_max_age=conn_max_age,
|
|
738
744
|
pre_ping=pre_ping,
|
|
739
745
|
lock_timeout=lock_timeout,
|
|
740
746
|
schema=schema,
|
|
741
747
|
)
|
|
742
748
|
|
|
749
|
+
def env_create_table(self) -> bool:
|
|
750
|
+
return strtobool(self.env.get(self.CREATE_TABLE) or "yes")
|
|
751
|
+
|
|
743
752
|
def aggregate_recorder(self, purpose: str = "events") -> AggregateRecorder:
|
|
744
753
|
prefix = self.env.name.lower() or "stored"
|
|
745
754
|
events_table_name = prefix + "_" + purpose
|
|
@@ -783,9 +792,6 @@ class Factory(InfrastructureFactory):
|
|
|
783
792
|
recorder.create_table()
|
|
784
793
|
return recorder
|
|
785
794
|
|
|
786
|
-
def env_create_table(self) -> bool:
|
|
787
|
-
return strtobool(self.env.get(self.CREATE_TABLE) or "yes")
|
|
788
|
-
|
|
789
795
|
def close(self) -> None:
|
|
790
796
|
if hasattr(self, "datastore"):
|
|
791
797
|
self.datastore.close()
|
|
@@ -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
|
+
Any,
|
|
11
12
|
ClassVar,
|
|
12
13
|
Dict,
|
|
13
14
|
Iterable,
|
|
@@ -21,6 +22,8 @@ from typing import (
|
|
|
21
22
|
cast,
|
|
22
23
|
)
|
|
23
24
|
|
|
25
|
+
from typing_extensions import Self
|
|
26
|
+
|
|
24
27
|
from eventsourcing.application import (
|
|
25
28
|
Application,
|
|
26
29
|
NotificationLog,
|
|
@@ -525,6 +528,13 @@ class SingleThreadedRunner(Runner, RecordingEventReceiver):
|
|
|
525
528
|
assert isinstance(app, cls)
|
|
526
529
|
return app
|
|
527
530
|
|
|
531
|
+
def __enter__(self) -> Self:
|
|
532
|
+
self.start()
|
|
533
|
+
return self
|
|
534
|
+
|
|
535
|
+
def __exit__(self, *args: object, **kwargs: Any) -> None:
|
|
536
|
+
self.stop()
|
|
537
|
+
|
|
528
538
|
|
|
529
539
|
class NewSingleThreadedRunner(Runner, RecordingEventReceiver):
|
|
530
540
|
"""
|
|
@@ -20,32 +20,32 @@ class TestDocs(TestCase):
|
|
|
20
20
|
super().setUp()
|
|
21
21
|
self.uris = tmpfile_uris()
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
with PostgresDatastore(
|
|
24
24
|
"eventsourcing",
|
|
25
25
|
"127.0.0.1",
|
|
26
26
|
"5432",
|
|
27
27
|
"eventsourcing",
|
|
28
28
|
"eventsourcing",
|
|
29
|
-
)
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
29
|
+
) as datastore:
|
|
30
|
+
drop_postgres_table(datastore, "dogschool_events")
|
|
31
|
+
drop_postgres_table(datastore, "counters_events")
|
|
32
|
+
drop_postgres_table(datastore, "counters_tracking")
|
|
33
33
|
|
|
34
34
|
def tearDown(self) -> None:
|
|
35
35
|
self.clean_env()
|
|
36
36
|
|
|
37
37
|
def clean_env(self):
|
|
38
38
|
clear_topic_cache()
|
|
39
|
-
|
|
39
|
+
with PostgresDatastore(
|
|
40
40
|
"eventsourcing",
|
|
41
41
|
"127.0.0.1",
|
|
42
42
|
"5432",
|
|
43
43
|
"eventsourcing",
|
|
44
44
|
"eventsourcing",
|
|
45
|
-
)
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
45
|
+
) as datastore:
|
|
46
|
+
drop_postgres_table(datastore, "dogschool_events")
|
|
47
|
+
drop_postgres_table(datastore, "counters_events")
|
|
48
|
+
drop_postgres_table(datastore, "counters_tracking")
|
|
49
49
|
|
|
50
50
|
keys = [
|
|
51
51
|
"PERSISTENCE_MODULE",
|