Prevent SensorEntity and RestoreEntity inheritance (#88971)

This commit is contained in:
epenet 2023-05-24 12:49:35 +02:00 committed by GitHub
parent db33aadcbb
commit c475273145
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 128 additions and 0 deletions

View File

@ -172,6 +172,7 @@ async def _async_migrate_old_unique_ids(hass, devices):
registry.async_update_entity(old_entity_id, new_unique_id=device.unique_id)
# pylint: disable-next=hass-invalid-inheritance # needs fixing
class AugustOperatorSensor(AugustEntityMixin, RestoreEntity, SensorEntity):
"""Representation of an August lock operation sensor."""

View File

@ -151,6 +151,7 @@ def setup_platform(
add_entities(entities)
# pylint: disable-next=hass-invalid-inheritance # needs fixing
class EnOceanSensor(EnOceanEntity, RestoreEntity, SensorEntity):
"""Representation of an EnOcean sensor device such as a power meter."""
@ -180,6 +181,7 @@ class EnOceanSensor(EnOceanEntity, RestoreEntity, SensorEntity):
"""Update the internal state of the sensor."""
# pylint: disable-next=hass-invalid-inheritance # needs fixing
class EnOceanPowerSensor(EnOceanSensor):
"""Representation of an EnOcean power sensor.
@ -200,6 +202,7 @@ class EnOceanPowerSensor(EnOceanSensor):
self.schedule_update_ha_state()
# pylint: disable-next=hass-invalid-inheritance # needs fixing
class EnOceanTemperatureSensor(EnOceanSensor):
"""Representation of an EnOcean temperature sensor device.
@ -249,6 +252,7 @@ class EnOceanTemperatureSensor(EnOceanSensor):
self.schedule_update_ha_state()
# pylint: disable-next=hass-invalid-inheritance # needs fixing
class EnOceanHumiditySensor(EnOceanSensor):
"""Representation of an EnOcean humidity sensor device.
@ -267,6 +271,7 @@ class EnOceanHumiditySensor(EnOceanSensor):
self.schedule_update_ha_state()
# pylint: disable-next=hass-invalid-inheritance # needs fixing
class EnOceanWindowHandle(EnOceanSensor):
"""Representation of an EnOcean window handle device.

View File

@ -111,6 +111,7 @@ class EufyLifeRealTimeWeightSensorEntity(EufyLifeSensorEntity):
return UnitOfMass.KILOGRAMS
# pylint: disable-next=hass-invalid-inheritance # needs fixing
class EufyLifeWeightSensorEntity(RestoreEntity, EufyLifeSensorEntity):
"""Representation of an EufyLife weight sensor."""
@ -171,6 +172,7 @@ class EufyLifeWeightSensorEntity(RestoreEntity, EufyLifeSensorEntity):
)
# pylint: disable-next=hass-invalid-inheritance # needs fixing
class EufyLifeHeartRateSensorEntity(RestoreEntity, EufyLifeSensorEntity):
"""Representation of an EufyLife heart rate sensor."""

View File

@ -24,6 +24,7 @@ async def async_setup_platform(
async_add_entities([SpeedtestSensor(hass.data[FASTDOTCOM_DOMAIN])])
# pylint: disable-next=hass-invalid-inheritance # needs fixing
class SpeedtestSensor(RestoreEntity, SensorEntity):
"""Implementation of a FAst.com sensor."""

View File

@ -23,6 +23,7 @@ async def async_setup_entry(
async_add_entities([IncidentsSensor(client)])
# pylint: disable-next=hass-invalid-inheritance # needs fixing
class IncidentsSensor(RestoreEntity, SensorEntity):
"""Representation of FireServiceRota incidents sensor."""

View File

@ -128,6 +128,7 @@ async def async_setup_platform(
async_add_entities([integral])
# pylint: disable-next=hass-invalid-inheritance # needs fixing
class IntegrationSensor(RestoreEntity, SensorEntity):
"""Representation of an integration sensor."""

View File

@ -35,6 +35,7 @@ async def async_setup_platform(
async_add_entities(entities, True)
# pylint: disable-next=hass-invalid-inheritance # needs fixing
class Iperf3Sensor(RestoreEntity, SensorEntity):
"""A Iperf3 sensor implementation."""

View File

@ -281,6 +281,7 @@ async def async_setup_entry(
)
# pylint: disable-next=hass-invalid-inheritance # needs fixing
class RfxtrxSensor(RfxtrxEntity, SensorEntity):
"""Representation of a RFXtrx sensor.

View File

@ -768,6 +768,7 @@ class RpcSensor(ShellyRpcAttributeEntity, SensorEntity):
return self.attribute_value
# pylint: disable-next=hass-invalid-inheritance # needs fixing
class BlockSleepingSensor(ShellySleepingBlockAttributeEntity, SensorEntity):
"""Represent a block sleeping sensor."""
@ -808,6 +809,7 @@ class BlockSleepingSensor(ShellySleepingBlockAttributeEntity, SensorEntity):
return self.last_state.attributes.get(ATTR_UNIT_OF_MEASUREMENT)
# pylint: disable-next=hass-invalid-inheritance # needs fixing
class RpcSleepingSensor(ShellySleepingRpcAttributeEntity, SensorEntity):
"""Represent a RPC sleeping sensor."""

View File

@ -40,6 +40,7 @@ async def async_setup_entry(
)
# pylint: disable-next=hass-invalid-inheritance # needs fixing
class SmartMeterTexasSensor(CoordinatorEntity, RestoreEntity, SensorEntity):
"""Representation of an Smart Meter Texas sensor."""

View File

@ -78,6 +78,7 @@ async def async_setup_entry(
)
# pylint: disable-next=hass-invalid-inheritance # needs fixing
class SpeedtestSensor(
CoordinatorEntity[SpeedTestDataCoordinator], RestoreEntity, SensorEntity
):

View File

@ -115,6 +115,7 @@ async def async_setup_entry(
config_entry.async_on_unload(unsub)
# pylint: disable-next=hass-invalid-inheritance # needs fixing
class Sensor(ZhaEntity, SensorEntity):
"""Base ZHA sensor."""
@ -187,6 +188,7 @@ class Sensor(ZhaEntity, SensorEntity):
manufacturers="Digi",
stop_on_match_group=CLUSTER_HANDLER_ANALOG_INPUT,
)
# pylint: disable-next=hass-invalid-inheritance # needs fixing
class AnalogInput(Sensor):
"""Sensor that displays analog input values."""
@ -195,6 +197,7 @@ class AnalogInput(Sensor):
@MULTI_MATCH(cluster_handler_names=CLUSTER_HANDLER_POWER_CONFIGURATION)
# pylint: disable-next=hass-invalid-inheritance # needs fixing
class Battery(Sensor):
"""Battery sensor of power configuration cluster."""
@ -253,6 +256,7 @@ class Battery(Sensor):
stop_on_match_group=CLUSTER_HANDLER_ELECTRICAL_MEASUREMENT,
models={"VZM31-SN", "SP 234", "outletv4"},
)
# pylint: disable-next=hass-invalid-inheritance # needs fixing
class ElectricalMeasurement(Sensor):
"""Active power measurement."""
@ -292,6 +296,7 @@ class ElectricalMeasurement(Sensor):
cluster_handler_names=CLUSTER_HANDLER_ELECTRICAL_MEASUREMENT,
stop_on_match_group=CLUSTER_HANDLER_ELECTRICAL_MEASUREMENT,
)
# pylint: disable-next=hass-invalid-inheritance # needs fixing
class PolledElectricalMeasurement(ElectricalMeasurement):
"""Polled active power measurement."""
@ -305,6 +310,7 @@ class PolledElectricalMeasurement(ElectricalMeasurement):
@MULTI_MATCH(cluster_handler_names=CLUSTER_HANDLER_ELECTRICAL_MEASUREMENT)
# pylint: disable-next=hass-invalid-inheritance # needs fixing
class ElectricalMeasurementApparentPower(
ElectricalMeasurement, id_suffix="apparent_power"
):
@ -318,6 +324,7 @@ class ElectricalMeasurementApparentPower(
@MULTI_MATCH(cluster_handler_names=CLUSTER_HANDLER_ELECTRICAL_MEASUREMENT)
# pylint: disable-next=hass-invalid-inheritance # needs fixing
class ElectricalMeasurementRMSCurrent(ElectricalMeasurement, id_suffix="rms_current"):
"""RMS current measurement."""
@ -329,6 +336,7 @@ class ElectricalMeasurementRMSCurrent(ElectricalMeasurement, id_suffix="rms_curr
@MULTI_MATCH(cluster_handler_names=CLUSTER_HANDLER_ELECTRICAL_MEASUREMENT)
# pylint: disable-next=hass-invalid-inheritance # needs fixing
class ElectricalMeasurementRMSVoltage(ElectricalMeasurement, id_suffix="rms_voltage"):
"""RMS Voltage measurement."""
@ -340,6 +348,7 @@ class ElectricalMeasurementRMSVoltage(ElectricalMeasurement, id_suffix="rms_volt
@MULTI_MATCH(cluster_handler_names=CLUSTER_HANDLER_ELECTRICAL_MEASUREMENT)
# pylint: disable-next=hass-invalid-inheritance # needs fixing
class ElectricalMeasurementFrequency(ElectricalMeasurement, id_suffix="ac_frequency"):
"""Frequency measurement."""
@ -351,6 +360,7 @@ class ElectricalMeasurementFrequency(ElectricalMeasurement, id_suffix="ac_freque
@MULTI_MATCH(cluster_handler_names=CLUSTER_HANDLER_ELECTRICAL_MEASUREMENT)
# pylint: disable-next=hass-invalid-inheritance # needs fixing
class ElectricalMeasurementPowerFactor(ElectricalMeasurement, id_suffix="power_factor"):
"""Frequency measurement."""
@ -368,6 +378,7 @@ class ElectricalMeasurementPowerFactor(ElectricalMeasurement, id_suffix="power_f
cluster_handler_names=CLUSTER_HANDLER_HUMIDITY,
stop_on_match_group=CLUSTER_HANDLER_HUMIDITY,
)
# pylint: disable-next=hass-invalid-inheritance # needs fixing
class Humidity(Sensor):
"""Humidity sensor."""
@ -380,6 +391,7 @@ class Humidity(Sensor):
@MULTI_MATCH(cluster_handler_names=CLUSTER_HANDLER_SOIL_MOISTURE)
# pylint: disable-next=hass-invalid-inheritance # needs fixing
class SoilMoisture(Sensor):
"""Soil Moisture sensor."""
@ -392,6 +404,7 @@ class SoilMoisture(Sensor):
@MULTI_MATCH(cluster_handler_names=CLUSTER_HANDLER_LEAF_WETNESS)
# pylint: disable-next=hass-invalid-inheritance # needs fixing
class LeafWetness(Sensor):
"""Leaf Wetness sensor."""
@ -404,6 +417,7 @@ class LeafWetness(Sensor):
@MULTI_MATCH(cluster_handler_names=CLUSTER_HANDLER_ILLUMINANCE)
# pylint: disable-next=hass-invalid-inheritance # needs fixing
class Illuminance(Sensor):
"""Illuminance Sensor."""
@ -422,6 +436,7 @@ class Illuminance(Sensor):
cluster_handler_names=CLUSTER_HANDLER_SMARTENERGY_METERING,
stop_on_match_group=CLUSTER_HANDLER_SMARTENERGY_METERING,
)
# pylint: disable-next=hass-invalid-inheritance # needs fixing
class SmartEnergyMetering(Sensor):
"""Metering sensor."""
@ -475,6 +490,7 @@ class SmartEnergyMetering(Sensor):
cluster_handler_names=CLUSTER_HANDLER_SMARTENERGY_METERING,
stop_on_match_group=CLUSTER_HANDLER_SMARTENERGY_METERING,
)
# pylint: disable-next=hass-invalid-inheritance # needs fixing
class SmartEnergySummation(SmartEnergyMetering, id_suffix="summation_delivered"):
"""Smart Energy Metering summation sensor."""
@ -516,6 +532,7 @@ class SmartEnergySummation(SmartEnergyMetering, id_suffix="summation_delivered")
models={"TS011F", "ZLinky_TIC"},
stop_on_match_group=CLUSTER_HANDLER_SMARTENERGY_METERING,
)
# pylint: disable-next=hass-invalid-inheritance # needs fixing
class PolledSmartEnergySummation(SmartEnergySummation):
"""Polled Smart Energy Metering summation sensor."""
@ -532,6 +549,7 @@ class PolledSmartEnergySummation(SmartEnergySummation):
cluster_handler_names=CLUSTER_HANDLER_SMARTENERGY_METERING,
models={"ZLinky_TIC"},
)
# pylint: disable-next=hass-invalid-inheritance # needs fixing
class Tier1SmartEnergySummation(
PolledSmartEnergySummation, id_suffix="tier1_summation_delivered"
):
@ -545,6 +563,7 @@ class Tier1SmartEnergySummation(
cluster_handler_names=CLUSTER_HANDLER_SMARTENERGY_METERING,
models={"ZLinky_TIC"},
)
# pylint: disable-next=hass-invalid-inheritance # needs fixing
class Tier2SmartEnergySummation(
PolledSmartEnergySummation, id_suffix="tier2_summation_delivered"
):
@ -558,6 +577,7 @@ class Tier2SmartEnergySummation(
cluster_handler_names=CLUSTER_HANDLER_SMARTENERGY_METERING,
models={"ZLinky_TIC"},
)
# pylint: disable-next=hass-invalid-inheritance # needs fixing
class Tier3SmartEnergySummation(
PolledSmartEnergySummation, id_suffix="tier3_summation_delivered"
):
@ -571,6 +591,7 @@ class Tier3SmartEnergySummation(
cluster_handler_names=CLUSTER_HANDLER_SMARTENERGY_METERING,
models={"ZLinky_TIC"},
)
# pylint: disable-next=hass-invalid-inheritance # needs fixing
class Tier4SmartEnergySummation(
PolledSmartEnergySummation, id_suffix="tier4_summation_delivered"
):
@ -584,6 +605,7 @@ class Tier4SmartEnergySummation(
cluster_handler_names=CLUSTER_HANDLER_SMARTENERGY_METERING,
models={"ZLinky_TIC"},
)
# pylint: disable-next=hass-invalid-inheritance # needs fixing
class Tier5SmartEnergySummation(
PolledSmartEnergySummation, id_suffix="tier5_summation_delivered"
):
@ -597,6 +619,7 @@ class Tier5SmartEnergySummation(
cluster_handler_names=CLUSTER_HANDLER_SMARTENERGY_METERING,
models={"ZLinky_TIC"},
)
# pylint: disable-next=hass-invalid-inheritance # needs fixing
class Tier6SmartEnergySummation(
PolledSmartEnergySummation, id_suffix="tier6_summation_delivered"
):
@ -607,6 +630,7 @@ class Tier6SmartEnergySummation(
@MULTI_MATCH(cluster_handler_names=CLUSTER_HANDLER_PRESSURE)
# pylint: disable-next=hass-invalid-inheritance # needs fixing
class Pressure(Sensor):
"""Pressure sensor."""
@ -619,6 +643,7 @@ class Pressure(Sensor):
@MULTI_MATCH(cluster_handler_names=CLUSTER_HANDLER_TEMPERATURE)
# pylint: disable-next=hass-invalid-inheritance # needs fixing
class Temperature(Sensor):
"""Temperature Sensor."""
@ -631,6 +656,7 @@ class Temperature(Sensor):
@MULTI_MATCH(cluster_handler_names=CLUSTER_HANDLER_DEVICE_TEMPERATURE)
# pylint: disable-next=hass-invalid-inheritance # needs fixing
class DeviceTemperature(Sensor):
"""Device Temperature Sensor."""
@ -644,6 +670,7 @@ class DeviceTemperature(Sensor):
@MULTI_MATCH(cluster_handler_names="carbon_dioxide_concentration")
# pylint: disable-next=hass-invalid-inheritance # needs fixing
class CarbonDioxideConcentration(Sensor):
"""Carbon Dioxide Concentration sensor."""
@ -657,6 +684,7 @@ class CarbonDioxideConcentration(Sensor):
@MULTI_MATCH(cluster_handler_names="carbon_monoxide_concentration")
# pylint: disable-next=hass-invalid-inheritance # needs fixing
class CarbonMonoxideConcentration(Sensor):
"""Carbon Monoxide Concentration sensor."""
@ -671,6 +699,7 @@ class CarbonMonoxideConcentration(Sensor):
@MULTI_MATCH(generic_ids="cluster_handler_0x042e", stop_on_match_group="voc_level")
@MULTI_MATCH(cluster_handler_names="voc_level", stop_on_match_group="voc_level")
# pylint: disable-next=hass-invalid-inheritance # needs fixing
class VOCLevel(Sensor):
"""VOC Level sensor."""
@ -688,6 +717,7 @@ class VOCLevel(Sensor):
models="lumi.airmonitor.acn01",
stop_on_match_group="voc_level",
)
# pylint: disable-next=hass-invalid-inheritance # needs fixing
class PPBVOCLevel(Sensor):
"""VOC Level sensor."""
@ -701,6 +731,7 @@ class PPBVOCLevel(Sensor):
@MULTI_MATCH(cluster_handler_names="pm25")
# pylint: disable-next=hass-invalid-inheritance # needs fixing
class PM25(Sensor):
"""Particulate Matter 2.5 microns or less sensor."""
@ -713,6 +744,7 @@ class PM25(Sensor):
@MULTI_MATCH(cluster_handler_names="formaldehyde_concentration")
# pylint: disable-next=hass-invalid-inheritance # needs fixing
class FormaldehydeConcentration(Sensor):
"""Formaldehyde Concentration sensor."""
@ -728,6 +760,7 @@ class FormaldehydeConcentration(Sensor):
cluster_handler_names=CLUSTER_HANDLER_THERMOSTAT,
stop_on_match_group=CLUSTER_HANDLER_THERMOSTAT,
)
# pylint: disable-next=hass-invalid-inheritance # needs fixing
class ThermostatHVACAction(Sensor, id_suffix="hvac_action"):
"""Thermostat HVAC action sensor."""
@ -821,6 +854,7 @@ class ThermostatHVACAction(Sensor, id_suffix="hvac_action"):
manufacturers="Sinope Technologies",
stop_on_match_group=CLUSTER_HANDLER_THERMOSTAT,
)
# pylint: disable-next=hass-invalid-inheritance # needs fixing
class SinopeHVACAction(ThermostatHVACAction):
"""Sinope Thermostat HVAC action sensor."""
@ -850,6 +884,7 @@ class SinopeHVACAction(ThermostatHVACAction):
@MULTI_MATCH(cluster_handler_names=CLUSTER_HANDLER_BASIC)
# pylint: disable-next=hass-invalid-inheritance # needs fixing
class RSSISensor(Sensor, id_suffix="rssi"):
"""RSSI sensor for a device."""
@ -886,6 +921,7 @@ class RSSISensor(Sensor, id_suffix="rssi"):
@MULTI_MATCH(cluster_handler_names=CLUSTER_HANDLER_BASIC)
# pylint: disable-next=hass-invalid-inheritance # needs fixing
class LQISensor(RSSISensor, id_suffix="lqi"):
"""LQI sensor for a device."""
@ -900,6 +936,7 @@ class LQISensor(RSSISensor, id_suffix="lqi"):
"_TZE200_htnnfasr",
},
)
# pylint: disable-next=hass-invalid-inheritance # needs fixing
class TimeLeft(Sensor, id_suffix="time_left"):
"""Sensor that displays time left value."""
@ -911,6 +948,7 @@ class TimeLeft(Sensor, id_suffix="time_left"):
@MULTI_MATCH(cluster_handler_names="ikea_airpurifier")
# pylint: disable-next=hass-invalid-inheritance # needs fixing
class IkeaDeviceRunTime(Sensor, id_suffix="device_run_time"):
"""Sensor that displays device run time (in minutes)."""
@ -922,6 +960,7 @@ class IkeaDeviceRunTime(Sensor, id_suffix="device_run_time"):
@MULTI_MATCH(cluster_handler_names="ikea_airpurifier")
# pylint: disable-next=hass-invalid-inheritance # needs fixing
class IkeaFilterRunTime(Sensor, id_suffix="filter_run_time"):
"""Sensor that displays run time of the current filter (in minutes)."""
@ -940,6 +979,7 @@ class AqaraFeedingSource(types.enum8):
@MULTI_MATCH(cluster_handler_names="opple_cluster", models={"aqara.feeder.acn001"})
# pylint: disable-next=hass-invalid-inheritance # needs fixing
class AqaraPetFeederLastFeedingSource(Sensor, id_suffix="last_feeding_source"):
"""Sensor that displays the last feeding source of pet feeder."""
@ -953,6 +993,7 @@ class AqaraPetFeederLastFeedingSource(Sensor, id_suffix="last_feeding_source"):
@MULTI_MATCH(cluster_handler_names="opple_cluster", models={"aqara.feeder.acn001"})
# pylint: disable-next=hass-invalid-inheritance # needs fixing
class AqaraPetFeederLastFeedingSize(Sensor, id_suffix="last_feeding_size"):
"""Sensor that displays the last feeding size of the pet feeder."""
@ -962,6 +1003,7 @@ class AqaraPetFeederLastFeedingSize(Sensor, id_suffix="last_feeding_size"):
@MULTI_MATCH(cluster_handler_names="opple_cluster", models={"aqara.feeder.acn001"})
# pylint: disable-next=hass-invalid-inheritance # needs fixing
class AqaraPetFeederPortionsDispensed(Sensor, id_suffix="portions_dispensed"):
"""Sensor that displays the number of portions dispensed by the pet feeder."""
@ -972,6 +1014,7 @@ class AqaraPetFeederPortionsDispensed(Sensor, id_suffix="portions_dispensed"):
@MULTI_MATCH(cluster_handler_names="opple_cluster", models={"aqara.feeder.acn001"})
# pylint: disable-next=hass-invalid-inheritance # needs fixing
class AqaraPetFeederWeightDispensed(Sensor, id_suffix="weight_dispensed"):
"""Sensor that displays the weight dispensed by the pet feeder."""
@ -983,6 +1026,7 @@ class AqaraPetFeederWeightDispensed(Sensor, id_suffix="weight_dispensed"):
@MULTI_MATCH(cluster_handler_names="opple_cluster", models={"lumi.sensor_smoke.acn03"})
# pylint: disable-next=hass-invalid-inheritance # needs fixing
class AqaraSmokeDensityDbm(Sensor, id_suffix="smoke_density_dbm"):
"""Sensor that displays the smoke density of an Aqara smoke sensor in dB/m."""

View File

@ -0,0 +1,66 @@
"""Plugin to enforce type hints on specific functions."""
from __future__ import annotations
import re
from astroid import nodes
from pylint.checkers import BaseChecker
from pylint.lint import PyLinter
_MODULE_REGEX: re.Pattern[str] = re.compile(r"^homeassistant\.components\.\w+(\.\w+)?$")
def _get_module_platform(module_name: str) -> str | None:
"""Return the platform for the module name."""
if not (module_match := _MODULE_REGEX.match(module_name)):
# Ensure `homeassistant.components.<component>`
# Or `homeassistant.components.<component>.<platform>`
return None
platform = module_match.groups()[0]
return platform.lstrip(".") if platform else "__init__"
class HassInheritanceChecker(BaseChecker): # type: ignore[misc]
"""Checker for invalid inheritance."""
name = "hass_inheritance"
priority = -1
msgs = {
"W7411": (
"Invalid inheritance: %s",
"hass-invalid-inheritance",
"Used when a class has inheritance has issues",
),
}
options = ()
_module_name: str
_module_platform: str | None
def visit_module(self, node: nodes.Module) -> None:
"""Populate matchers for a Module node."""
self._module_name = node.name
self._module_platform = _get_module_platform(node.name)
def visit_classdef(self, node: nodes.ClassDef) -> None:
"""Apply relevant type hint checks on a ClassDef node."""
if self._module_platform != "sensor":
return
ancestors = [a.name for a in node.ancestors()]
if (
"RestoreEntity" in ancestors
and "SensorEntity" in ancestors
and "RestoreSensor" not in ancestors
):
self.add_message(
"hass-invalid-inheritance",
node=node,
args="SensorEntity and RestoreEntity should not be combined, please use RestoreSensor",
)
def register(linter: PyLinter) -> None:
"""Register the checker."""
linter.register_checker(HassInheritanceChecker(linter))

View File

@ -113,6 +113,7 @@ load-plugins = [
"pylint.extensions.code_style",
"pylint.extensions.typing",
"hass_enforce_type_hints",
"hass_inheritance",
"hass_imports",
"hass_logger",
"pylint_per_file_ignores",