##// END OF EJS Templates
Sketch of working interrupt mechanism for Windows. Will need to be implemented in ipykernel.
Itamar Turner-Trauring -
Show More
@@ -4,10 +4,13 b''
4 4 # Copyright (c) IPython Development Team.
5 5 # Distributed under the terms of the Modified BSD License.
6 6
7 import signal
7 8 import sys
9 import time
8 10 import warnings
9 11 from tempfile import NamedTemporaryFile
10 from subprocess import check_output, CalledProcessError
12 from subprocess import check_output, CalledProcessError, PIPE
13 import subprocess
11 14
12 15 import nose.tools as nt
13 16
@@ -233,32 +236,24 b' from bdb import BdbQuit'
233 236
234 237 from IPython.core.debugger import set_trace
235 238
236 def interrupt():
237 # Try to emulate the way interruption works in ipykernel
238 time.sleep(0.1)
239 if sys.platform == "win32":
240 from _thread import interrupt_main
241 interrupt_main()
242 else:
243 import os, signal
244 os.kill(os.getpid(), signal.SIGINT)
245 threading.Thread(target=interrupt).start()
246
247 239 # Timeout if the interrupt doesn't happen:
248 def interrupt():
249 try:
250 time.sleep(2)
251 except KeyboardInterrupt:
252 return
240 def timeout():
241 time.sleep(5)
253 242 _exit(7)
254 threading.Thread(target=interrupt, daemon=True).start()
243 threading.Thread(target=timeout, daemon=True).start()
244
245 def break_handler(*args):
246 print("BREAK!")
247 raise KeyboardInterrupt()
255 248
256 249 def main():
250 import signal
251 signal.signal(signal.SIGBREAK, break_handler)
257 252 set_trace()
258 253
259 254 if __name__ == '__main__':
260 255 try:
261 #print("Starting debugger...")
256 print("Starting debugger...")
262 257 main()
263 258 print("Debugger exited without error.")
264 259 except (KeyboardInterrupt, BdbQuit):
@@ -270,16 +265,34 b" if __name__ == '__main__':"
270 265
271 266
272 267 def test_interruptible_core_debugger():
273 """The debugger can be interrupted."""
268 """The debugger can be interrupted.
269
270 See https://stackoverflow.com/a/35792192 for details on Windows.
271 """
274 272 with NamedTemporaryFile("w", delete=False) as f:
275 273 f.write(interruptible_debugger)
276 274 f.flush()
277 try:
278 result = check_output([sys.executable, f.name],
279 encoding=sys.getdefaultencoding())
280 except CalledProcessError as e:
281 print("STDOUT FROM SUBPROCESS:\n{}\n".format(e.stdout),
282 file=sys.stderr)
283 raise
284 # Wait for it to start:
285 assert "PASSED" in result
275 start = time.time()
276
277 p = subprocess.Popen([sys.executable, "-u", f.name],
278 creationflags=subprocess.CREATE_NEW_PROCESS_GROUP, # TODO disable on posix
279 encoding=sys.getdefaultencoding(),
280 stderr=PIPE, stdout=PIPE)
281 time.sleep(1) # wait for it to hit pdb
282 if sys.platform == "win32":
283 # Yes, this has to happen once. I have no idea why.
284 p.send_signal(signal.CTRL_BREAK_EVENT)
285 p.send_signal(signal.CTRL_BREAK_EVENT)
286 else:
287 p.send_signal(signal.SIGINT)
288 exit_code = p.wait()
289 stdout = p.stdout.read()
290 stderr = p.stderr.read()
291 print("STDOUT", stdout, file=sys.__stderr__)
292 print("STDERR", stderr, file=sys.__stderr__)
293 assert exit_code == 0
294 print("SUCCESS!", file=sys.__stderr__)
295 # Make sure it exited cleanly, and quickly:
296 end = time.time()
297 assert end - start < 2 # timeout is 5 seconds
298 assert "PASSED" in stdout No newline at end of file
General Comments 0
You need to be logged in to leave comments. Login now