UnboundLocalError when I try to open an invalid file name - python

I have written a program that takes a file name and returns numbers and it works as expected when the file name is inputted correctly but when I try to purposely write an incorrect file name, instead of giving me a "error: file not found" from the exception, it will say:
def getFile(fileName):
lines = []
try:
infile = open(fileName, 'r')
if infile != None:
for line in infile:
lines.append(line)
except IOError:
print('Error: file not found.')
finally:
infile.close()
return lines

If an exception is raised by open, the local variable infile is never declared let alone assigned, so the attempt to call infile.close() in the finally block will raise an UnboundLocalError as you see here. You can 'fix' this somewhat by declaring infile with some special uninitialized value (e.g. None) and checking explicitly like so:
def getFile(fileName):
lines = []
infile = None
try:
infile = open(fileName, 'r')
for line in infile:
lines.append(line)
except IOError:
print('Error: file not found.')
finally:
if infile is not None:
infile.close()
return lines
Alternatively, since file objects are context managers, you can write something like:
def getFile(fileName):
lines = []
try:
with open(fileName, 'r') as infile:
for line in infile:
lines.append(line)
except IOError:
print('Error: file not found.')
return lines
... which will ensure infile is closed in a more syntactically concise & structured manner.
Note that on failure open raises an OSError (e.g. a FileNotFoundError) rather than returning None, so your existing check is redundant.
Additionally, an IOError might be raised when iterating over the file rather than opening it initially, so the error message printed may be incorrect in those circumstances.
Lastly, since infile is an iterable, you can iteratively construct a list from it readily using the constructor that accepts an iterable directly like so:
return list(infile)

Related

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

Unable to return the list that is read from a file(.csv)

I have been learning and practicing python and during which
I found one error in my program, but I'm unable to resolve. I want to return list of that is retrieved from a csv file. I tried the below code and it returns me an error.
import csv
def returnTheRowsInTheFile(fileName):
READ = 'r'
listOfRows = []
try:
with open(fileName, READ) as myFile:
listOfRows = csv.reader(myFile)
return listOfRows
except FileNotFoundError:
print('The file ' + fileName + ' is not found')
except:
print('Something went wrong')
finally:
#myFile.close()
print()
def main():
fullString = returnTheRowsInTheFile('ABBREVATIONS.CSV')
for eachRow in fullString:
print(eachRow)
return
main()
And the error is
Traceback (most recent call last): File
"C:\Users\santo\workspace\PyProject\hello\FinalChallenge.py", line 36,
in
main() File "C:\Users\santo\workspace\PyProject\hello\FinalChallenge.py", line 32,
in main
for eachRow in fullString: ValueError: I/O operation on closed file.
The easy way to solve this problem is to return a list from your function. I know you assigned listOfRows = [] but this was overwritten when you did listOfRows = csv.reader(myFile).
So, the easy solution is:
def returnTheRowsInTheFile(fileName):
READ = 'r'
try:
with open(fileName, READ) as myFile:
listOfRows = csv.reader(myFile)
return list(listOfRows) # convert to a list
except FileNotFoundError:
print('The file ' + fileName + ' is not found')
except:
print('Something went wrong')
You should also read pep8 which is the style guide for Python; in order to understand how to name your variables and functions.
When you use with open it closes the file when the context ends. Now listOfRows is of the return type of csv.Reader, and so is then fullString (not a list). You are trying to iterate on it, which seems to iterate over a file object, which is already closed.
As JulienD already pointed the file is alread closed when you try to read the rows from it. You can get rid of this exception using this for example:
with open(fileName, READ) as myFile:
listOfRows = csv.reader(myFile)
for row in listOfRows:
yield row
UPDATE
Btw the way you handle exceptions makes it pretty hard to debug. I'd suggest something like this.
except Exception as e:
print('Something went wrong: "%s"' e)
This way you can at least see the error message.

Why doesn't "try, except" work with classic "open(fname, 'r')" in python?

I have a function that opens a file and returns an opened file object.
def read_any():
try:
opened = gzip.open(fname, 'r')
except IOError:
opened = open(fname, 'r')
return opened
When I attempt to run this function on some non-zipped file except condition does not get triggered and the function crashes with the message: IOError: Not a gzipped file.
Ok, now I try and do the same with with statement:
def read_any2():
try:
with gzip.open(fname, 'r') as f:
return f.read()
except IOError:
with open(fname, 'r') as f:
return f.read()
Now, if I try to run the same file the function works as intended.
Can you explain why doesn't except condition get triggered?
To see what's going on, test it in a REPL:
>>> import gzip
>>> f = gzip.open('some_nongzipped_file', 'r')
You will see that this doesn't raise an error. Once you, however, read from the object:
>>> f.read()
... (snip)
OSError: Not a gzipped file
, it raises the error.
In short: Simply creating the file object doesn't read anything from the file yet, and thus doesn't know if it should fail or not.
Since in the first example you just return the file object, when you try to read from it later it will raise the exception there (outside your raise-except block). In your second example you return f.read() which reads and therefore raises the exception. It has nothing to do with the with block, as you can see if you remove it:
def read_any_mod():
try:
opened = gzip.open(fname, 'r')
return opened.read()
except IOError:
opened = open(fname, 'r')
return opened.read()

Python: Readline returns error after 10 lines

I'm trying to use readline on file in a for loop. The problem is that I start getting I/O errors. It seems that I get I/O error after 10 readlines.
Here is my function:
def getAll():
with open("nodes2.txt", "r+") as f:
for i in range(0, 200):
print "**%s**"%(i)
try:
file = f.readline()
file = file[:-1]
# print "*%s*" % (file)
entities = getAllPagesEntities(file)
# print entities
for en in entities:
try:
dict = getFirmAttributes(en)
printToFile(dict)
except Exception,e:
with open("log_getFirmAttributes.txt","a") as f:
f.write(str(e))
f.write("\n")
except Exception,e:
with open("log_readFile.txt","a") as f:
f.write(str(e))
f.write("\n")
Here is a printed catched exception:
I/O operation on closed file
I think that this problem can't be caused by another used functions so I don't attach them here. I thought that it is caused by the file used but when I try to readline 200 and print them, everything works perfect.
with open("nodes2.txt", "r+") as f:
for i in range(0, 200):
print f.readline()
Have you any idea what could be the problem? Thanks
Following lines in the except block overwrites f causing open file to be closed.
with open("log_readFile.txt","a") as f:
f.write(str(e))
f.write("\n")
Change the name f for the file for appending to another name will solve the problem:
with open("log_readFile.txt", "a") as logf:
logf.write(str(e))
logf.write("\n")

Error handling but still getting a ValueError

I am trying to solve this challenge about error-handling. Maybe I'm way off!
The challenge description:
Write a function called "load_file" that accepts one parameter: a filename. The function should open the file and return the contents.
If the contents of the file can be interpreted as an integer, return the contents as an integer. Otherwise, if the contents of the file can be interpreted as a float, return the contents as a float. Otherwise, return the contents of the file as a string.
You may assume that the file has only one line.
I get ValueError: could not convert string to float: "b>a!\{\'"
Am I all wrong about the error-handling?
def load_file(file):
file = open(file, "r")
all_lines = file.read()
try:
return int(all_lines)
except ValueError:
return float(all_lines)
else:
return all_lines
file.close()
You need to do something like
with open(file, "r") as file_handle:
all_lines = file.read()
try:
return int(all_lines)
except ValueError:
pass
try:
return float(all_lines)
except ValueError:
pass
return all_lines
The point is you don't really care about the errors at all, because they just mean you need to proceed to the next option.
I would also point out that the with construct takes care of closing the file for you. If you want to do file = open(file, "r") then you will need to store your return value to a variable, and then do file.close() before you return.
You handle the ValueError thrown by using the int() function, but there's the possibility of float() also throwing such an error. The purpose of the try/catch structure is for running code inside the try block that may throw any exception, such as a ValueError, and to execute "error handler" code inside the except block.
when you try to parse as a float there is also an exception. you can try something like this
def load_file(file):
file = open(file, "r")
all_lines = file.read()
try:
return int(all_lines)
except ValueError:
try:
return float(all_lines)
except ValueError:
return all_lines
file.close()
You can nest trys inside of exceptions to get it to do what you want
The problem with your approach is that the float(all_lines) can fail but that exception isn't handled.
So it should be:
try:
return int(all_lines)
except ValueError: # handle the exception if it's not an integer
try:
return float(all_lines)
except ValueError: # handle the exception if it's not a float
return all_lines
But you could also just suppress errors (requires python 3.3 or newer though). This could reduce the length of the code and the number of nested try and excepts:
from contextlib import suppress
def load_file(file):
with open(file, "r") as file: # using open with "with" closes the file automatically.
all_lines = file.read()
with suppress(ValueError):
return int(all_lines)
with suppress(ValueError):
return float(all_lines)
return all_lines

Categories

Resources