Repository: microsoft/ptvsd

Issue:
DAP: stop sending some events from pydevd
- `on_pydevd_send_curr_exception_trace` should not be sent.
- `on_pydevd_send_curr_exception_trace_proceeded` should not be sent.
- `on_pydevd_get_breakpoint_exception` should not be sent.
- `on_pydevd_process_create` should not be sent.


Discussion:

Resolving patch:
diff --git a/src/ptvsd/_vendored/pydevd/_pydevd_bundle/pydevd_net_command.py b/src/ptvsd/_vendored/pydevd/_pydevd_bundle/pydevd_net_command.py
--- a/src/ptvsd/_vendored/pydevd/_pydevd_bundle/pydevd_net_command.py
+++ b/src/ptvsd/_vendored/pydevd/_pydevd_bundle/pydevd_net_command.py
@@ -9,6 +9,18 @@
 from _pydev_bundle import pydev_log
 
 
+class _NullNetCommand(object):
+
+    id = -1
+
+    def send(self, *args, **kwargs):
+        pass
+
+
+# Constant meant to be passed to the writer when the command is meant to be ignored.
+NULL_NET_COMMAND = _NullNetCommand()
+
+
 class NetCommand:
     """
     Commands received/sent over the network.
diff --git a/src/ptvsd/_vendored/pydevd/_pydevd_bundle/pydevd_net_command_factory_json.py b/src/ptvsd/_vendored/pydevd/_pydevd_bundle/pydevd_net_command_factory_json.py
--- a/src/ptvsd/_vendored/pydevd/_pydevd_bundle/pydevd_net_command_factory_json.py
+++ b/src/ptvsd/_vendored/pydevd/_pydevd_bundle/pydevd_net_command_factory_json.py
@@ -16,7 +16,7 @@
     CMD_SET_NEXT_STATEMENT, CMD_THREAD_SUSPEND_SINGLE_NOTIFICATION, \
     CMD_THREAD_RESUME_SINGLE_NOTIFICATION, CMD_THREAD_KILL
 from _pydevd_bundle.pydevd_constants import get_thread_id, dict_values
-from _pydevd_bundle.pydevd_net_command import NetCommand
+from _pydevd_bundle.pydevd_net_command import NetCommand, NULL_NET_COMMAND
 from _pydevd_bundle.pydevd_net_command_factory_xml import NetCommandFactory
 from _pydevd_bundle.pydevd_utils import get_non_pydevd_threads
 import pydevd_file_utils
@@ -306,3 +306,28 @@ def make_set_next_stmnt_status_message(self, seq, is_success, exception_msg):
             body={},
             message=(None if is_success else exception_msg))
         return NetCommand(CMD_RETURN, 0, response, is_json=True)
+
+    @overrides(NetCommandFactory.make_send_curr_exception_trace_message)
+    def make_send_curr_exception_trace_message(self, *args, **kwargs):
+        return NULL_NET_COMMAND  # Not a part of the debug adapter protocol
+
+    @overrides(NetCommandFactory.make_send_curr_exception_trace_proceeded_message)
+    def make_send_curr_exception_trace_proceeded_message(self, *args, **kwargs):
+        return NULL_NET_COMMAND  # Not a part of the debug adapter protocol
+
+    @overrides(NetCommandFactory.make_send_breakpoint_exception_message)
+    def make_send_breakpoint_exception_message(self, *args, **kwargs):
+        return NULL_NET_COMMAND  # Not a part of the debug adapter protocol
+
+    @overrides(NetCommandFactory.make_process_created_message)
+    def make_process_created_message(self, *args, **kwargs):
+        return NULL_NET_COMMAND  # Not a part of the debug adapter protocol
+
+    @overrides(NetCommandFactory.make_thread_suspend_message)
+    def make_thread_suspend_message(self, *args, **kwargs):
+        return NULL_NET_COMMAND  # Not a part of the debug adapter protocol
+
+    @overrides(NetCommandFactory.make_thread_run_message)
+    def make_thread_run_message(self, *args, **kwargs):
+        return NULL_NET_COMMAND  # Not a part of the debug adapter protocol
+
diff --git a/src/ptvsd/wrapper.py b/src/ptvsd/wrapper.py
--- a/src/ptvsd/wrapper.py
+++ b/src/ptvsd/wrapper.py
@@ -1600,14 +1600,6 @@ def on_pydevd_thread_kill(self, seq, args):
         tid = args['body']['threadId']
         self.send_event('thread', reason='exited', threadId=tid)
 
-    @pydevd_events.handler(pydevd_comm.CMD_THREAD_SUSPEND)
-    def on_pydevd_thread_suspend(self, seq, args):
-        pass  # We only care about the thread suspend single notification.
-
-    @pydevd_events.handler(pydevd_comm.CMD_THREAD_RUN)
-    def on_pydevd_thread_run(self, seq, args):
-        pass  # We only care about the thread suspend single notification.
-
     @pydevd_events.handler(pydevd_comm_constants.CMD_THREAD_SUSPEND_SINGLE_NOTIFICATION)
     def on_pydevd_thread_suspend_single_notification(self, seq, args):
         # NOTE: We should add the thread to VSC thread map only if the
@@ -1650,25 +1642,8 @@ def on_pydevd_thread_resume_single_notification(self, seq, args):
         if os.getenv('PTVSD_USE_CONTINUED'):
             self.send_event('continued', threadId=tid)
 
-    @pydevd_events.handler(pydevd_comm.CMD_SEND_CURR_EXCEPTION_TRACE)
-    def on_pydevd_send_curr_exception_trace(self, seq, args):
-        pass
-
-    @pydevd_events.handler(pydevd_comm.CMD_SEND_CURR_EXCEPTION_TRACE_PROCEEDED)
-    def on_pydevd_send_curr_exception_trace_proceeded(self, seq, args):
-        pass
-
     @pydevd_events.handler(pydevd_comm.CMD_WRITE_TO_CONSOLE)
     def on_pydevd_cmd_write_to_console2(self, seq, args):
         """Handle console output"""
         body = args.get('body', {})
         self.send_event('output', **body)
-
-    @pydevd_events.handler(pydevd_comm.CMD_GET_BREAKPOINT_EXCEPTION)
-    def on_pydevd_get_breakpoint_exception(self, seq, args):
-        # If pydevd sends exception info from a failed breakpoint condition, just ignore.
-        pass
-
-    @pydevd_events.handler(pydevd_comm.CMD_PROCESS_CREATED)
-    def on_pydevd_process_create(self, seq, args):
-        pass


Test patch:
diff --git a/src/ptvsd/_vendored/pydevd/tests_python/debugger_unittest.py b/src/ptvsd/_vendored/pydevd/tests_python/debugger_unittest.py
--- a/src/ptvsd/_vendored/pydevd/tests_python/debugger_unittest.py
+++ b/src/ptvsd/_vendored/pydevd/tests_python/debugger_unittest.py
@@ -190,6 +190,7 @@ def __init__(self, sock):
         self.sock = sock
         self._queue = Queue()
         self._kill = False
+        self.accept_xml_messages = True
 
     def set_messages_timeout(self, timeout):
         self.MESSAGES_TIMEOUT = timeout
@@ -224,6 +225,10 @@ def get_next_message(self, context_message, timeout=None):
 
             frame = None
             sys.stdout.write('Message returned in get_next_message(): %s --  ctx: %s, asked at:\n%s\n' % (unquote_plus(unquote_plus(msg)), context_message, frame_info))
+
+        if not self.accept_xml_messages:
+            if '<xml' in msg:
+                raise AssertionError('Xml messages disabled. Received: %s' % (msg,))
         return msg
 
     def _read(self, size):
diff --git a/src/ptvsd/_vendored/pydevd/tests_python/test_debugger_json.py b/src/ptvsd/_vendored/pydevd/tests_python/test_debugger_json.py
--- a/src/ptvsd/_vendored/pydevd/tests_python/test_debugger_json.py
+++ b/src/ptvsd/_vendored/pydevd/tests_python/test_debugger_json.py
@@ -31,6 +31,7 @@ class JsonFacade(object):
 
     def __init__(self, writer):
         self.writer = writer
+        writer.reader_thread.accept_xml_messages = False
         writer.write_set_protocol('http_json')
         writer.write_multi_threads_single_notification(True)
 
diff --git a/tests/func/test_threads.py b/tests/func/test_threads.py
--- a/tests/func/test_threads.py
+++ b/tests/func/test_threads.py
@@ -13,6 +13,7 @@
 
 @pytest.mark.parametrize('count', [1, 3])
 def test_thread_count(pyfile, run_as, start_method, count):
+
     @pyfile
     def code_to_debug():
         import threading
@@ -21,35 +22,38 @@ def code_to_debug():
         from dbgimporter import import_and_enable_debugger
         import_and_enable_debugger()
         stop = False
+
         def worker(tid, offset):
             i = 0
             global stop
             while not stop:
                 time.sleep(0.01)
                 i += 1
+
         threads = []
         if sys.argv[1] != '1':
             for i in [111, 222]:
                 thread = threading.Thread(target=worker, args=(i, len(threads)))
                 threads.append(thread)
                 thread.start()
-        print('check here')
+        print('check here')  # @bp
         stop = True
 
+    line_numbers = get_marked_line_numbers(code_to_debug)
     with DebugSession() as session:
         session.initialize(
             target=(run_as, code_to_debug),
             start_method=start_method,
             program_args=[str(count)],
         )
-        session.set_breakpoints(code_to_debug, [19])
+        session.set_breakpoints(code_to_debug, [line_numbers['bp']])
         session.start_debugging()
         session.wait_for_thread_stopped()
         resp_threads = session.send_request('threads').wait_for_response()
 
         assert len(resp_threads.body['threads']) == count
 
-        session.send_request('continue').wait_for_response()
+        session.send_request('continue').wait_for_response(freeze=False)
         session.wait_for_exit()
 
 
@@ -57,6 +61,7 @@ def worker(tid, offset):
     platform.system() not in ['Windows', 'Linux', 'Darwin'],
     reason='Test not implemented on ' + platform.system())
 def test_debug_this_thread(pyfile, run_as, start_method):
+
     @pyfile
     def code_to_debug():
         from dbgimporter import import_and_enable_debugger
@@ -68,7 +73,7 @@ def code_to_debug():
 
         def foo(x):
             ptvsd.debug_this_thread()
-            event.set() #@bp
+            event.set()  # @bp
             return 0
 
         event = threading.Event()
@@ -76,14 +81,14 @@ def foo(x):
         if platform.system() == 'Windows':
             from ctypes import CFUNCTYPE, c_void_p, c_size_t, c_uint32, windll
             thread_func_p = CFUNCTYPE(c_uint32, c_void_p)
-            thread_func = thread_func_p(foo) # must hold a reference to wrapper during the call
+            thread_func = thread_func_p(foo)  # must hold a reference to wrapper during the call
             assert windll.kernel32.CreateThread(c_void_p(0), c_size_t(0), thread_func, c_void_p(0), c_uint32(0), c_void_p(0))
         elif platform.system() == 'Linux' or platform.system() == 'Darwin':
             from ctypes import CDLL, CFUNCTYPE, byref, c_void_p, c_ulong
             from ctypes.util import find_library
             libpthread = CDLL(find_library('libpthread'))
             thread_func_p = CFUNCTYPE(c_void_p, c_void_p)
-            thread_func = thread_func_p(foo) # must hold a reference to wrapper during the call
+            thread_func = thread_func_p(foo)  # must hold a reference to wrapper during the call
             assert not libpthread.pthread_create(byref(c_ulong(0)), c_void_p(0), thread_func, c_void_p(0))
         else:
             assert False
@@ -101,5 +106,5 @@ def foo(x):
         session.start_debugging()
 
         session.wait_for_thread_stopped()
-        session.send_request('continue').wait_for_response()
+        session.send_request('continue').wait_for_response(freeze=False)
         session.wait_for_exit()