Quickstart
This quickstart shows the fastest path to run pytest-notebook-policy in a project. Runtime baseline: Python 3.12+.
1) Install
Add as a development dependency:
uv add --dev pytest-notebook-policy
2) Run checks on a notebook
Run semantic checks with pytest:
uv run pytest --notebook-check path/to/notebook.py
Run semantic checks across multiple notebooks:
uv run pytest --notebook-check notebooks/
3) Interpret findings
Current rule codes:
M001: prefer reactive dependencies overon_changehandlers.M002: avoid mixing tests and helpers in the same cell.M003: avoid mutable module-level state.M004: keep fixtures out of notebook modules.M005: avoid cross-cell mutation of shared objects.M006: avoid non-idempotent calls in cells.J001: avoid notebook magics and shell escapes.J002: avoid non-idempotent calls in Jupyter code cells.J010: optional sync rule for paired.ipynband.pynotebooks.J011: require a top-of-notebook parameter/configuration cell.J012: keep notebooks and cells short enough to stay maintainable.J013: avoid excessive inline definitions; move reusable logic to modules.
Detailed rationale and remediation guidance: RULES.md. Report interpretation and policy-tuning workflow: REPORT_INTERPRETATION.md.
4) Optional: start with a proportionate rule profile
Choose a baseline that matches your notebook context, then tighten over time.
PoC / exploratory (fast iteration with core guardrails):
uv run pytest-notebook-quality --skip-ruff \
--notebook-check-select M001 \
--notebook-check-select M003 \
--notebook-check-select M006 \
--notebook-check-select J011 \
notebooks/
MVP / delivery hardening (maintainability + reproducibility):
uv run pytest-notebook-quality --skip-ruff \
--notebook-check-select M \
--notebook-check-select J001 \
--notebook-check-select J002 \
--notebook-check-select J011 \
--notebook-check-select J012 \
--notebook-check-select J013 \
--notebook-check-ignore J010 \
notebooks/
Production / operational (full policy set):
uv run pytest-notebook-quality --skip-ruff \
--notebook-check-select M \
--notebook-check-select J \
notebooks/
Equivalent project defaults:
[tool.pytest_notebook_policy.quality]
# PoC profile example:
# select = ["M001", "M003", "M006", "J011"]
# MVP profile example:
# select = ["M", "J001", "J002", "J011", "J012", "J013"]
# ignore = ["J010"]
# Production profile example:
select = ["M", "J"]5) Optional: enable by default
Add to pyproject.toml:
[tool.pytest.ini_options]
notebook_check = truePrefer paired .py notebooks for Jupyter rule checks:
[tool.pytest.ini_options]
notebook_check = true
notebook_check_jupyter_source = "paired-py"Or set it on the command line:
uv run pytest --notebook-check --notebook-check-jupyter-source paired-py notebooks/
Tune J012/J013 thresholds:
uv run pytest --notebook-check \
--notebook-check-jupyter-max-code-cells 30 \
--notebook-check-jupyter-max-cell-lines 120 \
--notebook-check-jupyter-max-inline-definitions 5 notebooks/
Or set defaults:
[tool.pytest.ini_options]
notebook_check_jupyter_max_code_cells = "30"
notebook_check_jupyter_max_cell_lines = "120"
notebook_check_jupyter_max_inline_definitions = "5"6) Optional: run combined quality checks
Run Ruff and notebook policy checks together:
uv run pytest-notebook-quality notebooks/
Skip Ruff and run only semantic checks:
uv run pytest-notebook-quality --skip-ruff notebooks/
Customise rule toggles and thresholds:
uv run pytest-notebook-quality --skip-ruff \
--notebook-check-select M \
--notebook-check-select J \
--notebook-check-ignore J010 \
--notebook-check-jupyter-source paired-py \
--notebook-check-jupyter-max-code-cells 30 \
--notebook-check-jupyter-max-cell-lines 120 \
--notebook-check-jupyter-max-inline-definitions 5 \
notebooks/
Write an NBOM-style JSON manifest:
uv run pytest-notebook-quality --skip-ruff \
--report-nbom-json reports/notebook-policy-nbom.json \
--report-dependency-enrichment \
notebooks/
Include optional vulnerability IDs (queried from OSV):
uv run pytest-notebook-quality --skip-ruff \
--report-nbom-json reports/notebook-policy-nbom.json \
--report-dependency-vulns \
notebooks/
--report-dependency-vulns implicitly enables dependency enrichment.
Write a markdown report (with why/remediation guidance per finding):
uv run pytest-notebook-quality --skip-ruff --report-md reports/notebook-policy-report.md notebooks/
Add optional dependency enrichment to include import-to-package metadata:
uv run pytest-notebook-quality --skip-ruff \
--report-md reports/notebook-policy-report.md \
--report-dependency-enrichment \
notebooks/
Set project-specific defaults in pyproject.toml:
[tool.pytest_notebook_policy.quality]
select = ["M", "J"]
ignore = ["J010"]
jupyter_source = "paired-py"
jupyter_max_code_cells = 30
jupyter_max_cell_lines = 120
jupyter_max_inline_definitions = 5
report_md = "reports/notebook-policy-report.md"
report_dependency_enrichment = true
report_dependency_vulns = false
report_nbom_json = "reports/notebook-policy-nbom.json"Enable optional sync tooling:
uv add --dev 'pytest-notebook-policy[sync]'
7) Optional: prek hook
Example local hook:
repos:
- repo: local
hooks:
- id: pytest-notebook-quality
name: pytest-notebook-quality
entry: uv run pytest-notebook-quality notebooks
language: system
pass_filenames: falseInstall and run hooks:
uv run prek install
uv run prek run pytest-notebook-quality --all-files
8) Manual validation and remediation workflow
For a full manual testing walkthrough (including complex notebook remediation and new notebook authoring guidance for both .ipynb and .py), see: