Skip to content

Commit

Permalink
Add support for Python 3.13 (#129442)
Browse files Browse the repository at this point in the history
  • Loading branch information
cdce8p authored Nov 10, 2024
1 parent 7fdcb98 commit e382f92
Show file tree
Hide file tree
Showing 15 changed files with 89 additions and 23 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ env:
MYPY_CACHE_VERSION: 9
HA_SHORT_VERSION: "2024.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.32 is the version currently shipped with Synology (as of 17 Feb 2022)
# 10.6 is the current long-term-support
Expand Down
12 changes: 7 additions & 5 deletions .github/workflows/wheels.yml
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ jobs:
strategy:
fail-fast: false
matrix:
abi: ["cp312"]
abi: ["cp312", "cp313"]
arch: ${{ fromJson(needs.init.outputs.architectures) }}
steps:
- name: Checkout the repository
Expand Down Expand Up @@ -156,7 +156,7 @@ jobs:
strategy:
fail-fast: false
matrix:
abi: ["cp312"]
abi: ["cp312", "cp313"]
arch: ${{ fromJson(needs.init.outputs.architectures) }}
steps:
- name: Checkout the repository
Expand Down Expand Up @@ -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
- name: Create requirements for cython<3
if: matrix.abi == 'cp312'
run: |
# Some dependencies still require 'cython<3'
# and don't yet use isolated build environments.
Expand All @@ -209,6 +210,7 @@ jobs:
- name: Build wheels (old cython)
uses: home-assistant/wheels@2024.11.0
if: matrix.abi == 'cp312'
with:
abi: ${{ matrix.abi }}
tag: musllinux_1_2
Expand All @@ -231,7 +233,7 @@ jobs:
wheels-key: ${{ secrets.WHEELS_KEY }}
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"
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"
requirements-diff: "requirements_diff.txt"
requirements: "requirements_all.txtaa"
Expand All @@ -245,7 +247,7 @@ jobs:
wheels-key: ${{ secrets.WHEELS_KEY }}
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"
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"
requirements-diff: "requirements_diff.txt"
requirements: "requirements_all.txtab"
Expand All @@ -259,7 +261,7 @@ jobs:
wheels-key: ${{ secrets.WHEELS_KEY }}
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"
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"
requirements-diff: "requirements_diff.txt"
requirements: "requirements_all.txtac"
15 changes: 11 additions & 4 deletions homeassistant/components/huum/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,30 @@
from __future__ import annotations

import logging

from huum.exceptions import Forbidden, NotAuthenticated
from huum.huum import Huum
import sys

from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_PASSWORD, CONF_USERNAME
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 .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__)


async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""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]
password = entry.data[CONF_PASSWORD]

Expand Down
12 changes: 7 additions & 5 deletions homeassistant/components/huum/climate.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,9 @@
from __future__ import annotations

import logging
import sys
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 (
ClimateEntity,
ClimateEntityFeature,
Expand All @@ -24,6 +20,12 @@

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__)


Expand Down
7 changes: 5 additions & 2 deletions homeassistant/components/huum/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,9 @@
from __future__ import annotations

import logging
import sys
from typing import Any

from huum.exceptions import Forbidden, NotAuthenticated
from huum.huum import Huum
import voluptuous as vol

from homeassistant.config_entries import ConfigFlow, ConfigFlowResult
Expand All @@ -15,6 +14,10 @@

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__)

STEP_USER_DATA_SCHEMA = vol.Schema(
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/huum/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/huum",
"iot_class": "cloud_polling",
"requirements": ["huum==0.7.11"]
"requirements": ["huum==0.7.11;python_version<'3.13'"]
}
4 changes: 4 additions & 0 deletions homeassistant/components/profiler/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -436,6 +436,10 @@ async def _async_generate_memory_profile(hass: HomeAssistant, call: ServiceCall)
# Imports deferred to avoid loading modules
# in memory since usually only one part of this
# 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

start_time = int(time.time() * 1000000)
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/profiler/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"quality_scale": "internal",
"requirements": [
"pyprof2calltree==1.4.5",
"guppy3==3.1.4.post1",
"guppy3==3.1.4.post1;python_version<'3.13'",
"objgraph==3.5.0"
],
"single_config_entry": true
Expand Down
3 changes: 3 additions & 0 deletions homeassistant/package_constraints.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ async-interrupt==1.2.0
async-upnp-client==0.41.0
atomicwrites-homeassistant==1.4.1
attrs==24.2.0
audioop-lts==0.2.1;python_version>='3.13'
av==13.1.0
awesomeversion==24.6.0
bcrypt==4.2.0
Expand Down Expand Up @@ -59,6 +60,8 @@ PyYAML==6.0.2
requests==2.32.3
securetar==2024.2.1
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
ulid-transform==1.0.2
urllib3>=1.26.5,<2
Expand Down
14 changes: 14 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ dependencies = [
"async-interrupt==1.2.0",
"attrs==24.2.0",
"atomicwrites-homeassistant==1.4.1",
"audioop-lts==0.2.1;python_version>='3.13'",
"awesomeversion==24.6.0",
"bcrypt==4.2.0",
"certifi>=2021.5.30",
Expand Down Expand Up @@ -65,6 +66,8 @@ dependencies = [
"requests==2.32.3",
"securetar==2024.2.1",
"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",
"ulid-transform==1.0.2",
# Constrain urllib3 to ensure we deal with CVE-2020-26137 and CVE-2021-33503
Expand Down Expand Up @@ -617,6 +620,17 @@ filterwarnings = [
# 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",

# -- 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
# https://pypi.org/project/agent-py/ - v0.0.23 - 2020-06-04
"ignore:with timeout\\(\\) is deprecated:DeprecationWarning:agent.a",
Expand Down
3 changes: 3 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ astral==2.2
async-interrupt==1.2.0
attrs==24.2.0
atomicwrites-homeassistant==1.4.1
audioop-lts==0.2.1;python_version>='3.13'
awesomeversion==24.6.0
bcrypt==4.2.0
certifi>=2021.5.30
Expand All @@ -37,6 +38,8 @@ PyYAML==6.0.2
requests==2.32.3
securetar==2024.2.1
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
ulid-transform==1.0.2
urllib3>=1.26.5,<2
Expand Down
4 changes: 2 additions & 2 deletions requirements_all.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1066,7 +1066,7 @@ gspread==5.5.0
gstreamer-player==1.1.2

# homeassistant.components.profiler
guppy3==3.1.4.post1
guppy3==3.1.4.post1;python_version<'3.13'

# homeassistant.components.iaqualink
h2==4.1.0
Expand Down Expand Up @@ -1148,7 +1148,7 @@ httplib2==0.20.4
huawei-lte-api==1.10.0

# homeassistant.components.huum
huum==0.7.11
huum==0.7.11;python_version<'3.13'

# homeassistant.components.hyperion
hyperion-py==0.7.5
Expand Down
4 changes: 2 additions & 2 deletions requirements_test_all.txt
Original file line number Diff line number Diff line change
Expand Up @@ -904,7 +904,7 @@ growattServer==1.5.0
gspread==5.5.0

# homeassistant.components.profiler
guppy3==3.1.4.post1
guppy3==3.1.4.post1;python_version<'3.13'

# homeassistant.components.iaqualink
h2==4.1.0
Expand Down Expand Up @@ -971,7 +971,7 @@ httplib2==0.20.4
huawei-lte-api==1.10.0

# homeassistant.components.huum
huum==0.7.11
huum==0.7.11;python_version<'3.13'

# homeassistant.components.hyperion
hyperion-py==0.7.5
Expand Down
6 changes: 6 additions & 0 deletions tests/components/huum/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
"""Skip test collection for Python 3.13."""

import sys

if sys.version_info >= (3, 13):
collect_ignore_glob = ["test_*.py"]
22 changes: 22 additions & 0 deletions tests/components/profiler/test_init.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import logging
import os
from pathlib import Path
import sys
from unittest.mock import patch

from freezegun.api import FrozenDateTimeFactory
Expand Down Expand Up @@ -70,6 +71,9 @@ def _mock_path(filename: str) -> str:
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:
"""Test we can setup and the service is registered."""
test_dir = tmp_path / "profiles"
Expand Down Expand Up @@ -101,6 +105,24 @@ def _mock_path(filename: str) -> str:
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(
hass: HomeAssistant,
caplog: pytest.LogCaptureFixture,
Expand Down

0 comments on commit e382f92

Please sign in to comment.