kurrentdbclient 0.4__tar.gz → 1.0__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.
- {kurrentdbclient-0.4 → kurrentdbclient-1.0}/LICENSE +1 -1
- kurrentdbclient-0.4/README.md → kurrentdbclient-1.0/PKG-INFO +172 -61
- kurrentdbclient-0.4/PKG-INFO → kurrentdbclient-1.0/README.md +142 -91
- {kurrentdbclient-0.4 → kurrentdbclient-1.0}/kurrentdbclient/__init__.py +1 -5
- {kurrentdbclient-0.4 → kurrentdbclient-1.0}/kurrentdbclient/asyncio_client.py +433 -395
- {kurrentdbclient-0.4 → kurrentdbclient-1.0}/kurrentdbclient/client.py +492 -435
- {kurrentdbclient-0.4 → kurrentdbclient-1.0}/kurrentdbclient/common.py +113 -105
- {kurrentdbclient-0.4 → kurrentdbclient-1.0}/kurrentdbclient/connection.py +0 -2
- kurrentdbclient-1.0/kurrentdbclient/connection_spec.py +374 -0
- {kurrentdbclient-0.4 → kurrentdbclient-1.0}/kurrentdbclient/events.py +12 -10
- {kurrentdbclient-0.4 → kurrentdbclient-1.0}/kurrentdbclient/exceptions.py +34 -39
- {kurrentdbclient-0.4 → kurrentdbclient-1.0}/kurrentdbclient/gossip.py +15 -10
- {kurrentdbclient-0.4 → kurrentdbclient-1.0}/kurrentdbclient/instrumentation/opentelemetry/__init__.py +5 -4
- {kurrentdbclient-0.4 → kurrentdbclient-1.0}/kurrentdbclient/instrumentation/opentelemetry/attributes.py +0 -2
- {kurrentdbclient-0.4 → kurrentdbclient-1.0}/kurrentdbclient/instrumentation/opentelemetry/grpc.py +12 -12
- kurrentdbclient-1.0/kurrentdbclient/instrumentation/opentelemetry/package.py +1 -0
- {kurrentdbclient-0.4 → kurrentdbclient-1.0}/kurrentdbclient/instrumentation/opentelemetry/spanners.py +80 -81
- {kurrentdbclient-0.4 → kurrentdbclient-1.0}/kurrentdbclient/instrumentation/opentelemetry/utils.py +16 -17
- kurrentdbclient-1.0/kurrentdbclient/instrumentation/opentelemetry/version.py +1 -0
- {kurrentdbclient-0.4 → kurrentdbclient-1.0}/kurrentdbclient/persistent.py +521 -530
- {kurrentdbclient-0.4 → kurrentdbclient-1.0}/kurrentdbclient/projections.py +164 -86
- {kurrentdbclient-0.4 → kurrentdbclient-1.0}/kurrentdbclient/protos/Grpc/cluster_pb2.py +3 -3
- {kurrentdbclient-0.4 → kurrentdbclient-1.0}/kurrentdbclient/protos/Grpc/cluster_pb2_grpc.py +1 -1
- {kurrentdbclient-0.4 → kurrentdbclient-1.0}/kurrentdbclient/protos/Grpc/code_pb2.py +3 -3
- {kurrentdbclient-0.4 → kurrentdbclient-1.0}/kurrentdbclient/protos/Grpc/code_pb2_grpc.py +1 -1
- {kurrentdbclient-0.4 → kurrentdbclient-1.0}/kurrentdbclient/protos/Grpc/gossip_pb2.py +3 -3
- {kurrentdbclient-0.4 → kurrentdbclient-1.0}/kurrentdbclient/protos/Grpc/gossip_pb2_grpc.py +1 -1
- {kurrentdbclient-0.4 → kurrentdbclient-1.0}/kurrentdbclient/protos/Grpc/persistent_pb2.py +3 -3
- {kurrentdbclient-0.4 → kurrentdbclient-1.0}/kurrentdbclient/protos/Grpc/persistent_pb2_grpc.py +1 -1
- {kurrentdbclient-0.4 → kurrentdbclient-1.0}/kurrentdbclient/protos/Grpc/projections_pb2.py +3 -3
- {kurrentdbclient-0.4 → kurrentdbclient-1.0}/kurrentdbclient/protos/Grpc/projections_pb2_grpc.py +1 -1
- {kurrentdbclient-0.4 → kurrentdbclient-1.0}/kurrentdbclient/protos/Grpc/shared_pb2.py +3 -3
- {kurrentdbclient-0.4 → kurrentdbclient-1.0}/kurrentdbclient/protos/Grpc/shared_pb2_grpc.py +1 -1
- {kurrentdbclient-0.4 → kurrentdbclient-1.0}/kurrentdbclient/protos/Grpc/status_pb2.py +3 -3
- {kurrentdbclient-0.4 → kurrentdbclient-1.0}/kurrentdbclient/protos/Grpc/status_pb2_grpc.py +1 -1
- {kurrentdbclient-0.4 → kurrentdbclient-1.0}/kurrentdbclient/protos/Grpc/streams_pb2.py +3 -3
- {kurrentdbclient-0.4 → kurrentdbclient-1.0}/kurrentdbclient/protos/Grpc/streams_pb2_grpc.py +1 -1
- {kurrentdbclient-0.4 → kurrentdbclient-1.0}/kurrentdbclient/streams.py +270 -320
- kurrentdbclient-1.0/pyproject.toml +239 -0
- kurrentdbclient-0.4/kurrentdbclient/connection_spec.py +0 -371
- kurrentdbclient-0.4/kurrentdbclient/instrumentation/opentelemetry/package.py +0 -2
- kurrentdbclient-0.4/kurrentdbclient/instrumentation/opentelemetry/version.py +0 -2
- kurrentdbclient-0.4/pyproject.toml +0 -128
- {kurrentdbclient-0.4 → kurrentdbclient-1.0}/kurrentdbclient/instrumentation/__init__.py +0 -0
- {kurrentdbclient-0.4 → kurrentdbclient-1.0}/kurrentdbclient/protos/Grpc/cluster_pb2.pyi +0 -0
- {kurrentdbclient-0.4 → kurrentdbclient-1.0}/kurrentdbclient/protos/Grpc/code_pb2.pyi +0 -0
- {kurrentdbclient-0.4 → kurrentdbclient-1.0}/kurrentdbclient/protos/Grpc/gossip_pb2.pyi +0 -0
- {kurrentdbclient-0.4 → kurrentdbclient-1.0}/kurrentdbclient/protos/Grpc/persistent_pb2.pyi +0 -0
- {kurrentdbclient-0.4 → kurrentdbclient-1.0}/kurrentdbclient/protos/Grpc/projections_pb2.pyi +0 -0
- {kurrentdbclient-0.4 → kurrentdbclient-1.0}/kurrentdbclient/protos/Grpc/shared_pb2.pyi +0 -0
- {kurrentdbclient-0.4 → kurrentdbclient-1.0}/kurrentdbclient/protos/Grpc/status_pb2.pyi +0 -0
- {kurrentdbclient-0.4 → kurrentdbclient-1.0}/kurrentdbclient/protos/Grpc/streams_pb2.pyi +0 -0
- {kurrentdbclient-0.4 → kurrentdbclient-1.0}/kurrentdbclient/py.typed +0 -0
|
@@ -1,3 +1,42 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: kurrentdbclient
|
|
3
|
+
Version: 1.0
|
|
4
|
+
Summary: Python gRPC Client for KurrentDB
|
|
5
|
+
License: BSD 3-Clause
|
|
6
|
+
Author: John Bywater
|
|
7
|
+
Author-email: john.bywater@appropriatesoftware.net
|
|
8
|
+
Requires-Python: >=3.9,<4.0
|
|
9
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
10
|
+
Classifier: License :: OSI Approved :: BSD License
|
|
11
|
+
Classifier: License :: Other/Proprietary License
|
|
12
|
+
Classifier: Programming Language :: Python
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Provides-Extra: opentelemetry
|
|
20
|
+
Requires-Dist: grpcio[protobuf] (>=1.71.0,<1.72)
|
|
21
|
+
Requires-Dist: opentelemetry-api (>=1.28.0,<2.0.0) ; extra == "opentelemetry"
|
|
22
|
+
Requires-Dist: opentelemetry-instrumentation (>=0.49b0,<0.50) ; extra == "opentelemetry"
|
|
23
|
+
Requires-Dist: opentelemetry-semantic-conventions (>=0.49b0,<0.50) ; extra == "opentelemetry"
|
|
24
|
+
Requires-Dist: typing_extensions
|
|
25
|
+
Project-URL: Homepage, https://github.com/pyeventsourcing/kurrentdbclient
|
|
26
|
+
Project-URL: Repository, https://github.com/pyeventsourcing/kurrentdbclient
|
|
27
|
+
Description-Content-Type: text/markdown
|
|
28
|
+
|
|
29
|
+
<a href="https://kurrent.io">
|
|
30
|
+
<picture>
|
|
31
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://github.com/pyeventsourcing/kurrentdbclient/raw/1.0/KurrentLogo-White.png.png">
|
|
32
|
+
<source media="(prefers-color-scheme: light)" srcset="https://github.com/pyeventsourcing/kurrentdbclient/raw/1.0/KurrentLogo-Black.png">
|
|
33
|
+
<img alt="Kurrent" src="https://github.com/pyeventsourcing/kurrentdbclient/raw/1.0/KurrentLogo-Plum.png" height="50%" width="50%">
|
|
34
|
+
</picture>
|
|
35
|
+
</a>
|
|
36
|
+
|
|
37
|
+
Please note: following the rebranding of EventStoreDB to KurrentDB, this package
|
|
38
|
+
is a rebranding of the [`esdbclient`](https://pypi.org/project/esdbclient) package.
|
|
39
|
+
|
|
1
40
|
# Python gRPC Client for KurrentDB
|
|
2
41
|
|
|
3
42
|
This [Python package](https://pypi.org/project/kurrentdbclient/) provides multithreaded and asyncio Python
|
|
@@ -7,18 +46,18 @@ The multithreaded `KurrentDBClient` is described in detail below. Please scroll
|
|
|
7
46
|
down for <a href="#asyncio-client">information</a> about `AsyncKurrentDBClient`.
|
|
8
47
|
|
|
9
48
|
These clients have been developed and are being maintained in a collaboration
|
|
10
|
-
with the KurrentDB team, and are officially
|
|
49
|
+
with the KurrentDB team, and are officially supported by Kurrent Inc.
|
|
11
50
|
Although not all aspects of the KurrentDB gRPC API are implemented, most
|
|
12
51
|
features are presented in an easy-to-use interface.
|
|
13
52
|
|
|
14
|
-
These clients have been tested to work with KurrentDB
|
|
15
|
-
|
|
16
|
-
|
|
53
|
+
These clients have been tested to work with KurrentDB 25.0.0, without and without
|
|
54
|
+
SSL/TLS, with both single-server and cluster modes, and with Python versions
|
|
55
|
+
3.9, 3.10, 3.11, 3.12, and 3.13.
|
|
17
56
|
|
|
18
57
|
The test suite has 100% line and branch coverage. The code has typing annotations
|
|
19
58
|
checked strictly with mypy. The code is formatted with black and isort, and checked
|
|
20
59
|
with flake8. Poetry is used for package management during development, and for
|
|
21
|
-
building and publishing distributions to [PyPI](https://pypi.org/project/
|
|
60
|
+
building and publishing distributions to [PyPI](https://pypi.org/project/kurrentdbclient/).
|
|
22
61
|
|
|
23
62
|
For an example of usage, see the [eventsourcing-eventstoredb](
|
|
24
63
|
https://github.com/pyeventsourcing/eventsourcing-eventstoredb) package.
|
|
@@ -75,10 +114,13 @@ https://github.com/pyeventsourcing/eventsourcing-eventstoredb) package.
|
|
|
75
114
|
* [Projections](#projections)
|
|
76
115
|
* [Create projection](#create-projection)
|
|
77
116
|
* [Get projection state](#get-projection-state)
|
|
78
|
-
* [Get projection statistics](#get-projection-statistics)
|
|
79
117
|
* [Update projection](#update-projection)
|
|
80
|
-
* [
|
|
118
|
+
* [Get projection statistics](#get-projection-statistics)
|
|
119
|
+
* [List all projection statistics](#list-all-projection-statistics)
|
|
120
|
+
* [List continuous projection statistics](#list-continuous-projection-statistics)
|
|
81
121
|
* [Disable projection](#disable-projection)
|
|
122
|
+
* [Enable projection](#enable-projection)
|
|
123
|
+
* [Abort projection](#abort-projection)
|
|
82
124
|
* [Reset projection](#reset-projection)
|
|
83
125
|
* [Delete projection](#delete-projection)
|
|
84
126
|
* [Restart projections subsystem](#restart-projections-subsystem)
|
|
@@ -130,7 +172,7 @@ import uuid
|
|
|
130
172
|
|
|
131
173
|
from kurrentdbclient import KurrentDBClient, NewEvent, StreamState
|
|
132
174
|
|
|
133
|
-
# Construct KurrentDBClient with
|
|
175
|
+
# Construct KurrentDBClient with a KurrentDB URI. The
|
|
134
176
|
# connection string URI specifies that the client should
|
|
135
177
|
# connect to an "insecure" server running on port 2113.
|
|
136
178
|
|
|
@@ -176,7 +218,7 @@ commit_position1 = client.append_to_stream(
|
|
|
176
218
|
# Append events to an existing stream. The "current version"
|
|
177
219
|
# is the "stream position" of the last recorded event in a
|
|
178
220
|
# stream. We have recorded two new events, so the "current
|
|
179
|
-
# version" is 1. The exception '
|
|
221
|
+
# version" is 1. The exception 'WrongCurrentVersionError' will be
|
|
180
222
|
# raised if an incorrect value is given.
|
|
181
223
|
|
|
182
224
|
commit_position2 = client.append_to_stream(
|
|
@@ -287,9 +329,9 @@ The KurrentDB server can be run locally using the official Docker container imag
|
|
|
287
329
|
|
|
288
330
|
For development, you can run a "secure" KurrentDB server using the following command.
|
|
289
331
|
|
|
290
|
-
$ docker run -d --name kurrentdb-secure -it -p 2113:2113 --env "HOME=/tmp" docker.eventstore.com/
|
|
332
|
+
$ docker run -d --name kurrentdb-secure -it -p 2113:2113 --env "HOME=/tmp" docker.eventstore.com/kurrent-latest/kurrentdb:25.0.0-x64-8.0-bookworm-slim --dev
|
|
291
333
|
|
|
292
|
-
As we will see, your client will need
|
|
334
|
+
As we will see, your client will need a KurrentDB connection string URI as the value
|
|
293
335
|
of its `uri` constructor argument. The connection string for this "secure" KurrentDB
|
|
294
336
|
server would be:
|
|
295
337
|
|
|
@@ -317,7 +359,7 @@ server_certificate = ssl.get_server_certificate(addr=('localhost', 2113))
|
|
|
317
359
|
|
|
318
360
|
Alternatively, you can start an "insecure" server using the following command.
|
|
319
361
|
|
|
320
|
-
$ docker run -d --name kurrentdb-insecure -it -p 2113:2113 docker.eventstore.com/
|
|
362
|
+
$ docker run -d --name kurrentdb-insecure -it -p 2113:2113 docker.eventstore.com/kurrent-latest/kurrentdb:25.0.0-x64-8.0-bookworm-slim --insecure
|
|
321
363
|
|
|
322
364
|
The connection string URI for this "insecure" server would be:
|
|
323
365
|
|
|
@@ -361,7 +403,7 @@ from kurrentdbclient import KurrentDBClient
|
|
|
361
403
|
The `KurrentDBClient` class has one required constructor argument, `uri`, and three
|
|
362
404
|
optional constructor argument, `root_certificates`, `private_key`, and `certificate_chain`.
|
|
363
405
|
|
|
364
|
-
The `uri` argument is expected to be
|
|
406
|
+
The `uri` argument is expected to be a KurrentDB connection string URI that
|
|
365
407
|
conforms with the standard KurrentDB "kdb" or "kdb+discover" URI schemes.
|
|
366
408
|
|
|
367
409
|
The client must be configured to create a "secure" connection to a "secure" server,
|
|
@@ -412,7 +454,7 @@ client = KurrentDBClient(
|
|
|
412
454
|
|
|
413
455
|
## Connection strings<a id="connection-strings"></a>
|
|
414
456
|
|
|
415
|
-
|
|
457
|
+
A KurrentDB connection string is a URI that conforms with one of two possible
|
|
416
458
|
schemes: either the "kdb" scheme, or the "kdb+discover" scheme.
|
|
417
459
|
|
|
418
460
|
The syntax and semantics of the KurrentDB URI schemes are described below. The
|
|
@@ -432,7 +474,7 @@ In the "kdb" URI scheme, after the optional user info string, there must be at l
|
|
|
432
474
|
one gRPC target. If there are several gRPC targets, they must be separated from each
|
|
433
475
|
other with the "," character.
|
|
434
476
|
|
|
435
|
-
Each gRPC target should indicate
|
|
477
|
+
Each gRPC target should indicate a KurrentDB gRPC server socket, all in the same
|
|
436
478
|
KurrentDB cluster, by specifying a host and a port number separated with the ":"
|
|
437
479
|
character. The host may be a hostname that can be resolved to an IP address, or an IP
|
|
438
480
|
address.
|
|
@@ -548,13 +590,13 @@ Here are some examples of KurrentDB connection string URIs.
|
|
|
548
590
|
The following URI will cause the client to make an "insecure" connection to
|
|
549
591
|
gRPC target `'localhost:2113'`. Because the client's node preference is "follower",
|
|
550
592
|
methods that can be called on a follower should complete successfully, methods that
|
|
551
|
-
require a leader will raise a `
|
|
593
|
+
require a leader will raise a `NodeIsNotLeaderError` exception.
|
|
552
594
|
|
|
553
595
|
kdb://127.0.0.1:2113?Tls=false&NodePreference=follower
|
|
554
596
|
|
|
555
597
|
The following URI will cause the client to make an "insecure" connection to
|
|
556
598
|
gRPC target `'localhost:2113'`. Because the client's node preference is "leader",
|
|
557
|
-
if this node is not a leader, then a `
|
|
599
|
+
if this node is not a leader, then a `NodeIsNotLeaderError` exception will be raised by
|
|
558
600
|
all methods.
|
|
559
601
|
|
|
560
602
|
kdb://127.0.0.1:2113?Tls=false&NodePreference=leader
|
|
@@ -563,7 +605,7 @@ The following URI will cause the client to make a "secure" connection to
|
|
|
563
605
|
gRPC target `'localhost:2113'` with username `'admin'` and password `'changeit'`
|
|
564
606
|
as the default call credentials when making calls to the KurrentDB gRPC API.
|
|
565
607
|
Because the client's node preference is "leader", by default, if this node is not
|
|
566
|
-
a leader, then a `
|
|
608
|
+
a leader, then a `NodeIsNotLeaderError` exception will be raised by all methods.
|
|
567
609
|
|
|
568
610
|
kdb://admin:changeit@localhost:2113
|
|
569
611
|
|
|
@@ -611,7 +653,7 @@ This package defines a `NewEvent` class and a `RecordedEvent` class. The
|
|
|
611
653
|
|
|
612
654
|
### New events<a id="new-events"></a>
|
|
613
655
|
|
|
614
|
-
The `NewEvent` class should be used when writing events to
|
|
656
|
+
The `NewEvent` class should be used when writing events to a KurrentDB database.
|
|
615
657
|
You will need to construct new event objects before calling `append_to_stream()`.
|
|
616
658
|
|
|
617
659
|
The `NewEvent` class is a frozen Python dataclass. It has two required constructor
|
|
@@ -665,7 +707,7 @@ assert new_event2.id == event_id
|
|
|
665
707
|
|
|
666
708
|
### Recorded events<a id="recorded-events"></a>
|
|
667
709
|
|
|
668
|
-
The `RecordedEvent` class is used when reading events from
|
|
710
|
+
The `RecordedEvent` class is used when reading events from a KurrentDB
|
|
669
711
|
database. The client will return event objects of this type from all methods
|
|
670
712
|
that return recorded events, such as `get_stream()`, `subscribe_to_all()`,
|
|
671
713
|
and `read_subscription_to_all()`. You do not need to construct recorded event objects.
|
|
@@ -837,7 +879,7 @@ that indicates the stream position of the last recorded event in the stream, or
|
|
|
837
879
|
`StreamState.NO_STREAM` if the stream does not yet exist or has been deleted. The
|
|
838
880
|
stream positions are zero-based and gapless, so that if a stream has two events, the
|
|
839
881
|
`current_version` should be 1. If an incorrect value is given, this method will raise a
|
|
840
|
-
`
|
|
882
|
+
`WrongCurrentVersionError` exception. This behavior is designed to provide concurrency
|
|
841
883
|
control when recording new events. The correct value of `current_version` for any stream
|
|
842
884
|
can be obtained by calling `get_current_version()`. However, the typical approach is to
|
|
843
885
|
reconstruct an aggregate from the recorded events, so that the version of the aggregate
|
|
@@ -846,7 +888,7 @@ events, and then use the current version of the aggregate as the value of the
|
|
|
846
888
|
`current_version` argument when appending the new aggregate events. This ensures
|
|
847
889
|
the consistency of the recorded aggregate events, because operations that generate
|
|
848
890
|
new aggregate events can be retried with a freshly reconstructed aggregate if
|
|
849
|
-
a `
|
|
891
|
+
a `WrongCurrentVersionError` exception is encountered when recording new events. This
|
|
850
892
|
controlling behavior can be entirely disabled by setting the value of the `current_version`
|
|
851
893
|
argument to the constant `StreamState.ANY`. More selectively, this behaviour can be
|
|
852
894
|
disabled for existing streams by setting the value of the `current_version`
|
|
@@ -933,7 +975,7 @@ If the method call initially failed and the new events were not in fact recorded
|
|
|
933
975
|
makes good sense, when the method call is retried, that the new events are recorded
|
|
934
976
|
and that the method call returns successfully. If the concurrency controls have not been disabled,
|
|
935
977
|
that is if the `current version` is either `StreamState.NO_STREAM` or an integer value, and
|
|
936
|
-
if a `
|
|
978
|
+
if a `WrongCurrentVersionError` exception is raised when retrying the method call, then we can assume
|
|
937
979
|
both that the initial method call did not in fact successfully record the events, and also
|
|
938
980
|
that subsequent events have in the meantime been recorded by somebody else. In this case,
|
|
939
981
|
an application command which generated the new events may need to be executed again. And
|
|
@@ -947,7 +989,7 @@ can be sure the events have been recorded.
|
|
|
947
989
|
|
|
948
990
|
The example below shows the `append_to_stream()` method being called again with events
|
|
949
991
|
`event2` and `event3`, and with `current_version=0`. We can see that repeating the call
|
|
950
|
-
to `append_to_stream()` returns successfully without raising a `
|
|
992
|
+
to `append_to_stream()` returns successfully without raising a `WrongCurrentVersionError`
|
|
951
993
|
exception, as it would if the `append_to_stream()` operation were not idempotent.
|
|
952
994
|
|
|
953
995
|
```python
|
|
@@ -1115,15 +1157,15 @@ assert events[0] == event1
|
|
|
1115
1157
|
assert events[1] == event2
|
|
1116
1158
|
```
|
|
1117
1159
|
|
|
1118
|
-
The `read_stream()` and `get_stream()` methods will raise a `
|
|
1160
|
+
The `read_stream()` and `get_stream()` methods will raise a `NotFoundError` exception if the
|
|
1119
1161
|
named stream has never existed or has been deleted.
|
|
1120
1162
|
|
|
1121
1163
|
```python
|
|
1122
|
-
from kurrentdbclient.exceptions import
|
|
1164
|
+
from kurrentdbclient.exceptions import NotFoundError
|
|
1123
1165
|
|
|
1124
1166
|
try:
|
|
1125
1167
|
client.get_stream('does-not-exist')
|
|
1126
|
-
except
|
|
1168
|
+
except NotFoundError:
|
|
1127
1169
|
pass # The stream does not exist.
|
|
1128
1170
|
else:
|
|
1129
1171
|
raise Exception("Shouldn't get here")
|
|
@@ -1138,7 +1180,7 @@ when iterating over the "read response" starts, which means that the method retu
|
|
|
1138
1180
|
before the streaming starts, and so there is no chance for any decorators to catch
|
|
1139
1181
|
any connection issues.
|
|
1140
1182
|
|
|
1141
|
-
For the same reason, `read_stream()` will not raise a `
|
|
1183
|
+
For the same reason, `read_stream()` will not raise a `NotFoundError` exception when
|
|
1142
1184
|
the stream does not exist, until iterating over the "read response" object begins.
|
|
1143
1185
|
|
|
1144
1186
|
If you are reading a very large stream, then you might prefer to call `read_stream()`,
|
|
@@ -1203,10 +1245,10 @@ Event-sourced aggregates are typically reconstructed from recorded events by cal
|
|
|
1203
1245
|
a mutator function for each recorded event, evolving from an initial state
|
|
1204
1246
|
`None` to the current state of the aggregate. The function `get_aggregate()` shows
|
|
1205
1247
|
how this can be done. The aggregate ID is used as a stream name. The exception
|
|
1206
|
-
`
|
|
1248
|
+
`AggregateNotFoundError` is raised if the aggregate stream is not found.
|
|
1207
1249
|
|
|
1208
1250
|
```python
|
|
1209
|
-
class
|
|
1251
|
+
class AggregateNotFoundError(Exception):
|
|
1210
1252
|
"""Raised when an aggregate is not found."""
|
|
1211
1253
|
|
|
1212
1254
|
|
|
@@ -1219,8 +1261,8 @@ def get_aggregate(aggregate_id, mutator_func):
|
|
|
1219
1261
|
stream_name=stream_name,
|
|
1220
1262
|
stream_position=None
|
|
1221
1263
|
)
|
|
1222
|
-
except
|
|
1223
|
-
raise
|
|
1264
|
+
except NotFoundError as e:
|
|
1265
|
+
raise AggregateNotFoundError(aggregate_id) from e
|
|
1224
1266
|
else:
|
|
1225
1267
|
# Reconstruct aggregate from recorded events.
|
|
1226
1268
|
aggregate = None
|
|
@@ -1279,7 +1321,7 @@ def get_aggregate(aggregate_id, mutator_func):
|
|
|
1279
1321
|
backwards=True,
|
|
1280
1322
|
limit=1
|
|
1281
1323
|
)
|
|
1282
|
-
except
|
|
1324
|
+
except NotFoundError:
|
|
1283
1325
|
stream_position = None
|
|
1284
1326
|
else:
|
|
1285
1327
|
assert len(snapshots) == 1
|
|
@@ -1293,8 +1335,8 @@ def get_aggregate(aggregate_id, mutator_func):
|
|
|
1293
1335
|
stream_name=stream_name,
|
|
1294
1336
|
stream_position=stream_position
|
|
1295
1337
|
)
|
|
1296
|
-
except
|
|
1297
|
-
raise
|
|
1338
|
+
except NotFoundError as e:
|
|
1339
|
+
raise AggregateNotFoundError(aggregate_id) from e
|
|
1298
1340
|
else:
|
|
1299
1341
|
recorded_events += events
|
|
1300
1342
|
|
|
@@ -2267,7 +2309,7 @@ duration in seconds between recording "acknowledgements" (acks). The default val
|
|
|
2267
2309
|
|
|
2268
2310
|
The optional `max_subscriber_count` argument is a Python `int` which sets the maximum
|
|
2269
2311
|
number of concurrent readers of the persistent subscription, beyond which attempts to
|
|
2270
|
-
read the persistent subscription will raise a `
|
|
2312
|
+
read the persistent subscription will raise a `MaximumSubscriptionsReachedError` exception.
|
|
2271
2313
|
|
|
2272
2314
|
The optional `live_buffer_size` argument is a Python `int` which sets the size of the
|
|
2273
2315
|
buffer (in-memory) holding newly recorded events. The default value of `live_buffer_size`
|
|
@@ -2559,7 +2601,7 @@ duration in seconds between recording "acknowledgements" (acks). The default val
|
|
|
2559
2601
|
|
|
2560
2602
|
The optional `max_subscriber_count` argument is a Python `int` which sets the maximum
|
|
2561
2603
|
number of concurrent readers of the persistent subscription, beyond which attempts to
|
|
2562
|
-
read the persistent subscription will raise a `
|
|
2604
|
+
read the persistent subscription will raise a `MaximumSubscriptionsReachedError` exception.
|
|
2563
2605
|
|
|
2564
2606
|
The optional `live_buffer_size` argument is a Python `int` which sets the size of the
|
|
2565
2607
|
buffer (in-memory) holding newly recorded events. The default value of `live_buffer_size`
|
|
@@ -2992,6 +3034,41 @@ projection_state = client.get_projection_state(name=projection_name)
|
|
|
2992
3034
|
assert projection_state.value == {'count': 3}
|
|
2993
3035
|
```
|
|
2994
3036
|
|
|
3037
|
+
### Update projection<a id="update-projection"></a>
|
|
3038
|
+
|
|
3039
|
+
*requires leader*
|
|
3040
|
+
|
|
3041
|
+
The `update_projection()` method can be used to update a projection.
|
|
3042
|
+
|
|
3043
|
+
This method has two required arguments, `name` and `query`.
|
|
3044
|
+
|
|
3045
|
+
The required `name` argument is a Python `str` which specifies the name of the projection
|
|
3046
|
+
to be updated.
|
|
3047
|
+
|
|
3048
|
+
The required `query` argument is a Python `str` which defines what the projection will do.
|
|
3049
|
+
|
|
3050
|
+
This method also has three optional arguments, `emit_enabled`, `timeout`, and `credentials`.
|
|
3051
|
+
|
|
3052
|
+
The optional `emit_enabled` argument is a Python `bool` which specifies whether a
|
|
3053
|
+
projection will be able to emit events. If a `True` value is specified, the projection
|
|
3054
|
+
will be able to emit events. If a `False` value is specified, the projection will not
|
|
3055
|
+
be able to emit events. The default value of `emit_enabled` is `False`.
|
|
3056
|
+
|
|
3057
|
+
Please note, `emit_enabled` must be `True` if your projection query includes a call
|
|
3058
|
+
to `emit()`, otherwise the projection will not run.
|
|
3059
|
+
|
|
3060
|
+
Please note, it is not possible to update `track_emitted_streams` via the gRPC API.
|
|
3061
|
+
|
|
3062
|
+
The optional `timeout` argument is a Python `float` which sets a
|
|
3063
|
+
maximum duration, in seconds, for the completion of the gRPC operation.
|
|
3064
|
+
|
|
3065
|
+
The optional `credentials` argument can be used to
|
|
3066
|
+
override call credentials derived from the connection string URI.
|
|
3067
|
+
|
|
3068
|
+
```python
|
|
3069
|
+
client.update_projection(name=projection_name, query=projection_query)
|
|
3070
|
+
```
|
|
3071
|
+
|
|
2995
3072
|
### Get projection statistics<a id="get-projection-statistics"></a>
|
|
2996
3073
|
|
|
2997
3074
|
*requires leader*
|
|
@@ -3019,30 +3096,35 @@ statistics = client.get_projection_statistics(name=projection_name)
|
|
|
3019
3096
|
A `ProjectionStatistics` object is returned. The attributes of this object
|
|
3020
3097
|
have values that represent the progress of the projection.
|
|
3021
3098
|
|
|
3022
|
-
|
|
3099
|
+
|
|
3100
|
+
### List all projection statistics<a id="list-all-projection-statistics"></a>
|
|
3023
3101
|
|
|
3024
3102
|
*requires leader*
|
|
3025
3103
|
|
|
3026
|
-
The `
|
|
3104
|
+
The `list_all_projection_statistics()` method can be used to get a list of projection statistics for all projections.
|
|
3027
3105
|
|
|
3028
|
-
This method has two
|
|
3106
|
+
This method has two optional arguments, `timeout` and `credentials`.
|
|
3029
3107
|
|
|
3030
|
-
The
|
|
3031
|
-
|
|
3108
|
+
The optional `timeout` argument is a Python `float` which sets a
|
|
3109
|
+
maximum duration, in seconds, for the completion of the gRPC operation.
|
|
3032
3110
|
|
|
3033
|
-
The
|
|
3111
|
+
The optional `credentials` argument can be used to
|
|
3112
|
+
override call credentials derived from the connection string URI.
|
|
3034
3113
|
|
|
3035
|
-
This method
|
|
3114
|
+
This method returns a list of `ProjectionStatistics` objects that each represent
|
|
3115
|
+
a projection.
|
|
3036
3116
|
|
|
3037
|
-
|
|
3038
|
-
|
|
3039
|
-
|
|
3040
|
-
be able to emit events. The default value of `emit_enabled` is `False`.
|
|
3117
|
+
```python
|
|
3118
|
+
statistics = client.list_all_projection_statistics()
|
|
3119
|
+
```
|
|
3041
3120
|
|
|
3042
|
-
|
|
3043
|
-
to `emit()`, otherwise the projection will not run.
|
|
3121
|
+
### List continuous projection statistics<a id="list-continuous-projection-statistics"></a>
|
|
3044
3122
|
|
|
3045
|
-
|
|
3123
|
+
*requires leader*
|
|
3124
|
+
|
|
3125
|
+
The `list_continuous_projection_statistics()` method can be used to get a list of projection statistics for all continuous projections.
|
|
3126
|
+
|
|
3127
|
+
This method has two optional arguments, `timeout` and `credentials`.
|
|
3046
3128
|
|
|
3047
3129
|
The optional `timeout` argument is a Python `float` which sets a
|
|
3048
3130
|
maximum duration, in seconds, for the completion of the gRPC operation.
|
|
@@ -3050,8 +3132,33 @@ maximum duration, in seconds, for the completion of the gRPC operation.
|
|
|
3050
3132
|
The optional `credentials` argument can be used to
|
|
3051
3133
|
override call credentials derived from the connection string URI.
|
|
3052
3134
|
|
|
3135
|
+
This method returns a list of `ProjectionStatistics` objects that each represent
|
|
3136
|
+
a projection.
|
|
3137
|
+
|
|
3053
3138
|
```python
|
|
3054
|
-
client.
|
|
3139
|
+
statistics = client.list_continuous_projection_statistics()
|
|
3140
|
+
```
|
|
3141
|
+
|
|
3142
|
+
### Disable projection<a id="disable-projection"></a>
|
|
3143
|
+
|
|
3144
|
+
*requires leader*
|
|
3145
|
+
|
|
3146
|
+
The `disable_projection()` method can be used to disable (stop running) a projection.
|
|
3147
|
+
When a projection is stopped using this method, a checkpoint will be written.
|
|
3148
|
+
|
|
3149
|
+
This method has a required `name` argument, which is a Python `str` that
|
|
3150
|
+
specifies the name of the projection to be disabled.
|
|
3151
|
+
|
|
3152
|
+
This method also has two optional arguments, `timeout`, and `credentials`.
|
|
3153
|
+
|
|
3154
|
+
The optional `timeout` argument is a Python `float` which sets a
|
|
3155
|
+
maximum duration, in seconds, for the completion of the gRPC operation.
|
|
3156
|
+
|
|
3157
|
+
The optional `credentials` argument can be used to
|
|
3158
|
+
override call credentials derived from the connection string URI.
|
|
3159
|
+
|
|
3160
|
+
```python
|
|
3161
|
+
client.disable_projection(name=projection_name)
|
|
3055
3162
|
```
|
|
3056
3163
|
|
|
3057
3164
|
### Enable projection<a id="enable-projection"></a>
|
|
@@ -3076,11 +3183,13 @@ override call credentials derived from the connection string URI.
|
|
|
3076
3183
|
client.enable_projection(name=projection_name)
|
|
3077
3184
|
```
|
|
3078
3185
|
|
|
3079
|
-
###
|
|
3186
|
+
### Abort projection<a id="abort-projection"></a>
|
|
3080
3187
|
|
|
3081
3188
|
*requires leader*
|
|
3082
3189
|
|
|
3083
|
-
The `
|
|
3190
|
+
The `abort_projection()` method can be used to abort (stop running) a projection.
|
|
3191
|
+
When a projection is stopped using this method, it will be stopped without writing
|
|
3192
|
+
a checkpoint.
|
|
3084
3193
|
|
|
3085
3194
|
This method has a required `name` argument, which is a Python `str` that
|
|
3086
3195
|
specifies the name of the projection to be disabled.
|
|
@@ -3094,7 +3203,7 @@ The optional `credentials` argument can be used to
|
|
|
3094
3203
|
override call credentials derived from the connection string URI.
|
|
3095
3204
|
|
|
3096
3205
|
```python
|
|
3097
|
-
client.
|
|
3206
|
+
client.abort_projection(name=projection_name)
|
|
3098
3207
|
```
|
|
3099
3208
|
|
|
3100
3209
|
### Reset projection<a id="reset-projection"></a>
|
|
@@ -3159,6 +3268,7 @@ client.delete_projection(name=projection_name)
|
|
|
3159
3268
|
|
|
3160
3269
|
Please note, a projection must be disabled before it can be deleted.
|
|
3161
3270
|
|
|
3271
|
+
|
|
3162
3272
|
### Restart projections subsystem<a id="restart-projections-subsystem"></a>
|
|
3163
3273
|
|
|
3164
3274
|
*requires leader*
|
|
@@ -3223,14 +3333,14 @@ and then they will all return normally.
|
|
|
3223
3333
|
client.reconnect()
|
|
3224
3334
|
```
|
|
3225
3335
|
|
|
3336
|
+
Reconnection will happen automatically in many cases, due to the `@autoreconnect`
|
|
3337
|
+
decorator.
|
|
3338
|
+
|
|
3226
3339
|
An example of when it might be desirable to reconnect manually is when (for performance
|
|
3227
3340
|
reasons) the client's node preference is to be connected to a follower node in the
|
|
3228
3341
|
cluster, and, after a cluster leader election, the follower becomes the leader.
|
|
3229
|
-
|
|
3230
|
-
this client, but this behavior might be implemented in a future release.
|
|
3231
|
-
|
|
3232
|
-
Reconnection will happen automatically in many cases, due to the `@autoreconnect`
|
|
3233
|
-
decorator.
|
|
3342
|
+
Automatic reconnection to a follower node in this case is currently beyond the
|
|
3343
|
+
capabilities of this client, but this behavior might be implemented in a future release.
|
|
3234
3344
|
|
|
3235
3345
|
### Close<a id="close"></a>
|
|
3236
3346
|
|
|
@@ -3611,7 +3721,7 @@ span.
|
|
|
3611
3721
|
|
|
3612
3722
|
## Communities<a id="communities"></a>
|
|
3613
3723
|
|
|
3614
|
-
- [Issues](https://github.com/pyeventsourcing/
|
|
3724
|
+
- [Issues](https://github.com/pyeventsourcing/kurrentdbclient/issues)
|
|
3615
3725
|
- [Discuss](https://discuss.eventstore.com/)
|
|
3616
3726
|
- [Discord (Event Store)](https://discord.gg/Phn9pmCw3t)
|
|
3617
3727
|
|
|
@@ -3736,3 +3846,4 @@ Update the `poetry.lock` file, and the project's virtual environment, using the
|
|
|
3736
3846
|
following command.
|
|
3737
3847
|
|
|
3738
3848
|
$ make update-packages
|
|
3849
|
+
|