mirror of https://github.com/home-assistant/core
Code styling tweaks to core entity components (#85460)
This commit is contained in:
parent
9d7e99eeb7
commit
cf5fca0464
|
@ -84,9 +84,10 @@ class CalendarEventListener:
|
||||||
|
|
||||||
async def _fetch_events(self, last_endtime: datetime.datetime) -> None:
|
async def _fetch_events(self, last_endtime: datetime.datetime) -> None:
|
||||||
"""Update the set of eligible events."""
|
"""Update the set of eligible events."""
|
||||||
# Use a sliding window for selecting in scope events in the next interval. The event
|
# Use a sliding window for selecting in scope events in the next interval.
|
||||||
# search range is offset, then the fire time of the returned events are offset again below.
|
# The event search range is offset, then the fire time of the returned events
|
||||||
# Event time ranges are exclusive so the end time is expanded by 1sec
|
# are offset again below. Event time ranges are exclusive so the end time
|
||||||
|
# is expanded by 1sec.
|
||||||
start_time = last_endtime - self._offset
|
start_time = last_endtime - self._offset
|
||||||
end_time = start_time + UPDATE_INTERVAL + datetime.timedelta(seconds=1)
|
end_time = start_time + UPDATE_INTERVAL + datetime.timedelta(seconds=1)
|
||||||
_LOGGER.debug(
|
_LOGGER.debug(
|
||||||
|
|
|
@ -38,7 +38,10 @@ def find_supported_scaling_factor(
|
||||||
|
|
||||||
|
|
||||||
def scale_jpeg_camera_image(cam_image: Image, width: int, height: int) -> bytes:
|
def scale_jpeg_camera_image(cam_image: Image, width: int, height: int) -> bytes:
|
||||||
"""Scale a camera image as close as possible to one of the supported scaling factors."""
|
"""Scale a camera image.
|
||||||
|
|
||||||
|
Scale as close as possible to one of the supported scaling factors.
|
||||||
|
"""
|
||||||
turbo_jpeg = TurboJPEGSingleton.instance()
|
turbo_jpeg = TurboJPEGSingleton.instance()
|
||||||
if not turbo_jpeg:
|
if not turbo_jpeg:
|
||||||
return cam_image.content
|
return cam_image.content
|
||||||
|
|
|
@ -434,9 +434,8 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: # noqa:
|
||||||
):
|
):
|
||||||
profiles.apply_default(light.entity_id, light.is_on, params)
|
profiles.apply_default(light.entity_id, light.is_on, params)
|
||||||
|
|
||||||
legacy_supported_color_modes = (
|
# pylint: disable=protected-access
|
||||||
light._light_internal_supported_color_modes # pylint: disable=protected-access
|
legacy_supported_color_modes = light._light_internal_supported_color_modes
|
||||||
)
|
|
||||||
supported_color_modes = light.supported_color_modes
|
supported_color_modes = light.supported_color_modes
|
||||||
|
|
||||||
# If a color temperature is specified, emulate it if not supported by the light
|
# If a color temperature is specified, emulate it if not supported by the light
|
||||||
|
@ -504,8 +503,10 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: # noqa:
|
||||||
params[ATTR_RGBW_COLOR] = color_util.color_rgb_to_rgbw(*rgb_color)
|
params[ATTR_RGBW_COLOR] = color_util.color_rgb_to_rgbw(*rgb_color)
|
||||||
elif ColorMode.RGBWW in supported_color_modes:
|
elif ColorMode.RGBWW in supported_color_modes:
|
||||||
# https://github.com/python/mypy/issues/13673
|
# https://github.com/python/mypy/issues/13673
|
||||||
params[ATTR_RGBWW_COLOR] = color_util.color_rgb_to_rgbww( # type: ignore[call-arg]
|
params[ATTR_RGBWW_COLOR] = color_util.color_rgb_to_rgbww(
|
||||||
*rgb_color, light.min_color_temp_kelvin, light.max_color_temp_kelvin
|
*rgb_color, # type: ignore[call-arg]
|
||||||
|
light.min_color_temp_kelvin,
|
||||||
|
light.max_color_temp_kelvin,
|
||||||
)
|
)
|
||||||
elif ColorMode.HS in supported_color_modes:
|
elif ColorMode.HS in supported_color_modes:
|
||||||
params[ATTR_HS_COLOR] = color_util.color_RGB_to_hs(*rgb_color)
|
params[ATTR_HS_COLOR] = color_util.color_RGB_to_hs(*rgb_color)
|
||||||
|
|
|
@ -1201,7 +1201,8 @@ async def websocket_browse_media(
|
||||||
"""
|
"""
|
||||||
Browse media available to the media_player entity.
|
Browse media available to the media_player entity.
|
||||||
|
|
||||||
To use, media_player integrations can implement MediaPlayerEntity.async_browse_media()
|
To use, media_player integrations can implement
|
||||||
|
MediaPlayerEntity.async_browse_media()
|
||||||
"""
|
"""
|
||||||
component: EntityComponent[MediaPlayerEntity] = hass.data[DOMAIN]
|
component: EntityComponent[MediaPlayerEntity] = hass.data[DOMAIN]
|
||||||
player = component.get_entity(msg["entity_id"])
|
player = component.get_entity(msg["entity_id"])
|
||||||
|
|
|
@ -51,8 +51,9 @@ def async_process_play_media_url(
|
||||||
"Not signing path for content with query param"
|
"Not signing path for content with query param"
|
||||||
)
|
)
|
||||||
elif parsed.path.startswith(PATHS_WITHOUT_AUTH):
|
elif parsed.path.startswith(PATHS_WITHOUT_AUTH):
|
||||||
# We don't sign this path if it doesn't need auth. Although signing itself can't hurt,
|
# We don't sign this path if it doesn't need auth. Although signing itself can't
|
||||||
# some devices are unable to handle long URLs and the auth signature might push it over.
|
# hurt, some devices are unable to handle long URLs and the auth signature might
|
||||||
|
# push it over.
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
signed_path = async_sign_path(
|
signed_path = async_sign_path(
|
||||||
|
|
|
@ -424,7 +424,9 @@ class NumberEntityDescription(EntityDescription):
|
||||||
or self.step is not None
|
or self.step is not None
|
||||||
or self.unit_of_measurement is not None
|
or self.unit_of_measurement is not None
|
||||||
):
|
):
|
||||||
if self.__class__.__name__ == "NumberEntityDescription": # type: ignore[unreachable]
|
if ( # type: ignore[unreachable]
|
||||||
|
self.__class__.__name__ == "NumberEntityDescription"
|
||||||
|
):
|
||||||
caller = inspect.stack()[2]
|
caller = inspect.stack()[2]
|
||||||
module = inspect.getmodule(caller[0])
|
module = inspect.getmodule(caller[0])
|
||||||
else:
|
else:
|
||||||
|
@ -668,7 +670,9 @@ class NumberEntity(Entity):
|
||||||
hasattr(self, "entity_description")
|
hasattr(self, "entity_description")
|
||||||
and self.entity_description.unit_of_measurement is not None
|
and self.entity_description.unit_of_measurement is not None
|
||||||
):
|
):
|
||||||
return self.entity_description.unit_of_measurement # type: ignore[unreachable]
|
return ( # type: ignore[unreachable]
|
||||||
|
self.entity_description.unit_of_measurement
|
||||||
|
)
|
||||||
|
|
||||||
native_unit_of_measurement = self.native_unit_of_measurement
|
native_unit_of_measurement = self.native_unit_of_measurement
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,9 @@ from math import floor, log10
|
||||||
from typing import Any, Final, cast, final
|
from typing import Any, Final, cast, final
|
||||||
|
|
||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.const import ( # noqa: F401, pylint: disable=[hass-deprecated-import]
|
|
||||||
|
# pylint: disable=[hass-deprecated-import]
|
||||||
|
from homeassistant.const import ( # noqa: F401
|
||||||
CONF_UNIT_OF_MEASUREMENT,
|
CONF_UNIT_OF_MEASUREMENT,
|
||||||
DEVICE_CLASS_AQI,
|
DEVICE_CLASS_AQI,
|
||||||
DEVICE_CLASS_BATTERY,
|
DEVICE_CLASS_BATTERY,
|
||||||
|
@ -350,12 +352,12 @@ class SensorEntity(Entity):
|
||||||
For sensors without a `unique_id`, this takes precedence over legacy
|
For sensors without a `unique_id`, this takes precedence over legacy
|
||||||
temperature conversion rules only.
|
temperature conversion rules only.
|
||||||
|
|
||||||
For sensors with a `unique_id`, this is applied only if the unit is not set by the user,
|
For sensors with a `unique_id`, this is applied only if the unit is not set by
|
||||||
and takes precedence over automatic device-class conversion rules.
|
the user, and takes precedence over automatic device-class conversion rules.
|
||||||
|
|
||||||
Note:
|
Note:
|
||||||
suggested_unit_of_measurement is stored in the entity registry the first time
|
suggested_unit_of_measurement is stored in the entity registry the first
|
||||||
the entity is seen, and then never updated.
|
time the entity is seen, and then never updated.
|
||||||
"""
|
"""
|
||||||
if hasattr(self, "_attr_suggested_unit_of_measurement"):
|
if hasattr(self, "_attr_suggested_unit_of_measurement"):
|
||||||
return self._attr_suggested_unit_of_measurement
|
return self._attr_suggested_unit_of_measurement
|
||||||
|
@ -367,8 +369,8 @@ class SensorEntity(Entity):
|
||||||
@property
|
@property
|
||||||
def unit_of_measurement(self) -> str | None:
|
def unit_of_measurement(self) -> str | None:
|
||||||
"""Return the unit of measurement of the entity, after unit conversion."""
|
"""Return the unit of measurement of the entity, after unit conversion."""
|
||||||
# Highest priority, for registered entities: unit set by user, with fallback to unit suggested
|
# Highest priority, for registered entities: unit set by user,with fallback to
|
||||||
# by integration or secondary fallback to unit conversion rules
|
# unit suggested by integration or secondary fallback to unit conversion rules
|
||||||
if self._sensor_option_unit_of_measurement:
|
if self._sensor_option_unit_of_measurement:
|
||||||
return self._sensor_option_unit_of_measurement
|
return self._sensor_option_unit_of_measurement
|
||||||
|
|
||||||
|
|
|
@ -507,9 +507,19 @@ def _compile_statistics( # noqa: C901
|
||||||
# Make calculations
|
# Make calculations
|
||||||
stat: StatisticData = {"start": start}
|
stat: StatisticData = {"start": start}
|
||||||
if "max" in wanted_statistics[entity_id]:
|
if "max" in wanted_statistics[entity_id]:
|
||||||
stat["max"] = max(*itertools.islice(zip(*fstates), 1)) # type: ignore[typeddict-item]
|
stat["max"] = max(
|
||||||
|
*itertools.islice(
|
||||||
|
zip(*fstates), # type: ignore[typeddict-item]
|
||||||
|
1,
|
||||||
|
)
|
||||||
|
)
|
||||||
if "min" in wanted_statistics[entity_id]:
|
if "min" in wanted_statistics[entity_id]:
|
||||||
stat["min"] = min(*itertools.islice(zip(*fstates), 1)) # type: ignore[typeddict-item]
|
stat["min"] = min(
|
||||||
|
*itertools.islice(
|
||||||
|
zip(*fstates), # type: ignore[typeddict-item]
|
||||||
|
1,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
if "mean" in wanted_statistics[entity_id]:
|
if "mean" in wanted_statistics[entity_id]:
|
||||||
stat["mean"] = _time_weighted_average(fstates, start, end)
|
stat["mean"] = _time_weighted_average(fstates, start, end)
|
||||||
|
@ -519,7 +529,8 @@ def _compile_statistics( # noqa: C901
|
||||||
new_state = old_state = None
|
new_state = old_state = None
|
||||||
_sum = 0.0
|
_sum = 0.0
|
||||||
if entity_id in last_stats:
|
if entity_id in last_stats:
|
||||||
# We have compiled history for this sensor before, use that as a starting point
|
# We have compiled history for this sensor before,
|
||||||
|
# use that as a starting point.
|
||||||
last_reset = old_last_reset = last_stats[entity_id][0]["last_reset"]
|
last_reset = old_last_reset = last_stats[entity_id][0]["last_reset"]
|
||||||
if old_last_reset is not None:
|
if old_last_reset is not None:
|
||||||
last_reset = old_last_reset = old_last_reset.isoformat()
|
last_reset = old_last_reset = old_last_reset.isoformat()
|
||||||
|
|
|
@ -231,7 +231,8 @@ class SpeechToTextView(HomeAssistantView):
|
||||||
def metadata_from_header(request: web.Request) -> SpeechMetadata:
|
def metadata_from_header(request: web.Request) -> SpeechMetadata:
|
||||||
"""Extract STT metadata from header.
|
"""Extract STT metadata from header.
|
||||||
|
|
||||||
X-Speech-Content: format=wav; codec=pcm; sample_rate=16000; bit_rate=16; channel=1; language=de_de
|
X-Speech-Content:
|
||||||
|
format=wav; codec=pcm; sample_rate=16000; bit_rate=16; channel=1; language=de_de
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
data = request.headers[istr("X-Speech-Content")].split(";")
|
data = request.headers[istr("X-Speech-Content")].split(";")
|
||||||
|
|
|
@ -621,9 +621,18 @@ class SpeechManager:
|
||||||
if not tts_file.tags:
|
if not tts_file.tags:
|
||||||
tts_file.add_tags()
|
tts_file.add_tags()
|
||||||
if isinstance(tts_file.tags, ID3):
|
if isinstance(tts_file.tags, ID3):
|
||||||
tts_file["artist"] = ID3Text(encoding=3, text=artist) # type: ignore[no-untyped-call]
|
tts_file["artist"] = ID3Text(
|
||||||
tts_file["album"] = ID3Text(encoding=3, text=album) # type: ignore[no-untyped-call]
|
encoding=3,
|
||||||
tts_file["title"] = ID3Text(encoding=3, text=message) # type: ignore[no-untyped-call]
|
text=artist, # type: ignore[no-untyped-call]
|
||||||
|
)
|
||||||
|
tts_file["album"] = ID3Text(
|
||||||
|
encoding=3,
|
||||||
|
text=album, # type: ignore[no-untyped-call]
|
||||||
|
)
|
||||||
|
tts_file["title"] = ID3Text(
|
||||||
|
encoding=3,
|
||||||
|
text=message, # type: ignore[no-untyped-call]
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
tts_file["artist"] = artist
|
tts_file["artist"] = artist
|
||||||
tts_file["album"] = album
|
tts_file["album"] = album
|
||||||
|
|
|
@ -326,16 +326,16 @@ class UpdateEntity(RestoreEntity):
|
||||||
async def async_release_notes(self) -> str | None:
|
async def async_release_notes(self) -> str | None:
|
||||||
"""Return full release notes.
|
"""Return full release notes.
|
||||||
|
|
||||||
This is suitable for a long changelog that does not fit in the release_summary property.
|
This is suitable for a long changelog that does not fit in the release_summary
|
||||||
The returned string can contain markdown.
|
property. The returned string can contain markdown.
|
||||||
"""
|
"""
|
||||||
return await self.hass.async_add_executor_job(self.release_notes)
|
return await self.hass.async_add_executor_job(self.release_notes)
|
||||||
|
|
||||||
def release_notes(self) -> str | None:
|
def release_notes(self) -> str | None:
|
||||||
"""Return full release notes.
|
"""Return full release notes.
|
||||||
|
|
||||||
This is suitable for a long changelog that does not fit in the release_summary property.
|
This is suitable for a long changelog that does not fit in the release_summary
|
||||||
The returned string can contain markdown.
|
property. The returned string can contain markdown.
|
||||||
"""
|
"""
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
|
|
@ -9,5 +9,5 @@ from .const import ATTR_IN_PROGRESS, ATTR_RELEASE_SUMMARY
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def exclude_attributes(hass: HomeAssistant) -> set[str]:
|
def exclude_attributes(hass: HomeAssistant) -> set[str]:
|
||||||
"""Exclude large and chatty update attributes from being recorded in the database."""
|
"""Exclude large and chatty update attributes from being recorded."""
|
||||||
return {ATTR_ENTITY_PICTURE, ATTR_IN_PROGRESS, ATTR_RELEASE_SUMMARY}
|
return {ATTR_ENTITY_PICTURE, ATTR_IN_PROGRESS, ATTR_RELEASE_SUMMARY}
|
||||||
|
|
|
@ -157,7 +157,8 @@ def round_temperature(temperature: float | None, precision: float) -> float | No
|
||||||
class Forecast(TypedDict, total=False):
|
class Forecast(TypedDict, total=False):
|
||||||
"""Typed weather forecast dict.
|
"""Typed weather forecast dict.
|
||||||
|
|
||||||
All attributes are in native units and old attributes kept for backwards compatibility.
|
All attributes are in native units and old attributes kept
|
||||||
|
for backwards compatibility.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
condition: str | None
|
condition: str | None
|
||||||
|
@ -622,7 +623,10 @@ class WeatherEntity(Entity):
|
||||||
@final
|
@final
|
||||||
@property
|
@property
|
||||||
def state_attributes(self) -> dict[str, Any]:
|
def state_attributes(self) -> dict[str, Any]:
|
||||||
"""Return the state attributes, converted from native units to user-configured units."""
|
"""Return the state attributes, converted.
|
||||||
|
|
||||||
|
Attributes are configured from native units to user-configured units.
|
||||||
|
"""
|
||||||
data: dict[str, Any] = {}
|
data: dict[str, Any] = {}
|
||||||
|
|
||||||
precision = self.precision
|
precision = self.precision
|
||||||
|
|
Loading…
Reference in New Issue