how can I validate a list index as an integer? - python

I have the code which populates the list "oneStudent" with 5 values, I need to validate indexes 1-4 (so the last 4 values) as an integer. I have tried using try...except, however, no matter how I try to implement it, it breaks the code
I'm relatively new to coding and python, it's probably something small I'm missing, any help will be much appreciated
The idea behind the code is to populate the list oneStudent as many times as NumberOfStduent is input above, after each time the oneStudent list will be appended to allStudent and reset for the next one
in the end, allStudent will be a list containing lists with each oneStudent
while True:
NumberOfStudent = input ("Please input the number of students: ")
try:
NumberOfStudent=int(NumberOfStudent)
if NumberOfStudent in range (1, 6):
break
else:
print("Error, Please input between 1 and 5")
except:
print("Error, Please input a valid number")
print("Number of students:", NumberOfStudent)
allStudents=[]
oneStudent=[]
s=0
while s < NumberOfStudent:
oneStudent.append(input ("Please input student name: ", ))
oneStudent.append(input ("Please mark for the Web module: ", ))
try:
oneStudent[1]=int(oneStudent[1])
if oneStudent[1] > 0 and oneStudent[1] < 101:
pass
else:
print("error1")
except:
print("Error2")
oneStudent.append(input ("Please mark for the Programming module: ", ))
try:
oneStudent[2]=int(oneStudent[1])
if oneStudent[2] > 0 and oneStudent[2] < 101:
pass
else:
print("error1")
except:
print("Error2")
oneStudent.append(input ("Please mark for the Graphics module: ", ))
try:
oneStudent[3]=int(oneStudent[1])
if oneStudent[3] > 0 and oneStudent[3] < 101:
pass
else:
print("error1")
except:
print("Error2")
oneStudent.append(input("Please mark for the Networking module: ", ))
try:
oneStudent[4]=int(oneStudent[1])
if oneStudent[4] > 0 and oneStudent[4] < 101:
pass
else:
print("error1")
except:
print("Error2")
s = s+1
allStudents.append(oneStudent)
oneStudent=[]
if s == NumberOfStudent:
break
print(allStudents)

This should work:
oneStudent=[]
NumberOfStudent = 2
s=0
def validate_number(text):
while True:
try:
question = int(input(text))
if 1 <= question <= 100:
return question
except:
print("That's not a valid option!")
while s < NumberOfStudent:
oneStudent.append(input ("Please input student name: ", ))
web_module = validate_number("Please mark for the Web module: ")
oneStudent.append(web_module)
prog_module = validate_number("Please mark for the Programming module: ")
oneStudent.append(prog_module)
graph_module = validate_number("Please mark for the Graphics module: ")
oneStudent.append(graph_module)
net_module = validate_number("Please mark for the Networking module: ")
oneStudent.append(net_module)
s += 1
print(oneStudent)

allStudents = []
NumberOfStudent = 2
while len(allStudents) < NumberOfStudent:
oneStudent = []
try:
oneStudent.append(input("Please input student name: ",))
oneStudent.append(int(input("Please mark for the Web module: ",)))
oneStudent.append(int(input("Please mark for the Programming module: ",)))
oneStudent.append(int(input("Please mark for the Graphics module: ",)))
oneStudent.append(int(input("Please mark for the Networking module: ",)))
allStudents.append(oneStudent)
except:
print('Enter valid input')
print(allStudents)

Related

Python - list index out or range (unicode)

I am writing a program to encrypt / decrypt an inputted message using a key generated from a pool
The pool is created by appending unicode characters to an array
When selecting option 2 (encrypt) and reading the genkey.txt file (after generating the key with option 1), the program shows an index error as shown:
Exception has occurred: IndexError
list index out of range, line 58, in b = keyarray[a]
However, when removing the unicode script and replacing the pool with plain text (e.g [a, b, c...]) the message is encrypted without any issue.
Any way to fix this?
Code:
import random
programrun = 0
encryptedarray = []
decryptedarray = []
keyarray = []
while programrun < 1:
pool = []
for i in range(32,123): #Unicode characters
pool.append(chr(i))
print("Encryption / Decryption")
print("")
print("1. Generate Key")
print("2. Encrypt")
print("3. Decrypt")
print("4. Quit")
print("NOTE: Key must be generated before selecting Encryption / Decryption")
print("")
option = int(input("Enter the number corresponding to the option: "))
if option == 1:
a = 20
while a > 0:
b = random.randint(0,57)
c = pool[b]
keyarray.append(c)
a = a - 1
keygen = ("".join(keyarray))
print("Your generated key is:", keygen)
print("")
print("(Make sure you have generated a key before typing 'yes')")
writebool = input("Do you want to save the file to your computer? ")
if writebool == "yes":
keyfile = open("genkey.txt", "x")
keyfile.write(keygen)
keyfile.close()
wbval = 1
print("File saved to genkey.txt successfully")
print("")
quitval = 1
elif writebool == "no":
print("ok")
else:
print("Type yes or no")
elif option == 2:
encryptvalid = 0
while encryptvalid < 1:
msg = str(input("Enter the message to be encrypted: "))
genkeyf = open("genkey.txt", "r")
genkeydata = genkeyf.read()
if genkeydata == keygen:
print("File VALID")
encryptvalid = 1
for i in msg:
a = pool.index(i)
b = keyarray[a]
encryptedarray.append(b)
p = ("".join(encryptedarray))
print("")
print("Your encrypted string is: ")
print("".join(encryptedarray))
else:
print("File INVALID")
print("Please check if the genkey.txt file matches the current generated key.")
a = pool.index(i) looks up the index of a character of the message in the pool, then that index is used to lookup a value in the keyarray with b = keyarray[a].
pool is 91 bytes long, but keyarray is 20 bytes long, so many of the indexes are too high. You probably want b = keyarray[a % len(keyarray)]. This uses the modulus operator to constrain the lookup from 0-19.

How can I unit test a function that is called by another function

I am trying to unit test my program and have decided to unit test the withdraw_cash function. However, it is called by the bank_atm function. I have never called a function that is dependent on another function and am confused about how to do this. Would i use mock and patch to do this?
The tests would be:
check whether entering valid amount
check whether amount is less than balance
user = {
'pin': 1234,
'balance': 100
}
def withdraw_cash():
while True:
try:
amount = int(input("Enter the amount of money you want to withdraw: "))
except ValueError as v:
print(f"Enter correct amount: ")
else:
if amount > user['balance']:
raise ValueError("You don't have sufficient balance to make this withdrawal")
else:
user['balance'] = user['balance'] - amount
print(f"£{user['balance']}")
return
finally:
print("Program executed")
def bank_atm():
count = 0
to_exit = False
while (count < 3) and (not to_exit):
try:
pin = int(input('Please enter your four digit pin: '))
except ValueError:
print("Please enter correct pin")
count += 1
if pin != user['pin']:
print("Pin does not match.. Try Again")
count += 1
else:
withdraw_cash()
to_exit = True
if count == 3:
print('3 UNSUCCESFUL PIN ATTEMPTS, EXITING')
print('!!!!!YOUR CARD HAS BEEN LOCKED!!!!!')
try:
bank_atm()
except ValueError as v:
print(f"ERROR: {v}")
To expand on the comments. Put UI interactions in separate functions, such as getpin and getpounds. They can then be tested separately from the business functions. One can either mix manual input with the unittests or automate them by patching sys.stdin/out. My proof-of-concept experiment, which passes on 3.11.0b3 run from IDLE editor.
import sys
import unittest
from unittest.mock import patch
def getpin(realpin):
return input('Your pin? ') == realpin
class ManualTest(unittest.TestCase):
def test_pin(self):
print('\n(Enter 1234)')
self.assertEqual(getpin('1234'), True)
print('\n(Enter 1)')
self.assertEqual(getpin('1234'), False)
class MockOut:
def write(self, string): pass
# Or 'write = Mock()' to save and check prompts, using mockout.
class MockIn:
def readline(self): # input() uses readline, not read.
return self.line
#patch('sys.stdin', new_callable=MockIn)
#patch('sys.stdout', new_callable=MockOut)
class AutoTest(unittest.TestCase):
def test_pin(self, mockout, mockin):
mockin.line='1234\n' # input removes '\n' if present.
self.assertEqual(getpin('1234'), True)
mockin.line='1233'
self.assertEqual(getpin('1234'), False)
if __name__ == '__main__':
unittest.main(verbosity=2)
I have now refactored my program, by breaking it down into separate functions as you said but when I try and run a test specifically for one function, it runs the whole thing and asks for input from each function. I feel like testing each function individually will have to require specific parameters not dependent on the other function.
user = {
'pin': 1234
}
def withdraw_cash(amount):
balance_account = 100
if amount > balance_account:
raise ValueError("You don't have sufficient balance to make this withdrawal")
else:
new_balance = balance_account - amount
return new_balance
def get_pin():
count = 0
to_exit = False
while (count < 3) and (not to_exit):
try:
pin = int(input('Please enter your four digit pin: '))
except ValueError:
print("Please enter correct pin")
count += 1
if pin != user['pin']:
print("Pin does not match.. Try Again")
count += 1
else:
return get_amount(pin)
#return pin
if count == 3:
a = '3 UNSUCCESFUL PIN ATTEMPTS, EXITING \n !!!!!YOUR CARD HAS BEEN LOCKED!!!!!'
return a
def get_amount(pin):
while True:
try:
amount = int(input("Enter the amount of money you want to withdraw: "))
except ValueError as v:
print(f"Enter correct amount: ")
else:
#print(amount)
return withdraw_cash(amount)
#return amount
try:
get_pin()
except ValueError as v:
print(f"ERROR: {v}")

How to print output to text file from multiple functions (python)

I want to save the below code output to file.txt. The problem is that my code includes many functions.
In other words, I want my output in a text file, I'm using python but I posted as js, #python
import random
Generate_Number_CHOICE = 1
Average_Calculate_CHOICE = 2
Display_Grades_CHOICE = 3
Display_Failing_Marks_CHOICE = 4
QUIT_CHOICE = 5
def display_menu():
print(' MENU')
print('1) Enter Your Marks')
print('2) Get Your Average')
print('3) Display Your Grades')
print('4) Display Failin Marks')
print('5) Quit')
def generate_number():
numbers = random.sample(range(1 ,100),30)
print(numbers)
return numbers
def average_calculate(numbers):
total = sum(numbers)
average = total // 30
print('------------------------------------')
print('Your Average is:', average)
print(" ")
def display_grades(numbers):
for mark in(numbers):
if mark >= 90:
print('------------------------------------')
print('A+',mark)
elif mark >= 80:
print('------------------------------------')
print('B+',mark )
elif mark >= 70:
print('------------------------------------')
print('C+',mark)
elif mark >= 60:
print('------------------------------------')
print('D+',mark)
else:
print('------------------------------------')
print('F',mark)
return mark
return courses_Name
def display_failing(numbers):
for number in (numbers):
if number <= 59:
print('------------------------------------')
print("you Fail in",number)
print(" ")
def main():
infile = open('philosophers.txt', 'w')
choice = 0
while choice != QUIT_CHOICE:
display_menu()
choice = int(input('Enter your choice: '))
if choice == Generate_Number_CHOICE:
numbers = generate_number()
elif choice == Average_Calculate_CHOICE:
average_calculate(numbers)
elif choice == Display_Grades_CHOICE:
mark = display_grades(numbers)
elif choice == Display_Failing_Marks_CHOICE:
display_failing(numbers)
elif choice == QUIT_CHOICE:
print('Exiting the program...')
else:
print('Error: invalid selection.')
main()
You can just replace you print statements with infile.write('text goes here'), also don't forget to close your file after you're done with it using infile.close(). Alternately you can use a with statement.
with open('philosophers.txt', 'w') as infile:
infile.write('text')
and this will close the file without explicitly calling .close.
You can also print to a file
print('text', file=infile) #python 3
print >> infile, 'text' #python 2
You can open a file (as global variable) in the beginning of your main function and in all other functions use that file handle to write whatever you want in the file.But an even better solution is to pass that file handle to each function and use the handle to write to file. Either way, don't forget to close the file at the end of the main function.

Breaking a loop with input

I'm trying to make a an input timer on a question that gives the user 5 seconds to answer the question before deciding that no input is the same as the wrong answer, but no body wants to touch it with a 10ft pole, so I'm trying to go about it a different way and break a for loop with input?
Any one got suggestions?
import random
import operator
qLimit = 10
oqLimit = 10
score = 0
maxNum = 10
timeLimit = 0
otimeLimit = 5
import time
ops = {
'+':operator.add,
'-':operator.sub
}
def generateQuestion():
x = random.randint(1,maxNum)
y = random.randint(1,maxNum)
op = random.choice(list(ops.keys()))
a = ops.get(op)(x,y)
print("What is {} {} {}?\n".format(x, op, y))
return a
def askQuestion(a):
timeLimit = otimeLimit
for i in range(0,timeLimit):
guess = input("")
print (timeLimit - i)
time.sleep(1)
if timeLimit == 0:
try:
integer_input = int(guess)
except ValueError:
print('Please enter a valid number')
return
global score
if integer_input == a:
print("Correct!")
score += 1
else:
print("Wrong, the answer is",a)
while qLimit != 0:
askQuestion(generateQuestion())
qLimit -= 1
print ("You have", qLimit, "questions remaining")
print("Your score is",score)
if (qLimit == 0):
break
Adapting the example from the Python docs:
import signal
class OutOfTime(Exception):
"too slow"
def handler(signum, frame):
raise OutOfTime("no input received")
try:
# Set the signal handler and a 5-second alarm
signal.signal(signal.SIGALRM, handler)
signal.alarm(5)
ans = input('What is your favorite color? ')
signal.alarm(0)
except OutOfTime:
print('\nout of time! too slow!')
else:
print('%s, huh? Mine, too!' % ans)

Python: Can I combine these functions together to shorten my python code?

Can I combine these functions together to shorten my python code? I'm creating a quick program!
Here are the functions:
def try1():
try:
num1=input("Enter num 1: ")
return num1
except ValueError:
print("incorrect!")
return #value
def try2():
try:
num2=input("Enter num 2: ")
return num2
except ValueError:
print ("incorrect!")
return #value
def try3():
try:
num3=input("Enter num 3: ")
return num3
except ValueError:
print ("incorrect!")
return #value
def try4():
try:
num4=input("Enter num 4: ")
return num4
except ValueError:
print ("incorrect!")
return #value
Please post your suggestions and answers below.
As you can see from my reputations, I am a new programmer hoping to find kind people on Stackoverflow.
(This answer is based on the original revision of the question which is no longer accessible but showed a different problem, where the user is keep being asked until a valid number is entered. And the code showed some skill game system or something, so that’s why my questions are longer and more specific too.)
Something like this?
def getInt(name, target):
while True:
try:
return int(input('Please enter {0} for {1}: '.format(name, target)))
except ValueError:
print('Incorrect!')
strength0 = getInt('strength', 'character 1')
skill0 = getInt('skill', 'character 1')
strength1 = getInt('strength', 'character 2')
skill1 = getInt('skill', 'character 2')
In general, when you have multiple functions that approximately do the same thing, then yes, there is a lot potential to refactor it so you don’t repeat yourself. In this case, what was different is the question the user was being asked, so if we parameterize that, we are good to use just a single function to handle it all.
The function can be generalised to ask for the input of any number, for example:
def try_num(n):
num = int(input("Enter num {} : ".format(n)))
while num != n:
print ("incorrect!")
num = int(input("Enter num {} : ".format(n)))
return num
Use it like this:
try_num(10)
Enter num 10 : 9
incorrect!
Enter num 10 : 10
10
def safe_int(x):
try:
return int(x)
except ValueError:
return 0
[safe_int(raw_input("Number %d:"%i)) for i in range(4)]
I would create a validation method and simply pass in the strings.
def validate(question):
while True:
try:
print question,
input = raw_input()
if input.isdigit():
return int(input)
else:
print "Not a valid integer"

Categories