mirror of
https://github.com/microsoft/debugpy.git
synced 2025-12-23 08:48:12 +00:00
* Port stopped and continued events to pydevd. Fixes #1340, #1341 * Use 'ptvsd.log.exception' instead of traceback.print_exc.
This commit is contained in:
parent
5dbba4ac28
commit
60da1fee41
12 changed files with 363 additions and 289 deletions
|
|
@ -1079,98 +1079,106 @@ def internal_get_description(dbg, seq, thread_id, frame_id, expression):
|
|||
dbg.writer.add_command(cmd)
|
||||
|
||||
|
||||
def build_exception_info_response(dbg, thread_id, request_seq, set_additional_thread_info, iter_visible_frames_info, max_frames):
|
||||
'''
|
||||
:return ExceptionInfoResponse
|
||||
'''
|
||||
thread = pydevd_find_thread_by_id(thread_id)
|
||||
additional_info = set_additional_thread_info(thread)
|
||||
topmost_frame = additional_info.get_topmost_frame(thread)
|
||||
|
||||
frames = []
|
||||
exc_type = None
|
||||
exc_desc = None
|
||||
if topmost_frame is not None:
|
||||
frame_id_to_lineno = {}
|
||||
try:
|
||||
trace_obj = None
|
||||
frame = topmost_frame
|
||||
while frame is not None:
|
||||
if frame.f_code.co_name == 'do_wait_suspend' and frame.f_code.co_filename.endswith('pydevd.py'):
|
||||
arg = frame.f_locals.get('arg', None)
|
||||
if arg is not None:
|
||||
exc_type, exc_desc, trace_obj = arg
|
||||
break
|
||||
frame = frame.f_back
|
||||
|
||||
while trace_obj.tb_next is not None:
|
||||
trace_obj = trace_obj.tb_next
|
||||
|
||||
info = dbg.suspended_frames_manager.get_topmost_frame_and_frame_id_to_line(thread_id)
|
||||
if info is not None:
|
||||
topmost_frame, frame_id_to_lineno = info
|
||||
|
||||
if trace_obj is not None:
|
||||
for frame_id, frame, method_name, original_filename, filename_in_utf8, lineno in iter_visible_frames_info(
|
||||
dbg, trace_obj.tb_frame, frame_id_to_lineno):
|
||||
|
||||
line_text = linecache.getline(original_filename, lineno)
|
||||
|
||||
# Never filter out plugin frames!
|
||||
if not getattr(frame, 'IS_PLUGIN_FRAME', False):
|
||||
if not dbg.in_project_scope(original_filename):
|
||||
if not dbg.get_use_libraries_filter():
|
||||
continue
|
||||
frames.append((filename_in_utf8, lineno, method_name, line_text))
|
||||
finally:
|
||||
topmost_frame = None
|
||||
|
||||
name = 'exception: type unknown'
|
||||
if exc_type is not None:
|
||||
try:
|
||||
name = exc_type.__qualname__
|
||||
except:
|
||||
try:
|
||||
name = exc_type.__name__
|
||||
except:
|
||||
try:
|
||||
name = str(exc_type)
|
||||
except:
|
||||
pass
|
||||
|
||||
description = 'exception: no description'
|
||||
if exc_desc is not None:
|
||||
try:
|
||||
description = str(exc_desc)
|
||||
except:
|
||||
pass
|
||||
|
||||
stack_str = ''.join(traceback.format_list(frames[-max_frames:]))
|
||||
|
||||
# This is an extra bit of data used by Visual Studio
|
||||
source_path = frames[0][0] if frames else ''
|
||||
|
||||
if thread.stop_reason == CMD_STEP_CAUGHT_EXCEPTION:
|
||||
break_mode = pydevd_schema.ExceptionBreakMode.ALWAYS
|
||||
else:
|
||||
break_mode = pydevd_schema.ExceptionBreakMode.UNHANDLED
|
||||
|
||||
response = pydevd_schema.ExceptionInfoResponse(
|
||||
request_seq=request_seq,
|
||||
success=True,
|
||||
command='exceptionInfo',
|
||||
body=pydevd_schema.ExceptionInfoResponseBody(
|
||||
exceptionId=name,
|
||||
description=description,
|
||||
breakMode=break_mode,
|
||||
details=pydevd_schema.ExceptionDetails(
|
||||
message=description,
|
||||
typeName=name,
|
||||
stackTrace=stack_str,
|
||||
source=source_path
|
||||
)
|
||||
)
|
||||
)
|
||||
return response
|
||||
|
||||
|
||||
def internal_get_exception_details_json(dbg, request, thread_id, max_frames, set_additional_thread_info=None, iter_visible_frames_info=None):
|
||||
''' Fetch exception details
|
||||
'''
|
||||
try:
|
||||
thread = pydevd_find_thread_by_id(thread_id)
|
||||
additional_info = set_additional_thread_info(thread)
|
||||
topmost_frame = additional_info.get_topmost_frame(thread)
|
||||
|
||||
frames = []
|
||||
exc_type = None
|
||||
exc_desc = None
|
||||
if topmost_frame is not None:
|
||||
frame_id_to_lineno = {}
|
||||
try:
|
||||
trace_obj = None
|
||||
frame = topmost_frame
|
||||
while frame is not None:
|
||||
if frame.f_code.co_name == 'do_wait_suspend' and frame.f_code.co_filename.endswith('pydevd.py'):
|
||||
arg = frame.f_locals.get('arg', None)
|
||||
if arg is not None:
|
||||
exc_type, exc_desc, trace_obj = arg
|
||||
break
|
||||
frame = frame.f_back
|
||||
|
||||
while trace_obj.tb_next is not None:
|
||||
trace_obj = trace_obj.tb_next
|
||||
|
||||
info = dbg.suspended_frames_manager.get_topmost_frame_and_frame_id_to_line(thread_id)
|
||||
if info is not None:
|
||||
topmost_frame, frame_id_to_lineno = info
|
||||
|
||||
if trace_obj is not None:
|
||||
for frame_id, frame, method_name, original_filename, filename_in_utf8, lineno in iter_visible_frames_info(
|
||||
dbg, trace_obj.tb_frame, frame_id_to_lineno):
|
||||
|
||||
line_text = linecache.getline(original_filename, lineno)
|
||||
|
||||
# Never filter out plugin frames!
|
||||
if not getattr(frame, 'IS_PLUGIN_FRAME', False):
|
||||
if not dbg.in_project_scope(original_filename):
|
||||
if not dbg.get_use_libraries_filter():
|
||||
continue
|
||||
frames.append((filename_in_utf8, lineno, method_name, line_text))
|
||||
finally:
|
||||
topmost_frame = None
|
||||
|
||||
name = 'exception: type unknown'
|
||||
if exc_type is not None:
|
||||
try:
|
||||
name = exc_type.__qualname__
|
||||
except:
|
||||
try:
|
||||
name = exc_type.__name__
|
||||
except:
|
||||
try:
|
||||
name = str(exc_type)
|
||||
except:
|
||||
pass
|
||||
|
||||
description = 'exception: no description'
|
||||
if exc_desc is not None:
|
||||
try:
|
||||
description = str(exc_desc)
|
||||
except:
|
||||
pass
|
||||
|
||||
stack_str = ''.join(traceback.format_list(frames[-max_frames:]))
|
||||
|
||||
# This is an extra bit of data used by Visual Studio
|
||||
source_path = frames[0][0] if frames else ''
|
||||
|
||||
if thread.stop_reason == CMD_STEP_CAUGHT_EXCEPTION:
|
||||
break_mode = pydevd_schema.ExceptionBreakMode.ALWAYS
|
||||
else:
|
||||
break_mode = pydevd_schema.ExceptionBreakMode.UNHANDLED
|
||||
|
||||
response = pydevd_schema.ExceptionInfoResponse(
|
||||
request_seq=request.seq,
|
||||
success=True,
|
||||
command='exceptionInfo',
|
||||
body=pydevd_schema.ExceptionInfoResponseBody(
|
||||
exceptionId=name,
|
||||
description=description,
|
||||
breakMode=break_mode,
|
||||
details=pydevd_schema.ExceptionDetails(
|
||||
message=description,
|
||||
typeName=name,
|
||||
stackTrace=stack_str,
|
||||
source=source_path
|
||||
)
|
||||
)
|
||||
)
|
||||
response = build_exception_info_response(dbg, thread_id, request.seq, set_additional_thread_info, iter_visible_frames_info, max_frames)
|
||||
except:
|
||||
exc = get_exception_traceback_str()
|
||||
response = pydevd_base_schema.build_response(request, kwargs={
|
||||
|
|
|
|||
|
|
@ -1,22 +1,27 @@
|
|||
from functools import partial
|
||||
import itertools
|
||||
import os
|
||||
|
||||
from _pydev_bundle._pydev_imports_tipper import TYPE_IMPORT, TYPE_CLASS, TYPE_FUNCTION, TYPE_ATTR, \
|
||||
TYPE_BUILTIN, TYPE_PARAM
|
||||
from _pydev_bundle.pydev_is_thread_alive import is_thread_alive
|
||||
from _pydev_bundle.pydev_override import overrides
|
||||
from _pydev_imps._pydev_saved_modules import threading
|
||||
from _pydevd_bundle._debug_adapter import pydevd_schema
|
||||
from _pydevd_bundle._debug_adapter.pydevd_schema import ModuleEvent, ModuleEventBody, Module, \
|
||||
OutputEventBody, OutputEvent, ContinuedEventBody
|
||||
from _pydevd_bundle.pydevd_comm_constants import CMD_THREAD_CREATE, CMD_RETURN, CMD_MODULE_EVENT, \
|
||||
CMD_WRITE_TO_CONSOLE
|
||||
CMD_WRITE_TO_CONSOLE, CMD_STEP_INTO, CMD_STEP_INTO_MY_CODE, CMD_STEP_OVER, CMD_STEP_OVER_MY_CODE, \
|
||||
CMD_STEP_RETURN, CMD_STEP_CAUGHT_EXCEPTION, CMD_ADD_EXCEPTION_BREAK, CMD_SET_BREAK, \
|
||||
CMD_SET_NEXT_STATEMENT, CMD_THREAD_SUSPEND_SINGLE_NOTIFICATION, \
|
||||
CMD_THREAD_RESUME_SINGLE_NOTIFICATION
|
||||
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_factory_xml import NetCommandFactory
|
||||
from _pydevd_bundle.pydevd_utils import get_non_pydevd_threads
|
||||
from _pydev_imps._pydev_saved_modules import threading
|
||||
from _pydevd_bundle._debug_adapter.pydevd_schema import ModuleEvent, ModuleEventBody, Module, \
|
||||
OutputEventBody, OutputEvent
|
||||
from functools import partial
|
||||
import itertools
|
||||
import pydevd_file_utils
|
||||
from _pydevd_bundle.pydevd_comm import pydevd_find_thread_by_id, build_exception_info_response
|
||||
from _pydevd_bundle.pydevd_additional_thread_info_regular import set_additional_thread_info
|
||||
|
||||
|
||||
class ModulesManager(object):
|
||||
|
|
@ -224,3 +229,56 @@ class NetCommandFactoryJson(NetCommandFactory):
|
|||
body = OutputEventBody(v, category)
|
||||
event = OutputEvent(body)
|
||||
return NetCommand(CMD_WRITE_TO_CONSOLE, 0, event, is_json=True)
|
||||
|
||||
_STEP_REASONS = set([
|
||||
CMD_STEP_INTO,
|
||||
CMD_STEP_INTO_MY_CODE,
|
||||
CMD_STEP_OVER,
|
||||
CMD_STEP_OVER_MY_CODE,
|
||||
CMD_STEP_RETURN,
|
||||
CMD_STEP_INTO_MY_CODE,
|
||||
])
|
||||
_EXCEPTION_REASONS = set([
|
||||
CMD_STEP_CAUGHT_EXCEPTION,
|
||||
CMD_ADD_EXCEPTION_BREAK,
|
||||
])
|
||||
|
||||
@overrides(NetCommandFactory.make_thread_suspend_single_notification)
|
||||
def make_thread_suspend_single_notification(self, py_db, thread_id, stop_reason):
|
||||
exc_desc = None
|
||||
exc_name = None
|
||||
if stop_reason in self._STEP_REASONS:
|
||||
stop_reason = 'step'
|
||||
elif stop_reason in self._EXCEPTION_REASONS:
|
||||
stop_reason = 'exception'
|
||||
elif stop_reason == CMD_SET_BREAK:
|
||||
stop_reason = 'breakpoint'
|
||||
elif stop_reason == CMD_SET_NEXT_STATEMENT:
|
||||
stop_reason = 'goto'
|
||||
else:
|
||||
stop_reason = 'pause'
|
||||
|
||||
if stop_reason == 'exception':
|
||||
exception_info_response = build_exception_info_response(
|
||||
py_db, thread_id, -1, set_additional_thread_info, self._iter_visible_frames_info, max_frames=-1)
|
||||
exception_info_response
|
||||
|
||||
exc_name = exception_info_response.body.exceptionId
|
||||
exc_desc = exception_info_response.body.description
|
||||
|
||||
body = pydevd_schema.StoppedEventBody(
|
||||
reason=stop_reason,
|
||||
description=exc_desc,
|
||||
threadId=thread_id,
|
||||
text=exc_name,
|
||||
allThreadsStopped=True,
|
||||
preserveFocusHint=stop_reason not in ['step', 'exception', 'breakpoint'],
|
||||
)
|
||||
event = pydevd_schema.StoppedEvent(body)
|
||||
return NetCommand(CMD_THREAD_SUSPEND_SINGLE_NOTIFICATION, 0, event, is_json=True)
|
||||
|
||||
@overrides(NetCommandFactory.make_thread_resume_single_notification)
|
||||
def make_thread_resume_single_notification(self, thread_id):
|
||||
body = ContinuedEventBody(threadId=thread_id, allThreadsContinued=True)
|
||||
event = pydevd_schema.ContinuedEvent(body)
|
||||
return NetCommand(CMD_THREAD_RESUME_SINGLE_NOTIFICATION, 0, event, is_json=True)
|
||||
|
|
|
|||
|
|
@ -273,7 +273,7 @@ class NetCommandFactory(object):
|
|||
except:
|
||||
return self.make_error_message(0, get_exception_traceback_str())
|
||||
|
||||
def make_thread_suspend_single_notification(self, thread_id, stop_reason):
|
||||
def make_thread_suspend_single_notification(self, py_db, thread_id, stop_reason):
|
||||
try:
|
||||
return NetCommand(CMD_THREAD_SUSPEND_SINGLE_NOTIFICATION, 0, json.dumps(
|
||||
{'thread_id': thread_id, 'stop_reason':stop_reason}))
|
||||
|
|
|
|||
|
|
@ -759,10 +759,12 @@ class _PyDevJsonCommandProcessor(object):
|
|||
start_patterns = tuple(args['dontTraceStartPatterns'])
|
||||
end_patterns = tuple(args['dontTraceEndPatterns'])
|
||||
if self._can_set_dont_trace_pattern(py_db, start_patterns, end_patterns):
|
||||
|
||||
def dont_trace_files_property_request(abs_path):
|
||||
result = abs_path.startswith(start_patterns) or \
|
||||
abs_path.endswith(end_patterns)
|
||||
return result
|
||||
|
||||
dont_trace_files_property_request.start_patterns = start_patterns
|
||||
dont_trace_files_property_request.end_patterns = end_patterns
|
||||
py_db.dont_trace_external_files = dont_trace_files_property_request
|
||||
|
|
@ -788,4 +790,5 @@ class _PyDevJsonCommandProcessor(object):
|
|||
response = pydevd_base_schema.build_response(request, kwargs={'body': {}})
|
||||
return NetCommand(CMD_RETURN, 0, response, is_json=True)
|
||||
|
||||
|
||||
process_net_command_json = _PyDevJsonCommandProcessor(pydevd_base_schema.from_json).process_net_command_json
|
||||
|
|
|
|||
|
|
@ -139,6 +139,7 @@ file_system_encoding = getfilesystemencoding()
|
|||
|
||||
_CACHE_FILE_TYPE = {}
|
||||
|
||||
|
||||
#=======================================================================================================================
|
||||
# PyDBCommandThread
|
||||
#=======================================================================================================================
|
||||
|
|
@ -338,7 +339,7 @@ class ThreadsSuspendedSingleNotification(AbstractSingleNotificationBehavior):
|
|||
def send_suspend_notification(self, thread_id, stop_reason):
|
||||
py_db = self._py_db()
|
||||
if py_db is not None:
|
||||
py_db.writer.add_command(py_db.cmd_factory.make_thread_suspend_single_notification(thread_id, stop_reason))
|
||||
py_db.writer.add_command(py_db.cmd_factory.make_thread_suspend_single_notification(py_db, thread_id, stop_reason))
|
||||
|
||||
@overrides(AbstractSingleNotificationBehavior.notify_thread_suspended)
|
||||
@contextmanager
|
||||
|
|
@ -598,7 +599,7 @@ class PyDB(object):
|
|||
return file_type
|
||||
|
||||
def is_cache_file_type_empty(self):
|
||||
return bool(_CACHE_FILE_TYPE)
|
||||
return not _CACHE_FILE_TYPE
|
||||
|
||||
def get_thread_local_trace_func(self):
|
||||
try:
|
||||
|
|
|
|||
|
|
@ -1,7 +1,17 @@
|
|||
from _debugger_case_dont_trace import call_me_back
|
||||
import sys
|
||||
import os
|
||||
|
||||
try:
|
||||
from _debugger_case_dont_trace import call_me_back
|
||||
except ImportError:
|
||||
sys.path.append(os.path.dirname(__file__))
|
||||
from _debugger_case_dont_trace import call_me_back
|
||||
|
||||
|
||||
def my_callback():
|
||||
print('trace me') # Break here
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
call_me_back(my_callback)
|
||||
print('TEST SUCEEDED!')
|
||||
print('TEST SUCEEDED!')
|
||||
|
|
|
|||
|
|
@ -4,22 +4,24 @@ import pytest
|
|||
from _pydevd_bundle._debug_adapter import pydevd_schema, pydevd_base_schema
|
||||
from _pydevd_bundle._debug_adapter.pydevd_base_schema import from_json
|
||||
from tests_python.debugger_unittest import IS_JYTHON, REASON_STEP_INTO, REASON_STEP_OVER, \
|
||||
REASON_CAUGHT_EXCEPTION, REASON_THREAD_SUSPEND, REASON_STEP_RETURN, IS_APPVEYOR, overrides, \
|
||||
REASON_UNCAUGHT_EXCEPTION
|
||||
REASON_CAUGHT_EXCEPTION, REASON_STEP_RETURN, IS_APPVEYOR, overrides
|
||||
from _pydevd_bundle._debug_adapter.pydevd_schema import ThreadEvent, ModuleEvent, OutputEvent, \
|
||||
ExceptionOptions, Response
|
||||
ExceptionOptions, Response, StoppedEvent, ContinuedEvent
|
||||
from tests_python import debugger_unittest
|
||||
import json
|
||||
from collections import namedtuple
|
||||
from _pydevd_bundle.pydevd_constants import int_types
|
||||
from tests_python.debug_constants import * # noqa
|
||||
import time
|
||||
from os.path import normcase
|
||||
|
||||
pytest_plugins = [
|
||||
str('tests_python.debugger_fixtures'),
|
||||
]
|
||||
|
||||
_JsonHit = namedtuple('_JsonHit', 'frameId, stack_trace_response')
|
||||
_JsonHit = namedtuple('_JsonHit', 'thread_id, frame_id, stack_trace_response')
|
||||
|
||||
pytestmark = pytest.mark.skipif(IS_JYTHON, reason='Single notification is not OK in Jython (investigate).')
|
||||
|
||||
# Note: in reality must be < int32, but as it's created sequentially this should be
|
||||
# a reasonable number for tests.
|
||||
|
|
@ -30,6 +32,8 @@ class JsonFacade(object):
|
|||
|
||||
def __init__(self, writer):
|
||||
self.writer = writer
|
||||
writer.write_set_protocol('http_json')
|
||||
writer.write_multi_threads_single_notification(True)
|
||||
|
||||
def wait_for_json_message(self, expected_class, accept_message=lambda obj:True):
|
||||
|
||||
|
|
@ -75,6 +79,14 @@ class JsonFacade(object):
|
|||
def write_list_threads(self):
|
||||
return self.wait_for_response(self.write_request(pydevd_schema.ThreadsRequest()))
|
||||
|
||||
def wait_for_thread_stopped(self, reason='breakpoint', line=None):
|
||||
stopped_event = self.wait_for_json_message(StoppedEvent)
|
||||
assert stopped_event.body.reason == reason
|
||||
json_hit = self.get_stack_as_json_hit(stopped_event.body.threadId)
|
||||
if line is not None:
|
||||
assert json_hit.stack_trace_response.body.stackFrames[0]['line'] == line
|
||||
return json_hit
|
||||
|
||||
def write_set_breakpoints(self, lines, filename=None, line_to_info=None):
|
||||
'''
|
||||
Adds a breakpoint.
|
||||
|
|
@ -162,7 +174,8 @@ class JsonFacade(object):
|
|||
|
||||
stack_frame = next(iter(stack_trace_response_body.stackFrames))
|
||||
|
||||
return _JsonHit(frameId=stack_frame['id'], stack_trace_response=stack_trace_response)
|
||||
return _JsonHit(
|
||||
thread_id=thread_id, frame_id=stack_frame['id'], stack_trace_response=stack_trace_response)
|
||||
|
||||
def get_variables_response(self, variables_reference):
|
||||
assert variables_reference < MAX_EXPECTED_ID
|
||||
|
|
@ -192,12 +205,31 @@ class JsonFacade(object):
|
|||
references.append(reference)
|
||||
return references
|
||||
|
||||
def write_continue(self):
|
||||
continue_request = self.write_request(
|
||||
pydevd_schema.ContinueRequest(pydevd_schema.ContinueArguments('*')))
|
||||
|
||||
# The continued event is received before the response.
|
||||
assert self.wait_for_json_message(ContinuedEvent).body.allThreadsContinued
|
||||
|
||||
continue_response = self.wait_for_response(continue_request)
|
||||
assert continue_response.body.allThreadsContinued
|
||||
|
||||
def write_pause(self):
|
||||
pause_request = self.write_request(
|
||||
pydevd_schema.PauseRequest(pydevd_schema.PauseArguments('*')))
|
||||
pause_response = self.wait_for_response(pause_request)
|
||||
assert pause_response.success
|
||||
|
||||
def write_step_in(self, thread_id):
|
||||
arguments = pydevd_schema.StepInArguments(threadId=thread_id)
|
||||
self.wait_for_response(self.write_request(pydevd_schema.StepInRequest(arguments)))
|
||||
|
||||
|
||||
def test_case_json_logpoints(case_setup):
|
||||
with case_setup.test_file('_debugger_case_change_breaks.py') as writer:
|
||||
json_facade = JsonFacade(writer)
|
||||
|
||||
writer.write_set_protocol('http_json')
|
||||
json_facade.write_launch()
|
||||
break_2 = writer.get_line_index_with_content('break 2')
|
||||
break_3 = writer.get_line_index_with_content('break 3')
|
||||
|
|
@ -224,29 +256,24 @@ def test_case_json_logpoints(case_setup):
|
|||
break
|
||||
|
||||
# Just one hit at the end (break 3).
|
||||
hit = writer.wait_for_breakpoint_hit()
|
||||
writer.write_run_thread(hit.thread_id)
|
||||
json_facade.wait_for_thread_stopped(line=break_3)
|
||||
json_facade.write_continue()
|
||||
|
||||
writer.finished_ok = True
|
||||
|
||||
|
||||
@pytest.mark.skipif(IS_JYTHON, reason='Must check why it is failing in Jython.')
|
||||
def test_case_json_change_breaks(case_setup):
|
||||
with case_setup.test_file('_debugger_case_change_breaks.py') as writer:
|
||||
json_facade = JsonFacade(writer)
|
||||
|
||||
writer.write_set_protocol('http_json')
|
||||
json_facade.write_launch()
|
||||
json_facade.write_set_breakpoints(writer.get_line_index_with_content('break 1'))
|
||||
break1_line = writer.get_line_index_with_content('break 1')
|
||||
json_facade.write_set_breakpoints(break1_line)
|
||||
json_facade.write_make_initial_run()
|
||||
hit = writer.wait_for_breakpoint_hit()
|
||||
writer.write_run_thread(hit.thread_id)
|
||||
|
||||
hit = writer.wait_for_breakpoint_hit()
|
||||
writer.write_run_thread(hit.thread_id)
|
||||
|
||||
json_facade.wait_for_thread_stopped(line=break1_line)
|
||||
json_facade.write_set_breakpoints([])
|
||||
writer.write_run_thread(hit.thread_id)
|
||||
json_facade.write_continue()
|
||||
|
||||
writer.finished_ok = True
|
||||
|
||||
|
|
@ -255,21 +282,20 @@ def test_case_handled_exception_breaks(case_setup):
|
|||
with case_setup.test_file('_debugger_case_exceptions.py') as writer:
|
||||
json_facade = JsonFacade(writer)
|
||||
|
||||
writer.write_set_protocol('http_json')
|
||||
json_facade.write_launch()
|
||||
json_facade.write_set_exception_breakpoints(['raised'])
|
||||
json_facade.write_make_initial_run()
|
||||
|
||||
hit = writer.wait_for_breakpoint_hit(
|
||||
reason=REASON_CAUGHT_EXCEPTION, line=writer.get_line_index_with_content('raise indexerror line'))
|
||||
writer.write_run_thread(hit.thread_id)
|
||||
json_facade.wait_for_thread_stopped(
|
||||
reason='exception', line=writer.get_line_index_with_content('raise indexerror line'))
|
||||
json_facade.write_continue()
|
||||
|
||||
hit = writer.wait_for_breakpoint_hit(
|
||||
reason=REASON_CAUGHT_EXCEPTION, line=writer.get_line_index_with_content('reraise on method2'))
|
||||
json_facade.wait_for_thread_stopped(
|
||||
reason='exception', line=writer.get_line_index_with_content('reraise on method2'))
|
||||
|
||||
# Clear so that the last one is not hit.
|
||||
json_facade.write_set_exception_breakpoints([])
|
||||
writer.write_run_thread(hit.thread_id)
|
||||
json_facade.write_continue()
|
||||
|
||||
writer.finished_ok = True
|
||||
|
||||
|
|
@ -278,7 +304,6 @@ def test_case_handled_exception_breaks_by_type(case_setup):
|
|||
with case_setup.test_file('_debugger_case_exceptions.py') as writer:
|
||||
json_facade = JsonFacade(writer)
|
||||
|
||||
writer.write_set_protocol('http_json')
|
||||
json_facade.write_launch()
|
||||
json_facade.write_set_exception_breakpoints(exception_options=[
|
||||
ExceptionOptions(breakMode='always', path=[
|
||||
|
|
@ -288,8 +313,8 @@ def test_case_handled_exception_breaks_by_type(case_setup):
|
|||
])
|
||||
json_facade.write_make_initial_run()
|
||||
|
||||
hit = writer.wait_for_breakpoint_hit(
|
||||
reason=REASON_CAUGHT_EXCEPTION, line=writer.get_line_index_with_content('raise indexerror line'))
|
||||
json_facade.wait_for_thread_stopped(
|
||||
reason='exception', line=writer.get_line_index_with_content('raise indexerror line'))
|
||||
|
||||
# Deal only with RuntimeErorr now.
|
||||
json_facade.write_set_exception_breakpoints(exception_options=[
|
||||
|
|
@ -299,7 +324,7 @@ def test_case_handled_exception_breaks_by_type(case_setup):
|
|||
])
|
||||
])
|
||||
|
||||
writer.write_run_thread(hit.thread_id)
|
||||
json_facade.write_continue()
|
||||
|
||||
writer.finished_ok = True
|
||||
|
||||
|
|
@ -309,16 +334,14 @@ def test_case_json_protocol(case_setup):
|
|||
with case_setup.test_file('_debugger_case_print.py') as writer:
|
||||
json_facade = JsonFacade(writer)
|
||||
|
||||
writer.write_set_protocol('http_json')
|
||||
json_facade.write_launch()
|
||||
json_facade.write_set_breakpoints(writer.get_line_index_with_content('Break here'))
|
||||
break_line = writer.get_line_index_with_content('Break here')
|
||||
json_facade.write_set_breakpoints(break_line)
|
||||
json_facade.write_make_initial_run()
|
||||
|
||||
json_facade.wait_for_json_message(ThreadEvent, lambda event: event.body.reason == 'started')
|
||||
|
||||
hit = writer.wait_for_breakpoint_hit()
|
||||
thread_id = hit.thread_id
|
||||
frame_id = hit.frame_id
|
||||
json_facade.wait_for_thread_stopped(line=break_line)
|
||||
|
||||
# : :type response: ThreadsResponse
|
||||
response = json_facade.write_list_threads()
|
||||
|
|
@ -360,8 +383,6 @@ def test_case_path_translation_not_skipped(case_setup):
|
|||
with case_setup.test_file('my_code/my_code.py', get_environ=get_environ) as writer:
|
||||
json_facade = JsonFacade(writer)
|
||||
|
||||
writer.write_set_protocol('http_json')
|
||||
|
||||
bp_line = writer.get_line_index_with_content('break here')
|
||||
json_facade.write_set_breakpoints(
|
||||
bp_line,
|
||||
|
|
@ -369,11 +390,11 @@ def test_case_path_translation_not_skipped(case_setup):
|
|||
)
|
||||
json_facade.write_make_initial_run()
|
||||
|
||||
hit = writer.wait_for_breakpoint_hit(line=bp_line)
|
||||
json_hit = json_facade.get_stack_as_json_hit(hit.thread_id)
|
||||
json_hit = json_facade.wait_for_thread_stopped(line=bp_line)
|
||||
|
||||
assert json_hit.stack_trace_response.body.stackFrames[-1]['source']['path'] == \
|
||||
os.path.join(sys_folder, 'my_code.py')
|
||||
writer.write_run_thread(hit.thread_id)
|
||||
json_facade.write_continue()
|
||||
|
||||
writer.finished_ok = True
|
||||
|
||||
|
|
@ -390,7 +411,6 @@ def test_case_skipping_filters(case_setup, custom_setup):
|
|||
with case_setup.test_file('my_code/my_code.py') as writer:
|
||||
json_facade = JsonFacade(writer)
|
||||
|
||||
writer.write_set_protocol('http_json')
|
||||
if custom_setup == 'set_exclude_launch_path_match_filename':
|
||||
json_facade.write_launch(
|
||||
debugOptions=['DebugStdLib'],
|
||||
|
|
@ -440,12 +460,13 @@ def test_case_skipping_filters(case_setup, custom_setup):
|
|||
else:
|
||||
raise AssertionError('Unhandled: %s' % (custom_setup,))
|
||||
|
||||
json_facade.write_set_breakpoints(writer.get_line_index_with_content('break here'))
|
||||
break_line = writer.get_line_index_with_content('break here')
|
||||
json_facade.write_set_breakpoints(break_line)
|
||||
json_facade.write_make_initial_run()
|
||||
|
||||
json_facade.wait_for_json_message(ThreadEvent, lambda event: event.body.reason == 'started')
|
||||
|
||||
hit = writer.wait_for_breakpoint_hit()
|
||||
hit = writer.wait_for_breakpoint_hit(line=break_line)
|
||||
|
||||
writer.write_step_in(hit.thread_id)
|
||||
hit = writer.wait_for_breakpoint_hit(reason=REASON_STEP_INTO)
|
||||
|
|
@ -481,7 +502,6 @@ def test_case_completions_json(case_setup):
|
|||
with case_setup.test_file('_debugger_case_completions.py') as writer:
|
||||
json_facade = JsonFacade(writer)
|
||||
|
||||
writer.write_set_protocol('http_json')
|
||||
writer.write_add_breakpoint(writer.get_line_index_with_content('Break here'))
|
||||
|
||||
json_facade.write_make_initial_run()
|
||||
|
|
@ -495,7 +515,7 @@ def test_case_completions_json(case_setup):
|
|||
first_hit = json_hit
|
||||
|
||||
completions_arguments = pydevd_schema.CompletionsArguments(
|
||||
'dict.', 6, frameId=json_hit.frameId, line=0)
|
||||
'dict.', 6, frameId=json_hit.frame_id, line=0)
|
||||
completions_request = json_facade.write_request(
|
||||
pydevd_schema.CompletionsRequest(completions_arguments))
|
||||
|
||||
|
|
@ -505,7 +525,7 @@ def test_case_completions_json(case_setup):
|
|||
assert set(labels).issuperset(set(['__contains__', 'items', 'keys', 'values']))
|
||||
|
||||
completions_arguments = pydevd_schema.CompletionsArguments(
|
||||
'dict.item', 10, frameId=json_hit.frameId)
|
||||
'dict.item', 10, frameId=json_hit.frame_id)
|
||||
completions_request = json_facade.write_request(
|
||||
pydevd_schema.CompletionsRequest(completions_arguments))
|
||||
|
||||
|
|
@ -520,9 +540,9 @@ def test_case_completions_json(case_setup):
|
|||
|
||||
if i == 1:
|
||||
# Check with a previously existing frameId.
|
||||
assert first_hit.frameId != json_hit.frameId
|
||||
assert first_hit.frame_id != json_hit.frame_id
|
||||
completions_arguments = pydevd_schema.CompletionsArguments(
|
||||
'dict.item', 10, frameId=first_hit.frameId)
|
||||
'dict.item', 10, frameId=first_hit.frame_id)
|
||||
completions_request = json_facade.write_request(
|
||||
pydevd_schema.CompletionsRequest(completions_arguments))
|
||||
|
||||
|
|
@ -549,8 +569,6 @@ def test_modules(case_setup):
|
|||
with case_setup.test_file('_debugger_case_local_variables.py') as writer:
|
||||
json_facade = JsonFacade(writer)
|
||||
|
||||
writer.write_set_protocol('http_json')
|
||||
|
||||
writer.write_add_breakpoint(writer.get_line_index_with_content('Break 2 here'))
|
||||
json_facade.write_make_initial_run()
|
||||
|
||||
|
|
@ -580,14 +598,12 @@ def test_stack_and_variables_dict(case_setup):
|
|||
with case_setup.test_file('_debugger_case_local_variables.py') as writer:
|
||||
json_facade = JsonFacade(writer)
|
||||
|
||||
writer.write_set_protocol('http_json')
|
||||
|
||||
writer.write_add_breakpoint(writer.get_line_index_with_content('Break 2 here'))
|
||||
json_facade.write_make_initial_run()
|
||||
|
||||
hit = writer.wait_for_breakpoint_hit()
|
||||
json_hit = json_facade.get_stack_as_json_hit(hit.thread_id)
|
||||
variables_response = json_facade.get_variables_response(json_hit.frameId)
|
||||
variables_response = json_facade.get_variables_response(json_hit.frame_id)
|
||||
|
||||
variables_references = json_facade.pop_variables_reference(variables_response.body.variables)
|
||||
dict_variable_reference = variables_references[2]
|
||||
|
|
@ -632,7 +648,6 @@ def test_stack_and_variables_dict(case_setup):
|
|||
def test_return_value(case_setup):
|
||||
with case_setup.test_file('_debugger_case_return_value.py') as writer:
|
||||
json_facade = JsonFacade(writer)
|
||||
writer.write_set_protocol('http_json')
|
||||
|
||||
break_line = writer.get_line_index_with_content('break here')
|
||||
writer.write_add_breakpoint(break_line)
|
||||
|
|
@ -644,7 +659,7 @@ def test_return_value(case_setup):
|
|||
hit = writer.wait_for_breakpoint_hit(REASON_STEP_OVER, name='<module>', line=break_line + 1)
|
||||
|
||||
json_hit = json_facade.get_stack_as_json_hit(hit.thread_id)
|
||||
variables_response = json_facade.get_variables_response(json_hit.frameId)
|
||||
variables_response = json_facade.get_variables_response(json_hit.frame_id)
|
||||
return_variables = json_facade.filter_return_variables(variables_response.body.variables)
|
||||
assert return_variables == [{
|
||||
'name': '(return) method1',
|
||||
|
|
@ -662,14 +677,12 @@ def test_stack_and_variables_set_and_list(case_setup):
|
|||
with case_setup.test_file('_debugger_case_local_variables2.py') as writer:
|
||||
json_facade = JsonFacade(writer)
|
||||
|
||||
writer.write_set_protocol('http_json')
|
||||
|
||||
writer.write_add_breakpoint(writer.get_line_index_with_content('Break here'))
|
||||
json_facade.write_make_initial_run()
|
||||
|
||||
hit = writer.wait_for_breakpoint_hit()
|
||||
json_hit = json_facade.get_stack_as_json_hit(hit.thread_id)
|
||||
variables_response = json_facade.get_variables_response(json_hit.frameId)
|
||||
variables_response = json_facade.get_variables_response(json_hit.frame_id)
|
||||
|
||||
variables_references = json_facade.pop_variables_reference(variables_response.body.variables)
|
||||
if IS_PY2:
|
||||
|
|
@ -714,8 +727,6 @@ def test_evaluate_unicode(case_setup):
|
|||
with case_setup.test_file('_debugger_case_local_variables.py') as writer:
|
||||
json_facade = JsonFacade(writer)
|
||||
|
||||
writer.write_set_protocol('http_json')
|
||||
|
||||
writer.write_add_breakpoint(writer.get_line_index_with_content('Break 2 here'))
|
||||
json_facade.write_make_initial_run()
|
||||
|
||||
|
|
@ -723,7 +734,7 @@ def test_evaluate_unicode(case_setup):
|
|||
json_hit = json_facade.get_stack_as_json_hit(hit.thread_id)
|
||||
|
||||
evaluate_response = json_facade.wait_for_response(
|
||||
json_facade.write_request(EvaluateRequest(EvaluateArguments(u'\u16A0', json_hit.frameId))))
|
||||
json_facade.write_request(EvaluateRequest(EvaluateArguments(u'\u16A0', json_hit.frame_id))))
|
||||
|
||||
evaluate_response_body = evaluate_response.body.to_dict()
|
||||
|
||||
|
|
@ -769,8 +780,6 @@ def test_evaluate_variable_references(case_setup):
|
|||
with case_setup.test_file('_debugger_case_local_variables2.py') as writer:
|
||||
json_facade = JsonFacade(writer)
|
||||
|
||||
writer.write_set_protocol('http_json')
|
||||
|
||||
writer.write_add_breakpoint(writer.get_line_index_with_content('Break here'))
|
||||
json_facade.write_make_initial_run()
|
||||
|
||||
|
|
@ -778,7 +787,7 @@ def test_evaluate_variable_references(case_setup):
|
|||
json_hit = json_facade.get_stack_as_json_hit(hit.thread_id)
|
||||
|
||||
evaluate_response = json_facade.wait_for_response(
|
||||
json_facade.write_request(EvaluateRequest(EvaluateArguments('variable_for_test_2', json_hit.frameId))))
|
||||
json_facade.write_request(EvaluateRequest(EvaluateArguments('variable_for_test_2', json_hit.frame_id))))
|
||||
|
||||
evaluate_response_body = evaluate_response.body.to_dict()
|
||||
|
||||
|
|
@ -821,8 +830,6 @@ def test_set_expression(case_setup):
|
|||
with case_setup.test_file('_debugger_case_local_variables2.py') as writer:
|
||||
json_facade = JsonFacade(writer)
|
||||
|
||||
writer.write_set_protocol('http_json')
|
||||
|
||||
writer.write_add_breakpoint(writer.get_line_index_with_content('Break here'))
|
||||
json_facade.write_make_initial_run()
|
||||
|
||||
|
|
@ -831,11 +838,11 @@ def test_set_expression(case_setup):
|
|||
|
||||
set_expression_response = json_facade.wait_for_response(
|
||||
json_facade.write_request(SetExpressionRequest(
|
||||
SetExpressionArguments('bb', '20', frameId=json_hit.frameId))))
|
||||
SetExpressionArguments('bb', '20', frameId=json_hit.frame_id))))
|
||||
assert set_expression_response.to_dict()['body'] == {
|
||||
'value': '20', 'type': 'int', 'presentationHint': {}, 'variablesReference': 0}
|
||||
|
||||
variables_response = json_facade.get_variables_response(json_hit.frameId)
|
||||
variables_response = json_facade.get_variables_response(json_hit.frame_id)
|
||||
assert {'name': 'bb', 'value': '20', 'type': 'int', 'evaluateName': 'bb'} in \
|
||||
variables_response.to_dict()['body']['variables']
|
||||
|
||||
|
|
@ -849,7 +856,6 @@ def test_stack_and_variables(case_setup):
|
|||
with case_setup.test_file('_debugger_case_local_variables.py') as writer:
|
||||
json_facade = JsonFacade(writer)
|
||||
|
||||
writer.write_set_protocol('http_json')
|
||||
writer.write_add_breakpoint(writer.get_line_index_with_content('Break here'))
|
||||
|
||||
json_facade.write_make_initial_run()
|
||||
|
|
@ -975,7 +981,6 @@ def test_hex_variables(case_setup):
|
|||
with case_setup.test_file('_debugger_case_local_variables_hex.py') as writer:
|
||||
json_facade = JsonFacade(writer)
|
||||
|
||||
writer.write_set_protocol('http_json')
|
||||
writer.write_add_breakpoint(writer.get_line_index_with_content('Break here'))
|
||||
|
||||
json_facade.write_make_initial_run()
|
||||
|
|
@ -1051,33 +1056,40 @@ def test_hex_variables(case_setup):
|
|||
writer.finished_ok = True
|
||||
|
||||
|
||||
@pytest.mark.skipif(IS_JYTHON, reason='Flaky on Jython.')
|
||||
def test_pause_and_continue(case_setup):
|
||||
with case_setup.test_file('_debugger_case_pause_continue.py') as writer:
|
||||
def test_stopped_event(case_setup):
|
||||
with case_setup.test_file('_debugger_case_print.py') as writer:
|
||||
json_facade = JsonFacade(writer)
|
||||
|
||||
writer.write_multi_threads_single_notification(True)
|
||||
writer.write_set_protocol('http_json')
|
||||
writer.write_add_breakpoint(writer.get_line_index_with_content('Break here'))
|
||||
|
||||
json_facade.write_make_initial_run()
|
||||
|
||||
hit = writer.wait_for_breakpoint_hit()
|
||||
json_hit = json_facade.wait_for_thread_stopped()
|
||||
assert json_hit.thread_id
|
||||
|
||||
continue_request = json_facade.write_request(
|
||||
pydevd_schema.ContinueRequest(pydevd_schema.ContinueArguments('*')))
|
||||
continue_response = json_facade.wait_for_response(continue_request)
|
||||
assert continue_response.body.allThreadsContinued
|
||||
json_facade.write_continue()
|
||||
|
||||
pause_request = json_facade.write_request(
|
||||
pydevd_schema.PauseRequest(pydevd_schema.PauseArguments('*')))
|
||||
pause_response = json_facade.wait_for_response(pause_request)
|
||||
hit = writer.wait_for_breakpoint_hit(reason=REASON_THREAD_SUSPEND)
|
||||
writer.finished_ok = True
|
||||
|
||||
stack_trace_request = json_facade.write_request(
|
||||
pydevd_schema.StackTraceRequest(pydevd_schema.StackTraceArguments(threadId=hit.thread_id)))
|
||||
stack_trace_response = json_facade.wait_for_response(stack_trace_request)
|
||||
stack_frame = next(iter(stack_trace_response.body.stackFrames))
|
||||
|
||||
@pytest.mark.skipif(IS_JYTHON, reason='Not Jython compatible (fails on set variable).')
|
||||
def test_pause_and_continue(case_setup):
|
||||
with case_setup.test_file('_debugger_case_pause_continue.py') as writer:
|
||||
json_facade = JsonFacade(writer)
|
||||
|
||||
json_facade.write_set_breakpoints(writer.get_line_index_with_content('Break here'))
|
||||
|
||||
json_facade.write_make_initial_run()
|
||||
|
||||
json_facade.wait_for_thread_stopped()
|
||||
|
||||
json_facade.write_continue()
|
||||
|
||||
json_facade.write_pause()
|
||||
|
||||
json_hit = json_facade.wait_for_thread_stopped(reason="pause")
|
||||
|
||||
stack_frame = next(iter(json_hit.stack_trace_response.body.stackFrames))
|
||||
|
||||
scopes_request = json_facade.write_request(pydevd_schema.ScopesRequest(
|
||||
pydevd_schema.ScopesArguments(stack_frame['id'])))
|
||||
|
|
@ -1093,10 +1105,7 @@ def test_pause_and_continue(case_setup):
|
|||
set_variable_response_as_dict = set_variable_response.to_dict()['body']
|
||||
assert set_variable_response_as_dict == {'value': "False", 'type': 'bool'}
|
||||
|
||||
continue_request = json_facade.write_request(
|
||||
pydevd_schema.ContinueRequest(pydevd_schema.ContinueArguments('*')))
|
||||
continue_response = json_facade.wait_for_response(continue_request)
|
||||
assert continue_response.body.allThreadsContinued
|
||||
json_facade.write_continue()
|
||||
|
||||
writer.finished_ok = True
|
||||
|
||||
|
|
@ -1105,7 +1114,6 @@ def test_stepping(case_setup):
|
|||
with case_setup.test_file('_debugger_case_stepping.py') as writer:
|
||||
json_facade = JsonFacade(writer)
|
||||
|
||||
writer.write_set_protocol('http_json')
|
||||
writer.write_add_breakpoint(writer.get_line_index_with_content('Break here 1'))
|
||||
writer.write_add_breakpoint(writer.get_line_index_with_content('Break here 2'))
|
||||
|
||||
|
|
@ -1176,7 +1184,6 @@ def test_evaluate(case_setup):
|
|||
with case_setup.test_file('_debugger_case_evaluate.py') as writer:
|
||||
json_facade = JsonFacade(writer)
|
||||
|
||||
writer.write_set_protocol('http_json')
|
||||
writer.write_add_breakpoint(writer.get_line_index_with_content('Break here'))
|
||||
|
||||
json_facade.write_make_initial_run()
|
||||
|
|
@ -1220,7 +1227,6 @@ def test_exception_details(case_setup, max_frames):
|
|||
with case_setup.test_file('_debugger_case_large_exception_stack.py') as writer:
|
||||
json_facade = JsonFacade(writer)
|
||||
|
||||
writer.write_set_protocol('http_json')
|
||||
if max_frames == 'all':
|
||||
json_facade.write_launch(maxExceptionStackFrames=0)
|
||||
# trace back compresses repeated text
|
||||
|
|
@ -1248,7 +1254,7 @@ def test_exception_details(case_setup, max_frames):
|
|||
body = exc_info_response.body
|
||||
assert body.exceptionId.endswith('IndexError')
|
||||
assert body.description == 'foo'
|
||||
assert body.details.kwargs['source'] == writer.TEST_FILE
|
||||
assert normcase(body.details.kwargs['source']) == normcase(writer.TEST_FILE)
|
||||
stack_line_count = len(body.details.stackTrace.split('\n'))
|
||||
assert min_expected_lines <= stack_line_count <= max_expected_lines
|
||||
|
||||
|
|
@ -1262,7 +1268,6 @@ def test_stack_levels(case_setup):
|
|||
with case_setup.test_file('_debugger_case_deep_stacks.py') as writer:
|
||||
json_facade = JsonFacade(writer)
|
||||
|
||||
writer.write_set_protocol('http_json')
|
||||
writer.write_add_breakpoint(writer.get_line_index_with_content('Break here'))
|
||||
|
||||
json_facade.write_make_initial_run()
|
||||
|
|
@ -1331,7 +1336,6 @@ def test_goto(case_setup):
|
|||
with case_setup.test_file('_debugger_case_set_next_statement.py') as writer:
|
||||
json_facade = JsonFacade(writer)
|
||||
|
||||
writer.write_set_protocol('http_json')
|
||||
break_line = writer.get_line_index_with_content('Break here')
|
||||
step_line = writer.get_line_index_with_content('Step here')
|
||||
writer.write_add_breakpoint(break_line)
|
||||
|
|
@ -1382,12 +1386,12 @@ def test_goto(case_setup):
|
|||
|
||||
writer.finished_ok = True
|
||||
|
||||
|
||||
@pytest.mark.parametrize('dbg_property', ['dont_trace', 'trace', 'change_pattern', 'dont_trace_after_start'])
|
||||
def test_set_debugger_property(case_setup, dbg_property):
|
||||
with case_setup.test_file('_debugger_case_dont_trace_test.py') as writer:
|
||||
json_facade = JsonFacade(writer)
|
||||
|
||||
writer.write_set_protocol('http_json')
|
||||
writer.write_add_breakpoint(writer.get_line_index_with_content('Break here'))
|
||||
|
||||
if dbg_property in ('dont_trace', 'change_pattern', 'dont_trace_after_start'):
|
||||
|
|
@ -1473,7 +1477,6 @@ def test_path_translation_and_source_reference(case_setup):
|
|||
|
||||
json_facade = JsonFacade(writer)
|
||||
|
||||
writer.write_set_protocol('http_json')
|
||||
bp_line = writer.get_line_index_with_content('break here')
|
||||
writer.write_add_breakpoint(
|
||||
bp_line, 'call_this', filename=file_in_client)
|
||||
|
|
@ -1530,7 +1533,7 @@ def test_source_reference_no_file(case_setup, tmpdir):
|
|||
|
||||
with case_setup.test_file('_debugger_case_source_reference.py', get_environ=get_environ) as writer:
|
||||
json_facade = JsonFacade(writer)
|
||||
writer.write_set_protocol('http_json')
|
||||
|
||||
writer.write_add_breakpoint(writer.get_line_index_with_content('breakpoint'))
|
||||
json_facade.write_make_initial_run()
|
||||
|
||||
|
|
@ -1591,7 +1594,6 @@ def test_case_django_no_attribute_exception_breakpoint(case_setup_django, jmc):
|
|||
|
||||
with case_setup_django.test_file(EXPECTED_RETURNCODE='any') as writer:
|
||||
json_facade = JsonFacade(writer)
|
||||
writer.write_set_protocol('http_json')
|
||||
|
||||
if jmc:
|
||||
writer.write_set_project_roots([debugger_unittest._get_debugger_test_file('my_code')])
|
||||
|
|
@ -1627,7 +1629,7 @@ def test_case_django_no_attribute_exception_breakpoint(case_setup_django, jmc):
|
|||
assert stack_frame['source']['path'].endswith('template_error.html')
|
||||
|
||||
json_hit = json_facade.get_stack_as_json_hit(hit.thread_id)
|
||||
variables_response = json_facade.get_variables_response(json_hit.frameId)
|
||||
variables_response = json_facade.get_variables_response(json_hit.frame_id)
|
||||
entries = [x for x in variables_response.to_dict()['body']['variables'] if x['name'] == 'entry']
|
||||
assert len(entries) == 1
|
||||
variables_response = json_facade.get_variables_response(entries[0]['variablesReference'])
|
||||
|
|
@ -1645,7 +1647,6 @@ def test_case_django_no_attribute_exception_breakpoint(case_setup_django, jmc):
|
|||
def test_case_flask_exceptions(case_setup_flask, jmc):
|
||||
with case_setup_flask.test_file(EXPECTED_RETURNCODE='any') as writer:
|
||||
json_facade = JsonFacade(writer)
|
||||
writer.write_set_protocol('http_json')
|
||||
|
||||
if jmc:
|
||||
writer.write_set_project_roots([debugger_unittest._get_debugger_test_file('my_code')])
|
||||
|
|
@ -1684,7 +1685,7 @@ def test_redirect_output(case_setup):
|
|||
|
||||
with case_setup.test_file('_debugger_case_redirect.py', get_environ=get_environ) as writer:
|
||||
original_ignore_stderr_line = writer._ignore_stderr_line
|
||||
writer.write_set_protocol('http_json')
|
||||
|
||||
json_facade = JsonFacade(writer)
|
||||
|
||||
@overrides(writer._ignore_stderr_line)
|
||||
|
|
|
|||
|
|
@ -7,7 +7,18 @@ from tests_python.debug_constants import IS_PY26, IS_PY3K
|
|||
|
||||
def test_is_main_thread():
|
||||
from _pydevd_bundle.pydevd_utils import is_current_thread_main_thread
|
||||
assert is_current_thread_main_thread()
|
||||
if not is_current_thread_main_thread():
|
||||
error_msg = 'Current thread does not seem to be a main thread. Details:\n'
|
||||
current_thread = threading.current_thread()
|
||||
error_msg += 'Current thread: %s\n' % (current_thread,)
|
||||
|
||||
if hasattr(threading, 'main_thread'):
|
||||
error_msg += 'Main thread found: %s\n' % (threading.main_thread(),)
|
||||
else:
|
||||
error_msg += 'Current main thread not instance of: %s (%s)' % (
|
||||
threading._MainThread, current_thread.__class__.__mro__,)
|
||||
|
||||
raise AssertionError(error_msg)
|
||||
|
||||
class NonMainThread(threading.Thread):
|
||||
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ class DebugSession(Startable, Closeable):
|
|||
return raw
|
||||
if not is_socket(raw):
|
||||
# TODO: Create a new client socket from a remote address?
|
||||
#addr = Address.from_raw(raw)
|
||||
# addr = Address.from_raw(raw)
|
||||
raise NotImplementedError
|
||||
client = raw
|
||||
return cls(client, **kwargs)
|
||||
|
|
@ -42,9 +42,11 @@ class DebugSession(Startable, Closeable):
|
|||
super(DebugSession, self).__init__()
|
||||
|
||||
if notify_closing is not None:
|
||||
|
||||
def handle_closing(before):
|
||||
if before:
|
||||
notify_closing(self)
|
||||
|
||||
self.add_close_handler(handle_closing)
|
||||
|
||||
if notify_disconnecting is None:
|
||||
|
|
@ -54,6 +56,7 @@ class DebugSession(Startable, Closeable):
|
|||
self._sock = sock
|
||||
self._pre_socket_close = None
|
||||
if ownsock:
|
||||
|
||||
# Close the socket *after* calling sys.exit() (via notify_closing).
|
||||
def handle_closing(before):
|
||||
if before:
|
||||
|
|
@ -68,6 +71,7 @@ class DebugSession(Startable, Closeable):
|
|||
except TimeoutError:
|
||||
ptvsd.log.exception('timed out waiting for disconnect', category='D')
|
||||
close_socket(self._sock)
|
||||
|
||||
self.add_close_handler(handle_closing)
|
||||
|
||||
self._msgprocessor = None
|
||||
|
|
@ -171,6 +175,7 @@ class PyDevdDebugSession(DebugSession):
|
|||
self._notified_debugger_ready = True
|
||||
if _notify is not None:
|
||||
_notify(session)
|
||||
|
||||
self._notified_debugger_ready = False
|
||||
self._notify_debugger_ready = notify_debugger_ready
|
||||
|
||||
|
|
@ -178,7 +183,11 @@ class PyDevdDebugSession(DebugSession):
|
|||
if self._msgprocessor is None:
|
||||
# TODO: Do more than ignore?
|
||||
return
|
||||
return self._msgprocessor.on_pydevd_event(cmdid, seq, text)
|
||||
try:
|
||||
return self._msgprocessor.on_pydevd_event(cmdid, seq, text)
|
||||
except:
|
||||
ptvsd.log.exception('Error handling pydevd message: {0}', text)
|
||||
raise
|
||||
|
||||
# internal methods
|
||||
|
||||
|
|
|
|||
|
|
@ -51,19 +51,6 @@ from ptvsd.socket import TimeoutError # noqa
|
|||
|
||||
WAIT_FOR_THREAD_FINISH_TIMEOUT = 1 # seconds
|
||||
|
||||
STEP_REASONS = {
|
||||
pydevd_comm.CMD_STEP_INTO,
|
||||
pydevd_comm.CMD_STEP_INTO_MY_CODE,
|
||||
pydevd_comm.CMD_STEP_OVER,
|
||||
pydevd_comm.CMD_STEP_OVER_MY_CODE,
|
||||
pydevd_comm.CMD_STEP_RETURN,
|
||||
pydevd_comm.CMD_STEP_INTO_MY_CODE,
|
||||
}
|
||||
EXCEPTION_REASONS = {
|
||||
pydevd_comm.CMD_STEP_CAUGHT_EXCEPTION,
|
||||
pydevd_comm.CMD_ADD_EXCEPTION_BREAK
|
||||
}
|
||||
|
||||
debugger_attached = threading.Event()
|
||||
|
||||
|
||||
|
|
@ -78,12 +65,14 @@ def path_to_unicode(s):
|
|||
PTVSD_DIR_PATH = os.path.dirname(os.path.abspath(get_abs_path_real_path_and_base_from_file(__file__)[0])) + os.path.sep
|
||||
NORM_PTVSD_DIR_PATH = os.path.normcase(PTVSD_DIR_PATH)
|
||||
|
||||
|
||||
def dont_trace_ptvsd_files(py_db, file_path):
|
||||
"""
|
||||
Returns true if the file should not be traced.
|
||||
"""
|
||||
return file_path.startswith(PTVSD_DIR_PATH) or file_path.endswith('ptvsd_launcher.py')
|
||||
|
||||
|
||||
pydevd.PyDB.dont_trace_external_files = dont_trace_ptvsd_files
|
||||
|
||||
|
||||
|
|
@ -1333,11 +1322,11 @@ class VSCodeMessageProcessor(VSCLifecycleMsgProcessor):
|
|||
|
||||
# Don't trace files under ptvsd, and ptvsd_launcher.py files
|
||||
# TODO: un-comment this code after fixing https://github.com/Microsoft/ptvsd/issues/1355
|
||||
#dont_trace_request = self._get_new_setDebuggerProperty_request(
|
||||
# dont_trace_request = self._get_new_setDebuggerProperty_request(
|
||||
# dontTraceStartPatterns=[PTVSD_DIR_PATH],
|
||||
# dontTraceEndPatterns=['ptvsd_launcher.py']
|
||||
#)
|
||||
#yield self.pydevd_request(-1, dont_trace_request, is_json=True)
|
||||
# )
|
||||
# yield self.pydevd_request(-1, dont_trace_request, is_json=True)
|
||||
|
||||
def _handle_detach(self):
|
||||
ptvsd.log.info('Detaching ...')
|
||||
|
|
@ -1745,84 +1734,50 @@ class VSCodeMessageProcessor(VSCLifecycleMsgProcessor):
|
|||
pass # We only care about the thread suspend single notification.
|
||||
|
||||
@pydevd_events.handler(pydevd_comm_constants.CMD_THREAD_SUSPEND_SINGLE_NOTIFICATION)
|
||||
@async_handler
|
||||
def on_pydevd_thread_suspend_single_notification(self, seq, args):
|
||||
# NOTE: We should add the thread to VSC thread map only if the
|
||||
# thread is seen here for the first time in 'attach' scenario.
|
||||
# If we are here in 'launch' scenario and we get KeyError then
|
||||
# there is an issue in reporting of thread creation.
|
||||
suspend_info = json.loads(args)
|
||||
pyd_tid = suspend_info['thread_id']
|
||||
reason = suspend_info['stop_reason']
|
||||
body = args.get('body', {})
|
||||
|
||||
pyd_tid = body['threadId']
|
||||
autogen = self.start_reason == 'attach'
|
||||
vsc_tid = self.thread_map.to_vscode(pyd_tid, autogen=autogen)
|
||||
|
||||
exc_desc = None
|
||||
exc_name = None
|
||||
extra = {}
|
||||
if reason in STEP_REASONS:
|
||||
reason = 'step'
|
||||
elif reason in EXCEPTION_REASONS:
|
||||
reason = 'exception'
|
||||
elif reason == pydevd_comm.CMD_SET_BREAK:
|
||||
reason = 'breakpoint'
|
||||
elif reason == pydevd_comm.CMD_SET_NEXT_STATEMENT:
|
||||
reason = 'goto'
|
||||
else:
|
||||
reason = 'pause'
|
||||
|
||||
extra['preserveFocusHint'] = \
|
||||
reason not in ['step', 'exception', 'breakpoint']
|
||||
|
||||
reason = body['reason']
|
||||
if reason == 'exception':
|
||||
pydevd_request = {
|
||||
'type': 'request',
|
||||
'command': 'exceptionInfo',
|
||||
'arguments': {
|
||||
'threadId': pyd_tid
|
||||
},
|
||||
}
|
||||
exc_name = body['text']
|
||||
exc_desc = body['description']
|
||||
|
||||
_, _, resp_args = yield self.pydevd_request(
|
||||
pydevd_comm.CMD_GET_EXCEPTION_DETAILS,
|
||||
pydevd_request,
|
||||
is_json=True)
|
||||
exc_name = resp_args['body']['exceptionId']
|
||||
exc_desc = resp_args['body']['description']
|
||||
if not self.debug_options.get('BREAK_SYSTEMEXIT_ZERO', False) and exc_name == 'SystemExit':
|
||||
ptvsd.log.info('{0}({1!r})', exc_name, exc_desc)
|
||||
try:
|
||||
exit_code = int(exc_desc)
|
||||
except ValueError:
|
||||
# It is legal to invoke exit() with a non-integer argument, and SystemExit will
|
||||
# pass that through. It's considered an error exit, same as non-zero integer.
|
||||
ptvsd.log.info('Exit code {0!r} cannot be converted to int, treating as failure', exc_desc)
|
||||
ignore = False
|
||||
else:
|
||||
ignore = exit_code in self._success_exitcodes
|
||||
ptvsd.log.info(
|
||||
'Process exiting with {0} exit code {1}',
|
||||
'success' if ignore else 'failure',
|
||||
exc_desc,
|
||||
)
|
||||
if ignore:
|
||||
self._resume_all_threads()
|
||||
return
|
||||
|
||||
if not self.debug_options.get('BREAK_SYSTEMEXIT_ZERO', False) and exc_name == 'SystemExit':
|
||||
ptvsd.log.info('{0}({1!r})', exc_name, exc_desc)
|
||||
try:
|
||||
exit_code = int(exc_desc)
|
||||
except ValueError:
|
||||
# It is legal to invoke exit() with a non-integer argument, and SystemExit will
|
||||
# pass that through. It's considered an error exit, same as non-zero integer.
|
||||
ptvsd.log.info('Exit code {0!r} cannot be converted to int, treating as failure', exc_desc)
|
||||
ignore = False
|
||||
else:
|
||||
ignore = exit_code in self._success_exitcodes
|
||||
ptvsd.log.info(
|
||||
'Process exiting with {0} exit code {1}',
|
||||
'success' if ignore else 'failure',
|
||||
exc_desc,
|
||||
)
|
||||
if ignore:
|
||||
self._resume_all_threads()
|
||||
return
|
||||
|
||||
extra['allThreadsStopped'] = True
|
||||
self.send_event(
|
||||
'stopped',
|
||||
reason=reason,
|
||||
threadId=vsc_tid,
|
||||
text=exc_name,
|
||||
description=exc_desc,
|
||||
**extra)
|
||||
body = body.copy()
|
||||
body['threadId'] = vsc_tid
|
||||
self.send_event('stopped', **body)
|
||||
|
||||
@pydevd_events.handler(pydevd_comm_constants.CMD_THREAD_RESUME_SINGLE_NOTIFICATION)
|
||||
def on_pydevd_thread_resume_single_notification(self, seq, args):
|
||||
resumed_info = json.loads(args)
|
||||
pyd_tid = resumed_info['thread_id']
|
||||
body = args.get('body', {})
|
||||
pyd_tid = body['threadId']
|
||||
|
||||
try:
|
||||
vsc_tid = self.thread_map.to_vscode(pyd_tid, autogen=False)
|
||||
|
|
|
|||
|
|
@ -56,7 +56,11 @@ def test_vsc_exception_options_raise_with_except(pyfile, run_as, start_method, r
|
|||
})
|
||||
|
||||
if raised == 'raisedOn':
|
||||
hit = session.wait_for_thread_stopped(reason='exception')
|
||||
hit = session.wait_for_thread_stopped(
|
||||
reason='exception',
|
||||
text=ANY.such_that(lambda s: s.endswith('ArithmeticError')),
|
||||
description='bad code',
|
||||
)
|
||||
frames = hit.stacktrace.body['stackFrames']
|
||||
assert ex_line == frames[0]['line']
|
||||
|
||||
|
|
@ -313,6 +317,7 @@ def test_raise_exception_options(pyfile, run_as, start_method, exceptions, break
|
|||
|
||||
@pytest.mark.parametrize('exit_code', [0, 3])
|
||||
def test_success_exitcodes(pyfile, run_as, start_method, exit_code):
|
||||
|
||||
@pyfile
|
||||
def code_to_debug():
|
||||
from dbgimporter import import_and_enable_debugger
|
||||
|
|
@ -344,17 +349,19 @@ def test_success_exitcodes(pyfile, run_as, start_method, exit_code):
|
|||
|
||||
@pytest.mark.parametrize('max_frames', ['default', 'all', 10])
|
||||
def test_exception_stack(pyfile, run_as, start_method, max_frames):
|
||||
|
||||
@pyfile
|
||||
def code_to_debug():
|
||||
from dbgimporter import import_and_enable_debugger
|
||||
import_and_enable_debugger()
|
||||
|
||||
def do_something(n):
|
||||
if n <= 0:
|
||||
raise ArithmeticError('bad code') # @unhandled
|
||||
raise ArithmeticError('bad code') # @unhandled
|
||||
do_something2(n - 1)
|
||||
|
||||
def do_something2(n):
|
||||
do_something(n-1)
|
||||
do_something(n - 1)
|
||||
|
||||
do_something(100)
|
||||
|
||||
|
|
|
|||
|
|
@ -636,10 +636,21 @@ class DebugSession(object):
|
|||
'breakpoints': [{'line': bp_line} for bp_line in lines],
|
||||
}).wait_for_response().body.get('breakpoints', None)
|
||||
|
||||
def wait_for_thread_stopped(self, reason=ANY):
|
||||
def wait_for_thread_stopped(self, reason=ANY, text=None, description=None):
|
||||
thread_stopped = self.wait_for_next(Event('stopped', ANY.dict_with({'reason': reason})))
|
||||
|
||||
if text is not None:
|
||||
assert text == thread_stopped.body['text']
|
||||
|
||||
if description is not None:
|
||||
assert description == thread_stopped.body['description']
|
||||
|
||||
tid = thread_stopped.body['threadId']
|
||||
|
||||
assert thread_stopped.body['allThreadsStopped']
|
||||
assert thread_stopped.body['preserveFocusHint'] == \
|
||||
(thread_stopped.body['reason'] not in ['step', 'exception', 'breakpoint'])
|
||||
|
||||
assert tid is not None
|
||||
|
||||
resp_stacktrace = self.send_request('stackTrace', arguments={
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue