Catching a KeyboardInterrupt Signal4 min read

Catching a KeyboardInterrupt Signal4 min read

Hey everyone,

as I thought about writing the next post I came across the idea to explain what KeyboardInterrupt actually is and also how to catch it in Python 3.6.

KeyboardInterrupt is a User Signal which is executed by User. As an example could be pressing CTRL+C. In detail, the Signal is called SIGINT (Signal Interrupt). It could be useful catching a KeyboardInterrupt Signal to e.g. cleaning up temporary files which have been created during script execution.

Requirements

At first, we need to create a python script. Let’s name it ‘keyboardinterrupt.py’.

[email protected]: touch keyboardinterrupt.py

Catching SIGINT

Catching the SIGINT Signal may be useful for scripts or application which are multithreaded or when it’s necessary to be caught during the whole script execution.

Prerequisites

To catch the SIGINT it is required to import the signal library.

Importing signal
#!/usr/bin/env python3
import signal
Handler for the caught KeyboardInterrupt SIGINT

Now we need to add a function which is executed as soon as the SIGINT has been caught.

Signal Handler Function
def keyboardInterruptHandler(signal, frame):
    print("KeyboardInterrupt (ID: {}) has been caught. Cleaning up...".format(signal))
    exit(0)

As you can see, the function takes two positional arguments. The signal (integer) and the frame (object). The signal variable is an integer which represents the number of the caught signal. For SIGINT it’s the two (2). The frame variable represents the current Python stack frame which can be useful for debugging purposes.

Registering the signal action

To execute a function before quitting the program you need to register an action.

Action registering
signal.signal(signal.SIGINT, keyboardInterruptHandler)
Executing a long-running task

Now we’re executing a long-running task which will be interrupted by SIGINT.

Long-running task
while True:
    pass

Please note that the script will never end on it’s own.

Putting it all together
Whole script
#!/usr/bin/env python3
import signal

def keyboardInterruptHandler(signal, frame):
    print("KeyboardInterrupt (ID: {}) has been caught. Cleaning up...".format(signal))
    exit(0)

signal.signal(signal.SIGINT, keyboardInterruptHandler)

while True:
    pass

When you run the script from above you will notice that nothing is happening. Just press CTRL+C and you will see the print output from the highlighted line.

Running the script

[email protected]: python3 keyboardinterrupt.py
<PRESS CTRL+C NOW!!!>
^CKeyboardInterrupt (ID: 2) has been caught. Cleaning up…

Catching KeyboardInterrupt exception

The second method reacting to is catching the KeyboardInterrupt exception. It can be useful in a script which is single threaded and also in long-running task situations which can be skipped but not canceling the whole script.

Prerequisites

We use the time library to simulate a running task. Therefore we’re importing it into a new file.

Importing time library
#!/usr/bin/env python3
import time
Adding a long-running task in a “try” block

We’re catching the KeyboardInterrupt exception with a “try-except” block.

try-except block
try:
    while True:
        print("Heavy task!")
        time.sleep(2)
except KeyboardInterrupt:
    print("KeyboardInterrupt has been caught.")
Putting it all together
Catching the exception
#!/usr/bin/env python3
import time

print("Calculating a lot... Can be canceled with CTRL+C")
try:
    while True:
        print("Heavy task!")
        time.sleep(2)
except KeyboardInterrupt:
    print("KeyboardInterrupt has been caught.")

print("Continuing script execution")

As you can see i added some print information to add a hint to a user that the current task in the script can be skipped.

Running the script

[email protected]: python3 keyboardinterrupt.py
Calculating a lot… Can be canceled with CTRL+C
Heavy task!
Heavy task!
Heavy task!
Heavy task!
Heavy task!
^CKeyboardInterrupt has been caught.
Continuing script execution

Conclusion

It’s very easy to implement signal catching in python 3.6. You can easily catch any kind of signal and react to it in a matching manner. As an example taken from dd (this is a unix program to convert and copy files) it is required to send USRSIG1 to the running process to show the current state of the progress.

Do you have any interesting ideas what to do with caught signals?

Further Ressources

Marvyn Zalewski

Marvyn Zalewski

Marvyn is a nerdy guy which is into Linux and everything connected to it. He also loves to automate his home and build up a home lab which includes e.G. a custom steam machine and backup automation.
He loves to hear EDM music and try to become a
gin enthusiast.
Marvyn Zalewski

Latest posts by Marvyn Zalewski (see all)

Leave a Reply

Your email address will not be published.

13 − ten =