How to catch a default error as something? - python

Then using try catch in python you can catch errors and assign them to a variable with the as keyword
try
do something..
except IOError as e:
do something with e..
However then trying to do the same thing without knowing the type of error python complains about the syntax.
try
do something..
except as e:
do something with e..
Is there any way to catch a default error and assign it to a variable?

Yes there is. All exceptions derive from the Exception class.
So you can do:
try:
doSomething()
except Exception as e:
doSomethingWithException(e)
It is a kind of catch-all line.

You can also use sys.exc_info(). This allows you to handle exceptions on Python 2.x and Python 3.x with the same code.

The conventional manner is:
try:
do_whatever()
except Exception as e:
handle_it()
Although it's ill-advised to catch such broad excepts - it's preferable to catch specific exceptions you know you can handle and let anything else propogate.
It's worth noting that KeyboardInterrupt and SystemExit inherit from BaseException and not Exception, so these wouldn't be caught were you expecting to cater for those, but that shouldn't be a problem as they should be handled at the top level anyway.

Related

Python: How to catch a list of exceptions? [duplicate]

I know that I can do:
try:
# do something that may fail
except:
# do this if ANYTHING goes wrong
I can also do this:
try:
# do something that may fail
except IDontLikeYouException:
# say please
except YouAreTooShortException:
# stand on a ladder
But if I want to do the same thing inside two different exceptions, the best I can think of right now is to do this:
try:
# do something that may fail
except IDontLikeYouException:
# say please
except YouAreBeingMeanException:
# say please
Is there any way that I can do something like this (since the action to take in both exceptions is to say please):
try:
# do something that may fail
except IDontLikeYouException, YouAreBeingMeanException:
# say please
Now this really won't work, as it matches the syntax for:
try:
# do something that may fail
except Exception, e:
# say please
So, my effort to catch the two distinct exceptions doesn't exactly come through.
Is there a way to do this?
From Python Documentation:
An except clause may name multiple exceptions as a parenthesized tuple, for example
except (IDontLikeYouException, YouAreBeingMeanException) as e:
pass
Or, for Python 2 only:
except (IDontLikeYouException, YouAreBeingMeanException), e:
pass
Separating the exception from the variable with a comma will still work in Python 2.6 and 2.7, but is now deprecated and does not work in Python 3; now you should be using as.
How do I catch multiple exceptions in one line (except block)
Do this:
try:
may_raise_specific_errors():
except (SpecificErrorOne, SpecificErrorTwo) as error:
handle(error) # might log or have some other default behavior...
The parentheses are required due to older syntax that used the commas to assign the error object to a name. The as keyword is used for the assignment. You can use any name for the error object, I prefer error personally.
Best Practice
To do this in a manner currently and forward compatible with Python, you need to separate the Exceptions with commas and wrap them with parentheses to differentiate from earlier syntax that assigned the exception instance to a variable name by following the Exception type to be caught with a comma.
Here's an example of simple usage:
import sys
try:
mainstuff()
except (KeyboardInterrupt, EOFError): # the parens are necessary
sys.exit(0)
I'm specifying only these exceptions to avoid hiding bugs, which if I encounter I expect the full stack trace from.
This is documented here: https://docs.python.org/tutorial/errors.html
You can assign the exception to a variable, (e is common, but you might prefer a more verbose variable if you have long exception handling or your IDE only highlights selections larger than that, as mine does.) The instance has an args attribute. Here is an example:
import sys
try:
mainstuff()
except (KeyboardInterrupt, EOFError) as err:
print(err)
print(err.args)
sys.exit(0)
Note that in Python 3, the err object falls out of scope when the except block is concluded.
Deprecated
You may see code that assigns the error with a comma. This usage, the only form available in Python 2.5 and earlier, is deprecated, and if you wish your code to be forward compatible in Python 3, you should update the syntax to use the new form:
import sys
try:
mainstuff()
except (KeyboardInterrupt, EOFError), err: # don't do this in Python 2.6+
print err
print err.args
sys.exit(0)
If you see the comma name assignment in your codebase, and you're using Python 2.5 or higher, switch to the new way of doing it so your code remains compatible when you upgrade.
The suppress context manager
The accepted answer is really 4 lines of code, minimum:
try:
do_something()
except (IDontLikeYouException, YouAreBeingMeanException) as e:
pass
The try, except, pass lines can be handled in a single line with the suppress context manager, available in Python 3.4:
from contextlib import suppress
with suppress(IDontLikeYouException, YouAreBeingMeanException):
do_something()
So when you want to pass on certain exceptions, use suppress.
From Python documentation -> 8.3 Handling Exceptions:
A try statement may have more than one except clause, to specify
handlers for different exceptions. At most one handler will be
executed. Handlers only handle exceptions that occur in the
corresponding try clause, not in other handlers of the same try
statement. An except clause may name multiple exceptions as a
parenthesized tuple, for example:
except (RuntimeError, TypeError, NameError):
pass
Note that the parentheses around this tuple are required, because
except ValueError, e: was the syntax used for what is normally
written as except ValueError as e: in modern Python (described
below). The old syntax is still supported for backwards compatibility.
This means except RuntimeError, TypeError is not equivalent to
except (RuntimeError, TypeError): but to except RuntimeError as
TypeError: which is not what you want.
If you frequently use a large number of exceptions, you can pre-define a tuple, so you don't have to re-type them many times.
#This example code is a technique I use in a library that connects with websites to gather data
ConnectErrs = (URLError, SSLError, SocketTimeoutError, BadStatusLine, ConnectionResetError)
def connect(url, data):
#do connection and return some data
return(received_data)
def some_function(var_a, var_b, ...):
try: o = connect(url, data)
except ConnectErrs as e:
#do the recovery stuff
blah #do normal stuff you would do if no exception occurred
NOTES:
If you, also, need to catch other exceptions than those in the
pre-defined tuple, you will need to define another except block.
If you just cannot tolerate a global variable, define it in main()
and pass it around where needed...
One of the way to do this is..
try:
You do your operations here;
......................
except(Exception1[, Exception2[,...ExceptionN]]]):
If there is any exception from the given exception list,
then execute this block.
......................
else:
If there is no exception then execute this block.
and another way is to create method which performs task executed by except block and call it through all of the except block that you write..
try:
You do your operations here;
......................
except Exception1:
functionname(parameterList)
except Exception2:
functionname(parameterList)
except Exception3:
functionname(parameterList)
else:
If there is no exception then execute this block.
def functionname( parameters ):
//your task..
return [expression]
I know that second one is not the best way to do this, but i'm just showing number of ways to do this thing.
As of Python 3.11 you can take advantage of the except* clause that is used to handle multiple exceptions.
PEP-654 introduced a new standard exception type called ExceptionGroup that corresponds to a group of exceptions that are being propagated together. The ExceptionGroup can be handled using a new except* syntax. The * symbol indicates that multiple exceptions can be handled by each except* clause.
For example, you can handle multiple exceptions
try:
raise ExceptionGroup('Example ExceptionGroup', (
TypeError('Example TypeError'),
ValueError('Example ValueError'),
KeyError('Example KeyError'),
AttributeError('Example AttributeError')
))
except* TypeError:
...
except* ValueError as e:
...
except* (KeyError, AttributeError) as e:
...
For more details see PEP-654.

Python - Raising custom exception

What will be the proper way to raise an exception and let the user know that it was raised from my_module, even if its a common python exception, like a ValueError:
#my_module.exceptions.py
class MyModuleError(Exception):
pass
#my_module.do_something.py
def do_something(*args):
try:
some logic here
except Exception as e:
# i dont know in advance what kinds of exceptions
# this code might throw
raise MyModuleError('An error ocurred %s' % (repr(e))
I would like the user to know that the exception was trown inside of my module, even tho it was a general python Exception.
Edit1: sorry, i should´ve explained better:
Even tho i dont know what kind of exceptions the code above might throw, i´d like the user to know that it was an error originated from my_module.
Is this even best practice?
How should i handle unexpected exceptions inside custom modules?
You can do the following:
#...
raise ValueError('This exception was raised from myModule')
#....

In Python is there any reason to use try/except if errors are just going to be re-raised?

Is there any best practice, stylistic or programmatic reason to catch StandardErrors if I'm just going to re-raise them?
In other words, is it better for any reason to do this:
try:
do_something()
except StandardError:
raise
Instead of just this:
do_something()
I see this question Does a exception with just a raise have any use? which says that this is often used when some errors are pass and others are raise which I understand; and it suggests that the former is more useful for documentation (?) and as placeholders for future, which are both human-level reasons.
I'm just wondering if there's any lower-level answer, or even just which would be considered more Pythonic?
If you want to log your errors (for example) you can do this:
try:
do_something()
except StandardError as ex:
print(ex)
raise
And just
try:
do_something()
except StandardError:
raise
explicitly shows that you know about possible exception but don't want to catch it.

A case for catching a generic Exception in Python?

There is a simple scenario that I seem to encounter quite often: I invoke a function that can raise any number of exceptions. I won't do anything different if it is one exception versus another, I just want to log the exception information and either re-raise the exception or indicate in some other way that something didn't go as planned (such as returning None), otherwise proceed normally. So I use some form of the exception handling shown below.
Please note:
Imagine his code is running in a daemon that processes messages, so it needs to keep running, even if one of the messages causes some kind of exception.
I am aware that there is a rule of thumb that it is not generally advisable to catch a generic Exception because that may hide specfic errors that should be handled differently. (This is true in other languages as well.) This case is different because I don't care what exception is raised, the handling is the same.
Is there a better way?
def my_func(p1):
retval = None
try:
valx = other_func1(p1)
except Exception as ex:
log.error('other_func1 failed. {}: {}'.format(type(ex).__name__, ex))
else:
retval = ...
return retval
Is there a better way?
Doubt it, Python has these built-in Base Exception Classes so creating something on your own is really just being redundant. If you handle everything in the same way, generalizing in your except with Exception is most likely the best way to tackle this.
Small caveat here: Exception isn't the most general you can get, from the documentation:
All built-in, non-system-exiting exceptions are derived from this class. All user-defined exceptions should also be derived from this class.
So, it won't catch all exceptions:
In [4]: try:
...: raise SystemExit
...: except Exception as b:
...: print("Catch All")
To exit: use 'exit', 'quit', or Ctrl-D.
An exception has occurred, use %tb to see the full traceback.
SystemExit
Which, do note, is of course something you should want. A SystemExit should exit. But, if some edge case requires it, to also catch system-exiting exceptions you can use BaseException which is as loose as you can get with exception matching:
In [2]: try:
...: raise SystemExit
...: except BaseException as b:
...: print("Catch All")
Catch All
Use it at your own discretion but, it probably makes zero sense to actually use it, and this case does not seem to require it. I just mentioned it because it is the most general you can get. I believe the way you have done it is more than sufficient.
That looks like a fine way to catch them if you're handling them all the same way. If you want to check what kind of exception was raised, you can use the built-in function type and compare the result to an exception class (for example, one from the list of built-in exception types):
try:
f()
except Exception as ex:
if type(ex)==ValueError:
handle_valueerror()
else:
handle_other_exception()
If you're handling them differently, use except <SpecificExceptionClass>. I'm not sure what I was thinking before.

Does `try... except Exception as e` catch every possible exception?

In Python 2, are all exceptions that can be raised required to inherit from Exception?
That is, is the following sufficient to catch any possible exception:
try:
code()
except Exception as e:
pass
or do I need something even more general like
try:
code()
except:
pass
With the first variant you'll catch "all built-in, non-system-exiting exceptions" (https://docs.python.org/2/library/exceptions.html), and should catch user defined exceptions ("all user-defined exceptions should also be derived from this class").
For example, the first variant will not catch user-pressed Control-C (KeyboardInterrupt), but the second will.

Categories

Resources