How to implement Exception handing for both Python 2 and 3? - python

Python 3 changed the syntax of catching Exceptions. How can I make my script compatible for both versions? I know the way to detect Python version but do I need to use If-else check and repeat entire try-catch block?

Python 2.6 and 2.7 support the new except Exception as e: syntax, just like Python 3.
If you're unfortunate enough to use long-dead Python 2 versions 2.5, or even (gasp) 2.4, it is still "possible", but you must resort to some awful hacks like
>>> import sys
>>> try:
... 1/0
... except ZeroDivisionError:
... e = sys.exc_info()[1]
... # process e
... del e

Related

Python 2 detects exception outside except block but not Python 3

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.

Python invalid syntax for try/except

I'm trying to create an exception based on whether or not a file has been removed:
def remove_file():
print("Removing the output file: ", output_file)
try:
os.remove(output_file)
except RemoveFileError,e:
remove_stat = e.returncode
if remove_stat == 0:
print("File Removed!")
But I'm getting the following error:
File ".\aws_ec2_list_instances.py", line 198
except RemoveFileError,e:
^
SyntaxError: invalid syntax
I thought I could call the exception whatever I wanted. Is that not the case? How can I write this correctly?
Which version of Python are you using? Because the syntax has changed between Python 2 and Python 3.
In Python 2, it's (mostly) except Exception, var: where it is except Exception as var: in Python 3.
Notice that Python 3 syntax was backported to Python 2.6 and 2.7, so it is not unusual to see except Exception as var in those versions (and this should be preferred if you want this specific piece of code to work on both Python 2.6+ and 3+).

except Exception, ex: ^ SyntaxError: invalid syntax [duplicate]

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

How do I import FileNotFoundError from Python 3?

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

Python try...except comma vs 'as' in except

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

Categories