sorry if this isn't clear, or if this is simple, I'm a complete newbie at this.
I have this python code:
identer = input("Enter your Student ID... ")
passenter = input("Enter your password... ")
with open("pupil.csv", "r") as f:
reader = csv.reader(f)
for row in reader:
if identer != row["student_id"] or passenter != row["password"]:
print("Wrong ID or Password, try again.")
else:
The line if identer != row["student_id"] or passenter != row["password"]: is throwing the error:
TypeError: list indices must be integers or slices, not str
Is there a solution here I'm blind to? Here is the CSV file, if it helps.
forename,surname,phone_no,email,password,student_id,account_balance,module1,module2
nathan,m,099099,ddd,12345,754,100,,
reg,beg,180,regb,0987,331,100,,
g,b,334,email,911,203,100,,
Edit:
This is my code with dictreader
with open("pupil.csv", "r") as f:
reader = csv.DictReader(f)
for row in reader:
if identer != row[student_id] or passenter != row[password]:
print("Wrong ID or Password, try again.")
else:
This time it is throwing an error saying "KeyError: 754" 754 being the id
This should work:
with open("pupil.csv", "r") as f:
reader = csv.DictReader(f)
for row in reader:
if identer != row['student_id'] or passenter != row['password']:
print("Wrong ID or Password, try again.")
else:
# code for handling the else case
You access dictionary elements with strings as key by putting quotes around you column names. I believe you were doing that previously already, but weren’t using the DictReader. This is how you access the rows with it.
Related
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.
So, I am writing a program that takes user input of four variables in my list: [full_name, first_time, second_time, third_time]. I need to be able to take my list or dictionary, (which ever one is easier?) and have multiple stored lists that then transfer into my csv file named "times.csv" .
This program is meant for a coach to record his athletes running times. I know I can use things like .update and .append to add to one list but I do not know enough about csv files, lists, and programming in general to know how to take user input and store said (separate) lists into a csv file, without replacing the first user inputted column/list.
Maybe some kind of for loop in the writer section of my code??
code below:
import csv
file_name = 'times.csv'
true = 'yes'
while true:
user_entry = input("Do you want an entry? 'yes' to continue, ('no' to stop): ")
if user_entry == 'no':
break
else:
full_name = input("Enter a full name: ")
first_time = float(input("Enter first time: "))
second_time = float(input("Enter second time: "))
third_time = float(input("Enter third time: "))
list1 = [full_name, first_time, second_time, third_time]
print(list1)
with open(file_name, 'r') as csv_file:
csv_reader = csv.reader(csv_file)
fields = next(csv_reader)
for row in csv_reader:
list1.append(row)
print(', '.join(field for field in fields))
with open(file_name, 'w') as csv_file:
write_to_file = csv.writer(csv_file)
write_to_file.writerow(list1)
You could try something like:
Step 1: Create file csv file if not already exist
Step 2: Read the csv file to memory
Step 3: Get the user input and append to the data you read from the csv ( can be looped if there are multiple entries to be read)
Step 4: Write back the data (not append but as new file with the same name)
Implementation:
from pathlib import Path
import csv
def read_existing_data(filename):
csv_file = Path(filename)
csv_file.touch(exist_ok=True)
input_data = [row for row in csv.DictReader(open(filename))]
return input_data
def get_user_input():
entry_list = list()
entry = dict()
true = 'yes'
while true:
user_entry = input("Do you want an entry? 'yes' to continue, ('no' to stop): ")
if user_entry == 'no':
break
else:
entry["full_name"] = input("Enter a full name: ")
entry["first_time"] = float(input("Enter first time: "))
entry["second_time"] = float(input("Enter second time: "))
entry["third_time"] = float(input("Enter third time: "))
entry_list.append(entry)
return entry_list
def save_to_file(filename, csv_data):
columns = csv_data[0].keys()
try:
with open(filename, 'w') as csvfile:
writer = csv.DictWriter(csvfile, fieldnames=columns)
writer.writeheader()
for rows in csv_data:
writer.writerow(rows)
except IOError:
print("I/O error")
file_name = "times.csv"
# Read Existing data
data = read_existing_data(file_name)
# Append new data
data.extend(get_user_input())
# Save to file
save_to_file(file_name, data)
I have a phonebook that is working decently, and for my delete entry function I am not sure how to make it so you are able to type in just the first name of the person you want to be deleted, and it will delete their whole contact.
Here is the code:
def deleteEntry():
file = open("phone.txt")
phonebook = readFile("phone.txt")
while True:
try:
delete = input("Which entry would you like to delete?(enter name)")
print()
except ValueError:
print("Sorry, that didn't make sense. Try again.")
print()
continue
else:
break
print()
with open("phone.txt", "r") as f:
lines = f.readlines()
with open("phone.txt", "w") as f:
for line in lines:
if line.strip("\n") != delete:
f.write(line)
This works when I type the entire name and entire number separated by a comma (that is how the text is formatted in the txt file.)
Is there any way to make this function recognize if a first name is inputted?
Try this
file = open("phone.txt")
phonebook = readFile("phone.txt")
while True:
try:
delete = input("Which entry would you like to delete?(enter name)")
print()
except ValueError:
print("Sorry, that didn't make sense. Try again.")
print()
continue
else:
break
print()
with open("phone.txt", "r") as f:
lines = f.readlines()
with open("phone.txt", "w") as f:
for line in lines:
if delete not in line.strip("\n"):
f.write(line)
You can use the in keyword
Such as in
If 'search' in 'research':
This will do a contains search on the second string
Edit::
Modify your for loop to feature the code like the following
If delete in line:
Everything was going fine until I tried to combine a while loop with a CSV read and I am just unsure where to go with this.
The code that I am struggling with:
airport = input('Please input the airport ICAO code: ')
with open('airport-codes.csv', encoding='Latin-1') as f:
reader = csv.reader(f, delimiter=',')
for row in reader:
if airport.lower() == row[0].lower():
airportCode = row[2] + "/" + row[0]
print(airportCode)
else:
print('Sorry, I don\'t recognise that airport.')
print('Please try again.')
Executing this code causes the 'else' to print continuously until the code is stopped, regardless of whether or not the input matches that in the CSV file. The moment I remove this statement the code runs fine (albeit doesn't print anything if the input doesn't match).
What I am aiming to try and do is have the question loop until true. So my attempt was as follows:
with open('airport-codes.csv', encoding='Latin-1') as f:
reader = csv.reader(f, delimiter=',')
for row in reader:
while True:
airport = input('Please input the airport ICAO code: ')
if airport.lower() == row[0].lower():
airportCode = row[2] + "/" + row[0]
print(airportCode)
break
else:
print('Sorry, I don\'t recognise that airport.')
print('Please try again.')
False
I'm pretty sure my limited experience is causing me to oversee an obvious issue but I couldn't find anything similar with my search queries so my next stop was here.
As requested, a few lines of the CSV file:
EDQO small_airport Ottengrüner Heide Airport 50.22583389, 11.73166656
EDQP small_airport Rosenthal-Field Plössen Airport 49.86333466,
EDQR small_airport Ebern-Sendelbach Airport 50.03944397, 10.82277775
EDQS small_airport Suhl-Goldlauter Airport 50.63194275, 10.72749996
EDQT small_airport Haßfurt-Schweinfurt Airport 50.01805496,
EDQW small_airport Weiden in der Oberpfalz Airport 49.67890167,
If you want to do it precisely your way, you just need to make sure your csv reader's pointer returns back to the beginning of the file when a user enters bad code, something like:
with open('airport-codes.csv', encoding='Latin-1') as f:
reader = csv.reader(f, delimiter=',')
airportCode = None # store for our code
while not airportCode: # loop until valid code found
airport = input('Please input the airport ICAO code: ') # ask for the code
for row in reader: # loop through our CSV
if airport.lower() == row[0].lower(): # if code found in the first column...
airportCode = row[2] + "/" + row[0]
break # no need to search further
if not airportCode: # we didn't find the code, print a helpful message
print('Sorry, I don\'t recognise that airport.')
print('Please try again.')
f.seek(0) # reset the CSV pointer to the beginning for the next loop
print("Airport found: {}".format(airportCode))
But I'd suggest you to just load your codes in memory and do quick lookups on the spot:
airportCode = None # store for our code
airport_codes = {} # our in-memory fast lookup
with open('airport-codes.csv', encoding='Latin-1') as f:
reader = csv.reader(f, delimiter=',')
for row in reader: # loop through our CSV
airport_codes[row[0].lower()] = row[2] + "/" + row[0] # store the lookup map
while not airportCode:
airport = input('Please input the airport ICAO code: ') # ask for the code
airportCode = airport_codes.get(airport.lower(), None)
if not airportCode:
print('Sorry, I don\'t recognise that airport.')
print('Please try again.')
print("Airport found: {}".format(airportCode))
An easy solution would be something like this:
airport = input('Please input the airport ICAO code: ')
airportCode = None
with open('airport-codes.csv', encoding='Latin-1') as f:
reader = csv.reader(f, delimiter=',')
for row in reader:
if airport.lower() == row[0].lower():
airportCode = row[2] + "/" + row[0]
print(airportCode)
break
if airportCode is not None:
print('Sorry, I don\'t recognise that airport.')
print('Please try again.')
I had a different suggestion using functions:
import csv
def findAirportCode(airport):
with open('airport-codes.csv', encoding='Latin-1') as f:
reader = csv.reader(f, delimiter=',')
for row in reader:
if airport.lower() == row[0].lower():
airportCode = row[2] + "/" + row[0]
return airportCode
return None
airport = input('Please input the airport ICAO code: ')
code = findAirportCode(airport)
if(code != None ):
print (code)
else:
print('Sorry, I don\'t recognise that airport.')
print('Please try again.')
I think your logical flow is just a little off. If you want to continue looping through the csv file until you find the airport code, and then print an error message if the code is not there, then we need to do things in a different order. Currently, the code loops through every line of the file. And for every line, if the input code does not match any airport codes in the csv file, it prints out the message that it isn't there. Instead, we want to print the error message if it's not in ANY of the lines. We also only want one prompt per entire loop through the csv file. Instead of this:
with open('airport-codes.csv', encoding='Latin-1') as f:
reader = csv.reader(f, delimiter=',')
for row in reader: # Loop over every row in the csv
while True: # This effectively keeps you in the loop until you 'break'
airport = input('Please input the airport ICAO code: ')
if airport.lower() == row[0].lower():
airportCode = row[2] + "/" + row[0]
print(airportCode)
break # break if this row matches the airport code
else:
print('Sorry, I don\'t recognise that airport.')
print('Please try again.') # Prints if this row doesn't match
False # This doesn't set anything to 'False'
Try this:
with open('airport-codes.csv', encoding='Latin-1') as f:
reader = csv.reader(f, delimiter=',')
while True:
matches = False
airport = input('Please input the airport ICAO code:')
for row in reader:
if airport.lower() == row[0].lower():
airportCode = row[2] + "/" + row[0]
print(airportCode)
matches = True
break
if not matches:
print('Sorry, I don\'t recognise that airport.')
print('Please try again.')
False
With this code, the flow is different. First, ask for an airport code. Then check it against the file until either you reach the end of the file or you find a matching code. If the code is found in the file, print it out. If it wasn't found, print a message and ask the user for a new airport code again.
Rather than trying to match each line in your CSV with the entered input, it is best to first read your whole CSV data into a Python dictionary. This then lets you easily "look up" any airport code you like without having to keep re-reading the whole file in:
import csv
airport_codes = {}
with open('airport-codes.csv', encoding='Latin-1', newline='') as f_input:
csv_input = csv.reader(f_input, delimiter='\t')
for row in csv_input:
if len(row) >= 2: # Make sure the CSV line has at least 2 columns
airport_codes[row[0].lower()] = row[2]
while True:
icao_code = input('Please input the airport ICAO code: ').lower().strip()
try:
print("{}/{}".format(row[0], airport_codes[icao_code]))
except KeyError:
print("Sorry, I don't recognise airport.")
print("Please try again.\n")
Doing it this way would allow your script to prompt for multiple questions.
Note: The data you have posted in your question appears to be tab delimited, if that is the case, \t is needed to read the entries correctly. It is also recommended to add newline='' to your open() statement if it is going to be used with a CSV reader as can be seen in the documentation.
The try and except is what is called exception handling, in this case if the entry you are looking for in the dictionary is not present, the code jumps to the except part. This is the preferred approach in Python.
I already have this code. Now I want to change the code, that when someone types in his username, he has to fill in the right password which belongs to the username.
import csv
csvbestand='inlog.csv'
csv = open('inlog.csv', 'r').read().split('\n')[1].split(';')
username= input("Fill in your username: ")
if username == "admin" or username in csv:
print("Username found")
break
else:
print("Username not found")
while True:
import csv
csvbestand='inlog.csv'
csv = open('inlog.csv', 'r').read().split('\n')[2].split(';')
password = input("Fill in your password: ")
if password == "admin" or password in csv:
print("Congratiulations")
break
else:
print("Password not right")
So when the username is ''John'' then I want only the password which belongs to "John" as the right password.
I am supposing your csv will be like this:
user1, hash_pass_u1
user2, hash_pass_u2
user3, hash_pass_u3
...
Just one note before the solution. You are importing the CSV module of Python and you did not use it in your code, such a silly import, just use it.
The solution is simple
import csv
file = 'yourcsv.csv'
found = False
username = input('Write your username: ')
password_csv = None
with open(file, newline='') as csvfile:
reader = csv.reader(csvfile, delimiter=',')
for row in reader:
# row[0] is the first element, the username and row[1] the hash of the password
if row[0] == username:
password_csv = row[1]
found = True
break
if not found:
print('The username is not in our DB.')
while True:
passw = input('Let me your password: ')
hash_passw = your_method_to_get_the_hash(passw)
if hash_passw == password_csv:
print('Congrats, you are logged.')
break
else:
print('Wrong password dude, try again.')
In this way you only read the file once and you will use the CSV Module.
I'm supposing the format of your CSV if it is another format is easy to change the implementation of this solution. If you need some help with the CSV Module the documentation is here, for python2 and python3
Explanation of what you are doing wrong.
When you do the following sentence:
csv = open('inlog.csv', 'r').read().split('\n')[1].split(';')
You are opening the file, read all the file then split the file by \n character, with this you would obtain the following list ['user1;pass1';'user2;pass2','user3;pass3',...] and the last step you do there, is select the second element with [1], the result of this would be the string 'user2;pass2'. But the statement does not finish here, there is another split that would give you the list ['user2','pass2'].
So you are comparing that the username is admin or is in the list ['user2','pass2']. The same happens when you try to compare the password, but this time you select the third element.
with open('Usernames.txt', 'r') as f:
content = f.readlines()
index = [x for x in range(len(content)) if password in content[x].lower()]
index = (str(index)[1:-1])
if index == '':
print("user not found")
else:
index = (int(index))
with open('passwords.txt', 'r') as d:
d = d.readlines()
f = (d[index]).strip()
if password == f:
print("found password")
If I wanted to use separate files(txt) to contain usernames and passwords I would do this. It grabs the line no. the username is on, then in parallel the password