Update interactive.py.

This commit is contained in:
voussoir 2021-12-14 20:37:40 -08:00
parent 90f14e04f8
commit c2dae46c99
No known key found for this signature in database
GPG key ID: 5F7554F8C26DACCB

View file

@ -26,21 +26,42 @@ def _abc_make_option_letters(options):
return option_letters return option_letters
def abc_chooser(options, prompt='', must_pick=False): def abc_chooser(options, *, prompt='', must_pick=False, tostring=None):
''' '''
Given a list of options, the user will pick one by the corresponding letter. Given a list of options, the user will pick one by the corresponding letter.
The return value is the item from the options list, or None if must_pick is The return value is the item from the options list, or None if must_pick is
False and the user entered nothing. False and the user entered nothing.
options:
A list of options to choose from. The returned value will be one of
these, or None if must_pick is false and the user made no selection.
prompt:
A prompt string to appear at the bottom of the menu where the user
makes their choice.
must_pick:
If True, the menu will keep repeating until the user makes a choice.
If False, the user can submit a blank line to choose None.
tostring:
A function that converts the items from options into strings. Use this
if the objects' normal __str__ method is not suitable for your menu.
This way you don't have to convert your objects into strings and then
back again after getting the returned choice.
''' '''
assert_stdin() assert_stdin()
option_letters = _abc_make_option_letters(options) option_letters = _abc_make_option_letters(options)
if tostring is not None:
options_rendered = {letter: tostring(option) for (letter, option) in option_letters.items()}
else:
options_rendered = option_letters
while True: while True:
message = [] for (letter, option) in options_rendered.items():
for (letter, option) in option_letters.items(): pipeable.stderr(f'{letter}. {option}')
message.append(f'{letter}. {option}')
pipeable.stderr('\n'.join(message))
choice = input(prompt).strip().lower() choice = input(prompt).strip().lower()
if not choice: if not choice:
@ -48,7 +69,7 @@ def abc_chooser(options, prompt='', must_pick=False):
pipeable.stderr() pipeable.stderr()
continue continue
else: else:
return return None
if choice not in option_letters: if choice not in option_letters:
pipeable.stderr() pipeable.stderr()
@ -56,25 +77,45 @@ def abc_chooser(options, prompt='', must_pick=False):
return option_letters[choice] return option_letters[choice]
def abc_chooser_many(options, prompt='', label='X'): def abc_chooser_many(options, *, prompt='', label='X', tostring=None) -> list:
''' '''
Given a list of options, the user may pick zero or many options by their Given a list of options, the user may pick zero or more options by their
corresponding letter. They can toggle the options on and off as long as corresponding letter. They can toggle the options on and off as many times
they like, and submit their selection by entering one more blank line. as they like, and submit their selection by entering a blank line.
The return value is a list of items from the options list. The return value is a list of items from the options list.
options:
A list of options to choose from. The returned list will be a subset
of this.
prompt:
A prompt string to appear at the bottom of the menu where the user
makes their choices.
label:
This label is placed between square brackets and indicates which
choices are currently selected. For example [X] or [ACTIVE].
tostring:
A function that converts the items from options into strings. Use this
if the objects' normal __str__ method is not suitable for your menu.
This way you don't have to convert your objects into strings and then
back again after getting the returned choices.
''' '''
assert_stdin() assert_stdin()
selected = set()
option_letters = _abc_make_option_letters(options) option_letters = _abc_make_option_letters(options)
if tostring is not None:
options_rendered = {letter: tostring(option) for (letter, option) in option_letters.items()}
else:
options_rendered = option_letters
selected = set()
while True: while True:
message = [] for (letter, option) in options_rendered.items():
for (letter, option) in option_letters.items():
this_label = label if letter in selected else '' this_label = label if letter in selected else ''
this_label = this_label.center(len(label)) this_label = this_label.center(len(label))
message.append(f'{letter}. [{this_label}] {option}') pipeable.stderr(f'{letter}. [{this_label}] {option}')
pipeable.stderr('\n'.join(message))
choice = input(prompt).strip().lower() choice = input(prompt).strip().lower()
@ -91,7 +132,7 @@ def abc_chooser_many(options, prompt='', label='X'):
selected.add(choice) selected.add(choice)
pipeable.stderr() pipeable.stderr()
choices = [option_letters[letter] for letter in option_letters if letter in selected] choices = [option_letters[letter] for letter in sorted(selected)]
return choices return choices
#################################################################################################### ####################################################################################################
@ -113,12 +154,21 @@ def getpermission(
Return True for yes, False for no, and None if undecided. Return True for yes, False for no, and None if undecided.
You can customize the strings that mean yes or no. For example, you could prompt:
create a "type the name of the thing you're about to delete" prompt. This string will appear above the yes/no input.
If `must_pick`, then undecided is not allowed and the input will repeat yes_strings,
until they choose an acceptable answer. Either way, the intended usage of no_strings:
`if getpermission():` will always only accept in case of explicit yes. You can customize the strings that mean yes or no. For example, you
could require the user to confirm a deletion by making the resource name
the only yes string.
yes_strings and no_strings should be tuples/lists instead of sets because
the [0] item will be the one shown on the prompt. The rest are still
acceptable answers.
must_pick:
If True, the menu will keep repeating until the user makes a choice.
If False, the user can submit a blank line to choose None.
''' '''
assert_stdin() assert_stdin()