depeche-db


Namedepeche-db JSON
Version 0.12.1 PyPI version JSON
download
home_pageNone
SummaryA library for building event-based systems on top of PostgreSQL
upload_time2025-07-21 12:18:55
maintainerNone
docs_urlNone
authorMartin Vielsmaier
requires_python<4.0,>=3.9
licenseMIT
keywords sqlalchemy postgresql event-driven event store message store event sourcing
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            

<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

[![Tests](https://github.com/depeche-py/depeche-db/actions/workflows/tests.yml/badge.svg)](https://github.com/depeche-py/depeche-db/actions/workflows/tests.yml)
[![pypi](https://img.shields.io/pypi/v/depeche-db.svg)](https://pypi.python.org/pypi/depeche-db)
[![versions](https://img.shields.io/pypi/pyversions/depeche-db.svg)](https://github.com/depeche-py/depeche-db)
[![Docs](https://img.shields.io/badge/docs-here-green.svg)](https://depeche-py.github.io/depeche-db/)
[![license](https://img.shields.io/github/license/depeche-py/depeche-db.svg)](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
```

## 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": "<4.0,>=3.9",
    "maintainer_email": null,
    "keywords": "sqlalchemy, postgresql, event-driven, event store, message store, event sourcing",
    "author": "Martin Vielsmaier",
    "author_email": "martin@vielsmaier.net",
    "download_url": "https://files.pythonhosted.org/packages/cf/ea/fce038e87796dc83f4c243b2414acdaec1d9302c8176c0fa3d21522f019a/depeche_db-0.12.1.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[![Tests](https://github.com/depeche-py/depeche-db/actions/workflows/tests.yml/badge.svg)](https://github.com/depeche-py/depeche-db/actions/workflows/tests.yml)\n[![pypi](https://img.shields.io/pypi/v/depeche-db.svg)](https://pypi.python.org/pypi/depeche-db)\n[![versions](https://img.shields.io/pypi/pyversions/depeche-db.svg)](https://github.com/depeche-py/depeche-db)\n[![Docs](https://img.shields.io/badge/docs-here-green.svg)](https://depeche-py.github.io/depeche-db/)\n[![license](https://img.shields.io/github/license/depeche-py/depeche-db.svg)](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```\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\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "A library for building event-based systems on top of PostgreSQL",
    "version": "0.12.1",
    "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": [
        "sqlalchemy",
        " postgresql",
        " event-driven",
        " event store",
        " message store",
        " event sourcing"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "130f678e6d7143da6b9255fde681491868a2b3c79c2dace60b67201f4d559df7",
                "md5": "052b4e4f59aaa5920db66183287283d5",
                "sha256": "4eb1e5e9dd27791889a833722c80e0fdb9cf5b02f420495a7abde97085af0546"
            },
            "downloads": -1,
            "filename": "depeche_db-0.12.1-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "052b4e4f59aaa5920db66183287283d5",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": "<4.0,>=3.9",
            "size": 45483,
            "upload_time": "2025-07-21T12:18:53",
            "upload_time_iso_8601": "2025-07-21T12:18:53.886367Z",
            "url": "https://files.pythonhosted.org/packages/13/0f/678e6d7143da6b9255fde681491868a2b3c79c2dace60b67201f4d559df7/depeche_db-0.12.1-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "cfeafce038e87796dc83f4c243b2414acdaec1d9302c8176c0fa3d21522f019a",
                "md5": "a47cffb86c676db0abaaea7cbd58f452",
                "sha256": "beb77ac00a7cbe08a7b5f6213e4736c442048d8b07cd3345b2b644b7f7eba3dd"
            },
            "downloads": -1,
            "filename": "depeche_db-0.12.1.tar.gz",
            "has_sig": false,
            "md5_digest": "a47cffb86c676db0abaaea7cbd58f452",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": "<4.0,>=3.9",
            "size": 36183,
            "upload_time": "2025-07-21T12:18:55",
            "upload_time_iso_8601": "2025-07-21T12:18:55.128476Z",
            "url": "https://files.pythonhosted.org/packages/cf/ea/fce038e87796dc83f4c243b2414acdaec1d9302c8176c0fa3d21522f019a/depeche_db-0.12.1.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-07-21 12:18:55",
    "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"
}
        
Elapsed time: 1.75697s