Take the 2-minute tour ×
Geographic Information Systems Stack Exchange is a question and answer site for cartographers, geographers and GIS professionals. It's 100% free, no registration required.

The KeyboardInterrupt exception -- thrown when Ctrl-C, or Ctrl-Break on some machines, are pressed in a Python console window -- is commonly used to gracefully break out of long-process loops, allowing your script to perform cleanup, logging etc, before exiting.

Under my ArcGIS 9.3.1 SP2/Windows XP SP3 environment, there is an issue with catching the KeyboardInterrupt exception if the arcgisscripting module is loaded. Instead of hitting the KeyboardInterrupt catch statement, the script aborts abruptly, spitting out the following message:

forrtl: error (200): program aborting due to control-C event

If the arcgisscripting module is not loaded (removed from the import statement), the KeyboardInterrupt exception is thrown and processed properly.

From what I've read this is due to the use of Fortran in the arcgisscripting module which somehow overrides Python's interrupt processing.

Here's an example script you can use to test and reproduce the issue. Save it as a Python script, run it from the Windows command prompt and press Ctrl-C (Ctrl-Break on some machines) to test whether the KeyboardInterrupt exception is processed. Simply toggle the commenting for the import arcgisscripting line.

#import arcgisscripting
import time

try:
    while(True):
        time.sleep(1)
except KeyboardInterrupt:
    print "KeyboardInterrupt detected!"

Anyone know of a workaround to this problem? Thanks in advance for any insights you may have.

edit: here is my test script using Jason's suggestion which unfortunately doesn't work:

import arcgisscripting
import signal
import time

def ctrlc(sig, frame):
    raise KeyboardInterrupt("CTRL-C!")

print "Waiting 65s ..."
time.sleep(65)
print "Installing SIGINT handler"
signal.signal(signal.SIGINT, ctrlc)

try:
    while(True):
        time.sleep(1)
except KeyboardInterrupt:
    print "KeyboardInterrupt detected!"
share|improve this question
add comment

2 Answers

You can try reinstalling a custom handler for SIGINT using the signal module after importing arcgisscripting.

import arcgisscripting
import signal

def ctrlc(sig, frame):
    raise KeyboardInterrupt("CTRL-C!")

signal.signal(signal.SIGINT, ctrlc)

Let me know if this works for you.

share|improve this answer
    
Thanks for the response. It unfortunately doesn't seem to work, the forrtl error still occurs instead of my KeyboardInterrupt exception. Also, the help file on the signal module says that SIGINT is already translated to KeyboardInterrupt by default. So unfortunately it looks like arcgisscripting is still overriding it. –  blah238 Sep 27 '10 at 15:03
    
You might want to check the timing of when you reset the signal handler -- try doing it after doing your arcgisscripting.create() call, as many more DLLs get loaded after than, one of which must be the offending library that changes the signal handler. –  Jason Scheirer Sep 27 '10 at 21:41
    
In my test script I am not even calling arcgisscripting.create(), just importing the module. I also tried sticking a time.sleep() of 65 seconds in between the import statement and resetting the signal handler, just in case it was some timing issue but that did not help. –  blah238 Sep 28 '10 at 22:02
add comment
up vote 0 down vote accepted

I figured out a Windows-only workaround for this. It uses the msvcrt module, which is a Windows-only wrapper for the Visual C++ runtime, to read which keyboard character code was last received. It doesn't override the Ctrl-C, so I specified it should look for Ctrl-Alt-Q. When you press Ctrl-Alt-Q in my test script it will raise the KeyboardInterrupt exception. If you hit Ctrl-C it will still abruptly kill the script, however.

There are likely other ways to do this on *nix but I only needed this for Windows.

import arcgisscripting
import msvcrt
import time

def kbfunc():
   x = msvcrt.kbhit()
   if x:
      ret = ord(msvcrt.getch())
   else:
      ret = 0
   return ret

if __name__ == '__main__':
    try:
        while(True):
            time.sleep(1)

            # Check to see if Ctrl-Alt-Q is pressed
            x = kbfunc()
            if x == 16: # Ctrl-Alt-Q
                raise KeyboardInterrupt

    except KeyboardInterrupt:
        print "KeyboardInterrupt detected!"
share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.