Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Async-fix #6

Merged
merged 6 commits into from
May 8, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/python-package.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
strategy:
fail-fast: true
matrix:
python-version: ["3.5", "3.6", "3.7", "3.8", "3.9", "3.10"]
python-version: ["3.6", "3.7", "3.8", "3.9", "3.10"]

steps:
- uses: actions/checkout@v3
Expand Down
3 changes: 3 additions & 0 deletions codecov.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
ignore:
- "tests"
- "setup.py"
5 changes: 2 additions & 3 deletions setup.cfg
Original file line number Diff line number Diff line change
@@ -1,22 +1,21 @@
[metadata]
name = reretry
version = 0.11.1
version = 0.11.2
author = leshchenko1979
author_email = [email protected]
summary = An easy to use, but functional decorator for retrying on exceptions.
license = Apache License 2.0
description_file = README.md
long_description_content_type = text/x-rst
home_page = https://github.com/leshchenko1979/reretry
requires_python = >=3.5
requires_python = >=3.6
classifier =
Development Status :: 4 - Beta
Intended Audience :: Developers
License :: OSI Approved :: Apache Software License
Natural Language :: English
Operating System :: OS Independent
Programming Language :: Python
Programming Language :: Python :: 3.5
Programming Language :: Python :: 3.6
Programming Language :: Python :: 3.7
Programming Language :: Python :: 3.8
Expand Down
84 changes: 84 additions & 0 deletions tests/test_async.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
from unittest.mock import MagicMock

import asyncio

import pytest
from reretry.api import _is_async, retry, retry_call



def test_is_async():
async def async_func():
pass

def non_async_func():
pass

def generator():
yield

assert _is_async(async_func)
assert not _is_async(non_async_func)
assert not _is_async(generator)
assert not _is_async(generator())
assert not _is_async(MagicMock(spec=non_async_func, return_value=-1))


@pytest.mark.asyncio
async def test_async():
attempts = 1
raised = False

@retry(tries=2)
async def f():
await asyncio.sleep(0.01)
nonlocal attempts, raised
if attempts:
raised = True
attempts -= 1
raise RuntimeError
return True

assert await f()
assert raised
assert attempts == 0


@pytest.mark.asyncio
async def test_async_fail_and_callback():
cb_called = False

async def cb(exception: Exception):
nonlocal cb_called
cb_called = True
assert exception.args[0] == 1

attempts = 3

@retry(tries=2, fail_callback=cb)
async def f():
await asyncio.sleep(0.01)
nonlocal attempts
if attempts:
attempts -= 1
raise RuntimeError(1)
return True

with pytest.raises(RuntimeError):
await f()

assert cb_called


def test_check_params():
with pytest.raises(AssertionError):
retry_call(lambda: None, show_traceback=True, logger=None)

async def async_func():
pass

def non_async_func():
pass

with pytest.raises(AssertionError):
retry_call(async_func, fail_callback=non_async_func)
58 changes: 10 additions & 48 deletions tests/test_retry.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
from unittest.mock import MagicMock

import asyncio
import time

import pytest
from reretry.api import _is_async, retry, retry_call
from reretry.api import retry, retry_call


def test_retry(monkeypatch):
Expand Down Expand Up @@ -191,53 +190,16 @@ def cb(error):
assert callback_mock.called


def test_is_async():
async def async_func():
pass

def non_async_func():
pass

def generator():
yield


assert _is_async(async_func)
assert not _is_async(non_async_func)
assert not _is_async(generator)
assert not _is_async(generator())
assert not _is_async(MagicMock(spec=non_async_func, return_value=-1))


@pytest.mark.asyncio
async def test_async():
attempts = 1
raised = False

@retry(tries=2)
async def f():
await asyncio.sleep(0.1)
nonlocal attempts, raised
if attempts:
raised = True
attempts -= 1
raise RuntimeError
return True

assert await f()
assert raised
assert attempts == 0

def test_show_traceback():
logger = MagicMock()
logger.warning = MagicMock()

def test_check_params():
with pytest.raises(AssertionError):
retry_call(lambda: None, show_traceback=True, logger=None)

async def async_func():
pass
def f():
raise RuntimeError

def non_async_func():
try:
retry_call(f, show_traceback=True, logger=logger, tries=2)
except RuntimeError:
pass

with pytest.raises(AssertionError):
retry_call(async_func, fail_callback=non_async_func)
assert logger.warning.called