Exemplo n.º 1
0
def test__cli__formatters__violation(tmpdir):
    """Test formatting violations.

    NB Position is 1 + start_pos.
    """
    s = RawSegment(
        "foobarbar",
        PositionMarker(
            slice(10, 19),
            slice(10, 19),
            TemplatedFile.from_string("      \n\n  foobarbar"),
        ),
    )
    r = RuleGhost("A", "DESC")
    v = SQLLintError(segment=s, rule=r)
    formatter = OutputStreamFormatter(
        FileOutput(FluffConfig(require_dialect=False), str(tmpdir / "out.txt")), False
    )
    f = formatter.format_violation(v)
    # Position is 3, 3 becase foobarbar is on the third
    # line (i.e. it has two newlines preceding it) and
    # it's at the third position in that line (i.e. there
    # are two characters between it and the preceding
    # newline).
    assert escape_ansi(f) == "L:   3 | P:   3 |    A | DESC"
Exemplo n.º 2
0
def test__cli__formatters__violation():
    """Test formatting violations.

    NB Position is 1 + start_pos.
    """
    s = RawSegment("foobarbar", FilePositionMarker(0, 20, 11, 100))
    r = RuleGhost("A", "DESC")
    v = SQLLintError(segment=s, rule=r)
    f = format_violation(v)
    assert escape_ansi(f) == "L:  20 | P:  11 |    A | DESC"
Exemplo n.º 3
0
 def to_linting_error(self, rule):
     """Convert a linting result to a :exc:`SQLLintError` if appropriate."""
     if self.anchor:
         # Allow description override from the LintResult
         description = self.description or rule.description
         return SQLLintError(
             rule=rule,
             segment=self.anchor,
             fixes=self.fixes,
             description=description,
         )
     else:
         return None
Exemplo n.º 4
0
def test__cli__formatters__violation():
    """Test formatting violations.

    NB Position is 1 + start_pos.
    """
    s = RawSegment(
        "foobarbar",
        PositionMarker(
            slice(10, 19),
            slice(10, 19),
            TemplatedFile.from_string("      \n\n  foobarbar"),
        ),
    )
    r = RuleGhost("A", "DESC")
    v = SQLLintError(segment=s, rule=r)
    f = format_violation(v)
    # Position is 3, 3 becase foobarbar is on the third
    # line (i.e. it has two newlines preceding it) and
    # it's at the third position in that line (i.e. there
    # are two characters between it and the preceeding
    # newline).
    assert escape_ansi(f) == "L:   3 | P:   3 |    A | DESC"
Exemplo n.º 5
0
    def crawl(
        self,
        segment,
        dialect,
        parent_stack=None,
        siblings_pre=None,
        siblings_post=None,
        raw_stack=None,
        memory=None,
        fname=None,
        templated_file: Optional["TemplatedFile"] = None,
    ):
        """Recursively perform the crawl operation on a given segment.

        Returns:
            A tuple of (vs, raw_stack, fixes, memory)

        """
        # parent stack should be a tuple if it exists

        # Rules should evaluate on segments FIRST, before evaluating on their
        # children. They should also return a list of violations.

        parent_stack = parent_stack or ()
        raw_stack = raw_stack or ()
        siblings_post = siblings_post or ()
        siblings_pre = siblings_pre or ()
        memory = memory or {}
        vs: List[SQLLintError] = []
        fixes: List[LintFix] = []

        # First, check whether we're looking at an unparsable and whether
        # this rule will still operate on that.
        if not self._works_on_unparsable and segment.is_type("unparsable"):
            # Abort here if it doesn't. Otherwise we'll get odd results.
            return vs, raw_stack, [], memory

        # TODO: Document what options are available to the evaluation function.
        try:
            res = self._eval(
                segment=segment,
                parent_stack=parent_stack,
                siblings_pre=siblings_pre,
                siblings_post=siblings_post,
                raw_stack=raw_stack,
                memory=memory,
                dialect=dialect,
                path=pathlib.Path(fname) if fname else None,
                templated_file=templated_file,
            )
        # Any exception at this point would halt the linter and
        # cause the user to get no results
        except Exception as e:
            self.logger.critical(
                f"Applying rule {self.code} threw an Exception: {e}",
                exc_info=True)
            exception_line, _ = segment.pos_marker.source_position()
            vs.append(
                SQLLintError(
                    rule=self,
                    segment=segment,
                    fixes=[],
                    description=(f"""Unexpected exception: {str(e)};
                        Could you open an issue at https://github.com/sqlfluff/sqlfluff/issues ?
                        You can ignore this exception for now, by adding '--noqa: {self.code}' at the end
                        of line {exception_line}
                        """),
                ))
            return vs, raw_stack, fixes, memory

        new_lerrs = []
        new_fixes = []
        if res is None:
            # Assume this means no problems (also means no memory)
            pass
        elif isinstance(res, LintResult):
            # Extract any memory
            memory = res.memory
            lerr = res.to_linting_error(rule=self)
            if lerr:
                new_lerrs = [lerr]
            new_fixes = res.fixes
        elif isinstance(res, list) and all(
                isinstance(elem, LintResult) for elem in res):
            # Extract any memory from the *last* one, assuming
            # it was the last to be added
            memory = res[-1].memory
            for elem in res:
                lerr = elem.to_linting_error(rule=self)
                if lerr:
                    new_lerrs.append(lerr)
                new_fixes += elem.fixes
        else:
            raise TypeError(
                "Got unexpected result [{0!r}] back from linting rule: {1!r}".
                format(res, self.code))

        for lerr in new_lerrs:
            self.logger.debug("!! Violation Found: %r", lerr.description)
        for fix in new_fixes:
            self.logger.debug("!! Fix Proposed: %r", fix)

        # Consume the new results
        vs += new_lerrs
        fixes += new_fixes

        # The raw stack only keeps track of the previous raw segments
        if len(segment.segments) == 0:
            raw_stack += (segment, )
        # Parent stack keeps track of all the parent segments
        parent_stack += (segment, )

        for idx, child in enumerate(segment.segments):
            dvs, raw_stack, child_fixes, memory = self.crawl(
                segment=child,
                parent_stack=parent_stack,
                siblings_pre=segment.segments[:idx],
                siblings_post=segment.segments[idx + 1:],
                raw_stack=raw_stack,
                memory=memory,
                dialect=dialect,
                fname=fname,
                templated_file=templated_file,
            )
            vs += dvs
            fixes += child_fixes
        return vs, raw_stack, fixes, memory
Exemplo n.º 6
0
    def crawl(
        self,
        tree: BaseSegment,
        dialect: Dialect,
        fix: bool,
        templated_file: Optional["TemplatedFile"],
        ignore_mask: List[NoQaDirective],
        fname: Optional[str],
    ) -> Tuple[List[SQLLintError], Tuple[RawSegment, ...], List[LintFix], Any]:
        """Run the rule on a given tree.

        Returns:
            A tuple of (vs, raw_stack, fixes, memory)

        """
        root_context = RuleContext(
            dialect=dialect,
            fix=fix,
            templated_file=templated_file,
            path=pathlib.Path(fname) if fname else None,
            segment=tree,
        )
        vs: List[SQLLintError] = []
        fixes: List[LintFix] = []

        # Propagates memory from one rule _eval() to the next.
        memory: Any = root_context.memory
        context = root_context
        for context in self.crawl_behaviour.crawl(root_context):
            try:
                context.memory = memory
                res = self._eval(context=context)
            except (bdb.BdbQuit, KeyboardInterrupt):  # pragma: no cover
                raise
            # Any exception at this point would halt the linter and
            # cause the user to get no results
            except Exception as e:
                self.logger.critical(
                    f"Applying rule {self.code} threw an Exception: {e}", exc_info=True
                )
                assert context.segment.pos_marker
                exception_line, _ = context.segment.pos_marker.source_position()
                self._log_critical_errors(e)
                vs.append(
                    SQLLintError(
                        rule=self,
                        segment=context.segment,
                        fixes=[],
                        description=(
                            f"Unexpected exception: {str(e)};\n"
                            "Could you open an issue at "
                            "https://github.com/sqlfluff/sqlfluff/issues ?\n"
                            "You can ignore this exception for now, by adding "
                            f"'-- noqa: {self.code}' at the end\n"
                            f"of line {exception_line}\n"
                        ),
                    )
                )
                return vs, context.raw_stack, fixes, context.memory

            new_lerrs: List[SQLLintError] = []
            new_fixes: List[LintFix] = []

            if res is None or res == []:
                # Assume this means no problems (also means no memory)
                pass
            elif isinstance(res, LintResult):
                # Extract any memory
                memory = res.memory
                self._adjust_anchors_for_fixes(context, res)
                self._process_lint_result(
                    res, templated_file, ignore_mask, new_lerrs, new_fixes
                )
            elif isinstance(res, list) and all(
                isinstance(elem, LintResult) for elem in res
            ):
                # Extract any memory from the *last* one, assuming
                # it was the last to be added
                memory = res[-1].memory
                for elem in res:
                    self._adjust_anchors_for_fixes(context, elem)
                    self._process_lint_result(
                        elem, templated_file, ignore_mask, new_lerrs, new_fixes
                    )
            else:  # pragma: no cover
                raise TypeError(
                    "Got unexpected result [{!r}] back from linting rule: {!r}".format(
                        res, self.code
                    )
                )

            for lerr in new_lerrs:
                self.logger.info("!! Violation Found: %r", lerr.description)
            for lfix in new_fixes:
                self.logger.info("!! Fix Proposed: %r", lfix)

            # Consume the new results
            vs += new_lerrs
            fixes += new_fixes
        return vs, context.raw_stack if context else tuple(), fixes, context.memory