Fix workday blocking the event loop (#111310)

- Avoid calling list_supported_countries to setup workday
- Only call list_supported_countries in executor in the config flow
This commit is contained in:
J. Nick Koston 2024-02-24 11:22:07 -10:00 committed by GitHub
parent efc89cd34f
commit bccab1bad7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 52 additions and 32 deletions

View File

@ -1,7 +1,7 @@
"""Sensor to indicate whether the current day is a workday."""
from __future__ import annotations
from holidays import HolidayBase, country_holidays, list_supported_countries
from holidays import HolidayBase, country_holidays
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_COUNTRY, CONF_LANGUAGE
@ -12,20 +12,16 @@ from homeassistant.helpers.issue_registry import IssueSeverity, async_create_iss
from .const import CONF_PROVINCE, DOMAIN, PLATFORMS
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Set up Workday from a config entry."""
def _validate_country_and_province(
hass: HomeAssistant, entry: ConfigEntry, country: str | None, province: str | None
) -> None:
"""Validate country and province."""
country: str | None = entry.options.get(CONF_COUNTRY)
province: str | None = entry.options.get(CONF_PROVINCE)
if country and CONF_LANGUAGE not in entry.options:
cls: HolidayBase = country_holidays(country, subdiv=province)
default_language = cls.default_language
new_options = entry.options.copy()
new_options[CONF_LANGUAGE] = default_language
hass.config_entries.async_update_entry(entry, options=new_options)
if country and country not in list_supported_countries():
if not country:
return
try:
country_holidays(country)
except NotImplementedError as ex:
async_create_issue(
hass,
DOMAIN,
@ -37,9 +33,13 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
translation_placeholders={"title": entry.title},
data={"entry_id": entry.entry_id, "country": None},
)
raise ConfigEntryError(f"Selected country {country} is not valid")
raise ConfigEntryError(f"Selected country {country} is not valid") from ex
if country and province and province not in list_supported_countries()[country]:
if not province:
return
try:
country_holidays(country, prov=province)
except NotImplementedError as ex:
async_create_issue(
hass,
DOMAIN,
@ -48,17 +48,34 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
is_persistent=True,
severity=IssueSeverity.ERROR,
translation_key="bad_province",
translation_placeholders={CONF_COUNTRY: country, "title": entry.title},
translation_placeholders={
CONF_COUNTRY: country,
"title": entry.title,
},
data={"entry_id": entry.entry_id, "country": country},
)
raise ConfigEntryError(
f"Selected province {province} for country {country} is not valid"
)
) from ex
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Set up Workday from a config entry."""
country: str | None = entry.options.get(CONF_COUNTRY)
province: str | None = entry.options.get(CONF_PROVINCE)
_validate_country_and_province(hass, entry, country, province)
if country and CONF_LANGUAGE not in entry.options:
cls: HolidayBase = country_holidays(country, prov=province)
default_language = cls.default_language
new_options = entry.options.copy()
new_options[CONF_LANGUAGE] = default_language
hass.config_entries.async_update_entry(entry, options=new_options)
entry.async_on_unload(entry.add_update_listener(async_update_listener))
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
return True

View File

@ -1,6 +1,7 @@
"""Adds config flow for Workday integration."""
from __future__ import annotations
from functools import partial
from typing import Any
from holidays import HolidayBase, country_holidays, list_supported_countries
@ -141,17 +142,6 @@ def validate_custom_dates(user_input: dict[str, Any]) -> None:
raise RemoveDatesError("Incorrect date or name")
DATA_SCHEMA_SETUP = vol.Schema(
{
vol.Required(CONF_NAME, default=DEFAULT_NAME): TextSelector(),
vol.Optional(CONF_COUNTRY): CountrySelector(
CountrySelectorConfig(
countries=list(list_supported_countries(include_aliases=False)),
)
),
}
)
DATA_SCHEMA_OPT = vol.Schema(
{
vol.Optional(CONF_WORKDAYS, default=DEFAULT_WORKDAYS): SelectSelector(
@ -214,12 +204,25 @@ class WorkdayConfigFlow(ConfigFlow, domain=DOMAIN):
"""Handle the user initial step."""
errors: dict[str, str] = {}
supported_countries = await self.hass.async_add_executor_job(
partial(list_supported_countries, include_aliases=False)
)
if user_input is not None:
self.data = user_input
return await self.async_step_options()
return self.async_show_form(
step_id="user",
data_schema=DATA_SCHEMA_SETUP,
data_schema=vol.Schema(
{
vol.Required(CONF_NAME, default=DEFAULT_NAME): TextSelector(),
vol.Optional(CONF_COUNTRY): CountrySelector(
CountrySelectorConfig(
countries=list(supported_countries),
)
),
}
),
errors=errors,
)