0

EDIT: Since tenacity is a more recent for of retrying, this question can be considered a duplicate of the linked question, with the solution being to upgrade to tenacity.

Similar to this question, I want to unittest a function in python that has a retry decorator:

from retrying import retry # from retrying pypi module

WAIT_EXPONENTIAL_MULTIPLIER = 4 * 1000  # ms
STOP_MAX_ATTEMPT_NUMBER = 5

@retry(
   wait_exponential_multiplier=WAIT_EXPONENTIAL_MULTIPLIER,
   stop_max_attempt_number=STOP_MAX_ATTEMPT_NUMBER
)
def get_from_remote(key):
    raise ValueError() # for example

In my unittest, I want to call this function sometimes without retrying at all, sometimes with different parameters.

I tried setting the variables in setUp()/tearDown(), but it did not work. I tried patching the retry decorator, but it also did not work.

ingyhere
  • 11,818
  • 3
  • 38
  • 52
tkruse
  • 10,222
  • 7
  • 53
  • 80
  • I had exact same problem, where I was not in position to change the library because of all the review and legal process it had to go. I had a workaround by patching the @retry decorator in the test case with my custom decorator. I can add an answer if you can reopen the question with the code – parv desai May 18 '23 at 18:18

1 Answers1

0

Not sure if this is possible due to the line

Retrying(*dargs, **dkw).call(f, *args, **kw)

in retrying. The Retrying instance is created on-the-fly when the function is run and it is not possible to change its attributes anymore.

One approach could be to keep an undecorated reference to the function and decorate old-school at runtime.

from retrying import retry

WAIT_EXPONENTIAL_MULTIPLIER = 1 * 1000  # ms

# the "normal" decorator
retry_dec = retry(wait_exponential_multiplier=WAIT_EXPONENTIAL_MULTIPLIER)

# the undecorated function
def get_from_remote_undecorated(key):
    raise ValueError()

# this is the "normal" decorated function
get_from_remote = retry_dec(get_from_remote_undecorated)

This can be repeated in the unittests:

# some test
retry_dec_test_1 = retry(wait_exponential_multiplier=WAIT_EXPONENTIAL_MULTIPLIER)
get_from_remote_test_1 = retry_dec_test_1(get_from_remote_undecorated)

# another test with different parameters
retry_dec_test_2 = retry(stop_max_attempt_number=STOP_MAX_ATTEMPT_NUMBER)
get_from_remote_test_2 = retry_dec_test_2 (get_from_remote_undecorated)

But I am not really happy with this approach and will try to find a better solution.

Joe
  • 6,758
  • 2
  • 26
  • 47
  • After some research I found that tenacity is the recommended package to use, so it's a bit of a waste to try to fix this with retrying. – tkruse Jun 19 '19 at 13:15
  • You can do anything in python. It's not always pretty, but `get_from_remote.im_func.func_closure[1].cell_contents["stop_max_attempt_number"] = 0` – casey Jul 11 '20 at 05:25
  • I had exact same problem, where I was not in position to change the library because of all the review and legal process it had to go. I had a workaround by patching the `@retry` decorator in the test case with my custom decorator. I can add an answer if you can reopen the question with the code – parv desai May 18 '23 at 18:18