Skip to content

Commit

Permalink
feat($Tenacity): integrate Python retry library with Tenacity
Browse files Browse the repository at this point in the history
  • Loading branch information
johnnymillergh committed Sep 3, 2022
1 parent 8ed5022 commit edff79a
Show file tree
Hide file tree
Showing 6 changed files with 125 additions and 7 deletions.
2 changes: 2 additions & 0 deletions Pipfile
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ faker = "==14.1.0"
# A Python module to parse, validate and reformat standard numbers and codes in different formats.
# It contains a large collection of number formats. https://pypi.org/project/python-stdnum/
python-stdnum = "==1.17"
# Retrying library for Python. https://pypi.org/project/tenacity/
tenacity = "==8.0.1"

[dev-packages]
# Black is the uncompromising Python code formatter. By using it, you agree to cede control over minutiae of
Expand Down
23 changes: 16 additions & 7 deletions Pipfile.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Empty file.
71 changes: 71 additions & 0 deletions python_boilerplate/demo/tenacity_usage.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import logging
import random
from logging import INFO, WARNING
from typing import Final

from loguru import logger
from tenacity import (
after_log,
retry,
retry_if_exception_type,
retry_if_result,
stop_after_attempt,
wait_fixed,
)

SUCCESS_RANGE: Final = range(200, 300)
loging_logger: Final = logging.getLogger(__name__)


# https://tenacity.readthedocs.io/en/latest/
# https://jamesfheath.com/2020/07/python-library-tenacity.html


@retry(stop=stop_after_attempt(3), after=after_log(loging_logger, WARNING))
def exception_function_1() -> None:
logger.warning("Mocking failure 1")
raise RuntimeError("Failure message 1")


@retry(
stop=stop_after_attempt(3), wait=wait_fixed(2), after=after_log(loging_logger, INFO)
)
def exception_function_2() -> None:
logger.warning("Mocking failure 2")
raise RuntimeError("Failure message 2")


@retry(stop=stop_after_attempt(3), retry=retry_if_exception_type((IOError, ValueError)))
def different_exceptions_possible(x: int) -> str:
if x == 1:
logger.error("IO Error because x is 1")
raise IOError
elif x == 2:
logger.error("Connection Error because x is 2")
raise ConnectionError
elif x == 3:
logger.error("Type Error because x is 3")
raise TypeError
else:
return "success"


def validate_code(result: int) -> bool:
needs_retry = result not in SUCCESS_RANGE
if needs_retry:
logger.warning(
f"The result = {result}, which is NOT 2xx code, needs_retry = {needs_retry}"
)
else:
logger.info(
f"The result = {result}, which is 2xx code, needs_retry = {needs_retry}"
)
return needs_retry


@retry(stop=stop_after_attempt(3), retry=retry_if_result(validate_code))
def customized_retry_logic_function(input_int: int) -> int:
random_int = random.randint(0, 200)
result = input_int + random_int
logger.info(f"input_int + random_int = {input_int} + {random_int} = {result}")
return result
Empty file added tests/demo/__init__.py
Empty file.
36 changes: 36 additions & 0 deletions tests/demo/test_tenacity_usage.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import pytest
from tenacity import RetryError

from python_boilerplate.demo.tenacity_usage import (
customized_retry_logic_function,
different_exceptions_possible,
exception_function_1,
exception_function_2,
)


def test_exception_function_1():
with pytest.raises(RetryError):
exception_function_1()


def test_exception_function_2():
with pytest.raises(RetryError):
exception_function_2()


def test_different_exceptions_possible():
with pytest.raises(RetryError):
different_exceptions_possible(1)
with pytest.raises(RetryError):
different_exceptions_possible(2)
with pytest.raises(TypeError):
different_exceptions_possible(3)
assert different_exceptions_possible(4) == "success"


def test_customized_retry_logic_function():
try:
customized_retry_logic_function(240)
except Exception as ex:
assert True, f"Test passed even if exception raised, {ex.__str__()}"

0 comments on commit edff79a

Please sign in to comment.