diff --git a/.strict-typing b/.strict-typing index 295a0a352e0..5fb4b1759ee 100644 --- a/.strict-typing +++ b/.strict-typing @@ -60,6 +60,7 @@ homeassistant.components.hyperion.* homeassistant.components.image_processing.* homeassistant.components.integration.* homeassistant.components.iqvia.* +homeassistant.components.jewish_calendar.* homeassistant.components.knx.* homeassistant.components.kraken.* homeassistant.components.lcn.* diff --git a/homeassistant/components/jewish_calendar/__init__.py b/homeassistant/components/jewish_calendar/__init__.py index bb7cc9d2841..3f211d5d23d 100644 --- a/homeassistant/components/jewish_calendar/__init__.py +++ b/homeassistant/components/jewish_calendar/__init__.py @@ -1,12 +1,14 @@ """The jewish_calendar component.""" from __future__ import annotations -import hdate +from hdate import Location import voluptuous as vol from homeassistant.const import CONF_LATITUDE, CONF_LONGITUDE, CONF_NAME +from homeassistant.core import HomeAssistant import homeassistant.helpers.config_validation as cv from homeassistant.helpers.discovery import async_load_platform +from homeassistant.helpers.typing import ConfigType DOMAIN = "jewish_calendar" @@ -43,7 +45,7 @@ CONFIG_SCHEMA = vol.Schema( def get_unique_prefix( - location: hdate.Location, + location: Location, language: str, candle_lighting_offset: int | None, havdalah_offset: int | None, @@ -63,7 +65,7 @@ def get_unique_prefix( return f"{prefix}" -async def async_setup(hass, config): +async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: """Set up the Jewish Calendar component.""" name = config[DOMAIN][CONF_NAME] language = config[DOMAIN][CONF_LANGUAGE] @@ -75,7 +77,7 @@ async def async_setup(hass, config): candle_lighting_offset = config[DOMAIN][CONF_CANDLE_LIGHT_MINUTES] havdalah_offset = config[DOMAIN][CONF_HAVDALAH_OFFSET_MINUTES] - location = hdate.Location( + location = Location( latitude=latitude, longitude=longitude, timezone=hass.config.time_zone, diff --git a/homeassistant/components/jewish_calendar/binary_sensor.py b/homeassistant/components/jewish_calendar/binary_sensor.py index c4e9b1e347f..f239dfc31b6 100644 --- a/homeassistant/components/jewish_calendar/binary_sensor.py +++ b/homeassistant/components/jewish_calendar/binary_sensor.py @@ -2,14 +2,17 @@ from __future__ import annotations import datetime as dt +from datetime import datetime +from typing import cast import hdate +from hdate.zmanim import Zmanim from homeassistant.components.binary_sensor import ( BinarySensorEntity, BinarySensorEntityDescription, ) -from homeassistant.core import HomeAssistant, callback +from homeassistant.core import CALLBACK_TYPE, HomeAssistant, callback from homeassistant.helpers import event from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType @@ -29,7 +32,7 @@ async def async_setup_platform( config: ConfigType, async_add_entities: AddEntitiesCallback, discovery_info: DiscoveryInfoType | None = None, -): +) -> None: """Set up the Jewish Calendar binary sensor devices.""" if discovery_info is None: return @@ -42,7 +45,11 @@ class JewishCalendarBinarySensor(BinarySensorEntity): _attr_should_poll = False - def __init__(self, data, description: BinarySensorEntityDescription) -> None: + def __init__( + self, + data: dict[str, str | bool | int | float], + description: BinarySensorEntityDescription, + ) -> None: """Initialize the binary sensor.""" self._attr_name = f"{data['name']} {description.name}" self._attr_unique_id = f"{data['prefix']}_{description.key}" @@ -50,14 +57,14 @@ class JewishCalendarBinarySensor(BinarySensorEntity): self._hebrew = data["language"] == "hebrew" self._candle_lighting_offset = data["candle_lighting_offset"] self._havdalah_offset = data["havdalah_offset"] - self._update_unsub = None + self._update_unsub: CALLBACK_TYPE | None = None @property def is_on(self) -> bool: """Return true if sensor is on.""" - return self._get_zmanim().issur_melacha_in_effect + return cast(bool, self._get_zmanim().issur_melacha_in_effect) - def _get_zmanim(self): + def _get_zmanim(self) -> Zmanim: """Return the Zmanim object for now().""" return hdate.Zmanim( date=dt_util.now(), @@ -73,13 +80,13 @@ class JewishCalendarBinarySensor(BinarySensorEntity): self._schedule_update() @callback - def _update(self, now=None): + def _update(self, now: datetime | None = None) -> None: """Update the state of the sensor.""" self._update_unsub = None self._schedule_update() self.async_write_ha_state() - def _schedule_update(self): + def _schedule_update(self) -> None: """Schedule the next update of the sensor.""" now = dt_util.now() zmanim = self._get_zmanim() diff --git a/homeassistant/components/jewish_calendar/sensor.py b/homeassistant/components/jewish_calendar/sensor.py index 6a57eb0eeda..09a56a9e26a 100644 --- a/homeassistant/components/jewish_calendar/sensor.py +++ b/homeassistant/components/jewish_calendar/sensor.py @@ -1,17 +1,19 @@ """Platform to retrieve Jewish calendar information for Home Assistant.""" from __future__ import annotations -from datetime import datetime +from datetime import date as Date, datetime import logging +from typing import Any -import hdate +from hdate import HDate +from hdate.zmanim import Zmanim from homeassistant.components.sensor import SensorEntity, SensorEntityDescription from homeassistant.const import DEVICE_CLASS_TIMESTAMP, SUN_EVENT_SUNSET from homeassistant.core import HomeAssistant from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.sun import get_astral_event_date -from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType +from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType, StateType import homeassistant.util.dt as dt_util from . import DOMAIN @@ -130,7 +132,7 @@ async def async_setup_platform( config: ConfigType, async_add_entities: AddEntitiesCallback, discovery_info: DiscoveryInfoType | None = None, -): +) -> None: """Set up the Jewish calendar sensor platform.""" if discovery_info is None: return @@ -150,7 +152,11 @@ async def async_setup_platform( class JewishCalendarSensor(SensorEntity): """Representation of an Jewish calendar sensor.""" - def __init__(self, data, description: SensorEntityDescription) -> None: + def __init__( + self, + data: dict[str, str | bool | int | float], + description: SensorEntityDescription, + ) -> None: """Initialize the Jewish calendar sensor.""" self.entity_description = description self._attr_name = f"{data['name']} {description.name}" @@ -160,29 +166,33 @@ class JewishCalendarSensor(SensorEntity): self._candle_lighting_offset = data["candle_lighting_offset"] self._havdalah_offset = data["havdalah_offset"] self._diaspora = data["diaspora"] - self._state = None + self._state: datetime | None = None self._holiday_attrs: dict[str, str] = {} @property - def native_value(self): + def native_value(self) -> StateType: """Return the state of the sensor.""" if isinstance(self._state, datetime): return self._state.isoformat() return self._state - async def async_update(self): + async def async_update(self) -> None: """Update the state of the sensor.""" now = dt_util.now() _LOGGER.debug("Now: %s Location: %r", now, self._location) today = now.date() - sunset = dt_util.as_local( - get_astral_event_date(self.hass, SUN_EVENT_SUNSET, today) - ) + event_date = get_astral_event_date(self.hass, SUN_EVENT_SUNSET, today) + + if event_date is None: + _LOGGER.error("Can't get sunset event date for %s", today) + return + + sunset = dt_util.as_local(event_date) _LOGGER.debug("Now: %s Sunset: %s", now, sunset) - daytime_date = hdate.HDate(today, diaspora=self._diaspora, hebrew=self._hebrew) + daytime_date = HDate(today, diaspora=self._diaspora, hebrew=self._hebrew) # The Jewish day starts after darkness (called "tzais") and finishes at # sunset ("shkia"). The time in between is a gray area (aka "Bein @@ -203,9 +213,9 @@ class JewishCalendarSensor(SensorEntity): self._state = self.get_state(daytime_date, after_shkia_date, after_tzais_date) _LOGGER.debug("New value for %s: %s", self.entity_description.key, self._state) - def make_zmanim(self, date): + def make_zmanim(self, date: Date) -> Zmanim: """Create a Zmanim object.""" - return hdate.Zmanim( + return Zmanim( date=date, location=self._location, candle_lighting_offset=self._candle_lighting_offset, @@ -220,7 +230,9 @@ class JewishCalendarSensor(SensorEntity): return {} return self._holiday_attrs - def get_state(self, daytime_date, after_shkia_date, after_tzais_date): + def get_state( + self, daytime_date: HDate, after_shkia_date: HDate, after_tzais_date: HDate + ) -> Any | None: """For a given type of sensor, return the state.""" # Terminology note: by convention in py-libhdate library, "upcoming" # refers to "current" or "upcoming" dates. @@ -250,23 +262,15 @@ class JewishCalendarTimeSensor(JewishCalendarSensor): _attr_device_class = DEVICE_CLASS_TIMESTAMP @property - def native_value(self): + def native_value(self) -> StateType | None: """Return the state of the sensor.""" if self._state is None: return None return dt_util.as_utc(self._state).isoformat() - @property - def extra_state_attributes(self) -> dict[str, str]: - """Return the state attributes.""" - attrs: dict[str, str] = {} - - if self._state is None: - return attrs - - return attrs - - def get_state(self, daytime_date, after_shkia_date, after_tzais_date): + def get_state( + self, daytime_date: HDate, after_shkia_date: HDate, after_tzais_date: HDate + ) -> Any | None: """For a given type of sensor, return the state.""" if self.entity_description.key == "upcoming_shabbat_candle_lighting": times = self.make_zmanim( diff --git a/mypy.ini b/mypy.ini index 8114e3d39f5..c338ebe5a31 100644 --- a/mypy.ini +++ b/mypy.ini @@ -671,6 +671,17 @@ no_implicit_optional = true warn_return_any = true warn_unreachable = true +[mypy-homeassistant.components.jewish_calendar.*] +check_untyped_defs = true +disallow_incomplete_defs = true +disallow_subclassing_any = true +disallow_untyped_calls = true +disallow_untyped_decorators = true +disallow_untyped_defs = true +no_implicit_optional = true +warn_return_any = true +warn_unreachable = true + [mypy-homeassistant.components.knx.*] check_untyped_defs = true disallow_incomplete_defs = true