Beispiel #1
0
    def cmd_ignore_thrown_exception_at(self, py_db, cmd_id, seq, text):
        if text:
            replace = 'REPLACE:'  # Not all 3.x versions support u'REPLACE:', so, doing workaround.
            if not IS_PY3K:
                replace = unicode(replace)  # noqa

            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)
                    original_filename, line_number = line.split('|')
                    original_filename = self.api.filename_to_server(original_filename)

                    canonical_normalized_filename = pydevd_file_utils.canonical_normalized_path(original_filename)
                    absolute_filename = pydevd_file_utils.absolute_path(original_filename)

                    if os.path.exists(absolute_filename):
                        lines_ignored = py_db.filename_to_lines_where_exceptions_are_ignored.get(canonical_normalized_filename)
                        if lines_ignored is None:
                            lines_ignored = py_db.filename_to_lines_where_exceptions_are_ignored[canonical_normalized_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' % (absolute_filename,))
Beispiel #2
0
    def set_source_mapping(self, py_db, source_filename, mapping):
        '''
        :param str source_filename:
            The filename for the source mapping (bytes on py2 and str on py3).
            This filename will be made absolute in this function.

        :param list(SourceMappingEntry) mapping:
            A list with the source mapping entries to be applied to the given filename.

        :return str:
            An error message if it was not possible to set the mapping or an empty string if
            everything is ok.
        '''
        source_filename = self.filename_to_server(source_filename)
        absolute_source_filename = pydevd_file_utils.absolute_path(
            source_filename)
        for map_entry in mapping:
            map_entry.source_filename = absolute_source_filename
        error_msg = py_db.source_mapping.set_source_mapping(
            absolute_source_filename, mapping)
        if error_msg:
            return error_msg

        self.reapply_breakpoints(py_db)
        return ''
Beispiel #3
0
def _get_template_line(frame):
    if IS_DJANGO19_OR_HIGHER:
        node = frame.f_locals['self']
        if hasattr(node, 'token') and hasattr(node.token, 'lineno'):
            return node.token.lineno
        else:
            return None

    source = _get_source_django_18_or_lower(frame)
    original_filename = _get_template_original_file_name_from_frame(frame)
    if original_filename is not None:
        try:
            absolute_filename = absolute_path(original_filename)
            return _offset_to_line_number(_read_file(absolute_filename),
                                          source[1][0])
        except:
            return None
    return None
Beispiel #4
0
    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)

        qt_mode = _config.get("qt", "none")
        if qt_mode != "none":
            pydevd.enable_qt_support(qt_mode)

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

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

        try:
            return func(address, settrace_kwargs, **kwargs)
        except Exception:
            log.reraise_exception("{0}() failed:", func.__name__, level="info")
Beispiel #5
0
 def _absolute_normalized_path(self, filename):
     '''
     Provides a version of the filename that's absolute and normalized.
     '''
     return normcase(pydevd_file_utils.absolute_path(filename))
Beispiel #6
0
    def add_breakpoint(self,
                       py_db,
                       original_filename,
                       breakpoint_type,
                       breakpoint_id,
                       line,
                       condition,
                       func_name,
                       expression,
                       suspend_policy,
                       hit_condition,
                       is_logpoint,
                       adjust_line=False):
        '''
        :param str original_filename:
            Note: must be sent as it was received in the protocol. It may be translated in this
            function and its final value will be available in the returned _AddBreakpointResult.

        :param str breakpoint_type:
            One of: 'python-line', 'django-line', 'jinja2-line'.

        :param int breakpoint_id:

        :param int line:
            Note: it's possible that a new line was actually used. If that's the case its
            final value will be available in the returned _AddBreakpointResult.

        :param condition:
            Either None or the condition to activate the breakpoint.

        :param str func_name:
            If "None" (str), may hit in any context.
            Empty string will hit only top level.
            Any other value must match the scope of the method to be matched.

        :param str expression:
            None or the expression to be evaluated.

        :param suspend_policy:
            Either "NONE" (to suspend only the current thread when the breakpoint is hit) or
            "ALL" (to suspend all threads when a breakpoint is hit).

        :param str hit_condition:
            An expression where `@HIT@` will be replaced by the number of hits.
            i.e.: `@HIT@ == x` or `@HIT@ >= x`

        :param bool is_logpoint:
            If True and an expression is passed, pydevd will create an io message command with the
            result of the evaluation.

        :return _AddBreakpointResult:
        '''
        assert original_filename.__class__ == str, 'Expected str, found: %s' % (
            original_filename.__class__, )  # i.e.: bytes on py2 and str on py3

        pydev_log.debug('Request for breakpoint in: %s line: %s',
                        original_filename, line)
        # Parameters to reapply breakpoint.
        api_add_breakpoint_params = (original_filename, breakpoint_type,
                                     breakpoint_id, line, condition, func_name,
                                     expression, suspend_policy, hit_condition,
                                     is_logpoint)

        translated_filename = self.filename_to_server(
            original_filename)  # Apply user path mapping.
        pydev_log.debug('Breakpoint (after path translation) in: %s line: %s',
                        translated_filename, line)
        func_name = self.to_str(func_name)

        assert translated_filename.__class__ == str  # i.e.: bytes on py2 and str on py3
        assert func_name.__class__ == str  # i.e.: bytes on py2 and str on py3

        # Apply source mapping (i.e.: ipython).
        source_mapped_filename, new_line, multi_mapping_applied = py_db.source_mapping.map_to_server(
            translated_filename, line)

        if multi_mapping_applied:
            pydev_log.debug(
                'Breakpoint (after source mapping) in: %s line: %s',
                source_mapped_filename, new_line)
            # Note that source mapping is internal and does not change the resulting filename nor line
            # (we want the outside world to see the line in the original file and not in the ipython
            # cell, otherwise the editor wouldn't be correct as the returned line is the line to
            # which the breakpoint will be moved in the editor).
            result = self._AddBreakpointResult(original_filename, line)

            # If a multi-mapping was applied, consider it the canonical / source mapped version (translated to ipython cell).
            translated_absolute_filename = source_mapped_filename
            canonical_normalized_filename = pydevd_file_utils.normcase(
                source_mapped_filename)
            line = new_line

        else:
            translated_absolute_filename = pydevd_file_utils.absolute_path(
                translated_filename)
            canonical_normalized_filename = pydevd_file_utils.canonical_normalized_path(
                translated_filename)

            if adjust_line and not translated_absolute_filename.startswith(
                    '<'):
                # Validate breakpoints and adjust their positions.
                try:
                    lines = sorted(
                        _get_code_lines(translated_absolute_filename))
                except Exception:
                    pass
                else:
                    if line not in lines:
                        # Adjust to the first preceding valid line.
                        idx = bisect.bisect_left(lines, line)
                        if idx > 0:
                            line = lines[idx - 1]

            result = self._AddBreakpointResult(original_filename, line)

        py_db.api_received_breakpoints[(original_filename, breakpoint_id)] = (
            canonical_normalized_filename, api_add_breakpoint_params)

        if not translated_absolute_filename.startswith('<'):
            # Note: if a mapping pointed to a file starting with '<', don't validate.

            if not pydevd_file_utils.exists(translated_absolute_filename):
                result.error_code = self.ADD_BREAKPOINT_FILE_NOT_FOUND
                return result

            if (py_db.is_files_filter_enabled
                    and not py_db.get_require_module_for_filters()
                    and py_db.apply_files_filter(
                        self._DummyFrame(translated_absolute_filename),
                        translated_absolute_filename, False)):
                # Note that if `get_require_module_for_filters()` returns False, we don't do this check.
                # This is because we don't have the module name given a file at this point (in
                # runtime it's gotten from the frame.f_globals).
                # An option could be calculate it based on the filename and current sys.path,
                # but on some occasions that may be wrong (for instance with `__main__` or if
                # the user dynamically changes the PYTHONPATH).

                # Note: depending on the use-case, filters may be changed, so, keep on going and add the
                # breakpoint even with the error code.
                result.error_code = self.ADD_BREAKPOINT_FILE_EXCLUDED_BY_FILTERS

        if breakpoint_type == 'python-line':
            added_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:
            add_plugin_breakpoint_result = None
            plugin = py_db.get_plugin_lazy_init()
            if plugin is not None:
                add_plugin_breakpoint_result = plugin.add_breakpoint(
                    'add_line_breakpoint',
                    py_db,
                    breakpoint_type,
                    canonical_normalized_filename,
                    line,
                    condition,
                    expression,
                    func_name,
                    hit_condition=hit_condition,
                    is_logpoint=is_logpoint)

            if add_plugin_breakpoint_result is not None:
                supported_type = True
                added_breakpoint, breakpoints = add_plugin_breakpoint_result
                file_to_id_to_breakpoint = py_db.file_to_id_to_plugin_breakpoint
            else:
                supported_type = False

        if not supported_type:
            raise NameError(breakpoint_type)

        if DebugInfoHolder.DEBUG_TRACE_BREAKPOINTS > 0:
            pydev_log.debug('Added breakpoint:%s - line:%s - func_name:%s\n',
                            canonical_normalized_filename, line, func_name)

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

        id_to_pybreakpoint[breakpoint_id] = added_breakpoint
        py_db.consolidate_breakpoints(canonical_normalized_filename,
                                      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()
        return result