Python's "open()" throws different errors for "file not found" - how to handle both exceptions?
Asked Answered
K

4

50

I have a script where a user is prompted to type a filename (of a file that is to be opened), and if the file doesn't exist in the current directory, the user is prompted again. Here is the short version:

file = input("Type filename: ")

...
try:
    fileContent = open(filename, "r")
    ...
except FileNotFoundError:
    ...

When I tested my script on my MacOS X in Python 3.3x it worked perfectly fine when I type the wrong filename on purpose (it executes the suite under "expect").

However, when I wanted to run my code on a Windows computer in Python 3.2x, I get an error that says that "FileNotFoundError" is not defined. So, Python 3.2 on Windows thinks "FileNotFoundError" is a variable and the programs quits with an error.

I figured out that Python 3.2 on Windows throws an "IOError" if the input filename is not valid. I tested it on my Linux machine in Python 2.7, and it's also an IOError.

My problem is now, that the code with

except "FileNotFoundError":

won't run on Windows's Python 3.2, but if I change it to

except "IOError":

it won't work on my Mac anymore.

How could I work around it? The only way I can think of is to use just except, which I usually don't want.

Kelleher answered 22/2, 2013 at 19:48 Comment(1)
This isn't due to Mac/Windows, it's the version of Python. I would investigate 3.2/3.3 on OS X as well (and 3.3 on Windows), consult the change logs, and then revise the question/title as appropriate.Ignatzia
H
79

In 3.3, IOError became an alias for OSError, and FileNotFoundError is a subclass of OSError. So you might try

except (OSError, IOError) as e:
   ...

This will cast a pretty wide net, and you can't assume that the exception is "file not found" without inspecting e.errno, but it may cover your use case.

PEP 3151 discusses the rationale for the change in detail.

Haplite answered 22/2, 2013 at 20:11 Comment(1)
also catches PermissionError - for a catch all error message - print('Error:', e.args[1])Sciamachy
E
9

This strikes me as better than a simple except:, but I'm not sure if it is the best solution:

error_to_catch = getattr(__builtins__,'FileNotFoundError', IOError)

try:
    f = open('.....')
except error_to_catch:
    print('!')
Eradicate answered 22/2, 2013 at 20:13 Comment(3)
In other news except: followed by a comma is grammatically correct, but still seems very odd.Eradicate
That's is also a very nice solution. A little bit longer than except(IOError, OSError): but therefore more specificKelleher
this is a anti pattern.Marc
W
7

So to exactly catch only when a file is not found, I do:

import errno
try:
   open(filename, 'r')
except (OSError, IOError) as e: # FileNotFoundError does not exist on Python < 3.3
   if getattr(e, 'errno', 0) == errno.ENOENT:
      ... # file not found
   raise
Wholesale answered 9/9, 2016 at 14:39 Comment(0)
L
2

you can catch 2 errors at the same time

except (FileNotFoundError, IOError):

I didn't realize that is what you were asking. I hope there is a more eloquent solution then to manually inspect

try:
   error_to_catch = FileNotFoundError
except NameError:
   error_to_catch = IOError

except error_to_catch

cwallenpoole does this conditional more eloquently in his answer (error_to_catch = getattr(__builtins__,'FileNotFoundError', IOError))

Lakisha answered 22/2, 2013 at 19:49 Comment(2)
Will this work where - I get an error that says that "FileNotFoundError" is not defined. So, Python 3.2 on Windows thinks "FileNotFoundError" is a variable and the programs quits with an error - ?Ignatzia
@pst interesting sorry didn't consider itLakisha

© 2022 - 2024 — McMap. All rights reserved.