CSV rewriter keeps creating new headers - python

My code is creating the same headers each time, I want it to create one and append the data to a CSV without creating a new header.
What it looks like in the CSV
What I want it to look like
import csv
with open("Details.csv","a+") as Details:
w=csv.writer(Details,delimiter=",")
headers1=["Name","Age","Year Group"]
line=Details.readlines()
if line!=["Name","Age","Year Group"]:
w.writerow(headers1)
print("Welcome User, to my Topics Quiz!\n-------------------------------
--------\nYou can choose from 3 different topics:\n • History\n •
Music\n • Computer Science\n---------------------------------------")
print("Before we start, we need to register an account.")
User=input("Enter your name:\n")
Age=input("Enter your age:\n")
Year=input("Enter your year group:\n")
details=[User,Age,Year]
w.writerow(details)
Details.close()
with open("UserPass.csv","a+") as Userpass:
w=csv.writer(Userpass,delimiter=",")
headers2=["Username","Password"]
if headers2 not in Userpass:
w.writerow(headers2)
NewUser=(User[:3]+Age)
print("Great! Your username is set to: {}".format(NewUser))
Pass=input("Enter a password for your account:\n")
userpass=[NewUser,Pass]
w.writerow(userpass)
Userpass.close()
Any help is greatly appreciated.

You are opening file in appending mode (https://docs.python.org/3/library/functions.html#open), so this line=Details.readlines() will always be empty line and your headers will be written every time (code will always get into if).
It is similar with other file. So I suggest you first check if file exist, and if not create it and add headers, and remove headers part from with:
import csv
import os.path
if not os.path.isfile("Details.csv"):
with open("Details.csv", "a+") as Details:
w = csv.writer(Details, delimiter=",")
headers1 = ["Name", "Age", "Year Group"]
w.writerow(headers1)
Details.close()
if not os.path.isfile("UserPass.csv"):
with open("UserPass.csv", "a+") as Userpass:
w = csv.writer(Userpass, delimiter=",")
headers2 = ["Username", "Password"]
w.writerow(headers2)
Userpass.close()
with open("Details.csv", "a+") as Details:
w = csv.writer(Details, delimiter=",")
print("Welcome User, to my Topics Quiz!\n-------------------------------"
"--------\nYou can choose from 3 different topics:\n • History\n • "
"Music\n • Computer Science\n---------------------------------------")
print("Before we start, we need to register an account.")
User = input("Enter your name:\n")
Age = input("Enter your age:\n")
Year = input("Enter your year group:\n")
details = [User, Age, Year]
w.writerow(details)
Details.close()
with open("UserPass.csv", "a+") as Userpass:
w = csv.writer(Userpass, delimiter=",")
NewUser = (User[:3] + Age)
print("Great! Your username is set to: {}".format(NewUser))
Pass = input("Enter a password for your account:\n")
userpass = [NewUser, Pass]
w.writerow(userpass)
Userpass.close()

There are different problems in your code:
1) Empty line between lines with data in csv file, it happens because of the nonbinary type of opening and can be fixed by adding that arg in open function:
w=csv.writer(Details,delimiter=",",lineterminator='\n')
2) In your case Details.readlines() method was returning [], because of the a+ type of opening, it's supposed to add lines in the end of file, so pointer is in the end already and we need to return it at the beginning by using that code:
line=Details.seek(0)
3) Also, we need only first line, so just use readline() method. And after all, your condition should look that way, because of the return type and the fact that there's \n in the end of every line:
if line!="Name,Age,Year Group\n":
And the full code of that part. Let me know if it works well for you:
w=csv.writer(Details,delimiter=",",lineterminator='\n')
headers1=["Name","Age","Year Group"]
line=Details.seek(0)
line=Details.readlines()[0]
print(line)
if line!="Name,Age,Year Group\n":
w.writerow(headers1)

I don't understand everything your code is trying to accomplish, but the following will add a row to the Details.csv without creating any new headers:
import csv
import os
csv_fileheader = "Name", "Age", "Year Group"
csv_filename = "Details.csv"
print("Welcome User, to my Topics Quiz!\n"
"---------------------------------------\n"
"You can choose from 3 different topics:\n"
" • History\n • Music\n • Computer Science\n"
"---------------------------------------")
print("Before we start, we need to register an account.")
user = input("Enter your name:\n")
age = input("Enter your age:\n")
year = input("Enter your year group:\n")
if not os.path.isfile(csv_filename): # Create file if it doesn't exist.
with open(csv_filename, "w", newline='') as csv_file:
csv.writer(csv_file).writerow(csv_fileheader) # Put header row in it.
with open(csv_filename, "a+", newline='') as details2:
writer = csv.writer(details2, delimiter=",")
writer.writerow((user, age, year))
You should consider following the PEP 8 - Style Guide for Python Code recommendations as it will make your code easier for both you and others to read.

Related

What is wrong with my python code that seaches through a csv?

I'm very new to Python and have only been learning it for a week. I am trying to make a "username selection process" but can't work out how to search a CSV (without errors) to make sure that the name hasn't been used before. Below is my code:
def customusername():
cust = input('Please Enter Custom Username: ')
import csv
import sys
csv_file = csv.reader(open('usernamedatabase.csv', "r",
encoding='utf-8'), delimiter=",")
for row in csv_file:
if cust == row[1]:
print("Username Taken, Try a different name")
customusername()
else:
print("Username Selected")
#I will use code here to place the username
into the database but I already know how to do that
The errors recieved:
Traceback (most recent call last):
File "(the file path)", line 16, in <module>
customusername()
File "(the file path)", line 9, in customusername
if cust == row[1]:
IndexError: list index out of range
BTW I am using visual studio code
I have tried using code from many different websites, all returned errors
This is my solution!
import csv
header = ['UserName']
data = [["Mark"], ["Josh"], ["Lillo"]]
with open("userneame.csv",'w',newline='') as user:
writer=csv.writer(user)
writer.writerow(header)
writer.writerows(data)
NickName = input("username: ").title()
with open('userneame.csv', 'r', newline='') as users:
reader = csv.reader(users)
next(reader) #skips the header
usernames = []
for data in reader: #prints [Mark],[Josh] ecc
for names in data:#Printing all the names in the csv file
usernames.append(names) #just saving the names in the csv file, in a list
if NickName in usernames:
print(f"Sorry {NickName} is not available")
else:
print(f"Nice to meet you {NickName}")
You use recursion where you could use a loop. The call stack has a limit and this can cause your code to error out. You should read the file first, and then loop until you get a valid username. Remember that IO is expensive, so reading the file every time an invalid username is selected is going to take a lot longer than reading it once and remembering it.
import csv
import sys
def customusername():
with open('usernamedatabase.csv', "r", encoding='utf-8') as fh:
# One strategy is to load all rows into a list
csv_file = csv.reader(fh, delimiter=",")
csv_rows_list = list(csv_file)
with open('usernamedatabase.csv', "r", encoding='utf-8') as fh:
# Another is to load all rows into a dict,
# indexed by the 1th column which is presumably the username
csv_file = csv.reader(fh, delimiter=",")
csv_rows_dict = {row[1]: row for row in csv_file}
# Then, you can simply check if the input is in your list or dict:
# 1. List:
while True: # Keep asking for a username until you break
cust = input("Enter your custom username: ")
# if any of the 1th element of the items in
# csv_row_list are equal to username, it is taken
if any(row[1] == cust for row in csv_rows_list):
print("That username is taken. Pick another one.")
else: # Username is available, so end the loop
break
print(f"Hello {username}!")
# 2. Dict:
while True:
cust = input("Enter your custom. username: ")
if cust in csv_rows_dict:
print("That username is taken. Pick another one.")
else: # Username is available, so end the loop
break
print(f"Hello {username}!")
The second approach, with the dict is much better because it is much faster to look up a key in a dict than an item in a list.
If you have memory constraints and can't afford to load the entire csv file, you can simply keep the usernames from it as a set, and check for membership in that set the same way you check if the key exists in the dict.
with open('usernamedatabase.csv', "r", encoding='utf-8') as fh:
csv_file = csv.reader(fh, delimiter=",")
# A set comprehension is subtly different from a dict comprehension
csv_rows_set = {row[1] for row in csv_file}
Note the use of the context manager with to handle automatically closing the file. I also moved the imports outside the function because this.

How to create a for loop from a input dependent function in Python?

I am finally getting the hang of Python and have started using it on a daily basis at work. However, the learning curve is still steep and I have hit a roadblock in trying something new with a code I found here for scraping members from telegram channels.
Currently in lines 38-44 we can select a group from the list and it will scrape the user data into members.csv .
EDIT: Resolved the CSV naming issue:
print('Saving In file...')
print(target_group.title)
filename = target_group.title
with open(("{}.csv".format(filename)),"w",encoding='UTF-8') as f:
Instead of relying on input, I would like to create a for loop which would iterate through every group in the list.
print('Choose a group to scrape members from:')
i=0
for g in groups:
print(str(i) + '- ' + g.title)
i+=1
g_index = input("Enter a Number: ")
target_group=groups[int(g_index)]
The problem is that I am not sure exactly how to replace this part of the code with a for loop.
Although, just changing it into a for loop would make it merely overwrite the same members.csv file with each iteration, I plan on changing that so that it outputs into unique files.
So circling back to my question. How do I make this single program iteration loop through all of the groups, or just select all of them.
Thanks for the help !
Couldn't test this, but something like this maybe? This creates a new .csv file for each group.
for chat in chats:
try:
if chat.megagroup == True:
groups.append(chat)
except:
continue
for current_group in groups:
print(f"Fetching members for group \"{current_group.title}\"...")
all_participants = client.get_participants(current_group, aggressive=True)
current_file_name = f"members_{current_group.title}.csv"
print(f"Saving in file \"{current_file_name}\"...")
with open(current_file_name, "w+", encoding="UTF-8") as file:
writer = csv.writer(file, delimiter=",", lineterminator="\n")
writer.writerow(["username", "user id", "access hash", "name", "group", "group id"])
for user in all_participants:
username = user.username if user.username else ""
first_name = user.first_name.strip() if user.first_name else ""
last_name = user.last_name.strip() if user.last_name else ""
name = f"{first_name} {last_name}"
row = [username, user.id, user.access_hash, name, current_group.title, current_group.id]
writer.writerow(row)
print(f"Finished writing to file \"{current_file_name}\".")
print("Members scraped successfully.")
Ended up figuring out the issue:
On naming the CSV file: Used the title attribute to name the file and replacement within the string.
g_index = chat_num
target_group=groups[int(g_index)]
filename = target_group.title
print('Fetching Members from {} ...'.format(filename))
all_participants = []
all_participants = client.get_participants(target_group, aggressive=True)
print('Saving In file...')
with open(("{}.csv".format(filename)),"w",encoding='UTF-8') as f:
On creating a for loop for the sequence: The original code (posted in the question) did not include a for loop. My version of a workaround was to create a function from everything and then iterate through a an indexed list that was equal to the amount of instances detected. In the end looking like this:
chat_list_index = list(range(len(chats)))
for x in chat_list_index:
try:
get(x)
except:
print("No more groups.", end = " ")
pass
pass
print("Done")
Overall, this might not be the best solution to accomplish what I sought out to, however its good enough for me now, and I have learned a lot. Maybe someone in the future finds this beneficial. Full code available here: (https://github.com/ivanstruk/telegram-member-scraper/).
Cheers !

Searching file for user-inputed keyword, then printing each line with keyword in it

For my assignment, I was given a text file named 'measles.txt' which contains A LOT of information, but most importantly, I'm focused on the year for each line. My task is to make a program that reads 'measles.txt', prompts the user for the year, and outputs every line with that year into another text file.
The problem that I can't figure out is that my professor specified that it has to work if the user inputs an incomplete year. For example, a line whose Year field contains “1987” would be selected by any of the following user responses: {“1”, “19”, “198”, “1987”}
Also, if the user inputs "","all", or "ALL", it has to output all the lines from the text file.
Here's measles.txt: https://bpaste.net/show/ade0a362b882
My current code is this:
input_file = open('measles.txt', 'r')
output_file_name = input("Please enter the name of the output file: ")
output_file = open(output_file_name, 'w')
for line in input_file:
output_file.write(line)
output_file.close()
input_file.close()
I found a much simpler answer. Since the year number in measles.txt is 88 characters from the beginning, I used that to create an if/elif statement.
input_file = open('measles.txt', 'r')
year = input("Please enter a year: ")
output_file_name = input("Please enter the name of the output file: ")
output_file = open(output_file_name, 'w')
# For loop that checks the end of the file for the year number
for line in input_file:
if year == line[88:88+len(year)]:
output_file.write(line)
elif year == ("", "all", "ALL"):
output_file.write(line)
output_file.close()
input_file.close()
Something like this might work. You can check whether a year starts with a certain string (for example '1' or '200'), this code below should return all the matching lines.
EDIT:
It seems like you found this code too complex but you made a mistake while copy/pasting and broke your solution. I modified your code to simplify it even more and fix it.
input_file = open('measles.txt', 'r')
year = input("Please enter a year: ")
output_file_name = input("Please enter the name of the output file: ")
output_file = open(output_file_name, 'w')
for line in input_file:
if year in ("", "all", "ALL") or line.split()[-1].startswith(year):
output_file.write(line)
output_file.close()
input_file.close()

Writing functions to allow user define file name and enter file contents

I am learning Python as a beginner and have a question that I couldn't figure out. I need to write functions to allow users to setup/give a file a name and then enter contents.
The error message I got is: "Str' object is not callable. I don't know how to fix this. Please could you help me out. Many thanks!
The code is as follows:
=========================================
WRITE = "w"
APPEND = "a"
fName = ""
def fileName(): #to define name of the file.
fName = input("Please enter a name for your file: ")
fileName = open(fName, WRITE)
return fileName
#now to define a function for data entry
dataEntry = ""
def enterData():
dataEntry = input("Please enter guest name and age, separated by a coma: ")
dataFile = open(fName, APPEND(dataEntry))
fName.append(dataEntry)
return dataFile
#to determine if it's the end of data entry
moreEntry = input("Anymore guest: Y/N ")
while moreEntry != "N":
enterData() #here to call function to repeat data entry
fName.close()
fileName()
enterData()
print("Your file has been completed!")
fileContents = fName.readline()
print(fileContents)
I ran the code and... I seeing the error as line 14
14 dataFile = open(fName, APPEND(dataEntry))
APPEND appears to be a str. It does not appear to be a function.
fName is not declared in this scope. Your function spacing is off. Maybe you meant to run the all the code in order rather than in parts?
As it is, fName is declared and defined once globally (line 4), declared and defined in function filename() (line 6).
fName is also referred to in the function (line 7) Called unsuccessfully in line 14
dataFile = open(fName, APPEND(dataEntry)) # fName has not been declared in function enterData()
I suspect your code would work if you reordered your lines and not use functions (due to references) Also, please close your files. EG
f = open ("somefile.txt", "a+")
...
f.close() #all in the same block.
Thanks for all the inputs. Much appreciated. I've reworked the code a bit, and to put all data entry into a list first, then try to append the list to the file. It works, to a certain extent (about 80%, perhaps!)
However, I now have another problem. When I tried to open the file to append the list, it says "No such file or directory" next to the code (line31): "myFile = open(fName, APPEND)". But I thought I declared and then let user define the name at the beginning? How should I make it work, please?
Thanks in advance again!
WRITE = "w"
APPEND = "a"
fName = ""
def fileName(): #to define name of the file.
fName = input("Please enter a name for your file: ")
fileName = open(fName, WRITE)
fileName.close()
return fileName
#now to define a function for data entry
dataEntry = ""
dataList = []
def enterData():
dataEntry = input("Please enter guest name and age, separated by a coma: ")
dataList.append(dataEntry)
return
fileName()
enterData()
#to determine if it's the end of data entry
moreEntry = input("Anymore guest: Y/N ")
if moreEntry == "Y":
enterData()
else:
print("Your file has been completed successfully!")
myFile = open(fName, APPEND)
myFile.append(dataList)
myFile.close()
fileContents = fName.readline()
print(fileContents)

searching a csv and printing a line

Trying to create a train booking system.
Having trouble searching my csv and printing that certain line.
The user already has there id number,and the csv is is set out like
This is what I have so far:
You are matching the entire line against the ID. You need to split out the first field and check that:
def buySeat():
id = raw_input("please enter your ID")
for line in open("customers.csv"):
if line.split(',')[0] == id:
print line
else:
print "sorry cant find you"
Try using the built-in CSV module. It will make things easier to manage as your requirements change.
import csv
id = raw_input("please enter your ID")
ID_INDEX = 0
with open('customers.csv', 'rb') as csvfile:
csvReader = csv.reader(csvfile)
for row in csvReader:
# Ignore the column names on the first line.
if row[ID_INDEX] != 'counter':
if row[ID_INDEX] == id:
print ' '.join(row)
else:
print 'sorry cant find you'

Categories