Fully type Jewish Calendar (#56232)

This commit is contained in:
Yuval Aboulafia 2021-10-23 00:11:41 +03:00 committed by GitHub
parent fe0151491e
commit a9ccd70e71
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 64 additions and 39 deletions

View File

@ -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.*

View File

@ -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,

View File

@ -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()

View File

@ -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(

View File

@ -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