Improve code quality command_line (#65333)

This commit is contained in:
G Johansson 2022-02-12 15:19:37 +01:00 committed by GitHub
parent db6969739f
commit 3771c154fa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 190 additions and 205 deletions

View File

@ -1,4 +1,5 @@
"""The command_line component.""" """The command_line component."""
from __future__ import annotations
import logging import logging
import subprocess import subprocess
@ -6,7 +7,9 @@ import subprocess
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
def call_shell_with_timeout(command, timeout, *, log_return_code=True): def call_shell_with_timeout(
command: str, timeout: int, *, log_return_code: bool = True
) -> int:
"""Run a shell command with a timeout. """Run a shell command with a timeout.
If log_return_code is set to False, it will not print an error if a non-zero If log_return_code is set to False, it will not print an error if a non-zero
@ -30,7 +33,7 @@ def call_shell_with_timeout(command, timeout, *, log_return_code=True):
return -1 return -1
def check_output_or_log(command, timeout): def check_output_or_log(command: str, timeout: int) -> str | None:
"""Run a shell command with a timeout and return the output.""" """Run a shell command with a timeout and return the output."""
try: try:
return_value = subprocess.check_output( return_value = subprocess.check_output(

View File

@ -23,6 +23,7 @@ from homeassistant.core import HomeAssistant
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.reload import setup_reload_service from homeassistant.helpers.reload import setup_reload_service
from homeassistant.helpers.template import Template
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
from .const import CONF_COMMAND_TIMEOUT, DEFAULT_TIMEOUT, DOMAIN, PLATFORMS from .const import CONF_COMMAND_TIMEOUT, DEFAULT_TIMEOUT, DOMAIN, PLATFORMS
@ -59,14 +60,14 @@ def setup_platform(
setup_reload_service(hass, DOMAIN, PLATFORMS) setup_reload_service(hass, DOMAIN, PLATFORMS)
name = config.get(CONF_NAME) name: str = config[CONF_NAME]
command = config.get(CONF_COMMAND) command: str = config[CONF_COMMAND]
payload_off = config.get(CONF_PAYLOAD_OFF) payload_off: str = config[CONF_PAYLOAD_OFF]
payload_on = config.get(CONF_PAYLOAD_ON) payload_on: str = config[CONF_PAYLOAD_ON]
device_class = config.get(CONF_DEVICE_CLASS) device_class: str | None = config.get(CONF_DEVICE_CLASS)
value_template = config.get(CONF_VALUE_TEMPLATE) value_template: Template | None = config.get(CONF_VALUE_TEMPLATE)
command_timeout = config.get(CONF_COMMAND_TIMEOUT) command_timeout: int = config[CONF_COMMAND_TIMEOUT]
unique_id = config.get(CONF_UNIQUE_ID) unique_id: str | None = config.get(CONF_UNIQUE_ID)
if value_template is not None: if value_template is not None:
value_template.hass = hass value_template.hass = hass
data = CommandSensorData(hass, command, command_timeout) data = CommandSensorData(hass, command, command_timeout)
@ -74,7 +75,6 @@ def setup_platform(
add_entities( add_entities(
[ [
CommandBinarySensor( CommandBinarySensor(
hass,
data, data,
name, name,
device_class, device_class,
@ -93,42 +93,25 @@ class CommandBinarySensor(BinarySensorEntity):
def __init__( def __init__(
self, self,
hass, data: CommandSensorData,
data, name: str,
name, device_class: str | None,
device_class, payload_on: str,
payload_on, payload_off: str,
payload_off, value_template: Template | None,
value_template, unique_id: str | None,
unique_id, ) -> None:
):
"""Initialize the Command line binary sensor.""" """Initialize the Command line binary sensor."""
self._hass = hass
self.data = data self.data = data
self._name = name self._attr_name = name
self._device_class = device_class self._attr_device_class = device_class
self._state = False self._attr_is_on = None
self._payload_on = payload_on self._payload_on = payload_on
self._payload_off = payload_off self._payload_off = payload_off
self._value_template = value_template self._value_template = value_template
self._attr_unique_id = unique_id self._attr_unique_id = unique_id
@property def update(self) -> None:
def name(self):
"""Return the name of the sensor."""
return self._name
@property
def is_on(self):
"""Return true if the binary sensor is on."""
return self._state
@property
def device_class(self):
"""Return the class of the binary sensor."""
return self._device_class
def update(self):
"""Get the latest data and updates the state.""" """Get the latest data and updates the state."""
self.data.update() self.data.update()
value = self.data.value value = self.data.value
@ -136,6 +119,6 @@ class CommandBinarySensor(BinarySensorEntity):
if self._value_template is not None: if self._value_template is not None:
value = self._value_template.render_with_possible_json_value(value, False) value = self._value_template.render_with_possible_json_value(value, False)
if value == self._payload_on: if value == self._payload_on:
self._state = True self._attr_is_on = True
elif value == self._payload_off: elif value == self._payload_off:
self._state = False self._attr_is_on = False

View File

@ -2,6 +2,7 @@
from __future__ import annotations from __future__ import annotations
import logging import logging
from typing import TYPE_CHECKING, Any
import voluptuous as vol import voluptuous as vol
@ -20,6 +21,7 @@ from homeassistant.core import HomeAssistant
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.reload import setup_reload_service from homeassistant.helpers.reload import setup_reload_service
from homeassistant.helpers.template import Template
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
from . import call_shell_with_timeout, check_output_or_log from . import call_shell_with_timeout, check_output_or_log
@ -55,17 +57,16 @@ def setup_platform(
setup_reload_service(hass, DOMAIN, PLATFORMS) setup_reload_service(hass, DOMAIN, PLATFORMS)
devices = config.get(CONF_COVERS, {}) devices: dict[str, Any] = config.get(CONF_COVERS, {})
covers = [] covers = []
for device_name, device_config in devices.items(): for device_name, device_config in devices.items():
value_template = device_config.get(CONF_VALUE_TEMPLATE) value_template: Template | None = device_config.get(CONF_VALUE_TEMPLATE)
if value_template is not None: if value_template is not None:
value_template.hass = hass value_template.hass = hass
covers.append( covers.append(
CommandCover( CommandCover(
hass,
device_config.get(CONF_FRIENDLY_NAME, device_name), device_config.get(CONF_FRIENDLY_NAME, device_name),
device_config[CONF_COMMAND_OPEN], device_config[CONF_COMMAND_OPEN],
device_config[CONF_COMMAND_CLOSE], device_config[CONF_COMMAND_CLOSE],
@ -89,20 +90,18 @@ class CommandCover(CoverEntity):
def __init__( def __init__(
self, self,
hass, name: str,
name, command_open: str,
command_open, command_close: str,
command_close, command_stop: str,
command_stop, command_state: str | None,
command_state, value_template: Template | None,
value_template, timeout: int,
timeout, unique_id: str | None,
unique_id, ) -> None:
):
"""Initialize the cover.""" """Initialize the cover."""
self._hass = hass self._attr_name = name
self._name = name self._state: int | None = None
self._state = None
self._command_open = command_open self._command_open = command_open
self._command_close = command_close self._command_close = command_close
self._command_stop = command_stop self._command_stop = command_stop
@ -110,8 +109,9 @@ class CommandCover(CoverEntity):
self._value_template = value_template self._value_template = value_template
self._timeout = timeout self._timeout = timeout
self._attr_unique_id = unique_id self._attr_unique_id = unique_id
self._attr_should_poll = bool(command_state)
def _move_cover(self, command): def _move_cover(self, command: str) -> bool:
"""Execute the actual commands.""" """Execute the actual commands."""
_LOGGER.info("Running command: %s", command) _LOGGER.info("Running command: %s", command)
@ -123,35 +123,29 @@ class CommandCover(CoverEntity):
return success return success
@property @property
def should_poll(self): def is_closed(self) -> bool | None:
"""Only poll if we have state command."""
return self._command_state is not None
@property
def name(self):
"""Return the name of the cover."""
return self._name
@property
def is_closed(self):
"""Return if the cover is closed.""" """Return if the cover is closed."""
if self.current_cover_position is not None: if self.current_cover_position is not None:
return self.current_cover_position == 0 return self.current_cover_position == 0
return None
@property @property
def current_cover_position(self): def current_cover_position(self) -> int | None:
"""Return current position of cover. """Return current position of cover.
None is unknown, 0 is closed, 100 is fully open. None is unknown, 0 is closed, 100 is fully open.
""" """
return self._state return self._state
def _query_state(self): def _query_state(self) -> str | None:
"""Query for the state.""" """Query for the state."""
_LOGGER.info("Running state value command: %s", self._command_state) if self._command_state:
return check_output_or_log(self._command_state, self._timeout) _LOGGER.info("Running state value command: %s", self._command_state)
return check_output_or_log(self._command_state, self._timeout)
if TYPE_CHECKING:
return None
def update(self): def update(self) -> None:
"""Update device state.""" """Update device state."""
if self._command_state: if self._command_state:
payload = str(self._query_state()) payload = str(self._query_state())
@ -159,14 +153,14 @@ class CommandCover(CoverEntity):
payload = self._value_template.render_with_possible_json_value(payload) payload = self._value_template.render_with_possible_json_value(payload)
self._state = int(payload) self._state = int(payload)
def open_cover(self, **kwargs): def open_cover(self, **kwargs) -> None:
"""Open the cover.""" """Open the cover."""
self._move_cover(self._command_open) self._move_cover(self._command_open)
def close_cover(self, **kwargs): def close_cover(self, **kwargs) -> None:
"""Close the cover.""" """Close the cover."""
self._move_cover(self._command_close) self._move_cover(self._command_close)
def stop_cover(self, **kwargs): def stop_cover(self, **kwargs) -> None:
"""Stop the cover.""" """Stop the cover."""
self._move_cover(self._command_stop) self._move_cover(self._command_stop)

View File

@ -1,4 +1,6 @@
"""Support for command line notification services.""" """Support for command line notification services."""
from __future__ import annotations
import logging import logging
import subprocess import subprocess
@ -6,7 +8,9 @@ import voluptuous as vol
from homeassistant.components.notify import PLATFORM_SCHEMA, BaseNotificationService from homeassistant.components.notify import PLATFORM_SCHEMA, BaseNotificationService
from homeassistant.const import CONF_COMMAND, CONF_NAME from homeassistant.const import CONF_COMMAND, CONF_NAME
from homeassistant.core import HomeAssistant
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
from homeassistant.util.process import kill_subprocess from homeassistant.util.process import kill_subprocess
from .const import CONF_COMMAND_TIMEOUT, DEFAULT_TIMEOUT from .const import CONF_COMMAND_TIMEOUT, DEFAULT_TIMEOUT
@ -22,10 +26,14 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
) )
def get_service(hass, config, discovery_info=None): def get_service(
hass: HomeAssistant,
config: ConfigType,
discovery_info: DiscoveryInfoType | None = None,
) -> CommandLineNotificationService:
"""Get the Command Line notification service.""" """Get the Command Line notification service."""
command = config[CONF_COMMAND] command: str = config[CONF_COMMAND]
timeout = config[CONF_COMMAND_TIMEOUT] timeout: int = config[CONF_COMMAND_TIMEOUT]
return CommandLineNotificationService(command, timeout) return CommandLineNotificationService(command, timeout)
@ -33,12 +41,12 @@ def get_service(hass, config, discovery_info=None):
class CommandLineNotificationService(BaseNotificationService): class CommandLineNotificationService(BaseNotificationService):
"""Implement the notification service for the Command Line service.""" """Implement the notification service for the Command Line service."""
def __init__(self, command, timeout): def __init__(self, command: str, timeout: int) -> None:
"""Initialize the service.""" """Initialize the service."""
self.command = command self.command = command
self._timeout = timeout self._timeout = timeout
def send_message(self, message="", **kwargs): def send_message(self, message="", **kwargs) -> None:
"""Send a message to a command line.""" """Send a message to a command line."""
with subprocess.Popen( with subprocess.Popen(
self.command, self.command,

View File

@ -19,10 +19,10 @@ from homeassistant.const import (
) )
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.exceptions import TemplateError from homeassistant.exceptions import TemplateError
from homeassistant.helpers import template
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.reload import setup_reload_service from homeassistant.helpers.reload import setup_reload_service
from homeassistant.helpers.template import Template
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
from . import check_output_or_log from . import check_output_or_log
@ -59,23 +59,19 @@ def setup_platform(
setup_reload_service(hass, DOMAIN, PLATFORMS) setup_reload_service(hass, DOMAIN, PLATFORMS)
name = config.get(CONF_NAME) name: str = config[CONF_NAME]
command = config.get(CONF_COMMAND) command: str = config[CONF_COMMAND]
unit = config.get(CONF_UNIT_OF_MEASUREMENT) unit: str | None = config.get(CONF_UNIT_OF_MEASUREMENT)
value_template = config.get(CONF_VALUE_TEMPLATE) value_template: Template | None = config.get(CONF_VALUE_TEMPLATE)
command_timeout = config.get(CONF_COMMAND_TIMEOUT) command_timeout: int = config[CONF_COMMAND_TIMEOUT]
unique_id = config.get(CONF_UNIQUE_ID) unique_id: str | None = config.get(CONF_UNIQUE_ID)
if value_template is not None: if value_template is not None:
value_template.hass = hass value_template.hass = hass
json_attributes = config.get(CONF_JSON_ATTRIBUTES) json_attributes: list[str] | None = config.get(CONF_JSON_ATTRIBUTES)
data = CommandSensorData(hass, command, command_timeout) data = CommandSensorData(hass, command, command_timeout)
add_entities( add_entities(
[ [CommandSensor(data, name, unit, value_template, json_attributes, unique_id)],
CommandSensor(
hass, data, name, unit, value_template, json_attributes, unique_id
)
],
True, True,
) )
@ -85,57 +81,35 @@ class CommandSensor(SensorEntity):
def __init__( def __init__(
self, self,
hass, data: CommandSensorData,
data, name: str,
name, unit_of_measurement: str | None,
unit_of_measurement, value_template: Template | None,
value_template, json_attributes: list[str] | None,
json_attributes, unique_id: str | None,
unique_id, ) -> None:
):
"""Initialize the sensor.""" """Initialize the sensor."""
self._hass = hass
self.data = data self.data = data
self._attributes = None self._attr_extra_state_attributes = {}
self._json_attributes = json_attributes self._json_attributes = json_attributes
self._name = name self._attr_name = name
self._state = None self._attr_native_value = None
self._unit_of_measurement = unit_of_measurement self._attr_native_unit_of_measurement = unit_of_measurement
self._value_template = value_template self._value_template = value_template
self._attr_unique_id = unique_id self._attr_unique_id = unique_id
@property def update(self) -> None:
def name(self):
"""Return the name of the sensor."""
return self._name
@property
def native_unit_of_measurement(self):
"""Return the unit the value is expressed in."""
return self._unit_of_measurement
@property
def native_value(self):
"""Return the state of the device."""
return self._state
@property
def extra_state_attributes(self):
"""Return the state attributes."""
return self._attributes
def update(self):
"""Get the latest data and updates the state.""" """Get the latest data and updates the state."""
self.data.update() self.data.update()
value = self.data.value value = self.data.value
if self._json_attributes: if self._json_attributes:
self._attributes = {} self._attr_extra_state_attributes = {}
if value: if value:
try: try:
json_dict = json.loads(value) json_dict = json.loads(value)
if isinstance(json_dict, Mapping): if isinstance(json_dict, Mapping):
self._attributes = { self._attr_extra_state_attributes = {
k: json_dict[k] k: json_dict[k]
for k in self._json_attributes for k in self._json_attributes
if k in json_dict if k in json_dict
@ -150,24 +124,26 @@ class CommandSensor(SensorEntity):
if value is None: if value is None:
value = STATE_UNKNOWN value = STATE_UNKNOWN
elif self._value_template is not None: elif self._value_template is not None:
self._state = self._value_template.render_with_possible_json_value( self._attr_native_value = (
value, STATE_UNKNOWN self._value_template.render_with_possible_json_value(
value, STATE_UNKNOWN
)
) )
else: else:
self._state = value self._attr_native_value = value
class CommandSensorData: class CommandSensorData:
"""The class for handling the data retrieval.""" """The class for handling the data retrieval."""
def __init__(self, hass, command, command_timeout): def __init__(self, hass: HomeAssistant, command: str, command_timeout: int) -> None:
"""Initialize the data object.""" """Initialize the data object."""
self.value = None self.value: str | None = None
self.hass = hass self.hass = hass
self.command = command self.command = command
self.timeout = command_timeout self.timeout = command_timeout
def update(self): def update(self) -> None:
"""Get the latest data with a shell command.""" """Get the latest data with a shell command."""
command = self.command command = self.command
@ -177,7 +153,7 @@ class CommandSensorData:
args_compiled = None args_compiled = None
else: else:
prog, args = command.split(" ", 1) prog, args = command.split(" ", 1)
args_compiled = template.Template(args, self.hass) args_compiled = Template(args, self.hass)
if args_compiled: if args_compiled:
try: try:

View File

@ -2,6 +2,7 @@
from __future__ import annotations from __future__ import annotations
import logging import logging
from typing import TYPE_CHECKING, Any
import voluptuous as vol import voluptuous as vol
@ -24,6 +25,7 @@ from homeassistant.core import HomeAssistant
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.reload import setup_reload_service from homeassistant.helpers.reload import setup_reload_service
from homeassistant.helpers.template import Template
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
from . import call_shell_with_timeout, check_output_or_log from . import call_shell_with_timeout, check_output_or_log
@ -59,22 +61,21 @@ def setup_platform(
setup_reload_service(hass, DOMAIN, PLATFORMS) setup_reload_service(hass, DOMAIN, PLATFORMS)
devices = config.get(CONF_SWITCHES, {}) devices: dict[str, Any] = config.get(CONF_SWITCHES, {})
switches = [] switches = []
for object_id, device_config in devices.items(): for object_id, device_config in devices.items():
value_template = device_config.get(CONF_VALUE_TEMPLATE) value_template: Template | None = device_config.get(CONF_VALUE_TEMPLATE)
if value_template is not None: if value_template is not None:
value_template.hass = hass value_template.hass = hass
icon_template = device_config.get(CONF_ICON_TEMPLATE) icon_template: Template | None = device_config.get(CONF_ICON_TEMPLATE)
if icon_template is not None: if icon_template is not None:
icon_template.hass = hass icon_template.hass = hass
switches.append( switches.append(
CommandSwitch( CommandSwitch(
hass,
object_id, object_id,
device_config.get(CONF_FRIENDLY_NAME, object_id), device_config.get(CONF_FRIENDLY_NAME, object_id),
device_config[CONF_COMMAND_ON], device_config[CONF_COMMAND_ON],
@ -99,22 +100,20 @@ class CommandSwitch(SwitchEntity):
def __init__( def __init__(
self, self,
hass, object_id: str,
object_id, friendly_name: str,
friendly_name, command_on: str,
command_on, command_off: str,
command_off, command_state: str | None,
command_state, icon_template: Template | None,
icon_template, value_template: Template | None,
value_template, timeout: int,
timeout, unique_id: str | None,
unique_id, ) -> None:
):
"""Initialize the switch.""" """Initialize the switch."""
self._hass = hass
self.entity_id = ENTITY_ID_FORMAT.format(object_id) self.entity_id = ENTITY_ID_FORMAT.format(object_id)
self._name = friendly_name self._attr_name = friendly_name
self._state = False self._attr_is_on = False
self._command_on = command_on self._command_on = command_on
self._command_off = command_off self._command_off = command_off
self._command_state = command_state self._command_state = command_state
@ -122,8 +121,9 @@ class CommandSwitch(SwitchEntity):
self._value_template = value_template self._value_template = value_template
self._timeout = timeout self._timeout = timeout
self._attr_unique_id = unique_id self._attr_unique_id = unique_id
self._attr_should_poll = bool(command_state)
def _switch(self, command): def _switch(self, command: str) -> bool:
"""Execute the actual commands.""" """Execute the actual commands."""
_LOGGER.info("Running command: %s", command) _LOGGER.info("Running command: %s", command)
@ -134,12 +134,12 @@ class CommandSwitch(SwitchEntity):
return success return success
def _query_state_value(self, command): def _query_state_value(self, command: str) -> str | None:
"""Execute state command for return value.""" """Execute state command for return value."""
_LOGGER.info("Running state value command: %s", command) _LOGGER.info("Running state value command: %s", command)
return check_output_or_log(command, self._timeout) return check_output_or_log(command, self._timeout)
def _query_state_code(self, command): def _query_state_code(self, command: str) -> bool:
"""Execute state command for return code.""" """Execute state command for return code."""
_LOGGER.info("Running state code command: %s", command) _LOGGER.info("Running state code command: %s", command)
return ( return (
@ -147,32 +147,20 @@ class CommandSwitch(SwitchEntity):
) )
@property @property
def should_poll(self): def assumed_state(self) -> bool:
"""Only poll if we have state command."""
return self._command_state is not None
@property
def name(self):
"""Return the name of the switch."""
return self._name
@property
def is_on(self):
"""Return true if device is on."""
return self._state
@property
def assumed_state(self):
"""Return true if we do optimistic updates.""" """Return true if we do optimistic updates."""
return self._command_state is None return self._command_state is None
def _query_state(self): def _query_state(self) -> str | int | None:
"""Query for state.""" """Query for state."""
if self._value_template: if self._command_state:
return self._query_state_value(self._command_state) if self._value_template:
return self._query_state_code(self._command_state) return self._query_state_value(self._command_state)
return self._query_state_code(self._command_state)
if TYPE_CHECKING:
return None
def update(self): def update(self) -> None:
"""Update device state.""" """Update device state."""
if self._command_state: if self._command_state:
payload = str(self._query_state()) payload = str(self._query_state())
@ -182,16 +170,16 @@ class CommandSwitch(SwitchEntity):
) )
if self._value_template: if self._value_template:
payload = self._value_template.render_with_possible_json_value(payload) payload = self._value_template.render_with_possible_json_value(payload)
self._state = payload.lower() == "true" self._attr_is_on = payload.lower() == "true"
def turn_on(self, **kwargs): def turn_on(self, **kwargs) -> None:
"""Turn the device on.""" """Turn the device on."""
if self._switch(self._command_on) and not self._command_state: if self._switch(self._command_on) and not self._command_state:
self._state = True self._attr_is_on = True
self.schedule_update_ha_state() self.schedule_update_ha_state()
def turn_off(self, **kwargs): def turn_off(self, **kwargs) -> None:
"""Turn the device off.""" """Turn the device off."""
if self._switch(self._command_off) and not self._command_state: if self._switch(self._command_off) and not self._command_state:
self._state = False self._attr_is_on = False
self.schedule_update_ha_state() self.schedule_update_ha_state()

View File

@ -51,6 +51,7 @@ async def test_template(hass: HomeAssistant) -> None:
) )
entity_state = hass.states.get("binary_sensor.test") entity_state = hass.states.get("binary_sensor.test")
assert entity_state
assert entity_state.state == STATE_ON assert entity_state.state == STATE_ON
@ -65,10 +66,11 @@ async def test_sensor_off(hass: HomeAssistant) -> None:
}, },
) )
entity_state = hass.states.get("binary_sensor.test") entity_state = hass.states.get("binary_sensor.test")
assert entity_state
assert entity_state.state == STATE_OFF assert entity_state.state == STATE_OFF
async def test_unique_id(hass): async def test_unique_id(hass: HomeAssistant) -> None:
"""Test unique_id option and if it only creates one binary sensor per id.""" """Test unique_id option and if it only creates one binary sensor per id."""
assert await setup.async_setup_component( assert await setup.async_setup_component(
hass, hass,

View File

@ -6,6 +6,8 @@ import tempfile
from typing import Any from typing import Any
from unittest.mock import patch from unittest.mock import patch
from pytest import LogCaptureFixture
from homeassistant import config as hass_config, setup from homeassistant import config as hass_config, setup
from homeassistant.components.cover import DOMAIN, SCAN_INTERVAL from homeassistant.components.cover import DOMAIN, SCAN_INTERVAL
from homeassistant.const import ( from homeassistant.const import (
@ -36,7 +38,7 @@ async def setup_test_entity(hass: HomeAssistant, config_dict: dict[str, Any]) ->
await hass.async_block_till_done() await hass.async_block_till_done()
async def test_no_covers(caplog: Any, hass: HomeAssistant) -> None: async def test_no_covers(caplog: LogCaptureFixture, hass: HomeAssistant) -> None:
"""Test that the cover does not polls when there's no state command.""" """Test that the cover does not polls when there's no state command."""
with patch( with patch(
@ -150,7 +152,9 @@ async def test_reload(hass: HomeAssistant) -> None:
assert hass.states.get("cover.from_yaml") assert hass.states.get("cover.from_yaml")
async def test_move_cover_failure(caplog: Any, hass: HomeAssistant) -> None: async def test_move_cover_failure(
caplog: LogCaptureFixture, hass: HomeAssistant
) -> None:
"""Test with state value.""" """Test with state value."""
await setup_test_entity( await setup_test_entity(
@ -163,7 +167,7 @@ async def test_move_cover_failure(caplog: Any, hass: HomeAssistant) -> None:
assert "Command failed" in caplog.text assert "Command failed" in caplog.text
async def test_unique_id(hass): async def test_unique_id(hass: HomeAssistant) -> None:
"""Test unique_id option and if it only creates one cover per id.""" """Test unique_id option and if it only creates one cover per id."""
await setup_test_entity( await setup_test_entity(
hass, hass,

View File

@ -7,6 +7,8 @@ import tempfile
from typing import Any from typing import Any
from unittest.mock import patch from unittest.mock import patch
from pytest import LogCaptureFixture
from homeassistant import setup from homeassistant import setup
from homeassistant.components.notify import DOMAIN from homeassistant.components.notify import DOMAIN
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
@ -60,7 +62,9 @@ async def test_command_line_output(hass: HomeAssistant) -> None:
assert message == handle.read() assert message == handle.read()
async def test_error_for_none_zero_exit_code(caplog: Any, hass: HomeAssistant) -> None: async def test_error_for_none_zero_exit_code(
caplog: LogCaptureFixture, hass: HomeAssistant
) -> None:
"""Test if an error is logged for non zero exit codes.""" """Test if an error is logged for non zero exit codes."""
await setup_test_service( await setup_test_service(
hass, hass,
@ -75,7 +79,7 @@ async def test_error_for_none_zero_exit_code(caplog: Any, hass: HomeAssistant) -
assert "Command failed" in caplog.text assert "Command failed" in caplog.text
async def test_timeout(caplog: Any, hass: HomeAssistant) -> None: async def test_timeout(caplog: LogCaptureFixture, hass: HomeAssistant) -> None:
"""Test blocking is not forever.""" """Test blocking is not forever."""
await setup_test_service( await setup_test_service(
hass, hass,
@ -90,7 +94,9 @@ async def test_timeout(caplog: Any, hass: HomeAssistant) -> None:
assert "Timeout" in caplog.text assert "Timeout" in caplog.text
async def test_subprocess_exceptions(caplog: Any, hass: HomeAssistant) -> None: async def test_subprocess_exceptions(
caplog: LogCaptureFixture, hass: HomeAssistant
) -> None:
"""Test that notify subprocess exceptions are handled correctly.""" """Test that notify subprocess exceptions are handled correctly."""
with patch( with patch(

View File

@ -4,6 +4,8 @@ from __future__ import annotations
from typing import Any from typing import Any
from unittest.mock import patch from unittest.mock import patch
from pytest import LogCaptureFixture
from homeassistant import setup from homeassistant import setup
from homeassistant.components.sensor import DOMAIN from homeassistant.components.sensor import DOMAIN
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
@ -98,7 +100,9 @@ async def test_template_render_with_quote(hass: HomeAssistant) -> None:
) )
async def test_bad_template_render(caplog: Any, hass: HomeAssistant) -> None: async def test_bad_template_render(
caplog: LogCaptureFixture, hass: HomeAssistant
) -> None:
"""Test rendering a broken template.""" """Test rendering a broken template."""
await setup_test_entities( await setup_test_entities(
@ -141,7 +145,9 @@ async def test_update_with_json_attrs(hass: HomeAssistant) -> None:
assert entity_state.attributes["key_three"] == "value_three" assert entity_state.attributes["key_three"] == "value_three"
async def test_update_with_json_attrs_no_data(caplog, hass: HomeAssistant) -> None: # type: ignore[no-untyped-def] async def test_update_with_json_attrs_no_data(
caplog: LogCaptureFixture, hass: HomeAssistant
) -> None:
"""Test attributes when no JSON result fetched.""" """Test attributes when no JSON result fetched."""
await setup_test_entities( await setup_test_entities(
@ -157,7 +163,9 @@ async def test_update_with_json_attrs_no_data(caplog, hass: HomeAssistant) -> No
assert "Empty reply found when expecting JSON data" in caplog.text assert "Empty reply found when expecting JSON data" in caplog.text
async def test_update_with_json_attrs_not_dict(caplog, hass: HomeAssistant) -> None: # type: ignore[no-untyped-def] async def test_update_with_json_attrs_not_dict(
caplog: LogCaptureFixture, hass: HomeAssistant
) -> None:
"""Test attributes when the return value not a dict.""" """Test attributes when the return value not a dict."""
await setup_test_entities( await setup_test_entities(
@ -173,7 +181,9 @@ async def test_update_with_json_attrs_not_dict(caplog, hass: HomeAssistant) -> N
assert "JSON result was not a dictionary" in caplog.text assert "JSON result was not a dictionary" in caplog.text
async def test_update_with_json_attrs_bad_json(caplog, hass: HomeAssistant) -> None: # type: ignore[no-untyped-def] async def test_update_with_json_attrs_bad_json(
caplog: LogCaptureFixture, hass: HomeAssistant
) -> None:
"""Test attributes when the return value is invalid JSON.""" """Test attributes when the return value is invalid JSON."""
await setup_test_entities( await setup_test_entities(
@ -189,7 +199,9 @@ async def test_update_with_json_attrs_bad_json(caplog, hass: HomeAssistant) -> N
assert "Unable to parse output as JSON" in caplog.text assert "Unable to parse output as JSON" in caplog.text
async def test_update_with_missing_json_attrs(caplog, hass: HomeAssistant) -> None: # type: ignore[no-untyped-def] async def test_update_with_missing_json_attrs(
caplog: LogCaptureFixture, hass: HomeAssistant
) -> None:
"""Test attributes when an expected key is missing.""" """Test attributes when an expected key is missing."""
await setup_test_entities( await setup_test_entities(
@ -208,7 +220,9 @@ async def test_update_with_missing_json_attrs(caplog, hass: HomeAssistant) -> No
assert "missing_key" not in entity_state.attributes assert "missing_key" not in entity_state.attributes
async def test_update_with_unnecessary_json_attrs(caplog, hass: HomeAssistant) -> None: # type: ignore[no-untyped-def] async def test_update_with_unnecessary_json_attrs(
caplog: LogCaptureFixture, hass: HomeAssistant
) -> None:
"""Test attributes when an expected key is missing.""" """Test attributes when an expected key is missing."""
await setup_test_entities( await setup_test_entities(
@ -226,7 +240,7 @@ async def test_update_with_unnecessary_json_attrs(caplog, hass: HomeAssistant) -
assert "key_three" not in entity_state.attributes assert "key_three" not in entity_state.attributes
async def test_unique_id(hass): async def test_unique_id(hass: HomeAssistant) -> None:
"""Test unique_id option and if it only creates one sensor per id.""" """Test unique_id option and if it only creates one sensor per id."""
assert await setup.async_setup_component( assert await setup.async_setup_component(
hass, hass,

View File

@ -8,6 +8,8 @@ import tempfile
from typing import Any from typing import Any
from unittest.mock import patch from unittest.mock import patch
from pytest import LogCaptureFixture
from homeassistant import setup from homeassistant import setup
from homeassistant.components.switch import DOMAIN, SCAN_INTERVAL from homeassistant.components.switch import DOMAIN, SCAN_INTERVAL
from homeassistant.const import ( from homeassistant.const import (
@ -269,10 +271,13 @@ async def test_name_is_set_correctly(hass: HomeAssistant) -> None:
) )
entity_state = hass.states.get("switch.test") entity_state = hass.states.get("switch.test")
assert entity_state
assert entity_state.name == "Test friendly name!" assert entity_state.name == "Test friendly name!"
async def test_switch_command_state_fail(caplog: Any, hass: HomeAssistant) -> None: async def test_switch_command_state_fail(
caplog: LogCaptureFixture, hass: HomeAssistant
) -> None:
"""Test that switch failures are handled correctly.""" """Test that switch failures are handled correctly."""
await setup_test_entity( await setup_test_entity(
hass, hass,
@ -289,6 +294,7 @@ async def test_switch_command_state_fail(caplog: Any, hass: HomeAssistant) -> No
await hass.async_block_till_done() await hass.async_block_till_done()
entity_state = hass.states.get("switch.test") entity_state = hass.states.get("switch.test")
assert entity_state
assert entity_state.state == "on" assert entity_state.state == "on"
await hass.services.async_call( await hass.services.async_call(
@ -300,13 +306,14 @@ async def test_switch_command_state_fail(caplog: Any, hass: HomeAssistant) -> No
await hass.async_block_till_done() await hass.async_block_till_done()
entity_state = hass.states.get("switch.test") entity_state = hass.states.get("switch.test")
assert entity_state
assert entity_state.state == "on" assert entity_state.state == "on"
assert "Command failed" in caplog.text assert "Command failed" in caplog.text
async def test_switch_command_state_code_exceptions( async def test_switch_command_state_code_exceptions(
caplog: Any, hass: HomeAssistant caplog: LogCaptureFixture, hass: HomeAssistant
) -> None: ) -> None:
"""Test that switch state code exceptions are handled correctly.""" """Test that switch state code exceptions are handled correctly."""
@ -339,7 +346,7 @@ async def test_switch_command_state_code_exceptions(
async def test_switch_command_state_value_exceptions( async def test_switch_command_state_value_exceptions(
caplog: Any, hass: HomeAssistant caplog: LogCaptureFixture, hass: HomeAssistant
) -> None: ) -> None:
"""Test that switch state value exceptions are handled correctly.""" """Test that switch state value exceptions are handled correctly."""
@ -372,14 +379,14 @@ async def test_switch_command_state_value_exceptions(
assert "Error trying to exec command" in caplog.text assert "Error trying to exec command" in caplog.text
async def test_no_switches(caplog: Any, hass: HomeAssistant) -> None: async def test_no_switches(caplog: LogCaptureFixture, hass: HomeAssistant) -> None:
"""Test with no switches.""" """Test with no switches."""
await setup_test_entity(hass, {}) await setup_test_entity(hass, {})
assert "No switches" in caplog.text assert "No switches" in caplog.text
async def test_unique_id(hass): async def test_unique_id(hass: HomeAssistant) -> None:
"""Test unique_id option and if it only creates one switch per id.""" """Test unique_id option and if it only creates one switch per id."""
await setup_test_entity( await setup_test_entity(
hass, hass,