Jupyter notebook linter for hidden-state and execution-order bugs.
Project description
nborder
A fast, opinionated linter and auto-fixer for Jupyter notebook hidden-state and execution-order bugs.
What this catches
| Code | Name | One-line example |
|---|---|---|
| NB101 | Non-monotonic execution counts | Cell 1 ran with In [3]: after cell 0 ran with In [5]:. |
| NB102 | Won't survive Restart-and-Run-All | print(df) references a name no cell in the notebook defines. |
| NB201 | Use-before-assign across cells | Cell 0 uses df; df = ... only appears in cell 1. |
| NB103 | Stochastic library used without seed | np.random.rand(3) runs with no seed call before it. |
Each rule has a docs page under docs/rules/ explaining the bug class, a bad and good example, and the auto-fix behaviour.
Quick start
pip install nborder
nborder check notebook.ipynb
nborder check --fix notebook.ipynb
nborder check --output-format=json notebook.ipynb
The --fix flag reorders cells topologically when the dependency graph is a DAG, injects library-appropriate seed calls for stochastic libraries, and clears execution counts when they no longer reflect a reproducible run order. Every fix is a pipeline stage with a bailed outcome that does not block other fixes; running the same fix twice is a byte-stable no-op.
Pre-commit
Add this to your .pre-commit-config.yaml:
repos:
- repo: https://github.com/moonrunnerkc/nborder
rev: v0.1.0
hooks:
- id: nborder
Then pre-commit install. Full setup notes in docs/integrations/pre-commit.md.
GitHub Actions
- uses: moonrunnerkc/nborder@v0.1.0
with:
path: notebooks/
Diagnostics show up as inline annotations on the PR. Full options in docs/integrations/github-actions.md.
Configuration
nborder reads its configuration from [tool.nborder] in pyproject.toml:
[tool.nborder.seeds]
value = 42
libraries = ["numpy", "torch", "tensorflow", "random"]
Run nborder config to print the effective merged configuration.
FAQ
Why not use ruff? Ruff lints Python source, not notebook structure. It does not see cross-cell dataflow, so it cannot detect that df is used in cell 0 and only defined in cell 1. nborder is purpose-built for the cross-cell story; it is complementary to ruff, not competitive.
How is this different from nbqa? nbqa runs Python linters against notebook cells one at a time. nborder builds a cross-cell symbol dependency graph and reasons about the relationships between cells, which is the part nbqa explicitly does not do.
Does it work with R or Julia notebooks? Not in v0.1. Multi-language support is reserved for a future release. Python kernels cover roughly 95% of notebooks in the wild.
Will it modify my notebook outputs? No. Outputs, cell metadata, and notebook-level metadata are read-only. The only fix that touches execution_count is a clear-to-null operation that runs as part of the reorder fix.
What about magics? %line, %%cell, !shell, and shell-assignment forms (files = !ls) are stripped to typed metadata before parsing. Magic-defined bindings (e.g., %%capture out defines out) are recorded in the dataflow graph; see docs/known-limitations.md for the limits.
How do I suppress a false positive? Add # nborder: noqa (suppress all rules in the cell) or # nborder: noqa: NB201,NB102 (suppress specific rules) to any line in the cell.
What if I want to disable a rule entirely? Rule selection lands in v0.2. For now, use # nborder: noqa: NB201 to suppress a rule for one cell.
What is on the roadmap? v0.2 adds project-wide rule selection and the opt-in fresh-kernel --reproduce pass. The static linter remains the default path.
Contributing
See CONTRIBUTING.md.
License
MIT. See LICENSE.
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 nborder-0.1.2.tar.gz.
File metadata
- Download URL: nborder-0.1.2.tar.gz
- Upload date:
- Size: 47.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 |
5d87c4cffdb53b64eb1a1fea0ebddb96921978ad46cdb7016e22fb7fe7883dac
|
|
| MD5 |
78e232706b3b77b59bb2c979b0a12cf9
|
|
| BLAKE2b-256 |
4f39b9c9e8c82cc722cc536b8d1489ca0d7d8313f6353af32e3b3f22d0384555
|
Provenance
The following attestation bundles were made for nborder-0.1.2.tar.gz:
Publisher:
release.yml on moonrunnerkc/nborder
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
nborder-0.1.2.tar.gz -
Subject digest:
5d87c4cffdb53b64eb1a1fea0ebddb96921978ad46cdb7016e22fb7fe7883dac - Sigstore transparency entry: 1392568399
- Sigstore integration time:
-
Permalink:
moonrunnerkc/nborder@4136947068d531c5d6d2d41b190997c90fcd496b -
Branch / Tag:
refs/tags/v0.1.2 - Owner: https://github.com/moonrunnerkc
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@4136947068d531c5d6d2d41b190997c90fcd496b -
Trigger Event:
push
-
Statement type:
File details
Details for the file nborder-0.1.2-py3-none-any.whl.
File metadata
- Download URL: nborder-0.1.2-py3-none-any.whl
- Upload date:
- Size: 41.9 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 |
6f93f398940d3f4553986f8d8a7ba8dc03d6e3ad965131123bb3919252f28c2c
|
|
| MD5 |
89389b8135429d8aba325fe3e1d188b6
|
|
| BLAKE2b-256 |
8a6cdf6443f576ef21e5aa5a57b4db76c8e166970dc411909971600bd649048a
|
Provenance
The following attestation bundles were made for nborder-0.1.2-py3-none-any.whl:
Publisher:
release.yml on moonrunnerkc/nborder
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
nborder-0.1.2-py3-none-any.whl -
Subject digest:
6f93f398940d3f4553986f8d8a7ba8dc03d6e3ad965131123bb3919252f28c2c - Sigstore transparency entry: 1392568408
- Sigstore integration time:
-
Permalink:
moonrunnerkc/nborder@4136947068d531c5d6d2d41b190997c90fcd496b -
Branch / Tag:
refs/tags/v0.1.2 - Owner: https://github.com/moonrunnerkc
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@4136947068d531c5d6d2d41b190997c90fcd496b -
Trigger Event:
push
-
Statement type: