# -*- coding: utf-8 -*-
from setuptools import setup

packages = \
['esdbclient', 'esdbclient.protos.Grpc']

package_data = \
{'': ['*']}

install_requires = \
['grpcio>=1.44.0,<1.45.0', 'protobuf>=3.20.0,<3.21.0', 'typing_extensions']

setup_kwargs = {
    'name': 'esdbclient',
    'version': '0.4',
    'description': 'Python gRPC Client for EventStoreDB',
    'long_description': '# Python gRPC Client for EventStoreDB\n\nThis package provides a Python gRPC client for\n[EventStoreDB](https://www.eventstore.com/). It has been\ndeveloped and tested to work with version 21.10 of EventStoreDB,\nand with Python versions 3.7, 3.8, 3.9, and 3.10.\n\nMethods have typing annotations, the static typing is checked\nwith mypy, and the test coverage is 100%.\n\nNot all the features of the EventStoreDB API are presented\nby this client in its current form, however most of the useful\naspects are presented in an easy-to-use interface (see below).\n\n## Installation\n\nUse pip to install this package from the\n[the Python Package Index](https://pypi.org/project/esdbclient/).\n\n    $ pip install esdbclient\n\nIt is recommended to install Python packages into a Python virtual environment.\n\n## Getting started\n\n### Start EventStoreDB\n\nUse Docker to run EventStoreDB from the official container image on DockerHub.\n\n    $ docker run -d --name my-eventstoredb -it -p 2113:2113 -p 1113:1113 eventstore/eventstore:21.10.2-buster-slim --insecure\n\n### Construct client\n\nThe class `EsdbClient` can be constructed with a `uri` that indicates the hostname\nand port number of the EventStoreDB server.\n\n```python\nfrom esdbclient.client import EsdbClient\n\nclient = EsdbClient(uri=\'localhost:2113\')\n```\n\n### Append events\n\nThe method `append_events()` can be used to append events to\na stream.\n\nThe arguments `stream_name`, `expected_position` and `new_events`\nare required.\n\nThe `stream_name` argument is a string that uniquely identifies\nthe stream in the database.\n\nThe `expected_position` argument is an optional integer that specifies\nthe expected position of the end of the stream in the database: either\nan integer representing the expected current position of the stream;\nor `None` if the stream is expected not to exist.\n\nThe `events` argument is a list of new event objects to be appended to the\nstream. The class `NewEvent` can be used to construct new event objects.\n\nThe method `append_events()` returns the "commit position", which is a\nmonotonically increasing integer representing the position of the recorded\nevent in a "total order" of all recorded events in all streams.\n\nIn the example below, a stream is created by appending a new event with\n`expected_position=None`.\n\n```python\nfrom uuid import uuid4\n\nfrom esdbclient.events import NewEvent\n\n# Construct new event object.\nevent1 = NewEvent(type="OrderCreated", data=b"{}", metadata=b"{}")\n\n# Define stream name.\nstream_name1 = str(uuid4())\n\n# Append list of events to new stream.\ncommit_position1 = client.append_events(\n    stream_name=stream_name1, expected_position=None, events=[event1]\n)\n```\n\nIn the example below, two subsequent events are appended to an existing\nstream. Since the stream only has one recorded event, the current position\nof the end of the stream is `0`.\n\n```python\nevent2 = NewEvent(type="OrderUpdated", data=b"{}", metadata=b"{}")\nevent3 = NewEvent(type="OrderDeleted", data=b"{}", metadata=b"{}")\n\ncommit_position2 = client.append_events(\n    stream_name1, expected_position=0, events=[event2, event3]\n)\n```\n\nPlease note, whilst the appending in one operation of a list of events\nis atomic (either all or none will be recorded), by design it is only\npossible with EventStoreDB to atomically record events in one stream.\n\n### Read stream events\n\nThe method `read_stream_events()` can be used to read the recorded\nevents in a stream. The argument `stream_name` is required. By default,\nall recorded events in the stream are returned in the order they were\nappended. An iterable object of recorded events is returned.\n\nRead all the recorded events in a stream.\n\n```python\nevents = list(client.read_stream_events(stream_name=stream_name1))\n\nassert len(events) == 3\n\nassert events[0].stream_name == stream_name1\nassert events[0].stream_position == 0\nassert events[0].type == event1.type\nassert events[0].data == event1.data\n\nassert events[1].stream_name == stream_name1\nassert events[1].stream_position == 1\nassert events[1].type == event2.type\nassert events[1].data == event2.data\n\nassert events[2].stream_name == stream_name1\nassert events[2].stream_position == 2\nassert events[2].type == event3.type\nassert events[2].data == event3.data\n```\n\nThe method `read_stream_events()` also supports three optional arguments,\n`position`, `backwards`, and `limit`.\n\nThe argument `position` is an optional integer that can be used to indicate\nthe stream position from which to start reading. This argument is `None` by default,\nmeaning that the stream will be read from the start, or from the end if `backwards`\nis `True`.\n\nThe argument `backwards` is a boolean which is by default `False` meaning the\nstream will be read forwards by default, so that events are returned in the\norder they were appended, If `backwards` is `True`, the stream will be read\nbackwards, so that events are returned in reverse order.\n\nThe argument `limit` is an integer which limits the number of events that will\nbe returned.\n\nRead recorded events in a stream from a specific stream position.\n\n```python\nevents = list(client.read_stream_events(stream_name1, position=1))\n\nassert len(events) == 2\n\nassert events[0].stream_name == stream_name1\nassert events[0].stream_position == 1\nassert events[0].type == event2.type\nassert events[0].data == event2.data\n\nassert events[1].stream_name == stream_name1\nassert events[1].stream_position == 2\nassert events[1].type == event3.type\nassert events[1].data == event3.data\n```\n\nRead the recorded events in a stream backwards from the end.\n\n```python\nevents = list(client.read_stream_events(stream_name1, backwards=True))\n\nassert len(events) == 3\n\nassert events[0].stream_name == stream_name1\nassert events[0].stream_position == 2\nassert events[0].type == event3.type\nassert events[0].data == event3.data\n\nassert events[1].stream_name == stream_name1\nassert events[1].stream_position == 1\nassert events[1].type == event2.type\nassert events[1].data == event2.data\n```\n\nRead a limited number of recorded events in stream.\n\n```python\nevents = list(client.read_stream_events(stream_name1, limit=2))\n\nassert len(events) == 2\n\nassert events[0].stream_name == stream_name1\nassert events[0].stream_position == 0\nassert events[0].type == event1.type\nassert events[0].data == event1.data\n\nassert events[1].stream_name == stream_name1\nassert events[1].stream_position == 1\nassert events[1].type == event2.type\nassert events[1].data == event2.data\n```\n\nRead a limited number of recorded events backwards from given position.\n\n```python\nevents = list(client.read_stream_events(stream_name1, position=2, backwards=True, limit=1))\n\nassert len(events) == 1\n\nassert events[0].stream_name == stream_name1\nassert events[0].stream_position == 2\nassert events[0].type == event3.type\nassert events[0].data == event3.data\n```\n\n### Get current stream position\n\nThe method `get_stream_position()` can be used to get the current\nstream position of the last event in the stream.\n\n```python\ncurrent_position = client.get_stream_position(stream_name1)\n\nassert current_position == 2\n```\n\nThe sequence of stream positions is intended to be gapless. It is\nalso usually zero-based, so that the position of the end of the stream\nwhen one event has been appended is `0`. The position is `1` after two\nevents have been appended, `2` after three events have been appended,\nand so on.\n\nThe position of a stream that does not exist is reported by this method to\nbe `None`.\n\n```python\ncurrent_position = client.get_stream_position(stream_name="stream-unknown")\n\nassert current_position == None\n```\n\n### Read all recorded events\n\nThe method `read_all_events()` can be used to read all recorded events\nin all streams in the order they were committed. An iterable object of\nrecorded events is returned.\n\nRead events from all streams in the order they were committed.\n\n```python\nevents = list(client.read_all_events())\n\nassert len(events) >= 3\n```\n\nThe method `read_stream_events()` supports three optional arguments,\n`position`, `backwards`, and `limit`.\n\nThe argument `position` is an optional integer that can be used to indicate\nthe commit position from which to start reading. This argument is `None` by default,\nmeaning that all the events will be read from the start, or from the end if `backwards`\nis `True`. Please note, if given the commit position must be an actually existing\ncommit position, and any other numbers will result in an exception being raised.\n\nThe argument `backwards` is a boolean which is by default `False` meaning all the\nevents will be read forwards by default, so that events are returned in the\norder they were committed, If `backwards` is `True`, all the events will be read\nbackwards, so that events are returned in reverse order.\n\nThe argument `limit` is an integer which limits the number of events that will\nbe returned.\n\nPlease note, if `backwards` is used in combination with `position`, the recorded\nevent at the given commit position will NOT be included. This differs from reading\nevents from a stream backwards from a stream position, when the recorded event at\nthe given stream position WILL be included.\n\nRead recorded events in a stream from a particular position.\n\n```python\nevents = list(client.read_all_events(position=commit_position1))\n\nassert len(events) == 3\n\nassert events[0].stream_name == stream_name1\nassert events[0].stream_position == 0\nassert events[0].type == event1.type\nassert events[0].data == event1.data\n\nassert events[1].stream_name == stream_name1\nassert events[1].stream_position == 1\nassert events[1].type == event2.type\nassert events[1].data == event2.data\n\nassert events[2].stream_name == stream_name1\nassert events[2].stream_position == 2\nassert events[2].type == event3.type\nassert events[2].data == event3.data\n```\n\nRead all the recorded events backwards from the end.\n\n```python\nevents = list(client.read_all_events(backwards=True))\n\nassert len(events) >= 3\n\nassert events[0].stream_name == stream_name1\nassert events[0].stream_position == 2\nassert events[0].type == event3.type\nassert events[0].data == event3.data\n\nassert events[1].stream_name == stream_name1\nassert events[1].stream_position == 1\nassert events[1].type == event2.type\nassert events[1].data == event2.data\n\nassert events[2].stream_name == stream_name1\nassert events[2].stream_position == 0\nassert events[2].type == event1.type\nassert events[2].data == event1.data\n```\n\nRead a limited number of recorded events from a specific commit position.\n\n```python\nevents = list(client.read_all_events(position=commit_position1, limit=1))\n\nassert len(events) == 1\n\nassert events[0].stream_name == stream_name1\nassert events[0].stream_position == 0\nassert events[0].type == event1.type\nassert events[0].data == event1.data\n```\n\nRead a limited number of recorded events backwards from the end.\n\n```python\nevents = list(client.read_all_events(backwards=True, limit=1))\n\nassert len(events) == 1\n\nassert events[0].stream_name == stream_name1\nassert events[0].stream_position == 2\nassert events[0].type == event3.type\nassert events[0].data == event3.data\n```\n\n### Catch-up subscriptions\n\nThe method `subscribe_all_events()` can be used to create a\n"catch-up subscription" to EventStoreDB. The optional argument\n`position` can be used to specify a commit position from which\nto receive recorded events. Please note, returned events are those\nafter the given commit position.\n\nThis method returns an iterable object, a `CatchupSubscription`,\nfrom which recorded events can be obtained by iterating over the\nsubscription object.\n\nThe recorded events can be processed. The commit position of\nthe recorded event should be stored atomically with the results\nof processing the event. The value of the `position` argument can\nthen be determined by reading the recorded commit position. This\nwill accomplish "exactly once" processing of the events, from the\npoint of view of the recorded results of processing the events, so\nlong as there is a uniqueness constraint on the recorded commit\nposition.\n\n\n```python\n\n# Get the current commit position.\ncommit_position = client.get_commit_position()\n\n# Append three more events.\nstream_name = str(uuid4())\nevent1 = NewEvent(type="OrderCreated", data=b"", metadata=b"{}")\nevent2 = NewEvent(type="OrderUpdated", data=b"", metadata=b"{}")\nevent3 = NewEvent(type="OrderDeleted", data=b"", metadata=b"{}")\nclient.append_events(\n    stream_name, expected_position=None, events=[event1, event2, event3]\n)\n\n# Subscribe from the last commit position.\nsubscription = client.subscribe_all_events(position=commit_position)\n\n# Check the stream name of the newly received events.\nevents = []\nfor event in subscription:\n    assert event.stream_name == stream_name\n    events.append(event)\n    if len(events) == 3:\n        break\n\ndel subscription\n```\n\nThe `CatchupSubscription` subscription object might be used within a thread,\nwith recorded events put on a queue, for processing in a different thread.\nHowever, this client doesn\'t provide such a thing.\n\n### The NewEvent class\n\nThe `NewEvent` class can be used to define new events.\n\nThe attribute `type` is a unicode string, used to specify the type of the event\nto be recorded.\n\nThe attribute `data` is a byte string, used to specify the data of the event\nto be recorded.\n\nThe attribute `metadata` is a byte string, used to specify metadata for the event\nto be recorded.\n\n```python\nnew_event = NewEvent(\n    type="OrderCreated",\n    data=b"{}",\n    metadata=b"{}",\n)\n```\n\n### The RecordedEvent class\n\nThe `RecordedEvent` class is used when reading recorded events.\n\nThe attribute `type` is a unicode string, used to indicate the type of the event\nthat was recorded.\n\nThe attribute `data` is a byte string, used to specify the data of the event\nthat was recorded.\n\nThe attribute `metadata` is a byte string, used to specify metadata for the event\nthat was recorded.\n\nThe attribute `stream_name` is a unicode string, used to indicate the type of\nthe name of the stream in which the event was recorded.\n\nThe attribute `stream_position` is an integer, used to indicate\nthe position in the stream at which the event was recorded.\n\nThe attribute `commit_position` is an integer, used to indicate\nthe position in total order of all recorded events at which the\nevent was recorded.\n\n```python\n\nfrom esdbclient.events import RecordedEvent\n\nnew_event = RecordedEvent(\n    type="OrderCreated",\n    data=b"{}",\n    metadata=b"{}",\n    stream_name="stream1",\n    stream_position=0,\n    commit_position=512,\n)\n```\n\n### Stop EventStoreDB\n\nUse Docker to stop and remove the EventStoreDB container.\n\n    $ docker stop my-eventstoredb\n\t$ docker rm my-eventstoredb\n\n\n## Developers\n\nClone the project repository, set up a virtual environment, and install\ndependencies.\n\nUse your IDE (e.g. PyCharm) to open the project repository. Create a\nPoetry virtual environment, and then update packages.\n\n    $ make update-packages\n\nAlternatively, use the ``make install`` command to create a dedicated\nPython virtual environment for this project.\n\n    $ make install\n\nThe ``make install`` command uses the build tool Poetry to create a dedicated\nPython virtual environment for this project, and installs popular development\ndependencies such as Black, isort and pytest.\n\nAdd tests in `./tests`. Add code in `./esdbclient`.\n\nStart EventStoreDB.\n\n    $ make start-eventstoredb\n\nRun tests.\n\n    $ make test\n\nStop EventStoreDB.\n\n    $ make stop-eventstoredb\n\nCheck the formatting of the code.\n\n    $ make lint\n\nReformat the code.\n\n    $ make fmt\n\nAdd dependencies in `pyproject.toml` and then update installed packages.\n\n    $ make update-packages\n',
    'author': 'John Bywater',
    'author_email': 'john.bywater@appropriatesoftware.net',
    'maintainer': None,
    'maintainer_email': None,
    'url': 'https://github.com/pyeventsourcing/esdbclient',
    'packages': packages,
    'package_data': package_data,
    'install_requires': install_requires,
    'python_requires': '>=3.7,<4.0',
}


setup(**setup_kwargs)
