Skip to content

Migrate PrinterInfo fields from T | None to NotRequired[T]#169

Merged
agners merged 1 commit into
home-assistant-libs:mainfrom
heikkih:feat/printerinfo-not-required
May 12, 2026
Merged

Migrate PrinterInfo fields from T | None to NotRequired[T]#169
agners merged 1 commit into
home-assistant-libs:mainfrom
heikkih:feat/printerinfo-not-required

Conversation

@heikkih
Copy link
Copy Markdown
Contributor

@heikkih heikkih commented May 12, 2026

Part of the 3.0.0 release per agreement in #167. Submitting as its own PR for review clarity.

Why

The /api/v1/info endpoint actually omits absent fields rather than returning None — the original T | None typing was a lie that misled consumers into expecting info["x"] to always work. NotRequired[T] makes the contract honest: fields may be absent, and consumers must use .get() or membership checks.

Older Buddy firmware versions and edge configurations (e.g. printers not in farm mode) omit several fields. The docstring now documents this.

Field types verified

All 12 field types verified against Prusa-Link-Web's authoritative OpenAPI spec — no required list on the Info schema, so all properties are optional. Style matches the existing NotRequired[T] pattern on VersionInfo.

Breaking change

Strict-typed consumers that index missing fields (info["serial"]) need to switch to info.get("serial"). Runtime behavior is unchanged — info["serial"] already raises KeyError today whenever the field is absent; the old typing just hid that fact.

The HA-side prusalink integration already accesses PrinterInfo defensively via .get() in most places, so no HA-side code changes are required.

Test plan

  • pytest tests/ — 23 passed (1 new test_get_info_minimal_firmware covering the NotRequired semantics)
  • flake8 / black / isort clean

The /api/v1/info endpoint actually omits absent fields rather than
returning None — the original `T | None` typing was a lie that misled
consumers into expecting `info["x"]` to always work. NotRequired makes
the contract honest: fields may be absent, and consumers must use
.get() or membership checks.

Older Buddy firmware versions and edge configurations (e.g. printers
not in farm mode) omit several fields. Documented in the docstring.

Verified all 12 field types against Prusa-Link-Web's authoritative
OpenAPI spec (no `required` list, so all properties are optional).
Style matches the existing `NotRequired[T]` on `VersionInfo`.

Breaking change for strict-typed consumers that index missing fields;
they need to switch to `.get()`. Targeted at the 3.0.0 release (see
home-assistant-libs#167).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@agners agners left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@agners agners merged commit 9e08500 into home-assistant-libs:main May 12, 2026
2 checks passed
agners pushed a commit that referenced this pull request May 12, 2026
* Rewrite README for the 3.0 release

The old three-line README didn't say much beyond the package name.
The new one covers what someone landing on the PyPI page actually
needs:

- positioning: thin async wrapper, primary consumer is HA
- requirements and async-only / httpx caveat
- quickstart with credential note
- public API table by endpoint
- exception hierarchy and example
- type contract: NotRequired vs T | None, why we use cast() instead
  of pydantic/msgspec
- semver policy (TypedDict shape changes = breaking)
- development setup and the opt-in integration test invocation

Some of what's described — mypy strict, the cast() pattern, get_job()
returning None, get_transfer() returning None — is landing as part of
3.0.0 in #167/#169/#170, so this README is sized to match that state.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Reframe the README intro per agners' review

- Drop the "intentionally a thin wrapper" framing. As agners pointed
  out, that codifies a present-state property rather than a design
  principle — the library shape should be whatever serves the HA
  integration best, and may evolve.
- Replace with "API shape decisions are weighted toward serving the
  HA integration", and qualify the no-validation/no-retry note as a
  current state ("Today... but the shape may evolve").
- Fix "PrusaLink v2 API" — the API isn't versioned that way; replace
  with "PrusaLink HTTP API" and explicitly note the legacy paths.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
agners pushed a commit that referenced this pull request May 12, 2026
* Add Copilot code review instructions

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) <noreply@anthropic.com>

* Address review on Copilot instructions

- 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) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@heikkih heikkih deleted the feat/printerinfo-not-required branch May 13, 2026 09:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants