rtry


Namertry JSON
Version 1.5.0 PyPI version JSON
download
home_pagehttps://github.com/tsv1/rtry
SummaryThe easiest way to retry operations
upload_time2023-06-22 17:00:40
maintainer
docs_urlNone
authorNikita Tsvetkov
requires_python>=3.7
licenseMIT
keywords
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # rtry

[![Codecov](https://img.shields.io/codecov/c/github/tsv1/rtry/master.svg?style=flat-square)](https://codecov.io/gh/tsv1/rtry)
[![PyPI](https://img.shields.io/pypi/v/rtry.svg?style=flat-square)](https://pypi.python.org/pypi/rtry/)
[![PyPI - Downloads](https://img.shields.io/pypi/dm/rtry?style=flat-square)](https://pypi.python.org/pypi/rtry/)
[![Python Version](https://img.shields.io/pypi/pyversions/rtry.svg?style=flat-square)](https://pypi.python.org/pypi/rtry/)

## Installation

```bash
pip3 install rtry
```

## Documentation

* [timeout](#timeout)
    * [as context manager](#as-context-manager)
    * [as context manager (silent)](#as-context-manager-silent)
    * [as context manager (asyncio)](#as-context-manager-asyncio)
    * [as decorator](#as-decorator)
    * [as decorator (asyncio)](#as-decorator-asyncio)
    * [as argument](#as-argument)
* [retry](#retry)
    * [attempts](#attempts)
    * [until](#until)
    * [logger](#logger)
    * [delay](#delay)
    * [swallow](#swallow)
    * [asyncio](#asyncio)

---

## Timeout

##### As context manager

```python
from rtry import timeout, CancelledError

try:
    with timeout(3.0):
        resp = requests.get("https://httpbin.org/status/200")
except CancelledError:
    raise
else:
    print(resp)
```

##### As context manager (silent)

```python
from rtry import timeout, CancelledError

resp = None
with timeout(3.0, exception=None):
    resp = requests.get("https://httpbin.org/status/200")
```

##### As context manager (asyncio)

```python
import asyncio
import aiohttp
from rtry import timeout, CancelledError

async def main():
    try:
        async with aiohttp.ClientSession() as session, timeout(3.0):
            async with session.get("https://httpbin.org/status/200") as resp:
                return resp
    except CancelledError:
        raise
    else:
        print(resp)

asyncio.run(main())
```

##### As decorator

```python
from rtry import timeout, CancelledError

@timeout(3.0)
def fn():
    resp = requests.get("https://httpbin.org/status/200")
    return resp

try:
    resp = fn()
except CancelledError:
    raise
else:
    print(resp)
```

##### As decorator (asyncio)

```python
import asyncio
import aiohttp
from rtry import timeout, CancelledError

@timeout(3.0)
async def fn():
    async with aiohttp.ClientSession() as session:
        async with session.get("https://httpbin.org/status/200") as resp:
            return resp

async def main():
    try:
        resp = await fn()
    except CancelledError:
        raise
    else:
        print(resp)

asyncio.run(main())
```

##### As argument

```python
from rtry import retry, CancelledError

@retry(until=lambda r: r.status_code != 200, timeout=3.0)
def fn():
    resp = requests.get("https://httpbin.org/status/200")
    return resp

try:
    resp = fn()
except CancelledError:
    raise
else:
    print(resp)
```

## Retry

### Attempts

```python
@retry(attempts=2)
def fn():
    resp = requests.get("https://httpbin.org/status/500")
    print(resp)
    assert resp.status_code == 200
    return resp

resp = fn()
# <Response [500]>
# <Response [500]>
# Traceback:
#   AssertionError
```

### Until

```python
@retry(until=lambda r: r.status_code != 200, attempts=2)
def fn():
    resp = requests.get("https://httpbin.org/status/500")
    print(resp)
    return resp

resp = fn()
# <Response [500]>
# <Response [500]>
```

### Logger

##### Simple logger

```python
@retry(until=lambda r: r.status_code != 200, attempts=2, logger=print)
def fn():
    resp = requests.get("https://httpbin.org/status/500")
    return resp

resp = fn()
# 1 <Response [500]> <function fn at 0x103dcd268>
# 2 <Response [500]> <function fn at 0x103dcd268>
```

##### Custom logger

```python
def logger(attempt, result_or_exception, decorated):
    logging.info("Attempt: %d, Result: %s", attempt, result_or_exception)

@retry(until=lambda r: r.status_code != 200, attempts=2, logger=logger)
def fn():
    resp = requests.get("https://httpbin.org/status/500")
    return resp

resp = fn()
# INFO:root:Attempt: 1, Result: <Response [500]>
# INFO:root:Attempt: 2, Result: <Response [500]>
```

### Delay

##### Const delay

```python
@retry(until=lambda r: r.status_code != 200, attempts=2, delay=0.1)
def fn():
    resp = requests.get("https://httpbin.org/status/500")
    return resp

started_at = time.monotonic()
resp = fn()
ended_at = time.monotonic()
print('Elapsed {:.2f}'.format(ended_at - started_at))
# Elapsed 2.11
```

##### Custom delay

```python
from math import exp

@retry(until=lambda r: r.status_code != 200, attempts=2, delay=exp)
def fn():
    resp = requests.get("https://httpbin.org/status/500")
    return resp

started_at = time.monotonic()
resp = fn()
ended_at = time.monotonic()
print('Elapsed {:.2f}'.format(ended_at - started_at))
# Elapsed 11.79
```

### Swallow

##### Fail on first exception

```python
@retry(attempts=2, swallow=None, logger=print)
def fn():
    resp = requests.get("http://127.0.0.1/status/500")
    return resp

try:
    resp = fn()
except Exception as e:
    print(e)
    # HTTPConnectionPool(host='127.0.0.1', port=80): Max retries exceeded with url: /status/500
```

##### Swallow only ConnectionError

```python
from requests.exceptions import ConnectionError

@retry(attempts=2, swallow=ConnectionError, logger=print)
def fn():
    resp = requests.get("http://127.0.0.1/status/500")
    return resp

try:
    resp = fn()
except Exception as e:
    print(e)
    # 1 HTTPConnectionPool(host='127.0.0.1', port=80): Max retries exceeded with url: /status/500
    # 2 HTTPConnectionPool(host='127.0.0.1', port=80): Max retries exceeded with url: /status/500
    # HTTPConnectionPool(host='127.0.0.1', port=80): Max retries exceeded with url: /status/500
```

### AsyncIO

```python
import asyncio
import aiohttp
from rtry import retry

@retry(attempts=2)
async def fn():
    async with aiohttp.ClientSession() as session:
        async with session.get("https://httpbin.org/status/500") as resp:
            print(resp)
            assert resp.status == 200
            return resp

async def main():
    resp = await fn()
    # <ClientResponse(https://httpbin.org/status/500) [500 INTERNAL SERVER ERROR]>
    # <ClientResponse(https://httpbin.org/status/500) [500 INTERNAL SERVER ERROR]>
    # Traceback
    #   AssertionError

asyncio.run(main())
```

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/tsv1/rtry",
    "name": "rtry",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">=3.7",
    "maintainer_email": "",
    "keywords": "",
    "author": "Nikita Tsvetkov",
    "author_email": "tsv1@fastmail.com",
    "download_url": "https://files.pythonhosted.org/packages/a2/6b/7bd5da0d8432fa3726e90966b2939d06a02b0d4c906b93d118c38255547c/rtry-1.5.0.tar.gz",
    "platform": null,
    "description": "# rtry\n\n[![Codecov](https://img.shields.io/codecov/c/github/tsv1/rtry/master.svg?style=flat-square)](https://codecov.io/gh/tsv1/rtry)\n[![PyPI](https://img.shields.io/pypi/v/rtry.svg?style=flat-square)](https://pypi.python.org/pypi/rtry/)\n[![PyPI - Downloads](https://img.shields.io/pypi/dm/rtry?style=flat-square)](https://pypi.python.org/pypi/rtry/)\n[![Python Version](https://img.shields.io/pypi/pyversions/rtry.svg?style=flat-square)](https://pypi.python.org/pypi/rtry/)\n\n## Installation\n\n```bash\npip3 install rtry\n```\n\n## Documentation\n\n* [timeout](#timeout)\n    * [as context manager](#as-context-manager)\n    * [as context manager (silent)](#as-context-manager-silent)\n    * [as context manager (asyncio)](#as-context-manager-asyncio)\n    * [as decorator](#as-decorator)\n    * [as decorator (asyncio)](#as-decorator-asyncio)\n    * [as argument](#as-argument)\n* [retry](#retry)\n    * [attempts](#attempts)\n    * [until](#until)\n    * [logger](#logger)\n    * [delay](#delay)\n    * [swallow](#swallow)\n    * [asyncio](#asyncio)\n\n---\n\n## Timeout\n\n##### As context manager\n\n```python\nfrom rtry import timeout, CancelledError\n\ntry:\n    with timeout(3.0):\n        resp = requests.get(\"https://httpbin.org/status/200\")\nexcept CancelledError:\n    raise\nelse:\n    print(resp)\n```\n\n##### As context manager (silent)\n\n```python\nfrom rtry import timeout, CancelledError\n\nresp = None\nwith timeout(3.0, exception=None):\n    resp = requests.get(\"https://httpbin.org/status/200\")\n```\n\n##### As context manager (asyncio)\n\n```python\nimport asyncio\nimport aiohttp\nfrom rtry import timeout, CancelledError\n\nasync def main():\n    try:\n        async with aiohttp.ClientSession() as session, timeout(3.0):\n            async with session.get(\"https://httpbin.org/status/200\") as resp:\n                return resp\n    except CancelledError:\n        raise\n    else:\n        print(resp)\n\nasyncio.run(main())\n```\n\n##### As decorator\n\n```python\nfrom rtry import timeout, CancelledError\n\n@timeout(3.0)\ndef fn():\n    resp = requests.get(\"https://httpbin.org/status/200\")\n    return resp\n\ntry:\n    resp = fn()\nexcept CancelledError:\n    raise\nelse:\n    print(resp)\n```\n\n##### As decorator (asyncio)\n\n```python\nimport asyncio\nimport aiohttp\nfrom rtry import timeout, CancelledError\n\n@timeout(3.0)\nasync def fn():\n    async with aiohttp.ClientSession() as session:\n        async with session.get(\"https://httpbin.org/status/200\") as resp:\n            return resp\n\nasync def main():\n    try:\n        resp = await fn()\n    except CancelledError:\n        raise\n    else:\n        print(resp)\n\nasyncio.run(main())\n```\n\n##### As argument\n\n```python\nfrom rtry import retry, CancelledError\n\n@retry(until=lambda r: r.status_code != 200, timeout=3.0)\ndef fn():\n    resp = requests.get(\"https://httpbin.org/status/200\")\n    return resp\n\ntry:\n    resp = fn()\nexcept CancelledError:\n    raise\nelse:\n    print(resp)\n```\n\n## Retry\n\n### Attempts\n\n```python\n@retry(attempts=2)\ndef fn():\n    resp = requests.get(\"https://httpbin.org/status/500\")\n    print(resp)\n    assert resp.status_code == 200\n    return resp\n\nresp = fn()\n# <Response [500]>\n# <Response [500]>\n# Traceback:\n#   AssertionError\n```\n\n### Until\n\n```python\n@retry(until=lambda r: r.status_code != 200, attempts=2)\ndef fn():\n    resp = requests.get(\"https://httpbin.org/status/500\")\n    print(resp)\n    return resp\n\nresp = fn()\n# <Response [500]>\n# <Response [500]>\n```\n\n### Logger\n\n##### Simple logger\n\n```python\n@retry(until=lambda r: r.status_code != 200, attempts=2, logger=print)\ndef fn():\n    resp = requests.get(\"https://httpbin.org/status/500\")\n    return resp\n\nresp = fn()\n# 1 <Response [500]> <function fn at 0x103dcd268>\n# 2 <Response [500]> <function fn at 0x103dcd268>\n```\n\n##### Custom logger\n\n```python\ndef logger(attempt, result_or_exception, decorated):\n    logging.info(\"Attempt: %d, Result: %s\", attempt, result_or_exception)\n\n@retry(until=lambda r: r.status_code != 200, attempts=2, logger=logger)\ndef fn():\n    resp = requests.get(\"https://httpbin.org/status/500\")\n    return resp\n\nresp = fn()\n# INFO:root:Attempt: 1, Result: <Response [500]>\n# INFO:root:Attempt: 2, Result: <Response [500]>\n```\n\n### Delay\n\n##### Const delay\n\n```python\n@retry(until=lambda r: r.status_code != 200, attempts=2, delay=0.1)\ndef fn():\n    resp = requests.get(\"https://httpbin.org/status/500\")\n    return resp\n\nstarted_at = time.monotonic()\nresp = fn()\nended_at = time.monotonic()\nprint('Elapsed {:.2f}'.format(ended_at - started_at))\n# Elapsed 2.11\n```\n\n##### Custom delay\n\n```python\nfrom math import exp\n\n@retry(until=lambda r: r.status_code != 200, attempts=2, delay=exp)\ndef fn():\n    resp = requests.get(\"https://httpbin.org/status/500\")\n    return resp\n\nstarted_at = time.monotonic()\nresp = fn()\nended_at = time.monotonic()\nprint('Elapsed {:.2f}'.format(ended_at - started_at))\n# Elapsed 11.79\n```\n\n### Swallow\n\n##### Fail on first exception\n\n```python\n@retry(attempts=2, swallow=None, logger=print)\ndef fn():\n    resp = requests.get(\"http://127.0.0.1/status/500\")\n    return resp\n\ntry:\n    resp = fn()\nexcept Exception as e:\n    print(e)\n    # HTTPConnectionPool(host='127.0.0.1', port=80): Max retries exceeded with url: /status/500\n```\n\n##### Swallow only ConnectionError\n\n```python\nfrom requests.exceptions import ConnectionError\n\n@retry(attempts=2, swallow=ConnectionError, logger=print)\ndef fn():\n    resp = requests.get(\"http://127.0.0.1/status/500\")\n    return resp\n\ntry:\n    resp = fn()\nexcept Exception as e:\n    print(e)\n    # 1 HTTPConnectionPool(host='127.0.0.1', port=80): Max retries exceeded with url: /status/500\n    # 2 HTTPConnectionPool(host='127.0.0.1', port=80): Max retries exceeded with url: /status/500\n    # HTTPConnectionPool(host='127.0.0.1', port=80): Max retries exceeded with url: /status/500\n```\n\n### AsyncIO\n\n```python\nimport asyncio\nimport aiohttp\nfrom rtry import retry\n\n@retry(attempts=2)\nasync def fn():\n    async with aiohttp.ClientSession() as session:\n        async with session.get(\"https://httpbin.org/status/500\") as resp:\n            print(resp)\n            assert resp.status == 200\n            return resp\n\nasync def main():\n    resp = await fn()\n    # <ClientResponse(https://httpbin.org/status/500) [500 INTERNAL SERVER ERROR]>\n    # <ClientResponse(https://httpbin.org/status/500) [500 INTERNAL SERVER ERROR]>\n    # Traceback\n    #   AssertionError\n\nasyncio.run(main())\n```\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "The easiest way to retry operations",
    "version": "1.5.0",
    "project_urls": {
        "Homepage": "https://github.com/tsv1/rtry"
    },
    "split_keywords": [],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "256242a9f61be687909f809fcab349a80b4dab3452290f96452b934f60a65bcf",
                "md5": "fa30434babf690e4f7f21edc3939e5b4",
                "sha256": "6c71d8b6cf0d2bf44484cea6afd1faa9390f5803a92faef5b65e4f292f30c65a"
            },
            "downloads": -1,
            "filename": "rtry-1.5.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "fa30434babf690e4f7f21edc3939e5b4",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.7",
            "size": 8472,
            "upload_time": "2023-06-22T17:00:39",
            "upload_time_iso_8601": "2023-06-22T17:00:39.239645Z",
            "url": "https://files.pythonhosted.org/packages/25/62/42a9f61be687909f809fcab349a80b4dab3452290f96452b934f60a65bcf/rtry-1.5.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "a26b7bd5da0d8432fa3726e90966b2939d06a02b0d4c906b93d118c38255547c",
                "md5": "d780df0346fb4d422f1f12ae4d77bc1e",
                "sha256": "c9dcae88ebdfe9e4f45a4a7f1d3d0a6321bef3a5a908fa99d80bdde73056cb35"
            },
            "downloads": -1,
            "filename": "rtry-1.5.0.tar.gz",
            "has_sig": false,
            "md5_digest": "d780df0346fb4d422f1f12ae4d77bc1e",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.7",
            "size": 14395,
            "upload_time": "2023-06-22T17:00:40",
            "upload_time_iso_8601": "2023-06-22T17:00:40.662605Z",
            "url": "https://files.pythonhosted.org/packages/a2/6b/7bd5da0d8432fa3726e90966b2939d06a02b0d4c906b93d118c38255547c/rtry-1.5.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2023-06-22 17:00:40",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "tsv1",
    "github_project": "rtry",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "requirements": [],
    "lcname": "rtry"
}
        
Elapsed time: 0.14242s