Plugins

PragyaLint's extension point is the Python API: an analysis run is a set of finder passes, and the set is pluggable. There is no CLI plugin-autoloading yet — custom passes are registered by calling analyze() yourself.

How rules are wired

analyze() receives a hooks mapping from rule name to a finder class. default_hooks() returns the five built-in finders:

from pragyalint.analyzer import default_hooks

print(default_hooks())  # {rule: FinderClass, ...}

Writing a custom finder

A finder subclasses Finder, reads the module records and AST trees available on itself, and calls emit():

import ast
from pragyalint.analyzer import analyze, default_hooks
from pragyalint.finders import Finder
from pragyalint.models import Confidence, Finding

class MissingDocstringFinder(Finder):
    """Report modules whose first statement isn't a docstring."""

    rule = "missing_docstring"

    def run(self, records):
        for record in records:
            tree = self.trees.get(record.path)
            if tree is None:
                continue
            if isinstance(tree.body[0], ast.Expr) and isinstance(
                tree.body[0].value, ast.Constant
            ):
                continue
            self.emit(
                Finding(
                    rule=self.rule,
                    confidence=Confidence.LOW,
                    message="module lacks a docstring",
                    file=record.path,
                    line=1,
                )
            )

report = analyze(
    "src",
    hooks={**default_hooks(), "missing_docstring": MissingDocstringFinder},
)

for finding in report.findings:
    print(finding.rule, finding.confidence, finding.file)

What a finder gets to work with:

AttributeContents
self.reportThe AnalysisReport, already populated with module records and reachability.
self.graphThe module graph — used_members_for(), resolve_to_record(), tree_for().
self.treespath → ast.Module for every analyzed file.
self.optionsPassed-in options, e.g. include_entry_exports.
self.emit(finding)Appends the finding to the report and updates its summary counters.

Custom reporters

The reporters are plain functions over an AnalysisReport: format_terminal(report, color=True), format_json(report, indent=2), and format_sarif(report). Pass a report to your own formatter the same way.

Current limits

If a custom rule proves generally useful, consider contributing it as a built-in — see Contributing.