Type hint additions (#26831)

* Type hint additions

* Remove optional from sidebar_icon comment

Co-Authored-By: Franck Nijhof <frenck@frenck.nl>

* Remove optional from sidebar_title comment

Co-Authored-By: Franck Nijhof <frenck@frenck.nl>

* Fix issues after rebase and mypy 0.730
This commit is contained in:
Ville Skyttä 2019-09-29 20:07:49 +03:00 committed by GitHub
parent 4f55235aa2
commit f259ff17d5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
27 changed files with 184 additions and 68 deletions

View file

@ -1,16 +1,19 @@
"""Offer state listening automation rules.""" """Offer state listening automation rules."""
from datetime import timedelta
import logging import logging
from typing import Dict
import voluptuous as vol import voluptuous as vol
from homeassistant import exceptions from homeassistant import exceptions
from homeassistant.core import callback from homeassistant.core import HomeAssistant, CALLBACK_TYPE, callback
from homeassistant.const import MATCH_ALL, CONF_PLATFORM, CONF_FOR from homeassistant.const import MATCH_ALL, CONF_PLATFORM, CONF_FOR
from homeassistant.helpers import config_validation as cv, template from homeassistant.helpers import config_validation as cv, template
from homeassistant.helpers.event import async_track_state_change, async_track_same_state from homeassistant.helpers.event import async_track_state_change, async_track_same_state
# mypy: allow-untyped-calls, allow-untyped-defs, no-check-untyped-defs # mypy: allow-incomplete-defs, allow-untyped-calls, allow-untyped-defs
# mypy: no-check-untyped-defs
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -38,8 +41,13 @@ TRIGGER_SCHEMA = vol.All(
async def async_attach_trigger( async def async_attach_trigger(
hass, config, action, automation_info, *, platform_type="state" hass: HomeAssistant,
): config,
action,
automation_info,
*,
platform_type: str = "state",
) -> CALLBACK_TYPE:
"""Listen for state changes based on configuration.""" """Listen for state changes based on configuration."""
entity_id = config.get(CONF_ENTITY_ID) entity_id = config.get(CONF_ENTITY_ID)
from_state = config.get(CONF_FROM, MATCH_ALL) from_state = config.get(CONF_FROM, MATCH_ALL)
@ -48,7 +56,7 @@ async def async_attach_trigger(
template.attach(hass, time_delta) template.attach(hass, time_delta)
match_all = from_state == MATCH_ALL and to_state == MATCH_ALL match_all = from_state == MATCH_ALL and to_state == MATCH_ALL
unsub_track_same = {} unsub_track_same = {}
period = {} period: Dict[str, timedelta] = {}
@callback @callback
def state_automation_listener(entity, from_s, to_s): def state_automation_listener(entity, from_s, to_s):

View file

@ -1,6 +1,7 @@
"""Helpers for device automations.""" """Helpers for device automations."""
import asyncio import asyncio
import logging import logging
from typing import Any, List, MutableMapping
import voluptuous as vol import voluptuous as vol
@ -11,6 +12,9 @@ from homeassistant.loader import async_get_integration, IntegrationNotFound
from .exceptions import InvalidDeviceAutomationConfig from .exceptions import InvalidDeviceAutomationConfig
# mypy: allow-untyped-calls, allow-untyped-defs
DOMAIN = "device_automation" DOMAIN = "device_automation"
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -96,7 +100,7 @@ async def _async_get_device_automations(hass, automation_type, device_id):
) )
domains = set() domains = set()
automations = [] automations: List[MutableMapping[str, Any]] = []
device = device_registry.async_get(device_id) device = device_registry.async_get(device_id)
for entry_id in device.config_entries: for entry_id in device.config_entries:
config_entry = hass.config_entries.async_get_entry(entry_id) config_entry = hass.config_entries.async_get_entry(entry_id)

View file

@ -1,5 +1,5 @@
"""Device automation helpers for toggle entity.""" """Device automation helpers for toggle entity."""
from typing import List from typing import Any, Dict, List
import voluptuous as vol import voluptuous as vol
from homeassistant.core import Context, HomeAssistant, CALLBACK_TYPE from homeassistant.core import Context, HomeAssistant, CALLBACK_TYPE
@ -19,6 +19,9 @@ from homeassistant.helpers import condition, config_validation as cv, service
from homeassistant.helpers.typing import ConfigType, TemplateVarsType from homeassistant.helpers.typing import ConfigType, TemplateVarsType
from . import TRIGGER_BASE_SCHEMA from . import TRIGGER_BASE_SCHEMA
# mypy: allow-untyped-calls, allow-untyped-defs
ENTITY_ACTIONS = [ ENTITY_ACTIONS = [
{ {
# Turn entity off # Turn entity off
@ -88,7 +91,7 @@ async def async_call_action_from_config(
variables: TemplateVarsType, variables: TemplateVarsType,
context: Context, context: Context,
domain: str, domain: str,
): ) -> None:
"""Change state based on configuration.""" """Change state based on configuration."""
config = ACTION_SCHEMA(config) config = ACTION_SCHEMA(config)
action_type = config[CONF_TYPE] action_type = config[CONF_TYPE]
@ -156,7 +159,7 @@ async def _async_get_automations(
hass: HomeAssistant, device_id: str, automation_templates: List[dict], domain: str hass: HomeAssistant, device_id: str, automation_templates: List[dict], domain: str
) -> List[dict]: ) -> List[dict]:
"""List device automations.""" """List device automations."""
automations = [] automations: List[Dict[str, Any]] = []
entity_registry = await hass.helpers.entity_registry.async_get_registry() entity_registry = await hass.helpers.entity_registry.async_get_registry()
entries = [ entries = [

View file

@ -4,7 +4,7 @@ import logging
import mimetypes import mimetypes
import os import os
import pathlib import pathlib
from typing import Optional, Set, Tuple from typing import Any, Dict, Optional, Set, Tuple
from aiohttp import web, web_urldispatcher, hdrs from aiohttp import web, web_urldispatcher, hdrs
import voluptuous as vol import voluptuous as vol
@ -122,19 +122,19 @@ class Panel:
"""Abstract class for panels.""" """Abstract class for panels."""
# Name of the webcomponent # Name of the webcomponent
component_name = None component_name: Optional[str] = None
# Icon to show in the sidebar (optional) # Icon to show in the sidebar
sidebar_icon = None sidebar_icon: Optional[str] = None
# Title to show in the sidebar (optional) # Title to show in the sidebar
sidebar_title = None sidebar_title: Optional[str] = None
# Url to show the panel in the frontend # Url to show the panel in the frontend
frontend_url_path = None frontend_url_path: Optional[str] = None
# Config to pass to the webcomponent # Config to pass to the webcomponent
config = None config: Optional[Dict[str, Any]] = None
# If the panel should only be visible to admins # If the panel should only be visible to admins
require_admin = False require_admin = False

View file

@ -1,6 +1,7 @@
"""Provide the functionality to group entities.""" """Provide the functionality to group entities."""
import asyncio import asyncio
import logging import logging
from typing import Any, Iterable, List, Optional, cast
import voluptuous as vol import voluptuous as vol
@ -32,9 +33,12 @@ from homeassistant.helpers.entity_component import EntityComponent
from homeassistant.helpers.event import async_track_state_change from homeassistant.helpers.event import async_track_state_change
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.config_validation import ENTITY_SERVICE_SCHEMA from homeassistant.helpers.config_validation import ENTITY_SERVICE_SCHEMA
from homeassistant.helpers.typing import HomeAssistantType
from homeassistant.util.async_ import run_coroutine_threadsafe from homeassistant.util.async_ import run_coroutine_threadsafe
# mypy: allow-untyped-calls, allow-untyped-defs
DOMAIN = "group" DOMAIN = "group"
ENTITY_ID_FORMAT = DOMAIN + ".{}" ENTITY_ID_FORMAT = DOMAIN + ".{}"
@ -143,12 +147,12 @@ def is_on(hass, entity_id):
@bind_hass @bind_hass
def expand_entity_ids(hass, entity_ids): def expand_entity_ids(hass: HomeAssistantType, entity_ids: Iterable[Any]) -> List[str]:
"""Return entity_ids with group entity ids replaced by their members. """Return entity_ids with group entity ids replaced by their members.
Async friendly. Async friendly.
""" """
found_ids = [] found_ids: List[str] = []
for entity_id in entity_ids: for entity_id in entity_ids:
if not isinstance(entity_id, str): if not isinstance(entity_id, str):
continue continue
@ -182,7 +186,9 @@ def expand_entity_ids(hass, entity_ids):
@bind_hass @bind_hass
def get_entity_ids(hass, entity_id, domain_filter=None): def get_entity_ids(
hass: HomeAssistantType, entity_id: str, domain_filter: Optional[str] = None
) -> List[str]:
"""Get members of this group. """Get members of this group.
Async friendly. Async friendly.
@ -194,7 +200,7 @@ def get_entity_ids(hass, entity_id, domain_filter=None):
entity_ids = group.attributes[ATTR_ENTITY_ID] entity_ids = group.attributes[ATTR_ENTITY_ID]
if not domain_filter: if not domain_filter:
return entity_ids return cast(List[str], entity_ids)
domain_filter = domain_filter.lower() + "." domain_filter = domain_filter.lower() + "."

View file

@ -1,5 +1,6 @@
"""This platform allows several cover to be grouped into one cover.""" """This platform allows several cover to be grouped into one cover."""
import logging import logging
from typing import Dict, Optional, Set
import voluptuous as vol import voluptuous as vol
@ -11,7 +12,7 @@ from homeassistant.const import (
CONF_NAME, CONF_NAME,
STATE_CLOSED, STATE_CLOSED,
) )
from homeassistant.core import callback from homeassistant.core import callback, State
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.event import async_track_state_change from homeassistant.helpers.event import async_track_state_change
@ -41,6 +42,9 @@ from homeassistant.components.cover import (
CoverDevice, CoverDevice,
) )
# mypy: allow-incomplete-defs, allow-untyped-calls, allow-untyped-defs
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
KEY_OPEN_CLOSE = "open_close" KEY_OPEN_CLOSE = "open_close"
@ -76,13 +80,25 @@ class CoverGroup(CoverDevice):
self._assumed_state = True self._assumed_state = True
self._entities = entities self._entities = entities
self._covers = {KEY_OPEN_CLOSE: set(), KEY_STOP: set(), KEY_POSITION: set()} self._covers: Dict[str, Set[str]] = {
self._tilts = {KEY_OPEN_CLOSE: set(), KEY_STOP: set(), KEY_POSITION: set()} KEY_OPEN_CLOSE: set(),
KEY_STOP: set(),
KEY_POSITION: set(),
}
self._tilts: Dict[str, Set[str]] = {
KEY_OPEN_CLOSE: set(),
KEY_STOP: set(),
KEY_POSITION: set(),
}
@callback @callback
def update_supported_features( def update_supported_features(
self, entity_id, old_state, new_state, update_state=True self,
): entity_id: str,
old_state: Optional[State],
new_state: Optional[State],
update_state: bool = True,
) -> None:
"""Update dictionaries with supported features.""" """Update dictionaries with supported features."""
if not new_state: if not new_state:
for values in self._covers.values(): for values in self._covers.values():

View file

@ -3,7 +3,7 @@ import asyncio
from collections import Counter from collections import Counter
import itertools import itertools
import logging import logging
from typing import Any, Callable, Iterator, List, Optional, Tuple from typing import Any, Callable, Iterator, List, Optional, Tuple, cast
import voluptuous as vol import voluptuous as vol
@ -43,6 +43,9 @@ from homeassistant.components.light import (
SUPPORT_WHITE_VALUE, SUPPORT_WHITE_VALUE,
) )
# mypy: allow-incomplete-defs, allow-untyped-calls, allow-untyped-defs
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
DEFAULT_NAME = "Light Group" DEFAULT_NAME = "Light Group"
@ -69,7 +72,9 @@ async def async_setup_platform(
hass: HomeAssistantType, config: ConfigType, async_add_entities, discovery_info=None hass: HomeAssistantType, config: ConfigType, async_add_entities, discovery_info=None
) -> None: ) -> None:
"""Initialize light.group platform.""" """Initialize light.group platform."""
async_add_entities([LightGroup(config.get(CONF_NAME), config[CONF_ENTITIES])]) async_add_entities(
[LightGroup(cast(str, config.get(CONF_NAME)), config[CONF_ENTITIES])]
)
class LightGroup(light.Light): class LightGroup(light.Light):
@ -263,7 +268,7 @@ class LightGroup(light.Light):
async def async_update(self): async def async_update(self):
"""Query all members and determine the light group state.""" """Query all members and determine the light group state."""
all_states = [self.hass.states.get(x) for x in self._entity_ids] all_states = [self.hass.states.get(x) for x in self._entity_ids]
states = list(filter(None, all_states)) states: List[State] = list(filter(None, all_states))
on_states = [state for state in states if state.state == STATE_ON] on_states = [state for state in states if state.state == STATE_ON]
self._is_on = len(on_states) > 0 self._is_on = len(on_states) > 0

View file

@ -17,6 +17,9 @@ from homeassistant.components.notify import (
BaseNotificationService, BaseNotificationService,
) )
# mypy: allow-untyped-calls, allow-untyped-defs
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
CONF_SERVICES = "services" CONF_SERVICES = "services"

View file

@ -7,6 +7,7 @@ import functools as ft
import hashlib import hashlib
import logging import logging
from random import SystemRandom from random import SystemRandom
from typing import Optional
from urllib.parse import urlparse from urllib.parse import urlparse
from aiohttp import web from aiohttp import web
@ -347,7 +348,7 @@ async def async_unload_entry(hass, entry):
class MediaPlayerDevice(Entity): class MediaPlayerDevice(Entity):
"""ABC for media player devices.""" """ABC for media player devices."""
_access_token = None _access_token: Optional[str] = None
# Implement these for your media player # Implement these for your media player
@property @property
@ -356,7 +357,7 @@ class MediaPlayerDevice(Entity):
return None return None
@property @property
def access_token(self): def access_token(self) -> str:
"""Access token for this media player.""" """Access token for this media player."""
if self._access_token is None: if self._access_token is None:
self._access_token = hashlib.sha256( self._access_token = hashlib.sha256(

View file

@ -1,7 +1,7 @@
"""Support for displaying persistent notifications.""" """Support for displaying persistent notifications."""
from collections import OrderedDict from collections import OrderedDict
import logging import logging
from typing import Awaitable from typing import Any, Mapping, MutableMapping, Optional
import voluptuous as vol import voluptuous as vol
@ -14,6 +14,9 @@ from homeassistant.loader import bind_hass
from homeassistant.util import slugify from homeassistant.util import slugify
import homeassistant.util.dt as dt_util import homeassistant.util.dt as dt_util
# mypy: allow-untyped-calls, allow-untyped-defs
ATTR_CREATED_AT = "created_at" ATTR_CREATED_AT = "created_at"
ATTR_MESSAGE = "message" ATTR_MESSAGE = "message"
ATTR_NOTIFICATION_ID = "notification_id" ATTR_NOTIFICATION_ID = "notification_id"
@ -70,7 +73,10 @@ def dismiss(hass, notification_id):
@callback @callback
@bind_hass @bind_hass
def async_create( def async_create(
hass: HomeAssistant, message: str, title: str = None, notification_id: str = None hass: HomeAssistant,
message: str,
title: Optional[str] = None,
notification_id: Optional[str] = None,
) -> None: ) -> None:
"""Generate a notification.""" """Generate a notification."""
data = { data = {
@ -95,9 +101,9 @@ def async_dismiss(hass: HomeAssistant, notification_id: str) -> None:
hass.async_create_task(hass.services.async_call(DOMAIN, SERVICE_DISMISS, data)) hass.async_create_task(hass.services.async_call(DOMAIN, SERVICE_DISMISS, data))
async def async_setup(hass: HomeAssistant, config: dict) -> Awaitable[bool]: async def async_setup(hass: HomeAssistant, config: dict) -> bool:
"""Set up the persistent notification component.""" """Set up the persistent notification component."""
persistent_notifications = OrderedDict() persistent_notifications: MutableMapping[str, MutableMapping] = OrderedDict()
hass.data[DOMAIN] = {"notifications": persistent_notifications} hass.data[DOMAIN] = {"notifications": persistent_notifications}
@callback @callback
@ -201,8 +207,10 @@ async def async_setup(hass: HomeAssistant, config: dict) -> Awaitable[bool]:
@callback @callback
def websocket_get_notifications( def websocket_get_notifications(
hass: HomeAssistant, connection: websocket_api.ActiveConnection, msg hass: HomeAssistant,
): connection: websocket_api.ActiveConnection,
msg: Mapping[str, Any],
) -> None:
"""Return a list of persistent_notifications.""" """Return a list of persistent_notifications."""
connection.send_message( connection.send_message(
websocket_api.result_message( websocket_api.result_message(

View file

@ -17,6 +17,9 @@ from homeassistant.helpers.sun import (
) )
from homeassistant.util import dt as dt_util from homeassistant.util import dt as dt_util
# mypy: allow-untyped-calls, allow-untyped-defs
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
DOMAIN = "sun" DOMAIN = "sun"

View file

@ -4,6 +4,9 @@ from homeassistant.loader import bind_hass
from . import commands, connection, const, decorators, http, messages from . import commands, connection, const, decorators, http, messages
# mypy: allow-untyped-calls, allow-untyped-defs
DOMAIN = const.DOMAIN DOMAIN = const.DOMAIN
DEPENDENCIES = ("http",) DEPENDENCIES = ("http",)

View file

@ -2,6 +2,7 @@
import voluptuous as vol import voluptuous as vol
from voluptuous.humanize import humanize_error from voluptuous.humanize import humanize_error
from homeassistant.auth.models import RefreshToken, User
from homeassistant.auth.providers import legacy_api_password from homeassistant.auth.providers import legacy_api_password
from homeassistant.components.http.ban import process_wrong_login, process_success_login from homeassistant.components.http.ban import process_wrong_login, process_success_login
from homeassistant.const import __version__ from homeassistant.const import __version__
@ -9,6 +10,9 @@ from homeassistant.const import __version__
from .connection import ActiveConnection from .connection import ActiveConnection
from .error import Disconnect from .error import Disconnect
# mypy: allow-untyped-calls, allow-untyped-defs
TYPE_AUTH = "auth" TYPE_AUTH = "auth"
TYPE_AUTH_INVALID = "auth_invalid" TYPE_AUTH_INVALID = "auth_invalid"
TYPE_AUTH_OK = "auth_ok" TYPE_AUTH_OK = "auth_ok"
@ -87,7 +91,9 @@ class AuthPhase:
await process_wrong_login(self._request) await process_wrong_login(self._request)
raise Disconnect raise Disconnect
async def _async_finish_auth(self, user, refresh_token) -> ActiveConnection: async def _async_finish_auth(
self, user: User, refresh_token: RefreshToken
) -> ActiveConnection:
"""Create an active connection.""" """Create an active connection."""
self._logger.debug("Auth OK") self._logger.debug("Auth OK")
await process_success_login(self._request) await process_success_login(self._request)

View file

@ -12,6 +12,9 @@ from homeassistant.helpers.event import async_track_state_change
from . import const, decorators, messages from . import const, decorators, messages
# mypy: allow-untyped-calls, allow-untyped-defs
@callback @callback
def async_register_commands(hass, async_reg): def async_register_commands(hass, async_reg):
"""Register commands.""" """Register commands."""

View file

@ -1,5 +1,7 @@
"""Connection session.""" """Connection session."""
import asyncio import asyncio
from typing import Any, Callable, Dict, Hashable
import voluptuous as vol import voluptuous as vol
from homeassistant.core import callback, Context from homeassistant.core import callback, Context
@ -8,6 +10,9 @@ from homeassistant.exceptions import Unauthorized
from . import const, messages from . import const, messages
# mypy: allow-untyped-calls, allow-untyped-defs
class ActiveConnection: class ActiveConnection:
"""Handle an active websocket client connection.""" """Handle an active websocket client connection."""
@ -22,7 +27,7 @@ class ActiveConnection:
else: else:
self.refresh_token_id = None self.refresh_token_id = None
self.subscriptions = {} self.subscriptions: Dict[Hashable, Callable[[], Any]] = {}
self.last_id = 0 self.last_id = 0
def context(self, msg): def context(self, msg):

View file

@ -8,6 +8,8 @@ from homeassistant.exceptions import Unauthorized
from . import messages from . import messages
# mypy: allow-untyped-calls, allow-untyped-defs
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)

View file

@ -25,6 +25,9 @@ from .error import Disconnect
from .messages import error_message from .messages import error_message
# mypy: allow-untyped-calls, allow-untyped-defs
class WebsocketAPIView(HomeAssistantView): class WebsocketAPIView(HomeAssistantView):
"""View to serve a websockets endpoint.""" """View to serve a websockets endpoint."""
@ -45,7 +48,7 @@ class WebSocketHandler:
self.hass = hass self.hass = hass
self.request = request self.request = request
self.wsock = None self.wsock = None
self._to_write = asyncio.Queue(maxsize=MAX_PENDING_MSG) self._to_write: asyncio.Queue = asyncio.Queue(maxsize=MAX_PENDING_MSG)
self._handle_task = None self._handle_task = None
self._writer_task = None self._writer_task = None
self._logger = logging.getLogger("{}.connection.{}".format(__name__, id(self))) self._logger = logging.getLogger("{}.connection.{}".format(__name__, id(self)))
@ -106,7 +109,7 @@ class WebSocketHandler:
# Py3.7+ # Py3.7+
if hasattr(asyncio, "current_task"): if hasattr(asyncio, "current_task"):
# pylint: disable=no-member # pylint: disable=no-member
self._handle_task = asyncio.current_task() self._handle_task = asyncio.current_task() # type: ignore
else: else:
self._handle_task = asyncio.Task.current_task() self._handle_task = asyncio.Task.current_task()
@ -144,13 +147,13 @@ class WebSocketHandler:
raise Disconnect raise Disconnect
try: try:
msg = msg.json() msg_data = msg.json()
except ValueError: except ValueError:
disconnect_warn = "Received invalid JSON." disconnect_warn = "Received invalid JSON."
raise Disconnect raise Disconnect
self._logger.debug("Received %s", msg) self._logger.debug("Received %s", msg_data)
connection = await auth.async_handle(msg) connection = await auth.async_handle(msg_data)
self.hass.data[DATA_CONNECTIONS] = ( self.hass.data[DATA_CONNECTIONS] = (
self.hass.data.get(DATA_CONNECTIONS, 0) + 1 self.hass.data.get(DATA_CONNECTIONS, 0) + 1
) )
@ -170,13 +173,13 @@ class WebSocketHandler:
break break
try: try:
msg = msg.json() msg_data = msg.json()
except ValueError: except ValueError:
disconnect_warn = "Received invalid JSON." disconnect_warn = "Received invalid JSON."
break break
self._logger.debug("Received %s", msg) self._logger.debug("Received %s", msg_data)
connection.async_handle(msg) connection.async_handle(msg_data)
except asyncio.CancelledError: except asyncio.CancelledError:
self._logger.info("Connection closed by client") self._logger.info("Connection closed by client")

View file

@ -7,6 +7,8 @@ from homeassistant.helpers import config_validation as cv
from . import const from . import const
# mypy: allow-untyped-defs
# Minimal requirements of a message # Minimal requirements of a message
MINIMAL_MESSAGE_SCHEMA = vol.Schema( MINIMAL_MESSAGE_SCHEMA = vol.Schema(
{vol.Required("id"): cv.positive_int, vol.Required("type"): cv.string}, {vol.Required("id"): cv.positive_int, vol.Required("type"): cv.string},

View file

@ -10,6 +10,9 @@ from .const import (
) )
# mypy: allow-untyped-calls, allow-untyped-defs
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
"""Set up the API streams platform.""" """Set up the API streams platform."""
entity = APICount() entity = APICount()

View file

@ -1,9 +1,10 @@
"""Support for the definition of zones.""" """Support for the definition of zones."""
import logging import logging
from typing import Set, cast
import voluptuous as vol import voluptuous as vol
from homeassistant.core import callback from homeassistant.core import callback, State
from homeassistant.loader import bind_hass from homeassistant.loader import bind_hass
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
from homeassistant.const import ( from homeassistant.const import (
@ -25,6 +26,9 @@ from .config_flow import configured_zones
from .const import CONF_PASSIVE, DOMAIN, HOME_ZONE, ATTR_PASSIVE, ATTR_RADIUS from .const import CONF_PASSIVE, DOMAIN, HOME_ZONE, ATTR_PASSIVE, ATTR_RADIUS
from .zone import Zone from .zone import Zone
# mypy: allow-untyped-calls, allow-untyped-defs
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
DEFAULT_NAME = "Unnamed zone" DEFAULT_NAME = "Unnamed zone"
@ -78,10 +82,11 @@ def async_active_zone(hass, latitude, longitude, radius=0):
) )
within_zone = zone_dist - radius < zone.attributes[ATTR_RADIUS] within_zone = zone_dist - radius < zone.attributes[ATTR_RADIUS]
closer_zone = closest is None or zone_dist < min_dist closer_zone = closest is None or zone_dist < min_dist # type: ignore
smaller_zone = ( smaller_zone = (
zone_dist == min_dist zone_dist == min_dist
and zone.attributes[ATTR_RADIUS] < closest.attributes[ATTR_RADIUS] and zone.attributes[ATTR_RADIUS]
< cast(State, closest).attributes[ATTR_RADIUS]
) )
if within_zone and (closer_zone or smaller_zone): if within_zone and (closer_zone or smaller_zone):
@ -94,7 +99,7 @@ def async_active_zone(hass, latitude, longitude, radius=0):
async def async_setup(hass, config): async def async_setup(hass, config):
"""Set up configured zones as well as home assistant zone if necessary.""" """Set up configured zones as well as home assistant zone if necessary."""
hass.data[DOMAIN] = {} hass.data[DOMAIN] = {}
entities = set() entities: Set[str] = set()
zone_entries = configured_zones(hass) zone_entries = configured_zones(hass)
for _, entry in config_per_platform(config, DOMAIN): for _, entry in config_per_platform(config, DOMAIN):
if slugify(entry[CONF_NAME]) not in zone_entries: if slugify(entry[CONF_NAME]) not in zone_entries:

View file

@ -1,5 +1,7 @@
"""Config flow to configure zone component.""" """Config flow to configure zone component."""
from typing import Set
import voluptuous as vol import voluptuous as vol
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
@ -12,17 +14,23 @@ from homeassistant.const import (
CONF_RADIUS, CONF_RADIUS,
) )
from homeassistant.core import callback from homeassistant.core import callback
from homeassistant.helpers.typing import HomeAssistantType
from homeassistant.util import slugify from homeassistant.util import slugify
from .const import CONF_PASSIVE, DOMAIN, HOME_ZONE from .const import CONF_PASSIVE, DOMAIN, HOME_ZONE
# mypy: allow-untyped-defs
@callback @callback
def configured_zones(hass): def configured_zones(hass: HomeAssistantType) -> Set[str]:
"""Return a set of the configured zones.""" """Return a set of the configured zones."""
return set( return set(
(slugify(entry.data[CONF_NAME])) (slugify(entry.data[CONF_NAME]))
for entry in hass.config_entries.async_entries(DOMAIN) for entry in (
hass.config_entries.async_entries(DOMAIN) if hass.config_entries else []
)
) )

View file

@ -1,5 +1,9 @@
"""Zone entity and functionality.""" """Zone entity and functionality."""
from typing import cast
from homeassistant.const import ATTR_HIDDEN, ATTR_LATITUDE, ATTR_LONGITUDE from homeassistant.const import ATTR_HIDDEN, ATTR_LATITUDE, ATTR_LONGITUDE
from homeassistant.core import State
from homeassistant.helpers.entity import Entity from homeassistant.helpers.entity import Entity
from homeassistant.util.location import distance from homeassistant.util.location import distance
@ -8,7 +12,10 @@ from .const import ATTR_PASSIVE, ATTR_RADIUS
STATE = "zoning" STATE = "zoning"
def in_zone(zone, latitude, longitude, radius=0) -> bool: # mypy: allow-untyped-defs
def in_zone(zone: State, latitude: float, longitude: float, radius: float = 0) -> bool:
"""Test if given latitude, longitude is in given zone. """Test if given latitude, longitude is in given zone.
Async friendly. Async friendly.
@ -20,7 +27,9 @@ def in_zone(zone, latitude, longitude, radius=0) -> bool:
zone.attributes[ATTR_LONGITUDE], zone.attributes[ATTR_LONGITUDE],
) )
return zone_dist - radius < zone.attributes[ATTR_RADIUS] if zone_dist is None or zone.attributes[ATTR_RADIUS] is None:
return False
return zone_dist - radius < cast(float, zone.attributes[ATTR_RADIUS])
class Zone(Entity): class Zone(Entity):

View file

@ -28,6 +28,7 @@ from typing import (
Set, Set,
TYPE_CHECKING, TYPE_CHECKING,
Awaitable, Awaitable,
Mapping,
) )
from async_timeout import timeout from async_timeout import timeout
@ -704,7 +705,7 @@ class State:
self, self,
entity_id: str, entity_id: str,
state: str, state: str,
attributes: Optional[Dict] = None, attributes: Optional[Mapping] = None,
last_changed: Optional[datetime.datetime] = None, last_changed: Optional[datetime.datetime] = None,
last_updated: Optional[datetime.datetime] = None, last_updated: Optional[datetime.datetime] = None,
context: Optional[Context] = None, context: Optional[Context] = None,

View file

@ -170,7 +170,7 @@ class FlowHandler:
# Set by flow manager # Set by flow manager
flow_id: Optional[str] = None flow_id: Optional[str] = None
hass: Optional[HomeAssistant] = None hass: Optional[HomeAssistant] = None
handler = None handler: Optional[Hashable] = None
cur_step: Optional[Dict[str, str]] = None cur_step: Optional[Dict[str, str]] = None
context: Dict context: Dict
@ -188,7 +188,7 @@ class FlowHandler:
data_schema: vol.Schema = None, data_schema: vol.Schema = None,
errors: Optional[Dict] = None, errors: Optional[Dict] = None,
description_placeholders: Optional[Dict] = None, description_placeholders: Optional[Dict] = None,
) -> Dict: ) -> Dict[str, Any]:
"""Return the definition of a form to gather user input.""" """Return the definition of a form to gather user input."""
return { return {
"type": RESULT_TYPE_FORM, "type": RESULT_TYPE_FORM,
@ -208,7 +208,7 @@ class FlowHandler:
data: Dict, data: Dict,
description: Optional[str] = None, description: Optional[str] = None,
description_placeholders: Optional[Dict] = None, description_placeholders: Optional[Dict] = None,
) -> Dict: ) -> Dict[str, Any]:
"""Finish config flow and create a config entry.""" """Finish config flow and create a config entry."""
return { return {
"version": self.VERSION, "version": self.VERSION,
@ -224,7 +224,7 @@ class FlowHandler:
@callback @callback
def async_abort( def async_abort(
self, *, reason: str, description_placeholders: Optional[Dict] = None self, *, reason: str, description_placeholders: Optional[Dict] = None
) -> Dict: ) -> Dict[str, Any]:
"""Abort the config flow.""" """Abort the config flow."""
return { return {
"type": RESULT_TYPE_ABORT, "type": RESULT_TYPE_ABORT,
@ -237,7 +237,7 @@ class FlowHandler:
@callback @callback
def async_external_step( def async_external_step(
self, *, step_id: str, url: str, description_placeholders: Optional[Dict] = None self, *, step_id: str, url: str, description_placeholders: Optional[Dict] = None
) -> Dict: ) -> Dict[str, Any]:
"""Return the definition of an external step for the user to take.""" """Return the definition of an external step for the user to take."""
return { return {
"type": RESULT_TYPE_EXTERNAL_STEP, "type": RESULT_TYPE_EXTERNAL_STEP,
@ -249,7 +249,7 @@ class FlowHandler:
} }
@callback @callback
def async_external_step_done(self, *, next_step_id: str) -> Dict: def async_external_step_done(self, *, next_step_id: str) -> Dict[str, Any]:
"""Return the definition of an external step for the user to take.""" """Return the definition of an external step for the user to take."""
return { return {
"type": RESULT_TYPE_EXTERNAL_STEP_DONE, "type": RESULT_TYPE_EXTERNAL_STEP_DONE,

View file

@ -1,5 +1,7 @@
"""An abstract class for entities.""" """An abstract class for entities."""
from datetime import timedelta
import asyncio
from datetime import datetime, timedelta
import logging import logging
import functools as ft import functools as ft
from timeit import default_timer as timer from timeit import default_timer as timer
@ -22,6 +24,7 @@ from homeassistant.const import (
ATTR_SUPPORTED_FEATURES, ATTR_SUPPORTED_FEATURES,
ATTR_DEVICE_CLASS, ATTR_DEVICE_CLASS,
) )
from homeassistant.helpers.entity_platform import EntityPlatform
from homeassistant.helpers.entity_registry import ( from homeassistant.helpers.entity_registry import (
EVENT_ENTITY_REGISTRY_UPDATED, EVENT_ENTITY_REGISTRY_UPDATED,
RegistryEntry, RegistryEntry,
@ -94,7 +97,7 @@ class Entity:
hass: Optional[HomeAssistant] = None hass: Optional[HomeAssistant] = None
# Owning platform instance. Will be set by EntityPlatform # Owning platform instance. Will be set by EntityPlatform
platform = None platform: Optional[EntityPlatform] = None
# If we reported if this entity was slow # If we reported if this entity was slow
_slow_reported = False _slow_reported = False
@ -106,7 +109,7 @@ class Entity:
_update_staged = False _update_staged = False
# Process updates in parallel # Process updates in parallel
parallel_updates = None parallel_updates: Optional[asyncio.Semaphore] = None
# Entry in the entity registry # Entry in the entity registry
registry_entry: Optional[RegistryEntry] = None registry_entry: Optional[RegistryEntry] = None
@ -115,8 +118,8 @@ class Entity:
_on_remove: Optional[List[CALLBACK_TYPE]] = None _on_remove: Optional[List[CALLBACK_TYPE]] = None
# Context # Context
_context = None _context: Optional[Context] = None
_context_set = None _context_set: Optional[datetime] = None
@property @property
def should_poll(self) -> bool: def should_poll(self) -> bool:

View file

@ -124,7 +124,7 @@ class IntentHandler:
intent_type: Optional[str] = None intent_type: Optional[str] = None
slot_schema: Optional[vol.Schema] = None slot_schema: Optional[vol.Schema] = None
_slot_schema = None _slot_schema: Optional[vol.Schema] = None
platforms: Optional[Iterable[str]] = [] platforms: Optional[Iterable[str]] = []
@callback @callback

6
mypyrc
View file

@ -6,8 +6,10 @@ homeassistant/components/binary_sensor/
homeassistant/components/calendar/ homeassistant/components/calendar/
homeassistant/components/camera/ homeassistant/components/camera/
homeassistant/components/cover/ homeassistant/components/cover/
homeassistant/components/device_automation/
homeassistant/components/frontend/ homeassistant/components/frontend/
homeassistant/components/geo_location/ homeassistant/components/geo_location/
homeassistant/components/group/
homeassistant/components/history/ homeassistant/components/history/
homeassistant/components/http/ homeassistant/components/http/
homeassistant/components/image_processing/ homeassistant/components/image_processing/
@ -17,16 +19,20 @@ homeassistant/components/lock/
homeassistant/components/mailbox/ homeassistant/components/mailbox/
homeassistant/components/media_player/ homeassistant/components/media_player/
homeassistant/components/notify/ homeassistant/components/notify/
homeassistant/components/persistent_notification/
homeassistant/components/proximity/ homeassistant/components/proximity/
homeassistant/components/remote/ homeassistant/components/remote/
homeassistant/components/scene/ homeassistant/components/scene/
homeassistant/components/sensor/ homeassistant/components/sensor/
homeassistant/components/sun/
homeassistant/components/switch/ homeassistant/components/switch/
homeassistant/components/systemmonitor/ homeassistant/components/systemmonitor/
homeassistant/components/tts/ homeassistant/components/tts/
homeassistant/components/vacuum/ homeassistant/components/vacuum/
homeassistant/components/water_heater/ homeassistant/components/water_heater/
homeassistant/components/weather/ homeassistant/components/weather/
homeassistant/components/websocket_api/
homeassistant/components/zone/
homeassistant/helpers/ homeassistant/helpers/
homeassistant/scripts/ homeassistant/scripts/
homeassistant/util/ homeassistant/util/