Skip to content

Dependencies

Dependencies are special annotated types that extract data from events.

These are designed to be used in event handlers to automatically extract commonly used data from events without boilerplate code.

For example, instead of writing:

async def handle_state_change(event: RawStateChangeEvent):
    new_state = event.payload.data.new_state
    # do something with new_state

You can use the NewState dependency:

from hassette import D, states

async def handle_state_change(new_state: D.StateNew[states.ButtonState]):
    # do something with new_state

Hassette will automatically extract the value from the incoming event, cast it to the correct type, and pass it to your handler.

If you need to write your own dependencies, you can easily do so by annotating your parameter(s) with Annotated and either using an existing accessor from accessors or writing your own accessor function.

Examples:

Extracting the new state object from a RawStateChangeEvent

from hassette import D, states

async def handle_state_change(new_state: D.StateNew[states.ButtonState]):
    # new_state is automatically extracted and typed as states.ButtonState
    print(new_state.state)

Extracting the entity_id from any HassEvent

from hassette import D

async def handle_event(entity_id: D.EntityId):
    # entity_id is automatically extracted
    print(entity_id)

Writing your own dependency

from pathlib import Path

from typing import Annotated
from hassette import A

async def handle_event(
    file_paths: Annotated[frozenset[Path], A.get_path("payload.data.changed_file_paths")],
):
    # do something with file_paths

TypedStateChangeEvent: TypeAlias = Annotated[ActualTypedStateChangeEvent[StateT], AnnotationDetails['RawStateChangeEvent'](identity)] module-attribute

Convert a RawStateChangeEvent into a TypedStateChangeEvent with typed state objects.

Example:

async def handler(event: D.TypedStateChangeEvent[states.LightState]):
    brightness = event.payload.data.new_state.attributes.brightness

StateNew: TypeAlias = Annotated[StateT, AnnotationDetails['RawStateChangeEvent'](ensure_present(A.get_state_object_new))] module-attribute

Extract the new state object from a StateChangeEvent.

Example:

async def handler(new_state: D.StateNew[states.LightState]):
    brightness = new_state.attributes.brightness

MaybeStateNew: TypeAlias = Annotated[StateT | None, AnnotationDetails['RawStateChangeEvent'](A.get_state_object_new)] module-attribute

Extract the new state object from a StateChangeEvent, allowing for None.

Example:

async def handler(new_state: D.MaybeStateNew[states.LightState]):
    if new_state:
        brightness = new_state.attributes.brightness

StateOld: TypeAlias = Annotated[StateT, AnnotationDetails['RawStateChangeEvent'](ensure_present(A.get_state_object_old))] module-attribute

Extract the old state object from a StateChangeEvent.

Example:

async def handler(old_state: D.StateOld[states.LightState]):
    if old_state:
        previous_brightness = old_state.attributes.brightness

MaybeStateOld: TypeAlias = Annotated[StateT | None, AnnotationDetails['RawStateChangeEvent'](A.get_state_object_old)] module-attribute

Extract the old state object from a StateChangeEvent, allowing for None.

Example:

async def handler(old_state: D.MaybeStateOld[states.LightState]):
    if old_state:
        previous_brightness = old_state.attributes.brightness

EntityId: TypeAlias = Annotated[str, AnnotationDetails(ensure_present(A.get_entity_id))] module-attribute

Extract the entity_id from a HassEvent.

Returns the entity ID string (e.g., "light.bedroom").

Example:

async def handler(entity_id: D.EntityId):
    self.logger.info("Entity: %s", entity_id)

MaybeEntityId: TypeAlias = Annotated[str | FalseySentinel, AnnotationDetails(A.get_entity_id)] module-attribute

Extract the entity_id from a HassEvent, returning MISSING_VALUE sentinel if not present.

Domain: TypeAlias = Annotated[str, AnnotationDetails(ensure_present(A.get_domain))] module-attribute

Extract the domain from a HassEvent.

Returns the domain string (e.g., "light", "sensor") from the event payload or entity_id.

Example:

async def handler(domain: D.Domain):
    if domain == "light":
        self.logger.info("Light entity event")

MaybeDomain: TypeAlias = Annotated[str | FalseySentinel, AnnotationDetails(A.get_domain)] module-attribute

Extract the domain from a HassEvent, returning MISSING_VALUE sentinel if not present.

EventContext: TypeAlias = Annotated[HassContext, AnnotationDetails[Event](A.get_context)] module-attribute

Extract the context object from a HassEvent.

Returns the Home Assistant context object containing metadata about the event origin (user_id, parent_id, etc.).

Example:

async def handler(context: D.EventContext):
    if context.user_id:
        self.logger.info("Triggered by user: %s", context.user_id)

EventData: TypeAlias = Annotated[EventDataT, AnnotationDetails(ensure_present(A.get_path('payload.data')))] module-attribute

Extract the typed data from a broadcast event's payload.

Use with Bus.emit to receive the emitted data pre-extracted and typed.

Example:

async def handler(data: D.EventData[MyData]):
    print(data.some_field)

AnnotationDetails dataclass

Bases: Generic[T]

Details about an annotation used for dependency injection.

Source code in src/hassette/event_handling/dependencies.py
85
86
87
88
89
90
91
92
93
@dataclass(slots=True, frozen=True)
class AnnotationDetails(Generic[T]):
    """Details about an annotation used for dependency injection."""

    extractor: Callable[[T], Any]
    """Function to extract the dependency from the event."""

    converter: Callable[[Any, Any], Any] | None = None
    """Optional converter function to convert the extracted value to the desired type."""

extractor: Callable[[T], Any] instance-attribute

Function to extract the dependency from the event.

converter: Callable[[Any, Any], Any] | None = None class-attribute instance-attribute

Optional converter function to convert the extracted value to the desired type.

ensure_present(accessor: Callable[[T], R]) -> Callable[[T], R]

Wrap an accessor to raise if it returns None or MISSING_VALUE.

Parameters:

Name Type Description Default
accessor Callable[[T], R]

The accessor function to wrap

required

Returns:

Type Description
Callable[[T], R]

Wrapped accessor that validates the return value

Source code in src/hassette/event_handling/dependencies.py
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
def ensure_present(accessor: Callable[[T], R]) -> Callable[[T], R]:
    """Wrap an accessor to raise if it returns None or MISSING_VALUE.

    Args:
        accessor: The accessor function to wrap

    Returns:
        Wrapped accessor that validates the return value
    """

    def wrapper(event: T) -> R:
        result = accessor(event)

        # Check if the result is None or MISSING_VALUE
        if result is None or result is MISSING_VALUE:
            raise DependencyResolutionError(f"Required dependency returned {type(result).__name__}, expected a value")

        return result

    return wrapper

identity(x: Any) -> Any

Identity function - returns the input as-is.

Used when a parameter needs the full event object without transformation.

Source code in src/hassette/event_handling/dependencies.py
118
119
120
121
122
123
def identity(x: Any) -> Any:
    """Identity function - returns the input as-is.

    Used when a parameter needs the full event object without transformation.
    """
    return x