Show More
@@ -4,10 +4,13 b'' | |||||
4 | # Copyright (c) IPython Development Team. |
|
4 | # Copyright (c) IPython Development Team. | |
5 | # Distributed under the terms of the Modified BSD License. |
|
5 | # Distributed under the terms of the Modified BSD License. | |
6 |
|
6 | |||
|
7 | import signal | |||
7 | import sys |
|
8 | import sys | |
|
9 | import time | |||
8 | import warnings |
|
10 | import warnings | |
9 | from tempfile import NamedTemporaryFile |
|
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 | import nose.tools as nt |
|
15 | import nose.tools as nt | |
13 |
|
16 | |||
@@ -233,32 +236,24 b' from bdb import BdbQuit' | |||||
233 |
|
236 | |||
234 | from IPython.core.debugger import set_trace |
|
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 | # Timeout if the interrupt doesn't happen: |
|
239 | # Timeout if the interrupt doesn't happen: | |
248 |
def |
|
240 | def timeout(): | |
249 | try: |
|
241 | time.sleep(5) | |
250 | time.sleep(2) |
|
|||
251 | except KeyboardInterrupt: |
|
|||
252 | return |
|
|||
253 | _exit(7) |
|
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 | def main(): |
|
249 | def main(): | |
|
250 | import signal | |||
|
251 | signal.signal(signal.SIGBREAK, break_handler) | |||
257 | set_trace() |
|
252 | set_trace() | |
258 |
|
253 | |||
259 | if __name__ == '__main__': |
|
254 | if __name__ == '__main__': | |
260 | try: |
|
255 | try: | |
261 |
|
|
256 | print("Starting debugger...") | |
262 | main() |
|
257 | main() | |
263 | print("Debugger exited without error.") |
|
258 | print("Debugger exited without error.") | |
264 | except (KeyboardInterrupt, BdbQuit): |
|
259 | except (KeyboardInterrupt, BdbQuit): | |
@@ -270,16 +265,34 b" if __name__ == '__main__':" | |||||
270 |
|
265 | |||
271 |
|
266 | |||
272 | def test_interruptible_core_debugger(): |
|
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 | with NamedTemporaryFile("w", delete=False) as f: |
|
272 | with NamedTemporaryFile("w", delete=False) as f: | |
275 | f.write(interruptible_debugger) |
|
273 | f.write(interruptible_debugger) | |
276 | f.flush() |
|
274 | f.flush() | |
277 | try: |
|
275 | start = time.time() | |
278 | result = check_output([sys.executable, f.name], |
|
276 | ||
279 | encoding=sys.getdefaultencoding()) |
|
277 | p = subprocess.Popen([sys.executable, "-u", f.name], | |
280 | except CalledProcessError as e: |
|
278 | creationflags=subprocess.CREATE_NEW_PROCESS_GROUP, # TODO disable on posix | |
281 | print("STDOUT FROM SUBPROCESS:\n{}\n".format(e.stdout), |
|
279 | encoding=sys.getdefaultencoding(), | |
282 | file=sys.stderr) |
|
280 | stderr=PIPE, stdout=PIPE) | |
283 | raise |
|
281 | time.sleep(1) # wait for it to hit pdb | |
284 | # Wait for it to start: |
|
282 | if sys.platform == "win32": | |
285 | assert "PASSED" in result |
|
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