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:
Julian Pawlowski 2026-04-11 10:56:34 +00:00
parent f2f0d296d1
commit ac7cd5b572
11 changed files with 17 additions and 12 deletions

View file

@ -458,7 +458,7 @@ class TibberPricesConfigFlowHandler(ConfigFlow, domain=DOMAIN):
valid_to_dt = datetime.fromisoformat(valid_to)
if valid_to_dt < datetime.now(valid_to_dt.tzinfo):
return "expired"
except (ValueError, AttributeError):
except ValueError, AttributeError:
pass # If parsing fails, continue with other checks
# Check validFrom (contract start date)
@ -468,7 +468,7 @@ class TibberPricesConfigFlowHandler(ConfigFlow, domain=DOMAIN):
valid_from_dt = datetime.fromisoformat(valid_from)
if valid_from_dt > datetime.now(valid_from_dt.tzinfo):
return "future"
except (ValueError, AttributeError):
except ValueError, AttributeError:
pass # If parsing fails, assume active
return "active"

View file

@ -205,7 +205,7 @@ class TibberPricesPeriodCalculator:
# Internal calculations always use positive values with reverse_sort flag
try:
flex = abs(float(flex)) / 100 # Always positive internally
except (TypeError, ValueError):
except TypeError, ValueError:
flex = (
abs(_const.DEFAULT_BEST_PRICE_FLEX) / 100
if not reverse_sort

View file

@ -134,7 +134,7 @@ class TibberPricesEntity(CoordinatorEntity[TibberPricesDataUpdateCoordinator]):
home_name = f"{home_name}, {city}"
else:
home_name = "Tibber Home"
except (KeyError, IndexError, TypeError):
except KeyError, IndexError, TypeError:
return "Tibber Home", None
else:
return home_name, home_type

View file

@ -44,7 +44,7 @@ def add_next_avg_attributes( # noqa: PLR0913
# Extract hours from sensor key (e.g., "next_avg_3h" -> 3)
try:
hours = int(key.rsplit("_", maxsplit=1)[-1].replace("h", ""))
except (ValueError, AttributeError):
except ValueError, AttributeError:
return
# Use TimeService to get the N-hour window starting from next interval

View file

@ -20,7 +20,7 @@ def _hours_to_minutes(state_value: Any) -> int | None:
try:
return round(float(state_value) * 60)
except (TypeError, ValueError):
except TypeError, ValueError:
return None

View file

@ -14,10 +14,13 @@ The calculator provides smart defaults:
- No more periods 0 for numeric values, None for timestamps
"""
from datetime import datetime
from typing import TYPE_CHECKING
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

View file

@ -13,7 +13,6 @@ Caching strategy:
- Current trend + next change: Cached centrally for 60s to avoid duplicate calculations
"""
from datetime import datetime
from typing import TYPE_CHECKING, Any, ClassVar
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
if TYPE_CHECKING:
from datetime import datetime
from custom_components.tibber_prices.coordinator import (
TibberPricesDataUpdateCoordinator,
)

View file

@ -889,7 +889,7 @@ class TibberPricesSensor(TibberPricesEntity, RestoreSensor):
if self.entity_description.entity_category == EntityCategory.DIAGNOSTIC:
try:
value = self.native_value
except (KeyError, ValueError, TypeError):
except KeyError, ValueError, TypeError:
# If we can't get the value, hide the sensor
return False
else:

View file

@ -211,7 +211,7 @@ def _check_custom_cards_installed(hass: Any) -> dict[str, bool]:
installed_cards["apexcharts-card"] = True
if "config-template-card" in url:
installed_cards["config-template-card"] = True
except (AttributeError, TypeError):
except AttributeError, TypeError:
# Fallback: can't determine, assume not installed
pass

View file

@ -1,5 +1,5 @@
{
"name": "Tibber Price Information & Ratings",
"homeassistant": "2025.10.0",
"homeassistant": "2026.4.0",
"hacs": "2.0.5"
}

View file

@ -39,6 +39,7 @@ ignore = [
"D212", # multi-line-summary-first-line (incompatible with formatter)
"COM812", # incompatible with formatter
"ISC001", # incompatible with formatter
"UP037", # quoted annotations; needed for TYPE_CHECKING forward references
]
[tool.ruff.lint.per-file-ignores]