Rules in SQLFluff are implemented as crawlers. These are entities which work their way through the parsed structure of a query to evaluate a particular rule or set of rules. The intent is that the definition of each specific rule should be really streamlined and only contain the logic for the rule itself, with all the other mechanics abstracted away.
Class to define a ruleset.
A rule set is instantiated on module load, but the references to each of its classes are instantiated at runtime. This means that configuration values can be passed to those rules live and be responsive to any changes in configuration from the path that the file is in.
Rules should be fetched using the
get_rulelist()command which also handles any filtering (i.e. whitelisting and blacklisting).
New rules should be added to the instance of this class using the
register()decorator. That decorator registers the class, but also performs basic type and name-convention checks.
The code for the rule will be parsed from the name, the description from the docstring. The eval function is assumed that it will be overriden by the subclass, and the parent class raises an error on this function if not overriden.
Return a copy of self with a separate register.
Use the config to return the appropriate rules.
We use the config both for whitelisting and blacklisting, but also for configuring the rules given the given config.
Decorate a class with this to add it to the ruleset.
@myruleset.register class Rule_L001(BaseCrawler): "Description of rule." def eval(self, **kwargs): return LintResult()
We expect that rules are defined as classes with the name Rule_XXXX where XXXX is of the form LNNN, where L is a letter (literally L for linting by default) and N is a three digit number.
If this receives classes by any other name, then it will raise a
BaseCrawler(code, description, **kwargs)¶
The base class for a crawler, of which all rules are derived from.
str) – The identifier for this rule, used in inclusion or exclusion.
str) – A human readable description of what this rule does. It will be displayed when any violations are found.
Evaluate this rule against the current context.
This should indicate whether a linting violation has occurred and/or whether there is something to remember from this evaluation.
Note that an evaluate function should always accept **kwargs, but if it relies on any available kwargs, it should explicitly call them out at definition.
The reason that this method is called
_eval()and not eval is a bit of a hack with sphinx autodoc, to make it so that the rule documentation auto-generates nicely.
crawl(segment, dialect, parent_stack=None, siblings_pre=None, siblings_post=None, raw_stack=None, fix=False, memory=None)¶
Recursively perform the crawl operation on a given segment.
A tuple of (vs, raw_stack, fixes, memory)
Filter the segments to non-meta.
Or optionally the opposite if keep_meta is True.
Return the segment immediately containing segment.
NB: This is recursive.
segment – The segment to look for.
root_segment – Some known parent of the segment we’re looking for (although likely not the direct parent in question).
Make a keyword segment.
Make a newline segment.
Make a whitespace segment.
LintResult(anchor=None, fixes=None, memory=None, description=None)¶
A class to hold the results of a crawl operation.
BaseSegment, optional) – A segment which represents the position of the a problem. NB: Each fix will also hold its own reference to position, so this position is mostly for alerting the user to where the problem is.
LintFix, optional) – An array of any fixes which would correct this issue. If not present then it’s assumed that this issue will have to manually fixed.
dict, optional) – An object which stores any working memory for the crawler. The memory returned in any LintResult will be passed as an input to the next segment to be crawled.
str, optional) – A description of the problem identified as part of this result. This will override the description of the rule as what gets reported to the user with the problem if provided.
Convert a linting result to a
LintFix(edit_type, anchor, edit=None)¶
A class to hold a potential fix to a linting violation.
str) – One of create, edit, delete to indicate the kind of fix this represents.
BaseSegment) – A segment which represents the position that this fix should be applied at. For deletions it represents the segment to delete, for creations it implies the position to create at (with the existing element at this position to be moved after the edit), for an edit it implies the segment to be replaced.
BaseSegment, optional) – For edit and create fixes, this hold the segment, or iterable of segments to create to replace at the given anchor point.
Return true if the fix is trivial.
Trivial edits are: - Anything of zero length. - Any edits which result in themselves.
Removing these makes the routines which process fixes much faster.
The _eval function of each rule should take enough arguments that it can evaluate the position of the given segment in relation to its neighbors, and that the segment which finally “triggers” the error, should be the one that would be corrected OR if the rule relates to something that is missing, then it should flag on the segment FOLLOWING, the place that the desired element is missing.
Inline Ignoring Errors¶
SQLFluff features inline error ignoring. For example, the following will
ignore the lack of whitespace surrounding the
a.a*a.b AS bad_1 -- noqa: L006
Multiple rules can be ignored by placing them in a comma-delimited list.
a.a * a.b AS bad_2, -- noqa: L007, L006
It is also possible to ignore non-rule based errors, and instead opt to
ignore templating (
TMP) & parsing (
WHERE dt >= DATE_ADD(CURRENT_DATE(), INTERVAL -2 DAY) -- noqa: PRS
Should the need arise, not specifying specific rules to ignore will ignore all rules on the given line.
a.a*a.b AS bad_3 -- noqa