{ "info": { "author": "Clemens Koza", "author_email": "koza@pria.at", "bugtrack_url": null, "classifiers": [ "Development Status :: 4 - Beta", "Intended Audience :: Developers", "License :: OSI Approved :: GNU Affero General Public License v3 or later (AGPLv3+)", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.7", "Topic :: Software Development" ], "description": "Concurrent Utils\n================\n\nMaster: |travis-master|_ |coveralls-master|_\n\nDevelop: |travis-develop|_ |coveralls-develop|_\n\n.. |travis-master| image:: https://travis-ci.org/SillyFreak/ConcurrentUtils.svg?branch=master\n.. _travis-master: https://travis-ci.org/SillyFreak/ConcurrentUtils\n.. |coveralls-master| image:: https://coveralls.io/repos/github/SillyFreak/ConcurrentUtils/badge.svg?branch=master\n.. _coveralls-master: https://coveralls.io/github/SillyFreak/ConcurrentUtils?branch=master\n.. |travis-develop| image:: https://travis-ci.org/SillyFreak/ConcurrentUtils.svg?branch=develop\n.. _travis-develop: https://travis-ci.org/SillyFreak/ConcurrentUtils\n.. |coveralls-develop| image:: https://coveralls.io/repos/github/SillyFreak/ConcurrentUtils/badge.svg?branch=develop\n.. _coveralls-develop: https://coveralls.io/github/SillyFreak/ConcurrentUtils?branch=develop\n\n----\n\nConcurrency utilities for Python 3.7 + asyncio; the main portion is a component abstraction.\nTo support this, some pipe implementations for inter-task, inter-thread, and inter-process communication\nand some serialization utilities are provided as well.\nInter-process communication is based on ZeroMQ.\nFinally a class ``EventLoopThread`` is provided that can be used for bridging synchronous and asynchronous code.\n\nA \"component\" is code that is executing on its own, like an asyncio task, a thread, a worker thread's load, or a process.\nComponents process commands issued by their owner, and create events to be handler by their owner.\nComponents may also produce a result, and of course may communicate with other entities than their owner.\n\nAlthough asyncio is used heavily, the connection between a workload and its owner decouples the two\nto allow for any model of concurrency.\nHere is an example, taken and adapted from the test suite::\n\n import asyncio\n from concurrent.futures import ThreadPoolExecutor\n\n from concurrent_utils.component import Component, component_workload, start_component_in_thread\n\n\n async def test_thread_component_result_success_and_command():\n @component_workload\n async def component(x, *, commands, events):\n await events.send(Component.EVENT_START)\n ### startup complete\n\n # reply to command\n await commands.send(await commands.recv() + 1)\n\n # return\n return x\n\n e = ThreadPoolExecutor(1)\n comp = await start_component_in_thread(e, component, 1)\n\n assert await comp.request(1) == 2\n\n assert await comp.result() == 1\n\n\n asyncio.run(test_thread_component_result_success_and_command())\n\nAlthough the component is defined as a coroutine, it is (in this case) not executed on the owner's event loop.\nThe same component could, without modification, be run on the owner's event loop,\nor, with minor modifications to make the ``component`` function pickle-able, be run in a worker process instead.\n\n\n", "description_content_type": "", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/SillyFreak/ConcurrentUtils", "keywords": "asyncio concurrency", "license": "AGPLv3+", "maintainer": "", "maintainer_email": "", "name": "concurrent-utils", "package_url": "https://pypi.org/project/concurrent-utils/", "platform": "", "project_url": "https://pypi.org/project/concurrent-utils/", "project_urls": { "Homepage": "https://github.com/SillyFreak/ConcurrentUtils" }, "release_url": "https://pypi.org/project/concurrent-utils/0.2.0/", "requires_dist": [ "pytest; extra == 'dev'", "pytest-runner; extra == 'dev'", "pytest-asyncio; extra == 'dev'", "pytest-cov; extra == 'dev'", "pytest-timeout; extra == 'dev'", "mypy; extra == 'dev'", "msgpack; extra == 'msgpack'", "pyzmq; extra == 'zmq'" ], "requires_python": "", "summary": "concurrent-utils", "version": "0.2.0" }, "last_serial": 4444739, "releases": { "0.1.0": [ { "comment_text": "", "digests": { "md5": "53982b875fe6021253117557b5a865d7", "sha256": "11298aaaccd58e74c400379a69035d23e419bdbf5531268bd4db9864f99bd83f" }, "downloads": -1, "filename": "concurrent_utils-0.1.0-py3-none-any.whl", "has_sig": false, "md5_digest": "53982b875fe6021253117557b5a865d7", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 23802, "upload_time": "2018-10-29T09:54:51", "url": "https://files.pythonhosted.org/packages/31/36/2693611020894136798b487d88699be03770c50524d00bd68aa38012f8a1/concurrent_utils-0.1.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "6ef3bbe074840a1bb61b00c9b015ac0f", "sha256": "8c900769c688155fcfca5e99c32d7013e50812b7c4255be2bd60a49c0966c79f" }, "downloads": -1, "filename": "concurrent-utils-0.1.0.tar.gz", "has_sig": false, "md5_digest": "6ef3bbe074840a1bb61b00c9b015ac0f", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 23870, "upload_time": "2018-10-29T09:54:53", "url": "https://files.pythonhosted.org/packages/1e/2e/943f761cc0b6e62a947217da190139b8247da3e3d2d187c85670d0b806ee/concurrent-utils-0.1.0.tar.gz" } ], "0.2.0": [ { "comment_text": "", "digests": { "md5": "8b56d86052013e0d1b81a6723be88093", "sha256": "17b0b27d55c2478d885ccde7a0efa76bdf058963b05227d5ea98e898cb0f8a82" }, "downloads": -1, "filename": "concurrent_utils-0.2.0-py3-none-any.whl", "has_sig": false, "md5_digest": "8b56d86052013e0d1b81a6723be88093", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 25044, "upload_time": "2018-11-02T14:23:00", "url": "https://files.pythonhosted.org/packages/1a/f8/6dfa43d24666cf674c768351631a4840ffe80935ce039bd4652bd40584dd/concurrent_utils-0.2.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "3ee675e56d16c11f10675e136da480b0", "sha256": "2c9986689e9e2bff125871e2a5b128162ed00f14bd875c32057b1f9f9d6ce7b4" }, "downloads": -1, "filename": "concurrent-utils-0.2.0.tar.gz", "has_sig": false, "md5_digest": "3ee675e56d16c11f10675e136da480b0", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 24760, "upload_time": "2018-11-02T14:23:02", "url": "https://files.pythonhosted.org/packages/e0/97/e4950888d094cca2fbfb55f146314c01e2a432c3f558b96ad4d26d32416c/concurrent-utils-0.2.0.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "8b56d86052013e0d1b81a6723be88093", "sha256": "17b0b27d55c2478d885ccde7a0efa76bdf058963b05227d5ea98e898cb0f8a82" }, "downloads": -1, "filename": "concurrent_utils-0.2.0-py3-none-any.whl", "has_sig": false, "md5_digest": "8b56d86052013e0d1b81a6723be88093", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 25044, "upload_time": "2018-11-02T14:23:00", "url": "https://files.pythonhosted.org/packages/1a/f8/6dfa43d24666cf674c768351631a4840ffe80935ce039bd4652bd40584dd/concurrent_utils-0.2.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "3ee675e56d16c11f10675e136da480b0", "sha256": "2c9986689e9e2bff125871e2a5b128162ed00f14bd875c32057b1f9f9d6ce7b4" }, "downloads": -1, "filename": "concurrent-utils-0.2.0.tar.gz", "has_sig": false, "md5_digest": "3ee675e56d16c11f10675e136da480b0", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 24760, "upload_time": "2018-11-02T14:23:02", "url": "https://files.pythonhosted.org/packages/e0/97/e4950888d094cca2fbfb55f146314c01e2a432c3f558b96ad4d26d32416c/concurrent-utils-0.2.0.tar.gz" } ] }