Ask Your Question

Revision history [back]

click to hide/show revision 1
initial version

Bugged interaction with signal handler [SageMath 9.5, Linux]

This is a minimal reproducible example of a bug using a typical interrupt handler so that files being written to are not corrupted. Running the script as python filename.py works as intended, but the issue occurs on running this script as sage filename.sage or as python filename.py with any Sage import statement similar to from sage.all import matrix.

As commented, the first time.sleep(3) can be interrupted correctly, the second time.sleep(4) correctly raises the KeyboardInterrupt() on exiting the scope of with DelayedKeyboardInterrupt(), but the final time.sleep(5) call cannot be interrupted, but the hardcoded KeyboardInterrupt() at the end still works. Printing signal.getsignal(signal.SIGINT) shows that DelayedKeyboardInterrupt() correctly restores the handler.

I realise that cysignals is preferred with Sage, but cannot figure out how to without major changes.

import signal
import time

class DelayedKeyboardInterrupt:
    def __enter__(self):
        self.sigint_handler = signal.signal(signal.SIGINT, self.handler)
        self.signal_received = False

    def handler(self, sig, frame):
        self.signal_received = True
        print("Delaying exit for file I/O.")

    def __exit__(self, type, value, traceback):
        signal.signal(signal.SIGINT, self.sigint_handler)
        if self.signal_received:
            raise KeyboardInterrupt("delayed")

print("sleeping unprotected for 3 sec")
time.sleep(3)  # Ctrl+C here raises KeyboardInterrupt instantly

with DelayedKeyboardInterrupt():
    print("sleeping protected for 4 sec")
    time.sleep(4)  # Ctrl+C here raises KeyboardInterrupt("delayed") after end of 4 sec

print("sleeping 'unprotected' for 5 sec")
time.sleep(5)  # Ctrl+C here does not raise any KeyboardInterrupt

raise KeyboardInterrupt("hardcoded")  # this raises correctly