mirror of
https://github.com/jpawlowski/hass.tibber_prices.git
synced 2026-05-28 18:43:40 +00:00
fix(lint): apply Python 3.14 ruff rules and update HA minimum version
Add UP037 to ruff ignore list to preserve quoted TYPE_CHECKING forward references (PEP 649 lazy eval breaks get_type_hints() at runtime for TYPE_CHECKING-guarded imports). Move datetime imports into TYPE_CHECKING blocks in sensor/calculators timing.py and trend.py (TC003, type-only usage confirmed). Apply PEP 758 parenthesis-free except clauses across 7 files via ruff format with target-version=py314. Update hacs.json minimum HA version to 2026.4.0, the first HA release requiring Python 3.14. Impact: Linter config now correctly handles Python 3.14 semantics. Users need HA >= 2026.4 (Python 3.14) to use this integration.
This commit is contained in:
parent
f2f0d296d1
commit
ac7cd5b572
11 changed files with 17 additions and 12 deletions
|
|
@ -458,7 +458,7 @@ class TibberPricesConfigFlowHandler(ConfigFlow, domain=DOMAIN):
|
||||||
valid_to_dt = datetime.fromisoformat(valid_to)
|
valid_to_dt = datetime.fromisoformat(valid_to)
|
||||||
if valid_to_dt < datetime.now(valid_to_dt.tzinfo):
|
if valid_to_dt < datetime.now(valid_to_dt.tzinfo):
|
||||||
return "expired"
|
return "expired"
|
||||||
except (ValueError, AttributeError):
|
except ValueError, AttributeError:
|
||||||
pass # If parsing fails, continue with other checks
|
pass # If parsing fails, continue with other checks
|
||||||
|
|
||||||
# Check validFrom (contract start date)
|
# Check validFrom (contract start date)
|
||||||
|
|
@ -468,7 +468,7 @@ class TibberPricesConfigFlowHandler(ConfigFlow, domain=DOMAIN):
|
||||||
valid_from_dt = datetime.fromisoformat(valid_from)
|
valid_from_dt = datetime.fromisoformat(valid_from)
|
||||||
if valid_from_dt > datetime.now(valid_from_dt.tzinfo):
|
if valid_from_dt > datetime.now(valid_from_dt.tzinfo):
|
||||||
return "future"
|
return "future"
|
||||||
except (ValueError, AttributeError):
|
except ValueError, AttributeError:
|
||||||
pass # If parsing fails, assume active
|
pass # If parsing fails, assume active
|
||||||
|
|
||||||
return "active"
|
return "active"
|
||||||
|
|
|
||||||
|
|
@ -205,7 +205,7 @@ class TibberPricesPeriodCalculator:
|
||||||
# Internal calculations always use positive values with reverse_sort flag
|
# Internal calculations always use positive values with reverse_sort flag
|
||||||
try:
|
try:
|
||||||
flex = abs(float(flex)) / 100 # Always positive internally
|
flex = abs(float(flex)) / 100 # Always positive internally
|
||||||
except (TypeError, ValueError):
|
except TypeError, ValueError:
|
||||||
flex = (
|
flex = (
|
||||||
abs(_const.DEFAULT_BEST_PRICE_FLEX) / 100
|
abs(_const.DEFAULT_BEST_PRICE_FLEX) / 100
|
||||||
if not reverse_sort
|
if not reverse_sort
|
||||||
|
|
|
||||||
|
|
@ -134,7 +134,7 @@ class TibberPricesEntity(CoordinatorEntity[TibberPricesDataUpdateCoordinator]):
|
||||||
home_name = f"{home_name}, {city}"
|
home_name = f"{home_name}, {city}"
|
||||||
else:
|
else:
|
||||||
home_name = "Tibber Home"
|
home_name = "Tibber Home"
|
||||||
except (KeyError, IndexError, TypeError):
|
except KeyError, IndexError, TypeError:
|
||||||
return "Tibber Home", None
|
return "Tibber Home", None
|
||||||
else:
|
else:
|
||||||
return home_name, home_type
|
return home_name, home_type
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ def add_next_avg_attributes( # noqa: PLR0913
|
||||||
# Extract hours from sensor key (e.g., "next_avg_3h" -> 3)
|
# Extract hours from sensor key (e.g., "next_avg_3h" -> 3)
|
||||||
try:
|
try:
|
||||||
hours = int(key.rsplit("_", maxsplit=1)[-1].replace("h", ""))
|
hours = int(key.rsplit("_", maxsplit=1)[-1].replace("h", ""))
|
||||||
except (ValueError, AttributeError):
|
except ValueError, AttributeError:
|
||||||
return
|
return
|
||||||
|
|
||||||
# Use TimeService to get the N-hour window starting from next interval
|
# Use TimeService to get the N-hour window starting from next interval
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ def _hours_to_minutes(state_value: Any) -> int | None:
|
||||||
|
|
||||||
try:
|
try:
|
||||||
return round(float(state_value) * 60)
|
return round(float(state_value) * 60)
|
||||||
except (TypeError, ValueError):
|
except TypeError, ValueError:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,10 +14,13 @@ The calculator provides smart defaults:
|
||||||
- No more periods → 0 for numeric values, None for timestamps
|
- No more periods → 0 for numeric values, None for timestamps
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from datetime import datetime
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
from .base import TibberPricesBaseCalculator # Constants
|
from .base import TibberPricesBaseCalculator # Constants
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
PROGRESS_GRACE_PERIOD_SECONDS = 60 # Show 100% for 1 minute after period ends
|
PROGRESS_GRACE_PERIOD_SECONDS = 60 # Show 100% for 1 minute after period ends
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,6 @@ Caching strategy:
|
||||||
- Current trend + next change: Cached centrally for 60s to avoid duplicate calculations
|
- Current trend + next change: Cached centrally for 60s to avoid duplicate calculations
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from datetime import datetime
|
|
||||||
from typing import TYPE_CHECKING, Any, ClassVar
|
from typing import TYPE_CHECKING, Any, ClassVar
|
||||||
|
|
||||||
from custom_components.tibber_prices.const import get_display_unit_factor
|
from custom_components.tibber_prices.const import get_display_unit_factor
|
||||||
|
|
@ -27,6 +26,8 @@ from custom_components.tibber_prices.utils.price import (
|
||||||
from .base import TibberPricesBaseCalculator
|
from .base import TibberPricesBaseCalculator
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
from custom_components.tibber_prices.coordinator import (
|
from custom_components.tibber_prices.coordinator import (
|
||||||
TibberPricesDataUpdateCoordinator,
|
TibberPricesDataUpdateCoordinator,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -889,7 +889,7 @@ class TibberPricesSensor(TibberPricesEntity, RestoreSensor):
|
||||||
if self.entity_description.entity_category == EntityCategory.DIAGNOSTIC:
|
if self.entity_description.entity_category == EntityCategory.DIAGNOSTIC:
|
||||||
try:
|
try:
|
||||||
value = self.native_value
|
value = self.native_value
|
||||||
except (KeyError, ValueError, TypeError):
|
except KeyError, ValueError, TypeError:
|
||||||
# If we can't get the value, hide the sensor
|
# If we can't get the value, hide the sensor
|
||||||
return False
|
return False
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
|
|
@ -211,7 +211,7 @@ def _check_custom_cards_installed(hass: Any) -> dict[str, bool]:
|
||||||
installed_cards["apexcharts-card"] = True
|
installed_cards["apexcharts-card"] = True
|
||||||
if "config-template-card" in url:
|
if "config-template-card" in url:
|
||||||
installed_cards["config-template-card"] = True
|
installed_cards["config-template-card"] = True
|
||||||
except (AttributeError, TypeError):
|
except AttributeError, TypeError:
|
||||||
# Fallback: can't determine, assume not installed
|
# Fallback: can't determine, assume not installed
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"name": "Tibber Price Information & Ratings",
|
"name": "Tibber Price Information & Ratings",
|
||||||
"homeassistant": "2025.10.0",
|
"homeassistant": "2026.4.0",
|
||||||
"hacs": "2.0.5"
|
"hacs": "2.0.5"
|
||||||
}
|
}
|
||||||
|
|
@ -39,6 +39,7 @@ ignore = [
|
||||||
"D212", # multi-line-summary-first-line (incompatible with formatter)
|
"D212", # multi-line-summary-first-line (incompatible with formatter)
|
||||||
"COM812", # incompatible with formatter
|
"COM812", # incompatible with formatter
|
||||||
"ISC001", # incompatible with formatter
|
"ISC001", # incompatible with formatter
|
||||||
|
"UP037", # quoted annotations; needed for TYPE_CHECKING forward references
|
||||||
]
|
]
|
||||||
|
|
||||||
[tool.ruff.lint.per-file-ignores]
|
[tool.ruff.lint.per-file-ignores]
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue