From c475273145e9e966b2b3c2d79542efd0a0f63f11 Mon Sep 17 00:00:00 2001 From: epenet <6771947+epenet@users.noreply.github.com> Date: Wed, 24 May 2023 12:49:35 +0200 Subject: [PATCH] Prevent SensorEntity and RestoreEntity inheritance (#88971) --- homeassistant/components/august/sensor.py | 1 + homeassistant/components/enocean/sensor.py | 5 ++ .../components/eufylife_ble/sensor.py | 2 + homeassistant/components/fastdotcom/sensor.py | 1 + .../components/fireservicerota/sensor.py | 1 + .../components/integration/sensor.py | 1 + homeassistant/components/iperf3/sensor.py | 1 + homeassistant/components/rfxtrx/sensor.py | 1 + homeassistant/components/shelly/sensor.py | 2 + .../components/smart_meter_texas/sensor.py | 1 + .../components/speedtestdotnet/sensor.py | 1 + homeassistant/components/zha/sensor.py | 44 +++++++++++++ pylint/plugins/hass_inheritance.py | 66 +++++++++++++++++++ pyproject.toml | 1 + 14 files changed, 128 insertions(+) create mode 100644 pylint/plugins/hass_inheritance.py diff --git a/homeassistant/components/august/sensor.py b/homeassistant/components/august/sensor.py index 6e0969a6724..169a344e2bd 100644 --- a/homeassistant/components/august/sensor.py +++ b/homeassistant/components/august/sensor.py @@ -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.""" diff --git a/homeassistant/components/enocean/sensor.py b/homeassistant/components/enocean/sensor.py index 4fa3b25ed06..5d1c0027791 100644 --- a/homeassistant/components/enocean/sensor.py +++ b/homeassistant/components/enocean/sensor.py @@ -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. diff --git a/homeassistant/components/eufylife_ble/sensor.py b/homeassistant/components/eufylife_ble/sensor.py index e57b83687a6..d7c69dec165 100644 --- a/homeassistant/components/eufylife_ble/sensor.py +++ b/homeassistant/components/eufylife_ble/sensor.py @@ -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.""" diff --git a/homeassistant/components/fastdotcom/sensor.py b/homeassistant/components/fastdotcom/sensor.py index 4f00dd5a543..b3d5f66ae8c 100644 --- a/homeassistant/components/fastdotcom/sensor.py +++ b/homeassistant/components/fastdotcom/sensor.py @@ -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.""" diff --git a/homeassistant/components/fireservicerota/sensor.py b/homeassistant/components/fireservicerota/sensor.py index 1484ff7f154..20f8589d2a2 100644 --- a/homeassistant/components/fireservicerota/sensor.py +++ b/homeassistant/components/fireservicerota/sensor.py @@ -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.""" diff --git a/homeassistant/components/integration/sensor.py b/homeassistant/components/integration/sensor.py index 64d83506ad9..7e60f2c509c 100644 --- a/homeassistant/components/integration/sensor.py +++ b/homeassistant/components/integration/sensor.py @@ -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.""" diff --git a/homeassistant/components/iperf3/sensor.py b/homeassistant/components/iperf3/sensor.py index e39d1e1d864..d3db0e76631 100644 --- a/homeassistant/components/iperf3/sensor.py +++ b/homeassistant/components/iperf3/sensor.py @@ -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.""" diff --git a/homeassistant/components/rfxtrx/sensor.py b/homeassistant/components/rfxtrx/sensor.py index e594b47c93a..3613a640f1a 100644 --- a/homeassistant/components/rfxtrx/sensor.py +++ b/homeassistant/components/rfxtrx/sensor.py @@ -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. diff --git a/homeassistant/components/shelly/sensor.py b/homeassistant/components/shelly/sensor.py index b83131a1004..ce77a6e9ff6 100644 --- a/homeassistant/components/shelly/sensor.py +++ b/homeassistant/components/shelly/sensor.py @@ -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.""" diff --git a/homeassistant/components/smart_meter_texas/sensor.py b/homeassistant/components/smart_meter_texas/sensor.py index 57a88f7a409..7552f2c0697 100644 --- a/homeassistant/components/smart_meter_texas/sensor.py +++ b/homeassistant/components/smart_meter_texas/sensor.py @@ -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.""" diff --git a/homeassistant/components/speedtestdotnet/sensor.py b/homeassistant/components/speedtestdotnet/sensor.py index c3773802650..d44d66bbd47 100644 --- a/homeassistant/components/speedtestdotnet/sensor.py +++ b/homeassistant/components/speedtestdotnet/sensor.py @@ -78,6 +78,7 @@ async def async_setup_entry( ) +# pylint: disable-next=hass-invalid-inheritance # needs fixing class SpeedtestSensor( CoordinatorEntity[SpeedTestDataCoordinator], RestoreEntity, SensorEntity ): diff --git a/homeassistant/components/zha/sensor.py b/homeassistant/components/zha/sensor.py index 52c1f6a5b19..da1f1f6c04c 100644 --- a/homeassistant/components/zha/sensor.py +++ b/homeassistant/components/zha/sensor.py @@ -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.""" diff --git a/pylint/plugins/hass_inheritance.py b/pylint/plugins/hass_inheritance.py new file mode 100644 index 00000000000..afbe3453c7e --- /dev/null +++ b/pylint/plugins/hass_inheritance.py @@ -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.` + # Or `homeassistant.components..` + 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)) diff --git a/pyproject.toml b/pyproject.toml index 4a1a529d59f..caf904d86d3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -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",