diff --git a/src/ptvsd/_vendored/pydevd/pydevd.py b/src/ptvsd/_vendored/pydevd/pydevd.py index 0178994d..2c4b8c80 100644 --- a/src/ptvsd/_vendored/pydevd/pydevd.py +++ b/src/ptvsd/_vendored/pydevd/pydevd.py @@ -54,7 +54,7 @@ from _pydevd_frame_eval.pydevd_frame_eval_main import ( frame_eval_func, dummy_trace_dispatch) import pydev_ipython # @UnusedImport from _pydevd_bundle.pydevd_source_mapping import SourceMapping -from pydevd_concurrency_analyser.pydevd_concurrency_logger import ThreadingLogger, AsyncioLogger, send_message, cur_time +from pydevd_concurrency_analyser.pydevd_concurrency_logger import ThreadingLogger, AsyncioLogger, send_concurrency_message, cur_time from pydevd_concurrency_analyser.pydevd_thread_wrappers import wrap_threads from pydevd_file_utils import get_abs_path_real_path_and_base_from_frame, NORM_PATHS_AND_BASE_CONTAINER, get_abs_path_real_path_and_base_from_file from pydevd_file_utils import get_fullname, rPath, get_package_dir @@ -69,6 +69,7 @@ from _pydevd_bundle.pydevd_comm import(InternalConsoleExec, from _pydevd_bundle.pydevd_process_net_command_json import PyDevJsonCommandProcessor from _pydevd_bundle.pydevd_process_net_command import process_net_command +from _pydevd_bundle.pydevd_net_command import NetCommand from _pydevd_bundle.pydevd_breakpoints import stop_on_unhandled_exception from _pydevd_bundle.pydevd_collect_try_except_info import collect_try_except_info @@ -2126,11 +2127,11 @@ class PyDB(object): if self.thread_analyser is not None: wrap_threads() self.thread_analyser.set_start_time(cur_time()) - send_message("threading_event", 0, t.getName(), thread_id, "thread", "start", file, 1, None, parent=thread_id) + send_concurrency_message("threading_event", 0, t.getName(), thread_id, "thread", "start", file, 1, None, parent=thread_id) if self.asyncio_analyser is not None: # we don't have main thread in asyncio graph, so we should add a fake event - send_message("asyncio_event", 0, "Task", "Task", "thread", "stop", file, 1, frame=None, parent=None) + send_concurrency_message("asyncio_event", 0, "Task", "Task", "thread", "stop", file, 1, frame=None, parent=None) try: if INTERACTIVE_MODE_AVAILABLE: @@ -2236,6 +2237,29 @@ def add_dap_messages_listener(dap_messages_listener): py_db.add_dap_messages_listener(dap_messages_listener) +def send_json_message(msg): + ''' + API to send some custom json message. + + :param dict|pydevd_schema.BaseSchema msg: + The custom message to be sent. + + :return bool: + True if the message was added to the queue to be sent and False otherwise. + ''' + py_db = get_global_debugger() + if py_db is None: + return False + + writer = py_db.writer + if writer is None: + return False + + cmd = NetCommand(-1, 0, msg, is_json=True) + writer.add_command(cmd) + return True + + def set_debug(setup): setup['DEBUG_RECORD_SOCKET_READS'] = True setup['DEBUG_TRACE_BREAKPOINTS'] = 1 diff --git a/src/ptvsd/_vendored/pydevd/pydevd_concurrency_analyser/pydevd_concurrency_logger.py b/src/ptvsd/_vendored/pydevd/pydevd_concurrency_analyser/pydevd_concurrency_logger.py index 73a9bb51..73225e83 100644 --- a/src/ptvsd/_vendored/pydevd/pydevd_concurrency_analyser/pydevd_concurrency_logger.py +++ b/src/ptvsd/_vendored/pydevd/pydevd_concurrency_analyser/pydevd_concurrency_logger.py @@ -79,7 +79,7 @@ def get_text_list_for_frame(frame): return cmdTextList -def send_message(event_class, time, name, thread_id, type, event, file, line, frame, lock_id=0, parent=None): +def send_concurrency_message(event_class, time, name, thread_id, type, event, file, line, frame, lock_id=0, parent=None): dbg = GlobalDebuggerHolder.global_dbg if dbg is None: return @@ -109,7 +109,7 @@ def send_message(event_class, time, name, thread_id, type, event, file, line, fr def log_new_thread(global_debugger, t): event_time = cur_time() - global_debugger.thread_analyser.start_time - send_message("threading_event", event_time, t.getName(), get_thread_id(t), "thread", + send_concurrency_message("threading_event", event_time, t.getName(), get_thread_id(t), "thread", "start", "code_name", 0, None, parent=get_thread_id(t)) @@ -171,7 +171,7 @@ class ThreadingLogger: if real_method == "start": parent = get_thread_id(t) - send_message("threading_event", event_time, name, thread_id, "thread", + send_concurrency_message("threading_event", event_time, name, thread_id, "thread", real_method, back.f_code.co_filename, back.f_lineno, back, parent=parent) # print(event_time, self_obj.getName(), thread_id, "thread", # real_method, back.f_code.co_filename, back.f_lineno) @@ -191,7 +191,7 @@ class ThreadingLogger: send_massage = False # we can't detect stop after join in Python 2 yet if send_massage: - send_message("threading_event", event_time, "Thread", my_thread_id, "thread", + send_concurrency_message("threading_event", event_time, "Thread", my_thread_id, "thread", "stop", my_back.f_code.co_filename, my_back.f_lineno, my_back, parent=None) if self_obj.__class__ == ObjectWrapper: @@ -204,7 +204,7 @@ class ThreadingLogger: # back_back_base is the file, where the method was called froms return if method_name == "__init__": - send_message("threading_event", event_time, t.getName(), get_thread_id(t), "lock", + send_concurrency_message("threading_event", event_time, t.getName(), get_thread_id(t), "lock", method_name, back.f_code.co_filename, back.f_lineno, back, lock_id=str(id(frame.f_locals["self"]))) if "attr" in frame.f_locals and \ (frame.f_locals["attr"] in LOCK_METHODS or @@ -219,12 +219,12 @@ class ThreadingLogger: if real_method == "release_end": # do not log release end. Maybe use it later return - send_message("threading_event", event_time, t.getName(), get_thread_id(t), "lock", + send_concurrency_message("threading_event", event_time, t.getName(), get_thread_id(t), "lock", real_method, back.f_code.co_filename, back.f_lineno, back, lock_id=str(id(self_obj))) if real_method in ("put_end", "get_end"): # fake release for queue, cause we don't call it directly - send_message("threading_event", event_time, t.getName(), get_thread_id(t), "lock", + send_concurrency_message("threading_event", event_time, t.getName(), get_thread_id(t), "lock", "release", back.f_code.co_filename, back.f_lineno, back, lock_id=str(id(self_obj))) # print(event_time, t.getName(), get_thread_id(t), "lock", # real_method, back.f_code.co_filename, back.f_lineno) @@ -284,14 +284,14 @@ class AsyncioLogger: if method_name == "set_result": task_id = id(self_obj) task_name = self.task_mgr.get(str(task_id)) - send_message("asyncio_event", event_time, task_name, task_name, "thread", "stop", frame.f_code.co_filename, + send_concurrency_message("asyncio_event", event_time, task_name, task_name, "thread", "stop", frame.f_code.co_filename, frame.f_lineno, frame) method_name = back.f_code.co_name if method_name == "__init__": task_id = id(self_obj) task_name = self.task_mgr.get(str(task_id)) - send_message("asyncio_event", event_time, task_name, task_name, "thread", "start", frame.f_code.co_filename, + send_concurrency_message("asyncio_event", event_time, task_name, task_name, "thread", "start", frame.f_code.co_filename, frame.f_lineno, frame) method_name = frame.f_code.co_name @@ -302,7 +302,7 @@ class AsyncioLogger: if method_name == "acquire": if not self_obj._waiters and not self_obj.locked(): - send_message("asyncio_event", event_time, task_name, task_name, "lock", + send_concurrency_message("asyncio_event", event_time, task_name, task_name, "lock", method_name + "_begin", frame.f_code.co_filename, frame.f_lineno, frame, lock_id=str(id(self_obj))) if self_obj.locked(): method_name += "_begin" @@ -311,7 +311,7 @@ class AsyncioLogger: elif method_name == "release": method_name += "_end" - send_message("asyncio_event", event_time, task_name, task_name, "lock", + send_concurrency_message("asyncio_event", event_time, task_name, task_name, "lock", method_name, frame.f_code.co_filename, frame.f_lineno, frame, lock_id=str(id(self_obj))) if isinstance(self_obj, asyncio.Queue): @@ -320,20 +320,20 @@ class AsyncioLogger: task_name = self.task_mgr.get(str(task_id)) if method_name == "put": - send_message("asyncio_event", event_time, task_name, task_name, "lock", + send_concurrency_message("asyncio_event", event_time, task_name, task_name, "lock", "acquire_begin", frame.f_code.co_filename, frame.f_lineno, frame, lock_id=str(id(self_obj))) elif method_name == "_put": - send_message("asyncio_event", event_time, task_name, task_name, "lock", + send_concurrency_message("asyncio_event", event_time, task_name, task_name, "lock", "acquire_end", frame.f_code.co_filename, frame.f_lineno, frame, lock_id=str(id(self_obj))) - send_message("asyncio_event", event_time, task_name, task_name, "lock", + send_concurrency_message("asyncio_event", event_time, task_name, task_name, "lock", "release", frame.f_code.co_filename, frame.f_lineno, frame, lock_id=str(id(self_obj))) elif method_name == "get": back = frame.f_back if back.f_code.co_name != "send": - send_message("asyncio_event", event_time, task_name, task_name, "lock", + send_concurrency_message("asyncio_event", event_time, task_name, task_name, "lock", "acquire_begin", frame.f_code.co_filename, frame.f_lineno, frame, lock_id=str(id(self_obj))) else: - send_message("asyncio_event", event_time, task_name, task_name, "lock", + send_concurrency_message("asyncio_event", event_time, task_name, task_name, "lock", "acquire_end", frame.f_code.co_filename, frame.f_lineno, frame, lock_id=str(id(self_obj))) - send_message("asyncio_event", event_time, task_name, task_name, "lock", + send_concurrency_message("asyncio_event", event_time, task_name, task_name, "lock", "release", frame.f_code.co_filename, frame.f_lineno, frame, lock_id=str(id(self_obj))) diff --git a/src/ptvsd/_vendored/pydevd/tests_python/resources/_debugger_case_custom_message.py b/src/ptvsd/_vendored/pydevd/tests_python/resources/_debugger_case_custom_message.py new file mode 100644 index 00000000..20fb3347 --- /dev/null +++ b/src/ptvsd/_vendored/pydevd/tests_python/resources/_debugger_case_custom_message.py @@ -0,0 +1,14 @@ +import pydevd +from _pydevd_bundle._debug_adapter import pydevd_schema + +body = pydevd_schema.OutputEventBody('some output', 'my_category') +event = pydevd_schema.OutputEvent(body) +pydevd.send_json_message(event) + +pydevd.send_json_message({ + "type": "event", + "event": "output", + "body": {"output": "some output 2", "category": "my_category2"} +}) + +print('TEST SUCEEDED') diff --git a/src/ptvsd/_vendored/pydevd/tests_python/test_debugger_json.py b/src/ptvsd/_vendored/pydevd/tests_python/test_debugger_json.py index ad1f3d54..8baf89e9 100644 --- a/src/ptvsd/_vendored/pydevd/tests_python/test_debugger_json.py +++ b/src/ptvsd/_vendored/pydevd/tests_python/test_debugger_json.py @@ -3202,6 +3202,24 @@ def test_access_token(case_setup): writer.finished_ok = True +def test_send_json_message(case_setup): + + with case_setup.test_file('_debugger_case_custom_message.py') as writer: + json_facade = JsonFacade(writer) + + json_facade.write_launch() + + json_facade.write_make_initial_run() + + json_facade.wait_for_json_message( + OutputEvent, lambda msg: msg.body.category == 'my_category' and msg.body.output == 'some output') + + json_facade.wait_for_json_message( + OutputEvent, lambda msg: msg.body.category == 'my_category2' and msg.body.output == 'some output 2') + + writer.finished_ok = True + + if __name__ == '__main__': pytest.main(['-k', 'test_case_skipping_filters', '-s'])