Configure linter¶
This tutorial walks you through the steps to configure your linter. We will start from the code in the previous tutorial.
Warning
Gather code from the first Basic linter tutorial to follow along.
Update rule to use config¶
One of the rules in previous tutorial has a magic number which you might want to have customizable (e.g. by providing linter configuration via pyproject.toml like ruff ⧉).
Let's do this by adjusting NameIsShort rule first (leave rest of the file as is):
... # rest of the file
# Let's add one simple rule for fun
class NameIsShort(PyProjectNameLoader, code=4):
"""Checks if `name` is below `N` characters."""
def __init__(self):
# Always call base constructor
super().__init__()
self.max_name_length = self.config("max_name_length", 10)
def check(self, value: lintkit.Value[str | None]) -> bool:
# Change 10 to attribute
return isinstance(value, str) and len(value) > self.max_name_length
def message(self, v: lintkit.Value | None) -> str:
return (
f"Field 'project.name' is too long "
f"({len(v)} > {self.max_name_length} chars)"
)
Read on to see how max_name_length is loaded without passing values to __init__.
Tip
[lintkit.rule.Rule][] is instantiated by [lintkit.run][] call and no arguments are passed.
Update config¶
You will continue with previously define pyproject.toml, add the following section to our linter:
Load config¶
Lintkit can use loadfig ⧉ to load the linter's tool section from pyproject.toml. Install the config extra:
You can install it with pip (or use your package manager like uv ⧉):
Tip
Installing lintkit[config] enables both [lintkit.config][] and [lintkit.rule.Rule.config][]. Without the extra, neither API is exposed.
Now edit run.py:
import sys
import lintkit
import rules
def main() -> None:
# Loads [tool.mylinter], based on lowercase lintkit.settings.name
config = lintkit.config()
# Run the linter with code inclusions and exclusions
exit_code = lintkit.run(
["pyproject.toml"],
include_codes=config.get("include_codes", None),
exclude_codes=config.get("exclude_codes", None),
)
sys.exit(exit_code)
if __name__ == "__main__":
main()
Things you should note:
Rule.config()reads only the nested table matching that rule's exact public name, such as[tool.mylinter.MYLINTER4]- [
lintkit.config][] returns the whole[tool.mylinter]table for shared options such as rule selection - [
lintkit.registry.inject][] remains available for unrelated custom resources that should be shared by all rules - [
lintkit.run][] gives you more flexibility (e.g. including or excluding code parts).
Note
Exclusions take precedence over inclusions. In our case, the only included rule will be effectively 4.
Tip
You can use any other config loading tool or load the config directly using standard tomllib library ⧉
Run¶
You can run the run.py file once again, this time the output should be as follows:
Next steps¶
Check one of the following tutorials to learn more about what you can do with lintkit:
- Previous basic tutorial showcasing
lintkitcapabilities - Advanced linter for Python code
- File linters