Ask Your Question

Revision history [back]

click to hide/show revision 1
initial version

Sure. While I would have made it a little more explicit, the KeyboardInterrupt generated by alarm does contain information that a typical KeyboardInterrupt doesn't, in the .args and .message attributes. For example, control-C in the following

try:
    sleep(5)
except KeyboardInterrupt as KI:
    print 'args=',KI.args
    print 'message=', KI.message

produces

^Cargs= ()
message=

but adding alarm(2) before executing it produces:

args= ('computation timed out because alarm was set for 2 seconds',)
message= computation timed out because alarm was set for 2 seconds

So one way to take advantage of this would be through something like this:

while True:
    alarm(3)
    try:
        print 'sleeping..'
        sleep(5)
    except KeyboardInterrupt as KI:
        if KI.message.startswith("computation timed out"):
            print 'timed out!'
            continue
        else:
            # not a timeout, so break
            print 'manual exit!'
            alarm(0)
            break
    alarm(0)

which gives

sleeping..
timed out!
sleeping..
timed out!
sleeping..
timed out!
sleeping..
^Cmanual exit!

I tend to wrap this stuff up in decorators, but in this case mine is nested three deep so it's probably overkill for the problem, because it makes it look more complicated than it really is.

Updated: modern Sage raises an AlarmInterrupt instead of a KeyboardInterrupt, so you can catch it explicitly instead. That's a much cleaner solution than having to dig around inside a KeyboardInterrupt message.

Also, it's probably a better idea to use cancel_alarm() than alarm(0), which was apparently never officially supported.


Sure. While I would have made it a little more explicit, the KeyboardInterrupt generated by alarm does contain information that a typical KeyboardInterrupt doesn't, in the .args and .message attributes. For example, control-C in the following

try:
    sleep(5)
except KeyboardInterrupt as KI:
    print 'args=',KI.args
    print 'message=', KI.message

produces

^Cargs= ()
message=

but adding alarm(2) before executing it produces:

args= ('computation timed out because alarm was set for 2 seconds',)
message= computation timed out because alarm was set for 2 seconds

So one way to take advantage of this would be through something like this:

while True:
    alarm(3)
    try:
        print 'sleeping..'
        sleep(5)
    except KeyboardInterrupt as KI:
        if KI.message.startswith("computation timed out"):
            print 'timed out!'
            continue
        else:
            # not a timeout, so break
            print 'manual exit!'
            alarm(0)
            break
    alarm(0)

which gives

sleeping..
timed out!
sleeping..
timed out!
sleeping..
timed out!
sleeping..
^Cmanual exit!

I tend to wrap this stuff up in decorators, but in this case mine is nested three deep so it's probably overkill for the problem, because it makes it look more complicated than it really is.