keybord interrupt event listener - python

I have a problem with my script. i want do do an event listender for the whole script from beginning to the end.
if someone presses ctrl-c or something it should ignore, or end the scipt with an print.
I can show you my code if needed.
I tried signal and sys but I didnt know how to use it right

A simple approach for ending the script with a print could be to wrap the whole script in a try/except block:
import sys
try:
while 1:
print 'To infinity and beyond!'
# etc etc...
except KeyboardInterrupt:
print 'Handling the keyboard interrupt...'
The interrupt still kills the script, but I would think this is desired behaviour for any user; personally I wouldn't recommend trying to override it.

Related

Is there a way to implement a program termination protocol?

In my case, I am handling databases throughout the entire runtime of my program, and so I need to keep my 'cursor' open for the entire program. Is there anyway I can implement a termination protocol, so that when I terminate its execution or an error arises, I am able to run this quick piece of code that simply closes the cursor (I am using python sockets btw).
I would suspect I could do something like this:
if __name__ == "__main__":
Menu()
cursor.close()
However, the only reason that this doesn't work in my case is that Menu is simply starting up threads, and so its execution continues on, returning me back to cursor.close() whilst my program continues to run.
I'm not sure if there is a way to get around this problem.
Yes, you could use the signal library in python to achieve some of this functionality, in particular, capturing program termination as well interrupts to the program like ctrl + c. Example:
# a function to register the signal handlers
# once the program terminates or is halted by an interrupt like ctrl + c it executes the quit_gracefully function
def register_signal_handler():
signal.signal(signal.SIGINT, quit_gracefully)
signal.signal(signal.SIGTERM, quit_gracefully)
return
def quit_gracefully():
# close connections etc.
in case of a different error you could use a try-except block which handles the error and runs the quit_gracefully function in the except.
try:
# some code
except:
quit_gracefully()
EDIT:
this is a good post on signal. How do I capture SIGINT in Python?
You can also use the atexit module: https://docs.python.org/3/library/atexit.html.
Something like this:
import atexit
#atexit.register
def close_cursor():
print("Closing cursor before exiting.")
cursor.close()

How to exit a Python program or loop via keybind or macro? Keyboardinterrupt not working

I am trying to complete a simple GUI automation program that merely opens a web page and then clicks on a specific spot on the page every 0.2 seconds until I tell it to stop. I want my code to run and have its loop run infinitely until a keybind I specify breaks the loop (or entire program). I started out with the classic, KeyboardInterrupt, which enables CTRL+C to exit a program. Here is what I thought my final code would look like:
import webbrowser, pyautogui, time
webbrowser.open('https://example.com/')
print('Press Ctrl-C to quit.')
time.sleep(5)
#pyautogui.moveTo(1061, 881)
try:
while True:
time.sleep(0.2)
pyautogui.click(1061,881)
except KeyboardInterrupt:
print('\nDone.')
Everything about the code works, except the fact that I can't exit it once the clicking loop starts. Keyboard interrupt and using CTRL-C to exit do not work at all for this script, for whatever reason.
I merely want to be able to press "escape" (or any other key) to exit the loop (or the program altogether) - just any way to make the loop exit and stop. Right now it runs ad infinitum, but I want a simple keybind macro to be able to stop/break it.
I've tried using getch to keybind the escape key to cause a break, but to no avail:
import webbrowser, pyautogui, time, msvcrt
webbrowser.open('https://example.com')
print('Press Ctrl-C to quit.')
time.sleep(5)
#pyautogui.moveTo(1061, 881)
try:
while True:
time.sleep(0.2)
pyautogui.click(1061,881)
if msvcrt.kbhit():
key = ord(readch())
if key == 27:
break
I'm surprised it's been so hard to do this in Python. I've checked out a lot of similar problems across Stackoverflow, but with unsatisfactory answers, and none that solve my problem, unfortunately. I've been able to do things like this in simpler coding languages like AuotHotKeys with ease. I feel like I'm dancing around the solution. Any and all help would be wonderfully appreciated! Thanks in advance.
If I understood correctly, you want to be able to stop your program by pressing a key on your keyboard.
To make you create a thread that will check in background if you press the key in question.
A little example:
import threading, time
from msvcrt import getch
key = "lol"
def thread1():
global key
lock = threading.Lock()
while True:
with lock:
key = getch()
threading.Thread(target = thread1).start() # start the background task
while True:
time.sleep(1)
if key == "the key choosen":
# break the loop or quit your program
Hope its help.

Python/Calling python scripts within bash terminal: What exactly happens when user presses Ctrl-C?

I need help with controlling a python script. I want to run a script that controls two robots. A routine consists of a series of motions which either move the arm or move the gripper. The form of the code is as follows:
def robot_exec():
# List of robot arm poses:
*many_many_lines_of_position_vectors*
# List of robot gripper poses:
*open position*
*close position*
while 1:
*Call a function that moves the robot arm(s) to a position on the list*
*Call a function that moves the robot gripper(s) to a position on the list*
*continue calling functions many times until the desired routine is complete*
n = raw_input("Restart the routine? (Y/N)")
if n.strip() == 'n' or 'N':
break
elif n.strip() == 'y' or 'Y':
continue
else:
print "Invalid input. Exiting..."
break
If the routine is complete (i.e. every function was called), it asks if I want to restart, and if I choose yes, behaves as normal, which is good.
But, if I press ctrl-C in the middle of the routine, the message "Restart the routine?" still pops up and asks for input, and I don't want that. What I want is either one of the following:
if and only if the user presses ctrl-C, completely exit everything, no questions asked.
if and only if the user presses ctrl-C, return the robots to home position (defined in that list of arm poses) and then completely exit everything.
My main question is, how does ctrl-C actually work? I thought it would just exit the script but in actuality it still prints stuff and asks for input. A subset of that broad question is, how can I just get the desired behavior (completely exit everything when pressing ctrl-C)?
I realize this is a clunky way of doing what I need the robots to do, but it is the best way I can think of with my limited knowledge of python.
Thank you,
-Adrian
The comments/answers about signals are technically correct (on UNIX), but in Python the CTRL+C handling is neatly wrapped away from you. What happens in a Python program is that at the point where you press CTRL+C, a KeyboardInterrupt exception is raised.
Now, your problem seems to be in the code that you have removed from the listing, i.e., in the "calling robot routines" part. That code catches the KeyboardInterrupt.
I guess either your code or library code that you call does something like:
try:
# some long running code
# ...
except:
# something, or just pass
Note the naked except:. Naked excepts are almost always a bad thing. Instead you or the library should do:
try:
# some long running code
# ...
except Exception:
# something to fix the situation
Using except Exception: does not catch the KeyboardInterrupt exception, which will let you handle it appropriately, or just let the program exit. Have a look at the Exception class hierarchy.
What exactly happens when user presses Ctrl-C?
A signal is raised.
how can I just get the desired behavior
>>> import signal
>>> def handler(sig, stack_frame):
... print "Handled"
...
>>> signal.signal(signal.SIGINT, handler)
<built-in function default_int_handler>
^C # <--- typed ctrl-c here
>>> Handled
See the doc of signal for details.
Please note: on Linux I use signal.SIGINT. On Windows, maybe it is signal.CTRL_C_EVENT instead.
you can handle Ctrl_C with this code :
#!/usr/bin/env python
import signal
import sys
def signal_handler(signal, frame):
#write your command here for example i write print below :
print('You pressed Ctrl+C!')
sys.exit(0)
signal.signal(signal.SIGINT, signal_handler)
print('Press Ctrl+C')
signal.pause()

Ending an infinite while loop

I currently have code that basically runs an infinite while loop to collect data from users. Constantly updating dictionaries/lists based on the contents of a text file. For reference:
while (True):
IDs2=UpdatePoints(value,IDs2)
time.sleep(10)
Basically, my problem is that I do not know when I want this to end, but after this while loop runs I want to use the information collected, not lose it by crashing my program. Is there a simple, elegant way to simply exit out of the while loop whenever I want? Something like pressing a certain key on my keyboard would be awesome.
You can try wrapping that code in a try/except block, because keyboard interrupts are just exceptions:
try:
while True:
IDs2=UpdatePoints(value,IDs2)
time.sleep(10)
except KeyboardInterrupt:
print('interrupted!')
Then you can exit the loop with CTRL-C.
You could use exceptions. But you only should use exceptions for stuff that isn't supposed to happen. So not for this.
That is why I recommand signals:
import sys, signal
def signal_handler(signal, frame):
print("\nprogram exiting gracefully")
sys.exit(0)
signal.signal(signal.SIGINT, signal_handler)
you should put this on the beginning of your program and when you press ctrl+c wherever in your program it will shut down gracefully
Code explanation:
You import sys and signals.
Then you make a function that executes on exit. sys.exit(0) stops the programming with exit code 0 (the code that says, everything went good).
When the program get the SIGINT either by ctrl-c or by a kill command in the terminal you program will shutdown gracefully.
I think the easiest solution would be to catch the KeyboardInterrupt when the interrupt key is pressed, and use that to determine when to stop the loop.
except KeyboardInterrupt:
break
The disadvantage of looking for this exception is that it may prevent the user from terminating the program while the loop is still running.
I use python to track stock prices and submit automated buy/sell commands on my portfolio. Long story short, I wanted my tracking program to ping the data server for info, and place trades off of the information gathered, but I also wanted to save the stock data for future reference, on top of being able to start/stop the program whenever I wanted.
What ended up working for me was the following:
trigger = True
while trigger == True:
try:
(tracking program and purchasing program conditions here)
except:
trigger = False
print('shutdown initialized')
df = pd.DataFrame...
save all the datas
print('shutdown complete')
etc.
From here, while the program is in the forever loop spamming away requests for data from my broker's API, using the CTRL-C keyboard interrupt function toggles the exception to the try loop, which nullifies the while loop, allowing the script to finalize the data saving protocol without bringing the entire script to an abrupt halt.
Hope this helps!
Resultant
I would suggest using the try, except syntax within a loop if you are running on an IPYNB file in Google Colab or Jupyter, like:
while True:
try:
IDs2=UpdatePoints(value,IDs2)
time.sleep(10)
except KeyboardInterrupt:
break
except:
continue
the last except is for any other error if occurs the loop will resume
You can catch the KeyboardInterrupt error in Python:
try:
while 1>0:
IDs2=UpdatePoints(value,IDs2)
time.sleep(10)
except KeyboardInterrupt:
print('While loop ended!')
Also, instead of saying:
while True:
It looks more professional to use:
while 1>0:
To read more about Python Error handling (try, except, etc.):
https://www.w3schools.com/python/python_try_except.asp
or:
https://www.w3schools.com/python/gloss_python_try_finally.asp

Drop into an Interpreter anytime in Python

I know how to drop into an interpreter with pdb and IPython, but this requires me knowing beforehand exactly where I want to stop. However, I often run number crunching scripts that take minutes to hours, and I would like to know exactly what it's progress is. One solution is to simply put lots of logging statements everywhere, but then I either inundate myself with too much information or fail to log exactly what I want to know.
Is there a way to initialize a listener loop that under some key combination will drop me into the code wherever it currently is? Think CTRL+Z but leaving me in Python rather than Bash.
You can use the signal module to setup a handler that will launch the debugger when you hit control-C or control-Z or whatever.. SIGINTR, SIGSUSP.
For example, define a module instant_debug.py that overrides SIGQUIT,
import signal
import pdb
def handler(signum, frame):
pdb.set_trace()
signal.signal(signal.SIGQUIT, handler)
Then make a script
import instant_debug
import time
for i in xrange(1000000):
print i
time.sleep(0.1)
At any point during execution, you can jump into the code by typing CTRL+\, examine the stack with u and d as in normal pdb, then continue with c as if nothing ever happened. Note that you will only jump in at the end of the next "atomic" operation -- that means no stopping in the middle of a giant C module.
You could do this
def main():
i = 1000
while True:
print "Count Down %s" % i
time.sleep(1)
i -= 1
try:
main()
except KeyboardInterrupt:
pass # Swallow ctrl-c
finally:
code.interact("Dropped into interpreter", local=globals())

Categories

Resources