Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Re-enable homeassistant-stubs and mypy #738

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 12 additions & 13 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,15 @@ repos:
rev: v0.0.275
hooks:
- id: ruff
# Temporarily disabled due to crash, probably caused by us having to use HA stubs which are out of date?
# See https://github.com/nathanmarlor/foxess_modbus/actions/runs/12610946302/job/35146070831?pr=720
# - repo: https://github.com/pre-commit/mirrors-mypy
# rev: v1.5.1
# hooks:
# - id: mypy
# # These are duplicated from requirements.txt
# additional_dependencies:
# [
# homeassistant-stubs==2024.12.5,
# types-python-slugify==8.0.0.2,
# voluptuous-stubs==0.1.1,
# ]
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.14.1
hooks:
- id: mypy
args: [--show-traceback]
# These are duplicated from requirements.txt
additional_dependencies:
[
homeassistant-stubs==2025.1.1,
types-python-slugify==8.0.0.2,
voluptuous-stubs==0.1.1,
]
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ def connect(self) -> bool:
# https://github.com/nathanmarlor/foxess_modbus/issues/275
def recv(self, size: int | None) -> bytes:
"""Read data from the underlying descriptor."""
super(ModbusTcpClient, self).recv(size)
super(ModbusTcpClient, self).recv(size) # type: ignore
if not self.socket:
raise ConnectionException(str(self))

Expand Down Expand Up @@ -73,9 +73,7 @@ def recv(self, size: int | None) -> bytes:
# We expect a single-element list if this succeeds, or an empty list if it timed out
if len(poll_res) > 0:
if (recv_data := self.socket.recv(recv_size)) == b"":
return self._handle_abrupt_socket_close( # type: ignore[no-any-return]
size, data, time.time() - time_
)
return self._handle_abrupt_socket_close(size, data, time.time() - time_)
data.append(recv_data)
data_length += len(recv_data)
time_ = time.time()
Expand Down
5 changes: 2 additions & 3 deletions custom_components/foxess_modbus/client/modbus_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
from typing import Callable
from typing import Type
from typing import TypeVar
from typing import cast

import serial
from homeassistant.core import HomeAssistant
Expand Down Expand Up @@ -152,7 +151,7 @@ async def read_registers(
response,
)

return cast(list[int], response.registers)
return response.registers

async def write_registers(self, register_address: int, register_values: list[int], slave: int) -> None:
"""Write registers"""
Expand Down Expand Up @@ -199,7 +198,7 @@ async def write_registers(self, register_address: int, register_values: list[int
async def _async_pymodbus_call(self, call: Callable[..., T], *args: Any, auto_connect: bool = True) -> T:
"""Convert async to sync pymodbus call."""

def _call() -> T:
def _call(_: Any) -> T:
# When using pollserial://, connected calls into serial.serial_for_url, which calls importlib.import_module,
# which HA doesn't like (see https://github.com/nathanmarlor/foxess_modbus/issues/618).
# Therefore we need to do this check inside the executor job
Expand Down
4 changes: 2 additions & 2 deletions custom_components/foxess_modbus/entities/entity_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from typing import Sequence

from homeassistant.helpers.entity import Entity
from homeassistant.helpers.entity import EntityDescription
from homeassistant.util.frozen_dataclass_compat import FrozenOrThawed

from ..common.entity_controller import EntityController
from ..common.types import Inv
Expand All @@ -19,7 +19,7 @@
# We need to combine EntityDescription's metaclass with ABC's metaclass, see
# https://github.com/nathanmarlor/foxess_modbus/issues/480. This is to allow HA to move to frozen entity descriptions
# (to aid caching), and will start logging deprecation warnings in 2024.x.
class EntityFactoryMetaclass(type(EntityDescription), type(ABC)): # type: ignore
class EntityFactoryMetaclass(FrozenOrThawed, type(ABC)): # type: ignore
"""
Metaclass to use for EntityFactory.
"""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@


@dataclass(kw_only=True, **ENTITY_DESCRIPTION_KWARGS)
class ModbusBatterySensorDescription(ModbusSensorDescription):
class ModbusBatterySensorDescription(ModbusSensorDescription): # type: ignore[misc]
"""Description for ModbusBatterySensor"""

bms_connect_state_address: list[ModbusAddressSpec]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@


@dataclass(kw_only=True, **ENTITY_DESCRIPTION_KWARGS)
class ModbusBinarySensorDescription(BinarySensorEntityDescription, EntityFactory):
class ModbusBinarySensorDescription(BinarySensorEntityDescription, EntityFactory): # type: ignore[misc, override]
"""Description for ModbusBinarySensor"""

address: list[InverterModelSpec]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ def _is_force_charge_enabled(


@dataclass(kw_only=True, **ENTITY_DESCRIPTION_KWARGS)
class ModbusChargePeriodStartEndSensorDescription(SensorEntityDescription, EntityFactory):
class ModbusChargePeriodStartEndSensorDescription(SensorEntityDescription, EntityFactory): # type: ignore[misc, override]
"""Entity description for ModbusChargePeriodStartEndSensor"""

address: list[InverterModelSpec]
Expand Down Expand Up @@ -187,7 +187,9 @@ def addresses(self) -> list[int]:


@dataclass(kw_only=True, **ENTITY_DESCRIPTION_KWARGS)
class ModbusEnableForceChargeSensorDescription(BinarySensorEntityDescription, EntityFactory):
class ModbusEnableForceChargeSensorDescription( # type ignore[misc, override]
BinarySensorEntityDescription, EntityFactory
):
"""Entity description for ModbusEnableForceChargeSensor"""

period_start_address: list[InverterModelSpec]
Expand Down
16 changes: 9 additions & 7 deletions custom_components/foxess_modbus/entities/modbus_entity_mixin.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@

from homeassistant.const import Platform
from homeassistant.helpers import entity_registry
from homeassistant.helpers.entity import ABCCachedProperties
from homeassistant.helpers.entity import DeviceInfo
from homeassistant.helpers.entity import Entity
from propcache import cached_property

from ..common.entity_controller import EntityController
from ..common.entity_controller import ModbusControllerEntity
Expand Down Expand Up @@ -67,18 +69,18 @@ class ModbusEntityProtocol(Protocol):
_controller: EntityController


# HA introduced a ABCCachedProperties metaclass which is used by Entity, and which derives from ABCMeta.
# This conflicts with Protocol's metaclass (from ModbusEntityProtocol).
class ModbusEntityMixinMetaclass(ABCCachedProperties, type(Protocol)): # type: ignore
pass


if TYPE_CHECKING:
_ModbusEntityMixinBase = Entity
else:
_ModbusEntityMixinBase = object


# HA introduced a ABCCachedProperties metaclass which is used by Entity, and which derives from ABCMeta.
# This conflicts with Protocol's metaclass (from ModbusEntityProtocol).
class ModbusEntityMixinMetaclass(type(Entity), type(Protocol)): # type: ignore
pass


class ModbusEntityMixin(
ModbusControllerEntity, ModbusEntityProtocol, _ModbusEntityMixinBase, metaclass=ModbusEntityMixinMetaclass
):
Expand All @@ -88,7 +90,7 @@ class ModbusEntityMixin(
This provides properties which are common to all FoxESS entities.
"""

@property
@cached_property
def unique_id(self) -> str:
"""Return a unique ID."""
return _create_unique_id(self.entity_description.key, self._controller.inverter_details)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ def __post_init__(self) -> None:


@dataclass(kw_only=True, **ENTITY_DESCRIPTION_KWARGS)
class ModbusFaultSensorDescription(SensorEntityDescription, EntityFactory):
class ModbusFaultSensorDescription(SensorEntityDescription, EntityFactory): # type: ignore[misc, override]
"""Description for ModbusFaultSensor"""

addresses: list[ModbusAddressesSpec]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@


@dataclass(kw_only=True, **ENTITY_DESCRIPTION_KWARGS)
class ModbusIntegrationSensorDescription(SensorEntityDescription, EntityFactory):
class ModbusIntegrationSensorDescription(SensorEntityDescription, EntityFactory): # type: ignore[misc, override]
"""Custom sensor description"""

models: list[EntitySpec]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@


@dataclass(kw_only=True, **ENTITY_DESCRIPTION_KWARGS)
class ModbusInverterStateSensorDescription(SensorEntityDescription, EntityFactory):
class ModbusInverterStateSensorDescription(SensorEntityDescription, EntityFactory): # type: ignore[misc, override]
"""Description for ModbusInverterStateSensor"""

address: list[ModbusAddressSpec]
Expand Down Expand Up @@ -104,7 +104,7 @@ def addresses(self) -> list[int]:


@dataclass(kw_only=True, **ENTITY_DESCRIPTION_KWARGS)
class ModbusG2InverterStateSensorDescription(SensorEntityDescription, EntityFactory):
class ModbusG2InverterStateSensorDescription(SensorEntityDescription, EntityFactory): # type ignore[override]
"""Description for ModbusInverterStateSensor"""

# Fault 1 code, fault 3 code
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@


@dataclass(kw_only=True, **ENTITY_DESCRIPTION_KWARGS)
class ModbusLambdaSensorDescription(SensorEntityDescription, EntityFactory):
class ModbusLambdaSensorDescription(SensorEntityDescription, EntityFactory): # type: ignore[misc, override]
"""Entity description for ModbusLambdaSensors"""

models: list[EntitySpec]
Expand Down
2 changes: 1 addition & 1 deletion custom_components/foxess_modbus/entities/modbus_number.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@


@dataclass(kw_only=True, **ENTITY_DESCRIPTION_KWARGS)
class ModbusNumberDescription(NumberEntityDescription, EntityFactory):
class ModbusNumberDescription(NumberEntityDescription, EntityFactory): # type: ignore[misc, override]
"""Custom number entity description"""

address: list[ModbusAddressSpec]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@


@dataclass(kw_only=True, **ENTITY_DESCRIPTION_KWARGS)
class ModbusRemoteControlNumberDescription(NumberEntityDescription, EntityFactory):
class ModbusRemoteControlNumberDescription(NumberEntityDescription, EntityFactory): # type: ignore[misc, override]
"""Custom number entity description"""

models: list[EntitySpec]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@


@dataclass(kw_only=True, **ENTITY_DESCRIPTION_KWARGS)
class ModbusRemoteControlSelectDescription(SelectEntityDescription, EntityFactory):
class ModbusRemoteControlSelectDescription(SelectEntityDescription, EntityFactory): # type: ignore[misc]
models: list[EntitySpec]

@property
Expand Down
2 changes: 1 addition & 1 deletion custom_components/foxess_modbus/entities/modbus_select.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@


@dataclass(kw_only=True, **ENTITY_DESCRIPTION_KWARGS)
class ModbusSelectDescription(SelectEntityDescription, EntityFactory):
class ModbusSelectDescription(SelectEntityDescription, EntityFactory): # type: ignore[misc]
"""Custom select entity description"""

address: list[ModbusAddressSpec]
Expand Down
2 changes: 1 addition & 1 deletion custom_components/foxess_modbus/entities/modbus_sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@


@dataclass(kw_only=True, **ENTITY_DESCRIPTION_KWARGS)
class ModbusSensorDescription(SensorEntityDescription, EntityFactory):
class ModbusSensorDescription(SensorEntityDescription, EntityFactory): # type: ignore[misc, override]
"""Custom sensor description"""

addresses: list[ModbusAddressesSpec]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@


@dataclass(kw_only=True, **ENTITY_DESCRIPTION_KWARGS)
class ModbusVersionSensorDescription(SensorEntityDescription, EntityFactory):
class ModbusVersionSensorDescription(SensorEntityDescription, EntityFactory): # type: ignore[misc, override]
"""Description for ModbusVersionSensor"""

address: list[ModbusAddressSpec]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@


@dataclass(kw_only=True, **ENTITY_DESCRIPTION_KWARGS)
class ModbusWorkModeSelectDescription(ModbusSelectDescription):
class ModbusWorkModeSelectDescription(ModbusSelectDescription): # type: ignore[misc, override]
def create_entity_if_supported(
self,
controller: EntityController,
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ namespace_packages = true
explicit_package_bases = true

[[tool.mypy.overrides]]
module = 'pymodbus.*'
module = 'serial.*'
ignore_missing_imports = true

[tool.ruff]
Expand Down
9 changes: 4 additions & 5 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# pip>=21.0,<23.2
homeassistant==2025.1.0
homeassistant==2025.1.1

# Testing
pytest-homeassistant-custom-component==0.13.201 # Matching version for 2025.1.0
pytest-homeassistant-custom-component==0.13.202 # Matching version for 2025.1.0
psutil-home-assistant # Not sure why this is needed?
fnv_hash_fast # Or this?
pytest-asyncio
Expand All @@ -13,9 +13,8 @@ black==23.9.0
ruff==0.0.275
# These are duplicated in .pre-commit-config.yaml
reorder-python-imports==3.10.0
mypy==1.5.1
# Currently not avaiable, see https://github.com/KapJI/homeassistant-stubs/issues/510
# homeassistant-stubs==2025.1.0 # Matching HA version
mypy==1.13.0
homeassistant-stubs==2025.1.1 # Matching HA version
types-python-slugify==8.0.0.2
voluptuous-stubs==0.1.1
# For mypy. Keep in sync with manifest.json and https://github.com/home-assistant/core/blob/master/requirements_all.txt.
Expand Down
Loading