diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index bb75027224ad4f..fb07d60da3bcab 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -41,8 +41,8 @@ env: UV_CACHE_VERSION: 1 MYPY_CACHE_VERSION: 9 HA_SHORT_VERSION: "2025.2" - DEFAULT_PYTHON: "3.12" - ALL_PYTHON_VERSIONS: "['3.12', '3.13']" + DEFAULT_PYTHON: "3.13" + ALL_PYTHON_VERSIONS: "['3.13']" # 10.3 is the oldest supported version # - 10.3.32 is the version currently shipped with Synology (as of 17 Feb 2022) # 10.6 is the current long-term-support diff --git a/.github/workflows/translations.yml b/.github/workflows/translations.yml index 3fffc41e60c6d6..fa3c23051909ec 100644 --- a/.github/workflows/translations.yml +++ b/.github/workflows/translations.yml @@ -10,7 +10,7 @@ on: - "**strings.json" env: - DEFAULT_PYTHON: "3.12" + DEFAULT_PYTHON: "3.13" jobs: upload: diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index 1bab64e66e53b2..00f0c507414a92 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -17,7 +17,7 @@ on: - "script/gen_requirements_all.py" env: - DEFAULT_PYTHON: "3.12" + DEFAULT_PYTHON: "3.13" concurrency: group: ${{ github.workflow }}-${{ github.ref_name}} diff --git a/homeassistant/auth/mfa_modules/__init__.py b/homeassistant/auth/mfa_modules/__init__.py index 8a6430d770a028..d0cb190ec6eaa9 100644 --- a/homeassistant/auth/mfa_modules/__init__.py +++ b/homeassistant/auth/mfa_modules/__init__.py @@ -4,9 +4,8 @@ import logging import types -from typing import Any, Generic +from typing import Any, Generic, TypeVar -from typing_extensions import TypeVar import voluptuous as vol from voluptuous.humanize import humanize_error diff --git a/homeassistant/auth/providers/__init__.py b/homeassistant/auth/providers/__init__.py index 02f99e7bd71767..36faf0e5e9cc50 100644 --- a/homeassistant/auth/providers/__init__.py +++ b/homeassistant/auth/providers/__init__.py @@ -5,9 +5,8 @@ from collections.abc import Mapping import logging import types -from typing import Any, Generic +from typing import Any, Generic, TypeVar -from typing_extensions import TypeVar import voluptuous as vol from voluptuous.humanize import humanize_error diff --git a/homeassistant/components/actiontec/device_tracker.py b/homeassistant/components/actiontec/device_tracker.py index b1b9c81c674e67..273ca6a772fe66 100644 --- a/homeassistant/components/actiontec/device_tracker.py +++ b/homeassistant/components/actiontec/device_tracker.py @@ -3,9 +3,9 @@ from __future__ import annotations import logging -import telnetlib # pylint: disable=deprecated-module from typing import Final +import telnetlib # pylint: disable=deprecated-module import voluptuous as vol from homeassistant.components.device_tracker import ( diff --git a/homeassistant/components/assist_pipeline/websocket_api.py b/homeassistant/components/assist_pipeline/websocket_api.py index c96af655589934..d61580f4a14bd3 100644 --- a/homeassistant/components/assist_pipeline/websocket_api.py +++ b/homeassistant/components/assist_pipeline/websocket_api.py @@ -1,9 +1,6 @@ """Assist pipeline Websocket API.""" import asyncio - -# Suppressing disable=deprecated-module is needed for Python 3.11 -import audioop # pylint: disable=deprecated-module import base64 from collections.abc import AsyncGenerator, Callable import contextlib @@ -11,6 +8,8 @@ import math from typing import Any, Final +# Suppressing disable=deprecated-module is needed for Python 3.11 +import audioop # pylint: disable=deprecated-module import voluptuous as vol from homeassistant.components import conversation, stt, tts, websocket_api diff --git a/homeassistant/components/bluetooth/passive_update_coordinator.py b/homeassistant/components/bluetooth/passive_update_coordinator.py index be232f87b24a3f..c20f55abcee807 100644 --- a/homeassistant/components/bluetooth/passive_update_coordinator.py +++ b/homeassistant/components/bluetooth/passive_update_coordinator.py @@ -2,9 +2,7 @@ from __future__ import annotations -from typing import TYPE_CHECKING, Any - -from typing_extensions import TypeVar +from typing import TYPE_CHECKING, Any, TypeVar from homeassistant.core import CALLBACK_TYPE, HomeAssistant, callback from homeassistant.helpers.update_coordinator import ( diff --git a/homeassistant/components/broadlink/device.py b/homeassistant/components/broadlink/device.py index 75b6236a4731ef..ac90dd9af79f54 100644 --- a/homeassistant/components/broadlink/device.py +++ b/homeassistant/components/broadlink/device.py @@ -3,7 +3,7 @@ from contextlib import suppress from functools import partial import logging -from typing import Generic +from typing import Generic, TypeVar import broadlink as blk from broadlink.exceptions import ( @@ -13,7 +13,6 @@ ConnectionClosedError, NetworkTimeoutError, ) -from typing_extensions import TypeVar from homeassistant.config_entries import ConfigEntry from homeassistant.const import ( diff --git a/homeassistant/components/broadlink/updater.py b/homeassistant/components/broadlink/updater.py index f1455f5a5411b3..8e0a521e182cfb 100644 --- a/homeassistant/components/broadlink/updater.py +++ b/homeassistant/components/broadlink/updater.py @@ -5,11 +5,10 @@ from abc import ABC, abstractmethod from datetime import datetime, timedelta import logging -from typing import TYPE_CHECKING, Any, Generic +from typing import TYPE_CHECKING, Any, Generic, TypeVar import broadlink as blk from broadlink.exceptions import AuthorizationError, BroadlinkException -from typing_extensions import TypeVar from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed from homeassistant.util import dt as dt_util diff --git a/homeassistant/components/denon/media_player.py b/homeassistant/components/denon/media_player.py index 0a6fe18d9869f0..2f46cd422943f4 100644 --- a/homeassistant/components/denon/media_player.py +++ b/homeassistant/components/denon/media_player.py @@ -3,8 +3,8 @@ from __future__ import annotations import logging -import telnetlib # pylint: disable=deprecated-module +import telnetlib # pylint: disable=deprecated-module import voluptuous as vol from homeassistant.components.media_player import ( diff --git a/homeassistant/components/hddtemp/sensor.py b/homeassistant/components/hddtemp/sensor.py index fbb6a6b48f9bf5..7ff00b8e282801 100644 --- a/homeassistant/components/hddtemp/sensor.py +++ b/homeassistant/components/hddtemp/sensor.py @@ -5,9 +5,9 @@ from datetime import timedelta import logging import socket -from telnetlib import Telnet # pylint: disable=deprecated-module from typing import Any +from telnetlib import Telnet # pylint: disable=deprecated-module import voluptuous as vol from homeassistant.components.sensor import ( diff --git a/homeassistant/components/http/static.py b/homeassistant/components/http/static.py index 9ca34af3741349..022eb9387e5955 100644 --- a/homeassistant/components/http/static.py +++ b/homeassistant/components/http/static.py @@ -4,8 +4,7 @@ from collections.abc import Mapping from pathlib import Path -import sys -from typing import Final +from typing import TYPE_CHECKING, Final from aiohttp.hdrs import CACHE_CONTROL, CONTENT_TYPE from aiohttp.web import FileResponse, Request, StreamResponse @@ -18,14 +17,12 @@ CACHE_HEADERS: Mapping[str, str] = {CACHE_CONTROL: CACHE_HEADER} RESPONSE_CACHE: LRU[tuple[str, Path], tuple[Path, str]] = LRU(512) -if sys.version_info >= (3, 13): - # guess_type is soft-deprecated in 3.13 - # for paths and should only be used for - # URLs. guess_file_type should be used - # for paths instead. - _GUESSER = CONTENT_TYPES.guess_file_type -else: +if TYPE_CHECKING: + # mypy uses Python 3.12 syntax for type checking + # once it uses Python 3.13, this can be removed _GUESSER = CONTENT_TYPES.guess_type +else: + _GUESSER = CONTENT_TYPES.guess_file_type class CachingStaticResource(StaticResource): diff --git a/homeassistant/components/pioneer/media_player.py b/homeassistant/components/pioneer/media_player.py index 670ccffaea70c0..02072b6cb4301f 100644 --- a/homeassistant/components/pioneer/media_player.py +++ b/homeassistant/components/pioneer/media_player.py @@ -3,9 +3,9 @@ from __future__ import annotations import logging -import telnetlib # pylint: disable=deprecated-module from typing import Final +import telnetlib # pylint: disable=deprecated-module import voluptuous as vol from homeassistant.components.media_player import ( diff --git a/homeassistant/components/ring/entity.py b/homeassistant/components/ring/entity.py index b93a7f35322fb4..d48cc35a4f52de 100644 --- a/homeassistant/components/ring/entity.py +++ b/homeassistant/components/ring/entity.py @@ -2,7 +2,7 @@ from collections.abc import Awaitable, Callable, Coroutine from dataclasses import dataclass -from typing import Any, Concatenate, Generic, cast +from typing import Any, Concatenate, Generic, TypeVar, cast from ring_doorbell import ( AuthenticationError, @@ -11,7 +11,6 @@ RingGeneric, RingTimeout, ) -from typing_extensions import TypeVar from homeassistant.components.automation import automations_with_entity from homeassistant.components.script import scripts_with_entity diff --git a/homeassistant/components/telnet/switch.py b/homeassistant/components/telnet/switch.py index 82d8905a775664..0178a6521c4008 100644 --- a/homeassistant/components/telnet/switch.py +++ b/homeassistant/components/telnet/switch.py @@ -4,9 +4,9 @@ from datetime import timedelta import logging -import telnetlib # pylint: disable=deprecated-module from typing import Any +import telnetlib # pylint: disable=deprecated-module import voluptuous as vol from homeassistant.components.switch import ( diff --git a/homeassistant/components/thomson/device_tracker.py b/homeassistant/components/thomson/device_tracker.py index abf3e60447299a..4e44b2b1ffd9dd 100644 --- a/homeassistant/components/thomson/device_tracker.py +++ b/homeassistant/components/thomson/device_tracker.py @@ -4,8 +4,8 @@ import logging import re -import telnetlib # pylint: disable=deprecated-module +import telnetlib # pylint: disable=deprecated-module import voluptuous as vol from homeassistant.components.device_tracker import ( diff --git a/homeassistant/components/weather/__init__.py b/homeassistant/components/weather/__init__.py index 557765795ee88d..50d90c59d37e16 100644 --- a/homeassistant/components/weather/__init__.py +++ b/homeassistant/components/weather/__init__.py @@ -8,10 +8,19 @@ from datetime import timedelta from functools import partial import logging -from typing import Any, Final, Generic, Literal, Required, TypedDict, cast, final +from typing import ( + Any, + Final, + Generic, + Literal, + Required, + TypedDict, + TypeVar, + cast, + final, +) from propcache import cached_property -from typing_extensions import TypeVar import voluptuous as vol from homeassistant.config_entries import ConfigEntry diff --git a/homeassistant/config_entries.py b/homeassistant/config_entries.py index f73bed101eeb4e..00532152b532e4 100644 --- a/homeassistant/config_entries.py +++ b/homeassistant/config_entries.py @@ -22,11 +22,10 @@ import logging from random import randint from types import MappingProxyType -from typing import TYPE_CHECKING, Any, Generic, Self, cast +from typing import TYPE_CHECKING, Any, Generic, Self, TypeVar, cast from async_interrupt import interrupt from propcache import cached_property -from typing_extensions import TypeVar import voluptuous as vol from . import data_entry_flow, loader diff --git a/homeassistant/const.py b/homeassistant/const.py index efc01047caf932..699aebcafdf388 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -28,10 +28,10 @@ PATCH_VERSION: Final = "0.dev0" __short_version__: Final = f"{MAJOR_VERSION}.{MINOR_VERSION}" __version__: Final = f"{__short_version__}.{PATCH_VERSION}" -REQUIRED_PYTHON_VER: Final[tuple[int, int, int]] = (3, 12, 0) +REQUIRED_PYTHON_VER: Final[tuple[int, int, int]] = (3, 13, 0) REQUIRED_NEXT_PYTHON_VER: Final[tuple[int, int, int]] = (3, 13, 0) # Truthy date string triggers showing related deprecation warning messages. -REQUIRED_NEXT_PYTHON_HA_RELEASE: Final = "2025.2" +REQUIRED_NEXT_PYTHON_HA_RELEASE: Final = "" # Format for platform files PLATFORM_FORMAT: Final = "{platform}.{domain}" diff --git a/homeassistant/core.py b/homeassistant/core.py index 5d0fcdc2b09ccf..58f96ed0ad256d 100644 --- a/homeassistant/core.py +++ b/homeassistant/core.py @@ -36,12 +36,12 @@ NotRequired, Self, TypedDict, + TypeVar, cast, overload, ) from propcache import cached_property, under_cached_property -from typing_extensions import TypeVar import voluptuous as vol from . import util diff --git a/homeassistant/data_entry_flow.py b/homeassistant/data_entry_flow.py index 6df77443e7e1e4..e5ee5a7992287a 100644 --- a/homeassistant/data_entry_flow.py +++ b/homeassistant/data_entry_flow.py @@ -12,9 +12,8 @@ from enum import StrEnum import logging from types import MappingProxyType -from typing import Any, Generic, Required, TypedDict, cast +from typing import Any, Generic, Required, TypedDict, TypeVar, cast -from typing_extensions import TypeVar import voluptuous as vol from .core import HomeAssistant, callback diff --git a/homeassistant/helpers/collection.py b/homeassistant/helpers/collection.py index 86d3450c3a012f..1b01f1c3f5b496 100644 --- a/homeassistant/helpers/collection.py +++ b/homeassistant/helpers/collection.py @@ -11,9 +11,8 @@ from itertools import groupby import logging from operator import attrgetter -from typing import Any, Generic, TypedDict +from typing import Any, Generic, TypedDict, TypeVar -from typing_extensions import TypeVar import voluptuous as vol from voluptuous.humanize import humanize_error diff --git a/homeassistant/helpers/data_entry_flow.py b/homeassistant/helpers/data_entry_flow.py index adb2062a8ea58e..b15d8b9e6073b2 100644 --- a/homeassistant/helpers/data_entry_flow.py +++ b/homeassistant/helpers/data_entry_flow.py @@ -3,10 +3,9 @@ from __future__ import annotations from http import HTTPStatus -from typing import Any, Generic +from typing import Any, Generic, TypeVar from aiohttp import web -from typing_extensions import TypeVar import voluptuous as vol import voluptuous_serialize diff --git a/homeassistant/helpers/entity_component.py b/homeassistant/helpers/entity_component.py index 1be7289401ccfa..de20a257a9fe64 100644 --- a/homeassistant/helpers/entity_component.py +++ b/homeassistant/helpers/entity_component.py @@ -7,9 +7,7 @@ from datetime import timedelta import logging from types import ModuleType -from typing import Any, Generic - -from typing_extensions import TypeVar +from typing import Any, Generic, TypeVar from homeassistant import config as conf_util from homeassistant.config_entries import ConfigEntry diff --git a/homeassistant/helpers/update_coordinator.py b/homeassistant/helpers/update_coordinator.py index 6cc4584935e5f4..039fbac5787348 100644 --- a/homeassistant/helpers/update_coordinator.py +++ b/homeassistant/helpers/update_coordinator.py @@ -9,13 +9,12 @@ import logging from random import randint from time import monotonic -from typing import Any, Generic, Protocol +from typing import Any, Generic, Protocol, TypeVar import urllib.error import aiohttp from propcache import cached_property import requests -from typing_extensions import TypeVar from homeassistant import config_entries from homeassistant.const import EVENT_HOMEASSISTANT_STOP diff --git a/homeassistant/util/event_type.py b/homeassistant/util/event_type.py index 509a35d33ae2a9..7755a45d3b9690 100644 --- a/homeassistant/util/event_type.py +++ b/homeassistant/util/event_type.py @@ -6,9 +6,7 @@ from __future__ import annotations from collections.abc import Mapping -from typing import Any, Generic - -from typing_extensions import TypeVar +from typing import Any, Generic, TypeVar _DataT = TypeVar("_DataT", bound=Mapping[str, Any], default=Mapping[str, Any]) diff --git a/homeassistant/util/event_type.pyi b/homeassistant/util/event_type.pyi index 4285e54e8c98b1..d3adb8a1c5446f 100644 --- a/homeassistant/util/event_type.pyi +++ b/homeassistant/util/event_type.pyi @@ -2,9 +2,7 @@ # ruff: noqa: PYI021 # Allow docstrings from collections.abc import Mapping -from typing import Any, Generic - -from typing_extensions import TypeVar +from typing import Any, Generic, TypeVar __all__ = [ "EventType", diff --git a/pyproject.toml b/pyproject.toml index b1bac5a2e1520b..1269e6668d1030 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -18,11 +18,10 @@ classifiers = [ "Intended Audience :: Developers", "License :: OSI Approved :: Apache Software License", "Operating System :: OS Independent", - "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Topic :: Home Automation", ] -requires-python = ">=3.12.0" +requires-python = ">=3.13.0" dependencies = [ "aiodns==3.2.0", # Integrations may depend on hassio integration without listing it to @@ -104,7 +103,7 @@ include-package-data = true include = ["homeassistant*"] [tool.pylint.MAIN] -py-version = "3.12" +py-version = "3.13" # Use a conservative default here; 2 should speed up most setups and not hurt # any too bad. Override on command line as appropriate. jobs = 2 diff --git a/script/hassfest/mypy_config.py b/script/hassfest/mypy_config.py index 1d7f2b5ed88824..cd37dbd543dc0d 100644 --- a/script/hassfest/mypy_config.py +++ b/script/hassfest/mypy_config.py @@ -9,8 +9,6 @@ from pathlib import Path from typing import Final -from homeassistant.const import REQUIRED_PYTHON_VER - from .model import Config, Integration # Component modules which should set no_implicit_reexport = true. @@ -31,7 +29,18 @@ """.lstrip() GENERAL_SETTINGS: Final[dict[str, str]] = { - "python_version": ".".join(str(x) for x in REQUIRED_PYTHON_VER[:2]), + # We use @dataclass_transform in all our EntityDescriptions, causing + # `__replace__` to be already synthesized by mypy, causing **every** use of + # our entity descriptions to fail: + # + # error: Signature of "__replace__" incompatible with supertype "EntityDescription" + # + # Until this is fixed in mypy, we keep mypy locked on to Python 3.12 as we + # have done for the past few releases. + # + # Ref: https://github.com/python/mypy/issues/18216 + # "python_version": ".".join(str(x) for x in REQUIRED_PYTHON_VER[:2]), + "python_version": "3.12", "platform": "linux", "plugins": ", ".join( # noqa: FLY002 [ diff --git a/tests/common.py b/tests/common.py index d83955758de2d8..d9315ef074f90e 100644 --- a/tests/common.py +++ b/tests/common.py @@ -25,13 +25,12 @@ import pathlib import time from types import FrameType, ModuleType -from typing import Any, Literal, NoReturn +from typing import Any, Literal, NoReturn, TypeVar from unittest.mock import AsyncMock, Mock, patch from aiohttp.test_utils import unused_port as get_test_instance_port # noqa: F401 import pytest from syrupy import SnapshotAssertion -from typing_extensions import TypeVar import voluptuous as vol from homeassistant import auth, bootstrap, config_entries, loader diff --git a/tests/components/homee/conftest.py b/tests/components/homee/conftest.py index 881a24656f3ddc..a777f6b59a9447 100644 --- a/tests/components/homee/conftest.py +++ b/tests/components/homee/conftest.py @@ -1,9 +1,9 @@ """Fixtures for Homee integration tests.""" +from collections.abc import Generator from unittest.mock import AsyncMock, MagicMock, patch import pytest -from typing_extensions import Generator from homeassistant.components.homee.const import DOMAIN from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_USERNAME