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 |
|
|
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= |
|
|
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 |
|
|
|
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