Skip to content

refactor(models)!: clarify States value accessors and widen accessor typing#2108

Merged
iMicknl merged 2 commits into
mainfrom
feat/v2-accessor-ergonomics
Jun 1, 2026
Merged

refactor(models)!: clarify States value accessors and widen accessor typing#2108
iMicknl merged 2 commits into
mainfrom
feat/v2-accessor-ergonomics

Conversation

@iMicknl
Copy link
Copy Markdown
Owner

@iMicknl iMicknl commented Jun 1, 2026

Summary

Two related, breaking v2 ergonomics fixes to the device accessor surface, before the 2.0 freeze.

#2105States.has()/has_any() conflate existence with value

has() returned True only when the state existed and had a non-None value, which pushed call sites toward a double lookup (has(x) then get_value(x)). The two concepts are now separated:

  • has()has_value(), has_any()has_any_value() — explicit about the "present AND non-None value" semantic.
  • Pure existence is name in states (already provided by Mapping.__contains__).

Many consumers don't even need has_value anymore: get_value(x) == ON already returns False for a missing state, collapsing the double lookup to one call.

#2106 — Inconsistent accessor typing

State accessors were typed str-only even though OverkizState/OverkizAttribute are StrEnum and worked at runtime. Signatures now advertise enum support, matching the command helpers:

  • States.{get_value, first, first_value, has_value, has_any_value}str | OverkizState | OverkizAttribute (the States class backs both device.states and device.attributes).
  • StateDefinitions.{first, has_any}str | OverkizState.
  • CommandDefinitions and device.supports_command() already accepted enums — unchanged.

Scope deliberately excludes new device-level wrappers (e.g. device.has_state()): device.states is a first-class container read constantly in consumers, while device.supports_command() only exists as a shortcut to the buried device.definition.commands. Mirroring would duplicate the container API for no gain.

Changes

  • pyoverkiz/models.py: rename + widen typing (new StateName alias).
  • docs/device-control.md, docs/migration-v2.md: updated to new names; document in for pure existence.
  • tests/test_models.py: renamed tests + new test exercising enum keys.

Breaking changes

  • States.has()States.has_value()
  • States.has_any()States.has_any_value()

Test plan

  • ruff check / ruff format / mypy / ty clean
  • Full suite green (502 passed)

Closes #2105
Closes #2106

…typing

Rename States.has()/has_any() to has_value()/has_any_value() so the
"present AND non-None value" semantic is explicit, and let pure existence
be expressed via `name in states` (Mapping.__contains__). This removes the
double-lookup antipattern the old name invited (closes #2105).

Widen state accessor params to accept enums, not just str, advertising the
StrEnum support the implementation already had (closes #2106):
- States.{get_value,first,first_value,has_value,has_any_value}: str|OverkizState|OverkizAttribute
- StateDefinitions.{first,has_any}: str|OverkizState

CommandDefinitions and the device.supports_command wrappers already accept
enums and keep their current names/locations.

BREAKING CHANGE: States.has() -> has_value(), States.has_any() -> has_any_value().
Copilot AI review requested due to automatic review settings June 1, 2026 06:41
@iMicknl iMicknl requested a review from tetienne as a code owner June 1, 2026 06:41
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

This PR refactors the v2 States container API to clearly separate “state exists” vs “state exists and has a non-None value”, and updates accessor type hints to explicitly support StrEnum keys (OverkizState / OverkizAttribute) for better ergonomics ahead of the 2.0 freeze.

Changes:

  • Rename States.has()States.has_value() and States.has_any()States.has_any_value() to make the “non-None value” semantics explicit.
  • Widen States accessor parameter typing via a StateName alias to accept str | OverkizState | OverkizAttribute (and widen StateDefinitions.{first,has_any} to accept OverkizState).
  • Update migration/device-control docs and adjust/extend tests for the renamed API and enum keys.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

File Description
pyoverkiz/models.py Renames value-coupled States helpers and widens accessor typing to support enum keys.
tests/test_models.py Renames tests to match new API and adds coverage for enum-key access on device.states.
docs/migration-v2.md Updates migration guidance with new method names and recommends name in states for pure existence.
docs/device-control.md Updates examples to use has_value / has_any_value and documents in for existence checks.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread tests/test_models.py
@iMicknl iMicknl merged commit ddf09c0 into main Jun 1, 2026
11 checks passed
@iMicknl iMicknl deleted the feat/v2-accessor-ergonomics branch June 1, 2026 07:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

2 participants