Instantly share code, notes, and snippets.
-
Save JonasPf/5340085 to your computer and use it in GitHub Desktop.
A few simple methods to create interactive console applications with menus, prompts for text, date, boolean etc.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
menus.py | |
Version: 0.5 | |
A few simple methods to create interactive console applications. See the example at the bottom of this file. | |
Tested on Python 2.7 and Windows 7. | |
Copyright (c) 2013, Jonas Pfannschmidt | |
Licensed under the MIT license http://www.opensource.org/licenses/mit-license.php | |
""" | |
import datetime | |
import string | |
import types | |
from collections import OrderedDict | |
prompt = "> " | |
cancel_option = "0" | |
cancel_text = "Cancel" | |
more_option = "1" | |
more_text = "More" | |
list_format = "{option}) {text}" | |
empty_text = "No entries" | |
date_format = '%d/%m/%Y' | |
def wait_for_enter(): | |
"""Waits for the user to press enter.""" | |
raw_input("Press enter to continue" + prompt) | |
def get_string(text = '', default = None): | |
"""Get string or default value.""" | |
user_input = raw_input(text + prompt) | |
if use_default(user_input, default): | |
return default | |
else: | |
return user_input | |
def get_boolean(text = '', default = None): | |
"""Repeat until the user enters 'y', 'yes', 'n' or 'no'.""" | |
yes = ['y', 'yes'] | |
no = ['n', 'no'] | |
options = yes + no | |
if default: | |
options.append('') | |
user_input = get_option(options, text) | |
if use_default(user_input, default): | |
return default | |
elif user_input in yes: | |
return True | |
elif user_input in no: | |
return False | |
def get_integer(text = '', default = None): | |
"""Repeat until the user enters a valid number.""" | |
user_input = raw_input(text + prompt) | |
if use_default(user_input, default): | |
return default | |
elif user_input.isdigit(): | |
return int(user_input) | |
else: | |
print "Not a number: {}".format(user_input) | |
return get_integer(text, default) | |
def get_date(text = '', default = None): | |
"""Repeat until the user enters a valid date.""" | |
user_input = raw_input(text + prompt) | |
if use_default(user_input, default): | |
return default | |
else: | |
try: | |
return datetime.datetime.strptime(user_input, date_format).date() | |
except ValueError: | |
print "Not a date: {}".format(user_input) | |
return get_date(text, default) | |
def get_option(options, text = '', default = None): | |
"""Repeat until the user chooses a valid option. | |
Args: | |
options: a list of strings that are valid options | |
""" | |
user_input = raw_input(text + prompt) | |
if use_default(user_input, default): | |
return default | |
elif user_input in options: | |
return user_input | |
else: | |
print "Must be one of: {}".format(options) | |
return get_option(options, text) | |
def get_from_list(alist, text = '', show_cancel = True, default = None): | |
"""Let the user choose a value.""" | |
options = enumerate_list(alist) | |
show_enumerated_list(alist) | |
if show_cancel: | |
print "" | |
options.append(cancel_option) | |
print list_format.format(option=cancel_option, text=cancel_text) | |
chosen = get_option(options, text, default=default) | |
if chosen == default: | |
return default | |
elif chosen == cancel_option: | |
None | |
else: | |
return alist[letter_to_number(chosen)] | |
def get_from_dictionary(dictionary, show_cancel = True): | |
"""Let the user choose a key and return the corresponding value. | |
Note: Use OrderedDict to preserve the option order | |
""" | |
key = get_from_list(dictionary.keys(), show_cancel=show_cancel) | |
return dictionary[key] if key else key | |
def show_enumerated_list(alist): | |
"""Shows a list enumerated by a, b, c, ...""" | |
if (alist): | |
for option, value in zip(enumerate_list(alist), alist): | |
print list_format.format(option=option, text=value) | |
else: | |
print empty_text | |
def show_headline(headline): | |
""" Show a headline. | |
Example: | |
+------+ | |
| Test | | |
+------+ | |
""" | |
line = "+" + "-" * (len(headline) + 2) + "+" | |
print "" | |
print line | |
print "| " + headline + " |" | |
print line | |
print "" | |
def show_small_headline(headline): | |
""" Show a smaller headline. | |
Example: | |
+-- Test --+ | |
""" | |
print "+--- " + headline + " ---+" | |
def start_menu(menu, headline): | |
"""Show a menu and run a function if the user chooses one menu entry. | |
Args: | |
menu: an OrderedDict dictionary. The keys are shown as menu entries. If a value is a functions | |
it gets called when the user chooses the corresponding menu entry otherwise it gets returned. | |
headline: the title for the menu | |
""" | |
show_headline(headline) | |
chosen = get_from_dictionary(menu) | |
while isinstance(chosen, types.FunctionType): | |
chosen() | |
show_headline(headline) | |
chosen = get_from_dictionary(menu) | |
return chosen | |
def number_to_letter(i): | |
l = i % 26 | |
n = (i / 26) + 1 | |
return n * string.ascii_letters[:26][l] | |
def letter_to_number(l): | |
i = string.ascii_letters[:26].index(l[0]) | |
return i + ((len(l) - 1) * 26) | |
def enumerate_list(alist): | |
return [number_to_letter(i) for i, x in enumerate(alist)] | |
def use_default(user_input, default): | |
return default and len(user_input) == 0 | |
########### | |
# Example # | |
########### | |
def example_tour(): | |
print "Your name is: " + str(get_string("Enter your name or leave empty for the default", 'guest')) | |
print "Your choice: " + get_option(['dog', 'cat', 'mouse'], 'Which animal do you like most?') | |
print "Your birthday is: " + str(get_date("Enter your birthday in the format dd/mm/yyyy")) | |
print "Your choice: " + str(get_integer("Enter any number or leave empty for 12345", 12345)) | |
show_small_headline("Choose from an OrderedDict") | |
example = OrderedDict() | |
example['number 1'] = 'one' | |
example['number 2'] = 'two' | |
example['number 3'] = 'three' | |
print "Your choice: " + get_from_dictionary(example, show_cancel=False) | |
wait_for_enter() | |
show_small_headline("Choose from a List") | |
result = get_from_list(["one", "two", "three", "four"]) | |
if result is None: | |
print "Your choice: Cancel" | |
else: | |
print "Your choice: " + result | |
wait_for_enter() | |
if get_boolean("Do you want to do the tour again?"): | |
example_tour() | |
def example_headlines(): | |
mymenu = OrderedDict() | |
mymenu['Show headline'] = 'full' | |
mymenu['Show small headline'] = 'small' | |
result = start_menu(mymenu, "Example") | |
if result == 'full': | |
show_headline("Test headline") | |
elif result == 'small': | |
show_small_headline("Test small headline") | |
wait_for_enter() | |
if __name__=="__main__": | |
mymenu = OrderedDict() | |
mymenu['Show submenu for headlines'] = example_headlines | |
mymenu['Quick tour'] = example_tour | |
mymenu['A useless option'] = lambda: None | |
start_menu(mymenu, "Example") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment