diff --git a/docs/integrations/writing-integrations.md b/docs/integrations/writing-integrations.md index 42e4511..a942f64 100644 --- a/docs/integrations/writing-integrations.md +++ b/docs/integrations/writing-integrations.md @@ -370,9 +370,27 @@ Each official integration is its own repository and PyPI package, mirroring the `test_commands.py` (resolution through `FromDI`), and `test_websockets.py` where the framework has websockets. Aim for the same 100%-coverage gate `modern-di` holds. +- **Canonical example** (`examples/`). Ship a runnable `examples/app.py` (plus an + empty `examples/__init__.py`) demonstrating the recommended wiring: an + APP-scoped `Settings` plus one work-scoped service that depends on it by type, + resolved into a single handler/task/command via the framework's real idiom. + Use the `typing.Annotated[T, FromDI(...)]` marker form, not a `= FromDI(...)` + default (the default-call form trips ruff `B008`). Name the example's types to + match the integration's `docs/integrations/.md` snippet; diverge + only where testability requires it (e.g. return a value the test can assert). + A `tests/test_example.py` **smoke test** drives it through the repo's own + in-memory test double (test client / eager mode / in-memory broker — whatever + the existing tests use) and asserts the **real injected output**, never a mock. + The smoke test must cover `examples/app.py` to **100%** under the coverage + gate — do **not** add a coverage `omit`; mark `# pragma: no cover` only on a + genuinely unreachable boot line (`if __name__ == "__main__"` / server-run). + Link it from the README with a `Usage example: [examples/](./examples)` line + directly under `Full guide:`. - **Mirror `modern-di`'s** `CLAUDE.md`, `Justfile`, and `architecture/` truth home. Keep resolution sync-only and add no runtime dependency beyond the - framework and `modern-di`. + framework and `modern-di`. `ruff` is unpinned and CI floats it forward, so keep + `CPY001` (no per-file copyright header) in the lint `ignore` and reflow any + pre-existing Markdown-embedded code fences the current `ruff` reformats. - **Docs.** Add a `docs/integrations/.md` usage page **in the `modern-di` repo** and a nav entry for it in `mkdocs.yml` (under the matching family group: Web / Tasks & events / Bots / RPC / CLI / Testing). Follow the @@ -427,6 +445,9 @@ Each official integration is its own repository and PyPI package, mirroring the - [ ] Tests cover lifespan (incl. restart), resolution through `FromDI`, and context injection from the connection object; coverage gate green. - [ ] Usage page + `mkdocs.yml` nav entry added in the `modern-di` repo. +- [ ] `examples/app.py` (+ smoke test asserting real injected output, 100% + coverage, no `omit`) and a README `Usage example: [examples/](./examples)` + line. - [ ] `CLAUDE.md`, `Justfile`, `architecture/` mirrored; [planning-convention](https://github.com/lesnik512/planning-convention) followed. diff --git a/planning/changes/2026-07-25.01-codify-canonical-example.md b/planning/changes/2026-07-25.01-codify-canonical-example.md new file mode 100644 index 0000000..2d77b48 --- /dev/null +++ b/planning/changes/2026-07-25.01-codify-canonical-example.md @@ -0,0 +1,53 @@ +--- +summary: Codified the canonical-example authoring rule in writing-integrations.md — every integration ships a runnable examples/app.py + a 100%-covering in-memory smoke test (no coverage omit) + a README Usage-example line — after piloting it in faststream and rolling it to the other 9. +--- + +# Change: Codify the canonical-example authoring rule + +**Lane:** lightweight — docs-only, one authoring-doc edit (`writing-integrations.md`) +plus a checklist item; no code or public-API change. + +## Goal + +Turn the canonical-example pattern — piloted in `modern-di-faststream` and rolled +out to the other 9 integrations — into a documented authoring rule so present and +future integrations conform, instead of a de-facto pattern read off the existing +repos. + +## Approach + +Add a **Canonical example** bullet to `## Repo scaffolding` in +`docs/integrations/writing-integrations.md` and a matching `## Checklist` item. +The rule captures the shape the pilot locked plus the refinements the 9-repo +rollout surfaced: + +- `examples/app.py` (+ empty `examples/__init__.py`): APP-scoped `Settings` + one + work-scoped service depending on it by type, resolved into one + handler/task/command via the framework's real idiom. +- Use the `typing.Annotated[T, FromDI(...)]` marker form, not a `= FromDI(...)` + default (the default-call form trips ruff `B008`; the pilot needed a `noqa`, the + rollout avoided it with `Annotated`). +- Name the example's types to match the integration's docs-page snippet; diverge + only for testability. +- `tests/test_example.py` smoke test via the repo's own in-memory test double, + asserting real injected output (never a mock), covering `examples/app.py` to + **100%** — no coverage `omit`; `# pragma: no cover` only a genuinely unreachable + boot line. +- README `Usage example: [examples/](./examples)` line under `Full guide:`. +- Plus a ruff note: `ruff` is unpinned and CI floats it, so keep `CPY001` ignored + and reflow any pre-existing Markdown code fences the current `ruff` reformats + (every rollout PR hit this). + +Not an `architecture/` capability change — this is authoring guidance for the +sibling repos, so it lives only in `writing-integrations.md`. + +## Files + +- `docs/integrations/writing-integrations.md` — Canonical-example scaffolding + bullet + ruff-float note + checklist item. +- `planning/changes/2026-07-25.01-codify-canonical-example.md` — this file. + +## Verification + +- [x] `just check-planning` — bundle validates. +- [x] `just lint-ci` — no-autofix lint (ruff 0.16) + planning validation clean.