Is there a way to keep tracebacks from coming up when you hit Ctrl+c,
i.e. raise KeyboardInterrupt
in a Python script?
import sys
try:
# your code
except KeyboardInterrupt:
sys.exit(0) # or 1, or whatever
Is the simplest way, assuming you still want to exit when you get a Ctrl+c.
If you want to trap it without a try/except, you can use a recipe like this using the signal
module, except it doesn't seem to work for me on Windows..
input
, at least on my system. Try putting input("Press enter to continue")
inside the try
block. When you press enter, it just prints ^M
to stdout. This seems relevant. –
Accession input
it works, but if you add the try
it doesn't? I think something else must be different. –
Lasso try
is what makes the difference. Running stty sane
makes it work again. I don't know what this does though! –
Accession Try this:
import signal
import sys
signal.signal(signal.SIGINT, lambda x, y: sys.exit(0))
This way you don't need to wrap everything in an exception handler.
SIGINT
is triggered. The returned exit status must ideally be preserved, as if the exception were not caught. –
Spence signal.signal(signal.SIGINT, lambda signal_number, current_stack_frame: sys.exit(0))
–
Weissmann sys.exit()
raises SystemExit
which produces its own backtrace. Try using os._exit()
instead. –
Cyclonite import sys
try:
# your code
except KeyboardInterrupt:
sys.exit(0) # or 1, or whatever
Is the simplest way, assuming you still want to exit when you get a Ctrl+c.
If you want to trap it without a try/except, you can use a recipe like this using the signal
module, except it doesn't seem to work for me on Windows..
input
, at least on my system. Try putting input("Press enter to continue")
inside the try
block. When you press enter, it just prints ^M
to stdout. This seems relevant. –
Accession input
it works, but if you add the try
it doesn't? I think something else must be different. –
Lasso try
is what makes the difference. Running stty sane
makes it work again. I don't know what this does though! –
Accession Catch the KeyboardInterrupt
:
try:
# do something
except KeyboardInterrupt:
pass
According to Proper handling of SIGINT/SIGQUIT, the only way to exit correctly if you're catching a SIGINT is to subsequently kill yourself with a SIGINT signal (see the section titled "How to be a proper program"). It is incorrect to attempt to fake the proper exit code. For more info about that, check also Why is "Doing an exit 130 is not the same as dying of SIGINT"? over on Unix Stack Exchange.
It seems all the answers here which are exiting zero actually demonstrate programs that misbehave. It's preferable not to hide that you were interrupted, so that the caller (usually a shell) knows what to do.
In Python, the traceback printout on stderr comes from the default sys.excepthook
behaviour. So, to suppress the traceback spam, I've opted to tackle the problem directly at the cause by replacing the except hook on keyboard interrupt, and then preserve the correct exit code by re-raising the original exception:
import sys, time
def _no_traceback_excepthook(exc_type, exc_val, traceback):
pass
def main():
try:
# whatever your program does here...
print("hello world..")
time.sleep(42)
except KeyboardInterrupt:
# whatever cleanup code you need here...
print("bye")
if sys.excepthook is sys.__excepthook__:
sys.excepthook = _no_traceback_excepthook
raise
if __name__ == "__main__":
main()
The result is like this:
$ python3 /tmp/example.py
hello world..
^Cbye
$ echo $?
130
If you don't have any cleanup actions to execute, and all you wanted to do is suppress printing the traceback on interrupt, it may be simpler just to install that by default:
import sys
def _no_traceback_excepthook(exc_type, exc_val, traceback):
if isinstance(exc_val, KeyboardInterrupt):
return
sys.__excepthook__(exc_type, exc_val, traceback)
sys.excepthook = _no_traceback_excepthook
Catch it with a try/except block:
while True:
try:
print "This will go on forever"
except KeyboardInterrupt:
pass
try:
your_stuff()
except KeyboardInterrupt:
print("no traceback")
Also note that by default the interpreter exits with the status code 128 + the value of SIGINT on your platform (which is 2 on most systems).
import sys, signal
try:
# code...
except KeyboardInterrupt: # Suppress tracebacks on SIGINT
sys.exit(128 + signal.SIGINT) # http://tldp.org/LDP/abs/html/exitcodes.html
SIGINT
is different from a exiting with code 128 + SIGINT
. They may show up as the same $?
in your shell, but they are distinguishable in the underlying API and have different effects. For example, typically, a shell script will stop execution when a child exits with a signal and not when it exits with a code. –
Montiel suppress exception using context manager:
from contextlib import suppress
def output_forever():
while True:
print('endless script output. Press ctrl + C to exit')
if __name__ == '__main__':
with suppress(KeyboardInterrupt):
output_forever()
import sys
try:
print("HELLO")
english = input("Enter your main launguage: ")
print("GOODBYE")
except KeyboardInterrupt:
print("GET LOST")
© 2022 - 2024 — McMap. All rights reserved.