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 key == "_method_try_except": 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 elif sys.version_info[:2] >= (3, 8): for try_except_info in info: # On 3.8 the last bytecode actually has a different start line. if try_except_info.except_end_line == 7: try_except_info.except_end_line = 9 method_to_info[key] = [str(x) for x in info] method_to_info[key] = [str(x) for x in info] data_regression.check(method_to_info)
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 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(self.trace_dispatch_and_unhandled_exceptions) # ELSE return self.trace_dispatch_and_unhandled_exceptions
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 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 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 self._frame_trace_dispatch is not None: 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 # ret = SafeCallWrapper(self.trace_dispatch_and_unhandled_exceptions) # ELSE ret = self.trace_dispatch_and_unhandled_exceptions # ENDIF # Need to reset (the call to _frame_trace_dispatch may have changed it). frame.f_trace = ret return ret