From 10f3c63eba3cc9eccc15e997d01106690f34767b Mon Sep 17 00:00:00 2001 From: Heikki Henriksen Date: Tue, 12 May 2026 10:02:44 +0200 Subject: [PATCH 1/2] Add Copilot code review instructions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Captures the conventions Copilot's PR reviewer should follow when reviewing this repo: review-style rules at the top (avoid commenting on lint/formatting since CI already enforces it), public API conventions (TypedDicts + cast at JSON boundaries is intentional, NotRequired over T | None, T | None reserved for "no data" return paths), test layout (respx + optional integration marker), and semver expectations for TypedDict shape changes. Standalone — no generator script like home-assistant/core has; the file is small enough to maintain by hand. Some of the conventions described (mypy strict, cast() pattern, PrinterInfo NotRequired migration, get_job() -> JobInfo | None) are landing as part of the upcoming 3.0.0 release in #167 / #169 / #170. The file describes the end state; once 3.0.0 ships, everything in here will be true on main. Co-Authored-By: Claude Opus 4.7 (1M context) --- .github/copilot-instructions.md | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 .github/copilot-instructions.md diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 0000000..bc09f5d --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,26 @@ +# Copilot code review instructions + +- Start review comments with a short, one-sentence summary of the suggested fix. +- Do not comment on code style, formatting, or linting issues — `black`, `isort`, `flake8`, and `mypy --strict` run in CI. +- Suggest fixes at the library level rather than at the call site when the behaviour could affect downstream consumers. +- A dependency version bump PR should only contain changes required for the version bump. + +# Project context + +`pyprusalink` is a thin async Python wrapper around the [PrusaLink v2 API](https://github.com/prusa3d/Prusa-Link-Web/blob/master/spec/openapi.yaml). The primary consumer is the [Home Assistant `prusalink` integration](https://www.home-assistant.io/integrations/prusalink/); other consumers are negligible. + +## Public API conventions + +- Public methods return `TypedDict`s declared in `pyprusalink/types.py`. Runtime validation is deliberately **not** performed at the library boundary; `KeyError` / `AttributeError` from missing fields propagates to the caller. +- `response.json()` results are wrapped in `typing.cast(...)` against the declared `TypedDict`. This is the deliberate, lightweight alternative to runtime validation libraries (pydantic, msgspec); it is not a gap to be filled. +- For optional fields on a `TypedDict`, prefer `NotRequired[T]` over `T | None`. The PrusaLink API actually omits absent fields rather than returning `null`, so `NotRequired` is the honest contract. +- For methods that may not return data, use `T | None` for the return type (e.g. `get_transfer() -> Transfer | None`) rather than returning empty containers like `{}` or `[]`. + +## Test conventions + +- Tests live in `tests/`. HTTP is mocked with `respx`. Integration tests against a real printer are opt-in via the `integration` pytest marker; the default `pytest` invocation excludes them via `addopts = "-m 'not integration'"`. +- Test and lint dependencies live in `[project.optional-dependencies]` under `test` and `lint` groups. There is intentionally no `requirements-test.txt`. + +## Versioning + +Semantic versioning. Breaking changes — including changes to `TypedDict` shapes that affect strict-typed consumers — require a major version bump. From ede421330093c2baa3c704226b22b8ccf7d3aaa2 Mon Sep 17 00:00:00 2001 From: Heikki Henriksen Date: Tue, 12 May 2026 11:44:24 +0200 Subject: [PATCH 2/2] Address review on Copilot instructions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Drop "PrusaLink v2 API" framing — agners pointed out that the endpoints aren't versioned that way and the library also covers a few legacy paths (/api/version, /api/printer). Replace with "PrusaLink HTTP API" and explicitly mention both endpoint families. - Drop the blanket "suggest fixes at the library level" rule. As agners noted, that's case-by-case rather than a general principle. - Drop "thin wrapper" framing in favour of "the shape is weighted toward what serves the HA integration best". - Add concrete examples of helpful vs unhelpful Copilot feedback so the rule list isn't just abstract dos/don'ts. Co-Authored-By: Claude Opus 4.7 (1M context) --- .github/copilot-instructions.md | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index bc09f5d..059ff9f 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -2,12 +2,26 @@ - Start review comments with a short, one-sentence summary of the suggested fix. - Do not comment on code style, formatting, or linting issues — `black`, `isort`, `flake8`, and `mypy --strict` run in CI. -- Suggest fixes at the library level rather than at the call site when the behaviour could affect downstream consumers. - A dependency version bump PR should only contain changes required for the version bump. +## Helpful kinds of feedback + +- Type-soundness issues: `Any` leaks, `cast()` against the wrong type, `TypedDict` fields that lie about presence (`T | None` where the API actually omits the key). +- Behaviour drift between the public API and what the upstream PrusaLink HTTP endpoint actually returns. +- Async correctness: missing `await`, sync calls inside async functions, blocking I/O. +- Test gaps for newly added behaviour, especially 204/404/409 paths and the no-resource case. + +## Less helpful kinds of feedback + +- Suggestions to introduce a runtime validation library (pydantic, msgspec) for the `response.json()` boundary — see "Public API conventions" below for the trade-off. +- Generic "should we add retries / caching / backoff" suggestions on the HTTP layer; those are deliberately the consumer's concern. +- Style/lint comments (CI covers these). + # Project context -`pyprusalink` is a thin async Python wrapper around the [PrusaLink v2 API](https://github.com/prusa3d/Prusa-Link-Web/blob/master/spec/openapi.yaml). The primary consumer is the [Home Assistant `prusalink` integration](https://www.home-assistant.io/integrations/prusalink/); other consumers are negligible. +`pyprusalink` is an async Python client for the [PrusaLink HTTP API](https://github.com/prusa3d/Prusa-Link-Web/blob/master/spec/openapi.yaml). It covers both the current `/api/v1/...` endpoints and a few legacy paths (`/api/version`, `/api/printer`). + +The primary consumer is the [Home Assistant `prusalink` integration](https://www.home-assistant.io/integrations/prusalink/). API shape and breaking-change decisions are weighted toward what serves that integration best. ## Public API conventions