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

9.0.0: Unintended or missing behavior in retry_with #490

Open
at3560k opened this issue Aug 15, 2024 · 0 comments
Open

9.0.0: Unintended or missing behavior in retry_with #490

at3560k opened this issue Aug 15, 2024 · 0 comments

Comments

@at3560k
Copy link

at3560k commented Aug 15, 2024

Hi tenacity-devs. Love the project, but I went to try something today and encountered behavior that surprised me. I'm attaching a code snippet with two things I think aren't working right.

  1. retry_with does not appear to be modify logging behavior as I understand the documents
  2. retry_with seems to mask or entirely box the return type on success, which results in an exception when trying to capture teh value!

It may be that I'm missing a use-pattern here. If so, sorry -- please point me at the right spot.

My intended use-case necessitates a dynamic number of stop=stop_after_attempts, and the retry_with docs seemed perfectly suited to this vs. generating/passing a closure.


#!/usr/bin/env python3
# tenacity==9.0.0
# python 3.8.19

import logging
import random
import sys

from tenacity import before_log, retry, stop_after_attempt, retry_if_exception_type

logging.basicConfig(stream=sys.stderr, level=logging.INFO)
log = logging.getLogger(__name__)

@retry(
    reraise=True,
    retry=retry_if_exception_type(ZeroDivisionError),
    stop=stop_after_attempt(3)
)
def do_something_always_fails():
    """
    Try to return a string but screw it up.
    """
    raise ZeroDivisionError("terrible")
    return "you never get here, but this returns a string"


# Just have logging turned on to watch what happens
@retry(
    reraise=True,
    retry=retry_if_exception_type(ZeroDivisionError),
    stop=stop_after_attempt(3),
    before=before_log(log, logging.INFO)
)
def do_something_unreliable():
    """
    But return a string!
    """
    if random.randint(0, 10) > 2:
        raise ZeroDivisionError("sometimes fails")
    else:
        return "Yay, it worked"


try:
    x1 = do_something_always_fails()
    # X has no value ever
except Exception as e :
    print("[pass] Trapped and worked as intended")
    pass

try:
    x2 = do_something_always_fails().retry_with(retry=stop_after_attempt(4))
except Exception as e :
    # x2 has to be undefined
    print(f"[pass] Trapped and overrode as intended")
    pass

# Seems correct....
try:
    x3 = do_something_unreliable()
    print(f"[pass] unreliable thing worked with raw function {x3=}")
    # I work sometimes, and this is fine.
except ZeroDivisionError as e:
    # I Print sometimes, and this is fine.
    print(f"[pass] Unreliable thing kicked out")

# Seems buggy.
try:
    x4 = do_something_unreliable().retry_with(
        stop=stop_after_attempt(15),
        # bug 1?: Modifying the log level doesn't work, I expect to see failures at warn
        # but they land at info
        before=before_log(log, logging.WARNING)
    )
    # The below line has never been seen
    print(f"[pass] unreliable thing.retry_with worked {x4=}")
except ZeroDivisionError as e:
    print("I expect to never get here, statistically") # But I guess it's possible
except Exception as e: # This exception always happens...
    print(f"This is a bug? {e}")
    # str(e) ==  "'str' object has no attribute 'retry_with'" !
    # Where is my response, why isn't it yay it worked?

Sample output

❯  python tenacity_bug.py
[pass] Trapped and worked as intended
[pass] Trapped and overrode as intended
INFO:__main__:Starting call to '__main__.do_something_unreliable', this is the 1st time calling it.
INFO:__main__:Starting call to '__main__.do_something_unreliable', this is the 2nd time calling it.
INFO:__main__:Starting call to '__main__.do_something_unreliable', this is the 3rd time calling it.
[pass] Unreliable thing kicked out
INFO:__main__:Starting call to '__main__.do_something_unreliable', this is the 1st time calling it.
INFO:__main__:Starting call to '__main__.do_something_unreliable', this is the 2nd time calling it.
This is a bug? 'str' object has no attribute 'retry_with'

I expect:

  1. To see logs at warning instead of info level
  2. For the last output to show x4='yay it worked', not an exception.
@at3560k at3560k changed the title Unintended or missing behavior in retry_with 9.0.0: Unintended or missing behavior in retry_with Aug 15, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant