def code_to_debug(): from debug_me import backchannel from os import path import sys print("begin") backchannel.send(path.abspath(sys.modules["ptvsd"].__file__)) assert backchannel.receive() == "continue" print("end")
def child(): from debug_me import backchannel import sys from args import args as expected_args backchannel.send(expected_args) actual_args = sys.argv[1:] backchannel.send(actual_args)
def code_to_debug(): from debug_me import backchannel, ptvsd, scratchpad import sys import time _, host, port, wait_for_attach, is_attached, stop_method = sys.argv port = int(port) ptvsd.enable_attach((host, port)) if wait_for_attach: backchannel.send("wait_for_attach") ptvsd.wait_for_attach() if is_attached: backchannel.send("is_attached") while not ptvsd.is_attached(): print("looping until is_attached") time.sleep(0.1) if stop_method == "break_into_debugger": backchannel.send("break_into_debugger?") assert backchannel.receive() == "proceed" ptvsd.break_into_debugger() print("break") # @break_into_debugger else: scratchpad["paused"] = False backchannel.send("loop?") assert backchannel.receive() == "proceed" while not scratchpad["paused"]: print("looping until paused") time.sleep(0.1)
def code_to_debug(): from debug_me import backchannel import os import sys backchannel.send(os.path.abspath(__file__)) call_me_back_dir = backchannel.receive() sys.path.insert(0, call_me_back_dir) import call_me_back def call_func(): print("break here") # @bp call_me_back.call_me_back(call_func) # @call_me_back print("done")
def code_to_debug(): import multiprocessing import platform import sys import debug_me # noqa def child_of_child(q): print("entering child of child") assert q.get() == 2 q.put(3) print("leaving child of child") def child(q): print("entering child") assert q.get() == 1 print("spawning child of child") p = multiprocessing.Process(target=child_of_child, args=(q, )) p.start() p.join() assert q.get() == 3 q.put(4) print("leaving child") if __name__ == "__main__": from debug_me import backchannel if sys.version_info >= (3, 4): multiprocessing.set_start_method("spawn") else: assert platform.system() == "Windows" print("spawning child") q = multiprocessing.Queue() p = multiprocessing.Process(target=child, args=(q, )) p.start() print("child spawned") backchannel.send(p.pid) q.put(1) assert backchannel.receive() == "continue" q.put(2) p.join() assert q.get() == 4 q.close() backchannel.send("done")
def test_log_dir_env(pyfile, tmpdir, run, target): @pyfile def code_to_debug(): from debug_me import backchannel # noqa assert backchannel.receive() == "proceed" with check_logs(tmpdir, run): with debug.Session() as session: session.log_dir = None session.spawn_adapter.env["PTVSD_LOG_DIR"] = tmpdir if run.request != "launch": session.spawn_debuggee.env["PTVSD_LOG_DIR"] = tmpdir backchannel = session.open_backchannel() with run(session, target(code_to_debug)): pass backchannel.send("proceed")
def parent(q, a): from debug_me import backchannel print("spawning child") p = multiprocessing.Process(target=child, args=(q, a)) p.start() print("child spawned") q.put("child_pid?") what, child_pid = a.get() assert what == "child_pid" backchannel.send(child_pid) q.put("grandchild_pid?") what, grandchild_pid = a.get() assert what == "grandchild_pid" backchannel.send(grandchild_pid) assert backchannel.receive() == "continue" q.put("exit!") p.join()
def test_nodebug(pyfile, run, target): @pyfile def code_to_debug(): from debug_me import backchannel backchannel.receive() # @ bp1 print("ok") # @ bp2 with debug.Session() as session: session.config["noDebug"] = True backchannel = session.open_backchannel() run(session, target(code_to_debug)) with pytest.raises(messaging.MessageHandlingError): session.set_breakpoints(code_to_debug, all) backchannel.send(None) # Breakpoint shouldn't be hit. pass assert "ok" in session.output("stdout")
def test_run(pyfile, target, run): @pyfile def code_to_debug(): from debug_me import backchannel from os import path import sys print("begin") backchannel.send(path.abspath(sys.modules["ptvsd"].__file__)) assert backchannel.receive() == "continue" print("end") with debug.Session() as session: backchannel = session.open_backchannel() with run(session, target(code_to_debug)): pass expected_ptvsd_path = path.abspath(ptvsd.__file__) assert backchannel.receive() == some.str.matching( re.escape(expected_ptvsd_path) + r"(c|o)?") backchannel.send("continue") session.wait_for_next_event("terminated") session.proceed()
def child(): import os import sys assert "ptvsd" in sys.modules from debug_me import backchannel, ptvsd backchannel.send(os.getpid()) backchannel.send(ptvsd.__file__) backchannel.send(sys.argv)
def code_to_debug(): from debug_me import backchannel backchannel.send("continued") # @bp
def test_with_path_mappings(pyfile, long_tmpdir, target, run): @pyfile def code_to_debug(): from debug_me import backchannel import os import sys backchannel.send(os.path.abspath(__file__)) call_me_back_dir = backchannel.receive() sys.path.insert(0, call_me_back_dir) import call_me_back def call_func(): print("break here") # @bp call_me_back.call_me_back(call_func) # @call_me_back print("done") dir_local = long_tmpdir.mkdir("local") dir_remote = long_tmpdir.mkdir("remote") path_local = dir_local / "code_to_debug.py" path_remote = dir_remote / "code_to_debug.py" code_to_debug.copy(path_local) code_to_debug.copy(path_remote) call_me_back_dir = test_data / "call_me_back" call_me_back_py = call_me_back_dir / "call_me_back.py" with debug.Session() as session: session.config["pathMappings"] = [{ "localRoot": dir_local, "remoteRoot": dir_remote }] backchannel = session.open_backchannel() with run(session, target(path_remote)): # Set breakpoints using local path. This tests that local paths are # mapped to remote paths. session.set_breakpoints(path_local, ["bp"]) actual_path_remote = backchannel.receive() assert some.path(actual_path_remote) == path_remote backchannel.send(call_me_back_dir) stop = session.wait_for_stop( "breakpoint", expected_frames=[ some.dap.frame( # Mapped files should not have a sourceReference, so that the IDE # doesn't try to fetch them instead of opening the local file. some.dap.source(path_local, sourceReference=0), line="bp", ), some.dap.frame( # Unmapped files should have a sourceReference, since there's no # local file for the IDE to open. some.dap.source(call_me_back_py, sourceReference=some.int.not_equal_to(0)), line="callback", ), some.dap.frame( # Mapped files should not have a sourceReference, so that the IDE # doesn't try to fetch them instead of opening the local file. some.dap.source(path_local, sourceReference=0), line="call_me_back", ), ], ) srcref = stop.frames[1]["source"]["sourceReference"] try: session.request("source", {"sourceReference": 0}) except Exception as ex: assert "Source unavailable" in str(ex) else: pytest.fail("sourceReference=0 should not be valid") source = session.request("source", {"sourceReference": srcref}) assert "def call_me_back(callback):" in source["content"] session.request_continue()
def code_to_debug(): from debug_me import backchannel import os backchannel.send(os.path.abspath(__file__)) print("done") # @bp
def code_to_debug(): from debug_me import backchannel # @bp backchannel.send("done")
def code_to_debug(): from debug_me import backchannel a = 1 backchannel.send(a) # @bp
def code_to_debug(): from debug_me import backchannel import sys backchannel.send(sys.argv)
def test_attach_api(pyfile, target, wait_for_attach, is_attached, stop_method): @pyfile def code_to_debug(): from debug_me import backchannel, ptvsd, scratchpad import sys import time _, host, port, wait_for_attach, is_attached, stop_method = sys.argv port = int(port) ptvsd.enable_attach((host, port)) if wait_for_attach: backchannel.send("wait_for_attach") ptvsd.wait_for_attach() if is_attached: backchannel.send("is_attached") while not ptvsd.is_attached(): print("looping until is_attached") time.sleep(0.1) if stop_method == "break_into_debugger": backchannel.send("break_into_debugger?") assert backchannel.receive() == "proceed" ptvsd.break_into_debugger() print("break") # @break_into_debugger else: scratchpad["paused"] = False backchannel.send("loop?") assert backchannel.receive() == "proceed" while not scratchpad["paused"]: print("looping until paused") time.sleep(0.1) with debug.Session() as session: host, port = runners.attach_by_socket.host, runners.attach_by_socket.port session.config.update({"host": host, "port": port}) backchannel = session.open_backchannel() session.spawn_debuggee([ code_to_debug, host, port, wait_for_attach, is_attached, stop_method ]) session.wait_for_enable_attach() session.connect_to_adapter((host, port)) with session.request_attach(): pass if wait_for_attach: assert backchannel.receive() == "wait_for_attach" if is_attached: assert backchannel.receive() == "is_attached" if stop_method == "break_into_debugger": assert backchannel.receive() == "break_into_debugger?" backchannel.send("proceed") session.wait_for_stop(expected_frames=[ some.dap.frame(code_to_debug, "break_into_debugger") ]) elif stop_method == "pause": assert backchannel.receive() == "loop?" backchannel.send("proceed") session.request("pause", freeze=False) session.wait_for_stop("pause") session.scratchpad["paused"] = True else: pytest.fail(stop_method) session.request_continue()
def test_exceptions_and_partial_exclude_rules(pyfile, target, run, scenario): @pyfile def code_to_debug(): from debug_me import backchannel import sys call_me_back_dir = backchannel.receive() sys.path.insert(0, call_me_back_dir) import call_me_back def call_func(): raise RuntimeError("unhandled error") # @raise call_me_back.call_me_back(call_func) # @call_me_back print("done") call_me_back_dir = test_data / "call_me_back" call_me_back_py = call_me_back_dir / "call_me_back.py" call_me_back_py.lines = code.get_marked_line_numbers(call_me_back_py) if scenario == "exclude_code_to_debug": rules = [{"path": "**/" + code_to_debug.basename, "include": False}] elif scenario == "exclude_callback_dir": rules = [{"path": call_me_back_dir, "include": False}] else: pytest.fail(scenario) log.info("Rules: {0!j}", rules) with debug.Session() as session: session.expected_exit_code = some.int session.config["rules"] = rules backchannel = session.open_backchannel() with run(session, target(code_to_debug)): session.request( "setExceptionBreakpoints", {"filters": ["raised", "uncaught"]} ) backchannel.send(call_me_back_dir) if scenario == "exclude_code_to_debug": # Stop at handled exception, with code_to_debug.py excluded. # # Since the module raising the exception is excluded, it must not stop at # @raise, but rather at @callback (i.e. the closest non-excluded frame). stop = session.wait_for_stop( "exception", expected_frames=[ some.dap.frame( some.dap.source(call_me_back_py), line=call_me_back_py.lines["callback"], ) ], ) assert stop.frames != some.list.containing( [some.dap.frame(some.dap.source(code_to_debug), line=some.int)] ) # As exception unwinds the stack, we shouldn't stop at @call_me_back, # since that line is in the excluded file. Furthermore, although the # exception is unhandled, we shouldn't get a stop for that, either, # because the exception is last seen in an excluded file. session.request_continue() elif scenario == "exclude_callback_dir": # Stop at handled exception, with call_me_back.py excluded. # # Since the module raising the exception is not excluded, it must stop at # @raise. stop = session.wait_for_stop( "exception", expected_frames=[ some.dap.frame( some.dap.source(code_to_debug), name="call_func", line=code_to_debug.lines["raise"], ), some.dap.frame( some.dap.source(code_to_debug), name="<module>", line=code_to_debug.lines["call_me_back"], ), ], ) assert stop.frames != some.list.containing( [some.dap.frame(some.dap.source(call_me_back_py), line=some.int)] ) session.request_continue() # As exception unwinds the stack, it must not stop at @callback, since that # line is in the excluded file. However, it must stop at @call_me_back. stop = session.wait_for_stop( "exception", expected_frames=[ some.dap.frame( some.dap.source(code_to_debug), name="<module>", line=code_to_debug.lines["call_me_back"], ) ], ) assert stop.frames != some.list.containing( [some.dap.frame(some.dap.source(call_me_back_py), line=some.int)] ) session.request_continue() # Now the exception is unhandled, and should be reported as such. stop = session.wait_for_stop( "exception", expected_frames=[ some.dap.frame( some.dap.source(code_to_debug), name="call_func", line=code_to_debug.lines["raise"], ), some.dap.frame( some.dap.source(code_to_debug), name="<module>", line=code_to_debug.lines["call_me_back"], ), ], ) assert stop.frames != some.list.containing( [some.dap.frame(some.dap.source(call_me_back_py), line=some.int)] ) # Let the process crash due to unhandled exception. session.request_continue() else: pytest.fail(scenario)
def child(): import sys from debug_me import backchannel backchannel.send(sys.argv)
def code_to_debug(): from debug_me import backchannel, ptvsd a = 1 ptvsd.break_into_debugger() backchannel.send(a)
from debug_me import backchannel backchannel.send("ok")