toonarmycaptain/dionysus

Factor out menu choice

Open

#154 opened on Feb 21, 2019

 (2 comments) (0 reactions) (0 assignees)Python (14 forks)auto 404
enhancementgood first issuesize/M

Repository metrics

Stars
 (10 stars)
PR merge metrics
 (PR metrics pending)

Description

The code for taking user input to choose and run items from menus in main_menu.py and settings_menu.py deploy similar functionality which can be factored out.

take_settings_menu_input was recently refactored here and here not to use a flag to break the loop, matching the implementation in main_menu.py: https://github.com/toonarmycaptain/dionysus/blob/6046e12e01eb648d7c38d97f3948b911599ba020/dionysus_app/UI_menus/settings_menu.py#L41-L55)

To generalise the function I propose reintroducing a flag, returned by the functions corresponding to the options in a menu, that would indicate a return to a higher menu/scope. This also reintroduces using a function for breaking the loop/menu without action, as originally implemented in settings_menu.py (albeit with stdout user feedback).

This would allow any function to break the take/run menu selection loop with a flag returned to the calling menu logic, which may have a variety of uses - for example returning False if the action was unsuccessful could trigger feedback to the user before displaying the menu again eg Action unsuccessful. Please select another option: {menu options}. These implementations make assumptions about what the called functions return:

Assume only True is a relevant return value:

while True:
    chosen_option = input('>>> ')

    if chosen_option in possible_options:
        if possible_options[chosen_option]():  # or more explicitly: if possible_options[chosen_option]() is True:
            return True
        break  # Exit loop when chosen action finishes. Returns None.
    # else:
    print("Invalid input.")

Or to be able to return True or False flags: Assumes True and False are relevant return values.

while True:
    chosen_option = input('>>> ')

    if chosen_option in possible_options:
        return_flag = possible_options[chosen_option]()
        if return_flag is not None:
            return return_flag
        break  # Exit loop when chosen action finishes. Returns None.
    # else:
    print("Invalid input.")

Alternatively, assuming functions will return None, True or False - or equivalent values : A weakness of this approach is that there is a risk of bugs creeping in where functions happen to return an object (eg str, dict) that evaluates to True/False/None that the caller will then interpret as those values - which may be useful, or a source of bugs.

while True:
    chosen_option = input('>>> ')

    if chosen_option in possible_options:
        return possible_options[chosen_option]()
    # else:
    print("Invalid input.")

While the above is very elegant/simple, a more explicit implementation might be preferable:

while True:
    chosen_option = input('>>> ')

    if chosen_option in possible_options:
        return_flag = possible_options[chosen_option]()
        if return_flag is True or return_flag is  False or return_flag is  None:
            return return_flag
        break  # Exit loop when chosen action finishes. Returns None.
    # else:
    print("Invalid input.")

Contributor guide