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.
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, ...}
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:
| Attribute | Contents |
|---|---|
self.report | The AnalysisReport, already populated with module records and reachability. |
self.graph | The module graph — used_members_for(), resolve_to_record(), tree_for(). |
self.trees | path → ast.Module for every analyzed file. |
self.options | Passed-in options, e.g. include_entry_exports. |
self.emit(finding) | Appends the finding to the report and updates its summary counters. |
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.
analyze().If a custom rule proves generally useful, consider contributing it as a built-in — see Contributing.