def trace_dispatch(self, frame, event, arg): main_debugger, filename, info, thread = self._args try: info.is_tracing = True if main_debugger._finishDebuggingSession: return None if getattr(thread, 'pydev_do_not_trace', None): return None if event == 'call' and main_debugger.signature_factory: sendSignatureCallTrace(main_debugger, frame, filename) is_exception_event = event == 'exception' has_exception_breakpoints = main_debugger.break_on_caught_exceptions or main_debugger.django_exception_break if is_exception_event: if has_exception_breakpoints: flag, frame = self.should_stop_on_exception(frame, event, arg) if flag: self.handle_exception(frame, event, arg) return self.trace_dispatch elif event not in ('line', 'call', 'return'): #I believe this can only happen in jython on some frontiers on jython and java code, which we don't want to trace. return None stop_frame = info.pydev_step_stop step_cmd = info.pydev_step_cmd if is_exception_event: breakpoints_for_file = None else: # If we are in single step mode and something causes us to exit the current frame, we need to make sure we break # eventually. Force the step mode to step into and the step stop frame to None. # I.e.: F6 in the end of a function should stop in the next possible position (instead of forcing the user # to make a step in or step over at that location). # Note: this is especially troublesome when we're skipping code with the # @DontTrace comment. if stop_frame is frame and event in ('return', 'exception') and step_cmd in (CMD_STEP_RETURN, CMD_STEP_OVER): info.pydev_step_cmd = CMD_STEP_INTO info.pydev_step_stop = None breakpoints_for_file = main_debugger.breakpoints.get(filename) can_skip = False if info.pydev_state == STATE_RUN: #we can skip if: #- we have no stop marked #- we should make a step return/step over and we're not in the current frame can_skip = (step_cmd is None and stop_frame is None)\ or (step_cmd in (CMD_STEP_RETURN, CMD_STEP_OVER) and stop_frame is not frame) check_stop_on_django_render_call = main_debugger.django_breakpoints and self._is_django_render_call(frame) if check_stop_on_django_render_call: can_skip = False # Let's check to see if we are in a function that has a breakpoint. If we don't have a breakpoint, # we will return nothing for the next trace #also, after we hit a breakpoint and go to some other debugging state, we have to force the set trace anyway, #so, that's why the additional checks are there. if not breakpoints_for_file: if can_skip: if has_exception_breakpoints: return self.trace_exception else: return None else: #checks the breakpoint to see if there is a context match in some function curr_func_name = frame.f_code.co_name #global context is set with an empty name if curr_func_name in ('?', '<module>'): curr_func_name = '' for breakpoint in DictIterValues(breakpoints_for_file): #jython does not support itervalues() #will match either global or some function if breakpoint.func_name in ('None', curr_func_name): break else: # if we had some break, it won't get here (so, that's a context that we want to skip) if can_skip: if has_exception_breakpoints: return self.trace_exception else: return None #We may have hit a breakpoint or we are already in step mode. Either way, let's check what we should do in this frame #print 'NOT skipped', frame.f_lineno, frame.f_code.co_name, event try: line = frame.f_lineno flag = False if event == 'call' and info.pydev_state != STATE_SUSPEND and check_stop_on_django_render_call: flag, frame = self.should_stop_on_django_breakpoint(frame, event, arg) #return is not taken into account for breakpoint hit because we'd have a double-hit in this case #(one for the line and the other for the return). if not flag and event != 'return' and info.pydev_state != STATE_SUSPEND and breakpoints_for_file is not None\ and DictContains(breakpoints_for_file, line): #ok, hit breakpoint, now, we have to discover if it is a conditional breakpoint # lets do the conditional stuff here breakpoint = breakpoints_for_file[line] stop = True if step_cmd == CMD_STEP_OVER and stop_frame is frame and event in ('line', 'return'): stop = False #we don't stop on breakpoint if we have to stop by step-over (it will be processed later) else: condition = breakpoint.condition if condition is not None: try: val = eval(condition, frame.f_globals, frame.f_locals) if not val: return self.trace_dispatch except: if type(condition) != type(''): if hasattr(condition, 'encode'): condition = condition.encode('utf-8') msg = 'Error while evaluating expression: %s\n' % (condition,) sys.stderr.write(msg) traceback.print_exc() if not main_debugger.suspend_on_breakpoint_exception: return self.trace_dispatch else: stop = True try: additional_info = None try: additional_info = thread.additionalInfo except AttributeError: pass #that's ok, no info currently set if additional_info is not None: # add exception_type and stacktrace into thread additional info etype, value, tb = sys.exc_info() try: error = ''.join(traceback.format_exception_only(etype, value)) stack = traceback.extract_stack(f=tb.tb_frame.f_back) # On self.setSuspend(thread, CMD_SET_BREAK) this info will be # sent to the client. additional_info.conditional_breakpoint_exception = \ ('Condition:\n' + condition + '\n\nError:\n' + error, stack) finally: etype, value, tb = None, None, None except: traceback.print_exc() if breakpoint.expression is not None: try: try: val = eval(breakpoint.expression, frame.f_globals, frame.f_locals) except: val = sys.exc_info()[1] finally: if val is not None: thread.additionalInfo.message = val if stop: self.setSuspend(thread, CMD_SET_BREAK) # if thread has a suspend flag, we suspend with a busy wait if info.pydev_state == STATE_SUSPEND: self.doWaitSuspend(thread, frame, event, arg) return self.trace_dispatch except: traceback.print_exc() raise #step handling. We stop when we hit the right frame try: django_stop = False should_skip = False if pydevd_dont_trace.should_trace_hook is not None: if not hasattr(self, 'should_skip'): # I.e.: cache the result on self.should_skip (no need to evaluate the same frame multiple times). # Note that on a code reload, we won't re-evaluate this because in practice, the frame.f_code # Which will be handled by this frame is read-only, so, we can cache it safely. should_skip = self.should_skip = not pydevd_dont_trace.should_trace_hook(frame, filename) else: should_skip = self.should_skip if should_skip: stop = False elif step_cmd == CMD_STEP_INTO: stop = event in ('line', 'return') if is_django_suspended(thread): #django_stop = event == 'call' and is_django_render_call(frame) stop = stop and is_django_resolve_call(frame.f_back) and not is_django_context_get_call(frame) if stop: info.pydev_django_resolve_frame = 1 #we remember that we've go into python code from django rendering frame elif step_cmd == CMD_STEP_OVER: if is_django_suspended(thread): django_stop = event == 'call' and self._is_django_render_call(frame) stop = False else: if event == 'return' and info.pydev_django_resolve_frame is not None and is_django_resolve_call(frame.f_back): #we return to Django suspend mode and should not stop before django rendering frame stop_frame = info.pydev_step_stop = info.pydev_django_resolve_frame info.pydev_django_resolve_frame = None thread.additionalInfo.suspend_type = DJANGO_SUSPEND stop = stop_frame is frame and event in ('line', 'return') elif step_cmd == CMD_SMART_STEP_INTO: stop = False if info.pydev_smart_step_stop is frame: info.pydev_func_name = None info.pydev_smart_step_stop = None if event == 'line' or event == 'exception': curr_func_name = frame.f_code.co_name #global context is set with an empty name if curr_func_name in ('?', '<module>') or curr_func_name is None: curr_func_name = '' if curr_func_name == info.pydev_func_name: stop = True elif step_cmd == CMD_STEP_RETURN: stop = event == 'return' and stop_frame is frame elif step_cmd == CMD_RUN_TO_LINE or step_cmd == CMD_SET_NEXT_STATEMENT: stop = False if event == 'line' or event == 'exception': #Yes, we can only act on line events (weird hum?) #Note: This code is duplicated at pydevd.py #Acting on exception events after debugger breaks with exception curr_func_name = frame.f_code.co_name #global context is set with an empty name if curr_func_name in ('?', '<module>'): curr_func_name = '' if curr_func_name == info.pydev_func_name: line = info.pydev_next_line if frame.f_lineno == line: stop = True else: if frame.f_trace is None: frame.f_trace = self.trace_dispatch frame.f_lineno = line frame.f_trace = None stop = True else: stop = False if django_stop: frame = suspend_django(self, main_debugger, thread, frame) if frame: self.doWaitSuspend(thread, frame, event, arg) elif stop: #event is always == line or return at this point if event == 'line': self.setSuspend(thread, step_cmd) self.doWaitSuspend(thread, frame, event, arg) else: #return event back = frame.f_back if back is not None: #When we get to the pydevd run function, the debugging has actually finished for the main thread #(note that it can still go on for other threads, but for this one, we just make it finish) #So, just setting it to None should be OK base = basename(back.f_code.co_filename) if base == 'pydevd.py' and back.f_code.co_name == 'run': back = None elif base == 'pydevd_traceproperty.py': # We dont want to trace the return event of pydevd_traceproperty (custom property for debugging) #if we're in a return, we want it to appear to the user in the previous frame! return None if back is not None: #if we're in a return, we want it to appear to the user in the previous frame! self.setSuspend(thread, step_cmd) self.doWaitSuspend(thread, back, event, arg) else: #in jython we may not have a back frame info.pydev_step_stop = None info.pydev_step_cmd = None info.pydev_state = STATE_RUN except: traceback.print_exc() info.pydev_step_cmd = None #if we are quitting, let's stop the tracing retVal = None if not main_debugger.quitting: retVal = self.trace_dispatch return retVal finally: info.is_tracing = False
def trace_dispatch(self, frame, event, arg): main_debugger, filename, info, thread = self._args try: info.is_tracing = True if main_debugger._finishDebuggingSession: return None if getattr(thread, 'pydev_do_not_trace', None): return None if event == 'call' and main_debugger.signature_factory: sendSignatureCallTrace(main_debugger, frame, filename) is_exception_event = event == 'exception' has_exception_breakpoints = main_debugger.break_on_caught_exceptions \ or main_debugger.plugin_has_exception_breaks() if is_exception_event: if has_exception_breakpoints: flag, frame = self.should_stop_on_exception(frame, event, arg) if flag: self.handle_exception(frame, event, arg) return self.trace_dispatch elif event not in ('line', 'call', 'return'): #I believe this can only happen in jython on some frontiers on jython and java code, which we don't want to trace. return None stop_frame = info.pydev_step_stop step_cmd = info.pydev_step_cmd if is_exception_event: breakpoints_for_file = None else: # If we are in single step mode and something causes us to exit the current frame, we need to make sure we break # eventually. Force the step mode to step into and the step stop frame to None. # I.e.: F6 in the end of a function should stop in the next possible position (instead of forcing the user # to make a step in or step over at that location). # Note: this is especially troublesome when we're skipping code with the # @DontTrace comment. if stop_frame is frame and event in ('return', 'exception') and step_cmd in (CMD_STEP_RETURN, CMD_STEP_OVER): info.pydev_step_cmd = CMD_STEP_INTO info.pydev_step_stop = None breakpoints_for_file = main_debugger.breakpoints.get(filename) can_skip = False if info.pydev_state == STATE_RUN: #we can skip if: #- we have no stop marked #- we should make a step return/step over and we're not in the current frame can_skip = (step_cmd is None and stop_frame is None)\ or (step_cmd in (CMD_STEP_RETURN, CMD_STEP_OVER) and stop_frame is not frame) if can_skip: can_skip = main_debugger.plugin_can_skip(frame) # Let's check to see if we are in a function that has a breakpoint. If we don't have a breakpoint, # we will return nothing for the next trace #also, after we hit a breakpoint and go to some other debugging state, we have to force the set trace anyway, #so, that's why the additional checks are there. if not breakpoints_for_file: if can_skip: if has_exception_breakpoints: return self.trace_exception else: return None else: #checks the breakpoint to see if there is a context match in some function curr_func_name = frame.f_code.co_name #global context is set with an empty name if curr_func_name in ('?', '<module>'): curr_func_name = '' for breakpoint in DictIterValues(breakpoints_for_file): #jython does not support itervalues() #will match either global or some function if breakpoint.func_name in ('None', curr_func_name): break else: # if we had some break, it won't get here (so, that's a context that we want to skip) if can_skip: if has_exception_breakpoints: return self.trace_exception else: return None #We may have hit a breakpoint or we are already in step mode. Either way, let's check what we should do in this frame #print 'NOT skipped', frame.f_lineno, frame.f_code.co_name, event try: line = frame.f_lineno flag = False #return is not taken into account for breakpoint hit because we'd have a double-hit in this case #(one for the line and the other for the return). stop_info = {} breakpoint = None exist_result = False stop_info['stop'] = False if not flag and event != 'return' and info.pydev_state != STATE_SUSPEND and breakpoints_for_file is not None \ and DictContains(breakpoints_for_file, line): breakpoint = breakpoints_for_file[line] stop_info['stop'] = True new_frame = frame if info.pydev_step_cmd == CMD_STEP_OVER and info.pydev_step_stop is frame and event in ('line', 'return'): stop_info['stop'] = False #we don't stop on breakpoint if we have to stop by step-over (it will be processed later) else: result = main_debugger.plugin_get_breakpoint(frame, event, self._args) if result: exist_result = True (flag, breakpoint, new_frame) = result if breakpoint: #ok, hit breakpoint, now, we have to discover if it is a conditional breakpoint # lets do the conditional stuff here if stop_info['stop'] or exist_result: if breakpoint.condition is not None: try: val = eval(breakpoint.condition, new_frame.f_globals, new_frame.f_locals) if not val: return self.trace_dispatch except: pydev_log.info('Error while evaluating condition \'%s\': %s\n' % (breakpoint.condition, sys.exc_info()[1])) return self.trace_dispatch if breakpoint.expression is not None: try: try: val = eval(breakpoint.expression, new_frame.f_globals, new_frame.f_locals) except: val = sys.exc_info()[1] finally: if val is not None: thread.additionalInfo.message = val if stop_info['stop']: self.setSuspend(thread, CMD_SET_BREAK) elif flag: result = main_debugger.plugin_suspend(self, thread, frame) if result: frame = result # if thread has a suspend flag, we suspend with a busy wait if info.pydev_state == STATE_SUSPEND: self.doWaitSuspend(thread, frame, event, arg) return self.trace_dispatch except: traceback.print_exc() raise #step handling. We stop when we hit the right frame try: should_skip = False if pydevd_dont_trace.should_trace_hook is not None: if not hasattr(self, 'should_skip'): # I.e.: cache the result on self.should_skip (no need to evaluate the same frame multiple times). # Note that on a code reload, we won't re-evaluate this because in practice, the frame.f_code # Which will be handled by this frame is read-only, so, we can cache it safely. should_skip = self.should_skip = not pydevd_dont_trace.should_trace_hook(frame, filename) else: should_skip = self.should_skip if should_skip: stop_info['stop'] = False elif step_cmd == CMD_STEP_INTO: stop_info['stop'] = event in ('line', 'return') main_debugger.plugin_cmd_step_into(frame, event, self._args, stop_info) elif step_cmd == CMD_STEP_OVER: stop_info['stop'] = info.pydev_step_stop is frame and event in ('line', 'return') main_debugger.plugin_cmd_step_over(frame, event, self._args, stop_info) elif step_cmd == CMD_SMART_STEP_INTO: stop_info['stop'] = False if info.pydev_smart_step_stop is frame: info.pydev_func_name = None info.pydev_smart_step_stop = None if event == 'line' or event == 'exception': curr_func_name = frame.f_code.co_name #global context is set with an empty name if curr_func_name in ('?', '<module>') or curr_func_name is None: curr_func_name = '' if curr_func_name == info.pydev_func_name: stop_info['stop'] = True elif step_cmd == CMD_STEP_RETURN: stop_info['stop'] = event == 'return' and stop_frame is frame elif step_cmd == CMD_RUN_TO_LINE or step_cmd == CMD_SET_NEXT_STATEMENT: stop_info['stop'] = False if event == 'line' or event == 'exception': #Yes, we can only act on line events (weird hum?) #Note: This code is duplicated at pydevd.py #Acting on exception events after debugger breaks with exception curr_func_name = frame.f_code.co_name #global context is set with an empty name if curr_func_name in ('?', '<module>'): curr_func_name = '' if curr_func_name == info.pydev_func_name: line = info.pydev_next_line if frame.f_lineno == line: stop_info['stop'] = True else: if frame.f_trace is None: frame.f_trace = self.trace_dispatch frame.f_lineno = line frame.f_trace = None stop_info['stop'] = True else: stop_info['stop'] = False if True in stop_info.values(): stopped_on_plugin = main_debugger.plugin_stop(frame, event, self._args, stop_info, arg, step_cmd) if DictContains(stop_info, 'stop') and stop_info['stop'] and not stopped_on_plugin: if event == 'line': self.setSuspend(thread, step_cmd) self.doWaitSuspend(thread, frame, event, arg) else: #return event back = frame.f_back if back is not None: #When we get to the pydevd run function, the debugging has actually finished for the main thread #(note that it can still go on for other threads, but for this one, we just make it finish) #So, just setting it to None should be OK base = basename(back.f_code.co_filename) if base == 'pydevd.py' and back.f_code.co_name == 'run': back = None elif base == 'pydevd_traceproperty.py': # We dont want to trace the return event of pydevd_traceproperty (custom property for debugging) #if we're in a return, we want it to appear to the user in the previous frame! return None if back is not None: #if we're in a return, we want it to appear to the user in the previous frame! self.setSuspend(thread, step_cmd) self.doWaitSuspend(thread, back, event, arg) else: #in jython we may not have a back frame info.pydev_step_stop = None info.pydev_step_cmd = None info.pydev_state = STATE_RUN except: traceback.print_exc() info.pydev_step_cmd = None #if we are quitting, let's stop the tracing retVal = None if not main_debugger.quitting: retVal = self.trace_dispatch return retVal finally: info.is_tracing = False
def trace_dispatch(self, frame, event, arg): main_debugger, filename, info, thread = self._args try: info.is_tracing = True if main_debugger._finishDebuggingSession: return None if getattr(thread, "pydev_do_not_trace", None): return None if event == "call" and main_debugger.signature_factory: sendSignatureCallTrace(main_debugger, frame, filename) plugin_manager = main_debugger.plugin is_exception_event = event == "exception" has_exception_breakpoints = ( main_debugger.break_on_caught_exceptions or main_debugger.has_plugin_exception_breaks ) if is_exception_event: if has_exception_breakpoints: flag, frame = self.should_stop_on_exception(frame, event, arg) if flag: self.handle_exception(frame, event, arg) return self.trace_dispatch elif event not in ("line", "call", "return"): # I believe this can only happen in jython on some frontiers on jython and java code, which we don't want to trace. return None stop_frame = info.pydev_step_stop step_cmd = info.pydev_step_cmd if is_exception_event: breakpoints_for_file = None else: # If we are in single step mode and something causes us to exit the current frame, we need to make sure we break # eventually. Force the step mode to step into and the step stop frame to None. # I.e.: F6 in the end of a function should stop in the next possible position (instead of forcing the user # to make a step in or step over at that location). # Note: this is especially troublesome when we're skipping code with the # @DontTrace comment. if ( stop_frame is frame and event in ("return", "exception") and step_cmd in (CMD_STEP_RETURN, CMD_STEP_OVER) ): info.pydev_step_cmd = CMD_STEP_INTO info.pydev_step_stop = None breakpoints_for_file = main_debugger.breakpoints.get(filename) can_skip = False if info.pydev_state == STATE_RUN: # we can skip if: # - we have no stop marked # - we should make a step return/step over and we're not in the current frame can_skip = (step_cmd is None and stop_frame is None) or ( step_cmd in (CMD_STEP_RETURN, CMD_STEP_OVER) and stop_frame is not frame ) if can_skip and plugin_manager is not None and main_debugger.has_plugin_line_breaks: can_skip = not plugin_manager.can_not_skip(main_debugger, self, frame) # Let's check to see if we are in a function that has a breakpoint. If we don't have a breakpoint, # we will return nothing for the next trace # also, after we hit a breakpoint and go to some other debugging state, we have to force the set trace anyway, # so, that's why the additional checks are there. if not breakpoints_for_file: if can_skip: if has_exception_breakpoints: return self.trace_exception else: return None else: # checks the breakpoint to see if there is a context match in some function curr_func_name = frame.f_code.co_name # global context is set with an empty name if curr_func_name in ("?", "<module>"): curr_func_name = "" for breakpoint in DictIterValues(breakpoints_for_file): # jython does not support itervalues() # will match either global or some function if breakpoint.func_name in ("None", curr_func_name): break else: # if we had some break, it won't get here (so, that's a context that we want to skip) if can_skip: if has_exception_breakpoints: return self.trace_exception else: return None # We may have hit a breakpoint or we are already in step mode. Either way, let's check what we should do in this frame # print 'NOT skipped', frame.f_lineno, frame.f_code.co_name, event try: line = frame.f_lineno flag = False # return is not taken into account for breakpoint hit because we'd have a double-hit in this case # (one for the line and the other for the return). stop_info = {} breakpoint = None exist_result = False stop = False bp_type = None if ( not flag and event != "return" and info.pydev_state != STATE_SUSPEND and breakpoints_for_file is not None and DictContains(breakpoints_for_file, line) ): breakpoint = breakpoints_for_file[line] new_frame = frame stop = True if step_cmd == CMD_STEP_OVER and stop_frame is frame and event in ("line", "return"): stop = ( False ) # we don't stop on breakpoint if we have to stop by step-over (it will be processed later) elif plugin_manager is not None and main_debugger.has_plugin_line_breaks: result = plugin_manager.get_breakpoint(main_debugger, self, frame, event, self._args) if result: exist_result = True (flag, breakpoint, new_frame, bp_type) = result if breakpoint: # ok, hit breakpoint, now, we have to discover if it is a conditional breakpoint # lets do the conditional stuff here if stop or exist_result: condition = breakpoint.condition if condition is not None: try: val = eval(condition, new_frame.f_globals, new_frame.f_locals) if not val: return self.trace_dispatch except: if type(condition) != type(""): if hasattr(condition, "encode"): condition = condition.encode("utf-8") msg = "Error while evaluating expression: %s\n" % (condition,) sys.stderr.write(msg) traceback.print_exc() if not main_debugger.suspend_on_breakpoint_exception: return self.trace_dispatch else: stop = True try: additional_info = None try: additional_info = thread.additionalInfo except AttributeError: pass # that's ok, no info currently set if additional_info is not None: # add exception_type and stacktrace into thread additional info etype, value, tb = sys.exc_info() try: error = "".join(traceback.format_exception_only(etype, value)) stack = traceback.extract_stack(f=tb.tb_frame.f_back) # On self.setSuspend(thread, CMD_SET_BREAK) this info will be # sent to the client. additional_info.conditional_breakpoint_exception = ( "Condition:\n" + condition + "\n\nError:\n" + error, stack, ) finally: etype, value, tb = None, None, None except: traceback.print_exc() if breakpoint.expression is not None: try: try: val = eval(breakpoint.expression, new_frame.f_globals, new_frame.f_locals) except: val = sys.exc_info()[1] finally: if val is not None: thread.additionalInfo.message = val if not main_debugger.first_breakpoint_reached: if event == "call": if hasattr(frame, "f_back"): back = frame.f_back if back is not None: # When we start debug session, we call execfile in pydevd run function. It produces an additional # 'call' event for tracing and we stop on the first line of code twice. back_filename, base = GetFilenameAndBase(back) if (base == DEBUG_START[0] and back.f_code.co_name == DEBUG_START[1]) or ( base == DEBUG_START_PY3K[0] and back.f_code.co_name == DEBUG_START_PY3K[1] ): stop = False main_debugger.first_breakpoint_reached = True if stop: self.setSuspend(thread, CMD_SET_BREAK) elif flag and plugin_manager is not None: result = plugin_manager.suspend(main_debugger, thread, frame, bp_type) if result: frame = result # if thread has a suspend flag, we suspend with a busy wait if info.pydev_state == STATE_SUSPEND: self.doWaitSuspend(thread, frame, event, arg) return self.trace_dispatch except: traceback.print_exc() raise # step handling. We stop when we hit the right frame try: should_skip = False if pydevd_dont_trace.should_trace_hook is not None: if not hasattr(self, "should_skip"): # I.e.: cache the result on self.should_skip (no need to evaluate the same frame multiple times). # Note that on a code reload, we won't re-evaluate this because in practice, the frame.f_code # Which will be handled by this frame is read-only, so, we can cache it safely. should_skip = self.should_skip = not pydevd_dont_trace.should_trace_hook(frame, filename) else: should_skip = self.should_skip plugin_stop = False if should_skip: stop = False elif step_cmd == CMD_STEP_INTO: stop = event in ("line", "return") if plugin_manager is not None: result = plugin_manager.cmd_step_into(main_debugger, frame, event, self._args, stop_info, stop) if result: stop, plugin_stop = result elif step_cmd == CMD_STEP_INTO_MY_CODE: if not main_debugger.not_in_scope(frame.f_code.co_filename): stop = event == "line" elif step_cmd == CMD_STEP_OVER: stop = stop_frame is frame and event in ("line", "return") if plugin_manager is not None: result = plugin_manager.cmd_step_over(main_debugger, frame, event, self._args, stop_info, stop) if result: stop, plugin_stop = result elif step_cmd == CMD_SMART_STEP_INTO: stop = False if info.pydev_smart_step_stop is frame: info.pydev_func_name = None info.pydev_smart_step_stop = None if event == "line" or event == "exception": curr_func_name = frame.f_code.co_name # global context is set with an empty name if curr_func_name in ("?", "<module>") or curr_func_name is None: curr_func_name = "" if curr_func_name == info.pydev_func_name: stop = True elif step_cmd == CMD_STEP_RETURN: stop = event == "return" and stop_frame is frame elif step_cmd == CMD_RUN_TO_LINE or step_cmd == CMD_SET_NEXT_STATEMENT: stop = False if event == "line" or event == "exception": # Yes, we can only act on line events (weird hum?) # Note: This code is duplicated at pydevd.py # Acting on exception events after debugger breaks with exception curr_func_name = frame.f_code.co_name # global context is set with an empty name if curr_func_name in ("?", "<module>"): curr_func_name = "" if curr_func_name == info.pydev_func_name: line = info.pydev_next_line if frame.f_lineno == line: stop = True else: if frame.f_trace is None: frame.f_trace = self.trace_dispatch frame.f_lineno = line frame.f_trace = None stop = True else: stop = False if plugin_stop: stopped_on_plugin = plugin_manager.stop( main_debugger, frame, event, self._args, stop_info, arg, step_cmd ) elif stop: if event == "line": self.setSuspend(thread, step_cmd) self.doWaitSuspend(thread, frame, event, arg) else: # return event back = frame.f_back if back is not None: # When we get to the pydevd run function, the debugging has actually finished for the main thread # (note that it can still go on for other threads, but for this one, we just make it finish) # So, just setting it to None should be OK back_filename, base = GetFilenameAndBase(back) if base == DEBUG_START[0] and back.f_code.co_name == DEBUG_START[1]: back = None elif base == TRACE_PROPERTY: # We dont want to trace the return event of pydevd_traceproperty (custom property for debugging) # if we're in a return, we want it to appear to the user in the previous frame! return None if back is not None: # if we're in a return, we want it to appear to the user in the previous frame! self.setSuspend(thread, step_cmd) self.doWaitSuspend(thread, back, event, arg) else: # in jython we may not have a back frame info.pydev_step_stop = None info.pydev_step_cmd = None info.pydev_state = STATE_RUN except KeyboardInterrupt: raise except: try: traceback.print_exc() info.pydev_step_cmd = None except: return None # if we are quitting, let's stop the tracing retVal = None if not main_debugger.quitting: retVal = self.trace_dispatch return retVal finally: info.is_tracing = False
def trace_dispatch(self, frame, event, arg): main_debugger, filename, info, thread = self._args try: info.is_tracing = True if main_debugger._finishDebuggingSession: return None if getattr(thread, 'pydev_do_not_trace', None): return None if event == 'call' and main_debugger.signature_factory: sendSignatureCallTrace(main_debugger, frame, filename) plugin_manager = main_debugger.plugin is_exception_event = event == 'exception' has_exception_breakpoints = main_debugger.break_on_caught_exceptions \ or plugin_manager.has_exception_breaks(main_debugger) if is_exception_event: if has_exception_breakpoints: flag, frame = self.should_stop_on_exception( frame, event, arg) if flag: self.handle_exception(frame, event, arg) return self.trace_dispatch elif event not in ('line', 'call', 'return'): #I believe this can only happen in jython on some frontiers on jython and java code, which we don't want to trace. return None stop_frame = info.pydev_step_stop step_cmd = info.pydev_step_cmd if is_exception_event: breakpoints_for_file = None else: # If we are in single step mode and something causes us to exit the current frame, we need to make sure we break # eventually. Force the step mode to step into and the step stop frame to None. # I.e.: F6 in the end of a function should stop in the next possible position (instead of forcing the user # to make a step in or step over at that location). # Note: this is especially troublesome when we're skipping code with the # @DontTrace comment. if stop_frame is frame and event in ( 'return', 'exception') and step_cmd in (CMD_STEP_RETURN, CMD_STEP_OVER): info.pydev_step_cmd = CMD_STEP_INTO info.pydev_step_stop = None breakpoints_for_file = main_debugger.breakpoints.get(filename) can_skip = False if info.pydev_state == STATE_RUN: #we can skip if: #- we have no stop marked #- we should make a step return/step over and we're not in the current frame can_skip = (step_cmd is None and stop_frame is None)\ or (step_cmd in (CMD_STEP_RETURN, CMD_STEP_OVER) and stop_frame is not frame) if can_skip: can_skip = not plugin_manager.can_not_skip( main_debugger, self, frame) # Let's check to see if we are in a function that has a breakpoint. If we don't have a breakpoint, # we will return nothing for the next trace #also, after we hit a breakpoint and go to some other debugging state, we have to force the set trace anyway, #so, that's why the additional checks are there. if not breakpoints_for_file: if can_skip: if has_exception_breakpoints: return self.trace_exception else: return None else: #checks the breakpoint to see if there is a context match in some function curr_func_name = frame.f_code.co_name #global context is set with an empty name if curr_func_name in ('?', '<module>'): curr_func_name = '' for breakpoint in DictIterValues( breakpoints_for_file ): #jython does not support itervalues() #will match either global or some function if breakpoint.func_name in ('None', curr_func_name): break else: # if we had some break, it won't get here (so, that's a context that we want to skip) if can_skip: if has_exception_breakpoints: return self.trace_exception else: return None #We may have hit a breakpoint or we are already in step mode. Either way, let's check what we should do in this frame #print 'NOT skipped', frame.f_lineno, frame.f_code.co_name, event try: line = frame.f_lineno flag = False #return is not taken into account for breakpoint hit because we'd have a double-hit in this case #(one for the line and the other for the return). stop_info = {} breakpoint = None exist_result = False stop_info['stop'] = False if not flag and event != 'return' and info.pydev_state != STATE_SUSPEND and breakpoints_for_file is not None \ and DictContains(breakpoints_for_file, line): breakpoint = breakpoints_for_file[line] new_frame = frame stop_info['stop'] = True if step_cmd == CMD_STEP_OVER and stop_frame is frame and event in ( 'line', 'return'): stop_info[ 'stop'] = False #we don't stop on breakpoint if we have to stop by step-over (it will be processed later) else: result = plugin_manager.get_breakpoint( main_debugger, self, frame, event, self._args) if result: exist_result = True (flag, breakpoint, new_frame) = result if breakpoint: #ok, hit breakpoint, now, we have to discover if it is a conditional breakpoint # lets do the conditional stuff here if stop_info['stop'] or exist_result: condition = breakpoint.condition if condition is not None: try: val = eval(condition, new_frame.f_globals, new_frame.f_locals) if not val: return self.trace_dispatch except: if type(condition) != type(''): if hasattr(condition, 'encode'): condition = condition.encode('utf-8') msg = 'Error while evaluating expression: %s\n' % ( condition, ) sys.stderr.write(msg) traceback.print_exc() if not main_debugger.suspend_on_breakpoint_exception: return self.trace_dispatch else: stop_info['stop'] = True try: additional_info = None try: additional_info = thread.additionalInfo except AttributeError: pass #that's ok, no info currently set if additional_info is not None: # add exception_type and stacktrace into thread additional info etype, value, tb = sys.exc_info() try: error = ''.join( traceback. format_exception_only( etype, value)) stack = traceback.extract_stack( f=tb.tb_frame.f_back) # On self.setSuspend(thread, CMD_SET_BREAK) this info will be # sent to the client. additional_info.conditional_breakpoint_exception = \ ('Condition:\n' + condition + '\n\nError:\n' + error, stack) finally: etype, value, tb = None, None, None except: traceback.print_exc() if breakpoint.expression is not None: try: try: val = eval(breakpoint.expression, new_frame.f_globals, new_frame.f_locals) except: val = sys.exc_info()[1] finally: if val is not None: thread.additionalInfo.message = val if stop_info['stop']: self.setSuspend(thread, CMD_SET_BREAK) elif flag: result = plugin_manager.suspend(main_debugger, thread, frame) if result: frame = result # if thread has a suspend flag, we suspend with a busy wait if info.pydev_state == STATE_SUSPEND: self.doWaitSuspend(thread, frame, event, arg) return self.trace_dispatch except: traceback.print_exc() raise #step handling. We stop when we hit the right frame try: should_skip = False if pydevd_dont_trace.should_trace_hook is not None: if not hasattr(self, 'should_skip'): # I.e.: cache the result on self.should_skip (no need to evaluate the same frame multiple times). # Note that on a code reload, we won't re-evaluate this because in practice, the frame.f_code # Which will be handled by this frame is read-only, so, we can cache it safely. should_skip = self.should_skip = not pydevd_dont_trace.should_trace_hook( frame, filename) else: should_skip = self.should_skip if should_skip: stop_info['stop'] = False elif step_cmd == CMD_STEP_INTO: stop_info['stop'] = event in ('line', 'return') plugin_manager.cmd_step_into(main_debugger, frame, event, self._args, stop_info) elif step_cmd == CMD_STEP_OVER: stop_info['stop'] = stop_frame is frame and event in ( 'line', 'return') plugin_manager.cmd_step_over(main_debugger, frame, event, self._args, stop_info) elif step_cmd == CMD_SMART_STEP_INTO: stop_info['stop'] = False if info.pydev_smart_step_stop is frame: info.pydev_func_name = None info.pydev_smart_step_stop = None if event == 'line' or event == 'exception': curr_func_name = frame.f_code.co_name #global context is set with an empty name if curr_func_name in ( '?', '<module>') or curr_func_name is None: curr_func_name = '' if curr_func_name == info.pydev_func_name: stop_info['stop'] = True elif step_cmd == CMD_STEP_RETURN: stop_info[ 'stop'] = event == 'return' and stop_frame is frame elif step_cmd == CMD_RUN_TO_LINE or step_cmd == CMD_SET_NEXT_STATEMENT: stop_info['stop'] = False if event == 'line' or event == 'exception': #Yes, we can only act on line events (weird hum?) #Note: This code is duplicated at pydevd.py #Acting on exception events after debugger breaks with exception curr_func_name = frame.f_code.co_name #global context is set with an empty name if curr_func_name in ('?', '<module>'): curr_func_name = '' if curr_func_name == info.pydev_func_name: line = info.pydev_next_line if frame.f_lineno == line: stop_info['stop'] = True else: if frame.f_trace is None: frame.f_trace = self.trace_dispatch frame.f_lineno = line frame.f_trace = None stop_info['stop'] = True else: stop_info['stop'] = False if True in DictIterValues(stop_info): stopped_on_plugin = plugin_manager.stop( main_debugger, frame, event, self._args, stop_info, arg, step_cmd) if DictContains( stop_info, 'stop' ) and stop_info['stop'] and not stopped_on_plugin: if event == 'line': self.setSuspend(thread, step_cmd) self.doWaitSuspend(thread, frame, event, arg) else: #return event back = frame.f_back if back is not None: #When we get to the pydevd run function, the debugging has actually finished for the main thread #(note that it can still go on for other threads, but for this one, we just make it finish) #So, just setting it to None should be OK base = basename(back.f_code.co_filename) if base == 'pydevd.py' and back.f_code.co_name == 'run': back = None elif base == 'pydevd_traceproperty.py': # We dont want to trace the return event of pydevd_traceproperty (custom property for debugging) #if we're in a return, we want it to appear to the user in the previous frame! return None if back is not None: #if we're in a return, we want it to appear to the user in the previous frame! self.setSuspend(thread, step_cmd) self.doWaitSuspend(thread, back, event, arg) else: #in jython we may not have a back frame info.pydev_step_stop = None info.pydev_step_cmd = None info.pydev_state = STATE_RUN except: try: traceback.print_exc() info.pydev_step_cmd = None except: return None #if we are quitting, let's stop the tracing retVal = None if not main_debugger.quitting: retVal = self.trace_dispatch return retVal finally: info.is_tracing = False
def trace_dispatch(self, frame, event, arg): main_debugger, filename, info, thread = self._args if event not in ("line", "call", "return"): if event == "exception": if main_debugger.break_on_caught and main_debugger.is_subclass(arg[0], main_debugger.handle_exceptions): self.handle_exception(frame, event, arg) return self.trace_dispatch else: # I believe this can only happen in jython on some frontiers on jython and java code, which we don't want to trace. return None stop_frame = info.pydev_step_stop step_cmd = info.pydev_step_cmd # If we are in single step mode and something causes us to exit the current frame, we need to make sure we break # eventually. Force the step mode to step into and the step stop frame to None. # I.e.: F6 in the end of a function should stop in the next possible position (instead of forcing the user # to make a step in or step over at that location). if stop_frame is frame and event in ("return", "exception") and step_cmd in (CMD_STEP_RETURN, CMD_STEP_OVER): info.pydev_step_cmd = CMD_STEP_INTO info.pydev_step_stop = None breakpoint = main_debugger.breakpoints.get(filename) if info.pydev_state == STATE_RUN: # we can skip if: # - we have no stop marked # - we should make a step return/step over and we're not in the current frame can_skip = (step_cmd is None and stop_frame is None) or ( step_cmd in (CMD_STEP_RETURN, CMD_STEP_OVER) and stop_frame is not frame ) else: can_skip = False # Let's check to see if we are in a function that has a breakpoint. If we don't have a breakpoint, # we will return nothing for the next trace # also, after we hit a breakpoint and go to some other debugging state, we have to force the set trace anyway, # so, that's why the additional checks are there. if can_skip: # Evaluating a possible early return if we can skip. if not breakpoint: if main_debugger.break_on_caught: return self.trace_exception else: return None else: # checks the breakpoint to see if there is a context match in some function curr_func_name = frame.f_code.co_name # global context is set with an empty name if curr_func_name in ("?", "<module>"): curr_func_name = "" for condition, func_name in breakpoint.values(): # jython does not support itervalues() # will match either global or some function if func_name in ("None", curr_func_name): break else: # if we had some break, it won't get here (so, that's a context that we want to skip) # print 'skipping', frame.f_lineno, info.pydev_state, stop_frame, step_cmd if main_debugger.break_on_caught: return self.trace_exception else: return None # We may have hit a breakpoint or we are already in step mode. Either way, let's check what we should do in this frame # print 'NOT skipped', frame.f_lineno, frame.f_code.co_name try: line = frame.f_lineno # return is not taken into account for breakpoint hit because we'd have a double-hit in this case # (one for the line and the other for the return). if ( event != "return" and info.pydev_state != STATE_SUSPEND and breakpoint is not None and DictContains(breakpoint, line) ): # ok, hit breakpoint, now, we have to discover if it is a conditional breakpoint # lets do the conditional stuff here condition = breakpoint[line][0] if condition is not None: try: val = eval(condition, frame.f_globals, frame.f_locals) if not val: return self.trace_dispatch except: if type(condition) != type(""): if hasattr(condition, "encode"): condition = condition.encode("utf-8") msg = "Error while evaluating expression: %s\n" % (condition,) sys.stderr.write(msg) traceback.print_exc() if not main_debugger.suspend_on_breakpoint_exception: return self.trace_dispatch else: try: additional_info = None try: additional_info = thread.additionalInfo except AttributeError: pass # that's ok, no info currently set if additional_info is not None: # add exception_type and stacktrace into thread additional info etype, value, tb = sys.exc_info() try: error = "".join(traceback.format_exception_only(etype, value)) stack = traceback.extract_stack(f=tb.tb_frame.f_back) additional_info.conditional_breakpoint_exception = ( "Condition:\n" + condition + "\n\nError:\n" + error, stack, ) finally: etype, value, tb = None, None, None except: traceback.print_exc() self.setSuspend(thread, CMD_SET_BREAK) # if thread has a suspend flag, we suspend with a busy wait if info.pydev_state == STATE_SUSPEND: self.doWaitSuspend(thread, frame, event, arg) return self.trace_dispatch except: traceback.print_exc() raise # step handling. We stop when we hit the right frame try: should_skip = False if pydevd_dont_trace.should_trace_hook is not None: if not hasattr(self, "should_skip"): # I.e.: cache the result on self.should_skip (no need to evaluate the same frame multiple times). # Note that on a code reload, we won't re-evaluate this because in practice, the frame.f_code # Which will be handled by this frame is read-only, so, we can cache it safely. should_skip = self.should_skip = not pydevd_dont_trace.should_trace_hook(frame, filename) else: should_skip = self.should_skip if should_skip: stop = False elif step_cmd == CMD_STEP_INTO: stop = event in ("line", "return") elif step_cmd == CMD_STEP_OVER: stop = stop_frame is frame and event in ("line", "return") elif step_cmd == CMD_STEP_RETURN: stop = event == "return" and stop_frame is frame elif step_cmd == CMD_RUN_TO_LINE or step_cmd == CMD_SET_NEXT_STATEMENT: stop = False if event == "line" or event == "exception": # Yes, we can only act on line events (weird hum?) # Note: This code is duplicated at pydevd.py # Acting on exception events after debugger breaks with exception curr_func_name = frame.f_code.co_name # global context is set with an empty name if curr_func_name in ("?", "<module>"): curr_func_name = "" if curr_func_name == info.pydev_func_name: line = info.pydev_next_line if frame.f_lineno == line: stop = True else: if frame.f_trace is None: frame.f_trace = self.trace_dispatch frame.f_lineno = line frame.f_trace = None stop = True else: stop = False if stop: # event is always == line or return at this point if event == "line": self.setSuspend(thread, step_cmd) self.doWaitSuspend(thread, frame, event, arg) else: # return event back = frame.f_back if back is not None: # When we get to the pydevd run function, the debugging has actually finished for the main thread # (note that it can still go on for other threads, but for this one, we just make it finish) # So, just setting it to None should be OK base = basename(back.f_code.co_filename) if base == "pydevd.py" and back.f_code.co_name == "run": back = None elif base == "pydevd_traceproperty.py": # We dont want to trace the return event of pydevd_traceproperty (custom property for debugging) # if we're in a return, we want it to appear to the user in the previous frame! return None if back is not None: self.setSuspend(thread, step_cmd) self.doWaitSuspend(thread, back, event, arg) else: # in jython we may not have a back frame info.pydev_step_stop = None info.pydev_step_cmd = None info.pydev_state = STATE_RUN except: traceback.print_exc() info.pydev_step_cmd = None # if we are quitting, let's stop the tracing retVal = None if not main_debugger.quitting: retVal = self.trace_dispatch return retVal