toejough / pimento

simple CLI menu

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

best practice for invoking menu cmds

dcsan opened this issue · comments

commented

sorry for using your issues as a discussion board but ...

how do you recommend invoking a menu command? I'm doing something like below, not sure if it's very pythonic, or if it might be worth adding to the core library a way to associate menu options with their functions.

# cmdname, function-ptr
menu_opts = {
    'timeslice': timeslice,
    'webapp': webapp,
    'split_sessions': split_sessions,
    'quit': quit
}

def run_cmd(opt):
    """exec related anon func"""
    # print('menu_opts', menu_opts)
    cmd = menu_opts[opt]
    cmd()

No worries.

There was another library out there that explicitly did this behavior - paired menu options to functions, and invoked the functions, but at the time I wrote this lib, I wanted something simpler, that would allow you to do the same thing with little fuss, but would also allow you to just access the raw menu option chosen, if you wanted that.

I got an email with what must've been your first draft of this issue, that also included some CLI input... I've used pimento like this myself, and this is what I've done:

def run():
    menu_opts = ...
    choices = menu_opts.keys()
    user_choice = get_from_args(choices) or get_from_menu(choices)
    menu_opts[user_choice]()

...where get_from_args gets the choice from the CLI invocation arguments, if any, otherwise returns something falsey like None, and get_from_menu uses pimento to present a menu and return the option.

For more complex CLI's with lots of arguments, I will generally tell a user in the help text that an argument is required, check if it was set, and then if not, present a menu.

In other cases I prefer something like dispatcher(get_from_menu(options)), because it's cleaner at the caller level than what the above boils down to (menu_opts[get_from_menu(menu_opts.keys())]()), and inside dispatcher you can call functions that take arguments, further parse the menu choice, etc. Depends on what you need and personal preferences at that point, though, I think.

One of the big things I cared about when I wrote this lib, though, was that you don't always want to run a function when you present a menu. A menu presented for "choose a color" is just going to pass that color into another function - it's not going to call a do_it_with_red or do_it_with_blue function, it's just going to call do_it(color=chosen_color).

So I wanted a menu that would just return a choice to me, and I'm probably going to keep it that way.

Although... I could see adding a few more functions to the top level API, like dispatch_menu or dict_menu that just wrapped some of these calls up. I admit your use case is common (like I said, I've done it several times, too), so I could see adding a new function to make it simpler.

commented

while formalizing the data structs, a way to have simple menu numbers,
and allow one-key choice of them (without return) would be good.

1 tex
2 rugs
3 socks

could you make this a separate issue? Also, what about lists longer than 9 items? to allow choice without hitting enter requires unique input - would you want leading 0's 000 - 999, or just disallow the non-return selection for longer lists?

commented

new ticket made.