diff --git a/ptvsd/_vendored/pydevd/.travis_install_jython_deps.sh b/ptvsd/_vendored/pydevd/.travis_install_jython_deps.sh index f3a104fb7..caf677f30 100644 --- a/ptvsd/_vendored/pydevd/.travis_install_jython_deps.sh +++ b/ptvsd/_vendored/pydevd/.travis_install_jython_deps.sh @@ -2,4 +2,5 @@ set -ev pip install pytest -pip install untangle \ No newline at end of file +pip install untangle +pip install pathlib2 \ No newline at end of file diff --git a/ptvsd/_vendored/pydevd/.travis_install_python_deps.sh b/ptvsd/_vendored/pydevd/.travis_install_python_deps.sh index 258c931cd..ac9663250 100644 --- a/ptvsd/_vendored/pydevd/.travis_install_python_deps.sh +++ b/ptvsd/_vendored/pydevd/.travis_install_python_deps.sh @@ -7,6 +7,7 @@ conda install --yes numpy ipython pytest cython psutil if [ "$PYDEVD_PYTHON_VERSION" = "2.6" ]; then conda install --yes pyqt=4 pip install pympler==0.5 + pip install pathlib2 # Django 1.7 does not support Python 2.7 else # pytest-xdist not available for python 2.6 @@ -17,6 +18,7 @@ fi if [ "$PYDEVD_PYTHON_VERSION" = "2.7" ]; then conda install --yes pyqt=4 pip install "django>=1.7,<1.8" + pip install pathlib2 fi @@ -25,5 +27,13 @@ if [ "$PYDEVD_PYTHON_VERSION" = "3.5" ]; then pip install "django>=1.7,<1.8" fi +if [ "$PYDEVD_PYTHON_VERSION" = "3.6" ]; then + conda install --yes pyqt=5 +fi + +if [ "$PYDEVD_PYTHON_VERSION" = "3.7" ]; then + conda install --yes pyqt=5 +fi + pip install untangle pip install scapy==2.4.0 \ No newline at end of file diff --git a/ptvsd/_vendored/pydevd/_pydevd_bundle/pydevd_collect_try_except_info.py b/ptvsd/_vendored/pydevd/_pydevd_bundle/pydevd_collect_try_except_info.py new file mode 100644 index 000000000..4d6273674 --- /dev/null +++ b/ptvsd/_vendored/pydevd/_pydevd_bundle/pydevd_collect_try_except_info.py @@ -0,0 +1,191 @@ +from opcode import HAVE_ARGUMENT, EXTENDED_ARG, hasconst, opname, hasname, hasjrel, haslocal, \ + hascompare, hasfree, cmp_op +import dis +import sys +from collections import namedtuple + +try: + xrange +except NameError: + xrange = range + + +class TryExceptInfo(object): + + def __init__(self, try_line, is_finally=False): + self.try_line = try_line + self.is_finally = is_finally + self.except_line = -1 + self.except_bytecode_offset = -1 + self.except_end_line = -1 + self.except_end_bytecode_offset = -1 + self.raise_lines_in_except = [] + + def is_line_in_try_block(self, line): + return self.try_line <= line <= self.except_line + + def is_line_in_except_block(self, line): + return self.except_line <= line <= self.except_end_line + + def __str__(self): + lst = [ + '{try:', + str(self.try_line), + ' except ', + str(self.except_line), + ' end block ', + str(self.except_end_line), + ] + if self.raise_lines_in_except: + lst.append(' raises: %s' % (', '.join(str(x) for x in self.raise_lines_in_except),)) + + lst.append('}') + return ''.join(lst) + + __repr__ = __str__ + + +def _get_line(op_offset_to_line, op_offset, firstlineno, search=False): + op_offset_original = op_offset + while op_offset >= 0: + ret = op_offset_to_line.get(op_offset) + if ret is not None: + return ret - firstlineno + if not search: + return ret + else: + op_offset -= 1 + raise AssertionError('Unable to find line for offset: %s.Info: %s' % ( + op_offset_original, op_offset_to_line)) + + +def debug(s): + pass + + +_Instruction = namedtuple('_Instruction', 'opname, opcode, starts_line, argval, is_jump_target, offset') + + +def _iter_as_bytecode_as_instructions_py2(co): + code = co.co_code + op_offset_to_line = dict(dis.findlinestarts(co)) + labels = set(dis.findlabels(code)) + bytecode_len = len(code) + i = 0 + extended_arg = 0 + free = None + + op_to_name = opname + + while i < bytecode_len: + c = code[i] + op = ord(c) + is_jump_target = i in labels + + curr_op_name = op_to_name[op] + initial_bytecode_offset = i + + i = i + 1 + if op < HAVE_ARGUMENT: + yield _Instruction(curr_op_name, op, _get_line(op_offset_to_line, initial_bytecode_offset, 0), None, is_jump_target, initial_bytecode_offset) + + else: + oparg = ord(code[i]) + ord(code[i + 1]) * 256 + extended_arg + + extended_arg = 0 + i = i + 2 + if op == EXTENDED_ARG: + extended_arg = oparg * 65536 + + if op in hasconst: + yield _Instruction(curr_op_name, op, _get_line(op_offset_to_line, initial_bytecode_offset, 0), co.co_consts[oparg], is_jump_target, initial_bytecode_offset) + elif op in hasname: + yield _Instruction(curr_op_name, op, _get_line(op_offset_to_line, initial_bytecode_offset, 0), co.co_names[oparg], is_jump_target, initial_bytecode_offset) + elif op in hasjrel: + argval = i + oparg + yield _Instruction(curr_op_name, op, _get_line(op_offset_to_line, initial_bytecode_offset, 0), argval, is_jump_target, initial_bytecode_offset) + elif op in haslocal: + yield _Instruction(curr_op_name, op, _get_line(op_offset_to_line, initial_bytecode_offset, 0), co.co_varnames[oparg], is_jump_target, initial_bytecode_offset) + elif op in hascompare: + yield _Instruction(curr_op_name, op, _get_line(op_offset_to_line, initial_bytecode_offset, 0), cmp_op[oparg], is_jump_target, initial_bytecode_offset) + elif op in hasfree: + if free is None: + free = co.co_cellvars + co.co_freevars + yield _Instruction(curr_op_name, op, _get_line(op_offset_to_line, initial_bytecode_offset, 0), free[oparg], is_jump_target, initial_bytecode_offset) + else: + yield _Instruction(curr_op_name, op, _get_line(op_offset_to_line, initial_bytecode_offset, 0), oparg, is_jump_target, initial_bytecode_offset) + + +def collect_try_except_info(co, use_func_first_line=False): + if not hasattr(co, 'co_lnotab'): + return [] + + if use_func_first_line: + firstlineno = co.co_firstlineno + else: + firstlineno = 0 + + try_except_info_lst = [] + stack_in_setup = [] + + if sys.version_info[0] < 3: + iter_in = _iter_as_bytecode_as_instructions_py2(co) + else: + iter_in = dis.Bytecode(co) + iter_in = list(iter_in) + + op_offset_to_line = dict(dis.findlinestarts(co)) + bytecode_to_instruction = {} + for instruction in iter_in: + bytecode_to_instruction[instruction.offset] = instruction + + if iter_in: + for instruction in iter_in: + curr_op_name = instruction.opname + + if curr_op_name == 'SETUP_EXCEPT': + try_except_info = TryExceptInfo( + _get_line(op_offset_to_line, instruction.offset, firstlineno, search=True)) + try_except_info.except_bytecode_offset = instruction.argval + try_except_info.except_line = _get_line( + op_offset_to_line, + try_except_info.except_bytecode_offset, + firstlineno, + ) + + stack_in_setup.append(try_except_info) + + elif curr_op_name == 'SETUP_FINALLY': + # We need to collect try..finally blocks too to make sure that + # the stack_in_setup we're using to collect info is correct. + try_except_info = TryExceptInfo( + _get_line(op_offset_to_line, instruction.offset, firstlineno, search=True), is_finally=True) + stack_in_setup.append(try_except_info) + + elif curr_op_name == 'RAISE_VARARGS': + # We want to know about reraises and returns inside of except blocks (unfortunately + # a raise appears to the debugger as a return, so, we may need to differentiate). + if instruction.argval == 0: + for info in stack_in_setup: + info.raise_lines_in_except.append( + _get_line(op_offset_to_line, instruction.offset, firstlineno, search=True)) + + elif curr_op_name == 'END_FINALLY': # The except block also ends with 'END_FINALLY'. + stack_in_setup[-1].except_end_bytecode_offset = instruction.offset + stack_in_setup[-1].except_end_line = _get_line(op_offset_to_line, instruction.offset, firstlineno, search=True) + if not stack_in_setup[-1].is_finally: + # Don't add try..finally blocks. + try_except_info_lst.append(stack_in_setup[-1]) + del stack_in_setup[-1] + + while stack_in_setup: + # On Py3 the END_FINALLY may not be there (so, the end of the function is also the end + # of the stack). + stack_in_setup[-1].except_end_bytecode_offset = instruction.offset + stack_in_setup[-1].except_end_line = _get_line(op_offset_to_line, instruction.offset, firstlineno, search=True) + if not stack_in_setup[-1].is_finally: + # Don't add try..finally blocks. + try_except_info_lst.append(stack_in_setup[-1]) + del stack_in_setup[-1] + + return try_except_info_lst diff --git a/ptvsd/_vendored/pydevd/_pydevd_bundle/pydevd_comm.py b/ptvsd/_vendored/pydevd/_pydevd_bundle/pydevd_comm.py index 18da29218..a9d922269 100644 --- a/ptvsd/_vendored/pydevd/_pydevd_bundle/pydevd_comm.py +++ b/ptvsd/_vendored/pydevd/_pydevd_bundle/pydevd_comm.py @@ -255,6 +255,7 @@ def unquote(s): '200': 'CMD_REDIRECT_OUTPUT', '201': 'CMD_GET_NEXT_STATEMENT_TARGETS', + '202': 'CMD_SET_PROJECT_ROOTS', '501': 'CMD_VERSION', '502': 'CMD_RETURN', diff --git a/ptvsd/_vendored/pydevd/_pydevd_bundle/pydevd_dont_trace_files.py b/ptvsd/_vendored/pydevd/_pydevd_bundle/pydevd_dont_trace_files.py index 370390458..8466da0cf 100644 --- a/ptvsd/_vendored/pydevd/_pydevd_bundle/pydevd_dont_trace_files.py +++ b/ptvsd/_vendored/pydevd/_pydevd_bundle/pydevd_dont_trace_files.py @@ -64,6 +64,7 @@ 'pydevd_additional_thread_info.py': PYDEV_FILE, 'pydevd_additional_thread_info_regular.py': PYDEV_FILE, 'pydevd_breakpoints.py': PYDEV_FILE, + 'pydevd_collect_try_except_info.py': PYDEV_FILE, 'pydevd_comm.py': PYDEV_FILE, 'pydevd_command_line_handling.py': PYDEV_FILE, 'pydevd_concurrency_logger.py': PYDEV_FILE, diff --git a/ptvsd/_vendored/pydevd/_pydevd_bundle/pydevd_trace_dispatch_regular.py b/ptvsd/_vendored/pydevd/_pydevd_bundle/pydevd_trace_dispatch_regular.py index 60333453e..82145b264 100644 --- a/ptvsd/_vendored/pydevd/_pydevd_bundle/pydevd_trace_dispatch_regular.py +++ b/ptvsd/_vendored/pydevd/_pydevd_bundle/pydevd_trace_dispatch_regular.py @@ -16,6 +16,8 @@ from _pydevd_bundle.pydevd_frame import PyDBFrame # ENDIF from os.path import basename, splitext +from _pydevd_bundle.pydevd_breakpoints import stop_on_unhandled_exception +from _pydevd_bundle.pydevd_collect_try_except_info import collect_try_except_info threadingCurrentThread = threading.currentThread get_file_type = DONT_TRACE.get @@ -33,9 +35,32 @@ global_cache_skips = {} global_cache_frame_skips = {} +# IFDEF CYTHON +# cdef class SafeCallWrapper: +# cdef method_object +# def __init__(self, method_object): +# self.method_object = method_object +# def __call__(self, *args): +# #Cannot use 'self' once inside the delegate call since we are borrowing the self reference f_trace field +# #in the frame, and that reference might get destroyed by set trace on frame and parents +# cdef PyObject* method_obj = self.method_object +# Py_INCREF(method_obj) +# ret = (method_obj)(*args) +# Py_XDECREF (method_obj) +# return SafeCallWrapper(ret) if ret is not None else None +# ELSE +# ENDIF + + def trace_dispatch(py_db, frame, event, arg): + # IFDEF CYTHON + # cdef str filename; + # cdef str name; + # cdef tuple args; + # ENDIF + # Note: this is always the first entry-point in the tracing for any thread. - # After entering here we'll set a new tracing function for this thread + # After entering here we'll set a new tracing function for this thread # where more information is cached (and will also setup the tracing for # frames where we should deal with unhandled exceptions). thread = None @@ -43,8 +68,8 @@ def trace_dispatch(py_db, frame, event, arg): # (i.e.: thread entry-points). f_unhandled = frame - only_trace_for_unhandled_exceptions = True # print('called at', f_unhandled.f_code.co_name, f_unhandled.f_code.co_filename, f_unhandled.f_code.co_firstlineno) + force_only_unhandled_tracer = False while f_unhandled is not None: filename = f_unhandled.f_code.co_filename name = splitext(basename(filename))[0] @@ -52,30 +77,34 @@ def trace_dispatch(py_db, frame, event, arg): if f_unhandled.f_code.co_name in ('__bootstrap', '_bootstrap'): # We need __bootstrap_inner, not __bootstrap. 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. t = f_unhandled.f_locals.get('self') + force_only_unhandled_tracer = True if t is not None and isinstance(t, threading.Thread): thread = t - only_trace_for_unhandled_exceptions = True break - + + elif name == 'pydev_monkey': + if f_unhandled.f_code.co_name == '__call__': + force_only_unhandled_tracer = True + 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 + force_only_unhandled_tracer = True break - + elif f_unhandled.f_back is None: - only_trace_for_unhandled_exceptions = False break - + f_unhandled = f_unhandled.f_back - + if thread is None: # Important: don't call threadingCurrentThread if we're in the threading module # to avoid creating dummy threads. @@ -91,86 +120,51 @@ def trace_dispatch(py_db, frame, event, arg): raise AttributeError() except: additional_info = set_additional_thread_info(thread) - + # print('enter thread tracer', thread, get_thread_id(thread)) - thread_tracer = ThreadTracer((py_db, thread, additional_info, global_cache_skips, global_cache_frame_skips)) - + args = (py_db, thread, additional_info, global_cache_skips, global_cache_frame_skips) + if f_unhandled is not None: - # 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 + if f_unhandled.f_back is None and not force_only_unhandled_tracer: + # Happens when we attach to a running program. + top_level_thread_tracer = TopLevelThreadTracerNoBackFrame(ThreadTracer(args).__call__, args) else: - f_trace = thread_tracer.trace_dispatch_and_unhandled_exceptions + # Stop in some internal place to report about unhandled exceptions + top_level_thread_tracer = TopLevelThreadTracerOnlyUnhandledExceptions(args) +# IFDEF CYTHON +# thread._top_level_thread_tracer = top_level_thread_tracer # Hack for cython to keep it alive while the thread is alive (just the method in the SetTrace is not enough). +# ELSE +# ENDIF + # print(' --> found to trace unhandled', f_unhandled.f_code.co_name, f_unhandled.f_code.co_filename, f_unhandled.f_code.co_firstlineno) + f_trace = top_level_thread_tracer.get_trace_dispatch_func() # IFDEF CYTHON # f_unhandled.f_trace = SafeCallWrapper(f_trace) # ELSE f_unhandled.f_trace = f_trace # ENDIF - - if frame is f_unhandled: - if only_trace_for_unhandled_exceptions: - return thread_tracer.trace_unhandled_exceptions(frame, event, arg) - else: - return thread_tracer.trace_dispatch_and_unhandled_exceptions(frame, event, arg) - + + if frame is f_unhandled: + return f_unhandled.f_trace(frame, event, arg) + + thread_tracer = ThreadTracer(args) # IFDEF CYTHON # thread._tracer = thread_tracer # Hack for cython to keep it alive while the thread is alive (just the method in the SetTrace is not enough). # ELSE # ENDIF + + SetTrace(thread_tracer.__call__) return thread_tracer.__call__(frame, event, arg) -# IFDEF CYTHON -# cdef class PyDbFrameTraceAndUnhandledExceptionsTrace(object): -# cdef object _pydb_frame_trace; -# cdef object _unhandled_trace; -# ELSE -class PyDbFrameTraceAndUnhandledExceptionsTrace(object): - ''' - A tracer which is meant to be put at entry points to trace PyDBFrames and unhandled - exceptions (only really activated when the user started running without debugging - and used a settrace later on -- and only in the frame which is the topmost frame as we - don't trace threading.py nor inside of pydevd, which are the other frames where - we deal with unhandled exceptions). - ''' -# ENDIF - def __init__(self, pydb_frame_trace, unhandled_trace): - self._pydb_frame_trace = pydb_frame_trace - 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) - # IFDEF CYTHON - # return SafeCallWrapper(self.trace_dispatch) - # ELSE - return self.trace_dispatch - # ENDIF - # IFDEF CYTHON -# cdef class SafeCallWrapper: -# cdef method_object -# def __init__(self, method_object): -# self.method_object = method_object -# def __call__(self, *args): -# #Cannot use 'self' once inside the delegate call since we are borrowing the self reference f_trace field -# #in the frame, and that reference might get destroyed by set trace on frame and parents -# cdef PyObject* method_obj = self.method_object -# Py_INCREF(method_obj) -# ret = (method_obj)(*args) -# Py_XDECREF (method_obj) -# return SafeCallWrapper(ret) if ret is not None else None -# cdef class ThreadTracer: +# cdef class TopLevelThreadTracerOnlyUnhandledExceptions: # cdef public tuple _args; # def __init__(self, tuple args): # self._args = args # ELSE -class ThreadTracer: +class TopLevelThreadTracerOnlyUnhandledExceptions: + def __init__(self, args): self._args = args # ENDIF @@ -179,43 +173,140 @@ 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: if not additional_info.suspended_at_unhandled: - if frame.f_back is not None: - additional_info.suspended_at_unhandled = True - + additional_info.suspended_at_unhandled = True + stop_on_unhandled_exception(py_db, t, additional_info, arg) # IFDEF CYTHON # return SafeCallWrapper(self.trace_unhandled_exceptions) # ELSE return self.trace_unhandled_exceptions # ENDIF - + + def get_trace_dispatch_func(self): + return self.trace_unhandled_exceptions + + +# IFDEF CYTHON +# cdef class TopLevelThreadTracerNoBackFrame: +# +# cdef public object _frame_trace_dispatch; +# cdef public tuple _args; +# cdef public object _try_except_info; +# cdef public object _last_exc_arg; +# cdef public set _raise_lines; +# cdef public int _last_raise_line; +# +# def __init__(self, frame_trace_dispatch, tuple args): +# self._frame_trace_dispatch = frame_trace_dispatch +# self._args = args +# self._try_except_info = None +# self._last_exc_arg = None +# self._raise_lines = set() +# self._last_raise_line = -1 +# ELSE +class TopLevelThreadTracerNoBackFrame: + ''' + This tracer is pretty special in that it's dealing with a frame without f_back (i.e.: top frame + on remote attach or QThread). + + This means that we have to carefully inspect exceptions to discover whether the exception will + be unhandled or not (if we're dealing with an unhandled exception we need to stop as unhandled, + otherwise we need to use the regular tracer -- unfortunately the debugger has little info to + work with in the tracing -- see: https://bugs.python.org/issue34099, so, we inspect bytecode to + determine if some exception will be traced or not... note that if this is not available -- such + as on Jython -- we consider any top-level exception to be unnhandled). + ''' + + def __init__(self, frame_trace_dispatch, args): + self._frame_trace_dispatch = frame_trace_dispatch + self._args = args + self._try_except_info = None + self._last_exc_arg = None + self._raise_lines = set() + self._last_raise_line = -1 +# 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 - else: - pydb_frame_trace = self.__call__(frame, event, arg) - if pydb_frame_trace is None: - # If the PyDBFrame did not return a tracer, just go with the simpler - # tracer for unhandled exceptions. - ret = self.trace_unhandled_exceptions - else: - # 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( - pydb_frame_trace, self.trace_dispatch_and_unhandled_exceptions) - ret = py_db_frame_trace_and_unhandled_exceptions_trace.trace_dispatch + if self._frame_trace_dispatch is not None: + # This deals with raised exceptions + self._frame_trace_dispatch = self._frame_trace_dispatch(frame, event, arg) + + if event == 'exception': + self._last_exc_arg = arg + self._raise_lines.add(frame.f_lineno) + self._last_raise_line = frame.f_lineno + + elif event == 'return' and self._last_exc_arg is not None: + # For unhandled exceptions we actually track the return when at the topmost level. + try: + py_db, t, additional_info = self._args[0:3] + if not additional_info.suspended_at_unhandled: # Note: only check it here, don't set. + if frame.f_lineno in self._raise_lines: + stop_on_unhandled_exception(py_db, t, additional_info, self._last_exc_arg) + + else: + if self._try_except_info is None: + self._try_except_info = collect_try_except_info(frame.f_code) + if not self._try_except_info: + # Consider the last exception as unhandled because there's no try..except in it. + stop_on_unhandled_exception(py_db, t, additional_info, self._last_exc_arg) + else: + # Now, consider only the try..except for the raise + valid_try_except_infos = [] + for try_except_info in self._try_except_info: + if try_except_info.is_line_in_try_block(self._last_raise_line): + valid_try_except_infos.append(try_except_info) + + if not valid_try_except_infos: + stop_on_unhandled_exception(py_db, t, additional_info, self._last_exc_arg) + + else: + # Note: check all, not only the "valid" ones to cover the case + # in "tests_python.test_tracing_on_top_level.raise_unhandled10" + # where one try..except is inside the other with only a raise + # and it's gotten in the except line. + for try_except_info in self._try_except_info: + if try_except_info.is_line_in_except_block(frame.f_lineno): + if ( + frame.f_lineno == try_except_info.except_line or + frame.f_lineno in try_except_info.raise_lines_in_except + ): + # In a raise inside a try..except block or some except which doesn't + # match the raised exception. + stop_on_unhandled_exception(py_db, t, additional_info, self._last_exc_arg) + break + else: + break # exited during the except block (no exception raised) + finally: + # Remove reference to exception after handling it. + self._last_exc_arg = None + # IFDEF CYTHON - # return SafeCallWrapper(ret) + # return SafeCallWrapper(self.trace_dispatch_and_unhandled_exceptions) # ELSE - return ret + return self.trace_dispatch_and_unhandled_exceptions # ENDIF + def get_trace_dispatch_func(self): + return self.trace_dispatch_and_unhandled_exceptions + + +# IFDEF CYTHON +# cdef class ThreadTracer: +# cdef public tuple _args; +# def __init__(self, tuple args): +# self._args = args +# ELSE +class ThreadTracer: + + def __init__(self, args): + self._args = args +# ENDIF + def __call__(self, frame, event, arg): ''' This is the callback used when we enter some context in the debugger. @@ -261,13 +352,12 @@ def __call__(self, frame, event, arg): py_db.notify_thread_not_alive(get_thread_id(t)) return None # suspend tracing - if py_db.thread_analyser is not None: py_db.thread_analyser.log_event(frame) if py_db.asyncio_analyser is not None: py_db.asyncio_analyser.log_event(frame) - + # Note: it's important that the context name is also given because we may hit something once # in the global context and another in the local context. frame_cache_key = (frame.f_code.co_firstlineno, frame.f_code.co_name, frame.f_code.co_filename) @@ -280,12 +370,12 @@ def __call__(self, frame, event, arg): abs_path_real_path_and_base = NORM_PATHS_AND_BASE_CONTAINER[frame.f_code.co_filename] except: abs_path_real_path_and_base = get_abs_path_real_path_and_base_from_frame(frame) - + filename = abs_path_real_path_and_base[1] - file_type = get_file_type(abs_path_real_path_and_base[-1]) #we don't want to debug threading or anything related to pydevd + file_type = get_file_type(abs_path_real_path_and_base[-1]) # we don't want to debug threading or anything related to pydevd if file_type is not None: - if file_type == 1: # inlining LIB_FILE = 1 + if file_type == 1: # inlining LIB_FILE = 1 if not py_db.in_project_scope(filename): # print('skipped: trace_dispatch (not in scope)', abs_path_real_path_and_base[-1], frame.f_lineno, event, frame.f_code.co_name, file_type) cache_skips[frame_cache_key] = 1 @@ -317,7 +407,7 @@ def __call__(self, frame, event, arg): if ret is None: cache_skips[frame_cache_key] = 1 return None - + # IFDEF CYTHON # return SafeCallWrapper(ret) # ELSE @@ -329,7 +419,7 @@ def __call__(self, frame, event, arg): except Exception: if py_db._finish_debugging_session: - return None # Don't log errors when we're shutting down. + return None # Don't log errors when we're shutting down. # Log it try: if traceback is not None: @@ -351,12 +441,11 @@ def __call__(self, frame, event, arg): # # See: https://github.com/IronLanguages/main/issues/1630 from _pydevd_bundle.pydevd_additional_thread_info_regular import _tid_to_last_frame - + _original_call = ThreadTracer.__call__ - + def __call__(self, frame, event, arg): _tid_to_last_frame[self._args[1].ident] = frame return _original_call(self, frame, event, arg) - + ThreadTracer.__call__ = __call__ - diff --git a/ptvsd/_vendored/pydevd/conftest.py b/ptvsd/_vendored/pydevd/conftest.py index 185e3a1c2..9d8b6d5f8 100644 --- a/ptvsd/_vendored/pydevd/conftest.py +++ b/ptvsd/_vendored/pydevd/conftest.py @@ -243,6 +243,8 @@ def before_after_each_function(request): ) +from tests_python.regression_check import data_regression, datadir, original_datadir + if IS_JYTHON or IS_IRONPYTHON: # On Jython and IronPython, it's a no-op. diff --git a/ptvsd/_vendored/pydevd/pydevd.py b/ptvsd/_vendored/pydevd/pydevd.py index 4b2ea7b19..41fee9dc3 100644 --- a/ptvsd/_vendored/pydevd/pydevd.py +++ b/ptvsd/_vendored/pydevd/pydevd.py @@ -218,9 +218,11 @@ class PyDB: """ - def __init__(self): - set_global_debugger(self) - pydevd_tracing.replace_sys_set_trace_func() + def __init__(self, set_as_global=True): + if set_as_global: + set_global_debugger(self) + pydevd_tracing.replace_sys_set_trace_func() + self.reader = None self.writer = None self.output_checker = None @@ -242,7 +244,9 @@ def __init__(self): self._main_lock = thread.allocate_lock() self._lock_running_thread_ids = thread.allocate_lock() self._py_db_command_thread_event = threading.Event() - CustomFramesContainer._py_db_command_thread_event = self._py_db_command_thread_event + if set_as_global: + CustomFramesContainer._py_db_command_thread_event = self._py_db_command_thread_event + self._finish_debugging_session = False self._termination_event_set = False self.signature_factory = None @@ -782,7 +786,7 @@ def cancel_async_evaluation(self, thread_id, frame_id): t.frame_id == frame_id: t.cancel_event.set() except: - import traceback;traceback.print_exc() + traceback.print_exc() finally: self._main_lock.release() @@ -798,7 +802,7 @@ def do_wait_suspend(self, thread, frame, event, arg, suspend_type="trace", send_ if send_suspend_message: message = thread.additional_info.pydev_message cmd = self.cmd_factory.make_thread_suspend_message(get_thread_id(thread), frame, thread.stop_reason, message, suspend_type) - thread_stack_str = cmd.thread_stack_str + thread_stack_str = cmd.thread_stack_str # @UnusedVariable -- `make_get_thread_stack_message` uses it later. self.writer.add_command(cmd) with CustomFramesContainer.custom_frames_lock: # @UndefinedVariable diff --git a/ptvsd/_vendored/pydevd/tests_python/debugger_fixtures.py b/ptvsd/_vendored/pydevd/tests_python/debugger_fixtures.py index 2245c0dc1..601a208ae 100644 --- a/ptvsd/_vendored/pydevd/tests_python/debugger_fixtures.py +++ b/ptvsd/_vendored/pydevd/tests_python/debugger_fixtures.py @@ -183,6 +183,30 @@ def test_file( return CaseSetup() +@pytest.fixture +def case_setup_unhandled_exceptions(case_setup): + + original = case_setup.test_file + + def check_test_suceeded_msg(writer, stdout, stderr): + return 'TEST SUCEEDED' in ''.join(stderr) + + def additional_output_checks(writer, stdout, stderr): + # Don't call super as we have an expected exception + if 'ValueError: TEST SUCEEDED' not in stderr: + raise AssertionError('"ValueError: TEST SUCEEDED" not in stderr.\nstdout:\n%s\n\nstderr:\n%s' % ( + stdout, stderr)) + + def test_file(*args, **kwargs): + kwargs.setdefault('check_test_suceeded_msg', check_test_suceeded_msg) + kwargs.setdefault('additional_output_checks', additional_output_checks) + return original(*args, **kwargs) + + case_setup.test_file = test_file + + return case_setup + + @pytest.fixture def case_setup_remote(): diff --git a/ptvsd/_vendored/pydevd/tests_python/debugger_unittest.py b/ptvsd/_vendored/pydevd/tests_python/debugger_unittest.py index 608234e67..41fa3b7a6 100644 --- a/ptvsd/_vendored/pydevd/tests_python/debugger_unittest.py +++ b/ptvsd/_vendored/pydevd/tests_python/debugger_unittest.py @@ -520,10 +520,15 @@ def do_kill(self): self.sock.close() def write(self, s): - self.log.append('write: %s' % (s,)) + from _pydevd_bundle.pydevd_comm import ID_TO_MEANING + meaning = ID_TO_MEANING.get(re.search(r'\d+', s).group(), '') + if meaning: + meaning += ': ' + + self.log.append('write: %s%s' % (meaning, s,)) if SHOW_WRITES_AND_READS: - print('Test Writer Thread Written %s' % (s,)) + print('Test Writer Thread Written %s%s' % (meaning, s,)) msg = s + '\n' if IS_PY3K: msg = msg.encode('utf-8') diff --git a/ptvsd/_vendored/pydevd/tests_python/regression_check.py b/ptvsd/_vendored/pydevd/tests_python/regression_check.py new file mode 100644 index 000000000..5dd35ef1f --- /dev/null +++ b/ptvsd/_vendored/pydevd/tests_python/regression_check.py @@ -0,0 +1,240 @@ +# Based on: https://github.com/ESSS/pytest-regressions (License: MIT) +# Created copy because we need Python 2.6 which is not available on pytest-regressions. +# Note: only used for testing. + +# encoding: UTF-8 +import difflib +import pytest +import sys +from functools import partial + +if sys.version_info[0] <= 2: + from pathlib2 import Path +else: + from pathlib import Path + +FORCE_REGEN = False + + +@pytest.fixture +def original_datadir(request): + # Method from: https://github.com/gabrielcnr/pytest-datadir + # License: MIT + import os.path + return Path(os.path.splitext(request.module.__file__)[0]) + + +@pytest.fixture +def datadir(original_datadir, tmpdir): + # Method from: https://github.com/gabrielcnr/pytest-datadir + # License: MIT + import shutil + result = Path(str(tmpdir.join(original_datadir.stem))) + if original_datadir.is_dir(): + shutil.copytree(str(original_datadir), str(result)) + else: + result.mkdir() + return result + + +@pytest.fixture +def data_regression(datadir, original_datadir, request): + return DataRegressionFixture(datadir, original_datadir, request) + + +def check_text_files(obtained_fn, expected_fn, fix_callback=lambda x: x, encoding=None): + """ + Compare two files contents. If the files differ, show the diff and write a nice HTML + diff file into the data directory. + :param Path obtained_fn: path to obtained file during current testing. + :param Path expected_fn: path to the expected file, obtained from previous testing. + :param str encoding: encoding used to open the files. + :param callable fix_callback: + A callback to "fix" the contents of the obtained (first) file. + This callback receives a list of strings (lines) and must also return a list of lines, + changed as needed. + The resulting lines will be used to compare with the contents of expected_fn. + """ + __tracebackhide__ = True + + obtained_fn = Path(obtained_fn) + expected_fn = Path(expected_fn) + obtained_lines = fix_callback(obtained_fn.read_text(encoding=encoding).splitlines()) + expected_lines = expected_fn.read_text(encoding=encoding).splitlines() + + if obtained_lines != expected_lines: + diff_lines = list(difflib.unified_diff(expected_lines, obtained_lines)) + if len(diff_lines) <= 500: + html_fn = obtained_fn.with_suffix(".diff.html") + try: + differ = difflib.HtmlDiff() + html_diff = differ.make_file( + fromlines=expected_lines, + fromdesc=expected_fn, + tolines=obtained_lines, + todesc=obtained_fn, + ) + except Exception as e: + html_fn = "(failed to generate html diff: %s)" % e + else: + html_fn.write_text(html_diff, encoding="UTF-8") + + diff = ["FILES DIFFER:", str(expected_fn), str(obtained_fn)] + diff += ["HTML DIFF: %s" % html_fn] + diff += diff_lines + raise AssertionError("\n".join(diff)) + else: + # difflib has exponential scaling and for thousands of lines it starts to take minutes to render + # the HTML diff. + msg = [ + "Files are different, but diff is too big (%s lines)" % (len(diff_lines),), + "- obtained: %s" % (obtained_fn,), + "- expected: %s" % (expected_fn,), + ] + raise AssertionError("\n".join(msg)) + + +def perform_regression_check( + datadir, + original_datadir, + request, + check_fn, + dump_fn, + extension, + basename=None, + fullpath=None, + obtained_filename=None, + dump_aux_fn=lambda filename: [], +): + """ + First run of this check will generate a expected file. Following attempts will always try to + match obtained files with that expected file. + :param Path datadir: Fixture embed_data. + :param Path original_datadir: Fixture embed_data. + :param SubRequest request: Pytest request object. + :param callable check_fn: A function that receives as arguments, respectively, absolute path to + obtained file and absolute path to expected file. It must assert if contents of file match. + Function can safely assume that obtained file is already dumped and only care about + comparison. + :param callable dump_fn: A function that receive an absolute file path as argument. Implementor + must dump file in this path. + :param callable dump_aux_fn: A function that receives the same file path as ``dump_fn``, but may + dump additional files to help diagnose this regression later (for example dumping image of + 3d views and plots to compare later). Must return the list of file names written (used to display). + :param six.text_type extension: Extension of files compared by this check. + :param six.text_type obtained_filename: complete path to use to write the obtained file. By + default will prepend `.obtained` before the file extension. + ..see: `data_regression.Check` for `basename` and `fullpath` arguments. + """ + import re + + assert not (basename and fullpath), "pass either basename or fullpath, but not both" + + __tracebackhide__ = True + + if basename is None: + basename = re.sub("[\W]", "_", request.node.name) + + if fullpath: + filename = source_filename = Path(fullpath) + else: + filename = datadir / (basename + extension) + source_filename = original_datadir / (basename + extension) + + def make_location_message(banner, filename, aux_files): + msg = [banner, "- %s" % (filename,)] + if aux_files: + msg.append("Auxiliary:") + msg += ["- %s" % (x,) for x in aux_files] + return "\n".join(msg) + + if not filename.is_file(): + source_filename.parent.mkdir(parents=True, exist_ok=True) + dump_fn(source_filename) + aux_created = dump_aux_fn(source_filename) + + msg = make_location_message( + "File not found in data directory, created:", source_filename, aux_created + ) + pytest.fail(msg) + else: + if obtained_filename is None: + if fullpath: + obtained_filename = (datadir / basename).with_suffix( + ".obtained" + extension + ) + else: + obtained_filename = filename.with_suffix(".obtained" + extension) + + dump_fn(obtained_filename) + + try: + check_fn(obtained_filename, filename) + except AssertionError: + if FORCE_REGEN: + dump_fn(source_filename) + aux_created = dump_aux_fn(source_filename) + msg = make_location_message( + "Files differ and FORCE_REGEN set, regenerating file at:", + source_filename, + aux_created, + ) + pytest.fail(msg) + else: + dump_aux_fn(obtained_filename) + raise + + +class DataRegressionFixture(object): + """ + Implementation of `data_regression` fixture. + """ + + def __init__(self, datadir, original_datadir, request): + """ + :type datadir: Path + :type original_datadir: Path + :type request: FixtureRequest + """ + self.request = request + self.datadir = datadir + self.original_datadir = original_datadir + + def check(self, data_dict, basename=None, fullpath=None): + """ + Checks the given dict against a previously recorded version, or generate a new file. + :param dict data_dict: any yaml serializable dict. + :param str basename: basename of the file to test/record. If not given the name + of the test is used. + Use either `basename` or `fullpath`. + :param str fullpath: complete path to use as a reference file. This option + will ignore ``datadir`` fixture when reading *expected* files but will still use it to + write *obtained* files. Useful if a reference file is located in the session data dir for example. + ``basename`` and ``fullpath`` are exclusive. + """ + __tracebackhide__ = True + + def dump(filename): + """Dump dict contents to the given filename""" + import json + + s = json.dumps(data_dict, sort_keys=True, indent=4) + if isinstance(s, bytes): + s = s.decode('utf-8') + + s = u'\n'.join([line.rstrip() for line in s.splitlines()]) + s = s.encode('utf-8') + + with filename.open("wb") as f: + f.write(s) + + perform_regression_check( + datadir=self.datadir, + original_datadir=self.original_datadir, + request=self.request, + check_fn=partial(check_text_files, encoding="UTF-8"), + dump_fn=dump, + extension=".json", + basename=basename, + fullpath=fullpath, + ) diff --git a/ptvsd/_vendored/pydevd/tests_python/resources/_debugger_case_check_tracer.py b/ptvsd/_vendored/pydevd/tests_python/resources/_debugger_case_check_tracer.py new file mode 100644 index 000000000..099b7d87a --- /dev/null +++ b/ptvsd/_vendored/pydevd/tests_python/resources/_debugger_case_check_tracer.py @@ -0,0 +1,116 @@ +import threading, atexit, sys +from collections import namedtuple +import os.path + +if sys.version_info[0] >= 3: + from _thread import start_new_thread +else: + from thread import start_new_thread + +FrameInfo = namedtuple('FrameInfo', 'filename, name, f_trace') + + +def _atexit(): + sys.stderr.flush() + sys.stdout.flush() + + +# Register the TEST SUCEEDED msg to the exit of the process. +atexit.register(_atexit) + + +def _iter_frame_info(frame): + while frame is not None: + yield FrameInfo( + os.path.basename(frame.f_code.co_filename), + frame.f_code.co_name, + frame.f_trace.__name__ if frame.f_trace is not None else "None" + ) + frame = frame.f_back + + +def check_frame_info(expected): + found = list(_iter_frame_info(sys._getframe().f_back)) + + def fail(): + raise AssertionError('Expected:\n%s\n\nFound:\n%s\n' % ( + '\n'.join(str(x) for x in expected), + '\n'.join(str(x) for x in found))) + + for found_info, expected_info in zip(found, expected): + if found_info.filename != expected_info.filename or found_info.name != expected_info.name: + fail() + + for f_trace in expected_info.f_trace.split('|'): + if f_trace == found_info.f_trace: + break + else: + fail() + + +def thread_func(): + if sys.version_info[0] >= 3: + check_frame_info([ + FrameInfo(filename='_debugger_case_check_tracer.py', name='thread_func', f_trace='trace_exception'), + FrameInfo(filename='threading.py', name='run', f_trace='None'), + FrameInfo(filename='threading.py', name='_bootstrap_inner', f_trace='trace_unhandled_exceptions'), + FrameInfo(filename='threading.py', name='_bootstrap', f_trace='None'), + FrameInfo(filename='pydev_monkey.py', name='__call__', f_trace='None') + ]) + else: + check_frame_info([ + FrameInfo(filename='_debugger_case_check_tracer.py', name='thread_func', f_trace='trace_exception'), + FrameInfo(filename='threading.py', name='run', f_trace='None'), + FrameInfo(filename='threading.py', name='__bootstrap_inner', f_trace='trace_unhandled_exceptions'), + FrameInfo(filename='threading.py', name='__bootstrap', f_trace='None'), + FrameInfo(filename='pydev_monkey.py', name='__call__', f_trace='None'), + ]) + + +th = threading.Thread(target=thread_func) +th.setDaemon(True) +th.start() + +event = threading.Event() + + +def thread_func2(): + try: + check_frame_info([ + FrameInfo(filename='_debugger_case_check_tracer.py', name='thread_func2', f_trace='trace_exception'), + FrameInfo(filename='pydev_monkey.py', name='__call__', f_trace='trace_unhandled_exceptions') + ]) + finally: + event.set() + + +start_new_thread(thread_func2, ()) + +event.wait() +th.join() + +# This is a bit tricky: although we waited on the event, there's a slight chance +# that we didn't get the notification because the thread could've stopped executing, +# so, sleep a bit so that the test does not become flaky. +import time +time.sleep(.3) + +if sys.version_info[0] >= 3: + check_frame_info([ + FrameInfo(filename='_debugger_case_check_tracer.py', name='', f_trace='trace_exception'), + FrameInfo(filename='_pydev_execfile.py', name='execfile', f_trace='None'), + FrameInfo(filename='pydevd.py', name='_exec', f_trace='trace_unhandled_exceptions'), + FrameInfo(filename='pydevd.py', name='run', f_trace='trace_dispatch|None'), + FrameInfo(filename='pydevd.py', name='main', f_trace='trace_dispatch'), + FrameInfo(filename='pydevd.py', name='', f_trace='trace_dispatch') + ]) +else: + check_frame_info([ + FrameInfo(filename='_debugger_case_check_tracer.py', name='', f_trace='trace_exception'), + FrameInfo(filename='pydevd.py', name='_exec', f_trace='trace_unhandled_exceptions'), + FrameInfo(filename='pydevd.py', name='run', f_trace='trace_dispatch|None'), + FrameInfo(filename='pydevd.py', name='main', f_trace='trace_dispatch'), + FrameInfo(filename='pydevd.py', name='', f_trace='trace_dispatch'), + ]) + +print('TEST SUCEEDED') diff --git a/ptvsd/_vendored/pydevd/tests_python/test_collect_try_except_info.py b/ptvsd/_vendored/pydevd/tests_python/test_collect_try_except_info.py new file mode 100644 index 000000000..ec7c1cde0 --- /dev/null +++ b/ptvsd/_vendored/pydevd/tests_python/test_collect_try_except_info.py @@ -0,0 +1,263 @@ +from io import StringIO +import os.path +import sys +import traceback + +from _pydevd_bundle.pydevd_collect_try_except_info import collect_try_except_info +from tests_python.debugger_unittest import IS_CPYTHON + + +def _method_call_with_error(): + try: + _method_reraise() + except: + raise + + +def _method_except_local(): + Foo = AssertionError + try: # SETUP_EXCEPT (to except line) + raise AssertionError() + except Foo as exc: + # DUP_TOP, LOAD_FAST (x), COMPARE_OP (exception match), POP_JUMP_IF_FALSE + pass + + +def _method_reraise(): + try: # SETUP_EXCEPT (to except line) + raise AssertionError() + except AssertionError as e: # POP_TOP + raise e + + +def _method_return_with_error(): + _method_call_with_error() + + +def _method_return_with_error2(): + try: + _method_call_with_error() + except: + return + + +def _method_simple_raise_any_except(): + try: # SETUP_EXCEPT (to except line) + raise AssertionError() + except: # POP_TOP + pass + + +def _method_simple_raise_any_except_return_on_raise(): + # Note how the tracing the debugger has is equal to the tracing from _method_simple_raise_any_except + # but this one resulted in an unhandled exception while the other one didn't. + try: # SETUP_EXCEPT (to except line) + raise AssertionError() + except: # POP_TOP + raise # RAISE_VARARGS + + +def _method_simple_raise_local_load(): + x = AssertionError + try: # SETUP_EXCEPT (to except line) + raise AssertionError() + except x as exc: + # DUP_TOP, LOAD_GLOBAL (NameError), LOAD_GLOBAL(AssertionError), BUILD_TUPLE, + # COMPARE_OP (exception match), POP_JUMP_IF_FALSE + pass + + +def _method_simple_raise_multi_except(): + try: # SETUP_EXCEPT (to except line) + raise AssertionError() + except (NameError, AssertionError) as exc: + # DUP_TOP, LOAD_FAST (x), COMPARE_OP (exception match), POP_JUMP_IF_FALSE + pass + + +def _method_simple_raise_unmatched_except(): + try: # SETUP_EXCEPT (to except line) + raise AssertionError() + except NameError: # DUP_TOP, LOAD_GLOBAL (NameError), COMPARE_OP (exception match), POP_JUMP_IF_FALSE + pass + + +def _method_try_except(): + try: # SETUP_EXCEPT (to except line) + try: # SETUP_EXCEPT (to except line) + raise AssertionError() + except: # POP_TOP + raise + except: # POP_TOP + return ( + 1, + 2 + ) + + +class _Tracer(object): + + def __init__(self, partial_info=False): + self.partial_info = partial_info + self.stream = StringIO() + self._in_print = False + + def tracer_printer(self, frame, event, arg): + if self._in_print: + return None + self._in_print = True + try: + if arg is not None: + if event == 'exception': + arg = arg[0].__name__ + elif arg is not None: + arg = str(arg) + if arg is None: + arg = '' + + if self.partial_info: + s = ' '.join(( + os.path.basename(frame.f_code.co_filename), + event.upper() if event != 'line' else event, + arg, + )) + else: + s = ' '.join(( + str(frame.f_lineno), + frame.f_code.co_name, + os.path.basename(frame.f_code.co_filename), + event.upper() if event != 'line' else event, + arg, + )) + self.writeln(s) + except: + traceback.print_exc() + self._in_print = False + return self.tracer_printer + + def writeln(self, s): + self.write(s) + self.write('\n') + + def write(self, s): + if isinstance(s, bytes): + s = s.decode('utf-8') + self.stream.write(s) + + def call(self, c): + sys.settrace(self.tracer_printer) + try: + c() + except: + pass + sys.settrace(None) + return self.stream.getvalue() + + +import pytest + + +@pytest.mark.skipif(not IS_CPYTHON, reason='CPython only test.') +def test_collect_try_except_info(data_regression): + method_to_info = {} + for key, method in sorted(dict(globals()).items()): + if key.startswith('_method'): + info = collect_try_except_info(method.__code__, use_func_first_line=True) + + if sys.version_info[:2] >= (3, 7): + for try_except_info in info: + # On 3.7 the last bytecode actually has a different start line. + if try_except_info.except_end_line == 8: + try_except_info.except_end_line = 9 + + method_to_info[key] = [str(x) for x in info] + + data_regression.check(method_to_info) + + +def test_collect_try_except_info2(): + + def method(): + try: + raise AssertionError + except: + _a = 10 + raise + finally: + _b = 20 + _c = 20 + + code = method.__code__ + lst = collect_try_except_info(code, use_func_first_line=True) + if IS_CPYTHON: + assert str(lst) == '[{try:1 except 3 end block 5 raises: 5}]' + else: + assert lst == [] + + +def _create_entry(instruction): + argval = instruction.argval + return dict( + opname=instruction.opname, + argval=argval, + starts_line=instruction.starts_line, + is_jump_target=instruction.is_jump_target, + ) + + +def debug_test_iter_bytecode(data_regression): + # Note: not run by default, only to help visualizing bytecode and comparing differences among versions. + import dis + + basename = 'test_iter_bytecode.py%s%s' % (sys.version_info[:2]) + method_to_info = {} + for key, method in sorted(dict(globals()).items()): + if key.startswith('_method'): + info = [] + + if sys.version_info[0] < 3: + from _pydevd_bundle.pydevd_collect_try_except_info import _iter_as_bytecode_as_instructions_py2 + iter_in = _iter_as_bytecode_as_instructions_py2(method.__code__) + else: + iter_in = dis.Bytecode(method) + + for instruction in iter_in: + info.append(_create_entry(instruction)) + + msg = [] + for d in info: + line = [] + for k, v in sorted(d.items()): + line.append(u'%s=%s' % (k, v)) + msg.append(u' '.join(line)) + if isinstance(key, bytes): + key = key.decode('utf-8') + method_to_info[key] = msg + + data_regression.check(method_to_info, basename=basename) + + +def debug_test_tracing_output(): # Note: not run by default, only to debug tracing. + from collections import defaultdict + output_to_method_names = defaultdict(list) + for key, val in sorted(dict(globals()).items()): + if key.startswith('_method'): + tracer = _Tracer(partial_info=False) + output_to_method_names[tracer.call(val)].append(val.__name__) + + # Notes: + # + # Seen as the same by the tracing (so, we inspect the bytecode to disambiguate). + # _method_simple_raise_any_except + # _method_simple_raise_any_except_return_on_raise + # _method_simple_raise_multi_except + # + # The return with an exception is always None + # + # It's not possible to disambiguate from a return None, pass or raise just with the tracing + # (only a raise with an exception is gotten by the debugger). + for output, method_names in sorted(output_to_method_names.items(), key=lambda x:(-len(x[1]), ''.join(x[1]))): + print('=' * 80) + print(' %s ' % (', '.join(method_names),)) + print('=' * 80) + print(output) diff --git a/ptvsd/_vendored/pydevd/tests_python/test_collect_try_except_info/test_collect_try_except_info.json b/ptvsd/_vendored/pydevd/tests_python/test_collect_try_except_info/test_collect_try_except_info.json new file mode 100644 index 000000000..bb54b9a0e --- /dev/null +++ b/ptvsd/_vendored/pydevd/tests_python/test_collect_try_except_info/test_collect_try_except_info.json @@ -0,0 +1,34 @@ +{ + "_method_call_with_error": [ + "{try:1 except 3 end block 4 raises: 4}" + ], + "_method_except_local": [ + "{try:2 except 4 end block 6}" + ], + "_method_reraise": [ + "{try:1 except 3 end block 4}" + ], + "_method_return_with_error": [], + "_method_return_with_error2": [ + "{try:1 except 3 end block 4}" + ], + "_method_simple_raise_any_except": [ + "{try:1 except 3 end block 4}" + ], + "_method_simple_raise_any_except_return_on_raise": [ + "{try:3 except 5 end block 6 raises: 6}" + ], + "_method_simple_raise_local_load": [ + "{try:2 except 4 end block 7}" + ], + "_method_simple_raise_multi_except": [ + "{try:1 except 3 end block 5}" + ], + "_method_simple_raise_unmatched_except": [ + "{try:1 except 3 end block 4}" + ], + "_method_try_except": [ + "{try:2 except 4 end block 5 raises: 5}", + "{try:1 except 6 end block 9 raises: 5}" + ] +} \ No newline at end of file diff --git a/ptvsd/_vendored/pydevd/tests_python/test_collect_try_except_info/test_iter_bytecode.py26.json b/ptvsd/_vendored/pydevd/tests_python/test_collect_try_except_info/test_iter_bytecode.py26.json new file mode 100644 index 000000000..7013d74ba --- /dev/null +++ b/ptvsd/_vendored/pydevd/tests_python/test_collect_try_except_info/test_iter_bytecode.py26.json @@ -0,0 +1,210 @@ +{ + "_method_call_with_error": [ + "argval=14 is_jump_target=False opname=SETUP_EXCEPT starts_line=11", + "argval=_method_reraise is_jump_target=False opname=LOAD_GLOBAL starts_line=12", + "argval=0 is_jump_target=False opname=CALL_FUNCTION starts_line=None", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=None is_jump_target=False opname=POP_BLOCK starts_line=None", + "argval=24 is_jump_target=False opname=JUMP_FORWARD starts_line=None", + "argval=None is_jump_target=True opname=POP_TOP starts_line=13", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=0 is_jump_target=False opname=RAISE_VARARGS starts_line=14", + "argval=24 is_jump_target=False opname=JUMP_FORWARD starts_line=None", + "argval=None is_jump_target=False opname=END_FINALLY starts_line=None", + "argval=None is_jump_target=True opname=LOAD_CONST starts_line=None", + "argval=None is_jump_target=False opname=RETURN_VALUE starts_line=None" + ], + "_method_except_local": [ + "argval=AssertionError is_jump_target=False opname=LOAD_GLOBAL starts_line=18", + "argval=Foo is_jump_target=False opname=STORE_FAST starts_line=None", + "argval=22 is_jump_target=False opname=SETUP_EXCEPT starts_line=19", + "argval=AssertionError is_jump_target=False opname=LOAD_GLOBAL starts_line=20", + "argval=0 is_jump_target=False opname=CALL_FUNCTION starts_line=None", + "argval=1 is_jump_target=False opname=RAISE_VARARGS starts_line=None", + "argval=None is_jump_target=False opname=POP_BLOCK starts_line=None", + "argval=43 is_jump_target=False opname=JUMP_FORWARD starts_line=None", + "argval=None is_jump_target=True opname=DUP_TOP starts_line=21", + "argval=Foo is_jump_target=False opname=LOAD_FAST starts_line=None", + "argval=exception match is_jump_target=False opname=COMPARE_OP starts_line=None", + "argval=41 is_jump_target=False opname=JUMP_IF_FALSE starts_line=None", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=exc is_jump_target=False opname=STORE_FAST starts_line=None", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=43 is_jump_target=False opname=JUMP_FORWARD starts_line=23", + "argval=None is_jump_target=True opname=POP_TOP starts_line=None", + "argval=None is_jump_target=False opname=END_FINALLY starts_line=None", + "argval=None is_jump_target=True opname=LOAD_CONST starts_line=None", + "argval=None is_jump_target=False opname=RETURN_VALUE starts_line=None" + ], + "_method_reraise": [ + "argval=16 is_jump_target=False opname=SETUP_EXCEPT starts_line=27", + "argval=AssertionError is_jump_target=False opname=LOAD_GLOBAL starts_line=28", + "argval=0 is_jump_target=False opname=CALL_FUNCTION starts_line=None", + "argval=1 is_jump_target=False opname=RAISE_VARARGS starts_line=None", + "argval=None is_jump_target=False opname=POP_BLOCK starts_line=None", + "argval=43 is_jump_target=False opname=JUMP_FORWARD starts_line=None", + "argval=None is_jump_target=True opname=DUP_TOP starts_line=29", + "argval=AssertionError is_jump_target=False opname=LOAD_GLOBAL starts_line=None", + "argval=exception match is_jump_target=False opname=COMPARE_OP starts_line=None", + "argval=41 is_jump_target=False opname=JUMP_IF_FALSE starts_line=None", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=e is_jump_target=False opname=STORE_FAST starts_line=None", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=e is_jump_target=False opname=LOAD_FAST starts_line=30", + "argval=1 is_jump_target=False opname=RAISE_VARARGS starts_line=None", + "argval=43 is_jump_target=False opname=JUMP_FORWARD starts_line=None", + "argval=None is_jump_target=True opname=POP_TOP starts_line=None", + "argval=None is_jump_target=False opname=END_FINALLY starts_line=None", + "argval=None is_jump_target=True opname=LOAD_CONST starts_line=None", + "argval=None is_jump_target=False opname=RETURN_VALUE starts_line=None" + ], + "_method_return_with_error": [ + "argval=_method_call_with_error is_jump_target=False opname=LOAD_GLOBAL starts_line=34", + "argval=0 is_jump_target=False opname=CALL_FUNCTION starts_line=None", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=None is_jump_target=False opname=LOAD_CONST starts_line=None", + "argval=None is_jump_target=False opname=RETURN_VALUE starts_line=None" + ], + "_method_return_with_error2": [ + "argval=14 is_jump_target=False opname=SETUP_EXCEPT starts_line=38", + "argval=_method_call_with_error is_jump_target=False opname=LOAD_GLOBAL starts_line=39", + "argval=0 is_jump_target=False opname=CALL_FUNCTION starts_line=None", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=None is_jump_target=False opname=POP_BLOCK starts_line=None", + "argval=22 is_jump_target=False opname=JUMP_FORWARD starts_line=None", + "argval=None is_jump_target=True opname=POP_TOP starts_line=40", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=None is_jump_target=False opname=LOAD_CONST starts_line=41", + "argval=None is_jump_target=False opname=RETURN_VALUE starts_line=None", + "argval=None is_jump_target=False opname=END_FINALLY starts_line=None", + "argval=None is_jump_target=True opname=LOAD_CONST starts_line=None", + "argval=None is_jump_target=False opname=RETURN_VALUE starts_line=None" + ], + "_method_simple_raise_any_except": [ + "argval=16 is_jump_target=False opname=SETUP_EXCEPT starts_line=45", + "argval=AssertionError is_jump_target=False opname=LOAD_GLOBAL starts_line=46", + "argval=0 is_jump_target=False opname=CALL_FUNCTION starts_line=None", + "argval=1 is_jump_target=False opname=RAISE_VARARGS starts_line=None", + "argval=None is_jump_target=False opname=POP_BLOCK starts_line=None", + "argval=23 is_jump_target=False opname=JUMP_FORWARD starts_line=None", + "argval=None is_jump_target=True opname=POP_TOP starts_line=47", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=23 is_jump_target=False opname=JUMP_FORWARD starts_line=48", + "argval=None is_jump_target=False opname=END_FINALLY starts_line=None", + "argval=None is_jump_target=True opname=LOAD_CONST starts_line=None", + "argval=None is_jump_target=False opname=RETURN_VALUE starts_line=None" + ], + "_method_simple_raise_any_except_return_on_raise": [ + "argval=16 is_jump_target=False opname=SETUP_EXCEPT starts_line=54", + "argval=AssertionError is_jump_target=False opname=LOAD_GLOBAL starts_line=55", + "argval=0 is_jump_target=False opname=CALL_FUNCTION starts_line=None", + "argval=1 is_jump_target=False opname=RAISE_VARARGS starts_line=None", + "argval=None is_jump_target=False opname=POP_BLOCK starts_line=None", + "argval=26 is_jump_target=False opname=JUMP_FORWARD starts_line=None", + "argval=None is_jump_target=True opname=POP_TOP starts_line=56", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=0 is_jump_target=False opname=RAISE_VARARGS starts_line=57", + "argval=26 is_jump_target=False opname=JUMP_FORWARD starts_line=None", + "argval=None is_jump_target=False opname=END_FINALLY starts_line=None", + "argval=None is_jump_target=True opname=LOAD_CONST starts_line=None", + "argval=None is_jump_target=False opname=RETURN_VALUE starts_line=None" + ], + "_method_simple_raise_local_load": [ + "argval=AssertionError is_jump_target=False opname=LOAD_GLOBAL starts_line=61", + "argval=x is_jump_target=False opname=STORE_FAST starts_line=None", + "argval=22 is_jump_target=False opname=SETUP_EXCEPT starts_line=62", + "argval=AssertionError is_jump_target=False opname=LOAD_GLOBAL starts_line=63", + "argval=0 is_jump_target=False opname=CALL_FUNCTION starts_line=None", + "argval=1 is_jump_target=False opname=RAISE_VARARGS starts_line=None", + "argval=None is_jump_target=False opname=POP_BLOCK starts_line=None", + "argval=43 is_jump_target=False opname=JUMP_FORWARD starts_line=None", + "argval=None is_jump_target=True opname=DUP_TOP starts_line=64", + "argval=x is_jump_target=False opname=LOAD_FAST starts_line=None", + "argval=exception match is_jump_target=False opname=COMPARE_OP starts_line=None", + "argval=41 is_jump_target=False opname=JUMP_IF_FALSE starts_line=None", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=exc is_jump_target=False opname=STORE_FAST starts_line=None", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=43 is_jump_target=False opname=JUMP_FORWARD starts_line=67", + "argval=None is_jump_target=True opname=POP_TOP starts_line=None", + "argval=None is_jump_target=False opname=END_FINALLY starts_line=None", + "argval=None is_jump_target=True opname=LOAD_CONST starts_line=None", + "argval=None is_jump_target=False opname=RETURN_VALUE starts_line=None" + ], + "_method_simple_raise_multi_except": [ + "argval=16 is_jump_target=False opname=SETUP_EXCEPT starts_line=71", + "argval=AssertionError is_jump_target=False opname=LOAD_GLOBAL starts_line=72", + "argval=0 is_jump_target=False opname=CALL_FUNCTION starts_line=None", + "argval=1 is_jump_target=False opname=RAISE_VARARGS starts_line=None", + "argval=None is_jump_target=False opname=POP_BLOCK starts_line=None", + "argval=43 is_jump_target=False opname=JUMP_FORWARD starts_line=None", + "argval=None is_jump_target=True opname=DUP_TOP starts_line=73", + "argval=NameError is_jump_target=False opname=LOAD_GLOBAL starts_line=None", + "argval=AssertionError is_jump_target=False opname=LOAD_GLOBAL starts_line=None", + "argval=2 is_jump_target=False opname=BUILD_TUPLE starts_line=None", + "argval=exception match is_jump_target=False opname=COMPARE_OP starts_line=None", + "argval=41 is_jump_target=False opname=JUMP_IF_FALSE starts_line=None", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=exc is_jump_target=False opname=STORE_FAST starts_line=None", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=43 is_jump_target=False opname=JUMP_FORWARD starts_line=75", + "argval=None is_jump_target=True opname=POP_TOP starts_line=None", + "argval=None is_jump_target=False opname=END_FINALLY starts_line=None", + "argval=None is_jump_target=True opname=LOAD_CONST starts_line=None", + "argval=None is_jump_target=False opname=RETURN_VALUE starts_line=None" + ], + "_method_simple_raise_unmatched_except": [ + "argval=16 is_jump_target=False opname=SETUP_EXCEPT starts_line=79", + "argval=AssertionError is_jump_target=False opname=LOAD_GLOBAL starts_line=80", + "argval=0 is_jump_target=False opname=CALL_FUNCTION starts_line=None", + "argval=1 is_jump_target=False opname=RAISE_VARARGS starts_line=None", + "argval=None is_jump_target=False opname=POP_BLOCK starts_line=None", + "argval=35 is_jump_target=False opname=JUMP_FORWARD starts_line=None", + "argval=None is_jump_target=True opname=DUP_TOP starts_line=81", + "argval=NameError is_jump_target=False opname=LOAD_GLOBAL starts_line=None", + "argval=exception match is_jump_target=False opname=COMPARE_OP starts_line=None", + "argval=33 is_jump_target=False opname=JUMP_IF_FALSE starts_line=None", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=35 is_jump_target=False opname=JUMP_FORWARD starts_line=82", + "argval=None is_jump_target=True opname=POP_TOP starts_line=None", + "argval=None is_jump_target=False opname=END_FINALLY starts_line=None", + "argval=None is_jump_target=True opname=LOAD_CONST starts_line=None", + "argval=None is_jump_target=False opname=RETURN_VALUE starts_line=None" + ], + "_method_try_except": [ + "argval=33 is_jump_target=False opname=SETUP_EXCEPT starts_line=86", + "argval=19 is_jump_target=False opname=SETUP_EXCEPT starts_line=87", + "argval=AssertionError is_jump_target=False opname=LOAD_GLOBAL starts_line=88", + "argval=0 is_jump_target=False opname=CALL_FUNCTION starts_line=None", + "argval=1 is_jump_target=False opname=RAISE_VARARGS starts_line=None", + "argval=None is_jump_target=False opname=POP_BLOCK starts_line=None", + "argval=29 is_jump_target=False opname=JUMP_FORWARD starts_line=None", + "argval=None is_jump_target=True opname=POP_TOP starts_line=89", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=0 is_jump_target=False opname=RAISE_VARARGS starts_line=90", + "argval=29 is_jump_target=False opname=JUMP_FORWARD starts_line=None", + "argval=None is_jump_target=False opname=END_FINALLY starts_line=None", + "argval=None is_jump_target=True opname=POP_BLOCK starts_line=None", + "argval=41 is_jump_target=False opname=JUMP_FORWARD starts_line=None", + "argval=None is_jump_target=True opname=POP_TOP starts_line=91", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=(1, 2) is_jump_target=False opname=LOAD_CONST starts_line=94", + "argval=None is_jump_target=False opname=RETURN_VALUE starts_line=None", + "argval=None is_jump_target=False opname=END_FINALLY starts_line=None", + "argval=None is_jump_target=True opname=LOAD_CONST starts_line=None", + "argval=None is_jump_target=False opname=RETURN_VALUE starts_line=None" + ] +} \ No newline at end of file diff --git a/ptvsd/_vendored/pydevd/tests_python/test_collect_try_except_info/test_iter_bytecode.py27.json b/ptvsd/_vendored/pydevd/tests_python/test_collect_try_except_info/test_iter_bytecode.py27.json new file mode 100644 index 000000000..f4657b154 --- /dev/null +++ b/ptvsd/_vendored/pydevd/tests_python/test_collect_try_except_info/test_iter_bytecode.py27.json @@ -0,0 +1,200 @@ +{ + "_method_call_with_error": [ + "argval=14 is_jump_target=False opname=SETUP_EXCEPT starts_line=11", + "argval=_method_reraise is_jump_target=False opname=LOAD_GLOBAL starts_line=12", + "argval=0 is_jump_target=False opname=CALL_FUNCTION starts_line=None", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=None is_jump_target=False opname=POP_BLOCK starts_line=None", + "argval=24 is_jump_target=False opname=JUMP_FORWARD starts_line=None", + "argval=None is_jump_target=True opname=POP_TOP starts_line=13", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=0 is_jump_target=False opname=RAISE_VARARGS starts_line=14", + "argval=24 is_jump_target=False opname=JUMP_FORWARD starts_line=None", + "argval=None is_jump_target=False opname=END_FINALLY starts_line=None", + "argval=None is_jump_target=True opname=LOAD_CONST starts_line=None", + "argval=None is_jump_target=False opname=RETURN_VALUE starts_line=None" + ], + "_method_except_local": [ + "argval=AssertionError is_jump_target=False opname=LOAD_GLOBAL starts_line=18", + "argval=Foo is_jump_target=False opname=STORE_FAST starts_line=None", + "argval=22 is_jump_target=False opname=SETUP_EXCEPT starts_line=19", + "argval=AssertionError is_jump_target=False opname=LOAD_GLOBAL starts_line=20", + "argval=0 is_jump_target=False opname=CALL_FUNCTION starts_line=None", + "argval=1 is_jump_target=False opname=RAISE_VARARGS starts_line=None", + "argval=None is_jump_target=False opname=POP_BLOCK starts_line=None", + "argval=41 is_jump_target=False opname=JUMP_FORWARD starts_line=None", + "argval=None is_jump_target=True opname=DUP_TOP starts_line=21", + "argval=Foo is_jump_target=False opname=LOAD_FAST starts_line=None", + "argval=exception match is_jump_target=False opname=COMPARE_OP starts_line=None", + "argval=40 is_jump_target=False opname=POP_JUMP_IF_FALSE starts_line=None", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=exc is_jump_target=False opname=STORE_FAST starts_line=None", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=41 is_jump_target=False opname=JUMP_FORWARD starts_line=23", + "argval=None is_jump_target=True opname=END_FINALLY starts_line=None", + "argval=None is_jump_target=True opname=LOAD_CONST starts_line=None", + "argval=None is_jump_target=False opname=RETURN_VALUE starts_line=None" + ], + "_method_reraise": [ + "argval=16 is_jump_target=False opname=SETUP_EXCEPT starts_line=27", + "argval=AssertionError is_jump_target=False opname=LOAD_GLOBAL starts_line=28", + "argval=0 is_jump_target=False opname=CALL_FUNCTION starts_line=None", + "argval=1 is_jump_target=False opname=RAISE_VARARGS starts_line=None", + "argval=None is_jump_target=False opname=POP_BLOCK starts_line=None", + "argval=41 is_jump_target=False opname=JUMP_FORWARD starts_line=None", + "argval=None is_jump_target=True opname=DUP_TOP starts_line=29", + "argval=AssertionError is_jump_target=False opname=LOAD_GLOBAL starts_line=None", + "argval=exception match is_jump_target=False opname=COMPARE_OP starts_line=None", + "argval=40 is_jump_target=False opname=POP_JUMP_IF_FALSE starts_line=None", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=e is_jump_target=False opname=STORE_FAST starts_line=None", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=e is_jump_target=False opname=LOAD_FAST starts_line=30", + "argval=1 is_jump_target=False opname=RAISE_VARARGS starts_line=None", + "argval=41 is_jump_target=False opname=JUMP_FORWARD starts_line=None", + "argval=None is_jump_target=True opname=END_FINALLY starts_line=None", + "argval=None is_jump_target=True opname=LOAD_CONST starts_line=None", + "argval=None is_jump_target=False opname=RETURN_VALUE starts_line=None" + ], + "_method_return_with_error": [ + "argval=_method_call_with_error is_jump_target=False opname=LOAD_GLOBAL starts_line=34", + "argval=0 is_jump_target=False opname=CALL_FUNCTION starts_line=None", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=None is_jump_target=False opname=LOAD_CONST starts_line=None", + "argval=None is_jump_target=False opname=RETURN_VALUE starts_line=None" + ], + "_method_return_with_error2": [ + "argval=14 is_jump_target=False opname=SETUP_EXCEPT starts_line=38", + "argval=_method_call_with_error is_jump_target=False opname=LOAD_GLOBAL starts_line=39", + "argval=0 is_jump_target=False opname=CALL_FUNCTION starts_line=None", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=None is_jump_target=False opname=POP_BLOCK starts_line=None", + "argval=22 is_jump_target=False opname=JUMP_FORWARD starts_line=None", + "argval=None is_jump_target=True opname=POP_TOP starts_line=40", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=None is_jump_target=False opname=LOAD_CONST starts_line=41", + "argval=None is_jump_target=False opname=RETURN_VALUE starts_line=None", + "argval=None is_jump_target=False opname=END_FINALLY starts_line=None", + "argval=None is_jump_target=True opname=LOAD_CONST starts_line=None", + "argval=None is_jump_target=False opname=RETURN_VALUE starts_line=None" + ], + "_method_simple_raise_any_except": [ + "argval=16 is_jump_target=False opname=SETUP_EXCEPT starts_line=45", + "argval=AssertionError is_jump_target=False opname=LOAD_GLOBAL starts_line=46", + "argval=0 is_jump_target=False opname=CALL_FUNCTION starts_line=None", + "argval=1 is_jump_target=False opname=RAISE_VARARGS starts_line=None", + "argval=None is_jump_target=False opname=POP_BLOCK starts_line=None", + "argval=23 is_jump_target=False opname=JUMP_FORWARD starts_line=None", + "argval=None is_jump_target=True opname=POP_TOP starts_line=47", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=23 is_jump_target=False opname=JUMP_FORWARD starts_line=48", + "argval=None is_jump_target=False opname=END_FINALLY starts_line=None", + "argval=None is_jump_target=True opname=LOAD_CONST starts_line=None", + "argval=None is_jump_target=False opname=RETURN_VALUE starts_line=None" + ], + "_method_simple_raise_any_except_return_on_raise": [ + "argval=16 is_jump_target=False opname=SETUP_EXCEPT starts_line=54", + "argval=AssertionError is_jump_target=False opname=LOAD_GLOBAL starts_line=55", + "argval=0 is_jump_target=False opname=CALL_FUNCTION starts_line=None", + "argval=1 is_jump_target=False opname=RAISE_VARARGS starts_line=None", + "argval=None is_jump_target=False opname=POP_BLOCK starts_line=None", + "argval=26 is_jump_target=False opname=JUMP_FORWARD starts_line=None", + "argval=None is_jump_target=True opname=POP_TOP starts_line=56", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=0 is_jump_target=False opname=RAISE_VARARGS starts_line=57", + "argval=26 is_jump_target=False opname=JUMP_FORWARD starts_line=None", + "argval=None is_jump_target=False opname=END_FINALLY starts_line=None", + "argval=None is_jump_target=True opname=LOAD_CONST starts_line=None", + "argval=None is_jump_target=False opname=RETURN_VALUE starts_line=None" + ], + "_method_simple_raise_local_load": [ + "argval=AssertionError is_jump_target=False opname=LOAD_GLOBAL starts_line=61", + "argval=x is_jump_target=False opname=STORE_FAST starts_line=None", + "argval=22 is_jump_target=False opname=SETUP_EXCEPT starts_line=62", + "argval=AssertionError is_jump_target=False opname=LOAD_GLOBAL starts_line=63", + "argval=0 is_jump_target=False opname=CALL_FUNCTION starts_line=None", + "argval=1 is_jump_target=False opname=RAISE_VARARGS starts_line=None", + "argval=None is_jump_target=False opname=POP_BLOCK starts_line=None", + "argval=41 is_jump_target=False opname=JUMP_FORWARD starts_line=None", + "argval=None is_jump_target=True opname=DUP_TOP starts_line=64", + "argval=x is_jump_target=False opname=LOAD_FAST starts_line=None", + "argval=exception match is_jump_target=False opname=COMPARE_OP starts_line=None", + "argval=40 is_jump_target=False opname=POP_JUMP_IF_FALSE starts_line=None", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=exc is_jump_target=False opname=STORE_FAST starts_line=None", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=41 is_jump_target=False opname=JUMP_FORWARD starts_line=67", + "argval=None is_jump_target=True opname=END_FINALLY starts_line=None", + "argval=None is_jump_target=True opname=LOAD_CONST starts_line=None", + "argval=None is_jump_target=False opname=RETURN_VALUE starts_line=None" + ], + "_method_simple_raise_multi_except": [ + "argval=16 is_jump_target=False opname=SETUP_EXCEPT starts_line=71", + "argval=AssertionError is_jump_target=False opname=LOAD_GLOBAL starts_line=72", + "argval=0 is_jump_target=False opname=CALL_FUNCTION starts_line=None", + "argval=1 is_jump_target=False opname=RAISE_VARARGS starts_line=None", + "argval=None is_jump_target=False opname=POP_BLOCK starts_line=None", + "argval=41 is_jump_target=False opname=JUMP_FORWARD starts_line=None", + "argval=None is_jump_target=True opname=DUP_TOP starts_line=73", + "argval=NameError is_jump_target=False opname=LOAD_GLOBAL starts_line=None", + "argval=AssertionError is_jump_target=False opname=LOAD_GLOBAL starts_line=None", + "argval=2 is_jump_target=False opname=BUILD_TUPLE starts_line=None", + "argval=exception match is_jump_target=False opname=COMPARE_OP starts_line=None", + "argval=40 is_jump_target=False opname=POP_JUMP_IF_FALSE starts_line=None", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=exc is_jump_target=False opname=STORE_FAST starts_line=None", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=41 is_jump_target=False opname=JUMP_FORWARD starts_line=75", + "argval=None is_jump_target=True opname=END_FINALLY starts_line=None", + "argval=None is_jump_target=True opname=LOAD_CONST starts_line=None", + "argval=None is_jump_target=False opname=RETURN_VALUE starts_line=None" + ], + "_method_simple_raise_unmatched_except": [ + "argval=16 is_jump_target=False opname=SETUP_EXCEPT starts_line=79", + "argval=AssertionError is_jump_target=False opname=LOAD_GLOBAL starts_line=80", + "argval=0 is_jump_target=False opname=CALL_FUNCTION starts_line=None", + "argval=1 is_jump_target=False opname=RAISE_VARARGS starts_line=None", + "argval=None is_jump_target=False opname=POP_BLOCK starts_line=None", + "argval=33 is_jump_target=False opname=JUMP_FORWARD starts_line=None", + "argval=None is_jump_target=True opname=DUP_TOP starts_line=81", + "argval=NameError is_jump_target=False opname=LOAD_GLOBAL starts_line=None", + "argval=exception match is_jump_target=False opname=COMPARE_OP starts_line=None", + "argval=32 is_jump_target=False opname=POP_JUMP_IF_FALSE starts_line=None", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=33 is_jump_target=False opname=JUMP_FORWARD starts_line=82", + "argval=None is_jump_target=True opname=END_FINALLY starts_line=None", + "argval=None is_jump_target=True opname=LOAD_CONST starts_line=None", + "argval=None is_jump_target=False opname=RETURN_VALUE starts_line=None" + ], + "_method_try_except": [ + "argval=33 is_jump_target=False opname=SETUP_EXCEPT starts_line=86", + "argval=19 is_jump_target=False opname=SETUP_EXCEPT starts_line=87", + "argval=AssertionError is_jump_target=False opname=LOAD_GLOBAL starts_line=88", + "argval=0 is_jump_target=False opname=CALL_FUNCTION starts_line=None", + "argval=1 is_jump_target=False opname=RAISE_VARARGS starts_line=None", + "argval=None is_jump_target=False opname=POP_BLOCK starts_line=None", + "argval=29 is_jump_target=False opname=JUMP_FORWARD starts_line=None", + "argval=None is_jump_target=True opname=POP_TOP starts_line=89", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=0 is_jump_target=False opname=RAISE_VARARGS starts_line=90", + "argval=29 is_jump_target=False opname=JUMP_FORWARD starts_line=None", + "argval=None is_jump_target=False opname=END_FINALLY starts_line=None", + "argval=None is_jump_target=True opname=POP_BLOCK starts_line=None", + "argval=41 is_jump_target=False opname=JUMP_FORWARD starts_line=None", + "argval=None is_jump_target=True opname=POP_TOP starts_line=91", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=(1, 2) is_jump_target=False opname=LOAD_CONST starts_line=94", + "argval=None is_jump_target=False opname=RETURN_VALUE starts_line=None", + "argval=None is_jump_target=False opname=END_FINALLY starts_line=None", + "argval=None is_jump_target=True opname=LOAD_CONST starts_line=None", + "argval=None is_jump_target=False opname=RETURN_VALUE starts_line=None" + ] +} \ No newline at end of file diff --git a/ptvsd/_vendored/pydevd/tests_python/test_collect_try_except_info/test_iter_bytecode.py36.json b/ptvsd/_vendored/pydevd/tests_python/test_collect_try_except_info/test_iter_bytecode.py36.json new file mode 100644 index 000000000..9e6aea6c5 --- /dev/null +++ b/ptvsd/_vendored/pydevd/tests_python/test_collect_try_except_info/test_iter_bytecode.py36.json @@ -0,0 +1,235 @@ +{ + "_method_call_with_error": [ + "argval=12 is_jump_target=False opname=SETUP_EXCEPT starts_line=11", + "argval=_method_reraise is_jump_target=False opname=LOAD_GLOBAL starts_line=12", + "argval=0 is_jump_target=False opname=CALL_FUNCTION starts_line=None", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=None is_jump_target=False opname=POP_BLOCK starts_line=None", + "argval=26 is_jump_target=False opname=JUMP_FORWARD starts_line=None", + "argval=None is_jump_target=True opname=POP_TOP starts_line=13", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=0 is_jump_target=False opname=RAISE_VARARGS starts_line=14", + "argval=None is_jump_target=False opname=POP_EXCEPT starts_line=None", + "argval=26 is_jump_target=False opname=JUMP_FORWARD starts_line=None", + "argval=None is_jump_target=False opname=END_FINALLY starts_line=None", + "argval=None is_jump_target=True opname=LOAD_CONST starts_line=None", + "argval=None is_jump_target=False opname=RETURN_VALUE starts_line=None" + ], + "_method_except_local": [ + "argval=AssertionError is_jump_target=False opname=LOAD_GLOBAL starts_line=18", + "argval=Foo is_jump_target=False opname=STORE_FAST starts_line=None", + "argval=16 is_jump_target=False opname=SETUP_EXCEPT starts_line=19", + "argval=AssertionError is_jump_target=False opname=LOAD_GLOBAL starts_line=20", + "argval=0 is_jump_target=False opname=CALL_FUNCTION starts_line=None", + "argval=1 is_jump_target=False opname=RAISE_VARARGS starts_line=None", + "argval=None is_jump_target=False opname=POP_BLOCK starts_line=None", + "argval=50 is_jump_target=False opname=JUMP_FORWARD starts_line=None", + "argval=None is_jump_target=True opname=DUP_TOP starts_line=21", + "argval=Foo is_jump_target=False opname=LOAD_FAST starts_line=None", + "argval=exception match is_jump_target=False opname=COMPARE_OP starts_line=None", + "argval=48 is_jump_target=False opname=POP_JUMP_IF_FALSE starts_line=None", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=exc is_jump_target=False opname=STORE_FAST starts_line=None", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=38 is_jump_target=False opname=SETUP_FINALLY starts_line=None", + "argval=None is_jump_target=False opname=POP_BLOCK starts_line=23", + "argval=None is_jump_target=False opname=POP_EXCEPT starts_line=None", + "argval=None is_jump_target=False opname=LOAD_CONST starts_line=None", + "argval=None is_jump_target=True opname=LOAD_CONST starts_line=None", + "argval=exc is_jump_target=False opname=STORE_FAST starts_line=None", + "argval=exc is_jump_target=False opname=DELETE_FAST starts_line=None", + "argval=None is_jump_target=False opname=END_FINALLY starts_line=None", + "argval=50 is_jump_target=False opname=JUMP_FORWARD starts_line=None", + "argval=None is_jump_target=True opname=END_FINALLY starts_line=None", + "argval=None is_jump_target=True opname=LOAD_CONST starts_line=None", + "argval=None is_jump_target=False opname=RETURN_VALUE starts_line=None" + ], + "_method_reraise": [ + "argval=12 is_jump_target=False opname=SETUP_EXCEPT starts_line=27", + "argval=AssertionError is_jump_target=False opname=LOAD_GLOBAL starts_line=28", + "argval=0 is_jump_target=False opname=CALL_FUNCTION starts_line=None", + "argval=1 is_jump_target=False opname=RAISE_VARARGS starts_line=None", + "argval=None is_jump_target=False opname=POP_BLOCK starts_line=None", + "argval=50 is_jump_target=False opname=JUMP_FORWARD starts_line=None", + "argval=None is_jump_target=True opname=DUP_TOP starts_line=29", + "argval=AssertionError is_jump_target=False opname=LOAD_GLOBAL starts_line=None", + "argval=exception match is_jump_target=False opname=COMPARE_OP starts_line=None", + "argval=48 is_jump_target=False opname=POP_JUMP_IF_FALSE starts_line=None", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=e is_jump_target=False opname=STORE_FAST starts_line=None", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=38 is_jump_target=False opname=SETUP_FINALLY starts_line=None", + "argval=e is_jump_target=False opname=LOAD_FAST starts_line=30", + "argval=1 is_jump_target=False opname=RAISE_VARARGS starts_line=None", + "argval=None is_jump_target=False opname=POP_BLOCK starts_line=None", + "argval=None is_jump_target=False opname=POP_EXCEPT starts_line=None", + "argval=None is_jump_target=False opname=LOAD_CONST starts_line=None", + "argval=None is_jump_target=True opname=LOAD_CONST starts_line=None", + "argval=e is_jump_target=False opname=STORE_FAST starts_line=None", + "argval=e is_jump_target=False opname=DELETE_FAST starts_line=None", + "argval=None is_jump_target=False opname=END_FINALLY starts_line=None", + "argval=50 is_jump_target=False opname=JUMP_FORWARD starts_line=None", + "argval=None is_jump_target=True opname=END_FINALLY starts_line=None", + "argval=None is_jump_target=True opname=LOAD_CONST starts_line=None", + "argval=None is_jump_target=False opname=RETURN_VALUE starts_line=None" + ], + "_method_return_with_error": [ + "argval=_method_call_with_error is_jump_target=False opname=LOAD_GLOBAL starts_line=34", + "argval=0 is_jump_target=False opname=CALL_FUNCTION starts_line=None", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=None is_jump_target=False opname=LOAD_CONST starts_line=None", + "argval=None is_jump_target=False opname=RETURN_VALUE starts_line=None" + ], + "_method_return_with_error2": [ + "argval=12 is_jump_target=False opname=SETUP_EXCEPT starts_line=38", + "argval=_method_call_with_error is_jump_target=False opname=LOAD_GLOBAL starts_line=39", + "argval=0 is_jump_target=False opname=CALL_FUNCTION starts_line=None", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=None is_jump_target=False opname=POP_BLOCK starts_line=None", + "argval=22 is_jump_target=False opname=JUMP_FORWARD starts_line=None", + "argval=None is_jump_target=True opname=POP_TOP starts_line=40", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=None is_jump_target=False opname=LOAD_CONST starts_line=41", + "argval=None is_jump_target=False opname=RETURN_VALUE starts_line=None", + "argval=None is_jump_target=True opname=LOAD_CONST starts_line=None", + "argval=None is_jump_target=False opname=RETURN_VALUE starts_line=None" + ], + "_method_simple_raise_any_except": [ + "argval=12 is_jump_target=False opname=SETUP_EXCEPT starts_line=45", + "argval=AssertionError is_jump_target=False opname=LOAD_GLOBAL starts_line=46", + "argval=0 is_jump_target=False opname=CALL_FUNCTION starts_line=None", + "argval=1 is_jump_target=False opname=RAISE_VARARGS starts_line=None", + "argval=None is_jump_target=False opname=POP_BLOCK starts_line=None", + "argval=24 is_jump_target=False opname=JUMP_FORWARD starts_line=None", + "argval=None is_jump_target=True opname=POP_TOP starts_line=47", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=None is_jump_target=False opname=POP_EXCEPT starts_line=48", + "argval=24 is_jump_target=False opname=JUMP_FORWARD starts_line=None", + "argval=None is_jump_target=False opname=END_FINALLY starts_line=None", + "argval=None is_jump_target=True opname=LOAD_CONST starts_line=None", + "argval=None is_jump_target=False opname=RETURN_VALUE starts_line=None" + ], + "_method_simple_raise_any_except_return_on_raise": [ + "argval=12 is_jump_target=False opname=SETUP_EXCEPT starts_line=54", + "argval=AssertionError is_jump_target=False opname=LOAD_GLOBAL starts_line=55", + "argval=0 is_jump_target=False opname=CALL_FUNCTION starts_line=None", + "argval=1 is_jump_target=False opname=RAISE_VARARGS starts_line=None", + "argval=None is_jump_target=False opname=POP_BLOCK starts_line=None", + "argval=26 is_jump_target=False opname=JUMP_FORWARD starts_line=None", + "argval=None is_jump_target=True opname=POP_TOP starts_line=56", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=0 is_jump_target=False opname=RAISE_VARARGS starts_line=57", + "argval=None is_jump_target=False opname=POP_EXCEPT starts_line=None", + "argval=26 is_jump_target=False opname=JUMP_FORWARD starts_line=None", + "argval=None is_jump_target=False opname=END_FINALLY starts_line=None", + "argval=None is_jump_target=True opname=LOAD_CONST starts_line=None", + "argval=None is_jump_target=False opname=RETURN_VALUE starts_line=None" + ], + "_method_simple_raise_local_load": [ + "argval=AssertionError is_jump_target=False opname=LOAD_GLOBAL starts_line=61", + "argval=x is_jump_target=False opname=STORE_FAST starts_line=None", + "argval=16 is_jump_target=False opname=SETUP_EXCEPT starts_line=62", + "argval=AssertionError is_jump_target=False opname=LOAD_GLOBAL starts_line=63", + "argval=0 is_jump_target=False opname=CALL_FUNCTION starts_line=None", + "argval=1 is_jump_target=False opname=RAISE_VARARGS starts_line=None", + "argval=None is_jump_target=False opname=POP_BLOCK starts_line=None", + "argval=50 is_jump_target=False opname=JUMP_FORWARD starts_line=None", + "argval=None is_jump_target=True opname=DUP_TOP starts_line=64", + "argval=x is_jump_target=False opname=LOAD_FAST starts_line=None", + "argval=exception match is_jump_target=False opname=COMPARE_OP starts_line=None", + "argval=48 is_jump_target=False opname=POP_JUMP_IF_FALSE starts_line=None", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=exc is_jump_target=False opname=STORE_FAST starts_line=None", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=38 is_jump_target=False opname=SETUP_FINALLY starts_line=None", + "argval=None is_jump_target=False opname=POP_BLOCK starts_line=67", + "argval=None is_jump_target=False opname=POP_EXCEPT starts_line=None", + "argval=None is_jump_target=False opname=LOAD_CONST starts_line=None", + "argval=None is_jump_target=True opname=LOAD_CONST starts_line=None", + "argval=exc is_jump_target=False opname=STORE_FAST starts_line=None", + "argval=exc is_jump_target=False opname=DELETE_FAST starts_line=None", + "argval=None is_jump_target=False opname=END_FINALLY starts_line=None", + "argval=50 is_jump_target=False opname=JUMP_FORWARD starts_line=None", + "argval=None is_jump_target=True opname=END_FINALLY starts_line=None", + "argval=None is_jump_target=True opname=LOAD_CONST starts_line=None", + "argval=None is_jump_target=False opname=RETURN_VALUE starts_line=None" + ], + "_method_simple_raise_multi_except": [ + "argval=12 is_jump_target=False opname=SETUP_EXCEPT starts_line=71", + "argval=AssertionError is_jump_target=False opname=LOAD_GLOBAL starts_line=72", + "argval=0 is_jump_target=False opname=CALL_FUNCTION starts_line=None", + "argval=1 is_jump_target=False opname=RAISE_VARARGS starts_line=None", + "argval=None is_jump_target=False opname=POP_BLOCK starts_line=None", + "argval=50 is_jump_target=False opname=JUMP_FORWARD starts_line=None", + "argval=None is_jump_target=True opname=DUP_TOP starts_line=73", + "argval=NameError is_jump_target=False opname=LOAD_GLOBAL starts_line=None", + "argval=AssertionError is_jump_target=False opname=LOAD_GLOBAL starts_line=None", + "argval=2 is_jump_target=False opname=BUILD_TUPLE starts_line=None", + "argval=exception match is_jump_target=False opname=COMPARE_OP starts_line=None", + "argval=48 is_jump_target=False opname=POP_JUMP_IF_FALSE starts_line=None", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=exc is_jump_target=False opname=STORE_FAST starts_line=None", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=38 is_jump_target=False opname=SETUP_FINALLY starts_line=None", + "argval=None is_jump_target=False opname=POP_BLOCK starts_line=75", + "argval=None is_jump_target=False opname=POP_EXCEPT starts_line=None", + "argval=None is_jump_target=False opname=LOAD_CONST starts_line=None", + "argval=None is_jump_target=True opname=LOAD_CONST starts_line=None", + "argval=exc is_jump_target=False opname=STORE_FAST starts_line=None", + "argval=exc is_jump_target=False opname=DELETE_FAST starts_line=None", + "argval=None is_jump_target=False opname=END_FINALLY starts_line=None", + "argval=50 is_jump_target=False opname=JUMP_FORWARD starts_line=None", + "argval=None is_jump_target=True opname=END_FINALLY starts_line=None", + "argval=None is_jump_target=True opname=LOAD_CONST starts_line=None", + "argval=None is_jump_target=False opname=RETURN_VALUE starts_line=None" + ], + "_method_simple_raise_unmatched_except": [ + "argval=12 is_jump_target=False opname=SETUP_EXCEPT starts_line=79", + "argval=AssertionError is_jump_target=False opname=LOAD_GLOBAL starts_line=80", + "argval=0 is_jump_target=False opname=CALL_FUNCTION starts_line=None", + "argval=1 is_jump_target=False opname=RAISE_VARARGS starts_line=None", + "argval=None is_jump_target=False opname=POP_BLOCK starts_line=None", + "argval=32 is_jump_target=False opname=JUMP_FORWARD starts_line=None", + "argval=None is_jump_target=True opname=DUP_TOP starts_line=81", + "argval=NameError is_jump_target=False opname=LOAD_GLOBAL starts_line=None", + "argval=exception match is_jump_target=False opname=COMPARE_OP starts_line=None", + "argval=30 is_jump_target=False opname=POP_JUMP_IF_FALSE starts_line=None", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=None is_jump_target=False opname=POP_EXCEPT starts_line=82", + "argval=32 is_jump_target=False opname=JUMP_FORWARD starts_line=None", + "argval=None is_jump_target=True opname=END_FINALLY starts_line=None", + "argval=None is_jump_target=True opname=LOAD_CONST starts_line=None", + "argval=None is_jump_target=False opname=RETURN_VALUE starts_line=None" + ], + "_method_try_except": [ + "argval=32 is_jump_target=False opname=SETUP_EXCEPT starts_line=86", + "argval=14 is_jump_target=False opname=SETUP_EXCEPT starts_line=87", + "argval=AssertionError is_jump_target=False opname=LOAD_GLOBAL starts_line=88", + "argval=0 is_jump_target=False opname=CALL_FUNCTION starts_line=None", + "argval=1 is_jump_target=False opname=RAISE_VARARGS starts_line=None", + "argval=None is_jump_target=False opname=POP_BLOCK starts_line=None", + "argval=28 is_jump_target=False opname=JUMP_FORWARD starts_line=None", + "argval=None is_jump_target=True opname=POP_TOP starts_line=89", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=0 is_jump_target=False opname=RAISE_VARARGS starts_line=90", + "argval=None is_jump_target=False opname=POP_EXCEPT starts_line=None", + "argval=28 is_jump_target=False opname=JUMP_FORWARD starts_line=None", + "argval=None is_jump_target=False opname=END_FINALLY starts_line=None", + "argval=None is_jump_target=True opname=POP_BLOCK starts_line=None", + "argval=42 is_jump_target=False opname=JUMP_FORWARD starts_line=None", + "argval=None is_jump_target=True opname=POP_TOP starts_line=91", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=(1, 2) is_jump_target=False opname=LOAD_CONST starts_line=94", + "argval=None is_jump_target=False opname=RETURN_VALUE starts_line=None", + "argval=None is_jump_target=True opname=LOAD_CONST starts_line=None", + "argval=None is_jump_target=False opname=RETURN_VALUE starts_line=None" + ] +} \ No newline at end of file diff --git a/ptvsd/_vendored/pydevd/tests_python/test_collect_try_except_info/test_iter_bytecode.py37.json b/ptvsd/_vendored/pydevd/tests_python/test_collect_try_except_info/test_iter_bytecode.py37.json new file mode 100644 index 000000000..bef46a7fb --- /dev/null +++ b/ptvsd/_vendored/pydevd/tests_python/test_collect_try_except_info/test_iter_bytecode.py37.json @@ -0,0 +1,235 @@ +{ + "_method_call_with_error": [ + "argval=12 is_jump_target=False opname=SETUP_EXCEPT starts_line=11", + "argval=_method_reraise is_jump_target=False opname=LOAD_GLOBAL starts_line=12", + "argval=0 is_jump_target=False opname=CALL_FUNCTION starts_line=None", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=None is_jump_target=False opname=POP_BLOCK starts_line=None", + "argval=26 is_jump_target=False opname=JUMP_FORWARD starts_line=None", + "argval=None is_jump_target=True opname=POP_TOP starts_line=13", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=0 is_jump_target=False opname=RAISE_VARARGS starts_line=14", + "argval=None is_jump_target=False opname=POP_EXCEPT starts_line=None", + "argval=26 is_jump_target=False opname=JUMP_FORWARD starts_line=None", + "argval=None is_jump_target=False opname=END_FINALLY starts_line=None", + "argval=None is_jump_target=True opname=LOAD_CONST starts_line=None", + "argval=None is_jump_target=False opname=RETURN_VALUE starts_line=None" + ], + "_method_except_local": [ + "argval=AssertionError is_jump_target=False opname=LOAD_GLOBAL starts_line=18", + "argval=Foo is_jump_target=False opname=STORE_FAST starts_line=None", + "argval=16 is_jump_target=False opname=SETUP_EXCEPT starts_line=19", + "argval=AssertionError is_jump_target=False opname=LOAD_GLOBAL starts_line=20", + "argval=0 is_jump_target=False opname=CALL_FUNCTION starts_line=None", + "argval=1 is_jump_target=False opname=RAISE_VARARGS starts_line=None", + "argval=None is_jump_target=False opname=POP_BLOCK starts_line=None", + "argval=50 is_jump_target=False opname=JUMP_FORWARD starts_line=None", + "argval=None is_jump_target=True opname=DUP_TOP starts_line=21", + "argval=Foo is_jump_target=False opname=LOAD_FAST starts_line=None", + "argval=exception match is_jump_target=False opname=COMPARE_OP starts_line=None", + "argval=48 is_jump_target=False opname=POP_JUMP_IF_FALSE starts_line=None", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=exc is_jump_target=False opname=STORE_FAST starts_line=None", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=36 is_jump_target=False opname=SETUP_FINALLY starts_line=None", + "argval=None is_jump_target=False opname=POP_BLOCK starts_line=23", + "argval=None is_jump_target=False opname=LOAD_CONST starts_line=None", + "argval=None is_jump_target=True opname=LOAD_CONST starts_line=None", + "argval=exc is_jump_target=False opname=STORE_FAST starts_line=None", + "argval=exc is_jump_target=False opname=DELETE_FAST starts_line=None", + "argval=None is_jump_target=False opname=END_FINALLY starts_line=None", + "argval=None is_jump_target=False opname=POP_EXCEPT starts_line=None", + "argval=50 is_jump_target=False opname=JUMP_FORWARD starts_line=None", + "argval=None is_jump_target=True opname=END_FINALLY starts_line=None", + "argval=None is_jump_target=True opname=LOAD_CONST starts_line=None", + "argval=None is_jump_target=False opname=RETURN_VALUE starts_line=None" + ], + "_method_reraise": [ + "argval=12 is_jump_target=False opname=SETUP_EXCEPT starts_line=27", + "argval=AssertionError is_jump_target=False opname=LOAD_GLOBAL starts_line=28", + "argval=0 is_jump_target=False opname=CALL_FUNCTION starts_line=None", + "argval=1 is_jump_target=False opname=RAISE_VARARGS starts_line=None", + "argval=None is_jump_target=False opname=POP_BLOCK starts_line=None", + "argval=50 is_jump_target=False opname=JUMP_FORWARD starts_line=None", + "argval=None is_jump_target=True opname=DUP_TOP starts_line=29", + "argval=AssertionError is_jump_target=False opname=LOAD_GLOBAL starts_line=None", + "argval=exception match is_jump_target=False opname=COMPARE_OP starts_line=None", + "argval=48 is_jump_target=False opname=POP_JUMP_IF_FALSE starts_line=None", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=e is_jump_target=False opname=STORE_FAST starts_line=None", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=36 is_jump_target=False opname=SETUP_FINALLY starts_line=None", + "argval=e is_jump_target=False opname=LOAD_FAST starts_line=30", + "argval=1 is_jump_target=False opname=RAISE_VARARGS starts_line=None", + "argval=None is_jump_target=False opname=POP_BLOCK starts_line=None", + "argval=None is_jump_target=False opname=LOAD_CONST starts_line=None", + "argval=None is_jump_target=True opname=LOAD_CONST starts_line=None", + "argval=e is_jump_target=False opname=STORE_FAST starts_line=None", + "argval=e is_jump_target=False opname=DELETE_FAST starts_line=None", + "argval=None is_jump_target=False opname=END_FINALLY starts_line=None", + "argval=None is_jump_target=False opname=POP_EXCEPT starts_line=None", + "argval=50 is_jump_target=False opname=JUMP_FORWARD starts_line=None", + "argval=None is_jump_target=True opname=END_FINALLY starts_line=None", + "argval=None is_jump_target=True opname=LOAD_CONST starts_line=None", + "argval=None is_jump_target=False opname=RETURN_VALUE starts_line=None" + ], + "_method_return_with_error": [ + "argval=_method_call_with_error is_jump_target=False opname=LOAD_GLOBAL starts_line=34", + "argval=0 is_jump_target=False opname=CALL_FUNCTION starts_line=None", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=None is_jump_target=False opname=LOAD_CONST starts_line=None", + "argval=None is_jump_target=False opname=RETURN_VALUE starts_line=None" + ], + "_method_return_with_error2": [ + "argval=12 is_jump_target=False opname=SETUP_EXCEPT starts_line=38", + "argval=_method_call_with_error is_jump_target=False opname=LOAD_GLOBAL starts_line=39", + "argval=0 is_jump_target=False opname=CALL_FUNCTION starts_line=None", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=None is_jump_target=False opname=POP_BLOCK starts_line=None", + "argval=22 is_jump_target=False opname=JUMP_FORWARD starts_line=None", + "argval=None is_jump_target=True opname=POP_TOP starts_line=40", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=None is_jump_target=False opname=LOAD_CONST starts_line=41", + "argval=None is_jump_target=False opname=RETURN_VALUE starts_line=None", + "argval=None is_jump_target=True opname=LOAD_CONST starts_line=None", + "argval=None is_jump_target=False opname=RETURN_VALUE starts_line=None" + ], + "_method_simple_raise_any_except": [ + "argval=12 is_jump_target=False opname=SETUP_EXCEPT starts_line=45", + "argval=AssertionError is_jump_target=False opname=LOAD_GLOBAL starts_line=46", + "argval=0 is_jump_target=False opname=CALL_FUNCTION starts_line=None", + "argval=1 is_jump_target=False opname=RAISE_VARARGS starts_line=None", + "argval=None is_jump_target=False opname=POP_BLOCK starts_line=None", + "argval=24 is_jump_target=False opname=JUMP_FORWARD starts_line=None", + "argval=None is_jump_target=True opname=POP_TOP starts_line=47", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=None is_jump_target=False opname=POP_EXCEPT starts_line=48", + "argval=24 is_jump_target=False opname=JUMP_FORWARD starts_line=None", + "argval=None is_jump_target=False opname=END_FINALLY starts_line=None", + "argval=None is_jump_target=True opname=LOAD_CONST starts_line=None", + "argval=None is_jump_target=False opname=RETURN_VALUE starts_line=None" + ], + "_method_simple_raise_any_except_return_on_raise": [ + "argval=12 is_jump_target=False opname=SETUP_EXCEPT starts_line=54", + "argval=AssertionError is_jump_target=False opname=LOAD_GLOBAL starts_line=55", + "argval=0 is_jump_target=False opname=CALL_FUNCTION starts_line=None", + "argval=1 is_jump_target=False opname=RAISE_VARARGS starts_line=None", + "argval=None is_jump_target=False opname=POP_BLOCK starts_line=None", + "argval=26 is_jump_target=False opname=JUMP_FORWARD starts_line=None", + "argval=None is_jump_target=True opname=POP_TOP starts_line=56", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=0 is_jump_target=False opname=RAISE_VARARGS starts_line=57", + "argval=None is_jump_target=False opname=POP_EXCEPT starts_line=None", + "argval=26 is_jump_target=False opname=JUMP_FORWARD starts_line=None", + "argval=None is_jump_target=False opname=END_FINALLY starts_line=None", + "argval=None is_jump_target=True opname=LOAD_CONST starts_line=None", + "argval=None is_jump_target=False opname=RETURN_VALUE starts_line=None" + ], + "_method_simple_raise_local_load": [ + "argval=AssertionError is_jump_target=False opname=LOAD_GLOBAL starts_line=61", + "argval=x is_jump_target=False opname=STORE_FAST starts_line=None", + "argval=16 is_jump_target=False opname=SETUP_EXCEPT starts_line=62", + "argval=AssertionError is_jump_target=False opname=LOAD_GLOBAL starts_line=63", + "argval=0 is_jump_target=False opname=CALL_FUNCTION starts_line=None", + "argval=1 is_jump_target=False opname=RAISE_VARARGS starts_line=None", + "argval=None is_jump_target=False opname=POP_BLOCK starts_line=None", + "argval=50 is_jump_target=False opname=JUMP_FORWARD starts_line=None", + "argval=None is_jump_target=True opname=DUP_TOP starts_line=64", + "argval=x is_jump_target=False opname=LOAD_FAST starts_line=None", + "argval=exception match is_jump_target=False opname=COMPARE_OP starts_line=None", + "argval=48 is_jump_target=False opname=POP_JUMP_IF_FALSE starts_line=None", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=exc is_jump_target=False opname=STORE_FAST starts_line=None", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=36 is_jump_target=False opname=SETUP_FINALLY starts_line=None", + "argval=None is_jump_target=False opname=POP_BLOCK starts_line=67", + "argval=None is_jump_target=False opname=LOAD_CONST starts_line=None", + "argval=None is_jump_target=True opname=LOAD_CONST starts_line=None", + "argval=exc is_jump_target=False opname=STORE_FAST starts_line=None", + "argval=exc is_jump_target=False opname=DELETE_FAST starts_line=None", + "argval=None is_jump_target=False opname=END_FINALLY starts_line=None", + "argval=None is_jump_target=False opname=POP_EXCEPT starts_line=None", + "argval=50 is_jump_target=False opname=JUMP_FORWARD starts_line=None", + "argval=None is_jump_target=True opname=END_FINALLY starts_line=None", + "argval=None is_jump_target=True opname=LOAD_CONST starts_line=None", + "argval=None is_jump_target=False opname=RETURN_VALUE starts_line=None" + ], + "_method_simple_raise_multi_except": [ + "argval=12 is_jump_target=False opname=SETUP_EXCEPT starts_line=71", + "argval=AssertionError is_jump_target=False opname=LOAD_GLOBAL starts_line=72", + "argval=0 is_jump_target=False opname=CALL_FUNCTION starts_line=None", + "argval=1 is_jump_target=False opname=RAISE_VARARGS starts_line=None", + "argval=None is_jump_target=False opname=POP_BLOCK starts_line=None", + "argval=50 is_jump_target=False opname=JUMP_FORWARD starts_line=None", + "argval=None is_jump_target=True opname=DUP_TOP starts_line=73", + "argval=NameError is_jump_target=False opname=LOAD_GLOBAL starts_line=None", + "argval=AssertionError is_jump_target=False opname=LOAD_GLOBAL starts_line=None", + "argval=2 is_jump_target=False opname=BUILD_TUPLE starts_line=None", + "argval=exception match is_jump_target=False opname=COMPARE_OP starts_line=None", + "argval=48 is_jump_target=False opname=POP_JUMP_IF_FALSE starts_line=None", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=exc is_jump_target=False opname=STORE_FAST starts_line=None", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=36 is_jump_target=False opname=SETUP_FINALLY starts_line=None", + "argval=None is_jump_target=False opname=POP_BLOCK starts_line=75", + "argval=None is_jump_target=False opname=LOAD_CONST starts_line=None", + "argval=None is_jump_target=True opname=LOAD_CONST starts_line=None", + "argval=exc is_jump_target=False opname=STORE_FAST starts_line=None", + "argval=exc is_jump_target=False opname=DELETE_FAST starts_line=None", + "argval=None is_jump_target=False opname=END_FINALLY starts_line=None", + "argval=None is_jump_target=False opname=POP_EXCEPT starts_line=None", + "argval=50 is_jump_target=False opname=JUMP_FORWARD starts_line=None", + "argval=None is_jump_target=True opname=END_FINALLY starts_line=None", + "argval=None is_jump_target=True opname=LOAD_CONST starts_line=None", + "argval=None is_jump_target=False opname=RETURN_VALUE starts_line=None" + ], + "_method_simple_raise_unmatched_except": [ + "argval=12 is_jump_target=False opname=SETUP_EXCEPT starts_line=79", + "argval=AssertionError is_jump_target=False opname=LOAD_GLOBAL starts_line=80", + "argval=0 is_jump_target=False opname=CALL_FUNCTION starts_line=None", + "argval=1 is_jump_target=False opname=RAISE_VARARGS starts_line=None", + "argval=None is_jump_target=False opname=POP_BLOCK starts_line=None", + "argval=32 is_jump_target=False opname=JUMP_FORWARD starts_line=None", + "argval=None is_jump_target=True opname=DUP_TOP starts_line=81", + "argval=NameError is_jump_target=False opname=LOAD_GLOBAL starts_line=None", + "argval=exception match is_jump_target=False opname=COMPARE_OP starts_line=None", + "argval=30 is_jump_target=False opname=POP_JUMP_IF_FALSE starts_line=None", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=None is_jump_target=False opname=POP_EXCEPT starts_line=82", + "argval=32 is_jump_target=False opname=JUMP_FORWARD starts_line=None", + "argval=None is_jump_target=True opname=END_FINALLY starts_line=None", + "argval=None is_jump_target=True opname=LOAD_CONST starts_line=None", + "argval=None is_jump_target=False opname=RETURN_VALUE starts_line=None" + ], + "_method_try_except": [ + "argval=32 is_jump_target=False opname=SETUP_EXCEPT starts_line=86", + "argval=14 is_jump_target=False opname=SETUP_EXCEPT starts_line=87", + "argval=AssertionError is_jump_target=False opname=LOAD_GLOBAL starts_line=88", + "argval=0 is_jump_target=False opname=CALL_FUNCTION starts_line=None", + "argval=1 is_jump_target=False opname=RAISE_VARARGS starts_line=None", + "argval=None is_jump_target=False opname=POP_BLOCK starts_line=None", + "argval=28 is_jump_target=False opname=JUMP_FORWARD starts_line=None", + "argval=None is_jump_target=True opname=POP_TOP starts_line=89", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=0 is_jump_target=False opname=RAISE_VARARGS starts_line=90", + "argval=None is_jump_target=False opname=POP_EXCEPT starts_line=None", + "argval=28 is_jump_target=False opname=JUMP_FORWARD starts_line=None", + "argval=None is_jump_target=False opname=END_FINALLY starts_line=None", + "argval=None is_jump_target=True opname=POP_BLOCK starts_line=None", + "argval=42 is_jump_target=False opname=JUMP_FORWARD starts_line=None", + "argval=None is_jump_target=True opname=POP_TOP starts_line=91", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=None is_jump_target=False opname=POP_TOP starts_line=None", + "argval=(1, 2) is_jump_target=False opname=LOAD_CONST starts_line=93", + "argval=None is_jump_target=False opname=RETURN_VALUE starts_line=None", + "argval=None is_jump_target=True opname=LOAD_CONST starts_line=None", + "argval=None is_jump_target=False opname=RETURN_VALUE starts_line=None" + ] +} \ No newline at end of file diff --git a/ptvsd/_vendored/pydevd/tests_python/test_debugger.py b/ptvsd/_vendored/pydevd/tests_python/test_debugger.py index 4caec3523..e06c85acb 100644 --- a/ptvsd/_vendored/pydevd/tests_python/test_debugger.py +++ b/ptvsd/_vendored/pydevd/tests_python/test_debugger.py @@ -1007,6 +1007,15 @@ def test_module_entry_point(case_setup_m_switch_entry_point): writer.finished_ok = True +@pytest.mark.skipif(not IS_CPYTHON or TEST_CYTHON, reason='CPython only test without cython enabled.') +def test_check_tracer_with_exceptions(case_setup): + + with case_setup.test_file('_debugger_case_check_tracer.py') as writer: + writer.write_add_exception_breakpoint_with_policy('IndexError', "1", "1", "1") + writer.write_make_initial_run() + writer.finished_ok = True + + @pytest.mark.skipif(IS_JYTHON, reason='Failing on Jython -- needs to be investigated).') def test_unhandled_exceptions_basic(case_setup): @@ -1077,23 +1086,10 @@ def check(hit, exc_type, exc_desc): @pytest.mark.skipif(IS_JYTHON, reason='Failing on Jython -- needs to be investigated).') -def test_unhandled_exceptions_in_top_level(case_setup): - - # Note: expecting unhandled exception to be printed to stderr. - def check_test_suceeded_msg(writer, stdout, stderr): - return 'TEST SUCEEDED' in ''.join(stderr) - - def additional_output_checks(writer, stdout, stderr): - # Don't call super as we have an expected exception - if 'ValueError: TEST SUCEEDED' not in stderr: - raise AssertionError('"ValueError: TEST SUCEEDED" not in stderr.\nstdout:\n%s\n\nstderr:\n%s' % ( - stdout, stderr)) +def test_unhandled_exceptions_in_top_level(case_setup_unhandled_exceptions): - with case_setup.test_file( - '_debugger_case_unhandled_exceptions_on_top_level.py', - additional_output_checks=additional_output_checks, - check_test_suceeded_msg=check_test_suceeded_msg, - ) as writer: + with case_setup_unhandled_exceptions.test_file( + '_debugger_case_unhandled_exceptions_on_top_level.py') as writer: writer.write_add_exception_breakpoint_with_policy('Exception', "0", "1", "0") writer.write_make_initial_run() @@ -1107,7 +1103,7 @@ def additional_output_checks(writer, stdout, stderr): @pytest.mark.skipif(IS_JYTHON, reason='Failing on Jython -- needs to be investigated).') -def test_unhandled_exceptions_in_top_level2(case_setup): +def test_unhandled_exceptions_in_top_level2(case_setup_unhandled_exceptions): # Note: expecting unhandled exception to be printed to stderr. def get_environ(writer): @@ -1120,15 +1116,6 @@ def get_environ(writer): env['PYTHONPATH'] = curr_pythonpath return env - def check_test_suceeded_msg(writer, stdout, stderr): - return 'TEST SUCEEDED' in ''.join(stderr) - - def additional_output_checks(writer, stdout, stderr): - # Don't call super as we have an expected exception - if 'ValueError: TEST SUCEEDED' not in stderr: - raise AssertionError('"ValueError: TEST SUCEEDED" not in stderr.\nstdout:\n%s\n\nstderr:\n%s' % ( - stdout, stderr)) - def update_command_line_args(writer, args): # Start pydevd with '-m' to see how it deal with being called with # runpy at the start. @@ -1136,11 +1123,9 @@ def update_command_line_args(writer, args): args = ['-m', 'pydevd'] + args[1:] return args - with case_setup.test_file( + with case_setup_unhandled_exceptions.test_file( '_debugger_case_unhandled_exceptions_on_top_level.py', get_environ=get_environ, - additional_output_checks=additional_output_checks, - check_test_suceeded_msg=check_test_suceeded_msg, update_command_line_args=update_command_line_args, ) as writer: @@ -1156,22 +1141,10 @@ def update_command_line_args(writer, args): @pytest.mark.skipif(IS_JYTHON, reason='Failing on Jython -- needs to be investigated).') -def test_unhandled_exceptions_in_top_level3(case_setup): +def test_unhandled_exceptions_in_top_level3(case_setup_unhandled_exceptions): - def check_test_suceeded_msg(writer, stdout, stderr): - return 'TEST SUCEEDED' in ''.join(stderr) - - def additional_output_checks(writer, stdout, stderr): - # Don't call super as we have an expected exception - if 'ValueError: TEST SUCEEDED' not in stderr: - raise AssertionError('"ValueError: TEST SUCEEDED" not in stderr.\nstdout:\n%s\n\nstderr:\n%s' % ( - stdout, stderr)) - - with case_setup.test_file( - '_debugger_case_unhandled_exceptions_on_top_level.py', - additional_output_checks=additional_output_checks, - check_test_suceeded_msg=check_test_suceeded_msg, - ) as writer: + with case_setup_unhandled_exceptions.test_file( + '_debugger_case_unhandled_exceptions_on_top_level.py') as writer: # Handled and unhandled writer.write_add_exception_breakpoint_with_policy('Exception', "1", "1", "0") @@ -1190,21 +1163,11 @@ def additional_output_checks(writer, stdout, stderr): @pytest.mark.skipif(IS_JYTHON, reason='Failing on Jython -- needs to be investigated).') -def test_unhandled_exceptions_in_top_level4(case_setup): - - def check_test_suceeded_msg(writer, stdout, stderr): - return 'TEST SUCEEDED' in ''.join(stderr) - - def additional_output_checks(writer, stdout, stderr): - # Don't call super as we have an expected exception - assert 'ValueError: TEST SUCEEDED' in stderr +def test_unhandled_exceptions_in_top_level4(case_setup_unhandled_exceptions): # Note: expecting unhandled exception to be printed to stderr. - with case_setup.test_file( - '_debugger_case_unhandled_exceptions_on_top_level2.py', - additional_output_checks=additional_output_checks, - check_test_suceeded_msg=check_test_suceeded_msg, - ) as writer: + with case_setup_unhandled_exceptions.test_file( + '_debugger_case_unhandled_exceptions_on_top_level2.py') as writer: # Handled and unhandled writer.write_add_exception_breakpoint_with_policy('Exception', "1", "1", "0") @@ -2127,8 +2090,57 @@ def additional_output_checks(writer, stdout, stderr): writer.finished_ok = True +def scenario_uncaught(writer): + hit = writer.wait_for_breakpoint_hit(REASON_THREAD_SUSPEND) + writer.write_add_exception_breakpoint_with_policy('ValueError', '0', '1', '0') + writer.write_run_thread(hit.thread_id) + + hit = writer.wait_for_breakpoint_hit(REASON_UNCAUGHT_EXCEPTION) + writer.write_run_thread(hit.thread_id) + + +def scenario_caught(writer): + hit = writer.wait_for_breakpoint_hit(REASON_THREAD_SUSPEND) + writer.write_add_exception_breakpoint_with_policy('ValueError', '1', '0', '0') + writer.write_run_thread(hit.thread_id) + + for _ in range(2): + hit = writer.wait_for_breakpoint_hit(REASON_CAUGHT_EXCEPTION) + writer.write_run_thread(hit.thread_id) + + # Note: the one in the top-level will be hit once as caught (but not another time + # in postmortem mode). + hit = writer.wait_for_breakpoint_hit(REASON_CAUGHT_EXCEPTION) + writer.write_run_thread(hit.thread_id) + + +def scenario_caught_and_uncaught(writer): + hit = writer.wait_for_breakpoint_hit(REASON_THREAD_SUSPEND) + writer.write_add_exception_breakpoint_with_policy('ValueError', '1', '1', '0') + writer.write_run_thread(hit.thread_id) + + for _ in range(2): + hit = writer.wait_for_breakpoint_hit(REASON_CAUGHT_EXCEPTION) + writer.write_run_thread(hit.thread_id) + + # Note: the one in the top-level will be hit once as caught and another in postmortem mode. + hit = writer.wait_for_breakpoint_hit(REASON_CAUGHT_EXCEPTION) + writer.write_run_thread(hit.thread_id) + + hit = writer.wait_for_breakpoint_hit(REASON_UNCAUGHT_EXCEPTION) + writer.write_run_thread(hit.thread_id) + + @pytest.mark.skipif(not IS_CPYTHON, reason='CPython only test.') -def test_remote_unhandled_exceptions2(case_setup_remote): +@pytest.mark.parametrize( + 'check_scenario', + [ + scenario_uncaught, + scenario_caught, + scenario_caught_and_uncaught, + ] +) +def test_top_level_exceptions_on_attach(case_setup_remote, check_scenario): def check_test_suceeded_msg(writer, stdout, stderr): return 'TEST SUCEEDED' in ''.join(stderr) @@ -2145,25 +2157,7 @@ def additional_output_checks(writer, stdout, stderr): writer.log.append('making initial run') writer.write_make_initial_run() - writer.log.append('waiting for breakpoint hit') - hit = writer.wait_for_breakpoint_hit(REASON_THREAD_SUSPEND) - - writer.write_add_exception_breakpoint_with_policy('ValueError', '0', '1', '0') - - writer.log.append('run thread') - writer.write_run_thread(hit.thread_id) - - writer.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). - hit = writer.wait_for_breakpoint_hit(REASON_UNCAUGHT_EXCEPTION) - writer.write_run_thread(hit.thread_id) + check_scenario(writer) writer.log.append('finished ok') writer.finished_ok = True @@ -2173,3 +2167,7 @@ def additional_output_checks(writer, stdout, stderr): # set PATH=%PATH%;C:\bin\jython2.7.0\bin # set PATH=%PATH%;%JAVA_HOME%\bin # c:\bin\jython2.7.0\bin\jython.exe -m py.test tests_python + + +if __name__ == '__main__': + pytest.main(['-k', 'test_top_level_exceptions_on_attach']) diff --git a/ptvsd/_vendored/pydevd/tests_python/test_tracing_on_top_level.py b/ptvsd/_vendored/pydevd/tests_python/test_tracing_on_top_level.py new file mode 100644 index 000000000..fb703254e --- /dev/null +++ b/ptvsd/_vendored/pydevd/tests_python/test_tracing_on_top_level.py @@ -0,0 +1,479 @@ +from pydevd import PyDB +import pytest +from tests_python.debugger_unittest import IS_CPYTHON + +DEBUG = False + + +class DummyTopLevelFrame(object): + + __slots__ = ['f_code', 'f_back', 'f_lineno', 'f_trace'] + + def __init__(self, method): + self.f_code = method.__code__ + self.f_back = None + self.f_lineno = method.__code__.co_firstlineno + + +class DummyWriter(object): + + __slots__ = ['commands', 'command_meanings'] + + def __init__(self): + self.commands = [] + self.command_meanings = [] + + def add_command(self, cmd): + from _pydevd_bundle.pydevd_comm import ID_TO_MEANING + meaning = ID_TO_MEANING[str(cmd.id)] + if DEBUG: + print(meaning) + self.command_meanings.append(meaning) + if DEBUG: + print(cmd._as_bytes.decode('utf-8')) + self.commands.append(cmd) + + +class DummyPyDb(PyDB): + + def __init__(self): + PyDB.__init__(self, set_as_global=False) + + def do_wait_suspend(self, thread, frame, event, arg, suspend_type="trace", send_suspend_message=True): + from _pydevd_bundle.pydevd_constants import STATE_RUN + info = thread.additional_info + info.pydev_step_cmd = -1 + info.pydev_step_stop = None + info.pydev_state = STATE_RUN + + return PyDB.do_wait_suspend( + self, thread, frame, event, arg, suspend_type=suspend_type, send_suspend_message=send_suspend_message) + + +class _TraceTopLevel(object): + + def __init__(self): + self.py_db = DummyPyDb() + self.py_db.writer = DummyWriter() + + def set_target_func(self, target_func): + self.frame = DummyTopLevelFrame(target_func) + self.target_func = target_func + + def get_exception_arg(self): + import sys + try: + raise AssertionError() + except: + arg = sys.exc_info() + return arg + + def create_add_exception_breakpoint_with_policy( + self, exception, notify_on_handled_exceptions, notify_on_unhandled_exceptions, ignore_libraries): + return '\t'.join(str(x) for x in [ + exception, notify_on_handled_exceptions, notify_on_unhandled_exceptions, ignore_libraries]) + + def add_unhandled_exception_breakpoint(self): + from _pydevd_bundle.pydevd_process_net_command import process_net_command + from tests_python.debugger_unittest import CMD_ADD_EXCEPTION_BREAK + for exc_name in ('AssertionError', 'RuntimeError'): + process_net_command( + self.py_db, + CMD_ADD_EXCEPTION_BREAK, + 1, + self.create_add_exception_breakpoint_with_policy(exc_name, '0', '1', '0'), + ) + + def assert_last_commands(self, *commands): + assert self.py_db.writer.command_meanings[-len(commands):] == list(commands) + + def assert_no_commands(self, *commands): + for command in commands: + assert command not in self.py_db.writer.command_meanings + + def trace_dispatch(self, event, arg): + from _pydevd_bundle import pydevd_trace_dispatch_regular + + self.new_trace_func = pydevd_trace_dispatch_regular.trace_dispatch(self.py_db, self.frame, event, arg) + return self.new_trace_func + + def call_trace_dispatch(self, line): + self.frame.f_lineno = line + return self.trace_dispatch(event='call', arg=None) + + def exception_trace_dispatch(self, line, arg): + self.frame.f_lineno = line + self.new_trace_func = self.new_trace_func(self.frame, event='exception', arg=arg) + + def return_trace_dispatch(self, line): + self.frame.f_lineno = line + self.new_trace_func = self.new_trace_func(self.frame, event='return', arg=None) + + def assert_paused(self): + self.assert_last_commands('CMD_THREAD_SUSPEND', 'CMD_THREAD_RUN') + + def assert_not_paused(self): + self.assert_no_commands('CMD_THREAD_SUSPEND', 'CMD_THREAD_RUN') + + +@pytest.fixture +def trace_top_level(): + # Note: we trace with a dummy frame with no f_back to simulate the issue in a remote attach. + return _TraceTopLevel() + + +@pytest.fixture +def trace_top_level_unhandled(trace_top_level): + trace_top_level.add_unhandled_exception_breakpoint() + return trace_top_level + + +_expected_functions_to_test = 0 + + +def mark_handled(func): + global _expected_functions_to_test + _expected_functions_to_test += 1 + func.__handled__ = True + return func + + +def mark_unhandled(func): + global _expected_functions_to_test + _expected_functions_to_test += 1 + func.__handled__ = False + return func + + +#------------------------------------------------------------------------------------------- Handled +@mark_handled +def raise_handled_exception(): + try: + raise AssertionError() + except: + pass + + +@mark_handled +def raise_handled_exception2(): + try: + raise AssertionError() + except AssertionError: + pass + + +@mark_handled +def raise_handled_exception3(): + try: + try: + raise AssertionError() + except RuntimeError: + pass + except AssertionError: + pass + + +@mark_handled +def raise_handled_exception3a(): + try: + try: + raise AssertionError() + except AssertionError: + pass + except RuntimeError: + pass + + +@mark_handled +def raise_handled_exception4(): + try: + try: + raise AssertionError() + except RuntimeError: + pass + except ( + RuntimeError, + AssertionError): + pass + + +@mark_handled +def raise_handled(): + try: + try: + raise AssertionError() + except RuntimeError: + pass + except ( + RuntimeError, + AssertionError): + pass + + +@mark_handled +def raise_handled2(): + try: + raise AssertionError() + except ( + RuntimeError, + AssertionError): + pass + + try: + raise RuntimeError() + except ( + RuntimeError, + AssertionError): + pass + + +@mark_handled +def raise_handled9(): + for i in range(2): + try: + raise AssertionError() + except AssertionError: + if i == 1: + try: + raise + except: + pass + + +@mark_handled +def raise_handled10(): + for i in range(2): + try: + raise AssertionError() + except AssertionError: + if i == 1: + try: + raise + except: + pass + + _foo = 10 + +#----------------------------------------------------------------------------------------- Unhandled + + +@mark_unhandled +def raise_unhandled_exception(): + raise AssertionError() + + +@mark_unhandled +def raise_unhandled_exception_not_in_except_clause(): + try: + raise AssertionError() + except RuntimeError: + pass + + +@mark_unhandled +def raise_unhandled(): + try: + try: + raise AssertionError() + except RuntimeError: + pass + except ( + RuntimeError, + AssertionError): + raise + + +@mark_unhandled +def raise_unhandled2(): + try: + raise AssertionError() + except AssertionError: + pass + + raise AssertionError() + + +@mark_unhandled +def raise_unhandled3(): + try: + raise AssertionError() + except AssertionError: + raise AssertionError() + + +@mark_unhandled +def raise_unhandled4(): + try: + raise AssertionError() + finally: + _a = 10 + + +@mark_unhandled +def raise_unhandled5(): + try: + raise AssertionError() + finally: + raise RuntimeError() + + +@mark_unhandled +def raise_unhandled6(): + try: + raise AssertionError() + finally: + raise RuntimeError( + 'in another' + 'line' + ) + + +@mark_unhandled +def raise_unhandled7(): + try: + raise AssertionError() + except AssertionError: + try: + raise AssertionError() + except RuntimeError: + pass + + +@mark_unhandled +def raise_unhandled8(): + for i in range(2): + + def get_exc_to_treat(): + if i == 0: + return AssertionError + return RuntimeError + + try: + raise AssertionError() + except get_exc_to_treat(): + pass + + +@mark_unhandled +def raise_unhandled9(): + for i in range(2): + + def get_exc_to_treat(): + if i == 0: + return AssertionError + return RuntimeError + + try: + raise AssertionError() + except get_exc_to_treat(): + try: + raise + except: + pass + + +@mark_unhandled +def raise_unhandled10(): + for i in range(2): + try: + raise AssertionError() + except AssertionError: + if i == 1: + try: + raise + except RuntimeError: + pass + + +@mark_unhandled +def raise_unhandled11(): + try: + raise_unhandled10() + finally: + if True: + pass + + +@mark_unhandled +def raise_unhandled12(): + try: + raise AssertionError() + except: + pass + try: + raise AssertionError() + finally: + if True: + pass + + +@mark_unhandled +def reraise_handled_exception(): + try: + raise AssertionError() # Should be considered unhandled (because it's reraised). + except: + raise + + +def _collect_events(func): + collected = [] + + def events_collector(frame, event, arg): + if frame.f_code.co_name == func.__name__: + collected.append((event, frame.f_lineno, arg)) + return events_collector + + import sys + sys.settrace(events_collector) + try: + func() + except: + import traceback;traceback.print_exc() + finally: + sys.settrace(None) + return collected + + +def _replay_events(collected, trace_top_level_unhandled): + for event, lineno, arg in collected: + if event == 'call': + # Notify only unhandled + new_trace_func = trace_top_level_unhandled.call_trace_dispatch(lineno) + # Check that it's dealing with the top-level event. + assert new_trace_func.__name__ == 'trace_dispatch_and_unhandled_exceptions' + elif event == 'exception': + trace_top_level_unhandled.exception_trace_dispatch(lineno, arg) + + elif event == 'return': + trace_top_level_unhandled.return_trace_dispatch(lineno) + + elif event == 'line': + pass + + else: + raise AssertionError('Unexpected: %s' % (event,)) + + +def _collect_target_functions(): +# return [raise_unhandled10] + ret = [] + for _key, method in sorted(dict(globals()).items()): + if hasattr(method, '__handled__'): + ret.append(method) + + assert len(ret) == _expected_functions_to_test + return ret + + +@pytest.mark.skipif(not IS_CPYTHON, reason='try..except info only available on CPython') +@pytest.mark.parametrize("func", _collect_target_functions()) +def test_tracing_on_top_level_unhandled(trace_top_level_unhandled, func): + trace_top_level_unhandled.set_target_func(func) + + collected_events = _collect_events(func) + _replay_events(collected_events, trace_top_level_unhandled) + + if func.__handled__: + trace_top_level_unhandled.assert_not_paused() # handled exception + else: + trace_top_level_unhandled.assert_paused() diff --git a/tests/test_setup.py b/tests/test_setup.py index f97e5c663..34e56db92 100644 --- a/tests/test_setup.py +++ b/tests/test_setup.py @@ -175,6 +175,7 @@ def test_all(self): 'pydevd/_pydevd_bundle/pydevd_reload.py', 'pydevd/_pydevd_bundle/pydevd_trace_dispatch_regular.py', 'pydevd/_pydevd_bundle/pydevd_cython.pyx', + 'pydevd/_pydevd_bundle/pydevd_collect_try_except_info.py', 'pydevd/_pydevd_bundle/pydevd_extension_utils.py', 'pydevd/_pydevd_bundle/pydevd_stackless.py', 'pydevd/_pydevd_bundle/pydevd_constants.py',