예제 #1
0
    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
예제 #2
0
    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
예제 #4
0
    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
예제 #5
0
    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