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 test_argv_quoting(pyfile, start_method, run_as): @pyfile def args(): import debug_me # noqa args = [ # noqa r"regular", r"", r"with spaces" r'"quoted"', r'" quote at start', r'quote at end "', r'quote in " the middle', r'quotes "in the" middle', r"\path with\spaces", r"\path\with\terminal\backslash" + "\\", r"backslash \" before quote", ] @pyfile def parent(): import debug_me # noqa import sys import subprocess from args import args child = sys.argv[1] subprocess.check_call([sys.executable] + [child] + args) @pyfile 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) with debug.Session(start_method, backchannel=True) as session: backchannel = session.backchannel session.configure(run_as, parent, args=[child]) session.start_debugging() expected_args = backchannel.receive() actual_args = backchannel.receive() assert expected_args == actual_args
def parent(): import os import subprocess import sys from debug_me import backchannel argv = [sys.executable, sys.argv[1]] env = os.environ.copy() subprocess.Popen( argv, env=env, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, ) backchannel.receive()
def test_stop_on_entry(pyfile, run, target, breakpoint): @pyfile def code_to_debug(): from debug_me import backchannel # @bp backchannel.send("done") with debug.Session() as session: session.config["stopOnEntry"] = True backchannel = session.open_backchannel() with run(session, target(code_to_debug)): if breakpoint: session.set_breakpoints(code_to_debug, all) if breakpoint: stop = session.wait_for_stop( "breakpoint", expected_frames=[some.dap.frame(code_to_debug, 1)]) session.request("next", {"threadId": stop.thread_id}) stop = session.wait_for_stop( "step", expected_frames=[some.dap.frame(code_to_debug, 3)]) else: session.wait_for_stop( "entry", expected_frames=[some.dap.frame(code_to_debug, 1)]) session.request_continue() assert backchannel.receive() == "done"
def test_run_submodule(run): with debug.Session() as session: session.config["cwd"] = test_data / "testpkgs" backchannel = session.open_backchannel() with run(session, targets.Module(name="pkg1.sub")): pass assert backchannel.receive() == "ok"
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 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")
def test_args(pyfile, target, run): @pyfile def code_to_debug(): from debug_me import backchannel import sys backchannel.send(sys.argv) args = ["--arg1", "arg2", "-arg3", "--", "arg4", "-a"] with debug.Session() as session: backchannel = session.open_backchannel() with run(session, target(code_to_debug, args=args)): pass argv = backchannel.receive() assert argv == [some.str] + args
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_continue_on_disconnect_for_attach(pyfile, target, run): @pyfile def code_to_debug(): from debug_me import backchannel backchannel.send("continued") # @bp with debug.Session() as session: backchannel = session.open_backchannel() with run(session, target(code_to_debug)): session.set_breakpoints(code_to_debug, all) session.wait_for_stop( "breakpoint", expected_frames=[some.dap.frame(code_to_debug, line="bp")]) session.disconnect() assert "continued" == backchannel.receive()
def test_set_variable(pyfile, target, run): @pyfile def code_to_debug(): from debug_me import backchannel, ptvsd a = 1 ptvsd.break_into_debugger() backchannel.send(a) with debug.Session() as session: backchannel = session.open_backchannel() with run(session, target(code_to_debug)): pass stop = session.wait_for_stop() scopes = session.request("scopes", {"frameId": stop.frame_id})["scopes"] globals_ref = scopes[0]["variablesReference"] vars = session.request( "variables", {"variablesReference": globals_ref})["variables"] a, = (v for v in vars if v["name"] == "a") assert a == some.dict.containing({ "type": "int", "value": "1", "name": "a", "evaluateName": "a", "variablesReference": 0, }) set_a = session.request( "setVariable", { "variablesReference": globals_ref, "name": "a", "value": "1000" }, ) assert set_a == some.dict.containing({"type": "int", "value": "1000"}) session.request_continue() assert backchannel.receive() == 1000
def test_with_dot_remote_root(pyfile, long_tmpdir, target, run): @pyfile def code_to_debug(): from debug_me import backchannel import os backchannel.send(os.path.abspath(__file__)) print("done") # @bp 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) with debug.Session() as session: session.config["pathMappings"] = [{ "localRoot": dir_local, "remoteRoot": "." }] backchannel = session.open_backchannel() with run(session, target(path_remote), cwd=dir_remote): # Set breakpoints using local path. This tests that local paths are # mapped to remote paths. session.set_breakpoints(path_local, all) actual_path_remote = backchannel.receive() assert some.path(actual_path_remote) == path_remote session.wait_for_stop( "breakpoint", expected_frames=[ some.dap.frame(some.dap.source(path_local), line="bp") ], ) session.request_continue()
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_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 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_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 backchannel.receive() # @ bp1 print("ok") # @ bp2
def code_to_debug(): from debug_me import backchannel # noqa assert backchannel.receive() == "proceed"
def test_subprocess(pyfile, target, run): @pyfile 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) @pyfile def parent(): import debug_me # noqa import os import subprocess import sys argv = [sys.executable, sys.argv[1], "--arg1", "--arg2", "--arg3"] env = os.environ.copy() process = subprocess.Popen( argv, env=env, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, ) process.wait() with debug.Session() as parent_session: backchannel = parent_session.open_backchannel() with run(parent_session, target(parent, args=[child])): pass expected_child_config = dict(parent_session.config) expected_child_config.update({ "name": some.str, "request": "attach", "subProcessId": some.int, "host": some.str, "port": some.int, }) child_config = parent_session.wait_for_next_event("ptvsd_attach") assert child_config == expected_child_config parent_session.proceed() with debug.Session(child_config) as child_session: with child_session.start(): pass child_pid = backchannel.receive() assert child_pid == child_config["subProcessId"] assert str(child_pid) in child_config["name"] ptvsd_file = backchannel.receive() assert ptvsd_file == ptvsd.__file__ child_argv = backchannel.receive() assert child_argv == [child, "--arg1", "--arg2", "--arg3"]