Skip to content

prusalink: extract PrusaLinkEntityDescription base class#170092

Merged
joostlek merged 3 commits into
home-assistant:devfrom
heikkih:refactor/prusalink-entity-description
May 8, 2026
Merged

prusalink: extract PrusaLinkEntityDescription base class#170092
joostlek merged 3 commits into
home-assistant:devfrom
heikkih:refactor/prusalink-entity-description

Conversation

@heikkih
Copy link
Copy Markdown
Contributor

@heikkih heikkih commented May 8, 2026

Proposed change

Extracts a shared PrusaLinkEntityDescription base class so the per-platform descriptions (sensor, binary_sensor, button, camera) no longer duplicate the available_fn field, and so the available property can live on PrusaLinkEntity instead of being copy-pasted across the per-platform entity classes.

  • PrusaLinkEntityDescription(EntityDescription) in entity.py carries available_fn and supported_fn
  • PrusaLinkSensorEntityDescription, PrusaLinkBinarySensorEntityDescription, PrusaLinkButtonEntityDescription, and the new PrusaLinkCameraEntityDescription all inherit from it (combined with their respective HA platform descriptions)
  • PrusaLinkEntity.available reads entity_description.available_fn directly — no getattr fallback needed since the description type is known
  • Camera, which previously had no entity description, now uses PrusaLinkCameraEntityDescription (which inherits from both CameraEntityDescription and PrusaLinkEntityDescription). Its job-data-dependent availability check is expressed as available_fn on the description, so the available override is gone too. The class-level _attr_translation_key is replaced by translation_key="job_preview" on the description.
  • All description dataclasses are now kw_only=True so inherited fields with defaults compose cleanly with required fields.
  • The *EntityDescriptionMixin classes are merged into the main description classes — they were only needed to keep required fields ahead of default fields in dataclass ordering, which no longer matters with kw_only=True.

Notes for reviewers

  • Entity IDs are unchanged. Sensor, binary_sensor, and button entity_ids are derived from translation_key (unchanged). Camera previously used _attr_translation_key="job_preview"; now entity_description.translation_key="job_preview" — same resulting entity_id (camera.<device>_job_preview).
  • Camera availability behavior is preserved. The lambda short-circuits the same conditions in the same order as the previous override; the only intentional change is wrapping in bool() so the property's declared bool return type is satisfied (the previous version could return a truthy thumbnail string).
  • kw_only=True on the description dataclasses doesn't change call sites since all existing instantiations already use keyword arguments. It's required so the inherited defaulted fields (available_fn, supported_fn) compose with the platform descriptions' required fields without dataclass field-ordering errors.
  • PrusaLinkCameraEntityDescription combines CameraEntityDescription (HA's contract for Camera entities) and PrusaLinkEntityDescription (our shared predicates), mirroring the pattern used by the other platforms.

Why

This is the canonical HA pattern for integrations with multiple entity platforms: a single base entity description carries the cross-platform predicates (available_fn, supported_fn) so each platform doesn't redefine them, and the available property lives on the shared base entity. Beyond removing duplication, it makes the typing precise — we can drop the getattr fallbacks I had added in #169310 because entity_description is now typed as PrusaLinkEntityDescription on the base.

Credit to @edenhaus for catching this during review of #169310 and pointing toward the right structure, and to @joostlek for the follow-up that we no longer need the Mixin classes once descriptions are kw_only=True. Splitting it into its own PR because the typing change touches button.py and camera.py which are otherwise unrelated to that PR's scope (binary sensors).

Type of change

  • Dependency upgrade
  • Bugfix (non-breaking change which fixes an issue)
  • New feature (thank you!)
  • Breaking change (non-breaking change which fixes an issue)
  • Code quality improvements to existing code or addition of tests

Checklist

  • The code change is tested and works locally
  • Local tests pass (31 passed)
  • mypy passes
  • There is no commented out code in this PR

Add a shared PrusaLinkEntityDescription dataclass (inheriting from HA's
EntityDescription) with `available_fn` and `supported_fn` predicates.
The per-platform description classes (sensor, binary_sensor, button)
now inherit from it so the duplicated `available_fn` field disappears.
Camera, which had no entity description before, uses a
PrusaLinkEntityDescription instance directly with `key="job_preview"`
and `translation_key="job_preview"` (replacing the class-level
`_attr_translation_key`).

The `available` property moves from the per-entity classes to
PrusaLinkEntity, so sensor.py, button.py, and camera.py drop their
overrides. Direct attribute access works because `entity_description`
is now typed as PrusaLinkEntityDescription on the base — no getattr
fallback needed. Camera's job-data-dependent availability check is
expressed as `available_fn` on its entity description.

All entity description dataclasses (the Mixin classes and the main
descriptions) are now `kw_only=True` so the inherited fields with
defaults compose with the Mixin's required fields without ordering
errors.

Per @edenhaus' review feedback on home-assistant#169310.

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

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Refactors the prusalink integration’s entity-description structure by introducing a shared PrusaLinkEntityDescription so cross-platform predicates (available_fn, supported_fn) and the available implementation live in one place instead of being duplicated per platform.

Changes:

  • Added PrusaLinkEntityDescription (with available_fn / supported_fn) and moved available to PrusaLinkEntity.
  • Updated sensor, binary_sensor, and button entity description dataclasses to inherit from the new base and removed duplicated available overrides.
  • Converted the camera entity to use an entity_description with translation_key and an available_fn, removing the custom available override.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated no comments.

Show a summary per file
File Description
homeassistant/components/prusalink/entity.py Introduces shared PrusaLinkEntityDescription and centralizes available logic in PrusaLinkEntity.
homeassistant/components/prusalink/sensor.py Uses the shared base description and removes the sensor-specific available override.
homeassistant/components/prusalink/binary_sensor.py Uses the shared base description and sets description dataclasses to kw_only=True.
homeassistant/components/prusalink/button.py Uses the shared base description and removes the button-specific available override.
homeassistant/components/prusalink/camera.py Adds an entity_description for the camera with availability defined via available_fn and switches to translation_key.

Camera entities expect a `CameraEntityDescription` (HA's `Camera` base
class declares the type), so the camera's description should also
satisfy that contract — not just `PrusaLinkEntityDescription`.
Introduce `PrusaLinkCameraEntityDescription` that inherits from both,
mirroring the pattern used by the sensor/binary_sensor/button
descriptions which combine HA's platform description with ours.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Comment thread homeassistant/components/prusalink/binary_sensor.py Outdated
@home-assistant
Copy link
Copy Markdown
Contributor

home-assistant Bot commented May 8, 2026

Please take a look at the requested changes, and use the Ready for review button when you are done, thanks 👍

Learn more about our pull request process.

@home-assistant home-assistant Bot marked this pull request as draft May 8, 2026 09:01
The Mixin pattern was needed to keep required fields (no default)
ahead of default fields in dataclass field ordering. With the recent
move to `kw_only=True` on every description dataclass, fields are
keyword-only and order between defaulted and required fields no
longer matters — so the Mixin classes are pure indirection.

Per @joostlek's review feedback.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings May 8, 2026 09:37
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated no new comments.

@heikkih heikkih marked this pull request as ready for review May 8, 2026 10:01
@home-assistant home-assistant Bot requested a review from joostlek May 8, 2026 10:01
@joostlek joostlek merged commit c195ddd into home-assistant:dev May 8, 2026
36 of 37 checks passed
heikkih added a commit to heikkih/homeassistant-core that referenced this pull request May 8, 2026
Three binary sensors backed by data already fetched by existing
coordinators — no pyprusalink changes needed. All inherit the shared
`PrusaLinkEntityDescription` (which provides `available_fn` and
`supported_fn`) introduced in home-assistant#170092.

| Entity | Source | Default | Created when |
|---|---|---|---|
| SD card (`info.sd_ready`) | /api/v1/info | Disabled | Printer firmware exposes `sd_ready` |
| Farm mode (`info.farm_mode`) | /api/v1/info | Disabled | Printer firmware exposes `farm_mode` |
| Connectivity (`printer.status_connect.ok`) | /api/v1/status | Enabled | User has set up PrusaConnect (`status_connect` is in the response) |

The Connectivity sensor uses `BinarySensorDeviceClass.CONNECTIVITY`,
so HA provides the entity name and `_connectivity` entity_id suffix
automatically — no `translation_key` or strings entry needed for it.

`supported_fn` filters out unsupported entities at setup time so they
are not created (rather than created and marked unavailable). This
matches the pattern used by sensor.py and the contract documented in
home-assistant#170092.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions github-actions Bot locked and limited conversation to collaborators May 9, 2026
@heikkih heikkih deleted the refactor/prusalink-entity-description branch May 13, 2026 10:26
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants