Remove cloud dependency from islamic-prayer-times (#115146)

Co-authored-by: J. Nick Koston <nick@koston.org>
This commit is contained in:
Collin Fair
2024-04-15 15:42:33 -05:00
committed by GitHub
parent a16d98854a
commit 4aab073bd2
11 changed files with 33 additions and 179 deletions

View File

@ -683,8 +683,8 @@ build.json @home-assistant/supervisor
/homeassistant/components/iqvia/ @bachya
/tests/components/iqvia/ @bachya
/homeassistant/components/irish_rail_transport/ @ttroy50
/homeassistant/components/islamic_prayer_times/ @engrbm87
/tests/components/islamic_prayer_times/ @engrbm87
/homeassistant/components/islamic_prayer_times/ @engrbm87 @cpfair
/tests/components/islamic_prayer_times/ @engrbm87 @cpfair
/homeassistant/components/iss/ @DurgNomis-drol
/tests/components/iss/ @DurgNomis-drol
/homeassistant/components/isy994/ @bdraco @shbatm

View File

@ -4,8 +4,6 @@ from __future__ import annotations
from typing import Any
from prayer_times_calculator import InvalidResponseError, PrayerTimesCalculator
from requests.exceptions import ConnectionError as ConnError
import voluptuous as vol
from homeassistant.config_entries import (
@ -15,7 +13,7 @@ from homeassistant.config_entries import (
OptionsFlow,
)
from homeassistant.const import CONF_LATITUDE, CONF_LOCATION, CONF_LONGITUDE, CONF_NAME
from homeassistant.core import HomeAssistant, callback
from homeassistant.core import callback
from homeassistant.helpers.selector import (
LocationSelector,
SelectSelector,
@ -23,7 +21,6 @@ from homeassistant.helpers.selector import (
SelectSelectorMode,
TextSelector,
)
import homeassistant.util.dt as dt_util
from .const import (
CALC_METHODS,
@ -43,26 +40,6 @@ from .const import (
)
async def async_validate_location(
hass: HomeAssistant, lat: float, lon: float
) -> dict[str, str]:
"""Check if the selected location is valid."""
errors = {}
calc = PrayerTimesCalculator(
latitude=lat,
longitude=lon,
calculation_method=DEFAULT_CALC_METHOD,
date=str(dt_util.now().date()),
)
try:
await hass.async_add_executor_job(calc.fetch_prayer_times)
except InvalidResponseError:
errors["base"] = "invalid_location"
except ConnError:
errors["base"] = "conn_error"
return errors
class IslamicPrayerFlowHandler(ConfigFlow, domain=DOMAIN):
"""Handle the Islamic Prayer config flow."""
@ -81,7 +58,6 @@ class IslamicPrayerFlowHandler(ConfigFlow, domain=DOMAIN):
self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult:
"""Handle a flow initialized by the user."""
errors = {}
if user_input is not None:
lat: float = user_input[CONF_LOCATION][CONF_LATITUDE]
@ -89,14 +65,13 @@ class IslamicPrayerFlowHandler(ConfigFlow, domain=DOMAIN):
await self.async_set_unique_id(f"{lat}-{lon}")
self._abort_if_unique_id_configured()
if not (errors := await async_validate_location(self.hass, lat, lon)):
return self.async_create_entry(
title=user_input[CONF_NAME],
data={
CONF_LATITUDE: lat,
CONF_LONGITUDE: lon,
},
)
return self.async_create_entry(
title=user_input[CONF_NAME],
data={
CONF_LATITUDE: lat,
CONF_LONGITUDE: lon,
},
)
home_location = {
CONF_LATITUDE: self.hass.config.latitude,
@ -112,7 +87,6 @@ class IslamicPrayerFlowHandler(ConfigFlow, domain=DOMAIN):
): LocationSelector(),
}
),
errors=errors,
)

View File

@ -6,14 +6,13 @@ from datetime import datetime, timedelta
import logging
from typing import Any, cast
from prayer_times_calculator import PrayerTimesCalculator, exceptions
from requests.exceptions import ConnectionError as ConnError
from prayer_times_calculator_offline import PrayerTimesCalculator
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_LATITUDE, CONF_LONGITUDE
from homeassistant.core import CALLBACK_TYPE, HomeAssistant, callback
from homeassistant.helpers.event import async_call_later, async_track_point_in_time
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
from homeassistant.helpers.event import async_track_point_in_time
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
import homeassistant.util.dt as dt_util
from .const import (
@ -142,13 +141,7 @@ class IslamicPrayerDataUpdateCoordinator(DataUpdateCoordinator[dict[str, datetim
async def _async_update_data(self) -> dict[str, datetime]:
"""Update sensors with new prayer times."""
try:
prayer_times = await self.hass.async_add_executor_job(
self.get_new_prayer_times
)
except (exceptions.InvalidResponseError, ConnError) as err:
async_call_later(self.hass, 60, self.async_request_update)
raise UpdateFailed from err
prayer_times = self.get_new_prayer_times()
# introduced in prayer-times-calculator 0.0.8
prayer_times.pop("date", None)

View File

@ -1,10 +1,10 @@
{
"domain": "islamic_prayer_times",
"name": "Islamic Prayer Times",
"codeowners": ["@engrbm87"],
"codeowners": ["@engrbm87", "@cpfair"],
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/islamic_prayer_times",
"iot_class": "cloud_polling",
"iot_class": "calculated",
"loggers": ["prayer_times_calculator"],
"requirements": ["prayer-times-calculator==0.0.12"]
"requirements": ["prayer-times-calculator-offline==1.0.3"]
}

View File

@ -2879,7 +2879,7 @@
"islamic_prayer_times": {
"integration_type": "hub",
"config_flow": true,
"iot_class": "cloud_polling"
"iot_class": "calculated"
},
"ismartwindow": {
"name": "iSmartWindow",

View File

@ -1556,7 +1556,7 @@ poolsense==0.0.8
praw==7.5.0
# homeassistant.components.islamic_prayer_times
prayer-times-calculator==0.0.12
prayer-times-calculator-offline==1.0.3
# homeassistant.components.proliphix
proliphix==0.4.1

View File

@ -1227,7 +1227,7 @@ poolsense==0.0.8
praw==7.5.0
# homeassistant.components.islamic_prayer_times
prayer-times-calculator==0.0.12
prayer-times-calculator-offline==1.0.3
# homeassistant.components.prometheus
prometheus-client==0.17.1

View File

@ -22,14 +22,4 @@ PRAYER_TIMES = {
"Midnight": "2020-01-01T00:45:00+00:00",
}
NEW_PRAYER_TIMES = {
"Fajr": "2020-01-02T06:00:00+00:00",
"Sunrise": "2020-01-02T07:25:00+00:00",
"Dhuhr": "2020-01-02T12:30:00+00:00",
"Asr": "2020-01-02T15:32:00+00:00",
"Maghrib": "2020-01-02T17:45:00+00:00",
"Isha": "2020-01-02T18:53:00+00:00",
"Midnight": "2020-01-02T00:43:00+00:00",
}
NOW = datetime(2020, 1, 1, 00, 00, 0, tzinfo=dt_util.UTC)

View File

@ -1,10 +1,6 @@
"""Tests for Islamic Prayer Times config flow."""
from unittest.mock import patch
from prayer_times_calculator import InvalidResponseError
import pytest
from requests.exceptions import ConnectionError as ConnError
from homeassistant import config_entries
from homeassistant.components import islamic_prayer_times
@ -33,49 +29,15 @@ async def test_flow_works(hass: HomeAssistant) -> None:
assert result["type"] is FlowResultType.FORM
assert result["step_id"] == "user"
with patch(
"homeassistant.components.islamic_prayer_times.config_flow.async_validate_location",
return_value={},
):
result = await hass.config_entries.flow.async_configure(
result["flow_id"], user_input=MOCK_USER_INPUT
)
await hass.async_block_till_done()
result = await hass.config_entries.flow.async_configure(
result["flow_id"], user_input=MOCK_USER_INPUT
)
await hass.async_block_till_done()
assert result["type"] is FlowResultType.CREATE_ENTRY
assert result["title"] == "Home"
@pytest.mark.parametrize(
("exception", "error"),
[
(InvalidResponseError, "invalid_location"),
(ConnError, "conn_error"),
],
)
async def test_flow_error(
hass: HomeAssistant, exception: Exception, error: str
) -> None:
"""Test flow errors."""
result = await hass.config_entries.flow.async_init(
islamic_prayer_times.DOMAIN, context={"source": config_entries.SOURCE_USER}
)
assert result["type"] is FlowResultType.FORM
assert result["step_id"] == "user"
with patch(
"homeassistant.components.islamic_prayer_times.config_flow.PrayerTimesCalculator.fetch_prayer_times",
side_effect=exception,
):
result = await hass.config_entries.flow.async_configure(
result["flow_id"], user_input=MOCK_USER_INPUT
)
await hass.async_block_till_done()
assert result["type"] is FlowResultType.FORM
assert result["errors"]["base"] == error
async def test_options(hass: HomeAssistant) -> None:
"""Test updating options."""
entry = MockConfigEntry(

View File

@ -1,24 +1,21 @@
"""Tests for Islamic Prayer Times init."""
from datetime import timedelta
from unittest.mock import patch
from freezegun import freeze_time
from prayer_times_calculator.exceptions import InvalidResponseError
import pytest
from homeassistant.components import islamic_prayer_times
from homeassistant.components.islamic_prayer_times.const import CONF_CALC_METHOD
from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN
from homeassistant.config_entries import ConfigEntryState
from homeassistant.const import CONF_LATITUDE, CONF_LONGITUDE, STATE_UNAVAILABLE
from homeassistant.const import CONF_LATITUDE, CONF_LONGITUDE
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er
import homeassistant.util.dt as dt_util
from . import NEW_PRAYER_TIMES, NOW, PRAYER_TIMES
from . import NOW, PRAYER_TIMES
from tests.common import MockConfigEntry, async_fire_time_changed
from tests.common import MockConfigEntry
@pytest.fixture(autouse=True)
@ -37,7 +34,7 @@ async def test_successful_config_entry(hass: HomeAssistant) -> None:
entry.add_to_hass(hass)
with patch(
"prayer_times_calculator.PrayerTimesCalculator.fetch_prayer_times",
"prayer_times_calculator_offline.PrayerTimesCalculator.fetch_prayer_times",
return_value=PRAYER_TIMES,
):
await hass.config_entries.async_setup(entry.entry_id)
@ -46,25 +43,6 @@ async def test_successful_config_entry(hass: HomeAssistant) -> None:
assert entry.state is ConfigEntryState.LOADED
async def test_setup_failed(hass: HomeAssistant) -> None:
"""Test Islamic Prayer Times failed due to an error."""
entry = MockConfigEntry(
domain=islamic_prayer_times.DOMAIN,
data={},
)
entry.add_to_hass(hass)
# test request error raising ConfigEntryNotReady
with patch(
"prayer_times_calculator.PrayerTimesCalculator.fetch_prayer_times",
side_effect=InvalidResponseError(),
):
await hass.config_entries.async_setup(entry.entry_id)
await hass.async_block_till_done()
assert entry.state is ConfigEntryState.SETUP_RETRY
async def test_unload_entry(hass: HomeAssistant) -> None:
"""Test removing Islamic Prayer Times."""
entry = MockConfigEntry(
@ -74,7 +52,7 @@ async def test_unload_entry(hass: HomeAssistant) -> None:
entry.add_to_hass(hass)
with patch(
"prayer_times_calculator.PrayerTimesCalculator.fetch_prayer_times",
"prayer_times_calculator_offline.PrayerTimesCalculator.fetch_prayer_times",
return_value=PRAYER_TIMES,
):
await hass.config_entries.async_setup(entry.entry_id)
@ -91,7 +69,7 @@ async def test_options_listener(hass: HomeAssistant) -> None:
with (
patch(
"prayer_times_calculator.PrayerTimesCalculator.fetch_prayer_times",
"prayer_times_calculator_offline.PrayerTimesCalculator.fetch_prayer_times",
return_value=PRAYER_TIMES,
) as mock_fetch_prayer_times,
freeze_time(NOW),
@ -107,49 +85,6 @@ async def test_options_listener(hass: HomeAssistant) -> None:
assert mock_fetch_prayer_times.call_count == 2
async def test_update_failed(hass: HomeAssistant) -> None:
"""Test integrations tries to update after 1 min if update fails."""
entry = MockConfigEntry(domain=islamic_prayer_times.DOMAIN, data={})
entry.add_to_hass(hass)
with (
patch(
"prayer_times_calculator.PrayerTimesCalculator.fetch_prayer_times",
return_value=PRAYER_TIMES,
),
freeze_time(NOW),
):
await hass.config_entries.async_setup(entry.entry_id)
await hass.async_block_till_done()
assert entry.state is ConfigEntryState.LOADED
with patch(
"prayer_times_calculator.PrayerTimesCalculator.fetch_prayer_times"
) as FetchPrayerTimes:
FetchPrayerTimes.side_effect = [
InvalidResponseError,
NEW_PRAYER_TIMES,
]
midnight_time = dt_util.parse_datetime(PRAYER_TIMES["Midnight"])
assert midnight_time
future = midnight_time + timedelta(days=1, minutes=1)
with freeze_time(future):
async_fire_time_changed(hass, future)
await hass.async_block_till_done()
state = hass.states.get("sensor.islamic_prayer_times_fajr_prayer")
assert state.state == STATE_UNAVAILABLE
# coordinator tries to update after 1 minute
future = future + timedelta(minutes=1)
with freeze_time(future):
async_fire_time_changed(hass, future)
await hass.async_block_till_done()
state = hass.states.get("sensor.islamic_prayer_times_fajr_prayer")
assert state.state == "2020-01-02T06:00:00+00:00"
@pytest.mark.parametrize(
("object_id", "old_unique_id"),
[
@ -184,7 +119,7 @@ async def test_migrate_unique_id(
with (
patch(
"prayer_times_calculator.PrayerTimesCalculator.fetch_prayer_times",
"prayer_times_calculator_offline.PrayerTimesCalculator.fetch_prayer_times",
return_value=PRAYER_TIMES,
),
freeze_time(NOW),
@ -207,7 +142,7 @@ async def test_migration_from_1_1_to_1_2(hass: HomeAssistant) -> None:
with (
patch(
"prayer_times_calculator.PrayerTimesCalculator.fetch_prayer_times",
"prayer_times_calculator_offline.PrayerTimesCalculator.fetch_prayer_times",
return_value=PRAYER_TIMES,
),
freeze_time(NOW),

View File

@ -40,7 +40,7 @@ async def test_islamic_prayer_times_sensors(
with (
patch(
"prayer_times_calculator.PrayerTimesCalculator.fetch_prayer_times",
"prayer_times_calculator_offline.PrayerTimesCalculator.fetch_prayer_times",
return_value=PRAYER_TIMES,
),
freeze_time(NOW),