Code styling tweaks to core utils & YAML loader (#85433)

Code styling tweaks to core utils
This commit is contained in:
Franck Nijhof 2023-01-09 07:01:55 +01:00 committed by GitHub
parent aa1c539683
commit 7adb8d5ddc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 68 additions and 51 deletions

View file

@ -23,8 +23,7 @@ RE_SANITIZE_PATH = re.compile(r"(~|\.(\.)+)")
def raise_if_invalid_filename(filename: str) -> None: 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. 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: 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. Raises a ValueError if the path is invalid.
""" """

View file

@ -510,8 +510,7 @@ def color_temperature_to_hs(color_temperature_kelvin: float) -> tuple[float, flo
def color_temperature_to_rgb( def color_temperature_to_rgb(
color_temperature_kelvin: float, color_temperature_kelvin: float,
) -> tuple[float, float, 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 This is a rough approximation based on the formula provided by T. Helland
http://www.tannerhelland.com/4435/convert-temperature-rgb-algorithm-code/ 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: 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 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. 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: 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 This point will be reproducible by the lamp
as it is on the edge of the gamut. 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( def get_closest_point_to_point(
xy_tuple: tuple[float, float], Gamut: GamutType xy_tuple: tuple[float, float], Gamut: GamutType
) -> tuple[float, float]: ) -> 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. Should only be used if the supplied color is outside of the color gamut.
""" """

View file

@ -267,8 +267,7 @@ def parse_time(time_str: str) -> dt.time | None:
def get_age(date: dt.datetime) -> str: 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 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 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: def _dst_offset_diff(dattim: dt.datetime) -> dt.timedelta:
"""Return the offset when crossing the DST barrier.""" """Return the offset when crossing the DST barrier."""
delta = dt.timedelta(hours=24) 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: 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!") raise ValueError("Cannot find a next time: Time expression never matches!")
while True: 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) result = now.replace(microsecond=0, fold=0)
# Match next second # 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 # -> trigger on the next time that 1. matches the pattern and 2. does exist
# for example: # for example:
# on 2021.03.28 02:00:00 in CET timezone clocks are turned forward an hour # 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) # with pattern "02:30", don't run on 28 mar (such a wall time does not
# instead run at 02:30 the next day # 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 # We solve this edge case by just iterating one second until the result
# (max. 3600 operations, which should be fine for an edge case that happens once a year) # exists (max. 3600 operations, which should be fine for an edge case that
# happens once a year)
now += dt.timedelta(seconds=1) now += dt.timedelta(seconds=1)
continue continue
@ -420,29 +423,34 @@ def find_next_time_expression_time(
return result return result
# When leaving DST and clocks are turned backward. # 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 # Then there are wall clock times that are ambiguous i.e. exist with DST and
# The logic above does not take into account if a given pattern matches _twice_ # without DST. The logic above does not take into account if a given pattern
# in a day. # matches _twice_ in a day.
# Example: on 2021.10.31 02:00:00 in CET timezone clocks are turned backward an hour # Example: on 2021.10.31 02:00:00 in CET timezone clocks are turned
# backward an hour.
if _datetime_ambiguous(result): if _datetime_ambiguous(result):
# `now` and `result` are both ambiguous, so the next match happens # `now` and `result` are both ambiguous, so the next match happens
# _within_ the current fold. # _within_ the current fold.
# Examples: # Examples:
# 1. 2021.10.31 02:00:00+02:00 with pattern 02:30 -> 2021.10.31 02:30:00+02:00 # 1. 2021.10.31 02:00:00+02:00 with pattern 02:30
# 2. 2021.10.31 02:00:00+01:00 with pattern 02:30 -> 2021.10.31 02:30:00+01:00 # -> 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) return result.replace(fold=now.fold)
if now.fold == 0: if now.fold == 0:
# `now` is in the first fold, but result is not ambiguous (meaning it no longer matches # `now` is in the first fold, but result is not ambiguous (meaning it no
# within the fold). # longer matches within the fold).
# -> Check if result matches in the next fold. If so, emit that match # -> 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 # Turn back the time by the DST offset, effectively run the algorithm on
# If it matches on the first fold, that means it will also match on the second one. # 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( check_result = find_next_time_expression_time(
now + _dst_offset_diff(now), seconds, minutes, hours now + _dst_offset_diff(now), seconds, minutes, hours

View file

@ -124,7 +124,8 @@ def find_paths_unserializable_data(
except (ValueError, TypeError): except (ValueError, TypeError):
pass 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"): if hasattr(obj, "as_dict"):
desc = obj.__class__.__name__ desc = obj.__class__.__name__
if isinstance(obj, State): if isinstance(obj, State):

View file

@ -79,8 +79,7 @@ def distance(
def vincenty( def vincenty(
point1: tuple[float, float], point2: tuple[float, float], miles: bool = False point1: tuple[float, float], point2: tuple[float, float], miles: bool = False
) -> float | None: ) -> 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 Result in kilometers or miles between two points on the surface of a
spheroid. spheroid.

View file

@ -52,7 +52,9 @@ def is_installed(package: str) -> bool:
# was aborted while in progress see # was aborted while in progress see
# https://github.com/home-assistant/core/issues/47699 # https://github.com/home-assistant/core/issues/47699
if installed_version is None: 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 False
return installed_version in req return installed_version in req
except PackageNotFoundError: except PackageNotFoundError:

View file

@ -15,8 +15,7 @@ def draw_box(
text: str = "", text: str = "",
color: tuple[int, int, int] = (255, 255, 0), color: tuple[int, int, int] = (255, 255, 0),
) -> None: ) -> 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) 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 where the coordinates are floats in the range [0.0, 1.0] and

View file

@ -8,12 +8,12 @@ import certifi
def client_context() -> ssl.SSLContext: def client_context() -> ssl.SSLContext:
"""Return an SSL context for making requests.""" """Return an SSL context for making requests."""
# Reuse environment variable definition from requests, since it's already a requirement # Reuse environment variable definition from requests, since it's already a
# If the environment variable has no value, fall back to using certs from certifi package # requirement. If the environment variable has no value, fall back to using
# certs from certifi package.
cafile = environ.get("REQUESTS_CA_BUNDLE", certifi.where()) cafile = environ.get("REQUESTS_CA_BUNDLE", certifi.where())
context = ssl.create_default_context(purpose=ssl.Purpose.SERVER_AUTH, cafile=cafile) return ssl.create_default_context(purpose=ssl.Purpose.SERVER_AUTH, cafile=cafile)
return context
def server_context_modern() -> ssl.SSLContext: def server_context_modern() -> ssl.SSLContext:

View file

@ -342,8 +342,8 @@ class TemperatureConverter(BaseUnitConverter):
For converting an interval between two temperatures, please use For converting an interval between two temperatures, please use
`convert_interval` instead. `convert_interval` instead.
""" """
# We cannot use the implementation from BaseUnitConverter here because the temperature # We cannot use the implementation from BaseUnitConverter here because the
# units do not use the same floor: 0°C, 0°F and 0K do not align # temperature units do not use the same floor: 0°C, 0°F and 0K do not align
if from_unit == to_unit: if from_unit == to_unit:
return value return value

View file

@ -195,7 +195,9 @@ class UnitSystem:
raise TypeError(f"{wind_speed!s} is not a numeric value.") raise TypeError(f"{wind_speed!s} is not a numeric value.")
# type ignore: https://github.com/python/mypy/issues/7207 # 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: def volume(self, volume: float | None, from_unit: str) -> float:
"""Convert the given volume to this unit system.""" """Convert the given volume to this unit system."""
@ -203,7 +205,9 @@ class UnitSystem:
raise TypeError(f"{volume!s} is not a numeric value.") raise TypeError(f"{volume!s} is not a numeric value.")
# type ignore: https://github.com/python/mypy/issues/7207 # 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]: def as_dict(self) -> dict[str, str]:
"""Convert the unit system to a dictionary.""" """Convert the unit system to a dictionary."""

View file

@ -18,7 +18,9 @@ try:
HAS_C_LOADER = True HAS_C_LOADER = True
except ImportError: except ImportError:
HAS_C_LOADER = False 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 from homeassistant.exceptions import HomeAssistantError
@ -132,10 +134,14 @@ class SafeLineLoader(yaml.SafeLoader):
super().__init__(stream) super().__init__(stream)
self.secrets = secrets 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.""" """Annotate a node with the first line it was seen."""
last_line: int = self.line 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] node.__line__ = last_line + 1 # type: ignore[attr-defined]
return node 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.""" """Add file reference information to an object."""
if isinstance(obj, list): if isinstance(obj, list):
obj = NodeListClass(obj) obj = NodeListClass(obj)
@ -337,7 +345,9 @@ def _ordered_dict(loader: LoaderType, node: yaml.nodes.MappingNode) -> OrderedDi
fname = loader.get_stream_name() fname = loader.get_stream_name()
raise yaml.MarkedYAMLError( raise yaml.MarkedYAMLError(
context=f'invalid key: "{key}"', 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 ) from exc
if key in seen: if key in seen: