Python 3 try except issue - python

I'm having a little issue with my code, mainly (I think) with the try/except part. My code will generate a wordlist of the users choice. Here is the code:
def gen_wordlist():
filename = input("Please enter the name of the wordlist: ")
try:
my_file = open(filename, 'r')
except FileNotFoundError:
retry = input("No file named "+filename+". Would you like to try again (y/n)")
if retry == 'y' or retry == 'Y':
gen_wordlist()
else:
print("Goodbye :-)")
sys.exit()
words = my_file.read()
my_file.close()
return(words.split())
words = gen_wordlist()
If I enter a valid filename on the first attempt, it works as it should. However, if I enter an invalid filename and choose to try again, I get the following error, even if my second attempt is definitely a valid filename:
Traceback (most recent call last):
File "TEST.py", line 20, in <module>
words = gen_wordlist()
File "TEST.py", line 15, in gen_wordlist
words = my_file.read()
UnboundLocalError: local variable 'my_file' referenced before assignment
I can't work out why though. Surely, when I select 'y', the code just executes from the beginning of the gen_wordlist() function, and should work the same as if I had entered a valid filename on the first attempt, right?

If the open() call raises a FileNotFoundError exception, my_file was never set and all other references trying to use that name will fail.
That includes the code after gen_wordlist() was called in the exception handler. Sure, the new call may succeed, but that call then returns back to this frame where my_file was not set.
You want to return here too, instead:
if retry == 'y' or retry == 'Y':
return gen_wordlist()
Otherwise you'll ignore the result of the successful recursive call here too.
It's not a great idea to use recursion to handle errors in user input. Use a loop instead:
my_file = None
while my_file is None:
filename = input("Please enter the name of the wordlist: ")
try:
my_file = open(filename, 'r')
except FileNotFoundError:
retry = input("No file named " + filename + ". Would you like to try again (y/n)")
if retry.lower() == 'y':
# back to the top of the loop
continue
print("Goodbye :-)")
sys.exit()
This while loop then runs until my_file has successfully been set to a file object.

Re-read the error message, it clearly says you have used the variable my_file before assignment. Now, look at your code, when do you define my_file in the except clause? The try falls out without declaring/assigning to the my_file variable in case of an error. Rest, Martijn's answer points out some more issues.

Related

Function returns 'None' after reading file data, (only after FileNotFoundError exception is handled)

I am a total beginner to Python, and am attempting the following exercise:
1) Write code to open and read a file
2) Allow the user to specify a filename
3) Add error handling to allow the user to try again if the file cannot be located
I have tried searching for any related questions prior to this but was unable to resolve the issue below:
import sys
def file_name():
file_name = input("Please choose a filename you wish to open/read: ")
return file_name
def file_reader(file_name):
try:
while file_name.find(".") < 0:
file_name += ".txt"
read_mode = "r"
with open(file_name, read_mode) as file:
output = "\n" + file.read() + "\n"
return output
except FileNotFoundError:
print("\nFILE NOT FOUND! Please try again.\n")
print_contents()
except:
error = sys.exc_info()[0]
print("Many apologies! Something has went wrong!")
print(error)
def print_contents():
print(file_reader(file_name()))
while True:
print_contents()
Here, the function "file_reader(file_name)" concatenates ".txt" to the end of the user-specified filename where there is no file extension already specified, then attempts to read from the file.
In the event of a FileNotFoundError exception, this then prompts the user for another input.
However, if the user then enters a valid filename after the exception, the file contents are returned, followed by 'None'.
I am very confused as to why 'None' is returned with the file contents ONLY ONCE after a FileNotFoundError exception has been handled, after which the 'while True' loop seems to work correctly again. How can I prevent 'None from being returned with the user-specified file data after a FileNotFoundError exception was previously handled?
As I am still very new to Python, any other constructive feedback is welcomed.

How to fix error exception to allow for retries without the exception looping in Python

I'm attempting to write error handling in Python 2.7 for when an IOError exception is raised after a user enters a filename.
I have tried a couple of solutions our there on the internet including:
How to retry after exception?
Get a Try statement to loop around until correct value obtained
This is my original code:
while True:
try:
with open (userFile, 'r') as txtFile:
for curLine in txtFile:
curLine = curLine.rstrip("\n\r")
idList.append(curLine)
except IOError:
print("File does not exist")
Whenever the IOError exception is raised it goes into an infinite loop, printing "File does not exist" over and over again. In the instance where I limit the attempts by adding a range, it goes through that range, printing over and over again and then exits the script. Does anyone have an idea why this keeps looping when the exception is raised?
This will be much easier if you split the separate concerns into functions, i.e. (i) warning the user if a file doesn't exist and (ii) reading the contents of the file into a list of lines:
def read_file(f):
# you can't read a file line-by-line and get line endings that match '\n\r'
# the following will match what your code is trying to do, but perhaps not
# what you want to accomplish..?
return f.read().split("\n\r") # are you sure you haven't switched these..?
def checked_read_file(fname):
try:
with open(fname, 'rb') as fp: # you'll probably need binary mode to read \r
return read_file(fp)
except IOError:
print("File does not exist")
return False
then you can write your while loop:
while True:
result = checked_read_file(user_file)
if result is not False: # this is correct since the empty list is false-y
break
user_file = input("Enter another filename: ") # or user_file = raw_input("...: ") if you're on Python 2
# here result is an array of lines from the file

error in while loop combined with try-except

I want to keep asking the user to enter the file name if the input entered is incorrect. I've tested the program with incorrect input (misspelt file name) but instead of asking the user to try again an error message is prompted and the program terminates. The unsuccessful code (part of if) is below. Can anyone help me to detect what's wrong?
import nltk
from nltk.tokenize import word_tokenize
import re
import os
import sys
def main():
while True:
try:
file_to_open = input("insert the file you would like to use with its extension: ")
except FileNotFoundError:
print("File not found.Better try again")
continue
else:
break
with open(file_to_open) as f:
words = word_tokenize(f.read().lower())
with open ('Fr-dictionary2.txt') as fr:
dic = word_tokenize(fr.read().lower())
l=[ ]
errors=[ ]
for n,word in enumerate (words):
l.append(word)
if word == "*":
exp = words[n-1] + words[n+1]
print("\nconcatenation trials:", exp)
if exp in dic:
l.append(exp)
l.append("$")
errors.append(words[n-1])
errors.append(words[n+1])
else:
continue
It's possible to create a Path object even if the path itself does not exist in your filesystem. At some point, you need to ask the Path object if the path inside it exists in the filesystem, before exiting the while loop. You won't need the try/except block doing it like this:
while True:
p = Path(input("please input the path: "))
if p.exists():
break
print("path does not exist, try again")
The problem is that you are "protecting" the while loop where the name is simply asked. You could instead put the reading also inside the try/except to handle the problem:
while True:
try:
file_to_open = input("insert the file you would like to use with its extension: ")
with open(file_to_open) as f:
words = word_tokenize(f.read().lower())
break
except FileNotFoundError:
print("File not found.Better try again")

Open a file with a pre-defined function (with method)

I have a predefined function that I am currently running to check if a file a input is correct. I wish to open this file in my function with the with" operator. This is what I currently have:
def open_file():
'''Checks if the file is correct.'''
grab_file = True #Creates initial variable that checks if file is correct
while grab_file == True: #Loop initiates the check if true
txt = input("Enter a file name: ") #Asks for file input
try:
f = open(txt) #Tries to open the file
return f #File returned as output
grab_file = False #Stops the loop
except: #File is invalid, prompts for retry
print("Error. Please try again.")
def main():
'''Main function that runs through file and does delta calculations.'''
with open(open_file()) as f:
f.readline()
print_headers()
pass
Not sure what exactly is the issue, thanks! Note the second portion of the code is in its own main function and is not part of the open_file function.
The code gives me an error when I try to run the following:
f.readline()
date = f.readline()
print_headers()
This is the error I am getting, the code after the with open statement are just a simple readline(
"TypeError: expected str, bytes or os.PathLike object, not _io.TextIOWrapper"
Your error is a fairly easy fix:
just replace the
with open(open_file()) as f:
with
with open_file() as f:
because you've already opened the file and returned the open file in the open_file() function.
However the print_headers() function doesn't exist in standard python 3.x so I'm not quite sure if this is your own function or a different mistake.

Make python code continue after exception

I'm trying to read all files from a folder that matches a certain criteria. My program crashes once I have an exception raised. I am trying to continue even if there's an exception but it still stops executing.
This is what I get after a couple of seconds.
error <type 'exceptions.IOError'>
Here's my code
import os
path = 'Y:\\Files\\'
listing = os.listdir(path)
try:
for infile in listing:
if infile.startswith("ABC"):
fo = open(infile,"r")
for line in fo:
if line.startswith("REVIEW"):
print infile
fo.close()
except:
print "error "+str(IOError)
pass
Put your try/except structure more in-wards. Otherwise when you get an error, it will break all the loops.
Perhaps after the first for-loop, add the try/except. Then if an error is raised, it will continue with the next file.
for infile in listing:
try:
if infile.startswith("ABC"):
fo = open(infile,"r")
for line in fo:
if line.startswith("REVIEW"):
print infile
fo.close()
except:
pass
This is a perfect example of why you should use a with statement here to open files. When you open the file using open(), but an error is catched, the file will remain open forever. Now is better than never.
for infile in listing:
try:
if infile.startswith("ABC"):
with open(infile,"r") as fo
for line in fo:
if line.startswith("REVIEW"):
print infile
except:
pass
Now if an error is caught, the file will be closed, as that is what the with statement does.
Move the try/except inside the for loop.
Like in:
import os
path = 'C:\\'
listing = os.listdir(path)
for infile in listing:
try:
if infile.startswith("ABC"):
fo = open(infile,"r")
for line in fo:
if line.startswith("REVIEW"):
print infile
fo.close()
except:
print "error "+str(IOError)
You're code is doing exactly what you're telling it to do. When you get an exception, it jumps down to this section:
except:
print "error "+str(IOError)
pass
Since there's nothing after that, the program ends.
Also, that pass is superfluous.
As per strictest interpretation of the question "continue even if there's an exception". Python gives us a keyword "finally" which executes a block of code no matter what precedes it. The only issue with this method will run a block of code regardless of the type of error, which might not be desirable for all cases.
try:
unreal = 3/0 # raises divide by zero exception
print(unreal)
# handles zerodivision exception
except :
print("Can't divide by zero, 0 has no multiplicative inverse")
finally:
# this block is always executed
print("Brahmagupta claimed that “zero divided by a zero is zero.”)

Categories

Resources