From 297031687679762849dedeaf24aa3a19116f095b Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Thu, 2 Dec 2021 11:26:20 +0100 Subject: [PATCH 1/2] Don't use asyncio.coroutinefunction if it's not available Python 3.11 drops the deprecated @asyncio.coroutine and asyncio.iscoroutinefunction. Using a wrapper with @asyncio.coroutine in __get__ wasn't necessary (the future from asyncio.ensure_future is awaitable, and the wrapper doesn't do anything asynchronous), so the logic can be simplified to just call asyncio.ensure_future (to schedule the task and store the result when it's available). Tests for @asyncio.coroutine are skipped on 3.11+. An unnecessary call to asyncio.coroutine in tests is removed: it's not necessary to call this for `async def` functions. --- cached_property.py | 24 +++++++++++------------- conftest.py | 6 +++++- tests/test_async_cached_property.py | 3 +-- 3 files changed, 17 insertions(+), 16 deletions(-) diff --git a/cached_property.py b/cached_property.py index 3135871..254739c 100644 --- a/cached_property.py +++ b/cached_property.py @@ -13,6 +13,12 @@ import asyncio except (ImportError, SyntaxError): asyncio = None +try: + iscoroutinefunction = asyncio.iscoroutinefunction +except AttributeError: + # Python 3.11: @asyncio.coroutine was removed + from inspect import iscoroutinefunction + class cached_property(object): @@ -30,22 +36,14 @@ def __get__(self, obj, cls): if obj is None: return self - if asyncio and asyncio.iscoroutinefunction(self.func): - return self._wrap_in_coroutine(obj) + if asyncio and iscoroutinefunction(self.func): + value = asyncio.ensure_future(self.func(obj)) + else: + value = self.func(obj) - value = obj.__dict__[self.func.__name__] = self.func(obj) + obj.__dict__[self.func.__name__] = value return value - def _wrap_in_coroutine(self, obj): - @wraps(obj) - @asyncio.coroutine - def wrapper(): - future = asyncio.ensure_future(self.func(obj)) - obj.__dict__[self.func.__name__] = future - return future - - return wrapper() - class threaded_cached_property(object): """ diff --git a/conftest.py b/conftest.py index 0563f64..1c4b618 100644 --- a/conftest.py +++ b/conftest.py @@ -7,13 +7,17 @@ # Whether the async and await keywords work has_async_await = sys.version_info[0] == 3 and sys.version_info[1] >= 5 +# Whether "from asyncio import coroutine" *fails* +version_info = sys.version_info +dropped_asyncio_coroutine = version_info[0] == 3 and version_info[1] >= 11 + print("conftest.py", has_asyncio, has_async_await) collect_ignore = [] -if not has_asyncio: +if not has_asyncio or dropped_asyncio_coroutine: collect_ignore.append("tests/test_coroutine_cached_property.py") if not has_async_await: diff --git a/tests/test_async_cached_property.py b/tests/test_async_cached_property.py index 4ba84f3..d61cc28 100644 --- a/tests/test_async_cached_property.py +++ b/tests/test_async_cached_property.py @@ -9,8 +9,7 @@ def unittest_run_loop(f): def wrapper(*args, **kwargs): - coro = asyncio.coroutine(f) - future = coro(*args, **kwargs) + future = f(*args, **kwargs) loop = asyncio.get_event_loop() loop.run_until_complete(future) From 9b210d12fa73c91743378ba4a966417846e7ea9a Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Thu, 2 Dec 2021 11:44:18 +0100 Subject: [PATCH 2/2] Restore compatibility with python 2.7 This is still necessary according to the Contributing Guidelines. --- cached_property.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/cached_property.py b/cached_property.py index 254739c..944e2f5 100644 --- a/cached_property.py +++ b/cached_property.py @@ -13,12 +13,12 @@ import asyncio except (ImportError, SyntaxError): asyncio = None -try: - iscoroutinefunction = asyncio.iscoroutinefunction -except AttributeError: - # Python 3.11: @asyncio.coroutine was removed - from inspect import iscoroutinefunction - +if asyncio: + try: + iscoroutinefunction = asyncio.iscoroutinefunction + except AttributeError: + # Python 3.11: @asyncio.coroutine was removed + from inspect import iscoroutinefunction class cached_property(object):