Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for Python 3.13 #129442

Merged
merged 7 commits into from
Nov 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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/[email protected]
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(

Check warning on line 26 in homeassistant/components/huum/__init__.py

View check run for this annotation

Codecov / codecov/patch

homeassistant/components/huum/__init__.py#L25-L26

Added lines #L25 - L26 were not covered by tests
"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

Check warning on line 6 in homeassistant/components/huum/climate.py

View check run for this annotation

Codecov / codecov/patch

homeassistant/components/huum/climate.py#L6

Added line #L6 was not covered by tests
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

Check warning on line 27 in homeassistant/components/huum/climate.py

View check run for this annotation

Codecov / codecov/patch

homeassistant/components/huum/climate.py#L23-L27

Added lines #L23 - L27 were not covered by tests

_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