From 4b9253d3fd02e61763d6dd4f6c41824e9583f2d1 Mon Sep 17 00:00:00 2001 From: Michael Booth Date: Sat, 20 Jun 2026 16:49:45 +1000 Subject: [PATCH] Migrate hooks to prek and release 1.0.2 Co-Authored-By: Oz --- .pre-commit-config.yaml | 18 ------------ README.md | 23 ++++++++------- RELEASE_NOTES.md | 12 ++++++++ ROADMAP.md | 4 +-- docs/MANUAL_NOTEBOOK_VALIDATION.md | 9 +++--- docs/QUICKSTART.md | 9 +++++- docs/README.md | 2 +- .../blog/announcing-pytest-notebook-policy.md | 2 +- justfile | 6 ++++ prek.toml | 23 +++++++++++++++ pyproject.toml | 3 +- uv.lock | 28 ++++++++++++++++++- 12 files changed, 100 insertions(+), 39 deletions(-) delete mode 100644 .pre-commit-config.yaml create mode 100644 prek.toml diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml deleted file mode 100644 index a0f287a..0000000 --- a/.pre-commit-config.yaml +++ /dev/null @@ -1,18 +0,0 @@ -repos: - - repo: local - hooks: - - id: ruff-check - name: ruff-check - entry: uv run ruff check src tests - language: system - pass_filenames: false - - id: pytest-tests - name: pytest-tests - entry: uv run python -m pytest tests - language: system - pass_filenames: false - - id: pytest-report-regressions - name: pytest-report-regressions - entry: uv run python -m pytest tests/test_quality.py tests/test_report_regressions.py - language: system - pass_filenames: false diff --git a/README.md b/README.md index 98785f9..a4e1172 100644 --- a/README.md +++ b/README.md @@ -10,20 +10,23 @@ If you are looking for notebook **best practices**, **assurance**, **validation* ## What this package is `pytest-notebook-policy` is a lightweight semantic checker for notebook workflows. -It focuses on enforcing notebook patterns that are easy to miss in review, such as: +It focuses on enforcing notebook patterns that are easy to miss in review. + +### Patterns checked - `on_change` callback usage where reactivity is clearer - cross-cell mutation of shared objects - non-idempotent cell behaviour - mixed test/helper cells and fixture placement conventions ## Why this package exists -marimo already gives you: + +### What marimo already covers - native notebook testing with `pytest` - built-in notebook linting via `marimo check` ([announcement](https://marimo.io/blog/marimo-check)) `pytest-notebook-policy` is designed to complement those tools with opinionated, team-level checks tailored to a stricter “production notebook” style. -In practice: +### In practice - use **Ruff** for general Python quality/security - use **marimo check** for core notebook validity and formatting rules - use **pytest-notebook-policy** for extra policy checks around reactive design and notebook maintainability @@ -31,9 +34,9 @@ In practice: ## Machine-assisted coding guardrails `pytest-notebook-policy` is especially useful as an automated quality gate when notebooks are generated or edited by coding agents (for example Claude, Warp, Codex, or similar tools). -Adding it to pre-commit and CI helps catch marimo-specific issues immediately, so agents can self-correct before code reaches review. +Adding it to prek hooks and CI helps catch marimo-specific issues immediately, so agents can self-correct before code reaches review. -Example pre-commit hook: +Example prek hook configuration: ```yaml repos: @@ -46,9 +49,9 @@ repos: pass_filenames: false ``` -This keeps the feedback loop short: +### Feedback loop - agent proposes notebook edits -- pre-commit/CI runs Ruff + `pytest-notebook-policy` checks +- prek/CI runs Ruff + `pytest-notebook-policy` checks - agent fixes violations and retries ## Current rules @@ -74,16 +77,16 @@ Install in a project: uv add --dev pytest-notebook-policy ``` -Install pre-commit hooks: +Install prek hooks: ```shell -uv run --with pre-commit pre-commit install +uv run prek install ``` Run hooks across all files: ```shell -uv run --with pre-commit pre-commit run --all-files +uv run prek run --all-files ``` CI runs on push/PR using `.github/workflows/ci.yml` and executes Ruff plus the test suite. diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 048a9be..45337cb 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -5,6 +5,18 @@ This project follows Semantic Versioning (`MAJOR.MINOR.PATCH`). ### Changed - No unreleased entries yet. +## [1.0.2] - Hook tooling migration and docs quality fixes +### Release intent +- Improve local quality-gate ergonomics and documentation reliability without changing runtime policy behaviour. + +### Highlights +- Migrated local hook tooling from `pre-commit` to `prek` using a dedicated `prek.toml` configuration. +- Added `prek` as a development dependency and updated project docs/commands to use `prek`. +- Added `just` hook helper recipes for installing and running repository hooks with `prek`. +- Fixed README section/list formatting so key guidance renders correctly in generated docs output. +- Removed legacy `.pre-commit-config.yaml` from the repository to avoid dual-config ambiguity. +- Confirmed GitHub Pages deployment now runs via workflow mode with successful docs publication from `main`. + ## [1.0.0] - Stable baseline + Great Docs foundation ### Release intent - Mark the first stable major release and establish a modern runtime/docs baseline for ongoing development. diff --git a/ROADMAP.md b/ROADMAP.md index c55cb6c..3a27047 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -16,7 +16,7 @@ This document captures likely next steps for `pytest-notebook-policy` after the ## Immediate easy wins (prioritised) 1. Improve docs for report interpretation and policy tuning workflows. - Why first: highest user impact for lowest implementation effort. -2. Tighten pre-commit and CI quality gates around report regressions. +2. Tighten prek and CI quality gates around report regressions. - Why second: mostly workflow configuration with fast confidence gains. 3. Expand example notebooks and fixture coverage for real-world edge cases. - Why third: incremental additions that improve trust and regression safety. @@ -49,6 +49,6 @@ This document captures likely next steps for `pytest-notebook-policy` after the - complements deterministic rules with human-readable improvement suggestions ## Release and ecosystem readiness -- Tighten pre-commit and CI quality gates around report regressions. +- Tighten prek and CI quality gates around report regressions. - Publish and maintain clear release notes and upgrade guidance. - Expand example notebooks and fixture coverage for real-world edge cases. diff --git a/docs/MANUAL_NOTEBOOK_VALIDATION.md b/docs/MANUAL_NOTEBOOK_VALIDATION.md index 2dd304e..7842304 100644 --- a/docs/MANUAL_NOTEBOOK_VALIDATION.md +++ b/docs/MANUAL_NOTEBOOK_VALIDATION.md @@ -31,7 +31,7 @@ Run policy checks directly: uv run pytest-notebook-quality --skip-ruff manual_checks ``` -Optional pre-commit hook (local/manual usage): +Optional prek hook (local/manual usage): ```yaml repos: @@ -47,7 +47,8 @@ repos: Then run: ```shell -uv run --with pre-commit pre-commit run notebook-policy-manual --all-files +uv run prek install +uv run prek run notebook-policy-manual --all-files ``` ## 2) New notebook guide (`.ipynb` and `.py`) @@ -164,10 +165,10 @@ When stable, run on the whole manual check area: uv run pytest-notebook-quality --skip-ruff manual_checks ``` -If using pre-commit: +If using prek: ```shell -uv run --with pre-commit pre-commit run notebook-policy-manual --all-files +uv run prek run notebook-policy-manual --all-files ``` ### Stage D: Compliance sign-off diff --git a/docs/QUICKSTART.md b/docs/QUICKSTART.md index 32786dd..896d959 100644 --- a/docs/QUICKSTART.md +++ b/docs/QUICKSTART.md @@ -215,7 +215,7 @@ Enable optional sync tooling: uv add --dev 'pytest-notebook-policy[sync]' ``` -## 7) Optional: pre-commit hook +## 7) Optional: prek hook Example local hook: ```yaml @@ -229,6 +229,13 @@ repos: pass_filenames: false ``` +Install and run hooks: + +```shell +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: diff --git a/docs/README.md b/docs/README.md index d61adb4..629a6cb 100644 --- a/docs/README.md +++ b/docs/README.md @@ -2,7 +2,7 @@ This directory contains focused documentation for `pytest-notebook-policy`. ## Available docs -- [`QUICKSTART.md`](QUICKSTART.md): install, first run, and CI/pre-commit examples. +- [`QUICKSTART.md`](QUICKSTART.md): install, first run, and CI/prek examples. - [`REPORT_INTERPRETATION.md`](REPORT_INTERPRETATION.md): interpreting markdown/NBOM outputs and tuning policy profiles proportionately. - [`JUST_SETUP.md`](JUST_SETUP.md): using the repository's `just` recipes and where to install Just. - [`MANUAL_NOTEBOOK_VALIDATION.md`](MANUAL_NOTEBOOK_VALIDATION.md): manual behaviour validation, second-stage remediation checklist, and authoring guide for new `.ipynb` and marimo `.py` notebooks. diff --git a/docs/blog/announcing-pytest-notebook-policy.md b/docs/blog/announcing-pytest-notebook-policy.md index b4bb1a7..b74d9b7 100644 --- a/docs/blog/announcing-pytest-notebook-policy.md +++ b/docs/blog/announcing-pytest-notebook-policy.md @@ -14,7 +14,7 @@ The goal is simple: preserve the agility that makes notebooks powerful, while re ## Fast with confidence, not fast and fragile This package is designed so policy does not become a drag on delivery. -In the same way well-configured Ruff linting rules, enforced via pre-commit hooks, enable rapid high-quality code delivery, this package is the notebook equivalent: it guides and coaches users towards better outcomes while preserving notebook velocity. +In the same way well-configured Ruff linting rules, enforced via prek hooks, enable rapid high-quality code delivery, this package is the notebook equivalent: it guides and coaches users towards better outcomes while preserving notebook velocity. The intent is to help you **move faster confidently**, not slow you down: diff --git a/justfile b/justfile index 664c0ca..81a0f90 100644 --- a/justfile +++ b/justfile @@ -23,6 +23,12 @@ qa: uv run ruff check src tests scripts uv run python -m pytest tests +hooks-install: + uv run prek install + +hooks-run: + uv run prek run --all-files + docs-build: uv run great-docs build diff --git a/prek.toml b/prek.toml new file mode 100644 index 0000000..46d7019 --- /dev/null +++ b/prek.toml @@ -0,0 +1,23 @@ +[[repos]] +repo = "local" + +[[repos.hooks]] +id = "ruff-check" +name = "ruff-check" +entry = "uv run ruff check src tests" +language = "system" +pass_filenames = false + +[[repos.hooks]] +id = "pytest-tests" +name = "pytest-tests" +entry = "uv run python -m pytest tests" +language = "system" +pass_filenames = false + +[[repos.hooks]] +id = "pytest-report-regressions" +name = "pytest-report-regressions" +entry = "uv run python -m pytest tests/test_quality.py tests/test_report_regressions.py" +language = "system" +pass_filenames = false diff --git a/pyproject.toml b/pyproject.toml index a33b783..58d1ed6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "pytest-notebook-policy" -version = "1.0.0" +version = "1.0.2" description = "Pytest plugin for notebook policy and quality checks" readme = "README.md" license = "MIT" @@ -49,6 +49,7 @@ build-backend = "uv_build" dev = [ "great-docs>=0.14.0", "jupytext>=1.16", + "prek>=0.4.5", "pytest>=8.0", "ruff>=0.14.0", ] diff --git a/uv.lock b/uv.lock index 472a3fa..166ae3b 100644 --- a/uv.lock +++ b/uv.lock @@ -1178,6 +1178,30 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" }, ] +[[package]] +name = "prek" +version = "0.4.5" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/2f/65/23866f43521d31173879aa74bb3a2df50ab7f3f74cdb4eaa31b8f446c7ca/prek-0.4.5.tar.gz", hash = "sha256:2be7bcf839de19a0144ed5a5aadf73bc5899cf6823bb1c58cf1d45ae389c201a", size = 482566, upload-time = "2026-06-15T11:36:48.299Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f4/cb/a9eedf9a35ca6ec72f12af2b4392d7f757bb24863b7b7af4523f939cf3fa/prek-0.4.5-py3-none-linux_armv6l.whl", hash = "sha256:f7517774c72b001573520dc7111156779fd3e5b4452c11f09ff53c71a067e835", size = 5618105, upload-time = "2026-06-15T11:36:21.998Z" }, + { url = "https://files.pythonhosted.org/packages/30/a7/c96c06f17db7da0a57be2be4c229aa00b525bca8001c9c765663b339cbb7/prek-0.4.5-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:aca9fa995536036a0171bcf7a4db96dc0a14f480054eda1d7d1c2e7739650993", size = 5972998, upload-time = "2026-06-15T11:36:41.12Z" }, + { url = "https://files.pythonhosted.org/packages/28/f1/721695355cdaa44be6f091e3a77fb9c72ed60289520f78b2f8c9a7197bdd/prek-0.4.5-py3-none-macosx_11_0_arm64.whl", hash = "sha256:66877ff21ae9d548f0f7e56fab8e65f1500a74a810e7749188c3f35a4a1b911b", size = 5525098, upload-time = "2026-06-15T11:36:30.127Z" }, + { url = "https://files.pythonhosted.org/packages/9b/1b/a334e1bb5361b49adf52b5ac7b6532018940f9f0f253437e8f43c3c1f7f3/prek-0.4.5-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.musllinux_1_1_aarch64.whl", hash = "sha256:50697089a86a78d16f087c1912a2f3bc2bea82319a220fac52cc8e3ec9fc0426", size = 5793732, upload-time = "2026-06-15T11:36:35.745Z" }, + { url = "https://files.pythonhosted.org/packages/28/8c/aff94d276e91207a87cedff7cfefdd4aca20444137cca77bf53fffebe77a/prek-0.4.5-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:590427a42a3c1e5064487a0dc91167ae0c8a52168e77f574758ef9b138fcfd61", size = 5521719, upload-time = "2026-06-15T11:36:39.383Z" }, + { url = "https://files.pythonhosted.org/packages/4f/73/cfb0c5c909442050a8357e26233f7e511ba8e0d2f4b0bdc460065d62beb6/prek-0.4.5-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1fd98b986767dafdb6b4305b563ee5a3a8f13bd3c78b98d708626815ea9f147f", size = 5922623, upload-time = "2026-06-15T11:36:18.063Z" }, + { url = "https://files.pythonhosted.org/packages/0a/ad/ff9d26551ba80d190bd08c6341176a5d56d4e6de9c2ebf077793d4adbb78/prek-0.4.5-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fccd11613ae92619d1ecda0ab3359ceebeb38898909ec84a8d383733d12158cc", size = 6722071, upload-time = "2026-06-15T11:36:43.086Z" }, + { url = "https://files.pythonhosted.org/packages/d3/43/11d1dfd66c919953fe89ae2fdedd4f413ee923883043816d35982177bb75/prek-0.4.5-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14109d37b33e5529db41a3539d4f8f72d295f6eeddede3964994d898b8cec05c", size = 6176454, upload-time = "2026-06-15T11:36:33.803Z" }, + { url = "https://files.pythonhosted.org/packages/d7/d4/9749f25c2e0ee5225f812457b888acef301e0ccce64bebcda2ac1d04abee/prek-0.4.5-py3-none-manylinux_2_28_aarch64.whl", hash = "sha256:40d262418105b2ede9836593a1927fc927cc8093c432e998640964102196996e", size = 5791133, upload-time = "2026-06-15T11:36:23.891Z" }, + { url = "https://files.pythonhosted.org/packages/c7/72/5e0344bab1eacf813a5b1b082cb4c6253930096166dad51c1cccee0a4f83/prek-0.4.5-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:a586d14c3b852fdee1c3dcd0b9cb0915db9f9d054334b854fd9470bf68edf129", size = 5658098, upload-time = "2026-06-15T11:36:44.862Z" }, + { url = "https://files.pythonhosted.org/packages/be/a5/1f406e0362dd0f18ba09a562d50d7c04a70ac05d350b1ab6fba36ca3e9f0/prek-0.4.5-py3-none-musllinux_1_1_armv7l.whl", hash = "sha256:a8ed0d28f3e7790e4402a9324c386509066df6e67cc587f7406f9a245b97b7e8", size = 5498634, upload-time = "2026-06-15T11:36:31.828Z" }, + { url = "https://files.pythonhosted.org/packages/c7/df/b0cbf0fa527330188390b7b6c8d279cd5e509923262d0a6c5cc44bbdf103/prek-0.4.5-py3-none-musllinux_1_1_i686.whl", hash = "sha256:86f76bd3d2ecf6fd9034d75c62ff4c786eb11d0dd0a1f79bbb4343b023e12769", size = 5784840, upload-time = "2026-06-15T11:36:37.481Z" }, + { url = "https://files.pythonhosted.org/packages/9d/d7/977ee3c622c906677dd94187a00392ce2dd76035486b3a3b1b5a5267dd34/prek-0.4.5-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:e491a1a4641d91d8b03dcce5588397e76d2a5b432c9b0a6c70475972b4512ab4", size = 6300384, upload-time = "2026-06-15T11:36:27.602Z" }, + { url = "https://files.pythonhosted.org/packages/79/fa/43b1d761381dc1c7eeb8f2235c66e902970d4b2bff2dec0f02836c085769/prek-0.4.5-py3-none-win32.whl", hash = "sha256:7546989b2403c96137bd79d19ebfe21facb87266cefe819db2458c3b9b23f350", size = 5287935, upload-time = "2026-06-15T11:36:20.293Z" }, + { url = "https://files.pythonhosted.org/packages/f5/fe/59b5eb3124f5a4cc255a93857b9ab42402635b273f157e91de23bfa40e8f/prek-0.4.5-py3-none-win_amd64.whl", hash = "sha256:8b2ac9227504371d97338215b344184cb0b31ca94113515a3a90c509c6c5a707", size = 5682560, upload-time = "2026-06-15T11:36:25.865Z" }, + { url = "https://files.pythonhosted.org/packages/97/0e/589ff0eab9034909b1ec8654ee03483797305fb743b3554ce6140d82da9d/prek-0.4.5-py3-none-win_arm64.whl", hash = "sha256:646a86a1a082dbd99fed96314b1064f5644bb34c1f4037a63547a18e2160fb86", size = 5509019, upload-time = "2026-06-15T11:36:46.595Z" }, +] + [[package]] name = "prometheus-client" version = "0.25.0" @@ -1302,7 +1326,7 @@ wheels = [ [[package]] name = "pytest-notebook-policy" -version = "1.0.0" +version = "1.0.2" source = { editable = "." } dependencies = [ { name = "jinja2" }, @@ -1318,6 +1342,7 @@ sync = [ dev = [ { name = "great-docs" }, { name = "jupytext" }, + { name = "prek" }, { name = "pytest" }, { name = "ruff" }, ] @@ -1334,6 +1359,7 @@ provides-extras = ["sync"] dev = [ { name = "great-docs", specifier = ">=0.14.0" }, { name = "jupytext", specifier = ">=1.16" }, + { name = "prek", specifier = ">=0.4.5" }, { name = "pytest", specifier = ">=8.0" }, { name = "ruff", specifier = ">=0.14.0" }, ]