Skip to content

Commit d527113

Browse files
authored
Improve schema typing (3) (#120521)
1 parent afbd24a commit d527113

File tree

10 files changed

+44
-35
lines changed

10 files changed

+44
-35
lines changed

homeassistant/components/input_button/__init__.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,9 @@ class InputButtonStorageCollection(collection.DictStorageCollection):
5858

5959
CREATE_UPDATE_SCHEMA = vol.Schema(STORAGE_FIELDS)
6060

61-
async def _process_create_data(self, data: dict) -> vol.Schema:
61+
async def _process_create_data(self, data: dict) -> dict[str, str]:
6262
"""Validate the config is valid."""
63-
return self.CREATE_UPDATE_SCHEMA(data)
63+
return self.CREATE_UPDATE_SCHEMA(data) # type: ignore[no-any-return]
6464

6565
@callback
6666
def _get_suggested_id(self, info: dict) -> str:

homeassistant/components/input_text/__init__.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -163,9 +163,9 @@ class InputTextStorageCollection(collection.DictStorageCollection):
163163

164164
CREATE_UPDATE_SCHEMA = vol.Schema(vol.All(STORAGE_FIELDS, _cv_input_text))
165165

166-
async def _process_create_data(self, data: dict[str, Any]) -> vol.Schema:
166+
async def _process_create_data(self, data: dict[str, Any]) -> dict[str, Any]:
167167
"""Validate the config is valid."""
168-
return self.CREATE_UPDATE_SCHEMA(data)
168+
return self.CREATE_UPDATE_SCHEMA(data) # type: ignore[no-any-return]
169169

170170
@callback
171171
def _get_suggested_id(self, info: dict[str, Any]) -> str:

homeassistant/components/light/__init__.py

+4-2
Original file line numberDiff line numberDiff line change
@@ -302,7 +302,7 @@ def is_on(hass: HomeAssistant, entity_id: str) -> bool:
302302

303303

304304
def preprocess_turn_on_alternatives(
305-
hass: HomeAssistant, params: dict[str, Any]
305+
hass: HomeAssistant, params: dict[str, Any] | dict[str | vol.Optional, Any]
306306
) -> None:
307307
"""Process extra data for turn light on request.
308308
@@ -406,7 +406,9 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: # noqa:
406406
# of the light base platform.
407407
hass.async_create_task(profiles.async_initialize(), eager_start=True)
408408

409-
def preprocess_data(data: dict[str, Any]) -> dict[str | vol.Optional, Any]:
409+
def preprocess_data(
410+
data: dict[str | vol.Optional, Any],
411+
) -> dict[str | vol.Optional, Any]:
410412
"""Preprocess the service data."""
411413
base: dict[str | vol.Optional, Any] = {
412414
entity_field: data.pop(entity_field)

homeassistant/components/motioneye/config_flow.py

+5-3
Original file line numberDiff line numberDiff line change
@@ -226,14 +226,16 @@ async def async_step_init(
226226
if self.show_advanced_options:
227227
# The input URL is not validated as being a URL, to allow for the possibility
228228
# the template input won't be a valid URL until after it's rendered
229-
stream_kwargs = {}
229+
description: dict[str, str] | None = None
230230
if CONF_STREAM_URL_TEMPLATE in self._config_entry.options:
231-
stream_kwargs["description"] = {
231+
description = {
232232
"suggested_value": self._config_entry.options[
233233
CONF_STREAM_URL_TEMPLATE
234234
]
235235
}
236236

237-
schema[vol.Optional(CONF_STREAM_URL_TEMPLATE, **stream_kwargs)] = str
237+
schema[vol.Optional(CONF_STREAM_URL_TEMPLATE, description=description)] = (
238+
str
239+
)
238240

239241
return self.async_show_form(step_id="init", data_schema=vol.Schema(schema))

homeassistant/components/zha/device_action.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -167,8 +167,9 @@ async def async_get_action_capabilities(
167167
hass: HomeAssistant, config: ConfigType
168168
) -> dict[str, vol.Schema]:
169169
"""List action capabilities."""
170-
171-
return {"extra_fields": DEVICE_ACTION_SCHEMAS.get(config[CONF_TYPE], {})}
170+
if (fields := DEVICE_ACTION_SCHEMAS.get(config[CONF_TYPE])) is None:
171+
return {}
172+
return {"extra_fields": fields}
172173

173174

174175
async def _execute_service_based_action(

homeassistant/components/zwave_js/triggers/event.py

+2-4
Original file line numberDiff line numberDiff line change
@@ -80,10 +80,8 @@ def validate_event_data(obj: dict) -> dict:
8080
except ValidationError as exc:
8181
# Filter out required field errors if keys can be missing, and if there are
8282
# still errors, raise an exception
83-
if errors := [
84-
error for error in exc.errors() if error["type"] != "value_error.missing"
85-
]:
86-
raise vol.MultipleInvalid(errors) from exc
83+
if [error for error in exc.errors() if error["type"] != "value_error.missing"]:
84+
raise vol.MultipleInvalid from exc
8785
return obj
8886

8987

homeassistant/data_entry_flow.py

+5-4
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,15 @@
55
import abc
66
import asyncio
77
from collections import defaultdict
8-
from collections.abc import Callable, Container, Iterable, Mapping
8+
from collections.abc import Callable, Container, Hashable, Iterable, Mapping
99
from contextlib import suppress
1010
import copy
1111
from dataclasses import dataclass
1212
from enum import StrEnum
1313
from functools import partial
1414
import logging
1515
from types import MappingProxyType
16-
from typing import Any, Generic, Required, TypedDict
16+
from typing import Any, Generic, Required, TypedDict, cast
1717

1818
from typing_extensions import TypeVar
1919
import voluptuous as vol
@@ -120,7 +120,7 @@ class InvalidData(vol.Invalid): # type: ignore[misc]
120120
def __init__(
121121
self,
122122
message: str,
123-
path: list[str | vol.Marker] | None,
123+
path: list[Hashable] | None,
124124
error_message: str | None,
125125
schema_errors: dict[str, Any],
126126
**kwargs: Any,
@@ -384,6 +384,7 @@ async def _async_configure(
384384
if (
385385
data_schema := cur_step.get("data_schema")
386386
) is not None and user_input is not None:
387+
data_schema = cast(vol.Schema, data_schema)
387388
try:
388389
user_input = data_schema(user_input) # type: ignore[operator]
389390
except vol.Invalid as ex:
@@ -694,7 +695,7 @@ def add_suggested_values_to_schema(
694695
):
695696
# Copy the marker to not modify the flow schema
696697
new_key = copy.copy(key)
697-
new_key.description = {"suggested_value": suggested_values[key]}
698+
new_key.description = {"suggested_value": suggested_values[key.schema]}
698699
schema[new_key] = val
699700
return vol.Schema(schema)
700701

homeassistant/helpers/config_validation.py

+6-6
Original file line numberDiff line numberDiff line change
@@ -981,7 +981,7 @@ def removed(
981981

982982
def key_value_schemas(
983983
key: str,
984-
value_schemas: dict[Hashable, VolSchemaType],
984+
value_schemas: dict[Hashable, VolSchemaType | Callable[[Any], dict[str, Any]]],
985985
default_schema: VolSchemaType | None = None,
986986
default_description: str | None = None,
987987
) -> Callable[[Any], dict[Hashable, Any]]:
@@ -1016,12 +1016,12 @@ def key_value_validator(value: Any) -> dict[Hashable, Any]:
10161016
# Validator helpers
10171017

10181018

1019-
def key_dependency(
1019+
def key_dependency[_KT: Hashable, _VT](
10201020
key: Hashable, dependency: Hashable
1021-
) -> Callable[[dict[Hashable, Any]], dict[Hashable, Any]]:
1021+
) -> Callable[[dict[_KT, _VT]], dict[_KT, _VT]]:
10221022
"""Validate that all dependencies exist for key."""
10231023

1024-
def validator(value: dict[Hashable, Any]) -> dict[Hashable, Any]:
1024+
def validator(value: dict[_KT, _VT]) -> dict[_KT, _VT]:
10251025
"""Test dependencies."""
10261026
if not isinstance(value, dict):
10271027
raise vol.Invalid("key dependencies require a dict")
@@ -1405,13 +1405,13 @@ def script_action(value: Any) -> dict:
14051405
)
14061406

14071407

1408-
def STATE_CONDITION_SCHEMA(value: Any) -> dict:
1408+
def STATE_CONDITION_SCHEMA(value: Any) -> dict[str, Any]:
14091409
"""Validate a state condition."""
14101410
if not isinstance(value, dict):
14111411
raise vol.Invalid("Expected a dictionary")
14121412

14131413
if CONF_ATTRIBUTE in value:
1414-
validated: dict = STATE_CONDITION_ATTRIBUTE_SCHEMA(value)
1414+
validated: dict[str, Any] = STATE_CONDITION_ATTRIBUTE_SCHEMA(value)
14151415
else:
14161416
validated = STATE_CONDITION_STATE_SCHEMA(value)
14171417

homeassistant/helpers/intent.py

+10-7
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
from abc import abstractmethod
66
import asyncio
7-
from collections.abc import Collection, Coroutine, Iterable
7+
from collections.abc import Callable, Collection, Coroutine, Iterable
88
import dataclasses
99
from dataclasses import dataclass, field
1010
from enum import Enum, auto
@@ -37,6 +37,9 @@
3737

3838
_LOGGER = logging.getLogger(__name__)
3939
type _SlotsType = dict[str, Any]
40+
type _IntentSlotsType = dict[
41+
str | tuple[str, str], VolSchemaType | Callable[[Any], Any]
42+
]
4043

4144
INTENT_TURN_OFF = "HassTurnOff"
4245
INTENT_TURN_ON = "HassTurnOn"
@@ -808,8 +811,8 @@ def __init__(
808811
self,
809812
intent_type: str,
810813
speech: str | None = None,
811-
required_slots: dict[str | tuple[str, str], VolSchemaType] | None = None,
812-
optional_slots: dict[str | tuple[str, str], VolSchemaType] | None = None,
814+
required_slots: _IntentSlotsType | None = None,
815+
optional_slots: _IntentSlotsType | None = None,
813816
required_domains: set[str] | None = None,
814817
required_features: int | None = None,
815818
required_states: set[str] | None = None,
@@ -825,7 +828,7 @@ def __init__(
825828
self.description = description
826829
self.platforms = platforms
827830

828-
self.required_slots: dict[tuple[str, str], VolSchemaType] = {}
831+
self.required_slots: _IntentSlotsType = {}
829832
if required_slots:
830833
for key, value_schema in required_slots.items():
831834
if isinstance(key, str):
@@ -834,7 +837,7 @@ def __init__(
834837

835838
self.required_slots[key] = value_schema
836839

837-
self.optional_slots: dict[tuple[str, str], VolSchemaType] = {}
840+
self.optional_slots: _IntentSlotsType = {}
838841
if optional_slots:
839842
for key, value_schema in optional_slots.items():
840843
if isinstance(key, str):
@@ -1108,8 +1111,8 @@ def __init__(
11081111
domain: str,
11091112
service: str,
11101113
speech: str | None = None,
1111-
required_slots: dict[str | tuple[str, str], VolSchemaType] | None = None,
1112-
optional_slots: dict[str | tuple[str, str], VolSchemaType] | None = None,
1114+
required_slots: _IntentSlotsType | None = None,
1115+
optional_slots: _IntentSlotsType | None = None,
11131116
required_domains: set[str] | None = None,
11141117
required_features: int | None = None,
11151118
required_states: set[str] | None = None,

homeassistant/helpers/schema_config_entry_flow.py

+5-3
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,9 @@ async def _async_form_step(
175175
and key.default is not vol.UNDEFINED
176176
and key not in self._options
177177
):
178-
user_input[str(key.schema)] = key.default()
178+
user_input[str(key.schema)] = cast(
179+
Callable[[], Any], key.default
180+
)()
179181

180182
if user_input is not None and form_step.validate_user_input is not None:
181183
# Do extra validation of user input
@@ -215,7 +217,7 @@ def _update_and_remove_omitted_optional_keys(
215217
)
216218
):
217219
# Key not present, delete keys old value (if present) too
218-
values.pop(key, None)
220+
values.pop(key.schema, None)
219221

220222
async def _show_next_step_or_create_entry(
221223
self, form_step: SchemaFlowFormStep
@@ -491,7 +493,7 @@ def wrapped_entity_config_entry_title(
491493
def entity_selector_without_own_entities(
492494
handler: SchemaOptionsFlowHandler,
493495
entity_selector_config: selector.EntitySelectorConfig,
494-
) -> vol.Schema:
496+
) -> selector.EntitySelector:
495497
"""Return an entity selector which excludes own entities."""
496498
entity_registry = er.async_get(handler.hass)
497499
entities = er.async_entries_for_config_entry(

0 commit comments

Comments
 (0)