Created pydevd utility for clients to send custom json messages. Fixes #1860

This commit is contained in:
Fabio Zadrozny 2019-10-21 15:28:33 -03:00
parent 959412a77c
commit bb3865df8e
4 changed files with 76 additions and 20 deletions

View file

@ -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

View file

@ -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)))

View file

@ -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')

View file

@ -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'])