mirror of
https://github.com/microsoft/debugpy.git
synced 2025-12-23 08:48:12 +00:00
parent
c99f884ae0
commit
f8d324a4fc
13 changed files with 541 additions and 106 deletions
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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')
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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!')
|
||||
|
||||
|
|
@ -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!')
|
||||
|
||||
|
|
@ -0,0 +1 @@
|
|||
raise ValueError('TEST SUCEEDED')
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
try:
|
||||
raise ValueError('foobar')
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
raise ValueError('TEST SUCEEDED')
|
||||
|
|
@ -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():
|
||||
|
|
|
|||
11
ptvsd/_vendored/pydevd/tests_python/test_dump_threads.py
Normal file
11
ptvsd/_vendored/pydevd/tests_python/test_dump_threads.py
Normal 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
|
||||
Loading…
Add table
Add a link
Reference in a new issue