rwallace
rwallace

Reputation: 33619

Stop KeyboardInterrupt reaching batch file processor

I'm writing some code in Python 3 on Windows that looks like this:

try:
    do something that takes a long time
    (training a neural network in TensorFlow, as it happens)
except KeyboardInterrupt:
    print('^C')
print a summary of results
still useful even if the training was cut short early

This works perfectly if run directly from the console with python foo.py.

However, if the call to Python was within a batch file, it ends up doing all the above but then still spamming the console with the 'terminate batch job' prompt.

Is there a way to stop that happening? By fully eating the ^C within Python, jumping all the way out of the batch file or otherwise?

Upvotes: 2

Views: 1258

Answers (2)

Unanimous
Unanimous

Reputation: 11

Windows lets you turn Ctrl-C off for the current process, and this also supresses the record in the operating system of Ctrl-C having been sent to the current process.

You can use a context manager to totally ignore Ctrl-C as follows:

class Ignore_Ctrl_C:
     
     def __enter__(self):
        ctypes.windll.kernel32.SetConsoleCtrlHandler(None, True)
        return self
     
     def __exit__(self, exc_type, exc_value, traceback):
        ctypes.windll.kernel32.SetConsoleCtrlHandler(None, False)


with Ignore_Ctrl_C():
    do_something_that_requires_Ctrl_C_off()

If you have a main() function, you might try running it as a separate process using the multiprocess module, and have the top level process use Ignore_Ctrl_C() while waiting for main() to finish. I would expect any Ctrl-C's that go to the subprocess would not end up associated with the top level process, and your batch file should not ask to terminate.

Alternatively, if you can't or don't want to fiddle with your python program, instead of a batch file running your program directly, you might use Ignore_Ctrl_C() in a "runner" program that kicks off your program and waits for it to finish.

Upvotes: 1

Dwad
Dwad

Reputation: 185

Use the break (More info here) command in the batch file, which will disable CTRL+C halting the file

EDIT: According to this site of the break command

Newer versions of Windows (Windows ME, Windows 2000, Windows XP, and higher) only include this command for backward compatibility and turning the break off has no effect.

I personally tested this, and can confirm, I will edit when I find a workaround

EDIT #2: If you could have a second batch script that runs start "" /b /wait cmd /c "yourfile.bat" although, this is known to cause glitches with other nested batch files

The flag to disable Ctrl+C is inherited by child processes, so Python will no longer raise a KeyboardInterrupt. Plus we still have bugs here in Python if reading from the console gets interrupted by Ctrl+C without getting a SIGINT from the CRT. The Python script should manually enable Ctrl+C via ctypes. Use import ctypes; kernel32 = ctypes.WinDLL('kernel32', use_last_error=True); success = kernel32.SetConsoleCtrlHandler(None, False)

EDIT #3 As pointed by Eryksyn (in the comments), you can use cytpes to ENABLE it;

import ctypes; 
kernel32 = ctypes.WinDLL('kernel32', use_last_error=True); success = kernel32.SetConsoleCtrlHandler(None, False)

EDIT #4: I think I found it, try this (Although it may not work) Can you use the threading import?

import time
from threading import Thread

def noInterrupt():
    for i in xrange(4):
        print i
        time.sleep(1)

a = Thread(target=noInterrupt)
a.start()
a.join()
print "done"

Upvotes: 2

Related Questions