# ReAttempt
ReAttempt is a python decorator to retry a function when exceptions are raised.
### Demonstration:
```python
from reattempt import reattempt
@reattempt(max_retries=5, min_time=0.1, max_time=2)
def simulate_network_failure():
raise Exception("Connection timeout")
if __name__ == "__main__":
simulate_network_failure()
------------------------------------------------------- live log call -------------------------------------------------------
WARNING root:__init__.py:167 [RETRY] Attempt 1/5 failed, retrying in 0.17 seconds...
WARNING root:__init__.py:167 [RETRY] Attempt 2/5 failed, retrying in 0.19 seconds...
WARNING root:__init__.py:167 [RETRY] Attempt 3/5 failed, retrying in 0.19 seconds...
WARNING root:__init__.py:167 [RETRY] Attempt 4/5 failed, retrying in 0.19 seconds...
WARNING root:__init__.py:163 [RETRY] Attempt 5/5 failed, stopping
ERROR root:__init__.py:177 [RETRY] Max retries reached
```
## Table of Contents
- [ReAttempt](#ReAttempt)
- [Table of Contents](#table-of-contents)
- [Description](#description)
- [Installation](#installation)
- [Usage](#usage)
- [License](#license)
- [Contact](#contact)
## Description
ReAttempt is a Python library that provides a decorator to automatically retry a function when exceptions are raised. It uses an exponential backoff strategy to wait between retries, ensuring that the function has multiple chances to succeed before ultimately failing.
## Installation
```bash
# Install the dependency
pip install reattempt
uv add reattempt
poetry add reattempt
```
## Usage
```python
from reattempt import reattempt
import asyncio
import random
# List of flowers for our examples
flowers = ["Rose", "Tulip", "Sunflower", "Daisy", "Lily"]
# Synchronous function example
@reattempt
def plant_flower():
flower = random.choice(flowers)
print(f"Attempting to plant a {flower}")
if random.random() < 0.8: # 80% chance of failure
raise Exception(f"The {flower} didn't take root")
return f"{flower} planted successfully"
# Synchronous generator example
@reattempt
def grow_flowers():
for _ in range(3):
flower = random.choice(flowers)
print(f"Growing {flower}")
yield flower
if random.random() < 0.5: # 50% chance of failure at the end
raise Exception("The garden needs more fertilizer")
# Asynchronous function example
@reattempt
async def water_flower():
flower = random.choice(flowers)
print(f"Watering the {flower}")
await asyncio.sleep(0.1) # Simulating watering time
if random.random() < 0.6: # 60% chance of failure
raise Exception(f"The {flower} needs more water")
return f"{flower} is well-watered"
# Asynchronous generator function example
@reattempt
async def harvest_flowers():
for _ in range(3):
flower = random.choice(flowers)
print(f"Harvesting {flower}")
yield flower
await asyncio.sleep(0.1) # Time between harvests
if random.random() < 0.4: # 40% chance of failure at the end
raise Exception("The garden needs more care")
async def tend_garden():
# Plant a flower (sync function)
try:
result = plant_flower()
print(result)
except Exception as e:
print(f"Planting error: {e}")
# Grow flowers (sync generator)
try:
for flower in grow_flowers():
print(f"Grown: {flower}")
except Exception as e:
print(f"Growing error: {e}")
# Water a flower (async function)
try:
result = await water_flower()
print(result)
except Exception as e:
print(f"Watering error: {e}")
# Harvest flowers (async generator function)
try:
async for flower in harvest_flowers():
print(f"Harvested: {flower}")
except Exception as e:
print(f"Harvesting error: {e}")
if __name__ == "__main__":
asyncio.run(tend_garden())
```
## License
ReAttempt is released under the MIT License. See the [LICENSE](LICENSE) file for more details.
## Contact
For questions, suggestions, or issues related to ReAttempt, please open an issue on the GitHub repository.
Raw data
{
"_id": null,
"home_page": null,
"name": "reattempt",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.10",
"maintainer_email": null,
"keywords": "async, async gen, decorator, exception handling, exponential backoff, generator, python, retry, sync",
"author": null,
"author_email": "Sylvain Mouquet <sylvain.mouquet@gmail.com>",
"download_url": "https://files.pythonhosted.org/packages/35/8d/a56393bbb21da5a63c359c516d6f065660984e49b6fda755a04e37d56c08/reattempt-1.1.3.tar.gz",
"platform": null,
"description": "# ReAttempt\n\nReAttempt is a python decorator to retry a function when exceptions are raised.\n\n### Demonstration:\n\n```python\nfrom reattempt import reattempt\n\n@reattempt(max_retries=5, min_time=0.1, max_time=2)\ndef simulate_network_failure():\n raise Exception(\"Connection timeout\")\n\nif __name__ == \"__main__\":\n simulate_network_failure()\n\n------------------------------------------------------- live log call -------------------------------------------------------\nWARNING root:__init__.py:167 [RETRY] Attempt 1/5 failed, retrying in 0.17 seconds...\nWARNING root:__init__.py:167 [RETRY] Attempt 2/5 failed, retrying in 0.19 seconds...\nWARNING root:__init__.py:167 [RETRY] Attempt 3/5 failed, retrying in 0.19 seconds...\nWARNING root:__init__.py:167 [RETRY] Attempt 4/5 failed, retrying in 0.19 seconds...\nWARNING root:__init__.py:163 [RETRY] Attempt 5/5 failed, stopping\nERROR root:__init__.py:177 [RETRY] Max retries reached\n```\n\n## Table of Contents\n\n- [ReAttempt](#ReAttempt)\n - [Table of Contents](#table-of-contents)\n - [Description](#description)\n - [Installation](#installation)\n - [Usage](#usage)\n - [License](#license)\n - [Contact](#contact)\n\n## Description\n\nReAttempt is a Python library that provides a decorator to automatically retry a function when exceptions are raised. It uses an exponential backoff strategy to wait between retries, ensuring that the function has multiple chances to succeed before ultimately failing.\n\n## Installation\n\n```bash\n# Install the dependency\npip install reattempt\nuv add reattempt\npoetry add reattempt\n```\n\n## Usage\n\n```python\nfrom reattempt import reattempt\nimport asyncio\nimport random\n\n# List of flowers for our examples\nflowers = [\"Rose\", \"Tulip\", \"Sunflower\", \"Daisy\", \"Lily\"]\n\n# Synchronous function example\n@reattempt\ndef plant_flower():\n flower = random.choice(flowers)\n print(f\"Attempting to plant a {flower}\")\n if random.random() < 0.8: # 80% chance of failure\n raise Exception(f\"The {flower} didn't take root\")\n return f\"{flower} planted successfully\"\n\n# Synchronous generator example\n@reattempt\ndef grow_flowers():\n for _ in range(3):\n flower = random.choice(flowers)\n print(f\"Growing {flower}\")\n yield flower\n if random.random() < 0.5: # 50% chance of failure at the end\n raise Exception(\"The garden needs more fertilizer\")\n\n# Asynchronous function example\n@reattempt\nasync def water_flower():\n flower = random.choice(flowers)\n print(f\"Watering the {flower}\")\n await asyncio.sleep(0.1) # Simulating watering time\n if random.random() < 0.6: # 60% chance of failure\n raise Exception(f\"The {flower} needs more water\")\n return f\"{flower} is well-watered\"\n\n# Asynchronous generator function example\n@reattempt\nasync def harvest_flowers():\n for _ in range(3):\n flower = random.choice(flowers)\n print(f\"Harvesting {flower}\")\n yield flower\n await asyncio.sleep(0.1) # Time between harvests\n if random.random() < 0.4: # 40% chance of failure at the end\n raise Exception(\"The garden needs more care\")\n\nasync def tend_garden():\n # Plant a flower (sync function)\n try:\n result = plant_flower()\n print(result)\n except Exception as e:\n print(f\"Planting error: {e}\")\n\n # Grow flowers (sync generator)\n try:\n for flower in grow_flowers():\n print(f\"Grown: {flower}\")\n except Exception as e:\n print(f\"Growing error: {e}\")\n\n # Water a flower (async function)\n try:\n result = await water_flower()\n print(result)\n except Exception as e:\n print(f\"Watering error: {e}\")\n\n # Harvest flowers (async generator function)\n try:\n async for flower in harvest_flowers():\n print(f\"Harvested: {flower}\")\n except Exception as e:\n print(f\"Harvesting error: {e}\")\n\nif __name__ == \"__main__\":\n asyncio.run(tend_garden())\n```\n\n\n## License\n\nReAttempt is released under the MIT License. See the [LICENSE](LICENSE) file for more details.\n\n## Contact\n\nFor questions, suggestions, or issues related to ReAttempt, please open an issue on the GitHub repository.\n\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "Retrying a python function when exceptions are raised",
"version": "1.1.3",
"project_urls": {
"changelog": "https://github.com/sylvainmouquet/reattempt/releases",
"documentation": "https://github.com/sylvainmouquet/reattempt",
"homepage": "https://github.com/sylvainmouquet/reattempt",
"repository": "https://github.com/sylvainmouquet/reattempt"
},
"split_keywords": [
"async",
" async gen",
" decorator",
" exception handling",
" exponential backoff",
" generator",
" python",
" retry",
" sync"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "9518c9839bc6ed1a88dcfc58d0e9e119ddc3864289eeafa2ad01cc0384239e7c",
"md5": "7043a530d578a04ac3d8745a9092c2a6",
"sha256": "8c9193c7f6c4d186dc1475321c890e64306bfa6348bae91922baf1ba37b9241f"
},
"downloads": -1,
"filename": "reattempt-1.1.3-py3-none-any.whl",
"has_sig": false,
"md5_digest": "7043a530d578a04ac3d8745a9092c2a6",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.10",
"size": 5162,
"upload_time": "2024-10-09T18:58:36",
"upload_time_iso_8601": "2024-10-09T18:58:36.254653Z",
"url": "https://files.pythonhosted.org/packages/95/18/c9839bc6ed1a88dcfc58d0e9e119ddc3864289eeafa2ad01cc0384239e7c/reattempt-1.1.3-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "358da56393bbb21da5a63c359c516d6f065660984e49b6fda755a04e37d56c08",
"md5": "0b5f2292fd20717ace40f9121f08fe7a",
"sha256": "de04b069bfb3e5bf09ccfec0163d93bc6ae0595badca43b7eb36483057996ff1"
},
"downloads": -1,
"filename": "reattempt-1.1.3.tar.gz",
"has_sig": false,
"md5_digest": "0b5f2292fd20717ace40f9121f08fe7a",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.10",
"size": 44613,
"upload_time": "2024-10-09T18:58:37",
"upload_time_iso_8601": "2024-10-09T18:58:37.885411Z",
"url": "https://files.pythonhosted.org/packages/35/8d/a56393bbb21da5a63c359c516d6f065660984e49b6fda755a04e37d56c08/reattempt-1.1.3.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-10-09 18:58:37",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "sylvainmouquet",
"github_project": "reattempt",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "reattempt"
}