Projects/worblehat-old
Projects
/
worblehat-old
Archived
12
0
Fork 0
This repository has been archived on 2024-07-04. You can view files and clone it, but cannot push or open issues or pull requests.
worblehat-old/python/dibbler_snippet.py

406 lines
12 KiB
Python
Raw Normal View History

exit_commands = ['exit', 'abort', 'quit', 'bye', 'eat flaming death', 'q']
help_commands = ['help', '?']
context_commands = ['what', '??']
local_help_commands = ['help!', '???']
class Menu():
def __init__(self, name, items=[], prompt='> ',
return_index=True,
exit_msg=None, exit_confirm_msg=None, exit_disallowed_msg=None,
help_text=None, uses_db=False):
self.name = name
self.items = items
self.prompt = prompt
self.return_index = return_index
self.exit_msg = exit_msg
self.exit_confirm_msg = exit_confirm_msg
self.exit_disallowed_msg = exit_disallowed_msg
self.help_text = help_text
self.context = None
self.header_format = '[%s]'
self.uses_db = uses_db
def exit_menu(self):
if self.exit_disallowed_msg != None:
print self.exit_disallowed_msg
return
if self.exit_confirm_msg != None:
if not self.confirm(self.exit_confirm_msg, default=True):
return
raise ExitMenu()
def at_exit(self):
if self.exit_msg:
print self.exit_msg
def set_context(self, string, display=True):
self.context = string
if self.context != None and display:
print self.context
def add_to_context(self, string):
self.context += string
def printc(self, string):
print string
if self.context == None:
self.context = string
else:
self.context += '\n' + string
def show_context(self):
print self.header_format % self.name
if self.context != None:
print self.context
def item_is_submenu(self, i):
return isinstance(self.items[i], Menu)
def item_name(self, i):
if self.item_is_submenu(i):
return self.items[i].name
elif isinstance(self.items[i], tuple):
return self.items[i][1]
else:
return self.items[i]
def item_value(self, i):
if isinstance(self.items[i], tuple):
return self.items[i][0]
if self.return_index:
return i
return self.items[i]
def input_str(self, prompt=None, regex=None, length_range=(None,None),
empty_string_is_none=False):
if regex != None:
while True:
result = self.input_str(prompt, length_range=length_range,
empty_string_is_none=empty_string_is_none)
if result == None or re.match(regex+'$', result):
return result
else:
print 'Value must match regular expression "%s"' % regex
if length_range != (None,None):
while True:
result = self.input_str(prompt, empty_string_is_none=empty_string_is_none)
if result == None:
length = 0
else:
length = len(result)
if ((length_range[0] and length < length_range[0]) or
(length_range[1] and length > length_range[1])):
if length_range[0] and length_range[1]:
print 'Value must have length in range [%d,%d]' % length_range
elif length_range[0]:
print 'Value must have length at least %d' % length_range[0]
else:
print 'Value must have length at most %d' % length_range[1]
else:
return result
if prompt == None:
prompt = self.prompt
while True:
try:
result = unicode(raw_input(safe_str(prompt)),
conf.input_encoding)
except EOFError:
print 'quit'
self.exit_menu()
continue
if result in exit_commands:
self.exit_menu()
continue
if result in help_commands:
self.general_help()
continue
if result in local_help_commands:
self.local_help()
continue
if result in context_commands:
self.show_context()
continue
# if result in faq_commands:
# FAQMenu().execute()
# continue
# if result in restart_commands:
# if self.confirm('Restart Dibbler?'):
# restart()
# continue
if empty_string_is_none and result == '':
return None
return result
def input_int(self, prompt=None, allowed_range=(None,None)):
if prompt == None:
prompt = self.prompt
while True:
result = self.input_str(prompt)
try:
value = int(result)
if ((allowed_range[0] and value < allowed_range[0]) or
(allowed_range[1] and value > allowed_range[1])):
if allowed_range[0] and allowed_range[1]:
print 'Value must be in range [%d,%d]' % allowed_range
elif allowed_range[0]:
print 'Value must be at least %d' % allowed_range[0]
else:
print 'Value must be at most %d' % allowed_range[1]
else:
return value
except ValueError:
print 'Please enter an integer'
# def input_user(self, prompt=None):
# user = None
# while user == None:
# user = self.retrieve_user(self.input_str(prompt))
# return user
# def retrieve_user(self, search_str):
# return self.search_ui(search_user, search_str, 'user')
# def input_product(self, prompt=None):
# product = None
# while product == None:
# product = self.retrieve_product(self.input_str(prompt))
# return product
# def retrieve_product(self, search_str):
# return self.search_ui(search_product, search_str, 'product')
# def input_thing(self, prompt=None, permitted_things=('user','product'),
# add_nonexisting=(), empty_input_permitted=False):
# result = None
# while result == None:
# search_str = self.input_str(prompt)
# if search_str == '' and empty_input_permitted:
# return None
# result = self.search_for_thing(search_str, permitted_things, add_nonexisting)
# return result
# def search_for_thing(self, search_str, permitted_things=('user','product'),
# add_nonexisting=()):
# search_fun = {'user': search_user,
# 'product': search_product}
# results = {}
# result_values = {}
# for thing in permitted_things:
# results[thing] = search_fun[thing](search_str, self.session)
# result_values[thing] = self.search_result_value(results[thing])
# selected_thing = argmax(result_values)
# if results[selected_thing] == []:
# thing_for_type = {'card': 'user', 'username': 'user',
# 'bar_code': 'product'}
# type_guess = guess_data_type(search_str)
# if type_guess != None and thing_for_type[type_guess] in add_nonexisting:
# return self.search_add(search_str)
# print 'No match found for "%s".' % search_str
# return None
# return self.search_ui2(search_str, results[selected_thing], selected_thing)
def search_result_value(self, result):
if result == None:
return 0
if not isinstance(result, list):
return 3
if len(result) == 0:
return 0
if len(result) == 1:
return 2
return 1
def search_add(self, string):
type_guess = guess_data_type(string)
if type_guess == 'username':
print '"%s" looks like a username, but no such user exists.' % string
if self.confirm('Create user %s?' % string):
user = User(string, None)
self.session.add(user)
return user
return None
if type_guess == 'card':
selector = Selector('"%s" looks like a card number, but no user with that card number exists.' % string,
[('create', 'Create user with card number %s' % string),
('set', 'Set card number of an existing user to %s' % string)])
selection = selector.execute()
if selection == 'create':
username = self.input_str('Username for new user (should be same as PVV username)> ',
User.name_re, (1,10))
user = User(username, string)
self.session.add(user)
return user
if selection == 'set':
user = self.input_user('User to set card number for> ')
old_card = user.card
user.card = string
print 'Card number of %s set to %s (was %s)' % (user.name, string, old_card)
return user
return None
if type_guess == 'bar_code':
print '"%s" looks like the bar code for a product, but no such product exists.' % string
return None
def search_ui(self, search_fun, search_str, thing):
result = search_fun(search_str, self.session)
return self.search_ui2(search_str, result, thing)
def search_ui2(self, search_str, result, thing):
if not isinstance(result, list):
return result
if len(result) == 0:
print 'No %ss matching "%s"' % (thing, search_str)
return None
if len(result) == 1:
msg = 'One %s matching "%s": %s. Use this?' %\
(thing, search_str, unicode(result[0]))
if self.confirm(msg, default=True):
return result[0]
return None
limit = 9
if len(result) > limit:
select_header = '%d %ss matching "%s"; showing first %d' % \
(len(result), thing, search_str, limit)
select_items = result[:limit]
else:
select_header = '%d %ss matching "%s"' % \
(len(result), thing, search_str)
select_items = result
selector = Selector(select_header, items=select_items,
return_index=False)
return selector.execute()
def confirm(self, prompt, default=None):
return ConfirmMenu(prompt, default).execute()
def print_header(self):
print
print self.header_format % self.name
def pause(self):
self.input_str('.')
def general_help(self):
print '''
DIBBLER HELP
The following commands are recognized (almost) everywhere:
help, ? -- display this help
what, ?? -- redisplay the current context
help!, ??? -- display context-specific help (if any)
faq -- display frequently asked questions (with answers)
exit, quit, etc. -- exit from the current menu
When prompted for a user, you can type (parts of) the user name or
card number. When prompted for a product, you can type (parts of) the
product name or barcode.
About payment and "credit": When paying for something, use either
Dibbler or the good old money box -- never both at the same time.
Dibbler keeps track of a "credit" for each user, which is the amount
of money PVVVV owes the user. This value decreases with the
appropriate amount when you register a purchase, and you may increase
it by putting money in the box and using the "Adjust credit" menu.
'''
def local_help(self):
if self.help_text == None:
print 'no help here'
else:
print
print 'Help for %s:' % (self.header_format%self.name)
print self.help_text
def execute(self):
self.set_context(None)
try:
if self.uses_db:
self.session = Session()
else:
self.session = None
return self._execute()
except ExitMenu:
self.at_exit()
return None
finally:
if self.session != None:
self.session.close()
self.session = None
def _execute(self):
line_format = '%' + str(len(str(len(self.items)))) + 'd ) %s'
while True:
self.print_header()
self.set_context(None)
if len(self.items)==0:
self.printc('(empty menu)')
self.pause()
return None
for i in range(len(self.items)):
self.printc(line_format % (i+1, self.item_name(i)))
item_i = self.input_int(self.prompt, (1,len(self.items)))-1
if self.item_is_submenu(item_i):
self.items[item_i].execute()
else:
return self.item_value(item_i)
class Selector(Menu):
def __init__(self, name, items=[], prompt='select> ',
return_index=True,
exit_msg=None, exit_confirm_msg=None,
help_text=None):
Menu.__init__(self, name, items, prompt, return_index, exit_msg)
self.header_format = '%s'
def print_header(self):
print self.header_format % self.name
def local_help(self):
if self.help_text == None:
print 'This is a selection menu. Enter one of the listed numbers, or'
print '\'exit\' to go out and do something else.'
else:
print
print 'Help for selector (%s):' % self.name
print self.help_text
class ConfirmMenu(Menu):
def __init__(self, prompt='confirm?', default=None):
Menu.__init__(self, 'question', prompt=prompt,
exit_disallowed_msg='Please answer yes or no')
self.default=default
def _execute(self):
options = {True: '[y]/n', False: 'y/[n]', None: 'y/n'}[self.default]
while True:
result = self.input_str('%s (%s) ' % (self.prompt, options))
result = result.lower()
if result in ['y','yes']:
return True
if result in ['n','no']:
return False
if self.default != None and result == '':
return self.default
print 'Please answer yes or no'
class MessageMenu(Menu):
def __init__(self, name, message, pause_after_message=True):
Menu.__init__(self, name)
self.message = message.strip()
self.pause_after_message = pause_after_message
def _execute(self):
self.print_header()
print
print self.message
if self.pause_after_message:
self.pause()