Skip to content

Commit 010badc

Browse files
committed
Fixed code formatting and linting issues in README.md.
Also mentioned versions of KurrentDB and EventStoreDB that this package has been tested with. Also adjusted wording in README.md.
1 parent 12963fd commit 010badc

File tree

2 files changed

+45
-45
lines changed

2 files changed

+45
-45
lines changed

README.md

Lines changed: 44 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,11 @@ package when you are ready.
66
# Event Sourcing in Python with KurrentDB
77

88
This is an extension package for the Python [eventsourcing](https://github.com/pyeventsourcing/eventsourcing) library
9-
that provides a persistence module for [KurrentDB](https://www.kurrent.io).
9+
that provides a persistence module for [KurrentDB and EventStoreDB](https://www.kurrent.io).
1010
It uses the [kurrentdbclient](https://github.com/pyeventsourcing/kurrentdbclient)
11-
package to communicate with KurrentDB via the gRPC interface.
11+
package to communicate with KurrentDB via the gRPC interface. It is tested with
12+
KurrentDB 25.0 and three previous LTS versions of EventStoreDB (24.10, 23.10, and 22.10)
13+
across Python versions 3.9 to 3.13.
1214

1315
## Installation
1416

@@ -29,8 +31,8 @@ to be `0`, so you must set `INITIAL_VERSION` on your aggregate classes to `0`.
2931
```python
3032
from __future__ import annotations
3133

32-
from uuid import uuid5, NAMESPACE_URL
33-
from typing import List, TypedDict, Tuple
34+
from typing import TypedDict
35+
from uuid import NAMESPACE_URL, UUID, uuid5
3436

3537
from eventsourcing.application import Application
3638
from eventsourcing.domain import Aggregate, event
@@ -50,65 +52,60 @@ class TrainingSchool(Application):
5052

5153
def get_dog_details(self, name: str) -> DogDetails:
5254
dog = self._get_dog(name)
53-
return {'name': dog.name, 'tricks': tuple(dog.tricks)}
55+
return {"name": dog.name, "tricks": tuple(dog.tricks)}
5456

5557
def _get_dog(self, name: str) -> Dog:
5658
return self.repository.get(Dog.create_id(name))
5759

5860

59-
6061
class Dog(Aggregate):
6162
INITIAL_VERSION = 0 # for KurrentDB
6263

6364
@staticmethod
64-
def create_id(name: str):
65+
def create_id(name: str) -> UUID:
6566
return uuid5(NAMESPACE_URL, f"/dogs/{name}")
6667

67-
@event('Registered')
68-
def __init__(self, name):
68+
@event("Registered")
69+
def __init__(self, name: str) -> None:
6970
self.name = name
70-
self.tricks: List[str] = []
71+
self.tricks: list[str] = []
7172

72-
@event('TrickAdded')
73-
def add_trick(self, trick):
73+
@event("TrickAdded")
74+
def add_trick(self, trick: str) -> None:
7475
self.tricks.append(trick)
7576

7677

7778
class DogDetails(TypedDict):
7879
name: str
79-
tricks: Tuple[str, ...]
80+
tricks: tuple[str, ...]
8081
```
8182

82-
Configure the `TrainingSchool` application to use KurrentDB by setting
83-
the environment variable `PERSISTENCE_MODULE` to `'eventsourcing_kurrentdb'`. You
84-
can do this in actual environment variables, or by passing in an `env` argument when
85-
constructing the application object, or by setting `env` on the application class.
83+
Configure the `TrainingSchool` application to use KurrentDB with environment variables.
84+
You can configure an application with environment variables by setting them in the
85+
operating system environment, or by using the application constructor argument `env`,
86+
or by setting the application class attribute `env`.
87+
88+
Set `PERSISTENCE_MODULE` to `'eventsourcing_kurrentdb'`. Also set `KURRENTDB_URI` to a
89+
KurrentDB connection string URI. This value will be used as the `uri` argument when
90+
the `KurrentDBClient` class is constructed by this package.
8691

8792
```python
8893
import os
8994

90-
os.environ['TRAININGSCHOOL_PERSISTENCE_MODULE'] = 'eventsourcing_kurrentdb'
91-
```
92-
93-
Also set environment variable `KURRENTDB_URI` to a KurrentDB connection
94-
string URI. This value will be used as the `uri` argument when the `KurrentDBClient`
95-
class is constructed by this package.
96-
97-
```python
98-
os.environ['KURRENTDB_URI'] = 'esdb://localhost:2113?Tls=false'
95+
os.environ["TRAININGSCHOOL_PERSISTENCE_MODULE"] = "eventsourcing_kurrentdb"
96+
os.environ["KURRENTDB_URI"] = "esdb://localhost:2113?Tls=false"
9997
```
10098

101-
If you are connecting to a "secure" KurrentDB server, unless
99+
If you are connecting to a "secure" KurrentDB server, and if
102100
the root certificate of the certificate authority used to generate the
103-
server's certificate is installed locally, then also set environment
101+
server's certificate is not installed locally, then also set environment
104102
variable `KURRENTDB_ROOT_CERTIFICATES` to an SSL/TLS certificate
105103
suitable for making a secure gRPC connection to the KurrentDB server(s).
106104
This value will be used as the `root_certificates` argument when the
107105
`KurrentDBClient` class is constructed by this package.
108106

109-
110107
```python
111-
os.environ['KURRENTDB_ROOT_CERTIFICATES'] = '<PEM encoded SSL/TLS root certificates>'
108+
os.environ["KURRENTDB_ROOT_CERTIFICATES"] = "<PEM encoded SSL/TLS root certificates>"
112109
```
113110

114111
Please refer to the [kurrentdbclient](https://github.com/pyeventsourcing/kurrentdbclient)
@@ -117,7 +114,7 @@ server, and the "kdb" and "kdb+discover" KurrentDB connection string
117114
URI schemes, and how to obtain a suitable SSL/TLS certificate for use
118115
in the client when connecting to a "secure" KurrentDB server.
119116

120-
Construct the application.
117+
After configuring environment variables, construct the application.
121118

122119
```python
123120
training_school = TrainingSchool()
@@ -126,24 +123,24 @@ training_school = TrainingSchool()
126123
Call application methods from tests and user interfaces.
127124

128125
```python
129-
training_school.register('Fido')
130-
training_school.add_trick('Fido', 'roll over')
131-
training_school.add_trick('Fido', 'play dead')
132-
dog_details = training_school.get_dog_details('Fido')
133-
assert dog_details['name'] == 'Fido'
134-
assert dog_details['tricks'] == ('roll over', 'play dead')
126+
training_school.register("Fido")
127+
training_school.add_trick("Fido", "roll over")
128+
training_school.add_trick("Fido", "play dead")
129+
dog_details = training_school.get_dog_details("Fido")
130+
assert dog_details["name"] == "Fido"
131+
assert dog_details["tricks"] == ("roll over", "play dead")
135132
```
136133

137-
To see the events have been saved, we can reconstruct the application
134+
To see the events have been saved in KurrentDB, we can reconstruct the application
138135
and get Fido's details again.
139136

140137
```python
141138
training_school = TrainingSchool()
142139

143-
dog_details = training_school.get_dog_details('Fido')
140+
dog_details = training_school.get_dog_details("Fido")
144141

145-
assert dog_details['name'] == 'Fido'
146-
assert dog_details['tricks'] == ('roll over', 'play dead')
142+
assert dog_details["name"] == "Fido"
143+
assert dog_details["tricks"] == ("roll over", "play dead")
147144
```
148145

149146
## Eventually-consistent materialised views
@@ -157,8 +154,10 @@ application
157154

158155
```python
159156
from abc import abstractmethod
157+
160158
from eventsourcing.persistence import Tracking, TrackingRecorder
161159

160+
162161
class MaterialisedViewInterface(TrackingRecorder):
163162
@abstractmethod
164163
def incr_dog_counter(self, tracking: Tracking) -> None:
@@ -184,6 +183,7 @@ The example below counts dogs and tricks in memory, using "plain old Python obje
184183
```python
185184
from eventsourcing.popo import POPOTrackingRecorder
186185

186+
187187
class InMemoryMaterialiseView(POPOTrackingRecorder, MaterialisedViewInterface):
188188
def __init__(self):
189189
super().__init__()
@@ -216,8 +216,8 @@ by calling `incr_dog_counter()` on the materialised view. The `Dog.TrickAdded` e
216216
are processed by calling `incr_trick_counter()`.
217217

218218
```python
219-
from eventsourcing.domain import DomainEventProtocol
220219
from eventsourcing.dispatch import singledispatchmethod
220+
from eventsourcing.domain import DomainEventProtocol
221221
from eventsourcing.projection import Projection
222222
from eventsourcing.utils import get_topic
223223

@@ -274,7 +274,7 @@ with ProjectionRunner(
274274
trick_count = materialised_view.get_trick_counter()
275275

276276
# Record another event in "write model".
277-
notification_id = training_school.add_trick('Fido', 'sit and stay')
277+
notification_id = training_school.add_trick("Fido", "sit and stay")
278278

279279
# Wait for the new event to be processed.
280280
materialised_view.wait(
@@ -287,7 +287,7 @@ with ProjectionRunner(
287287
assert trick_count + 1 == materialised_view.get_trick_counter()
288288

289289
# Write another event.
290-
notification_id = training_school.add_trick('Fido', 'jump hoop')
290+
notification_id = training_school.add_trick("Fido", "jump hoop")
291291

292292
# Wait for the new event to be processed.
293293
materialised_view.wait(

tests/test_docs.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ def substitute_lines(self, lines: list[str]) -> None:
171171
fido_suffix = str(uuid.uuid4())
172172
for i in range(len(lines)):
173173
line = lines[i]
174-
line = line.replace("'Fido'", "'Fido-" + fido_suffix + "'")
174+
line = line.replace('"Fido"', '"Fido-' + fido_suffix + '"')
175175
lines[i] = line
176176

177177

0 commit comments

Comments
 (0)