mirror of
https://github.com/home-assistant/core.git
synced 2025-07-16 09:47:13 +00:00
Add custom validator for countries (#30280)
This commit is contained in:
parent
33738cc83a
commit
d0c9a42b81
@ -367,6 +367,7 @@ homeassistant/components/websocket_api/* @home-assistant/core
|
|||||||
homeassistant/components/wemo/* @sqldiablo
|
homeassistant/components/wemo/* @sqldiablo
|
||||||
homeassistant/components/withings/* @vangorra
|
homeassistant/components/withings/* @vangorra
|
||||||
homeassistant/components/wled/* @frenck
|
homeassistant/components/wled/* @frenck
|
||||||
|
homeassistant/components/workday/* @fabaff
|
||||||
homeassistant/components/worldclock/* @fabaff
|
homeassistant/components/worldclock/* @fabaff
|
||||||
homeassistant/components/wwlln/* @bachya
|
homeassistant/components/wwlln/* @bachya
|
||||||
homeassistant/components/xbox_live/* @MartinHjelmare
|
homeassistant/components/xbox_live/* @MartinHjelmare
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
"""Sensor to indicate whether the current day is a workday."""
|
"""Sensor to indicate whether the current day is a workday."""
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
import logging
|
import logging
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
import holidays
|
import holidays
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
@ -11,111 +12,6 @@ import homeassistant.helpers.config_validation as cv
|
|||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
# List of all countries currently supported by holidays
|
|
||||||
# Source: https://github.com/dr-prodigy/python-holidays#available-countries
|
|
||||||
# There seems to be no way to get the list out at runtime
|
|
||||||
ALL_COUNTRIES = [
|
|
||||||
"Argentina",
|
|
||||||
"AR",
|
|
||||||
"Aruba",
|
|
||||||
"AW",
|
|
||||||
"Australia",
|
|
||||||
"AU",
|
|
||||||
"Austria",
|
|
||||||
"AT",
|
|
||||||
"Brazil",
|
|
||||||
"BR",
|
|
||||||
"Belarus",
|
|
||||||
"BY",
|
|
||||||
"Belgium",
|
|
||||||
"BE",
|
|
||||||
"Bulgaria",
|
|
||||||
"BG",
|
|
||||||
"Canada",
|
|
||||||
"CA",
|
|
||||||
"Colombia",
|
|
||||||
"CO",
|
|
||||||
"Croatia",
|
|
||||||
"HR",
|
|
||||||
"Czech",
|
|
||||||
"CZ",
|
|
||||||
"Denmark",
|
|
||||||
"DK",
|
|
||||||
"England",
|
|
||||||
"Estonia",
|
|
||||||
"EE",
|
|
||||||
"EuropeanCentralBank",
|
|
||||||
"ECB",
|
|
||||||
"TAR",
|
|
||||||
"Finland",
|
|
||||||
"FI",
|
|
||||||
"France",
|
|
||||||
"FRA",
|
|
||||||
"Germany",
|
|
||||||
"DE",
|
|
||||||
"Hungary",
|
|
||||||
"HU",
|
|
||||||
"Honduras",
|
|
||||||
"HND",
|
|
||||||
"Iceland",
|
|
||||||
"IS",
|
|
||||||
"India",
|
|
||||||
"IND",
|
|
||||||
"Ireland",
|
|
||||||
"IE",
|
|
||||||
"Isle of Man",
|
|
||||||
"Italy",
|
|
||||||
"IT",
|
|
||||||
"Japan",
|
|
||||||
"JP",
|
|
||||||
"Kenya",
|
|
||||||
"KE",
|
|
||||||
"Lithuania",
|
|
||||||
"LT",
|
|
||||||
"Luxembourg",
|
|
||||||
"LU",
|
|
||||||
"Mexico",
|
|
||||||
"MX",
|
|
||||||
"Netherlands",
|
|
||||||
"NL",
|
|
||||||
"NewZealand",
|
|
||||||
"NZ",
|
|
||||||
"Northern Ireland",
|
|
||||||
"Norway",
|
|
||||||
"NO",
|
|
||||||
"Peru",
|
|
||||||
"PE",
|
|
||||||
"Poland",
|
|
||||||
"Polish",
|
|
||||||
"PL",
|
|
||||||
"Portugal",
|
|
||||||
"PT",
|
|
||||||
"PortugalExt",
|
|
||||||
"PTE",
|
|
||||||
"Russia",
|
|
||||||
"RU",
|
|
||||||
"Scotland",
|
|
||||||
"Slovenia",
|
|
||||||
"SI",
|
|
||||||
"Slovakia",
|
|
||||||
"SK",
|
|
||||||
"South Africa",
|
|
||||||
"ZA",
|
|
||||||
"Spain",
|
|
||||||
"ES",
|
|
||||||
"Sweden",
|
|
||||||
"SE",
|
|
||||||
"Switzerland",
|
|
||||||
"CH",
|
|
||||||
"Ukraine",
|
|
||||||
"UA",
|
|
||||||
"UnitedKingdom",
|
|
||||||
"UK",
|
|
||||||
"UnitedStates",
|
|
||||||
"US",
|
|
||||||
"Wales",
|
|
||||||
]
|
|
||||||
|
|
||||||
ALLOWED_DAYS = WEEKDAYS + ["holiday"]
|
ALLOWED_DAYS = WEEKDAYS + ["holiday"]
|
||||||
|
|
||||||
CONF_COUNTRY = "country"
|
CONF_COUNTRY = "country"
|
||||||
@ -132,9 +28,28 @@ DEFAULT_EXCLUDES = ["sat", "sun", "holiday"]
|
|||||||
DEFAULT_NAME = "Workday Sensor"
|
DEFAULT_NAME = "Workday Sensor"
|
||||||
DEFAULT_OFFSET = 0
|
DEFAULT_OFFSET = 0
|
||||||
|
|
||||||
|
|
||||||
|
def valid_country(value: Any) -> str:
|
||||||
|
"""Validate that the given country is supported."""
|
||||||
|
value = cv.string(value)
|
||||||
|
all_supported_countries = holidays.list_supported_countries()
|
||||||
|
|
||||||
|
try:
|
||||||
|
raw_value = value.encode("utf-8")
|
||||||
|
except UnicodeError:
|
||||||
|
raise vol.Invalid(
|
||||||
|
"The country name or the abbreviation must be a valid UTF-8 string."
|
||||||
|
)
|
||||||
|
if not raw_value:
|
||||||
|
raise vol.Invalid("Country name or the abbreviation must not be empty.")
|
||||||
|
if value not in all_supported_countries:
|
||||||
|
raise vol.Invalid("Country is not supported.")
|
||||||
|
return value
|
||||||
|
|
||||||
|
|
||||||
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
|
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
|
||||||
{
|
{
|
||||||
vol.Required(CONF_COUNTRY): vol.In(ALL_COUNTRIES),
|
vol.Required(CONF_COUNTRY): valid_country,
|
||||||
vol.Optional(CONF_EXCLUDES, default=DEFAULT_EXCLUDES): vol.All(
|
vol.Optional(CONF_EXCLUDES, default=DEFAULT_EXCLUDES): vol.All(
|
||||||
cv.ensure_list, [vol.In(ALLOWED_DAYS)]
|
cv.ensure_list, [vol.In(ALLOWED_DAYS)]
|
||||||
),
|
),
|
||||||
@ -151,13 +66,13 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
|
|||||||
|
|
||||||
def setup_platform(hass, config, add_entities, discovery_info=None):
|
def setup_platform(hass, config, add_entities, discovery_info=None):
|
||||||
"""Set up the Workday sensor."""
|
"""Set up the Workday sensor."""
|
||||||
sensor_name = config.get(CONF_NAME)
|
|
||||||
country = config.get(CONF_COUNTRY)
|
|
||||||
province = config.get(CONF_PROVINCE)
|
|
||||||
workdays = config.get(CONF_WORKDAYS)
|
|
||||||
excludes = config.get(CONF_EXCLUDES)
|
|
||||||
days_offset = config.get(CONF_OFFSET)
|
|
||||||
add_holidays = config.get(CONF_ADD_HOLIDAYS)
|
add_holidays = config.get(CONF_ADD_HOLIDAYS)
|
||||||
|
country = config[CONF_COUNTRY]
|
||||||
|
days_offset = config[CONF_OFFSET]
|
||||||
|
excludes = config[CONF_EXCLUDES]
|
||||||
|
province = config.get(CONF_PROVINCE)
|
||||||
|
sensor_name = config[CONF_NAME]
|
||||||
|
workdays = config[CONF_WORKDAYS]
|
||||||
|
|
||||||
year = (get_date(datetime.today()) + timedelta(days=days_offset)).year
|
year = (get_date(datetime.today()) + timedelta(days=days_offset)).year
|
||||||
obj_holidays = getattr(holidays, country)(years=year)
|
obj_holidays = getattr(holidays, country)(years=year)
|
||||||
@ -259,7 +174,7 @@ class IsWorkdaySensor(BinarySensorDevice):
|
|||||||
# Default is no workday
|
# Default is no workday
|
||||||
self._state = False
|
self._state = False
|
||||||
|
|
||||||
# Get iso day of the week (1 = Monday, 7 = Sunday)
|
# Get ISO day of the week (1 = Monday, 7 = Sunday)
|
||||||
date = get_date(datetime.today()) + timedelta(days=self._days_offset)
|
date = get_date(datetime.today()) + timedelta(days=self._days_offset)
|
||||||
day = date.isoweekday() - 1
|
day = date.isoweekday() - 1
|
||||||
day_of_week = day_to_string(day)
|
day_of_week = day_to_string(day)
|
||||||
|
@ -3,8 +3,8 @@
|
|||||||
"name": "Workday",
|
"name": "Workday",
|
||||||
"documentation": "https://www.home-assistant.io/integrations/workday",
|
"documentation": "https://www.home-assistant.io/integrations/workday",
|
||||||
"requirements": [
|
"requirements": [
|
||||||
"holidays==0.9.11"
|
"holidays==0.9.12"
|
||||||
],
|
],
|
||||||
"dependencies": [],
|
"dependencies": [],
|
||||||
"codeowners": []
|
"codeowners": ["@fabaff"]
|
||||||
}
|
}
|
@ -663,7 +663,7 @@ hlk-sw16==0.0.7
|
|||||||
hole==0.5.0
|
hole==0.5.0
|
||||||
|
|
||||||
# homeassistant.components.workday
|
# homeassistant.components.workday
|
||||||
holidays==0.9.11
|
holidays==0.9.12
|
||||||
|
|
||||||
# homeassistant.components.frontend
|
# homeassistant.components.frontend
|
||||||
home-assistant-frontend==20191204.1
|
home-assistant-frontend==20191204.1
|
||||||
|
@ -228,7 +228,7 @@ herepy==2.0.0
|
|||||||
hole==0.5.0
|
hole==0.5.0
|
||||||
|
|
||||||
# homeassistant.components.workday
|
# homeassistant.components.workday
|
||||||
holidays==0.9.11
|
holidays==0.9.12
|
||||||
|
|
||||||
# homeassistant.components.frontend
|
# homeassistant.components.frontend
|
||||||
home-assistant-frontend==20191204.1
|
home-assistant-frontend==20191204.1
|
||||||
|
@ -2,7 +2,10 @@
|
|||||||
from datetime import date
|
from datetime import date
|
||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
|
|
||||||
from homeassistant.components.workday.binary_sensor import day_to_string
|
import pytest
|
||||||
|
import voluptuous as vol
|
||||||
|
|
||||||
|
import homeassistant.components.workday.binary_sensor as binary_sensor
|
||||||
from homeassistant.setup import setup_component
|
from homeassistant.setup import setup_component
|
||||||
|
|
||||||
from tests.common import assert_setup_component, get_test_home_assistant
|
from tests.common import assert_setup_component, get_test_home_assistant
|
||||||
@ -68,6 +71,20 @@ class TestWorkdaySetup:
|
|||||||
"""Stop everything that was started."""
|
"""Stop everything that was started."""
|
||||||
self.hass.stop()
|
self.hass.stop()
|
||||||
|
|
||||||
|
def test_valid_country(self):
|
||||||
|
"""Test topic name/filter validation."""
|
||||||
|
# Invalid UTF-8, must not contain U+D800 to U+DFFF
|
||||||
|
with pytest.raises(vol.Invalid):
|
||||||
|
binary_sensor.valid_country("\ud800")
|
||||||
|
with pytest.raises(vol.Invalid):
|
||||||
|
binary_sensor.valid_country("\udfff")
|
||||||
|
# Country MUST NOT be empty
|
||||||
|
with pytest.raises(vol.Invalid):
|
||||||
|
binary_sensor.valid_country("")
|
||||||
|
# Country must be supported by holidays
|
||||||
|
with pytest.raises(vol.Invalid):
|
||||||
|
binary_sensor.valid_country("HomeAssistantLand")
|
||||||
|
|
||||||
def test_setup_component_province(self):
|
def test_setup_component_province(self):
|
||||||
"""Set up workday component."""
|
"""Set up workday component."""
|
||||||
with assert_setup_component(1, "binary_sensor"):
|
with assert_setup_component(1, "binary_sensor"):
|
||||||
@ -214,7 +231,7 @@ class TestWorkdaySetup:
|
|||||||
|
|
||||||
def test_day_to_string(self):
|
def test_day_to_string(self):
|
||||||
"""Test if day_to_string is behaving correctly."""
|
"""Test if day_to_string is behaving correctly."""
|
||||||
assert day_to_string(0) == "mon"
|
assert binary_sensor.day_to_string(0) == "mon"
|
||||||
assert day_to_string(1) == "tue"
|
assert binary_sensor.day_to_string(1) == "tue"
|
||||||
assert day_to_string(7) == "holiday"
|
assert binary_sensor.day_to_string(7) == "holiday"
|
||||||
assert day_to_string(8) is None
|
assert binary_sensor.day_to_string(8) is None
|
||||||
|
Loading…
x
Reference in New Issue
Block a user