I have a try block case in my code and I want to ignore one particular exception and all the rest should be raised.
For example:
try:
blah
except <exception> as e:
raise Exception(e)
In this kind of case, I want all the exceptions to be raised except for one case, say if the exception is "query not found" I have to ignore it.
How do I ignore that single exception?
I can use multiple except blocks but how to define a exception?
You can give something like this:
try:
print(x)
except NameError:
print("Variable x is not defined")
except:
print("Something else went wrong")
In this case, you want to catch NameError and specify a message. For all others, you want to specify another message.
Let's say you want to ignore NameError, then you can just give continue or pass.
Alternatively, you can also raise an exception.
Example will be:
x = -1
if x < 0:
raise Exception("Sorry, no numbers below zero")
So you can use a combination of all this to get you what you want.
If you want more details on exception, see the below links:
https://docs.python.org/3/tutorial/errors.html
https://www.w3schools.com/python/python_try_except.asp
https://realpython.com/python-exceptions/
And on stack overflow (as Gino highlighted), see
Handling all but one exception
As an alternative to #Joe Ferndz's answer, in case you don't want the exception to be raised but still want the block to exit, you can use suppress from the contextlib module:
from contextlib import suppress
with suppress(ValueError):
print('hello world')
raise ValueError
print('this will not be printed')
In this case, the block still exits on raise ValueError, but an exception is not raised.
Related
Recently I met an example of code I've never seen before:
try:
# a simple bunch of code
if sample == 0:
return True
else:
raise ExampleError()
except not ExampleError:
raise AnotherExampleError()
How does it work (if it works at all)?
EDIT: The answer below was for Python 3, I didn't realise the question related to Python 2.7. in Python 2, as it seems, the interpreter does not complain if the expression after except does not result in a subtype of BaseException. However, the behavior is still wrong, it will just ignore that except block in all cases.
That's a funny construction that is syntactically valid but semantically wrong. I suppose the author of the code meant to express something like "run this except block for any exception type but ExampleError". However, what is really happening is more like:
try:
# ...
except (not bool(ExampleError)):
# ...
When an exception is raised in the try block, Python goes through the different except blocks looking for one that matches the exception type. When it sees except not ExampleError, equivalent to except (not bool(ExampleError)), it results in except False, which is invalid because False is not a subtype of BaseException (or a tuple of subtypes of BaseException). So the code may even run if no exceptions are raised but is wrong.
This is not going to be successful on any version of Python as far as I know. Because the not operator always results in a Boolean value (True or False) this is trying to catch one of those values here, in this case False. Since you can't throw True or False there's no use for this.
I think the intent of the author was something like this:
try:
raise ExampleError()
except ExampleError e:
throw e
except:
raise AnotherExampleError()
A quick test shows that the code will throw a TypeError if it reaches that line:
try:
raise BaseException
except not BaseException:
print("Test1")
except BaseException:
print("Test2")
Exception:
During handling of the above exception, another exception occurred:
Traceback (most recent call last): File "main.py", line 3, in
except not BaseException: TypeError: catching classes that do not inherit from BaseException is not allowed
In Python's try, except blocks, why does else need to exist if I can just use an except: without a specifier?
It seems like your understanding of how try, except, else, and finally is off.
Here's a summary of how they all work together, from looking at https://docs.python.org/2/tutorial/errors.html:
try:
#Try something that might raise an exception
except <exception specifier>:
#Code here will only run if the exception that came up was the one specified
except:
#Except clause without specifier will catch all exceptions
else:
#Executed if try clause doesn't raise exception
#You can only have this else here if you also have except blocks
finally:
#Runs no matter what
I have this kind of code:
try:
return make_success_result()
except FirstException:
handle_first_exception()
return make_error_result()
except SecondException:
handle_second_exception()
return make_error_result()
And I'm wondering is there any way I can achieve this:
try:
# do something
except Error1:
# do Error1 specific handling
except Error2:
# do Error2 specific handling
else:
# do this if there was no exception
????:
# ALSO do this if there was ANY of the listed exceptions (e.g. some common error handling)
So the code is executed in one of following sequences:
try > else > finally
try > except > ???? > finally
EDIT: my point here is that ???? block should execute right after ANY of the except blocks, meaning that it's an addition to error handling, not a substitution.
What I would do in that case is to set a boolean when you get an exception, like so:
got_exception = False
try:
# do something
except Error1:
# do Error1 specific handling
got_exception = True
except Error2:
# do Error2 specific handling
got_exception = True
else:
# If there was no exception
finally:
if got_exception:
# ALSO do this if there was ANY exception (e.g. some common error handling)
This should fit your needs, which is IMO the cleanest way of combining all of the solutions which have been presented into the most readable code structure that's going to be the easiest to debug.
You can actually do this:
try:
print 'try'
# 1/0
# {}[1]
# {}.a
except AttributeError, KeyError: # only handle these exceptions..
try:
raise # re-raise the exception so we can add a finally-clause executing iff there was an exception.
except AttributeError:
print 'attrerr'
# raise ... # any raises here will also execute 'common'
except KeyError:
print 'keyerror'
finally: # update 0: you wanted the common code after the exceptions..
print "common"
else:
print 'no exception'
but it is horrid and I would not suggest that you do without copious amounts of comments describing why..
UPDATE: you don't need to catch anything but the interesting exceptions in the inner try-block. Code updated.
UPDATE2: per OP's clarification, common should just be executed when an interesting exception is thrown. Code updated. #MattTaylor's version is definitely the way to go ;-)
Yes, exception handling in python includes both an else and a finally clause. You can do this:
try:
# do something
except Error1:
# do Error1 specific handling
except Error2:
# do Error2 specific handling
else:
# do this if there was no exception
finally:
# Do this in any case!
The python docs mention these blocks, even though it doesn't show the full example you need.
EDIT:
I see that you do not ask specifically for the clean-up in the general case. Python docs put it this way:
The try statement has another optional clause which is intended to define clean-up actions that must be executed under all circumstances.
Note that the finally will run whether there was an exception or not. Combined with the else block, you should still be able to do what you want.
You could trap all errors and check for its type in the error handling code like this:
try:
# do something
except Exception as e:
if isinstance(e, Error1):
# do Error1 specific handling
elif isinstance(e, Error2):
# do Error2 specific handling
else:
# do non-Error1/Error2 handling
# ALSO do this if there was ANY exception (e.g. some common error handling)
else:
# do this if there was no exception
I have a list of functions that may fail and, if one fails, I don't want the script to stop, but to continue with next function.
I am executing it with something like this :
list_of_functions = [f_a, f_b, f_c]
for current_function in list_of_functions:
try:
current_function()
except Exception:
print(traceback.format_exc())
It's working fine, but it is not PEP8 compliant:
When catching exceptions, mention specific exceptions whenever
possible instead of using a bare except: clause.
For example, use:
try:
import platform_specific_module
except ImportError:
platform_specific_module = None
A bare except: clause will catch SystemExit and KeyboardInterrupt
exceptions, making it harder to interrupt a program with Control-C,
and can disguise other problems. If you want to catch all exceptions
that signal program errors, use except Exception: (bare except is
equivalent to except BaseException: ).
A good rule of thumb is to limit use of bare 'except' clauses to two
cases:
If the exception handler will be printing out or logging the traceback; at least the user will be aware that an error has occurred.
If the code needs to do some cleanup work, but then lets the exception propagate upwards with raise . try...finally can be a better
way to handle this case.
How can I do this the good way?
The PEP8 guide you quote suggests that it is okay to use a bare exception in your case provided you are logging the errors. I would think that you should cover as many exceptions as you can/know how to deal with and then log the rest and pass, e.g.
import logging
list_of_functions = [f_a,f_b,f_c]
for current_function in list_of_functions:
try:
current_function()
except KnownException:
raise
except Exception as e:
logging.exception(e)
Use this to cheat PEP8:
try:
"""code"""
except (Exception,):
pass
I think in some rare cases catching general exception is just justified and there is a way to trick PEP8 inspection:
list_of_functions = [f_a,f_b,f_c]
for current_function in list_of_functions:
try:
current_function()
except (ValueError, Exception):
print(traceback.format_exc())
You can replace ValueError by any other. It works for me (at least in PyCharm).
You can just put a comment like except Exception as error: # pylint: disable=broad-except that's worked for me actually. I hope it could be work for you.
From issue PY-9715 on yourtrack.jetbrains.com:
From pep-0348:
BaseException
The superclass that all exceptions must inherit from. It's name was
chosen to reflect that it is at the base of the exception hierarchy
while being an exception itself. "Raisable" was considered as a name,
it was passed on because its name did not properly reflect the fact
that it is an exception itself.
Direct inheritance of BaseException is not expected, and will be
discouraged for the general case. Most user-defined exceptions should
inherit from Exception instead. This allows catching Exception to
continue to work in the common case of catching all exceptions that
should be caught. Direct inheritance of BaseException should only be
done in cases where an entirely new category of exception is desired.
But, for cases where all exceptions should be caught blindly, except
BaseException will work.
You can avoid the error if you then re-raise the Exception. This way you are able to do damage control and not endanger loosing track of its occurance.
Do you perhaps mean that each function can raise different exceptions? When you name the exception type in the except clause it can be any name that refers to an exception, not just the class name.
eg.
def raise_value_error():
raise ValueError
def raise_type_error():
raise TypeError
def raise_index_error():
doesnt_exist
func_and_exceptions = [(raise_value_error, ValueError), (raise_type_error, TypeError),
(raise_index_error, IndexError)]
for function, possible_exception in func_and_exceptions:
try:
function()
except possible_exception as e:
print("caught", repr(e), "when calling", function.__name__)
prints:
caught ValueError() when calling raise_value_error
caught TypeError() when calling raise_type_error
Traceback (most recent call last):
File "run.py", line 14, in <module>
function()
File "run.py", line 8, in raise_index_error
doesnt_exist
NameError: name 'doesnt_exist' is not defined
Of course that leaves you with not knowing what to do when each exception occurs. But since you just want to ignore it and carry on then that's not a problem.
First, generate the pylintrc using the below command
pylint --generate-rcfile > .pylintrc
For reference:
https://learn.microsoft.com/en-us/visualstudio/python/linting-python-code?view=vs-2022
Search for disable (uncomment if needed) in the generate pylintrc file and add the below exception.
broad-except
Rerun the pylint command and see the magic
zip_file_name = "not_exist.py"
try:
with zipfile.ZipFile(zip_file_name) as f_handle:
print("open it successfully")
except (zipfile.BadZipfile, zipfile.LargeZipFile), e:
print(e)
Is this the correct way to handle exception throw by a with statement?
Yes, this is how you would want to handle exceptions from inside a with statement. ContextManagers (that implement the behavior behind the with statement) can handle exceptions but should only do so to properly clean up resources used by the object.
Here's a snippet from the relevant documentation:
If BLOCK raises an exception, the context manager’s exit() method
is called with three arguments, the exception details (type, value,
traceback, the same values returned by sys.exc_info(), which can also
be None if no exception occurred). The method’s return value controls
whether an exception is re-raised: any false value re-raises the
exception, and True will result in suppressing it. You’ll only rarely
want to suppress the exception, because if you do the author of the
code containing the ‘with‘ statement will never realize anything went
wrong.
Yes, that's fine.
Another alternative is:
try:
f_handle = zipfile.ZipFile(zip_file_name)
# no more code here
except (zipfile.BadZipfile, zipfile.LargeZipFile), e:
print(e)
else:
with f_handle:
print("open it successfully")
This prevents you from accidentally catching an exception from the body of the with statement in your except handler.