mirror of
https://github.com/microsoft/debugpy.git
synced 2025-12-23 08:48:12 +00:00
Created pydevd utility for clients to send custom json messages. Fixes #1860
This commit is contained in:
parent
959412a77c
commit
bb3865df8e
4 changed files with 76 additions and 20 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)))
|
||||
|
|
|
|||
|
|
@ -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')
|
||||
|
|
@ -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'])
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue