Catching Keyboard Interrupt with Raw Input - python

I have a bit of python code to to try and make raw_input catch keyboard interrupts. If I run the code in this function it works perfectly fine. But if I run it in my program, the print statement is never made, indicating that the keyboard interrupt is not caught. The program attempts to exit and fails until it escalates to SIGKILL, which of course works fine. My guess is somewhere else the keyboard interrupt is being caught, preventing the exception from running at all. My question is, where would such an interrupt likely occur, and how can I prevent it from blocking this one. My plan has been to add a slight delay between the program catching a keyboard interrupt and killing itself to give excepting here a moment to catch.
Any ideas appreciated
Thanks!
import sys
def interruptable_input(text=''):
'''Takes raw input, but accepts keyboard interrupt'''
try:
return raw_input(text)
except KeyboardInterrupt:
print "Interrupted by user"
sys.exit()

I have narrowed it down to the following:
import sys
text=''
try:
print raw_input(text)
except KeyboardInterrupt:
print "Interrupted by user"
sys.exit()
Which works perfectly when i run it on the command line using python 2.7.
It lets me type an input on the console and when I hit ctrl+c it prints intterupted by user
Edit:
I misread your question at first, however when i use the method from your example and call it from another method the result is the same

I have determined the reason for my issue was another interrupt handler killing the script before the KeyboardInterrupt was hit. I solved it by setting my own interrupt handler for signal.SIGINT like so:
import sys
import signal
signal.signal(signal.SIGINT, signal_term_handler)
def signal_term_handler(signal, frame):
'''Handles KeyboardInterrupts to ensure smooth exit'''
rospy.logerr('User Keyboard interrupt')
sys.exit(0)
it's slightly less direct but it get's the job done. Now raw_input() will simply die when told to.

Related

Ctrl C won't kill looped subprocess in Python

Is there a proper way to create a script that loops through files in a folder and executes a subprocess that can be externally killed with Ctrl C? I have something like the following embedded in a pipeline and cannot Ctrl C it from the command line when the main process is killed.
Example script:
import subprocess
import os
import sys
input_directory = sys.argv[1]
for file in os.listdir(os.path.abspath(input_directory)):
output = file + "_out.out"
command = ['somescript.py', file, output]
try:
subprocess.check_call(command)
except:
print "Command Failed"
I would then execute program:
Example_script.py /path/to/some/directory/containing/files/
While it is looping, if I see the command failed, I want use Ctrl C. However, it fails and continues to run additional subprocesses despite the main script has been destroyer with Ctrl C. Is there a proper way to write something like this that can kill the childs (additional subprocess) with Ctrl C?
Any help, or pointing me in the direction is appreciated greatly. I am currently looking for a good method to do.
What you have in your try/except block is too permissive, such that when Ctrl+C is pressed, the KeyboardInterrupt exception is also handled by that same exception handler as the one that print "Command Failed", and as that is now properly handled there, the flow of the program is continued through the for loop. What you should do is:
Replace except: with except Exception: so that the KeyboardInterrupt exception will not be trapped, such that any time Ctrl+C is pressed the program will terminate (including subprocesses that isn't stuck in some non-terminatable state);
After the print statement, break out of the loop to prevent further execution from happening, if that is the intended behavior that you want this program to do.
You can catch KeyboardInterrupt, that way you can deal with Ctrl+C in whatever manner you want.
import subprocess
import os
import sys
input_directory = sys.argv[1]
for file in os.listdir(os.path.abspath(input_directory)):
output = file + "_out.out"
command = ['somescript.py', file, output]
try:
subprocess.check_call(command)
except KeyboardInterrupt as e:
print "Interrupted"
sys.exit(1)
except:
print "Command Failed"
However I agree with the other posters in that your exception is too vague, and you should be more specific in what can and can't fail.
I think Ctrl + Z can also help you to push the execution to background and suspended.

using quit(), exit(), ETC. says "The program is still running, do you want to kill it?"

While making an HTML help tool in Python, I wanted to exit the program smoothly, like clicking the X button on Google Chrome. But, I encountered an issue. It asks me if I want to kill the program, instead of doing it automatically.
I tried using quit(), exit() and sys.exit(). All do the same thing. How can I get the program to exit smoothly?
As it was suggested in the comments, your problem should only be noticed inside Python's IDLE, but should run just fine when executed inside a terminal. However, this code should also kill your program in IDLE:
import os, signal
from time import sleep
print("I will sleep for 3 secs and shut down!")
sleep(3)
os.kill(os.getpid(), signal.SIGTERM)
This sends a signal to your application to terminate.
Or alternatively you could call os' _exit function.
From the docs:
Exit the process with status n, without calling cleanup handlers, flushing stdio buffers, etc.
I know it's late but I took a different way.
It might be a dirty way of doing it. I don't like the accepted
answer because you have to hardcode those lines in every script.
I just comment out the lines, so that the dialog never shows on screen.
You can find the file /usr/lib/python3.9/idlelib/pyshell.py
aprx: line 1007
def close(self):
"Extend EditorWindow.close()"
#if self.executing:
#response = messagebox.askokcancel(
#"Kill?",
#"Your program is still running!\n Do you want to kill it?",
#default="ok",
#parent=self.text)
#if response is False:
#return "cancel"
self.stop_readline()
self.canceled = True
self.closing = True
return EditorWindow.close(self)
That way it will never ask you this silly question "Your program is still running!\n Do you want to kill it?"

Run a function at forceful termination of the script in Python

I have created a log and want it to be updated at forceful termination of the python script. This will help in keeping a track of all the forceful terminations. I tried , but atexit() runs only on normal termination.
Just catch the KeyboardInterrupt exception.
This simple program demonstrates how a function can be run when the Ctrl+C key combination is pressed to exit.
def main():
while True:
input('')
def onexit():
print('on exit')
try:
main()
except KeyboardInterrupt:
onexit()

How to stop Python PyGame program from a thread [duplicate]

How can I exit my entire Python application from one of its threads? sys.exit() only terminates the thread in which it is called, so that is no help.
I would not like to use an os.kill() solution, as this isn't very clean.
Short answer: use os._exit.
Long answer with example:
I yanked and slightly modified a simple threading example from a tutorial on DevShed:
import threading, sys, os
theVar = 1
class MyThread ( threading.Thread ):
def run ( self ):
global theVar
print 'This is thread ' + str ( theVar ) + ' speaking.'
print 'Hello and good bye.'
theVar = theVar + 1
if theVar == 4:
#sys.exit(1)
os._exit(1)
print '(done)'
for x in xrange ( 7 ):
MyThread().start()
If you keep sys.exit(1) commented out, the script will die after the third thread prints out. If you use sys.exit(1) and comment out os._exit(1), the third thread does not print (done), and the program runs through all seven threads.
os._exit "should normally only be used in the child process after a fork()" -- and a separate thread is close enough to that for your purpose. Also note that there are several enumerated values listed right after os._exit in that manual page, and you should prefer those as arguments to os._exit instead of simple numbers like I used in the example above.
If all your threads except the main ones are daemons, the best approach is generally thread.interrupt_main() -- any thread can use it to raise a KeyboardInterrupt in the main thread, which can normally lead to reasonably clean exit from the main thread (including finalizers in the main thread getting called, etc).
Of course, if this results in some non-daemon thread keeping the whole process alive, you need to followup with os._exit as Mark recommends -- but I'd see that as the last resort (kind of like a kill -9;-) because it terminates things quite brusquely (finalizers not run, including try/finally blocks, with blocks, atexit functions, etc).
Using thread.interrupt_main() may not help in some situation. KeyboardInterrupts are often used in command line applications to exit the current command or to clean the input line.
In addition, os._exit will kill the process immediately without running any finally blocks in your code, which may be dangerous (files and connections will not be closed for example).
The solution I've found is to register a signal handler in the main thread that raises a custom exception. Use the background thread to fire the signal.
import signal
import os
import threading
import time
class ExitCommand(Exception):
pass
def signal_handler(signal, frame):
raise ExitCommand()
def thread_job():
time.sleep(5)
os.kill(os.getpid(), signal.SIGUSR1)
signal.signal(signal.SIGUSR1, signal_handler)
threading.Thread(target=thread_job).start() # thread will fire in 5 seconds
try:
while True:
user_input = raw_input('Blocked by raw_input loop ')
# do something with 'user_input'
except ExitCommand:
pass
finally:
print('finally will still run')
Related questions:
Why does sys.exit() not exit when called inside a thread in Python?
Python: How to quit CLI when stuck in blocking raw_input?
The easiest way to exit the whole program is, we should terminate the program by using the process id (pid).
import os
import psutil
current_system_pid = os.getpid()
ThisSystem = psutil.Process(current_system_pid)
ThisSystem.terminate()
To install psutl:- "pip install psutil"
For Linux you can use the kill() command and pass the current process' ID and the SIGINT signal to start the steps to exit the app.
import signal
os.kill(os.getpid(), signal.SIGINT)

Graceful exiting of a program in Python?

I have a script that runs as a
while True:
doStuff()
What is the best way to communicate with this script if I need to stop it but I don't want to kill it if it is in the middle of an operation?
And I'm assuming you mean killing from outside the python script.
The way I've found easiest is
#atexit.register
def cleanup()
sys.unlink("myfile.%d" % os.getpid() )
f = open("myfile.%d" % os.getpid(), "w" )
f.write("Nothing")
f.close()
while os.path.exists("myfile.%d" % os.getpid() ):
doSomething()
Then to terminate the script just remove the myfile.xxx and the application should quit for you. You can use this even with multiple instances of the same script running at once if you only need to shut one down. And it tries to clean up after itself....
The best way is to rewrite the script so it doesn't use while True:.
Sadly, it's impossible to conjecture a good way to terminate this.
You could use the Linux signals.
You could use a timer and stop after a while.
You could have dostuff return a value and stop if the value is False.
You could check for a local file and stop if the file exists.
You could check an FTP site for a remote file and stop of the file exists.
You could check an HTTP web page for information that indicates if your loop should stop or not stop.
You could use OS-specific things like semaphores or shared memory.
I think the most elegant would be:
keep_running = true
while keep_running:
dostufF()
and then dostuff() can set keep_running = false whenever in no longer wants to keep running, then the while loop ends, and everything cleans up nicely.
If that's a console aplication and exiting by pressing Ctrl+C is ok, could that solve your problem?
try:
while True:
doStuff()
except KeyboardInterrupt:
doOtherStuff()
I guess the problem with that approach is that you wouldn't have any control exactly when and where in doStuff the execution is terminated.
Long time ago I've implemented such a thing. It catches Ctrl+C (or keyboard interrupt). It uses my package snuff-utils.
To install:
pip install snuff-utils
from snuff_utils.graceful_exit import graceful_exit
while True:
do_task_until_complete()
if graceful_exit:
do_stuff_before_exit()
break
On Ctrl+C it will log:
An interrupt signal has been received. The signal will be processed according to the logic of the application.
The goal I was after is to exit program but only after finishing already running task.
Be careful with multiprocessing/multithreading. It is not tested.
The signal module can trap signals and react accordingly?

Categories