{ "info": { "author": "Thomas Feldmann", "author_email": "mail@tfeldmann.de", "bugtrack_url": null, "classifiers": [ "Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.6", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.2", "Programming Language :: Python :: 3.3", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5" ], "description": "|Build Status| |Coverage Status|\n\ntryagain\n========\n\nA lightweight and pythonic retry helper.\n\n``tryagain`` aims to simplify working with unstable functions. Whether\nyou have networking code that sometimes raises timeout exceptions or you\nare controlling devices which only seem to listen on the second try -\n``tryagain`` makes it easier to repeat the call.\n\n``tryagain`` offers you hooks to clean up after a failed attempt or to\nprepare for the next call. You can set a waittime between retries or\nspecify your own waittime function to realize exponential waittimes etc.\n\n``tryagain`` is lightweight, fully tested, MIT licensed and comes as a single\npython file with no dependencies. It supports Python 2.6+ and 3.2+.\n\nTo install, run ``pip install tryagain``.\n\n\nBasic syntax\n------------\nUsing the tryagain function ``call``:\n\n.. code:: python\n\n import tryagain\n\n def unstable_function():\n # Attention: This function sometimes fails!\n ...\n\n result = tryagain.call(unstable_function,\n max_attempts=None, exceptions=Exception, wait=0.0,\n cleanup_hook=None, pre_retry_hook=None)\n\nUsing the tryagain decorator ``retries``:\n\n.. code:: python\n\n from tryagain import retries\n\n @retries(max_attempts=3)\n def unstable_funcation(arg1, arg2):\n # Attention: This function sometimes fails!\n ...\n\n result = unstable_function('foo', arg2='bar')\n\n\nParameters\n~~~~~~~~~~\n\n- ``func``: The unstable function to call\n- ``max_attemps``: Any integer number to limit the maximum number of\n attempts. Set to None for unlimited retries. (Default = None)\n- ``exceptions``: An iterable of exceptions that should result in a\n retry. (Default = ``Exception``)\n- ``wait``: Can be an integer or float value (to specify a waittime in seconds) or a custom function (see Waittime documentation) (Default = 0.0)\n- ``cleanup_hook``: Can be set to a callable and will be called after\n an exception is raised from calling ``func``. (Default = None)\n- ``pre_retry_hook``: Can be set to any callable that will be called\n before ``func`` is called. (Default = None)\n\n\nResult\n~~~~~~\n\n``tryagain.call`` will return whatever the unstable function would\nreturn. ``tryagain.call`` (and the decorator ``tryagain.retries``) reraises\nany exception which is:\n\n- not in the given ``exceptions``\n- raised in the ``pre_retry_hook`` or in ``cleanup_hook``\n- raised in the last attempt at calling the unstable function.\n\n\nQuickstart\n----------\n\nRetry calling an unstable function\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n.. code:: python\n\n import tryagain\n\n def unstable():\n ...\n\n # retry calling 'unstable' until it returns without raising an exception\n result = tryagain.call(unstable)\n\n # limit to maximum 5 attempts\n result = tryagain.call(unstable, max_attempts=5)\n\n # only retry after specific exceptions\n result = tryagain.call(unstable, exceptions=(ValueError, TypeError))\n\n\nWaittimes\n~~~~~~~~~\n\nThe tryagain library allows fixed wait values as well as custom waittime\nfunctions.\n\n.. code:: python\n\n # wait one second before trying again\n tryagain.call(unstable, wait=1.0)\n\n # waittime rises linearly (n is the number of attempts)\n # (will wait 1s, 2s, 3s, ...)\n tryagain.call(unstable, wait=lambda n: n)\n\n # waittime rises exponentially with each attempt\n # (will wait 2s, 4s, 8s, ...)\n tryagain.call(unstable, wait=lambda n: 2 ** n)\n\n # exponentially rising waittime with maximum\n # (will wait 2s, 4s, 5s, 5s, ..., 5s)\n tryagain.call(unstable, wait=lambda n: min(n ** 2, 5))\n\n # no waiting time before second attempt, 1.0s afterwards\n def no_first_wait(attempt):\n if attempt == 2:\n return 0\n else:\n return 1.0\n tryagain.call(unstable, wait=no_first_wait)\n\n\nRetry calling a function with parameters\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nThe ``tryagain.call``-function only supports a function reference as the\n``func`` parameter. To pass arguments to the unstable function you have to use\none of the following idioms:\n\n.. code:: python\n\n # using a lambda\n tryagain.call(lambda: unstable('message', some_arg=True), wait=1.0)\n\n # using a partial\n from functools import partial\n tryagain.call(partial(unstable, 'message', some_arg=True), wait=1.0)\n\n # using a separate function\n def call_unstable_function():\n msg = 'message'\n return unstable(msg, some_arg=True)\n tryagain.call(call_unstable_function, wait=1.0)\n\nBut it is much nicer to wrap your unstable function in the ``@retries``\ndecorator.\nThis way you can call your unstable function with parameters easily:\n\n\nFunction decorator\n~~~~~~~~~~~~~~~~~~\n\nInstead of using the ``tryagain.call`` function, you can use the ``retries``\ndecorator.\n\n.. code:: python\n\n from tryagain import retries\n @retries(max_attempts=3, exceptions=(TypeError, ValueError))\n def unstable(arg1, arg2):\n # your unstable function here\n\n result = unstable('foo', arg2='bar')\n\nThe decorator takes the same arguments as the ``call``-function\nexcept the ``func`` parameter.\n\n\nHooks\n~~~~~\n\nThe tryagain library features two hooks that can be used,\n``cleanup_hook`` and ``pre_retry_hook``.\n\n.. code:: python\n\n\n def unstable():\n print('Calling unstable function')\n print('Exception!')\n raise Exception\n\n tryagain.call(unstable, max_attempts=2,\n wait=lambda n: print('waiting'),\n cleanup_hook=lambda: print('cleaning up'),\n pre_retry_hook=lambda: print('do preparations'))\n 'Calling unstable function'\n 'Exception!'\n 'cleaning up'\n 'waiting'\n 'do preparations'\n 'Calling unstable function'\n 'Exception!'\n 'cleaning up'\n Error: Exception raised...\n\n\n.. |Build Status| image:: https://travis-ci.org/tfeldmann/tryagain.svg?branch=master\n :target: https://travis-ci.org/tfeldmann/tryagain\n.. |Coverage Status| image:: https://coveralls.io/repos/github/tfeldmann/tryagain/badge.svg?branch=master\n :target: https://coveralls.io/github/tfeldmann/tryagain?branch=master", "description_content_type": null, "docs_url": null, "download_url": "UNKNOWN", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/tfeldmann/tryagain", "keywords": "retry,unstable,tryagain,redo,try,again,exception", "license": "MIT", "maintainer": null, "maintainer_email": null, "name": "tryagain", "package_url": "https://pypi.org/project/tryagain/", "platform": "UNKNOWN", "project_url": "https://pypi.org/project/tryagain/", "project_urls": { "Download": "UNKNOWN", "Homepage": "https://github.com/tfeldmann/tryagain" }, "release_url": "https://pypi.org/project/tryagain/1.0/", "requires_dist": null, "requires_python": null, "summary": "A lightweight and pythonic retry helper", "version": "1.0" }, "last_serial": 2286301, "releases": { "0.9": [ { "comment_text": "", "digests": { "md5": "1ae5db748065fcbcd8f30b8ca0489e44", "sha256": "b7b29146c26131eb9896c765b1d09f6091e3b502a866dd0b605f0e0fafd96102" }, "downloads": -1, "filename": "tryagain-0.9-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "1ae5db748065fcbcd8f30b8ca0489e44", "packagetype": "bdist_wheel", "python_version": "3.5", "requires_python": null, "size": 7214, "upload_time": "2016-02-12T14:33:57", "url": "https://files.pythonhosted.org/packages/e5/02/7ac70e6cc69e8acfaf7535c0211b7bad0e92041ecf18dcd197cbaf685f4a/tryagain-0.9-py2.py3-none-any.whl" } ], "1.0": [ { "comment_text": "", "digests": { "md5": "77fb71bc24be623034c075be592baa0f", "sha256": "34861fe1fa3a20dd4d2627697c6b890ad1d5b54a06c79dab15130c1f3458703f" }, "downloads": -1, "filename": "tryagain-1.0-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "77fb71bc24be623034c075be592baa0f", "packagetype": "bdist_wheel", "python_version": "3.5", "requires_python": null, "size": 7826, "upload_time": "2016-04-27T07:14:02", "url": "https://files.pythonhosted.org/packages/5c/0b/07f6730638e813103b76c7b6f586b344978829ad76b69a9a9f1adac7fc95/tryagain-1.0-py2.py3-none-any.whl" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "77fb71bc24be623034c075be592baa0f", "sha256": "34861fe1fa3a20dd4d2627697c6b890ad1d5b54a06c79dab15130c1f3458703f" }, "downloads": -1, "filename": "tryagain-1.0-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "77fb71bc24be623034c075be592baa0f", "packagetype": "bdist_wheel", "python_version": "3.5", "requires_python": null, "size": 7826, "upload_time": "2016-04-27T07:14:02", "url": "https://files.pythonhosted.org/packages/5c/0b/07f6730638e813103b76c7b6f586b344978829ad76b69a9a9f1adac7fc95/tryagain-1.0-py2.py3-none-any.whl" } ] }