{ "info": { "author": "Caleb Hattingh", "author_email": "caleb.hattingh@gmail.com", "bugtrack_url": null, "classifiers": [ "License :: OSI Approved :: Apache Software License", "Natural Language :: English", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7" ], "description": ".. image:: https://travis-ci.org/cjrh/aiorun.svg?branch=master\n :target: https://travis-ci.org/cjrh/aiorun\n\n.. image:: https://coveralls.io/repos/github/cjrh/aiorun/badge.svg?branch=master\n :target: https://coveralls.io/github/cjrh/aiorun?branch=master\n\n.. image:: https://img.shields.io/pypi/pyversions/aiorun.svg\n :target: https://pypi.python.org/pypi/aiorun\n\n.. image:: https://img.shields.io/github/tag/cjrh/aiorun.svg\n :target: https://img.shields.io/github/tag/cjrh/aiorun.svg\n\n.. image:: https://img.shields.io/badge/install-pip%20install%20aiorun-ff69b4.svg\n :target: https://img.shields.io/badge/install-pip%20install%20aiorun-ff69b4.svg\n\n.. image:: https://img.shields.io/pypi/v/aiorun.svg\n :target: https://img.shields.io/pypi/v/aiorun.svg\n\n.. image:: https://img.shields.io/badge/calver-YYYY.MM.MINOR-22bfda.svg\n :target: http://calver.org/\n\n\n\ud83c\udfc3 aiorun\n======================\n\nHere's the big idea (how you use it):\n\n.. code-block:: python\n\n import asyncio\n from aiorun import run\n\n async def main():\n # Put your application code here\n await asyncio.sleep(1.0)\n\n if __name__ == '__main__':\n run(main())\n\nThis package provides a ``run()`` function as the starting point\nof your ``asyncio``-based application. The ``run()`` function will\nrun forever. If you want to shut down when ``main()`` completes, just\ncall ``loop.stop()`` inside it: that will initiate shutdown.\n\n\ud83e\udd14 Why?\n----------------\n\nThe ``run()`` function will handle **everything** that normally needs\nto be done during the shutdown sequence of the application. All you\nneed to do is write your coroutines and run them.\n\nSo what the heck does ``run()`` do exactly?? It does these standard,\nidiomatic actions for asyncio apps:\n\n- creates a ``Task`` for the given coroutine (schedules it on the\n event loop),\n- calls ``loop.run_forever()``,\n- adds default (and smart) signal handlers for both ``SIGINT``\n and ``SIGTERM`` that will stop the loop;\n- and *when* the loop stops (either by signal or called directly), then it will...\n- ...gather all outstanding tasks,\n- cancel them using ``task.cancel()``,\n- resume running the loop until all those tasks are done,\n- wait for the *executor* to complete shutdown, and\n- finally close the loop.\n\nAll of this stuff is boilerplate that you will never have to write\nagain. So, if you use ``aiorun`` this is what **you** need to remember:\n\n- Spawn all your work from a single, starting coroutine\n- When a shutdown signal is received, **all** currently-pending tasks\n will have ``CancelledError`` raised internally. It's up to you whether\n you want to handle this inside each coroutine with\n a ``try/except`` or not.\n- If you want to protect coros from cancellation, see `shutdown_waits_for()`\n further down.\n- Try to have executor jobs be shortish, since the shutdown process will wait\n for them to finish. If you need a long-running thread or process tasks, use\n a dedicated thread/subprocess and set ``daemon=True`` instead.\n\nThere's not much else to know for general use. `aiorun` has a few special\ntools that you might need in unusual circumstances. These are discussed\nnext.\n\n\ud83d\udda5\ufe0f What about TCP server startup?\n-----------------------------------\n\nYou will see in many examples online that for servers, startup happens in\nseveral ``run_until_complete()`` phases before the primary ``run_forever()``\nwhich is the \"main\" running part of the program. How do we handle that with\n*aiorun*?\n\nLet's recreate the `echo client & server `_\nexamples from the Standard Library documentation:\n\n**Client:**\n\n.. code-block:: python\n\n # echo_client.py\n import asyncio\n from aiorun import run\n\n async def tcp_echo_client(message):\n # Same as original!\n reader, writer = await asyncio.open_connection('127.0.0.1', 8888)\n print('Send: %r' % message)\n writer.write(message.encode())\n data = await reader.read(100)\n print('Received: %r' % data.decode())\n print('Close the socket')\n writer.close()\n asyncio.get_event_loop().stop() # Exit after one msg like original\n\n message = 'Hello World!'\n run(tcp_echo_client(message))\n\n**Server:**\n\n.. code-block:: python\n\n import asyncio\n from aiorun import run\n\n async def handle_echo(reader, writer):\n # Same as original!\n data = await reader.read(100)\n message = data.decode()\n addr = writer.get_extra_info('peername')\n print(\"Received %r from %r\" % (message, addr))\n print(\"Send: %r\" % message)\n writer.write(data)\n await writer.drain()\n print(\"Close the client socket\")\n writer.close()\n\n async def main():\n server = await asyncio.start_server(handle_echo, '127.0.0.1', 8888)\n print('Serving on {}'.format(server.sockets[0].getsockname()))\n try:\n # Wait for cancellation\n while True:\n await asyncio.sleep(10)\n except asyncio.CancelledError:\n server.close()\n await server.wait_closed()\n\n run(main())\n\nIt works the same as the original examples, except you see this\nwhen you hit ``CTRL-C`` on the server instance:\n\n.. code-block:: bash\n\n $ python echo_server.py\n Running forever.\n Serving on ('127.0.0.1', 8888)\n Received 'Hello World!' from ('127.0.0.1', 57198)\n Send: 'Hello World!'\n Close the client socket\n ^CStopping the loop\n Entering shutdown phase.\n Cancelling pending tasks.\n Cancelling task: \n Running pending tasks till complete\n Waiting for executor shutdown.\n Leaving. Bye!\n\nTask gathering, cancellation, and executor shutdown all happen\nautomatically.\n\n\ud83d\udca8 Do you like `uvloop `_?\n------------------------------------------------------------------\n\n.. code-block:: python\n\n import asyncio, aiorun\n\n async def main():\n \n\n if __name__ == '__main__':\n run(main(), use_uvloop=True)\n\nNote that you have to ``pip install uvloop`` yourself.\n\n\ud83d\udee1\ufe0f Smart shield for shutdown\n---------------------------------\n\nIt's unusual, but sometimes you're going to want a coroutine to not get\ninterrupted by cancellation *during the shutdown sequence*. You'll look in\nthe official docs and find ``asyncio.shield()``.\n\nUnfortunately, ``shield()`` doesn't work in shutdown scenarios because\nthe protection offered by ``shield()`` only applies if the specific coroutine\n*inside which* the ``shield()`` is used, gets cancelled directly.\n\nLet me explain: if you do a conventional shutdown sequence (like ``aiorun``\nis doing internally), this is the sequence of steps:\n\n- ``tasks = all_tasks()``, followed by\n- ``group = gather(*tasks)``, and then\n- ``group.cancel()``\n\nThe way ``shield()`` works internally is it creates a *secret, inner*\ntask\u2014which also gets included in the ``all_tasks()`` call above! Thus\nit also receives a cancellation signal just like everything else.\n\nTherefore, we have an alternative version of ``shield()`` that works better for\nus: ``shutdown_waits_for()``. If you've got a coroutine that must **not** be\ncancelled during the shutdown sequence, just wrap it in\n``shutdown_waits_for()``!\n\nHere's an example:\n\n.. code-block:: python\n\n import asyncio\n from aiorun import run, shutdown_waits_for\n\n async def corofn():\n await asyncio.sleep(60)\n print('done!')\n\n async def main():\n try:\n await shutdown_waits_for(corofn())\n except asyncio.CancelledError\n print('oh noes!')\n\n run(main())\n\nIf you hit ``CTRL-C`` *before* 60 seconds has passed, you will see\n``oh noes!`` printed immediately, and then after 60 seconds (since start),\n``done!`` is printed, and thereafter the program exits.\n\nBehind the scenes, ``all_tasks()`` would have been cancelled by ``CTRL-C``,\n*except* ones wrapped in ``shutdown_waits_for()`` calls. In this respect, it\nis loosely similar to ``asyncio.shield()``, but with special applicability\nto our shutdown scenario in ``aiorun()``.\n\nBe careful with this: the coroutine should still finish up at some point.\nThe main use case for this is short-lived tasks that you don't want to\nwrite explicit cancellation handling.\n\nOh, and you can use ``shutdown_waits_for()`` as if it were ``asyncio.shield()``\ntoo. For that use-case it works the same. If you're using ``aiorun``, there\nis no reason to use ``shield()``.\n", "description_content_type": "text/x-rst", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/cjrh/aiorun", "keywords": "", "license": "", "maintainer": "", "maintainer_email": "", "name": "graingert-aiorun", "package_url": "https://pypi.org/project/graingert-aiorun/", "platform": "", "project_url": "https://pypi.org/project/graingert-aiorun/", "project_urls": { "Homepage": "https://github.com/cjrh/aiorun" }, "release_url": "https://pypi.org/project/graingert-aiorun/2018.9.1/", "requires_dist": [ "typing; python_version < '3.5'", "pytest; extra == \"dev\"", "pytest-cov; extra == \"dev\"" ], "requires_python": "", "summary": "Boilerplate for asyncio applications", "version": "2018.9.1" }, "last_serial": 4968159, "releases": { "2018.9.1": [ { "comment_text": "", "digests": { "md5": "cfda4ac86ab6b03f157cebce0c684c5a", "sha256": "e451a9f1f0976ff59d90a30830a70a85a104e70577137daa182bd78e6888c049" }, "downloads": -1, "filename": "graingert_aiorun-2018.9.1-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "cfda4ac86ab6b03f157cebce0c684c5a", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 25088, "upload_time": "2019-03-21T13:43:12", "url": "https://files.pythonhosted.org/packages/eb/40/e15e0c6ab4f9506e87d26548e5cac05b68ea1da8545cdc95cde553746f79/graingert_aiorun-2018.9.1-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "fb34b653c44fc2198c1c3628233bec3c", "sha256": "4859e4b13807af55fb9c467d523e949c54379cd848f9702d95438500982b5f67" }, "downloads": -1, "filename": "graingert-aiorun-2018.9.1.tar.gz", "has_sig": false, "md5_digest": "fb34b653c44fc2198c1c3628233bec3c", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 14447, "upload_time": "2019-03-21T13:43:15", "url": "https://files.pythonhosted.org/packages/b2/66/7e05c65f246e7adfd6bec3215e969a79d30836b5765208cf4d32ca897c91/graingert-aiorun-2018.9.1.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "cfda4ac86ab6b03f157cebce0c684c5a", "sha256": "e451a9f1f0976ff59d90a30830a70a85a104e70577137daa182bd78e6888c049" }, "downloads": -1, "filename": "graingert_aiorun-2018.9.1-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "cfda4ac86ab6b03f157cebce0c684c5a", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 25088, "upload_time": "2019-03-21T13:43:12", "url": "https://files.pythonhosted.org/packages/eb/40/e15e0c6ab4f9506e87d26548e5cac05b68ea1da8545cdc95cde553746f79/graingert_aiorun-2018.9.1-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "fb34b653c44fc2198c1c3628233bec3c", "sha256": "4859e4b13807af55fb9c467d523e949c54379cd848f9702d95438500982b5f67" }, "downloads": -1, "filename": "graingert-aiorun-2018.9.1.tar.gz", "has_sig": false, "md5_digest": "fb34b653c44fc2198c1c3628233bec3c", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 14447, "upload_time": "2019-03-21T13:43:15", "url": "https://files.pythonhosted.org/packages/b2/66/7e05c65f246e7adfd6bec3215e969a79d30836b5765208cf4d32ca897c91/graingert-aiorun-2018.9.1.tar.gz" } ] }