0

I want to create a simple log-in account program in Python using the "CSV" library. Here is the code:

import csv

account_password = ""

with open("accounts.csv") as csvfile:
    reader = csv.reader(csvfile)    

    while True:
        username = input("\nEnter username: ")
        # Checks if username exists
        for row in reader:
            if row[0] == username:
                account_password = row[1] # Get user's password
                break

        password = input("Enter password: ")

        # Check if password is valid
        if password == account_password:
            break
        else:
            print("Username/password is incorrect. Try again.")


print("\nSuccessfully logged in!")

Here is how my CSV file looks like. The first column is the usernames and the second one is the passwords:

Tim,myPassword
John,monkey32
Fred,WooHoo!    

When I tried to test my program in IDLE, I noticed an unusual log-in issue.

If I log in with the correct credentials, then the program works perfectly fine:

Image of code working under correct log in details.

If I log in with incorrect log in details, the program works as expected:

Image of code working under incorrect login details.


But here is the issue. After entering incorrect log in details, the program asks the user to try again. This is done with a "while loop" in my code. Yet when I "try again", but with the correct details, the program thinks the log-in details are incorrect:

Image of code not working.

Here is the same issue with another user from the csv file:

Image of code not working again.

I would love it if anyone could let me know what is wrong with my code.

Please also show the full updated code along with an explanation for why the code in the answer is working and the difference between it and mine.

Thank you.

Suraj Kothari
  • 1,642
  • 13
  • 22
  • 1
    `for row in reader` runs through the file only once. If its size is not too large, you can store the entirety of it in memory. Also, hash your passwords. – Norrius Jan 27 '18 at 13:02
  • Hashing my passwords isn't as important of an issue as getting my log in to run successfully. Although, I will consider it at a later date. Thanks. – Suraj Kothari Jan 27 '18 at 13:04
  • Possible duplicate of [Iterating on a file using Python](https://stackoverflow.com/questions/10255273/iterating-on-a-file-using-python) – Aran-Fey Jan 27 '18 at 13:08
  • I checked out the "duplicate" post and it mentions closing the file. However, in python "with open() as ..." opens and closes the file. – Suraj Kothari Jan 27 '18 at 13:10

3 Answers3

1

for row in csv.reader(csvfile) goes through the file line by line, once. After the file is exhausted, it doesn't do anything. You can instead load it into memory as a dictionary (provided it is not too large, otherwise you probably need a DB):

import csv

account_passwords = dict()

with open("accounts.csv") as csvfile:
    reader = csv.reader(csvfile)    
    for row in reader:
        account_passwords[row[0]] = row[1]

while True:
    username = input("\nEnter username: ")
    password = input("Enter password: ")

    if username in account_passwords and \
            account_passwords[username] == password:
        print("\nSuccessfully logged in!")
        break
    else:
        print("Username/password is incorrect. Try again.")

If you're doing this for anything serious, consider hashing the passwords and using getpass.getpass instead of input for reading passwords.

Norrius
  • 7,558
  • 5
  • 40
  • 49
1

It looks like that for row in reader running only once
try change the order of your code
Try to open the file inside the while True: like this:

while True:
    with open("accounts.csv") as csvfile:
        reader = csv.reader(csvfile)

should work fine because you close the file before each iteration

Eran Elbaz
  • 46
  • 4
0

csv.reader(%filename%) is generator.

Python generators can be processed only once. So when your enter incorrect details generator goes up to last row and found nothing. When your code return to "while True" reader will be empty and "for row in reader:" will not return any values.

Correct (or at least working) version should be something like this:

import csv

account_password = ""


def get_pass_from_file(username):
    with open("accounts.csv") as csvfile:
        for item in csv.reader(csvfile):
            if item[0] == username:
                return item[1]


if __name__ == '__main__':
    while True:
        username = input("\nEnter username: ")
        account_password = get_pass_from_file(username)
        if account_password is None:
            print("Username not found. Try again.")
            continue

        password = input("Enter password: ")
        if password == account_password:
            break
        else:
            print("Username/password is incorrect. Try again.")

    print("\nSuccessfully logged in!")