python – Obtaining a limited number of users: strings and numbers

I've posted some of this module earlier (here). I have implemented these comments and am now looking for another set of intestinal checks. Questions / concerns that I have:

  • Does the way I structured my functions make sense? Can they be broken down more / differently?
  • Is there a better way to handle errors? I feel like I'm repeating a lot of code, especially in getNumber, GetNumberInRange, and _AcceptAndValidateNumber
  • Anything that could help me improve my coding skills

In addition, I do not know if I am qualified as a beginner, but I labeled it as such because I feel that I still am.

Thanks in advance!

"" "
This module contains tools for getting feedback from a user.
At any time, while getting an entry, the user can enter "quit", "exit" or
"leave" to trigger a SystemExit exception and quit.
"" "

import textwrap as tw
from enum import Enum, auto

_EXIT_WORDS = {"quit", "quit", "quit"}


OutputMode class (Enum):
"" "
Used to determine the output of the GetNumber function
"" "
INT = auto ()
FLOAT = auto ()
NUM = auto ()


def GetStringChoice (prompt, ** kwoptions):
"" "
Print the prompt, and then return the entry as long as it matches a
options (data in the form of key / value pairs)

Call example:
>>> prompt = "Who is the strongest Avenger?"
>>> input_options = {
"t": "Thor",
"i": "Iron Man",
"c": "Captain America",
"h": "The Hulk"}
>>> response = GetStringChoice (prompt, ** input_options)
Who is the strongest Avenger?
- & # 39; t & # 39; for & # 39; Thor & # 39;
- & # 39; i & # 39; for 'Iron Man & # 39;
- & c. for & # 39; Captain America & # 39;
- & # 39; h & # 39; for & # 39; The Hulk & # 39;
h
>>> answer
& # 39; h & # 39;
Invalid results are rejected:
>>> response = GetStringChoice (prompt, ** input_options)
Who is the strongest Avenger?
- & # 39; t & # 39; for & # 39; Thor & # 39;
- & # 39; i & # 39; for 'Iron Man & # 39;
- & c. for & # 39; Captain America & # 39;
- & # 39; h & # 39; for & # 39; The Hulk & # 39;
The ant man
This was not one of the options.
Who is the strongest Avenger?
...
"" "
formated_options = _get_formatted_options (** kwoptions)

print (tw.fill (prompt))
while true:
try:
print (formated_options)

user_choice = input ()
if user_choice in kwoptions:
returns user_choice
elif user_choice in _EXIT_WORDS:
_SysExitMsg ()

print ("This was not one of the options.",)
except TypeError as t:
raise t
except SystemExit as s:
raise s
with the exception of e:
raise e


def _get_formatted_options (** kwoptions):
"" "Formats an option dictionary and returns them as a string" ""

OPTION_TEMPLATE = "- & # 39; {0: {1}} for & # 39; {2} & # 39;
# The 1 as the second argument below is a fill because the format does not allow 0
# -2 ensures that the next indent aligns with the first character
STR_PADDING = len (OPTION_TEMPLATE.format ("", 1, "")) - 2

# This is used to adjust the section before the "-" so that it is as wide as the
# longest key
space = max (map (len, kwoptions))
pad_length = space + STR_PADDING

prompt_lines = []

    for key in kwoptions:
# This wraps the text to the maximum line length and compresses the new
# lines if it looks good.
full_option = tw.fill (
kwoptions[key],
later_indent = "" * pad_length)

prompt_lines.append (OPTION_TEMPLATE.format (key, space, full option))

return " n" .join (prompt_lines)


def GetYesNo (prompt):
"" "
Calls GetStringChoice and allows the answers yes or no. Return y / n.

Example:
>>> response = GetYesNo ("Is Footloose still the biggest movie of all time?")
Is Footloose still the biggest movie of all time?
- & # 39; y & # 39; for & # 39; yes & # 39;
- & # 39; n & # 39; for & # 39; no & # 39;
It has never been!
This was not one of the options.
Is Footloose still the biggest movie of all time?
- & # 39; y & # 39; for & # 39; yes & # 39;
- & # 39; n & # 39; for & # 39; no & # 39;
not
>>> answer
& # 39; n & # 39;

"" "
Returns GetStringChoice (prompt, y = "yes", n = "no")


def GetTrueFalse (prompt):
"" "
Calls GetStringChoice and allows only one Boolean answer.
Returns Boolean True or False.

Example:
>>> GetTrueFalse ("True or False: Star-Lord was responsible for"
"the team loses on Titan:")
True or False: Star-Lord was responsible for the defeat of Titan:
- & # 39; t & # 39; for & # 39; True & # 39;
- & # 39; f & # 39; for & # 39; False & # 39;
F
False
>>>
"" "
if GetStringChoice (prompt, t = "true", f = "false") == "t":
returns True
returns False


def GetNumber (prompt, min_opt = 1, max_opt = 10, data type = OutputMode.NUM,
restrict_range = False):
"" "
Returns the choice of the user number.

If restrict_range = False, do not restrict the range (deaf).
Otherwise, limit the response to min / max_opt.

Use data_type to determine the type of number to return, passing a
OutputMode enum. Examples:
- ui.OutputMode.NUM: regardless of the type of user entered (default)
>>> my_num = GetNumber ("Choose a number:")
Choose a number:
5.0
>>> my_num
5.0
>>> my_num = GetNumber ("Choose a number:")
Choose a number:
5
>>> my_num
5
- ui.OutputMode.INT: integers
>>> my_num = GetNumber ("Choose an integer:", 1, 10, ui.OutputMode.INT,
restrict_range = False)
Choose an integer:
(min = 1, max = 10)
5.0
>>> my_num
5
- ui.OutputMode.FLOAT: fleet
>>> my_num = GetNumber ("Choose an integer:", 1, 10, ui.OutputMode.FLOAT
restrict_range = False)
Choose an integer:
(min = 1, max = 10)
5
>>> my_num
5.0
"" "
print (tw.fill (prompt))

if not restrict_range:
# The user is not limited to the min / max range
num_choice = _AcceptAndValidateNumber ()
other:
num_choice = GetNumberInRange (min_opt, max_opt)

if data_type == OutputMode.NUM:
returns num_choice
elif data_type == OutputMode.FLOAT:
return float (num_choice)
elif data_type == OutputMode.INT:
return int (num_choice)


def GetNumberInRange (min_opt, max_opt):
"" "
Let the user choose a number
Return it under the type of data used by the user
"" "

# It could live in a separate function, but then it would have to be assigned
# min / max_opt even when nothing changes
if max_opt <min_opt:
# Change the order if the maximum is less than the minimum.
# This is done for aesthetics
min_opt, max_opt = max_opt, min_opt

if max_opt == min_opt:
# It does not make sense to be equal, so note an error
raise ValueError ("The min and max numbers must not be the same.  n")

print ("(min = {0:,}, max = {1 :,})". format (min_opt, max_opt))

while true:
try:
num_choice = _AcceptAndValidateNumber ()

# Check if the num_choice is valid in our range
if eval ("{0} <= {1} <= {2}". format (min_opt, num_choice, max_opt)):
returns num_choice
print ("Choose a number between {0} and {1}.". format (
min_opt,
max_opt))
# The comma here places the user's answer on the same line
except SystemExit as s:
raise s
with the exception of e:
raise e


def _AcceptAndValidateNumber ():
"" "
Accept the choice of the number of a user, and then return it as a float or an int.

The type is determined by whether or not the user includes a decimal point.
"" "
while true:
try:
num_choice = input ()
if num_choice in _EXIT_WORDS:
_SysExitMsg ()

# Returns the corresponding number type
if num_choice.find (".") == -1:
return int (float (num_choice))
return float (num_choice)
except ValueError:
# Do not raise; just force the user back into the loop
print ("Please choose a number.")
except SystemExit as s:
raise s
with the exception of e:
raise e


def _SysExitMsg (msg = "Thank you!"):
"" "
A consistent process for SystemExit when a user enters one of the
_EXIT_WORDS
"" "
print (msg)
raises SystemExit # throws the SystemExit exception again to exit

I do not currently have unit tests for this module (I have trouble testing the incorrect answers), so I use these functions as a way to browse the different variations of entries that this module can receive:

def ():
"" "
A demonstration function.
"" "
_demonstrateGetNumber ()
_demonstrateGetStringChoice ()


def _demonstrateGetNumber ():
impression("""
Demonstration of GetNumber ()
"" ")

print ("Returns {0}  n" .format (GetNumber (
"Go up and choose a number, any number!")))

print ("Returns {0}  n" .format (GetNumber (
"Only whole numbers this time (the decimals will be rounded)."
"Choose any integer!",
data_type = OutputMode.INT)))
print ("Returns {0}  n" .format (GetNumber (
prompt = "Now only an integer in the range below!",
data_type = OutputMode.INT,
restrict_range = True)))
print ("Returns {0}  n" .format (GetNumber (
"Now choose a float! (Unauthorized beer root)",
data_type = OutputMode.FLOAT)))
print ("Returns {0}  n" .format (GetNumber (
prompt = "And finally, a float in the given range:",
min_opt = 1,
max_opt = 50,
data_type = OutputMode.FLOAT,
restrict_range = True)))
return None


def _demonstrateGetStringChoice ():
impression("""
Demonstration of GetStringChoice ()
"" ")

print ("Returns {0}  n" .format (GetStringChoice (
"What does your mother smell?", E = "elderberries", h = "hamster")))

print ("Returns {0}  n" .format (GetYesNo (
"It was just a little Python humor. Did you appreciate it?")))

print ("Returns {0}  n" .format (GetTrueFalse (
"Is it true that an African swallow could carry a coconut?")))

return None