Command Choice restructered: understanding input splitted in several methods

This commit is contained in:
Bela 2018-05-09 12:37:20 +02:00
parent 8e25703dab
commit af5f403ad0

View file

@ -392,6 +392,20 @@ class Choice(Command):
"""
class SavedException(Exception):
"""Raise if a value is saved and asking the user should stop.
To be used in the check methods.
"""
class AgainException(Exception):
"""Raise if no value is saved and the user should be asked again.
To be used in the check methods.
"""
@property
def options(self):
"""Return the list of options of the field of this choice.
@ -519,8 +533,12 @@ class Choice(Command):
print(self.reason.name, "Options:", sep="\n")
# show Default as first option -> included in sorting
self.sortOptions()
for option in self.options:
print(self.optionDescriptionInterpreted(option))
for i in range(len(self.options)):
# for option in self.options:
print(i + 1, ") ",
self.optionDescriptionInterpreted(self.options[i]),
sep="")
# print(self.optionDescriptionInterpreted(option))
def usedefault(self):
"""Save the default value.
@ -531,19 +549,128 @@ class Choice(Command):
Raises:
ConfigError: if the default is not a valid option.
Returns:
whether a value is saved aka if the user is not to be asked again
AgainException: if a help was shown.
SavedException: if the default was shown.
"""
default = self.getEnterDefault()
if default is None:
self.showHelp()
return False
raise self.AgainException()
else:
self.reason["Value"] = default
print(self.optionDescription(default))
return True
self.saveValue(default)
def saveValue(self, value):
"""Save value in self.reason["Value"].
Print message what was chosen.
Raises:
SavedException: always
"""
self.reason["Value"] = value
print("Chose", self.optionDescription(value))
raise self.SavedException()
def checkAbort(self, text):
"""Save nothing if the user gave no input (Ctrl + D).
Raises:
SavedException: if nothing is saved.
"""
if text is None:
# user aborts, nothing to be saved
self.reason["Value"] = text # = None = delete if existent
print("Chose nothing.")
raise self.SavedException()
def checkDefault(self, text):
"""Save value if the user wants to use the default.
Raises:
SavedException: if a value got saved, asking the user should stop.
AgainException: if the user should be asked again.
"""
if text == "":
self.usedefault()
# SavedException or AgainException or ConfigError raised
def checkHelp(self, text):
"""Show help if text is '?'.
Raises:
AgainException: if help is shown
"""
if text == "?":
self.showHelp()
raise self.AgainException()
def checkOptionNumber(self, text):
"""Save value which number is entered.
Raises:
SavedException: if input was a valid index.
"""
try:
number = int(text) - 1
# -1 because shown number start with 1, indeces with 0
if number < 0:
raise ValueError
except ValueError:
pass
# is not non-negative int, continue with next try
else:
try:
option = self.options[number]
except IndexError:
pass
# is not valid index, continue with next try
else:
print("debug: understood as number:", int(text) - 1)
self.saveValue(option)
def checkOptionDescription(self, text):
"""Save value if user input matches beginning of option description.
Ignore case.
Raises:
SavedException: if a value is saved.
AgainException: if two options are possible.
"""
choice = None
for option in self.options:
if ("Option" + SUBINFO_SEP + option in self
# option help exists
and self["Option" + SUBINFO_SEP + option].lower(
).startswith(text.lower())):
if choice is None:
choice = option
else:
# found second match
print("Choice not well-defined.")
raise self.AgainException()
if choice is not None:
self.saveValue(choice)
def notValidInput(self, text):
"""Assume that text is not possible to understand.
Print explaining message.
Raise:
AgainException
"""
print(text, "could not be understood as a valid choice.")
self.showHelp()
raise self.AgainException()
def do(self):
"""Ask the user a question and save the result in the field.
@ -557,7 +684,7 @@ class Choice(Command):
if "Enter" is present, take this value
otherwise show help and reask
if the answer is ?, show help and reask
if it is equal to one of the options, take this. Otherwise
if the answer is number and a valid index of the option list take it
if one of the descriptions start with the answer, (ignore case):
take this one.
if none of the above, reask
@ -570,42 +697,24 @@ class Choice(Command):
while True: # while no usable input
self.showPrompt()
text = self.userinput(prompt="Choice")
if text is None:
# user aborts, nothing to be saved
self.reason["Value"] = text # = None = delete if existent
print("Chose nothing.")
try:
self.checkAbort(text)
except self.SavedException:
break
text = text.strip()
if text == "":
if self.usedefault():
# value is saved
break
else:
# ask again aka continue
pass
elif text == "?":
self.showHelp()
elif text in self.options:
self.reason["Value"] = text
print("Chose", self.optionDescription(text))
print("debug: text after strip:", text)
try:
for check in [self.checkDefault,
self.checkHelp,
self.checkOptionNumber,
self.checkOptionDescription,
self.notValidInput]:
check(text)
# Exceptions stop the inner for loop
except self.SavedException:
break
else:
for option in self.options:
if ("Option" + SUBINFO_SEP + option in self
# option help exists
and self["Option" + SUBINFO_SEP + option].lower(
).startswith(text.lower())):
self.reason["Value"] = option
print("Chose", self.optionDescription(option))
break
else:
# if the loop went through, hence nothing found
# ask again
print("Answer not understood. Type '?' for help.")
continue
# otherwise end outer loop
break
except self.AgainException:
continue
class Default(Command):
"""A default value is saved.