Skip to main content

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 over select on 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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

cacao_nib-0.1.1.tar.gz (38.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

cacao_nib-0.1.1-py3-none-any.whl (21.4 kB view details)

Uploaded Python 3

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

Hashes for cacao_nib-0.1.1.tar.gz
Algorithm Hash digest
SHA256 23968c2535145a74d005487a334d2421924f335f737de7a073cb6a0849d146ae
MD5 f0aa926a3dffc5713b60a3b29b0cce5f
BLAKE2b-256 3c22af79bb8b8e3e87db1c549c616fb472b7f41640f8f8668265282428f8819d

See more details on using hashes here.

Provenance

The following attestation bundles were made for cacao_nib-0.1.1.tar.gz:

Publisher: publish.yml on g-nie/cacao-nib

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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

Hashes for cacao_nib-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 35d3ce55f0dd79f2c570b48d081e19c541a6f88b5a30675362918b4227ab2d11
MD5 16bbfc46fa4e5654cb947d9778ffb1a0
BLAKE2b-256 95eca43c5eca84f1641d80551dcc6613a880cb882d50adf4280fe37dc59b3327

See more details on using hashes here.

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

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page