Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve type hints in homeassistant scene #76930

Merged
merged 3 commits into from Aug 18, 2022
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
36 changes: 21 additions & 15 deletions homeassistant/components/homeassistant/scene.py
@@ -1,8 +1,9 @@
"""Allow users to set and activate scenes."""
from __future__ import annotations

from collections.abc import Mapping
import logging
from typing import Any, NamedTuple
from typing import Any, NamedTuple, cast

import voluptuous as vol

Expand Down Expand Up @@ -34,14 +35,14 @@
config_validation as cv,
entity_platform,
)
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.entity_platform import AddEntitiesCallback, EntityPlatform
from homeassistant.helpers.service import async_register_admin_service
from homeassistant.helpers.state import async_reproduce_state
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
from homeassistant.loader import async_get_integration


def _convert_states(states):
def _convert_states(states: dict[str, Any]) -> dict[str, Any]:
frenck marked this conversation as resolved.
Show resolved Hide resolved
"""Convert state definitions to State objects."""
result = {}

Expand All @@ -68,7 +69,7 @@ def _convert_states(states):
return result


def _ensure_no_intersection(value):
def _ensure_no_intersection(value: dict[str, Any]) -> dict[str, Any]:
"""Validate that entities and snapshot_entities do not overlap."""
if (
CONF_SNAPSHOT not in value
Expand Down Expand Up @@ -143,12 +144,12 @@ def scenes_with_entity(hass: HomeAssistant, entity_id: str) -> list[str]:
if DATA_PLATFORM not in hass.data:
return []

platform = hass.data[DATA_PLATFORM]
platform: EntityPlatform = hass.data[DATA_PLATFORM]

return [
scene_entity.entity_id
for scene_entity in platform.entities.values()
if entity_id in scene_entity.scene_config.states
if entity_id in cast(HomeAssistantScene, scene_entity).scene_config.states
Copy link
Member

Choose a reason for hiding this comment

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

We could avoid the casting here.

    scene_entities: list[HomeAssistantScene] = platform.entities.values()
    return [
        scene_entity.entity_id
        for scene_entity in scene_entities
        if entity_id in scene_entity.scene_config.states
    ]

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This suggestion is not working:

Incompatible types in assignment (expression has type "dict_values[str, Entity]", variable has type "List[HomeAssistantScene]")  [assignment]

Copy link
Member

Choose a reason for hiding this comment

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

Oh I see, maybe change it to:

    return [
        scene_entity.entity_id
        for scene_entity in cast(
            ValuesView[HomeAssistantScene], platform.entities.values()
        )
        if entity_id in scene_entity.scene_config.states
    ]

That way, we only call cast once.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

]


Expand All @@ -158,12 +159,12 @@ def entities_in_scene(hass: HomeAssistant, entity_id: str) -> list[str]:
if DATA_PLATFORM not in hass.data:
return []

platform = hass.data[DATA_PLATFORM]
platform: EntityPlatform = hass.data[DATA_PLATFORM]

if (entity := platform.entities.get(entity_id)) is None:
return []

return list(entity.scene_config.states)
return list(cast(HomeAssistantScene, entity).scene_config.states)
frenck marked this conversation as resolved.
Show resolved Hide resolved


async def async_setup_platform(
Expand Down Expand Up @@ -270,9 +271,12 @@ async def create_service(call: ServiceCall) -> None:
)


def _process_scenes_config(hass, async_add_entities, config):
def _process_scenes_config(
hass, async_add_entities: AddEntitiesCallback, config: dict[str, Any]
) -> None:
"""Process multiple scenes and add them."""
# Check empty list
scene_config: list[dict[str, Any]]
if not (scene_config := config[STATES]):
return

Expand All @@ -293,31 +297,33 @@ def _process_scenes_config(hass, async_add_entities, config):
class HomeAssistantScene(Scene):
"""A scene is a group of entities and the states we want them to be."""

def __init__(self, hass, scene_config, from_service=False):
def __init__(
self, hass: HomeAssistant, scene_config: SceneConfig, from_service: bool = False
) -> None:
"""Initialize the scene."""
self.hass = hass
self.scene_config = scene_config
self.from_service = from_service

@property
def name(self):
def name(self) -> str:
"""Return the name of the scene."""
return self.scene_config.name

@property
def icon(self):
def icon(self) -> str | None:
"""Return the icon of the scene."""
return self.scene_config.icon

@property
def unique_id(self):
def unique_id(self) -> str | None:
"""Return unique ID."""
return self.scene_config.id

@property
def extra_state_attributes(self):
def extra_state_attributes(self) -> Mapping[str, Any]:
"""Return the scene state attributes."""
attributes = {ATTR_ENTITY_ID: list(self.scene_config.states)}
attributes: dict[str, Any] = {ATTR_ENTITY_ID: list(self.scene_config.states)}
if (unique_id := self.unique_id) is not None:
attributes[CONF_ID] = unique_id
return attributes
Expand Down