Code styling tweaks to core utils & YAML loader (#85433)
Code styling tweaks to core utils
This commit is contained in:
parent
aa1c539683
commit
7adb8d5ddc
11 changed files with 68 additions and 51 deletions
|
@ -23,8 +23,7 @@ RE_SANITIZE_PATH = re.compile(r"(~|\.(\.)+)")
|
|||
|
||||
|
||||
def raise_if_invalid_filename(filename: str) -> None:
|
||||
"""
|
||||
Check if a filename is valid.
|
||||
"""Check if a filename is valid.
|
||||
|
||||
Raises a ValueError if the filename is invalid.
|
||||
"""
|
||||
|
@ -33,8 +32,7 @@ def raise_if_invalid_filename(filename: str) -> None:
|
|||
|
||||
|
||||
def raise_if_invalid_path(path: str) -> None:
|
||||
"""
|
||||
Check if a path is valid.
|
||||
"""Check if a path is valid.
|
||||
|
||||
Raises a ValueError if the path is invalid.
|
||||
"""
|
||||
|
|
|
@ -510,8 +510,7 @@ def color_temperature_to_hs(color_temperature_kelvin: float) -> tuple[float, flo
|
|||
def color_temperature_to_rgb(
|
||||
color_temperature_kelvin: float,
|
||||
) -> tuple[float, float, float]:
|
||||
"""
|
||||
Return an RGB color from a color temperature in Kelvin.
|
||||
"""Return an RGB color from a color temperature in Kelvin.
|
||||
|
||||
This is a rough approximation based on the formula provided by T. Helland
|
||||
http://www.tannerhelland.com/4435/convert-temperature-rgb-algorithm-code/
|
||||
|
@ -581,8 +580,7 @@ def _white_levels_to_color_temperature(
|
|||
|
||||
|
||||
def _clamp(color_component: float, minimum: float = 0, maximum: float = 255) -> float:
|
||||
"""
|
||||
Clamp the given color component value between the given min and max values.
|
||||
"""Clamp the given color component value between the given min and max values.
|
||||
|
||||
The range defined by the minimum and maximum values is inclusive, i.e. given a
|
||||
color_component of 0 and a minimum of 10, the returned value is 10.
|
||||
|
@ -644,8 +642,7 @@ def get_distance_between_two_points(one: XYPoint, two: XYPoint) -> float:
|
|||
|
||||
|
||||
def get_closest_point_to_line(A: XYPoint, B: XYPoint, P: XYPoint) -> XYPoint:
|
||||
"""
|
||||
Find the closest point from P to a line defined by A and B.
|
||||
"""Find the closest point from P to a line defined by A and B.
|
||||
|
||||
This point will be reproducible by the lamp
|
||||
as it is on the edge of the gamut.
|
||||
|
@ -667,8 +664,7 @@ def get_closest_point_to_line(A: XYPoint, B: XYPoint, P: XYPoint) -> XYPoint:
|
|||
def get_closest_point_to_point(
|
||||
xy_tuple: tuple[float, float], Gamut: GamutType
|
||||
) -> tuple[float, float]:
|
||||
"""
|
||||
Get the closest matching color within the gamut of the light.
|
||||
"""Get the closest matching color within the gamut of the light.
|
||||
|
||||
Should only be used if the supplied color is outside of the color gamut.
|
||||
"""
|
||||
|
|
|
@ -267,8 +267,7 @@ def parse_time(time_str: str) -> dt.time | None:
|
|||
|
||||
|
||||
def get_age(date: dt.datetime) -> str:
|
||||
"""
|
||||
Take a datetime and return its "age" as a string.
|
||||
"""Take a datetime and return its "age" as a string.
|
||||
|
||||
The age can be in second, minute, hour, day, month or year. Only the
|
||||
biggest unit is considered, e.g. if it's 2 days and 3 hours, "2 days" will
|
||||
|
@ -328,7 +327,9 @@ def parse_time_expression(parameter: Any, min_value: int, max_value: int) -> lis
|
|||
def _dst_offset_diff(dattim: dt.datetime) -> dt.timedelta:
|
||||
"""Return the offset when crossing the DST barrier."""
|
||||
delta = dt.timedelta(hours=24)
|
||||
return (dattim + delta).utcoffset() - (dattim - delta).utcoffset() # type: ignore[operator]
|
||||
return (dattim + delta).utcoffset() - ( # type: ignore[operator]
|
||||
dattim - delta
|
||||
).utcoffset()
|
||||
|
||||
|
||||
def _lower_bound(arr: list[int], cmp: int) -> int | None:
|
||||
|
@ -360,7 +361,8 @@ def find_next_time_expression_time(
|
|||
raise ValueError("Cannot find a next time: Time expression never matches!")
|
||||
|
||||
while True:
|
||||
# Reset microseconds and fold; fold (for ambiguous DST times) will be handled later
|
||||
# Reset microseconds and fold; fold (for ambiguous DST times) will be
|
||||
# handled later.
|
||||
result = now.replace(microsecond=0, fold=0)
|
||||
|
||||
# Match next second
|
||||
|
@ -408,11 +410,12 @@ def find_next_time_expression_time(
|
|||
# -> trigger on the next time that 1. matches the pattern and 2. does exist
|
||||
# for example:
|
||||
# on 2021.03.28 02:00:00 in CET timezone clocks are turned forward an hour
|
||||
# with pattern "02:30", don't run on 28 mar (such a wall time does not exist on this day)
|
||||
# instead run at 02:30 the next day
|
||||
# with pattern "02:30", don't run on 28 mar (such a wall time does not
|
||||
# exist on this day) instead run at 02:30 the next day
|
||||
|
||||
# We solve this edge case by just iterating one second until the result exists
|
||||
# (max. 3600 operations, which should be fine for an edge case that happens once a year)
|
||||
# We solve this edge case by just iterating one second until the result
|
||||
# exists (max. 3600 operations, which should be fine for an edge case that
|
||||
# happens once a year)
|
||||
now += dt.timedelta(seconds=1)
|
||||
continue
|
||||
|
||||
|
@ -420,29 +423,34 @@ def find_next_time_expression_time(
|
|||
return result
|
||||
|
||||
# When leaving DST and clocks are turned backward.
|
||||
# Then there are wall clock times that are ambiguous i.e. exist with DST and without DST
|
||||
# The logic above does not take into account if a given pattern matches _twice_
|
||||
# in a day.
|
||||
# Example: on 2021.10.31 02:00:00 in CET timezone clocks are turned backward an hour
|
||||
# Then there are wall clock times that are ambiguous i.e. exist with DST and
|
||||
# without DST. The logic above does not take into account if a given pattern
|
||||
# matches _twice_ in a day.
|
||||
# Example: on 2021.10.31 02:00:00 in CET timezone clocks are turned
|
||||
# backward an hour.
|
||||
|
||||
if _datetime_ambiguous(result):
|
||||
# `now` and `result` are both ambiguous, so the next match happens
|
||||
# _within_ the current fold.
|
||||
|
||||
# Examples:
|
||||
# 1. 2021.10.31 02:00:00+02:00 with pattern 02:30 -> 2021.10.31 02:30:00+02:00
|
||||
# 2. 2021.10.31 02:00:00+01:00 with pattern 02:30 -> 2021.10.31 02:30:00+01:00
|
||||
# 1. 2021.10.31 02:00:00+02:00 with pattern 02:30
|
||||
# -> 2021.10.31 02:30:00+02:00
|
||||
# 2. 2021.10.31 02:00:00+01:00 with pattern 02:30
|
||||
# -> 2021.10.31 02:30:00+01:00
|
||||
return result.replace(fold=now.fold)
|
||||
|
||||
if now.fold == 0:
|
||||
# `now` is in the first fold, but result is not ambiguous (meaning it no longer matches
|
||||
# within the fold).
|
||||
# `now` is in the first fold, but result is not ambiguous (meaning it no
|
||||
# longer matches within the fold).
|
||||
# -> Check if result matches in the next fold. If so, emit that match
|
||||
|
||||
# Turn back the time by the DST offset, effectively run the algorithm on the first fold
|
||||
# If it matches on the first fold, that means it will also match on the second one.
|
||||
# Turn back the time by the DST offset, effectively run the algorithm on
|
||||
# the first fold. If it matches on the first fold, that means it will also
|
||||
# match on the second one.
|
||||
|
||||
# Example: 2021.10.31 02:45:00+02:00 with pattern 02:30 -> 2021.10.31 02:30:00+01:00
|
||||
# Example: 2021.10.31 02:45:00+02:00 with pattern 02:30
|
||||
# -> 2021.10.31 02:30:00+01:00
|
||||
|
||||
check_result = find_next_time_expression_time(
|
||||
now + _dst_offset_diff(now), seconds, minutes, hours
|
||||
|
|
|
@ -124,7 +124,8 @@ def find_paths_unserializable_data(
|
|||
except (ValueError, TypeError):
|
||||
pass
|
||||
|
||||
# We convert objects with as_dict to their dict values so we can find bad data inside it
|
||||
# We convert objects with as_dict to their dict values
|
||||
# so we can find bad data inside it
|
||||
if hasattr(obj, "as_dict"):
|
||||
desc = obj.__class__.__name__
|
||||
if isinstance(obj, State):
|
||||
|
|
|
@ -79,8 +79,7 @@ def distance(
|
|||
def vincenty(
|
||||
point1: tuple[float, float], point2: tuple[float, float], miles: bool = False
|
||||
) -> float | None:
|
||||
"""
|
||||
Vincenty formula (inverse method) to calculate the distance.
|
||||
"""Vincenty formula (inverse method) to calculate the distance.
|
||||
|
||||
Result in kilometers or miles between two points on the surface of a
|
||||
spheroid.
|
||||
|
|
|
@ -52,7 +52,9 @@ def is_installed(package: str) -> bool:
|
|||
# was aborted while in progress see
|
||||
# https://github.com/home-assistant/core/issues/47699
|
||||
if installed_version is None:
|
||||
_LOGGER.error("Installed version for %s resolved to None", req.project_name) # type: ignore[unreachable]
|
||||
_LOGGER.error( # type: ignore[unreachable]
|
||||
"Installed version for %s resolved to None", req.project_name
|
||||
)
|
||||
return False
|
||||
return installed_version in req
|
||||
except PackageNotFoundError:
|
||||
|
|
|
@ -15,8 +15,7 @@ def draw_box(
|
|||
text: str = "",
|
||||
color: tuple[int, int, int] = (255, 255, 0),
|
||||
) -> None:
|
||||
"""
|
||||
Draw a bounding box on and image.
|
||||
"""Draw a bounding box on and image.
|
||||
|
||||
The bounding box is defined by the tuple (y_min, x_min, y_max, x_max)
|
||||
where the coordinates are floats in the range [0.0, 1.0] and
|
||||
|
|
|
@ -8,12 +8,12 @@ import certifi
|
|||
def client_context() -> ssl.SSLContext:
|
||||
"""Return an SSL context for making requests."""
|
||||
|
||||
# Reuse environment variable definition from requests, since it's already a requirement
|
||||
# If the environment variable has no value, fall back to using certs from certifi package
|
||||
# Reuse environment variable definition from requests, since it's already a
|
||||
# requirement. If the environment variable has no value, fall back to using
|
||||
# certs from certifi package.
|
||||
cafile = environ.get("REQUESTS_CA_BUNDLE", certifi.where())
|
||||
|
||||
context = ssl.create_default_context(purpose=ssl.Purpose.SERVER_AUTH, cafile=cafile)
|
||||
return context
|
||||
return ssl.create_default_context(purpose=ssl.Purpose.SERVER_AUTH, cafile=cafile)
|
||||
|
||||
|
||||
def server_context_modern() -> ssl.SSLContext:
|
||||
|
|
|
@ -342,8 +342,8 @@ class TemperatureConverter(BaseUnitConverter):
|
|||
For converting an interval between two temperatures, please use
|
||||
`convert_interval` instead.
|
||||
"""
|
||||
# We cannot use the implementation from BaseUnitConverter here because the temperature
|
||||
# units do not use the same floor: 0°C, 0°F and 0K do not align
|
||||
# We cannot use the implementation from BaseUnitConverter here because the
|
||||
# temperature units do not use the same floor: 0°C, 0°F and 0K do not align
|
||||
if from_unit == to_unit:
|
||||
return value
|
||||
|
||||
|
|
|
@ -195,7 +195,9 @@ class UnitSystem:
|
|||
raise TypeError(f"{wind_speed!s} is not a numeric value.")
|
||||
|
||||
# type ignore: https://github.com/python/mypy/issues/7207
|
||||
return SpeedConverter.convert(wind_speed, from_unit, self.wind_speed_unit) # type: ignore[unreachable]
|
||||
return SpeedConverter.convert( # type: ignore[unreachable]
|
||||
wind_speed, from_unit, self.wind_speed_unit
|
||||
)
|
||||
|
||||
def volume(self, volume: float | None, from_unit: str) -> float:
|
||||
"""Convert the given volume to this unit system."""
|
||||
|
@ -203,7 +205,9 @@ class UnitSystem:
|
|||
raise TypeError(f"{volume!s} is not a numeric value.")
|
||||
|
||||
# type ignore: https://github.com/python/mypy/issues/7207
|
||||
return VolumeConverter.convert(volume, from_unit, self.volume_unit) # type: ignore[unreachable]
|
||||
return VolumeConverter.convert( # type: ignore[unreachable]
|
||||
volume, from_unit, self.volume_unit
|
||||
)
|
||||
|
||||
def as_dict(self) -> dict[str, str]:
|
||||
"""Convert the unit system to a dictionary."""
|
||||
|
|
|
@ -18,7 +18,9 @@ try:
|
|||
HAS_C_LOADER = True
|
||||
except ImportError:
|
||||
HAS_C_LOADER = False
|
||||
from yaml import SafeLoader as FastestAvailableSafeLoader # type: ignore[assignment]
|
||||
from yaml import ( # type: ignore[assignment]
|
||||
SafeLoader as FastestAvailableSafeLoader,
|
||||
)
|
||||
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
|
||||
|
@ -132,10 +134,14 @@ class SafeLineLoader(yaml.SafeLoader):
|
|||
super().__init__(stream)
|
||||
self.secrets = secrets
|
||||
|
||||
def compose_node(self, parent: yaml.nodes.Node, index: int) -> yaml.nodes.Node: # type: ignore[override]
|
||||
def compose_node( # type: ignore[override]
|
||||
self, parent: yaml.nodes.Node, index: int
|
||||
) -> yaml.nodes.Node:
|
||||
"""Annotate a node with the first line it was seen."""
|
||||
last_line: int = self.line
|
||||
node: yaml.nodes.Node = super().compose_node(parent, index) # type: ignore[assignment]
|
||||
node: yaml.nodes.Node = super().compose_node( # type: ignore[assignment]
|
||||
parent, index
|
||||
)
|
||||
node.__line__ = last_line + 1 # type: ignore[attr-defined]
|
||||
return node
|
||||
|
||||
|
@ -226,7 +232,9 @@ def _add_reference(obj: _DictT, loader: LoaderType, node: yaml.nodes.Node) -> _D
|
|||
...
|
||||
|
||||
|
||||
def _add_reference(obj, loader: LoaderType, node: yaml.nodes.Node): # type: ignore[no-untyped-def]
|
||||
def _add_reference( # type: ignore[no-untyped-def]
|
||||
obj, loader: LoaderType, node: yaml.nodes.Node
|
||||
):
|
||||
"""Add file reference information to an object."""
|
||||
if isinstance(obj, list):
|
||||
obj = NodeListClass(obj)
|
||||
|
@ -337,7 +345,9 @@ def _ordered_dict(loader: LoaderType, node: yaml.nodes.MappingNode) -> OrderedDi
|
|||
fname = loader.get_stream_name()
|
||||
raise yaml.MarkedYAMLError(
|
||||
context=f'invalid key: "{key}"',
|
||||
context_mark=yaml.Mark(fname, 0, line, -1, None, None), # type: ignore[arg-type]
|
||||
context_mark=yaml.Mark(
|
||||
fname, 0, line, -1, None, None # type: ignore[arg-type]
|
||||
),
|
||||
) from exc
|
||||
|
||||
if key in seen:
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue