Add support for Python 3.13 (#129442)

This commit is contained in:
Marc Mueller 2024-11-10 11:38:56 +01:00 committed by GitHub
parent 7fdcb98518
commit e382f924e6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 89 additions and 23 deletions

View File

@ -42,7 +42,7 @@ env:
MYPY_CACHE_VERSION: 9 MYPY_CACHE_VERSION: 9
HA_SHORT_VERSION: "2024.12" HA_SHORT_VERSION: "2024.12"
DEFAULT_PYTHON: "3.12" DEFAULT_PYTHON: "3.12"
ALL_PYTHON_VERSIONS: "['3.12']" ALL_PYTHON_VERSIONS: "['3.12', '3.13']"
# 10.3 is the oldest supported version # 10.3 is the oldest supported version
# - 10.3.32 is the version currently shipped with Synology (as of 17 Feb 2022) # - 10.3.32 is the version currently shipped with Synology (as of 17 Feb 2022)
# 10.6 is the current long-term-support # 10.6 is the current long-term-support

View File

@ -112,7 +112,7 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
abi: ["cp312"] abi: ["cp312", "cp313"]
arch: ${{ fromJson(needs.init.outputs.architectures) }} arch: ${{ fromJson(needs.init.outputs.architectures) }}
steps: steps:
- name: Checkout the repository - name: Checkout the repository
@ -156,7 +156,7 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
abi: ["cp312"] abi: ["cp312", "cp313"]
arch: ${{ fromJson(needs.init.outputs.architectures) }} arch: ${{ fromJson(needs.init.outputs.architectures) }}
steps: steps:
- name: Checkout the repository - name: Checkout the repository
@ -198,6 +198,7 @@ jobs:
split -l $(expr $(expr $(cat requirements_all.txt | wc -l) + 1) / 3) requirements_all_wheels_${{ matrix.arch }}.txt requirements_all.txt split -l $(expr $(expr $(cat requirements_all.txt | wc -l) + 1) / 3) requirements_all_wheels_${{ matrix.arch }}.txt requirements_all.txt
- name: Create requirements for cython<3 - name: Create requirements for cython<3
if: matrix.abi == 'cp312'
run: | run: |
# Some dependencies still require 'cython<3' # Some dependencies still require 'cython<3'
# and don't yet use isolated build environments. # and don't yet use isolated build environments.
@ -209,6 +210,7 @@ jobs:
- name: Build wheels (old cython) - name: Build wheels (old cython)
uses: home-assistant/wheels@2024.11.0 uses: home-assistant/wheels@2024.11.0
if: matrix.abi == 'cp312'
with: with:
abi: ${{ matrix.abi }} abi: ${{ matrix.abi }}
tag: musllinux_1_2 tag: musllinux_1_2
@ -231,7 +233,7 @@ jobs:
wheels-key: ${{ secrets.WHEELS_KEY }} wheels-key: ${{ secrets.WHEELS_KEY }}
env-file: true env-file: true
apk: "bluez-dev;libffi-dev;openssl-dev;glib-dev;eudev-dev;libxml2-dev;libxslt-dev;libpng-dev;libjpeg-turbo-dev;tiff-dev;cups-dev;gmp-dev;mpfr-dev;mpc1-dev;ffmpeg-dev;gammu-dev;yaml-dev;openblas-dev;fftw-dev;lapack-dev;gfortran;blas-dev;eigen-dev;freetype-dev;glew-dev;harfbuzz-dev;hdf5-dev;libdc1394-dev;libtbb-dev;mesa-dev;openexr-dev;openjpeg-dev;uchardet-dev;nasm;zlib-dev" apk: "bluez-dev;libffi-dev;openssl-dev;glib-dev;eudev-dev;libxml2-dev;libxslt-dev;libpng-dev;libjpeg-turbo-dev;tiff-dev;cups-dev;gmp-dev;mpfr-dev;mpc1-dev;ffmpeg-dev;gammu-dev;yaml-dev;openblas-dev;fftw-dev;lapack-dev;gfortran;blas-dev;eigen-dev;freetype-dev;glew-dev;harfbuzz-dev;hdf5-dev;libdc1394-dev;libtbb-dev;mesa-dev;openexr-dev;openjpeg-dev;uchardet-dev;nasm;zlib-dev"
skip-binary: aiohttp;charset-normalizer;grpcio;multidict;SQLAlchemy;propcache;protobuf;pydantic;pymicro-vad;yarl skip-binary: aiohttp;charset-normalizer;grpcio;multidict;SQLAlchemy;propcache;protobuf;pymicro-vad;yarl
constraints: "homeassistant/package_constraints.txt" constraints: "homeassistant/package_constraints.txt"
requirements-diff: "requirements_diff.txt" requirements-diff: "requirements_diff.txt"
requirements: "requirements_all.txtaa" requirements: "requirements_all.txtaa"
@ -245,7 +247,7 @@ jobs:
wheels-key: ${{ secrets.WHEELS_KEY }} wheels-key: ${{ secrets.WHEELS_KEY }}
env-file: true env-file: true
apk: "bluez-dev;libffi-dev;openssl-dev;glib-dev;eudev-dev;libxml2-dev;libxslt-dev;libpng-dev;libjpeg-turbo-dev;tiff-dev;cups-dev;gmp-dev;mpfr-dev;mpc1-dev;ffmpeg-dev;gammu-dev;yaml-dev;openblas-dev;fftw-dev;lapack-dev;gfortran;blas-dev;eigen-dev;freetype-dev;glew-dev;harfbuzz-dev;hdf5-dev;libdc1394-dev;libtbb-dev;mesa-dev;openexr-dev;openjpeg-dev;uchardet-dev;nasm;zlib-dev" apk: "bluez-dev;libffi-dev;openssl-dev;glib-dev;eudev-dev;libxml2-dev;libxslt-dev;libpng-dev;libjpeg-turbo-dev;tiff-dev;cups-dev;gmp-dev;mpfr-dev;mpc1-dev;ffmpeg-dev;gammu-dev;yaml-dev;openblas-dev;fftw-dev;lapack-dev;gfortran;blas-dev;eigen-dev;freetype-dev;glew-dev;harfbuzz-dev;hdf5-dev;libdc1394-dev;libtbb-dev;mesa-dev;openexr-dev;openjpeg-dev;uchardet-dev;nasm;zlib-dev"
skip-binary: aiohttp;charset-normalizer;grpcio;multidict;SQLAlchemy;propcache;protobuf;pydantic;pymicro-vad;yarl skip-binary: aiohttp;charset-normalizer;grpcio;multidict;SQLAlchemy;propcache;protobuf;pymicro-vad;yarl
constraints: "homeassistant/package_constraints.txt" constraints: "homeassistant/package_constraints.txt"
requirements-diff: "requirements_diff.txt" requirements-diff: "requirements_diff.txt"
requirements: "requirements_all.txtab" requirements: "requirements_all.txtab"
@ -259,7 +261,7 @@ jobs:
wheels-key: ${{ secrets.WHEELS_KEY }} wheels-key: ${{ secrets.WHEELS_KEY }}
env-file: true env-file: true
apk: "bluez-dev;libffi-dev;openssl-dev;glib-dev;eudev-dev;libxml2-dev;libxslt-dev;libpng-dev;libjpeg-turbo-dev;tiff-dev;cups-dev;gmp-dev;mpfr-dev;mpc1-dev;ffmpeg-dev;gammu-dev;yaml-dev;openblas-dev;fftw-dev;lapack-dev;gfortran;blas-dev;eigen-dev;freetype-dev;glew-dev;harfbuzz-dev;hdf5-dev;libdc1394-dev;libtbb-dev;mesa-dev;openexr-dev;openjpeg-dev;uchardet-dev;nasm;zlib-dev" apk: "bluez-dev;libffi-dev;openssl-dev;glib-dev;eudev-dev;libxml2-dev;libxslt-dev;libpng-dev;libjpeg-turbo-dev;tiff-dev;cups-dev;gmp-dev;mpfr-dev;mpc1-dev;ffmpeg-dev;gammu-dev;yaml-dev;openblas-dev;fftw-dev;lapack-dev;gfortran;blas-dev;eigen-dev;freetype-dev;glew-dev;harfbuzz-dev;hdf5-dev;libdc1394-dev;libtbb-dev;mesa-dev;openexr-dev;openjpeg-dev;uchardet-dev;nasm;zlib-dev"
skip-binary: aiohttp;charset-normalizer;grpcio;multidict;SQLAlchemy;propcache;protobuf;pydantic;pymicro-vad;yarl skip-binary: aiohttp;charset-normalizer;grpcio;multidict;SQLAlchemy;propcache;protobuf;pymicro-vad;yarl
constraints: "homeassistant/package_constraints.txt" constraints: "homeassistant/package_constraints.txt"
requirements-diff: "requirements_diff.txt" requirements-diff: "requirements_diff.txt"
requirements: "requirements_all.txtac" requirements: "requirements_all.txtac"

View File

@ -3,23 +3,30 @@
from __future__ import annotations from __future__ import annotations
import logging import logging
import sys
from huum.exceptions import Forbidden, NotAuthenticated
from huum.huum import Huum
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_PASSWORD, CONF_USERNAME from homeassistant.const import CONF_PASSWORD, CONF_USERNAME
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryNotReady from homeassistant.exceptions import ConfigEntryNotReady, HomeAssistantError
from homeassistant.helpers.aiohttp_client import async_get_clientsession from homeassistant.helpers.aiohttp_client import async_get_clientsession
from .const import DOMAIN, PLATFORMS from .const import DOMAIN, PLATFORMS
if sys.version_info < (3, 13):
from huum.exceptions import Forbidden, NotAuthenticated
from huum.huum import Huum
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Set up Huum from a config entry.""" """Set up Huum from a config entry."""
if sys.version_info >= (3, 13):
raise HomeAssistantError(
"Huum is not supported on Python 3.13. Please use Python 3.12."
)
username = entry.data[CONF_USERNAME] username = entry.data[CONF_USERNAME]
password = entry.data[CONF_PASSWORD] password = entry.data[CONF_PASSWORD]

View File

@ -3,13 +3,9 @@
from __future__ import annotations from __future__ import annotations
import logging import logging
import sys
from typing import Any from typing import Any
from huum.const import SaunaStatus
from huum.exceptions import SafetyException
from huum.huum import Huum
from huum.schemas import HuumStatusResponse
from homeassistant.components.climate import ( from homeassistant.components.climate import (
ClimateEntity, ClimateEntity,
ClimateEntityFeature, ClimateEntityFeature,
@ -24,6 +20,12 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback
from .const import DOMAIN from .const import DOMAIN
if sys.version_info < (3, 13):
from huum.const import SaunaStatus
from huum.exceptions import SafetyException
from huum.huum import Huum
from huum.schemas import HuumStatusResponse
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)

View File

@ -3,10 +3,9 @@
from __future__ import annotations from __future__ import annotations
import logging import logging
import sys
from typing import Any from typing import Any
from huum.exceptions import Forbidden, NotAuthenticated
from huum.huum import Huum
import voluptuous as vol import voluptuous as vol
from homeassistant.config_entries import ConfigFlow, ConfigFlowResult from homeassistant.config_entries import ConfigFlow, ConfigFlowResult
@ -15,6 +14,10 @@ from homeassistant.helpers.aiohttp_client import async_get_clientsession
from .const import DOMAIN from .const import DOMAIN
if sys.version_info < (3, 13):
from huum.exceptions import Forbidden, NotAuthenticated
from huum.huum import Huum
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
STEP_USER_DATA_SCHEMA = vol.Schema( STEP_USER_DATA_SCHEMA = vol.Schema(

View File

@ -5,5 +5,5 @@
"config_flow": true, "config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/huum", "documentation": "https://www.home-assistant.io/integrations/huum",
"iot_class": "cloud_polling", "iot_class": "cloud_polling",
"requirements": ["huum==0.7.11"] "requirements": ["huum==0.7.11;python_version<'3.13'"]
} }

View File

@ -436,6 +436,10 @@ async def _async_generate_memory_profile(hass: HomeAssistant, call: ServiceCall)
# Imports deferred to avoid loading modules # Imports deferred to avoid loading modules
# in memory since usually only one part of this # in memory since usually only one part of this
# integration is used at a time # integration is used at a time
if sys.version_info >= (3, 13):
raise HomeAssistantError(
"Memory profiling is not supported on Python 3.13. Please use Python 3.12."
)
from guppy import hpy # pylint: disable=import-outside-toplevel from guppy import hpy # pylint: disable=import-outside-toplevel
start_time = int(time.time() * 1000000) start_time = int(time.time() * 1000000)

View File

@ -7,7 +7,7 @@
"quality_scale": "internal", "quality_scale": "internal",
"requirements": [ "requirements": [
"pyprof2calltree==1.4.5", "pyprof2calltree==1.4.5",
"guppy3==3.1.4.post1", "guppy3==3.1.4.post1;python_version<'3.13'",
"objgraph==3.5.0" "objgraph==3.5.0"
], ],
"single_config_entry": true "single_config_entry": true

View File

@ -13,6 +13,7 @@ async-interrupt==1.2.0
async-upnp-client==0.41.0 async-upnp-client==0.41.0
atomicwrites-homeassistant==1.4.1 atomicwrites-homeassistant==1.4.1
attrs==24.2.0 attrs==24.2.0
audioop-lts==0.2.1;python_version>='3.13'
av==13.1.0 av==13.1.0
awesomeversion==24.6.0 awesomeversion==24.6.0
bcrypt==4.2.0 bcrypt==4.2.0
@ -59,6 +60,8 @@ PyYAML==6.0.2
requests==2.32.3 requests==2.32.3
securetar==2024.2.1 securetar==2024.2.1
SQLAlchemy==2.0.31 SQLAlchemy==2.0.31
standard-aifc==3.13.0;python_version>='3.13'
standard-telnetlib==3.13.0;python_version>='3.13'
typing-extensions>=4.12.2,<5.0 typing-extensions>=4.12.2,<5.0
ulid-transform==1.0.2 ulid-transform==1.0.2
urllib3>=1.26.5,<2 urllib3>=1.26.5,<2

View File

@ -36,6 +36,7 @@ dependencies = [
"async-interrupt==1.2.0", "async-interrupt==1.2.0",
"attrs==24.2.0", "attrs==24.2.0",
"atomicwrites-homeassistant==1.4.1", "atomicwrites-homeassistant==1.4.1",
"audioop-lts==0.2.1;python_version>='3.13'",
"awesomeversion==24.6.0", "awesomeversion==24.6.0",
"bcrypt==4.2.0", "bcrypt==4.2.0",
"certifi>=2021.5.30", "certifi>=2021.5.30",
@ -65,6 +66,8 @@ dependencies = [
"requests==2.32.3", "requests==2.32.3",
"securetar==2024.2.1", "securetar==2024.2.1",
"SQLAlchemy==2.0.31", "SQLAlchemy==2.0.31",
"standard-aifc==3.13.0;python_version>='3.13'",
"standard-telnetlib==3.13.0;python_version>='3.13'",
"typing-extensions>=4.12.2,<5.0", "typing-extensions>=4.12.2,<5.0",
"ulid-transform==1.0.2", "ulid-transform==1.0.2",
# Constrain urllib3 to ensure we deal with CVE-2020-26137 and CVE-2021-33503 # Constrain urllib3 to ensure we deal with CVE-2020-26137 and CVE-2021-33503
@ -617,6 +620,17 @@ filterwarnings = [
# https://github.com/ssaenger/pyws66i/blob/v1.1/pyws66i/__init__.py#L2 # https://github.com/ssaenger/pyws66i/blob/v1.1/pyws66i/__init__.py#L2
"ignore:'telnetlib' is deprecated and slated for removal in Python 3.13:DeprecationWarning:pyws66i", "ignore:'telnetlib' is deprecated and slated for removal in Python 3.13:DeprecationWarning:pyws66i",
# -- New in Python 3.13
# https://github.com/kurtmckee/feedparser/pull/389 - >6.0.11
# https://github.com/kurtmckee/feedparser/issues/481
"ignore:'count' is passed as positional argument:DeprecationWarning:feedparser.html",
# https://github.com/youknowone/python-deadlib - Backports for aifc, telnetlib
"ignore:aifc was removed in Python 3.13.*'standard-aifc':DeprecationWarning:speech_recognition",
"ignore:telnetlib was removed in Python 3.13.*'standard-telnetlib':DeprecationWarning:homeassistant.components.hddtemp.sensor",
"ignore:telnetlib was removed in Python 3.13.*'standard-telnetlib':DeprecationWarning:ndms2_client.connection",
"ignore:telnetlib was removed in Python 3.13.*'standard-telnetlib':DeprecationWarning:plumlightpad.lightpad",
"ignore:telnetlib was removed in Python 3.13.*'standard-telnetlib':DeprecationWarning:pyws66i",
# -- unmaintained projects, last release about 2+ years # -- unmaintained projects, last release about 2+ years
# https://pypi.org/project/agent-py/ - v0.0.23 - 2020-06-04 # https://pypi.org/project/agent-py/ - v0.0.23 - 2020-06-04
"ignore:with timeout\\(\\) is deprecated:DeprecationWarning:agent.a", "ignore:with timeout\\(\\) is deprecated:DeprecationWarning:agent.a",

View File

@ -13,6 +13,7 @@ astral==2.2
async-interrupt==1.2.0 async-interrupt==1.2.0
attrs==24.2.0 attrs==24.2.0
atomicwrites-homeassistant==1.4.1 atomicwrites-homeassistant==1.4.1
audioop-lts==0.2.1;python_version>='3.13'
awesomeversion==24.6.0 awesomeversion==24.6.0
bcrypt==4.2.0 bcrypt==4.2.0
certifi>=2021.5.30 certifi>=2021.5.30
@ -37,6 +38,8 @@ PyYAML==6.0.2
requests==2.32.3 requests==2.32.3
securetar==2024.2.1 securetar==2024.2.1
SQLAlchemy==2.0.31 SQLAlchemy==2.0.31
standard-aifc==3.13.0;python_version>='3.13'
standard-telnetlib==3.13.0;python_version>='3.13'
typing-extensions>=4.12.2,<5.0 typing-extensions>=4.12.2,<5.0
ulid-transform==1.0.2 ulid-transform==1.0.2
urllib3>=1.26.5,<2 urllib3>=1.26.5,<2

View File

@ -1066,7 +1066,7 @@ gspread==5.5.0
gstreamer-player==1.1.2 gstreamer-player==1.1.2
# homeassistant.components.profiler # homeassistant.components.profiler
guppy3==3.1.4.post1 guppy3==3.1.4.post1;python_version<'3.13'
# homeassistant.components.iaqualink # homeassistant.components.iaqualink
h2==4.1.0 h2==4.1.0
@ -1148,7 +1148,7 @@ httplib2==0.20.4
huawei-lte-api==1.10.0 huawei-lte-api==1.10.0
# homeassistant.components.huum # homeassistant.components.huum
huum==0.7.11 huum==0.7.11;python_version<'3.13'
# homeassistant.components.hyperion # homeassistant.components.hyperion
hyperion-py==0.7.5 hyperion-py==0.7.5

View File

@ -904,7 +904,7 @@ growattServer==1.5.0
gspread==5.5.0 gspread==5.5.0
# homeassistant.components.profiler # homeassistant.components.profiler
guppy3==3.1.4.post1 guppy3==3.1.4.post1;python_version<'3.13'
# homeassistant.components.iaqualink # homeassistant.components.iaqualink
h2==4.1.0 h2==4.1.0
@ -971,7 +971,7 @@ httplib2==0.20.4
huawei-lte-api==1.10.0 huawei-lte-api==1.10.0
# homeassistant.components.huum # homeassistant.components.huum
huum==0.7.11 huum==0.7.11;python_version<'3.13'
# homeassistant.components.hyperion # homeassistant.components.hyperion
hyperion-py==0.7.5 hyperion-py==0.7.5

View File

@ -0,0 +1,6 @@
"""Skip test collection for Python 3.13."""
import sys
if sys.version_info >= (3, 13):
collect_ignore_glob = ["test_*.py"]

View File

@ -5,6 +5,7 @@ from functools import lru_cache
import logging import logging
import os import os
from pathlib import Path from pathlib import Path
import sys
from unittest.mock import patch from unittest.mock import patch
from freezegun.api import FrozenDateTimeFactory from freezegun.api import FrozenDateTimeFactory
@ -70,6 +71,9 @@ async def test_basic_usage(hass: HomeAssistant, tmp_path: Path) -> None:
await hass.async_block_till_done() await hass.async_block_till_done()
@pytest.mark.skipif(
sys.version_info >= (3, 13), reason="not yet available on Python 3.13"
)
async def test_memory_usage(hass: HomeAssistant, tmp_path: Path) -> None: async def test_memory_usage(hass: HomeAssistant, tmp_path: Path) -> None:
"""Test we can setup and the service is registered.""" """Test we can setup and the service is registered."""
test_dir = tmp_path / "profiles" test_dir = tmp_path / "profiles"
@ -101,6 +105,24 @@ async def test_memory_usage(hass: HomeAssistant, tmp_path: Path) -> None:
await hass.async_block_till_done() await hass.async_block_till_done()
@pytest.mark.skipif(sys.version_info < (3, 13), reason="still works on python 3.12")
async def test_memory_usage_py313(hass: HomeAssistant, tmp_path: Path) -> None:
"""Test raise an error on python3.13."""
entry = MockConfigEntry(domain=DOMAIN)
entry.add_to_hass(hass)
assert await hass.config_entries.async_setup(entry.entry_id)
await hass.async_block_till_done()
assert hass.services.has_service(DOMAIN, SERVICE_MEMORY)
with pytest.raises(
HomeAssistantError,
match="Memory profiling is not supported on Python 3.13. Please use Python 3.12.",
):
await hass.services.async_call(
DOMAIN, SERVICE_MEMORY, {CONF_SECONDS: 0.000001}, blocking=True
)
async def test_object_growth_logging( async def test_object_growth_logging(
hass: HomeAssistant, hass: HomeAssistant,
caplog: pytest.LogCaptureFixture, caplog: pytest.LogCaptureFixture,