Пример #1
0
 def request_stack(self, py_db, seq, thread_id, timeout=.5):
     # If it's already suspended, get it right away.
     internal_get_thread_stack = InternalGetThreadStack(seq, thread_id, py_db, set_additional_thread_info, timeout=timeout)
     if internal_get_thread_stack.can_be_executed_by(get_current_thread_id(threading.current_thread())):
         internal_get_thread_stack.do_it(py_db)
     else:
         py_db.post_internal_command(internal_get_thread_stack, '*')
Пример #2
0
def _run_with_unblock_threads(original_func, py_db, curr_thread, frame, expression, is_exec):
    on_timeout_unblock_threads = None
    timeout_tracker = py_db.timeout_tracker  # : :type timeout_tracker: TimeoutTracker

    if py_db.multi_threads_single_notification:
        unblock_threads_timeout = pydevd_constants.PYDEVD_UNBLOCK_THREADS_TIMEOUT
    else:
        unblock_threads_timeout = -1  # Don't use this if threads are managed individually.

    if unblock_threads_timeout >= 0:
        pydev_log.info('Doing evaluate with unblock threads timeout: %s.', unblock_threads_timeout)
        tid = get_current_thread_id(curr_thread)

        def on_timeout_unblock_threads():
            on_timeout_unblock_threads.called = True
            pydev_log.info('Resuming threads after evaluate timeout.')
            resume_threads('*', except_thread=curr_thread)
            py_db.threads_suspended_single_notification.on_thread_resume(tid)

        on_timeout_unblock_threads.called = False

    try:
        if on_timeout_unblock_threads is None:
            return _run_with_interrupt_thread(original_func, py_db, curr_thread, frame, expression, is_exec)
        else:
            with timeout_tracker.call_on_timeout(unblock_threads_timeout, on_timeout_unblock_threads):
                return _run_with_interrupt_thread(original_func, py_db, curr_thread, frame, expression, is_exec)

    finally:
        if on_timeout_unblock_threads is not None and on_timeout_unblock_threads.called:
            mark_thread_suspended(curr_thread, CMD_SET_BREAK)
            py_db.threads_suspended_single_notification.increment_suspend_time()
            suspend_all_threads(py_db, except_thread=curr_thread)
            py_db.threads_suspended_single_notification.on_thread_suspend(tid, CMD_SET_BREAK)
Пример #3
0
def add_custom_frame(frame, name, thread_id):
    '''
    It's possible to show paused frames by adding a custom frame through this API (it's
    intended to be used for coroutines, but could potentially be used for generators too).

    :param frame:
        The topmost frame to be shown paused when a thread with thread.ident == thread_id is paused.

    :param name:
        The name to be shown for the custom thread in the UI.

    :param thread_id:
        The thread id to which this frame is related (must match thread.ident).

    :return: str
        Returns the custom thread id which will be used to show the given frame paused.
    '''
    with CustomFramesContainer.custom_frames_lock:
        curr_thread_id = get_current_thread_id(threading.currentThread())
        next_id = CustomFramesContainer._next_frame_id = CustomFramesContainer._next_frame_id + 1

        # Note: the frame id kept contains an id and thread information on the thread where the frame was added
        # so that later on we can check if the frame is from the current thread by doing frame_id.endswith('|'+thread_id).
        frame_custom_thread_id = '__frame__:%s|%s' % (next_id, curr_thread_id)
        if DEBUG:
            sys.stderr.write('add_custom_frame: %s (%s) %s %s\n' % (
                frame_custom_thread_id, get_abs_path_real_path_and_base_from_frame(frame)[-1], frame.f_lineno, frame.f_code.co_name))

        CustomFramesContainer.custom_frames[frame_custom_thread_id] = CustomFrame(name, frame, thread_id)
        CustomFramesContainer._py_db_command_thread_event.set()
        return frame_custom_thread_id
Пример #4
0
    def get_current_thread_id(self, thread=None):
        from robotframework_debug_adapter.vendored import force_pydevd  # noqa
        from _pydevd_bundle.pydevd_constants import get_current_thread_id

        if thread is None:
            thread = threading.current_thread()
        return get_current_thread_id(thread)
Пример #5
0
    def __call__(self):
        # We monkey-patch the thread creation so that this function is called in the new thread. At this point
        # we notify of its creation and start tracing it.
        global_debugger = get_global_debugger()

        thread_id = None
        if global_debugger is not None:
            # Note: if this is a thread from threading.py, we're too early in the boostrap process (because we mocked
            # the start_new_thread internal machinery and thread._bootstrap has not finished), so, the code below needs
            # to make sure that we use the current thread bound to the original function and not use
            # threading.currentThread() unless we're sure it's a dummy thread.
            t = getattr(self.original_func, '__self__', getattr(self.original_func, 'im_self', None))
            if not isinstance(t, threading.Thread):
                # This is not a threading.Thread but a Dummy thread (so, get it as a dummy thread using
                # currentThread).
                t = threading.currentThread()

            if not getattr(t, 'is_pydev_daemon_thread', False):
                thread_id = get_current_thread_id(t)
                global_debugger.notify_thread_created(thread_id, t)
                _on_set_trace_for_new_thread(global_debugger)

            if getattr(global_debugger, 'thread_analyser', None) is not None:
                try:
                    from pydevd_concurrency_analyser.pydevd_concurrency_logger import log_new_thread
                    log_new_thread(global_debugger, t)
                except:
                    sys.stderr.write("Failed to detect new thread for visualization")
        try:
            ret = self.original_func(*self.args, **self.kwargs)
        finally:
            if thread_id is not None:
                global_debugger.notify_thread_not_alive(thread_id)

        return ret
Пример #6
0
def test_find_thread():
    from _pydevd_bundle.pydevd_constants import get_current_thread_id
    assert pydevd_find_thread_by_id('123') is None

    assert pydevd_find_thread_by_id(
        get_current_thread_id(
            threading.current_thread())) is threading.current_thread()
Пример #7
0
    def __call__(self):
        # We monkey-patch the thread creation so that this function is called in the new thread. At this point
        # we notify of its creation and start tracing it.
        global_debugger = get_global_debugger()

        thread_id = None
        if global_debugger is not None:
            # Note: if this is a thread from threading.py, we're too early in the boostrap process (because we mocked
            # the start_new_thread internal machinery and thread._bootstrap has not finished), so, the code below needs
            # to make sure that we use the current thread bound to the original function and not use
            # threading.currentThread() unless we're sure it's a dummy thread.
            t = getattr(self.original_func, '__self__', getattr(self.original_func, 'im_self', None))
            if not isinstance(t, threading.Thread):
                # This is not a threading.Thread but a Dummy thread (so, get it as a dummy thread using
                # currentThread).
                t = threading.currentThread()

            if not getattr(t, 'is_pydev_daemon_thread', False):
                thread_id = get_current_thread_id(t)
                global_debugger.notify_thread_created(thread_id, t)
                _on_set_trace_for_new_thread(global_debugger)
            
            if getattr(global_debugger, 'thread_analyser', None) is not None:
                try:
                    from pydevd_concurrency_analyser.pydevd_concurrency_logger import log_new_thread
                    log_new_thread(global_debugger, t)
                except:
                    sys.stderr.write("Failed to detect new thread for visualization")
        try:
            ret = self.original_func(*self.args, **self.kwargs)
        finally:
            if thread_id is not None:
                global_debugger.notify_thread_not_alive(thread_id)
        
        return ret
Пример #8
0
def add_custom_frame(frame, name, thread_id):
    '''
    It's possible to show paused frames by adding a custom frame through this API (it's
    intended to be used for coroutines, but could potentially be used for generators too).

    :param frame:
        The topmost frame to be shown paused when a thread with thread.ident == thread_id is paused.

    :param name:
        The name to be shown for the custom thread in the UI.

    :param thread_id:
        The thread id to which this frame is related (must match thread.ident).

    :return: str
        Returns the custom thread id which will be used to show the given frame paused.
    '''
    with CustomFramesContainer.custom_frames_lock:
        curr_thread_id = get_current_thread_id(threading.currentThread())
        next_id = CustomFramesContainer._next_frame_id = CustomFramesContainer._next_frame_id + 1

        # Note: the frame id kept contains an id and thread information on the thread where the frame was added
        # so that later on we can check if the frame is from the current thread by doing frame_id.endswith('|'+thread_id).
        frame_custom_thread_id = '__frame__:%s|%s' % (next_id, curr_thread_id)
        if DEBUG:
            sys.stderr.write(
                'add_custom_frame: %s (%s) %s %s\n' %
                (frame_custom_thread_id,
                 get_abs_path_real_path_and_base_from_frame(frame)[-1],
                 frame.f_lineno, frame.f_code.co_name))

        CustomFramesContainer.custom_frames[
            frame_custom_thread_id] = CustomFrame(name, frame, thread_id)
        CustomFramesContainer._py_db_command_thread_event.set()
        return frame_custom_thread_id
Пример #9
0
    def get_current_thread_id(self):
        if self._run_in_debug_mode:
            from robotframework_debug_adapter.vendored import force_pydevd  # noqa
            from _pydevd_bundle.pydevd_constants import get_current_thread_id

            return get_current_thread_id(threading.current_thread())
        else:
            return 1
Пример #10
0
 def request_stack(self, py_db, seq, thread_id, fmt=None, timeout=.5, start_frame=0, levels=0):
     # If it's already suspended, get it right away.
     internal_get_thread_stack = InternalGetThreadStack(
         seq, thread_id, py_db, set_additional_thread_info, fmt=fmt, timeout=timeout, start_frame=start_frame, levels=levels)
     if internal_get_thread_stack.can_be_executed_by(get_current_thread_id(threading.current_thread())):
         internal_get_thread_stack.do_it(py_db)
     else:
         py_db.post_internal_command(internal_get_thread_stack, '*')
Пример #11
0
def dump_frames(thread_id):
    sys.stdout.write('dumping frames\n')
    if thread_id != get_current_thread_id(threading.current_thread()):
        raise VariableError("find_frame: must execute on same thread")

    frame = get_frame()
    for frame in iter_frames(frame):
        sys.stdout.write('%s\n' % pickle.dumps(frame))
Пример #12
0
def dump_frames(thread_id):
    sys.stdout.write('dumping frames\n')
    if thread_id != get_current_thread_id(threading.currentThread()):
        raise VariableError("find_frame: must execute on same thread")

    frame = get_frame()
    for frame in iter_frames(frame):
        sys.stdout.write('%s\n' % pickle.dumps(frame))
Пример #13
0
    def __call__(self):
        # We monkey-patch the thread creation so that this function is called in the new thread. At this point
        # we notify of its creation and start tracing it.
        global_debugger = get_global_debugger()

        thread_id = None
        if global_debugger is not None:
            # Note: if this is a thread from threading.py, we're too early in the boostrap process (because we mocked
            # the start_new_thread internal machinery and thread._bootstrap has not finished), so, the code below needs
            # to make sure that we use the current thread bound to the original function and not use
            # threading.currentThread() unless we're sure it's a dummy thread.
            t = getattr(self.original_func, '__self__',
                        getattr(self.original_func, 'im_self', None))
            if not isinstance(t, threading.Thread):
                # This is not a threading.Thread but a Dummy thread (so, get it as a dummy thread using
                # currentThread).
                t = threading.currentThread()

            if not getattr(t, 'is_pydev_daemon_thread', False):
                thread_id = get_current_thread_id(t)
                global_debugger.notify_thread_created(thread_id, t)
                _on_set_trace_for_new_thread(global_debugger)

            if getattr(global_debugger, 'thread_analyser', None) is not None:
                try:
                    from pydevd_concurrency_analyser.pydevd_concurrency_logger import log_new_thread
                    log_new_thread(global_debugger, t)
                except:
                    sys.stderr.write(
                        "Failed to detect new thread for visualization")
        try:
            try:
                ret = self.original_func(*self.args, **self.kwargs)
            except:
                # If threads die with the debugger alive, it's possible that we
                # have exceptions during teardown (Python goes through each module
                # and sets their attributes to None). In this situation, don't
                # report spurious exceptions because of that.
                if sys is None or pydevd_tracing is None:
                    return
        finally:
            if sys is None or pydevd_tracing is None:
                return
            else:
                if thread_id is not None and global_debugger is not None:
                    global_debugger.notify_thread_not_alive(thread_id)
                frame = sys._getframe()
                while frame is not None:
                    if frame.f_trace is not None:
                        frame.f_trace = NO_FTRACE
                    frame = frame.f_back
                pydevd_tracing.SetTrace(None)

        return ret
Пример #14
0
def suspend_django(main_debugger, thread, frame, cmd=CMD_SET_BREAK):
    frame = DjangoTemplateFrame(frame)

    if frame.f_lineno is None:
        return None

    pydevd_vars.add_additional_frame_by_id(get_current_thread_id(thread), {id(frame): frame})

    main_debugger.set_suspend(thread, cmd)
    thread.additional_info.suspend_type = DJANGO_SUSPEND

    return frame
Пример #15
0
def _suspend_jinja2(pydb, thread, frame, cmd=CMD_SET_BREAK, message=None):
    frame = Jinja2TemplateFrame(frame)

    if frame.f_lineno is None:
        return None

    pydevd_vars.add_additional_frame_by_id(get_current_thread_id(thread), {id(frame): frame})
    pydb.set_suspend(thread, cmd)

    thread.additional_info.suspend_type = JINJA2_SUSPEND
    if cmd == CMD_ADD_EXCEPTION_BREAK:
        # send exception name as message
        if message:
            message = str(message)
        thread.additional_info.pydev_message = message

    return frame
Пример #16
0
def _suspend_jinja2(pydb, thread, frame, cmd=CMD_SET_BREAK, message=None):
    frame = Jinja2TemplateFrame(frame)

    if frame.f_lineno is None:
        return None

    pydevd_vars.add_additional_frame_by_id(get_current_thread_id(thread),
                                           {id(frame): frame})
    pydb.set_suspend(thread, cmd)

    thread.additional_info.suspend_type = JINJA2_SUSPEND
    if cmd == CMD_ADD_EXCEPTION_BREAK:
        # send exception name as message
        if message:
            message = str(message)
        thread.additional_info.pydev_message = message

    return frame
Пример #17
0
def add_custom_frame(frame, name, thread_id):
    CustomFramesContainer.custom_frames_lock.acquire()
    try:
        curr_thread_id = get_current_thread_id(threading.currentThread())
        next_id = CustomFramesContainer._next_frame_id = CustomFramesContainer._next_frame_id + 1

        # Note: the frame id kept contains an id and thread information on the thread where the frame was added
        # so that later on we can check if the frame is from the current thread by doing frame_id.endswith('|'+thread_id).
        frame_id = '__frame__:%s|%s' % (next_id, curr_thread_id)
        if DEBUG:
            sys.stderr.write('add_custom_frame: %s (%s) %s %s\n' % (
                frame_id, get_abs_path_real_path_and_base_from_frame(frame)[-1], frame.f_lineno, frame.f_code.co_name))

        CustomFramesContainer.custom_frames[frame_id] = CustomFrame(name, frame, thread_id)
        CustomFramesContainer._py_db_command_thread_event.set()
        return frame_id
    finally:
        CustomFramesContainer.custom_frames_lock.release()
Пример #18
0
def find_frame(thread_id, frame_id):
    """ returns a frame on the thread that has a given frame_id """
    try:
        curr_thread_id = get_current_thread_id(threading.currentThread())
        if thread_id != curr_thread_id:
            try:
                return get_custom_frame(thread_id, frame_id)  # I.e.: thread_id could be a stackless frame id + thread_id.
            except:
                pass

            raise VariableError("find_frame: must execute on same thread (%s != %s)" % (thread_id, curr_thread_id))

        lookingFor = int(frame_id)

        if AdditionalFramesContainer.additional_frames:
            if thread_id in AdditionalFramesContainer.additional_frames:
                frame = AdditionalFramesContainer.additional_frames[thread_id].get(lookingFor)

                if frame is not None:
                    return frame

        curFrame = get_frame()
        if frame_id == "*":
            return curFrame  # any frame is specified with "*"

        frameFound = None

        for frame in _iter_frames(curFrame):
            if lookingFor == id(frame):
                frameFound = frame
                del frame
                break

            del frame

        # Important: python can hold a reference to the frame from the current context
        # if an exception is raised, so, if we don't explicitly add those deletes
        # we might have those variables living much more than we'd want to.

        # I.e.: sys.exc_info holding reference to frame that raises exception (so, other places
        # need to call sys.exc_clear())
        del curFrame

        if frameFound is None:
            msgFrames = ''
            i = 0

            for frame in _iter_frames(get_frame()):
                i += 1
                msgFrames += str(id(frame))
                if i % 5 == 0:
                    msgFrames += '\n'
                else:
                    msgFrames += '  -  '

# Note: commented this error message out (it may commonly happen 
# if a message asking for a frame is issued while a thread is paused
# but the thread starts running before the message is actually 
# handled).
# Leaving code to uncomment during tests.  
#             err_msg = '''find_frame: frame not found.
#     Looking for thread_id:%s, frame_id:%s
#     Current     thread_id:%s, available frames:
#     %s\n
#     ''' % (thread_id, lookingFor, curr_thread_id, msgFrames)
# 
#             sys.stderr.write(err_msg)
            return None

        return frameFound
    except:
        import traceback
        traceback.print_exc()
        return None
Пример #19
0
def test_find_thread():
    from _pydevd_bundle.pydevd_constants import get_current_thread_id
    assert pydevd_find_thread_by_id('123') is None

    assert pydevd_find_thread_by_id(
        get_current_thread_id(threading.current_thread())) is threading.current_thread()
Пример #20
0
    def handle_exception(self, frame, event, arg):
        try:
            # print('handle_exception', frame.f_lineno, frame.f_code.co_name)

            # We have 3 things in arg: exception type, description, traceback object
            trace_obj = arg[2]
            main_debugger = self._args[0]

            initial_trace_obj = trace_obj
            if trace_obj.tb_next is None and trace_obj.tb_frame is frame:
                # I.e.: tb_next should be only None in the context it was thrown (trace_obj.tb_frame is frame is just a double check).
                pass
            else:
                # Get the trace_obj from where the exception was raised...
                while trace_obj.tb_next is not None:
                    trace_obj = trace_obj.tb_next

            if main_debugger.ignore_exceptions_thrown_in_lines_with_ignore_exception:
                for check_trace_obj in (initial_trace_obj, trace_obj):
                    filename = get_abs_path_real_path_and_base_from_frame(check_trace_obj.tb_frame)[1]

                    filename_to_lines_where_exceptions_are_ignored = self.filename_to_lines_where_exceptions_are_ignored

                    lines_ignored = filename_to_lines_where_exceptions_are_ignored.get(filename)
                    if lines_ignored is None:
                        lines_ignored = filename_to_lines_where_exceptions_are_ignored[filename] = {}

                    try:
                        curr_stat = os.stat(filename)
                        curr_stat = (curr_stat.st_size, curr_stat.st_mtime)
                    except:
                        curr_stat = None

                    last_stat = self.filename_to_stat_info.get(filename)
                    if last_stat != curr_stat:
                        self.filename_to_stat_info[filename] = curr_stat
                        lines_ignored.clear()
                        try:
                            linecache.checkcache(filename)
                        except:
                            # Jython 2.1
                            linecache.checkcache()

                    from_user_input = main_debugger.filename_to_lines_where_exceptions_are_ignored.get(filename)
                    if from_user_input:
                        merged = {}
                        merged.update(lines_ignored)
                        # Override what we have with the related entries that the user entered
                        merged.update(from_user_input)
                    else:
                        merged = lines_ignored

                    exc_lineno = check_trace_obj.tb_lineno

                    # print ('lines ignored', lines_ignored)
                    # print ('user input', from_user_input)
                    # print ('merged', merged, 'curr', exc_lineno)

                    if exc_lineno not in merged:  # Note: check on merged but update lines_ignored.
                        try:
                            line = linecache.getline(filename, exc_lineno, check_trace_obj.tb_frame.f_globals)
                        except:
                            # Jython 2.1
                            line = linecache.getline(filename, exc_lineno)

                        if IGNORE_EXCEPTION_TAG.match(line) is not None:
                            lines_ignored[exc_lineno] = 1
                            return
                        else:
                            # Put in the cache saying not to ignore
                            lines_ignored[exc_lineno] = 0
                    else:
                        # Ok, dict has it already cached, so, let's check it...
                        if merged.get(exc_lineno, 0):
                            return

            thread = self._args[3]

            try:
                frame_id_to_frame = {}
                frame_id_to_frame[id(frame)] = frame
                f = trace_obj.tb_frame
                while f is not None:
                    frame_id_to_frame[id(f)] = f
                    f = f.f_back
                f = None

                thread_id = get_current_thread_id(thread)
                pydevd_vars.add_additional_frame_by_id(thread_id, frame_id_to_frame)
                try:
                    main_debugger.send_caught_exception_stack(thread, arg, id(frame))
                    self.set_suspend(thread, CMD_STEP_CAUGHT_EXCEPTION)
                    self.do_wait_suspend(thread, frame, event, arg)
                    main_debugger.send_caught_exception_stack_proceeded(thread)

                finally:
                    pydevd_vars.remove_additional_frame_by_id(thread_id)
            except:
                traceback.print_exc()

            main_debugger.set_trace_for_frame_and_parents(frame)
        finally:
            # Make sure the user cannot see the '__exception__' we added after we leave the suspend state.
            remove_exception_from_frame(frame)
            # Clear some local variables...
            frame = None
            trace_obj = None
            initial_trace_obj = None
            check_trace_obj = None
            f = None
            frame_id_to_frame = None
            main_debugger = None
            thread = None
Пример #21
0
def getVariable(dbg, thread_id, frame_id, scope, attrs):
    """
    returns the value of a variable

    :scope: can be BY_ID, EXPRESSION, GLOBAL, LOCAL, FRAME

    BY_ID means we'll traverse the list of all objects alive to get the object.

    :attrs: after reaching the proper scope, we have to get the attributes until we find
            the proper location (i.e.: obj\tattr1\tattr2)

    :note: when BY_ID is used, the frame_id is considered the id of the object to find and
           not the frame (as we don't care about the frame in this case).
    """
    if scope == 'BY_ID':
        if thread_id != get_current_thread_id(threading.currentThread()):
            raise VariableError("getVariable: must execute on same thread")

        try:
            import gc
            objects = gc.get_objects()
        except:
            pass  # Not all python variants have it.
        else:
            frame_id = int(frame_id)
            for var in objects:
                if id(var) == frame_id:
                    if attrs is not None:
                        attrList = attrs.split('\t')
                        for k in attrList:
                            _type, _typeName, resolver = get_type(var)
                            var = resolver.resolve(var, k)

                    return var

        # If it didn't return previously, we coudn't find it by id (i.e.: alrceady garbage collected).
        sys.stderr.write('Unable to find object with id: %s\n' % (frame_id,))
        return None

    frame = dbg.find_frame(thread_id, frame_id)
    if frame is None:
        return {}

    if attrs is not None:
        attrList = attrs.split('\t')
    else:
        attrList = []

    for attr in attrList:
        attr.replace("@_@TAB_CHAR@_@", '\t')

    if scope == 'EXPRESSION':
        for count in xrange(len(attrList)):
            if count == 0:
                # An Expression can be in any scope (globals/locals), therefore it needs to evaluated as an expression
                var = evaluate_expression(dbg, thread_id, frame_id, attrList[count], False)
            else:
                _type, _typeName, resolver = get_type(var)
                var = resolver.resolve(var, attrList[count])
    else:
        if scope == "GLOBAL":
            var = frame.f_globals
            del attrList[0]  # globals are special, and they get a single dummy unused attribute
        else:
            # in a frame access both locals and globals as Python does
            var = {}
            var.update(frame.f_globals)
            var.update(frame.f_locals)

        for k in attrList:
            _type, _typeName, resolver = get_type(var)
            var = resolver.resolve(var, k)

    return var
Пример #22
0
def getVariable(dbg, thread_id, frame_id, scope, attrs):
    """
    returns the value of a variable

    :scope: can be BY_ID, EXPRESSION, GLOBAL, LOCAL, FRAME

    BY_ID means we'll traverse the list of all objects alive to get the object.

    :attrs: after reaching the proper scope, we have to get the attributes until we find
            the proper location (i.e.: obj\tattr1\tattr2)

    :note: when BY_ID is used, the frame_id is considered the id of the object to find and
           not the frame (as we don't care about the frame in this case).
    """
    if scope == 'BY_ID':
        if thread_id != get_current_thread_id(threading.current_thread()):
            raise VariableError("getVariable: must execute on same thread")

        try:
            import gc
            objects = gc.get_objects()
        except:
            pass  # Not all python variants have it.
        else:
            frame_id = int(frame_id)
            for var in objects:
                if id(var) == frame_id:
                    if attrs is not None:
                        attrList = attrs.split('\t')
                        for k in attrList:
                            _type, _type_name, resolver = get_type(var)
                            var = resolver.resolve(var, k)

                    return var

        # If it didn't return previously, we coudn't find it by id (i.e.: alrceady garbage collected).
        sys.stderr.write('Unable to find object with id: %s\n' % (frame_id, ))
        return None

    frame = dbg.find_frame(thread_id, frame_id)
    if frame is None:
        return {}

    if attrs is not None:
        attrList = attrs.split('\t')
    else:
        attrList = []

    for attr in attrList:
        attr.replace("@_@TAB_CHAR@_@", '\t')

    if scope == 'EXPRESSION':
        for count in range(len(attrList)):
            if count == 0:
                # An Expression can be in any scope (globals/locals), therefore it needs to evaluated as an expression
                var = evaluate_expression(dbg, frame, attrList[count], False)
            else:
                _type, _type_name, resolver = get_type(var)
                var = resolver.resolve(var, attrList[count])
    else:
        if scope == "GLOBAL":
            var = frame.f_globals
            del attrList[
                0]  # globals are special, and they get a single dummy unused attribute
        else:
            # in a frame access both locals and globals as Python does
            var = {}
            var.update(frame.f_globals)
            var.update(frame.f_locals)

        for k in attrList:
            _type, _type_name, resolver = get_type(var)
            var = resolver.resolve(var, k)

    return var
Пример #23
0
    def __call__(self, frame, event, arg):
        ''' This is the callback used when we enter some context in the debugger.

        We also decorate the thread we are in with info about the debugging.
        The attributes added are:
            pydev_state
            pydev_step_stop
            pydev_step_cmd
            pydev_notify_kill

        :param PyDB py_db:
            This is the global debugger (this method should actually be added as a method to it).
        '''
        # IFDEF CYTHON
        # cdef str filename;
        # cdef str base;
        # cdef int pydev_step_cmd;
        # cdef tuple frame_cache_key;
        # cdef dict cache_skips;
        # cdef bint is_stepping;
        # cdef tuple abs_path_canonical_path_and_base;
        # cdef PyDBAdditionalThreadInfo additional_info;
        # ENDIF

        # DEBUG = 'code_to_debug' in frame.f_code.co_filename
        # if DEBUG: print('ENTER: trace_dispatch: %s %s %s %s' % (frame.f_code.co_filename, frame.f_lineno, event, frame.f_code.co_name))
        py_db, t, additional_info, cache_skips, frame_skips_cache = self._args
        if additional_info.is_tracing:
            return None if event == 'call' else NO_FTRACE  # we don't wan't to trace code invoked from pydevd_frame.trace_dispatch

        additional_info.is_tracing += 1
        try:
            pydev_step_cmd = additional_info.pydev_step_cmd
            is_stepping = pydev_step_cmd != -1
            if py_db.pydb_disposed:
                return None if event == 'call' else NO_FTRACE

            # if thread is not alive, cancel trace_dispatch processing
            if not is_thread_alive(t):
                py_db.notify_thread_not_alive(get_current_thread_id(t))
                return None if event == 'call' else NO_FTRACE

            # Note: it's important that the context name is also given because we may hit something once
            # in the global context and another in the local context.
            frame_cache_key = (frame.f_code.co_firstlineno, frame.f_code.co_name, frame.f_code.co_filename)
            if frame_cache_key in cache_skips:
                if not is_stepping:
                    # if DEBUG: print('skipped: trace_dispatch (cache hit)', frame_cache_key, frame.f_lineno, event, frame.f_code.co_name)
                    return None if event == 'call' else NO_FTRACE
                else:
                    # When stepping we can't take into account caching based on the breakpoints (only global filtering).
                    if cache_skips.get(frame_cache_key) == 1:

                        if additional_info.pydev_original_step_cmd in (CMD_STEP_INTO, CMD_STEP_INTO_MY_CODE) and not _global_notify_skipped_step_in:
                            notify_skipped_step_in_because_of_filters(py_db, frame)

                        back_frame = frame.f_back
                        if back_frame is not None and pydev_step_cmd in (CMD_STEP_INTO, CMD_STEP_INTO_MY_CODE, CMD_STEP_RETURN, CMD_STEP_RETURN_MY_CODE):
                            back_frame_cache_key = (back_frame.f_code.co_firstlineno, back_frame.f_code.co_name, back_frame.f_code.co_filename)
                            if cache_skips.get(back_frame_cache_key) == 1:
                                # if DEBUG: print('skipped: trace_dispatch (cache hit: 1)', frame_cache_key, frame.f_lineno, event, frame.f_code.co_name)
                                return None if event == 'call' else NO_FTRACE
                        else:
                            # if DEBUG: print('skipped: trace_dispatch (cache hit: 2)', frame_cache_key, frame.f_lineno, event, frame.f_code.co_name)
                            return None if event == 'call' else NO_FTRACE

            try:
                # Make fast path faster!
                abs_path_canonical_path_and_base = NORM_PATHS_AND_BASE_CONTAINER[frame.f_code.co_filename]
            except:
                abs_path_canonical_path_and_base = get_abs_path_real_path_and_base_from_frame(frame)

            file_type = py_db.get_file_type(frame, abs_path_canonical_path_and_base)  # we don't want to debug threading or anything related to pydevd

            if file_type is not None:
                if file_type == 1:  # inlining LIB_FILE = 1
                    if not py_db.in_project_scope(frame, abs_path_canonical_path_and_base[0]):
                        # if DEBUG: print('skipped: trace_dispatch (not in scope)', abs_path_canonical_path_and_base[2], frame.f_lineno, event, frame.f_code.co_name, file_type)
                        cache_skips[frame_cache_key] = 1
                        return None if event == 'call' else NO_FTRACE
                else:
                    # if DEBUG: print('skipped: trace_dispatch', abs_path_canonical_path_and_base[2], frame.f_lineno, event, frame.f_code.co_name, file_type)
                    cache_skips[frame_cache_key] = 1
                    return None if event == 'call' else NO_FTRACE

            if py_db.is_files_filter_enabled:
                if py_db.apply_files_filter(frame, abs_path_canonical_path_and_base[0], False):
                    cache_skips[frame_cache_key] = 1

                    if is_stepping and additional_info.pydev_original_step_cmd in (CMD_STEP_INTO, CMD_STEP_INTO_MY_CODE) and not _global_notify_skipped_step_in:
                        notify_skipped_step_in_because_of_filters(py_db, frame)

                    # A little gotcha, sometimes when we're stepping in we have to stop in a
                    # return event showing the back frame as the current frame, so, we need
                    # to check not only the current frame but the back frame too.
                    back_frame = frame.f_back
                    if back_frame is not None and pydev_step_cmd in (CMD_STEP_INTO, CMD_STEP_INTO_MY_CODE, CMD_STEP_RETURN, CMD_STEP_RETURN_MY_CODE):
                        if py_db.apply_files_filter(back_frame, back_frame.f_code.co_filename, False):
                            back_frame_cache_key = (back_frame.f_code.co_firstlineno, back_frame.f_code.co_name, back_frame.f_code.co_filename)
                            cache_skips[back_frame_cache_key] = 1
                            # if DEBUG: print('skipped: trace_dispatch (filtered out: 1)', frame_cache_key, frame.f_lineno, event, frame.f_code.co_name)
                            return None if event == 'call' else NO_FTRACE
                    else:
                        # if DEBUG: print('skipped: trace_dispatch (filtered out: 2)', frame_cache_key, frame.f_lineno, event, frame.f_code.co_name)
                        return None if event == 'call' else NO_FTRACE

            # if DEBUG: print('trace_dispatch', filename, frame.f_lineno, event, frame.f_code.co_name, file_type)

            # Just create PyDBFrame directly (removed support for Python versions < 2.5, which required keeping a weak
            # reference to the frame).
            ret = PyDBFrame(
                (
                    py_db, abs_path_canonical_path_and_base, additional_info, t, frame_skips_cache, frame_cache_key,
                )
            ).trace_dispatch(frame, event, arg)
            if ret is None:
                # 1 means skipped because of filters.
                # 2 means skipped because no breakpoints were hit.
                cache_skips[frame_cache_key] = 2
                return None if event == 'call' else NO_FTRACE

            # IFDEF CYTHON
            # frame.f_trace = SafeCallWrapper(ret)  # Make sure we keep the returned tracer.
            # ELSE
            frame.f_trace = ret  # Make sure we keep the returned tracer.
            # ENDIF
            return ret

        except SystemExit:
            return None if event == 'call' else NO_FTRACE

        except Exception:
            if py_db.pydb_disposed:
                return None if event == 'call' else NO_FTRACE  # Don't log errors when we're shutting down.
            # Log it
            try:
                if pydev_log_exception is not None:
                    # This can actually happen during the interpreter shutdown in Python 2.7
                    pydev_log_exception()
            except:
                # Error logging? We're really in the interpreter shutdown...
                # (https://github.com/fabioz/PyDev.Debugger/issues/8)
                pass
            return None if event == 'call' else NO_FTRACE
        finally:
            additional_info.is_tracing -= 1
Пример #24
0
    def handle_exception(self, frame, event, arg):
        try:
            # print('handle_exception', frame.f_lineno, frame.f_code.co_name)

            # We have 3 things in arg: exception type, description, traceback object
            trace_obj = arg[2]
            main_debugger = self._args[0]

            initial_trace_obj = trace_obj
            if trace_obj.tb_next is None and trace_obj.tb_frame is frame:
                # I.e.: tb_next should be only None in the context it was thrown (trace_obj.tb_frame is frame is just a double check).
                pass
            else:
                # Get the trace_obj from where the exception was raised...
                while trace_obj.tb_next is not None:
                    trace_obj = trace_obj.tb_next

            if main_debugger.ignore_exceptions_thrown_in_lines_with_ignore_exception:
                for check_trace_obj in (initial_trace_obj, trace_obj):
                    filename = get_abs_path_real_path_and_base_from_frame(check_trace_obj.tb_frame)[1]

                    filename_to_lines_where_exceptions_are_ignored = self.filename_to_lines_where_exceptions_are_ignored

                    lines_ignored = filename_to_lines_where_exceptions_are_ignored.get(filename)
                    if lines_ignored is None:
                        lines_ignored = filename_to_lines_where_exceptions_are_ignored[filename] = {}

                    try:
                        curr_stat = os.stat(filename)
                        curr_stat = (curr_stat.st_size, curr_stat.st_mtime)
                    except:
                        curr_stat = None

                    last_stat = self.filename_to_stat_info.get(filename)
                    if last_stat != curr_stat:
                        self.filename_to_stat_info[filename] = curr_stat
                        lines_ignored.clear()
                        try:
                            linecache.checkcache(filename)
                        except:
                            # Jython 2.1
                            linecache.checkcache()

                    from_user_input = main_debugger.filename_to_lines_where_exceptions_are_ignored.get(filename)
                    if from_user_input:
                        merged = {}
                        merged.update(lines_ignored)
                        # Override what we have with the related entries that the user entered
                        merged.update(from_user_input)
                    else:
                        merged = lines_ignored

                    exc_lineno = check_trace_obj.tb_lineno

                    # print ('lines ignored', lines_ignored)
                    # print ('user input', from_user_input)
                    # print ('merged', merged, 'curr', exc_lineno)

                    if exc_lineno not in merged:  # Note: check on merged but update lines_ignored.
                        try:
                            line = linecache.getline(filename, exc_lineno, check_trace_obj.tb_frame.f_globals)
                        except:
                            # Jython 2.1
                            line = linecache.getline(filename, exc_lineno)

                        if IGNORE_EXCEPTION_TAG.match(line) is not None:
                            lines_ignored[exc_lineno] = 1
                            return
                        else:
                            # Put in the cache saying not to ignore
                            lines_ignored[exc_lineno] = 0
                    else:
                        # Ok, dict has it already cached, so, let's check it...
                        if merged.get(exc_lineno, 0):
                            return

            thread = self._args[3]

            try:
                frame_id_to_frame = {}
                frame_id_to_frame[id(frame)] = frame
                f = trace_obj.tb_frame
                while f is not None:
                    frame_id_to_frame[id(f)] = f
                    f = f.f_back
                f = None

                thread_id = get_current_thread_id(thread)
                pydevd_vars.add_additional_frame_by_id(thread_id, frame_id_to_frame)
                try:
                    main_debugger.send_caught_exception_stack(thread, arg, id(frame))
                    self.set_suspend(thread, CMD_STEP_CAUGHT_EXCEPTION)
                    self.do_wait_suspend(thread, frame, event, arg)
                    main_debugger.send_caught_exception_stack_proceeded(thread)

                finally:
                    pydevd_vars.remove_additional_frame_by_id(thread_id)
            except:
                traceback.print_exc()

            main_debugger.set_trace_for_frame_and_parents(frame)
        finally:
            # Make sure the user cannot see the '__exception__' we added after we leave the suspend state.
            remove_exception_from_frame(frame)
            # Clear some local variables...
            frame = None
            trace_obj = None
            initial_trace_obj = None
            check_trace_obj = None
            f = None
            frame_id_to_frame = None
            main_debugger = None
            thread = None
Пример #25
0
    def __call__(self, frame, event, arg):
        ''' This is the callback used when we enter some context in the debugger.

        We also decorate the thread we are in with info about the debugging.
        The attributes added are:
            pydev_state
            pydev_step_stop
            pydev_step_cmd
            pydev_notify_kill

        :param PyDB py_db:
            This is the global debugger (this method should actually be added as a method to it).
        '''
        # IFDEF CYTHON
        # cdef str filename;
        # cdef str base;
        # cdef int pydev_step_cmd;
        # cdef tuple frame_cache_key;
        # cdef dict cache_skips;
        # cdef bint is_stepping;
        # cdef tuple abs_path_real_path_and_base;
        # cdef PyDBAdditionalThreadInfo additional_info;
        # ENDIF
        # print('ENTER: trace_dispatch', frame.f_code.co_filename, frame.f_lineno, event, frame.f_code.co_name)
        py_db, t, additional_info, cache_skips, frame_skips_cache = self._args
        pydev_step_cmd = additional_info.pydev_step_cmd
        is_stepping = pydev_step_cmd != -1

        try:
            if py_db._finish_debugging_session:
                if not py_db._termination_event_set:
                    # that was not working very well because jython gave some socket errors
                    try:
                        if py_db.output_checker_thread is None:
                            kill_all_pydev_threads()
                    except:
                        traceback.print_exc()
                    py_db._termination_event_set = True
                if event != 'call': frame.f_trace = NO_FTRACE
                return None

            # if thread is not alive, cancel trace_dispatch processing
            if not is_thread_alive(t):
                py_db.notify_thread_not_alive(get_current_thread_id(t))
                if event != 'call': frame.f_trace = NO_FTRACE
                return None  # suspend tracing

            if py_db.thread_analyser is not None:
                py_db.thread_analyser.log_event(frame)

            if py_db.asyncio_analyser is not None:
                py_db.asyncio_analyser.log_event(frame)

            # Note: it's important that the context name is also given because we may hit something once
            # in the global context and another in the local context.
            frame_cache_key = (frame.f_code.co_firstlineno, frame.f_code.co_name, frame.f_code.co_filename)
            if not is_stepping and frame_cache_key in cache_skips:
                # print('skipped: trace_dispatch (cache hit)', frame_cache_key, frame.f_lineno, event, frame.f_code.co_name)
                if event != 'call': frame.f_trace = NO_FTRACE
                return None

            try:
                # Make fast path faster!
                abs_path_real_path_and_base = NORM_PATHS_AND_BASE_CONTAINER[frame.f_code.co_filename]
            except:
                abs_path_real_path_and_base = get_abs_path_real_path_and_base_from_frame(frame)

            filename = abs_path_real_path_and_base[1]
            file_type = get_file_type(abs_path_real_path_and_base[-1])  # we don't want to debug threading or anything related to pydevd

            if file_type is not None:
                if file_type == 1:  # inlining LIB_FILE = 1
                    if not py_db.in_project_scope(filename):
                        # print('skipped: trace_dispatch (not in scope)', abs_path_real_path_and_base[-1], frame.f_lineno, event, frame.f_code.co_name, file_type)
                        cache_skips[frame_cache_key] = 1
                        if event != 'call': frame.f_trace = NO_FTRACE
                        return None
                else:
                    # print('skipped: trace_dispatch', abs_path_real_path_and_base[-1], frame.f_lineno, event, frame.f_code.co_name, file_type)
                    cache_skips[frame_cache_key] = 1
                    if event != 'call': frame.f_trace = NO_FTRACE
                    return None

            if is_stepping:
                if py_db.is_filter_enabled and py_db.is_ignored_by_filters(filename):
                    # ignore files matching stepping filters
                    if event != 'call': frame.f_trace = NO_FTRACE
                    return None
                if py_db.is_filter_libraries and not py_db.in_project_scope(filename):
                    # ignore library files while stepping
                    if event != 'call': frame.f_trace = NO_FTRACE
                    return None

            # print('trace_dispatch', base, frame.f_lineno, event, frame.f_code.co_name, file_type)
            if additional_info.is_tracing:
                if event != 'call': frame.f_trace = NO_FTRACE
                return None  # we don't wan't to trace code invoked from pydevd_frame.trace_dispatch

            # Just create PyDBFrame directly (removed support for Python versions < 2.5, which required keeping a weak
            # reference to the frame).
            ret = PyDBFrame(
                (
                    py_db, filename, additional_info, t, frame_skips_cache, frame_cache_key,
                )
            ).trace_dispatch(frame, event, arg)
            if ret is None:
                cache_skips[frame_cache_key] = 1
                if event != 'call': frame.f_trace = NO_FTRACE
                return None

            # IFDEF CYTHON
            # ret = SafeCallWrapper(ret)
            # ENDIF
            frame.f_trace = ret  # Make sure we keep the returned tracer.
            return ret

        except SystemExit:
            if event != 'call': frame.f_trace = NO_FTRACE
            return None

        except Exception:
            if py_db._finish_debugging_session:
                if event != 'call': frame.f_trace = NO_FTRACE
                return None  # Don't log errors when we're shutting down.
            # Log it
            try:
                if traceback is not None:
                    # This can actually happen during the interpreter shutdown in Python 2.7
                    traceback.print_exc()
            except:
                # Error logging? We're really in the interpreter shutdown...
                # (https://github.com/fabioz/PyDev.Debugger/issues/8)
                pass
            if event != 'call': frame.f_trace = NO_FTRACE
            return None
def process_net_command(py_db, cmd_id, seq, text):
    '''Processes a command received from the Java side

    @param cmd_id: the id of the command
    @param seq: the sequence of the command
    @param text: the text received in the command

    @note: this method is run as a big switch... after doing some tests, it's not clear whether changing it for
    a dict id --> function call will have better performance result. A simple test with xrange(10000000) showed
    that the gains from having a fast access to what should be executed are lost because of the function call in
    a way that if we had 10 elements in the switch the if..elif are better -- but growing the number of choices
    makes the solution with the dispatch look better -- so, if this gets more than 20-25 choices at some time,
    it may be worth refactoring it (actually, reordering the ifs so that the ones used mostly come before
    probably will give better performance).
    '''
    # print(ID_TO_MEANING[str(cmd_id)], repr(text))

    py_db._main_lock.acquire()
    try:
        try:
            cmd = None
            if cmd_id == CMD_RUN:
                py_db.ready_to_run = True

            elif cmd_id == CMD_SET_PROTOCOL:
                expected = (NetCommand.HTTP_PROTOCOL,
                            NetCommand.QUOTED_LINE_PROTOCOL)
                text = text.strip()
                assert text.strip(
                ) in expected, 'Protocol (%s) should be one of: %s' % (
                    text, expected)

                NetCommand.protocol = text
                cmd = py_db.cmd_factory.make_protocol_set_message(seq)

            elif cmd_id == CMD_VERSION:
                # response is version number
                # ide_os should be 'WINDOWS' or 'UNIX'.

                # Default based on server process (although ideally the IDE should
                # provide it).
                if IS_WINDOWS:
                    ide_os = 'WINDOWS'
                else:
                    ide_os = 'UNIX'

                # Breakpoints can be grouped by 'LINE' or by 'ID'.
                breakpoints_by = 'LINE'

                splitted = text.split('\t')
                if len(splitted) == 1:
                    _local_version = splitted

                elif len(splitted) == 2:
                    _local_version, ide_os = splitted

                elif len(splitted) == 3:
                    _local_version, ide_os, breakpoints_by = splitted

                if breakpoints_by == 'ID':
                    py_db._set_breakpoints_with_id = True
                else:
                    py_db._set_breakpoints_with_id = False

                pydevd_file_utils.set_ide_os(ide_os)

                cmd = py_db.cmd_factory.make_version_message(seq)

            elif cmd_id == CMD_LIST_THREADS:
                # response is a list of threads
                cmd = py_db.cmd_factory.make_list_threads_message(seq)

            elif cmd_id == CMD_GET_THREAD_STACK:
                # Receives a thread_id and a given timeout, which is the time we should
                # wait to the provide the stack if a given thread is still not suspended.
                if '\t' in text:
                    thread_id, timeout = text.split('\t')
                    timeout = float(timeout)
                else:
                    thread_id = text
                    timeout = .5  # Default timeout is .5 seconds

                # If it's already suspended, get it right away.
                internal_get_thread_stack = InternalGetThreadStack(
                    seq,
                    thread_id,
                    py_db,
                    set_additional_thread_info,
                    timeout=timeout)
                if internal_get_thread_stack.can_be_executed_by(
                        get_current_thread_id(threading.current_thread())):
                    internal_get_thread_stack.do_it(py_db)
                else:
                    py_db.post_internal_command(internal_get_thread_stack, '*')

            elif cmd_id == CMD_THREAD_SUSPEND:
                # Yes, thread suspend is done at this point, not through an internal command.
                threads = []
                suspend_all = text.strip() == '*'
                if suspend_all:
                    threads = pydevd_utils.get_non_pydevd_threads()

                elif text.startswith('__frame__:'):
                    sys.stderr.write("Can't suspend tasklet: %s\n" % (text, ))

                else:
                    threads = [pydevd_find_thread_by_id(text)]

                for t in threads:
                    if t is None:
                        continue
                    py_db.set_suspend(
                        t,
                        CMD_THREAD_SUSPEND,
                        suspend_other_threads=suspend_all,
                        is_pause=True,
                    )
                    # Break here (even if it's suspend all) as py_db.set_suspend will
                    # take care of suspending other threads.
                    break

            elif cmd_id == CMD_THREAD_RUN:
                threads = []
                if text.strip() == '*':
                    threads = pydevd_utils.get_non_pydevd_threads()

                elif text.startswith('__frame__:'):
                    sys.stderr.write("Can't make tasklet run: %s\n" % (text, ))

                else:
                    threads = [pydevd_find_thread_by_id(text)]

                for t in threads:
                    if t is None:
                        continue
                    additional_info = set_additional_thread_info(t)
                    additional_info.pydev_step_cmd = -1
                    additional_info.pydev_step_stop = None
                    additional_info.pydev_state = STATE_RUN

            elif cmd_id == CMD_STEP_INTO or cmd_id == CMD_STEP_OVER or cmd_id == CMD_STEP_RETURN or \
                    cmd_id == CMD_STEP_INTO_MY_CODE:
                # we received some command to make a single step
                t = pydevd_find_thread_by_id(text)
                if t:
                    thread_id = get_thread_id(t)
                    int_cmd = InternalStepThread(thread_id, cmd_id)
                    py_db.post_internal_command(int_cmd, thread_id)

                elif text.startswith('__frame__:'):
                    sys.stderr.write("Can't make tasklet step command: %s\n" %
                                     (text, ))

            elif cmd_id in (CMD_RUN_TO_LINE, CMD_SET_NEXT_STATEMENT,
                            CMD_SMART_STEP_INTO):
                if cmd_id == CMD_SMART_STEP_INTO:
                    # we received a smart step into command
                    thread_id, frame_id, line, func_name, call_order, start_line, end_line = text.split(
                        '\t', 6)
                else:
                    # we received some command to make a single step
                    thread_id, line, func_name = text.split('\t', 2)
                if func_name == "None":
                    # global context
                    func_name = ''
                t = pydevd_find_thread_by_id(thread_id)
                if t:
                    if cmd_id == CMD_SMART_STEP_INTO:
                        int_cmd = InternalSmartStepInto(
                            thread_id, frame_id, cmd_id, func_name, line,
                            call_order, start_line, end_line, seq)
                    else:
                        int_cmd = InternalSetNextStatementThread(
                            thread_id, cmd_id, line, func_name, seq)
                    py_db.post_internal_command(int_cmd, thread_id)
                elif thread_id.startswith('__frame__:'):
                    sys.stderr.write(
                        "Can't set next statement in tasklet: %s\n" %
                        (thread_id, ))

            elif cmd_id == CMD_RELOAD_CODE:
                # we received some command to make a reload of a module
                module_name = text.strip()

                thread_id = '*'  # Any thread
                # Note: not going for the main thread because in this case it'd only do the load
                # when we stopped on a breakpoint.
                int_cmd = ReloadCodeCommand(module_name, thread_id)
                py_db.post_internal_command(int_cmd, thread_id)

            elif cmd_id == CMD_CHANGE_VARIABLE:
                # the text is: thread\tstackframe\tFRAME|GLOBAL\tattribute_to_change\tvalue_to_change
                try:
                    thread_id, frame_id, scope, attr_and_value = text.split(
                        '\t', 3)

                    tab_index = attr_and_value.rindex('\t')
                    attr = attr_and_value[0:tab_index].replace('\t', '.')
                    value = attr_and_value[tab_index + 1:]
                    int_cmd = InternalChangeVariable(seq, thread_id, frame_id,
                                                     scope, attr, value)
                    py_db.post_internal_command(int_cmd, thread_id)

                except:
                    traceback.print_exc()

            elif cmd_id == CMD_GET_VARIABLE:
                # we received some command to get a variable
                # the text is: thread_id\tframe_id\tFRAME|GLOBAL\tattributes*
                try:
                    thread_id, frame_id, scopeattrs = text.split('\t', 2)

                    if scopeattrs.find(
                            '\t') != -1:  # there are attributes beyond scope
                        scope, attrs = scopeattrs.split('\t', 1)
                    else:
                        scope, attrs = (scopeattrs, None)

                    int_cmd = InternalGetVariable(seq, thread_id, frame_id,
                                                  scope, attrs)
                    py_db.post_internal_command(int_cmd, thread_id)

                except:
                    traceback.print_exc()

            elif cmd_id == CMD_GET_ARRAY:
                # we received some command to get an array variable
                # the text is: thread_id\tframe_id\tFRAME|GLOBAL\tname\ttemp\troffs\tcoffs\trows\tcols\tformat
                try:
                    roffset, coffset, rows, cols, format, thread_id, frame_id, scopeattrs = text.split(
                        '\t', 7)

                    if scopeattrs.find(
                            '\t') != -1:  # there are attributes beyond scope
                        scope, attrs = scopeattrs.split('\t', 1)
                    else:
                        scope, attrs = (scopeattrs, None)

                    int_cmd = InternalGetArray(seq, roffset, coffset, rows,
                                               cols, format, thread_id,
                                               frame_id, scope, attrs)
                    py_db.post_internal_command(int_cmd, thread_id)

                except:
                    traceback.print_exc()

            elif cmd_id == CMD_SHOW_RETURN_VALUES:
                try:
                    show_return_values = text.split('\t')[1]
                    if int(show_return_values) == 1:
                        py_db.show_return_values = True
                    else:
                        if py_db.show_return_values:
                            # We should remove saved return values
                            py_db.remove_return_values_flag = True
                        py_db.show_return_values = False
                    pydev_log.debug("Show return values: %s\n" %
                                    py_db.show_return_values)
                except:
                    traceback.print_exc()

            elif cmd_id == CMD_SET_UNIT_TEST_DEBUGGING_MODE:
                py_db.set_unit_tests_debugging_mode()

            elif cmd_id == CMD_LOAD_FULL_VALUE:
                try:
                    thread_id, frame_id, scopeattrs = text.split('\t', 2)
                    vars = scopeattrs.split(NEXT_VALUE_SEPARATOR)

                    int_cmd = InternalLoadFullValue(seq, thread_id, frame_id,
                                                    vars)
                    py_db.post_internal_command(int_cmd, thread_id)
                except:
                    traceback.print_exc()

            elif cmd_id == CMD_GET_COMPLETIONS:
                # we received some command to get a variable
                # the text is: thread_id\tframe_id\tactivation token
                try:
                    thread_id, frame_id, scope, act_tok = text.split('\t', 3)

                    int_cmd = InternalGetCompletions(seq, thread_id, frame_id,
                                                     act_tok)
                    py_db.post_internal_command(int_cmd, thread_id)

                except:
                    traceback.print_exc()
            elif cmd_id == CMD_GET_DESCRIPTION:
                try:

                    thread_id, frame_id, expression = text.split('\t', 2)
                    int_cmd = InternalGetDescription(seq, thread_id, frame_id,
                                                     expression)
                    py_db.post_internal_command(int_cmd, thread_id)
                except:
                    traceback.print_exc()

            elif cmd_id == CMD_GET_FRAME:
                thread_id, frame_id, scope = text.split('\t', 2)

                int_cmd = InternalGetFrame(seq, thread_id, frame_id)
                py_db.post_internal_command(int_cmd, thread_id)

            elif cmd_id == CMD_SET_BREAK:
                # func name: 'None': match anything. Empty: match global, specified: only method context.
                # command to add some breakpoint.
                # text is file\tline. Add to breakpoints dictionary
                suspend_policy = "NONE"  # Can be 'NONE' or 'ALL'
                is_logpoint = False
                hit_condition = None
                if py_db._set_breakpoints_with_id:
                    try:
                        try:
                            breakpoint_id, type, file, line, func_name, condition, expression, hit_condition, is_logpoint, suspend_policy = text.split(
                                '\t', 9)
                        except ValueError:  # not enough values to unpack
                            # No suspend_policy passed (use default).
                            breakpoint_id, type, file, line, func_name, condition, expression, hit_condition, is_logpoint = text.split(
                                '\t', 8)
                        is_logpoint = is_logpoint == 'True'
                    except ValueError:  # not enough values to unpack
                        breakpoint_id, type, file, line, func_name, condition, expression = text.split(
                            '\t', 6)

                    breakpoint_id = int(breakpoint_id)
                    line = int(line)

                    # We must restore new lines and tabs as done in
                    # AbstractDebugTarget.breakpointAdded
                    condition = condition.replace("@_@NEW_LINE_CHAR@_@", '\n'). \
                        replace("@_@TAB_CHAR@_@", '\t').strip()

                    expression = expression.replace("@_@NEW_LINE_CHAR@_@", '\n'). \
                        replace("@_@TAB_CHAR@_@", '\t').strip()
                else:
                    # Note: this else should be removed after PyCharm migrates to setting
                    # breakpoints by id (and ideally also provides func_name).
                    type, file, line, func_name, suspend_policy, condition, expression = text.split(
                        '\t', 6)
                    # If we don't have an id given for each breakpoint, consider
                    # the id to be the line.
                    breakpoint_id = line = int(line)

                    condition = condition.replace("@_@NEW_LINE_CHAR@_@", '\n'). \
                        replace("@_@TAB_CHAR@_@", '\t').strip()

                    expression = expression.replace("@_@NEW_LINE_CHAR@_@", '\n'). \
                        replace("@_@TAB_CHAR@_@", '\t').strip()

                if not IS_PY3K:  # In Python 3, the frame object will have unicode for the file, whereas on python 2 it has a byte-array encoded with the filesystem encoding.
                    file = file.encode(file_system_encoding)

                if pydevd_file_utils.is_real_file(file):
                    file = pydevd_file_utils.norm_file_to_server(file)

                    if not pydevd_file_utils.exists(file):
                        sys.stderr.write(
                            'pydev debugger: warning: trying to add breakpoint'
                            ' to file that does not exist: %s (will have no effect)\n'
                            % (file, ))
                        sys.stderr.flush()

                if condition is not None and (len(condition) <= 0
                                              or condition == "None"):
                    condition = None

                if expression is not None and (len(expression) <= 0
                                               or expression == "None"):
                    expression = None

                if hit_condition is not None and (len(hit_condition) <= 0
                                                  or hit_condition == "None"):
                    hit_condition = None

                if type == 'python-line':
                    breakpoint = LineBreakpoint(line,
                                                condition,
                                                func_name,
                                                expression,
                                                suspend_policy,
                                                hit_condition=hit_condition,
                                                is_logpoint=is_logpoint)
                    breakpoints = py_db.breakpoints
                    file_to_id_to_breakpoint = py_db.file_to_id_to_line_breakpoint
                    supported_type = True
                else:
                    result = None
                    plugin = py_db.get_plugin_lazy_init()
                    if plugin is not None:
                        result = plugin.add_breakpoint(
                            'add_line_breakpoint',
                            py_db,
                            type,
                            file,
                            line,
                            condition,
                            expression,
                            func_name,
                            hit_condition=hit_condition,
                            is_logpoint=is_logpoint)
                    if result is not None:
                        supported_type = True
                        breakpoint, breakpoints = result
                        file_to_id_to_breakpoint = py_db.file_to_id_to_plugin_breakpoint
                    else:
                        supported_type = False

                if not supported_type:
                    if type == 'jupyter-line':
                        return
                    else:
                        raise NameError(type)

                if DebugInfoHolder.DEBUG_TRACE_BREAKPOINTS > 0:
                    pydev_log.debug(
                        'Added breakpoint:%s - line:%s - func_name:%s\n' %
                        (file, line, func_name.encode('utf-8')))
                    sys.stderr.flush()

                if file in file_to_id_to_breakpoint:
                    id_to_pybreakpoint = file_to_id_to_breakpoint[file]
                else:
                    id_to_pybreakpoint = file_to_id_to_breakpoint[file] = {}

                id_to_pybreakpoint[breakpoint_id] = breakpoint
                py_db.consolidate_breakpoints(file, id_to_pybreakpoint,
                                              breakpoints)
                if py_db.plugin is not None:
                    py_db.has_plugin_line_breaks = py_db.plugin.has_line_breaks(
                    )
                    if py_db.has_plugin_line_breaks:
                        py_db.frame_eval_func = None

                py_db.on_breakpoints_changed()

            elif cmd_id == CMD_REMOVE_BREAK:
                #command to remove some breakpoint
                #text is type\file\tid. Remove from breakpoints dictionary
                breakpoint_type, file, breakpoint_id = text.split('\t', 2)

                if not IS_PY3K:  # In Python 3, the frame object will have unicode for the file, whereas on python 2 it has a byte-array encoded with the filesystem encoding.
                    file = file.encode(file_system_encoding)

                if pydevd_file_utils.is_real_file(file):
                    file = pydevd_file_utils.norm_file_to_server(file)

                try:
                    breakpoint_id = int(breakpoint_id)
                except ValueError:
                    pydev_log.error(
                        'Error removing breakpoint. Expected breakpoint_id to be an int. Found: %s'
                        % (breakpoint_id, ))

                else:
                    file_to_id_to_breakpoint = None
                    if breakpoint_type == 'python-line':
                        breakpoints = py_db.breakpoints
                        file_to_id_to_breakpoint = py_db.file_to_id_to_line_breakpoint
                    elif py_db.get_plugin_lazy_init() is not None:
                        result = py_db.plugin.get_breakpoints(
                            py_db, breakpoint_type)
                        if result is not None:
                            file_to_id_to_breakpoint = py_db.file_to_id_to_plugin_breakpoint
                            breakpoints = result

                    if file_to_id_to_breakpoint is None:
                        pydev_log.error(
                            'Error removing breakpoint. Cant handle breakpoint of type %s'
                            % breakpoint_type)
                    else:
                        try:
                            id_to_pybreakpoint = file_to_id_to_breakpoint.get(
                                file, {})
                            if DebugInfoHolder.DEBUG_TRACE_BREAKPOINTS > 0:
                                existing = id_to_pybreakpoint[breakpoint_id]
                                sys.stderr.write(
                                    'Removed breakpoint:%s - line:%s - func_name:%s (id: %s)\n'
                                    % (file, existing.line,
                                       existing.func_name.encode('utf-8'),
                                       breakpoint_id))

                            del id_to_pybreakpoint[breakpoint_id]
                            py_db.consolidate_breakpoints(
                                file, id_to_pybreakpoint, breakpoints)
                            if py_db.plugin is not None:
                                py_db.has_plugin_line_breaks = py_db.plugin.has_line_breaks(
                                )

                        except KeyError:
                            pydev_log.error(
                                "Error removing breakpoint: Breakpoint id not found: %s id: %s. Available ids: %s\n"
                                % (file, breakpoint_id,
                                   dict_keys(id_to_pybreakpoint)))

                py_db.on_breakpoints_changed(removed=True)

            elif cmd_id == CMD_EVALUATE_EXPRESSION or cmd_id == CMD_EXEC_EXPRESSION:
                #command to evaluate the given expression
                #text is: thread\tstackframe\tLOCAL\texpression
                temp_name = ""
                try:
                    thread_id, frame_id, scope, expression, trim, temp_name = text.split(
                        '\t', 5)
                except ValueError:
                    thread_id, frame_id, scope, expression, trim = text.split(
                        '\t', 4)
                int_cmd = InternalEvaluateExpression(
                    seq, thread_id, frame_id, expression,
                    cmd_id == CMD_EXEC_EXPRESSION,
                    int(trim) == 1, temp_name)
                py_db.post_internal_command(int_cmd, thread_id)

            elif cmd_id == CMD_CONSOLE_EXEC:
                #command to exec expression in console, in case expression is only partially valid 'False' is returned
                #text is: thread\tstackframe\tLOCAL\texpression

                thread_id, frame_id, scope, expression = text.split('\t', 3)

                int_cmd = InternalConsoleExec(seq, thread_id, frame_id,
                                              expression)
                py_db.post_internal_command(int_cmd, thread_id)

            elif cmd_id == CMD_SET_PY_EXCEPTION:
                # Command which receives set of exceptions on which user wants to break the debugger
                # text is:
                #
                # break_on_uncaught;
                # break_on_caught;
                # skip_on_exceptions_thrown_in_same_context;
                # ignore_exceptions_thrown_in_lines_with_ignore_exception;
                # ignore_libraries;
                # TypeError;ImportError;zipimport.ZipImportError;
                #
                # i.e.: true;true;true;true;true;TypeError;ImportError;zipimport.ZipImportError;
                #
                # This API is optional and works 'in bulk' -- it's possible
                # to get finer-grained control with CMD_ADD_EXCEPTION_BREAK/CMD_REMOVE_EXCEPTION_BREAK
                # which allows setting caught/uncaught per exception.
                splitted = text.split(';')
                py_db.break_on_uncaught_exceptions = {}
                py_db.break_on_caught_exceptions = {}
                if len(splitted) >= 5:
                    if splitted[0] == 'true':
                        break_on_uncaught = True
                    else:
                        break_on_uncaught = False

                    if splitted[1] == 'true':
                        break_on_caught = True
                    else:
                        break_on_caught = False

                    if splitted[2] == 'true':
                        py_db.skip_on_exceptions_thrown_in_same_context = True
                    else:
                        py_db.skip_on_exceptions_thrown_in_same_context = False

                    if splitted[3] == 'true':
                        py_db.ignore_exceptions_thrown_in_lines_with_ignore_exception = True
                    else:
                        py_db.ignore_exceptions_thrown_in_lines_with_ignore_exception = False

                    if splitted[4] == 'true':
                        ignore_libraries = True
                    else:
                        ignore_libraries = False

                    for exception_type in splitted[5:]:
                        exception_type = exception_type.strip()
                        if not exception_type:
                            continue

                        exception_breakpoint = py_db.add_break_on_exception(
                            exception_type,
                            condition=None,
                            expression=None,
                            notify_on_handled_exceptions=break_on_caught,
                            notify_on_unhandled_exceptions=break_on_uncaught,
                            notify_on_first_raise_only=True,
                            ignore_libraries=ignore_libraries,
                        )

                    py_db.on_breakpoints_changed()

                else:
                    sys.stderr.write(
                        "Error when setting exception list. Received: %s\n" %
                        (text, ))

            elif cmd_id == CMD_GET_FILE_CONTENTS:

                if not IS_PY3K:  # In Python 3, the frame object will have unicode for the file, whereas on python 2 it has a byte-array encoded with the filesystem encoding.
                    text = text.encode(file_system_encoding)

                if os.path.exists(text):
                    f = open(text, 'r')
                    try:
                        source = f.read()
                    finally:
                        f.close()
                    cmd = py_db.cmd_factory.make_get_file_contents(seq, source)

            elif cmd_id == CMD_SET_PROPERTY_TRACE:
                # Command which receives whether to trace property getter/setter/deleter
                # text is feature_state(true/false);disable_getter/disable_setter/disable_deleter
                if text != "":
                    splitted = text.split(';')
                    if len(splitted) >= 3:
                        if py_db.disable_property_trace is False and splitted[
                                0] == 'true':
                            # Replacing property by custom property only when the debugger starts
                            pydevd_traceproperty.replace_builtin_property()
                            py_db.disable_property_trace = True
                        # Enable/Disable tracing of the property getter
                        if splitted[1] == 'true':
                            py_db.disable_property_getter_trace = True
                        else:
                            py_db.disable_property_getter_trace = False
                        # Enable/Disable tracing of the property setter
                        if splitted[2] == 'true':
                            py_db.disable_property_setter_trace = True
                        else:
                            py_db.disable_property_setter_trace = False
                        # Enable/Disable tracing of the property deleter
                        if splitted[3] == 'true':
                            py_db.disable_property_deleter_trace = True
                        else:
                            py_db.disable_property_deleter_trace = False
                else:
                    # User hasn't configured any settings for property tracing
                    pass

            elif cmd_id == CMD_ADD_EXCEPTION_BREAK:
                # Note that this message has some idiosyncrasies...
                #
                # notify_on_handled_exceptions can be 0, 1 or 2
                # 0 means we should not stop on handled exceptions.
                # 1 means we should stop on handled exceptions showing it on all frames where the exception passes.
                # 2 means we should stop on handled exceptions but we should only notify about it once.
                #
                # To ignore_libraries properly, besides setting ignore_libraries to 1, the IDE_PROJECT_ROOTS environment
                # variable must be set (so, we'll ignore anything not below IDE_PROJECT_ROOTS) -- this is not ideal as
                # the environment variable may not be properly set if it didn't start from the debugger (we should
                # create a custom message for that).
                #
                # There are 2 global settings which can only be set in CMD_SET_PY_EXCEPTION. Namely:
                #
                # py_db.skip_on_exceptions_thrown_in_same_context
                # - If True, we should only show the exception in a caller, not where it was first raised.
                #
                # py_db.ignore_exceptions_thrown_in_lines_with_ignore_exception
                # - If True exceptions thrown in lines with '@IgnoreException' will not be shown.

                condition = ""
                expression = ""
                if text.find('\t') != -1:
                    try:
                        exception, condition, expression, notify_on_handled_exceptions, notify_on_unhandled_exceptions, ignore_libraries = text.split(
                            '\t', 5)
                    except:
                        exception, notify_on_handled_exceptions, notify_on_unhandled_exceptions, ignore_libraries = text.split(
                            '\t', 3)
                else:
                    exception, notify_on_handled_exceptions, notify_on_unhandled_exceptions, ignore_libraries = text, 0, 0, 0

                condition = condition.replace("@_@NEW_LINE_CHAR@_@",
                                              '\n').replace(
                                                  "@_@TAB_CHAR@_@",
                                                  '\t').strip()

                if condition is not None and (len(condition) == 0
                                              or condition == "None"):
                    condition = None

                expression = expression.replace("@_@NEW_LINE_CHAR@_@",
                                                '\n').replace(
                                                    "@_@TAB_CHAR@_@",
                                                    '\t').strip()

                if expression is not None and (len(expression) == 0
                                               or expression == "None"):
                    expression = None

                if exception.find('-') != -1:
                    breakpoint_type, exception = exception.split('-')
                else:
                    breakpoint_type = 'python'

                if breakpoint_type == 'python':
                    exception_breakpoint = py_db.add_break_on_exception(
                        exception,
                        condition=condition,
                        expression=expression,
                        notify_on_handled_exceptions=int(
                            notify_on_handled_exceptions) > 0,
                        notify_on_unhandled_exceptions=int(
                            notify_on_unhandled_exceptions) == 1,
                        notify_on_first_raise_only=int(
                            notify_on_handled_exceptions) == 2,
                        ignore_libraries=int(ignore_libraries) > 0)

                    if exception_breakpoint is not None:
                        py_db.on_breakpoints_changed()
                else:
                    supported_type = False
                    plugin = py_db.get_plugin_lazy_init()
                    if plugin is not None:
                        supported_type = plugin.add_breakpoint(
                            'add_exception_breakpoint', py_db, breakpoint_type,
                            exception)

                    if supported_type:
                        py_db.has_plugin_exception_breaks = py_db.plugin.has_exception_breaks(
                        )
                        py_db.on_breakpoints_changed()
                    else:
                        raise NameError(breakpoint_type)

            elif cmd_id == CMD_REMOVE_EXCEPTION_BREAK:
                exception = text
                if exception.find('-') != -1:
                    exception_type, exception = exception.split('-')
                else:
                    exception_type = 'python'

                if exception_type == 'python':
                    try:
                        cp = py_db.break_on_uncaught_exceptions.copy()
                        cp.pop(exception, None)
                        py_db.break_on_uncaught_exceptions = cp

                        cp = py_db.break_on_caught_exceptions.copy()
                        cp.pop(exception, None)
                        py_db.break_on_caught_exceptions = cp
                    except:
                        pydev_log.debug("Error while removing exception %s" %
                                        sys.exc_info()[0])
                else:
                    supported_type = False

                    # I.e.: no need to initialize lazy (if we didn't have it in the first place, we can't remove
                    # anything from it anyways).
                    plugin = py_db.plugin
                    if plugin is not None:
                        supported_type = plugin.remove_exception_breakpoint(
                            py_db, exception_type, exception)

                    if supported_type:
                        py_db.has_plugin_exception_breaks = py_db.plugin.has_exception_breaks(
                        )
                    else:
                        raise NameError(exception_type)

                py_db.on_breakpoints_changed(removed=True)

            elif cmd_id == CMD_LOAD_SOURCE:
                path = text
                try:
                    if not IS_PY3K:  # In Python 3, the frame object will have unicode for the file, whereas on python 2 it has a byte-array encoded with the filesystem encoding.
                        path = path.encode(file_system_encoding)

                    path = pydevd_file_utils.norm_file_to_server(path)
                    f = open(path, 'r')
                    source = f.read()
                    cmd = py_db.cmd_factory.make_load_source_message(
                        seq, source)
                except:
                    cmd = py_db.cmd_factory.make_error_message(
                        seq, pydevd_tracing.get_exception_traceback_str())

            elif cmd_id == CMD_ADD_DJANGO_EXCEPTION_BREAK:
                exception = text
                plugin = py_db.get_plugin_lazy_init()
                if plugin is not None:
                    plugin.add_breakpoint('add_exception_breakpoint', py_db,
                                          'django', exception)
                    py_db.has_plugin_exception_breaks = py_db.plugin.has_exception_breaks(
                    )
                    py_db.on_breakpoints_changed()

            elif cmd_id == CMD_REMOVE_DJANGO_EXCEPTION_BREAK:
                exception = text

                # I.e.: no need to initialize lazy (if we didn't have it in the first place, we can't remove
                # anything from it anyways).
                plugin = py_db.plugin
                if plugin is not None:
                    plugin.remove_exception_breakpoint(py_db, 'django',
                                                       exception)
                    py_db.has_plugin_exception_breaks = py_db.plugin.has_exception_breaks(
                    )
                py_db.on_breakpoints_changed(removed=True)

            elif cmd_id == CMD_EVALUATE_CONSOLE_EXPRESSION:
                # Command which takes care for the debug console communication
                if text != "":
                    thread_id, frame_id, console_command = text.split('\t', 2)
                    console_command, line = console_command.split('\t')

                    if console_command == 'EVALUATE':
                        int_cmd = InternalEvaluateConsoleExpression(
                            seq, thread_id, frame_id, line, buffer_output=True)

                    elif console_command == 'EVALUATE_UNBUFFERED':
                        int_cmd = InternalEvaluateConsoleExpression(
                            seq,
                            thread_id,
                            frame_id,
                            line,
                            buffer_output=False)

                    elif console_command == 'GET_COMPLETIONS':
                        int_cmd = InternalConsoleGetCompletions(
                            seq, thread_id, frame_id, line)

                    else:
                        raise ValueError('Unrecognized command: %s' %
                                         (console_command, ))

                    py_db.post_internal_command(int_cmd, thread_id)

            elif cmd_id == CMD_RUN_CUSTOM_OPERATION:
                # Command which runs a custom operation
                if text != "":
                    try:
                        location, custom = text.split('||', 1)
                    except:
                        sys.stderr.write(
                            'Custom operation now needs a || separator. Found: %s\n'
                            % (text, ))
                        raise

                    thread_id, frame_id, scopeattrs = location.split('\t', 2)

                    if scopeattrs.find(
                            '\t') != -1:  # there are attributes beyond scope
                        scope, attrs = scopeattrs.split('\t', 1)
                    else:
                        scope, attrs = (scopeattrs, None)

                    # : style: EXECFILE or EXEC
                    # : encoded_code_or_file: file to execute or code
                    # : fname: name of function to be executed in the resulting namespace
                    style, encoded_code_or_file, fnname = custom.split('\t', 3)
                    int_cmd = InternalRunCustomOperation(
                        seq, thread_id, frame_id, scope, attrs, style,
                        encoded_code_or_file, fnname)
                    py_db.post_internal_command(int_cmd, thread_id)

            elif cmd_id == CMD_IGNORE_THROWN_EXCEPTION_AT:
                if text:
                    replace = 'REPLACE:'  # Not all 3.x versions support u'REPLACE:', so, doing workaround.
                    if not IS_PY3K:
                        replace = unicode(replace)

                    if text.startswith(replace):
                        text = text[8:]
                        py_db.filename_to_lines_where_exceptions_are_ignored.clear(
                        )

                    if text:
                        for line in text.split(
                                '||'
                        ):  # Can be bulk-created (one in each line)
                            filename, line_number = line.split('|')
                            if not IS_PY3K:
                                filename = filename.encode(
                                    file_system_encoding)

                            filename = pydevd_file_utils.norm_file_to_server(
                                filename)

                            if os.path.exists(filename):
                                lines_ignored = py_db.filename_to_lines_where_exceptions_are_ignored.get(
                                    filename)
                                if lines_ignored is None:
                                    lines_ignored = py_db.filename_to_lines_where_exceptions_are_ignored[
                                        filename] = {}
                                lines_ignored[int(line_number)] = 1
                            else:
                                sys.stderr.write(
                                    'pydev debugger: warning: trying to ignore exception thrown'
                                    ' on file that does not exist: %s (will have no effect)\n'
                                    % (filename, ))

            elif cmd_id == CMD_ENABLE_DONT_TRACE:
                if text:
                    true_str = 'true'  # Not all 3.x versions support u'str', so, doing workaround.
                    if not IS_PY3K:
                        true_str = unicode(true_str)

                    mode = text.strip() == true_str
                    pydevd_dont_trace.trace_filter(mode)

            elif cmd_id == CMD_PROCESS_CREATED_MSG_RECEIVED:
                original_seq = int(text)

                event = py_db.process_created_msg_received_events.pop(
                    original_seq, None)

                if event:
                    event.set()

            elif cmd_id == CMD_REDIRECT_OUTPUT:
                if text:
                    py_db.enable_output_redirection('STDOUT' in text, 'STDERR'
                                                    in text)

            elif cmd_id == CMD_GET_NEXT_STATEMENT_TARGETS:
                thread_id, frame_id = text.split('\t', 1)

                int_cmd = InternalGetNextStatementTargets(
                    seq, thread_id, frame_id)
                py_db.post_internal_command(int_cmd, thread_id)

            elif cmd_id == CMD_SET_PROJECT_ROOTS:
                pydevd_utils.set_project_roots(text.split(u'\t'))

            elif cmd_id == CMD_THREAD_DUMP_TO_STDERR:
                pydevd_utils.dump_threads()

            elif cmd_id == CMD_STOP_ON_START:
                py_db.stop_on_start = text.strip() in ('True', 'true', '1')

            elif cmd_id == CMD_PYDEVD_JSON_CONFIG:
                # Expected to receive a json string as:
                # {
                #     'skip_suspend_on_breakpoint_exception': [<exception names where we should suspend>],
                #     'skip_print_breakpoint_exception': [<exception names where we should print>],
                #     'multi_threads_single_notification': bool,
                # }
                msg = json.loads(text.strip())
                if 'skip_suspend_on_breakpoint_exception' in msg:
                    py_db.skip_suspend_on_breakpoint_exception = tuple(
                        get_exception_class(x)
                        for x in msg['skip_suspend_on_breakpoint_exception'])

                if 'skip_print_breakpoint_exception' in msg:
                    py_db.skip_print_breakpoint_exception = tuple(
                        get_exception_class(x)
                        for x in msg['skip_print_breakpoint_exception'])

                if 'multi_threads_single_notification' in msg:
                    py_db.multi_threads_single_notification = msg[
                        'multi_threads_single_notification']

            elif cmd_id == CMD_GET_EXCEPTION_DETAILS:
                thread_id = text
                t = pydevd_find_thread_by_id(thread_id)
                frame = None
                if t and not getattr(t, 'pydev_do_not_trace', None):
                    additional_info = set_additional_thread_info(t)
                    frame = additional_info.get_topmost_frame(t)
                try:
                    cmd = py_db.cmd_factory.make_get_exception_details_message(
                        seq, thread_id, frame)
                finally:
                    frame = None
                    t = None

            elif cmd_id == CMD_GET_SMART_STEP_INTO_VARIANTS:
                thread_id, frame_id, start_line, end_line = text.split('\t', 3)
                int_cmd = InternalGetSmartStepIntoVariants(
                    seq, thread_id, frame_id, start_line, end_line)
                py_db.post_internal_command(int_cmd, thread_id)

            # Powerful DataViewer commands
            elif cmd_id == CMD_DATAVIEWER_ACTION:
                # format: thread_id frame_id name temp
                try:
                    thread_id, frame_id, var, action, args = text.split(
                        '\t', 4)
                    args = args.split('\t')

                    int_cmd = InternalDataViewerAction(seq, thread_id,
                                                       frame_id, var, action,
                                                       args)
                    py_db.post_internal_command(int_cmd, thread_id)

                except:
                    traceback.print_exc()

            elif cmd_id == CMD_TABLE_EXEC:
                try:
                    thread_id, frame_id, init_command, command_type = text.split(
                        '\t', 3)
                    int_cmd = InternalTableCommand(seq, thread_id, frame_id,
                                                   init_command, command_type)
                    py_db.post_internal_command(int_cmd, thread_id)
                except:
                    traceback.print_exc()

            else:
                #I have no idea what this is all about
                cmd = py_db.cmd_factory.make_error_message(
                    seq, "unexpected command " + str(cmd_id))

            if cmd is not None:
                py_db.writer.add_command(cmd)
                del cmd

        except Exception:
            traceback.print_exc()
            try:
                from StringIO import StringIO
            except ImportError:
                from io import StringIO
            stream = StringIO()
            traceback.print_exc(file=stream)
            cmd = py_db.cmd_factory.make_error_message(
                seq,
                "Unexpected exception in process_net_command.\nInitial params: %s. Exception: %s"
                % (((cmd_id, seq, text), stream.getvalue())))

            py_db.writer.add_command(cmd)
    finally:
        py_db._main_lock.release()
def process_net_command(py_db, cmd_id, seq, text):
    '''Processes a command received from the Java side

    @param cmd_id: the id of the command
    @param seq: the sequence of the command
    @param text: the text received in the command

    @note: this method is run as a big switch... after doing some tests, it's not clear whether changing it for
    a dict id --> function call will have better performance result. A simple test with xrange(10000000) showed
    that the gains from having a fast access to what should be executed are lost because of the function call in
    a way that if we had 10 elements in the switch the if..elif are better -- but growing the number of choices
    makes the solution with the dispatch look better -- so, if this gets more than 20-25 choices at some time,
    it may be worth refactoring it (actually, reordering the ifs so that the ones used mostly come before
    probably will give better performance).
    '''
    # print(ID_TO_MEANING[str(cmd_id)], repr(text))

    py_db._main_lock.acquire()
    try:
        try:
            cmd = None
            if cmd_id == CMD_RUN:
                py_db.ready_to_run = True

            elif cmd_id == CMD_SET_PROTOCOL:
                expected = (NetCommand.HTTP_PROTOCOL, NetCommand.QUOTED_LINE_PROTOCOL)
                text = text.strip()
                assert text.strip() in expected, 'Protocol (%s) should be one of: %s' % (
                    text, expected)

                NetCommand.protocol = text
                cmd = py_db.cmd_factory.make_protocol_set_message(seq)

            elif cmd_id == CMD_VERSION:
                # response is version number
                # ide_os should be 'WINDOWS' or 'UNIX'.

                # Default based on server process (although ideally the IDE should
                # provide it).
                if IS_WINDOWS:
                    ide_os = 'WINDOWS'
                else:
                    ide_os = 'UNIX'

                # Breakpoints can be grouped by 'LINE' or by 'ID'.
                breakpoints_by = 'LINE'

                splitted = text.split('\t')
                if len(splitted) == 1:
                    _local_version = splitted

                elif len(splitted) == 2:
                    _local_version, ide_os = splitted

                elif len(splitted) == 3:
                    _local_version, ide_os, breakpoints_by = splitted

                if breakpoints_by == 'ID':
                    py_db._set_breakpoints_with_id = True
                else:
                    py_db._set_breakpoints_with_id = False

                pydevd_file_utils.set_ide_os(ide_os)

                cmd = py_db.cmd_factory.make_version_message(seq)

            elif cmd_id == CMD_LIST_THREADS:
                # response is a list of threads
                cmd = py_db.cmd_factory.make_list_threads_message(seq)

            elif cmd_id == CMD_GET_THREAD_STACK:
                # Receives a thread_id and a given timeout, which is the time we should
                # wait to the provide the stack if a given thread is still not suspended.
                if '\t' in text:
                    thread_id, timeout = text.split('\t')
                    timeout = float(timeout)
                else:
                    thread_id = text
                    timeout = .5  # Default timeout is .5 seconds

                # If it's already suspended, get it right away.
                internal_get_thread_stack = InternalGetThreadStack(seq, thread_id, py_db, set_additional_thread_info, timeout=timeout)
                if internal_get_thread_stack.can_be_executed_by(get_current_thread_id(threading.current_thread())):
                    internal_get_thread_stack.do_it(py_db)
                else:
                    py_db.post_internal_command(internal_get_thread_stack, '*')

            elif cmd_id == CMD_THREAD_SUSPEND:
                # Yes, thread suspend is done at this point, not through an internal command.
                threads = []
                suspend_all = text.strip() == '*'
                if suspend_all:
                    threads = pydevd_utils.get_non_pydevd_threads()
                
                elif text.startswith('__frame__:'):
                    sys.stderr.write("Can't suspend tasklet: %s\n" % (text,))
                    
                else:
                    threads = [pydevd_find_thread_by_id(text)]
                    
                for t in threads:
                    if t is None:
                        continue
                    py_db.set_suspend(
                        t,
                        CMD_THREAD_SUSPEND,
                        suspend_other_threads=suspend_all,
                        is_pause=True,
                    )
                    # Break here (even if it's suspend all) as py_db.set_suspend will
                    # take care of suspending other threads.
                    break

            elif cmd_id == CMD_THREAD_RUN:
                threads = []
                if text.strip() == '*':
                    threads = pydevd_utils.get_non_pydevd_threads()
                
                elif text.startswith('__frame__:'):
                    sys.stderr.write("Can't make tasklet run: %s\n" % (text,))
                    
                else:
                    threads = [pydevd_find_thread_by_id(text)]

                for t in threads:
                    if t is None:
                        continue
                    additional_info = set_additional_thread_info(t)
                    additional_info.pydev_step_cmd = -1
                    additional_info.pydev_step_stop = None
                    additional_info.pydev_state = STATE_RUN

            elif cmd_id == CMD_STEP_INTO or cmd_id == CMD_STEP_OVER or cmd_id == CMD_STEP_RETURN or \
                    cmd_id == CMD_STEP_INTO_MY_CODE:
                # we received some command to make a single step
                t = pydevd_find_thread_by_id(text)
                if t:
                    thread_id = get_thread_id(t)
                    int_cmd = InternalStepThread(thread_id, cmd_id)
                    py_db.post_internal_command(int_cmd, thread_id)

                elif text.startswith('__frame__:'):
                    sys.stderr.write("Can't make tasklet step command: %s\n" % (text,))


            elif cmd_id == CMD_RUN_TO_LINE or cmd_id == CMD_SET_NEXT_STATEMENT or cmd_id == CMD_SMART_STEP_INTO:
                # we received some command to make a single step
                thread_id, line, func_name = text.split('\t', 2)
                t = pydevd_find_thread_by_id(thread_id)
                if t:
                    int_cmd = InternalSetNextStatementThread(thread_id, cmd_id, line, func_name)
                    py_db.post_internal_command(int_cmd, thread_id)
                elif thread_id.startswith('__frame__:'):
                    sys.stderr.write("Can't set next statement in tasklet: %s\n" % (thread_id,))


            elif cmd_id == CMD_RELOAD_CODE:
                # we received some command to make a reload of a module
                module_name = text.strip()

                thread_id = '*'  # Any thread
                # Note: not going for the main thread because in this case it'd only do the load
                # when we stopped on a breakpoint.
                int_cmd = ReloadCodeCommand(module_name, thread_id)
                py_db.post_internal_command(int_cmd, thread_id)


            elif cmd_id == CMD_CHANGE_VARIABLE:
                # the text is: thread\tstackframe\tFRAME|GLOBAL\tattribute_to_change\tvalue_to_change
                try:
                    thread_id, frame_id, scope, attr_and_value = text.split('\t', 3)

                    tab_index = attr_and_value.rindex('\t')
                    attr = attr_and_value[0:tab_index].replace('\t', '.')
                    value = attr_and_value[tab_index + 1:]
                    int_cmd = InternalChangeVariable(seq, thread_id, frame_id, scope, attr, value)
                    py_db.post_internal_command(int_cmd, thread_id)

                except:
                    traceback.print_exc()

            elif cmd_id == CMD_GET_VARIABLE:
                # we received some command to get a variable
                # the text is: thread_id\tframe_id\tFRAME|GLOBAL\tattributes*
                try:
                    thread_id, frame_id, scopeattrs = text.split('\t', 2)

                    if scopeattrs.find('\t') != -1:  # there are attributes beyond scope
                        scope, attrs = scopeattrs.split('\t', 1)
                    else:
                        scope, attrs = (scopeattrs, None)

                    int_cmd = InternalGetVariable(seq, thread_id, frame_id, scope, attrs)
                    py_db.post_internal_command(int_cmd, thread_id)

                except:
                    traceback.print_exc()

            elif cmd_id == CMD_GET_ARRAY:
                # we received some command to get an array variable
                # the text is: thread_id\tframe_id\tFRAME|GLOBAL\tname\ttemp\troffs\tcoffs\trows\tcols\tformat
                try:
                    roffset, coffset, rows, cols, format, thread_id, frame_id, scopeattrs  = text.split('\t', 7)

                    if scopeattrs.find('\t') != -1:  # there are attributes beyond scope
                        scope, attrs = scopeattrs.split('\t', 1)
                    else:
                        scope, attrs = (scopeattrs, None)

                    int_cmd = InternalGetArray(seq, roffset, coffset, rows, cols, format, thread_id, frame_id, scope, attrs)
                    py_db.post_internal_command(int_cmd, thread_id)

                except:
                    traceback.print_exc()

            elif cmd_id == CMD_SHOW_RETURN_VALUES:
                try:
                    show_return_values = text.split('\t')[1]
                    if int(show_return_values) == 1:
                        py_db.show_return_values = True
                    else:
                        if py_db.show_return_values:
                            # We should remove saved return values
                            py_db.remove_return_values_flag = True
                        py_db.show_return_values = False
                    pydev_log.debug("Show return values: %s\n" % py_db.show_return_values)
                except:
                    traceback.print_exc()

            elif cmd_id == CMD_LOAD_FULL_VALUE:
                try:
                    thread_id, frame_id, scopeattrs = text.split('\t', 2)
                    vars = scopeattrs.split(NEXT_VALUE_SEPARATOR)

                    int_cmd = InternalLoadFullValue(seq, thread_id, frame_id, vars)
                    py_db.post_internal_command(int_cmd, thread_id)
                except:
                    traceback.print_exc()

            elif cmd_id == CMD_GET_COMPLETIONS:
                # we received some command to get a variable
                # the text is: thread_id\tframe_id\tactivation token
                try:
                    thread_id, frame_id, scope, act_tok = text.split('\t', 3)

                    int_cmd = InternalGetCompletions(seq, thread_id, frame_id, act_tok)
                    py_db.post_internal_command(int_cmd, thread_id)

                except:
                    traceback.print_exc()
            elif cmd_id == CMD_GET_DESCRIPTION:
                try:

                    thread_id, frame_id, expression = text.split('\t', 2)
                    int_cmd = InternalGetDescription(seq, thread_id, frame_id, expression)
                    py_db.post_internal_command(int_cmd, thread_id)
                except:
                    traceback.print_exc()

            elif cmd_id == CMD_GET_FRAME:
                thread_id, frame_id, scope = text.split('\t', 2)

                int_cmd = InternalGetFrame(seq, thread_id, frame_id)
                py_db.post_internal_command(int_cmd, thread_id)

            elif cmd_id == CMD_SET_BREAK:
                # func name: 'None': match anything. Empty: match global, specified: only method context.
                # command to add some breakpoint.
                # text is file\tline. Add to breakpoints dictionary
                suspend_policy = "NONE" # Can be 'NONE' or 'ALL'
                is_logpoint = False
                hit_condition = None
                if py_db._set_breakpoints_with_id:
                    try:
                        try:
                            breakpoint_id, type, file, line, func_name, condition, expression, hit_condition, is_logpoint, suspend_policy = text.split('\t', 9)
                        except ValueError: # not enough values to unpack
                            # No suspend_policy passed (use default).
                            breakpoint_id, type, file, line, func_name, condition, expression, hit_condition, is_logpoint = text.split('\t', 8)
                        is_logpoint = is_logpoint == 'True'
                    except ValueError: # not enough values to unpack
                        breakpoint_id, type, file, line, func_name, condition, expression = text.split('\t', 6)

                    breakpoint_id = int(breakpoint_id)
                    line = int(line)

                    # We must restore new lines and tabs as done in
                    # AbstractDebugTarget.breakpointAdded
                    condition = condition.replace("@_@NEW_LINE_CHAR@_@", '\n').\
                        replace("@_@TAB_CHAR@_@", '\t').strip()

                    expression = expression.replace("@_@NEW_LINE_CHAR@_@", '\n').\
                        replace("@_@TAB_CHAR@_@", '\t').strip()
                else:
                    # Note: this else should be removed after PyCharm migrates to setting
                    # breakpoints by id (and ideally also provides func_name).
                    type, file, line, func_name, suspend_policy, condition, expression = text.split('\t', 6)
                    # If we don't have an id given for each breakpoint, consider
                    # the id to be the line.
                    breakpoint_id = line = int(line)

                    condition = condition.replace("@_@NEW_LINE_CHAR@_@", '\n'). \
                        replace("@_@TAB_CHAR@_@", '\t').strip()

                    expression = expression.replace("@_@NEW_LINE_CHAR@_@", '\n'). \
                        replace("@_@TAB_CHAR@_@", '\t').strip()

                if not IS_PY3K:  # In Python 3, the frame object will have unicode for the file, whereas on python 2 it has a byte-array encoded with the filesystem encoding.
                    file = file.encode(file_system_encoding)

                file = pydevd_file_utils.norm_file_to_server(file)

                if not pydevd_file_utils.exists(file):
                    sys.stderr.write('pydev debugger: warning: trying to add breakpoint'\
                        ' to file that does not exist: %s (will have no effect)\n' % (file,))
                    sys.stderr.flush()


                if condition is not None and (len(condition) <= 0 or condition == "None"):
                    condition = None

                if expression is not None and (len(expression) <= 0 or expression == "None"):
                    expression = None

                if hit_condition is not None and (len(hit_condition) <= 0 or hit_condition == "None"):
                    hit_condition = None

                if type == 'python-line':
                    breakpoint = LineBreakpoint(line, condition, func_name, expression, suspend_policy, hit_condition=hit_condition, is_logpoint=is_logpoint)
                    breakpoints = py_db.breakpoints
                    file_to_id_to_breakpoint = py_db.file_to_id_to_line_breakpoint
                    supported_type = True
                else:
                    result = None
                    plugin = py_db.get_plugin_lazy_init()
                    if plugin is not None:
                        result = plugin.add_breakpoint('add_line_breakpoint', py_db, type, file, line, condition, expression, func_name, hit_condition=hit_condition, is_logpoint=is_logpoint)
                    if result is not None:
                        supported_type = True
                        breakpoint, breakpoints = result
                        file_to_id_to_breakpoint = py_db.file_to_id_to_plugin_breakpoint
                    else:
                        supported_type = False

                if not supported_type:
                    raise NameError(type)

                if DebugInfoHolder.DEBUG_TRACE_BREAKPOINTS > 0:
                    pydev_log.debug('Added breakpoint:%s - line:%s - func_name:%s\n' % (file, line, func_name.encode('utf-8')))
                    sys.stderr.flush()

                if file in file_to_id_to_breakpoint:
                    id_to_pybreakpoint = file_to_id_to_breakpoint[file]
                else:
                    id_to_pybreakpoint = file_to_id_to_breakpoint[file] = {}

                id_to_pybreakpoint[breakpoint_id] = breakpoint
                py_db.consolidate_breakpoints(file, id_to_pybreakpoint, breakpoints)
                if py_db.plugin is not None:
                    py_db.has_plugin_line_breaks = py_db.plugin.has_line_breaks()

                py_db.on_breakpoints_changed()

            elif cmd_id == CMD_REMOVE_BREAK:
                #command to remove some breakpoint
                #text is type\file\tid. Remove from breakpoints dictionary
                breakpoint_type, file, breakpoint_id = text.split('\t', 2)

                if not IS_PY3K:  # In Python 3, the frame object will have unicode for the file, whereas on python 2 it has a byte-array encoded with the filesystem encoding.
                    file = file.encode(file_system_encoding)

                file = pydevd_file_utils.norm_file_to_server(file)

                try:
                    breakpoint_id = int(breakpoint_id)
                except ValueError:
                    pydev_log.error('Error removing breakpoint. Expected breakpoint_id to be an int. Found: %s' % (breakpoint_id,))

                else:
                    file_to_id_to_breakpoint = None
                    if breakpoint_type == 'python-line':
                        breakpoints = py_db.breakpoints
                        file_to_id_to_breakpoint = py_db.file_to_id_to_line_breakpoint
                    elif py_db.get_plugin_lazy_init() is not None:
                        result = py_db.plugin.get_breakpoints(py_db, breakpoint_type)
                        if result is not None:
                            file_to_id_to_breakpoint = py_db.file_to_id_to_plugin_breakpoint
                            breakpoints = result

                    if file_to_id_to_breakpoint is None:
                        pydev_log.error('Error removing breakpoint. Cant handle breakpoint of type %s' % breakpoint_type)
                    else:
                        try:
                            id_to_pybreakpoint = file_to_id_to_breakpoint.get(file, {})
                            if DebugInfoHolder.DEBUG_TRACE_BREAKPOINTS > 0:
                                existing = id_to_pybreakpoint[breakpoint_id]
                                sys.stderr.write('Removed breakpoint:%s - line:%s - func_name:%s (id: %s)\n' % (
                                    file, existing.line, existing.func_name.encode('utf-8'), breakpoint_id))

                            del id_to_pybreakpoint[breakpoint_id]
                            py_db.consolidate_breakpoints(file, id_to_pybreakpoint, breakpoints)
                            if py_db.plugin is not None:
                                py_db.has_plugin_line_breaks = py_db.plugin.has_line_breaks()

                        except KeyError:
                            pydev_log.error("Error removing breakpoint: Breakpoint id not found: %s id: %s. Available ids: %s\n" % (
                                file, breakpoint_id, dict_keys(id_to_pybreakpoint)))

                py_db.on_breakpoints_changed(removed=True)

            elif cmd_id == CMD_EVALUATE_EXPRESSION or cmd_id == CMD_EXEC_EXPRESSION:
                #command to evaluate the given expression
                #text is: thread\tstackframe\tLOCAL\texpression
                temp_name = ""
                try:
                    thread_id, frame_id, scope, expression, trim, temp_name = text.split('\t', 5)
                except ValueError:
                    thread_id, frame_id, scope, expression, trim = text.split('\t', 4)
                int_cmd = InternalEvaluateExpression(seq, thread_id, frame_id, expression,
                    cmd_id == CMD_EXEC_EXPRESSION, int(trim) == 1, temp_name)
                py_db.post_internal_command(int_cmd, thread_id)

            elif cmd_id == CMD_CONSOLE_EXEC:
                #command to exec expression in console, in case expression is only partially valid 'False' is returned
                #text is: thread\tstackframe\tLOCAL\texpression

                thread_id, frame_id, scope, expression = text.split('\t', 3)

                int_cmd = InternalConsoleExec(seq, thread_id, frame_id, expression)
                py_db.post_internal_command(int_cmd, thread_id)

            elif cmd_id == CMD_SET_PY_EXCEPTION:
                # Command which receives set of exceptions on which user wants to break the debugger
                # text is:
                #
                # break_on_uncaught;
                # break_on_caught;
                # skip_on_exceptions_thrown_in_same_context;
                # ignore_exceptions_thrown_in_lines_with_ignore_exception;
                # ignore_libraries;
                # TypeError;ImportError;zipimport.ZipImportError;
                #
                # i.e.: true;true;true;true;true;TypeError;ImportError;zipimport.ZipImportError;
                #
                # This API is optional and works 'in bulk' -- it's possible
                # to get finer-grained control with CMD_ADD_EXCEPTION_BREAK/CMD_REMOVE_EXCEPTION_BREAK
                # which allows setting caught/uncaught per exception.
                splitted = text.split(';')
                py_db.break_on_uncaught_exceptions = {}
                py_db.break_on_caught_exceptions = {}
                if len(splitted) >= 5:
                    if splitted[0] == 'true':
                        break_on_uncaught = True
                    else:
                        break_on_uncaught = False

                    if splitted[1] == 'true':
                        break_on_caught = True
                    else:
                        break_on_caught = False

                    if splitted[2] == 'true':
                        py_db.skip_on_exceptions_thrown_in_same_context = True
                    else:
                        py_db.skip_on_exceptions_thrown_in_same_context = False

                    if splitted[3] == 'true':
                        py_db.ignore_exceptions_thrown_in_lines_with_ignore_exception = True
                    else:
                        py_db.ignore_exceptions_thrown_in_lines_with_ignore_exception = False

                    if splitted[4] == 'true':
                        ignore_libraries = True
                    else:
                        ignore_libraries = False

                    for exception_type in splitted[5:]:
                        exception_type = exception_type.strip()
                        if not exception_type:
                            continue

                        exception_breakpoint = py_db.add_break_on_exception(
                            exception_type,
                            condition=None,
                            expression=None,
                            notify_on_handled_exceptions=break_on_caught,
                            notify_on_unhandled_exceptions=break_on_uncaught,
                            notify_on_first_raise_only=True,
                            ignore_libraries=ignore_libraries,
                        )

                    py_db.on_breakpoints_changed()

                else:
                    sys.stderr.write("Error when setting exception list. Received: %s\n" % (text,))

            elif cmd_id == CMD_GET_FILE_CONTENTS:

                if not IS_PY3K:  # In Python 3, the frame object will have unicode for the file, whereas on python 2 it has a byte-array encoded with the filesystem encoding.
                    text = text.encode(file_system_encoding)

                if os.path.exists(text):
                    f = open(text, 'r')
                    try:
                        source = f.read()
                    finally:
                        f.close()
                    cmd = py_db.cmd_factory.make_get_file_contents(seq, source)

            elif cmd_id == CMD_SET_PROPERTY_TRACE:
                # Command which receives whether to trace property getter/setter/deleter
                # text is feature_state(true/false);disable_getter/disable_setter/disable_deleter
                if text != "":
                    splitted = text.split(';')
                    if len(splitted) >= 3:
                        if py_db.disable_property_trace is False and splitted[0] == 'true':
                            # Replacing property by custom property only when the debugger starts
                            pydevd_traceproperty.replace_builtin_property()
                            py_db.disable_property_trace = True
                        # Enable/Disable tracing of the property getter
                        if splitted[1] == 'true':
                            py_db.disable_property_getter_trace = True
                        else:
                            py_db.disable_property_getter_trace = False
                        # Enable/Disable tracing of the property setter
                        if splitted[2] == 'true':
                            py_db.disable_property_setter_trace = True
                        else:
                            py_db.disable_property_setter_trace = False
                        # Enable/Disable tracing of the property deleter
                        if splitted[3] == 'true':
                            py_db.disable_property_deleter_trace = True
                        else:
                            py_db.disable_property_deleter_trace = False
                else:
                    # User hasn't configured any settings for property tracing
                    pass

            elif cmd_id == CMD_ADD_EXCEPTION_BREAK:
                # Note that this message has some idiosyncrasies...
                #
                # notify_on_handled_exceptions can be 0, 1 or 2
                # 0 means we should not stop on handled exceptions.
                # 1 means we should stop on handled exceptions showing it on all frames where the exception passes.
                # 2 means we should stop on handled exceptions but we should only notify about it once.
                #
                # To ignore_libraries properly, besides setting ignore_libraries to 1, the IDE_PROJECT_ROOTS environment
                # variable must be set (so, we'll ignore anything not below IDE_PROJECT_ROOTS) -- this is not ideal as
                # the environment variable may not be properly set if it didn't start from the debugger (we should
                # create a custom message for that).
                #
                # There are 2 global settings which can only be set in CMD_SET_PY_EXCEPTION. Namely:
                #
                # py_db.skip_on_exceptions_thrown_in_same_context
                # - If True, we should only show the exception in a caller, not where it was first raised.
                #
                # py_db.ignore_exceptions_thrown_in_lines_with_ignore_exception
                # - If True exceptions thrown in lines with '@IgnoreException' will not be shown.

                condition = ""
                expression = ""
                if text.find('\t') != -1:
                    try:
                        exception, condition, expression, notify_on_handled_exceptions, notify_on_unhandled_exceptions, ignore_libraries = text.split('\t', 5)
                    except:
                        exception, notify_on_handled_exceptions, notify_on_unhandled_exceptions, ignore_libraries = text.split('\t', 3)
                else:
                    exception, notify_on_handled_exceptions, notify_on_unhandled_exceptions, ignore_libraries = text, 0, 0, 0

                condition = condition.replace("@_@NEW_LINE_CHAR@_@", '\n').replace("@_@TAB_CHAR@_@", '\t').strip()

                if condition is not None and (len(condition) == 0 or condition == "None"):
                    condition = None

                expression = expression.replace("@_@NEW_LINE_CHAR@_@", '\n').replace("@_@TAB_CHAR@_@", '\t').strip()

                if expression is not None and (len(expression) == 0 or expression == "None"):
                    expression = None

                if exception.find('-') != -1:
                    breakpoint_type, exception = exception.split('-')
                else:
                    breakpoint_type = 'python'

                if breakpoint_type == 'python':
                    exception_breakpoint = py_db.add_break_on_exception(
                        exception,
                        condition=condition,
                        expression=expression,
                        notify_on_handled_exceptions=int(notify_on_handled_exceptions) > 0,
                        notify_on_unhandled_exceptions=int(notify_on_unhandled_exceptions) == 1,
                        notify_on_first_raise_only=int(notify_on_handled_exceptions) == 2,
                        ignore_libraries=int(ignore_libraries) > 0
                    )

                    if exception_breakpoint is not None:
                        py_db.on_breakpoints_changed()
                else:
                    supported_type = False
                    plugin = py_db.get_plugin_lazy_init()
                    if plugin is not None:
                        supported_type = plugin.add_breakpoint('add_exception_breakpoint', py_db, breakpoint_type, exception)

                    if supported_type:
                        py_db.has_plugin_exception_breaks = py_db.plugin.has_exception_breaks()
                        py_db.on_breakpoints_changed()
                    else:
                        raise NameError(breakpoint_type)



            elif cmd_id == CMD_REMOVE_EXCEPTION_BREAK:
                exception = text
                if exception.find('-') != -1:
                    exception_type, exception = exception.split('-')
                else:
                    exception_type = 'python'

                if exception_type == 'python':
                    try:
                        cp = py_db.break_on_uncaught_exceptions.copy()
                        cp.pop(exception, None)
                        py_db.break_on_uncaught_exceptions = cp

                        cp = py_db.break_on_caught_exceptions.copy()
                        cp.pop(exception, None)
                        py_db.break_on_caught_exceptions = cp
                    except:
                        pydev_log.debug("Error while removing exception %s"%sys.exc_info()[0])
                else:
                    supported_type = False

                    # I.e.: no need to initialize lazy (if we didn't have it in the first place, we can't remove
                    # anything from it anyways).
                    plugin = py_db.plugin
                    if plugin is not None:
                        supported_type = plugin.remove_exception_breakpoint(py_db, exception_type, exception)

                    if supported_type:
                        py_db.has_plugin_exception_breaks = py_db.plugin.has_exception_breaks()
                    else:
                        raise NameError(exception_type)

                py_db.on_breakpoints_changed(remove=True)

            elif cmd_id == CMD_LOAD_SOURCE:
                path = text
                try:
                    if not IS_PY3K:  # In Python 3, the frame object will have unicode for the file, whereas on python 2 it has a byte-array encoded with the filesystem encoding.
                        path = path.encode(file_system_encoding)

                    path = pydevd_file_utils.norm_file_to_server(path)
                    f = open(path, 'r')
                    source = f.read()
                    cmd = py_db.cmd_factory.make_load_source_message(seq, source)
                except:
                    cmd = py_db.cmd_factory.make_error_message(seq, pydevd_tracing.get_exception_traceback_str())

            elif cmd_id == CMD_ADD_DJANGO_EXCEPTION_BREAK:
                exception = text
                plugin = py_db.get_plugin_lazy_init()
                if plugin is not None:
                    plugin.add_breakpoint('add_exception_breakpoint', py_db, 'django', exception)
                    py_db.has_plugin_exception_breaks = py_db.plugin.has_exception_breaks()
                    py_db.on_breakpoints_changed()

            elif cmd_id == CMD_REMOVE_DJANGO_EXCEPTION_BREAK:
                exception = text

                # I.e.: no need to initialize lazy (if we didn't have it in the first place, we can't remove
                # anything from it anyways).
                plugin = py_db.plugin
                if plugin is not None:
                    plugin.remove_exception_breakpoint(py_db, 'django', exception)
                    py_db.has_plugin_exception_breaks = py_db.plugin.has_exception_breaks()
                py_db.on_breakpoints_changed(removed=True)

            elif cmd_id == CMD_EVALUATE_CONSOLE_EXPRESSION:
                # Command which takes care for the debug console communication
                if text != "":
                    thread_id, frame_id, console_command = text.split('\t', 2)
                    console_command, line = console_command.split('\t')

                    if console_command == 'EVALUATE':
                        int_cmd = InternalEvaluateConsoleExpression(
                            seq, thread_id, frame_id, line, buffer_output=True)

                    elif console_command == 'EVALUATE_UNBUFFERED':
                        int_cmd = InternalEvaluateConsoleExpression(
                            seq, thread_id, frame_id, line, buffer_output=False)

                    elif console_command == 'GET_COMPLETIONS':
                        int_cmd = InternalConsoleGetCompletions(seq, thread_id, frame_id, line)

                    else:
                        raise ValueError('Unrecognized command: %s' % (console_command,))

                    py_db.post_internal_command(int_cmd, thread_id)

            elif cmd_id == CMD_RUN_CUSTOM_OPERATION:
                # Command which runs a custom operation
                if text != "":
                    try:
                        location, custom = text.split('||', 1)
                    except:
                        sys.stderr.write('Custom operation now needs a || separator. Found: %s\n' % (text,))
                        raise

                    thread_id, frame_id, scopeattrs = location.split('\t', 2)

                    if scopeattrs.find('\t') != -1:  # there are attributes beyond scope
                        scope, attrs = scopeattrs.split('\t', 1)
                    else:
                        scope, attrs = (scopeattrs, None)

                    # : style: EXECFILE or EXEC
                    # : encoded_code_or_file: file to execute or code
                    # : fname: name of function to be executed in the resulting namespace
                    style, encoded_code_or_file, fnname = custom.split('\t', 3)
                    int_cmd = InternalRunCustomOperation(seq, thread_id, frame_id, scope, attrs,
                                                         style, encoded_code_or_file, fnname)
                    py_db.post_internal_command(int_cmd, thread_id)

            elif cmd_id == CMD_IGNORE_THROWN_EXCEPTION_AT:
                if text:
                    replace = 'REPLACE:'  # Not all 3.x versions support u'REPLACE:', so, doing workaround.
                    if not IS_PY3K:
                        replace = unicode(replace)

                    if text.startswith(replace):
                        text = text[8:]
                        py_db.filename_to_lines_where_exceptions_are_ignored.clear()

                    if text:
                        for line in text.split('||'):  # Can be bulk-created (one in each line)
                            filename, line_number = line.split('|')
                            if not IS_PY3K:
                                filename = filename.encode(file_system_encoding)

                            filename = pydevd_file_utils.norm_file_to_server(filename)

                            if os.path.exists(filename):
                                lines_ignored = py_db.filename_to_lines_where_exceptions_are_ignored.get(filename)
                                if lines_ignored is None:
                                    lines_ignored = py_db.filename_to_lines_where_exceptions_are_ignored[filename] = {}
                                lines_ignored[int(line_number)] = 1
                            else:
                                sys.stderr.write('pydev debugger: warning: trying to ignore exception thrown'\
                                    ' on file that does not exist: %s (will have no effect)\n' % (filename,))

            elif cmd_id == CMD_ENABLE_DONT_TRACE:
                if text:
                    true_str = 'true'  # Not all 3.x versions support u'str', so, doing workaround.
                    if not IS_PY3K:
                        true_str = unicode(true_str)

                    mode = text.strip() == true_str
                    pydevd_dont_trace.trace_filter(mode)

            elif cmd_id == CMD_REDIRECT_OUTPUT:
                if text:
                    py_db.enable_output_redirection('STDOUT' in text, 'STDERR' in text)

            elif cmd_id == CMD_GET_NEXT_STATEMENT_TARGETS:
                thread_id, frame_id = text.split('\t', 1)

                int_cmd = InternalGetNextStatementTargets(seq, thread_id, frame_id)
                py_db.post_internal_command(int_cmd, thread_id)

            elif cmd_id == CMD_SET_PROJECT_ROOTS:
                pydevd_utils.set_project_roots(text.split(u'\t'))

            elif cmd_id == CMD_THREAD_DUMP_TO_STDERR:
                pydevd_utils.dump_threads()

            elif cmd_id == CMD_STOP_ON_START:
                py_db.stop_on_start = text.strip() in ('True', 'true', '1')
                
            elif cmd_id == CMD_PYDEVD_JSON_CONFIG:
                # Expected to receive a json string as:
                # {
                #     'skip_suspend_on_breakpoint_exception': [<exception names where we should suspend>],
                #     'skip_print_breakpoint_exception': [<exception names where we should print>],
                #     'multi_threads_single_notification': bool,
                # }
                msg = json.loads(text.strip())
                if 'skip_suspend_on_breakpoint_exception' in msg:
                    py_db.skip_suspend_on_breakpoint_exception = tuple(
                        get_exception_class(x) for x in msg['skip_suspend_on_breakpoint_exception'])
                
                if 'skip_print_breakpoint_exception' in msg:
                    py_db.skip_print_breakpoint_exception = tuple(
                        get_exception_class(x) for x in msg['skip_print_breakpoint_exception'])
                    
                if 'multi_threads_single_notification' in msg:
                    py_db.multi_threads_single_notification = msg['multi_threads_single_notification']

            elif cmd_id == CMD_GET_EXCEPTION_DETAILS:
                thread_id = text
                t = pydevd_find_thread_by_id(thread_id)
                frame = None
                if t and not getattr(t, 'pydev_do_not_trace', None):
                    additional_info = set_additional_thread_info(t)
                    frame = additional_info.get_topmost_frame(t)
                try:
                    cmd = py_db.cmd_factory.make_get_exception_details_message(seq, thread_id, frame)
                finally:
                    frame = None
                    t = None

            else:
                #I have no idea what this is all about
                cmd = py_db.cmd_factory.make_error_message(seq, "unexpected command " + str(cmd_id))

            if cmd is not None:
                py_db.writer.add_command(cmd)
                del cmd

        except Exception:
            traceback.print_exc()
            try:
                from StringIO import StringIO
            except ImportError:
                from io import StringIO
            stream = StringIO()
            traceback.print_exc(file=stream)
            cmd = py_db.cmd_factory.make_error_message(
                seq,
                "Unexpected exception in process_net_command.\nInitial params: %s. Exception: %s" % (
                    ((cmd_id, seq, text), stream.getvalue())
                )
            )

            py_db.writer.add_command(cmd)
    finally:
        py_db._main_lock.release()
    def __call__(self, frame, event, arg):
        ''' This is the callback used when we enter some context in the debugger.

        We also decorate the thread we are in with info about the debugging.
        The attributes added are:
            pydev_state
            pydev_step_stop
            pydev_step_cmd
            pydev_notify_kill

        :param PyDB py_db:
            This is the global debugger (this method should actually be added as a method to it).
        '''
        # IFDEF CYTHON
        # cdef str filename;
        # cdef str base;
        # cdef int pydev_step_cmd;
        # cdef tuple frame_cache_key;
        # cdef dict cache_skips;
        # cdef bint is_stepping;
        # cdef tuple abs_path_real_path_and_base;
        # cdef PyDBAdditionalThreadInfo additional_info;
        # ENDIF
        # print('ENTER: trace_dispatch', frame.f_code.co_filename, frame.f_lineno, event, frame.f_code.co_name)
        py_db, t, additional_info, cache_skips, frame_skips_cache = self._args
        pydev_step_cmd = additional_info.pydev_step_cmd
        is_stepping = pydev_step_cmd != -1

        try:
            if py_db._finish_debugging_session:
                if not py_db._termination_event_set:
                    # that was not working very well because jython gave some socket errors
                    try:
                        if py_db.output_checker_thread is None:
                            kill_all_pydev_threads()
                    except:
                        traceback.print_exc()
                    py_db._termination_event_set = True
                if event != 'call': frame.f_trace = NO_FTRACE
                return None

            # if thread is not alive, cancel trace_dispatch processing
            if not is_thread_alive(t):
                py_db.notify_thread_not_alive(get_current_thread_id(t))
                if event != 'call': frame.f_trace = NO_FTRACE
                return None  # suspend tracing

            if py_db.thread_analyser is not None:
                py_db.thread_analyser.log_event(frame)

            if py_db.asyncio_analyser is not None:
                py_db.asyncio_analyser.log_event(frame)

            # Note: it's important that the context name is also given because we may hit something once
            # in the global context and another in the local context.
            frame_cache_key = (frame.f_code.co_firstlineno, frame.f_code.co_name, frame.f_code.co_filename)
            if not is_stepping and frame_cache_key in cache_skips:
                # print('skipped: trace_dispatch (cache hit)', frame_cache_key, frame.f_lineno, event, frame.f_code.co_name)
                if event != 'call': frame.f_trace = NO_FTRACE
                return None

            try:
                # Make fast path faster!
                abs_path_real_path_and_base = NORM_PATHS_AND_BASE_CONTAINER[frame.f_code.co_filename]
            except:
                abs_path_real_path_and_base = get_abs_path_real_path_and_base_from_frame(frame)

            filename = abs_path_real_path_and_base[1]
            file_type = get_file_type(abs_path_real_path_and_base[-1])  # we don't want to debug threading or anything related to pydevd

            if file_type is not None:
                if file_type == 1:  # inlining LIB_FILE = 1
                    if not py_db.in_project_scope(filename):
                        # print('skipped: trace_dispatch (not in scope)', abs_path_real_path_and_base[-1], frame.f_lineno, event, frame.f_code.co_name, file_type)
                        cache_skips[frame_cache_key] = 1
                        if event != 'call': frame.f_trace = NO_FTRACE
                        return None
                else:
                    # print('skipped: trace_dispatch', abs_path_real_path_and_base[-1], frame.f_lineno, event, frame.f_code.co_name, file_type)
                    cache_skips[frame_cache_key] = 1
                    if event != 'call': frame.f_trace = NO_FTRACE
                    return None

            if is_stepping:
                if py_db.is_filter_enabled and py_db.is_ignored_by_filters(filename):
                    # ignore files matching stepping filters
                    if event != 'call': frame.f_trace = NO_FTRACE
                    return None
                if py_db.is_filter_libraries and not py_db.in_project_scope(filename):
                    # ignore library files while stepping
                    if event != 'call': frame.f_trace = NO_FTRACE
                    return None

            # print('trace_dispatch', base, frame.f_lineno, event, frame.f_code.co_name, file_type)
            if additional_info.is_tracing:
                if event != 'call': frame.f_trace = NO_FTRACE
                return None  # we don't wan't to trace code invoked from pydevd_frame.trace_dispatch

            # Just create PyDBFrame directly (removed support for Python versions < 2.5, which required keeping a weak
            # reference to the frame).
            ret = PyDBFrame(
                (
                    py_db, filename, additional_info, t, frame_skips_cache, frame_cache_key,
                )
            ).trace_dispatch(frame, event, arg)
            if ret is None:
                cache_skips[frame_cache_key] = 1
                if event != 'call': frame.f_trace = NO_FTRACE
                return None

            # IFDEF CYTHON
            # ret = SafeCallWrapper(ret)
            # ENDIF
            frame.f_trace = ret  # Make sure we keep the returned tracer.
            return ret

        except SystemExit:
            if event != 'call': frame.f_trace = NO_FTRACE
            return None

        except Exception:
            if py_db._finish_debugging_session:
                if event != 'call': frame.f_trace = NO_FTRACE
                return None  # Don't log errors when we're shutting down.
            # Log it
            try:
                if traceback is not None:
                    # This can actually happen during the interpreter shutdown in Python 2.7
                    traceback.print_exc()
            except:
                # Error logging? We're really in the interpreter shutdown...
                # (https://github.com/fabioz/PyDev.Debugger/issues/8)
                pass
            if event != 'call': frame.f_trace = NO_FTRACE
            return None
Пример #29
0
def find_frame(thread_id, frame_id):
    """ returns a frame on the thread that has a given frame_id """
    try:
        curr_thread_id = get_current_thread_id(threading.currentThread())
        if thread_id != curr_thread_id:
            try:
                return get_custom_frame(
                    thread_id, frame_id
                )  # I.e.: thread_id could be a stackless frame id + thread_id.
            except:
                pass

            raise VariableError(
                "find_frame: must execute on same thread (%s != %s)" %
                (thread_id, curr_thread_id))

        lookingFor = int(frame_id)

        if AdditionalFramesContainer.additional_frames:
            if thread_id in AdditionalFramesContainer.additional_frames:
                frame = AdditionalFramesContainer.additional_frames[
                    thread_id].get(lookingFor)

                if frame is not None:
                    return frame

        curFrame = get_frame()
        if frame_id == "*":
            return curFrame  # any frame is specified with "*"

        frameFound = None

        for frame in _iter_frames(curFrame):
            if lookingFor == id(frame):
                frameFound = frame
                del frame
                break

            del frame

        # Important: python can hold a reference to the frame from the current context
        # if an exception is raised, so, if we don't explicitly add those deletes
        # we might have those variables living much more than we'd want to.

        # I.e.: sys.exc_info holding reference to frame that raises exception (so, other places
        # need to call sys.exc_clear())
        del curFrame

        if frameFound is None:
            msgFrames = ''
            i = 0

            for frame in _iter_frames(get_frame()):
                i += 1
                msgFrames += str(id(frame))
                if i % 5 == 0:
                    msgFrames += '\n'
                else:
                    msgFrames += '  -  '


# Note: commented this error message out (it may commonly happen
# if a message asking for a frame is issued while a thread is paused
# but the thread starts running before the message is actually
# handled).
# Leaving code to uncomment during tests.
#             err_msg = '''find_frame: frame not found.
#     Looking for thread_id:%s, frame_id:%s
#     Current     thread_id:%s, available frames:
#     %s\n
#     ''' % (thread_id, lookingFor, curr_thread_id, msgFrames)
#
#             sys.stderr.write(err_msg)
            return None

        return frameFound
    except:
        import traceback
        traceback.print_exc()
        return None