trapping keyboard interupt
Bengt Richter
bokr at oz.net
Mon Oct 7 21:44:49 EDT 2002
On Mon, 7 Oct 2002 23:32:54 +0800, "Rob Hall" <bloke at ii.net> wrote:
>Having a bit of trouble trapping the keyboard interupt. I have something
>like this:
>
>continueFlag = 1
>
>try:
> while continueFlag:
> doSomeStuff
>except KeyboardInterrupt:
> continueFlag = 0
>
>doCleanUpOperations
>
>Basically, I have a program that runs continuously. Sometimes I need to
>terminate the program, save its state, and restart it at a later time.
>However, In it, I have a long process that can take 5 minutes to complete,
>and once this process starts, i don't want it to stop. But I would like it
>to know that as soon as it has finnished this process it should terminate.
>
>My intention was to trap the Keyboard Interupt, reset a flag that would tell
>the program to exit the main loop. But I can't figure how to resume
>execution from the point I gave the Keyboard Interupt.
>
>Can someone help?
>
You want to catch the interrupt before python's default handler turns it into
an interrupt. Then you can just watch a flag in the loop and not get blasted out
of it. E.g., you may find this amusing:
----< interruptpy.py >-----------
#!/usr/bin/python
# maybe useful part
import signal
class SigHandler:
def __init__(self):
self.signaled = 0
self.sn=None
reset = __init__
def __call__(self, sn, sf):
self.sn = sn # latest
self.signaled += 1
def test():
import msvcrt
sh = SigHandler()
old_SIGINT_Handler = signal.signal(signal.SIGINT,sh)
old_SIGBREAK_Handler = signal.signal(signal.SIGBREAK,sh)
signames = {
signal.SIGINT:'SIGINT',
signal.SIGBREAK:'SIGBREAK'
}
# just for this demo, but main loop might be useful
def puts(s): # helper
for c in s: msvcrt.putch(c)
CTRL_C_ECHO = '<CC>' # same length as repr, to line up
SIGINT_ECHO = '<Ctrl-C signal seen>'
SIGBREAK_ECHO = '<Ctrl-Break signal seen>'
# this plays the role of your loop body, see loop below
def dostuff():
print 'Enter a line: ',
line = c = ''
sigEchoes=[]
sh.reset()
while c != '\r': # Enter key ends input
# we could break on signals, but we want to finish line, so
# just echo and record them FTHOI
if sh.signaled and sh.sn:
sigEchoes.append((len(line),sh.sn)) # log where
if sh.sn==signal.SIGBREAK:
puts(SIGBREAK_ECHO)
elif sh.sn==signal.SIGINT:
puts(SIGINT_ECHO)
sh.sn = 0 # reset latest flag
if not msvcrt.kbhit(): continue # apparently screens ctrl-c?
c = msvcrt.getch() # should get ctrl-c but not ctrl-break?
if c=='\r': break # Enter
if c=='\b':
if sigEchoes and len(line)==sigEchoes[-1][0]:
# "erase" break effect"
puts('\b \b'*len(
(SIGINT_ECHO,SIGBREAK_ECHO)[sigEchoes[-1][1]==signal.SIGBREAK]
))
sh.signaled -= 1
sigEchoes = sigEchoes[:-1]
assert sh.signaled == len(sigEchoes) # how fast can you type ;-)
continue
elif line[-1:]=='\x03': # inc case it's getting to getch
puts('\b \b'*len(CTRL_C_ECHO))
else:
puts('\b \b'*(len(repr(line[-1:]))-2))
line = line[:-1]
elif c=='\x03':
puts(CTRL_C_ECHO)
line += c
else:
puts(repr(c)[1:-1])
line += c
print '\nIts repr was %s' % `line`
return sigEchoes
# main loop
print 'Type Ctrl-C(s) and/or Ctrl-Break(s) anywhere in input line.'
while not sh.signaled: # put this condition in your program loop
result = dostuff() # your stuff goes here
print """\
This should appear after dostuff() has done everything
as if not interrupted by signals."""
print 'Loop was terminated gracefully by %d signal%s\n' \
' %s\n' \
'setting a polled variable (not via exception).' % (
sh.signaled, 's'[sh.signaled==1:],
', '.join(map(lambda x: signames[x], [e[1] for e in result]))
)
# restore old signal handlers
signal.signal(signal.SIGINT,old_SIGINT_Handler)
signal.signal(signal.SIGBREAK,old_SIGBREAK_Handler)
if __name__ == '__main__':
test()
---------------------------------
A log of some usage (NT4, Python 2.2):
You may find backspacing amusing ;-)
[18:38] C:\pywk>python interruptpy.py
Type Ctrl-C(s) and/or Ctrl-Break(s) anywhere in input line.
Enter a line: 123<Ctrl-C signal seen>456<Ctrl-Break signal seen>789
Its repr was '123456789'
This should appear after dostuff() has done everything
as if not interrupted by signals.
Loop was terminated gracefully by 2 signals
SIGINT, SIGBREAK
setting a polled variable (not via exception).
[18:38] C:\pywk>python interruptpy.py
Type Ctrl-C(s) and/or Ctrl-Break(s) anywhere in input line.
Enter a line: <Ctrl-C signal seen><Ctrl-C signal seen><Ctrl-C signal seen>
Its repr was ''
This should appear after dostuff() has done everything
as if not interrupted by signals.
Loop was terminated gracefully by 3 signals
SIGINT, SIGINT, SIGINT
setting a polled variable (not via exception).
[18:39] C:\pywk>python interruptpy.py
Type Ctrl-C(s) and/or Ctrl-Break(s) anywhere in input line.
Enter a line: Now we'll show some control chars...
Its repr was "Now we'll show some control chars..."
Enter a line: Starting with ctrl-@ with spaces between
Its repr was 'Starting with ctrl-@ with spaces between'
Enter a line: \x00<CC> \x01 \x02 <Ctrl-C signal seen> \x04 \x05 \x06 \x07
Its repr was '\x00\x03 \x01 \x02 \x04 \x05 \x06 \x07'
This should appear after dostuff() has done everything
as if not interrupted by signals.
Loop was terminated gracefully by 1 signal
SIGINT
setting a polled variable (not via exception).
[18:40] C:\pywk>python interruptpy.py
Type Ctrl-C(s) and/or Ctrl-Break(s) anywhere in input line.
Enter a line: Similarly F1-F5: \x00; \x00< \x00= \x00> \x00?
Its repr was 'Similarly F1-F5: \x00; \x00< \x00= \x00> \x00?'
Enter a line: <Ctrl-Break signal seen><Ctrl-Break signal seen>
Its repr was ''
This should appear after dostuff() has done everything
as if not interrupted by signals.
Loop was terminated gracefully by 2 signals
SIGBREAK, SIGBREAK
setting a polled variable (not via exception).
Regards,
Bengt Richter
More information about the Python-list
mailing list