<p align="center">
<img src="https://depeche-py.github.io/depeche-db/assets/logo-bg.png" width="200" />
</p>
# Depeche DB
A library for building event-based systems on top of PostgreSQL
[](https://github.com/depeche-py/depeche-db/actions/workflows/tests.yml)
[](https://pypi.python.org/pypi/depeche-db)
[](https://github.com/depeche-py/depeche-db)
[](https://depeche-py.github.io/depeche-db/)
[](https://github.com/depeche-py/depeche-db/blob/main/LICENSE)
---
**Documentation**: [https://depeche-py.github.io/depeche-db/](https://depeche-py.github.io/depeche-db/)
**Source code**: [https://github.com/depeche-py/depeche-db](https://github.com/depeche-py/depeche-db)
---
Depeche DB is modern Python library for building event-based systems
Key features:
* Message store with optimistic concurrency control & strong ordering guarantees
* Subscriptions with "at least once" semantics
* Parallel processing of (partitioned) subscriptions
* No database polling
## Requirements
Python 3.9+
SQLAlchemy 1.4 or 2+
PostgreSQL 12+
Psycopg (Version 2 >= 2.9.3 or Version 3 >= 3.1)
## Installation
```bash
pip install depeche-db
# OR
poetry add depeche-db
# OR
uv add depeche-db
```
## Example
```python
import pydantic, sqlalchemy, uuid, datetime as dt
from depeche_db import (
MessageStore,
StoredMessage,
MessageHandler,
SubscriptionMessage,
)
from depeche_db.tools import PydanticMessageSerializer
DB_DSN = "postgresql://depeche:depeche@localhost:4888/depeche_demo"
db_engine = sqlalchemy.create_engine(DB_DSN)
class MyMessage(pydantic.BaseModel):
content: int
message_id: uuid.UUID = pydantic.Field(default_factory=uuid.uuid4)
sent_at: dt.datetime = pydantic.Field(default_factory=dt.datetime.utcnow)
def get_message_id(self) -> uuid.UUID:
return self.message_id
def get_message_time(self) -> dt.datetime:
return self.sent_at
message_store = MessageStore[MyMessage](
name="example_store",
engine=db_engine,
serializer=PydanticMessageSerializer(MyMessage),
)
message_store.write(stream="aggregate-me-1", message=MyMessage(content=2))
print(list(message_store.read(stream="aggregate-me-1")))
# [StoredMessage(message_id=UUID('...'), stream='aggregate-me-1', version=1, message=MyMessage(content=2, message_id=UUID('...'), sent_at=datetime.datetime(...)), global_position=1)]
class ContentMessagePartitioner:
def get_partition(self, message: StoredMessage[MyMessage]) -> int:
return message.message.content % 10
class MyHandlers(MessageHandler[MyMessage]):
@MessageHandler.register
def handle_message(self, message: SubscriptionMessage[MyMessage]):
print(message)
aggregated_stream = message_store.aggregated_stream(
name="aggregated",
partitioner=ContentMessagePartitioner(),
stream_wildcards=["aggregate-me-%"],
)
subscription = aggregated_stream.subscription(
name="example_subscription",
handlers=MyHandlers(),
)
aggregated_stream.projector.run()
subscription.runner.run()
# MyHandlers.handle_message prints:
# SubscriptionMessage(partition=2, position=0, stored_message=StoredMessage(...))
```
## Contribute
Contributions in the form of issues, questions, feedback and pull requests are
welcome. Before investing a lot of time, let me know what you are up to so
we can see if your contribution fits the vision of the project.
Raw data
{
"_id": null,
"home_page": null,
"name": "depeche-db",
"maintainer": null,
"docs_url": null,
"requires_python": "~=3.9",
"maintainer_email": null,
"keywords": "event sourcing, event store, event-driven, message store, postgresql, sqlalchemy",
"author": null,
"author_email": "Martin Vielsmaier <martin@vielsmaier.net>",
"download_url": "https://files.pythonhosted.org/packages/cb/a3/f1bd895ef276139842bd12c7ce32bf3ea3f0a5e76dd91248e57487c2f1e2/depeche_db-0.12.4.tar.gz",
"platform": null,
"description": "\n\n<p align=\"center\">\n <img src=\"https://depeche-py.github.io/depeche-db/assets/logo-bg.png\" width=\"200\" />\n</p>\n\n# Depeche DB\n\nA library for building event-based systems on top of PostgreSQL\n\n[](https://github.com/depeche-py/depeche-db/actions/workflows/tests.yml)\n[](https://pypi.python.org/pypi/depeche-db)\n[](https://github.com/depeche-py/depeche-db)\n[](https://depeche-py.github.io/depeche-db/)\n[](https://github.com/depeche-py/depeche-db/blob/main/LICENSE)\n\n---\n\n**Documentation**: [https://depeche-py.github.io/depeche-db/](https://depeche-py.github.io/depeche-db/)\n\n**Source code**: [https://github.com/depeche-py/depeche-db](https://github.com/depeche-py/depeche-db)\n\n---\n\nDepeche DB is modern Python library for building event-based systems\n\nKey features:\n\n* Message store with optimistic concurrency control & strong ordering guarantees\n* Subscriptions with \"at least once\" semantics\n* Parallel processing of (partitioned) subscriptions\n* No database polling\n\n## Requirements\n\nPython 3.9+\nSQLAlchemy 1.4 or 2+\nPostgreSQL 12+\nPsycopg (Version 2 >= 2.9.3 or Version 3 >= 3.1)\n\n\n## Installation\n\n```bash\npip install depeche-db\n# OR\npoetry add depeche-db\n# OR\nuv add depeche-db\n```\n\n## Example\n\n```python\nimport pydantic, sqlalchemy, uuid, datetime as dt\n\nfrom depeche_db import (\n MessageStore,\n StoredMessage,\n MessageHandler,\n SubscriptionMessage,\n)\nfrom depeche_db.tools import PydanticMessageSerializer\n\nDB_DSN = \"postgresql://depeche:depeche@localhost:4888/depeche_demo\"\ndb_engine = sqlalchemy.create_engine(DB_DSN)\n\n\nclass MyMessage(pydantic.BaseModel):\n content: int\n message_id: uuid.UUID = pydantic.Field(default_factory=uuid.uuid4)\n sent_at: dt.datetime = pydantic.Field(default_factory=dt.datetime.utcnow)\n\n def get_message_id(self) -> uuid.UUID:\n return self.message_id\n\n def get_message_time(self) -> dt.datetime:\n return self.sent_at\n\n\nmessage_store = MessageStore[MyMessage](\n name=\"example_store\",\n engine=db_engine,\n serializer=PydanticMessageSerializer(MyMessage),\n)\nmessage_store.write(stream=\"aggregate-me-1\", message=MyMessage(content=2))\nprint(list(message_store.read(stream=\"aggregate-me-1\")))\n# [StoredMessage(message_id=UUID('...'), stream='aggregate-me-1', version=1, message=MyMessage(content=2, message_id=UUID('...'), sent_at=datetime.datetime(...)), global_position=1)]\n\n\nclass ContentMessagePartitioner:\n def get_partition(self, message: StoredMessage[MyMessage]) -> int:\n return message.message.content % 10\n\n\nclass MyHandlers(MessageHandler[MyMessage]):\n @MessageHandler.register\n def handle_message(self, message: SubscriptionMessage[MyMessage]):\n print(message)\n\n\naggregated_stream = message_store.aggregated_stream(\n name=\"aggregated\",\n partitioner=ContentMessagePartitioner(),\n stream_wildcards=[\"aggregate-me-%\"],\n)\nsubscription = aggregated_stream.subscription(\n name=\"example_subscription\",\n handlers=MyHandlers(),\n)\n\naggregated_stream.projector.run()\nsubscription.runner.run()\n# MyHandlers.handle_message prints:\n# SubscriptionMessage(partition=2, position=0, stored_message=StoredMessage(...))\n\n```\n\n\n## Contribute\n\nContributions in the form of issues, questions, feedback and pull requests are\nwelcome. Before investing a lot of time, let me know what you are up to so\nwe can see if your contribution fits the vision of the project.\n",
"bugtrack_url": null,
"license": null,
"summary": "A library for building event-based systems on top of PostgreSQL",
"version": "0.12.4",
"project_urls": {
"Changelog": "https://depeche-py.github.io/depeche-db/CHANGELOG/",
"Documentation": "https://depeche-py.github.io/depeche-db/",
"Homepage": "https://github.com/depeche-py/depeche-db",
"Repository": "https://github.com/depeche-py/depeche-db"
},
"split_keywords": [
"event sourcing",
" event store",
" event-driven",
" message store",
" postgresql",
" sqlalchemy"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "844d1f52604e3edfd371e9b80d84b1bceef36753f71790522d243fc5b2aed2a4",
"md5": "6d0df5d15f35ec1f65f02b21870c8307",
"sha256": "58f26b8b694aa9b80ab2b87e1e308a530be4fd86d381be84e03644b90cd42efb"
},
"downloads": -1,
"filename": "depeche_db-0.12.4-py3-none-any.whl",
"has_sig": false,
"md5_digest": "6d0df5d15f35ec1f65f02b21870c8307",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": "~=3.9",
"size": 45926,
"upload_time": "2025-08-13T14:53:28",
"upload_time_iso_8601": "2025-08-13T14:53:28.051152Z",
"url": "https://files.pythonhosted.org/packages/84/4d/1f52604e3edfd371e9b80d84b1bceef36753f71790522d243fc5b2aed2a4/depeche_db-0.12.4-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "cba3f1bd895ef276139842bd12c7ce32bf3ea3f0a5e76dd91248e57487c2f1e2",
"md5": "a72da5b2fe017820c8b6ed21805981d8",
"sha256": "9f2d0a75f4695d55a3598fd18142b1a7977c75b4dffa27d88036f7ef921e3da9"
},
"downloads": -1,
"filename": "depeche_db-0.12.4.tar.gz",
"has_sig": false,
"md5_digest": "a72da5b2fe017820c8b6ed21805981d8",
"packagetype": "sdist",
"python_version": "source",
"requires_python": "~=3.9",
"size": 327157,
"upload_time": "2025-08-13T14:53:29",
"upload_time_iso_8601": "2025-08-13T14:53:29.062237Z",
"url": "https://files.pythonhosted.org/packages/cb/a3/f1bd895ef276139842bd12c7ce32bf3ea3f0a5e76dd91248e57487c2f1e2/depeche_db-0.12.4.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-08-13 14:53:29",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "depeche-py",
"github_project": "depeche-db",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "depeche-db"
}