#653: unhandled exceptions no longer reported twice. (#671)

This commit is contained in:
Fabio Zadrozny 2018-07-18 14:12:48 -03:00 committed by Karthik Nadig
parent c99f884ae0
commit f8d324a4fc
13 changed files with 541 additions and 106 deletions

View file

@ -1,49 +1,35 @@
def overrides(method):
'''
Initially meant to be used as
Meant to be used as
class B:
@overrides(A.m1)
def m1(self):
pass
but as we want to be compatible with Jython 2.1 where decorators have an uglier syntax (needing an assign
after the method), it should now be used without being a decorator as below (in which case we don't even check
for anything, just that the parent name was actually properly loaded).
i.e.:
class B:
overrides(A.m1)
def m1(self):
pass
'''
return
def wrapper(func):
if func.__name__ != method.__name__:
msg = "Wrong @override: %r expected, but overwriting %r."
msg = msg % (func.__name__, method.__name__)
raise AssertionError(msg)
# def wrapper(func):
# if func.__name__ != method.__name__:
# msg = "Wrong @override: %r expected, but overwriting %r."
# msg = msg % (func.__name__, method.__name__)
# raise AssertionError(msg)
#
# if func.__doc__ is None:
# func.__doc__ = method.__doc__
#
# return func
#
# return wrapper
if func.__doc__ is None:
func.__doc__ = method.__doc__
return func
return wrapper
def implements(method):
return
# def wrapper(func):
# if func.__name__ != method.__name__:
# msg = "Wrong @implements: %r expected, but implementing %r."
# msg = msg % (func.__name__, method.__name__)
# raise AssertionError(msg)
#
# if func.__doc__ is None:
# func.__doc__ = method.__doc__
#
# return func
#
# return wrapper
def wrapper(func):
if func.__name__ != method.__name__:
msg = "Wrong @implements: %r expected, but implementing %r."
msg = msg % (func.__name__, method.__name__)
raise AssertionError(msg)
if func.__doc__ is None:
func.__doc__ = method.__doc__
return func
return wrapper

View file

@ -77,6 +77,7 @@ class PyDBAdditionalThreadInfo(object):
# cdef public int suspend_type;
# cdef public int pydev_next_line;
# cdef public str pydev_func_name;
# cdef public bint suspended_at_unhandled;
# ELSE
__slots__ = [
'pydev_state',
@ -93,6 +94,7 @@ class PyDBAdditionalThreadInfo(object):
'suspend_type',
'pydev_next_line',
'pydev_func_name',
'suspended_at_unhandled',
]
# ENDIF
@ -111,6 +113,7 @@ class PyDBAdditionalThreadInfo(object):
self.suspend_type = PYTHON_SUSPEND
self.pydev_next_line = -1
self.pydev_func_name = '.invalid.' # Must match the type in cython
self.suspended_at_unhandled = False
def iter_frames(self, t):
# sys._current_frames(): dictionary with thread id -> topmost frame

View file

@ -66,7 +66,7 @@ class ConsoleMessage:
#=======================================================================================================================
class DebugConsoleStdIn(BaseStdIn):
overrides(BaseStdIn.readline)
@overrides(BaseStdIn.readline)
def readline(self, *args, **kwargs):
sys.stderr.write('Warning: Reading from stdin is still not supported in this console.\n')
return '\n'
@ -79,7 +79,7 @@ class DebugConsole(InteractiveConsole, BaseInterpreterInterface):
errors and outputs to the debug console
"""
overrides(BaseInterpreterInterface.create_std_in)
@overrides(BaseInterpreterInterface.create_std_in)
def create_std_in(self, *args, **kwargs):
try:
if not self.__buffer_output:
@ -90,7 +90,7 @@ class DebugConsole(InteractiveConsole, BaseInterpreterInterface):
return DebugConsoleStdIn() #If buffered, raw_input is not supported in this console.
overrides(InteractiveConsole.push)
@overrides(InteractiveConsole.push)
def push(self, line, frame, buffer_output=True):
"""Change built-in stdout and stderr methods by the
new custom StdMessage.
@ -134,12 +134,12 @@ class DebugConsole(InteractiveConsole, BaseInterpreterInterface):
return more, [], []
overrides(BaseInterpreterInterface.do_add_exec)
@overrides(BaseInterpreterInterface.do_add_exec)
def do_add_exec(self, line):
return InteractiveConsole.push(self, line)
overrides(InteractiveConsole.runcode)
@overrides(InteractiveConsole.runcode)
def runcode(self, code):
"""Execute a code object.

View file

@ -51,7 +51,7 @@ def trace_dispatch(py_db, frame, event, arg):
if name == 'threading':
if f_unhandled.f_code.co_name in ('__bootstrap', '_bootstrap'):
# We need __bootstrap_inner, not __bootstrap.
return py_db.trace_dispatch
return None
elif f_unhandled.f_code.co_name in ('__bootstrap_inner', '_bootstrap_inner'):
# Note: be careful not to use threading.currentThread to avoid creating a dummy thread.
@ -62,6 +62,10 @@ def trace_dispatch(py_db, frame, event, arg):
break
elif name == 'pydevd':
if f_unhandled.f_code.co_name in ('run', 'main'):
# We need to get to _exec
return None
if f_unhandled.f_code.co_name == '_exec':
only_trace_for_unhandled_exceptions = True
break
@ -92,7 +96,7 @@ def trace_dispatch(py_db, frame, event, arg):
thread_tracer = ThreadTracer((py_db, thread, additional_info, global_cache_skips, global_cache_frame_skips))
if f_unhandled is not None:
# print(' --> found', f_unhandled.f_code.co_name, f_unhandled.f_code.co_filename, f_unhandled.f_code.co_firstlineno)
# print(' --> found to trace unhandled', f_unhandled.f_code.co_name, f_unhandled.f_code.co_filename, f_unhandled.f_code.co_firstlineno)
if only_trace_for_unhandled_exceptions:
f_trace = thread_tracer.trace_unhandled_exceptions
else:
@ -135,7 +139,9 @@ class PyDbFrameTraceAndUnhandledExceptionsTrace(object):
self._unhandled_trace = unhandled_trace
def trace_dispatch(self, frame, event, arg):
# print('PyDbFrameTraceAndUnhandledExceptionsTrace', event, frame.f_code.co_name, frame.f_code.co_filename, frame.f_code.co_firstlineno)
if event == 'exception' and arg is not None:
# print('self._unhandled_trace', self._unhandled_trace)
self._unhandled_trace(frame, event, arg)
else:
self._pydb_frame_trace(frame, event, arg)
@ -171,12 +177,17 @@ class ThreadTracer:
def trace_unhandled_exceptions(self, frame, event, arg):
# Note that we ignore the frame as this tracing method should only be put in topmost frames already.
# print('trace_unhandled_exceptions', event, frame.f_code.co_name, frame.f_code.co_filename, frame.f_code.co_firstlineno)
if event == 'exception' and arg is not None:
from _pydevd_bundle.pydevd_breakpoints import stop_on_unhandled_exception
py_db, t, additional_info = self._args[0:3]
if arg is not None:
exctype, value, tb = arg
stop_on_unhandled_exception(py_db, t, additional_info, exctype, value, tb)
if not additional_info.suspended_at_unhandled:
if frame.f_back is not None:
additional_info.suspended_at_unhandled = True
exctype, value, tb = arg
stop_on_unhandled_exception(py_db, t, additional_info, exctype, value, tb)
# IFDEF CYTHON
# return SafeCallWrapper(self.trace_unhandled_exceptions)
# ELSE
@ -184,6 +195,7 @@ class ThreadTracer:
# ENDIF
def trace_dispatch_and_unhandled_exceptions(self, frame, event, arg):
# print('trace_dispatch_and_unhandled_exceptions', event, frame.f_code.co_name, frame.f_code.co_filename, frame.f_code.co_firstlineno)
if event == 'exception' and arg is not None:
self.trace_unhandled_exceptions(frame, event, arg)
ret = self.trace_dispatch_and_unhandled_exceptions
@ -197,7 +209,7 @@ class ThreadTracer:
# Ok, this frame needs to be traced and needs to deal with unhandled exceptions. Create
# a class which does this for us.
py_db_frame_trace_and_unhandled_exceptions_trace = PyDbFrameTraceAndUnhandledExceptionsTrace(
self.trace_dispatch_and_unhandled_exceptions, pydb_frame_trace)
pydb_frame_trace, self.trace_dispatch_and_unhandled_exceptions)
ret = py_db_frame_trace_and_unhandled_exceptions_trace.trace_dispatch
# IFDEF CYTHON
# return SafeCallWrapper(ret)

View file

@ -137,13 +137,18 @@ def find_frame(thread_id, frame_id):
else:
msgFrames += ' - '
errMsg = '''find_frame: frame not found.
Looking for thread_id:%s, frame_id:%s
Current thread_id:%s, available frames:
%s\n
''' % (thread_id, lookingFor, curr_thread_id, msgFrames)
sys.stderr.write(errMsg)
# Note: commented this error message out (it may commonly happen
# if a message asking for a frame is issued while a thread is paused
# but the thread starts running before the message is actually
# handled).
# Leaving code to uncomment during tests.
# err_msg = '''find_frame: frame not found.
# Looking for thread_id:%s, frame_id:%s
# Current thread_id:%s, available frames:
# %s\n
# ''' % (thread_id, lookingFor, curr_thread_id, msgFrames)
#
# sys.stderr.write(err_msg)
return None
return frameFound

View file

@ -1130,6 +1130,40 @@ def enable_qt_support(qt_support_mode):
pydev_monkey_qt.patch_qt(qt_support_mode)
def dump_threads(stream=None):
'''
Helper to dump thread info.
'''
if stream is None:
stream = sys.stderr
thread_id_to_name = {}
try:
for t in threading.enumerate():
thread_id_to_name[t.ident] = '%s (daemon: %s, pydevd thread: %s)' % (
t.name, t.daemon, getattr(t, 'is_pydev_daemon_thread', False))
except:
pass
stack_trace = [
'===============================================================================',
'Threads running',
'================================= Thread Dump =================================']
for thread_id, stack in sys._current_frames().items():
stack_trace.append('\n-------------------------------------------------------------------------------')
stack_trace.append(" Thread %s" % thread_id_to_name.get(thread_id, thread_id))
stack_trace.append('')
if 'self' in stack.f_locals:
stream.write(str(stack.f_locals['self']) + '\n')
for filename, lineno, name, line in traceback.extract_stack(stack):
stack_trace.append(' File "%s", line %d, in %s' % (filename, lineno, name))
if line:
stack_trace.append(" %s" % (line.strip()))
stack_trace.append('\n=============================== END Thread Dump ===============================')
stream.write('\n'.join(stack_trace))
def usage(doExit=0):
sys.stdout.write('Usage:\n')

View file

@ -78,6 +78,11 @@ CMD_RETURN = 502
CMD_ERROR = 901
REASON_CAUGHT_EXCEPTION = CMD_STEP_CAUGHT_EXCEPTION
REASON_UNCAUGHT_EXCEPTION = CMD_ADD_EXCEPTION_BREAK
REASON_STOP_ON_BREAKPOINT = CMD_SET_BREAK
REASON_THREAD_SUSPEND = CMD_THREAD_SUSPEND
# Always True (because otherwise when we do have an error, it's hard to diagnose).
SHOW_WRITES_AND_READS = True
@ -95,6 +100,22 @@ try:
except:
xrange = range
def overrides(method):
'''
Helper to check that one method overrides another (redeclared in unit-tests to avoid importing pydevd).
'''
def wrapper(func):
if func.__name__ != method.__name__:
msg = "Wrong @override: %r expected, but overwriting %r."
msg = msg % (func.__name__, method.__name__)
raise AssertionError(msg)
if func.__doc__ is None:
func.__doc__ = method.__doc__
return func
return wrapper
#=======================================================================================================================
# ReaderThread
@ -126,10 +147,16 @@ class ReaderThread(threading.Thread):
raise AssertionError('No message was written in %s seconds. Error message:\n%s' % (self.TIMEOUT, context_messag,))
else:
frame = sys._getframe().f_back
frame_info = ' -- File "%s", line %s, in %s\n' % (frame.f_code.co_filename, frame.f_lineno, frame.f_code.co_name)
frame_info += ' -- File "%s", line %s, in %s\n' % (frame.f_back.f_code.co_filename, frame.f_back.f_lineno, frame.f_back.f_code.co_name)
frame_info = ''
while frame:
stack_msg = ' -- File "%s", line %s, in %s\n' % (frame.f_code.co_filename, frame.f_lineno, frame.f_code.co_name)
if 'run' == frame.f_code.co_name:
frame_info = stack_msg # Ok, found the writer thread 'run' method (show only that).
break
frame_info += stack_msg
frame = frame.f_back
frame = None
sys.stdout.write('Message returned in get_next_message(): %s -- ctx: %s, returned to:\n%s\n' % (unquote_plus(unquote_plus(msg)), context_messag, frame_info))
sys.stdout.write('Message returned in get_next_message(): %s -- ctx: %s, asked at:\n%s\n' % (unquote_plus(unquote_plus(msg)), context_messag, frame_info))
return msg
def run(self):
@ -176,7 +203,7 @@ class DebuggerRunner(object):
port = int(writer_thread.port)
localhost = pydev_localhost.get_localhost()
ret = args + [
ret = [
writer_thread.get_pydevd_file(),
'--DEBUG_RECORD_SOCKET_READS',
'--qt-support',
@ -189,8 +216,9 @@ class DebuggerRunner(object):
if writer_thread.IS_MODULE:
ret += ['--module']
ret = ret + ['--file'] + writer_thread.get_command_line_args()
return ret
ret += ['--file'] + writer_thread.get_command_line_args()
ret = writer_thread.update_command_line_args(ret) # Provide a hook for the writer
return args + ret
def check_case(self, writer_thread_class):
if callable(writer_thread_class):
@ -226,7 +254,7 @@ class DebuggerRunner(object):
process = subprocess.Popen(
args,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
stderr=subprocess.PIPE,
cwd=writer_thread.get_cwd() if writer_thread is not None else '.',
env=writer_thread.get_environ() if writer_thread is not None else None,
)
@ -239,7 +267,7 @@ class DebuggerRunner(object):
finish = [False]
try:
def read(stream, buffer):
def read(stream, buffer, debug_stream, stream_name):
for line in stream.readlines():
if finish[0]:
return
@ -247,10 +275,11 @@ class DebuggerRunner(object):
line = line.decode('utf-8', errors='replace')
if SHOW_STDOUT:
sys.stdout.write('stdout: %s' % (line,))
debug_stream.write('%s: %s' % (stream_name, line,))
buffer.append(line)
start_new_thread(read, (process.stdout, stdout))
start_new_thread(read, (process.stdout, stdout, sys.stdout, 'stdout'))
start_new_thread(read, (process.stderr, stderr, sys.stderr, 'stderr'))
if SHOW_OTHER_DEBUG_INFO:
@ -297,10 +326,10 @@ class DebuggerRunner(object):
"The other process may still be running -- and didn't give any output.", stdout, stderr, writer_thread)
check = 0
while 'TEST SUCEEDED' not in ''.join(stdout):
while not writer_thread.check_test_suceeded_msg(stdout, stderr):
check += 1
if check == 50:
self.fail_with_message("TEST SUCEEDED not found in stdout.", stdout, stderr, writer_thread)
self.fail_with_message("TEST SUCEEDED not found.", stdout, stderr, writer_thread)
time.sleep(.1)
for _i in xrange(100):
@ -338,8 +367,35 @@ class AbstractWriterThread(threading.Thread):
self._next_breakpoint_id = 0
self.log = []
def check_test_suceeded_msg(self, stdout, stderr):
return 'TEST SUCEEDED' in ''.join(stdout)
def update_command_line_args(self, args):
return args
def _ignore_stderr_line(self, line):
if line.startswith((
'debugger: ',
'>>',
'<<',
'warning: Debugger speedups',
'pydev debugger: New process is launching',
'pydev debugger: To debug that process'
)):
return True
if re.match(r'^(\d+)\t(\d)+', line):
return True
return False
def additional_output_checks(self, stdout, stderr):
pass
for line in stderr.splitlines():
line = line.strip()
if not line:
continue
if not self._ignore_stderr_line(line):
raise AssertionError('Did not expect to have line in stderr:\n\n%s\n\nFull stderr:\n\n%s' % (line, stderr))
def get_environ(self):
return None
@ -384,14 +440,15 @@ class AbstractWriterThread(threading.Thread):
socket_name = get_socket_name(close=True)
else:
socket_name = (pydev_localhost.get_localhost(), port)
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(socket_name)
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server_socket.bind(socket_name)
self.port = socket_name[1]
s.listen(1)
server_socket.listen(1)
if SHOW_WRITES_AND_READS:
print('Waiting in socket.accept()')
self.server_socket = s
new_sock, addr = s.accept()
self.server_socket = server_socket
new_sock, addr = server_socket.accept()
if SHOW_WRITES_AND_READS:
print('Test Writer Thread Socket:', new_sock, addr)
@ -443,7 +500,7 @@ class AbstractWriterThread(threading.Thread):
def wait_for_breakpoint_hit(self, *args, **kwargs):
return self.wait_for_breakpoint_hit_with_suspend_type(*args, **kwargs)[:-1]
def wait_for_breakpoint_hit_with_suspend_type(self, reason='111', get_line=False, get_name=False):
def wait_for_breakpoint_hit_with_suspend_type(self, reason=REASON_STOP_ON_BREAKPOINT, get_line=False, get_name=False):
'''
108 is over
109 is return
@ -451,9 +508,10 @@ class AbstractWriterThread(threading.Thread):
'''
self.log.append('Start: wait_for_breakpoint_hit')
# wait for hit breakpoint
last = ''
last = self.reader_thread.get_next_message('wait_for_breakpoint_hit. reason=%s' % (reason,))
while not ('stop_reason="%s"' % reason) in last:
last = self.reader_thread.get_next_message('wait_for_breakpoint_hit. reason=%s' % (reason,))
# we have something like <xml><thread id="12152656" stop_reason="111"><frame id="12453120" name="encode" ...
splitted = last.split('"')
@ -603,8 +661,10 @@ class AbstractWriterThread(threading.Thread):
def write_set_project_roots(self, project_roots):
self.write("%s\t%s\t%s" % (CMD_SET_PROJECT_ROOTS, self.next_seq(), '\t'.join(str(x) for x in project_roots)))
def write_add_exception_breakpoint_with_policy(self, exception, notify_on_handled_exceptions, notify_on_unhandled_exceptions, ignore_libraries):
self.write("%s\t%s\t%s" % (CMD_ADD_EXCEPTION_BREAK, self.next_seq(), '\t'.join(str(x) for x in [exception, notify_on_handled_exceptions, notify_on_unhandled_exceptions, ignore_libraries])))
def write_add_exception_breakpoint_with_policy(
self, exception, notify_on_handled_exceptions, notify_on_unhandled_exceptions, ignore_libraries):
self.write("%s\t%s\t%s" % (CMD_ADD_EXCEPTION_BREAK, self.next_seq(), '\t'.join(str(x) for x in [
exception, notify_on_handled_exceptions, notify_on_unhandled_exceptions, ignore_libraries])))
self.log.append('write_add_exception_breakpoint: %s' % (exception,))
def write_remove_breakpoint(self, breakpoint_id):

View file

@ -0,0 +1,14 @@
if __name__ == '__main__':
import os
import sys
root_dirname = os.path.dirname(os.path.dirname(__file__))
if root_dirname not in sys.path:
sys.path.append(root_dirname)
import pydevd
print('before pydevd.settrace')
pydevd.settrace(port=8787)
print('after pydevd.settrace')
raise ValueError('TEST SUCEEDED!')

View file

@ -0,0 +1,20 @@
if __name__ == '__main__':
import os
import sys
root_dirname = os.path.dirname(os.path.dirname(__file__))
if root_dirname not in sys.path:
sys.path.append(root_dirname)
import pydevd
print('before pydevd.settrace')
pydevd.settrace(port=8787)
print('after pydevd.settrace')
for i in range(2):
try:
raise ValueError('not finished')
except:
pass
raise ValueError('TEST SUCEEDED!')

View file

@ -0,0 +1 @@
raise ValueError('TEST SUCEEDED')

View file

@ -0,0 +1,6 @@
try:
raise ValueError('foobar')
except ValueError:
pass
raise ValueError('TEST SUCEEDED')

View file

@ -16,10 +16,8 @@ import unittest
import pytest
from tests_python import debugger_unittest
from tests_python.debugger_unittest import get_free_port
CMD_SET_PROPERTY_TRACE, CMD_EVALUATE_CONSOLE_EXPRESSION, CMD_RUN_CUSTOM_OPERATION, CMD_ENABLE_DONT_TRACE = 133, 134, 135, 141
from tests_python.debugger_unittest import get_free_port, CMD_SET_PROPERTY_TRACE, REASON_CAUGHT_EXCEPTION, \
REASON_UNCAUGHT_EXCEPTION, REASON_STOP_ON_BREAKPOINT, REASON_THREAD_SUSPEND, overrides
IS_CPYTHON = platform.python_implementation() == 'CPython'
IS_IRONPYTHON = platform.python_implementation() == 'IronPython'
@ -71,7 +69,7 @@ class WriterThreadCaseSetNextStatement(debugger_unittest.AbstractWriterThread):
breakpoint_id = self.write_add_breakpoint(6, None)
self.write_make_initial_run()
thread_id, frame_id, line = self.wait_for_breakpoint_hit('111', True)
thread_id, frame_id, line = self.wait_for_breakpoint_hit(REASON_STOP_ON_BREAKPOINT, True)
assert line == 6, 'Expected return to be in line 6, was: %s' % line
@ -104,7 +102,7 @@ class WriterThreadCaseGetNextStatementTargets(debugger_unittest.AbstractWriterTh
breakpoint_id = self.write_add_breakpoint(21, None)
self.write_make_initial_run()
thread_id, frame_id, line = self.wait_for_breakpoint_hit('111', True)
thread_id, frame_id, line = self.wait_for_breakpoint_hit(REASON_STOP_ON_BREAKPOINT, True)
assert line == 21, 'Expected return to be in line 21, was: %s' % line
@ -123,6 +121,15 @@ class WriterThreadCaseGetNextStatementTargets(debugger_unittest.AbstractWriterTh
#======================================================================================================================
class AbstractWriterThreadCaseDjango(debugger_unittest.AbstractWriterThread):
FORCE_KILL_PROCESS_WHEN_FINISHED_OK = True
def _ignore_stderr_line(self, line):
if debugger_unittest.AbstractWriterThread._ignore_stderr_line(self, line):
return True
if 'GET /my_app' in line:
return True
return False
def get_command_line_args(self):
free_port = get_free_port()
@ -174,7 +181,7 @@ class WriterThreadCaseDjango(AbstractWriterThreadCaseDjango):
time.sleep(5) # Give django some time to get to startup before requesting the page
t.start()
thread_id, frame_id, line = self.wait_for_breakpoint_hit('111', True)
thread_id, frame_id, line = self.wait_for_breakpoint_hit(REASON_STOP_ON_BREAKPOINT, True)
assert line == 5, 'Expected return to be in line 5, was: %s' % line
self.write_get_variable(thread_id, frame_id, 'entry')
self.wait_for_vars([
@ -184,7 +191,7 @@ class WriterThreadCaseDjango(AbstractWriterThreadCaseDjango):
self.write_run_thread(thread_id)
thread_id, frame_id, line = self.wait_for_breakpoint_hit('111', True)
thread_id, frame_id, line = self.wait_for_breakpoint_hit(REASON_STOP_ON_BREAKPOINT, True)
assert line == 5, 'Expected return to be in line 5, was: %s' % line
self.write_get_variable(thread_id, frame_id, 'entry')
self.wait_for_vars([
@ -221,7 +228,7 @@ class WriterThreadCaseDjango2(AbstractWriterThreadCaseDjango):
time.sleep(5) # Give django some time to get to startup before requesting the page
t.start()
thread_id, frame_id, line = self.wait_for_breakpoint_hit('111', True)
thread_id, frame_id, line = self.wait_for_breakpoint_hit(REASON_STOP_ON_BREAKPOINT, True)
assert line == 4, 'Expected return to be in line 4, was: %s' % line
self.write_get_frame(thread_id, frame_id)
@ -241,7 +248,7 @@ class WriterThreadCase19(debugger_unittest.AbstractWriterThread):
self.write_add_breakpoint(8, None)
self.write_make_initial_run()
thread_id, frame_id, line = self.wait_for_breakpoint_hit('111', True)
thread_id, frame_id, line = self.wait_for_breakpoint_hit(REASON_STOP_ON_BREAKPOINT, True)
assert line == 8, 'Expected return to be in line 8, was: %s' % line
@ -281,7 +288,7 @@ class WriterThreadCase18(debugger_unittest.AbstractWriterThread):
self.write_add_breakpoint(5, 'm2')
self.write_make_initial_run()
thread_id, frame_id, line = self.wait_for_breakpoint_hit('111', True)
thread_id, frame_id, line = self.wait_for_breakpoint_hit(REASON_STOP_ON_BREAKPOINT, True)
assert line == 5, 'Expected return to be in line 2, was: %s' % line
self.write_change_variable(thread_id, frame_id, 'a', '40')
@ -307,7 +314,7 @@ class WriterThreadCase17(debugger_unittest.AbstractWriterThread):
self.write_make_initial_run()
for i in range(4):
thread_id, frame_id, line = self.wait_for_breakpoint_hit('111', True)
thread_id, frame_id, line = self.wait_for_breakpoint_hit(REASON_STOP_ON_BREAKPOINT, True)
self.write_step_in(thread_id)
thread_id, frame_id, line = self.wait_for_breakpoint_hit('107', True)
@ -331,7 +338,7 @@ class WriterThreadCase17a(debugger_unittest.AbstractWriterThread):
self.write_add_breakpoint(2, 'm1')
self.write_make_initial_run()
thread_id, frame_id, line = self.wait_for_breakpoint_hit('111', True)
thread_id, frame_id, line = self.wait_for_breakpoint_hit(REASON_STOP_ON_BREAKPOINT, True)
assert line == 2, 'Expected return to be in line 2, was: %s' % line
self.write_step_in(thread_id)
@ -357,7 +364,7 @@ class WriterThreadCase16(debugger_unittest.AbstractWriterThread):
self.write_add_breakpoint(9, 'main')
self.write_make_initial_run()
thread_id, frame_id, line = self.wait_for_breakpoint_hit('111', True)
thread_id, frame_id, line = self.wait_for_breakpoint_hit(REASON_STOP_ON_BREAKPOINT, True)
# In this test we check that the three arrays of different shapes, sizes and types
# are all resolved properly as ndarrays.
@ -455,7 +462,7 @@ class WriterThreadCase15(debugger_unittest.AbstractWriterThread):
self.write_add_breakpoint(22, 'main')
self.write_make_initial_run()
thread_id, frame_id, line = self.wait_for_breakpoint_hit('111', True)
thread_id, frame_id, line = self.wait_for_breakpoint_hit(REASON_STOP_ON_BREAKPOINT, True)
# Access some variable
self.write_custom_operation("%s\t%s\tEXPRESSION\tcarObj.color" % (thread_id, frame_id), "EXEC", "f=lambda x: 'val=%s' % x", "f")
@ -912,20 +919,174 @@ class WriterThreadCaseUnhandledExceptions(debugger_unittest.AbstractWriterThread
# Note: expecting unhandled exceptions to be printed to stdout.
TEST_FILE = debugger_unittest._get_debugger_test_file('_debugger_case_unhandled_exceptions.py')
@overrides(debugger_unittest.AbstractWriterThread.additional_output_checks)
def additional_output_checks(self, stdout, stderr):
if 'raise Exception' not in stderr:
raise AssertionError('Expected test to have an unhandled exception.')
# Don't call super (we have an unhandled exception in the stack trace).
def run(self):
self.start_socket()
self.write_add_exception_breakpoint_with_policy('Exception', "0", "1", "0")
self.write_make_initial_run()
# Will stop in 2 background threads
thread_id1, frame_id = self.wait_for_breakpoint_hit('122')
thread_id2, frame_id = self.wait_for_breakpoint_hit('122')
thread_id1, frame_id = self.wait_for_breakpoint_hit(REASON_UNCAUGHT_EXCEPTION)
thread_id2, frame_id = self.wait_for_breakpoint_hit(REASON_UNCAUGHT_EXCEPTION)
self.write_run_thread(thread_id1)
self.write_run_thread(thread_id2)
# Will stop in main thread
thread_id3, frame_id = self.wait_for_breakpoint_hit('122')
thread_id3, frame_id = self.wait_for_breakpoint_hit(REASON_UNCAUGHT_EXCEPTION)
self.write_run_thread(thread_id3)
self.log.append('Marking finished ok.')
self.finished_ok = True
#=======================================================================================================================
# WriterThreadCaseUnhandledExceptionsOnTopLevel
#=======================================================================================================================
class WriterThreadCaseUnhandledExceptionsOnTopLevel(debugger_unittest.AbstractWriterThread):
# Note: expecting unhandled exception to be printed to stderr.
TEST_FILE = debugger_unittest._get_debugger_test_file('_debugger_case_unhandled_exceptions_on_top_level.py')
@overrides(debugger_unittest.AbstractWriterThread.check_test_suceeded_msg)
def check_test_suceeded_msg(self, stdout, stderr):
return 'TEST SUCEEDED' in ''.join(stderr)
@overrides(debugger_unittest.AbstractWriterThread.additional_output_checks)
def additional_output_checks(self, stdout, stderr):
# Don't call super as we have an expected exception
assert 'ValueError: TEST SUCEEDED' in stderr
def run(self):
self.start_socket()
self.write_add_exception_breakpoint_with_policy('Exception', "0", "1", "0")
self.write_make_initial_run()
# Will stop in main thread
thread_id3, frame_id = self.wait_for_breakpoint_hit(REASON_UNCAUGHT_EXCEPTION)
self.write_run_thread(thread_id3)
self.log.append('Marking finished ok.')
self.finished_ok = True
#=======================================================================================================================
# WriterThreadCaseUnhandledExceptionsOnTopLevel2
#=======================================================================================================================
class WriterThreadCaseUnhandledExceptionsOnTopLevel2(debugger_unittest.AbstractWriterThread):
# Note: expecting unhandled exception to be printed to stderr.
TEST_FILE = debugger_unittest._get_debugger_test_file('_debugger_case_unhandled_exceptions_on_top_level.py')
@overrides(debugger_unittest.AbstractWriterThread.check_test_suceeded_msg)
def check_test_suceeded_msg(self, stdout, stderr):
return 'TEST SUCEEDED' in ''.join(stderr)
@overrides(debugger_unittest.AbstractWriterThread.additional_output_checks)
def additional_output_checks(self, stdout, stderr):
# Don't call super as we have an expected exception
assert 'ValueError: TEST SUCEEDED' in stderr
@overrides(debugger_unittest.AbstractWriterThread.get_environ)
def get_environ(self):
env = os.environ.copy()
curr_pythonpath = env.get('PYTHONPATH', '')
pydevd_dirname = os.path.dirname(self.get_pydevd_file())
curr_pythonpath = pydevd_dirname + os.pathsep + curr_pythonpath
env['PYTHONPATH'] = curr_pythonpath
return env
def update_command_line_args(self, args):
# Start pydevd with '-m' to see how it deal with being called with
# runpy at the start.
assert args[0].endswith('pydevd.py')
args = ['-m', 'pydevd'] + args[1:]
return args
def run(self):
self.start_socket()
self.write_add_exception_breakpoint_with_policy('Exception', "0", "1", "0")
self.write_make_initial_run()
# Should stop (only once) in the main thread.
thread_id3, frame_id = self.wait_for_breakpoint_hit(REASON_UNCAUGHT_EXCEPTION)
self.write_run_thread(thread_id3)
self.log.append('Marking finished ok.')
self.finished_ok = True
#=======================================================================================================================
# WriterThreadCaseUnhandledExceptionsOnTopLevel3
#=======================================================================================================================
class WriterThreadCaseUnhandledExceptionsOnTopLevel3(debugger_unittest.AbstractWriterThread):
# Note: expecting unhandled exception to be printed to stderr.
TEST_FILE = debugger_unittest._get_debugger_test_file('_debugger_case_unhandled_exceptions_on_top_level.py')
@overrides(debugger_unittest.AbstractWriterThread.check_test_suceeded_msg)
def check_test_suceeded_msg(self, stdout, stderr):
return 'TEST SUCEEDED' in ''.join(stderr)
@overrides(debugger_unittest.AbstractWriterThread.additional_output_checks)
def additional_output_checks(self, stdout, stderr):
# Don't call super as we have an expected exception
assert 'ValueError: TEST SUCEEDED' in stderr
def run(self):
self.start_socket()
# Handled and unhandled
self.write_add_exception_breakpoint_with_policy('Exception', "1", "1", "0")
self.write_make_initial_run()
# Will stop in main thread twice: once one we find that the exception is being
# thrown and another in postmortem mode when we discover it's uncaught.
thread_id3, frame_id = self.wait_for_breakpoint_hit(REASON_CAUGHT_EXCEPTION)
self.write_run_thread(thread_id3)
thread_id3, frame_id = self.wait_for_breakpoint_hit(REASON_UNCAUGHT_EXCEPTION)
self.write_run_thread(thread_id3)
self.log.append('Marking finished ok.')
self.finished_ok = True
#=======================================================================================================================
# WriterThreadCaseUnhandledExceptionsOnTopLevel4
#=======================================================================================================================
class WriterThreadCaseUnhandledExceptionsOnTopLevel4(debugger_unittest.AbstractWriterThread):
# Note: expecting unhandled exception to be printed to stderr.
TEST_FILE = debugger_unittest._get_debugger_test_file('_debugger_case_unhandled_exceptions_on_top_level2.py')
@overrides(debugger_unittest.AbstractWriterThread.check_test_suceeded_msg)
def check_test_suceeded_msg(self, stdout, stderr):
return 'TEST SUCEEDED' in ''.join(stderr)
@overrides(debugger_unittest.AbstractWriterThread.additional_output_checks)
def additional_output_checks(self, stdout, stderr):
# Don't call super as we have an expected exception
assert 'ValueError: TEST SUCEEDED' in stderr
def run(self):
self.start_socket()
# Handled and unhandled
self.write_add_exception_breakpoint_with_policy('Exception', "1", "1", "0")
self.write_make_initial_run()
# We have an exception thrown and handled and another which is thrown and is then unhandled.
thread_id3, frame_id = self.wait_for_breakpoint_hit(REASON_CAUGHT_EXCEPTION)
self.write_run_thread(thread_id3)
thread_id3, frame_id = self.wait_for_breakpoint_hit(REASON_CAUGHT_EXCEPTION)
self.write_run_thread(thread_id3)
thread_id3, frame_id = self.wait_for_breakpoint_hit(REASON_UNCAUGHT_EXCEPTION)
self.write_run_thread(thread_id3)
self.log.append('Marking finished ok.')
@ -946,7 +1107,7 @@ class WriterThreadCase2(debugger_unittest.AbstractWriterThread):
thread_id, frame_id = self.wait_for_breakpoint_hit()
self.write_get_frame(thread_id, frame_id)
self.write_get_frame(thread_id, frame_id) # Note: write get frame but not waiting for it to be gotten.
self.write_add_breakpoint(14, 'Call2')
@ -954,7 +1115,7 @@ class WriterThreadCase2(debugger_unittest.AbstractWriterThread):
thread_id, frame_id = self.wait_for_breakpoint_hit()
self.write_get_frame(thread_id, frame_id)
self.write_get_frame(thread_id, frame_id) # Note: write get frame but not waiting for it to be gotten.
self.write_run_thread(thread_id)
@ -1056,7 +1217,9 @@ class WriterThreadCaseQThread4(debugger_unittest.AbstractWriterThread):
self.log.append('Marking finished ok.')
self.finished_ok = True
@overrides(debugger_unittest.AbstractWriterThread.additional_output_checks)
def additional_output_checks(self, stdout, stderr):
debugger_unittest.AbstractWriterThread.additional_output_checks(self, stdout, stderr)
if 'On start called' not in stdout:
raise AssertionError('Expected "On start called" to be in stdout:\n%s' % (stdout,))
if 'Done sleeping' not in stdout:
@ -1113,6 +1276,7 @@ class WriterThreadCaseMSwitch(debugger_unittest.AbstractWriterThread):
TEST_FILE = 'tests_python.resources._debugger_case_m_switch'
IS_MODULE = True
@overrides(debugger_unittest.AbstractWriterThread.get_environ)
def get_environ(self):
env = os.environ.copy()
curr_pythonpath = env.get('PYTHONPATH', '')
@ -1123,6 +1287,7 @@ class WriterThreadCaseMSwitch(debugger_unittest.AbstractWriterThread):
env['PYTHONPATH'] = curr_pythonpath
return env
@overrides(debugger_unittest.AbstractWriterThread.get_main_filename)
def get_main_filename(self):
return debugger_unittest._get_debugger_test_file('_debugger_case_m_switch.py')
@ -1161,12 +1326,12 @@ class WriterThreadCaseModuleWithEntryPoint(WriterThreadCaseMSwitch):
TEST_FILE = 'tests_python.resources._debugger_case_module_entry_point:main'
IS_MODULE = True
@overrides(WriterThreadCaseMSwitch.get_main_filename)
def get_main_filename(self):
return debugger_unittest._get_debugger_test_file('_debugger_case_module_entry_point.py')
#=======================================================================================================================
# WriterThreadCaseRemoteDebugger
#=======================================================================================================================
@ -1181,7 +1346,7 @@ class WriterThreadCaseRemoteDebugger(debugger_unittest.AbstractWriterThread):
self.write_make_initial_run()
self.log.append('waiting for breakpoint hit')
thread_id, frame_id = self.wait_for_breakpoint_hit('105')
thread_id, frame_id = self.wait_for_breakpoint_hit(REASON_THREAD_SUSPEND)
self.log.append('run thread')
self.write_run_thread(thread_id)
@ -1195,6 +1360,88 @@ class WriterThreadCaseRemoteDebugger(debugger_unittest.AbstractWriterThread):
self.log.append('asserted')
self.finished_ok = True
#=======================================================================================================================
# WriterThreadCaseRemoteDebuggerUnhandledExceptions
#=======================================================================================================================
class WriterThreadCaseRemoteDebuggerUnhandledExceptions(debugger_unittest.AbstractWriterThread):
TEST_FILE = debugger_unittest._get_debugger_test_file('_debugger_case_remote_unhandled_exceptions.py')
@overrides(debugger_unittest.AbstractWriterThread.check_test_suceeded_msg)
def check_test_suceeded_msg(self, stdout, stderr):
return 'TEST SUCEEDED' in ''.join(stderr)
@overrides(debugger_unittest.AbstractWriterThread.additional_output_checks)
def additional_output_checks(self, stdout, stderr):
# Don't call super as we have an expected exception
assert 'ValueError: TEST SUCEEDED' in stderr
def run(self):
self.start_socket(8787) # Wait for it to connect back at this port.
self.log.append('making initial run')
self.write_make_initial_run()
self.log.append('waiting for breakpoint hit')
thread_id, frame_id = self.wait_for_breakpoint_hit(REASON_THREAD_SUSPEND)
self.write_add_exception_breakpoint_with_policy('Exception', '0', '1', '0')
self.log.append('run thread')
self.write_run_thread(thread_id)
self.log.append('waiting for uncaught exception')
thread_id, frame_id = self.wait_for_breakpoint_hit(REASON_UNCAUGHT_EXCEPTION)
self.write_run_thread(thread_id)
self.log.append('finished ok')
self.finished_ok = True
#=======================================================================================================================
# WriterThreadCaseRemoteDebuggerUnhandledExceptions2
#=======================================================================================================================
class WriterThreadCaseRemoteDebuggerUnhandledExceptions2(debugger_unittest.AbstractWriterThread):
TEST_FILE = debugger_unittest._get_debugger_test_file('_debugger_case_remote_unhandled_exceptions2.py')
@overrides(debugger_unittest.AbstractWriterThread.check_test_suceeded_msg)
def check_test_suceeded_msg(self, stdout, stderr):
return 'TEST SUCEEDED' in ''.join(stderr)
@overrides(debugger_unittest.AbstractWriterThread.additional_output_checks)
def additional_output_checks(self, stdout, stderr):
# Don't call super as we have an expected exception
assert 'ValueError: TEST SUCEEDED' in stderr
def run(self):
self.start_socket(8787) # Wait for it to connect back at this port.
self.log.append('making initial run')
self.write_make_initial_run()
self.log.append('waiting for breakpoint hit')
thread_id, frame_id = self.wait_for_breakpoint_hit(REASON_THREAD_SUSPEND)
self.write_add_exception_breakpoint_with_policy('ValueError', '0', '1', '0')
self.log.append('run thread')
self.write_run_thread(thread_id)
self.log.append('waiting for uncaught exception')
for _ in range(3):
# Note: this isn't ideal, but in the remote attach case, if the
# exception is raised at the topmost frame, we consider the exception to
# be an uncaught exception even if it'll be handled at that point.
# See: https://github.com/Microsoft/ptvsd/issues/580
# To properly fix this, we'll need to identify that this exception
# will be handled later on with the information we have at hand (so,
# no back frame but within a try..except block).
thread_id, frame_id = self.wait_for_breakpoint_hit(REASON_UNCAUGHT_EXCEPTION)
self.write_run_thread(thread_id)
self.log.append('finished ok')
self.finished_ok = True
#=======================================================================================================================
# _SecondaryMultiProcProcessWriterThread
@ -1243,7 +1490,7 @@ class WriterThreadCaseRemoteDebuggerMultiProc(debugger_unittest.AbstractWriterTh
self.write_make_initial_run()
self.log.append('waiting for breakpoint hit')
thread_id, frame_id = self.wait_for_breakpoint_hit('105')
thread_id, frame_id = self.wait_for_breakpoint_hit(REASON_THREAD_SUSPEND)
self.secondary_multi_proc_process_writer_thread = secondary_multi_proc_process_writer_thread = \
_SecondaryMultiProcProcessWriterThread(self.server_socket)
@ -1296,6 +1543,7 @@ class WriterThreadCaseTypeExt(debugger_unittest.AbstractWriterThread):
self.finished_ok = True
@overrides(debugger_unittest.AbstractWriterThread.get_environ)
def get_environ(self):
env = os.environ.copy()
@ -1316,10 +1564,13 @@ class WriterThreadCaseEventExt(debugger_unittest.AbstractWriterThread):
self.write_make_initial_run()
self.finished_ok = True
@overrides(debugger_unittest.AbstractWriterThread.additional_output_checks)
def additional_output_checks(self, stdout, stderr):
debugger_unittest.AbstractWriterThread.additional_output_checks(self, stdout, stderr)
if 'INITIALIZE EVENT RECEIVED' not in stdout:
raise AssertionError('No initialize event received')
@overrides(debugger_unittest.AbstractWriterThread.get_environ)
def get_environ(self):
env = os.environ.copy()
@ -1393,7 +1644,7 @@ class WriterThreadCaseHandledExceptions(debugger_unittest.AbstractWriterThread):
)
self.write_make_initial_run()
thread_id, frame_id, line = self.wait_for_breakpoint_hit('137', True)
thread_id, frame_id, line = self.wait_for_breakpoint_hit(REASON_CAUGHT_EXCEPTION, True)
assert line == 2, 'Expected return to be in line 2, was: %s' % line
self.write_run_thread(thread_id)
@ -1406,6 +1657,7 @@ class WriterThreadCaseHandledExceptions1(debugger_unittest.AbstractWriterThread)
TEST_FILE = debugger_unittest._get_debugger_test_file('_debugger_case_exceptions.py')
@overrides(debugger_unittest.AbstractWriterThread.get_environ)
def get_environ(self):
env = os.environ.copy()
@ -1422,15 +1674,15 @@ class WriterThreadCaseHandledExceptions1(debugger_unittest.AbstractWriterThread)
)
self.write_make_initial_run()
thread_id, frame_id, line = self.wait_for_breakpoint_hit('137', True)
thread_id, frame_id, line = self.wait_for_breakpoint_hit(REASON_CAUGHT_EXCEPTION, True)
assert line == 2, 'Expected return to be in line 2, was: %s' % line
self.write_run_thread(thread_id)
thread_id, frame_id, line = self.wait_for_breakpoint_hit('137', True)
thread_id, frame_id, line = self.wait_for_breakpoint_hit(REASON_CAUGHT_EXCEPTION, True)
assert line == 5, 'Expected return to be in line 5, was: %s' % line
self.write_run_thread(thread_id)
thread_id, frame_id, line = self.wait_for_breakpoint_hit('137', True)
thread_id, frame_id, line = self.wait_for_breakpoint_hit(REASON_CAUGHT_EXCEPTION, True)
assert line == 9, 'Expected return to be in line 9, was: %s' % line
self.write_run_thread(thread_id)
@ -1443,6 +1695,7 @@ class WriterThreadCaseHandledExceptions2(debugger_unittest.AbstractWriterThread)
TEST_FILE = debugger_unittest._get_debugger_test_file('_debugger_case_exceptions.py')
@overrides(debugger_unittest.AbstractWriterThread.get_environ)
def get_environ(self):
env = os.environ.copy()
@ -1468,6 +1721,7 @@ class WriterThreadCaseHandledExceptions3(debugger_unittest.AbstractWriterThread)
TEST_FILE = debugger_unittest._get_debugger_test_file('_debugger_case_exceptions.py')
@overrides(debugger_unittest.AbstractWriterThread.get_environ)
def get_environ(self):
env = os.environ.copy()
@ -1487,7 +1741,7 @@ class WriterThreadCaseHandledExceptions3(debugger_unittest.AbstractWriterThread)
)
self.write_make_initial_run()
thread_id, frame_id, line = self.wait_for_breakpoint_hit('137', True)
thread_id, frame_id, line = self.wait_for_breakpoint_hit(REASON_CAUGHT_EXCEPTION, True)
assert line == 2, 'Expected return to be in line 2, was: %s' % line
self.write_run_thread(thread_id)
@ -1509,7 +1763,7 @@ class WriterCaseSetTrace(debugger_unittest.AbstractWriterThread):
assert line == 12, 'Expected return to be in line 12, was: %s' % line
self.write_run_thread(thread_id)
thread_id, frame_id, line = self.wait_for_breakpoint_hit('105', True)
thread_id, frame_id, line = self.wait_for_breakpoint_hit(REASON_THREAD_SUSPEND, True)
assert line == 7, 'Expected return to be in line 7, was: %s' % line
self.write_run_thread(thread_id)
@ -1522,6 +1776,16 @@ class WriterThreadCaseRedirectOutput(debugger_unittest.AbstractWriterThread):
TEST_FILE = debugger_unittest._get_debugger_test_file('_debugger_case_redirect.py')
def _ignore_stderr_line(self, line):
if debugger_unittest.AbstractWriterThread._ignore_stderr_line(self, line):
return True
return line.startswith((
'text',
'binary',
'a'
))
@overrides(debugger_unittest.AbstractWriterThread.get_environ)
def get_environ(self):
env = os.environ.copy()
@ -1579,6 +1843,7 @@ class WriterThreadCasePathTranslation(debugger_unittest.AbstractWriterThread):
file_in_client = os.path.dirname(os.path.dirname(self.TEST_FILE))
return os.path.join(os.path.dirname(file_in_client), 'foo', '_debugger_case_path_translation.py')
@overrides(debugger_unittest.AbstractWriterThread.get_environ)
def get_environ(self):
import json
env = os.environ.copy()
@ -1750,6 +2015,7 @@ class WriterDebugZipFiles(debugger_unittest.AbstractWriterThread):
zip_file.writestr('zipped2/zipped_contents2.py', 'def call_in_zip2():\n return 1')
zip_file.close()
@overrides(debugger_unittest.AbstractWriterThread.get_environ)
def get_environ(self):
env = os.environ.copy()
curr_pythonpath = env.get('PYTHONPATH', '')
@ -1951,6 +2217,18 @@ class Test(unittest.TestCase, debugger_unittest.DebuggerRunner):
def test_unhandled_exceptions(self):
self.check_case(WriterThreadCaseUnhandledExceptions)
def test_unhandled_exceptions_in_top_level(self):
self.check_case(WriterThreadCaseUnhandledExceptionsOnTopLevel)
def test_unhandled_exceptions_in_top_level2(self):
self.check_case(WriterThreadCaseUnhandledExceptionsOnTopLevel2)
def test_unhandled_exceptions_in_top_level3(self):
self.check_case(WriterThreadCaseUnhandledExceptionsOnTopLevel3)
def test_unhandled_exceptions_in_top_level4(self):
self.check_case(WriterThreadCaseUnhandledExceptionsOnTopLevel4)
@pytest.mark.skipif(not IS_CPYTHON or (IS_PY36 and sys.platform != 'win32'), reason='Only for Python (failing on 3.6 on travis (linux) -- needs to be investigated).')
def test_case_set_next_statement(self):
@ -2034,6 +2312,11 @@ class TestPythonRemoteDebugger(unittest.TestCase, debugger_unittest.DebuggerRunn
def test_remote_debugger2(self):
self.check_case(WriterThreadCaseRemoteDebuggerMultiProc)
def test_remote_unhandled_exceptions(self):
self.check_case(WriterThreadCaseRemoteDebuggerUnhandledExceptions)
def test_remote_unhandled_exceptions2(self):
self.check_case(WriterThreadCaseRemoteDebuggerUnhandledExceptions2)
def get_java_location():

View file

@ -0,0 +1,11 @@
def test_dump_threads():
import pydevd
try:
from StringIO import StringIO
except:
from io import StringIO
stream = StringIO()
pydevd.dump_threads(stream=stream)
contents = stream.getvalue()
assert 'Thread MainThread (daemon: False, pydevd thread: False)' in contents
assert 'test_dump_threads' in contents