Name | rtry JSON |
Version |
1.5.0
JSON |
| download |
home_page | https://github.com/tsv1/rtry |
Summary | The easiest way to retry operations |
upload_time | 2023-06-22 17:00:40 |
maintainer | |
docs_url | None |
author | Nikita Tsvetkov |
requires_python | >=3.7 |
license | MIT |
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"
}