mirror of
https://github.com/home-assistant/core.git
synced 2025-07-16 09:47:13 +00:00
Improve code quality workday (#66446)
* Code quality workday * Modify from review * Modify from review 2 * Fix mypy
This commit is contained in:
parent
fa8238bc04
commit
abc73ff2e1
@ -1,14 +1,18 @@
|
|||||||
"""Sensor to indicate whether the current day is a workday."""
|
"""Sensor to indicate whether the current day is a workday."""
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from datetime import timedelta
|
from datetime import date, timedelta
|
||||||
import logging
|
import logging
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
import holidays
|
import holidays
|
||||||
|
from holidays import HolidayBase
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
from homeassistant.components.binary_sensor import PLATFORM_SCHEMA, BinarySensorEntity
|
from homeassistant.components.binary_sensor import (
|
||||||
|
PLATFORM_SCHEMA as PARENT_PLATFORM_SCHEMA,
|
||||||
|
BinarySensorEntity,
|
||||||
|
)
|
||||||
from homeassistant.const import CONF_NAME, WEEKDAYS
|
from homeassistant.const import CONF_NAME, WEEKDAYS
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
import homeassistant.helpers.config_validation as cv
|
import homeassistant.helpers.config_validation as cv
|
||||||
@ -54,7 +58,7 @@ def valid_country(value: Any) -> str:
|
|||||||
return value
|
return value
|
||||||
|
|
||||||
|
|
||||||
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
|
PLATFORM_SCHEMA = PARENT_PLATFORM_SCHEMA.extend(
|
||||||
{
|
{
|
||||||
vol.Required(CONF_COUNTRY): valid_country,
|
vol.Required(CONF_COUNTRY): valid_country,
|
||||||
vol.Optional(CONF_EXCLUDES, default=DEFAULT_EXCLUDES): vol.All(
|
vol.Optional(CONF_EXCLUDES, default=DEFAULT_EXCLUDES): vol.All(
|
||||||
@ -83,17 +87,17 @@ def setup_platform(
|
|||||||
discovery_info: DiscoveryInfoType | None = None,
|
discovery_info: DiscoveryInfoType | None = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Set up the Workday sensor."""
|
"""Set up the Workday sensor."""
|
||||||
add_holidays = config[CONF_ADD_HOLIDAYS]
|
add_holidays: list[str] = config[CONF_ADD_HOLIDAYS]
|
||||||
remove_holidays = config[CONF_REMOVE_HOLIDAYS]
|
remove_holidays: list[str] = config[CONF_REMOVE_HOLIDAYS]
|
||||||
country = config[CONF_COUNTRY]
|
country: str = config[CONF_COUNTRY]
|
||||||
days_offset = config[CONF_OFFSET]
|
days_offset: int = config[CONF_OFFSET]
|
||||||
excludes = config[CONF_EXCLUDES]
|
excludes: list[str] = config[CONF_EXCLUDES]
|
||||||
province = config.get(CONF_PROVINCE)
|
province: str | None = config.get(CONF_PROVINCE)
|
||||||
sensor_name = config[CONF_NAME]
|
sensor_name: str = config[CONF_NAME]
|
||||||
workdays = config[CONF_WORKDAYS]
|
workdays: list[str] = config[CONF_WORKDAYS]
|
||||||
|
|
||||||
year = (get_date(dt.now()) + timedelta(days=days_offset)).year
|
year: int = (get_date(dt.now()) + timedelta(days=days_offset)).year
|
||||||
obj_holidays = getattr(holidays, country)(years=year)
|
obj_holidays: HolidayBase = getattr(holidays, country)(years=year)
|
||||||
|
|
||||||
if province:
|
if province:
|
||||||
if (
|
if (
|
||||||
@ -113,27 +117,29 @@ def setup_platform(
|
|||||||
|
|
||||||
# Remove holidays
|
# Remove holidays
|
||||||
try:
|
try:
|
||||||
for date in remove_holidays:
|
for remove_holiday in remove_holidays:
|
||||||
try:
|
try:
|
||||||
# is this formatted as a date?
|
# is this formatted as a date?
|
||||||
if dt.parse_date(date):
|
if dt.parse_date(remove_holiday):
|
||||||
# remove holiday by date
|
# remove holiday by date
|
||||||
removed = obj_holidays.pop(date)
|
removed = obj_holidays.pop(remove_holiday)
|
||||||
_LOGGER.debug("Removed %s", date)
|
_LOGGER.debug("Removed %s", remove_holiday)
|
||||||
else:
|
else:
|
||||||
# remove holiday by name
|
# remove holiday by name
|
||||||
_LOGGER.debug("Treating '%s' as named holiday", date)
|
_LOGGER.debug("Treating '%s' as named holiday", remove_holiday)
|
||||||
removed = obj_holidays.pop_named(date)
|
removed = obj_holidays.pop_named(remove_holiday)
|
||||||
for holiday in removed:
|
for holiday in removed:
|
||||||
_LOGGER.debug("Removed %s by name '%s'", holiday, date)
|
_LOGGER.debug(
|
||||||
|
"Removed %s by name '%s'", holiday, remove_holiday
|
||||||
|
)
|
||||||
except KeyError as unmatched:
|
except KeyError as unmatched:
|
||||||
_LOGGER.warning("No holiday found matching %s", unmatched)
|
_LOGGER.warning("No holiday found matching %s", unmatched)
|
||||||
except TypeError:
|
except TypeError:
|
||||||
_LOGGER.debug("No holidays to remove or invalid holidays")
|
_LOGGER.debug("No holidays to remove or invalid holidays")
|
||||||
|
|
||||||
_LOGGER.debug("Found the following holidays for your configuration:")
|
_LOGGER.debug("Found the following holidays for your configuration:")
|
||||||
for date, name in sorted(obj_holidays.items()):
|
for remove_holiday, name in sorted(obj_holidays.items()):
|
||||||
_LOGGER.debug("%s %s", date, name)
|
_LOGGER.debug("%s %s", remove_holiday, name)
|
||||||
|
|
||||||
add_entities(
|
add_entities(
|
||||||
[IsWorkdaySensor(obj_holidays, workdays, excludes, days_offset, sensor_name)],
|
[IsWorkdaySensor(obj_holidays, workdays, excludes, days_offset, sensor_name)],
|
||||||
@ -141,7 +147,7 @@ def setup_platform(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def day_to_string(day):
|
def day_to_string(day: int) -> str | None:
|
||||||
"""Convert day index 0 - 7 to string."""
|
"""Convert day index 0 - 7 to string."""
|
||||||
try:
|
try:
|
||||||
return ALLOWED_DAYS[day]
|
return ALLOWED_DAYS[day]
|
||||||
@ -149,34 +155,35 @@ def day_to_string(day):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def get_date(date):
|
def get_date(input_date: date) -> date:
|
||||||
"""Return date. Needed for testing."""
|
"""Return date. Needed for testing."""
|
||||||
return date
|
return input_date
|
||||||
|
|
||||||
|
|
||||||
class IsWorkdaySensor(BinarySensorEntity):
|
class IsWorkdaySensor(BinarySensorEntity):
|
||||||
"""Implementation of a Workday sensor."""
|
"""Implementation of a Workday sensor."""
|
||||||
|
|
||||||
def __init__(self, obj_holidays, workdays, excludes, days_offset, name):
|
def __init__(
|
||||||
|
self,
|
||||||
|
obj_holidays: HolidayBase,
|
||||||
|
workdays: list[str],
|
||||||
|
excludes: list[str],
|
||||||
|
days_offset: int,
|
||||||
|
name: str,
|
||||||
|
) -> None:
|
||||||
"""Initialize the Workday sensor."""
|
"""Initialize the Workday sensor."""
|
||||||
self._name = name
|
self._attr_name = name
|
||||||
self._obj_holidays = obj_holidays
|
self._obj_holidays = obj_holidays
|
||||||
self._workdays = workdays
|
self._workdays = workdays
|
||||||
self._excludes = excludes
|
self._excludes = excludes
|
||||||
self._days_offset = days_offset
|
self._days_offset = days_offset
|
||||||
self._state = None
|
self._attr_extra_state_attributes = {
|
||||||
|
CONF_WORKDAYS: workdays,
|
||||||
|
CONF_EXCLUDES: excludes,
|
||||||
|
CONF_OFFSET: days_offset,
|
||||||
|
}
|
||||||
|
|
||||||
@property
|
def is_include(self, day: str, now: date) -> bool:
|
||||||
def name(self):
|
|
||||||
"""Return the name of the sensor."""
|
|
||||||
return self._name
|
|
||||||
|
|
||||||
@property
|
|
||||||
def is_on(self):
|
|
||||||
"""Return the state of the device."""
|
|
||||||
return self._state
|
|
||||||
|
|
||||||
def is_include(self, day, now):
|
|
||||||
"""Check if given day is in the includes list."""
|
"""Check if given day is in the includes list."""
|
||||||
if day in self._workdays:
|
if day in self._workdays:
|
||||||
return True
|
return True
|
||||||
@ -185,7 +192,7 @@ class IsWorkdaySensor(BinarySensorEntity):
|
|||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def is_exclude(self, day, now):
|
def is_exclude(self, day: str, now: date) -> bool:
|
||||||
"""Check if given day is in the excludes list."""
|
"""Check if given day is in the excludes list."""
|
||||||
if day in self._excludes:
|
if day in self._excludes:
|
||||||
return True
|
return True
|
||||||
@ -194,28 +201,21 @@ class IsWorkdaySensor(BinarySensorEntity):
|
|||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@property
|
async def async_update(self) -> None:
|
||||||
def extra_state_attributes(self):
|
|
||||||
"""Return the attributes of the entity."""
|
|
||||||
# return self._attributes
|
|
||||||
return {
|
|
||||||
CONF_WORKDAYS: self._workdays,
|
|
||||||
CONF_EXCLUDES: self._excludes,
|
|
||||||
CONF_OFFSET: self._days_offset,
|
|
||||||
}
|
|
||||||
|
|
||||||
async def async_update(self):
|
|
||||||
"""Get date and look whether it is a holiday."""
|
"""Get date and look whether it is a holiday."""
|
||||||
# Default is no workday
|
# Default is no workday
|
||||||
self._state = False
|
self._attr_is_on = False
|
||||||
|
|
||||||
# Get ISO day of the week (1 = Monday, 7 = Sunday)
|
# Get ISO day of the week (1 = Monday, 7 = Sunday)
|
||||||
date = get_date(dt.now()) + timedelta(days=self._days_offset)
|
adjusted_date = get_date(dt.now()) + timedelta(days=self._days_offset)
|
||||||
day = date.isoweekday() - 1
|
day = adjusted_date.isoweekday() - 1
|
||||||
day_of_week = day_to_string(day)
|
day_of_week = day_to_string(day)
|
||||||
|
|
||||||
if self.is_include(day_of_week, date):
|
if day_of_week is None:
|
||||||
self._state = True
|
return
|
||||||
|
|
||||||
if self.is_exclude(day_of_week, date):
|
if self.is_include(day_of_week, adjusted_date):
|
||||||
self._state = False
|
self._attr_is_on = True
|
||||||
|
|
||||||
|
if self.is_exclude(day_of_week, adjusted_date):
|
||||||
|
self._attr_is_on = False
|
||||||
|
Loading…
x
Reference in New Issue
Block a user