Linter guide
Linting is a powerful tool for improving code quality and consistency. It enables you to automatically validate model definition, ensuring they adhere to your team's best practices.
When a SQLMesh command is executed and the project is loaded, each model's code is checked for compliance with a set of rules you choose.
SQLMesh provides built-in rules, and you can define custom rules. This improves code quality and helps detect issues early in the development cycle when they are simpler to debug.
Rules
Each linting rule is responsible for identifying a pattern in a model's code.
Some rules validate that a pattern is not present, such as not allowing SELECT *
in a model's outermost query. Other rules validate that a pattern is present, like ensuring that every model's owner
field is specified. We refer to both of these below as "validating a pattern".
Rules are defined in Python. Each rule is an individual Python class that inherits from SQLMesh's Rule
base class and defines the logic for validating a pattern.
We display a portion of the Rule
base class's code below (full source code). Its methods and properties illustrate the most important components of the subclassed rules you define.
Each rule class you create has four vital components:
- Name: the class's name is used as the rule's name.
- Description: the class should define a docstring that provides a short explanation of the rule's purpose.
- Pattern validation logic: the class should define a
check_model()
method containing the core logic that validates the rule's pattern. The method can access anyModel
attribute. - Rule violation logic: if a rule's pattern is not validated, the rule is "violated" and the class should return a
RuleViolation
object. TheRuleViolation
object should include the contextual information a user needs to understand and fix the problem.
Built-in rules
SQLMesh includes a set of predefined rules that check for potential SQL errors or enforce code style.
An example of the latter is the NoSelectStar
rule, which prohibits a model from using SELECT *
in its query's outer-most select statement.
Here is code for the built-in NoSelectStar
rule class, with the different components annotated:
Here are all of SQLMesh's built-in linting rules:
Name | Check type | Explanation |
---|---|---|
ambiguousorinvalidcolumn |
Correctness | SQLMesh found duplicate columns or was unable to determine whether a column is duplicated or not |
invalidselectstarexpansion |
Correctness | The query's top-level selection may be SELECT * , but only if SQLMesh can expand the SELECT * into individual columns |
noselectstar |
Stylistic | The query's top-level selection may not be SELECT * , even if SQLMesh can expand the SELECT * into individual columns |
nomissingaudits |
Governance | SQLMesh did not find any audits in the model's configuration to test data quality. |
User-defined rules
You may define custom rules to implement your team's best practices.
For instance, you could ensure all models have an owner
by defining the following linting rule:
Place a rule's code in the project's linter/
directory. SQLMesh will load all subclasses of Rule
from that directory.
If the rule is specified in the project's configuration file, SQLMesh will run it when the project is loaded. All SQLMesh commands will load the project, except for create_external_models
, migrate
, rollback
, run
, environments
, and invalidate
.
SQLMesh will error if a model violates the rule, informing you which model(s) violated the rule. In this example, full_model.sql
violated the NoMissingOwner
rule:
$ sqlmesh plan
Linter errors for .../models/full_model.sql:
- nomissingowner: Model owner should always be specified.
Error: Linter detected errors in the code. Please fix them before proceeding.
Applying linting rules
Specify which linting rules a project should apply in the project's configuration file.
Rules are specified as lists of rule names under the linter
key. Globally enable or disable linting with the enabled
key, which is false
by default.
NOTE: you must set the enabled
key to true
key to apply the project's linting rules.
Specific linting rules
This example specifies that the "ambiguousorinvalidcolumn"
and "invalidselectstarexpansion"
linting rules should be enforced:
All linting rules
Apply every built-in and user-defined rule by specifying "ALL"
instead of a list of rules:
If you want to apply all rules except for a few, you can specify "ALL"
and list the rules to ignore in the ignored_rules
key:
Exclude a model from linting
You can specify that a specific model ignore a linting rule by specifying ignored_rules
in its MODEL
block.
This example specifies that the model docs_example.full_model
should not run the invalidselectstarexpansion
rule:
Rule violation behavior
Linting rule violations raise an error by default, preventing the project from running until the violation is addressed.
You may specify that a rule's violation should not error and only log a warning by specifying it in the warn_rules
key instead of the rules
key.
SQLMesh will raise an error if the same rule is included in more than one of the rules
, warn_rules
, and ignored_rules
keys since they should be mutually exclusive.