Linter Service

Overview

The linter service provides a shared framework to run pre- and post-linters with central ignore handling.

  • Abstract linter API: name, stage, and a run(ctx) generator that yields LinterIssue objects. For pre-lint, the parsed project model is available as ctx.project.

  • Class-level registration: linters call LinterService.register(MyLinter) at import time to self-register.

  • Central ignore rules: the service owns IgnoreConfig and enforces user intent via should_ignore before applying app-specific policy hooks.

API

Abstract linter

class craft_application.lint.base.AbstractLinter

Bases: ABC

Base class for all linters.

Linters should set:
  • name: stable identifier (used in ignore config)

  • stage: Stage.PRE or Stage.POST

abstract run(ctx: LintContext) Iterable[LinterIssue]

Execute the linter and yield issues.

Types

class craft_application.lint.Stage

Lifecycle stage for linting.

__new__(value)
class craft_application.lint.Severity

Severity level for linter issues.

__new__(value)
class craft_application.lint.ExitCode

Exit codes summarising lint results.

__new__(value)
class craft_application.lint.LintContext

Stage-agnostic environment for linters.

  • project_dir: the source tree on disk

  • project: the parsed project model (available for pre-lint)

  • artifact_dirs: list of directories with built artifacts (may be empty in pre-stage)

__init__(project_dir: Path, artifact_dirs: list[Path], project: Project | None = None) None
class craft_application.lint.LinterIssue

Single issue reported by a linter.

__init__(id: str, message: str, severity: Severity, filename: str, url: str = '') None
class craft_application.lint.IgnoreSpec

Suppression rules for one linter.

  • ids: “*” to ignore every issue, or a set of issue ids

  • by_filename: map of issue id -> set of filename globs

__init__(ids: str | set[str], by_filename: dict[str, set[str]]) None

IgnoreConfig is a dict[str, IgnoreSpec] mapping linter names to their ignore rules.

craft_application.lint.should_ignore(linter_name: str, issue: LinterIssue, cfg: dict[str, IgnoreSpec]) bool

Return True when issue is covered by the user’s ignore rules.

Uses issue id and optional shell-style filename globs per the approved design.

Service

class craft_application.services.linter.LinterService

Bases: AppService

Orchestrates linter registration, ignore config and execution.

__init__(app: AppMetadata, services: ServiceFactory) None
classmethod build_ignore_config(project_dir: Path, cli_ignores: IgnoreConfig | None = None) IgnoreConfig

Merge ignore config from app-specific project rules and CLI overrides.

get_highest_severity() Severity | None

Return the highest severity present among collected issues.

property issues: list[LinterIssue]

Return a copy of issues collected during the last run.

property issues_by_linter: dict[str, list[LinterIssue]]

Return collected issues grouped by linter name.

load_ignore_config(project_dir: Path, cli_ignores: IgnoreConfig | None = None) IgnoreConfig

Load ignore configuration using the class-level builder.

post_filter_issues(linter: AbstractLinter, issues: Iterable[LinterIssue], ctx: LintContext) Iterator[LinterIssue]

App-specific filtering hook.

pre_filter_linters(stage: Stage, ctx: LintContext, candidates: list[type[AbstractLinter]] | None = None) list[type[AbstractLinter]]

App-specific selection hook.

classmethod register(linter_cls: type[AbstractLinter]) None

Register a linter class for use by the service.

run(stage: Stage, ctx: LintContext) Iterator[LinterIssue]

Run linters for a stage, streaming non-suppressed issues.

summary() ExitCode

Return an exit code (non-zero only for errors).

For a step-by-step guide on adding linters, see Create a linter.

Ignore configuration

Users can suppress issues through app-specific rules stored in the project file (if supported) and/or CLI rules (if exposed by the application). The examples below show the IgnoreConfig shape that applications should map to:

snapcraft.desktop:
  ids: ["MISSING_ICON"]

# or glob-based suppression per issue id
snapcraft.desktop:
  by_filename:
    MISSING_ICON: ["*/examples/*"]

Apps can override build_ignore_config (e.g., Snapcraft can parse snapcraft.yaml: lint.ignore rules and fold them into the generic IgnoreConfig format).