예제 #1
0
def test_zip_paths(tmpdir):
    import pydevd_file_utils
    import sys
    import zipfile

    for i, zip_basename in enumerate(('MY1.zip', 'my2.egg!')):
        zipfile_path = str(tmpdir.join(zip_basename))
        zip_file = zipfile.ZipFile(zipfile_path, 'w')
        zip_file.writestr('zipped%s/__init__.py' % (i, ), '')
        zip_file.writestr('zipped%s/zipped_contents.py' % (i, ),
                          'def call_in_zip():\n    return 1')
        zip_file.close()

        sys.path.append(zipfile_path)
        try:
            import importlib
        except ImportError:
            __import__('zipped%s' % (i, ))  # Py2.6 does not have importlib
        else:
            importlib.import_module('zipped%s' %
                                    (i, ))  # Check that it's importable.

        # Check that we can deal with the zip path.
        assert pydevd_file_utils.exists(zipfile_path)
        abspath, realpath, basename = pydevd_file_utils.get_abs_path_real_path_and_base_from_file(
            zipfile_path)
        if IS_WINDOWS:
            assert abspath == zipfile_path.lower()
            assert basename == zip_basename.lower()
        else:
            assert abspath == zipfile_path
            assert basename == zip_basename

        # Check that we can deal with zip contents.
        for path in [
                zipfile_path + '/zipped%s/__init__.py' % (i, ),
                zipfile_path + '/zipped%s/zipped_contents.py' % (i, ),
                zipfile_path + '\\zipped%s\\__init__.py' % (i, ),
                zipfile_path + '\\zipped%s\\zipped_contents.py' % (i, ),
        ]:
            assert pydevd_file_utils.exists(
                path), 'Expected exists to return True for path:\n%s' % (
                    path, )
            abspath, realpath, basename = pydevd_file_utils.get_abs_path_real_path_and_base_from_file(
                path)
            assert pydevd_file_utils.exists(
                abspath), 'Expected exists to return True for path:\n%s' % (
                    abspath, )
            assert pydevd_file_utils.exists(
                realpath), 'Expected exists to return True for path:\n%s' % (
                    realpath, )

        assert zipfile_path in pydevd_file_utils._ZIP_SEARCH_CACHE, '%s not in %s' % (
            zipfile_path, '\n'.join(
                sorted(pydevd_file_utils._ZIP_SEARCH_CACHE.keys())))
def _get_template_file_name(frame):
    try:
        if IS_DJANGO19_OR_HIGHER:
            # The Node source was removed since Django 1.9
            if dict_contains(frame.f_locals, 'context'):
                context = frame.f_locals['context']
                if hasattr(context, 'template') and hasattr(context.template, 'origin') and \
                        hasattr(context.template.origin, 'name'):
                    return context.template.origin.name
            return None

        source = _get_source_django_18_or_lower(frame)
        if source is None:
            pydev_log.debug("Source is None\n")
            return None
        fname = source[0].name

        if fname == '<unknown source>':
            pydev_log.debug("Source name is %s\n" % fname)
            return None
        else:
            abs_path_real_path_and_base = get_abs_path_real_path_and_base_from_file(
                fname)
            return abs_path_real_path_and_base[1]
    except:
        pydev_log.debug(traceback.format_exc())
        return None
예제 #3
0
def _get_jinja2_template_filename(frame):
    if dict_contains(frame.f_globals, '__jinja_template__'):
        fname = frame.f_globals['__jinja_template__'].filename
        abs_path_real_path_and_base = get_abs_path_real_path_and_base_from_file(
            fname)
        return abs_path_real_path_and_base[1]
    return None
예제 #4
0
def _get_jinja2_template_filename(frame):
    if '__jinja_template__' in frame.f_globals:
        fname = _convert_to_str(frame.f_globals['__jinja_template__'].filename)
        abs_path_real_path_and_base = get_abs_path_real_path_and_base_from_file(
            fname)
        return abs_path_real_path_and_base[1]
    return None
예제 #5
0
파일: api.py 프로젝트: int19h/ptvsd
    def debug(address, log_dir=None, multiprocess=True):
        if log_dir:
            log.log_dir = log_dir

        log.to_file(prefix="ptvsd.server")
        log.describe_environment("ptvsd.server debug start environment:")
        log.debug("{0}{1!r}", func.__name__, (address, log_dir, multiprocess))

        if is_attached():
            log.info("{0}() ignored - already attached.", func.__name__)
            return options.host, options.port

        # Ensure port is int
        if address is not options:
            host, port = address
            options.host, options.port = (host, int(port))

        if multiprocess is not options:
            options.multiprocess = multiprocess

        ptvsd_path, _, _ = get_abs_path_real_path_and_base_from_file(ptvsd.__file__)
        ptvsd_path = os.path.dirname(ptvsd_path)
        start_patterns = (ptvsd_path,)
        end_patterns = ("ptvsd_launcher.py",)
        log.info(
            "Won't trace filenames starting with: {0!j}\n"
            "Won't trace filenames ending with: {1!j}",
            start_patterns,
            end_patterns,
        )

        try:
            return func(start_patterns, end_patterns)
        except Exception:
            raise log.exception("{0}() failed:", func.__name__, level="info")
예제 #6
0
파일: api.py 프로젝트: jhutchings1/debugpy
    def debug(address, **kwargs):
        if _settrace.called:
            raise RuntimeError("this process already has a debug adapter")

        try:
            _, port = address
        except Exception:
            port = address
            address = ("127.0.0.1", port)
        try:
            port.__index__()  # ensure it's int-like
        except Exception:
            raise ValueError("expected port or (host, port)")
        if not (0 <= port < 2**16):
            raise ValueError("invalid port number")

        ensure_logging()
        log.debug("{0}({1!r}, **{2!r})", func.__name__, address, kwargs)
        log.info("Initial debug configuration: {0!j}", _config)

        settrace_kwargs = {
            "suspend": False,
            "patch_multiprocessing": _config.get("subProcess", True),
        }

        debugpy_path, _, _ = get_abs_path_real_path_and_base_from_file(
            debugpy.__file__)
        debugpy_path = os.path.dirname(debugpy_path)
        settrace_kwargs["dont_trace_start_patterns"] = (debugpy_path, )
        settrace_kwargs["dont_trace_end_patterns"] = ("debugpy_launcher.py", )

        try:
            return func(address, settrace_kwargs, **kwargs)
        except Exception:
            log.reraise_exception("{0}() failed:", func.__name__, level="info")
예제 #7
0
def _get_template_file_name(frame):
    try:
        if IS_DJANGO19_OR_HIGHER:
            # The Node source was removed since Django 1.9
            if dict_contains(frame.f_locals, 'context'):
                context = frame.f_locals['context']
                if hasattr(context, 'template') and hasattr(context.template, 'origin') and \
                        hasattr(context.template.origin, 'name'):
                    return context.template.origin.name
            return None

        source = _get_source_django_18_or_lower(frame)
        if source is None:
            pydev_log.debug("Source is None\n")
            return None
        fname = source[0].name

        if fname == '<unknown source>':
            pydev_log.debug("Source name is %s\n" % fname)
            return None
        else:
            abs_path_real_path_and_base = get_abs_path_real_path_and_base_from_file(fname)
            return abs_path_real_path_and_base[1]
    except:
        pydev_log.debug(traceback.format_exc())
        return None
def test_relative_paths(tmpdir):
    '''
    We need to check that we can deal with relative paths.

    Use cases:
        - Relative path of file that does not exist:
            Use case is a cython-generated module which is generated from a .pyx which
            is not distributed. In this case we need to resolve the file to a library path file.

        - Relative path of a file that exists but not when resolved from the working directory:
            Use case is a cython-generated module which is generated from a .pyx which is
            distributed. In this case we need to resolve to the real file based on the sys.path
            entries.
    '''
    import pydevd_file_utils
    import sys
    sys.path.append(str(tmpdir))
    try:
        pydevd_file_utils.NORM_PATHS_AND_BASE_CONTAINER.clear()
        pydevd_file_utils.NORM_PATHS_CONTAINER.clear()
        abs_path = pydevd_file_utils.get_abs_path_real_path_and_base_from_file(
            'my_dir/my_file.pyx')[0]
        assert 'site-packages' in abs_path
        assert os.path.normcase(str(tmpdir)) not in abs_path
        assert not pydevd_file_utils.exists('my_dir/my_file.pyx')

        # If the relative file exists when joined with some entry in the PYTHONPATH we'll consider
        # that the relative path points to that absolute path.
        target_dir = os.path.join(str(tmpdir), 'my_dir')
        os.makedirs(target_dir)
        with open(os.path.join(target_dir, 'my_file.pyx'), 'w') as stream:
            stream.write('empty')

        pydevd_file_utils.NORM_PATHS_AND_BASE_CONTAINER.clear()
        pydevd_file_utils.NORM_PATHS_CONTAINER.clear()
        abs_path = pydevd_file_utils.get_abs_path_real_path_and_base_from_file(
            'my_dir/my_file.pyx')[0]
        assert 'site-packages' not in abs_path
        assert str(tmpdir) in abs_path
        assert pydevd_file_utils.exists('my_dir/my_file.pyx')
    finally:
        sys.path.remove(str(tmpdir))
예제 #9
0
def _get_template_file_name(frame):
    try:
        if IS_DJANGO19:
            # The Node source was removed since Django 1.9
            if 'context' in frame.f_locals:
                context = frame.f_locals['context']
                if hasattr(context, '_has_included_template'):
                    # if there was included template we need to inspect the previous frames and find its name
                    back = frame.f_back
                    while back is not None and frame.f_code.co_name in (
                            'render', '_render'):
                        locals = back.f_locals
                        if 'self' in locals:
                            self = locals['self']
                            if self.__class__.__name__ == 'Template' and hasattr(self, 'origin') and \
                                    hasattr(self.origin, 'name'):
                                return normcase(
                                    _convert_to_str(self.origin.name))
                        back = back.f_back
                else:
                    if hasattr(context, 'template') and hasattr(context.template, 'origin') and \
                            hasattr(context.template.origin, 'name'):
                        return normcase(
                            _convert_to_str(context.template.origin.name))
            return None
        elif IS_DJANGO19_OR_HIGHER:
            # For Django 1.10 and later there is much simpler way to get template name
            if 'self' in frame.f_locals:
                self = frame.f_locals['self']
                if hasattr(self, 'origin') and hasattr(self.origin, 'name'):
                    return normcase(_convert_to_str(self.origin.name))
            return None

        source = _get_source_django_18_or_lower(frame)
        if source is None:
            pydev_log.debug("Source is None\n")
            return None
        fname = _convert_to_str(source[0].name)

        if fname == '<unknown source>':
            pydev_log.debug("Source name is %s\n" % fname)
            return None
        else:
            abs_path_real_path_and_base = get_abs_path_real_path_and_base_from_file(
                fname)
            return abs_path_real_path_and_base[1]
    except:
        pydev_log.debug(traceback.format_exc())
        return None
예제 #10
0
def _get_template_file_name(frame):
    try:
        if IS_DJANGO19:
            # The Node source was removed since Django 1.9
            if 'context' in frame.f_locals:
                context = frame.f_locals['context']
                if hasattr(context, '_has_included_template'):
                    #  if there was included template we need to inspect the previous frames and find its name
                    back = frame.f_back
                    while back is not None and frame.f_code.co_name in ('render', '_render'):
                        locals = back.f_locals
                        if 'self' in locals:
                            self = locals['self']
                            if self.__class__.__name__ == 'Template' and hasattr(self, 'origin') and \
                                    hasattr(self.origin, 'name'):
                                return normcase(self.origin.name)
                        back = back.f_back
                else:
                    if hasattr(context, 'template') and hasattr(context.template, 'origin') and \
                            hasattr(context.template.origin, 'name'):
                        return normcase(context.template.origin.name)
            return None
        elif IS_DJANGO19_OR_HIGHER:
            # For Django 1.10 and later there is much simpler way to get template name
            if 'self' in frame.f_locals:
                self = frame.f_locals['self']
                if hasattr(self, 'origin') and hasattr(self.origin, 'name'):
                    return normcase(self.origin.name)
            return None

        source = _get_source_django_18_or_lower(frame)
        if source is None:
            pydev_log.debug("Source is None\n")
            return None
        fname = source[0].name

        if fname == '<unknown source>':
            pydev_log.debug("Source name is %s\n" % fname)
            return None
        else:
            abs_path_real_path_and_base = get_abs_path_real_path_and_base_from_file(fname)
            return abs_path_real_path_and_base[1]
    except:
        pydev_log.debug(traceback.format_exc())
        return None
예제 #11
0
def _normpath(filename):
    return pydevd_file_utils.get_abs_path_real_path_and_base_from_file(filename)[0]
예제 #12
0
def _get_jinja2_template_filename(frame):
    if '__jinja_template__' in frame.f_globals:
        fname = frame.f_globals['__jinja_template__'].filename
        abs_path_real_path_and_base = get_abs_path_real_path_and_base_from_file(fname)
        return abs_path_real_path_and_base[1]
    return None
예제 #13
0
 def _normpath(self, filename):
     return pydevd_file_utils.get_abs_path_real_path_and_base_from_file(filename)[0]
예제 #14
0
    def trace_dispatch(self, frame, event, arg):
    # ENDIF
        # DEBUG = 'code_to_debug' in frame.f_code.co_filename
        main_debugger, filename, info, thread, frame_skips_cache, frame_cache_key = self._args
        # if DEBUG: print('frame trace_dispatch %s %s %s %s %s' % (frame.f_lineno, frame.f_code.co_name, frame.f_code.co_filename, event, info.pydev_step_cmd))
        try:
            info.is_tracing = True
            line = frame.f_lineno
            line_cache_key = (frame_cache_key, line)

            if main_debugger._finish_debugging_session:
                return None if event == 'call' else NO_FTRACE

            plugin_manager = main_debugger.plugin

            is_exception_event = event == 'exception'
            has_exception_breakpoints = main_debugger.break_on_caught_exceptions or main_debugger.has_plugin_exception_breaks

            if is_exception_event:
                if has_exception_breakpoints:
                    should_stop, frame = self.should_stop_on_exception(frame, event, arg)
                    if should_stop:
                        self.handle_exception(frame, event, arg)
                        return self.trace_dispatch
                is_line = False
                is_return = False
                is_call = False
            else:
                is_line = event == 'line'
                is_return = event == 'return'
                is_call = event == 'call'
                if not is_line and not is_return and not is_call:
                    # Unexpected: just keep the same trace func.
                    return self.trace_dispatch

            need_signature_trace_return = False
            if main_debugger.signature_factory is not None:
                if is_call:
                    need_signature_trace_return = send_signature_call_trace(main_debugger, frame, filename)
                elif is_return:
                    send_signature_return_trace(main_debugger, frame, filename, arg)

            stop_frame = info.pydev_step_stop
            step_cmd = info.pydev_step_cmd

            if is_exception_event:
                breakpoints_for_file = None
                # CMD_STEP_OVER = 108, CMD_STEP_OVER_MY_CODE = 159
                if stop_frame and stop_frame is not frame and step_cmd in (108, 159) and \
                                arg[0] in (StopIteration, GeneratorExit) and arg[2] is None:
                    if step_cmd == CMD_STEP_OVER:
                        info.pydev_step_cmd = CMD_STEP_INTO
                    else:
                        info.pydev_step_cmd = CMD_STEP_INTO_MY_CODE
                    info.pydev_step_stop = None
            else:
                # If we are in single step mode and something causes us to exit the current frame, we need to make sure we break
                # eventually.  Force the step mode to step into and the step stop frame to None.
                # I.e.: F6 in the end of a function should stop in the next possible position (instead of forcing the user
                # to make a step in or step over at that location).
                # Note: this is especially troublesome when we're skipping code with the
                # @DontTrace comment.
                if stop_frame is frame and is_return and step_cmd in (108, 109, 159, 160):
                    # CMD_STEP_OVER = 108, CMD_STEP_RETURN = 109, CMD_STEP_OVER_MY_CODE = 159, CMD_STEP_RETURN_MY_CODE = 160

                    if not frame.f_code.co_flags & 0x20:  # CO_GENERATOR = 0x20 (inspect.CO_GENERATOR)
                        if step_cmd in (108, 109):
                            info.pydev_step_cmd = CMD_STEP_INTO
                        else:
                            info.pydev_step_cmd = CMD_STEP_INTO_MY_CODE
                        info.pydev_step_stop = None

                breakpoints_for_file = main_debugger.breakpoints.get(filename)

                can_skip = False

                if info.pydev_state == 1:  # STATE_RUN = 1
                    # we can skip if:
                    # - we have no stop marked
                    # - we should make a step return/step over and we're not in the current frame
                    # CMD_STEP_OVER = 108, CMD_STEP_RETURN = 109, CMD_STEP_OVER_MY_CODE = 159, CMD_STEP_RETURN_MY_CODE = 160
                    can_skip = (step_cmd == -1 and stop_frame is None) \
                        or (step_cmd in (108, 109, 159, 160) and stop_frame is not frame)

                    if can_skip:
                        if plugin_manager is not None and (
                                main_debugger.has_plugin_line_breaks or main_debugger.has_plugin_exception_breaks):
                            can_skip = plugin_manager.can_skip(main_debugger, frame)

                        # CMD_STEP_OVER = 108, CMD_STEP_OVER_MY_CODE = 159
                        if can_skip and main_debugger.show_return_values and info.pydev_step_cmd in (108, 159) and frame.f_back is info.pydev_step_stop:
                            # trace function for showing return values after step over
                            can_skip = False

                # Let's check to see if we are in a function that has a breakpoint. If we don't have a breakpoint,
                # we will return nothing for the next trace
                # also, after we hit a breakpoint and go to some other debugging state, we have to force the set trace anyway,
                # so, that's why the additional checks are there.
                if not breakpoints_for_file:
                    if can_skip:
                        if has_exception_breakpoints:
                            return self.trace_exception
                        else:
                            if need_signature_trace_return:
                                return self.trace_return
                            else:
                                return None if is_call else NO_FTRACE

                else:
                    # When cached, 0 means we don't have a breakpoint and 1 means we have.
                    if can_skip:
                        breakpoints_in_line_cache = frame_skips_cache.get(line_cache_key, -1)
                        if breakpoints_in_line_cache == 0:
                            return self.trace_dispatch

                    breakpoints_in_frame_cache = frame_skips_cache.get(frame_cache_key, -1)
                    if breakpoints_in_frame_cache != -1:
                        # Gotten from cache.
                        has_breakpoint_in_frame = breakpoints_in_frame_cache == 1

                    else:
                        has_breakpoint_in_frame = False
                        # Checks the breakpoint to see if there is a context match in some function
                        curr_func_name = frame.f_code.co_name

                        # global context is set with an empty name
                        if curr_func_name in ('?', '<module>', '<lambda>'):
                            curr_func_name = ''

                        for breakpoint in dict_iter_values(breakpoints_for_file):  # jython does not support itervalues()
                            # will match either global or some function
                            if breakpoint.func_name in ('None', curr_func_name):
                                has_breakpoint_in_frame = True
                                break

                        # Cache the value (1 or 0 or -1 for default because of cython).
                        if has_breakpoint_in_frame:
                            frame_skips_cache[frame_cache_key] = 1
                        else:
                            frame_skips_cache[frame_cache_key] = 0

                    if can_skip and not has_breakpoint_in_frame:
                        if has_exception_breakpoints:
                            return self.trace_exception
                        else:
                            if need_signature_trace_return:
                                return self.trace_return
                            else:
                                return None if is_call else NO_FTRACE

            # We may have hit a breakpoint or we are already in step mode. Either way, let's check what we should do in this frame
            # if DEBUG: print('NOT skipped: %s %s %s %s' % (frame.f_lineno, frame.f_code.co_name, event, frame.__class__.__name__))

            try:
                flag = False
                # return is not taken into account for breakpoint hit because we'd have a double-hit in this case
                # (one for the line and the other for the return).

                stop_info = {}
                breakpoint = None
                exist_result = False
                stop = False
                bp_type = None
                if not is_return and info.pydev_state != STATE_SUSPEND and breakpoints_for_file is not None and line in breakpoints_for_file:
                    breakpoint = breakpoints_for_file[line]
                    new_frame = frame
                    stop = True
                    if step_cmd in (CMD_STEP_OVER, CMD_STEP_OVER_MY_CODE) and (stop_frame is frame and is_line):
                        stop = False  # we don't stop on breakpoint if we have to stop by step-over (it will be processed later)
                elif plugin_manager is not None and main_debugger.has_plugin_line_breaks:
                    result = plugin_manager.get_breakpoint(main_debugger, self, frame, event, self._args)
                    if result:
                        exist_result = True
                        flag, breakpoint, new_frame, bp_type = result

                if breakpoint:
                    # ok, hit breakpoint, now, we have to discover if it is a conditional breakpoint
                    # lets do the conditional stuff here
                    if stop or exist_result:
                        eval_result = False
                        if breakpoint.has_condition:
                            eval_result = main_debugger.handle_breakpoint_condition(info, breakpoint, new_frame)

                        if breakpoint.expression is not None:
                            main_debugger.handle_breakpoint_expression(breakpoint, info, new_frame)
                            if breakpoint.is_logpoint and info.pydev_message is not None and len(info.pydev_message) > 0:
                                cmd = main_debugger.cmd_factory.make_io_message(info.pydev_message + os.linesep, '1')
                                main_debugger.writer.add_command(cmd)

                        if breakpoint.has_condition:
                            if not eval_result:
                                return self.trace_dispatch
                        elif breakpoint.is_logpoint:
                            return self.trace_dispatch

                    if is_call and frame.f_code.co_name in ('<module>', '<lambda>'):
                        # If we find a call for a module, it means that the module is being imported/executed for the
                        # first time. In this case we have to ignore this hit as it may later duplicated by a
                        # line event at the same place (so, if there's a module with a print() in the first line
                        # the user will hit that line twice, which is not what we want).
                        #
                        # As for lambda, as it only has a single statement, it's not interesting to trace
                        # its call and later its line event as they're usually in the same line.

                        return self.trace_dispatch

                if main_debugger.show_return_values:
                    if is_return and info.pydev_step_cmd in (CMD_STEP_OVER, CMD_STEP_OVER_MY_CODE) and frame.f_back == info.pydev_step_stop:
                        self.show_return_values(frame, arg)

                elif main_debugger.remove_return_values_flag:
                    try:
                        self.remove_return_values(main_debugger, frame)
                    finally:
                        main_debugger.remove_return_values_flag = False

                if stop:
                    self.set_suspend(
                        thread,
                        CMD_SET_BREAK,
                        suspend_other_threads=breakpoint and breakpoint.suspend_policy == "ALL",
                    )

                elif flag and plugin_manager is not None:
                    result = plugin_manager.suspend(main_debugger, thread, frame, bp_type)
                    if result:
                        frame = result

                # if thread has a suspend flag, we suspend with a busy wait
                if info.pydev_state == STATE_SUSPEND:
                    self.do_wait_suspend(thread, frame, event, arg)
                    return self.trace_dispatch
                else:
                    if not breakpoint and is_line:
                        # No stop from anyone and no breakpoint found in line (cache that).
                        frame_skips_cache[line_cache_key] = 0

            except:
                traceback.print_exc()
                raise

            # step handling. We stop when we hit the right frame
            try:
                should_skip = 0
                if pydevd_dont_trace.should_trace_hook is not None:
                    if self.should_skip == -1:
                        # I.e.: cache the result on self.should_skip (no need to evaluate the same frame multiple times).
                        # Note that on a code reload, we won't re-evaluate this because in practice, the frame.f_code
                        # Which will be handled by this frame is read-only, so, we can cache it safely.
                        if not pydevd_dont_trace.should_trace_hook(frame, filename):
                            # -1, 0, 1 to be Cython-friendly
                            should_skip = self.should_skip = 1
                        else:
                            should_skip = self.should_skip = 0
                    else:
                        should_skip = self.should_skip

                plugin_stop = False
                if should_skip:
                    stop = False

                elif step_cmd in (CMD_STEP_INTO, CMD_STEP_INTO_MY_CODE):
                    force_check_project_scope = step_cmd == CMD_STEP_INTO_MY_CODE
                    if is_line:
                        if force_check_project_scope or main_debugger.is_files_filter_enabled:
                            stop = not main_debugger.apply_files_filter(frame, frame.f_code.co_filename, force_check_project_scope)
                        else:
                            stop = True

                    elif is_return and frame.f_back is not None:
                        if main_debugger.get_file_type(
                                get_abs_path_real_path_and_base_from_frame(frame.f_back)) == main_debugger.PYDEV_FILE:
                            stop = False
                        else:
                            if force_check_project_scope or main_debugger.is_files_filter_enabled:
                                stop = not main_debugger.apply_files_filter(frame.f_back, frame.f_back.f_code.co_filename, force_check_project_scope)
                            else:
                                stop = True

                    if plugin_manager is not None:
                        result = plugin_manager.cmd_step_into(main_debugger, frame, event, self._args, stop_info, stop)
                        if result:
                            stop, plugin_stop = result

                elif step_cmd in (CMD_STEP_OVER, CMD_STEP_OVER_MY_CODE):
                    # Note: when dealing with a step over my code it's the same as a step over (the
                    # difference is that when we return from a frame in one we go to regular step
                    # into and in the other we go to a step into my code).
                    stop = stop_frame is frame and is_line
                    # Note: don't stop on a return for step over, only for line events
                    # i.e.: don't stop in: (stop_frame is frame.f_back and is_return) as we'd stop twice in that line.

                    if frame.f_code.co_flags & CO_GENERATOR:
                        if is_return:
                            stop = False

                    if plugin_manager is not None:
                        result = plugin_manager.cmd_step_over(main_debugger, frame, event, self._args, stop_info, stop)
                        if result:
                            stop, plugin_stop = result

                elif step_cmd == CMD_SMART_STEP_INTO:
                    stop = False
                    if info.pydev_smart_step_stop is frame:
                        info.pydev_func_name = '.invalid.'  # Must match the type in cython
                        info.pydev_smart_step_stop = None

                    if is_line or is_exception_event:
                        curr_func_name = frame.f_code.co_name

                        # global context is set with an empty name
                        if curr_func_name in ('?', '<module>') or curr_func_name is None:
                            curr_func_name = ''

                        if curr_func_name == info.pydev_func_name:
                            stop = True

                elif step_cmd in (CMD_STEP_RETURN, CMD_STEP_RETURN_MY_CODE):
                    stop = is_return and stop_frame is frame

                else:
                    stop = False

                if stop and step_cmd != -1 and is_return and IS_PY3K and hasattr(frame, "f_back"):
                    f_code = getattr(frame.f_back, 'f_code', None)
                    if f_code is not None:
                        if main_debugger.get_file_type(
                                get_abs_path_real_path_and_base_from_file(f_code.co_filename)) == main_debugger.PYDEV_FILE:
                            stop = False

                if plugin_stop:
                    stopped_on_plugin = plugin_manager.stop(main_debugger, frame, event, self._args, stop_info, arg, step_cmd)
                elif stop:
                    if is_line:
                        self.set_suspend(thread, step_cmd)
                        self.do_wait_suspend(thread, frame, event, arg)
                    else:  # return event
                        back = frame.f_back
                        if back is not None:
                            # When we get to the pydevd run function, the debugging has actually finished for the main thread
                            # (note that it can still go on for other threads, but for this one, we just make it finish)
                            # So, just setting it to None should be OK
                            _, back_filename, base = get_abs_path_real_path_and_base_from_frame(back)
                            if (base, back.f_code.co_name) in (DEBUG_START, DEBUG_START_PY3K):
                                back = None

                            elif base == TRACE_PROPERTY:
                                # We dont want to trace the return event of pydevd_traceproperty (custom property for debugging)
                                # if we're in a return, we want it to appear to the user in the previous frame!
                                return None if is_call else NO_FTRACE

                            elif pydevd_dont_trace.should_trace_hook is not None:
                                if not pydevd_dont_trace.should_trace_hook(back, back_filename):
                                    # In this case, we'll have to skip the previous one because it shouldn't be traced.
                                    # Also, we have to reset the tracing, because if the parent's parent (or some
                                    # other parent) has to be traced and it's not currently, we wouldn't stop where
                                    # we should anymore (so, a step in/over/return may not stop anywhere if no parent is traced).
                                    # Related test: _debugger_case17a.py
                                    main_debugger.set_trace_for_frame_and_parents(back)
                                    return None if is_call else NO_FTRACE

                        if back is not None:
                            # if we're in a return, we want it to appear to the user in the previous frame!
                            self.set_suspend(thread, step_cmd)
                            self.do_wait_suspend(thread, back, event, arg)
                        else:
                            # in jython we may not have a back frame
                            info.pydev_step_stop = None
                            info.pydev_step_cmd = -1
                            info.pydev_state = STATE_RUN

            except KeyboardInterrupt:
                raise
            except:
                try:
                    traceback.print_exc()
                    info.pydev_step_cmd = -1
                except:
                    return None if is_call else NO_FTRACE

            # if we are quitting, let's stop the tracing
            if not main_debugger.quitting:
                return self.trace_dispatch
            else:
                return None if is_call else NO_FTRACE
        finally:
            info.is_tracing = False
예제 #15
0
    def trace_dispatch(self, frame, event, arg):
    # ENDIF
        # DEBUG = 'code_to_debug' in frame.f_code.co_filename
        main_debugger, filename, info, thread, frame_skips_cache, frame_cache_key = self._args
        # if DEBUG: print('frame trace_dispatch %s %s %s %s %s' % (frame.f_lineno, frame.f_code.co_name, frame.f_code.co_filename, event, info.pydev_step_cmd))
        try:
            info.is_tracing = True
            line = frame.f_lineno
            line_cache_key = (frame_cache_key, line)

            if main_debugger._finish_debugging_session:
                return None if event == 'call' else NO_FTRACE

            plugin_manager = main_debugger.plugin

            is_exception_event = event == 'exception'
            has_exception_breakpoints = main_debugger.break_on_caught_exceptions or main_debugger.has_plugin_exception_breaks

            if is_exception_event:
                if has_exception_breakpoints:
                    should_stop, frame = self.should_stop_on_exception(frame, event, arg)
                    if should_stop:
                        self.handle_exception(frame, event, arg)
                        return self.trace_dispatch
                is_line = False
                is_return = False
                is_call = False
            else:
                is_line = event == 'line'
                is_return = event == 'return'
                is_call = event == 'call'
                if not is_line and not is_return and not is_call:
                    # Unexpected: just keep the same trace func.
                    return self.trace_dispatch

            need_signature_trace_return = False
            if main_debugger.signature_factory is not None:
                if is_call:
                    need_signature_trace_return = send_signature_call_trace(main_debugger, frame, filename)
                elif is_return:
                    send_signature_return_trace(main_debugger, frame, filename, arg)

            stop_frame = info.pydev_step_stop
            step_cmd = info.pydev_step_cmd

            if is_exception_event:
                breakpoints_for_file = None
                # CMD_STEP_OVER = 108
                if stop_frame and stop_frame is not frame and step_cmd == 108 and \
                                arg[0] in (StopIteration, GeneratorExit) and arg[2] is None:
                    info.pydev_step_cmd = 107  # CMD_STEP_INTO = 107
                    info.pydev_step_stop = None
            else:
                # If we are in single step mode and something causes us to exit the current frame, we need to make sure we break
                # eventually.  Force the step mode to step into and the step stop frame to None.
                # I.e.: F6 in the end of a function should stop in the next possible position (instead of forcing the user
                # to make a step in or step over at that location).
                # Note: this is especially troublesome when we're skipping code with the
                # @DontTrace comment.
                if stop_frame is frame and is_return and step_cmd in (109, 108):  # CMD_STEP_RETURN = 109, CMD_STEP_OVER = 108
                    if not frame.f_code.co_flags & 0x20:  # CO_GENERATOR = 0x20 (inspect.CO_GENERATOR)
                        info.pydev_step_cmd = 107  # CMD_STEP_INTO = 107
                        info.pydev_step_stop = None

                breakpoints_for_file = main_debugger.breakpoints.get(filename)

                can_skip = False

                if info.pydev_state == 1:  # STATE_RUN = 1
                    # we can skip if:
                    # - we have no stop marked
                    # - we should make a step return/step over and we're not in the current frame
                    # CMD_STEP_RETURN = 109, CMD_STEP_OVER = 108
                    can_skip = (step_cmd == -1 and stop_frame is None) \
                        or (step_cmd in (109, 108) and stop_frame is not frame)

                    if can_skip:
                        if plugin_manager is not None and main_debugger.has_plugin_line_breaks:
                            can_skip = not plugin_manager.can_not_skip(main_debugger, self, frame)

                        # CMD_STEP_OVER = 108
                        if can_skip and main_debugger.show_return_values and info.pydev_step_cmd == 108 and frame.f_back is info.pydev_step_stop:
                            # trace function for showing return values after step over
                            can_skip = False

                # Let's check to see if we are in a function that has a breakpoint. If we don't have a breakpoint,
                # we will return nothing for the next trace
                # also, after we hit a breakpoint and go to some other debugging state, we have to force the set trace anyway,
                # so, that's why the additional checks are there.
                if not breakpoints_for_file:
                    if can_skip:
                        if has_exception_breakpoints:
                            return self.trace_exception
                        else:
                            if need_signature_trace_return:
                                return self.trace_return
                            else:
                                return None if is_call else NO_FTRACE

                else:
                    # When cached, 0 means we don't have a breakpoint and 1 means we have.
                    if can_skip:
                        breakpoints_in_line_cache = frame_skips_cache.get(line_cache_key, -1)
                        if breakpoints_in_line_cache == 0:
                            return self.trace_dispatch

                    breakpoints_in_frame_cache = frame_skips_cache.get(frame_cache_key, -1)
                    if breakpoints_in_frame_cache != -1:
                        # Gotten from cache.
                        has_breakpoint_in_frame = breakpoints_in_frame_cache == 1

                    else:
                        has_breakpoint_in_frame = False
                        # Checks the breakpoint to see if there is a context match in some function
                        curr_func_name = frame.f_code.co_name

                        # global context is set with an empty name
                        if curr_func_name in ('?', '<module>', '<lambda>'):
                            curr_func_name = ''

                        for breakpoint in dict_iter_values(breakpoints_for_file):  # jython does not support itervalues()
                            # will match either global or some function
                            if breakpoint.func_name in ('None', curr_func_name):
                                has_breakpoint_in_frame = True
                                break

                        # Cache the value (1 or 0 or -1 for default because of cython).
                        if has_breakpoint_in_frame:
                            frame_skips_cache[frame_cache_key] = 1
                        else:
                            frame_skips_cache[frame_cache_key] = 0

                    if can_skip and not has_breakpoint_in_frame:
                        if has_exception_breakpoints:
                            return self.trace_exception
                        else:
                            if need_signature_trace_return:
                                return self.trace_return
                            else:
                                return None if is_call else NO_FTRACE

            # We may have hit a breakpoint or we are already in step mode. Either way, let's check what we should do in this frame
            # if DEBUG: print('NOT skipped: %s %s %s %s' % (frame.f_lineno, frame.f_code.co_name, event, frame.__class__.__name__))

            try:
                flag = False
                # return is not taken into account for breakpoint hit because we'd have a double-hit in this case
                # (one for the line and the other for the return).

                stop_info = {}
                breakpoint = None
                exist_result = False
                stop = False
                bp_type = None
                if not is_return and info.pydev_state != STATE_SUSPEND and breakpoints_for_file is not None and line in breakpoints_for_file:
                    breakpoint = breakpoints_for_file[line]
                    new_frame = frame
                    stop = True
                    if step_cmd == CMD_STEP_OVER and stop_frame is frame and (is_line or is_return):
                        stop = False  # we don't stop on breakpoint if we have to stop by step-over (it will be processed later)
                elif plugin_manager is not None and main_debugger.has_plugin_line_breaks:
                    result = plugin_manager.get_breakpoint(main_debugger, self, frame, event, self._args)
                    if result:
                        exist_result = True
                        flag, breakpoint, new_frame, bp_type = result

                if breakpoint:
                    # ok, hit breakpoint, now, we have to discover if it is a conditional breakpoint
                    # lets do the conditional stuff here
                    if stop or exist_result:
                        eval_result = False
                        if breakpoint.has_condition:
                            eval_result = main_debugger.handle_breakpoint_condition(info, breakpoint, new_frame)

                        if breakpoint.expression is not None:
                            main_debugger.handle_breakpoint_expression(breakpoint, info, new_frame)
                            if breakpoint.is_logpoint and info.pydev_message is not None and len(info.pydev_message) > 0:
                                cmd = main_debugger.cmd_factory.make_io_message(info.pydev_message + os.linesep, '1')
                                main_debugger.writer.add_command(cmd)

                        if breakpoint.has_condition and not eval_result:
                            return self.trace_dispatch

                    if is_call and frame.f_code.co_name in ('<module>', '<lambda>'):
                        # If we find a call for a module, it means that the module is being imported/executed for the
                        # first time. In this case we have to ignore this hit as it may later duplicated by a
                        # line event at the same place (so, if there's a module with a print() in the first line
                        # the user will hit that line twice, which is not what we want).
                        #
                        # As for lambda, as it only has a single statement, it's not interesting to trace
                        # its call and later its line event as they're usually in the same line.
                        return self.trace_dispatch

                else:
                    # if the frame is traced after breakpoint stop,
                    # but the file should be ignored while stepping because of filters
                    if step_cmd != -1:
                        if main_debugger.is_filter_enabled and main_debugger.is_ignored_by_filters(filename):
                            # ignore files matching stepping filters
                            return self.trace_dispatch
                        if main_debugger.is_filter_libraries and not main_debugger.in_project_scope(filename):
                            # ignore library files while stepping
                            return self.trace_dispatch

                if main_debugger.show_return_values:
                    if is_return and info.pydev_step_cmd == CMD_STEP_OVER and frame.f_back == info.pydev_step_stop:
                        self.show_return_values(frame, arg)

                elif main_debugger.remove_return_values_flag:
                    try:
                        self.remove_return_values(main_debugger, frame)
                    finally:
                        main_debugger.remove_return_values_flag = False

                if stop:
                    self.set_suspend(
                        thread, 
                        CMD_SET_BREAK, 
                        suspend_other_threads=breakpoint and breakpoint.suspend_policy == "ALL",
                    )
                        
                elif flag and plugin_manager is not None:
                    result = plugin_manager.suspend(main_debugger, thread, frame, bp_type)
                    if result:
                        frame = result

                # if thread has a suspend flag, we suspend with a busy wait
                if info.pydev_state == STATE_SUSPEND:
                    self.do_wait_suspend(thread, frame, event, arg)
                    return self.trace_dispatch
                else:
                    if not breakpoint and is_line:
                        # No stop from anyone and no breakpoint found in line (cache that).
                        frame_skips_cache[line_cache_key] = 0

            except:
                traceback.print_exc()
                raise

            # step handling. We stop when we hit the right frame
            try:
                should_skip = 0
                if pydevd_dont_trace.should_trace_hook is not None:
                    if self.should_skip == -1:
                        # I.e.: cache the result on self.should_skip (no need to evaluate the same frame multiple times).
                        # Note that on a code reload, we won't re-evaluate this because in practice, the frame.f_code
                        # Which will be handled by this frame is read-only, so, we can cache it safely.
                        if not pydevd_dont_trace.should_trace_hook(frame, filename):
                            # -1, 0, 1 to be Cython-friendly
                            should_skip = self.should_skip = 1
                        else:
                            should_skip = self.should_skip = 0
                    else:
                        should_skip = self.should_skip

                plugin_stop = False
                if should_skip:
                    stop = False

                elif step_cmd == CMD_STEP_INTO:
                    stop = is_line or is_return
                    if plugin_manager is not None:
                        result = plugin_manager.cmd_step_into(main_debugger, frame, event, self._args, stop_info, stop)
                        if result:
                            stop, plugin_stop = result

                elif step_cmd == CMD_STEP_INTO_MY_CODE:
                    if main_debugger.in_project_scope(frame.f_code.co_filename):
                        stop = is_line

                elif step_cmd == CMD_STEP_OVER:
                    stop = stop_frame is frame and (is_line or is_return)

                    if frame.f_code.co_flags & CO_GENERATOR:
                        if is_return:
                            stop = False

                    if plugin_manager is not None:
                        result = plugin_manager.cmd_step_over(main_debugger, frame, event, self._args, stop_info, stop)
                        if result:
                            stop, plugin_stop = result

                elif step_cmd == CMD_SMART_STEP_INTO:
                    stop = False
                    if info.pydev_smart_step_stop is frame:
                        info.pydev_func_name = '.invalid.'  # Must match the type in cython
                        info.pydev_smart_step_stop = None

                    if is_line or is_exception_event:
                        curr_func_name = frame.f_code.co_name

                        # global context is set with an empty name
                        if curr_func_name in ('?', '<module>') or curr_func_name is None:
                            curr_func_name = ''

                        if curr_func_name == info.pydev_func_name:
                            stop = True

                elif step_cmd == CMD_STEP_RETURN:
                    stop = is_return and stop_frame is frame

                else:
                    stop = False

                if stop and step_cmd != -1 and is_return and IS_PY3K and hasattr(frame, "f_back"):
                    f_code = getattr(frame.f_back, 'f_code', None)
                    if f_code is not None:
                        if main_debugger.get_file_type(
                                get_abs_path_real_path_and_base_from_file(f_code.co_filename)) == main_debugger.PYDEV_FILE:
                            stop = False

                if plugin_stop:
                    stopped_on_plugin = plugin_manager.stop(main_debugger, frame, event, self._args, stop_info, arg, step_cmd)
                elif stop:
                    if is_line:
                        self.set_suspend(thread, step_cmd)
                        self.do_wait_suspend(thread, frame, event, arg)
                    else:  # return event
                        back = frame.f_back
                        if back is not None:
                            # When we get to the pydevd run function, the debugging has actually finished for the main thread
                            # (note that it can still go on for other threads, but for this one, we just make it finish)
                            # So, just setting it to None should be OK
                            _, back_filename, base = get_abs_path_real_path_and_base_from_frame(back)
                            if (base, back.f_code.co_name) in (DEBUG_START, DEBUG_START_PY3K):
                                back = None

                            elif base == TRACE_PROPERTY:
                                # We dont want to trace the return event of pydevd_traceproperty (custom property for debugging)
                                # if we're in a return, we want it to appear to the user in the previous frame!
                                return None if is_call else NO_FTRACE

                            elif pydevd_dont_trace.should_trace_hook is not None:
                                if not pydevd_dont_trace.should_trace_hook(back, back_filename):
                                    # In this case, we'll have to skip the previous one because it shouldn't be traced.
                                    # Also, we have to reset the tracing, because if the parent's parent (or some
                                    # other parent) has to be traced and it's not currently, we wouldn't stop where
                                    # we should anymore (so, a step in/over/return may not stop anywhere if no parent is traced).
                                    # Related test: _debugger_case17a.py
                                    main_debugger.set_trace_for_frame_and_parents(back)
                                    return None if is_call else NO_FTRACE

                        if back is not None:
                            # if we're in a return, we want it to appear to the user in the previous frame!
                            self.set_suspend(thread, step_cmd)
                            self.do_wait_suspend(thread, back, event, arg)
                        else:
                            # in jython we may not have a back frame
                            info.pydev_step_stop = None
                            info.pydev_step_cmd = -1
                            info.pydev_state = STATE_RUN

            except KeyboardInterrupt:
                raise
            except:
                try:
                    traceback.print_exc()
                    info.pydev_step_cmd = -1
                except:
                    return None if is_call else NO_FTRACE

            # if we are quitting, let's stop the tracing
            if not main_debugger.quitting:
                return self.trace_dispatch
            else:
                return None if is_call else NO_FTRACE
        finally:
            info.is_tracing = False
예제 #16
0
파일: wrapper.py 프로젝트: SamB/ptvsd
from ptvsd.socket import TimeoutError  # noqa

WAIT_FOR_THREAD_FINISH_TIMEOUT = 1  # seconds

debugger_attached = threading.Event()


def NOOP(*args, **kwargs):
    pass


def path_to_unicode(s):
    return s if isinstance(s, unicode) else s.decode(sys.getfilesystemencoding())


PTVSD_DIR_PATH = os.path.dirname(os.path.abspath(get_abs_path_real_path_and_base_from_file(__file__)[0])) + os.path.sep
NORM_PTVSD_DIR_PATH = os.path.normcase(PTVSD_DIR_PATH)


class UnsupportedPyDevdCommandError(Exception):

    def __init__(self, cmdid):
        msg = 'unsupported pydevd command ' + str(cmdid)
        super(UnsupportedPyDevdCommandError, self).__init__(msg)
        self.cmdid = cmdid


if sys.version_info >= (3,):

    def unquote(s):
        return None if s is None else urllib.unquote(s)
예제 #17
0
debugger_attached = threading.Event()


def NOOP(*args, **kwargs):
    pass


def path_to_unicode(s):
    return s if isinstance(s, unicode) else s.decode(
        sys.getfilesystemencoding())


PTVSD_DIR_PATH = os.path.dirname(
    os.path.abspath(
        get_abs_path_real_path_and_base_from_file(__file__)[0])) + os.path.sep
NORM_PTVSD_DIR_PATH = os.path.normcase(PTVSD_DIR_PATH)


class UnsupportedPyDevdCommandError(Exception):
    def __init__(self, cmdid):
        msg = 'unsupported pydevd command ' + str(cmdid)
        super(UnsupportedPyDevdCommandError, self).__init__(msg)
        self.cmdid = cmdid


if sys.version_info >= (3, ):

    def unquote(s):
        return None if s is None else urllib.unquote(s)