Ask the user a question using raw_input() and looking something
like this (style=="compact"
):
QUESTION [DEFAULT]: _
...validation...
or this (style=="verbose"
):
QUESTION
Hit <Enter> to use the default, DEFAULT.
> _
...validate...
It supports some basic validation/normalization of the given answer.
See also: Recipe 577058 (query yes/no), Recipe 577097 (query yes/no/quit), Recipe 577096 (query custom answers)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 | def command_line_query(question, default=None, validate=None, style="compact"):
"""Ask the user a question using raw_input() and looking something
like this ("compact" style, the default, `_` is the cursor):
QUESTION [DEFAULT]: _
...validation...
or this ("verbose" style):
QUESTION
Hit <Enter> to use the default, DEFAULT.
> _
...validation...
@param question {str} The question to ask.
@param default {str} Optional. The default value if non is given.
@param validate {str|function} is either a string naming a stock
validator
not-empty Ensure the user's answer is not empty.
yes-or-no Ensure the user's answer is 'yes' or 'no'.
('y', 'n' and any capitalization are
also accepted)
int Answer is an integer.
or a callback function with this signature:
validate(answer) -> normalized-answer
It should raise `ValueError` to indicate an invalid answer.
By default no validation is done.
@param style {str} is a name for the interaction style, either "compact"
(the default) or "verbose". See the examples above.
@returns {str} The normalized answer.
"""
if isinstance(validate, (str, unicode)):
if validate == "not-empty":
def validate_not_empty(answer):
if not answer:
raise ValueError("You must enter some non-empty value.")
return answer
validate = validate_notempty
elif validate == "yes-or-no":
def validate_yes_or_no(answer):
normalized = {"yes":"yes", "y":"yes", "ye":"yes",
"no":"no", "n":"no"}
try:
return normalized[answer.lower()]
except KeyError:
raise ValueError("Please enter 'yes' or 'no'.")
validate = validate_yes_or_no
elif validate == "int":
def validate_int(answer):
try:
int(answer)
except ValueError:
raise ValueError("Please enter an integer.")
else:
return answer
validate = validate_int
else:
raise ValueError("unknown stock validator: '%s'" % validate)
def indented(text, indent=' '*4):
lines = text.splitlines(1)
return indent + indent.join(lines)
if style == "compact":
prompt = question
if default is not None:
prompt += " [%s]" % (default or "<empty>")
prompt += ": "
elif style == "verbose":
sys.stdout.write(question + '\n')
if default:
sys.stdout.write("Hit <Enter> to use the default, %r.\n" % default)
elif default is not None:
default_str = default and repr(default) or '<empty>'
sys.stdout.write("Hit <Enter> to leave blank.\n")
prompt = "> "
else:
raise ValueError("unknown query style: %r" % style)
while True:
if True:
answer = raw_input(prompt)
else:
sys.stdout.write(prompt)
sys.stdout.flush()
answer = sys.stdout.readline()
if not answer and default:
answer = default
if validate is not None:
orig_answer = answer
try:
norm_answer = validate(answer)
except ValueError, ex:
sys.stdout.write(str(ex) + '\n')
continue
else:
norm_answer = answer
break
return norm_answer
|