TheWanderingJedi
TheWanderingJedi

Reputation: 25

Verifying Username and Password in a Text File in Python

First post here although I have lurked for many years

I am currently working on a programming project and am stuck. The goal of the project is to take input from a user, a username and password, and verify through a text file to see if it is correct. If correct, it will print "Welcome!" and end, if not, it will ask for the username and password and loop through until a correct combination is entered.

The textfile is in the following format:

Darth:Vader

Boba:Fett

R2:D2

ObiWan:Kenobi

Luke:Skywalker

Here is my code:

# Lets user know what this program will do
print("Please login");

# Opens accounts txt file
accounts_file = open("accounts.txt", "r")

# Flag to terminate while loop
complete = False
# Runs loop until username and password are correct
while complete == False:
    # Asks user for username and stores as variable
    usernameInput = input("Username:");
    # Asks user for password and stores as variable
    passwordInput = input("Password:");
    # Reads each line of the text file line by line
    # Darth:Vader
    # Luke:Skywalker
    # R2:D2
    # ObiWan:Kenobi
    # Boba:Fett
    for line in accounts_file:
        # Stores each line in file as a username/password combo
        username, password = line.replace("\n","").split(":")
        # If username and password match, breaks out of the loop and sets complete to  True
        if usernameInput == username and passwordInput == password:
            complete = True
            break
        # Sets complete to False and loops back    
        else:
            complete = False
            continue
if complete == True:
    print("Welcome!");

I can get it to run correctly if enter a correct name the first time: For instance:

Please login:

Username:Darth

Password:Vader

Welcome!

  • ends program

If I enter the wrong name, it loops back like so:

Please login:

Username:Darth

Password:Fett

Username:.....

However, if I enter a wrong username and then correct username, it will not end the program like I want it to, and continue to loop: Example:

Please login:

Username:Luke Password:Vader

Username:Darth Password:Vader

Username:R2 Password:D2

Any idea what is causing it to not accept the next input by the user and finishing the loop?

Thank you for the help!

Upvotes: 2

Views: 3648

Answers (4)

Mad Physicist
Mad Physicist

Reputation: 114290

Once you open a file and iterate through it, the iterator is exhausted. Just because your outer loop goes into another iteration does not restart the file iteration.

When you do for x in [1, 2, 3]:, python calls iter([1, 2, 3] under the hood. For a list, this returns a new iterator object every time. When a similar loop calls iter(accounts_file), a new iterator is not returned: the file object is the iterator.

You have two basic options to restart the iteration:

  1. Reopen the file every time. Normally, the idiomatic way to do that is with a with block, as that will also close the file automatically in case of error:

    while not complete:
        usernameInput = input("Username:")
        passwordInput = input("Password:")
        with open("accounts.txt", "r") as accounts_file:
            for line in accounts_file:
                username, password = line.replace("\n","").split(":")
                if usernameInput == username and passwordInput == password:
                    complete = True
                    break
    

    This option is less desirable because it does a lot of disk I/O every time the user enters a wrong option.

  2. Load the entire file into a list. That lets you iterate over and over without hitting the disk multiple times. You can pre-load before the loop, or do it lazily after the first input. The first option is shown here:

    with open("accounts.txt", "r") as accounts_file:
        lines = accounts_file.readlines()
    while not complete:
        usernameInput = input("Username:")
        passwordInput = input("Password:")
         for line in lines:
             username, password = line.replace("\n","").split(":")
             if usernameInput == username and passwordInput == password:
                 complete = True
                 break
    

A third option would be a hybrid of these two, which might work for large files. You could pre-load an index into the file, and then look up small snippets based on user input.

Notice that the else clause is not necessary. complete is False and only changes when you want to break out of the loop.

It's more idiomatic to write while not complete:. The expression in the condition of a while loop is always interpreted as a boolean: there is no need to make the comparison explicit. And even then, bool values True and False are singletons. In the relatively rare situations when you need to compare against them explicitly, use the identity operator is rather than ==. I.e., complete is False is more pythonic than complete == False.

You could actually get rid of the complete variable entirely by using an arcane feature of for loops: the else clause. This clause gets triggered whenever a loop completes without breaking:

while True:
    usernameInput = input("Username:")
    passwordInput = input("Password:")
    with open("accounts.txt", "r") as accounts_file:
        for line in accounts_file:
            username, password = line.replace("\n","").split(":")
            if usernameInput == username and passwordInput == password:
                   break
        else:
            continue
        break

Also, don't use semicolons normally in python. They aren't invalid, but they aren't conventional except in rare situations like command-line interaction.

Upvotes: 2

Javets M
Javets M

Reputation: 47

print("Please Login !")
accounts_file = open("accounts.txt", "r")
USERS = []
for line in accounts_file:
    if line.replace("\n","").split(":") != [""]:
        accounts.append(line.replace("\n","").split(":"))
accounts_file.close()


def passCheck(username , password):
    if [username,password] in USERS:
        return   
    else:
        return passCheck(input("Enter your username : ") , input("Enter your password"))
passCheck(input("Enter your username : ") , input("Enter your password"))
print("Welcome!")

Upvotes: 0

user2668284
user2668284

Reputation:

How about this:-

ACCOUNTS = {}
with open('accounts.txt') as afile:
    for line in afile.readlines():
        tokens = line.split(':')
        ACCOUNTS[tokens[0]] = tokens[1].strip()
print('Please log in')
while True:
    n = input('Please enter your name: ')
    p = input('Please enter your password: ')
    if (password := ACCOUNTS.get(n)) and password == p:
        break
    print('Incorrect username or password')
print('Welcome')

Upvotes: 0

Eladtopaz
Eladtopaz

Reputation: 1054

It it doing so because your file is empty in the second time you try to read it.

After the first time you ran on the whole file here:

for line in accounts_file:
        # Stores each line in file as a username/password combo
        username, password = line.replace("\n","").split(":")
        # If username and password match, breaks out of the loop and sets complete to  True
        if usernameInput == username and passwordInput == password:
            complete = True
            break
        # Sets complete to False and loops back    
        else:
            complete = False
            continue

The file is empty, so called ‘depleted’. You need to make a new file object every time all over again if the user is wrong. Just do like so:

accounts_file = open("accounts.txt", "r")
for line in accounts_file:
        # Stores each line in file as a username/password combo
        username, password = line.replace("\n","").split(":")
        # If username and password match, breaks out of the loop and sets complete to  True
        if usernameInput == username and passwordInput == password:
            complete = True
            break
        # Sets complete to False and loops back    
        else:
            complete = False
            continue
account_file.close() # Very important to close the file for next time!

Or you could use with ... as ... like so:

with open("accounts.txt", "r") as accounts_file:
    for line in accounts_file:
        # Stores each line in file as a username/password combo
        username, password = line.replace("\n","").split(":")
        # If username and password match, breaks out of the loop and sets complete to  True
        if usernameInput == username and passwordInput == password:
            complete = True
            break
        # Sets complete to False and loops back    
        else:
            complete = False
            continue

Upvotes: 3

Related Questions