I am currently using Python 2 on a project that needs a Python 3 built-in exception: FileNotFoundError. How do I do it?
You can of course define any exceptions you want.
But they're not going to do you any good. The whole point of FileNotFoundError is that any Python operation that runs into a file-not-found error will raise that exception. Just defining your own exception won't make that true. All you're going to get is an OSError (or IOError, depending on 2.x version) with an appropriate errno value. If you try to handle a custom FileNotFoundError, your handler will never get called.
So, what you really want is (for example):
try:
f = open(path)
except OSError as e:
if e.errno == errno.ENOENT:
# do your FileNotFoundError code here
else:
raise
You could use IOError instead:
Raised when an I/O operation (such as a print statement, the built-in open() function or a method of a file object) fails for an I/O-related reason, e.g., “file not found” or “disk full”.
This class is derived from EnvironmentError. See the discussion above for more information on exception instance attributes.
Changed in version 2.6: Changed socket.error to use this as a base class.
You can simply create the FileNotFoundError exception yourself:
class FileNotFoundError(OSError):
pass
This new exception class inherits from OSError just like the one in Python 3.x.
Here is a reference on User-defined Exceptions in Python.
Short answer: Just use EnvironmentError and check err.errno == errno.ENOENT for either Python 2 or Python 3.
Long answer:
As other answers have mentioned, FileNotFoundError is new to Python 3.
Python 2 used OSError (or IOError, depending on 2.x version). OSError and IOError both inherit from EnvironmentError.
In Python 3, EnvironmentError is aliased to OSError. FileNotFoundError inherits from OSError, which means that FileNotFoundError can be caught with EnvironmentError, and it shares the same interface as OSError and IOError.
So, good news! This means that there is a relatively easy way to make your project compatible with both Python 2 and Python 3 at the same time: leave FileNotFoundError out of it, and just catch EnvironmentError.
# Works for Python 2. Also works for Python 3.
import errno
try:
open("fake.file", 'r')
except EnvironmentError as err:
if err.errno == errno.ENOENT: # ENOENT -> "no entity" -> "file not found"
print("Caught 'file not found' exception")
else:
raise
Related
I am working with a git repo that is showing syntax error for "except Exception, e:"
I am using Python 2.7.
which python version supports syntax like "except Exception, e"?
except Exception, e
In Python 3.x the syntax is:
except Exception as e:
...
As you can see here the same syntax was used in version 2.7.
except Exception,e:
same syntax with:
except Exception as e:
Its not related with python version, You may look PEP document.
PEP 3110: "Catching Exceptions in Python 3000"
What you are looking for is:
try:
do_sth()
except Exception as ex:
traceback.print_exc()
print(ex.message)
print(ex.args)
I found this piece of code detecting exception within the try block itself when run in python 2.
import sys
for i in range(3):
try:
if sys.exc_info()[1]:
print("Exception found")
else:
print("Exception not found")
raise Exception("Random exception")
except Exception as e:
pass
Output generated by python 2.7.17 -
Exception not found
Exception found
Exception found
When run on python 3, the exception is not detected.
Output generated by python 3.7.7 -
Exception not found
Exception not found
Exception not found
Why does python 2 behave this way? Is there any workaround in python 2 to avoid this behavior?
Wrong exception detection is throwing off my application's logging when run using gunicorn.
Regarding the meaning of "handling an exception" there is a difference between Python 2 and Python 3 in this context. It's best visualized with a diff of the relevant docs entry (Py2 vs. Py3):
So while in Python 3 this definition includes only the exception being currently handled, in Python 2 also the most recently handled exception is included.
What is the difference between ',' and 'as' in except statements, eg:
try:
pass
except Exception, exception:
pass
and:
try:
pass
except Exception as exception:
pass
Is the second syntax legal in 2.6? It works in CPython 2.6 on Windows but the 2.5 interpreter in cygwin complains that it is invalid.
If they are both valid in 2.6 which should I use?
The definitive document is PEP-3110: Catching Exceptions
Summary:
In Python 3.x, using as is required to assign an exception to a variable.
In Python 2.6+, use the as syntax, since it is far less ambiguous and forward compatible with Python 3.x.
In Python 2.5 and earlier, use the comma version, since as isn't supported.
Yes it's legal. I'm running Python 2.6
try:
[] + 3
except Exception as x:
print "woo hoo"
>>>
woo hoo
Update: There is another reason to use the as syntax. Using , makes things a lot more ambiguous, as others have pointed out; and here's what makes the difference. As of Python 2.6, there is multicatch which allows you to catch multiple exceptions in one except block. In such a situation, it's more expressive and pythonic to say
except (exception1, exception2) as e
rather than to say
except (exception1, exception2), e
which would still work
the "as" syntax is the preferred one going forward, however if your code needs to work with older Python versions (2.6 is the first to support the new one) then you'll need to use the comma syntax.
If you want to support all python versions you can use the sys.exc_info() function like this:
try:
a = 1/'0'
except (ZeroDivisionError, TypeError):
e = sys.exc_info()[1]
print(e.args[0])
(source:http://python3porting.com/noconv.html)
As of Python 3.7 (not sure about other versions) the 'comma' syntax is not supported any more:
Source file exception_comma.py:
try:
result = 1/0
except Exception, e:
print("An error occurred")
exit(1)
exit(0)
$ python --version --> Python 2.7.10
$ python exception_comma.py
An error occurred
$ python3 --version --> Python 3.7.2
$ python3 exception_comma.py
File "exception_comma.py", line 3
except Exception, e:
^
SyntaxError: invalid syntax
I am trying to understand exceptions with Python 2.7.6, on Windows 8.
Here's the code I am testing, which aims to create a new directory at My_New_Dir. If the directory already exists, I want to delete the entire directory and its contents, and then create a fresh directory.
import os
dir = 'My_New_Dir'
try:
os.mkdir(dir)
except IOError as e:
print 'exception thrown'
shutil.rmtree(dir)
os.mkdir(dir)
The thing is, the exception is never thrown. The code works fine if the directory does not already exist, but if the directory does exist, then I get the error:
WindowsError: [Error 183] Cannot create a file when that file already exists: 'My_New_Dir'
But according to the Python documentation for os.mkdir(),
If the directory already exists, OSError is raised.
So why is the Windows error being thrown, rather than the Python exception?
WindowsError is a subclass of OSError. From the exceptions documentation:
Raised when a Windows-specific error occurs or when the error number does not correspond to an errno value. The winerror and strerror values are created from the return values of the GetLastError() and FormatMessage() functions from the Windows Platform API. The errno value maps the winerror value to corresponding errno.h values. This is a subclass of OSError.
You are trying to catch IOError however, which is not such a parent class of WindowsError; as a result it won't suffice to catch either OSError nor WindowsError.
Alter your code to use the correct exception here:
try:
os.mkdir(dir)
except OSError as e:
or use WindowsError; this would tie your code to the Windows platform.
You mis-read it. It is "OSError" not "IOError", and WindowsError is a subclasss of "OSError" for your specific working OS.
>>> issubclass(WindowsError, OSError)
True
Besides, for your propose, this API is better:
os.path.isdir(path): Return True if path is an existing directory. This follows symbolic links, so both islink() and isdir() can be true for the same path.
if os.path.isdir(dir):
shutil.rmtree(dir)
os.mkdir(dir)
If you search for "WindowsError" on the exceptions page, you will see that WindowsError is in fact a Python exception. It is a subclass of OSError, so the documentation is still correct. If you change to
try:
os.mkdir(dir)
except OSError as e:
print 'exception thrown'
shutil.rmtree(dir)
os.mkdir(dir)
then you will catch the exception.
Python documentation says that
os.rename(src, dst)
... On Windows, if dst already exists, OSError will be raised even if it is a file ...
However, for me it raises WindowsError. Is there a mistake in the documentation?
The second part of the question (more general, but inspired by the problem formulated above):
UPD I am sorry, the second part of the question was incorrect. WindowsError is indeed catched by except OSError as it should.
Since OSError is a superclass of WindowsError, just catch the OSError.
FWIW, the core devs are free to raise an exception more specific than the minimum promised by the docs.
Also, the following code works fine for me (Python2.7.2 running on WindowsXP):
try:
raise os.rename('nonexisting_file', 'def')
except OSError:
print 'caught'