Mark base components' state_attribute @final, rename others to extra_state_attributes (#48161)

* Mark base state_attributes @final, rename others to extra_state_attributes

* Fix calendar, update tests
This commit is contained in:
Erik Montnemery 2021-03-21 10:38:24 +01:00 committed by GitHub
parent 668d018e9c
commit 346a724ac3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
52 changed files with 106 additions and 71 deletions

View file

@ -132,7 +132,7 @@ class AcerSwitch(SwitchEntity):
return self._state return self._state
@property @property
def state_attributes(self): def extra_state_attributes(self):
"""Return state attributes.""" """Return state attributes."""
return self._attributes return self._attributes

View file

@ -1,6 +1,7 @@
"""Component for handling Air Quality data for your location.""" """Component for handling Air Quality data for your location."""
from datetime import timedelta from datetime import timedelta
import logging import logging
from typing import final
from homeassistant.const import ( from homeassistant.const import (
ATTR_ATTRIBUTION, ATTR_ATTRIBUTION,
@ -131,6 +132,7 @@ class AirQualityEntity(Entity):
"""Return the NO2 (nitrogen dioxide) level.""" """Return the NO2 (nitrogen dioxide) level."""
return None return None
@final
@property @property
def state_attributes(self): def state_attributes(self):
"""Return the state attributes.""" """Return the state attributes."""

View file

@ -2,6 +2,7 @@
from abc import abstractmethod from abc import abstractmethod
from datetime import timedelta from datetime import timedelta
import logging import logging
from typing import final
import voluptuous as vol import voluptuous as vol
@ -172,6 +173,7 @@ class AlarmControlPanelEntity(Entity):
def supported_features(self) -> int: def supported_features(self) -> int:
"""Return the list of supported features.""" """Return the list of supported features."""
@final
@property @property
def state_attributes(self): def state_attributes(self):
"""Return the state attributes.""" """Return the state attributes."""

View file

@ -154,7 +154,7 @@ class ArwnSensor(Entity):
return self._uid return self._uid
@property @property
def state_attributes(self): def extra_state_attributes(self):
"""Return all the state attributes.""" """Return all the state attributes."""
return self.event return self.event

View file

@ -274,7 +274,7 @@ class AutomationEntity(ToggleEntity, RestoreEntity):
return False return False
@property @property
def state_attributes(self): def extra_state_attributes(self):
"""Return the entity state attributes.""" """Return the entity state attributes."""
attrs = { attrs = {
ATTR_LAST_TRIGGERED: self.action_script.last_triggered, ATTR_LAST_TRIGGERED: self.action_script.last_triggered,

View file

@ -4,7 +4,7 @@ from __future__ import annotations
from datetime import timedelta from datetime import timedelta
import logging import logging
import re import re
from typing import cast from typing import cast, final
from aiohttp import web from aiohttp import web
@ -129,13 +129,14 @@ def is_offset_reached(event):
class CalendarEventDevice(Entity): class CalendarEventDevice(Entity):
"""A calendar event device.""" """Base class for calendar event entities."""
@property @property
def event(self): def event(self):
"""Return the next upcoming event.""" """Return the next upcoming event."""
raise NotImplementedError() raise NotImplementedError()
@final
@property @property
def state_attributes(self): def state_attributes(self):
"""Return the entity state attributes.""" """Return the entity state attributes."""

View file

@ -8,6 +8,7 @@ import hashlib
import logging import logging
import os import os
from random import SystemRandom from random import SystemRandom
from typing import final
from aiohttp import web from aiohttp import web
import async_timeout import async_timeout
@ -441,6 +442,7 @@ class Camera(Entity):
"""Call the job and disable motion detection.""" """Call the job and disable motion detection."""
await self.hass.async_add_executor_job(self.disable_motion_detection) await self.hass.async_add_executor_job(self.disable_motion_detection)
@final
@property @property
def state_attributes(self): def state_attributes(self):
"""Return the camera state attributes.""" """Return the camera state attributes."""

View file

@ -5,7 +5,7 @@ from abc import abstractmethod
from datetime import timedelta from datetime import timedelta
import functools as ft import functools as ft
import logging import logging
from typing import Any from typing import Any, final
import voluptuous as vol import voluptuous as vol
@ -167,7 +167,7 @@ async def async_unload_entry(hass: HomeAssistantType, entry):
class ClimateEntity(Entity): class ClimateEntity(Entity):
"""Representation of a climate entity.""" """Base class for climate entities."""
@property @property
def state(self) -> str: def state(self) -> str:
@ -213,6 +213,7 @@ class ClimateEntity(Entity):
return data return data
@final
@property @property
def state_attributes(self) -> dict[str, Any]: def state_attributes(self) -> dict[str, Any]:
"""Return the optional state attributes.""" """Return the optional state attributes."""

View file

@ -208,7 +208,7 @@ class Counter(RestoreEntity):
return self._state return self._state
@property @property
def state_attributes(self) -> dict: def extra_state_attributes(self) -> dict:
"""Return the state attributes.""" """Return the state attributes."""
ret = { ret = {
ATTR_EDITABLE: self.editable, ATTR_EDITABLE: self.editable,

View file

@ -2,7 +2,7 @@
from datetime import timedelta from datetime import timedelta
import functools as ft import functools as ft
import logging import logging
from typing import Any from typing import Any, final
import voluptuous as vol import voluptuous as vol
@ -165,7 +165,7 @@ async def async_unload_entry(hass, entry):
class CoverEntity(Entity): class CoverEntity(Entity):
"""Representation of a cover.""" """Base class for cover entities."""
@property @property
def current_cover_position(self): def current_cover_position(self):
@ -196,6 +196,7 @@ class CoverEntity(Entity):
return STATE_CLOSED if closed else STATE_OPEN return STATE_CLOSED if closed else STATE_OPEN
@final
@property @property
def state_attributes(self): def state_attributes(self):
"""Return the state attributes.""" """Return the state attributes."""

View file

@ -1,6 +1,8 @@
"""Code to set up a device tracker platform using a config entry.""" """Code to set up a device tracker platform using a config entry."""
from __future__ import annotations from __future__ import annotations
from typing import final
from homeassistant.components import zone from homeassistant.components import zone
from homeassistant.const import ( from homeassistant.const import (
ATTR_BATTERY_LEVEL, ATTR_BATTERY_LEVEL,
@ -59,7 +61,7 @@ class BaseTrackerEntity(Entity):
class TrackerEntity(BaseTrackerEntity): class TrackerEntity(BaseTrackerEntity):
"""Represent a tracked device.""" """Base class for a tracked device."""
@property @property
def should_poll(self): def should_poll(self):
@ -114,6 +116,7 @@ class TrackerEntity(BaseTrackerEntity):
return None return None
@final
@property @property
def state_attributes(self): def state_attributes(self):
"""Return the device state attributes.""" """Return the device state attributes."""
@ -128,7 +131,7 @@ class TrackerEntity(BaseTrackerEntity):
class ScannerEntity(BaseTrackerEntity): class ScannerEntity(BaseTrackerEntity):
"""Represent a tracked device that is on a scanned network.""" """Base class for a tracked device that is on a scanned network."""
@property @property
def ip_address(self) -> str: def ip_address(self) -> str:
@ -157,6 +160,7 @@ class ScannerEntity(BaseTrackerEntity):
"""Return true if the device is connected to the network.""" """Return true if the device is connected to the network."""
raise NotImplementedError raise NotImplementedError
@final
@property @property
def state_attributes(self): def state_attributes(self):
"""Return the device state attributes.""" """Return the device state attributes."""

View file

@ -5,7 +5,7 @@ import asyncio
from datetime import timedelta from datetime import timedelta
import hashlib import hashlib
from types import ModuleType from types import ModuleType
from typing import Any, Callable, Sequence from typing import Any, Callable, Sequence, final
import attr import attr
import voluptuous as vol import voluptuous as vol
@ -588,7 +588,7 @@ class DeviceTracker:
class Device(RestoreEntity): class Device(RestoreEntity):
"""Represent a tracked device.""" """Base class for a tracked device."""
host_name: str = None host_name: str = None
location_name: str = None location_name: str = None
@ -661,6 +661,7 @@ class Device(RestoreEntity):
"""Return the picture of the device.""" """Return the picture of the device."""
return self.config_picture return self.config_picture
@final
@property @property
def state_attributes(self): def state_attributes(self):
"""Return the device state attributes.""" """Return the device state attributes."""

View file

@ -66,7 +66,7 @@ class BanSensor(Entity):
return self._name return self._name
@property @property
def state_attributes(self): def extra_state_attributes(self):
"""Return the state attributes of the fail2ban sensor.""" """Return the state attributes of the fail2ban sensor."""
return self.ban_dict return self.ban_dict

View file

@ -5,6 +5,7 @@ from datetime import timedelta
import functools as ft import functools as ft
import logging import logging
import math import math
from typing import final
import voluptuous as vol import voluptuous as vol
@ -220,7 +221,7 @@ def _fan_native(method):
class FanEntity(ToggleEntity): class FanEntity(ToggleEntity):
"""Representation of a fan.""" """Base class for fan entities."""
@_fan_native @_fan_native
def set_speed(self, speed: str) -> None: def set_speed(self, speed: str) -> None:
@ -586,6 +587,7 @@ class FanEntity(ToggleEntity):
f"The speed_list {speed_list} does not contain any valid speeds." f"The speed_list {speed_list} does not contain any valid speeds."
) from ex ) from ex
@final
@property @property
def state_attributes(self) -> dict: def state_attributes(self) -> dict:
"""Return optional state attributes.""" """Return optional state attributes."""

View file

@ -93,7 +93,7 @@ class FritzboxMonitorSensor(Entity):
return self._state return self._state
@property @property
def state_attributes(self): def extra_state_attributes(self):
"""Return the device state attributes.""" """Return the device state attributes."""
# Don't return attributes if FritzBox is unreachable # Don't return attributes if FritzBox is unreachable
if self._state == STATE_UNAVAILABLE: if self._state == STATE_UNAVAILABLE:

View file

@ -3,6 +3,7 @@ from __future__ import annotations
from datetime import timedelta from datetime import timedelta
import logging import logging
from typing import final
from homeassistant.const import ATTR_LATITUDE, ATTR_LONGITUDE from homeassistant.const import ATTR_LATITUDE, ATTR_LONGITUDE
from homeassistant.helpers.config_validation import ( # noqa: F401 from homeassistant.helpers.config_validation import ( # noqa: F401
@ -46,7 +47,7 @@ async def async_unload_entry(hass, entry):
class GeolocationEvent(Entity): class GeolocationEvent(Entity):
"""This represents an external event with an associated geolocation.""" """Base class for an external event with an associated geolocation."""
@property @property
def state(self): def state(self):
@ -75,6 +76,7 @@ class GeolocationEvent(Entity):
"""Return longitude value of this external event.""" """Return longitude value of this external event."""
return None return None
@final
@property @property
def state_attributes(self): def state_attributes(self):
"""Return the state attributes of this external event.""" """Return the state attributes of this external event."""

View file

@ -547,7 +547,7 @@ class Group(Entity):
self._icon = value self._icon = value
@property @property
def state_attributes(self): def extra_state_attributes(self):
"""Return the state attributes for the group.""" """Return the state attributes for the group."""
data = {ATTR_ENTITY_ID: self.tracking, ATTR_ORDER: self._order} data = {ATTR_ENTITY_ID: self.tracking, ATTR_ORDER: self._order}
if not self.user_defined: if not self.user_defined:

View file

@ -231,7 +231,7 @@ class HMHub(Entity):
return self._state return self._state
@property @property
def state_attributes(self): def extra_state_attributes(self):
"""Return the state attributes.""" """Return the state attributes."""
return self._variables.copy() return self._variables.copy()

View file

@ -3,7 +3,7 @@ from __future__ import annotations
from datetime import timedelta from datetime import timedelta
import logging import logging
from typing import Any from typing import Any, final
import voluptuous as vol import voluptuous as vol
@ -99,7 +99,7 @@ async def async_unload_entry(hass: HomeAssistantType, entry: ConfigEntry) -> boo
class HumidifierEntity(ToggleEntity): class HumidifierEntity(ToggleEntity):
"""Representation of a humidifier device.""" """Base class for humidifier entities."""
@property @property
def capability_attributes(self) -> dict[str, Any]: def capability_attributes(self) -> dict[str, Any]:
@ -115,6 +115,7 @@ class HumidifierEntity(ToggleEntity):
return data return data
@final
@property @property
def state_attributes(self) -> dict[str, Any]: def state_attributes(self) -> dict[str, Any]:
"""Return the optional state attributes.""" """Return the optional state attributes."""

View file

@ -502,6 +502,6 @@ class IcloudDevice:
return self._location return self._location
@property @property
def state_attributes(self) -> dict[str, any]: def exta_state_attributes(self) -> dict[str, any]:
"""Return the attributes.""" """Return the attributes."""
return self._attrs return self._attrs

View file

@ -2,6 +2,7 @@
import asyncio import asyncio
from datetime import timedelta from datetime import timedelta
import logging import logging
from typing import final
import voluptuous as vol import voluptuous as vol
@ -175,6 +176,7 @@ class ImageProcessingFaceEntity(ImageProcessingEntity):
"""Return the class of this device, from component DEVICE_CLASSES.""" """Return the class of this device, from component DEVICE_CLASSES."""
return "face" return "face"
@final
@property @property
def state_attributes(self): def state_attributes(self):
"""Return device specific state attributes.""" """Return device specific state attributes."""

View file

@ -169,7 +169,7 @@ class InputBoolean(ToggleEntity, RestoreEntity):
return self._config.get(CONF_NAME) return self._config.get(CONF_NAME)
@property @property
def state_attributes(self): def extra_state_attributes(self):
"""Return the state attributes of the entity.""" """Return the state attributes of the entity."""
return {ATTR_EDITABLE: self.editable} return {ATTR_EDITABLE: self.editable}

View file

@ -319,7 +319,7 @@ class InputDatetime(RestoreEntity):
return self._current_datetime.strftime(FMT_TIME) return self._current_datetime.strftime(FMT_TIME)
@property @property
def state_attributes(self): def extra_state_attributes(self):
"""Return the state attributes.""" """Return the state attributes."""
attrs = { attrs = {
ATTR_EDITABLE: self.editable, ATTR_EDITABLE: self.editable,

View file

@ -256,7 +256,7 @@ class InputNumber(RestoreEntity):
return self._config[CONF_ID] return self._config[CONF_ID]
@property @property
def state_attributes(self): def extra_state_attributes(self):
"""Return the state attributes.""" """Return the state attributes."""
return { return {
ATTR_INITIAL: self._config.get(CONF_INITIAL), ATTR_INITIAL: self._config.get(CONF_INITIAL),

View file

@ -253,7 +253,7 @@ class InputSelect(RestoreEntity):
return self._current_option return self._current_option
@property @property
def state_attributes(self): def extra_state_attributes(self):
"""Return the state attributes.""" """Return the state attributes."""
return {ATTR_OPTIONS: self._config[ATTR_OPTIONS], ATTR_EDITABLE: self.editable} return {ATTR_OPTIONS: self._config[ATTR_OPTIONS], ATTR_EDITABLE: self.editable}

View file

@ -245,7 +245,7 @@ class InputText(RestoreEntity):
return self._config[CONF_ID] return self._config[CONF_ID]
@property @property
def state_attributes(self): def extra_state_attributes(self):
"""Return the state attributes.""" """Return the state attributes."""
return { return {
ATTR_EDITABLE: self.editable, ATTR_EDITABLE: self.editable,

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 cast from typing import cast, final
import voluptuous as vol import voluptuous as vol
@ -478,7 +478,7 @@ class Profiles:
class LightEntity(ToggleEntity): class LightEntity(ToggleEntity):
"""Representation of a light.""" """Base class for light entities."""
@property @property
def brightness(self) -> int | None: def brightness(self) -> int | None:
@ -634,6 +634,7 @@ class LightEntity(ToggleEntity):
data[ATTR_XY_COLOR] = color_util.color_RGB_to_xy(*rgb_color) data[ATTR_XY_COLOR] = color_util.color_RGB_to_xy(*rgb_color)
return data return data
@final
@property @property
def state_attributes(self): def state_attributes(self):
"""Return state attributes.""" """Return state attributes."""

View file

@ -2,6 +2,7 @@
from datetime import timedelta from datetime import timedelta
import functools as ft import functools as ft
import logging import logging
from typing import final
import voluptuous as vol import voluptuous as vol
@ -76,7 +77,7 @@ async def async_unload_entry(hass, entry):
class LockEntity(Entity): class LockEntity(Entity):
"""Representation of a lock.""" """Base class for lock entities."""
@property @property
def changed_by(self): def changed_by(self):
@ -117,6 +118,7 @@ class LockEntity(Entity):
"""Open the door latch.""" """Open the door latch."""
await self.hass.async_add_executor_job(ft.partial(self.open, **kwargs)) await self.hass.async_add_executor_job(ft.partial(self.open, **kwargs))
@final
@property @property
def state_attributes(self): def state_attributes(self):
"""Return the state attributes.""" """Return the state attributes."""

View file

@ -9,6 +9,7 @@ import functools as ft
import hashlib import hashlib
import logging import logging
import secrets import secrets
from typing import final
from urllib.parse import urlparse from urllib.parse import urlparse
from aiohttp import web from aiohttp import web
@ -853,6 +854,7 @@ class MediaPlayerEntity(Entity):
return data return data
@final
@property @property
def state_attributes(self): def state_attributes(self):
"""Return the state attributes.""" """Return the state attributes."""

View file

@ -169,7 +169,7 @@ class NetioSwitch(SwitchEntity):
self.netio.update() self.netio.update()
@property @property
def state_attributes(self): def extra_state_attributes(self):
"""Return optional state attributes.""" """Return optional state attributes."""
return { return {
ATTR_TOTAL_CONSUMPTION_KWH: self.cumulated_consumption_kwh, ATTR_TOTAL_CONSUMPTION_KWH: self.cumulated_consumption_kwh,

View file

@ -99,7 +99,7 @@ class ImageProcessingAlprEntity(ImageProcessingEntity):
return "alpr" return "alpr"
@property @property
def state_attributes(self): def extra_state_attributes(self):
"""Return device specific state attributes.""" """Return device specific state attributes."""
return {ATTR_PLATES: self.plates, ATTR_VEHICLES: self.vehicles} return {ATTR_PLATES: self.plates, ATTR_VEHICLES: self.vehicles}

View file

@ -152,7 +152,7 @@ class OpenCVImageProcessor(ImageProcessingEntity):
return self._total_matches return self._total_matches
@property @property
def state_attributes(self): def extra_state_attributes(self):
"""Return device specific state attributes.""" """Return device specific state attributes."""
return {ATTR_MATCHES: self._matches, ATTR_TOTAL_MATCHES: self._total_matches} return {ATTR_MATCHES: self._matches, ATTR_TOTAL_MATCHES: self._total_matches}

View file

@ -73,8 +73,8 @@ class OpenHardwareMonitorDevice(Entity):
return self.value return self.value
@property @property
def state_attributes(self): def extra_state_attributes(self):
"""Return the state attributes of the sun.""" """Return the state attributes of the entity."""
return self.attributes return self.attributes
@classmethod @classmethod

View file

@ -400,7 +400,7 @@ class Person(RestoreEntity):
return self._state return self._state
@property @property
def state_attributes(self): def extra_state_attributes(self):
"""Return the state attributes of the person.""" """Return the state attributes of the person."""
data = {ATTR_EDITABLE: self.editable, ATTR_ID: self.unique_id} data = {ATTR_EDITABLE: self.editable, ATTR_ID: self.unique_id}
if self._latitude is not None: if self._latitude is not None:

View file

@ -348,7 +348,7 @@ class Plant(Entity):
return self._state return self._state
@property @property
def state_attributes(self): def extra_state_attributes(self):
"""Return the attributes of the entity. """Return the attributes of the entity.
Provide the individual measurements from the Provide the individual measurements from the

View file

@ -148,7 +148,7 @@ class Proximity(Entity):
return self._unit_of_measurement return self._unit_of_measurement
@property @property
def state_attributes(self): def extra_state_attributes(self):
"""Return the state attributes.""" """Return the state attributes."""
return {ATTR_DIR_OF_TRAVEL: self.dir_of_travel, ATTR_NEAREST: self.nearest} return {ATTR_DIR_OF_TRAVEL: self.dir_of_travel, ATTR_NEAREST: self.nearest}

View file

@ -4,7 +4,7 @@ from __future__ import annotations
from datetime import timedelta from datetime import timedelta
import functools as ft import functools as ft
import logging import logging
from typing import Any, Iterable, cast from typing import Any, Iterable, cast, final
import voluptuous as vol import voluptuous as vol
@ -141,7 +141,7 @@ async def async_unload_entry(hass: HomeAssistantType, entry: ConfigEntry) -> boo
class RemoteEntity(ToggleEntity): class RemoteEntity(ToggleEntity):
"""Representation of a remote.""" """Base class for remote entities."""
@property @property
def supported_features(self) -> int: def supported_features(self) -> int:
@ -158,6 +158,7 @@ class RemoteEntity(ToggleEntity):
"""List of available activities.""" """List of available activities."""
return None return None
@final
@property @property
def state_attributes(self) -> dict[str, Any] | None: def state_attributes(self) -> dict[str, Any] | None:
"""Return optional state attributes.""" """Return optional state attributes."""

View file

@ -151,7 +151,7 @@ class RMVDepartureSensor(Entity):
return self._state return self._state
@property @property
def state_attributes(self): def extra_state_attributes(self):
"""Return the state attributes.""" """Return the state attributes."""
try: try:
return { return {

View file

@ -284,7 +284,7 @@ class ScriptEntity(ToggleEntity):
return self.script.name return self.script.name
@property @property
def state_attributes(self): def extra_state_attributes(self):
"""Return the state attributes.""" """Return the state attributes."""
attrs = { attrs = {
ATTR_LAST_TRIGGERED: self.script.last_triggered, ATTR_LAST_TRIGGERED: self.script.last_triggered,

View file

@ -65,7 +65,7 @@ class SonyProjector(SwitchEntity):
return self._state return self._state
@property @property
def state_attributes(self): def extra_state_attributes(self):
"""Return state attributes.""" """Return state attributes."""
return self._attributes return self._attributes

View file

@ -124,7 +124,7 @@ class Sun(Entity):
return STATE_BELOW_HORIZON return STATE_BELOW_HORIZON
@property @property
def state_attributes(self): def extra_state_attributes(self):
"""Return the state attributes of the sun.""" """Return the state attributes of the sun."""
return { return {
STATE_ATTR_NEXT_DAWN: self.next_dawn.isoformat(), STATE_ATTR_NEXT_DAWN: self.next_dawn.isoformat(),

View file

@ -1,6 +1,7 @@
"""Component to interface with switches that can be controlled remotely.""" """Component to interface with switches that can be controlled remotely."""
from datetime import timedelta from datetime import timedelta
import logging import logging
from typing import final
import voluptuous as vol import voluptuous as vol
@ -79,7 +80,7 @@ async def async_unload_entry(hass, entry):
class SwitchEntity(ToggleEntity): class SwitchEntity(ToggleEntity):
"""Representation of a switch.""" """Base class for switch entities."""
@property @property
def current_power_w(self): def current_power_w(self):
@ -96,6 +97,7 @@ class SwitchEntity(ToggleEntity):
"""Return true if device is in standby.""" """Return true if device is in standby."""
return None return None
@final
@property @property
def state_attributes(self): def state_attributes(self):
"""Return the optional state attributes.""" """Return the optional state attributes."""

View file

@ -232,7 +232,7 @@ class Timer(RestoreEntity):
return self._state return self._state
@property @property
def state_attributes(self): def extra_state_attributes(self):
"""Return the state attributes.""" """Return the state attributes."""
attrs = { attrs = {
ATTR_DURATION: _format_timedelta(self._duration), ATTR_DURATION: _format_timedelta(self._duration),

View file

@ -129,7 +129,7 @@ class TwinklyLight(LightEntity):
return self._brightness return self._brightness
@property @property
def state_attributes(self) -> dict: def extra_state_attributes(self) -> dict:
"""Return device specific state attributes.""" """Return device specific state attributes."""
attributes = self._attributes attributes = self._attributes

View file

@ -165,7 +165,7 @@ class TariffSelect(RestoreEntity):
return self._current_tariff return self._current_tariff
@property @property
def state_attributes(self): def extra_state_attributes(self):
"""Return the state attributes.""" """Return the state attributes."""
return {ATTR_TARIFFS: self._tariffs} return {ATTR_TARIFFS: self._tariffs}

View file

@ -2,6 +2,7 @@
from datetime import timedelta from datetime import timedelta
from functools import partial from functools import partial
import logging import logging
from typing import final
import voluptuous as vol import voluptuous as vol
@ -271,6 +272,7 @@ class VacuumEntity(_BaseVacuum, ToggleEntity):
battery_level=self.battery_level, charging=charging battery_level=self.battery_level, charging=charging
) )
@final
@property @property
def state_attributes(self): def state_attributes(self):
"""Return the state attributes of the vacuum cleaner.""" """Return the state attributes of the vacuum cleaner."""

View file

@ -2,6 +2,7 @@
from datetime import timedelta from datetime import timedelta
import functools as ft import functools as ft
import logging import logging
from typing import final
import voluptuous as vol import voluptuous as vol
@ -129,7 +130,7 @@ async def async_unload_entry(hass, entry):
class WaterHeaterEntity(Entity): class WaterHeaterEntity(Entity):
"""Representation of a water_heater device.""" """Base class for water heater entities."""
@property @property
def state(self): def state(self):
@ -162,6 +163,7 @@ class WaterHeaterEntity(Entity):
return data return data
@final
@property @property
def state_attributes(self): def state_attributes(self):
"""Return the optional state attributes.""" """Return the optional state attributes."""

View file

@ -1,6 +1,7 @@
"""Weather component that handles meteorological data for your location.""" """Weather component that handles meteorological data for your location."""
from datetime import timedelta from datetime import timedelta
import logging import logging
from typing import final
from homeassistant.const import PRECISION_TENTHS, PRECISION_WHOLE, TEMP_CELSIUS from homeassistant.const import PRECISION_TENTHS, PRECISION_WHOLE, TEMP_CELSIUS
from homeassistant.helpers.config_validation import ( # noqa: F401 from homeassistant.helpers.config_validation import ( # noqa: F401
@ -138,6 +139,7 @@ class WeatherEntity(Entity):
else PRECISION_WHOLE else PRECISION_WHOLE
) )
@final
@property @property
def state_attributes(self): def state_attributes(self):
"""Return the state attributes.""" """Return the state attributes."""

View file

@ -171,7 +171,7 @@ class IsWorkdaySensor(BinarySensorEntity):
return False return False
@property @property
def state_attributes(self): def extra_state_attributes(self):
"""Return the attributes of the entity.""" """Return the attributes of the entity."""
# return self._attributes # return self._attributes
return { return {

View file

@ -315,7 +315,7 @@ class Zone(entity.Entity):
return self._config.get(CONF_ICON) return self._config.get(CONF_ICON)
@property @property
def state_attributes(self) -> dict | None: def extra_state_attributes(self) -> dict | None:
"""Return the state attributes of the zone.""" """Return the state attributes of the zone."""
return self._attrs return self._attrs

View file

@ -89,8 +89,8 @@ async def test_single_ban(hass):
sensor.update() sensor.update()
assert sensor.state == "111.111.111.111" assert sensor.state == "111.111.111.111"
assert sensor.state_attributes[STATE_CURRENT_BANS] == ["111.111.111.111"] assert sensor.extra_state_attributes[STATE_CURRENT_BANS] == ["111.111.111.111"]
assert sensor.state_attributes[STATE_ALL_BANS] == ["111.111.111.111"] assert sensor.extra_state_attributes[STATE_ALL_BANS] == ["111.111.111.111"]
async def test_ipv6_ban(hass): async def test_ipv6_ban(hass):
@ -103,8 +103,8 @@ async def test_ipv6_ban(hass):
sensor.update() sensor.update()
assert sensor.state == "2607:f0d0:1002:51::4" assert sensor.state == "2607:f0d0:1002:51::4"
assert sensor.state_attributes[STATE_CURRENT_BANS] == ["2607:f0d0:1002:51::4"] assert sensor.extra_state_attributes[STATE_CURRENT_BANS] == ["2607:f0d0:1002:51::4"]
assert sensor.state_attributes[STATE_ALL_BANS] == ["2607:f0d0:1002:51::4"] assert sensor.extra_state_attributes[STATE_ALL_BANS] == ["2607:f0d0:1002:51::4"]
async def test_multiple_ban(hass): async def test_multiple_ban(hass):
@ -117,11 +117,11 @@ async def test_multiple_ban(hass):
sensor.update() sensor.update()
assert sensor.state == "222.222.222.222" assert sensor.state == "222.222.222.222"
assert sensor.state_attributes[STATE_CURRENT_BANS] == [ assert sensor.extra_state_attributes[STATE_CURRENT_BANS] == [
"111.111.111.111", "111.111.111.111",
"222.222.222.222", "222.222.222.222",
] ]
assert sensor.state_attributes[STATE_ALL_BANS] == [ assert sensor.extra_state_attributes[STATE_ALL_BANS] == [
"111.111.111.111", "111.111.111.111",
"222.222.222.222", "222.222.222.222",
] ]
@ -137,8 +137,8 @@ async def test_unban_all(hass):
sensor.update() sensor.update()
assert sensor.state == "None" assert sensor.state == "None"
assert sensor.state_attributes[STATE_CURRENT_BANS] == [] assert sensor.extra_state_attributes[STATE_CURRENT_BANS] == []
assert sensor.state_attributes[STATE_ALL_BANS] == [ assert sensor.extra_state_attributes[STATE_ALL_BANS] == [
"111.111.111.111", "111.111.111.111",
"222.222.222.222", "222.222.222.222",
] ]
@ -154,8 +154,8 @@ async def test_unban_one(hass):
sensor.update() sensor.update()
assert sensor.state == "222.222.222.222" assert sensor.state == "222.222.222.222"
assert sensor.state_attributes[STATE_CURRENT_BANS] == ["222.222.222.222"] assert sensor.extra_state_attributes[STATE_CURRENT_BANS] == ["222.222.222.222"]
assert sensor.state_attributes[STATE_ALL_BANS] == [ assert sensor.extra_state_attributes[STATE_ALL_BANS] == [
"111.111.111.111", "111.111.111.111",
"222.222.222.222", "222.222.222.222",
] ]
@ -174,11 +174,11 @@ async def test_multi_jail(hass):
sensor2.update() sensor2.update()
assert sensor1.state == "111.111.111.111" assert sensor1.state == "111.111.111.111"
assert sensor1.state_attributes[STATE_CURRENT_BANS] == ["111.111.111.111"] assert sensor1.extra_state_attributes[STATE_CURRENT_BANS] == ["111.111.111.111"]
assert sensor1.state_attributes[STATE_ALL_BANS] == ["111.111.111.111"] assert sensor1.extra_state_attributes[STATE_ALL_BANS] == ["111.111.111.111"]
assert sensor2.state == "222.222.222.222" assert sensor2.state == "222.222.222.222"
assert sensor2.state_attributes[STATE_CURRENT_BANS] == ["222.222.222.222"] assert sensor2.extra_state_attributes[STATE_CURRENT_BANS] == ["222.222.222.222"]
assert sensor2.state_attributes[STATE_ALL_BANS] == ["222.222.222.222"] assert sensor2.extra_state_attributes[STATE_ALL_BANS] == ["222.222.222.222"]
async def test_ban_active_after_update(hass): async def test_ban_active_after_update(hass):
@ -192,5 +192,5 @@ async def test_ban_active_after_update(hass):
assert sensor.state == "111.111.111.111" assert sensor.state == "111.111.111.111"
sensor.update() sensor.update()
assert sensor.state == "111.111.111.111" assert sensor.state == "111.111.111.111"
assert sensor.state_attributes[STATE_CURRENT_BANS] == ["111.111.111.111"] assert sensor.extra_state_attributes[STATE_CURRENT_BANS] == ["111.111.111.111"]
assert sensor.state_attributes[STATE_ALL_BANS] == ["111.111.111.111"] assert sensor.extra_state_attributes[STATE_ALL_BANS] == ["111.111.111.111"]

View file

@ -58,7 +58,7 @@ async def test_valid_data(hass):
State(GOOD_CONFIG["sensors"][reading], value), State(GOOD_CONFIG["sensors"][reading], value),
) )
assert sensor.state == "ok" assert sensor.state == "ok"
attrib = sensor.state_attributes attrib = sensor.extra_state_attributes
for reading, value in GOOD_DATA.items(): for reading, value in GOOD_DATA.items():
# battery level has a different name in # battery level has a different name in
# the JSON format than in hass # the JSON format than in hass
@ -70,13 +70,13 @@ async def test_low_battery(hass):
sensor = plant.Plant("other plant", GOOD_CONFIG) sensor = plant.Plant("other plant", GOOD_CONFIG)
sensor.entity_id = "sensor.mqtt_plant_battery" sensor.entity_id = "sensor.mqtt_plant_battery"
sensor.hass = hass sensor.hass = hass
assert sensor.state_attributes["problem"] == "none" assert sensor.extra_state_attributes["problem"] == "none"
sensor.state_changed( sensor.state_changed(
"sensor.mqtt_plant_battery", "sensor.mqtt_plant_battery",
State("sensor.mqtt_plant_battery", 10), State("sensor.mqtt_plant_battery", 10),
) )
assert sensor.state == "problem" assert sensor.state == "problem"
assert sensor.state_attributes["problem"] == "battery low" assert sensor.extra_state_attributes["problem"] == "battery low"
async def test_initial_states(hass): async def test_initial_states(hass):