Skip to content

Commit 8668f47

Browse files
authored
Add strict typing for input_text (home-assistant#103095)
1 parent 8e2c2e5 commit 8668f47

File tree

3 files changed

+39
-25
lines changed

3 files changed

+39
-25
lines changed

.strict-typing

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,7 @@ homeassistant.components.image_upload.*
180180
homeassistant.components.imap.*
181181
homeassistant.components.input_button.*
182182
homeassistant.components.input_select.*
183+
homeassistant.components.input_text.*
183184
homeassistant.components.integration.*
184185
homeassistant.components.ipp.*
185186
homeassistant.components.iqvia.*

homeassistant/components/input_text/__init__.py

Lines changed: 28 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
from __future__ import annotations
33

44
import logging
5-
from typing import Self
5+
from typing import Any, Self
66

77
import voluptuous as vol
88

@@ -61,20 +61,20 @@
6161
}
6262

6363

64-
def _cv_input_text(cfg):
64+
def _cv_input_text(config: dict[str, Any]) -> dict[str, Any]:
6565
"""Configure validation helper for input box (voluptuous)."""
66-
minimum = cfg.get(CONF_MIN)
67-
maximum = cfg.get(CONF_MAX)
66+
minimum: int = config[CONF_MIN]
67+
maximum: int = config[CONF_MAX]
6868
if minimum > maximum:
6969
raise vol.Invalid(
7070
f"Max len ({minimum}) is not greater than min len ({maximum})"
7171
)
72-
state = cfg.get(CONF_INITIAL)
72+
state: str | None = config.get(CONF_INITIAL)
7373
if state is not None and (len(state) < minimum or len(state) > maximum):
7474
raise vol.Invalid(
7575
f"Initial value {state} length not in range {minimum}-{maximum}"
7676
)
77-
return cfg
77+
return config
7878

7979

8080
CONFIG_SCHEMA = vol.Schema(
@@ -86,7 +86,7 @@ def _cv_input_text(cfg):
8686
vol.Optional(CONF_NAME): cv.string,
8787
vol.Optional(CONF_MIN, default=CONF_MIN_VALUE): vol.Coerce(int),
8888
vol.Optional(CONF_MAX, default=CONF_MAX_VALUE): vol.Coerce(int),
89-
vol.Optional(CONF_INITIAL, ""): cv.string,
89+
vol.Optional(CONF_INITIAL): cv.string,
9090
vol.Optional(CONF_ICON): cv.icon,
9191
vol.Optional(CONF_UNIT_OF_MEASUREMENT): cv.string,
9292
vol.Optional(CONF_PATTERN): cv.string,
@@ -162,16 +162,18 @@ class InputTextStorageCollection(collection.DictStorageCollection):
162162

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

165-
async def _process_create_data(self, data: dict) -> dict:
165+
async def _process_create_data(self, data: dict[str, Any]) -> vol.Schema:
166166
"""Validate the config is valid."""
167167
return self.CREATE_UPDATE_SCHEMA(data)
168168

169169
@callback
170-
def _get_suggested_id(self, info: dict) -> str:
170+
def _get_suggested_id(self, info: dict[str, Any]) -> str:
171171
"""Suggest an ID based on the config."""
172-
return info[CONF_NAME]
172+
return info[CONF_NAME] # type: ignore[no-any-return]
173173

174-
async def _update_data(self, item: dict, update_data: dict) -> dict:
174+
async def _update_data(
175+
self, item: dict[str, Any], update_data: dict[str, Any]
176+
) -> dict[str, Any]:
175177
"""Return a new updated data object."""
176178
update_data = self.CREATE_UPDATE_SCHEMA(update_data)
177179
return {CONF_ID: item[CONF_ID]} | update_data
@@ -185,6 +187,7 @@ class InputText(collection.CollectionEntity, RestoreEntity):
185187
)
186188

187189
_attr_should_poll = False
190+
_current_value: str | None
188191
editable: bool
189192

190193
def __init__(self, config: ConfigType) -> None:
@@ -195,55 +198,55 @@ def __init__(self, config: ConfigType) -> None:
195198
@classmethod
196199
def from_storage(cls, config: ConfigType) -> Self:
197200
"""Return entity instance initialized from storage."""
198-
input_text = cls(config)
201+
input_text: Self = cls(config)
199202
input_text.editable = True
200203
return input_text
201204

202205
@classmethod
203206
def from_yaml(cls, config: ConfigType) -> Self:
204207
"""Return entity instance initialized from yaml."""
205-
input_text = cls(config)
208+
input_text: Self = cls(config)
206209
input_text.entity_id = f"{DOMAIN}.{config[CONF_ID]}"
207210
input_text.editable = False
208211
return input_text
209212

210213
@property
211-
def name(self):
214+
def name(self) -> str | None:
212215
"""Return the name of the text input entity."""
213216
return self._config.get(CONF_NAME)
214217

215218
@property
216-
def icon(self):
219+
def icon(self) -> str | None:
217220
"""Return the icon to be used for this entity."""
218221
return self._config.get(CONF_ICON)
219222

220223
@property
221224
def _maximum(self) -> int:
222225
"""Return max len of the text."""
223-
return self._config[CONF_MAX]
226+
return self._config[CONF_MAX] # type: ignore[no-any-return]
224227

225228
@property
226229
def _minimum(self) -> int:
227230
"""Return min len of the text."""
228-
return self._config[CONF_MIN]
231+
return self._config[CONF_MIN] # type: ignore[no-any-return]
229232

230233
@property
231-
def state(self):
234+
def state(self) -> str | None:
232235
"""Return the state of the component."""
233236
return self._current_value
234237

235238
@property
236-
def unit_of_measurement(self):
239+
def unit_of_measurement(self) -> str | None:
237240
"""Return the unit the value is expressed in."""
238241
return self._config.get(CONF_UNIT_OF_MEASUREMENT)
239242

240243
@property
241-
def unique_id(self) -> str | None:
244+
def unique_id(self) -> str:
242245
"""Return unique id for the entity."""
243-
return self._config[CONF_ID]
246+
return self._config[CONF_ID] # type: ignore[no-any-return]
244247

245248
@property
246-
def extra_state_attributes(self):
249+
def extra_state_attributes(self) -> dict[str, Any]:
247250
"""Return the state attributes."""
248251
return {
249252
ATTR_EDITABLE: self.editable,
@@ -253,20 +256,20 @@ def extra_state_attributes(self):
253256
ATTR_MODE: self._config[CONF_MODE],
254257
}
255258

256-
async def async_added_to_hass(self):
259+
async def async_added_to_hass(self) -> None:
257260
"""Run when entity about to be added to hass."""
258261
await super().async_added_to_hass()
259262
if self._current_value is not None:
260263
return
261264

262265
state = await self.async_get_last_state()
263-
value = state and state.state
266+
value: str | None = state and state.state # type: ignore[assignment]
264267

265268
# Check against None because value can be 0
266269
if value is not None and self._minimum <= len(value) <= self._maximum:
267270
self._current_value = value
268271

269-
async def async_set_value(self, value):
272+
async def async_set_value(self, value: str) -> None:
270273
"""Select new value."""
271274
if len(value) < self._minimum or len(value) > self._maximum:
272275
_LOGGER.warning(

mypy.ini

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1561,6 +1561,16 @@ disallow_untyped_defs = true
15611561
warn_return_any = true
15621562
warn_unreachable = true
15631563

1564+
[mypy-homeassistant.components.input_text.*]
1565+
check_untyped_defs = true
1566+
disallow_incomplete_defs = true
1567+
disallow_subclassing_any = true
1568+
disallow_untyped_calls = true
1569+
disallow_untyped_decorators = true
1570+
disallow_untyped_defs = true
1571+
warn_return_any = true
1572+
warn_unreachable = true
1573+
15641574
[mypy-homeassistant.components.integration.*]
15651575
check_untyped_defs = true
15661576
disallow_incomplete_defs = true

0 commit comments

Comments
 (0)