[Tutor] KeyboardInterrupt handler

Lloyd Kvam pythontutor@venix.com
Sat, 02 Feb 2002 12:10:22 -0500

Thanks very much!

I was running one of my Python programs that produces a report.
This run took an unusually long time.  It struck me that an interrupt handler
that displayed some progress information and offered a chance to cancel or
resume could be useful.

Michael P. Reilly wrote:

> On Thu, Jan 31, 2002 at 05:15:01PM -0500, Lloyd Kvam wrote:
>>Would it be practical to write a KeyboardInterrupt handler that "resumed" execution?
>>Since the debugger seems to do this kind of thing, I assume the traceback object and
>>its frame list could be used to accomplish a resume.  (This is more idle curiosity than
>>any real need.)  Searching Google, my books, and the manual failed to come up with
>>anything useful.
> You can't restart Python from a frame (there is a version of Python
> called "Microthreads" where you can handle continuations, but not in
> Python itself).
> The debugger doesn't do what you might think it does.  There is a hook
> in the Python interpreter that can run code.  The debugger carefully
> manages what code runs via this hook, and it can capture what exceptions
> are being handled.
> (cf. <URL: http://www.python.org/doc/current/lib/debugger-hooks.html>)
> Typically, you'd write code that would reset what you are doing and
> continue in whatever you were doing.  Most importantly, if you have
> something you are doing, then wrap it in a try-finally statement.
> For example, if you had a command interpreter.
> while 1:
>   try:
>     cmd = raw_input(prompt)
>     ...
>     if cmd == 'change':
>       # call something that could potentially break if the user
>       # interrupted
>       make_change()
>   # catch the exception and reset the interpreter
>   except KeyboardInterrupt:
>     reset()  # maybe just print so the prompt starts in the first column
> def make_change():
>   try:
>     os.rename('file', 'file.temp')
>     inf = open('file.temp', 'rb')
>     outf = open('file', 'wb')
>     modify_file(inf, outf)
>     inf.close()
>     outf.close()
>   # if there is an error, then the files will still be open,
>   # and we will back-out the changes
>   # in this case, if the user types ^C, we move the files back and
>   # the exception gets back to the loop above to reset the command
>   finally:
>     if not outf.closed: # we didn't finish it
>       outf.close()
>       try:
>         os.remove('file')
>       except:
>         pass
>       inf.close()
>       os.rename('file.temp', 'file')
>     # otherwise, things completed successfully
> Most database extensions will have provisions for rolling back
> transactions.  But you can do most everything in a similar way at
> some level.  I had to do this same exact thing ten years ago, writing
> a bullet-proof command interpreter in Bourne shell.  Using the
> debugging mechanism is not going to help much to handle rolling back
> operations like the above.
> Your original question is: would it be practical.  My response is: if
> the user interrupted the program for a reason... should you resume at
> the same place?  That might help you answer your question.
>   -Arcege
> _______________________________________________
> Tutor maillist  -  Tutor@python.org
> http://mail.python.org/mailman/listinfo/tutor

Lloyd Kvam
Venix Corp.
1 Court Street, Suite 378
Lebanon, NH 03766-1358