C Not a Valid Input Try Again
eight
INPUT VALIDATION
Input validation lawmaking checks that values entered by the user, such as text from the input() function, are formatted correctly. For example, if you desire users to enter their ages, your lawmaking shouldn't accept nonsensical answers such as negative numbers (which are exterior the range of adequate integers) or words (which are the wrong information type). Input validation can also prevent bugs or security vulnerabilities. If you implement a withdrawFromAccount() role that takes an argument for the corporeality to subtract from an account, you need to ensure the amount is a positive number. If the withdrawFromAccount() office subtracts a negative number from the account, the "withdrawal" will end upwardly calculation money!
Typically, we perform input validation by repeatedly request the user for input until they enter valid text, as in the following example:
while True:
impress('Enter your historic period:')
age = input()
endeavour:
age = int(age)
except:
impress('Delight use numeric digits.')
continue
if age < 1:
print('Please enter a positive number.')
continue
break
impress(f'Your age is {age}.')
When you lot run this program, the output could look like this:
Enter your age:
five
Please use numeric digits.
Enter your age:
-2
Please enter a positive number.
Enter your age:
30
Your age is xxx.
When you lot run this code, you'll be prompted for your age until y'all enter a valid one. This ensures that by the time the execution leaves the while loop, the age variable volition contain a valid value that won't crash the program later on.
However, writing input validation lawmaking for every input() call in your plan quickly becomes irksome. Likewise, yous may miss certain cases and allow invalid input to pass through your checks. In this chapter, you'll acquire how to utilize the third-party PyInputPlus module for input validation.
The PyInputPlus Module
PyInputPlus contains functions like to input() for several kinds of data: numbers, dates, electronic mail addresses, and more. If the user ever enters invalid input, such as a badly formatted appointment or a number that is exterior of an intended range, PyInputPlus will reprompt them for input just similar our code in the previous section did. PyInputPlus besides has other useful features like a limit for the number of times information technology reprompts users and a timeout if users are required to answer within a time limit.
PyInputPlus is not a part of the Python Standard Library, so yous must install it separately using Pip. To install PyInputPlus, run pip install --user pyinputplus from the command line. Appendix A has complete instructions for installing third-party modules. To bank check if PyInputPlus installed correctly, import it in the interactive shell:
>>> import pyinputplus
If no errors appear when y'all import the module, it has been successfully installed.
PyInputPlus has several functions for dissimilar kinds of input:
inputStr() Is like the born input() role only has the general PyInputPlus features. You can likewise pass a custom validation function to it
inputNum() Ensures the user enters a number and returns an int or float, depending on if the number has a decimal point in information technology
inputChoice() Ensures the user enters one of the provided choices
inputMenu() Is similar to inputChoice(), but provides a menu with numbered or lettered options
inputDatetime() Ensures the user enters a date and time
inputYesNo() Ensures the user enters a "yes" or "no" response
inputBool() Is similar to inputYesNo(), just takes a "True" or "Imitation" response and returns a Boolean value
inputEmail() Ensures the user enters a valid email address
inputFilepath() Ensures the user enters a valid file path and filename, and can optionally check that a file with that name exists
inputPassword() Is like the built-in input(), but displays * characters as the user types and then that passwords, or other sensitive information, aren't displayed on the screen
These functions will automatically reprompt the user for as long every bit they enter invalid input:
>>> import pyinputplus as pyip
>>> response = pyip.inputNum()
five
'five' is non a number.
42
>>> response
42
The as pyip code in the import argument saves us from typing pyinputplus each fourth dimension nosotros want to telephone call a PyInputPlus function. Instead nosotros can utilise the shorter pyip name. If you take a expect at the instance, you encounter that unlike input(), these functions render an int or bladder value: 42 and three.xiv instead of the strings '42' and '3.xiv'.
Just as yous can laissez passer a string to input() to provide a prompt, you tin can pass a cord to a PyInputPlus function'due south prompt keyword argument to display a prompt:
>>> response = input('Enter a number: ')
Enter a number: 42
>>> response
'42'
>>> import pyinputplus equally pyip
>>> response = pyip.inputInt(prompt='Enter a number: ')
Enter a number: true cat
'true cat' is not an integer.
Enter a number: 42
>>> response
42
Utilize Python's help() part to find out more well-nigh each of these functions. For example, assistance(pyip.inputChoice) displays assistance information for the inputChoice() role. Complete documentation can be institute at https://pyinputplus.readthedocs.io/.
Dissimilar Python's built-in input(), PyInputPlus functions have several boosted features for input validation, as shown in the side by side section.
The min, max, greaterThan, and lessThan Keyword Arguments
The inputNum(), inputInt(), and inputFloat() functions, which have int and float numbers, also take min, max, greaterThan, and lessThan keyword arguments for specifying a range of valid values. For example, enter the following into the interactive trounce:
>>> import pyinputplus equally pyip
>>> response = pyip.inputNum('Enter num: ', min=four)
Enter num:3
Input must be at minimum 4.
Enter num:4
>>> response
iv
>>> response = pyip.inputNum('Enter num: ', greaterThan=4)
Enter num: iv
Input must be greater than four.
Enter num: 5
>>> response
5
>>> response = pyip.inputNum('>', min=4, lessThan=6)
Enter num: 6
Input must exist less than 6.
Enter num: 3
Input must be at minimum iv.
Enter num: 4
>>> response
4
These keyword arguments are optional, simply if supplied, the input cannot exist less than the min statement or greater than the max statement (though the input can be equal to them). Too, the input must exist greater than the greaterThan and less than the lessThan arguments (that is, the input cannot be equal to them).
The bare Keyword Argument
By default, blank input isn't allowed unless the bare keyword argument is set to True:
>>> import pyinputplus as pyip
>>> response = pyip.inputNum('Enter num: ')
Enter num:(blank input entered hither)
Blank values are non immune.
Enter num: 42
>>> response
42
>>> response = pyip.inputNum(blank=True)
(blank input entered hither)
>>> response
''
Use blank=True if you'd similar to brand input optional so that the user doesn't need to enter anything.
The limit, timeout, and default Keyword Arguments
By default, the PyInputPlus functions will go on to ask the user for valid input forever (or for equally long equally the programme runs). If yous'd like a office to stop asking the user for input afterward a certain number of tries or a certain amount of time, y'all can utilise the limit and timeout keyword arguments. Pass an integer for the limit keyword argument to determine how many attempts a PyInputPlus function will brand to receive valid input before giving up, and pass an integer for the timeout keyword argument to decide how many seconds the user has to enter valid input earlier the PyInputPlus function gives up.
If the user fails to enter valid input, these keyword arguments will crusade the function to raise a RetryLimitException or TimeoutException, respectively. For example, enter the following into the interactive vanquish:
>>> import pyinputplus as pyip
>>> response = pyip.inputNum(limit=2)
blah
'blah' is not a number.
Enter num: number
'number' is not a number.
Traceback (about recent telephone call terminal):
--snip--
pyinputplus.RetryLimitException
>>> response = pyip.inputNum(timeout=10)
42 (entered afterward 10 seconds of waiting)
Traceback (nearly recent call concluding):
--snip--
pyinputplus.TimeoutException
When you use these keyword arguments and also pass a default keyword argument, the function returns the default value instead of raising an exception. Enter the following into the interactive beat out:
>>> response = pyip.inputNum(limit=two, default='Northward/A')
hello
'howdy' is not a number.
world
'world' is non a number.
>>> response
'Due north/A'
Instead of raising RetryLimitException, the inputNum() function simply returns the cord 'N/A'.
The allowRegexes and blockRegexes Keyword Arguments
Yous tin as well use regular expressions to specify whether an input is allowed or not. The allowRegexes and blockRegexes keyword arguments have a list of regular expression strings to determine what the PyInputPlus function volition take or decline as valid input. For example, enter the post-obit code into the interactive beat and then that inputNum() will accept Roman numerals in add-on to the usual numbers:
>>> import pyinputplus every bit pyip
>>> response = pyip.inputNum(allowRegexes=[r'(I|V|X|L|C|D|M)+', r'nil'])
XLII
>>> response
'XLII'
>>> response = pyip.inputNum(allowRegexes=[r'(i|5|x|l|c|d|grand)+', r'zero'])
xlii
>>> response
'xlii'
Of course, this regex affects only what messages the inputNum() function will accept from the user; the function volition still accept Roman numerals with invalid ordering such every bit 'XVX' or 'MILLI' because the r'(I|V|10|L|C|D|Thousand)+' regular expression accepts those strings.
You can also specify a listing of regular expression strings that a PyInputPlus office won't accept by using the blockRegexes keyword statement. Enter the following into the interactive beat out then that inputNum() won't have even numbers:
>>> import pyinputplus as pyip
>>> response = pyip.inputNum(blockRegexes=[r'[02468]$'])
42
This response is invalid.
44
This response is invalid.
43
>>> response
43
If y'all specify both an allowRegexes and blockRegexes argument, the let list overrides the block listing. For case, enter the following into the interactive shell, which allows 'caterpillar' and 'category' merely blocks anything else that has the word 'true cat' in information technology:
>>> import pyinputplus every bit pyip
>>> response = pyip.inputStr(allowRegexes=[r'caterpillar', 'category'],
blockRegexes=[r'true cat'])
cat
This response is invalid.
catastrophe
This response is invalid.
category
>>> response
'category'
The PyInputPlus module'due south functions tin save you from writing tedious input validation code yourself. Merely there's more to the PyInputPlus module than what has been detailed hither. Yous tin examine its total documentation online at https://pyinputplus.readthedocs.io/.
Passing a Custom Validation Function to inputCustom()
Yous can write a function to perform your own custom validation logic by passing the function to inputCustom(). For example, say you want the user to enter a serial of digits that adds up to 10. There is no pyinputplus.inputAddsUpToTen() office, simply y'all tin create your own function that:
- Accepts a unmarried string argument of what the user entered
- Raises an exception if the string fails validation
- Returns None (or has no return argument) if inputCustom() should render the string unchanged
- Returns a non-None value if inputCustom() should return a different string from the one the user entered
- Is passed equally the starting time argument to inputCustom()
For instance, we tin create our own addsUpToTen() office, and then pass it to inputCustom(). Annotation that the function call looks like inputCustom(addsUpToTen) and not inputCustom(addsUpToTen()) because we are passing the addsUpToTen() function itself to inputCustom(), not calling addsUpToTen() and passing its render value.
>>> import pyinputplus as pyip
>>> def addsUpToTen(numbers):
...numbersList = list(numbers)
...for i, digit in enumerate(numbersList):
...numbersList[i] = int(digit)
...if sum(numbersList) != 10:
...raise Exception('The digits must add up to 10, not %s.' %
(sum(numbersList)))
...return int(numbers) # Return an int class of numbers.
...
>>> response = pyip.inputCustom(addsUpToTen) # No parentheses after
addsUpToTen here.
123
The digits must add together up to 10, not vi.
1235
The digits must add up to 10, not eleven.
1234
>>> response # inputStr() returned an int, non a cord.
1234
>>> response = pyip.inputCustom(addsUpToTen)
hello
invalid literal for int() with base of operations 10: 'h'
55
>>> response
The inputCustom() role besides supports the general PyInputPlus features, such every bit the blank, limit, timeout, default, allowRegexes, and blockRegexes keyword arguments. Writing your own custom validation function is useful when it's otherwise difficult or incommunicable to write a regular expression for valid input, as in the "adds up to 10" example.
Projection: How to Go along an Idiot Busy for Hours
Let'south apply PyInputPlus to create a unproblematic program that does the following:
- Inquire the user if they'd like to know how to keep an idiot busy for hours.
- If the user answers no, quit.
- If the user answers aye, go to Step 1.
Of form, we don't know if the user will enter something too "aye" or "no," so nosotros need to perform input validation. Information technology would also be user-friendly for the user to exist able to enter "y" or "n" instead of the full words. PyInputPlus's inputYesNo() function volition handle this for us and, no matter what instance the user enters, render a lowercase 'yes' or 'no' string value.
When you run this program, it should wait similar the post-obit:
Want to know how to go on an idiot busy for hours?
sure
'sure' is non a valid yes/no response.
Want to know how to keep an idiot busy for hours?
aye
Want to know how to keep an idiot busy for hours?
y
Desire to know how to go on an idiot decorated for hours?
Yes
Want to know how to go on an idiot busy for hours?
Yes
Want to know how to proceed an idiot decorated for hours?
YES!!!!!!
'Yeah!!!!!!' is not a valid yes/no response.
Want to know how to go on an idiot busy for hours?
TELL ME HOW TO KEEP AN IDIOT Decorated FOR HOURS.
'TELL ME HOW TO Keep AN IDIOT BUSY FOR HOURS.' is not a valid yes/no response.
Want to know how to go on an idiot decorated for hours?
no
Thanks. Have a overnice day.
Open up a new file editor tab and relieve information technology equally idiot.py. Then enter the following code:
import pyinputplus as pyip
This imports the PyInputPlus module. Since pyinputplus is a flake much to type, we'll apply the name pyip for short.
while True:
prompt = 'Want to know how to keep an idiot busy for hours?\n'
response = pyip.inputYesNo(prompt)
Side by side, while Truthful: creates an infinite loop that continues to run until information technology encounters a interruption argument. In this loop, we call pyip.inputYesNo() to ensure that this part phone call won't render until the user enters a valid answer.
if response == 'no':
pause
The pyip.inputYesNo() call is guaranteed to only return either the cord yeah or the string no. If it returned no, and then our program breaks out of the infinite loop and continues to the last line, which thanks the user:
print('Thank y'all. Have a overnice twenty-four hour period.')
Otherwise, the loop iterates in one case again.
You lot tin can also make employ of the inputYesNo() function in non-English languages by passing yesVal and noVal keyword arguments. For example, the Spanish version of this program would have these two lines:
prompt = '¿Quieres saber cómo mantener ocupado a un idiota durante horas?\n'
response = pyip.inputYesNo(prompt, yesVal='sí', noVal='no')
if response == 'sí':
Now the user tin enter either sí or s (in lower- or majuscule) instead of yes or y for an affirmative respond.
Project: Multiplication Quiz
PyInputPlus'south features can be useful for creating a timed multiplication quiz. By setting the allowRegexes, blockRegexes, timeout, and limit keyword argument to pyip.inputStr(), you can get out most of the implementation to PyInputPlus. The less code you demand to write, the faster y'all can write your programs. Allow'southward create a program that poses 10 multiplication issues to the user, where the valid input is the problem's right reply. Open a new file editor tab and save the file equally multiplicationQuiz.py.
First, nosotros'll import pyinputplus, random, and time. Nosotros'll continue track of how many questions the programme asks and how many right answers the user gives with the variables numberOfQuestions and correctAnswers. A for loop will repeatedly pose a random multiplication problem 10 times:
import pyinputplus as pyip
import random, time
numberOfQuestions = ten
correctAnswers = 0
for questionNumber in range(numberOfQuestions):
Inside the for loop, the programme volition option 2 single-digit numbers to multiply. We'll utilize these numbers to create a #Q: Due north × N = prompt for the user, where Q is the question number (1 to 10) and N are the two numbers to multiply.
# Selection two random numbers:
num1 = random.randint(0, 9)
num2 = random.randint(0, 9)
prompt = '#%s: %s x %southward = ' % (questionNumber, num1, num2)
The pyip.inputStr() function will handle nearly of the features of this quiz program. The argument we pass for allowRegexes is a listing with the regex cord '^%s$', where %southward is replaced with the correct respond. The ^ and % characters ensure that the respond begins and ends with the right number, though PyInputPlus trims whatsoever whitespace from the get-go and terminate of the user's response first merely in case they inadvertently pressed the spacebar before or after their reply. The statement we pass for blocklistRegexes is a listing with ('.*', 'Incorrect!'). The start cord in the tuple is a regex that matches every possible cord. Therefore, if the user response doesn't match the right answer, the program will reject any other reply they provide. In that case, the 'Incorrect!' cord is displayed and the user is prompted to reply again. Additionally, passing viii for timeout and 3 for limit will ensure that the user only has 8 seconds and 3 tries to provide a right respond:
effort:
# Right answers are handled by allowRegexes.
# Wrong answers are handled by blockRegexes, with a custom message.
pyip.inputStr(prompt, allowRegexes=['^%southward$' % (num1 * num2)],
blockRegexes=[('.*', 'Incorrect!')],
timeout=8, limit=iii)
If the user answers afterwards the viii-second timeout has expired, fifty-fifty if they answer correctly, pyip.inputStr() raises a TimeoutException exception. If the user answers incorrectly more 3 times, it raises a RetryLimitException exception. Both of these exception types are in the PyInputPlus module, then pyip. needs to prepend them:
except pyip.TimeoutException:
print('Out of time!')
except pyip.RetryLimitException:
print('Out of tries!')
Remember that, just similar how else blocks can follow an if or elif block, they can optionally follow the last except block. The code inside the following else block will run if no exception was raised in the try block. In our case, that means the lawmaking runs if the user entered the correct answer:
else:
# This block runs if no exceptions were raised in the try cake.
print('Correct!')
correctAnswers += ane
No matter which of the three messages, "Out of fourth dimension!", "Out of tries!", or "Right!", displays, let's place a 1-2nd intermission at the end of the for loop to give the user time to read information technology. Subsequently the plan has asked 10 questions and the for loop continues, permit'southward show the user how many correct answers they fabricated:
fourth dimension.sleep(1) # Cursory suspension to let user run across the result.
print('Score: %s / %south' % (correctAnswers, numberOfQuestions))
PyInputPlus is flexible enough that you can utilize it in a wide variety of programs that take keyboard input from the user, as demonstrated by the programs in this chapter.
Summary
It'due south like shooting fish in a barrel to forget to write input validation code, but without information technology, your programs volition well-nigh certainly take bugs. The values you lot wait users to enter and the values they actually enter can be completely different, and your programs need to exist robust plenty to handle these exceptional cases. You lot can use regular expressions to create your own input validation lawmaking, but for common cases, it'southward easier to use an existing module, such as PyInputPlus. You tin import the module with import pyinputplus as pyip then that you can enter a shorter name when calling the module'south functions.
PyInputPlus has functions for entering a diversity of input, including strings, numbers, dates, yes/no, True/False, emails, and files. While input() always returns a string, these functions return the value in an appropriate information type. The inputChoice() function allow you to select 1 of several pre-selected options, while inputMenu() besides adds numbers or letters for quick choice.
All of these functions have the following standard features: stripping whitespace from the sides, setting timeout and retry limits with the timeout and limit keyword arguments, and passing lists of regular expression strings to allowRegexes or blockRegexes to include or exclude particular responses. Yous'll no longer need to write your own irksome while loops that bank check for valid input and reprompt the user.
If none of the PyInputPlus module's, functions fit your needs, but yous'd withal like the other features that PyInputPlus provides, y'all can call inputCustom() and pass your own custom validation function for PyInputPlus to use. The documentation at https://pyinputplus.readthedocs.io/en/latest/ has a consummate listing of PyInputPlus's functions and additional features. There's far more in the PyInputPlus online documentation than what was described in this chapter. There'southward no use in reinventing the wheel, and learning to employ this module will save yous from having to write and debug code for yourself.
Now that you have expertise manipulating and validating text, information technology's fourth dimension to learn how to read from and write to files on your estimator'south difficult bulldoze.
Practice Questions
ane. Does PyInputPlus come with the Python Standard Library?
two. Why is PyInputPlus commonly imported with import pyinputplus equally pyip?
3. What is the deviation betwixt inputInt() and inputFloat()?
4. How tin you lot ensure that the user enters a whole number between 0 and 99 using PyInputPlus?
v. What is passed to the allowRegexes and blockRegexes keyword arguments?
6. What does inputStr(limit=3) do if blank input is entered three times?
seven. What does inputStr(limit=3, default='how-do-you-do') do if blank input is entered 3 times?
Practice Projects
For practice, write programs to exercise the following tasks.
Sandwich Maker
Write a program that asks users for their sandwich preferences. The program should use PyInputPlus to ensure that they enter valid input, such as:
- Using inputMenu() for a breadstuff type: wheat, white, or sourdough.
- Using inputMenu() for a protein type: chicken, turkey, ham, or tofu.
- Using inputYesNo() to ask if they want cheese.
- If so, using inputMenu() to ask for a cheese type: cheddar, Swiss, or mozzarella.
- Using inputYesNo() to ask if they want mayo, mustard, lettuce, or love apple.
- Using inputInt() to ask how many sandwiches they want. Make sure this number is ane or more.
Come up with prices for each of these options, and accept your program display a total cost after the user enters their option.
Write Your Ain Multiplication Quiz
To see how much PyInputPlus is doing for yous, try re-creating the multiplication quiz project on your own without importing it. This program will prompt the user with 10 multiplication questions, ranging from 0 × 0 to 9 × nine. Y'all'll need to implement the following features:
- If the user enters the correct respond, the program displays "Correct!" for 1 second and moves on to the next question.
- The user gets three tries to enter the correct answer before the program moves on to the next question.
- 8 seconds after first displaying the question, the question is marked as incorrect even if the user enters the right answer after the 8-second limit.
Compare your lawmaking to the code using PyInputPlus in "Project: Multiplication Quiz" on page 196.
Source: https://automatetheboringstuff.com/2e/chapter8/
0 Response to "C Not a Valid Input Try Again"
Post a Comment