Skip to content

noqa-justification (KNQ001)

noqa justification

What it does

Requires every # noqa comment to carry a reason. The reason is any text after the directive in the same comment (leading #, - and : are ignored, but it needs at least one letter or digit). The # noqa: CODE # reason form is recommended because it reads the same to every tool that parses the comment. Only real comments count: # noqa inside a string literal is not flagged. Opt-in: the rule is not run by default; enable it with extend-select = ["KNQ001"] in [tool.konform.lint] (or --extend-select KNQ001).

Why is this bad?

A bare suppression hides a violation without recording why that is fine. Months later nobody knows whether it is still needed or safe to remove. A short reason makes the exception reviewable.

Example

from os.path import join   # noqa: KIS001
value = compute()          # noqa

Use instead:

from os.path import join   # noqa: KIS001  # re-exported for plugins
value = compute()          # noqa: KPT010 - generated code

Placeholder reasons

A reason that only repeats a placeholder is flagged too. The whole reason has to match (ignoring case, spacing and a trailing ./!), so todo: drop in v3 or ok for generated code are fine. Tighten the list in [tool.konform.lint.noqa-justification]:

[tool.konform.lint.noqa-justification]
extend-placeholder-reasons = ["legacy", "needed"]  # add to the defaults
# placeholder-reasons = ["ok", "todo"]  # ... or replace them ([] = off)

Minimum length

A reason needs at least 3 letters (ab or #123 alone are flagged), and a reason that is one repeated character (xxxx, 1111, a a a) is rejected. Both are configurable:

[tool.konform.lint.noqa-justification]
min-reason-letters = 5               # default 3; 0 = no minimum
reject-repeated-characters = false   # default true

Exempt codes

Some suppressions explain themselves, such as F401 on a re-export or E501 on a long URL. List those codes (prefixes, like # noqa) and their comments need no reason:

[tool.konform.lint.noqa-justification]
exempt-codes = ["F401", "E501"]

The comment is only exempt when every listed code is. # noqa: F401, KIS001 still needs a reason, and a bare # noqa is never exempt. To exempt whole files instead (say __init__.py), use per-file-ignores: "**/__init__.py" = ["KNQ001"].

Suppressing and fixing

This rule cannot be suppressed with # noqa (not even # noqa: KNQ001), and --ignore-noqa does not affect it. Turn it off with ignore or per-file-ignores instead. It is not fixable. konform check --add-noqa --noqa-reason "..." fills in a missing reason on the comments it flags (see Baselining).

Options

Configured in [tool.konform.lint.noqa-justification].

Option Type Default Description
level "warning" \| "error" "error" Severity of violations. Set warning to roll the rule out gradually.
placeholder-reasons list[str] ["ok", "fine", "todo", "fixme", "tbd", "wip", "later", "fix later", "n/a", "ignore", "noqa"] Reasons that say nothing. Replaces the defaults; [] turns the check off.
extend-placeholder-reasons list[str] [] Added to the placeholder list (default or replaced).
min-reason-letters int 3 Letters a reason needs; 0 = no minimum.
reject-repeated-characters bool true Reject a reason made of one repeated character (xxxx).
exempt-codes list[str] [] Code prefixes whose # noqa comments need no reason.

Suppression

x = 1  # noqa: KNQ001
x = 1  # noqa: KNQ  (every KNQ* rule)