# Event Sourcing in Python with EventStoreDB
This is an extension package for the Python
[eventsourcing](https://github.com/pyeventsourcing/eventsourcing) library
that provides a persistence module for [EventStoreDB](https://www.eventstore.com/).
It uses the [esdbclient](https://github.com/pyeventsourcing/esdbclient)
package to communicate with EventStoreDB via its gRPC interface.
## Installation
Use pip to install the [stable distribution](https://pypi.org/project/eventsourcing-eventstoredb/)
from the Python Package Index.
$ pip install eventsourcing-eventstoredb
Please note, it is recommended to install Python packages into a Python virtual environment.
## Getting started
Define aggregates and applications in the usual way. Please note, "streams"
in EventStoreDB are constrained to start from position `0`, and this package
expects the `originator_version` of the first event in an aggregate sequence
to be `0`, so you must set `INITIAL_VERSION` on your aggregate classes to `0`.
```python
from eventsourcing.application import Application
from eventsourcing.domain import Aggregate, event
class TrainingSchool(Application):
def register(self, name):
dog = Dog(name)
self.save(dog)
return dog.id
def add_trick(self, dog_id, trick):
dog = self.repository.get(dog_id)
dog.add_trick(trick)
self.save(dog)
def get_dog(self, dog_id):
dog = self.repository.get(dog_id)
return {'name': dog.name, 'tricks': list(dog.tricks)}
class Dog(Aggregate):
INITIAL_VERSION = 0 # for EventStoreDB
@event('Registered')
def __init__(self, name):
self.name = name
self.tricks = []
@event('TrickAdded')
def add_trick(self, trick):
self.tricks.append(trick)
```
Configure the application to use EventStoreDB by setting the application environment
variable `PERSISTENCE_MODULE` to `'eventsourcing_eventstoredb'`. You can do this
in actual environment variables, by passing in an `env` argument when constructing
the application object, or by setting `env` on the application class.
```python
import os
os.environ['PERSISTENCE_MODULE'] = 'eventsourcing_eventstoredb'
```
Also set environment variable `EVENTSTOREDB_URI` and to an EventStoreDB
connection string URI. This value will be used as the `uri`
argument when the `ESDBClient` class is constructed by this package.
```python
os.environ['EVENTSTOREDB_URI'] = 'esdb://localhost:2113?Tls=false'
```
If you are connecting to a "secure" EventStoreDB server, unless the
root certificate of the certificate authority used to generate the
server's certificate is installed locally, then also set environment
variable `EVENTSTOREDB_ROOT_CERTIFICATES` to an SSL/TLS certificate
suitable for making a secure gRPC connection to the EventStoreDB server(s).
This value will be used as the `root_certificates` argument when the
`ESDBClient` class is constructed by this package.
```python
os.environ['EVENTSTOREDB_ROOT_CERTIFICATES'] = '<PEM encoded SSL/TLS root certificates>'
```
Please refer to the [esdbclient](https://github.com/pyeventsourcing/esdbclient)
documentation for details about starting a "secure" or "insecure" EventStoreDB
server, the "esdb" and "esdb+discover" EventStoreDB connection string
URI schemes, and how to obtain a suitable SSL/TLS certificate for use
in the client when connecting to a "secure" EventStoreDB server.
Construct the application.
```python
school = TrainingSchool()
```
Call application methods from tests and user interfaces.
```python
dog_id = school.register('Fido')
school.add_trick(dog_id, 'roll over')
school.add_trick(dog_id, 'play dead')
dog_details = school.get_dog(dog_id)
assert dog_details['name'] == 'Fido'
assert dog_details['tricks'] == ['roll over', 'play dead']
```
To see the events have been saved, we can reconstruct the application
and get Fido's details again.
```python
school = TrainingSchool()
dog_details = school.get_dog(dog_id)
assert dog_details['name'] == 'Fido'
assert dog_details['tricks'] == ['roll over', 'play dead']
```
For more information, please refer to the Python
[eventsourcing](https://github.com/pyeventsourcing/eventsourcing) library, the
Python [esdbclient](https://github.com/pyeventsourcing/esdbclient) package,
and the [EventStoreDB](https://www.eventstore.com/) project.
## Contributors
### Install Poetry
The first thing is to check you have Poetry installed.
$ poetry --version
If you don't, then please [install Poetry](https://python-poetry.org/docs/#installing-with-the-official-installer).
It will help to make sure Poetry's bin directory is in your `PATH` environment variable.
But in any case, make sure you know the path to the `poetry` executable. The Poetry
installer tells you where it has been installed, and how to configure your shell.
Please refer to the [Poetry docs](https://python-poetry.org/docs/) for guidance on
using Poetry.
### Setup for PyCharm users
You can easily obtain the project files using PyCharm (menu "Git > Clone...").
PyCharm will then usually prompt you to open the project.
Open the project in a new window. PyCharm will then usually prompt you to create
a new virtual environment.
Create a new Poetry virtual environment for the project. If PyCharm doesn't already
know where your `poetry` executable is, then set the path to your `poetry` executable
in the "New Poetry Environment" form input field labelled "Poetry executable". In the
"New Poetry Environment" form, you will also have the opportunity to select which
Python executable will be used by the virtual environment.
PyCharm will then create a new Poetry virtual environment for your project, using
a particular version of Python, and also install into this virtual environment the
project's package dependencies according to the `pyproject.toml` file, or the
`poetry.lock` file if that exists in the project files.
You can add different Poetry environments for different Python versions, and switch
between them using the "Python Interpreter" settings of PyCharm. If you want to use
a version of Python that isn't installed, either use your favourite package manager,
or install Python by downloading an installer for recent versions of Python directly
from the [Python website](https://www.python.org/downloads/).
Once project dependencies have been installed, you should be able to run tests
from within PyCharm (right-click on the `tests` folder and select the 'Run' option).
Because of a conflict between pytest and PyCharm's debugger and the coverage tool,
you may need to add ``--no-cov`` as an option to the test runner template. Alternatively,
just use the Python Standard Library's ``unittest`` module.
You should also be able to open a terminal window in PyCharm, and run the project's
Makefile commands from the command line (see below).
### Setup from command line
Obtain the project files, using Git or suitable alternative.
In a terminal application, change your current working directory
to the root folder of the project files. There should be a Makefile
in this folder.
Use the Makefile to create a new Poetry virtual environment for the
project and install the project's package dependencies into it,
using the following command.
$ make install-packages
It's also possible to also install the project in 'editable mode'.
$ make install
Please note, if you create the virtual environment in this way, and then try to
open the project in PyCharm and configure the project to use this virtual
environment as an "Existing Poetry Environment", PyCharm sometimes has some
issues (don't know why) which might be problematic. If you encounter such
issues, you can resolve these issues by deleting the virtual environment
and creating the Poetry virtual environment using PyCharm (see above).
### Project Makefile commands
You can start EventStoreDB using the following command.
$ make start-eventstoredb
You can run tests using the following command (needs EventStoreDB to be running).
$ make test
You can stop EventStoreDB using the following command.
$ make stop-eventstoredb
You can check the formatting of the code using the following command.
$ make lint
You can reformat the code using the following command.
$ make fmt
Tests belong in `./tests`. Code-under-test belongs in `./eventsourcing_eventstoredb`.
Edit package dependencies in `pyproject.toml`. Update installed packages (and the
`poetry.lock` file) using the following command.
$ make update-packages
Raw data
{
"_id": null,
"home_page": "https://github.com/pyeventsourcing/eventsourcing-eventstoredb",
"name": "eventsourcing-eventstoredb",
"maintainer": null,
"docs_url": null,
"requires_python": "<4.0,>=3.8",
"maintainer_email": null,
"keywords": null,
"author": "John Bywater",
"author_email": "john.bywater@appropriatesoftware.net",
"download_url": "https://files.pythonhosted.org/packages/19/8a/4a3bca7413e907bc917cbeb795e267fe5feef71b71cf8089e375d50e4392/eventsourcing_eventstoredb-1.1.2.tar.gz",
"platform": null,
"description": "# Event Sourcing in Python with EventStoreDB\n\nThis is an extension package for the Python\n[eventsourcing](https://github.com/pyeventsourcing/eventsourcing) library\nthat provides a persistence module for [EventStoreDB](https://www.eventstore.com/).\nIt uses the [esdbclient](https://github.com/pyeventsourcing/esdbclient)\npackage to communicate with EventStoreDB via its gRPC interface.\n\n## Installation\n\nUse pip to install the [stable distribution](https://pypi.org/project/eventsourcing-eventstoredb/)\nfrom the Python Package Index.\n\n $ pip install eventsourcing-eventstoredb\n\nPlease note, it is recommended to install Python packages into a Python virtual environment.\n\n## Getting started\n\nDefine aggregates and applications in the usual way. Please note, \"streams\"\nin EventStoreDB are constrained to start from position `0`, and this package\nexpects the `originator_version` of the first event in an aggregate sequence\nto be `0`, so you must set `INITIAL_VERSION` on your aggregate classes to `0`.\n\n```python\nfrom eventsourcing.application import Application\nfrom eventsourcing.domain import Aggregate, event\n\n\nclass TrainingSchool(Application):\n def register(self, name):\n dog = Dog(name)\n self.save(dog)\n return dog.id\n\n def add_trick(self, dog_id, trick):\n dog = self.repository.get(dog_id)\n dog.add_trick(trick)\n self.save(dog)\n\n def get_dog(self, dog_id):\n dog = self.repository.get(dog_id)\n return {'name': dog.name, 'tricks': list(dog.tricks)}\n\n\nclass Dog(Aggregate):\n INITIAL_VERSION = 0 # for EventStoreDB\n\n @event('Registered')\n def __init__(self, name):\n self.name = name\n self.tricks = []\n\n @event('TrickAdded')\n def add_trick(self, trick):\n self.tricks.append(trick)\n```\n\nConfigure the application to use EventStoreDB by setting the application environment\nvariable `PERSISTENCE_MODULE` to `'eventsourcing_eventstoredb'`. You can do this\nin actual environment variables, by passing in an `env` argument when constructing\nthe application object, or by setting `env` on the application class.\n\n```python\nimport os\n\nos.environ['PERSISTENCE_MODULE'] = 'eventsourcing_eventstoredb'\n```\n\nAlso set environment variable `EVENTSTOREDB_URI` and to an EventStoreDB\nconnection string URI. This value will be used as the `uri`\nargument when the `ESDBClient` class is constructed by this package.\n\n```python\nos.environ['EVENTSTOREDB_URI'] = 'esdb://localhost:2113?Tls=false'\n```\n\nIf you are connecting to a \"secure\" EventStoreDB server, unless the\nroot certificate of the certificate authority used to generate the\nserver's certificate is installed locally, then also set environment\nvariable `EVENTSTOREDB_ROOT_CERTIFICATES` to an SSL/TLS certificate\nsuitable for making a secure gRPC connection to the EventStoreDB server(s).\nThis value will be used as the `root_certificates` argument when the\n`ESDBClient` class is constructed by this package.\n\n\n```python\nos.environ['EVENTSTOREDB_ROOT_CERTIFICATES'] = '<PEM encoded SSL/TLS root certificates>'\n```\n\nPlease refer to the [esdbclient](https://github.com/pyeventsourcing/esdbclient)\ndocumentation for details about starting a \"secure\" or \"insecure\" EventStoreDB\nserver, the \"esdb\" and \"esdb+discover\" EventStoreDB connection string\nURI schemes, and how to obtain a suitable SSL/TLS certificate for use\nin the client when connecting to a \"secure\" EventStoreDB server.\n\nConstruct the application.\n\n```python\nschool = TrainingSchool()\n```\n\nCall application methods from tests and user interfaces.\n\n```python\ndog_id = school.register('Fido')\nschool.add_trick(dog_id, 'roll over')\nschool.add_trick(dog_id, 'play dead')\ndog_details = school.get_dog(dog_id)\nassert dog_details['name'] == 'Fido'\nassert dog_details['tricks'] == ['roll over', 'play dead']\n```\n\nTo see the events have been saved, we can reconstruct the application\nand get Fido's details again.\n\n```python\nschool = TrainingSchool()\n\ndog_details = school.get_dog(dog_id)\n\nassert dog_details['name'] == 'Fido'\nassert dog_details['tricks'] == ['roll over', 'play dead']\n```\n\nFor more information, please refer to the Python\n[eventsourcing](https://github.com/pyeventsourcing/eventsourcing) library, the\nPython [esdbclient](https://github.com/pyeventsourcing/esdbclient) package,\nand the [EventStoreDB](https://www.eventstore.com/) project.\n\n## Contributors\n\n### Install Poetry\n\nThe first thing is to check you have Poetry installed.\n\n $ poetry --version\n\nIf you don't, then please [install Poetry](https://python-poetry.org/docs/#installing-with-the-official-installer).\n\nIt will help to make sure Poetry's bin directory is in your `PATH` environment variable.\n\nBut in any case, make sure you know the path to the `poetry` executable. The Poetry\ninstaller tells you where it has been installed, and how to configure your shell.\n\nPlease refer to the [Poetry docs](https://python-poetry.org/docs/) for guidance on\nusing Poetry.\n\n### Setup for PyCharm users\n\nYou can easily obtain the project files using PyCharm (menu \"Git > Clone...\").\nPyCharm will then usually prompt you to open the project.\n\nOpen the project in a new window. PyCharm will then usually prompt you to create\na new virtual environment.\n\nCreate a new Poetry virtual environment for the project. If PyCharm doesn't already\nknow where your `poetry` executable is, then set the path to your `poetry` executable\nin the \"New Poetry Environment\" form input field labelled \"Poetry executable\". In the\n\"New Poetry Environment\" form, you will also have the opportunity to select which\nPython executable will be used by the virtual environment.\n\nPyCharm will then create a new Poetry virtual environment for your project, using\na particular version of Python, and also install into this virtual environment the\nproject's package dependencies according to the `pyproject.toml` file, or the\n`poetry.lock` file if that exists in the project files.\n\nYou can add different Poetry environments for different Python versions, and switch\nbetween them using the \"Python Interpreter\" settings of PyCharm. If you want to use\na version of Python that isn't installed, either use your favourite package manager,\nor install Python by downloading an installer for recent versions of Python directly\nfrom the [Python website](https://www.python.org/downloads/).\n\nOnce project dependencies have been installed, you should be able to run tests\nfrom within PyCharm (right-click on the `tests` folder and select the 'Run' option).\n\nBecause of a conflict between pytest and PyCharm's debugger and the coverage tool,\nyou may need to add ``--no-cov`` as an option to the test runner template. Alternatively,\njust use the Python Standard Library's ``unittest`` module.\n\nYou should also be able to open a terminal window in PyCharm, and run the project's\nMakefile commands from the command line (see below).\n\n### Setup from command line\n\nObtain the project files, using Git or suitable alternative.\n\nIn a terminal application, change your current working directory\nto the root folder of the project files. There should be a Makefile\nin this folder.\n\nUse the Makefile to create a new Poetry virtual environment for the\nproject and install the project's package dependencies into it,\nusing the following command.\n\n $ make install-packages\n\nIt's also possible to also install the project in 'editable mode'.\n\n $ make install\n\nPlease note, if you create the virtual environment in this way, and then try to\nopen the project in PyCharm and configure the project to use this virtual\nenvironment as an \"Existing Poetry Environment\", PyCharm sometimes has some\nissues (don't know why) which might be problematic. If you encounter such\nissues, you can resolve these issues by deleting the virtual environment\nand creating the Poetry virtual environment using PyCharm (see above).\n\n### Project Makefile commands\n\nYou can start EventStoreDB using the following command.\n\n $ make start-eventstoredb\n\nYou can run tests using the following command (needs EventStoreDB to be running).\n\n $ make test\n\nYou can stop EventStoreDB using the following command.\n\n $ make stop-eventstoredb\n\nYou can check the formatting of the code using the following command.\n\n $ make lint\n\nYou can reformat the code using the following command.\n\n $ make fmt\n\nTests belong in `./tests`. Code-under-test belongs in `./eventsourcing_eventstoredb`.\n\nEdit package dependencies in `pyproject.toml`. Update installed packages (and the\n`poetry.lock` file) using the following command.\n\n $ make update-packages\n",
"bugtrack_url": null,
"license": "BSD 3-Clause",
"summary": "Python package for eventsourcing with EventStoreDB",
"version": "1.1.2",
"project_urls": {
"Homepage": "https://github.com/pyeventsourcing/eventsourcing-eventstoredb",
"Repository": "https://github.com/pyeventsourcing/eventsourcing-eventstoredb"
},
"split_keywords": [],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "7d57e094299a38d530c9e3663b9e4516e17559ad259159b75721badf16190399",
"md5": "42330149e175e5f2c4d81ee08235297f",
"sha256": "6162efe294593e9c0c01ee4effff234e3e14d1ab2d009f72080f8336ee2e7293"
},
"downloads": -1,
"filename": "eventsourcing_eventstoredb-1.1.2-py3-none-any.whl",
"has_sig": false,
"md5_digest": "42330149e175e5f2c4d81ee08235297f",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": "<4.0,>=3.8",
"size": 9019,
"upload_time": "2024-11-08T03:13:26",
"upload_time_iso_8601": "2024-11-08T03:13:26.931298Z",
"url": "https://files.pythonhosted.org/packages/7d/57/e094299a38d530c9e3663b9e4516e17559ad259159b75721badf16190399/eventsourcing_eventstoredb-1.1.2-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "198a4a3bca7413e907bc917cbeb795e267fe5feef71b71cf8089e375d50e4392",
"md5": "75dba392823644b13179551c8cfeca91",
"sha256": "183eac81cdfd91b21ec6fa3078a16ebc09a4406514678b1ad7508fc62762b542"
},
"downloads": -1,
"filename": "eventsourcing_eventstoredb-1.1.2.tar.gz",
"has_sig": false,
"md5_digest": "75dba392823644b13179551c8cfeca91",
"packagetype": "sdist",
"python_version": "source",
"requires_python": "<4.0,>=3.8",
"size": 10967,
"upload_time": "2024-11-08T03:13:29",
"upload_time_iso_8601": "2024-11-08T03:13:29.052504Z",
"url": "https://files.pythonhosted.org/packages/19/8a/4a3bca7413e907bc917cbeb795e267fe5feef71b71cf8089e375d50e4392/eventsourcing_eventstoredb-1.1.2.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-11-08 03:13:29",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "pyeventsourcing",
"github_project": "eventsourcing-eventstoredb",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "eventsourcing-eventstoredb"
}