noqaexplain
Comply or explain - justify every ignored linting rule.
✨ Features 🚀 Quick start 📚 Documentation 🤝 Contribute 👍 Adopters 📜 Legal
Features
noqaexplain is a linter which enforces justifying every ignored linting rule supporting multiple formats/linters:
- Python -
ruffandflake8# noqa,coveragepy# pragma: no cover, andlintkitline, span, and file suppressions - JavaScript/TypeScript -
eslint - Rust -
clippy - Dockerfiles -
hadolint - YAML -
yamllintandlintkitline, span, and file suppressions - TOML -
lintkitline, span, and file suppressions - Markdown -
PyMarkdown,Vale, andmd-dead-link-check - Shell -
shellcheck
[!IMPORTANT] You can expand this list with any language and linter by using
extend_mapping_suffixand/orextend_mapping_name! Feel free to open a request to add support for more linters.
Table of contents
Quick start
Installation
[!TIP] You can use your favorite package manager like
uv,hatchorpdminstead ofpip.
> pip install noqaexplain[all]
To install rich output and MCP server as well:
> pip install noqaexplain[all]
Usage
To check against all files (the ones with defined mappings from file extension to error disable comment format), run:
> noqaxplain check
You can pass additional arguments to noqaexplain check, like files
to check:
> noqaexplain check path/to/file.py maybe.rs other.yml formats.js
If a certain file has a line with disabled check without an explanation, the tool will report it:
path/to/file.py:10:5: ENQ0 Missing explanation (enoqa) for disabled linting rule
to fix it, just add an explanation after the disable comment prefixed by enq:,
e.g.:
import some_library
# enq: Disabled private access check as there is no other workaround currently.
# noqa: SLF001
some_library._private_function()
The same rule applies to opening span and file-wide lintkit directives:
# enq: Generated settings are checked separately before publication.
# noqa-file: MYLINTER1
# enq: This generated section cannot follow the repository style.
# noqa-start: MYLINTER2
generated = true
# noqa-end: MYLINTER2
Markdown suppressions use an HTML comment for the explanation:
<!-- enq: Generated content cannot satisfy the line length rule. -->
<!-- pyml disable-next-line line-length -->
Markdown matching uses the literal comment prefixes <!-- pyml, <!-- vale,
and <!-- md-dead-link-check. Every matching comment needs an explanation.
Advanced
Configuration
You can configure noqaexplain in pyproject.toml (or .noqaexplain.toml
in the root of your project, just remove the [tool.noqaexplain] section),
for example:
[tool.noqaexplain]
# include rules by their complete, case-sensitive name
names = ["ENQ0"] # default: all rules included
# whether to exit after first error or all errors
end_mode = "first" # default: "all"
# Extends Python noqas mappings
# Now every # my_noqa_header: will be treated as a noqa comment
# and checked for explanations.
extend_mapping_suffix = {".py" = ["# my_noqa_header:"]}
# Target any MySuperFile.md file(s) and look for explanations
extend_mapping_name = {"MySuperFile.md" = ["# my_noqa_header:"]}
[!TIP] Rule-specific configuration can be found in the section below.
Run as a pre-commit hook
noqaexplain can be used as a pre-commit hook, to add as a plugin:
repos:
- repo: "https://github.com/open-nudge/noqaexplain"
rev: ... # select the tag or revision you want, or run `pre-commit autoupdate`
hooks:
- id: "noqaexplain"
Rules
[!TIP] Run
noqaexplain rulesto see the list of available rules.
noqaexplain provides the following rules:
| Name | Description |
|---|---|
NQE0 |
Ensures that all disabled linting rules have an explanation on the nearest preceding nonblank line |
NQE1 |
Ensures that all disabled linting rules have an associated explanation of at least |
and the following configurable options (in pyproject.toml
or .noqaexplain.toml):
| Option | Description | Affected rules | Default |
|---|---|---|---|
extend_mapping_suffix |
Additional file suffix to noqa comment(s) format mappings (dict of lists) | All | {} |
extend_mapping_name |
Additional file name to noqas comment(s) format mappings (dict of lists) | All | {} |
mapping_suffix |
File suffix to noqa comment format(s) mappings (dict of lists, overrides default!) | All | {} |
mapping_name |
File name to noqa comment format(s) mappings (dict of lists, overrides default!) | All | {} |
min_explain_length |
Minimum length of explanation for disabled linting rules | NQE1 | 10 |
explain_noqa_pattern |
String identifying explanation for disabled linting rule | NQE0 | "enq:" |
Contribute
We welcome your contributions! Start here:
Legal
- This project is licensed under the Apache 2.0 License - see the LICENSE file for details.
- This project is copyrighted by open-nudge - the appropriate copyright notice is included in each file.
Metadata
Release files for noqaexplain 1.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| noqaexplain-1.0.0.tar.gz | 18.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| noqaexplain-1.0.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 30.0 kB
Release files / noqaexplain-1.0.0.tar.gz
| Download URL | noqaexplain-1.0.0.tar.gz |
|---|---|
| Size | 18.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
c94004bbe952052e8dd730b9382f7ac729214346e01f37cdfc943cf08488b6f5
|
|
BLAKE2b-256 checksum How to use checksums |
8cfad289e496dd22985dd80acb4f85e7a9bed015a1f406ca4cee8179d2d3635f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 31, 2026.
Transparency logRelease files / noqaexplain-1.0.0-py3-none-any.whl
| Download URL | noqaexplain-1.0.0-py3-none-any.whl |
|---|---|
| Size | 11.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
9cfe1b4909d406b087809768e2050d860ff2f978c098ae866730b29f617c69aa
|
|
BLAKE2b-256 checksum How to use checksums |
4274c0a3593dd3d6a5537de6182433d6208fb297c477feb9a1c07b4dd9ea6b66
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 31, 2026.
Transparency log