From dfea1c2b7c68abdcc39b87e12095dfaf6c9e87de Mon Sep 17 00:00:00 2001 From: Robert Resch Date: Wed, 11 Oct 2023 17:41:31 +0200 Subject: [PATCH] Remove NONE_SENTINEL in favor of optional select in scrape (#101278) Co-authored-by: Erik Montnemery --- .../components/scrape/config_flow.py | 48 +++++++------------ homeassistant/components/scrape/strings.json | 2 - tests/components/scrape/test_config_flow.py | 19 -------- 3 files changed, 18 insertions(+), 51 deletions(-) diff --git a/homeassistant/components/scrape/config_flow.py b/homeassistant/components/scrape/config_flow.py index dc0254cc642..b4305b3948e 100644 --- a/homeassistant/components/scrape/config_flow.py +++ b/homeassistant/components/scrape/config_flow.py @@ -97,8 +97,6 @@ RESOURCE_SETUP = { vol.Optional(CONF_ENCODING, default=DEFAULT_ENCODING): TextSelector(), } -NONE_SENTINEL = "none" - SENSOR_SETUP = { vol.Required(CONF_SELECT): TextSelector(), vol.Optional(CONF_INDEX, default=0): NumberSelector( @@ -106,45 +104,36 @@ SENSOR_SETUP = { ), vol.Optional(CONF_ATTRIBUTE): TextSelector(), vol.Optional(CONF_VALUE_TEMPLATE): TemplateSelector(), - vol.Required(CONF_DEVICE_CLASS, default=NONE_SENTINEL): SelectSelector( + vol.Optional(CONF_DEVICE_CLASS): SelectSelector( SelectSelectorConfig( - options=[NONE_SENTINEL] - + sorted( - [ - cls.value - for cls in SensorDeviceClass - if cls != SensorDeviceClass.ENUM - ] - ), + options=[ + cls.value for cls in SensorDeviceClass if cls != SensorDeviceClass.ENUM + ], mode=SelectSelectorMode.DROPDOWN, translation_key="device_class", + sort=True, ) ), - vol.Required(CONF_STATE_CLASS, default=NONE_SENTINEL): SelectSelector( + vol.Optional(CONF_STATE_CLASS): SelectSelector( SelectSelectorConfig( - options=[NONE_SENTINEL] + sorted([cls.value for cls in SensorStateClass]), + options=[cls.value for cls in SensorStateClass], mode=SelectSelectorMode.DROPDOWN, translation_key="state_class", + sort=True, ) ), - vol.Required(CONF_UNIT_OF_MEASUREMENT, default=NONE_SENTINEL): SelectSelector( + vol.Optional(CONF_UNIT_OF_MEASUREMENT): SelectSelector( SelectSelectorConfig( - options=[NONE_SENTINEL] + sorted([cls.value for cls in UnitOfTemperature]), + options=[cls.value for cls in UnitOfTemperature], custom_value=True, mode=SelectSelectorMode.DROPDOWN, translation_key="unit_of_measurement", + sort=True, ) ), } -def _strip_sentinel(options: dict[str, Any]) -> None: - """Convert sentinel to None.""" - for key in (CONF_DEVICE_CLASS, CONF_STATE_CLASS, CONF_UNIT_OF_MEASUREMENT): - if options[key] == NONE_SENTINEL: - options.pop(key) - - async def validate_rest_setup( handler: SchemaCommonFlowHandler, user_input: dict[str, Any] ) -> dict[str, Any]: @@ -171,7 +160,6 @@ async def validate_sensor_setup( # Standard behavior is to merge the result with the options. # In this case, we want to add a sub-item so we update the options directly. sensors: list[dict[str, Any]] = handler.options.setdefault(SENSOR_DOMAIN, []) - _strip_sentinel(user_input) sensors.append(user_input) return {} @@ -203,11 +191,7 @@ async def get_edit_sensor_suggested_values( ) -> dict[str, Any]: """Return suggested values for sensor editing.""" idx: int = handler.flow_state["_idx"] - suggested_values: dict[str, Any] = dict(handler.options[SENSOR_DOMAIN][idx]) - for key in (CONF_DEVICE_CLASS, CONF_STATE_CLASS, CONF_UNIT_OF_MEASUREMENT): - if not suggested_values.get(key): - suggested_values[key] = NONE_SENTINEL - return suggested_values + return dict(handler.options[SENSOR_DOMAIN][idx]) async def validate_sensor_edit( @@ -217,10 +201,14 @@ async def validate_sensor_edit( user_input[CONF_INDEX] = int(user_input[CONF_INDEX]) # Standard behavior is to merge the result with the options. - # In this case, we want to add a sub-item so we update the options directly. + # In this case, we want to add a sub-item so we update the options directly, + # including popping omitted optional schema items. idx: int = handler.flow_state["_idx"] handler.options[SENSOR_DOMAIN][idx].update(user_input) - _strip_sentinel(handler.options[SENSOR_DOMAIN][idx]) + for key in DATA_SCHEMA_EDIT_SENSOR.schema: + if isinstance(key, vol.Optional) and key not in user_input: + # Key not present, delete keys old value (if present) too + handler.options[SENSOR_DOMAIN][idx].pop(key, None) return {} diff --git a/homeassistant/components/scrape/strings.json b/homeassistant/components/scrape/strings.json index fc2d83dada4..45f48c8401e 100644 --- a/homeassistant/components/scrape/strings.json +++ b/homeassistant/components/scrape/strings.json @@ -133,7 +133,6 @@ "selector": { "device_class": { "options": { - "none": "No device class", "date": "[%key:component::sensor::entity_component::date::name%]", "duration": "[%key:component::sensor::entity_component::duration::name%]", "apparent_power": "[%key:component::sensor::entity_component::apparent_power::name%]", @@ -187,7 +186,6 @@ }, "state_class": { "options": { - "none": "No state class", "measurement": "[%key:component::sensor::entity_component::_::state_attributes::state_class::state::measurement%]", "total": "[%key:component::sensor::entity_component::_::state_attributes::state_class::state::total%]", "total_increasing": "[%key:component::sensor::entity_component::_::state_attributes::state_class::state::total_increasing%]" diff --git a/tests/components/scrape/test_config_flow.py b/tests/components/scrape/test_config_flow.py index 9e1895f3a58..7dd2954f8c3 100644 --- a/tests/components/scrape/test_config_flow.py +++ b/tests/components/scrape/test_config_flow.py @@ -8,7 +8,6 @@ from homeassistant import config_entries from homeassistant.components.rest.data import DEFAULT_TIMEOUT from homeassistant.components.rest.schema import DEFAULT_METHOD from homeassistant.components.scrape import DOMAIN -from homeassistant.components.scrape.config_flow import NONE_SENTINEL from homeassistant.components.scrape.const import ( CONF_ENCODING, CONF_INDEX, @@ -71,9 +70,6 @@ async def test_form( CONF_NAME: "Current version", CONF_SELECT: ".current-version h1", CONF_INDEX: 0.0, - CONF_DEVICE_CLASS: NONE_SENTINEL, - CONF_STATE_CLASS: NONE_SENTINEL, - CONF_UNIT_OF_MEASUREMENT: NONE_SENTINEL, }, ) await hass.async_block_till_done() @@ -132,9 +128,6 @@ async def test_form_with_post( CONF_NAME: "Current version", CONF_SELECT: ".current-version h1", CONF_INDEX: 0.0, - CONF_DEVICE_CLASS: NONE_SENTINEL, - CONF_STATE_CLASS: NONE_SENTINEL, - CONF_UNIT_OF_MEASUREMENT: NONE_SENTINEL, }, ) await hass.async_block_till_done() @@ -226,9 +219,6 @@ async def test_flow_fails( CONF_NAME: "Current version", CONF_SELECT: ".current-version h1", CONF_INDEX: 0.0, - CONF_DEVICE_CLASS: NONE_SENTINEL, - CONF_STATE_CLASS: NONE_SENTINEL, - CONF_UNIT_OF_MEASUREMENT: NONE_SENTINEL, }, ) await hass.async_block_till_done() @@ -350,9 +340,6 @@ async def test_options_add_remove_sensor_flow( CONF_NAME: "Template", CONF_SELECT: "template", CONF_INDEX: 0.0, - CONF_DEVICE_CLASS: NONE_SENTINEL, - CONF_STATE_CLASS: NONE_SENTINEL, - CONF_UNIT_OF_MEASUREMENT: NONE_SENTINEL, }, ) await hass.async_block_till_done() @@ -480,9 +467,6 @@ async def test_options_edit_sensor_flow( user_input={ CONF_SELECT: "template", CONF_INDEX: 0.0, - CONF_DEVICE_CLASS: NONE_SENTINEL, - CONF_STATE_CLASS: NONE_SENTINEL, - CONF_UNIT_OF_MEASUREMENT: NONE_SENTINEL, }, ) await hass.async_block_till_done() @@ -646,9 +630,6 @@ async def test_sensor_options_remove_device_class( CONF_SELECT: ".current-temp h3", CONF_INDEX: 0.0, CONF_VALUE_TEMPLATE: "{{ value.split(':')[1] }}", - CONF_DEVICE_CLASS: NONE_SENTINEL, - CONF_STATE_CLASS: NONE_SENTINEL, - CONF_UNIT_OF_MEASUREMENT: NONE_SENTINEL, }, ) await hass.async_block_till_done()