I have started learning python about 2 weeks ago and am trying to create a password system that can store multiple usernames and passwords. I am trying to add a bit of code where it makes you wait a minute if you input a wrong password 3 times.
I keep on getting an error where if you get the password wrong 3 times and wait the 60 seconds, even if you do input the right password and username it prints "Your password is wrong. You have only 3 attempts left."
Can somebody help and point out flaws that I have in the code?
import time
username = ["Test","Test2"]
password = ["1Ac!","2Bd!"]
success = 0
Tries = 0
Valid = False
Pass = ""
def login():
global success
global Pass
global Tries
inuser = input(str("Enter your username: \n"))
inpass = input(str("Enter your password: \n"))
if inuser not in username:
print("username not found in directory")
login()
else:
posUser = username.index(inuser)
Pass = password[posUser]
while success != 1:
if Tries == 3:
print("You have had too many attempts. Wait 60 seconds before trying again")
for i in range(60, 0, -1):
time.sleep(1)
print(i)
if Tries == 3:
Tries = 0
inuser=str("0")
inuser=str("0")
login()
else:
break
if Pass == inpass:
success=1
else:
Tries += 1
AttemptsLeft = (3 - Tries)+ 1
print("Your password is wrong. You have only {} attempts left.".format(AttemptsLeft))
login()
login()
if success==1:
print("Welcome to ------")
If you get rid of the recursion, everything will get simpler.
import time
username = ["Test","Test2"]
password = ["1Ac!","2Bd!"]
success = 0
Tries = 0
Valid = False
Pass = ""
def login():
global success
global Pass
global Tries
while success != 1:
inuser = input(str("Enter your username: \n"))
inpass = input(str("Enter your password: \n"))
if inuser not in username:
print("username not found in directory")
else:
posUser = username.index(inuser)
Pass = password[posUser]
if Tries == 3:
print("You have had too many attempts. Wait 60 seconds before trying again")
for i in range(60, 0, -1):
time.sleep(1)
print(i)
Tries = 0
inuser=str("0")
inuser=str("0")
if Pass == inpass:
success=1
elif Pass != "":
Tries += 1
AttemptsLeft = (3 - Tries)+ 1
print("Your password is wrong. You have only {} attempts left.".format(AttemptsLeft))
login()
if success==1:
print("Welcome to ------")
You should also consider getting rid of the global variables. Instead, return values using return.
import time
username = ["Test","Test2"]
password = ["1Ac!","2Bd!"]
success = 0
Tries = 0
Valid = False
Pass = ""
def login():
success = 0
Pass = ""
Tries = 0
while success != 1:
inuser = input(str("Enter your username: \n"))
inpass = input(str("Enter your password: \n"))
if inuser not in username:
print("username not found in directory")
else:
posUser = username.index(inuser)
Pass = password[posUser]
if Tries == 3:
print("You have had too many attempts. Wait 60 seconds before trying again")
for i in range(10, 0, -1):
time.sleep(1)
print(i)
Tries = 0
inuser=str("0")
inuser=str("0")
if Pass == inpass:
return True
elif Pass != "":
Tries += 1
AttemptsLeft = (3 - Tries)+ 1
print("Your password is wrong. You have only {} attempts left.".format(AttemptsLeft))
if login():
print("Welcome to ------")
Your code needed some refining. I also made a timer for stopping. Also, you should use getpass library to not show the password.
import time
import getpass
username = ["Test","Test2"]
password = ["1Ac!","2Bd!"]
Tries = 1
def login():
global Tries
print("\n----------------- Login -----------------------\n")
inuser = input("Enter your username: ")
inpass = getpass.getpass("Enter your password: ")
if inuser not in username:
print(f"User {inuser} was not found.")
login()
else:
xindex=username.index(inuser)
passw=password[xindex]
if inpass==passw:
return True
else:
if Tries==3:
print("\nToo many attempts. Please wait for 60 seconds.")
for k in range(x,0,-1):
b=f"Time left: {k} Seconds"
print(b,end="\r")
time.sleep(1)
Tries=0
login()
else:
Tries+=1
print("\nWrong Password or Username.")
login()
x=login()
if x:
print("Welcome to ---------")
Others have provided the solution, I will try to provide the reasoning:
This is because of the recursion in line number 38 where you're calling the login function after setting Tries=0.
When the recursive call is made, the compiler puts the rest of the statements below it on hold (you can imagine all the below statements pushed to a stack to be executed later). The program counter now goes to the start of the function: Where you'll enter the right username and password, therefore it sets the success variable to 1. Now that your function has completed, the compiler had a set of pending statements before remember?
It goes and executes them. But in there, the value of the variable inpass is still the old, incorrect one and that is why it prints out Wrong password. You can understand this by printing out inpass just before the line
if Pass == inpass:
TlDr; Get rid of the recursion
Related
I'm practising my coding - pretty new to this - and i'm trying to create a login system, all is working well so far but i'm trying to use a while loop to maximise the number of user attempts at inputting the correct password. Even if the user inputs the correct password, the loop will carry on until the loop is completed and will continue to say carry on.
login = {
"alex": "dog123"
}
passkey = login.values()
correct_user = True
while correct_user:
user = input("Please input your username ")
if user in login:
print(f'Hello {user}, please input your password.')
correct_user = False
else:
print("Invalid user")
attempt = 0
max_attempts = 3
correct_password = True
while correct_password:
password = input(">")
if password in passkey:
print(f"""Welcome back {user}!
How can i help you today?""")
correct_password = False
else:
while attempt < max_attempts:
print("try again")
attempt += 1
password = input(">")
if password in passkey:
correct_password = False
else:
print("too many guesses!")
break
Try this.
login = {
"alex": "dog123"
}
passkey = login.values()
correct_user = True
while correct_user:
user = input("Please input your username ")
if user in login:
print(f'Hello {user}, please input your password.')
correct_user = False
else:
print("Invalid user")
attempt = 0
max_attempts = 3
correct_password = True
while correct_password:
if attempt < max_attempts: # checks if an attempt is left.
password = input(">")
if password == login[user]: # Check password equal current userpassword.
print(f"""Welcome back {user}!
How can I help you today?""")
correct_password = False
else:
print("Invalid password")
attempt += 1
else: # print too many attempts
print("Too many attempts")
correct_password = False
Don't use password in passkey to check that if password is correct or not. Why?
Explanation
Let say you have more than one users
login = {
"alex": "dog123",
"alice": "cat123"
}
If you use in and check that if password is in passwords list then you face a bug
When
Example
If user is equal alex and password is cat123 then you code don't print that password is incorrect.
So use == and check if password == login[user] here user and password are the one that user enters.
"#alex comments. what does the '[user]' aspect mean?".
#alex if you want all values from the dictionary then you use dict.values(), But if you want a specific key's value then you use dict['Key'] or dict.get('Key'). Let's say user='alex' then login[user] gives the value of the user from the login dict which is 'dog123'. Note if the user is not in the dict then it will give you a KeyError. But if you use dict.get(user) it will return the value of user or None if user is not in dict
Your error comes from breaking out of the inner while loop but still having the outer one running; it's better to use only one loop (and you don't need the 'correct_password' flag any more):
attempt = 0
max_attempts = 3
passkey = ['sesame']
while attempt < max_attempts:
password = input(">")
if password in passkey:
print(f"""Welcome back {user}! How can i help you today?""")
break
else:
attempt += 1
if attempt < max_attempts:
print("try again")
else:
print("too many guesses!")
As a side note, codester_09 is right about the way you check the password, so implement their modification too.
Here is my code:
import pickle
current_user = None
class User:
def __init__(self, username, password):
self.username = username
self.password = password
def set_password(self):
self.password = input("Enter NEW password > ")
def __get_password(self):
return self.password
def __get_username(self):
return self.username
def change_password(self):
my_password = input("Enter your CURRENT password > ")
if my_password == self.__get_password():
self.set_password()
else:
print("Please try again")
def display_details(self):
print()
print("Username and password")
print("---------------------")
print("username is: ", User.__get_username(self))
print("password is: ", User.__get_password(self))
print()
def __repr__(self):
return f'username: {self.username}'
try:
users = pickle.load(open("users.pickle", "rb"))
except (OSError, IOError) as f:
users = [User("MichaelPalin", "P4rr0t"), User("EricIdle", "M0nty"), User("TerryJones", "Pyth0n")]
pickle.dump(foo, open("users.pickle", "wb"))
def find_user(name):
for user in users:
if user.username == name:
return user
def add_user():
user = input("Enter NEW user > ")
password = input(f"Enter password for {user} > ")
users.append(User(user, password))
def delete_user():
delete_user = input("Enter the user you wish to remove > ")
user = find_user(delete_user)
if user:
users.remove(user)
print('done')
else:
print(f'user {delete_user} not found')
def display_users():
for user in users:
print(user)
def invalid_entry(): # Response for invalid entries to menu.
print("Invalid entry, please try again")
print()
def menu(): # Display menu, prompt for and accept keyboard choice
print("Please select one of the following:")
print()
print("Enter a if you want to add a new user")
print("Enter d if you want to delete a user")
print("Enter f if you want to find a user")
print("Enter c if you want to change your password")
print("Enter u if you want to display a list of users")
print("Enter q if you want to Quit")
choice = input("")
return choice
while True:
menu_choice = menu()
if menu_choice.lower() == "a":
add_user()
elif menu_choice.lower() == "d":
delete_user()
elif menu_choice.lower() == "f":
current_user = find_user()
elif menu_choice.lower() == "c":
if current_user is None:
print("No user selected!")
continue
else:
current_user.change_password()
elif menu_choice.lower() == 'u':
display_users()
elif menu_choice.lower() == "q":
print("Goodbye")
with open('users.pickle', 'wb') as f:
pickle.dump(users, f)
quit()
else:
invalid_entry()
There's clearly something wrong as it's getting stuck in a loop:
Enter your CURRENT password > password
Enter your CURRENT password > password
Enter your CURRENT password >
I can see PyCharm is coming up 'local variable my_password is not used' too.
I tried removing my_password = input("Enter your CURRENT password > ") from the def change_password() block, but that just results in a fatal error.
I also tried renaming the first change_password function to update_password and updating the second one accordingly, so that it went...
def change_password():
update_password()
...but that didn't work either.
This is the logic that I want to use:
IF the user selects 'c' in the menu THEN do the following...
Prompt the user to enter their current password
IF the entered input matches their current password THEN prompt them to enter a new password and update their password accordingly
IF the entered input does not match their current password THEN prompt them to try again
Any help please? TIA
By the way, I'm puzzled that PyCharm is coming up 'unresolved reference 'foo''. That section seems to work OK, but any insights on why that is and if it's a problem or not would be appreciated.
Edit: I've updated the code in line with the suggestions, as much as I can, anyway.
Edit 2: PyCharm said that self in if my_password == self.__get_password(self) is an unexpected argument, so I removed it, and that didn't seem to do any harm.
You're not stuck in a loop, you stuck in recursion
def change_password():
my_password = input("Enter your CURRENT password > ")
change_password()
notice that you just keep calling change password over and over... also you have double methods for some reason, use the ones in you User class.
when 'c' is chosen you have no context, you don't know WHO is trying to change their password, so first you must ask who the user is, try the following changes:
before your while true loop put current_user = None
change the entry for 'f' to be current_user = find_user()
and the entry for 'c' to be
if current_user is None:
print("No user selected!")
continue
else:
current_user.change_password()
The other change_password function in the outer scope also requests command line input. try to eliminate all the unneeded
input("Enter your CURRENT password > ")
except for one and use parameters in your function calls instead.
On top of that, the outer scope change_password() function is calling itself over and over, because its shadowing the inner one. Try renaming one of the two.
When I log in as an "existing user", it works perfectly when I log in first try
But in the while loop, when I get the login incorrect and it prompts me again and THEN I get the login correct, it comes up as login failed
import sys
existing = " "
possibleAnswersExisting = ["y","n"]
accountFileW = open("AccountFile.txt","a")
accountFileR = open("AccountFile.txt","r")
while existing not in possibleAnswersExisting:
existing = input("Are you an already existing user? (Please input y/n)\n>>")
if existing not in possibleAnswersExisting:
print('Please enter a valid answer. (Only "y" or "n")')
def register():
username = input("What would you like your username to be?")
password = input("What would you like your password to be?")
print("Welcome" ,username + "! Make sure to remember your password or write it down in case your forget!")
accountFileW.writelines([username, " ", password, "\n"])
def login():
x = ""
attempts = 0
while x != True:
lusername = input("What is your username? (CaSe SeNsItIvE PleAsE)\n>>")
lpassword = input("What is your password? (CaSe SeNsItIvE PleAsE)\n>>")
for line in accountFileR:
print("in for loop")
loginInfo = line.split()
print(loginInfo)
if lusername == loginInfo[0] and lpassword == loginInfo[1]:
print("--Successful login, setting x to true")
x = True
break
attempts = attempts + 1
if str((4 - attempts)) == 0:
print("Error, login credentials invalid. Exiting program...")
sys.exit()
if attempts > 0 and attempts < 5:
print("Incorrect" ,str((4 - attempts)), "attemptsleft.")
print("Successful login")
if existing == "n":
register()
elif existing == "y":
login()
else:
print("Error with existing")
sys.exit()
accountFileW.close()
accountFileR.close()
I expect the output for the login to be successful, but it says incorrect unlike when I get it right the first try
After Python has read a file, its "Prompt" is at the end of the file. If you do call read on the fileobject again it will return nothin since there is nothing left to read.
With seek(x) you can place the "Prompt" to the postion x. In you case 0 since you want to read the file again.
I injected the line on the right place:
import sys
existing = " "
possibleAnswersExisting = ["y","n"]
accountFileW = open("AccountFile.txt","a")
accountFileR = open("AccountFile.txt","r")
while existing not in possibleAnswersExisting:
existing = input("Are you an already existing user? (Please input y/n)\n>>")
if existing not in possibleAnswersExisting:
print('Please enter a valid answer. (Only "y" or "n")')
def register():
username = input("What would you like your username to be?")
password = input("What would you like your password to be?")
print("Welcome" ,username + "! Make sure to remember your password or write it down in case your forget!")
accountFileW.writelines([username, " ", password, "\n"])
def login():
x = ""
attempts = 0
while x != True:
lusername = input("What is your username? (CaSe SeNsItIvE PleAsE)\n>>")
lpassword = input("What is your password? (CaSe SeNsItIvE PleAsE)\n>>")
accountFileR.seek(0) # <---- injected line
for line in accountFileR:
print("in for loop")
loginInfo = line.split()
print(loginInfo)
if lusername == loginInfo[0] and lpassword == loginInfo[1]:
print("--Successful login, setting x to true")
x = True
break
attempts = attempts + 1
if str((4 - attempts)) == 0:
print("Error, login credentials invalid. Exiting program...")
sys.exit()
if attempts > 0 and attempts < 5:
print("Incorrect" ,str((4 - attempts)), "attemptsleft.")
print("Successful login")
if existing == "n":
register()
elif existing == "y":
login()
else:
print("Error with existing")
sys.exit()
accountFileW.close()
accountFileR.close()
I have come across a problem with returning two variables from a function, although I have set the variables to be global. The program I am making is designed to imitate the process of adding a user and login in to that user or changing said user's password.
check = False
global uname
global pword
uname = 0
pword = 0
while check == False:
def user(uname, pword):
set_uname = input("Enter username: ")
set_pword = input("Enter password: ")
print("Username and Password set")
return(set_uname, set_pword)
def login(uname, pword):
correct = False
while correct == False:
enter_uname = input("Enter username: ")
enter_pword = input("Enter password: ")
if enter_uname == uname and enter_pword == pword:
print("Login successful")
elif enter_uname != uname or enter_pword != pword:
print("Incorrect username or password")
correct = False
def cpword(pword):
done = False
while done == False:
check_pword = input("Enter current password: ")
if check_pword == pword:
new_pword = input("Enter new password: ")
if new_pword == pword:
print("New password cannot be old password")
done = False
elif new_pword != pword:
print("Password successfully changed")
pword = new_pword
done = True
return(pword)
elif check_pword != pword:
print("Incorrect password")
done = False
print("Enter User")
user(uname, pword)
uname = set_uname
pword = set_pword
print("Login = 1")
print("Change Password = 2")
choice = int(input("Enter function: "))
if choice == 1:
login(uname, pword)
elif choice == 2:
cpword(pword)
pword = pword
I keep receiving the error:
Traceback (most recent call last):
File "C:\Users\tay.swain\Documents\Login.py", line 54, in
uname = set_uname
NameError: name 'set_uname' is not defined
Once i set the user, when I run the login function this error appears. I am trying to return
return(set_uname, set_pword)
from the user function. I understand how to return variable from a function as I have done it before, however I cannot get it to work in this code.
You are trying to return two variables from the function, say:
def foo():
a = 1
b = 2
return a,b
Obviously, if I try to access a or b from outside the function I will receive the same error that you are seeing, i.e. a NameError.
In order to return the values to use outside of the function we can do:
c = foo()
print (c)
# (1,2) which is a tuple
In order to get whatever you return into two variables, simply use two variables when calling the function:
a,b = foo()
print (a,b)
# 1 1
If you do the following, in the output, there would be the "func called" and the "0 1".
def func():
a = 0
b = 1
print("func called")
return a, b
c = func()[0] # a
d = func()[1] # b
print(c, d) # 0, 1
So the function is called when you define the global variables.
Can someone try to help me make with this, please. So once the user guesses 3 times the entire program closes, but once the user gets it wrong it doesn't make them exit the program. Yes I'm aware that I'm asking the same question again but I haven't got my question answered yet so please can someone help.
Here's another one I'm trying out. Any Suggestions on how to do exit the program if the user gets a certain number of attempts by trying to guess the password wrong. I've been trying to use sys.exit and exit()but it hasn't been working for me, so maybe you can try to that , (but remember my teacher wants it so that it on IDLE).
Counter=1
Password=("Test")
Password=input("Enter Password: ")
if Password == "Test":
print("Successful Login")
while Password != "Test":
Password=input("Enter Password: ")
Counter=Counter+1
if Counter == 3:
print("Locked Out: ")
break
counter = 1
password = input("Enter password: ")
while True:
if counter == 3:
print("Locked out")
exit()
elif password == "Test":
print("That is the correct password!")
break
else:
password = input("Wrong password, try again: ")
counter += 1
Move your counter check into the while loop.
Also use getpass for getting password input in python :)
import sys
import getpass
counter = 1
password = getpass.getpass("Enter Password: ")
while password != "Test":
counter = counter + 1
password = getpass.getpass("Incorrect, try again: ")
if counter == 3:
print("Locked Out")
sys.exit(1)
print("Logged on!")
You need to move the condition counter==3 inside the while loop
This can also be done in this way
import sys
password = input("Enter password : ")
for __ in range(2): # loop thrice
if (password=="Test"):
break #user has enterd correct password so break
password = input("Incorrect, try again : ")
else:
print ("Locked out")
sys.exit(1)
#You can put your normal code that is supposed to be
# executed after the correct password is entered
print ("Correct password is entered :)")
#Do whatever you want here
An even better way is to wrap this password-checking thing into a function.
import sys
def checkPassword():
password = input("Enter password : ")
for __ in range(2):
if (password=="Test"):
return True
password = input("Incorrect, try again : ")
else:
print ("Locked out")
return False
if (checkPassword()):
#continue doing you main thing
print ("Correct password entered successfully")