Skip to content

Instantly share code, notes, and snippets.

@JonasPf
Created April 8, 2013 20:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save JonasPf/5340085 to your computer and use it in GitHub Desktop.
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.
"""
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