1
0
mirror of https://github.com/home-assistant/core.git synced 2026-02-15 07:36:16 +00:00

Enable pylint consider-math-not-float check (#154338)

This commit is contained in:
Marc Mueller
2025-10-13 21:14:57 +02:00
committed by GitHub
parent 82c536a4e9
commit 1e5f5f4ad3
11 changed files with 31 additions and 22 deletions

View File

@@ -4,6 +4,7 @@ from __future__ import annotations
from enum import StrEnum
import logging
import math
from typing import TYPE_CHECKING
from uuid import UUID
@@ -281,7 +282,7 @@ class HabiticaTodosListEntity(BaseHabiticaListEntity):
return sorted(
tasks,
key=lambda task: (
float("inf")
math.inf
if (uid := UUID(task.uid))
not in (tasks_order := self.coordinator.data.user.tasksOrder.todos)
else tasks_order.index(uid)
@@ -367,7 +368,7 @@ class HabiticaDailiesListEntity(BaseHabiticaListEntity):
return sorted(
tasks,
key=lambda task: (
float("inf")
math.inf
if (uid := UUID(task.uid))
not in (tasks_order := self.coordinator.data.user.tasksOrder.dailys)
else tasks_order.index(uid)

View File

@@ -4,6 +4,7 @@ from __future__ import annotations
from abc import ABC
from collections import OrderedDict
import math
from typing import ClassVar, Final
import voluptuous as vol
@@ -86,7 +87,7 @@ def number_limit_sub_validator(entity_config: OrderedDict) -> OrderedDict:
raise vol.Invalid(f"'type: {value_type}' is not a valid numeric sensor type.")
# Infinity is not supported by Home Assistant frontend so user defined
# config is required if if xknx DPTNumeric subclass defines it as limit.
if min_config is None and dpt_class.value_min == float("-inf"):
if min_config is None and dpt_class.value_min == -math.inf:
raise vol.Invalid(f"'min' key required for value type '{value_type}'")
if min_config is not None and min_config < dpt_class.value_min:
raise vol.Invalid(
@@ -94,7 +95,7 @@ def number_limit_sub_validator(entity_config: OrderedDict) -> OrderedDict:
f" of value type '{value_type}': {dpt_class.value_min}"
)
if max_config is None and dpt_class.value_max == float("inf"):
if max_config is None and dpt_class.value_max == math.inf:
raise vol.Invalid(f"'max' key required for value type '{value_type}'")
if max_config is not None and max_config > dpt_class.value_max:
raise vol.Invalid(

View File

@@ -5,6 +5,7 @@ from __future__ import annotations
from collections import deque
from io import DEFAULT_BUFFER_SIZE, BytesIO
import logging
import math
import os
from typing import TYPE_CHECKING
@@ -76,7 +77,7 @@ class RecorderOutput(StreamOutput):
# units which seem to be defined inversely to how stream time_bases are defined
running_duration = 0
last_sequence = float("-inf")
last_sequence = -math.inf
def write_segment(segment: Segment) -> None:
"""Write a segment to output."""

View File

@@ -9,6 +9,7 @@ from dataclasses import fields
import datetime
from io import SEEK_END, BytesIO
import logging
import math
from threading import Event
from typing import Any, Self, cast
@@ -46,7 +47,7 @@ from .fmp4utils import read_init
from .hls import HlsStreamOutput
_LOGGER = logging.getLogger(__name__)
NEGATIVE_INF = float("-inf")
NEGATIVE_INF = -math.inf
def redact_av_error_string(err: av.FFmpegError) -> str:

View File

@@ -30,6 +30,7 @@ The following cases will never be passed to your function:
from __future__ import annotations
from collections.abc import Callable, Mapping
import math
from types import MappingProxyType
from typing import Any, Protocol
@@ -161,7 +162,7 @@ def check_percentage_change(
try:
return (abs(new_state - old_state) / old_state) * 100.0
except ZeroDivisionError:
return float("inf")
return math.inf
return _check_numeric_change(old_state, new_state, change, percentage_change)

View File

@@ -161,7 +161,6 @@ class-const-naming-style = "any"
# possibly-used-before-assignment - too many errors / not necessarily issues
# ---
# Pylint CodeStyle plugin
# consider-math-not-float
# consider-using-namedtuple-or-dataclass - too opinionated
# consider-using-assignment-expr - decision to use := better left to devs
disable = [
@@ -182,7 +181,6 @@ disable = [
"too-many-boolean-expressions",
"too-many-positional-arguments",
"wrong-import-order",
"consider-math-not-float",
"consider-using-namedtuple-or-dataclass",
"consider-using-assignment-expr",
"possibly-used-before-assignment",

View File

@@ -3,6 +3,7 @@
from decimal import Decimal
from http import HTTPStatus
import json
import math
from unittest.mock import AsyncMock, Mock
from aiohttp.web_exceptions import (
@@ -46,7 +47,7 @@ async def test_invalid_json(caplog: pytest.LogCaptureFixture) -> None:
async def test_nan_serialized_to_null() -> None:
"""Test nan serialized to null JSON."""
response = HomeAssistantView.json(float("NaN"))
response = HomeAssistantView.json(math.nan)
assert json.loads(response.body.decode("utf-8")) is None

View File

@@ -1,5 +1,6 @@
"""The tests for the Modbus sensor component."""
import math
import struct
import pytest
@@ -738,8 +739,8 @@ async def test_all_sensor(hass: HomeAssistant, mock_do_cycle, expected) -> None:
[
0x5102,
0x0304,
int.from_bytes(struct.pack(">f", float("nan"))[0:2]),
int.from_bytes(struct.pack(">f", float("nan"))[2:4]),
int.from_bytes(struct.pack(">f", math.nan)[0:2]),
int.from_bytes(struct.pack(">f", math.nan)[2:4]),
],
False,
["34899771392.0", STATE_UNKNOWN],
@@ -753,8 +754,8 @@ async def test_all_sensor(hass: HomeAssistant, mock_do_cycle, expected) -> None:
[
0x5102,
0x0304,
int.from_bytes(struct.pack(">f", float("nan"))[0:2]),
int.from_bytes(struct.pack(">f", float("nan"))[2:4]),
int.from_bytes(struct.pack(">f", math.nan)[0:2]),
int.from_bytes(struct.pack(">f", math.nan)[2:4]),
],
False,
["34899771392.0", STATE_UNKNOWN],
@@ -1160,8 +1161,8 @@ async def test_wrong_unpack(hass: HomeAssistant, mock_do_cycle) -> None:
CONF_DATA_TYPE: DataType.FLOAT32,
},
[
int.from_bytes(struct.pack(">f", float("nan"))[0:2]),
int.from_bytes(struct.pack(">f", float("nan"))[2:4]),
int.from_bytes(struct.pack(">f", math.nan)[0:2]),
int.from_bytes(struct.pack(">f", math.nan)[2:4]),
],
STATE_UNKNOWN,
),
@@ -1224,8 +1225,8 @@ async def test_unpack_ok(hass: HomeAssistant, mock_do_cycle, expected) -> None:
# floats: nan, 10.600000381469727,
# 1.000879611487865e-28, 10.566553115844727
[
int.from_bytes(struct.pack(">f", float("nan"))[0:2]),
int.from_bytes(struct.pack(">f", float("nan"))[2:4]),
int.from_bytes(struct.pack(">f", math.nan)[0:2]),
int.from_bytes(struct.pack(">f", math.nan)[2:4]),
0x4129,
0x999A,
0x10FD,

View File

@@ -5,6 +5,7 @@ from __future__ import annotations
from collections.abc import Generator
from datetime import UTC, date, datetime
from decimal import Decimal
import math
from typing import Any
from unittest.mock import patch
@@ -2313,9 +2314,11 @@ async def test_state_classes_with_invalid_unit_of_measurement(
(datetime(2012, 11, 10, 7, 35, 1), "non-numeric"),
(date(2012, 11, 10), "non-numeric"),
("inf", "non-finite"),
(float("inf"), "non-finite"),
(math.inf, "non-finite"),
(float("inf"), "non-finite"), # pylint: disable=consider-math-not-float
("nan", "non-finite"),
(float("nan"), "non-finite"),
(math.nan, "non-finite"),
(float("nan"), "non-finite"), # pylint: disable=consider-math-not-float
],
)
async def test_non_numeric_validation_error(

View File

@@ -4,6 +4,7 @@ import asyncio
from copy import deepcopy
import io
import logging
import math
from typing import Any
from unittest.mock import ANY, AsyncMock, Mock, patch
@@ -1061,7 +1062,7 @@ async def test_get_states_not_allows_nan(
) -> None:
"""Test get_states command converts NaN to None."""
hass.states.async_set("greeting.hello", "world")
hass.states.async_set("greeting.bad", "data", {"hello": float("NaN")})
hass.states.async_set("greeting.bad", "data", {"hello": math.nan})
hass.states.async_set("greeting.bye", "universe")
await websocket_client.send_json_auto_id({"type": "get_states"})

View File

@@ -306,7 +306,7 @@ def test_find_unserializable_data() -> None:
assert find_paths_unserializable_data({("A",): 1}) == {"$<key: ('A',)>": ("A",)}
assert math.isnan(
find_paths_unserializable_data(
float("nan"), dump=partial(json.dumps, allow_nan=False)
math.nan, dump=partial(json.dumps, allow_nan=False)
)["$"]
)