Quantcast
Channel: Active questions tagged retry-logic - Stack Overflow
Viewing all articles
Browse latest Browse all 950

Can I use exceptions to trigger a recursive function retry in a wrapper function in python?

$
0
0

Im building a python console application, and Im using functions to show a menu. These functions are waiting for an input from the user and sometimes they must be validated (like it must be either "Y" or "N"). When the answer is invalid, a message should be shown with the invalid value. The user can press ENTER to hide this message and the menu must be written to the output again, and the user can input a choice again.

Now I wrote a wrapper for the menu functions which will clear the console before and after the function call. Using this I dont have to manually put these clearings into the menu function. This is also letting the function to call itself with its own parameters, whenever it wants to reset its state and the menu shown on the console like:

import osdef clear_console(func):    def wrapper(*args, **kwargs):        os.system("cls")        result = func(*args, **kwargs)        os.system("cls")        return result    return wrapper@clear_consoledef invalid_input_menu():    input("Invalid input. Press ENTER to continue...")@clear_consoledef my_menu(some_data):    print(some_data)    is_this_data_correct = input("Is this data correct? (Y/N) ").strip().upper()    if is_this_data_correct not in {"Y", "N"}:        invalid_input_menu()        return my_menu(some_data)    return is_this_data_correct == "Y"

I used this approach to the point I had to add extra parameters to one of my menus. My problem is that if more parameters are added to such a function, its retry call should be updated as well, like if I want to add another parameter to my_menu, I must provide its value to the my_menu recursive call as well, and I tend to forget that when the menu's code structure is becaming bigger.

So I created another retry wrapper which will doing this retries in a loop, but how would the wrapper knows if it should retry? There are three approaches I was thinking about:

  • If the menu returns with None -> I cant use that when I want the function to actually return None
  • If the menu returns with a custom class instance which I define for indicating that I want to retry the function -> its useful because I can return informations about the validation as well, but a menu should not instantiate classes for this, and its strange if its returning with some strange class instances
  • If the menu raises a specific exception, the wrapper could catch it and retry to call the menu function -> that sounds about right but I dont think thats a conventional use of exceptions

Heres the last approach using an exception:

import osdef clear_console(func):    def wrapper(*args, **kwargs):        os.system("cls")        result = func(*args, **kwargs)        os.system("cls")        return result    return wrapperclass InvalidInputRetryEvent(Exception):    def __init__(self, user_input):        self.user_input = user_input    @clear_console    def print_invalid_input_menu(self):        if not self.user_input:            msg = "Invalid input: empty value"        else:            msg = f"Invalid input: {self.user_input}"        input(msg)def retryable(func):    def wrapper(*args, **kwargs):        while True:            try:                return func(*args, **kwargs)            except InvalidInputRetryEvent as e:                e.print_invalid_input_menu()    return wrapper@retryable@clear_consoledef my_menu(some_data):    print(some_data)    is_this_data_correct = input("Is this data correct? (Y/N) ").strip().upper()    if is_this_data_correct not in {"Y", "N"}:         raise InvalidInputRetryEvent(user_input=is_this_data_correct)    return is_this_data_correct == "Y"print(my_menu("aknwor anw\niwgnwinoi n\nowngwoijgwjg"))

Do you think that this solution is acceptable? If not, how else can I simply solve this?


Viewing all articles
Browse latest Browse all 950


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>