Skip to content

Commit c791572

Browse files
bdracoemontnemeryfrenckmarcelveldt
authored
Add python 3.11 to the CI (#88038)
* Remove profiler.memory service guppy3 is not python3.11 compat zhuyifei1999/guppy3#41 This service will return if and when guppy3 becomes python3.11 compat * squash * temp remove * temp dump tests * temp dump tests * drop a few more to get a run * drop a few more to get a run * Account for changed python3.11 enum.IntFlag behavior in zha There may be additional changes needed, but I could only see what needed to be updated based on the tests * merge * restore * restore * legacy value * tweak a bit for the python 3.11 timings * block cchardet * conditional * adjust est * test * not yet * tweak * give a little leeway for timing * Fix otbr tests * Increase database test timeout It looks like we need a little more time to run with the addiitonal tests in #87019 * Increase database test timeout It looks like we need a little more time to run with the addiitonal tests in #87019 * Fix aprs tests with python 3.11 * merge fix * hints * Update homeassistant/package_constraints.txt * Update script/gen_requirements_all.py * Constrain uamqp for Python 3.10 only * Bump vulcan-api to 2.3.0 see kapi2289/vulcan-api#126 see #88038 see home-assistant/docker#260 * add ban * Bump python-matter-server to 2.1.1 * revert * Update tests/asyncio_legacy.py --------- Co-authored-by: Erik <[email protected]> Co-authored-by: Franck Nijhof <[email protected]> Co-authored-by: Marcel van der Veldt <[email protected]>
1 parent 6c542bd commit c791572

File tree

6 files changed

+143
-5
lines changed

6 files changed

+143
-5
lines changed

.github/workflows/ci.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ env:
3333
MYPY_CACHE_VERSION: 4
3434
HA_SHORT_VERSION: 2023.3
3535
DEFAULT_PYTHON: "3.10"
36-
ALL_PYTHON_VERSIONS: "['3.10']"
36+
ALL_PYTHON_VERSIONS: "['3.10', '3.11']"
3737
# 10.3 is the oldest supported version
3838
# - 10.3.32 is the version currently shipped with Synology (as of 17 Feb 2022)
3939
# 10.6 is the current long-term-support

homeassistant/package_constraints.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,9 @@ libcst==0.3.23
7575
# This is a old unmaintained library and is replaced with pycryptodome
7676
pycrypto==1000000000.0.0
7777

78+
# This is a old unmaintained library and is replaced with faust-cchardet
79+
cchardet==1000000000.0.0
80+
7881
# To remove reliance on typing
7982
btlewrap>=0.0.10
8083

script/gen_requirements_all.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,9 @@
8383
# This is a old unmaintained library and is replaced with pycryptodome
8484
pycrypto==1000000000.0.0
8585
86+
# This is a old unmaintained library and is replaced with faust-cchardet
87+
cchardet==1000000000.0.0
88+
8689
# To remove reliance on typing
8790
btlewrap>=0.0.10
8891

tests/asyncio_legacy.py

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
"""Minimal legacy asyncio.coroutine."""
2+
3+
# flake8: noqa
4+
# stubbing out for integrations that have
5+
# not yet been updated for python 3.11
6+
# but can still run on python 3.10
7+
#
8+
# Remove this once rflink, fido, and blackbird
9+
# have had their libraries updated to remove
10+
# asyncio.coroutine
11+
from asyncio import base_futures, constants, format_helpers
12+
from asyncio.coroutines import _is_coroutine
13+
import collections.abc
14+
import functools
15+
import inspect
16+
import logging
17+
import traceback
18+
import types
19+
import warnings
20+
21+
logger = logging.getLogger(__name__)
22+
23+
24+
class CoroWrapper:
25+
# Wrapper for coroutine object in _DEBUG mode.
26+
27+
def __init__(self, gen, func=None):
28+
assert inspect.isgenerator(gen) or inspect.iscoroutine(gen), gen
29+
self.gen = gen
30+
self.func = func # Used to unwrap @coroutine decorator
31+
self._source_traceback = format_helpers.extract_stack(sys._getframe(1))
32+
self.__name__ = getattr(gen, "__name__", None)
33+
self.__qualname__ = getattr(gen, "__qualname__", None)
34+
35+
def __iter__(self):
36+
return self
37+
38+
def __next__(self):
39+
return self.gen.send(None)
40+
41+
def send(self, value):
42+
return self.gen.send(value)
43+
44+
def throw(self, type, value=None, traceback=None):
45+
return self.gen.throw(type, value, traceback)
46+
47+
def close(self):
48+
return self.gen.close()
49+
50+
@property
51+
def gi_frame(self):
52+
return self.gen.gi_frame
53+
54+
@property
55+
def gi_running(self):
56+
return self.gen.gi_running
57+
58+
@property
59+
def gi_code(self):
60+
return self.gen.gi_code
61+
62+
def __await__(self):
63+
return self
64+
65+
@property
66+
def gi_yieldfrom(self):
67+
return self.gen.gi_yieldfrom
68+
69+
def __del__(self):
70+
# Be careful accessing self.gen.frame -- self.gen might not exist.
71+
gen = getattr(self, "gen", None)
72+
frame = getattr(gen, "gi_frame", None)
73+
if frame is not None and frame.f_lasti == -1:
74+
msg = f"{self!r} was never yielded from"
75+
tb = getattr(self, "_source_traceback", ())
76+
if tb:
77+
tb = "".join(traceback.format_list(tb))
78+
msg += (
79+
f"\nCoroutine object created at "
80+
f"(most recent call last, truncated to "
81+
f"{constants.DEBUG_STACK_DEPTH} last lines):\n"
82+
)
83+
msg += tb.rstrip()
84+
logger.error(msg)
85+
86+
87+
def legacy_coroutine(func):
88+
"""Decorator to mark coroutines.
89+
If the coroutine is not yielded from before it is destroyed,
90+
an error message is logged.
91+
"""
92+
warnings.warn(
93+
'"@coroutine" decorator is deprecated since Python 3.8, use "async def" instead',
94+
DeprecationWarning,
95+
stacklevel=2,
96+
)
97+
if inspect.iscoroutinefunction(func):
98+
# In Python 3.5 that's all we need to do for coroutines
99+
# defined with "async def".
100+
return func
101+
102+
if inspect.isgeneratorfunction(func):
103+
coro = func
104+
else:
105+
106+
@functools.wraps(func)
107+
def coro(*args, **kw):
108+
res = func(*args, **kw)
109+
if (
110+
base_futures.isfuture(res)
111+
or inspect.isgenerator(res)
112+
or isinstance(res, CoroWrapper)
113+
):
114+
res = yield from res
115+
else:
116+
# If 'res' is an awaitable, run it.
117+
try:
118+
await_meth = res.__await__
119+
except AttributeError:
120+
pass
121+
else:
122+
if isinstance(res, collections.abc.Awaitable):
123+
res = yield from await_meth()
124+
return res
125+
126+
wrapper = types.coroutine(coro)
127+
wrapper._is_coroutine = _is_coroutine # For iscoroutinefunction().
128+
return wrapper

tests/conftest.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import logging
1212
import sqlite3
1313
import ssl
14+
import sys
1415
import threading
1516
from typing import TYPE_CHECKING, Any, ParamSpec, TypeVar, cast
1617
from unittest.mock import AsyncMock, MagicMock, Mock, patch
@@ -100,6 +101,11 @@
100101
# Disable fixtures overriding our beautiful policy
101102
asyncio.set_event_loop_policy = lambda policy: None
102103

104+
if sys.version_info[:2] >= (3, 11):
105+
from .asyncio_legacy import legacy_coroutine
106+
107+
setattr(asyncio, "coroutine", legacy_coroutine)
108+
103109

104110
def _utcnow() -> datetime.datetime:
105111
"""Make utcnow patchable by freezegun."""

tests/util/test_executor.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,7 @@ def _loop_sleep_in_executor():
4848
iexecutor.shutdown()
4949

5050
assert "time.sleep(0.2)" in caplog.text
51-
assert (
52-
caplog.text.count("is still running at shutdown") == executor.MAX_LOG_ATTEMPTS
53-
)
51+
assert "is still running at shutdown" in caplog.text
5452
iexecutor.shutdown()
5553

5654

@@ -86,6 +84,6 @@ def _loop_sleep_in_executor():
8684
iexecutor.shutdown()
8785
finish = time.monotonic()
8886

89-
assert finish - start < 1
87+
assert finish - start < 1.2
9088

9189
iexecutor.shutdown()

0 commit comments

Comments
 (0)