Question

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.

Was it helpful?

Solution

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.

OTHER TIPS

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('!')

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

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))

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top