Update hdate dependency to 1.0.3 (#137247)

* Update hdate version

* Update code to reflect changes from hdate==1.0.0

* Fix some tests

* Fix parasha tests

* Fix  holiday tests

* Cleanup holidays changes

* Zmanim objects should now access the local attribute

* Fix binary sensors

* Update test values on upcoming shabbat times

* Update hdate to 1.0.1

* Adapt to changes from 1.0.0 -> 1.0.1

* Change shabbat candle lighthing test scenario to 40 minutes as expected in Jerusalem

* Update to version 1.0.2

* Update keys based on updated nomenclature in library

* Update HolidayDatabase .get_all_names in test

* Make holiday type an ordered set

* Fix freeze_time

* Fix imports

* Fix tests and minor change

* Update hdate version 1.0.3, add migration method

* Fix migration code

* Add test for migration

* The change is not backwards compatible if config is not restored
This commit is contained in:
Tsvi Mostovicz 2025-03-11 10:43:29 +02:00 committed by GitHub
parent 3b115506b9
commit 52408e67b2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 202 additions and 110 deletions

View File

@ -3,6 +3,7 @@
from __future__ import annotations from __future__ import annotations
from functools import partial from functools import partial
import logging
from hdate import Location from hdate import Location
@ -14,7 +15,8 @@ from homeassistant.const import (
CONF_TIME_ZONE, CONF_TIME_ZONE,
Platform, Platform,
) )
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers import entity_registry as er
from .const import ( from .const import (
CONF_CANDLE_LIGHT_MINUTES, CONF_CANDLE_LIGHT_MINUTES,
@ -27,6 +29,7 @@ from .const import (
) )
from .entity import JewishCalendarConfigEntry, JewishCalendarData from .entity import JewishCalendarConfigEntry, JewishCalendarData
_LOGGER = logging.getLogger(__name__)
PLATFORMS: list[Platform] = [Platform.BINARY_SENSOR, Platform.SENSOR] PLATFORMS: list[Platform] = [Platform.BINARY_SENSOR, Platform.SENSOR]
@ -80,3 +83,49 @@ async def async_unload_entry(
) -> bool: ) -> bool:
"""Unload a config entry.""" """Unload a config entry."""
return await hass.config_entries.async_unload_platforms(config_entry, PLATFORMS) return await hass.config_entries.async_unload_platforms(config_entry, PLATFORMS)
async def async_migrate_entry(
hass: HomeAssistant, config_entry: JewishCalendarConfigEntry
) -> bool:
"""Migrate old entry."""
_LOGGER.debug("Migrating from version %s", config_entry.version)
@callback
def update_unique_id(
entity_entry: er.RegistryEntry,
) -> dict[str, str] | None:
"""Update unique ID of entity entry."""
key_translations = {
"first_light": "alot_hashachar",
"talit": "talit_and_tefillin",
"sunrise": "netz_hachama",
"gra_end_shma": "sof_zman_shema_gra",
"mga_end_shma": "sof_zman_shema_mga",
"gra_end_tfila": "sof_zman_tfilla_gra",
"mga_end_tfila": "sof_zman_tfilla_mga",
"midday": "chatzot_hayom",
"big_mincha": "mincha_gedola",
"small_mincha": "mincha_ketana",
"plag_mincha": "plag_hamincha",
"sunset": "shkia",
"first_stars": "tset_hakohavim_tsom",
"three_stars": "tset_hakohavim_shabbat",
}
new_keys = tuple(key_translations.values())
if not entity_entry.unique_id.endswith(new_keys):
old_key = entity_entry.unique_id.split("-")[1]
new_unique_id = f"{config_entry.entry_id}-{key_translations[old_key]}"
return {"new_unique_id": new_unique_id}
return None
if config_entry.version > 1:
# This means the user has downgraded from a future version
return False
if config_entry.version == 1:
await er.async_migrate_entries(hass, config_entry.entry_id, update_unique_id)
hass.config_entries.async_update_entry(config_entry, version=2)
return True

View File

@ -5,9 +5,7 @@ from __future__ import annotations
from collections.abc import Callable from collections.abc import Callable
from dataclasses import dataclass from dataclasses import dataclass
import datetime as dt import datetime as dt
from datetime import datetime
import hdate
from hdate.zmanim import Zmanim from hdate.zmanim import Zmanim
from homeassistant.components.binary_sensor import ( from homeassistant.components.binary_sensor import (
@ -27,7 +25,7 @@ from .entity import JewishCalendarConfigEntry, JewishCalendarEntity
class JewishCalendarBinarySensorMixIns(BinarySensorEntityDescription): class JewishCalendarBinarySensorMixIns(BinarySensorEntityDescription):
"""Binary Sensor description mixin class for Jewish Calendar.""" """Binary Sensor description mixin class for Jewish Calendar."""
is_on: Callable[[Zmanim], bool] = lambda _: False is_on: Callable[[Zmanim, dt.datetime], bool] = lambda _, __: False
@dataclass(frozen=True) @dataclass(frozen=True)
@ -42,18 +40,18 @@ BINARY_SENSORS: tuple[JewishCalendarBinarySensorEntityDescription, ...] = (
key="issur_melacha_in_effect", key="issur_melacha_in_effect",
name="Issur Melacha in Effect", name="Issur Melacha in Effect",
icon="mdi:power-plug-off", icon="mdi:power-plug-off",
is_on=lambda state: bool(state.issur_melacha_in_effect), is_on=lambda state, now: bool(state.issur_melacha_in_effect(now)),
), ),
JewishCalendarBinarySensorEntityDescription( JewishCalendarBinarySensorEntityDescription(
key="erev_shabbat_hag", key="erev_shabbat_hag",
name="Erev Shabbat/Hag", name="Erev Shabbat/Hag",
is_on=lambda state: bool(state.erev_shabbat_chag), is_on=lambda state, now: bool(state.erev_shabbat_chag(now)),
entity_registry_enabled_default=False, entity_registry_enabled_default=False,
), ),
JewishCalendarBinarySensorEntityDescription( JewishCalendarBinarySensorEntityDescription(
key="motzei_shabbat_hag", key="motzei_shabbat_hag",
name="Motzei Shabbat/Hag", name="Motzei Shabbat/Hag",
is_on=lambda state: bool(state.motzei_shabbat_chag), is_on=lambda state, now: bool(state.motzei_shabbat_chag(now)),
entity_registry_enabled_default=False, entity_registry_enabled_default=False,
), ),
) )
@ -84,16 +82,16 @@ class JewishCalendarBinarySensor(JewishCalendarEntity, BinarySensorEntity):
def is_on(self) -> bool: def is_on(self) -> bool:
"""Return true if sensor is on.""" """Return true if sensor is on."""
zmanim = self._get_zmanim() zmanim = self._get_zmanim()
return self.entity_description.is_on(zmanim) return self.entity_description.is_on(zmanim, dt_util.now())
def _get_zmanim(self) -> Zmanim: def _get_zmanim(self) -> Zmanim:
"""Return the Zmanim object for now().""" """Return the Zmanim object for now()."""
return hdate.Zmanim( return Zmanim(
date=dt_util.now(), date=dt.date.today(),
location=self._location, location=self._location,
candle_lighting_offset=self._candle_lighting_offset, candle_lighting_offset=self._candle_lighting_offset,
havdalah_offset=self._havdalah_offset, havdalah_offset=self._havdalah_offset,
hebrew=self._hebrew, language=self._language,
) )
async def async_added_to_hass(self) -> None: async def async_added_to_hass(self) -> None:
@ -109,7 +107,7 @@ class JewishCalendarBinarySensor(JewishCalendarEntity, BinarySensorEntity):
return await super().async_will_remove_from_hass() return await super().async_will_remove_from_hass()
@callback @callback
def _update(self, now: datetime | None = None) -> None: def _update(self, now: dt.datetime | None = None) -> None:
"""Update the state of the sensor.""" """Update the state of the sensor."""
self._update_unsub = None self._update_unsub = None
self._schedule_update() self._schedule_update()
@ -119,7 +117,7 @@ class JewishCalendarBinarySensor(JewishCalendarEntity, BinarySensorEntity):
"""Schedule the next update of the sensor.""" """Schedule the next update of the sensor."""
now = dt_util.now() now = dt_util.now()
zmanim = self._get_zmanim() zmanim = self._get_zmanim()
update = zmanim.zmanim["sunrise"] + dt.timedelta(days=1) update = zmanim.netz_hachama.local + dt.timedelta(days=1)
candle_lighting = zmanim.candle_lighting candle_lighting = zmanim.candle_lighting
if candle_lighting is not None and now < candle_lighting < update: if candle_lighting is not None and now < candle_lighting < update:
update = candle_lighting update = candle_lighting

View File

@ -86,7 +86,7 @@ def _get_data_schema(hass: HomeAssistant) -> vol.Schema:
class JewishCalendarConfigFlow(ConfigFlow, domain=DOMAIN): class JewishCalendarConfigFlow(ConfigFlow, domain=DOMAIN):
"""Handle a config flow for Jewish calendar.""" """Handle a config flow for Jewish calendar."""
VERSION = 1 VERSION = 2
@staticmethod @staticmethod
@callback @callback

View File

@ -3,6 +3,7 @@
from dataclasses import dataclass from dataclasses import dataclass
from hdate import Location from hdate import Location
from hdate.translator import Language
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
from homeassistant.helpers.device_registry import DeviceEntryType, DeviceInfo from homeassistant.helpers.device_registry import DeviceEntryType, DeviceInfo
@ -17,7 +18,7 @@ type JewishCalendarConfigEntry = ConfigEntry[JewishCalendarData]
class JewishCalendarData: class JewishCalendarData:
"""Jewish Calendar runtime dataclass.""" """Jewish Calendar runtime dataclass."""
language: str language: Language
diaspora: bool diaspora: bool
location: Location location: Location
candle_lighting_offset: int candle_lighting_offset: int
@ -43,7 +44,6 @@ class JewishCalendarEntity(Entity):
) )
data = config_entry.runtime_data data = config_entry.runtime_data
self._location = data.location self._location = data.location
self._hebrew = data.language == "hebrew"
self._language = data.language self._language = data.language
self._candle_lighting_offset = data.candle_lighting_offset self._candle_lighting_offset = data.candle_lighting_offset
self._havdalah_offset = data.havdalah_offset self._havdalah_offset = data.havdalah_offset

View File

@ -6,6 +6,6 @@
"documentation": "https://www.home-assistant.io/integrations/jewish_calendar", "documentation": "https://www.home-assistant.io/integrations/jewish_calendar",
"iot_class": "calculated", "iot_class": "calculated",
"loggers": ["hdate"], "loggers": ["hdate"],
"requirements": ["hdate==0.11.1"], "requirements": ["hdate[astral]==1.0.3"],
"single_config_entry": true "single_config_entry": true
} }

View File

@ -2,12 +2,13 @@
from __future__ import annotations from __future__ import annotations
from datetime import date as Date import datetime as dt
import logging import logging
from typing import Any, cast from typing import Any
from hdate import HDate, HebrewDate, htables from hdate import HDateInfo, Zmanim
from hdate.zmanim import Zmanim from hdate.holidays import HolidayDatabase
from hdate.parasha import Parasha
from homeassistant.components.sensor import ( from homeassistant.components.sensor import (
SensorDeviceClass, SensorDeviceClass,
@ -59,83 +60,83 @@ INFO_SENSORS: tuple[SensorEntityDescription, ...] = (
TIME_SENSORS: tuple[SensorEntityDescription, ...] = ( TIME_SENSORS: tuple[SensorEntityDescription, ...] = (
SensorEntityDescription( SensorEntityDescription(
key="first_light", key="alot_hashachar",
name="Alot Hashachar", # codespell:ignore alot name="Alot Hashachar", # codespell:ignore alot
icon="mdi:weather-sunset-up", icon="mdi:weather-sunset-up",
entity_registry_enabled_default=False, entity_registry_enabled_default=False,
), ),
SensorEntityDescription( SensorEntityDescription(
key="talit", key="talit_and_tefillin",
name="Talit and Tefillin", name="Talit and Tefillin",
icon="mdi:calendar-clock", icon="mdi:calendar-clock",
entity_registry_enabled_default=False, entity_registry_enabled_default=False,
), ),
SensorEntityDescription( SensorEntityDescription(
key="sunrise", key="netz_hachama",
name="Hanetz Hachama", name="Hanetz Hachama",
icon="mdi:calendar-clock", icon="mdi:calendar-clock",
), ),
SensorEntityDescription( SensorEntityDescription(
key="gra_end_shma", key="sof_zman_shema_gra",
name='Latest time for Shma Gr"a', name='Latest time for Shma Gr"a',
icon="mdi:calendar-clock", icon="mdi:calendar-clock",
entity_registry_enabled_default=False, entity_registry_enabled_default=False,
), ),
SensorEntityDescription( SensorEntityDescription(
key="mga_end_shma", key="sof_zman_shema_mga",
name='Latest time for Shma MG"A', name='Latest time for Shma MG"A',
icon="mdi:calendar-clock", icon="mdi:calendar-clock",
entity_registry_enabled_default=False, entity_registry_enabled_default=False,
), ),
SensorEntityDescription( SensorEntityDescription(
key="gra_end_tfila", key="sof_zman_tfilla_gra",
name='Latest time for Tefilla Gr"a', name='Latest time for Tefilla Gr"a',
icon="mdi:calendar-clock", icon="mdi:calendar-clock",
entity_registry_enabled_default=False, entity_registry_enabled_default=False,
), ),
SensorEntityDescription( SensorEntityDescription(
key="mga_end_tfila", key="sof_zman_tfilla_mga",
name='Latest time for Tefilla MG"A', name='Latest time for Tefilla MG"A',
icon="mdi:calendar-clock", icon="mdi:calendar-clock",
entity_registry_enabled_default=False, entity_registry_enabled_default=False,
), ),
SensorEntityDescription( SensorEntityDescription(
key="midday", key="chatzot_hayom",
name="Chatzot Hayom", name="Chatzot Hayom",
icon="mdi:calendar-clock", icon="mdi:calendar-clock",
entity_registry_enabled_default=False, entity_registry_enabled_default=False,
), ),
SensorEntityDescription( SensorEntityDescription(
key="big_mincha", key="mincha_gedola",
name="Mincha Gedola", name="Mincha Gedola",
icon="mdi:calendar-clock", icon="mdi:calendar-clock",
entity_registry_enabled_default=False, entity_registry_enabled_default=False,
), ),
SensorEntityDescription( SensorEntityDescription(
key="small_mincha", key="mincha_ketana",
name="Mincha Ketana", name="Mincha Ketana",
icon="mdi:calendar-clock", icon="mdi:calendar-clock",
entity_registry_enabled_default=False, entity_registry_enabled_default=False,
), ),
SensorEntityDescription( SensorEntityDescription(
key="plag_mincha", key="plag_hamincha",
name="Plag Hamincha", name="Plag Hamincha",
icon="mdi:weather-sunset-down", icon="mdi:weather-sunset-down",
entity_registry_enabled_default=False, entity_registry_enabled_default=False,
), ),
SensorEntityDescription( SensorEntityDescription(
key="sunset", key="shkia",
name="Shkia", name="Shkia",
icon="mdi:weather-sunset", icon="mdi:weather-sunset",
), ),
SensorEntityDescription( SensorEntityDescription(
key="first_stars", key="tset_hakohavim_tsom",
name="T'set Hakochavim", name="T'set Hakochavim",
icon="mdi:weather-night", icon="mdi:weather-night",
entity_registry_enabled_default=False, entity_registry_enabled_default=False,
), ),
SensorEntityDescription( SensorEntityDescription(
key="three_stars", key="tset_hakohavim_shabbat",
name="T'set Hakochavim, 3 stars", name="T'set Hakochavim, 3 stars",
icon="mdi:weather-night", icon="mdi:weather-night",
entity_registry_enabled_default=False, entity_registry_enabled_default=False,
@ -212,7 +213,9 @@ class JewishCalendarSensor(JewishCalendarEntity, SensorEntity):
_LOGGER.debug("Now: %s Sunset: %s", now, sunset) _LOGGER.debug("Now: %s Sunset: %s", now, sunset)
daytime_date = HDate(today, diaspora=self._diaspora, hebrew=self._hebrew) daytime_date = HDateInfo(
today, diaspora=self._diaspora, language=self._language
)
# The Jewish day starts after darkness (called "tzais") and finishes at # The Jewish day starts after darkness (called "tzais") and finishes at
# sunset ("shkia"). The time in between is a gray area # sunset ("shkia"). The time in between is a gray area
@ -238,14 +241,14 @@ class JewishCalendarSensor(JewishCalendarEntity, SensorEntity):
"New value for %s: %s", self.entity_description.key, self._attr_native_value "New value for %s: %s", self.entity_description.key, self._attr_native_value
) )
def make_zmanim(self, date: Date) -> Zmanim: def make_zmanim(self, date: dt.date) -> Zmanim:
"""Create a Zmanim object.""" """Create a Zmanim object."""
return Zmanim( return Zmanim(
date=date, date=date,
location=self._location, location=self._location,
candle_lighting_offset=self._candle_lighting_offset, candle_lighting_offset=self._candle_lighting_offset,
havdalah_offset=self._havdalah_offset, havdalah_offset=self._havdalah_offset,
hebrew=self._hebrew, language=self._language,
) )
@property @property
@ -254,43 +257,40 @@ class JewishCalendarSensor(JewishCalendarEntity, SensorEntity):
return self._attrs return self._attrs
def get_state( def get_state(
self, daytime_date: HDate, after_shkia_date: HDate, after_tzais_date: HDate self,
daytime_date: HDateInfo,
after_shkia_date: HDateInfo,
after_tzais_date: HDateInfo,
) -> Any | None: ) -> Any | None:
"""For a given type of sensor, return the state.""" """For a given type of sensor, return the state."""
# Terminology note: by convention in py-libhdate library, "upcoming" # Terminology note: by convention in py-libhdate library, "upcoming"
# refers to "current" or "upcoming" dates. # refers to "current" or "upcoming" dates.
if self.entity_description.key == "date": if self.entity_description.key == "date":
hdate = cast(HebrewDate, after_shkia_date.hdate) hdate = after_shkia_date.hdate
month = htables.MONTHS[hdate.month.value - 1] hdate.month.set_language(self._language)
self._attrs = { self._attrs = {
"hebrew_year": hdate.year, "hebrew_year": str(hdate.year),
"hebrew_month_name": month.hebrew if self._hebrew else month.english, "hebrew_month_name": str(hdate.month),
"hebrew_day": hdate.day, "hebrew_day": str(hdate.day),
} }
return after_shkia_date.hebrew_date return after_shkia_date.hdate
if self.entity_description.key == "weekly_portion": if self.entity_description.key == "weekly_portion":
self._attr_options = [ self._attr_options = list(Parasha)
(p.hebrew if self._hebrew else p.english) for p in htables.PARASHAOT
]
# Compute the weekly portion based on the upcoming shabbat. # Compute the weekly portion based on the upcoming shabbat.
return after_tzais_date.upcoming_shabbat.parasha return after_tzais_date.upcoming_shabbat.parasha
if self.entity_description.key == "holiday": if self.entity_description.key == "holiday":
_id = _type = _type_id = "" _holidays = after_shkia_date.holidays
_holiday_type = after_shkia_date.holiday_type _id = ", ".join(holiday.name for holiday in _holidays)
if isinstance(_holiday_type, list): _type = ", ".join(
_id = ", ".join(after_shkia_date.holiday_name) dict.fromkeys(_holiday.type.name for _holiday in _holidays)
_type = ", ".join([_htype.name for _htype in _holiday_type]) )
_type_id = ", ".join([str(_htype.value) for _htype in _holiday_type]) self._attrs = {"id": _id, "type": _type}
else: self._attr_options = HolidayDatabase(self._diaspora).get_all_names(
_id = after_shkia_date.holiday_name self._language
_type = _holiday_type.name )
_type_id = _holiday_type.value return ", ".join(str(holiday) for holiday in _holidays) if _holidays else ""
self._attrs = {"id": _id, "type": _type, "type_id": _type_id}
self._attr_options = htables.get_all_holidays(self._language)
return after_shkia_date.holiday_description
if self.entity_description.key == "omer_count": if self.entity_description.key == "omer_count":
return after_shkia_date.omer_day return after_shkia_date.omer.total_days if after_shkia_date.omer else 0
if self.entity_description.key == "daf_yomi": if self.entity_description.key == "daf_yomi":
return daytime_date.daf_yomi return daytime_date.daf_yomi
@ -303,7 +303,10 @@ class JewishCalendarTimeSensor(JewishCalendarSensor):
_attr_device_class = SensorDeviceClass.TIMESTAMP _attr_device_class = SensorDeviceClass.TIMESTAMP
def get_state( def get_state(
self, daytime_date: HDate, after_shkia_date: HDate, after_tzais_date: HDate self,
daytime_date: HDateInfo,
after_shkia_date: HDateInfo,
after_tzais_date: HDateInfo,
) -> Any | None: ) -> Any | None:
"""For a given type of sensor, return the state.""" """For a given type of sensor, return the state."""
if self.entity_description.key == "upcoming_shabbat_candle_lighting": if self.entity_description.key == "upcoming_shabbat_candle_lighting":
@ -325,5 +328,5 @@ class JewishCalendarTimeSensor(JewishCalendarSensor):
) )
return times.havdalah return times.havdalah
times = self.make_zmanim(dt_util.now()).zmanim times = self.make_zmanim(dt_util.now().date())
return times[self.entity_description.key] return times.zmanim[self.entity_description.key].local

2
requirements_all.txt generated
View File

@ -1121,7 +1121,7 @@ hass-splunk==0.1.1
hassil==2.2.3 hassil==2.2.3
# homeassistant.components.jewish_calendar # homeassistant.components.jewish_calendar
hdate==0.11.1 hdate[astral]==1.0.3
# homeassistant.components.heatmiser # homeassistant.components.heatmiser
heatmiserV3==2.0.3 heatmiserV3==2.0.3

View File

@ -959,7 +959,7 @@ hass-nabucasa==0.94.0
hassil==2.2.3 hassil==2.2.3
# homeassistant.components.jewish_calendar # homeassistant.components.jewish_calendar
hdate==0.11.1 hdate[astral]==1.0.3
# homeassistant.components.here_travel_time # homeassistant.components.here_travel_time
here-routing==1.0.1 here-routing==1.0.1

View File

@ -3,8 +3,6 @@
from collections import namedtuple from collections import namedtuple
from datetime import datetime from datetime import datetime
from freezegun import freeze_time as alter_time # noqa: F401
from homeassistant.components import jewish_calendar from homeassistant.components import jewish_calendar
from homeassistant.util import dt as dt_util from homeassistant.util import dt as dt_util
@ -49,7 +47,7 @@ def make_jerusalem_test_params(dtime, results, havdalah_offset=0):
} }
return ( return (
dtime, dtime,
jewish_calendar.DEFAULT_CANDLE_LIGHT, 40,
havdalah_offset, havdalah_offset,
False, False,
"Asia/Jerusalem", "Asia/Jerusalem",

View File

@ -3,6 +3,7 @@
from datetime import datetime as dt, timedelta from datetime import datetime as dt, timedelta
import logging import logging
from freezegun import freeze_time
import pytest import pytest
from homeassistant.components.binary_sensor import DOMAIN as BINARY_SENSOR_DOMAIN from homeassistant.components.binary_sensor import DOMAIN as BINARY_SENSOR_DOMAIN
@ -18,7 +19,7 @@ from homeassistant.core import HomeAssistant
from homeassistant.setup import async_setup_component from homeassistant.setup import async_setup_component
from homeassistant.util import dt as dt_util from homeassistant.util import dt as dt_util
from . import alter_time, make_jerusalem_test_params, make_nyc_test_params from . import make_jerusalem_test_params, make_nyc_test_params
from tests.common import MockConfigEntry, async_fire_time_changed from tests.common import MockConfigEntry, async_fire_time_changed
@ -191,7 +192,7 @@ async def test_issur_melacha_sensor(
hass.config.latitude = latitude hass.config.latitude = latitude
hass.config.longitude = longitude hass.config.longitude = longitude
with alter_time(test_time): with freeze_time(test_time):
entry = MockConfigEntry( entry = MockConfigEntry(
title=DEFAULT_NAME, title=DEFAULT_NAME,
domain=DOMAIN, domain=DOMAIN,
@ -213,7 +214,7 @@ async def test_issur_melacha_sensor(
== result["state"] == result["state"]
) )
with alter_time(result["update"]): with freeze_time(result["update"]):
async_fire_time_changed(hass, result["update"]) async_fire_time_changed(hass, result["update"])
await hass.async_block_till_done() await hass.async_block_till_done()
assert ( assert (
@ -264,7 +265,7 @@ async def test_issur_melacha_sensor_update(
hass.config.latitude = latitude hass.config.latitude = latitude
hass.config.longitude = longitude hass.config.longitude = longitude
with alter_time(test_time): with freeze_time(test_time):
entry = MockConfigEntry( entry = MockConfigEntry(
title=DEFAULT_NAME, title=DEFAULT_NAME,
domain=DOMAIN, domain=DOMAIN,
@ -286,7 +287,7 @@ async def test_issur_melacha_sensor_update(
) )
test_time += timedelta(microseconds=1) test_time += timedelta(microseconds=1)
with alter_time(test_time): with freeze_time(test_time):
async_fire_time_changed(hass, test_time) async_fire_time_changed(hass, test_time)
await hass.async_block_till_done() await hass.async_block_till_done()
assert ( assert (

View File

@ -1 +1,44 @@
"""Tests for the Jewish Calendar component's init.""" """Tests for the Jewish Calendar component's init."""
import pytest
from homeassistant.components.jewish_calendar.const import DOMAIN
from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er
from tests.common import MockConfigEntry
@pytest.mark.parametrize(
("old_key", "new_key"),
[
("first_light", "alot_hashachar"),
("sunset", "shkia"),
("havdalah", "havdalah"), # Test no change
],
)
async def test_migrate_unique_id(
hass: HomeAssistant,
entity_registry: er.EntityRegistry,
old_key: str,
new_key: str,
) -> None:
"""Test unique id migration."""
entry = MockConfigEntry(domain=DOMAIN, data={})
entry.add_to_hass(hass)
entity: er.RegistryEntry = entity_registry.async_get_or_create(
domain=SENSOR_DOMAIN,
platform=DOMAIN,
unique_id=f"{entry.entry_id}-{old_key}",
config_entry=entry,
)
assert entity.unique_id.endswith(f"-{old_key}")
await hass.config_entries.async_setup(entry.entry_id)
await hass.async_block_till_done()
entity_migrated = entity_registry.async_get(entity.entity_id)
assert entity_migrated
assert entity_migrated.unique_id == f"{entry.entry_id}-{new_key}"

View File

@ -2,10 +2,11 @@
from datetime import datetime as dt, timedelta from datetime import datetime as dt, timedelta
from hdate import htables from freezegun import freeze_time
from hdate.holidays import HolidayDatabase
from hdate.parasha import Parasha
import pytest import pytest
from homeassistant.components.binary_sensor import DOMAIN as SENSOR_DOMAIN
from homeassistant.components.jewish_calendar.const import ( from homeassistant.components.jewish_calendar.const import (
CONF_CANDLE_LIGHT_MINUTES, CONF_CANDLE_LIGHT_MINUTES,
CONF_DIASPORA, CONF_DIASPORA,
@ -13,12 +14,13 @@ from homeassistant.components.jewish_calendar.const import (
DEFAULT_NAME, DEFAULT_NAME,
DOMAIN, DOMAIN,
) )
from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN
from homeassistant.const import CONF_LANGUAGE, CONF_PLATFORM from homeassistant.const import CONF_LANGUAGE, CONF_PLATFORM
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.setup import async_setup_component from homeassistant.setup import async_setup_component
from homeassistant.util import dt as dt_util from homeassistant.util import dt as dt_util
from . import alter_time, make_jerusalem_test_params, make_nyc_test_params from . import make_jerusalem_test_params, make_nyc_test_params
from tests.common import MockConfigEntry, async_fire_time_changed from tests.common import MockConfigEntry, async_fire_time_changed
@ -92,8 +94,7 @@ TEST_PARAMS = [
"icon": "mdi:calendar-star", "icon": "mdi:calendar-star",
"id": "rosh_hashana_i", "id": "rosh_hashana_i",
"type": "YOM_TOV", "type": "YOM_TOV",
"type_id": 1, "options": HolidayDatabase(False).get_all_names("english"),
"options": htables.get_all_holidays("english"),
}, },
), ),
( (
@ -111,8 +112,7 @@ TEST_PARAMS = [
"icon": "mdi:calendar-star", "icon": "mdi:calendar-star",
"id": "chanukah, rosh_chodesh", "id": "chanukah, rosh_chodesh",
"type": "MELACHA_PERMITTED_HOLIDAY, ROSH_CHODESH", "type": "MELACHA_PERMITTED_HOLIDAY, ROSH_CHODESH",
"type_id": "4, 10", "options": HolidayDatabase(False).get_all_names("english"),
"options": htables.get_all_holidays("english"),
}, },
), ),
( (
@ -128,7 +128,7 @@ TEST_PARAMS = [
"device_class": "enum", "device_class": "enum",
"friendly_name": "Jewish Calendar Parshat Hashavua", "friendly_name": "Jewish Calendar Parshat Hashavua",
"icon": "mdi:book-open-variant", "icon": "mdi:book-open-variant",
"options": [p.hebrew for p in htables.PARASHAOT], "options": list(Parasha),
}, },
), ),
( (
@ -139,7 +139,7 @@ TEST_PARAMS = [
"hebrew", "hebrew",
"t_set_hakochavim", "t_set_hakochavim",
True, True,
dt(2018, 9, 8, 19, 45), dt(2018, 9, 8, 19, 47),
None, None,
), ),
( (
@ -150,7 +150,7 @@ TEST_PARAMS = [
"hebrew", "hebrew",
"t_set_hakochavim", "t_set_hakochavim",
False, False,
dt(2018, 9, 8, 19, 19), dt(2018, 9, 8, 19, 21),
None, None,
), ),
( (
@ -185,9 +185,9 @@ TEST_PARAMS = [
False, False,
"ו' מרחשוון ה' תשע\"ט", "ו' מרחשוון ה' תשע\"ט",
{ {
"hebrew_year": 5779, "hebrew_year": "5779",
"hebrew_month_name": "מרחשוון", "hebrew_month_name": "מרחשוון",
"hebrew_day": 6, "hebrew_day": "6",
"icon": "mdi:star-david", "icon": "mdi:star-david",
"friendly_name": "Jewish Calendar Date", "friendly_name": "Jewish Calendar Date",
}, },
@ -245,7 +245,7 @@ async def test_jewish_calendar_sensor(
hass.config.latitude = latitude hass.config.latitude = latitude
hass.config.longitude = longitude hass.config.longitude = longitude
with alter_time(test_time): with freeze_time(test_time):
entry = MockConfigEntry( entry = MockConfigEntry(
title=DEFAULT_NAME, title=DEFAULT_NAME,
domain=DOMAIN, domain=DOMAIN,
@ -258,7 +258,7 @@ async def test_jewish_calendar_sensor(
await hass.config_entries.async_setup(entry.entry_id) await hass.config_entries.async_setup(entry.entry_id)
await hass.async_block_till_done() await hass.async_block_till_done()
future = dt_util.utcnow() + timedelta(seconds=30) future = test_time + timedelta(seconds=30)
async_fire_time_changed(hass, future) async_fire_time_changed(hass, future)
await hass.async_block_till_done() await hass.async_block_till_done()
@ -424,9 +424,9 @@ SHABBAT_PARAMS = [
make_jerusalem_test_params( make_jerusalem_test_params(
dt(2018, 9, 29, 21, 25), dt(2018, 9, 29, 21, 25),
{ {
"english_upcoming_candle_lighting": dt(2018, 9, 30, 18, 7), "english_upcoming_candle_lighting": dt(2018, 9, 30, 17, 45),
"english_upcoming_havdalah": dt(2018, 10, 1, 19, 1), "english_upcoming_havdalah": dt(2018, 10, 1, 19, 1),
"english_upcoming_shabbat_candle_lighting": dt(2018, 10, 5, 18, 1), "english_upcoming_shabbat_candle_lighting": dt(2018, 10, 5, 17, 39),
"english_upcoming_shabbat_havdalah": dt(2018, 10, 6, 18, 54), "english_upcoming_shabbat_havdalah": dt(2018, 10, 6, 18, 54),
"english_parshat_hashavua": "Bereshit", "english_parshat_hashavua": "Bereshit",
"hebrew_parshat_hashavua": "בראשית", "hebrew_parshat_hashavua": "בראשית",
@ -437,22 +437,22 @@ SHABBAT_PARAMS = [
make_jerusalem_test_params( make_jerusalem_test_params(
dt(2018, 9, 30, 21, 25), dt(2018, 9, 30, 21, 25),
{ {
"english_upcoming_candle_lighting": dt(2018, 9, 30, 18, 7), "english_upcoming_candle_lighting": dt(2018, 9, 30, 17, 45),
"english_upcoming_havdalah": dt(2018, 10, 1, 19, 1), "english_upcoming_havdalah": dt(2018, 10, 1, 19, 1),
"english_upcoming_shabbat_candle_lighting": dt(2018, 10, 5, 18, 1), "english_upcoming_shabbat_candle_lighting": dt(2018, 10, 5, 17, 39),
"english_upcoming_shabbat_havdalah": dt(2018, 10, 6, 18, 54), "english_upcoming_shabbat_havdalah": dt(2018, 10, 6, 18, 54),
"english_parshat_hashavua": "Bereshit", "english_parshat_hashavua": "Bereshit",
"hebrew_parshat_hashavua": "בראשית", "hebrew_parshat_hashavua": "בראשית",
"english_holiday": "Shmini Atzeret", "english_holiday": "Shmini Atzeret, Simchat Torah",
"hebrew_holiday": "שמיני עצרת", "hebrew_holiday": "שמיני עצרת, שמחת תורה",
}, },
), ),
make_jerusalem_test_params( make_jerusalem_test_params(
dt(2018, 10, 1, 21, 25), dt(2018, 10, 1, 21, 25),
{ {
"english_upcoming_candle_lighting": dt(2018, 10, 5, 18, 1), "english_upcoming_candle_lighting": dt(2018, 10, 5, 17, 39),
"english_upcoming_havdalah": dt(2018, 10, 6, 18, 54), "english_upcoming_havdalah": dt(2018, 10, 6, 18, 54),
"english_upcoming_shabbat_candle_lighting": dt(2018, 10, 5, 18, 1), "english_upcoming_shabbat_candle_lighting": dt(2018, 10, 5, 17, 39),
"english_upcoming_shabbat_havdalah": dt(2018, 10, 6, 18, 54), "english_upcoming_shabbat_havdalah": dt(2018, 10, 6, 18, 54),
"english_parshat_hashavua": "Bereshit", "english_parshat_hashavua": "Bereshit",
"hebrew_parshat_hashavua": "בראשית", "hebrew_parshat_hashavua": "בראשית",
@ -487,9 +487,9 @@ SHABBAT_PARAMS = [
make_jerusalem_test_params( make_jerusalem_test_params(
dt(2017, 9, 21, 8, 25), dt(2017, 9, 21, 8, 25),
{ {
"english_upcoming_candle_lighting": dt(2017, 9, 20, 18, 20), "english_upcoming_candle_lighting": dt(2017, 9, 20, 17, 58),
"english_upcoming_havdalah": dt(2017, 9, 23, 19, 11), "english_upcoming_havdalah": dt(2017, 9, 23, 19, 11),
"english_upcoming_shabbat_candle_lighting": dt(2017, 9, 22, 19, 12), "english_upcoming_shabbat_candle_lighting": dt(2017, 9, 22, 17, 56),
"english_upcoming_shabbat_havdalah": dt(2017, 9, 23, 19, 11), "english_upcoming_shabbat_havdalah": dt(2017, 9, 23, 19, 11),
"english_parshat_hashavua": "Ha'Azinu", "english_parshat_hashavua": "Ha'Azinu",
"hebrew_parshat_hashavua": "האזינו", "hebrew_parshat_hashavua": "האזינו",
@ -500,9 +500,9 @@ SHABBAT_PARAMS = [
make_jerusalem_test_params( make_jerusalem_test_params(
dt(2017, 9, 22, 8, 25), dt(2017, 9, 22, 8, 25),
{ {
"english_upcoming_candle_lighting": dt(2017, 9, 20, 18, 20), "english_upcoming_candle_lighting": dt(2017, 9, 20, 17, 58),
"english_upcoming_havdalah": dt(2017, 9, 23, 19, 11), "english_upcoming_havdalah": dt(2017, 9, 23, 19, 11),
"english_upcoming_shabbat_candle_lighting": dt(2017, 9, 22, 19, 12), "english_upcoming_shabbat_candle_lighting": dt(2017, 9, 22, 17, 56),
"english_upcoming_shabbat_havdalah": dt(2017, 9, 23, 19, 11), "english_upcoming_shabbat_havdalah": dt(2017, 9, 23, 19, 11),
"english_parshat_hashavua": "Ha'Azinu", "english_parshat_hashavua": "Ha'Azinu",
"hebrew_parshat_hashavua": "האזינו", "hebrew_parshat_hashavua": "האזינו",
@ -513,9 +513,9 @@ SHABBAT_PARAMS = [
make_jerusalem_test_params( make_jerusalem_test_params(
dt(2017, 9, 23, 8, 25), dt(2017, 9, 23, 8, 25),
{ {
"english_upcoming_candle_lighting": dt(2017, 9, 20, 18, 20), "english_upcoming_candle_lighting": dt(2017, 9, 20, 17, 58),
"english_upcoming_havdalah": dt(2017, 9, 23, 19, 11), "english_upcoming_havdalah": dt(2017, 9, 23, 19, 11),
"english_upcoming_shabbat_candle_lighting": dt(2017, 9, 22, 19, 12), "english_upcoming_shabbat_candle_lighting": dt(2017, 9, 22, 17, 56),
"english_upcoming_shabbat_havdalah": dt(2017, 9, 23, 19, 11), "english_upcoming_shabbat_havdalah": dt(2017, 9, 23, 19, 11),
"english_parshat_hashavua": "Ha'Azinu", "english_parshat_hashavua": "Ha'Azinu",
"hebrew_parshat_hashavua": "האזינו", "hebrew_parshat_hashavua": "האזינו",
@ -587,7 +587,7 @@ async def test_shabbat_times_sensor(
hass.config.latitude = latitude hass.config.latitude = latitude
hass.config.longitude = longitude hass.config.longitude = longitude
with alter_time(test_time): with freeze_time(test_time):
entry = MockConfigEntry( entry = MockConfigEntry(
title=DEFAULT_NAME, title=DEFAULT_NAME,
domain=DOMAIN, domain=DOMAIN,
@ -604,7 +604,7 @@ async def test_shabbat_times_sensor(
await hass.config_entries.async_setup(entry.entry_id) await hass.config_entries.async_setup(entry.entry_id)
await hass.async_block_till_done() await hass.async_block_till_done()
future = dt_util.utcnow() + timedelta(seconds=30) future = test_time + timedelta(seconds=30)
async_fire_time_changed(hass, future) async_fire_time_changed(hass, future)
await hass.async_block_till_done() await hass.async_block_till_done()
@ -649,13 +649,13 @@ async def test_omer_sensor(hass: HomeAssistant, test_time, result) -> None:
"""Test Omer Count sensor output.""" """Test Omer Count sensor output."""
test_time = test_time.replace(tzinfo=dt_util.get_time_zone(hass.config.time_zone)) test_time = test_time.replace(tzinfo=dt_util.get_time_zone(hass.config.time_zone))
with alter_time(test_time): with freeze_time(test_time):
entry = MockConfigEntry(title=DEFAULT_NAME, domain=DOMAIN) entry = MockConfigEntry(title=DEFAULT_NAME, domain=DOMAIN)
entry.add_to_hass(hass) entry.add_to_hass(hass)
await hass.config_entries.async_setup(entry.entry_id) await hass.config_entries.async_setup(entry.entry_id)
await hass.async_block_till_done() await hass.async_block_till_done()
future = dt_util.utcnow() + timedelta(seconds=30) future = test_time + timedelta(seconds=30)
async_fire_time_changed(hass, future) async_fire_time_changed(hass, future)
await hass.async_block_till_done() await hass.async_block_till_done()
@ -684,13 +684,13 @@ async def test_dafyomi_sensor(hass: HomeAssistant, test_time, result) -> None:
"""Test Daf Yomi sensor output.""" """Test Daf Yomi sensor output."""
test_time = test_time.replace(tzinfo=dt_util.get_time_zone(hass.config.time_zone)) test_time = test_time.replace(tzinfo=dt_util.get_time_zone(hass.config.time_zone))
with alter_time(test_time): with freeze_time(test_time):
entry = MockConfigEntry(title=DEFAULT_NAME, domain=DOMAIN) entry = MockConfigEntry(title=DEFAULT_NAME, domain=DOMAIN)
entry.add_to_hass(hass) entry.add_to_hass(hass)
await hass.config_entries.async_setup(entry.entry_id) await hass.config_entries.async_setup(entry.entry_id)
await hass.async_block_till_done() await hass.async_block_till_done()
future = dt_util.utcnow() + timedelta(seconds=30) future = test_time + timedelta(seconds=30)
async_fire_time_changed(hass, future) async_fire_time_changed(hass, future)
await hass.async_block_till_done() await hass.async_block_till_done()