def shouldStopOnException(self, frame, event, arg): mainDebugger, filename, info, thread = self._args flag = False if info.pydev_state != STATE_SUSPEND: #and breakpoint is not None: (exception, value, trace) = arg if trace is not None: #on jython trace is None on the first event exception_breakpoint = get_exception_breakpoint(exception, dict(mainDebugger.exception_set), NOTIFY_ALWAYS) if exception_breakpoint is not None: if not exception_breakpoint.notify_on_first_raise_only or just_raised(trace): curr_func_name = frame.f_code.co_name add_exception_to_frame(frame, (exception, value, trace)) self.setSuspend(thread, CMD_ADD_EXCEPTION_BREAK) thread.additionalInfo.message = exception_breakpoint.qname flag = True else: flag = False else: try: if mainDebugger.django_exception_break and get_exception_name(exception) in ['VariableDoesNotExist', 'TemplateDoesNotExist', 'TemplateSyntaxError'] and just_raised(trace) and is_django_exception_break_context(frame): render_frame = find_django_render_frame(frame) if render_frame: suspend_frame = suspend_django(self, mainDebugger, thread, render_frame, CMD_ADD_DJANGO_EXCEPTION_BREAK) if suspend_frame: add_exception_to_frame(suspend_frame, (exception, value, trace)) flag = True thread.additionalInfo.message = 'VariableDoesNotExist' suspend_frame.f_back = frame frame = suspend_frame except : flag = False return (flag, frame)
def should_stop_on_django_breakpoint(self, frame, event, arg): mainDebugger = self._args[0] thread = self._args[3] flag = False template_frame_file = get_template_file_name(frame) #pydev_log.debug("Django is rendering a template: %s\n" % template_frame_file) django_breakpoints_for_file = mainDebugger.django_breakpoints.get(template_frame_file) if django_breakpoints_for_file: #pydev_log.debug("Breakpoints for that file: %s\n" % django_breakpoints_for_file) template_frame_line = get_template_line(frame, template_frame_file) #pydev_log.debug("Tracing template line: %d\n" % template_frame_line) if DictContains(django_breakpoints_for_file, template_frame_line): django_breakpoint = django_breakpoints_for_file[template_frame_line] if django_breakpoint.is_triggered(template_frame_file, template_frame_line): #pydev_log.debug("Breakpoint is triggered.\n") flag = True new_frame = DjangoTemplateFrame( frame, template_frame_file=template_frame_file, template_frame_line=template_frame_line, ) if django_breakpoint.condition is not None: try: val = eval(django_breakpoint.condition, new_frame.f_globals, new_frame.f_locals) if not val: flag = False pydev_log.debug("Condition '%s' is evaluated to %s. Not suspending.\n" % (django_breakpoint.condition, val)) except: pydev_log.info( 'Error while evaluating condition \'%s\': %s\n' % (django_breakpoint.condition, sys.exc_info()[1])) if django_breakpoint.expression is not None: try: try: val = eval(django_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 flag: frame = suspend_django(self, mainDebugger, thread, frame) return flag, frame
def shouldStopOnException(self, frame, event, arg): mainDebugger, filename, info, thread = self._args flag = False if info.pydev_state != STATE_SUSPEND: #and breakpoint is not None: (exception, value, trace) = arg if trace is not None: #on jython trace is None on the first event exception_breakpoint = get_exception_breakpoint( exception, dict(mainDebugger.exception_set), NOTIFY_ALWAYS) if exception_breakpoint is not None: if not exception_breakpoint.notify_on_first_raise_only or just_raised( trace): curr_func_name = frame.f_code.co_name add_exception_to_frame(frame, (exception, value, trace)) self.setSuspend(thread, CMD_ADD_EXCEPTION_BREAK) thread.additionalInfo.message = exception_breakpoint.qname flag = True else: flag = False else: try: if mainDebugger.django_exception_break and get_exception_name( exception) in [ 'VariableDoesNotExist', 'TemplateDoesNotExist', 'TemplateSyntaxError' ] and just_raised( trace ) and is_django_exception_break_context(frame): render_frame = find_django_render_frame(frame) if render_frame: suspend_frame = suspend_django( self, mainDebugger, thread, render_frame, CMD_ADD_DJANGO_EXCEPTION_BREAK) if suspend_frame: add_exception_to_frame( suspend_frame, (exception, value, trace)) flag = True thread.additionalInfo.message = 'VariableDoesNotExist' suspend_frame.f_back = frame frame = suspend_frame except: flag = False return (flag, frame)
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): mainDebugger, filename, info, thread = self._args try: info.is_tracing = True if mainDebugger._finishDebuggingSession: return None if getattr(thread, 'pydev_do_not_trace', None): return None if event == 'call': sendSignatureCallTrace(mainDebugger, frame, filename) if event not in ('line', 'call', 'return'): if event == 'exception': (flag, frame) = self.shouldStopOnException(frame, event, arg) if flag: 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 if event is not 'exception': breakpoints_for_file = mainDebugger.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 = (info.pydev_step_cmd is None and info.pydev_step_stop is None)\ or (info.pydev_step_cmd in (CMD_STEP_RETURN, CMD_STEP_OVER) and info.pydev_step_stop is not frame) if mainDebugger.django_breakpoints: 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 mainDebugger.always_exception_set or mainDebugger.django_exception_break: 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 breakpoints_for_file.values(): #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: #print 'skipping', frame.f_lineno, info.pydev_state, info.pydev_step_stop, info.pydev_step_cmd return None else: breakpoints_for_file = 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 mainDebugger.django_breakpoints \ and is_django_render_call(frame): (flag, frame) = self.shouldStopOnDjangoBreak(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 info.pydev_step_cmd == CMD_STEP_OVER and info.pydev_step_stop 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: if breakpoint.condition is not None: try: val = eval(breakpoint.condition, frame.f_globals, 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, 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 if info.pydev_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 info.pydev_step_cmd == CMD_STEP_OVER: if is_django_suspended(thread): django_stop = event == 'call' and 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 info.pydev_step_stop = info.pydev_django_resolve_frame info.pydev_django_resolve_frame = None thread.additionalInfo.suspend_type = DJANGO_SUSPEND stop = info.pydev_step_stop is frame and event in ('line', 'return') elif info.pydev_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 info.pydev_step_cmd == CMD_STEP_RETURN: stop = event == 'return' and info.pydev_step_stop is frame elif info.pydev_step_cmd == CMD_RUN_TO_LINE or info.pydev_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, mainDebugger, 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, info.pydev_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 if basename(back.f_code.co_filename) == 'pydevd.py' and back.f_code.co_name == 'run': back = 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, info.pydev_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 mainDebugger.quitting: retVal = self.trace_dispatch return retVal finally: info.is_tracing = False
def trace_dispatch(self, frame, event, arg): mainDebugger, filename, info, thread = self._args try: info.is_tracing = True if mainDebugger._finishDebuggingSession: return None if getattr(thread, 'pydev_do_not_trace', None): return None if event == 'call': sendSignatureCallTrace(mainDebugger, frame, filename) if event not in ('line', 'call', 'return'): if event == 'exception': (flag, frame) = self.shouldStopOnException(frame, event, arg) if flag: 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 if event is not 'exception': breakpoints_for_file = mainDebugger.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 = (info.pydev_step_cmd is None and info.pydev_step_stop is None)\ or (info.pydev_step_cmd in (CMD_STEP_RETURN, CMD_STEP_OVER) and info.pydev_step_stop is not frame) if mainDebugger.django_breakpoints: 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 mainDebugger.always_exception_set or mainDebugger.django_exception_break: 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 breakpoints_for_file.values( ): #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: #print 'skipping', frame.f_lineno, info.pydev_state, info.pydev_step_stop, info.pydev_step_cmd return None else: breakpoints_for_file = 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 mainDebugger.django_breakpoints \ and is_django_render_call(frame): (flag, frame) = self.shouldStopOnDjangoBreak(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 info.pydev_step_cmd == CMD_STEP_OVER and info.pydev_step_stop 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: if breakpoint.condition is not None: try: val = eval(breakpoint.condition, frame.f_globals, 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, 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: raise #step handling. We stop when we hit the right frame try: django_stop = False if info.pydev_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 info.pydev_step_cmd == CMD_STEP_OVER: if is_django_suspended(thread): django_stop = event == 'call' and 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 info.pydev_step_stop = info.pydev_django_resolve_frame info.pydev_django_resolve_frame = None thread.additionalInfo.suspend_type = DJANGO_SUSPEND stop = info.pydev_step_stop is frame and event in ( 'line', 'return') elif info.pydev_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 info.pydev_step_cmd == CMD_STEP_RETURN: stop = event == 'return' and info.pydev_step_stop is frame elif info.pydev_step_cmd == CMD_RUN_TO_LINE or info.pydev_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, mainDebugger, 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, info.pydev_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 if basename( back.f_code.co_filename ) == 'pydevd.py' and back.f_code.co_name == 'run': back = 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, info.pydev_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 mainDebugger.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': 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