Skip to content

Fix listener callback contracts across domain APIs #72

Description

@Faerkeren

Problem

Domain listener docstrings and annotations do not match the actual callback contract.

src/haclient/entity/base.py:33 defines ValueChangeHandler as (old_value, new_value). _schedule_value() calls handlers with two arguments at src/haclient/entity/base.py:175-189. State transition listeners are also dispatched with (old_state, new_state) at src/haclient/entity/base.py:146-148.

Many public domain APIs document a different contract:

  • src/haclient/domains/light.py:26-40, where on_turn_on() says the callback is zero-argument.
  • src/haclient/domains/light.py:58-71, where on_brightness_change() says the callback receives the new brightness value, not (old, new).
  • src/haclient/domains/sensor.py:23-38, where on_value_change() says the callback receives the new state string, not (old, new).
  • Similar zero-argument or single-value wording appears across switch, binary_sensor, cover, lock, media_player, timer, vacuum, valve, climate, and humidifier listeners.

The public signatures also use Any -> Any, so type checking does not protect users from registering callbacks with the documented but wrong arity.

Suggested Fix

Choose one callback contract and make it consistent.

Recommended: keep the existing runtime behavior of (old, new) because tests already assert that shape, then:

  • Update every public listener docstring to say callbacks receive (old, new).
  • Replace func: Any) -> Any with typed callables such as ValueChangeHandler or a domain-specific alias.
  • Add targeted tests that registering a zero-argument callback either fails early with a clear error or is no longer documented as valid.
  • If zero-argument transition callbacks are preferred, add adapter helpers so transition listeners actually receive zero arguments and update existing tests accordingly.

Rationale

This is a user-facing API correctness bug. A user following the docs will register callbacks that raise TypeError when events fire. The library catches and logs those exceptions, so the callback silently does nothing from the caller’s perspective.

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:apiPublic API shape and consistencyseverity:highHigh severitytype:bugBug fix or correctness issue

    Type

    Fields

    No fields configured for Bug.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions