I want to pause a python script when Crtl+C is pressed but to handle the rest of exceptions with different code.
If I got:
except KeyboardInterrupt:
print '\nPausing... (Hit ENTER to continue, type quit to exit.)'
try:
response = raw_input()
if response == 'quit':
break
print 'Resuming...'
except KeyboardInterrupt:
print 'Resuming...'
continue
except Exception, e:
print traceback.print_exc()
continue
sleep(170)
Won't second except go also for KeyboardInterrupt, isn't a keyboard interrupt supposed to be an exception?
Won't second except go also for KeyboardInterrupt, isn't a keyboard interrupt supposed to be an exception?
Well, this is interesting... Apparently it is not a subclass of the Exception class, but is child to a superclass called BaseException.
Python's doc Built-in Exceptions explains why they implemented it this way:
The exception inherits from BaseException so as to not be accidentally caught by code that catches Exception and thus prevent the interpreter from exiting.
And it can be checked like this:
>>> issubclass(KeyboardInterrupt, Exception)
False
>>> issubclass(KeyboardInterrupt, BaseException)
True
>>> issubclass(Exception, BaseException)
True
Nevertheless, even if you changed your last except block to catch a BaseException instead of a Exception, it would still not enter it (because your inner except KeyboardInterrupt avoids the exception to be thrown to the outer indentation or "parent" levels).
In case you also removed this inner except KeyboardInterrupt block, the exception would be thrown to the outer indentation, which I assume it does not exist (given your indentation level) and the execution would terminate...
Related
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.
I write a server which handles events and uncaught exceptions during handling the event must not terminate the server.
The server is a single non-threaded python process.
I want to terminate on these errors types:
KeyboardInterrupt
MemoryError
...
The list of built in exceptions is long: https://docs.python.org/2/library/exceptions.html
I don't want to re-invent this exception handling, since I guess it was done several times before.
How to proceed?
Have a white-list: A list of exceptions which are ok and processing the next event is the right choice
Have a black-list: A list of exceptions which indicate that terminating the server is the right choice.
Hint: This question is not about running a unix daemon in background. It is not about double fork and not about redirecting stdin/stdout :-)
I would do this in a similar way you're thinking of, using the 'you shall not pass' Gandalf exception handler except Exception to catch all non-system-exiting exceptions while creating a black-listed set of exceptions that should pass and end be re-raised.
Using the Gandalf handler will make sure GeneratorExit, SystemExit and KeyboardInterrupt (all system-exiting exceptions) pass and terminate the program if no other handlers are present higher in the call stack. Here is where you can check with type(e) that a __class__ of a caught exception e actually belongs in the set of black-listed exceptions and re-raise it.
As a small demonstration:
import exceptions # Py2.x only
# dictionary holding {exception_name: exception_class}
excptDict = vars(exceptions)
exceptionNames = ['MemoryError', 'OSError', 'SystemError'] # and others
# set containing black-listed exceptions
blackSet = {excptDict[exception] for exception in exceptionNames}
Now blackSet = {OSError, SystemError, MemoryError} holding the classes of the non-system-exiting exceptions we want to not handle.
A try-except block can now look like this:
try:
# calls that raise exceptions:
except Exception as e:
if type(e) in blackSet: raise e # re-raise
# else just handle it
An example which catches all exceptions using BaseException can help illustrate what I mean. (this is done for demonstration purposes only, in order to see how this raising will eventually terminate your program). Do note: I'm not suggesting you use BaseException; I'm using it in order to demonstrate what exception will actually 'pass through' and cause termination (i.e everything that BaseException catches):
for i, j in excptDict.iteritems():
if i.startswith('__'): continue # __doc__ and other dunders
try:
try:
raise j
except Exception as ex:
# print "Handler 'Exception' caught " + str(i)
if type(ex) in blackSet:
raise ex
except BaseException:
print "Handler 'BaseException' caught " + str(i)
# prints exceptions that would cause the system to exit
Handler 'BaseException' caught GeneratorExit
Handler 'BaseException' caught OSError
Handler 'BaseException' caught SystemExit
Handler 'BaseException' caught SystemError
Handler 'BaseException' caught KeyboardInterrupt
Handler 'BaseException' caught MemoryError
Handler 'BaseException' caught BaseException
Finally, in order to make this Python 2/3 agnostic, you can try and import exceptions and if that fails (which it does in Python 3), fall-back to importing builtins which contains all Exceptions; we search the dictionary by name so it makes no difference:
try:
import exceptions
excDict = vars(exceptions)
except ImportError:
import builtins
excDict = vars(builtins)
I don't know if there's a smarter way to actually do this, another solution might be instead of having a try-except with a signle except, having 2 handlers, one for the black-listed exceptions and the other for the general case:
try:
# calls that raise exceptions:
except tuple(blackSet) as be: # Must go first, of course.
raise be
except Exception as e:
# handle the rest
The top-most exception is BaseException. There are two groups under that:
Exception derived
everything else
Things like Stopiteration, ValueError, TypeError, etc., are all examples of Exception.
Things like GeneratorExit, SystemExit and KeyboardInterrupt are not descended from Execption.
So the first step is to catch Exception and not BaseException which will allow you to easily terminate the program. I recommend also catching GeneratorExit as 1) it should never actually be seen unless it is raised manually; 2) you can log it and restart the loop; and 3) it is intended to signal a generator has exited and can be cleaned up, not that the program should exit.
The next step is to log each exception with enough detail that you have the possibility of figuring out what went wrong (when you later get around to debugging).
Finally, you have to decide for yourself which, if any, of the Exception derived exceptions you want to terminate on: I would suggest RuntimeError and MemoryError, although you may be able to get around those by simply stopping and restarting your server loop.
So, really, it's up to you.
If there is some other error (such as IOError when trying to load a config file) that is serious enough to quit on, then the code responsible for loading the config file should be smart enough to catch that IOError and raise SystemExit instead.
As far as whitelist/blacklist -- use a black list, as there should only be a handful, if any, Exception-based exceptions that you need to actually terminate the server on.
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
These days I am learning Python's Exception handling features deeply. I encountered exception SystemExit. While reading about this from official Python Docs I got question in mind that what exactly would have happen when I terminate Python script by pressing Ctrl+c?
lets take this sample code:
def func1(a,b):
print "func1: "+str(a/b)
#some more functions
def func2(a,b):
print "func2: "+str(a/b)
#some more functions
if __name__=="__main__":
import random
count=0
for i in range(1000000):
count=count+1
print "count: "+str(count)
try:
func1(random.randint(-2,3),random.randint(-2,3))
except KeyboardInterrupt:
raise
except:
print "error in func1"
try:
func2(random.randint(-2,3),random.randint(-2,3))
except KeyboardInterrupt:
raise
except:
print "error in func2"
print "\n"
In this sample code I am catching KeyboardInterrupt so I can stop my script by pressing Ctrl+c. Should I catch SystemExit too to make this code more mature? if yes then why? actually this question is source of my main question which appear on title. so don't consider that I am asking two different question in one post.
You usually not need to catch SystemExit as it is what makes exit() and sys.exit() functions work:
sys.exit([arg])
Exit from Python. This is implemented by raising the SystemExit exception, so cleanup actions specified by finally clauses of try statements are honored, and it is possible to intercept the exit attempt at an outer level.
Example:
try:
exit()
except SystemExit:
print "caught"
Therefore, you usually don't want to catch all exceptions in the first place (by using an empty except: clause). The best approach is generally to make your exception handlers as specific as possible. It otherwise makes debugging your application exceptionally hard, as it either hides errors entirely or at least makes it hard to diagnose the details.
The only exception your functions can raise is a ZeroDivisionError, so you should only catch that one:
import random
if __name__ == "__main__":
for count in range(1000000):
print "count:", count
try:
func1(random.randint(-2, 3),random.randint(-2, 3))
except ZeroDivisionError:
print "error in func1"
try:
func2(random.randint(-2, 3),random.randint(-2, 3))
except ZeroDivisionError:
print "error in func2"
print "\n"
Your title says something different than the body of your question.
To the title:
What happens internally is that python captures the SIGINT and raises a KeyboardInterrupt exception from it.
To the text:
You don't want to do except:.
Instead, you want
if __name__=="__main__":
try:
import random
count=0
for i in range(1000000):
count=count+1
print "count: "+str(count)
try:
func1(random.randint(-2,3),random.randint(-2,3))
except Exception, e:
print "error in func1", e # or something...
try:
func2(random.randint(-2,3),random.randint(-2,3))
except Exception, e:
print "error in func2", e # or something...
print "\n"
except Exception:
raise # any other "normal" exception.
except: # Here it is ok, as you handle most exceptions above.
pass
Most "normal" exception which should normally be handled derive from Exception. Those which have an internal meaning and should normally not be caught (except on global level) don't derive from Exception.
These are KeyboardInterrupt, SystemExit and GeneratorExit.
If you're uncertain what exceptions the code you're calling throws to indicate errors then you should (in order of preference):
Find out what it is documented to throw and only catch that
catch Exception, not everything.
Neither KeyboardInterrupt nor SystemExit is a subclass of Exception, but all of the standard Python exceptions used to indicate errors are.
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.