Python class adds empty line to last value - python

I'm trying to write a Login Program in python. I'm trying to read and add the usernames, emails and passwords to a text file. When reading the file I'm using a class to create accounts using the usernames etc. and store them inside my users[] list so I can access it with something like "users[3].username". Everything worked fine but I'm having one problem: When printing the last value of each account (in this case the password) there is an additional empty line. I dont want this because I cant use it like that for example when checking if a password is correct.
This is the code
class Accounts:
def __init__(self, username, email, password):
self.username = username
self.email = email
self.password = password
users = []
def add_account(username, email, password):
file = open("useraccounts.txt", "a")
file.write(username + ", " + email + ", " + password + "\n")
file.close()
def read_accounts():
file = open("useraccounts.txt", "r")
count = 0
for line in file:
count += 1
file.seek(0)
for i in range(count):
x = file.readline()
x = x.rsplit(", ")
new_account = Accounts(x[0], x[1], x[2])
users.append(new_account)
file.close()
add_account("Banana", "banana#email.com", "1234")
read_accounts()
print(users[0].username)
print(users[0].email)
print(users[0].password)
print("Something")
This is what the Output looks like
Banana
banana#email.com
1234
Something
It also happens when dealing wiht multiple accounts and when writing the text file manually instead of using the add_account function.
I'm sure the problem is my read_accounts function, because the problem does not occur when creating an account manually like this
account = Accounts("Banana", "banana#email.com", "1234")
Also since this is one my firsts programs let me know if you have any other tips.
1 More thing: Originally my post started with "Hey guys" but it got removed. Why does that happen lol?

file.readline() doesn't strip the newline character from the end of the line, so when you split it up, the newline is still attached to the last element (the password). So you should add an rstrip() to your reading, e.g.:
x = file.readline().rstrip()
This should help, happy coding!

Related

Combine lines when writing to file in Python?

So I'm trying to write all this info to a .txt file, but due to the names being pulled from a .txt file that goes
Liam
Noah
William
etc...
When I write to a file, it puts the first and last names on separate lines from everything else.
I've looked on StackOverflow for a solution but I couldn't find anything specific enough.
password = input('Enter the Password you would like to use ')
open('names.txt', 'r+')
lines = open("names.txt").readlines()
firstName = lines[0]
words = firstName.split()
firstNameChoice = random.choice(lines)
open('names.txt', 'r+')
lines = open("names.txt").readlines()
lastName = lines[0]
words = lastName.split()
lastNameChoice = random.choice(lines)
def signUp():
randomNumber = str(random.randint(0,10000))
accountFile = open('accounts.txt', 'a')
accountFile.write(firstNameChoice)
accountFile.write(lastNameChoice)
accountFile.write(randomNumber)
accountFile.write('#')
accountFile.write(catchall)
accountFile.write(':')
accountFile.write(password)
accountFile.write('\n')
signUp()
Expectation would be everything printed to one line but that's not the case.
As a quick fix for your problem, you could merge all writing commands in one line:
with open('accounts.txt', 'a') as accountFile: # using a context manager is highly recommended
# with spaces
accountFile.write('{} {} {} # {} : {} \n'.format(
firstNameChoice,
lastNameChoice,
randomNumber,
catchall,
password
)
)
# without spaces
accountFile.write('{}{}{}#{}:{}\n'.format(
firstNameChoice,
lastNameChoice,
randomNumber,
catchall,
password
)
)
If my understanding is right then you want to write everything in one line.
The variables you are writing containing \n while writing into the file.
So you have to replace it with a ' '. Replace this code into your program like:
accountFile.write(firstNameChoice.replace('\n',' '))
accountFile.write(lastNameChoice.replace('\n',' '))
accountFile.write(str(randomNumber).replace('\n',' '))
accountFile.write('#'.replace('\n',' '))
#accountFile.write(catchall)
accountFile.write(':'.replace('\n',' '))
accountFile.write(str(password).replace('\n',' '))
Now it will print like this WilliamWilliam448#:dsada
By the way I dont know what you mean by catchall
The reason it puts it all on a new line is because the strings of your names contains the "\n" on the end because it has an enter to a new line. There is an easy fix for this.
Where you define your first and last name variables add .rstrip() at the end. Like this:
firstNameChoice = random.choice(lines).rstrip()
lastNameChoice = random.choice(lines).rstrip()
def signUp():
randomNumber = str(random.randint(0,10000))
accountFile = open('accounts.txt', 'a')
accountFile.write(f'{firstNameChoice} {lastNameChoice} {randomNumber} # {catchall}: {password} \n')

Program stops working when the list of strings is swapped for a text file

My program filters through a list of usernames and checks their availability on twitter. In testing I used a list that I entered manually into the code. However, once it was working I swapped them out for a txt file. Only to notice that actually it was no longer checking successfully for the first 4 names in the text file but was working for the last one.
I've printed the json output on the failed 4 tests and it was "Only use letters, numbers and '_'"
available = open("Available-Twitter.txt", "a")
with open ("accounts.txt", "r") as usernames:
for username in usernames:
r = requests.get("https://twitter.com/users/username_available?username={}".format(username))
print (r.json()['msg'])
print (' ')
if "!" in (r.json()['msg']):
print(Fore.GREEN + "Account available - {}".format(username))
available.write(username+"\n")
else:
print(Fore.RED + "Account is unavailable - {}".format(username))
The file generator produces lines that end with a newline character. You should strip it if you don't need it:
with open ("accounts.txt", "r") as usernames:
for username in usernames:
username = username.rstrip()
...

Outer for loop execute only once in Python

The code below just print the first user from the outer loop and all the passwords from inner loop. Once the inner is executed once the program exit from the outer loop also.
passfile = open("passfile.txt", "r")
userfile = open("userfile.txt", "r")
for user in userfile:
for password in passfile:
print("user: " + user + " password: " + password)
Every iteration the inner loop is executed whatever is this. In this case it will read the file from the beginning till the end. Once it has reached the end of the file cannot read more no matter how many times the outer loop iterates.
If you can suppose that it contains user-password pairs you may try zip as suggested here.
I think this is the behaviour you actually want, see Jónás Balázs answer for the cause of problem:
Edited:
with open("passfile.txt", "r") as passfile:
passwords = passfile.readlines()
with open("userfile.txt", "r") as userfile:
usernames = userfile.readlines()
for user in usernames:
for password in passwords:
print("user:", user, "password:", password)
Try to run both loops simultaneously:
userfile = open("userfile.txt", "r")
passfile = open("passfile.txt", "r")
for user, password in zip(userfile, passfile):
print("user: " + user + " password: " + password)
The problem you are encountering is as described by #Jónás Balázs. Use izip if using Python 2 or zip if python 3 so you can iterate over two files simultaneously in just a single loop.
try:
from itertools import izip # For Python 2
except ImportError:
izip = zip # For Python 3
for user, password in izip(open("userfile.txt"), open("passfile.txt")):
print("User: " + user + "Password: " + password)
This is assuming that both files have the same number of lines and has a 1-to-1 relationship between the user and the password.

How do I split a combo list in a large text file?

my problem is that I have a very large database of emails and passwords and I need to send it to a mysql database.
The .txt file format is something like this:
emailnumberone#gmail.com:password1
emailnumbertwo#gmail.com:password2
emailnumberthree#gmail.com:password3
emailnumberfour#gmail.com:password4
emailnumberfive#gmail.com:password5
My idea is to make a loop that takes the line and make it a variable, search the ":" and pick the text before, send it to the db and then the same with the after part of the line. How do I do this?
Short program with some error handling:
Create demo data file:
t = """
emailnumberone#gmail.com:password1
emailnumbertwo#gmail.com:password2
emailnumberthree#gmail.com:password3
emailnumberfour#gmail.com:password4
emailnumberfive#gmail.com:password5
k
: """
with open("f.txt","w") as f: f.write(t)
Parse data / store:
def store_in_db(email,pw):
# replace with db access code
# see http://bobby-tables.com/python
# for parametrized db code in python (or the API of your choice)
print("stored: ", email, pw)
with open("f.txt") as r:
for line in r:
if line.strip(): # weed out empty lines
try:
email, pw = line.split(":",1) # even if : in pw: only split at 1st :
if email.strip() and pw.strip(): # only if both filled
store_in_db(email,pw)
else:
raise ValueError("Something is empty: '"+line+"'")
except Exception as ex:
print("Error: ", line, ex)
Output:
stored: emailnumberone#gmail.com password1
stored: emailnumbertwo#gmail.com password2
stored: emailnumberthree#gmail.com password3
stored: emailnumberfour#gmail.com password4
stored: emailnumberfive#gmail.com password5
Error: k
not enough values to unpack (expected 2, got 1)
Error: : Something is empty: ': '
Edit: According to What characters are allowed in an email address? - a ':' may be part of the first part of an email if quoted.
This would theoretically allow inputs as
`"Cool:Emailadress#google.com:coolish_password"`
which will get errors with this code. See Talip Tolga Sans answer for how to break down the splitting differently to avoid this problem.
This can be done through simple split() method of the strings in python.
>>> a = 'emailnumberone#gmail.com:password1'
>>> b = a.split(':')
>>> b
['emailnumberone#gmail.com', 'password1']
To accomodate #PatrickArtner's complex password fail this can be done:
atLocation = a.find('#')
realSeperator = atLocation + a[atLocation:].find(':')
emailName = a[0:atLocation]
emailDomain = a[atLocation:realSeperator]
email = emailName + emailDomain
password = a[realSeperator + 1:]
print(email, password)
>>> emailnumberone#gmail.com com:plex:PassWord:fail
str.find() returns the first occurrence location of the given character in the given string. Emails can have : in their name field but they can not have #. So first locating the # then locating the : would give you the correct separation locations. After that splitting the string will be piece of cake.
Open file as context manager (with open(...)), You can iterate over the lines with a for loop, then regex match(re Module)(or just split on ":") and use sqlite3 to insert your values to DB.
So the file:
with open("file.txt", "r") as f:
for line in f:
pass #manipulation
Sqlite3 Docs: https://docs.python.org/2/library/sqlite3.html

Reading two consecutive lines in Python if one starts with a specific string

I am currently trying to learn Python. I know some basics and I'm trying to practise by making a game. My code so far is:
import time
import datetime
now = datetime.datetime.now()
name = input('What is your name? >> ')
file = open("users.txt","+w")
file.write(name + ' started playing at: ' + now.strftime("%Y-%m-%d %H:%M") + '. \n')
file.close()
account = input('Do you have an account ' + name + '? >> ')
while(account != 'yes'):
if(account == 'no'):
break
account = input('Sorry, I did not understand. Please input yes/no >> ')
if(account == 'yes'):
login = input('Login >>')
passwd = input('Password >>')
if login in open('accounts.txt').read():
if passwd in open('accounts.txt').read():
print('Login Successful ' + login + '!')
else:
print('Password incorrect! The password you typed in is ' + passwd + '.')
else:
print('Login incorrect! The login you typed in is ' + login + '.')
As you probably noticed I am working on a login system. Now please ignore all the bugs and inefficient code etc. I want to focus on how I can get Python to check for a line in a .txt file and, if it's there, check the one below.
My .txt file is:
loggn
pass
__________
I want to make the program multi-account. This is why I am using a .txt file. If you need me to clarify anything, please ask. Thankyou! :)
with open('filename') as f:
for line in f:
if line.startswith('something'):
firstline = line.strip() # strip() removes whitespace surrounding the line
secondline = next(f).strip() # f is an iterator, you can call the next object with next.
Store the results of "open('accounts.txt').read()" yourself, and iterate over them as an array - if you know what line number you are on, it is trivial to check the next. Assuming that every even numbered line is a login, and every odd numbered line is a password, you would have something like this:
success = False
# Storing the value in a variable keeps from reading the file twice
lines = open('account.txt').readlines()
# This removes the newlines at the end of each line
lines = [line.strip() for line in lines]
# Iterate through the number of lines
for idx in range(0, len(lines)):
# Skip password lines
if idx % 2 != 0:
continue
# Check login
if lines[idx] == login:
# Check password
if lines[idx + 1] == password:
success = True
break
if success:
print('Login success!')
else:
print('Login failure')
You may also consider changing your file format: using something that won't occur in the login name (such as a colon, unprintable ASCII character, tab, or similar) followed by the password for each line means you could use your original approach by just checking for (login + "\t" + password) for each line, rather than having to worry about having two lines.

Categories