{ "info": { "author": "Sebastian Buczy\u0144ski", "author_email": "nnplaya@gmail.com", "bugtrack_url": null, "classifiers": [ "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Programming Language :: Python :: 3" ], "description": "Pythonic implementations of Command and Event Buses \n====\n[![Build Status](https://travis-ci.org/Enforcer/pycommand_bus.svg?branch=master)](https://travis-ci.org/Enforcer/pycommand_bus)\n[![Coverage Status](https://coveralls.io/repos/github/Enforcer/pycommand_bus/badge.svg)](https://coveralls.io/github/Enforcer/pycommand_bus)\n\nZero-dependencies, flexible implementation of Command Bus. *Python 3.6+ only*\n## Basic usage of CommandBus\n```python\nfrom typing import List\n\nfrom pybuses import CommandBus\n\n\n# Firstly, create command class\nclass MakeSandwich:\n def __init__(self, ingredients: List[str]) -> None:\n self.ingredients = ingredients\n\n\n# Then create callable responsible for handling command.\n# It must accept only one argument and is required to have type annotation for it.\ndef sandwich_maker(command: MakeSandwich) -> None:\n print(f'Making sandwich with {command.ingredients}!')\n\n\n# finally, register the handler by subscribing\ncommand_bus = CommandBus()\ncommand_bus.subscribe(sandwich_maker)\ncommand_bus.handle(MakeSandwich(['cheese', 'ham']))\n```\n\n## Middlewares\nMiddlewares are lightweight plugins that let us inject custom logic before and after given command was handled.\n\nContext managers are for now the only supported way of defining middlewares. They simplify exception handling and specifying whether middleware logic should be executed before or after handling event. \n```python\nimport contextlib\nfrom typing import (\n Any,\n Generator,\n)\n\n@contextlib.contextmanager\ndef example_middleware(command: Any) -> Generator:\n print(f'Before handling {command}')\n yield\n print(f'After handling {command}')\n\n\ncommand_bus = CommandBus([example_middleware])\ncommand_bus.subscribe(sandwich_maker)\ncommand_bus.handle(MakeSandwich(['cheese', 'ham']))\n```\n\n\n## Basic usage of EventBus\n```python\nfrom decimal import Decimal\n\nfrom pybuses import EventBus\n\n\n# Create event\nclass PaymentMade:\n amount: Decimal\n who: int\n\n def __init__(self, amount: Decimal, who: int) -> None:\n self.amount = amount\n self.who = who\n\n\ndef handler(payment_made: PaymentMade) -> None:\n print(f'Oh, cool! {payment_made.who} paid {payment_made.amount / 100}$!')\n\n\nevent_bus = EventBus()\nevent_bus.subscribe(handler)\nevent_bus.post(PaymentMade(Decimal('10.99'), 123))\n```\n\n## Similarities & differences between Event- and CommandBus\nEventBus can have 0 or many handlers subscribed to every event, while CommandBus must have exactly one handler for each command.\n\nCommandBus supports middlewares while EventBus does not.\n\n\n## data classes compatible\nUsing [dataclasses](https://docs.python.org/3/library/dataclasses.html) for building commands/events is supported\n```python\nfrom dataclasses import dataclass\nfrom typing import List\n\nfrom pybuses import CommandBus\n\n\n@dataclass\nclass MakeSandwich:\n ingredients: List[str]\n\n\ndef handler(command: MakeSandwich) -> None:\n print(f'dataclass-based command: {command}')\n\n\ncommand_bus = CommandBus()\ncommand_bus.subscribe(handler)\ncommand_bus.handle(MakeSandwich(['ham', 'butter']))\n```\n\n## attrs compatible\nUsing [attrs](http://attrs.org/) for building commands/events is supported\n```python\nimport attr\nfrom pybuses import CommandBus\n\n\n@attr.s(frozen=True)\nclass Example:\n number: int = attr.ib()\n name: str = attr.ib()\n\n\ndef example_handler(command: Example) -> None:\n print(f'Inside handler of {type(command)} - got {command}!')\n\n\ncommand_bus = CommandBus()\ncommand_bus.subscribe(example_handler)\ncommand_bus.handle(Example(number=1, name='Sebastian'))\n```\n\n\n", "description_content_type": "text/markdown", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/Enforcer/pybuses", "keywords": "", "license": "", "maintainer": "", "maintainer_email": "", "name": "pybuses", "package_url": "https://pypi.org/project/pybuses/", "platform": "", "project_url": "https://pypi.org/project/pybuses/", "project_urls": { "Homepage": "https://github.com/Enforcer/pybuses" }, "release_url": "https://pypi.org/project/pybuses/1.1.0/", "requires_dist": null, "requires_python": "", "summary": "Pythonic Command & Event buses", "version": "1.1.0" }, "last_serial": 4746855, "releases": { "1.0.0": [ { "comment_text": "", "digests": { "md5": "aa92441f3922cd6911c289b9eeb93155", "sha256": "e922af50a40b8b7f8057648c87b5b82bd3e5deefc904e20d0407d8c5a942a88c" }, "downloads": -1, "filename": "pybuses-1.0.0-py3-none-any.whl", "has_sig": false, "md5_digest": "aa92441f3922cd6911c289b9eeb93155", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 6957, "upload_time": "2019-01-07T20:33:43", "url": "https://files.pythonhosted.org/packages/3f/96/034a45dcf09d8c2536251d2181d897fdf5fa595869bca9fe7df43c6cff61/pybuses-1.0.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "49467f0f4da78df9f2d171e8b234d00d", "sha256": "adbac8e6bf0dab96e7d2cf39128660a8c97960152bb3d338c5dba1f918da13d7" }, "downloads": -1, "filename": "pybuses-1.0.0.tar.gz", "has_sig": false, "md5_digest": "49467f0f4da78df9f2d171e8b234d00d", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 4373, "upload_time": "2019-01-07T20:33:45", "url": "https://files.pythonhosted.org/packages/96/58/c705252f5fb2c148aec365c070b31fdbb543ff03b060bcf609fa04cce273/pybuses-1.0.0.tar.gz" } ], "1.1.0": [ { "comment_text": "", "digests": { "md5": "0c9fd1bdceeeeda400d84e30fd494da7", "sha256": "3c28d261c69ece867fbb4af3cdb6a7ffb76425b6c8c0f2dc4aa7fdec78147dfd" }, "downloads": -1, "filename": "pybuses-1.1.0-py3-none-any.whl", "has_sig": false, "md5_digest": "0c9fd1bdceeeeda400d84e30fd494da7", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 7060, "upload_time": "2019-01-27T18:42:49", "url": "https://files.pythonhosted.org/packages/98/4b/5dc1e0b60d2806c7fcdf108f852a09dcef03316d100c295a8087d7665b2f/pybuses-1.1.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "905d93de31c5939f36bc1b822637906b", "sha256": "ef69ba58be97d0747b47c29bdcb06621909fe00ae778b5da87fc995a09348e7a" }, "downloads": -1, "filename": "pybuses-1.1.0.tar.gz", "has_sig": false, "md5_digest": "905d93de31c5939f36bc1b822637906b", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 4453, "upload_time": "2019-01-27T18:42:51", "url": "https://files.pythonhosted.org/packages/e1/95/23f0e6b0c8f300eb8a6e26ea6b9921c5bcb78a2507cd08774788a220b1c0/pybuses-1.1.0.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "0c9fd1bdceeeeda400d84e30fd494da7", "sha256": "3c28d261c69ece867fbb4af3cdb6a7ffb76425b6c8c0f2dc4aa7fdec78147dfd" }, "downloads": -1, "filename": "pybuses-1.1.0-py3-none-any.whl", "has_sig": false, "md5_digest": "0c9fd1bdceeeeda400d84e30fd494da7", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 7060, "upload_time": "2019-01-27T18:42:49", "url": "https://files.pythonhosted.org/packages/98/4b/5dc1e0b60d2806c7fcdf108f852a09dcef03316d100c295a8087d7665b2f/pybuses-1.1.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "905d93de31c5939f36bc1b822637906b", "sha256": "ef69ba58be97d0747b47c29bdcb06621909fe00ae778b5da87fc995a09348e7a" }, "downloads": -1, "filename": "pybuses-1.1.0.tar.gz", "has_sig": false, "md5_digest": "905d93de31c5939f36bc1b822637906b", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 4453, "upload_time": "2019-01-27T18:42:51", "url": "https://files.pythonhosted.org/packages/e1/95/23f0e6b0c8f300eb8a6e26ea6b9921c5bcb78a2507cd08774788a220b1c0/pybuses-1.1.0.tar.gz" } ] }