A pluggable framework for writing Python lint rules on the standard-library AST.
Project description
cacao-nib (nib)
A pluggable framework for writing Python lint rules on top of the stdlib
ast module. Ships zero builtin rules: rules live in plugin packages you write or install.
Plugins are loaded explicitly via [tool.nib] plugins = [...] in pyproject.toml,
so what runs is exactly what you list.
Installation
Requires Python 3.14+.
cacao-nib isn't on PyPI yet, so you can install it from GitHub:
python -m pip install git+https://github.com/g-nie/cacao-nib.git
Usage
nib check # lint current directory (recursive)
nib check path/to/file.py
nib check --plugins nib_rules
nib check --select X001,DJ # only these codes/groups
nib check --ignore X002 --extend-ignore DJ # ignore X002, then also skip the DJ group
Run nib --help for the full set of options; each subcommand takes --help
too (e.g. nib check --help).
[tool.nib] is read from the nearest pyproject.toml, found by searching up
from the current directory (a pyproject.toml without a [tool.nib] table
is skipped and the search continues in the parent). So running nib from a
subdirectory still picks up the project's config:
[tool.nib]
plugins = ["nib_rules"]
select = ["X001", "DJ"] # optional - empty = run everything
ignore = ["X002"] # optional
plugins- the rule modules to load. With none, nib has no rules and every file is "clean".select- codes/groups to run; omitted or empty runs every loaded rule.ignore- codes/groups to skip; takes precedence overselecton overlap.
CLI --select / --ignore replace their config counterparts;
--extend-select / --extend-ignore add to them. Each token is matched
exactly against either a rule's code or a rule's group.
Each entry in plugins is just an importable module name: nib imports it and
the Rule subclasses defined there register themselves. So a plugin can be a
third-party package you pip install, or a module that lives in your own repo.
In-repo rules (no install needed)
The plugin doesn't have to be a published package. nib prepends the project
root (the directory of the pyproject.toml it found) to sys.path before
importing plugins, so any importable module sitting next to your
pyproject.toml works from anywhere in the tree. Example layout:
your_repo/
pyproject.toml # [tool.nib] plugins = ["nib_rules"]
nib_rules/
__init__.py # your Rule subclasses live here
src/your_app/...
Then nib check picks them up from your_repo or any subdirectory of it.
Writing a rule
A rule is a Python class with visit_<AstName> methods:
from nib import Rule, Diagnostic, ast
class NoEval(Rule):
code = "X001"
group = "X" # optional. `--select X` then picks every rule in this group
def visit_Call(self, node):
if isinstance(node.func, ast.Name) and node.func.id == "eval":
return [Diagnostic(node, "no eval")]
Subclassing Rule auto-registers it; the visit_<AstName> methods mirror
ast.NodeVisitor's
dispatch. code identifies the individual rule; group (optional) is a category label
shared by related rules so users can select/ignore them as a set.
Suppressing diagnostics
eval("x") # noqa — suppress every code on this line
eval("x") # noqa: X001 — suppress only X001
eval("x"); print("y") # noqa: X001,X002 — multiple codes
The comment must sit on the same line as the diagnostic's reported position (for multi-line nodes, that's the start line).
Performance
On large runs nib checks files in parallel across CPU cores using subinterpreters. Small runs stay single-process to skip the startup overhead. Repeat runs are cached on top of that (see below).
nib is benchmarked against a full Django checkout; the results are tracked here.
Caching
A re-run skips files that haven't changed since they last passed, so repeated
nib invocations are very fast on an unchanged tree. The cache lives in
./.cacao_nib_cache, keyed by nib version and enabled rule set - a new release
or a different --select/--ignore/plugin list invalidates the cache. Only clean files
are cached; files with diagnostics are re-checked (and re-reported) until fixed.
nib check --no-cache # ignore the cache: check every file
nib check --cache-dir path/to/c # use a different cache directory
Pre-commit
nib ships a pre-commit hook. Add to your .pre-commit-config.yaml:
repos:
- repo: https://github.com/g-nie/cacao-nib
rev: v0.1.1
hooks:
- id: nib
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file cacao_nib-0.1.1.tar.gz.
File metadata
- Download URL: cacao_nib-0.1.1.tar.gz
- Upload date:
- Size: 38.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
23968c2535145a74d005487a334d2421924f335f737de7a073cb6a0849d146ae
|
|
| MD5 |
f0aa926a3dffc5713b60a3b29b0cce5f
|
|
| BLAKE2b-256 |
3c22af79bb8b8e3e87db1c549c616fb472b7f41640f8f8668265282428f8819d
|
Provenance
The following attestation bundles were made for cacao_nib-0.1.1.tar.gz:
Publisher:
publish.yml on g-nie/cacao-nib
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
cacao_nib-0.1.1.tar.gz -
Subject digest:
23968c2535145a74d005487a334d2421924f335f737de7a073cb6a0849d146ae - Sigstore transparency entry: 1766547677
- Sigstore integration time:
-
Permalink:
g-nie/cacao-nib@124d028451a55b42d3549ddd1ee19bff63046cf1 -
Branch / Tag:
refs/tags/0.1.1 - Owner: https://github.com/g-nie
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@124d028451a55b42d3549ddd1ee19bff63046cf1 -
Trigger Event:
release
-
Statement type:
File details
Details for the file cacao_nib-0.1.1-py3-none-any.whl.
File metadata
- Download URL: cacao_nib-0.1.1-py3-none-any.whl
- Upload date:
- Size: 21.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
35d3ce55f0dd79f2c570b48d081e19c541a6f88b5a30675362918b4227ab2d11
|
|
| MD5 |
16bbfc46fa4e5654cb947d9778ffb1a0
|
|
| BLAKE2b-256 |
95eca43c5eca84f1641d80551dcc6613a880cb882d50adf4280fe37dc59b3327
|
Provenance
The following attestation bundles were made for cacao_nib-0.1.1-py3-none-any.whl:
Publisher:
publish.yml on g-nie/cacao-nib
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
cacao_nib-0.1.1-py3-none-any.whl -
Subject digest:
35d3ce55f0dd79f2c570b48d081e19c541a6f88b5a30675362918b4227ab2d11 - Sigstore transparency entry: 1766547878
- Sigstore integration time:
-
Permalink:
g-nie/cacao-nib@124d028451a55b42d3549ddd1ee19bff63046cf1 -
Branch / Tag:
refs/tags/0.1.1 - Owner: https://github.com/g-nie
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@124d028451a55b42d3549ddd1ee19bff63046cf1 -
Trigger Event:
release
-
Statement type: