Improve boolean validator (#24294)
* Improve boolean validator * Remove extra throw * Remove None test as discussed * Fix for tests depending on None == False
This commit is contained in:
parent
233bc1a108
commit
b30f4b8fc0
5 changed files with 20 additions and 9 deletions
|
@ -6,6 +6,7 @@ import re
|
||||||
from datetime import (timedelta, datetime as datetime_sys,
|
from datetime import (timedelta, datetime as datetime_sys,
|
||||||
time as time_sys, date as date_sys)
|
time as time_sys, date as date_sys)
|
||||||
from socket import _GLOBAL_DEFAULT_TIMEOUT
|
from socket import _GLOBAL_DEFAULT_TIMEOUT
|
||||||
|
from numbers import Number
|
||||||
from typing import Any, Union, TypeVar, Callable, Sequence, Dict, Optional
|
from typing import Any, Union, TypeVar, Callable, Sequence, Dict, Optional
|
||||||
from urllib.parse import urlparse
|
from urllib.parse import urlparse
|
||||||
from uuid import UUID
|
from uuid import UUID
|
||||||
|
@ -81,14 +82,17 @@ def has_at_most_one_key(*keys: str) -> Callable:
|
||||||
|
|
||||||
def boolean(value: Any) -> bool:
|
def boolean(value: Any) -> bool:
|
||||||
"""Validate and coerce a boolean value."""
|
"""Validate and coerce a boolean value."""
|
||||||
|
if isinstance(value, bool):
|
||||||
|
return value
|
||||||
if isinstance(value, str):
|
if isinstance(value, str):
|
||||||
value = value.lower()
|
value = value.lower().strip()
|
||||||
if value in ('1', 'true', 'yes', 'on', 'enable'):
|
if value in ('1', 'true', 'yes', 'on', 'enable'):
|
||||||
return True
|
return True
|
||||||
if value in ('0', 'false', 'no', 'off', 'disable'):
|
if value in ('0', 'false', 'no', 'off', 'disable'):
|
||||||
return False
|
return False
|
||||||
|
elif isinstance(value, Number):
|
||||||
|
return value != 0
|
||||||
raise vol.Invalid('invalid boolean value {}'.format(value))
|
raise vol.Invalid('invalid boolean value {}'.format(value))
|
||||||
return bool(value)
|
|
||||||
|
|
||||||
|
|
||||||
def isdevice(value):
|
def isdevice(value):
|
||||||
|
|
|
@ -203,6 +203,7 @@ class TestDemoClimate(unittest.TestCase):
|
||||||
"""Test setting the away mode without required attribute."""
|
"""Test setting the away mode without required attribute."""
|
||||||
state = self.hass.states.get(ENTITY_CLIMATE)
|
state = self.hass.states.get(ENTITY_CLIMATE)
|
||||||
assert 'on' == state.attributes.get('away_mode')
|
assert 'on' == state.attributes.get('away_mode')
|
||||||
|
with pytest.raises(vol.Invalid):
|
||||||
common.set_away_mode(self.hass, None, ENTITY_CLIMATE)
|
common.set_away_mode(self.hass, None, ENTITY_CLIMATE)
|
||||||
self.hass.block_till_done()
|
self.hass.block_till_done()
|
||||||
assert 'on' == state.attributes.get('away_mode')
|
assert 'on' == state.attributes.get('away_mode')
|
||||||
|
@ -246,6 +247,7 @@ class TestDemoClimate(unittest.TestCase):
|
||||||
"""Test setting the auxiliary heater without required attribute."""
|
"""Test setting the auxiliary heater without required attribute."""
|
||||||
state = self.hass.states.get(ENTITY_CLIMATE)
|
state = self.hass.states.get(ENTITY_CLIMATE)
|
||||||
assert 'off' == state.attributes.get('aux_heat')
|
assert 'off' == state.attributes.get('aux_heat')
|
||||||
|
with pytest.raises(vol.Invalid):
|
||||||
common.set_aux_heat(self.hass, None, ENTITY_CLIMATE)
|
common.set_aux_heat(self.hass, None, ENTITY_CLIMATE)
|
||||||
self.hass.block_till_done()
|
self.hass.block_till_done()
|
||||||
assert 'off' == state.attributes.get('aux_heat')
|
assert 'off' == state.attributes.get('aux_heat')
|
||||||
|
|
|
@ -90,6 +90,7 @@ class TestDemoMediaPlayer(unittest.TestCase):
|
||||||
|
|
||||||
assert False is state.attributes.get('is_volume_muted')
|
assert False is state.attributes.get('is_volume_muted')
|
||||||
|
|
||||||
|
with pytest.raises(vol.Invalid):
|
||||||
common.mute_volume(self.hass, None, entity_id)
|
common.mute_volume(self.hass, None, entity_id)
|
||||||
self.hass.block_till_done()
|
self.hass.block_till_done()
|
||||||
state = self.hass.states.get(entity_id)
|
state = self.hass.states.get(entity_id)
|
||||||
|
|
|
@ -95,6 +95,7 @@ class TestDemowater_heater(unittest.TestCase):
|
||||||
"""Test setting the away mode without required attribute."""
|
"""Test setting the away mode without required attribute."""
|
||||||
state = self.hass.states.get(ENTITY_WATER_HEATER)
|
state = self.hass.states.get(ENTITY_WATER_HEATER)
|
||||||
assert 'off' == state.attributes.get('away_mode')
|
assert 'off' == state.attributes.get('away_mode')
|
||||||
|
with pytest.raises(vol.Invalid):
|
||||||
common.set_away_mode(self.hass, None, ENTITY_WATER_HEATER)
|
common.set_away_mode(self.hass, None, ENTITY_WATER_HEATER)
|
||||||
self.hass.block_till_done()
|
self.hass.block_till_done()
|
||||||
assert 'off' == state.attributes.get('away_mode')
|
assert 'off' == state.attributes.get('away_mode')
|
||||||
|
|
|
@ -17,11 +17,14 @@ def test_boolean():
|
||||||
"""Test boolean validation."""
|
"""Test boolean validation."""
|
||||||
schema = vol.Schema(cv.boolean)
|
schema = vol.Schema(cv.boolean)
|
||||||
|
|
||||||
for value in ('T', 'negative', 'lock'):
|
for value in (
|
||||||
|
None, 'T', 'negative', 'lock', 'tr ue',
|
||||||
|
[], [1, 2], {'one': 'two'}, test_boolean):
|
||||||
with pytest.raises(vol.MultipleInvalid):
|
with pytest.raises(vol.MultipleInvalid):
|
||||||
schema(value)
|
schema(value)
|
||||||
|
|
||||||
for value in ('true', 'On', '1', 'YES', 'enable', 1, True):
|
for value in ('true', 'On', '1', 'YES', ' true ',
|
||||||
|
'enable', 1, 50, True, 0.1):
|
||||||
assert schema(value)
|
assert schema(value)
|
||||||
|
|
||||||
for value in ('false', 'Off', '0', 'NO', 'disable', 0, False):
|
for value in ('false', 'Off', '0', 'NO', 'disable', 0, False):
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue