Convert row in csv file to menu - python

I have a csv file named codes.csv as below.
CATEGORY SUB-CATEGORY
Technology Accessories
Technology Phones
Technology Copier
Technology Machines
Furniture Chairs
Furniture Tables
Furniture Bookcase
Office Supplies Appliances
Office Supplies Stationery
Office Supplies Binders
I would like to print it out in the program as a menu like below:
Choose a Sub Catgory:
1:Technology
2:Furniture
3:Office Supplies
Enter a Catgory:2
Choose a Sub Catgory:
1:Chairs
2:Tables
3:Bookcase
Enter a Sub Catgory:1
If the user selects 2 (Furniture) in Category, then the program will print out the sub-categories, like Chairs, Tables, and Bookcase, which are under Furniture.
I'm able to print out the categories as a menu, but when the user keys in the option, the program does nothing.
import csv
filePath1 = "codes.csv"
print("Choose a Category : ")
categories = {}
sub_categories = {}
option = 0
with open(filePath1) as csvfile: # open category file
reader = csv.DictReader(csvfile) # dictread file
for row in reader:
categories[row['CATEGORY']] = 0
for key,value in categories.items():
option = option + 1
print("{:>1} : {:<20}".format(option,key))
category = input("Enter Category : ")
if(category == option):
print(option)

The first problem is the formatting of you data. It seems like you've used spaces as separators which entails two problems:
One of your data points contains a space, too. That's ambiguous and will mess up your parsing.
You have many spaces as separators between the columns. I'm not sure if it's possible to do that in csv but it won't simplify things.
What is the original data formatting? Maybe you've tabs in your original data which have been converted while copying pasting it here.
From here on, I assume that there is one tab (\t) between the columns.
When I run the code, I get an error:
Choose a Category :
Traceback (most recent call last):
File "./x.py", line 12, in <module>
categories[row['CATEGORY']] = 0
KeyError: 'CATEGORY'
That's because the csv.DictReader does not understand the formatting. It's strange that you don't get an error like that, I guess it's because you have some other data formatting. For tab-separated columns we need an additional argument:
with open(filePath1) as csvfile: # open category file
reader = csv.DictReader(csvfile, delimiter='\t') # dictread file
for row in reader:
categories[row['CATEGORY']] = 0
Then you have the problem of comparing int with str in the last section. Fix it by converting the string to an integer first:
try:
category = int(input("Enter Category : "))
if category == option:
print(option)
except ValueError:
print("Try again with a valid category")
Finally, one logical problem remains: In the end, option is the number of categories you have, so this does not make any sense to me at all.
How about this?
#!/usr/bin/env python3
import csv
import sys
filePath1 = "codes.csv"
with open(filePath1) as csvfile:
reader = csv.DictReader(csvfile, delimiter='\t')
categories = [ row["CATEGORY"] for row in reader ]
# eliminate duplicates, but also destroys the order
categories = list(set(categories))
for i, category in enumerate(categories):
print("{}: {}".format(i, category))
try:
option = int(input("Enter Category: "))
except ValueError:
print("Try again with a valid integer.")
sys.exit(1)
try:
category = categories[option]
print(category)
except IndexError:
print("Value out of bounds.")
sys.exit(1)
# Do something with category...

Related

Read lines from .txt file into sql query

I want to run a .txt file line for line through an SQL query. The .txt file consists of songtitles that may or may not exist in the database. If there is more than one option that fits the songtitle in the database a selection menu should appear. If there is only one option no further action is needed. If the line in the .txt file is not in the database a print statment shoud appear saying the song is not found.
To test this I made a .txt file with each of the three options described above:
Your (this gives 7 hits)
Bohemian (this gives 1 hit)
Thriller (this gives 0 hits)
I created the .txt file in another .py file, like this:
with open('MijnMuziek.txt', 'w') as f:
f.writelines("""
your
bohemian
thriller""")
f.close()
But if I run the code below in a separate .py file it only prints 'Choose from the following options: ' and than gives an error message saying index is out of range.
import sqlite3
music_database = sqlite3.connect("C:\\Users\marlo\Downloads\chinook_LOI.db")
cursor = music_database.cursor()
def read_file(filename):
with open(filename) as f:
for track in f:
cursor.execute(f"""SELECT DISTINCT t.TrackId, t.Name, art.Name
FROM tracks t
JOIN albums alb ON t.AlbumId = alb.AlbumId
JOIN artists art ON alb.ArtistId = art.ArtistId
WHERE t.Name LIKE '{track}%'""")
def selection_menu():
for position, song in enumerate(tracks_available):
print(str(position + 1), *song[1:3], sep='\t')
choice = int(input('Choose from the following options: '))
print('You chose:', *tracks_available[choice - 1], sep='\t')
read_file('MijnMuziek.txt')
tracks_available = cursor.fetchall()
selection_menu()
music_database.close()
When I put only one option in the .txt file (f.writelines('your')) the code does work and I get a selection menu.But with more than one line in the .txt file it does not work.
How do I solve this?
I don't have your database to test this, but this is
a way to do it.
It makes sense to open & close the database in the read function.
It also is a good idea to avoid global variable use and instead pass
them into functions.
I included protection against blank lines in your text file.
I didn't fix the SQL injection for you because I'd need to google
how it works with the LIKE % you use...
import sqlite3
DATABASE_FILE = r"C:\\Users\marlo\Downloads\chinook_LOI.db"
def read_tracks_from_file(filename, database_file):
music_database = sqlite3.connect(database_file)
cursor = music_database.cursor()
tracks_available = []
with open(filename) as f:
for track in f:
if track:
cursor.execute(f"""SELECT DISTINCT t.TrackId, t.Name, art.Name
FROM tracks t
JOIN albums alb ON t.AlbumId = alb.AlbumId
JOIN artists art ON alb.ArtistId = art.ArtistId
WHERE t.Name LIKE '{track}%'""")
for track in cursor.fetchall():
tracks_available.append(track)
music_database.close()
return tracks_available
def selection_menu(track_selection):
for position, song in enumerate(track_selection, start=1):
print(str(position), *song[1:3], sep='\t')
choice = int(input('Choose from the following options: '))
print('You chose:', *track_selection[choice - 1], sep='\t')
tracks_available = read_tracks_from_file(filename='MijnMuziek.txt',
database_file=DATABASE_FILE)
selection_menu(track_selection=tracks_available)

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.

Function that uses infomation from a csv file to display more infomation

the question I have to answer is : Write a function displayTime that receives the list of runners and the number of a runner and displays the name and the time. If the number is not found on the list the function displays an error message.
So far I have created a function which loads all the data from the excel spreadsheet and stores it as dictionaries under separate categories. The code is as follows:
import csv
def loadResults():
with open('marathon.csv') as csvfile:
readCSV = csv.reader(csvfile, delimiter=',')
s = {}
runners = []
number = []
time = []
name = []
surname = []
for row in readCSV:
num = row[0]
times = row[1]
firstname = row[2]
surnam = row[3]
number.append(num)
time.append(times)
name.append(firstname)
surname.append(surnam)
However for the question I have to display the name and the time of a runner when their number is entered. So far I have:
def displayTime(runners,number):
for s in runners:
if s['time']==number:
print(s['name'])
Any help would be greatly appreciated
Try doing this, I am not 100% sure but I think it would work
Variable_Name = open("marathon.csv","r")
and then seperate the parts of the file you want with
Variable_Name.split(",")
tell me if it works or not

CSV rewriter keeps creating new headers

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.

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