Well since you asked about testing ctrl-c, I noticed a small problem with the current implentation which can cause a crash. However you need to have a considerable amount of bad luck to hit it so I didnt report it yesterday (I hit it only once when trying, but maybe for slower systems it is a larger problem).
The problem is in runcode of MtInteractiveShell?, where the CODE_RUN variable is set at the beginning of the function to True. However exception catching is only done properly within the runcode function of InteractiveShell?. A keyboardinterrupt within runcode of MtInteractiveShell? causes a deadlock (lock is not released).
So 100 times a second when this function executes, and just before and after code executes, there is slight chance of hitting this interval.
A possible solution is to move the CODE_RUN lines around the runcode call.
CODE_RUN=True
InteractiveShell.runcode(self,code_to_run)
CODE_RUN=False
However people with really bad luck could still hit the bug during the start and end of the function call, so to prevent that an extra try: except has to be used:
try:
CODE_RUN=True
InteractiveShell.runcode(self,code_to_run)
except KeyboardInterrupt:
print "Keyboard interrupted in mainloop"
while not self.code_queue.empty():
self.code_queue.get_nowait()
break
finally:
if(got_lock is True):
CODE_RUN = False
When interrupted it also removes the rest of the code queue as a bonus (ctrl-c during the actual executing of the user code does not do this, so this is a bit inconsistent). The 'if(got_lock is True):' condition is there to handle a possible reentrant call of runcode (although I have no idea why anyone would do that).
There is still one possiblility for a crash that I can see (those async exceptions really make it a mess), when someone hits ctrl-c when executing the finally clause. Most of that can be repaired by adding an extra
if(got_lock is True):
CODE_RUN = False
just after InteractiveShell?.runcode(self,code_to_run).
Of course then you still have those people left which manage to hit ctrl-c twice just before both CODE_RUN=False lines ... :)