I have written this question after reading this question and this other one.
I would like to stop the execution of a Python script when a button is pressed. Here the code:
import turtle
from sys import exit
def stop_program():
print("exit function")
exit(0) #raise SystemExit(0) gives the same result
print("after the exit function")
# Create keyboard binding
turtle.listen()
turtle.onkey(stop_program, "q")
# Main function
while True:
# Code: everything you want
If I press the button "q" (even muliple time) the output is:
exit function
exit function
exit function
exit function
exit function
exit function
exit function
...
i.e. one line every time I press.
This means that the exit works for the function and not for the whole program. Any suggestion?
Dont use the while loop, use turtle.mainloop()
import turtle
from sys import exit
def stop_program():
print("exit function")
exit(0) #raise SystemExit(0) gives the same result
print("after the exit function")
# Create keyboard binding
turtle.listen()
turtle.onkey(stop_program, "q")
turtle.mainloop()
That seems to work fine for me, give it a try.
Try to use: sys.exit(), see if that works. Below code worked for me.
import turtle
import sys
def stop_program():
print("exit function")
sys.exit() #raise SystemExit(0) gives the same result
print("after the exit function")
# Create keyboard binding
turtle.listen()
turtle.onkey(stop_program, "q")
turtle.mainloop()
Related
I'm trying to set up my Python script to allow the user to end the program, however the program needs to finish what it's doing first. I have the following code set up:
import sys
import keyboard
import time
prepareToStop = 0;
try:
while prepareToStop == 0:
#Program code here
print(prepareToStop)
time.sleep(0.1)
except KeyboardInterrupt:
prepareToStop = 1
print("\nProgram will shut down after current operation is complete.\n")
print("Program shutting down...")
sys.exit()
However, the program still exits the loop as soon as the KeyboardInterrupt is received. I've seen advice that this could be fixed by placing the 'try, except' inside the while loop, however this causes the program to fail to detect the KeyboardInterrupt at all.
If I understand your problem correctly, maybe threading can help you. Note how end do something appears even after KeyboardInterrupt.
EDIT : I placed t.join() in the try
import sys
import time
import threading
def do_something(prepareToStop):
print(prepareToStop)
time.sleep(1)
print('end do something')
prepareToStop = 0
while prepareToStop == 0:
t = threading.Thread(target=do_something, args=[prepareToStop])
try:
t.start()
t.join() # wait for the threading task to end
except KeyboardInterrupt:
prepareToStop = 1
print("\nProgram will shut down after current operation is complete.\n")
print('will not appear for last run')
print("Program shutting down...")
sys.exit()
Example of output :
0
end do something
will not appear for last run
0
^C
Program will shut down after current operation is complete.
will not appear for last run
Program shutting down...
end do something
The keyboard interrupt that you were trying to use works like any system interrupt and will jump immediately to the exception block, without going back to where it was when the interrupt has occurred.
You can confirm this by using the debugger in your IDE (ie. Press F5 in VSCODE).
The code below works like you want, but the user has to hold ESC key pressed in the keyboard for it to be captured from the program in the proper time.
import sys
import keyboard
import time
prepareToStop = 0;
while prepareToStop == 0:
if keyboard.is_pressed('Esc'):
prepareToStop = 1
print("\nProgram will shut down after current operation is complete.\n")
#Program code here
print('Sleeping 5 sec - hold the ESC key for some time to exit')
time.sleep(5)
print('This prints only after the delay')
#end code here
print(prepareToStop)
time.sleep(0.1)
print("Program shutting down...")
sys.exit()
And then I would recommend to change into this:
import sys
import keyboard
import time
while not keyboard.is_pressed('Esc'):
#Program code here
print('Sleeping 5 sec - hold the ESC key for some time to exit')
time.sleep(5)
print('This prints only after the delay')
#end code here
time.sleep(0.1)
print("Program shutting down...")
sys.exit()
The above solution is not better than using threading, but it is much more simpler.
The following code works perfectly, the loop can be stop by pressing esc:
import time
import keyboard
run = 1
def end():
global run
run = 0
print(run)
def do_stuff():
while run:
print('running')
time.sleep(0.5)
keyboard.add_hotkey('esc', end)
do_stuff()
But if I start this loop with another add_hotkey, I cannot stop it with esc anymore.
import time
import keyboard
run = 1
def end():
global run
run = 0
print(run)
def do_stuff():
while run:
print('running')
time.sleep(0.5)
keyboard.add_hotkey('esc', end)
# do_stuff()
keyboard.add_hotkey('enter', do_stuff)
keyboard.wait()
What should I do to stop this loop? I tried to replace the while run: with while not keyboard.is_pressed('esc'):. It can stop the loop if I hold the esc for a while. But it doesn't seem like a good solution.
=======================
updates:
the following works:
import keyboard
import threading
run = 1
def end():
global run
run = 0
print(run)
def do_stuff():
while run:
print('running')
time.sleep(0.5)
def new_do_stuff():
t = threading.Thread(target=do_stuff, name='LoopThread')
t.start()
keyboard.add_hotkey('esc', end)
keyboard.add_hotkey('enter', new_do_stuff)
keyboard.wait('esc')
Since in the second example you enter the do_stuff() loop through the hotkey and never leave the do_stuff() loop, the system is still captured in the hotkey command and is not listening for hotkeys anymore. You would have to find a way to leave the loop after the keyboard.add_hotkey('enter', do_stuff) command and enter it externally through another way, so the system listens for hotkey-entries again.
I'm not aware of the context you're using this in, but using some sort of a main-loop, that does nothing but wait for a flag to be set (it should be set when you get the hotkey interrupt) and then enters the do_stuff() loop seems like a way to solve it.
Am trying to create a hotkey to stop my script, this is my code so far.
import time
import keyboard
running = True
def stop(event):
global running
running = False
print("stop")
# press ctrl+esc to stop the script
keyboard.add_hotkey("ctrl+esc", lambda: stop)
while running:
time.sleep(2)
print("Hello")
time.sleep(2)
add_hotkey expects a callback as the second argument, so you must pass it the stop function, on the other hand, when the callback is invoked, no event is passed.
A better solution than using a boolean variable is to use threading.Event since this is thread-safe since the callback is invoked in a secondary thread.
import threading
import time
import keyboard
event = threading.Event()
def stop():
event.set()
print("stop")
keyboard.add_hotkey("ctrl+esc", stop)
while not event.is_set():
time.sleep(2)
print("Hello")
time.sleep(2)
I'm currently using quit() to end my program but the command line still persists after the execution has finished. How do I "kill" the program?
def ed():
quit()
timer = threading.Timer(time, ed)
timer.start()
The pointer stays active and acts like the script is running.
This could work:
import os
def ed():
os._exit(1)
You can use standard function of Python exit() which can print whatever before exiting and exit from program.
print("start")
exit() # exiting from program
print("end")
start
or
print("start")
exit("exiting") # exiting with output
print("end")
start
exiting
I have a python application in which a function runs in a recursive loop and prints updated info to the terminal with each cycle around the loop, all is good until I try to stop this recursion.
It does not stop until the terminal window is closed or the application is killed (control-c is pressed) however I am not satisfied with that method.
I have a function which will stop the loop and exit the program it just never has a chance to get called in the loop, so I wish to assign it to a key so that when it is pressed it will be called.
What is the simplest method to assign one function to one or many keys?
You can intercept the ctrl+c signal and call your own function at that time rather than
exiting.
import signal
import sys
def exit_func(signal, frame):
'''Exit function to be called when the user presses ctrl+c.
Replace this with whatever you want to do to break out of the loop.
'''
print("Exiting")
sys.exit(0) # remove this if you do not want to exit here
# register your exit function to handle the ctrl+c signal
signal.signal(signal.SIGINT, exit_func)
#loop forever
while True:
...
You should replace sys.exit(0) with something more useful to you. You could raise an exception and that except on it outside the loop body (or just finally) to perform your cleanup actions.
import keyboard
import sys
from time import sleep
def kb():
while True:
if keyboard.is_pressed("a"):
print("A key was pressed")
sys.exit(0)
def main():
kb()
if __name__ == "__main__":
main()
Here is some code
import keyboard
import sys
def kb():
while True:
#your code here
if keyboard.is_pressed("a"): #replace with your key
print("Key interrupt detected")
#cleanup here
sys.exit()
#or here
if __name__ == "__main__":
kb()
This program checks if you have pressed the key "A" every cycle. If you have, it exits.
import keyboard
def mywait():
keyboard.read_key()
def my_function():
print("hello")
def my_exit():
quit()
keyboard.add_hotkey('h', my_function)
keyboard.add_hotkey('esc', my_exit)
while True:
mywait()