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

packages = \
['eventsourcing_django',
 'eventsourcing_django.management.commands',
 'eventsourcing_django.migrations']

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

install_requires = \
['Django>=2.2.24,<5.0', 'eventsourcing>=9.2.13,<9.3.0']

setup_kwargs = {
    'name': 'eventsourcing-django',
    'version': '0.3',
    'description': 'Python package for eventsourcing with Django.',
    'long_description': '# Event Sourcing with Django\n\nThis package supports using the Python\n[eventsourcing](https://github.com/pyeventsourcing/eventsourcing) library\nwith [Django ORM](https://www.djangoproject.com/).\n\nTo use Django with your Python eventsourcing applications:\n* install the Python package `eventsourcing_django`\n* add `\'eventsourcing_django\'` to your Django project\'s `INSTALLED_APPS` setting\n* migrate your database for this Django app\n* set the environment variable `PERSISTENCE_MODULE` to `\'eventsourcing_django\'`\n\nSee below for more information.\n\n\n## Installation\n\nUse pip to install the [stable distribution](https://pypi.org/project/eventsourcing_django/)\nfrom the Python Package Index. Please note, it is recommended to\ninstall Python packages into a Python virtual environment.\n\n    $ pip install eventsourcing_django\n\n\n## Django\n\nIf you are using Django 3.2 or later, add `\'eventsourcing_django\'`\nto your Django project\'s `INSTALLED_APPS` setting.\n\n    INSTALLED_APPS = [\n        ...\n        \'eventsourcing_django\',\n    ]\n\nIf you are using Django 2.2, 3.0 or 3.1, please add\n`\'eventsourcing_django.apps.EventsourcingConfig\'` to your Django\nproject\'s `INSTALLED_APPS` setting.\n\n    INSTALLED_APPS = [\n        ...\n        \'eventsourcing_django.apps.EventsourcingConfig\',\n    ]\n\n\nTo migrate your database, please run Django\'s `manage.py migrate` command.\n\n    $ python manage.py migrate eventsourcing_django\n\n\n## Event sourcing\n\nDefine aggregates and applications in the usual way.\n\n```python\nfrom eventsourcing.application import Application\nfrom eventsourcing.domain import Aggregate, event\nfrom uuid import uuid5, NAMESPACE_URL\n\n\nclass TrainingSchool(Application):\n    def register(self, name):\n        dog = Dog(name)\n        self.save(dog)\n\n    def add_trick(self, name, trick):\n        dog = self.repository.get(Dog.create_id(name))\n        dog.add_trick(trick)\n        self.save(dog)\n\n    def get_tricks(self, name):\n        dog = self.repository.get(Dog.create_id(name))\n        return dog.tricks\n\n\nclass Dog(Aggregate):\n    @event(\'Registered\')\n    def __init__(self, name):\n        self.name = name\n        self.tricks = []\n\n    @staticmethod\n    def create_id(name):\n        return uuid5(NAMESPACE_URL, f\'/dogs/{name}\')\n\n    @event(\'TrickAdded\')\n    def add_trick(self, trick):\n        self.tricks.append(trick)\n```\nConstruct and use the application in the usual way.\nSet `PERSISTENCE_MODULE` to `\'eventsourcing_django\'`\nin the application\'s environment.\nYou may wish to construct the application object on a signal\nwhen the Django project is "ready". You can use the `ready()`\nmethod of the `AppConfig` class in the `apps.py` module of a\nDjango app.\n\n```python\nschool = TrainingSchool(env={\n    "PERSISTENCE_MODULE": "eventsourcing_django",\n})\n```\n\nThe application\'s methods may be called from Django views and forms.\n\n```python\nschool.register(\'Fido\')\nschool.add_trick(\'Fido\', \'roll over\')\nschool.add_trick(\'Fido\', \'play dead\')\ntricks = school.get_tricks(\'Fido\')\nassert tricks == [\'roll over\', \'play dead\']\n```\n\nFor more information, please refer to the Python\n[eventsourcing](https://github.com/johnbywater/eventsourcing) library\nand the [Django](https://www.djangoproject.com/) project.\n\n\n## Management Commands\n\nThe Django app `eventsourcing_django` ships with the following management commands.\n\n### Synchronise Followers\n\nManually synchronise followers (i.e. `ProcessApplication` instances) with all of their\nleaders, as defined in the `eventsourcing.system.System`\'s pipes.\n\n#### Usage\n\n```shell\n$ python manage.py sync_followers [-n] [-v {0,1,2,3}] [follower [follower ...]]\n```\n\nWhere `follower` denotes the name of a follower to synchronize. Not specifying any means\nsynchronising *all followers* found in the system.\n\nRelevant options:\n\n  - `-n`, `--dry-run`: Load and process all unseen events for the selected followers,\n    but roll back all changes at the end.\n  - `-v {0,1,2,3}`, `--verbosity {0,1,2,3}`: Verbosity level; 0=minimal output, 1=normal\n    output, 2=verbose output, 3=very verbose output.\n\nFor a full list of options, pass the `--help` flag to the command.\n\n#### Examples\n\n  - To synchronise all followers found in the runner:\n\n      ```shell\n      $ python manage.py sync_followers\n      ```\n\n  - To synchronise a single follower:\n\n      ```shell\n      $ python manage.py sync_followers TrainingSchool\n      ```\n\nThe command supports the regular `-v/--verbosity` optional argument, as well as a\n`-n/--dry-run` flag.\n\nNote that running the command in dry-run mode *will* pull and process every new\nevent, though the changes will eventually be rolled back.\n\n#### Error handling\n\nEach selected follower should have its own chance at synchronisation. Therefore, the\ncommand will catch some exceptions on a per-follower basis and continue with the\nremaining followers.\n\nThe base Django exceptions that are caught are `EmptyResultSet`, `FieldDoesNotExist`,\n`FieldError`, `MultipleObjectsReturned`, and `ObjectDoesNotExist`. The base exception\n`EventSourcingError` from the `eventsourcing` library is also caught per follower.\n\n### Configuration\n\nThis command needs to access a `eventsourcing.system.Runner` instance to query and act\non its followers. The runner\'s system is additionally the one defining the pipes between\nleaders and followers.\n\nThe default behaviour, without additional configuration, is to inspect all installed\nDjango apps and look for an instance of `eventsourcing.system.Runner`. The attribute\nname does not matter as long as it is public (i.e. not start with an underscore).\n\n```python\n# djangoproject/apps/my_es_app/apps.py\nimport eventsourcing.system\nfrom django.apps import AppConfig\n\n\nclass MyEventSourcedAppConfig(AppConfig):\n   name = "my_event_sourced_app"\n   runner: eventsourcing.system.Runner\n\n   def ready(self) -> None:\n       self.runner = eventsourcing.system.SingleThreadedRunner(\n           eventsourcing.system.System(...)\n       )\n```\n\nThis is usually enough unless you i) have multiple runners defined in one or more apps,\nor ii) do not hold the runner(s) in Django apps. In which case, you should configure the\nDjango setting `EVENTSOURCING_RUNNER` in one of two ways:\n\n1. Set `EVENTSOURCING_RUNNER` to an app name\'s attribute. This attribute must be a\n   `eventsourcing.system.Runner` instance.\n\n   ```python\n   # djangoproject/settings.py\n   ...\n   EVENTSOURCING_RUNNER = "my_event_sourced_app.runner"\n   ```\n\n2. Set `EVENTSOURCING_RUNNER` to a fully qualified function name. This function will be\n   called without arguments and should return a `eventsourcing.system.Runner` instance.\n\n   ```python\n   # djangoproject/settings.py\n   ...\n   EVENTSOURCING_RUNNER = "djangoproject.runner_utils.get_runner"\n   ```\n   ```python\n   # djangoproject/runner_utils.py\n   import eventsourcing.system\n\n\n   def get_runner() -> eventsourcing.system.Runner:\n      return ...\n   ```\n\nAll runner classes shipped with the `eventsourcing` library are compatible.\n',
    'author': 'John Bywater',
    'author_email': 'john.bywater@appropriatesoftware.net',
    'maintainer': None,
    'maintainer_email': None,
    'url': 'https://eventsourcing.readthedocs.io/',
    'packages': packages,
    'package_data': package_data,
    'install_requires': install_requires,
    'python_requires': '>=3.7,<4.0',
}


setup(**setup_kwargs)
