ValueError: I/O operation on closed file inside an if statement - python

I made a login/signup program where the user must type in credentials in order to make an account or enter.
But I have two problems though, one is inside the function 'sign_up()' if the user is attempting to make a pre-existing account it should print the 'This username is taken' statement, but that's not the case. It prints a Value Error called 'I/O operation on closed file' instead.
Then the second problem is, it doesn't print the credentials in a designated file called 'LOG-IN_DATA', it's basically where you store it.
Anyway here is the code:
from class1 import Credentials
def sign_up():
choose_username_data = input("Choose a UserName: ")
choose_password_data = input("Choose your password: ")
Credentials(choose_username_data, choose_password_data)
data = open('LOG-IN_DATA', 'a+')
if choose_username_data not in data:
data.write(str(Credentials))
data.write('\n')
welcome()
data.close()
if choose_username_data in data:
print("This username is taken!")
sign_up()
data.close()
def log_in():
username_data = input("Enter your username: ")
password_data = input("Enter your password: ")
data = open('LOG-IN_DATA', 'r')
data.read()
data.close()
if username_data and password_data in data:
welcome()
elif username_data and password_data not in data:
print("Username or Password does not match or not recognized.")
log_in()
def welcome():
print("Welcome! You made it in!")
def login_or_signup():
signup_var = ('Signup', 'SignUp', 'signup')
login_var = ('Login', 'LogIn', 'login')
prompt_user = input("Welcome! Would you like to Login or Signup?: ")
if prompt_user in login_var:
log_in()
elif prompt_user in signup_var:
sign_up()
else:
print("\nChoose 'Login' or 'Signup'")
login_or_signup()
login_or_signup()
Sorry if the code is too long. I just want problems and potential ones to be eliminated as far as I am concerned.
Anyways thank you in advance!

Try using with statements when manipulating files. It handles flush and close automatically even when errors occur.
For example:
with open("path", 'r') as f:
content = f.read()
instead of:
f = open("path", 'r')
content = f.read()
f.close()
The problem with this line if choose_username_data in data: is that before, you also used data. The cursor in the file is at the end of this file. So when you ask a second time without setting the cursor back to the start of the file, it read nothing. That's why the 2nd statement never evaluates true.
With everything I told you, the sign_up function can be written:
def sign_up():
loop = True
while loop:
choose_username_data = input("Choose a username: ")
choose_password_data = input("Choose your password: ")
creds = Credentials(choose_username_data, choose_password_data)
with open('LOG-IN_DATA', 'a+') as data:
content = data.read()
if choose_username_data not in content:
data.write(str(creds)+'\n')
welcome()
loop = False
# if choose_username_data in content:
else:
print("This username is taken!")

Related

Hashed identical strings aren't the same when hashed twice

I have a login program that hashes a string and stores it in a file to create a new account. When I need to log in, the login detail strings get hashed, and the program checks if the hashed strings have a match in the file. The program works without hashing, but when I hash the identical login details, the hash values are not the same. I have checked and the strings are exactly the same. Here is my code:
import tkinter
import math
import os
import hashlib
# The login function #
def login(username, password, file_path):
file_new = open(file_path, "a")
file_new.close()
file = open(file_path, "r")
file_content = file.read()
print(file_content)
file.close()
hashed_username = hashlib.md5(bytes(username, "utf-8"))
hashed_password = hashlib.md5(bytes(password, "utf-8"))
print(f"Hashed username: {hashed_username}, hashed password: {hashed_password}")
if f"{hashed_username},{hashed_password}" in file_content[:]:
return "You were logged in successfully"
else:
return "We could not find your account. Please check your spelling and try again."
# The account creation function #
def newaccount(username, password, file_path):
file_new = open(file_path, "a")
file_new.close()
# Reading the file #
file = open(file_path, "r")
file_content = file.read()
print(file_content)
file.close()
# Hashing the account details #
hashed_username = hashlib.md5(bytes(username, "utf-8"))
hashed_password = hashlib.md5(bytes(password, "utf-8"))
print(f"Hashed username: {hashed_username}, hashed password: {hashed_password}")
file_append = open(file_path, "a")
# Checking to see if the details exist in the file #
if f"{hashed_username},{hashed_password}" in file_content[:]:
file_append.close()
return "You already have an account, and were logged in successfully"
else:
# Writing the hashed details to the file #
file_append.write(f"{hashed_username},{hashed_password}\n")
file_append.close()
return "New account created."
logins_path = "Random Scripts\Login Program\logins.txt"
signin_message = input("Would you like to: \n1. Create an account \nor \n2. Log in\n")
if signin_message == "1":
print("User chose to create account")
newacc_username = input("Input a username: ")
newacc_password = input("Input a password: ")
print(newaccount(newacc_username, newacc_password, logins_path))
elif signin_message == "2":
print("User chose to log in")
username = input("Input your username: ")
password = input("Input your password: ")
print(login(username, password,logins_path))
else:
print("Please enter 1 or 2")
hashed_username = hashlib.md5(bytes(username, "utf-8"))
This function returns a hash object, and when you print it or write it to a file, you get something like this:
<md5 HASH object # 0x7f8274221990>
... which isn't terribly useful.
If you want the actual text of the hashes, call .hexdigest():
hashed_username = hashlib.md5(bytes(username, "utf-8")).hexdigest()
# returns e.g. "47bce5c74f589f4867dbd57e9ca9f808"

why closes my python program without fully executing?

I am completely new to programming and started a few days ago with learning Python(v.3.8.8). I wanted to make a small password manager, but with a little secret function(I think that's not important and it would take too much time to describe). Anyways I converted the main.py to a .exe with auto-py-to-exe but every time I wanna execute the .exe I can only enter my Login data and the window instantly closes but in Pycharm everything works totally fine. Does anyone know why?
EDIT: It works now, there was no missing "Input()" or stuff like that, I had a spelling mistake in my code and pycharm ignored it!
from cryptography.fernet import Fernet
welcome = input("Login(1), New User (2): ")
def new_user(): # creates a new user and safe the Username and pw in a .txt
print("The login is just for the safety of your data, everything is stored on your local PC!")
username = input("Enter a username:")
password = input("Enter a password:")
password1 = input("Confirm password:")
if password == password1:
key = Fernet.generate_key()
f = Fernet(key)
f.encypt(b'password')
file = open(username + ".txt", "w")
file.write(username + ":" + password)
#file.close()
login() # go to login after everything is safed in the .txt
else:
print("Passwords do NOT match!")
def login(): # checks if the entered username and pw match with the .txt content
login1 = input("Login:")
login2 = input("Password:")
file = open(login1 + ".txt", "r")
pw = file.readline()
#file.close()
if pw == login1 + ":" + login2: # infinte trys to enter the username and pw
print("Welcome " + login1)
pwrequest()
else: # returns to login() if the pw is incorrect
print("Incorrect username or password. Please try again")
login()
def pwrequest():
q = input("safe new Password(1), show safed passwords(2)")
if q == "2":
data() # show all saved pw
if q == "1":
newdata() # go to data() if the user want to add a new pw or
# want to acces the hidden part
def data():
file = open('1.txt', 'r') # prints all saved passwords
file_pw = file.read()
print(file_pw)
file.close()
c = input("Press (1) to delete something and press (2) to log out.")
if c == '1':
delete() # delete a pw or acces to hidden part
if c == '2':
login() # simple logout system, probably have to change this to something more intermediate
def newdata(): # safes the data in variables and put it in a .txt file
company = input("Enter the companys name: ")
username = input("Enter your username: ")
password = input("Enter your password: ")
print(company + username + password + ", is everything correct?")
a = input("y/n")
if a == "y":
file = open("1.txt", "w")
file.write(
"Company: " + company + "\n" + "Username: " + username + "\n" + "Password: " + password + "\n" + "\n")
file.close()
pwrequest() # return to pwrequest()
if a == "n":
newdata() # return to newdata() if something is incorrect
secretWord = "CompanyUsernamePassword" # define the secret word to finaly acces the hidden part
if company + username + password == secretWord:
secrettest() # go to secrettest() to enter the secret word
def delete(): # just simple code that delete specific content of the pw .txt
name = input("Please enter the Company, Username and password you wanna delete: ")
with open("1.txt", "r") as f:
lines = f.readlines()
with open("1.txt", "w") as f:
for line in lines:
if line.strip("\n") != name:
f.write(line)
def secrettest():
key = Fernet.generate_key()
f = Fernet(key)
truepass = f.encrypt(b"Test1234")
trys = 3
while trys != 0: # checks if you entered the correct pw and if not count 2 times
password = input("Pls enter the password: ")
d = f.decrypt(truepass)
if password == d.decode():
print(truepass)
break
else:
print("Wrong password!")
trys -= 1
if trys == 0:
print("You entered the wrong password to many times!")
if welcome == "1": # should probably try to move that to the top
login()
if welcome == "2": # this too
new_user()
I think I know why the .exe always closes. I executed the .exe in the windows cmd, and got this error "AttributeError: 'Fernet' object has no attribute 'enrcypt'". I'm kinda sure that this is the part that caused the trouble. I'm just wondering why pycharm just ignored this error...

Why does my Python program fail to read the second line of my data file?

I am learning python. I wanted to learn to work with text files, so I decided to make a simple console program.
The program does the following:
Asks if you had already a profile.
If no, then asks to create a username and a password. The information is saved in a text file.
If yes, then asks to input your password and username.
When the user doesn't have a profile, everything works well. When the user has a profile and wants to log in, it doesn't work and I don't know why.
The username is saved in the first line of the text file and the password in the second line, so, I use readlines()[0] and readlines()[1].
The username is recognized correctly, but the password doesn't. I get this error
Traceback (most recent call last):
File "Archivo de prueba.py", line 4, in <module>
print(text_file.readlines()[1])
IndexError: list index out of range
This is the code I wrote:
text_file = open("Archivo de prueba.txt", "r+")
def ask_for_account():
global has_account
has_account = input("Do you have an account? (Write \"Yes\" or \"No) ")
ask_for_account()
def create_profile():
create_user = str(input("Type your new username: "))
create_password = str(input("Type your new password: "))
text_file.write(create_user)
text_file.write("\n")
text_file.write(create_password)
def login():
username = text_file.readlines()[0]
password = text_file.readlines()[1]
current_user = input("Type your username: ")
current_password = input("Type your password: ")
if str(current_user) == str(username) and str(current_password) == str(password):
print("Succesfully logged in.")
else:
print("Invalid username or password")
if has_account == "No":
create_profile()
elif has_account == "Yes":
login()
else:
print("Invalid input")
ask_for_account()
text_file.close()
The following code works. I added a few comments to indicate changes.
def ask_for_account():
return input("Do you have an account? (Enter 'Yes' or 'No') ")
def create_profile():
create_user = str(input("Type your new username: "))
create_password = str(input("Type your new password: "))
# Open the file for writing and close it after use.
text_file = open("Archivo de prueba.txt", "w")
text_file.write("{}\n".format(create_user))
text_file.write("{}\n".format(create_password))
text_file.close()
def login():
# Open the file for reading and close it after use.
text_file = open("Archivo de prueba.txt", "r")
lines = text_file.readlines()
text_file.close()
# remove the newline at the end of the input lines.
username = lines[0].rstrip()
password = lines[1].rstrip()
current_user = input("Type your username: ")
current_password = input("Type your password: ")
if current_user == username and current_password == password:
print("Succesfully logged in.")
else:
print("Invalid username or password")
#
# Put program logic in one place after the methods are defined.
#
has_account = ask_for_account()
if has_account == "No":
create_profile()
elif has_account == "Yes":
login()
else:
print("Invalid input")
username = text_file.readlines()[0]
password = text_file.readlines()[1]
The first call to readlines() consumes the entire file and there are no lines remaining for the second call to read, so it returns an empty list.
Read the file once and save the lines in a list, then pick the desired lines from the list:
file_lines = text_file.readlines()
username = file_lines[0]
password = file_lines[1]
Also, be aware that readlines() puts a carriage return \n at the end of every line, so you might have to strip that off depending on how you use these values.

How can I make a basic program that allows someone to sign in to an account previously created?

I am trying to make a python program that will allow a user to sign up or sign in, and I am currently doing so by creating a file that stores every username and its password. Right now, it is not writing to the file, and I was wondering if anyone could tell me what I'm doing wrong. Please forgive me if it is a stupid error, I am not very experienced with python, but I can still make a basic program. This is my code:
# -*- coding: utf-8 -*-
from time import sleep
def signin():
usrlist = open("users.txt", 'w+')
complete = False
while (complete == False):
usr = raw_input("Username: ")
pwd = raw_input("Password: ")
usrinfo = (usr + ":" + pwd)
if (usrinfo in usrlist.read()):
print("Welcome back " + usr + ".")
complete = True
else:
print("Username or Password incorrect. Please try again.")
def signup():
usrlist = open("users.txt", 'w+')
usravailable = False
while (usravailable == False):
newusr = raw_input("Please choose a Username: ")
if (newusr in usrlist.read()):
print("Username taken. Please choose again.")
else:
usravailable = True
newpwd = raw_input("Please choose a password: ")
oldusrlist = usrlist.read()
usrlist.write(oldusrlist + newusr + ":" + newpwd + ".")
print("Thank You. Please Sign in.")
signin()
print("Please Choose An Option:")
print("1. Sign In")
print("2. Sign Up")
inorup = input()
if (inorup == 1):
signin()
elif (inorup == 2):
signup()
Also, if you have any suggestions about how I could do this differently, or better(even if it's using a different language) Thank you and I appreciate your help.
EDIT:
If anyone can give me information on doing a program like this either using JSON, javascript, or multiple files that can store larger amounts of data about each account, please tell me how in the comments or an answer. I appreciate the help.
To fix your not saving issue, you need to do two changes:
1) in your signin() routine, change the line 'usrlist = open("users.txt", 'w+')' into 'usrlist = open("users.txt", 'r')
2) in your singup() routine, after the line 'usrlist.write(oldusrlist + newusr + ":" + newpwd + ".")', add: 'usrlist.close()'
Then you should be able to see the stuff got saved.
here is a way to use json
import json
import os
FILENAME = "./f.json"
# init the data file
def init_data():
with open(FILENAME, "wb") as f:
json.dump({}, f)
def load_content():
with open(FILENAME) as f:
infos = json.load(f)
return infos
def save_content(content):
with open(FILENAME, "w+") as f:
json.dump(content, f)
return True
def save_info(username, password):
infos = load_content()
if username in infos:
return False
infos[username] = password
save_content(infos)
return True
def sign_in(username, password,):
status = save_info(username, password)
if not status:
print "username exists"
def login(username, password):
infos = load_content()
if username in infos:
if password == infos[username]:
print "login success"
return True
else:
print "password wrong"
return False
else:
print "no user named %s" %username
if __name__ == "__main__":
# here is some simple test
os.system("rm -f %s" %FILENAME)
if not os.path.exists(FILENAME):
init_data()
# login fail
login("hello","world")
# sign_in
sign_in("hello", "world")
# login success
login("hello","world")
# sign_in fail
sign_in("hello", "world")
# login fail
login("hello", "hello")

Invisible jump to the main menu from a function - can anyone spot the error?

I have the following code in which a bewildering jump back to line 48 in the login function from the quiz1() function occurs. The code seems fine and cannot find the source or cause for the error as there is no reason for it to go back!
The full code with file can be tested and found here:
https://repl.it/KdEI/2
Test data:
username: admin
password: admin123
Press 1 to play
Press 1 to go to Quiz
>>ERROR (Jumps back to the main menu, and specifically to line 48 in the login function
Comment
I'm assuming the error lies somewhere in the login code. To award an answer I would like:
The error spotted and explained
Comments on more elegant ways of solving the login (username and password read from file) <-- Currently the set up for "invalid username or password" doesn't quite work properly either.
Login Function code:
def login():
print("===Login===")
username=input("Enter username:")
password=input("Enter password:")
with open('userinfo.txt','r') as f:
reader=csv.reader(f)
username_correct=False
password_correct=False
while username_correct==False and password_correct==False:
for row in reader:
for field in row:
if field==username:
currentindex=row.index(field)
if row[currentindex+1]==password:
print("****You're in!*****")
username_correct=True
password_correct=True
print()
f.close()
mainmenu()
else:
break
print("Wrong username or password, sorry!")
welcomemenu()
Update:
This seems to work, by removing the call to main menu from the while loop. However, the code needs restructuring for elegance and the best way to output the "invalid combination or user details" if the user gets it wrong:
def login():
print("===Login===")
passwordC=False
usernameC=False
while passwordC==False and usernameC==False:
username=input("Enter username:")
password=input("Enter password:")
with open('userinfo.txt','r') as f:
reader=csv.reader(f)
for row in reader:
for field in row:
if field==username and row[1]==password:
passwordC=True
usernameC=True
if passwordC==True and usernameC==True:
print("**You're in**")
mainmenu()
else:
print("Try again - wrong username and password")
login()
Executing mainmenu within the loop is your error.
Try:
def login():
print("===Login===")
username=input("Enter username:")
password=input("Enter password:")
with open('userinfo.txt','r') as f:
reader=csv.reader(f)
username_correct=False
password_correct=False
for row in reader:
for field in row:
if field==username:
currentindex=row.index(field)
if row[currentindex+1]==password:
username_correct=True
password_correct=True
if password_correct == False or username_correct == False:
print("Wrong username or password, sorry!")
welcomemenu()
print("****You're in!*****")
mainmenu()
As the program is not complete, you need to exit
def quiz1():
print("===Quiz1===")
print("Question 1:")
exit()
I found what I think is the error.
for row in reader:
for field in row:
if field==username:
currentindex=row.index(field)
if row[currentindex+1]==password:
print("****You're in!*****")
username_correct=True
password_correct=True
print()
f.close()
mainmenu()
else:
break
After the user logs in you close the file. Then you call the mainmenu function. After you return from the main menu function you continue your for loop onto the next row of the file... but you closed that file already... Thus error.
Try this out see if it works (no need for csv reader)
def login():
print("===Login===")
username=input("Enter username:")
password=input("Enter password:")
with open('userinfo.txt','r') as f:
authenticated = False
line = f.readline().strip()
while authenticated ==False and line != "":
values = line.split(",")
if len(values) >= 2 and values[0] == username and values[1] == password:
authenticated=True
line = f.readline().strip()
if authenticated:
print("****You're in!*****")
mainmenu()
else:
print("Wrong username or password, sorry!")
welcomemenu()
There's no need of usernameC and passwordC:
def login():
print("===Login===")
while True:
username=input("Enter username:")
password=input("Enter password:")
with open('userinfo.txt','r') as f:
reader=csv.reader(f)
for row in reader:
for field in row:
if field==username and row[1]==password:
mainmenu()
break
print("Try again - wrong username and password")
This should fix things.
If you want to use pickle as I've described below, the function definition would look like the following (much simpler):
with open("userdata.pkl", "rb") as f:
userdata = pickle.load(f)
def login():
print("===Login===")
while True:
username=input("Enter username:")
password=input("Enter password:")
if username in userdata:
if userdata[username] == password: # Checks the password.
mainmenu()
break
print("Try again - wrong username and password")
Also, I would like to point out that storing passwords in a text file is a bad idea, even for learning purposes. If you don't want to use a database, use binary files instead to store the usernames and passwords. Use a routine like the following:
import pickle
data = {"user1": "password1", "user2": "password2"} # dictionary would be the data structure of the choice for this case.
with open("userdata.pkl", "wb") as f:
pickle.dump(data, f)
Later, you can retrieve the dictionary as follows:
with open("userdata.pkl", "rb") as f:
userdata = pickle.load(f)
Now, print(userdata) would give: {"user1": "password1", "user2": "password2"}
I don't know whether you've solved this or not, but the original problem is that list.index doesn't do what you think it does - it doesn't give the index of the current item, but searches for a matching item and gives that index. So, for example:
row = [1, 1, 1, 1, 1]
print(row[4], row.index(row[4]))
prints 1 0, not 1 4. Your userinfo file contains two fields containing 'admin', so you'll get two matches with the password.
The best way to get the index of the current field is to use enumerate.
for currentindex, field in enumerate(row):
Rewriting the login() function so it's a bit more readable, I think you intend to do something like the following:
def is_valid_user(username, password):
with open('userinfo.txt','r') as f:
for row in csv.reader(f):
if row[0] == username and row[1] == password:
return True
return False
def login():
print("===Login===")
username=input("Enter username:")
password=input("Enter password:")
if is_valid_user(username, password):
mainmenu()
else:
print("Wrong username or password, sorry!")
welcomemenu()
There's also a problem with the way that you call the next function from the current one. e.g., if you repeatedly enter the wrong password, you get the following chain of function calls:
main -> welcomemenu -> login -> welcomemenu -> login -> welcomemenu ->
login -> welcomemenu -> login -> welcomemenu -> login -> welcomemenu ->
login -> welcomemenu -> login -> welcomemenu -> login -> welcomemenu etc
Sooner or later, this pattern will cause you a problem. Instead, try to arrange the function calls to 'fan out', something like the following:
def welcomemenu():
while True:
print("""
=========*WELCOME MENU*===========
1. Register
2. Login
3. Quit
*You need to register and login for access to the game menu
""")
userselection=int(input("Enter Selection"))
if userselection==1:
register()
elif userselection==2:
if login():
mainmenu()
break
elif userselection==3:
break
def is_valid_user(username, password):
with open('userinfo.txt','r') as f:
for row in csv.reader(f):
if row[0] == username and row[1] == password:
return True
return False
def login():
print("===Login===")
username=input("Enter username:")
password=input("Enter password:")
valid = is_valid_user(username, password)
if not valid:
print("Wrong username or password, sorry!")
return valid
so the 'wrong password' sequence will now go:
main -> welcomemenu -> login (back) -> login (back) -> login (back) etc

Categories

Resources