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:
"""
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.
"""

View file

@ -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.
"""

View file

@ -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

View file

@ -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):

View file

@ -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.

View file

@ -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:

View file

@ -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

View file

@ -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:

View file

@ -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

View file

@ -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."""

View file

@ -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: