{"id":17334818,"url":"https://github.com/tfeldmann/tryagain","last_synced_at":"2025-04-14T18:14:15.505Z","repository":{"id":57723396,"uuid":"47896360","full_name":"tfeldmann/tryagain","owner":"tfeldmann","description":"A simple and pythonic retry helper for calling unstable functions","archived":false,"fork":false,"pushed_at":"2019-05-22T09:01:43.000Z","size":38,"stargazers_count":10,"open_issues_count":1,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-28T06:41:18.534Z","etag":null,"topics":["helpers","library","python"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tfeldmann.png","metadata":{"files":{"readme":"README.rst","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-12-12T22:07:00.000Z","updated_at":"2022-08-21T22:52:18.000Z","dependencies_parsed_at":"2022-09-02T06:54:05.391Z","dependency_job_id":null,"html_url":"https://github.com/tfeldmann/tryagain","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tfeldmann%2Ftryagain","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tfeldmann%2Ftryagain/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tfeldmann%2Ftryagain/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tfeldmann%2Ftryagain/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tfeldmann","download_url":"https://codeload.github.com/tfeldmann/tryagain/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248602279,"owners_count":21131614,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["helpers","library","python"],"created_at":"2024-10-15T15:07:15.444Z","updated_at":"2025-04-14T18:14:15.480Z","avatar_url":"https://github.com/tfeldmann.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"|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\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftfeldmann%2Ftryagain","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftfeldmann%2Ftryagain","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftfeldmann%2Ftryagain/lists"}