Command Choice restructered: understanding input splitted in several methods
This commit is contained in:
parent
8e25703dab
commit
af5f403ad0
1 changed files with 152 additions and 43 deletions
195
commands.py
195
commands.py
|
@ -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.
|
||||
|
|
Loading…
Reference in a new issue