Update typing 10 (#48071)

This commit is contained in:
Marc Mueller 2021-03-18 13:07:04 +01:00 committed by GitHub
parent 00dca88024
commit 25a13d1554
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
73 changed files with 412 additions and 333 deletions

View File

@ -1,5 +1,5 @@
"""The jewish_calendar component.""" """The jewish_calendar component."""
from typing import Optional from __future__ import annotations
import hdate import hdate
import voluptuous as vol import voluptuous as vol
@ -78,8 +78,8 @@ CONFIG_SCHEMA = vol.Schema(
def get_unique_prefix( def get_unique_prefix(
location: hdate.Location, location: hdate.Location,
language: str, language: str,
candle_lighting_offset: Optional[int], candle_lighting_offset: int | None,
havdalah_offset: Optional[int], havdalah_offset: int | None,
) -> str: ) -> str:
"""Create a prefix for unique ids.""" """Create a prefix for unique ids."""
config_properties = [ config_properties = [

View File

@ -1,5 +1,5 @@
"""Config flow for Keenetic NDMS2.""" """Config flow for Keenetic NDMS2."""
from typing import List from __future__ import annotations
from ndms2_client import Client, ConnectionException, InterfaceInfo, TelnetConnection from ndms2_client import Client, ConnectionException, InterfaceInfo, TelnetConnection
import voluptuous as vol import voluptuous as vol
@ -103,7 +103,7 @@ class KeeneticOptionsFlowHandler(config_entries.OptionsFlow):
ROUTER ROUTER
] ]
interfaces: List[InterfaceInfo] = await self.hass.async_add_executor_job( interfaces: list[InterfaceInfo] = await self.hass.async_add_executor_job(
router.client.get_interfaces router.client.get_interfaces
) )

View File

@ -1,7 +1,8 @@
"""Support for Keenetic routers as device tracker.""" """Support for Keenetic routers as device tracker."""
from __future__ import annotations
from datetime import timedelta from datetime import timedelta
import logging import logging
from typing import List, Optional, Set
from ndms2_client import Device from ndms2_client import Device
import voluptuous as vol import voluptuous as vol
@ -57,8 +58,8 @@ async def async_get_scanner(hass: HomeAssistant, config):
"""Import legacy configuration from YAML.""" """Import legacy configuration from YAML."""
scanner_config = config[DEVICE_TRACKER_DOMAIN] scanner_config = config[DEVICE_TRACKER_DOMAIN]
scan_interval: Optional[timedelta] = scanner_config.get(CONF_SCAN_INTERVAL) scan_interval: timedelta | None = scanner_config.get(CONF_SCAN_INTERVAL)
consider_home: Optional[timedelta] = scanner_config.get(CONF_CONSIDER_HOME) consider_home: timedelta | None = scanner_config.get(CONF_CONSIDER_HOME)
host: str = scanner_config[CONF_HOST] host: str = scanner_config[CONF_HOST]
hass.data[DOMAIN][f"imported_options_{host}"] = { hass.data[DOMAIN][f"imported_options_{host}"] = {
@ -139,9 +140,9 @@ async def async_setup_entry(
@callback @callback
def update_items(router: KeeneticRouter, async_add_entities, tracked: Set[str]): def update_items(router: KeeneticRouter, async_add_entities, tracked: set[str]):
"""Update tracked device state from the hub.""" """Update tracked device state from the hub."""
new_tracked: List[KeeneticTracker] = [] new_tracked: list[KeeneticTracker] = []
for mac, device in router.last_devices.items(): for mac, device in router.last_devices.items():
if mac not in tracked: if mac not in tracked:
tracked.add(mac) tracked.add(mac)

View File

@ -1,7 +1,9 @@
"""The Keenetic Client class.""" """The Keenetic Client class."""
from __future__ import annotations
from datetime import timedelta from datetime import timedelta
import logging import logging
from typing import Callable, Dict, Optional from typing import Callable
from ndms2_client import Client, ConnectionException, Device, TelnetConnection from ndms2_client import Client, ConnectionException, Device, TelnetConnection
from ndms2_client.client import RouterInfo from ndms2_client.client import RouterInfo
@ -39,11 +41,11 @@ class KeeneticRouter:
"""Initialize the Client.""" """Initialize the Client."""
self.hass = hass self.hass = hass
self.config_entry = config_entry self.config_entry = config_entry
self._last_devices: Dict[str, Device] = {} self._last_devices: dict[str, Device] = {}
self._router_info: Optional[RouterInfo] = None self._router_info: RouterInfo | None = None
self._connection: Optional[TelnetConnection] = None self._connection: TelnetConnection | None = None
self._client: Optional[Client] = None self._client: Client | None = None
self._cancel_periodic_update: Optional[Callable] = None self._cancel_periodic_update: Callable | None = None
self._available = False self._available = False
self._progress = None self._progress = None

View File

@ -1,7 +1,8 @@
"""Support KNX devices.""" """Support KNX devices."""
from __future__ import annotations
import asyncio import asyncio
import logging import logging
from typing import Union
import voluptuous as vol import voluptuous as vol
from xknx import XKNX from xknx import XKNX
@ -466,7 +467,7 @@ class KNXModule:
attr_payload = call.data.get(SERVICE_KNX_ATTR_PAYLOAD) attr_payload = call.data.get(SERVICE_KNX_ATTR_PAYLOAD)
attr_type = call.data.get(SERVICE_KNX_ATTR_TYPE) attr_type = call.data.get(SERVICE_KNX_ATTR_TYPE)
payload: Union[DPTBinary, DPTArray] payload: DPTBinary | DPTArray
if attr_type is not None: if attr_type is not None:
transcoder = DPTBase.parse_transcoder(attr_type) transcoder = DPTBase.parse_transcoder(attr_type)
if transcoder is None: if transcoder is None:

View File

@ -1,5 +1,7 @@
"""Support for KNX/IP binary sensors.""" """Support for KNX/IP binary sensors."""
from typing import Any, Dict, Optional from __future__ import annotations
from typing import Any
from xknx.devices import BinarySensor as XknxBinarySensor from xknx.devices import BinarySensor as XknxBinarySensor
@ -38,7 +40,7 @@ class KNXBinarySensor(KnxEntity, BinarySensorEntity):
return self._device.is_on() return self._device.is_on()
@property @property
def extra_state_attributes(self) -> Optional[Dict[str, Any]]: def extra_state_attributes(self) -> dict[str, Any] | None:
"""Return device specific state attributes.""" """Return device specific state attributes."""
if self._device.counter is not None: if self._device.counter is not None:
return {ATTR_COUNTER: self._device.counter} return {ATTR_COUNTER: self._device.counter}

View File

@ -1,5 +1,5 @@
"""Support for KNX/IP climate devices.""" """Support for KNX/IP climate devices."""
from typing import List, Optional from __future__ import annotations
from xknx.devices import Climate as XknxClimate from xknx.devices import Climate as XknxClimate
from xknx.dpt.dpt_hvac_mode import HVACControllerMode, HVACOperationMode from xknx.dpt.dpt_hvac_mode import HVACControllerMode, HVACOperationMode
@ -88,7 +88,7 @@ class KNXClimate(KnxEntity, ClimateEntity):
self.async_write_ha_state() self.async_write_ha_state()
@property @property
def hvac_mode(self) -> Optional[str]: def hvac_mode(self) -> str | None:
"""Return current operation ie. heat, cool, idle.""" """Return current operation ie. heat, cool, idle."""
if self._device.supports_on_off and not self._device.is_on: if self._device.supports_on_off and not self._device.is_on:
return HVAC_MODE_OFF return HVAC_MODE_OFF
@ -100,7 +100,7 @@ class KNXClimate(KnxEntity, ClimateEntity):
return HVAC_MODE_HEAT return HVAC_MODE_HEAT
@property @property
def hvac_modes(self) -> Optional[List[str]]: def hvac_modes(self) -> list[str] | None:
"""Return the list of available operation/controller modes.""" """Return the list of available operation/controller modes."""
_controller_modes = [ _controller_modes = [
CONTROLLER_MODES.get(controller_mode.value) CONTROLLER_MODES.get(controller_mode.value)
@ -131,7 +131,7 @@ class KNXClimate(KnxEntity, ClimateEntity):
self.async_write_ha_state() self.async_write_ha_state()
@property @property
def preset_mode(self) -> Optional[str]: def preset_mode(self) -> str | None:
"""Return the current preset mode, e.g., home, away, temp. """Return the current preset mode, e.g., home, away, temp.
Requires SUPPORT_PRESET_MODE. Requires SUPPORT_PRESET_MODE.
@ -141,7 +141,7 @@ class KNXClimate(KnxEntity, ClimateEntity):
return None return None
@property @property
def preset_modes(self) -> Optional[List[str]]: def preset_modes(self) -> list[str] | None:
"""Return a list of available preset modes. """Return a list of available preset modes.
Requires SUPPORT_PRESET_MODE. Requires SUPPORT_PRESET_MODE.

View File

@ -1,5 +1,5 @@
"""Exposures to KNX bus.""" """Exposures to KNX bus."""
from typing import Union from __future__ import annotations
from xknx import XKNX from xknx import XKNX
from xknx.devices import DateTime, ExposeSensor from xknx.devices import DateTime, ExposeSensor
@ -22,7 +22,7 @@ from .schema import ExposeSchema
@callback @callback
def create_knx_exposure( def create_knx_exposure(
hass: HomeAssistant, xknx: XKNX, config: ConfigType hass: HomeAssistant, xknx: XKNX, config: ConfigType
) -> Union["KNXExposeSensor", "KNXExposeTime"]: ) -> KNXExposeSensor | KNXExposeTime:
"""Create exposures from config.""" """Create exposures from config."""
address = config[KNX_ADDRESS] address = config[KNX_ADDRESS]
attribute = config.get(ExposeSchema.CONF_KNX_EXPOSE_ATTRIBUTE) attribute = config.get(ExposeSchema.CONF_KNX_EXPOSE_ATTRIBUTE)
@ -30,7 +30,7 @@ def create_knx_exposure(
expose_type = config.get(ExposeSchema.CONF_KNX_EXPOSE_TYPE) expose_type = config.get(ExposeSchema.CONF_KNX_EXPOSE_TYPE)
default = config.get(ExposeSchema.CONF_KNX_EXPOSE_DEFAULT) default = config.get(ExposeSchema.CONF_KNX_EXPOSE_DEFAULT)
exposure: Union["KNXExposeSensor", "KNXExposeTime"] exposure: KNXExposeSensor | KNXExposeTime
if expose_type.lower() in ["time", "date", "datetime"]: if expose_type.lower() in ["time", "date", "datetime"]:
exposure = KNXExposeTime(xknx, expose_type, address) exposure = KNXExposeTime(xknx, expose_type, address)
else: else:

View File

@ -1,5 +1,5 @@
"""Factory function to initialize KNX devices from config.""" """Factory function to initialize KNX devices from config."""
from typing import Optional, Tuple from __future__ import annotations
from xknx import XKNX from xknx import XKNX
from xknx.devices import ( from xknx.devices import (
@ -95,7 +95,7 @@ def _create_cover(knx_module: XKNX, config: ConfigType) -> XknxCover:
def _create_light_color( def _create_light_color(
color: str, config: ConfigType color: str, config: ConfigType
) -> Tuple[Optional[str], Optional[str], Optional[str], Optional[str]]: ) -> tuple[str | None, str | None, str | None, str | None]:
"""Load color configuration from configuration structure.""" """Load color configuration from configuration structure."""
if "individual_colors" in config and color in config["individual_colors"]: if "individual_colors" in config and color in config["individual_colors"]:
sub_config = config["individual_colors"][color] sub_config = config["individual_colors"][color]

View File

@ -1,6 +1,8 @@
"""Support for KNX/IP fans.""" """Support for KNX/IP fans."""
from __future__ import annotations
import math import math
from typing import Any, Optional from typing import Any
from xknx.devices import Fan as XknxFan from xknx.devices import Fan as XknxFan
from xknx.devices.fan import FanSpeedMode from xknx.devices.fan import FanSpeedMode
@ -58,7 +60,7 @@ class KNXFan(KnxEntity, FanEntity):
return flags return flags
@property @property
def percentage(self) -> Optional[int]: def percentage(self) -> int | None:
"""Return the current speed as a percentage.""" """Return the current speed as a percentage."""
if self._device.current_speed is None: if self._device.current_speed is None:
return None return None
@ -78,9 +80,9 @@ class KNXFan(KnxEntity, FanEntity):
async def async_turn_on( async def async_turn_on(
self, self,
speed: Optional[str] = None, speed: str | None = None,
percentage: Optional[int] = None, percentage: int | None = None,
preset_mode: Optional[str] = None, preset_mode: str | None = None,
**kwargs, **kwargs,
) -> None: ) -> None:
"""Turn on the fan.""" """Turn on the fan."""

View File

@ -1,5 +1,5 @@
"""Support for KNX/IP notification services.""" """Support for KNX/IP notification services."""
from typing import List from __future__ import annotations
from xknx.devices import Notification as XknxNotification from xknx.devices import Notification as XknxNotification
@ -22,7 +22,7 @@ async def async_get_service(hass, config, discovery_info=None):
class KNXNotificationService(BaseNotificationService): class KNXNotificationService(BaseNotificationService):
"""Implement demo notification service.""" """Implement demo notification service."""
def __init__(self, devices: List[XknxNotification]): def __init__(self, devices: list[XknxNotification]):
"""Initialize the service.""" """Initialize the service."""
self.devices = devices self.devices = devices

View File

@ -1,5 +1,5 @@
"""Provides device automations for Kodi.""" """Provides device automations for Kodi."""
from typing import List from __future__ import annotations
import voluptuous as vol import voluptuous as vol
@ -29,7 +29,7 @@ TRIGGER_SCHEMA = TRIGGER_BASE_SCHEMA.extend(
) )
async def async_get_triggers(hass: HomeAssistant, device_id: str) -> List[dict]: async def async_get_triggers(hass: HomeAssistant, device_id: str) -> list[dict]:
"""List device triggers for Kodi devices.""" """List device triggers for Kodi devices."""
registry = await entity_registry.async_get_registry(hass) registry = await entity_registry.async_get_registry(hass)
triggers = [] triggers = []

View File

@ -1,7 +1,9 @@
"""Kuler Sky light platform.""" """Kuler Sky light platform."""
from __future__ import annotations
from datetime import timedelta from datetime import timedelta
import logging import logging
from typing import Callable, List from typing import Callable
import pykulersky import pykulersky
@ -34,7 +36,7 @@ DISCOVERY_INTERVAL = timedelta(seconds=60)
async def async_setup_entry( async def async_setup_entry(
hass: HomeAssistantType, hass: HomeAssistantType,
config_entry: ConfigEntry, config_entry: ConfigEntry,
async_add_entities: Callable[[List[Entity], bool], None], async_add_entities: Callable[[list[Entity], bool], None],
) -> None: ) -> None:
"""Set up Kuler sky light devices.""" """Set up Kuler sky light devices."""
if DOMAIN not in hass.data: if DOMAIN not in hass.data:

View File

@ -1,7 +1,8 @@
"""A sensor platform that give you information about the next space launch.""" """A sensor platform that give you information about the next space launch."""
from __future__ import annotations
from datetime import timedelta from datetime import timedelta
import logging import logging
from typing import Optional
from pylaunches import PyLaunches, PyLaunchesException from pylaunches import PyLaunches, PyLaunchesException
import voluptuous as vol import voluptuous as vol
@ -64,7 +65,7 @@ class LaunchLibrarySensor(Entity):
return self._name return self._name
@property @property
def state(self) -> Optional[str]: def state(self) -> str | None:
"""Return the state of the sensor.""" """Return the state of the sensor."""
if self.next_launch: if self.next_launch:
return self.next_launch.name return self.next_launch.name
@ -76,7 +77,7 @@ class LaunchLibrarySensor(Entity):
return "mdi:rocket" return "mdi:rocket"
@property @property
def extra_state_attributes(self) -> Optional[dict]: def extra_state_attributes(self) -> dict | None:
"""Return attributes for the sensor.""" """Return attributes for the sensor."""
if self.next_launch: if self.next_launch:
return { return {

View File

@ -6,7 +6,7 @@ import dataclasses
from datetime import timedelta from datetime import timedelta
import logging import logging
import os import os
from typing import Dict, List, Optional, Set, Tuple, cast from typing import cast
import voluptuous as vol import voluptuous as vol
@ -364,11 +364,11 @@ class Profile:
"""Representation of a profile.""" """Representation of a profile."""
name: str name: str
color_x: Optional[float] = dataclasses.field(repr=False) color_x: float | None = dataclasses.field(repr=False)
color_y: Optional[float] = dataclasses.field(repr=False) color_y: float | None = dataclasses.field(repr=False)
brightness: Optional[int] brightness: int | None
transition: Optional[int] = None transition: int | None = None
hs_color: Optional[Tuple[float, float]] = dataclasses.field(init=False) hs_color: tuple[float, float] | None = dataclasses.field(init=False)
SCHEMA = vol.Schema( # pylint: disable=invalid-name SCHEMA = vol.Schema( # pylint: disable=invalid-name
vol.Any( vol.Any(
@ -403,7 +403,7 @@ class Profile:
) )
@classmethod @classmethod
def from_csv_row(cls, csv_row: List[str]) -> Profile: def from_csv_row(cls, csv_row: list[str]) -> Profile:
"""Create profile from a CSV row tuple.""" """Create profile from a CSV row tuple."""
return cls(*cls.SCHEMA(csv_row)) return cls(*cls.SCHEMA(csv_row))
@ -414,9 +414,9 @@ class Profiles:
def __init__(self, hass: HomeAssistantType): def __init__(self, hass: HomeAssistantType):
"""Initialize profiles.""" """Initialize profiles."""
self.hass = hass self.hass = hass
self.data: Dict[str, Profile] = {} self.data: dict[str, Profile] = {}
def _load_profile_data(self) -> Dict[str, Profile]: def _load_profile_data(self) -> dict[str, Profile]:
"""Load built-in profiles and custom profiles.""" """Load built-in profiles and custom profiles."""
profile_paths = [ profile_paths = [
os.path.join(os.path.dirname(__file__), LIGHT_PROFILES_FILE), os.path.join(os.path.dirname(__file__), LIGHT_PROFILES_FILE),
@ -453,7 +453,7 @@ class Profiles:
self.data = await self.hass.async_add_executor_job(self._load_profile_data) self.data = await self.hass.async_add_executor_job(self._load_profile_data)
@callback @callback
def apply_default(self, entity_id: str, params: Dict) -> None: def apply_default(self, entity_id: str, params: dict) -> None:
"""Return the default turn-on profile for the given light.""" """Return the default turn-on profile for the given light."""
for _entity_id in (entity_id, "group.all_lights"): for _entity_id in (entity_id, "group.all_lights"):
name = f"{_entity_id}.default" name = f"{_entity_id}.default"
@ -462,7 +462,7 @@ class Profiles:
return return
@callback @callback
def apply_profile(self, name: str, params: Dict) -> None: def apply_profile(self, name: str, params: dict) -> None:
"""Apply a profile.""" """Apply a profile."""
profile = self.data.get(name) profile = self.data.get(name)
@ -481,12 +481,12 @@ class LightEntity(ToggleEntity):
"""Representation of a light.""" """Representation of a light."""
@property @property
def brightness(self) -> Optional[int]: def brightness(self) -> int | None:
"""Return the brightness of this light between 0..255.""" """Return the brightness of this light between 0..255."""
return None return None
@property @property
def color_mode(self) -> Optional[str]: def color_mode(self) -> str | None:
"""Return the color mode of the light.""" """Return the color mode of the light."""
return None return None
@ -519,27 +519,27 @@ class LightEntity(ToggleEntity):
return color_mode return color_mode
@property @property
def hs_color(self) -> Optional[Tuple[float, float]]: def hs_color(self) -> tuple[float, float] | None:
"""Return the hue and saturation color value [float, float].""" """Return the hue and saturation color value [float, float]."""
return None return None
@property @property
def xy_color(self) -> Optional[Tuple[float, float]]: def xy_color(self) -> tuple[float, float] | None:
"""Return the xy color value [float, float].""" """Return the xy color value [float, float]."""
return None return None
@property @property
def rgb_color(self) -> Optional[Tuple[int, int, int]]: def rgb_color(self) -> tuple[int, int, int] | None:
"""Return the rgb color value [int, int, int].""" """Return the rgb color value [int, int, int]."""
return None return None
@property @property
def rgbw_color(self) -> Optional[Tuple[int, int, int, int]]: def rgbw_color(self) -> tuple[int, int, int, int] | None:
"""Return the rgbw color value [int, int, int, int].""" """Return the rgbw color value [int, int, int, int]."""
return None return None
@property @property
def _light_internal_rgbw_color(self) -> Optional[Tuple[int, int, int, int]]: def _light_internal_rgbw_color(self) -> tuple[int, int, int, int] | None:
"""Return the rgbw color value [int, int, int, int].""" """Return the rgbw color value [int, int, int, int]."""
rgbw_color = self.rgbw_color rgbw_color = self.rgbw_color
if ( if (
@ -558,12 +558,12 @@ class LightEntity(ToggleEntity):
return rgbw_color return rgbw_color
@property @property
def rgbww_color(self) -> Optional[Tuple[int, int, int, int, int]]: def rgbww_color(self) -> tuple[int, int, int, int, int] | None:
"""Return the rgbww color value [int, int, int, int, int].""" """Return the rgbww color value [int, int, int, int, int]."""
return None return None
@property @property
def color_temp(self) -> Optional[int]: def color_temp(self) -> int | None:
"""Return the CT color value in mireds.""" """Return the CT color value in mireds."""
return None return None
@ -582,17 +582,17 @@ class LightEntity(ToggleEntity):
return 500 return 500
@property @property
def white_value(self) -> Optional[int]: def white_value(self) -> int | None:
"""Return the white value of this light between 0..255.""" """Return the white value of this light between 0..255."""
return None return None
@property @property
def effect_list(self) -> Optional[List[str]]: def effect_list(self) -> list[str] | None:
"""Return the list of supported effects.""" """Return the list of supported effects."""
return None return None
@property @property
def effect(self) -> Optional[str]: def effect(self) -> str | None:
"""Return the current effect.""" """Return the current effect."""
return None return None
@ -616,7 +616,7 @@ class LightEntity(ToggleEntity):
return data return data
def _light_internal_convert_color(self, color_mode: str) -> dict: def _light_internal_convert_color(self, color_mode: str) -> dict:
data: Dict[str, Tuple] = {} data: dict[str, tuple] = {}
if color_mode == COLOR_MODE_HS and self.hs_color: if color_mode == COLOR_MODE_HS and self.hs_color:
hs_color = self.hs_color hs_color = self.hs_color
data[ATTR_HS_COLOR] = (round(hs_color[0], 3), round(hs_color[1], 3)) data[ATTR_HS_COLOR] = (round(hs_color[0], 3), round(hs_color[1], 3))
@ -692,7 +692,7 @@ class LightEntity(ToggleEntity):
return {key: val for key, val in data.items() if val is not None} return {key: val for key, val in data.items() if val is not None}
@property @property
def _light_internal_supported_color_modes(self) -> Set: def _light_internal_supported_color_modes(self) -> set:
"""Calculate supported color modes with backwards compatibility.""" """Calculate supported color modes with backwards compatibility."""
supported_color_modes = self.supported_color_modes supported_color_modes = self.supported_color_modes
@ -717,7 +717,7 @@ class LightEntity(ToggleEntity):
return supported_color_modes return supported_color_modes
@property @property
def supported_color_modes(self) -> Optional[Set]: def supported_color_modes(self) -> set | None:
"""Flag supported color modes.""" """Flag supported color modes."""
return None return None

View File

@ -1,5 +1,5 @@
"""Provides device actions for lights.""" """Provides device actions for lights."""
from typing import List from __future__ import annotations
import voluptuous as vol import voluptuous as vol
@ -78,7 +78,7 @@ async def async_call_action_from_config(
) )
async def async_get_actions(hass: HomeAssistant, device_id: str) -> List[dict]: async def async_get_actions(hass: HomeAssistant, device_id: str) -> list[dict]:
"""List device actions.""" """List device actions."""
actions = await toggle_entity.async_get_actions(hass, device_id, DOMAIN) actions = await toggle_entity.async_get_actions(hass, device_id, DOMAIN)

View File

@ -1,5 +1,5 @@
"""Provides device conditions for lights.""" """Provides device conditions for lights."""
from typing import Dict, List from __future__ import annotations
import voluptuous as vol import voluptuous as vol
@ -28,7 +28,7 @@ def async_condition_from_config(
async def async_get_conditions( async def async_get_conditions(
hass: HomeAssistant, device_id: str hass: HomeAssistant, device_id: str
) -> List[Dict[str, str]]: ) -> list[dict[str, str]]:
"""List device conditions.""" """List device conditions."""
return await toggle_entity.async_get_conditions(hass, device_id, DOMAIN) return await toggle_entity.async_get_conditions(hass, device_id, DOMAIN)

View File

@ -1,5 +1,5 @@
"""Provides device trigger for lights.""" """Provides device trigger for lights."""
from typing import List from __future__ import annotations
import voluptuous as vol import voluptuous as vol
@ -28,7 +28,7 @@ async def async_attach_trigger(
) )
async def async_get_triggers(hass: HomeAssistant, device_id: str) -> List[dict]: async def async_get_triggers(hass: HomeAssistant, device_id: str) -> list[dict]:
"""List device triggers.""" """List device triggers."""
return await toggle_entity.async_get_triggers(hass, device_id, DOMAIN) return await toggle_entity.async_get_triggers(hass, device_id, DOMAIN)

View File

@ -1,8 +1,10 @@
"""Reproduce an Light state.""" """Reproduce an Light state."""
from __future__ import annotations
import asyncio import asyncio
import logging import logging
from types import MappingProxyType from types import MappingProxyType
from typing import Any, Dict, Iterable, Optional from typing import Any, Iterable
from homeassistant.const import ( from homeassistant.const import (
ATTR_ENTITY_ID, ATTR_ENTITY_ID,
@ -95,8 +97,8 @@ async def _async_reproduce_state(
hass: HomeAssistantType, hass: HomeAssistantType,
state: State, state: State,
*, *,
context: Optional[Context] = None, context: Context | None = None,
reproduce_options: Optional[Dict[str, Any]] = None, reproduce_options: dict[str, Any] | None = None,
) -> None: ) -> None:
"""Reproduce a single state.""" """Reproduce a single state."""
cur_state = hass.states.get(state.entity_id) cur_state = hass.states.get(state.entity_id)
@ -123,7 +125,7 @@ async def _async_reproduce_state(
): ):
return return
service_data: Dict[str, Any] = {ATTR_ENTITY_ID: state.entity_id} service_data: dict[str, Any] = {ATTR_ENTITY_ID: state.entity_id}
if reproduce_options is not None and ATTR_TRANSITION in reproduce_options: if reproduce_options is not None and ATTR_TRANSITION in reproduce_options:
service_data[ATTR_TRANSITION] = reproduce_options[ATTR_TRANSITION] service_data[ATTR_TRANSITION] = reproduce_options[ATTR_TRANSITION]
@ -171,8 +173,8 @@ async def async_reproduce_states(
hass: HomeAssistantType, hass: HomeAssistantType,
states: Iterable[State], states: Iterable[State],
*, *,
context: Optional[Context] = None, context: Context | None = None,
reproduce_options: Optional[Dict[str, Any]] = None, reproduce_options: dict[str, Any] | None = None,
) -> None: ) -> None:
"""Reproduce Light states.""" """Reproduce Light states."""
await asyncio.gather( await asyncio.gather(

View File

@ -1,5 +1,7 @@
"""Helper to test significant Light state changes.""" """Helper to test significant Light state changes."""
from typing import Any, Optional from __future__ import annotations
from typing import Any
from homeassistant.core import HomeAssistant, callback from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.significant_change import ( from homeassistant.helpers.significant_change import (
@ -24,7 +26,7 @@ def async_check_significant_change(
new_state: str, new_state: str,
new_attrs: dict, new_attrs: dict,
**kwargs: Any, **kwargs: Any,
) -> Optional[bool]: ) -> bool | None:
"""Test if state significantly changed.""" """Test if state significantly changed."""
if old_state != new_state: if old_state != new_state:
return True return True

View File

@ -1,6 +1,8 @@
"""Config flow for the LiteJet lighting system.""" """Config flow for the LiteJet lighting system."""
from __future__ import annotations
import logging import logging
from typing import Any, Dict, Optional from typing import Any
import pylitejet import pylitejet
from serial import SerialException from serial import SerialException
@ -18,8 +20,8 @@ class LiteJetConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
"""LiteJet config flow.""" """LiteJet config flow."""
async def async_step_user( async def async_step_user(
self, user_input: Optional[Dict[str, Any]] = None self, user_input: dict[str, Any] | None = None
) -> Dict[str, Any]: ) -> dict[str, Any]:
"""Create a LiteJet config entry based upon user input.""" """Create a LiteJet config entry based upon user input."""
if self.hass.config_entries.async_entries(DOMAIN): if self.hass.config_entries.async_entries(DOMAIN):
return self.async_abort(reason="single_instance_allowed") return self.async_abort(reason="single_instance_allowed")

View File

@ -1,8 +1,10 @@
"""A wrapper 'hub' for the Litter-Robot API and base entity for common attributes.""" """A wrapper 'hub' for the Litter-Robot API and base entity for common attributes."""
from __future__ import annotations
from datetime import time, timedelta from datetime import time, timedelta
import logging import logging
from types import MethodType from types import MethodType
from typing import Any, Optional from typing import Any
import pylitterbot import pylitterbot
from pylitterbot.exceptions import LitterRobotException, LitterRobotLoginException from pylitterbot.exceptions import LitterRobotException, LitterRobotLoginException
@ -106,7 +108,7 @@ class LitterRobotEntity(CoordinatorEntity):
async_call_later(self.hass, REFRESH_WAIT_TIME, async_call_later_callback) async_call_later(self.hass, REFRESH_WAIT_TIME, async_call_later_callback)
@staticmethod @staticmethod
def parse_time_at_default_timezone(time_str: str) -> Optional[time]: def parse_time_at_default_timezone(time_str: str) -> time | None:
"""Parse a time string and add default timezone.""" """Parse a time string and add default timezone."""
parsed_time = dt_util.parse_time(time_str) parsed_time = dt_util.parse_time(time_str)

View File

@ -1,5 +1,5 @@
"""Support for Litter-Robot sensors.""" """Support for Litter-Robot sensors."""
from typing import Optional from __future__ import annotations
from pylitterbot.robot import Robot from pylitterbot.robot import Robot
@ -10,7 +10,7 @@ from .const import DOMAIN
from .hub import LitterRobotEntity, LitterRobotHub from .hub import LitterRobotEntity, LitterRobotHub
def icon_for_gauge_level(gauge_level: Optional[int] = None, offset: int = 0) -> str: def icon_for_gauge_level(gauge_level: int | None = None, offset: int = 0) -> str:
"""Return a gauge icon valid identifier.""" """Return a gauge icon valid identifier."""
if gauge_level is None or gauge_level <= 0 + offset: if gauge_level is None or gauge_level <= 0 + offset:
return "mdi:gauge-empty" return "mdi:gauge-empty"

View File

@ -1,6 +1,7 @@
"""Support for Locative.""" """Support for Locative."""
from __future__ import annotations
import logging import logging
from typing import Dict
from aiohttp import web from aiohttp import web
import voluptuous as vol import voluptuous as vol
@ -34,7 +35,7 @@ def _id(value: str) -> str:
return value.replace("-", "") return value.replace("-", "")
def _validate_test_mode(obj: Dict) -> Dict: def _validate_test_mode(obj: dict) -> dict:
"""Validate that id is provided outside of test mode.""" """Validate that id is provided outside of test mode."""
if ATTR_ID not in obj and obj[ATTR_TRIGGER] != "test": if ATTR_ID not in obj and obj[ATTR_TRIGGER] != "test":
raise vol.Invalid("Location id not specified") raise vol.Invalid("Location id not specified")

View File

@ -1,5 +1,5 @@
"""Provides device automations for Lock.""" """Provides device automations for Lock."""
from typing import List, Optional from __future__ import annotations
import voluptuous as vol import voluptuous as vol
@ -30,7 +30,7 @@ ACTION_SCHEMA = cv.DEVICE_ACTION_BASE_SCHEMA.extend(
) )
async def async_get_actions(hass: HomeAssistant, device_id: str) -> List[dict]: async def async_get_actions(hass: HomeAssistant, device_id: str) -> list[dict]:
"""List device actions for Lock devices.""" """List device actions for Lock devices."""
registry = await entity_registry.async_get_registry(hass) registry = await entity_registry.async_get_registry(hass)
actions = [] actions = []
@ -75,7 +75,7 @@ async def async_get_actions(hass: HomeAssistant, device_id: str) -> List[dict]:
async def async_call_action_from_config( async def async_call_action_from_config(
hass: HomeAssistant, config: dict, variables: dict, context: Optional[Context] hass: HomeAssistant, config: dict, variables: dict, context: Context | None
) -> None: ) -> None:
"""Execute a device action.""" """Execute a device action."""
config = ACTION_SCHEMA(config) config = ACTION_SCHEMA(config)

View File

@ -1,5 +1,5 @@
"""Provides device automations for Lock.""" """Provides device automations for Lock."""
from typing import List from __future__ import annotations
import voluptuous as vol import voluptuous as vol
@ -30,7 +30,7 @@ CONDITION_SCHEMA = DEVICE_CONDITION_BASE_SCHEMA.extend(
) )
async def async_get_conditions(hass: HomeAssistant, device_id: str) -> List[dict]: async def async_get_conditions(hass: HomeAssistant, device_id: str) -> list[dict]:
"""List device conditions for Lock devices.""" """List device conditions for Lock devices."""
registry = await entity_registry.async_get_registry(hass) registry = await entity_registry.async_get_registry(hass)
conditions = [] conditions = []

View File

@ -1,5 +1,5 @@
"""Provides device automations for Lock.""" """Provides device automations for Lock."""
from typing import List from __future__ import annotations
import voluptuous as vol import voluptuous as vol
@ -31,7 +31,7 @@ TRIGGER_SCHEMA = TRIGGER_BASE_SCHEMA.extend(
) )
async def async_get_triggers(hass: HomeAssistant, device_id: str) -> List[dict]: async def async_get_triggers(hass: HomeAssistant, device_id: str) -> list[dict]:
"""List device triggers for Lock devices.""" """List device triggers for Lock devices."""
registry = await entity_registry.async_get_registry(hass) registry = await entity_registry.async_get_registry(hass)
triggers = [] triggers = []

View File

@ -1,7 +1,9 @@
"""Reproduce an Lock state.""" """Reproduce an Lock state."""
from __future__ import annotations
import asyncio import asyncio
import logging import logging
from typing import Any, Dict, Iterable, Optional from typing import Any, Iterable
from homeassistant.const import ( from homeassistant.const import (
ATTR_ENTITY_ID, ATTR_ENTITY_ID,
@ -24,8 +26,8 @@ async def _async_reproduce_state(
hass: HomeAssistantType, hass: HomeAssistantType,
state: State, state: State,
*, *,
context: Optional[Context] = None, context: Context | None = None,
reproduce_options: Optional[Dict[str, Any]] = None, reproduce_options: dict[str, Any] | None = None,
) -> None: ) -> None:
"""Reproduce a single state.""" """Reproduce a single state."""
cur_state = hass.states.get(state.entity_id) cur_state = hass.states.get(state.entity_id)
@ -60,8 +62,8 @@ async def async_reproduce_states(
hass: HomeAssistantType, hass: HomeAssistantType,
states: Iterable[State], states: Iterable[State],
*, *,
context: Optional[Context] = None, context: Context | None = None,
reproduce_options: Optional[Dict[str, Any]] = None, reproduce_options: dict[str, Any] | None = None,
) -> None: ) -> None:
"""Reproduce Lock states.""" """Reproduce Lock states."""
await asyncio.gather( await asyncio.gather(

View File

@ -1,5 +1,7 @@
"""Helper to test significant Lock state changes.""" """Helper to test significant Lock state changes."""
from typing import Any, Optional from __future__ import annotations
from typing import Any
from homeassistant.core import HomeAssistant, callback from homeassistant.core import HomeAssistant, callback
@ -12,7 +14,7 @@ def async_check_significant_change(
new_state: str, new_state: str,
new_attrs: dict, new_attrs: dict,
**kwargs: Any, **kwargs: Any,
) -> Optional[bool]: ) -> bool | None:
"""Test if state significantly changed.""" """Test if state significantly changed."""
if old_state != new_state: if old_state != new_state:
return True return True

View File

@ -1,6 +1,8 @@
"""Lovelace resources support.""" """Lovelace resources support."""
from __future__ import annotations
import logging import logging
from typing import List, Optional, cast from typing import Optional, cast
import uuid import uuid
import voluptuous as vol import voluptuous as vol
@ -38,7 +40,7 @@ class ResourceYAMLCollection:
return {"resources": len(self.async_items() or [])} return {"resources": len(self.async_items() or [])}
@callback @callback
def async_items(self) -> List[dict]: def async_items(self) -> list[dict]:
"""Return list of items in collection.""" """Return list of items in collection."""
return self.data return self.data
@ -66,7 +68,7 @@ class ResourceStorageCollection(collection.StorageCollection):
return {"resources": len(self.async_items() or [])} return {"resources": len(self.async_items() or [])}
async def _async_load_data(self) -> Optional[dict]: async def _async_load_data(self) -> dict | None:
"""Load the data.""" """Load the data."""
data = await self.store.async_load() data = await self.store.async_load()

View File

@ -1,5 +1,5 @@
"""Provides device triggers for lutron caseta.""" """Provides device triggers for lutron caseta."""
from typing import List from __future__ import annotations
import voluptuous as vol import voluptuous as vol
@ -225,7 +225,7 @@ async def async_validate_trigger_config(hass: HomeAssistant, config: ConfigType)
return schema(config) return schema(config)
async def async_get_triggers(hass: HomeAssistant, device_id: str) -> List[dict]: async def async_get_triggers(hass: HomeAssistant, device_id: str) -> list[dict]:
"""List device triggers for lutron caseta devices.""" """List device triggers for lutron caseta devices."""
triggers = [] triggers = []

View File

@ -1,6 +1,7 @@
"""Support for Lutron Caseta fans.""" """Support for Lutron Caseta fans."""
from __future__ import annotations
import logging import logging
from typing import Optional
from pylutron_caseta import FAN_HIGH, FAN_LOW, FAN_MEDIUM, FAN_MEDIUM_HIGH, FAN_OFF from pylutron_caseta import FAN_HIGH, FAN_LOW, FAN_MEDIUM, FAN_MEDIUM_HIGH, FAN_OFF
@ -42,7 +43,7 @@ class LutronCasetaFan(LutronCasetaDevice, FanEntity):
"""Representation of a Lutron Caseta fan. Including Fan Speed.""" """Representation of a Lutron Caseta fan. Including Fan Speed."""
@property @property
def percentage(self) -> Optional[int]: def percentage(self) -> int | None:
"""Return the current speed percentage.""" """Return the current speed percentage."""
if self._device["fan_speed"] is None: if self._device["fan_speed"] is None:
return None return None

View File

@ -1,8 +1,10 @@
"""The Honeywell Lyric integration.""" """The Honeywell Lyric integration."""
from __future__ import annotations
import asyncio import asyncio
from datetime import timedelta from datetime import timedelta
import logging import logging
from typing import Any, Dict, Optional from typing import Any
from aiolyric import Lyric from aiolyric import Lyric
from aiolyric.objects.device import LyricDevice from aiolyric.objects.device import LyricDevice
@ -147,7 +149,7 @@ class LyricEntity(CoordinatorEntity):
device: LyricDevice, device: LyricDevice,
key: str, key: str,
name: str, name: str,
icon: Optional[str], icon: str | None,
) -> None: ) -> None:
"""Initialize the Honeywell Lyric entity.""" """Initialize the Honeywell Lyric entity."""
super().__init__(coordinator) super().__init__(coordinator)
@ -190,7 +192,7 @@ class LyricDeviceEntity(LyricEntity):
"""Defines a Honeywell Lyric device entity.""" """Defines a Honeywell Lyric device entity."""
@property @property
def device_info(self) -> Dict[str, Any]: def device_info(self) -> dict[str, Any]:
"""Return device information about this Honeywell Lyric instance.""" """Return device information about this Honeywell Lyric instance."""
return { return {
"connections": {(dr.CONNECTION_NETWORK_MAC, self._mac_id)}, "connections": {(dr.CONNECTION_NETWORK_MAC, self._mac_id)},

View File

@ -1,7 +1,8 @@
"""Support for Honeywell Lyric climate platform.""" """Support for Honeywell Lyric climate platform."""
from __future__ import annotations
import logging import logging
from time import gmtime, strftime, time from time import gmtime, strftime, time
from typing import List, Optional
from aiolyric.objects.device import LyricDevice from aiolyric.objects.device import LyricDevice
from aiolyric.objects.location import LyricLocation from aiolyric.objects.location import LyricLocation
@ -162,7 +163,7 @@ class LyricClimate(LyricDeviceEntity, ClimateEntity):
return self._temperature_unit return self._temperature_unit
@property @property
def current_temperature(self) -> Optional[float]: def current_temperature(self) -> float | None:
"""Return the current temperature.""" """Return the current temperature."""
return self.device.indoorTemperature return self.device.indoorTemperature
@ -180,12 +181,12 @@ class LyricClimate(LyricDeviceEntity, ClimateEntity):
return HVAC_MODES[self.device.changeableValues.mode] return HVAC_MODES[self.device.changeableValues.mode]
@property @property
def hvac_modes(self) -> List[str]: def hvac_modes(self) -> list[str]:
"""List of available hvac modes.""" """List of available hvac modes."""
return self._hvac_modes return self._hvac_modes
@property @property
def target_temperature(self) -> Optional[float]: def target_temperature(self) -> float | None:
"""Return the temperature we try to reach.""" """Return the temperature we try to reach."""
device = self.device device = self.device
if not device.hasDualSetpointStatus: if not device.hasDualSetpointStatus:
@ -193,7 +194,7 @@ class LyricClimate(LyricDeviceEntity, ClimateEntity):
return None return None
@property @property
def target_temperature_low(self) -> Optional[float]: def target_temperature_low(self) -> float | None:
"""Return the upper bound temperature we try to reach.""" """Return the upper bound temperature we try to reach."""
device = self.device device = self.device
if device.hasDualSetpointStatus: if device.hasDualSetpointStatus:
@ -201,7 +202,7 @@ class LyricClimate(LyricDeviceEntity, ClimateEntity):
return None return None
@property @property
def target_temperature_high(self) -> Optional[float]: def target_temperature_high(self) -> float | None:
"""Return the upper bound temperature we try to reach.""" """Return the upper bound temperature we try to reach."""
device = self.device device = self.device
if device.hasDualSetpointStatus: if device.hasDualSetpointStatus:
@ -209,12 +210,12 @@ class LyricClimate(LyricDeviceEntity, ClimateEntity):
return None return None
@property @property
def preset_mode(self) -> Optional[str]: def preset_mode(self) -> str | None:
"""Return current preset mode.""" """Return current preset mode."""
return self.device.changeableValues.thermostatSetpointStatus return self.device.changeableValues.thermostatSetpointStatus
@property @property
def preset_modes(self) -> Optional[List[str]]: def preset_modes(self) -> list[str] | None:
"""Return preset modes.""" """Return preset modes."""
return [ return [
PRESET_NO_HOLD, PRESET_NO_HOLD,

View File

@ -9,7 +9,6 @@ import functools as ft
import hashlib import hashlib
import logging import logging
import secrets import secrets
from typing import List, Optional, Tuple
from urllib.parse import urlparse from urllib.parse import urlparse
from aiohttp import web from aiohttp import web
@ -355,7 +354,7 @@ async def async_unload_entry(hass, entry):
class MediaPlayerEntity(Entity): class MediaPlayerEntity(Entity):
"""ABC for media player entities.""" """ABC for media player entities."""
_access_token: Optional[str] = None _access_token: str | None = None
# Implement these for your media player # Implement these for your media player
@property @property
@ -439,8 +438,8 @@ class MediaPlayerEntity(Entity):
self, self,
media_content_type: str, media_content_type: str,
media_content_id: str, media_content_id: str,
media_image_id: Optional[str] = None, media_image_id: str | None = None,
) -> Tuple[Optional[str], Optional[str]]: ) -> tuple[str | None, str | None]:
""" """
Optionally fetch internally accessible image for media browser. Optionally fetch internally accessible image for media browser.
@ -851,8 +850,8 @@ class MediaPlayerEntity(Entity):
async def async_browse_media( async def async_browse_media(
self, self,
media_content_type: Optional[str] = None, media_content_type: str | None = None,
media_content_id: Optional[str] = None, media_content_id: str | None = None,
) -> BrowseMedia: ) -> BrowseMedia:
"""Return a BrowseMedia instance. """Return a BrowseMedia instance.
@ -914,7 +913,7 @@ class MediaPlayerEntity(Entity):
self, self,
media_content_type: str, media_content_type: str,
media_content_id: str, media_content_id: str,
media_image_id: Optional[str] = None, media_image_id: str | None = None,
) -> str: ) -> str:
"""Generate an url for a media browser image.""" """Generate an url for a media browser image."""
url_path = ( url_path = (
@ -947,8 +946,8 @@ class MediaPlayerImageView(HomeAssistantView):
self, self,
request: web.Request, request: web.Request,
entity_id: str, entity_id: str,
media_content_type: Optional[str] = None, media_content_type: str | None = None,
media_content_id: Optional[str] = None, media_content_id: str | None = None,
) -> web.Response: ) -> web.Response:
"""Start a get request.""" """Start a get request."""
player = self.component.get_entity(entity_id) player = self.component.get_entity(entity_id)
@ -1047,7 +1046,7 @@ async def websocket_browse_media(hass, connection, msg):
To use, media_player integrations can implement MediaPlayerEntity.async_browse_media() To use, media_player integrations can implement MediaPlayerEntity.async_browse_media()
""" """
component = hass.data[DOMAIN] component = hass.data[DOMAIN]
player: Optional[MediaPlayerDevice] = component.get_entity(msg["entity_id"]) player: MediaPlayerDevice | None = component.get_entity(msg["entity_id"])
if player is None: if player is None:
connection.send_error(msg["id"], "entity_not_found", "Entity not found") connection.send_error(msg["id"], "entity_not_found", "Entity not found")
@ -1119,9 +1118,9 @@ class BrowseMedia:
title: str, title: str,
can_play: bool, can_play: bool,
can_expand: bool, can_expand: bool,
children: Optional[List["BrowseMedia"]] = None, children: list[BrowseMedia] | None = None,
children_media_class: Optional[str] = None, children_media_class: str | None = None,
thumbnail: Optional[str] = None, thumbnail: str | None = None,
): ):
"""Initialize browse media item.""" """Initialize browse media item."""
self.media_class = media_class self.media_class = media_class

View File

@ -1,5 +1,5 @@
"""Provides device automations for Media player.""" """Provides device automations for Media player."""
from typing import Dict, List from __future__ import annotations
import voluptuous as vol import voluptuous as vol
@ -35,7 +35,7 @@ CONDITION_SCHEMA = DEVICE_CONDITION_BASE_SCHEMA.extend(
async def async_get_conditions( async def async_get_conditions(
hass: HomeAssistant, device_id: str hass: HomeAssistant, device_id: str
) -> List[Dict[str, str]]: ) -> list[dict[str, str]]:
"""List device conditions for Media player devices.""" """List device conditions for Media player devices."""
registry = await entity_registry.async_get_registry(hass) registry = await entity_registry.async_get_registry(hass)
conditions = [] conditions = []

View File

@ -1,5 +1,5 @@
"""Provides device automations for Media player.""" """Provides device automations for Media player."""
from typing import List from __future__ import annotations
import voluptuous as vol import voluptuous as vol
@ -34,7 +34,7 @@ TRIGGER_SCHEMA = TRIGGER_BASE_SCHEMA.extend(
) )
async def async_get_triggers(hass: HomeAssistant, device_id: str) -> List[dict]: async def async_get_triggers(hass: HomeAssistant, device_id: str) -> list[dict]:
"""List device triggers for Media player entities.""" """List device triggers for Media player entities."""
registry = await entity_registry.async_get_registry(hass) registry = await entity_registry.async_get_registry(hass)
triggers = [] triggers = []

View File

@ -1,6 +1,8 @@
"""Module that groups code required to handle state restore for component.""" """Module that groups code required to handle state restore for component."""
from __future__ import annotations
import asyncio import asyncio
from typing import Any, Dict, Iterable, Optional from typing import Any, Iterable
from homeassistant.const import ( from homeassistant.const import (
SERVICE_MEDIA_PAUSE, SERVICE_MEDIA_PAUSE,
@ -40,8 +42,8 @@ async def _async_reproduce_states(
hass: HomeAssistantType, hass: HomeAssistantType,
state: State, state: State,
*, *,
context: Optional[Context] = None, context: Context | None = None,
reproduce_options: Optional[Dict[str, Any]] = None, reproduce_options: dict[str, Any] | None = None,
) -> None: ) -> None:
"""Reproduce component states.""" """Reproduce component states."""
@ -104,8 +106,8 @@ async def async_reproduce_states(
hass: HomeAssistantType, hass: HomeAssistantType,
states: Iterable[State], states: Iterable[State],
*, *,
context: Optional[Context] = None, context: Context | None = None,
reproduce_options: Optional[Dict[str, Any]] = None, reproduce_options: dict[str, Any] | None = None,
) -> None: ) -> None:
"""Reproduce component states.""" """Reproduce component states."""
await asyncio.gather( await asyncio.gather(

View File

@ -1,6 +1,7 @@
"""The media_source integration.""" """The media_source integration."""
from __future__ import annotations
from datetime import timedelta from datetime import timedelta
from typing import Optional
import voluptuous as vol import voluptuous as vol
@ -54,7 +55,7 @@ async def _process_media_source_platform(hass, domain, platform):
@callback @callback
def _get_media_item( def _get_media_item(
hass: HomeAssistant, media_content_id: Optional[str] hass: HomeAssistant, media_content_id: str | None
) -> models.MediaSourceItem: ) -> models.MediaSourceItem:
"""Return media item.""" """Return media item."""
if media_content_id: if media_content_id:

View File

@ -1,7 +1,8 @@
"""Local Media Source Implementation.""" """Local Media Source Implementation."""
from __future__ import annotations
import mimetypes import mimetypes
from pathlib import Path from pathlib import Path
from typing import Tuple
from aiohttp import web from aiohttp import web
@ -40,7 +41,7 @@ class LocalSource(MediaSource):
return Path(self.hass.config.media_dirs[source_dir_id], location) return Path(self.hass.config.media_dirs[source_dir_id], location)
@callback @callback
def async_parse_identifier(self, item: MediaSourceItem) -> Tuple[str, str]: def async_parse_identifier(self, item: MediaSourceItem) -> tuple[str, str]:
"""Parse identifier.""" """Parse identifier."""
if not item.identifier: if not item.identifier:
# Empty source_dir_id and location # Empty source_dir_id and location
@ -69,7 +70,7 @@ class LocalSource(MediaSource):
return PlayMedia(f"/media/{item.identifier}", mime_type) return PlayMedia(f"/media/{item.identifier}", mime_type)
async def async_browse_media( async def async_browse_media(
self, item: MediaSourceItem, media_types: Tuple[str] = MEDIA_MIME_TYPES self, item: MediaSourceItem, media_types: tuple[str] = MEDIA_MIME_TYPES
) -> BrowseMediaSource: ) -> BrowseMediaSource:
"""Return media.""" """Return media."""
try: try:

View File

@ -3,7 +3,6 @@ from __future__ import annotations
from abc import ABC from abc import ABC
from dataclasses import dataclass from dataclasses import dataclass
from typing import List, Optional, Tuple
from homeassistant.components.media_player import BrowseMedia from homeassistant.components.media_player import BrowseMedia
from homeassistant.components.media_player.const import ( from homeassistant.components.media_player.const import (
@ -28,9 +27,9 @@ class PlayMedia:
class BrowseMediaSource(BrowseMedia): class BrowseMediaSource(BrowseMedia):
"""Represent a browsable media file.""" """Represent a browsable media file."""
children: Optional[List["BrowseMediaSource"]] children: list[BrowseMediaSource] | None
def __init__(self, *, domain: Optional[str], identifier: Optional[str], **kwargs): def __init__(self, *, domain: str | None, identifier: str | None, **kwargs):
"""Initialize media source browse media.""" """Initialize media source browse media."""
media_content_id = f"{URI_SCHEME}{domain or ''}" media_content_id = f"{URI_SCHEME}{domain or ''}"
if identifier: if identifier:
@ -47,7 +46,7 @@ class MediaSourceItem:
"""A parsed media item.""" """A parsed media item."""
hass: HomeAssistant hass: HomeAssistant
domain: Optional[str] domain: str | None
identifier: str identifier: str
async def async_browse(self) -> BrowseMediaSource: async def async_browse(self) -> BrowseMediaSource:
@ -118,7 +117,7 @@ class MediaSource(ABC):
raise NotImplementedError raise NotImplementedError
async def async_browse_media( async def async_browse_media(
self, item: MediaSourceItem, media_types: Tuple[str] self, item: MediaSourceItem, media_types: tuple[str]
) -> BrowseMediaSource: ) -> BrowseMediaSource:
"""Browse media.""" """Browse media."""
raise NotImplementedError raise NotImplementedError

View File

@ -1,8 +1,10 @@
"""The MELCloud Climate integration.""" """The MELCloud Climate integration."""
from __future__ import annotations
import asyncio import asyncio
from datetime import timedelta from datetime import timedelta
import logging import logging
from typing import Any, Dict, List from typing import Any
from aiohttp import ClientConnectionError from aiohttp import ClientConnectionError
from async_timeout import timeout from async_timeout import timeout
@ -101,7 +103,7 @@ class MelCloudDevice:
_LOGGER.warning("Connection failed for %s", self.name) _LOGGER.warning("Connection failed for %s", self.name)
self._available = False self._available = False
async def async_set(self, properties: Dict[str, Any]): async def async_set(self, properties: dict[str, Any]):
"""Write state changes to the MELCloud API.""" """Write state changes to the MELCloud API."""
try: try:
await self.device.set(properties) await self.device.set(properties)
@ -142,7 +144,7 @@ class MelCloudDevice:
return _device_info return _device_info
async def mel_devices_setup(hass, token) -> List[MelCloudDevice]: async def mel_devices_setup(hass, token) -> list[MelCloudDevice]:
"""Query connected devices from MELCloud.""" """Query connected devices from MELCloud."""
session = hass.helpers.aiohttp_client.async_get_clientsession() session = hass.helpers.aiohttp_client.async_get_clientsession()
try: try:

View File

@ -1,6 +1,8 @@
"""Platform for climate integration.""" """Platform for climate integration."""
from __future__ import annotations
from datetime import timedelta from datetime import timedelta
from typing import Any, Dict, List, Optional from typing import Any
from pymelcloud import DEVICE_TYPE_ATA, DEVICE_TYPE_ATW, AtaDevice, AtwDevice from pymelcloud import DEVICE_TYPE_ATA, DEVICE_TYPE_ATW, AtaDevice, AtwDevice
import pymelcloud.ata_device as ata import pymelcloud.ata_device as ata
@ -114,7 +116,7 @@ class MelCloudClimate(ClimateEntity):
return self.api.device_info return self.api.device_info
@property @property
def target_temperature_step(self) -> Optional[float]: def target_temperature_step(self) -> float | None:
"""Return the supported step of target temperature.""" """Return the supported step of target temperature."""
return self._base_device.temperature_increment return self._base_device.temperature_increment
@ -128,7 +130,7 @@ class AtaDeviceClimate(MelCloudClimate):
self._device = ata_device self._device = ata_device
@property @property
def unique_id(self) -> Optional[str]: def unique_id(self) -> str | None:
"""Return a unique ID.""" """Return a unique ID."""
return f"{self.api.device.serial}-{self.api.device.mac}" return f"{self.api.device.serial}-{self.api.device.mac}"
@ -138,7 +140,7 @@ class AtaDeviceClimate(MelCloudClimate):
return self._name return self._name
@property @property
def extra_state_attributes(self) -> Optional[Dict[str, Any]]: def extra_state_attributes(self) -> dict[str, Any] | None:
"""Return the optional state attributes with device specific additions.""" """Return the optional state attributes with device specific additions."""
attr = {} attr = {}
@ -190,19 +192,19 @@ class AtaDeviceClimate(MelCloudClimate):
await self._device.set(props) await self._device.set(props)
@property @property
def hvac_modes(self) -> List[str]: def hvac_modes(self) -> list[str]:
"""Return the list of available hvac operation modes.""" """Return the list of available hvac operation modes."""
return [HVAC_MODE_OFF] + [ return [HVAC_MODE_OFF] + [
ATA_HVAC_MODE_LOOKUP.get(mode) for mode in self._device.operation_modes ATA_HVAC_MODE_LOOKUP.get(mode) for mode in self._device.operation_modes
] ]
@property @property
def current_temperature(self) -> Optional[float]: def current_temperature(self) -> float | None:
"""Return the current temperature.""" """Return the current temperature."""
return self._device.room_temperature return self._device.room_temperature
@property @property
def target_temperature(self) -> Optional[float]: def target_temperature(self) -> float | None:
"""Return the temperature we try to reach.""" """Return the temperature we try to reach."""
return self._device.target_temperature return self._device.target_temperature
@ -213,7 +215,7 @@ class AtaDeviceClimate(MelCloudClimate):
) )
@property @property
def fan_mode(self) -> Optional[str]: def fan_mode(self) -> str | None:
"""Return the fan setting.""" """Return the fan setting."""
return self._device.fan_speed return self._device.fan_speed
@ -222,7 +224,7 @@ class AtaDeviceClimate(MelCloudClimate):
await self._device.set({"fan_speed": fan_mode}) await self._device.set({"fan_speed": fan_mode})
@property @property
def fan_modes(self) -> Optional[List[str]]: def fan_modes(self) -> list[str] | None:
"""Return the list of available fan modes.""" """Return the list of available fan modes."""
return self._device.fan_speeds return self._device.fan_speeds
@ -243,7 +245,7 @@ class AtaDeviceClimate(MelCloudClimate):
await self._device.set({ata.PROPERTY_VANE_VERTICAL: position}) await self._device.set({ata.PROPERTY_VANE_VERTICAL: position})
@property @property
def swing_mode(self) -> Optional[str]: def swing_mode(self) -> str | None:
"""Return vertical vane position or mode.""" """Return vertical vane position or mode."""
return self._device.vane_vertical return self._device.vane_vertical
@ -252,7 +254,7 @@ class AtaDeviceClimate(MelCloudClimate):
await self.async_set_vane_vertical(swing_mode) await self.async_set_vane_vertical(swing_mode)
@property @property
def swing_modes(self) -> Optional[str]: def swing_modes(self) -> str | None:
"""Return a list of available vertical vane positions and modes.""" """Return a list of available vertical vane positions and modes."""
return self._device.vane_vertical_positions return self._device.vane_vertical_positions
@ -300,7 +302,7 @@ class AtwDeviceZoneClimate(MelCloudClimate):
self._zone = atw_zone self._zone = atw_zone
@property @property
def unique_id(self) -> Optional[str]: def unique_id(self) -> str | None:
"""Return a unique ID.""" """Return a unique ID."""
return f"{self.api.device.serial}-{self._zone.zone_index}" return f"{self.api.device.serial}-{self._zone.zone_index}"
@ -310,7 +312,7 @@ class AtwDeviceZoneClimate(MelCloudClimate):
return f"{self._name} {self._zone.name}" return f"{self._name} {self._zone.name}"
@property @property
def extra_state_attributes(self) -> Dict[str, Any]: def extra_state_attributes(self) -> dict[str, Any]:
"""Return the optional state attributes with device specific additions.""" """Return the optional state attributes with device specific additions."""
data = { data = {
ATTR_STATUS: ATW_ZONE_HVAC_MODE_LOOKUP.get( ATTR_STATUS: ATW_ZONE_HVAC_MODE_LOOKUP.get(
@ -351,17 +353,17 @@ class AtwDeviceZoneClimate(MelCloudClimate):
await self._device.set(props) await self._device.set(props)
@property @property
def hvac_modes(self) -> List[str]: def hvac_modes(self) -> list[str]:
"""Return the list of available hvac operation modes.""" """Return the list of available hvac operation modes."""
return [self.hvac_mode] return [self.hvac_mode]
@property @property
def current_temperature(self) -> Optional[float]: def current_temperature(self) -> float | None:
"""Return the current temperature.""" """Return the current temperature."""
return self._zone.room_temperature return self._zone.room_temperature
@property @property
def target_temperature(self) -> Optional[float]: def target_temperature(self) -> float | None:
"""Return the temperature we try to reach.""" """Return the temperature we try to reach."""
return self._zone.target_temperature return self._zone.target_temperature

View File

@ -1,6 +1,7 @@
"""Config flow for the MELCloud platform.""" """Config flow for the MELCloud platform."""
from __future__ import annotations
import asyncio import asyncio
from typing import Optional
from aiohttp import ClientError, ClientResponseError from aiohttp import ClientError, ClientResponseError
from async_timeout import timeout from async_timeout import timeout
@ -37,8 +38,8 @@ class FlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
self, self,
username: str, username: str,
*, *,
password: Optional[str] = None, password: str | None = None,
token: Optional[str] = None, token: str | None = None,
): ):
"""Create client.""" """Create client."""
if password is None and token is None: if password is None and token is None:

View File

@ -1,5 +1,5 @@
"""Platform for water_heater integration.""" """Platform for water_heater integration."""
from typing import List, Optional from __future__ import annotations
from pymelcloud import DEVICE_TYPE_ATW, AtwDevice from pymelcloud import DEVICE_TYPE_ATW, AtwDevice
from pymelcloud.atw_device import ( from pymelcloud.atw_device import (
@ -49,7 +49,7 @@ class AtwWaterHeater(WaterHeaterEntity):
await self._api.async_update() await self._api.async_update()
@property @property
def unique_id(self) -> Optional[str]: def unique_id(self) -> str | None:
"""Return a unique ID.""" """Return a unique ID."""
return f"{self._api.device.serial}" return f"{self._api.device.serial}"
@ -83,17 +83,17 @@ class AtwWaterHeater(WaterHeaterEntity):
return TEMP_CELSIUS return TEMP_CELSIUS
@property @property
def current_operation(self) -> Optional[str]: def current_operation(self) -> str | None:
"""Return current operation as reported by pymelcloud.""" """Return current operation as reported by pymelcloud."""
return self._device.operation_mode return self._device.operation_mode
@property @property
def operation_list(self) -> List[str]: def operation_list(self) -> list[str]:
"""Return the list of available operation modes as reported by pymelcloud.""" """Return the list of available operation modes as reported by pymelcloud."""
return self._device.operation_modes return self._device.operation_modes
@property @property
def current_temperature(self) -> Optional[float]: def current_temperature(self) -> float | None:
"""Return the current temperature.""" """Return the current temperature."""
return self._device.tank_temperature return self._device.tank_temperature
@ -122,11 +122,11 @@ class AtwWaterHeater(WaterHeaterEntity):
return SUPPORT_TARGET_TEMPERATURE | SUPPORT_OPERATION_MODE return SUPPORT_TARGET_TEMPERATURE | SUPPORT_OPERATION_MODE
@property @property
def min_temp(self) -> Optional[float]: def min_temp(self) -> float | None:
"""Return the minimum temperature.""" """Return the minimum temperature."""
return self._device.target_tank_temperature_min return self._device.target_tank_temperature_min
@property @property
def max_temp(self) -> Optional[float]: def max_temp(self) -> float | None:
"""Return the maximum temperature.""" """Return the maximum temperature."""
return self._device.target_tank_temperature_max return self._device.target_tank_temperature_max

View File

@ -1,5 +1,7 @@
"""Config flow to configure Met component.""" """Config flow to configure Met component."""
from typing import Any, Dict, Optional from __future__ import annotations
from typing import Any
import voluptuous as vol import voluptuous as vol
@ -73,9 +75,7 @@ class MetFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
errors=self._errors, errors=self._errors,
) )
async def async_step_import( async def async_step_import(self, user_input: dict | None = None) -> dict[str, Any]:
self, user_input: Optional[Dict] = None
) -> Dict[str, Any]:
"""Handle configuration by yaml file.""" """Handle configuration by yaml file."""
return await self.async_step_user(user_input) return await self.async_step_user(user_input)

View File

@ -1,9 +1,10 @@
"""The Minecraft Server integration.""" """The Minecraft Server integration."""
from __future__ import annotations
import asyncio import asyncio
from datetime import datetime, timedelta from datetime import datetime, timedelta
import logging import logging
from typing import Any, Dict from typing import Any
from mcstatus.server import MinecraftServer as MCStatus from mcstatus.server import MinecraftServer as MCStatus
@ -260,7 +261,7 @@ class MinecraftServerEntity(Entity):
return self._unique_id return self._unique_id
@property @property
def device_info(self) -> Dict[str, Any]: def device_info(self) -> dict[str, Any]:
"""Return device information.""" """Return device information."""
return self._device_info return self._device_info

View File

@ -1,6 +1,7 @@
"""Helper functions for the Minecraft Server integration.""" """Helper functions for the Minecraft Server integration."""
from __future__ import annotations
from typing import Any, Dict from typing import Any
import aiodns import aiodns
@ -10,7 +11,7 @@ from homeassistant.helpers.typing import HomeAssistantType
from .const import SRV_RECORD_PREFIX from .const import SRV_RECORD_PREFIX
async def async_check_srv_record(hass: HomeAssistantType, host: str) -> Dict[str, Any]: async def async_check_srv_record(hass: HomeAssistantType, host: str) -> dict[str, Any]:
"""Check if the given host is a valid Minecraft SRV record.""" """Check if the given host is a valid Minecraft SRV record."""
# Check if 'host' is a valid SRV record. # Check if 'host' is a valid SRV record.
return_value = None return_value = None

View File

@ -1,5 +1,7 @@
"""The Minecraft Server sensor platform.""" """The Minecraft Server sensor platform."""
from typing import Any, Dict from __future__ import annotations
from typing import Any
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
from homeassistant.const import TIME_MILLISECONDS from homeassistant.const import TIME_MILLISECONDS
@ -151,7 +153,7 @@ class MinecraftServerPlayersOnlineSensor(MinecraftServerSensorEntity):
self._extra_state_attributes = extra_state_attributes self._extra_state_attributes = extra_state_attributes
@property @property
def extra_state_attributes(self) -> Dict[str, Any]: def extra_state_attributes(self) -> dict[str, Any]:
"""Return players list in device state attributes.""" """Return players list in device state attributes."""
return self._extra_state_attributes return self._extra_state_attributes

View File

@ -1,9 +1,10 @@
"""Minio component.""" """Minio component."""
from __future__ import annotations
import logging import logging
import os import os
from queue import Queue from queue import Queue
import threading import threading
from typing import List
import voluptuous as vol import voluptuous as vol
@ -230,7 +231,7 @@ class MinioListener:
bucket_name: str, bucket_name: str,
prefix: str, prefix: str,
suffix: str, suffix: str,
events: List[str], events: list[str],
): ):
"""Create Listener.""" """Create Listener."""
self._queue = queue self._queue = queue

View File

@ -1,4 +1,6 @@
"""Minio helper methods.""" """Minio helper methods."""
from __future__ import annotations
from collections.abc import Iterable from collections.abc import Iterable
import json import json
import logging import logging
@ -6,7 +8,7 @@ from queue import Queue
import re import re
import threading import threading
import time import time
from typing import Iterator, List from typing import Iterator
from urllib.parse import unquote from urllib.parse import unquote
from minio import Minio from minio import Minio
@ -38,7 +40,7 @@ def create_minio_client(
def get_minio_notification_response( def get_minio_notification_response(
minio_client, bucket_name: str, prefix: str, suffix: str, events: List[str] minio_client, bucket_name: str, prefix: str, suffix: str, events: list[str]
): ):
"""Start listening to minio events. Copied from minio-py.""" """Start listening to minio events. Copied from minio-py."""
query = {"prefix": prefix, "suffix": suffix, "events": events} query = {"prefix": prefix, "suffix": suffix, "events": events}
@ -87,7 +89,7 @@ class MinioEventThread(threading.Thread):
bucket_name: str, bucket_name: str,
prefix: str, prefix: str,
suffix: str, suffix: str,
events: List[str], events: list[str],
): ):
"""Copy over all Minio client options.""" """Copy over all Minio client options."""
super().__init__() super().__init__()

View File

@ -1,5 +1,5 @@
"""Provides device actions for Mobile App.""" """Provides device actions for Mobile App."""
from typing import List, Optional from __future__ import annotations
import voluptuous as vol import voluptuous as vol
@ -22,7 +22,7 @@ ACTION_SCHEMA = cv.DEVICE_ACTION_BASE_SCHEMA.extend(
) )
async def async_get_actions(hass: HomeAssistant, device_id: str) -> List[dict]: async def async_get_actions(hass: HomeAssistant, device_id: str) -> list[dict]:
"""List device actions for Mobile App devices.""" """List device actions for Mobile App devices."""
webhook_id = webhook_id_from_device_id(hass, device_id) webhook_id = webhook_id_from_device_id(hass, device_id)
@ -33,7 +33,7 @@ async def async_get_actions(hass: HomeAssistant, device_id: str) -> List[dict]:
async def async_call_action_from_config( async def async_call_action_from_config(
hass: HomeAssistant, config: dict, variables: dict, context: Optional[Context] hass: HomeAssistant, config: dict, variables: dict, context: Context | None
) -> None: ) -> None:
"""Execute a device action.""" """Execute a device action."""
webhook_id = webhook_id_from_device_id(hass, config[CONF_DEVICE_ID]) webhook_id = webhook_id_from_device_id(hass, config[CONF_DEVICE_ID])

View File

@ -1,7 +1,9 @@
"""Helpers for mobile_app.""" """Helpers for mobile_app."""
from __future__ import annotations
import json import json
import logging import logging
from typing import Callable, Dict, Tuple from typing import Callable
from aiohttp.web import Response, json_response from aiohttp.web import Response, json_response
from nacl.encoding import Base64Encoder from nacl.encoding import Base64Encoder
@ -36,7 +38,7 @@ from .const import (
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
def setup_decrypt() -> Tuple[int, Callable]: def setup_decrypt() -> tuple[int, Callable]:
"""Return decryption function and length of key. """Return decryption function and length of key.
Async friendly. Async friendly.
@ -49,7 +51,7 @@ def setup_decrypt() -> Tuple[int, Callable]:
return (SecretBox.KEY_SIZE, decrypt) return (SecretBox.KEY_SIZE, decrypt)
def setup_encrypt() -> Tuple[int, Callable]: def setup_encrypt() -> tuple[int, Callable]:
"""Return encryption function and length of key. """Return encryption function and length of key.
Async friendly. Async friendly.
@ -62,7 +64,7 @@ def setup_encrypt() -> Tuple[int, Callable]:
return (SecretBox.KEY_SIZE, encrypt) return (SecretBox.KEY_SIZE, encrypt)
def _decrypt_payload(key: str, ciphertext: str) -> Dict[str, str]: def _decrypt_payload(key: str, ciphertext: str) -> dict[str, str]:
"""Decrypt encrypted payload.""" """Decrypt encrypted payload."""
try: try:
keylen, decrypt = setup_decrypt() keylen, decrypt = setup_decrypt()
@ -88,12 +90,12 @@ def _decrypt_payload(key: str, ciphertext: str) -> Dict[str, str]:
return None return None
def registration_context(registration: Dict) -> Context: def registration_context(registration: dict) -> Context:
"""Generate a context from a request.""" """Generate a context from a request."""
return Context(user_id=registration[CONF_USER_ID]) return Context(user_id=registration[CONF_USER_ID])
def empty_okay_response(headers: Dict = None, status: int = HTTP_OK) -> Response: def empty_okay_response(headers: dict = None, status: int = HTTP_OK) -> Response:
"""Return a Response with empty JSON object and a 200.""" """Return a Response with empty JSON object and a 200."""
return Response( return Response(
text="{}", status=status, content_type=CONTENT_TYPE_JSON, headers=headers text="{}", status=status, content_type=CONTENT_TYPE_JSON, headers=headers
@ -121,7 +123,7 @@ def supports_encryption() -> bool:
return False return False
def safe_registration(registration: Dict) -> Dict: def safe_registration(registration: dict) -> dict:
"""Return a registration without sensitive values.""" """Return a registration without sensitive values."""
# Sensitive values: webhook_id, secret, cloudhook_url # Sensitive values: webhook_id, secret, cloudhook_url
return { return {
@ -137,7 +139,7 @@ def safe_registration(registration: Dict) -> Dict:
} }
def savable_state(hass: HomeAssistantType) -> Dict: def savable_state(hass: HomeAssistantType) -> dict:
"""Return a clean object containing things that should be saved.""" """Return a clean object containing things that should be saved."""
return { return {
DATA_DELETED_IDS: hass.data[DOMAIN][DATA_DELETED_IDS], DATA_DELETED_IDS: hass.data[DOMAIN][DATA_DELETED_IDS],
@ -145,7 +147,7 @@ def savable_state(hass: HomeAssistantType) -> Dict:
def webhook_response( def webhook_response(
data, *, registration: Dict, status: int = HTTP_OK, headers: Dict = None data, *, registration: dict, status: int = HTTP_OK, headers: dict = None
) -> Response: ) -> Response:
"""Return a encrypted response if registration supports it.""" """Return a encrypted response if registration supports it."""
data = json.dumps(data, cls=JSONEncoder) data = json.dumps(data, cls=JSONEncoder)
@ -165,7 +167,7 @@ def webhook_response(
) )
def device_info(registration: Dict) -> Dict: def device_info(registration: dict) -> dict:
"""Return the device info for this registration.""" """Return the device info for this registration."""
return { return {
"identifiers": {(DOMAIN, registration[ATTR_DEVICE_ID])}, "identifiers": {(DOMAIN, registration[ATTR_DEVICE_ID])},

View File

@ -1,6 +1,7 @@
"""Provides an HTTP API for mobile_app.""" """Provides an HTTP API for mobile_app."""
from __future__ import annotations
import secrets import secrets
from typing import Dict
from aiohttp.web import Request, Response from aiohttp.web import Request, Response
import emoji import emoji
@ -58,7 +59,7 @@ class RegistrationsView(HomeAssistantView):
extra=vol.REMOVE_EXTRA, extra=vol.REMOVE_EXTRA,
) )
) )
async def post(self, request: Request, data: Dict) -> Response: async def post(self, request: Request, data: dict) -> Response:
"""Handle the POST request for registration.""" """Handle the POST request for registration."""
hass = request.app["hass"] hass = request.app["hass"]

View File

@ -1,5 +1,7 @@
"""Mobile app utility functions.""" """Mobile app utility functions."""
from typing import TYPE_CHECKING, Optional from __future__ import annotations
from typing import TYPE_CHECKING
from homeassistant.core import callback from homeassistant.core import callback
@ -18,7 +20,7 @@ if TYPE_CHECKING:
@callback @callback
def webhook_id_from_device_id(hass, device_id: str) -> Optional[str]: def webhook_id_from_device_id(hass, device_id: str) -> str | None:
"""Get webhook ID from device ID.""" """Get webhook ID from device ID."""
if DOMAIN not in hass.data: if DOMAIN not in hass.data:
return None return None
@ -39,7 +41,7 @@ def supports_push(hass, webhook_id: str) -> bool:
@callback @callback
def get_notify_service(hass, webhook_id: str) -> Optional[str]: def get_notify_service(hass, webhook_id: str) -> str | None:
"""Return the notify service for this webhook ID.""" """Return the notify service for this webhook ID."""
notify_service: "MobileAppNotificationService" = hass.data[DOMAIN][DATA_NOTIFY] notify_service: "MobileAppNotificationService" = hass.data[DOMAIN][DATA_NOTIFY]

View File

@ -1,5 +1,5 @@
"""Support for Modbus Coil and Discrete Input sensors.""" """Support for Modbus Coil and Discrete Input sensors."""
from typing import Optional from __future__ import annotations
from pymodbus.exceptions import ConnectionException, ModbusException from pymodbus.exceptions import ConnectionException, ModbusException
from pymodbus.pdu import ExceptionResponse from pymodbus.pdu import ExceptionResponse
@ -94,7 +94,7 @@ class ModbusBinarySensor(BinarySensorEntity):
return self._value return self._value
@property @property
def device_class(self) -> Optional[str]: def device_class(self) -> str | None:
"""Return the device class of the sensor.""" """Return the device class of the sensor."""
return self._device_class return self._device_class

View File

@ -1,8 +1,10 @@
"""Support for Generic Modbus Thermostats.""" """Support for Generic Modbus Thermostats."""
from __future__ import annotations
from datetime import timedelta from datetime import timedelta
import logging import logging
import struct import struct
from typing import Any, Dict, Optional from typing import Any
from pymodbus.exceptions import ConnectionException, ModbusException from pymodbus.exceptions import ConnectionException, ModbusException
from pymodbus.pdu import ExceptionResponse from pymodbus.pdu import ExceptionResponse
@ -57,7 +59,7 @@ async def async_setup_platform(
hass: HomeAssistantType, hass: HomeAssistantType,
config: ConfigType, config: ConfigType,
async_add_entities, async_add_entities,
discovery_info: Optional[DiscoveryInfoType] = None, discovery_info: DiscoveryInfoType | None = None,
): ):
"""Read configuration and create Modbus climate.""" """Read configuration and create Modbus climate."""
if discovery_info is None: if discovery_info is None:
@ -108,7 +110,7 @@ class ModbusThermostat(ClimateEntity):
def __init__( def __init__(
self, self,
hub: ModbusHub, hub: ModbusHub,
config: Dict[str, Any], config: dict[str, Any],
): ):
"""Initialize the modbus thermostat.""" """Initialize the modbus thermostat."""
self._hub: ModbusHub = hub self._hub: ModbusHub = hub
@ -232,7 +234,7 @@ class ModbusThermostat(ClimateEntity):
self.schedule_update_ha_state() self.schedule_update_ha_state()
def _read_register(self, register_type, register) -> Optional[float]: def _read_register(self, register_type, register) -> float | None:
"""Read register using the Modbus hub slave.""" """Read register using the Modbus hub slave."""
try: try:
if register_type == CALL_TYPE_REGISTER_INPUT: if register_type == CALL_TYPE_REGISTER_INPUT:

View File

@ -1,6 +1,8 @@
"""Support for Modbus covers.""" """Support for Modbus covers."""
from __future__ import annotations
from datetime import timedelta from datetime import timedelta
from typing import Any, Dict, Optional from typing import Any
from pymodbus.exceptions import ConnectionException, ModbusException from pymodbus.exceptions import ConnectionException, ModbusException
from pymodbus.pdu import ExceptionResponse from pymodbus.pdu import ExceptionResponse
@ -41,7 +43,7 @@ async def async_setup_platform(
hass: HomeAssistantType, hass: HomeAssistantType,
config: ConfigType, config: ConfigType,
async_add_entities, async_add_entities,
discovery_info: Optional[DiscoveryInfoType] = None, discovery_info: DiscoveryInfoType | None = None,
): ):
"""Read configuration and create Modbus cover.""" """Read configuration and create Modbus cover."""
if discovery_info is None: if discovery_info is None:
@ -61,7 +63,7 @@ class ModbusCover(CoverEntity, RestoreEntity):
def __init__( def __init__(
self, self,
hub: ModbusHub, hub: ModbusHub,
config: Dict[str, Any], config: dict[str, Any],
): ):
"""Initialize the modbus cover.""" """Initialize the modbus cover."""
self._hub: ModbusHub = hub self._hub: ModbusHub = hub
@ -108,7 +110,7 @@ class ModbusCover(CoverEntity, RestoreEntity):
) )
@property @property
def device_class(self) -> Optional[str]: def device_class(self) -> str | None:
"""Return the device class of the sensor.""" """Return the device class of the sensor."""
return self._device_class return self._device_class
@ -178,7 +180,7 @@ class ModbusCover(CoverEntity, RestoreEntity):
self.schedule_update_ha_state() self.schedule_update_ha_state()
def _read_status_register(self) -> Optional[int]: def _read_status_register(self) -> int | None:
"""Read status register using the Modbus hub slave.""" """Read status register using the Modbus hub slave."""
try: try:
if self._status_register_type == CALL_TYPE_REGISTER_INPUT: if self._status_register_type == CALL_TYPE_REGISTER_INPUT:
@ -212,7 +214,7 @@ class ModbusCover(CoverEntity, RestoreEntity):
self._available = True self._available = True
def _read_coil(self) -> Optional[bool]: def _read_coil(self) -> bool | None:
"""Read coil using the Modbus hub slave.""" """Read coil using the Modbus hub slave."""
try: try:
result = self._hub.read_coils(self._slave, self._coil, 1) result = self._hub.read_coils(self._slave, self._coil, 1)

View File

@ -1,7 +1,9 @@
"""Support for Modbus Register sensors.""" """Support for Modbus Register sensors."""
from __future__ import annotations
import logging import logging
import struct import struct
from typing import Any, Optional, Union from typing import Any
from pymodbus.exceptions import ConnectionException, ModbusException from pymodbus.exceptions import ConnectionException, ModbusException
from pymodbus.pdu import ExceptionResponse from pymodbus.pdu import ExceptionResponse
@ -44,7 +46,7 @@ from .const import (
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
def number(value: Any) -> Union[int, float]: def number(value: Any) -> int | float:
"""Coerce a value to number without losing precision.""" """Coerce a value to number without losing precision."""
if isinstance(value, int): if isinstance(value, int):
return value return value
@ -217,7 +219,7 @@ class ModbusRegisterSensor(RestoreEntity):
return self._unit_of_measurement return self._unit_of_measurement
@property @property
def device_class(self) -> Optional[str]: def device_class(self) -> str | None:
"""Return the device class of the sensor.""" """Return the device class of the sensor."""
return self._device_class return self._device_class

View File

@ -1,7 +1,9 @@
"""Support for Modbus switches.""" """Support for Modbus switches."""
from __future__ import annotations
from abc import ABC from abc import ABC
import logging import logging
from typing import Any, Dict, Optional from typing import Any
from pymodbus.exceptions import ConnectionException, ModbusException from pymodbus.exceptions import ConnectionException, ModbusException
from pymodbus.pdu import ExceptionResponse from pymodbus.pdu import ExceptionResponse
@ -99,7 +101,7 @@ async def async_setup_platform(
class ModbusBaseSwitch(ToggleEntity, RestoreEntity, ABC): class ModbusBaseSwitch(ToggleEntity, RestoreEntity, ABC):
"""Base class representing a Modbus switch.""" """Base class representing a Modbus switch."""
def __init__(self, hub: ModbusHub, config: Dict[str, Any]): def __init__(self, hub: ModbusHub, config: dict[str, Any]):
"""Initialize the switch.""" """Initialize the switch."""
self._hub: ModbusHub = hub self._hub: ModbusHub = hub
self._name = config[CONF_NAME] self._name = config[CONF_NAME]
@ -133,7 +135,7 @@ class ModbusBaseSwitch(ToggleEntity, RestoreEntity, ABC):
class ModbusCoilSwitch(ModbusBaseSwitch, SwitchEntity): class ModbusCoilSwitch(ModbusBaseSwitch, SwitchEntity):
"""Representation of a Modbus coil switch.""" """Representation of a Modbus coil switch."""
def __init__(self, hub: ModbusHub, config: Dict[str, Any]): def __init__(self, hub: ModbusHub, config: dict[str, Any]):
"""Initialize the coil switch.""" """Initialize the coil switch."""
super().__init__(hub, config) super().__init__(hub, config)
self._coil = config[CALL_TYPE_COIL] self._coil = config[CALL_TYPE_COIL]
@ -184,7 +186,7 @@ class ModbusCoilSwitch(ModbusBaseSwitch, SwitchEntity):
class ModbusRegisterSwitch(ModbusBaseSwitch, SwitchEntity): class ModbusRegisterSwitch(ModbusBaseSwitch, SwitchEntity):
"""Representation of a Modbus register switch.""" """Representation of a Modbus register switch."""
def __init__(self, hub: ModbusHub, config: Dict[str, Any]): def __init__(self, hub: ModbusHub, config: dict[str, Any]):
"""Initialize the register switch.""" """Initialize the register switch."""
super().__init__(hub, config) super().__init__(hub, config)
self._register = config[CONF_REGISTER] self._register = config[CONF_REGISTER]
@ -238,7 +240,7 @@ class ModbusRegisterSwitch(ModbusBaseSwitch, SwitchEntity):
value, value,
) )
def _read_register(self) -> Optional[int]: def _read_register(self) -> int | None:
try: try:
if self._register_type == CALL_TYPE_REGISTER_INPUT: if self._register_type == CALL_TYPE_REGISTER_INPUT:
result = self._hub.read_input_registers( result = self._hub.read_input_registers(

View File

@ -1,4 +1,6 @@
"""Support for MQTT message handling.""" """Support for MQTT message handling."""
from __future__ import annotations
import asyncio import asyncio
from functools import lru_cache, partial, wraps from functools import lru_cache, partial, wraps
import inspect import inspect
@ -8,7 +10,7 @@ from operator import attrgetter
import os import os
import ssl import ssl
import time import time
from typing import Any, Callable, List, Optional, Union from typing import Any, Callable, Union
import uuid import uuid
import attr import attr
@ -310,7 +312,7 @@ async def async_subscribe(
topic: str, topic: str,
msg_callback: MessageCallbackType, msg_callback: MessageCallbackType,
qos: int = DEFAULT_QOS, qos: int = DEFAULT_QOS,
encoding: Optional[str] = "utf-8", encoding: str | None = "utf-8",
): ):
"""Subscribe to an MQTT topic. """Subscribe to an MQTT topic.
@ -385,7 +387,7 @@ async def _async_setup_discovery(
async def async_setup(hass: HomeAssistantType, config: ConfigType) -> bool: async def async_setup(hass: HomeAssistantType, config: ConfigType) -> bool:
"""Start the MQTT protocol service.""" """Start the MQTT protocol service."""
conf: Optional[ConfigType] = config.get(DOMAIN) conf: ConfigType | None = config.get(DOMAIN)
websocket_api.async_register_command(hass, websocket_subscribe) websocket_api.async_register_command(hass, websocket_subscribe)
websocket_api.async_register_command(hass, websocket_remove_device) websocket_api.async_register_command(hass, websocket_remove_device)
@ -552,7 +554,7 @@ class MQTT:
self.hass = hass self.hass = hass
self.config_entry = config_entry self.config_entry = config_entry
self.conf = conf self.conf = conf
self.subscriptions: List[Subscription] = [] self.subscriptions: list[Subscription] = []
self.connected = False self.connected = False
self._ha_started = asyncio.Event() self._ha_started = asyncio.Event()
self._last_subscribe = time.time() self._last_subscribe = time.time()
@ -730,7 +732,7 @@ class MQTT:
topic: str, topic: str,
msg_callback: MessageCallbackType, msg_callback: MessageCallbackType,
qos: int, qos: int,
encoding: Optional[str] = None, encoding: str | None = None,
) -> Callable[[], None]: ) -> Callable[[], None]:
"""Set up a subscription to a topic with the provided qos. """Set up a subscription to a topic with the provided qos.

View File

@ -1,6 +1,8 @@
"""Provides device automations for MQTT.""" """Provides device automations for MQTT."""
from __future__ import annotations
import logging import logging
from typing import Callable, List, Optional from typing import Callable
import attr import attr
import voluptuous as vol import voluptuous as vol
@ -86,7 +88,7 @@ class TriggerInstance:
action: AutomationActionType = attr.ib() action: AutomationActionType = attr.ib()
automation_info: dict = attr.ib() automation_info: dict = attr.ib()
trigger: "Trigger" = attr.ib() trigger: "Trigger" = attr.ib()
remove: Optional[CALLBACK_TYPE] = attr.ib(default=None) remove: CALLBACK_TYPE | None = attr.ib(default=None)
async def async_attach_trigger(self): async def async_attach_trigger(self):
"""Attach MQTT trigger.""" """Attach MQTT trigger."""
@ -126,7 +128,7 @@ class Trigger:
topic: str = attr.ib() topic: str = attr.ib()
type: str = attr.ib() type: str = attr.ib()
value_template: str = attr.ib() value_template: str = attr.ib()
trigger_instances: List[TriggerInstance] = attr.ib(factory=list) trigger_instances: list[TriggerInstance] = attr.ib(factory=list)
async def add_trigger(self, action, automation_info): async def add_trigger(self, action, automation_info):
"""Add MQTT trigger.""" """Add MQTT trigger."""
@ -285,7 +287,7 @@ async def async_device_removed(hass: HomeAssistant, device_id: str):
) )
async def async_get_triggers(hass: HomeAssistant, device_id: str) -> List[dict]: async def async_get_triggers(hass: HomeAssistant, device_id: str) -> list[dict]:
"""List device triggers for MQTT devices.""" """List device triggers for MQTT devices."""
triggers = [] triggers = []

View File

@ -1,8 +1,9 @@
"""MQTT component mixins and helpers.""" """MQTT component mixins and helpers."""
from __future__ import annotations
from abc import abstractmethod from abc import abstractmethod
import json import json
import logging import logging
from typing import Optional
import voluptuous as vol import voluptuous as vol
@ -502,7 +503,7 @@ def device_info_from_config(config):
class MqttEntityDeviceInfo(Entity): class MqttEntityDeviceInfo(Entity):
"""Mixin used for mqtt platforms that support the device registry.""" """Mixin used for mqtt platforms that support the device registry."""
def __init__(self, device_config: Optional[ConfigType], config_entry=None) -> None: def __init__(self, device_config: ConfigType | None, config_entry=None) -> None:
"""Initialize the device mixin.""" """Initialize the device mixin."""
self._device_config = device_config self._device_config = device_config
self._config_entry = config_entry self._config_entry = config_entry

View File

@ -1,6 +1,8 @@
"""Modesl used by multiple MQTT modules.""" """Modesl used by multiple MQTT modules."""
from __future__ import annotations
import datetime as dt import datetime as dt
from typing import Callable, Optional, Union from typing import Callable, Union
import attr import attr
@ -15,8 +17,8 @@ class Message:
payload: PublishPayloadType = attr.ib() payload: PublishPayloadType = attr.ib()
qos: int = attr.ib() qos: int = attr.ib()
retain: bool = attr.ib() retain: bool = attr.ib()
subscribed_topic: Optional[str] = attr.ib(default=None) subscribed_topic: str | None = attr.ib(default=None)
timestamp: Optional[dt.datetime] = attr.ib(default=None) timestamp: dt.datetime | None = attr.ib(default=None)
MessageCallbackType = Callable[[Message], None] MessageCallbackType = Callable[[Message], None]

View File

@ -1,7 +1,8 @@
"""Support for MQTT sensors.""" """Support for MQTT sensors."""
from __future__ import annotations
from datetime import timedelta from datetime import timedelta
import functools import functools
from typing import Optional
import voluptuous as vol import voluptuous as vol
@ -166,7 +167,7 @@ class MqttSensor(MqttEntity, Entity):
return self._state return self._state
@property @property
def device_class(self) -> Optional[str]: def device_class(self) -> str | None:
"""Return the device class of the sensor.""" """Return the device class of the sensor."""
return self._config.get(CONF_DEVICE_CLASS) return self._config.get(CONF_DEVICE_CLASS)

View File

@ -1,5 +1,7 @@
"""Helper to handle a set of topics to subscribe to.""" """Helper to handle a set of topics to subscribe to."""
from typing import Any, Callable, Dict, Optional from __future__ import annotations
from typing import Any, Callable
import attr import attr
@ -19,7 +21,7 @@ class EntitySubscription:
hass: HomeAssistantType = attr.ib() hass: HomeAssistantType = attr.ib()
topic: str = attr.ib() topic: str = attr.ib()
message_callback: MessageCallbackType = attr.ib() message_callback: MessageCallbackType = attr.ib()
unsubscribe_callback: Optional[Callable[[], None]] = attr.ib() unsubscribe_callback: Callable[[], None] | None = attr.ib()
qos: int = attr.ib(default=0) qos: int = attr.ib(default=0)
encoding: str = attr.ib(default="utf-8") encoding: str = attr.ib(default="utf-8")
@ -62,8 +64,8 @@ class EntitySubscription:
@bind_hass @bind_hass
async def async_subscribe_topics( async def async_subscribe_topics(
hass: HomeAssistantType, hass: HomeAssistantType,
new_state: Optional[Dict[str, EntitySubscription]], new_state: dict[str, EntitySubscription] | None,
topics: Dict[str, Any], topics: dict[str, Any],
): ):
"""(Re)Subscribe to a set of MQTT topics. """(Re)Subscribe to a set of MQTT topics.

View File

@ -1,8 +1,10 @@
"""Connect to a MySensors gateway via pymysensors API.""" """Connect to a MySensors gateway via pymysensors API."""
from __future__ import annotations
import asyncio import asyncio
from functools import partial from functools import partial
import logging import logging
from typing import Callable, Dict, List, Optional, Tuple, Type, Union from typing import Callable
from mysensors import BaseAsyncGateway from mysensors import BaseAsyncGateway
import voluptuous as vol import voluptuous as vol
@ -265,13 +267,13 @@ async def async_unload_entry(hass: HomeAssistantType, entry: ConfigEntry) -> boo
def setup_mysensors_platform( def setup_mysensors_platform(
hass: HomeAssistant, hass: HomeAssistant,
domain: str, # hass platform name domain: str, # hass platform name
discovery_info: Dict[str, List[DevId]], discovery_info: dict[str, list[DevId]],
device_class: Union[Type[MySensorsDevice], Dict[SensorType, Type[MySensorsEntity]]], device_class: type[MySensorsDevice] | dict[SensorType, type[MySensorsEntity]],
device_args: Optional[ device_args: (
Tuple None | tuple
] = None, # extra arguments that will be given to the entity constructor ) = None, # extra arguments that will be given to the entity constructor
async_add_entities: Optional[Callable] = None, async_add_entities: Callable | None = None,
) -> Optional[List[MySensorsDevice]]: ) -> list[MySensorsDevice] | None:
"""Set up a MySensors platform. """Set up a MySensors platform.
Sets up a bunch of instances of a single platform that is supported by this integration. Sets up a bunch of instances of a single platform that is supported by this integration.
@ -281,10 +283,10 @@ def setup_mysensors_platform(
""" """
if device_args is None: if device_args is None:
device_args = () device_args = ()
new_devices: List[MySensorsDevice] = [] new_devices: list[MySensorsDevice] = []
new_dev_ids: List[DevId] = discovery_info[ATTR_DEVICES] new_dev_ids: list[DevId] = discovery_info[ATTR_DEVICES]
for dev_id in new_dev_ids: for dev_id in new_dev_ids:
devices: Dict[DevId, MySensorsDevice] = get_mysensors_devices(hass, domain) devices: dict[DevId, MySensorsDevice] = get_mysensors_devices(hass, domain)
if dev_id in devices: if dev_id in devices:
_LOGGER.debug( _LOGGER.debug(
"Skipping setup of %s for platform %s as it already exists", "Skipping setup of %s for platform %s as it already exists",
@ -293,7 +295,7 @@ def setup_mysensors_platform(
) )
continue continue
gateway_id, node_id, child_id, value_type = dev_id gateway_id, node_id, child_id, value_type = dev_id
gateway: Optional[BaseAsyncGateway] = get_mysensors_gateway(hass, gateway_id) gateway: BaseAsyncGateway | None = get_mysensors_gateway(hass, gateway_id)
if not gateway: if not gateway:
_LOGGER.warning("Skipping setup of %s, no gateway found", dev_id) _LOGGER.warning("Skipping setup of %s, no gateway found", dev_id)
continue continue

View File

@ -1,7 +1,9 @@
"""Config flow for MySensors.""" """Config flow for MySensors."""
from __future__ import annotations
import logging import logging
import os import os
from typing import Any, Dict, Optional from typing import Any
from awesomeversion import ( from awesomeversion import (
AwesomeVersion, AwesomeVersion,
@ -42,7 +44,7 @@ from .gateway import MQTT_COMPONENT, is_serial_port, is_socket_address, try_conn
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
def _get_schema_common(user_input: Dict[str, str]) -> dict: def _get_schema_common(user_input: dict[str, str]) -> dict:
"""Create a schema with options common to all gateway types.""" """Create a schema with options common to all gateway types."""
schema = { schema = {
vol.Required( vol.Required(
@ -57,7 +59,7 @@ def _get_schema_common(user_input: Dict[str, str]) -> dict:
return schema return schema
def _validate_version(version: str) -> Dict[str, str]: def _validate_version(version: str) -> dict[str, str]:
"""Validate a version string from the user.""" """Validate a version string from the user."""
version_okay = False version_okay = False
try: try:
@ -75,7 +77,7 @@ def _validate_version(version: str) -> Dict[str, str]:
def _is_same_device( def _is_same_device(
gw_type: ConfGatewayType, user_input: Dict[str, str], entry: ConfigEntry gw_type: ConfGatewayType, user_input: dict[str, str], entry: ConfigEntry
): ):
"""Check if another ConfigDevice is actually the same as user_input. """Check if another ConfigDevice is actually the same as user_input.
@ -102,9 +104,9 @@ class MySensorsConfigFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
def __init__(self) -> None: def __init__(self) -> None:
"""Set up config flow.""" """Set up config flow."""
self._gw_type: Optional[str] = None self._gw_type: str | None = None
async def async_step_import(self, user_input: Optional[Dict[str, str]] = None): async def async_step_import(self, user_input: dict[str, str] | None = None):
"""Import a config entry. """Import a config entry.
This method is called by async_setup and it has already This method is called by async_setup and it has already
@ -124,12 +126,12 @@ class MySensorsConfigFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
else: else:
user_input[CONF_GATEWAY_TYPE] = CONF_GATEWAY_TYPE_SERIAL user_input[CONF_GATEWAY_TYPE] = CONF_GATEWAY_TYPE_SERIAL
result: Dict[str, Any] = await self.async_step_user(user_input=user_input) result: dict[str, Any] = await self.async_step_user(user_input=user_input)
if result["type"] == "form": if result["type"] == "form":
return self.async_abort(reason=next(iter(result["errors"].values()))) return self.async_abort(reason=next(iter(result["errors"].values())))
return result return result
async def async_step_user(self, user_input: Optional[Dict[str, str]] = None): async def async_step_user(self, user_input: dict[str, str] | None = None):
"""Create a config entry from frontend user input.""" """Create a config entry from frontend user input."""
schema = {vol.Required(CONF_GATEWAY_TYPE): vol.In(CONF_GATEWAY_TYPE_ALL)} schema = {vol.Required(CONF_GATEWAY_TYPE): vol.In(CONF_GATEWAY_TYPE_ALL)}
schema = vol.Schema(schema) schema = vol.Schema(schema)
@ -146,7 +148,7 @@ class MySensorsConfigFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
return self.async_show_form(step_id="user", data_schema=schema) return self.async_show_form(step_id="user", data_schema=schema)
async def async_step_gw_serial(self, user_input: Optional[Dict[str, str]] = None): async def async_step_gw_serial(self, user_input: dict[str, str] | None = None):
"""Create config entry for a serial gateway.""" """Create config entry for a serial gateway."""
errors = {} errors = {}
if user_input is not None: if user_input is not None:
@ -175,7 +177,7 @@ class MySensorsConfigFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
step_id="gw_serial", data_schema=schema, errors=errors step_id="gw_serial", data_schema=schema, errors=errors
) )
async def async_step_gw_tcp(self, user_input: Optional[Dict[str, str]] = None): async def async_step_gw_tcp(self, user_input: dict[str, str] | None = None):
"""Create a config entry for a tcp gateway.""" """Create a config entry for a tcp gateway."""
errors = {} errors = {}
if user_input is not None: if user_input is not None:
@ -213,7 +215,7 @@ class MySensorsConfigFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
return True return True
return False return False
async def async_step_gw_mqtt(self, user_input: Optional[Dict[str, str]] = None): async def async_step_gw_mqtt(self, user_input: dict[str, str] | None = None):
"""Create a config entry for a mqtt gateway.""" """Create a config entry for a mqtt gateway."""
errors = {} errors = {}
if user_input is not None: if user_input is not None:
@ -269,8 +271,8 @@ class MySensorsConfigFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
@callback @callback
def _async_create_entry( def _async_create_entry(
self, user_input: Optional[Dict[str, str]] = None self, user_input: dict[str, str] | None = None
) -> Dict[str, Any]: ) -> dict[str, Any]:
"""Create the config entry.""" """Create the config entry."""
return self.async_create_entry( return self.async_create_entry(
title=f"{user_input[CONF_DEVICE]}", title=f"{user_input[CONF_DEVICE]}",
@ -283,9 +285,9 @@ class MySensorsConfigFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
async def validate_common( async def validate_common(
self, self,
gw_type: ConfGatewayType, gw_type: ConfGatewayType,
errors: Dict[str, str], errors: dict[str, str],
user_input: Optional[Dict[str, str]] = None, user_input: dict[str, str] | None = None,
) -> Dict[str, str]: ) -> dict[str, str]:
"""Validate parameters common to all gateway types.""" """Validate parameters common to all gateway types."""
if user_input is not None: if user_input is not None:
errors.update(_validate_version(user_input.get(CONF_VERSION))) errors.update(_validate_version(user_input.get(CONF_VERSION)))

View File

@ -1,6 +1,8 @@
"""MySensors constants.""" """MySensors constants."""
from __future__ import annotations
from collections import defaultdict from collections import defaultdict
from typing import Dict, List, Literal, Set, Tuple from typing import Literal, Tuple
ATTR_DEVICES: str = "devices" ATTR_DEVICES: str = "devices"
ATTR_GATEWAY_ID: str = "gateway_id" ATTR_GATEWAY_ID: str = "gateway_id"
@ -21,7 +23,7 @@ ConfGatewayType = Literal["Serial", "TCP", "MQTT"]
CONF_GATEWAY_TYPE_SERIAL: ConfGatewayType = "Serial" CONF_GATEWAY_TYPE_SERIAL: ConfGatewayType = "Serial"
CONF_GATEWAY_TYPE_TCP: ConfGatewayType = "TCP" CONF_GATEWAY_TYPE_TCP: ConfGatewayType = "TCP"
CONF_GATEWAY_TYPE_MQTT: ConfGatewayType = "MQTT" CONF_GATEWAY_TYPE_MQTT: ConfGatewayType = "MQTT"
CONF_GATEWAY_TYPE_ALL: List[str] = [ CONF_GATEWAY_TYPE_ALL: list[str] = [
CONF_GATEWAY_TYPE_MQTT, CONF_GATEWAY_TYPE_MQTT,
CONF_GATEWAY_TYPE_SERIAL, CONF_GATEWAY_TYPE_SERIAL,
CONF_GATEWAY_TYPE_TCP, CONF_GATEWAY_TYPE_TCP,
@ -62,7 +64,7 @@ DevId = Tuple[GatewayId, int, int, int]
# The MySensors integration brings these together by creating an entity for every v_type of every child_id of every node. # The MySensors integration brings these together by creating an entity for every v_type of every child_id of every node.
# The DevId tuple perfectly captures this. # The DevId tuple perfectly captures this.
BINARY_SENSOR_TYPES: Dict[SensorType, Set[ValueType]] = { BINARY_SENSOR_TYPES: dict[SensorType, set[ValueType]] = {
"S_DOOR": {"V_TRIPPED"}, "S_DOOR": {"V_TRIPPED"},
"S_MOTION": {"V_TRIPPED"}, "S_MOTION": {"V_TRIPPED"},
"S_SMOKE": {"V_TRIPPED"}, "S_SMOKE": {"V_TRIPPED"},
@ -73,23 +75,23 @@ BINARY_SENSOR_TYPES: Dict[SensorType, Set[ValueType]] = {
"S_MOISTURE": {"V_TRIPPED"}, "S_MOISTURE": {"V_TRIPPED"},
} }
CLIMATE_TYPES: Dict[SensorType, Set[ValueType]] = {"S_HVAC": {"V_HVAC_FLOW_STATE"}} CLIMATE_TYPES: dict[SensorType, set[ValueType]] = {"S_HVAC": {"V_HVAC_FLOW_STATE"}}
COVER_TYPES: Dict[SensorType, Set[ValueType]] = { COVER_TYPES: dict[SensorType, set[ValueType]] = {
"S_COVER": {"V_DIMMER", "V_PERCENTAGE", "V_LIGHT", "V_STATUS"} "S_COVER": {"V_DIMMER", "V_PERCENTAGE", "V_LIGHT", "V_STATUS"}
} }
DEVICE_TRACKER_TYPES: Dict[SensorType, Set[ValueType]] = {"S_GPS": {"V_POSITION"}} DEVICE_TRACKER_TYPES: dict[SensorType, set[ValueType]] = {"S_GPS": {"V_POSITION"}}
LIGHT_TYPES: Dict[SensorType, Set[ValueType]] = { LIGHT_TYPES: dict[SensorType, set[ValueType]] = {
"S_DIMMER": {"V_DIMMER", "V_PERCENTAGE"}, "S_DIMMER": {"V_DIMMER", "V_PERCENTAGE"},
"S_RGB_LIGHT": {"V_RGB"}, "S_RGB_LIGHT": {"V_RGB"},
"S_RGBW_LIGHT": {"V_RGBW"}, "S_RGBW_LIGHT": {"V_RGBW"},
} }
NOTIFY_TYPES: Dict[SensorType, Set[ValueType]] = {"S_INFO": {"V_TEXT"}} NOTIFY_TYPES: dict[SensorType, set[ValueType]] = {"S_INFO": {"V_TEXT"}}
SENSOR_TYPES: Dict[SensorType, Set[ValueType]] = { SENSOR_TYPES: dict[SensorType, set[ValueType]] = {
"S_SOUND": {"V_LEVEL"}, "S_SOUND": {"V_LEVEL"},
"S_VIBRATION": {"V_LEVEL"}, "S_VIBRATION": {"V_LEVEL"},
"S_MOISTURE": {"V_LEVEL"}, "S_MOISTURE": {"V_LEVEL"},
@ -117,7 +119,7 @@ SENSOR_TYPES: Dict[SensorType, Set[ValueType]] = {
"S_DUST": {"V_DUST_LEVEL", "V_LEVEL"}, "S_DUST": {"V_DUST_LEVEL", "V_LEVEL"},
} }
SWITCH_TYPES: Dict[SensorType, Set[ValueType]] = { SWITCH_TYPES: dict[SensorType, set[ValueType]] = {
"S_LIGHT": {"V_LIGHT"}, "S_LIGHT": {"V_LIGHT"},
"S_BINARY": {"V_STATUS"}, "S_BINARY": {"V_STATUS"},
"S_DOOR": {"V_ARMED"}, "S_DOOR": {"V_ARMED"},
@ -134,7 +136,7 @@ SWITCH_TYPES: Dict[SensorType, Set[ValueType]] = {
} }
PLATFORM_TYPES: Dict[str, Dict[SensorType, Set[ValueType]]] = { PLATFORM_TYPES: dict[str, dict[SensorType, set[ValueType]]] = {
"binary_sensor": BINARY_SENSOR_TYPES, "binary_sensor": BINARY_SENSOR_TYPES,
"climate": CLIMATE_TYPES, "climate": CLIMATE_TYPES,
"cover": COVER_TYPES, "cover": COVER_TYPES,
@ -145,13 +147,13 @@ PLATFORM_TYPES: Dict[str, Dict[SensorType, Set[ValueType]]] = {
"switch": SWITCH_TYPES, "switch": SWITCH_TYPES,
} }
FLAT_PLATFORM_TYPES: Dict[Tuple[str, SensorType], Set[ValueType]] = { FLAT_PLATFORM_TYPES: dict[tuple[str, SensorType], set[ValueType]] = {
(platform, s_type_name): v_type_name (platform, s_type_name): v_type_name
for platform, platform_types in PLATFORM_TYPES.items() for platform, platform_types in PLATFORM_TYPES.items()
for s_type_name, v_type_name in platform_types.items() for s_type_name, v_type_name in platform_types.items()
} }
TYPE_TO_PLATFORMS: Dict[SensorType, List[str]] = defaultdict(list) TYPE_TO_PLATFORMS: dict[SensorType, list[str]] = defaultdict(list)
for platform, platform_types in PLATFORM_TYPES.items(): for platform, platform_types in PLATFORM_TYPES.items():
for s_type_name in platform_types: for s_type_name in platform_types:

View File

@ -1,7 +1,9 @@
"""Handle MySensors devices.""" """Handle MySensors devices."""
from __future__ import annotations
from functools import partial from functools import partial
import logging import logging
from typing import Any, Dict, Optional from typing import Any
from mysensors import BaseAsyncGateway, Sensor from mysensors import BaseAsyncGateway, Sensor
from mysensors.sensor import ChildSensor from mysensors.sensor import ChildSensor
@ -107,7 +109,7 @@ class MySensorsDevice:
return f"{self.gateway_id}-{self.node_id}-{self.child_id}-{self.value_type}" return f"{self.gateway_id}-{self.node_id}-{self.child_id}-{self.value_type}"
@property @property
def device_info(self) -> Optional[Dict[str, Any]]: def device_info(self) -> dict[str, Any] | None:
"""Return a dict that allows home assistant to puzzle all entities belonging to a node together.""" """Return a dict that allows home assistant to puzzle all entities belonging to a node together."""
return { return {
"identifiers": {(DOMAIN, f"{self.gateway_id}-{self.node_id}")}, "identifiers": {(DOMAIN, f"{self.gateway_id}-{self.node_id}")},
@ -196,7 +198,7 @@ class MySensorsDevice:
self.hass.loop.call_later(UPDATE_DELAY, delayed_update) self.hass.loop.call_later(UPDATE_DELAY, delayed_update)
def get_mysensors_devices(hass, domain: str) -> Dict[DevId, MySensorsDevice]: def get_mysensors_devices(hass, domain: str) -> dict[DevId, MySensorsDevice]:
"""Return MySensors devices for a hass platform name.""" """Return MySensors devices for a hass platform name."""
if MYSENSORS_PLATFORM_DEVICES.format(domain) not in hass.data[DOMAIN]: if MYSENSORS_PLATFORM_DEVICES.format(domain) not in hass.data[DOMAIN]:
hass.data[DOMAIN][MYSENSORS_PLATFORM_DEVICES.format(domain)] = {} hass.data[DOMAIN][MYSENSORS_PLATFORM_DEVICES.format(domain)] = {}

View File

@ -1,10 +1,12 @@
"""Handle MySensors gateways.""" """Handle MySensors gateways."""
from __future__ import annotations
import asyncio import asyncio
from collections import defaultdict from collections import defaultdict
import logging import logging
import socket import socket
import sys import sys
from typing import Any, Callable, Coroutine, Dict, Optional from typing import Any, Callable, Coroutine
import async_timeout import async_timeout
from mysensors import BaseAsyncGateway, Message, Sensor, mysensors from mysensors import BaseAsyncGateway, Message, Sensor, mysensors
@ -63,7 +65,7 @@ def is_socket_address(value):
raise vol.Invalid("Device is not a valid domain name or ip address") from err raise vol.Invalid("Device is not a valid domain name or ip address") from err
async def try_connect(hass: HomeAssistantType, user_input: Dict[str, str]) -> bool: async def try_connect(hass: HomeAssistantType, user_input: dict[str, str]) -> bool:
"""Try to connect to a gateway and report if it worked.""" """Try to connect to a gateway and report if it worked."""
if user_input[CONF_DEVICE] == MQTT_COMPONENT: if user_input[CONF_DEVICE] == MQTT_COMPONENT:
return True # dont validate mqtt. mqtt gateways dont send ready messages :( return True # dont validate mqtt. mqtt gateways dont send ready messages :(
@ -73,7 +75,7 @@ async def try_connect(hass: HomeAssistantType, user_input: Dict[str, str]) -> bo
def on_conn_made(_: BaseAsyncGateway) -> None: def on_conn_made(_: BaseAsyncGateway) -> None:
gateway_ready.set() gateway_ready.set()
gateway: Optional[BaseAsyncGateway] = await _get_gateway( gateway: BaseAsyncGateway | None = await _get_gateway(
hass, hass,
device=user_input[CONF_DEVICE], device=user_input[CONF_DEVICE],
version=user_input[CONF_VERSION], version=user_input[CONF_VERSION],
@ -110,7 +112,7 @@ async def try_connect(hass: HomeAssistantType, user_input: Dict[str, str]) -> bo
def get_mysensors_gateway( def get_mysensors_gateway(
hass: HomeAssistantType, gateway_id: GatewayId hass: HomeAssistantType, gateway_id: GatewayId
) -> Optional[BaseAsyncGateway]: ) -> BaseAsyncGateway | None:
"""Return the Gateway for a given GatewayId.""" """Return the Gateway for a given GatewayId."""
if MYSENSORS_GATEWAYS not in hass.data[DOMAIN]: if MYSENSORS_GATEWAYS not in hass.data[DOMAIN]:
hass.data[DOMAIN][MYSENSORS_GATEWAYS] = {} hass.data[DOMAIN][MYSENSORS_GATEWAYS] = {}
@ -120,7 +122,7 @@ def get_mysensors_gateway(
async def setup_gateway( async def setup_gateway(
hass: HomeAssistantType, entry: ConfigEntry hass: HomeAssistantType, entry: ConfigEntry
) -> Optional[BaseAsyncGateway]: ) -> BaseAsyncGateway | None:
"""Set up the Gateway for the given ConfigEntry.""" """Set up the Gateway for the given ConfigEntry."""
ready_gateway = await _get_gateway( ready_gateway = await _get_gateway(
@ -145,14 +147,14 @@ async def _get_gateway(
device: str, device: str,
version: str, version: str,
event_callback: Callable[[Message], None], event_callback: Callable[[Message], None],
persistence_file: Optional[str] = None, persistence_file: str | None = None,
baud_rate: Optional[int] = None, baud_rate: int | None = None,
tcp_port: Optional[int] = None, tcp_port: int | None = None,
topic_in_prefix: Optional[str] = None, topic_in_prefix: str | None = None,
topic_out_prefix: Optional[str] = None, topic_out_prefix: str | None = None,
retain: bool = False, retain: bool = False,
persistence: bool = True, # old persistence option has been deprecated. kwarg is here so we can run try_connect() without persistence persistence: bool = True, # old persistence option has been deprecated. kwarg is here so we can run try_connect() without persistence
) -> Optional[BaseAsyncGateway]: ) -> BaseAsyncGateway | None:
"""Return gateway after setup of the gateway.""" """Return gateway after setup of the gateway."""
if persistence_file is not None: if persistence_file is not None:

View File

@ -1,5 +1,5 @@
"""Handle MySensors messages.""" """Handle MySensors messages."""
from typing import Dict, List from __future__ import annotations
from mysensors import Message from mysensors import Message
@ -70,16 +70,16 @@ async def handle_sketch_version(
@callback @callback
def _handle_child_update( def _handle_child_update(
hass: HomeAssistantType, gateway_id: GatewayId, validated: Dict[str, List[DevId]] hass: HomeAssistantType, gateway_id: GatewayId, validated: dict[str, list[DevId]]
): ):
"""Handle a child update.""" """Handle a child update."""
signals: List[str] = [] signals: list[str] = []
# Update all platforms for the device via dispatcher. # Update all platforms for the device via dispatcher.
# Add/update entity for validated children. # Add/update entity for validated children.
for platform, dev_ids in validated.items(): for platform, dev_ids in validated.items():
devices = get_mysensors_devices(hass, platform) devices = get_mysensors_devices(hass, platform)
new_dev_ids: List[DevId] = [] new_dev_ids: list[DevId] = []
for dev_id in dev_ids: for dev_id in dev_ids:
if dev_id in devices: if dev_id in devices:
signals.append(CHILD_CALLBACK.format(*dev_id)) signals.append(CHILD_CALLBACK.format(*dev_id))

View File

@ -1,8 +1,10 @@
"""Helper functions for mysensors package.""" """Helper functions for mysensors package."""
from __future__ import annotations
from collections import defaultdict from collections import defaultdict
from enum import IntEnum from enum import IntEnum
import logging import logging
from typing import Callable, DefaultDict, Dict, List, Optional, Set, Union from typing import Callable, DefaultDict
from mysensors import BaseAsyncGateway, Message from mysensors import BaseAsyncGateway, Message
from mysensors.sensor import ChildSensor from mysensors.sensor import ChildSensor
@ -35,7 +37,7 @@ SCHEMAS = Registry()
async def on_unload( async def on_unload(
hass: HomeAssistantType, entry: Union[ConfigEntry, GatewayId], fnct: Callable hass: HomeAssistantType, entry: ConfigEntry | GatewayId, fnct: Callable
) -> None: ) -> None:
"""Register a callback to be called when entry is unloaded. """Register a callback to be called when entry is unloaded.
@ -53,7 +55,7 @@ async def on_unload(
@callback @callback
def discover_mysensors_platform( def discover_mysensors_platform(
hass: HomeAssistant, gateway_id: GatewayId, platform: str, new_devices: List[DevId] hass: HomeAssistant, gateway_id: GatewayId, platform: str, new_devices: list[DevId]
) -> None: ) -> None:
"""Discover a MySensors platform.""" """Discover a MySensors platform."""
_LOGGER.debug("Discovering platform %s with devIds: %s", platform, new_devices) _LOGGER.debug("Discovering platform %s with devIds: %s", platform, new_devices)
@ -150,7 +152,7 @@ def invalid_msg(
) )
def validate_set_msg(gateway_id: GatewayId, msg: Message) -> Dict[str, List[DevId]]: def validate_set_msg(gateway_id: GatewayId, msg: Message) -> dict[str, list[DevId]]:
"""Validate a set message.""" """Validate a set message."""
if not validate_node(msg.gateway, msg.node_id): if not validate_node(msg.gateway, msg.node_id):
return {} return {}
@ -171,34 +173,34 @@ def validate_child(
gateway: BaseAsyncGateway, gateway: BaseAsyncGateway,
node_id: int, node_id: int,
child: ChildSensor, child: ChildSensor,
value_type: Optional[int] = None, value_type: int | None = None,
) -> DefaultDict[str, List[DevId]]: ) -> DefaultDict[str, list[DevId]]:
"""Validate a child. Returns a dict mapping hass platform names to list of DevId.""" """Validate a child. Returns a dict mapping hass platform names to list of DevId."""
validated: DefaultDict[str, List[DevId]] = defaultdict(list) validated: DefaultDict[str, list[DevId]] = defaultdict(list)
pres: IntEnum = gateway.const.Presentation pres: IntEnum = gateway.const.Presentation
set_req: IntEnum = gateway.const.SetReq set_req: IntEnum = gateway.const.SetReq
child_type_name: Optional[SensorType] = next( child_type_name: SensorType | None = next(
(member.name for member in pres if member.value == child.type), None (member.name for member in pres if member.value == child.type), None
) )
value_types: Set[int] = {value_type} if value_type else {*child.values} value_types: set[int] = {value_type} if value_type else {*child.values}
value_type_names: Set[ValueType] = { value_type_names: set[ValueType] = {
member.name for member in set_req if member.value in value_types member.name for member in set_req if member.value in value_types
} }
platforms: List[str] = TYPE_TO_PLATFORMS.get(child_type_name, []) platforms: list[str] = TYPE_TO_PLATFORMS.get(child_type_name, [])
if not platforms: if not platforms:
_LOGGER.warning("Child type %s is not supported", child.type) _LOGGER.warning("Child type %s is not supported", child.type)
return validated return validated
for platform in platforms: for platform in platforms:
platform_v_names: Set[ValueType] = FLAT_PLATFORM_TYPES[ platform_v_names: set[ValueType] = FLAT_PLATFORM_TYPES[
platform, child_type_name platform, child_type_name
] ]
v_names: Set[ValueType] = platform_v_names & value_type_names v_names: set[ValueType] = platform_v_names & value_type_names
if not v_names: if not v_names:
child_value_names: Set[ValueType] = { child_value_names: set[ValueType] = {
member.name for member in set_req if member.value in child.values member.name for member in set_req if member.value in child.values
} }
v_names: Set[ValueType] = platform_v_names & child_value_names v_names: set[ValueType] = platform_v_names & child_value_names
for v_name in v_names: for v_name in v_names:
child_schema_gen = SCHEMAS.get((platform, v_name), default_schema) child_schema_gen = SCHEMAS.get((platform, v_name), default_schema)