aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorZac Medico <zmedico@gentoo.org>2024-02-28 20:26:02 -0800
committerZac Medico <zmedico@gentoo.org>2024-02-28 20:37:21 -0800
commitb2d8226af4589d95f44d20d441056f645a523039 (patch)
treef2176bdb45dedacd57b1d51523c7a2c1bd9e9cd7 /lib
parentgpkg: placate black (diff)
downloadportage-b2d8226af4589d95f44d20d441056f645a523039.tar.gz
portage-b2d8226af4589d95f44d20d441056f645a523039.tar.bz2
portage-b2d8226af4589d95f44d20d441056f645a523039.zip
Delete compat_coroutine module
The compat_coroutine module has been unused since the migration to PEP 492 async and await syntax in 2021, which began in commit b3b9acc13c43 and was completed in commit bcda30d0a6fa. Signed-off-by: Zac Medico <zmedico@gentoo.org>
Diffstat (limited to 'lib')
-rw-r--r--lib/portage/tests/util/futures/meson.build1
-rw-r--r--lib/portage/tests/util/futures/test_compat_coroutine.py210
-rw-r--r--lib/portage/util/futures/_asyncio/__init__.py15
-rw-r--r--lib/portage/util/futures/compat_coroutine.py142
-rw-r--r--lib/portage/util/futures/meson.build1
5 files changed, 1 insertions, 368 deletions
diff --git a/lib/portage/tests/util/futures/meson.build b/lib/portage/tests/util/futures/meson.build
index 877acc27c..cb7831484 100644
--- a/lib/portage/tests/util/futures/meson.build
+++ b/lib/portage/tests/util/futures/meson.build
@@ -1,6 +1,5 @@
py.install_sources(
[
- 'test_compat_coroutine.py',
'test_done_callback.py',
'test_done_callback_after_exit.py',
'test_iter_completed.py',
diff --git a/lib/portage/tests/util/futures/test_compat_coroutine.py b/lib/portage/tests/util/futures/test_compat_coroutine.py
deleted file mode 100644
index b25708886..000000000
--- a/lib/portage/tests/util/futures/test_compat_coroutine.py
+++ /dev/null
@@ -1,210 +0,0 @@
-# Copyright 2018 Gentoo Foundation
-# Distributed under the terms of the GNU General Public License v2
-
-from portage.util.futures import asyncio
-from portage.util.futures.compat_coroutine import (
- coroutine,
- coroutine_return,
-)
-from portage.util.futures._sync_decorator import _sync_decorator, _sync_methods
-from portage.tests import TestCase
-
-
-class CompatCoroutineTestCase(TestCase):
- def test_returning_coroutine(self):
- @coroutine
- def returning_coroutine(loop=None):
- yield asyncio.sleep(0, loop=loop)
- coroutine_return("success")
-
- loop = asyncio.get_event_loop()
- self.assertEqual(
- "success",
- asyncio.get_event_loop().run_until_complete(returning_coroutine(loop=loop)),
- )
-
- def test_raising_coroutine(self):
- class TestException(Exception):
- pass
-
- @coroutine
- def raising_coroutine(loop=None):
- yield asyncio.sleep(0, loop=loop)
- raise TestException("exception")
-
- loop = asyncio.get_event_loop()
- self.assertRaises(
- TestException, loop.run_until_complete, raising_coroutine(loop=loop)
- )
-
- def test_catching_coroutine(self):
- class TestException(Exception):
- pass
-
- @coroutine
- def catching_coroutine(loop=None):
- loop = asyncio._wrap_loop(loop)
- future = loop.create_future()
- loop.call_soon(future.set_exception, TestException("exception"))
- try:
- yield future
- except TestException:
- self.assertTrue(True)
- else:
- self.assertTrue(False)
- coroutine_return("success")
-
- loop = asyncio.get_event_loop()
- self.assertEqual(
- "success", loop.run_until_complete(catching_coroutine(loop=loop))
- )
-
- def test_cancelled_coroutine(self):
- """
- Verify that a coroutine can handle (and reraise) asyncio.CancelledError
- in order to perform any necessary cleanup. Note that the
- asyncio.CancelledError will only be thrown in the coroutine if there's
- an opportunity (yield) before the generator raises StopIteration.
- """
- loop = asyncio.get_event_loop()
- ready_for_exception = loop.create_future()
- exception_in_coroutine = loop.create_future()
-
- @coroutine
- def cancelled_coroutine(loop=None):
- loop = asyncio._wrap_loop(loop)
- while True:
- task = loop.create_future()
- try:
- ready_for_exception.set_result(None)
- yield task
- except BaseException as e:
- # Since python3.8, asyncio.CancelledError inherits
- # from BaseException.
- task.done() or task.cancel()
- exception_in_coroutine.set_exception(e)
- raise
- else:
- exception_in_coroutine.set_result(None)
-
- future = cancelled_coroutine(loop=loop)
- loop.run_until_complete(ready_for_exception)
- future.cancel()
-
- self.assertRaises(asyncio.CancelledError, loop.run_until_complete, future)
-
- self.assertRaises(
- asyncio.CancelledError, loop.run_until_complete, exception_in_coroutine
- )
-
- def test_cancelled_future(self):
- """
- When a coroutine raises CancelledError, the coroutine's
- future is cancelled.
- """
-
- @coroutine
- def cancelled_future_coroutine(loop=None):
- loop = asyncio._wrap_loop(loop)
- while True:
- future = loop.create_future()
- loop.call_soon(future.cancel)
- yield future
-
- loop = asyncio.get_event_loop()
- future = loop.run_until_complete(
- asyncio.wait([cancelled_future_coroutine(loop=loop)], loop=loop)
- )[0].pop()
- self.assertTrue(future.cancelled())
-
- def test_yield_expression_result(self):
- @coroutine
- def yield_expression_coroutine(loop=None):
- for i in range(3):
- x = yield asyncio.sleep(0, result=i, loop=loop)
- self.assertEqual(x, i)
-
- loop = asyncio.get_event_loop()
- loop.run_until_complete(yield_expression_coroutine(loop=loop))
-
- def test_method_coroutine(self):
- class Cubby:
- _empty = object()
-
- def __init__(self, loop):
- self._loop = loop
- self._value = self._empty
- self._waiters = []
-
- def _notify(self):
- waiters = self._waiters
- self._waiters = []
- for waiter in waiters:
- waiter.cancelled() or waiter.set_result(None)
-
- def _wait(self):
- waiter = self._loop.create_future()
- self._waiters.append(waiter)
- return waiter
-
- @coroutine
- def read(self, loop=None):
- while self._value is self._empty:
- yield self._wait()
-
- value = self._value
- self._value = self._empty
- self._notify()
- coroutine_return(value)
-
- @coroutine
- def write(self, value, loop=None):
- while self._value is not self._empty:
- yield self._wait()
-
- self._value = value
- self._notify()
-
- @coroutine
- def writer_coroutine(cubby, values, sentinel, loop=None):
- for value in values:
- yield cubby.write(value, loop=loop)
- yield cubby.write(sentinel, loop=loop)
-
- @coroutine
- def reader_coroutine(cubby, sentinel, loop=None):
- results = []
- while True:
- result = yield cubby.read(loop=loop)
- if result == sentinel:
- break
- results.append(result)
- coroutine_return(results)
-
- loop = asyncio.get_event_loop()
- cubby = Cubby(loop)
- values = list(range(3))
- writer = asyncio.ensure_future(
- writer_coroutine(cubby, values, None, loop=loop), loop=loop
- )
- reader = asyncio.ensure_future(
- reader_coroutine(cubby, None, loop=loop), loop=loop
- )
- loop.run_until_complete(asyncio.wait([writer, reader], loop=loop))
-
- self.assertEqual(reader.result(), values)
-
- # Test decoration of coroutine methods and functions for
- # synchronous usage, allowing coroutines to smoothly
- # blend with synchronous code.
- sync_cubby = _sync_methods(cubby, loop=loop)
- sync_reader = _sync_decorator(reader_coroutine, loop=loop)
- writer = asyncio.ensure_future(
- writer_coroutine(cubby, values, None, loop=loop), loop=loop
- )
- self.assertEqual(sync_reader(cubby, None), values)
- self.assertTrue(writer.done())
-
- for i in range(3):
- sync_cubby.write(i)
- self.assertEqual(sync_cubby.read(), i)
diff --git a/lib/portage/util/futures/_asyncio/__init__.py b/lib/portage/util/futures/_asyncio/__init__.py
index 4eecc46a8..e377a9cdd 100644
--- a/lib/portage/util/futures/_asyncio/__init__.py
+++ b/lib/portage/util/futures/_asyncio/__init__.py
@@ -38,6 +38,7 @@ from asyncio import (
FIRST_EXCEPTION,
Future,
InvalidStateError,
+ iscoroutinefunction,
Lock as _Lock,
shield,
TimeoutError,
@@ -51,7 +52,6 @@ import portage
portage.proxy.lazyimport.lazyimport(
globals(),
"portage.util.futures.unix_events:_PortageEventLoopPolicy",
- "portage.util.futures:compat_coroutine@_compat_coroutine",
)
from portage.util._eventloop.asyncio_event_loop import (
AsyncioEventLoop as _AsyncioEventLoop,
@@ -158,19 +158,6 @@ def wait(futures, loop=None, timeout=None, return_when=ALL_COMPLETED):
return _real_asyncio.wait(futures, timeout=timeout, return_when=return_when)
-def iscoroutinefunction(func):
- """
- Return True if func is a decorated coroutine function,
- supporting both asyncio.coroutine and compat_coroutine since
- their behavior is identical for all practical purposes.
- """
- if _compat_coroutine._iscoroutinefunction(func):
- return True
- if _real_asyncio.iscoroutinefunction(func):
- return True
- return False
-
-
class Lock(_Lock):
"""
Inject loop parameter for python3.9 or less in order to avoid
diff --git a/lib/portage/util/futures/compat_coroutine.py b/lib/portage/util/futures/compat_coroutine.py
deleted file mode 100644
index afb850040..000000000
--- a/lib/portage/util/futures/compat_coroutine.py
+++ /dev/null
@@ -1,142 +0,0 @@
-# Copyright 2018-2021 Gentoo Foundation
-# Distributed under the terms of the GNU General Public License v2
-
-import functools
-
-import portage
-
-portage.proxy.lazyimport.lazyimport(
- globals(),
- "portage.util.futures:asyncio",
-)
-
-# A marker for iscoroutinefunction.
-_is_coroutine = object()
-
-
-def _iscoroutinefunction(func):
- """
- Return True if func is a decorated coroutine function
- created with the coroutine decorator for this module.
- """
- return getattr(func, "_is_coroutine", None) is _is_coroutine
-
-
-def coroutine(generator_func):
- """
- A decorator for a generator function that behaves as coroutine function.
- The generator should yield a Future instance in order to wait for it,
- and the result becomes the result of the current yield-expression,
- via the PEP 342 generator send() method.
-
- The decorated function returns a Future which is done when the generator
- is exhausted. The generator can return a value via the coroutine_return
- function.
-
- @param generator_func: A generator function that yields Futures, and
- will receive the result of each Future as the result of the
- corresponding yield-expression.
- @type generator_func: function
- @rtype: function
- @return: A function which calls the given generator function and
- returns a Future that is done when the generator is exhausted.
- """
-
- # Note that functools.partial does not work for decoration of
- # methods, since it doesn't implement the descriptor protocol.
- # This problem is solve by defining a wrapper function.
- @functools.wraps(generator_func)
- def wrapped(*args, **kwargs):
- return _generator_future(generator_func, *args, **kwargs)
-
- wrapped._is_coroutine = _is_coroutine
- return wrapped
-
-
-def coroutine_return(result=None):
- """
- Terminate the current coroutine and set the result of the associated
- Future.
-
- @param result: of the current coroutine's Future
- @type object
- """
- raise _CoroutineReturnValue(result)
-
-
-def _generator_future(generator_func, *args, **kwargs):
- """
- Call generator_func with the given arguments, and return a Future
- that is done when the resulting generation is exhausted. If a
- keyword argument named 'loop' is given, then it is used instead of
- the default event loop.
- """
- loop = kwargs.get("loop")
- loop = asyncio._wrap_loop(loop)
- result = loop.create_future()
- _GeneratorTask(generator_func(*args, **kwargs), result, loop=loop)
- return result
-
-
-class _CoroutineReturnValue(Exception):
- def __init__(self, result):
- self.result = result
-
-
-class _GeneratorTask:
- """
- Asynchronously executes the generator to completion, waiting for
- the result of each Future that it yields, and sending the result
- to the generator.
- """
-
- def __init__(self, generator, result, loop):
- self._generator = generator
- self._result = result
- self._current_task = None
- self._loop = loop
- result.add_done_callback(self._cancel_callback)
- loop.call_soon(self._next)
-
- def _cancel_callback(self, result):
- if result.cancelled() and self._current_task is not None:
- # The done callback for self._current_task invokes
- # _next in either case here.
- self._current_task.done() or self._current_task.cancel()
-
- def _next(self, previous=None):
- self._current_task = None
- if self._result.cancelled():
- if previous is not None:
- # Consume exceptions, in order to avoid triggering
- # the event loop's exception handler.
- previous.cancelled() or previous.exception()
-
- # This will throw asyncio.CancelledError in the coroutine if
- # there's an opportunity (yield) before the generator raises
- # StopIteration.
- previous = self._result
- try:
- if previous is None:
- future = next(self._generator)
- elif previous.cancelled():
- future = self._generator.throw(asyncio.CancelledError())
- elif previous.exception() is None:
- future = self._generator.send(previous.result())
- else:
- future = self._generator.throw(previous.exception())
-
- except asyncio.CancelledError:
- self._result.cancel()
- except _CoroutineReturnValue as e:
- if not self._result.cancelled():
- self._result.set_result(e.result)
- except StopIteration:
- if not self._result.cancelled():
- self._result.set_result(None)
- except Exception as e:
- if not self._result.cancelled():
- self._result.set_exception(e)
- else:
- self._current_task = asyncio.ensure_future(future, loop=self._loop)
- self._current_task.add_done_callback(self._next)
diff --git a/lib/portage/util/futures/meson.build b/lib/portage/util/futures/meson.build
index 90bfc8666..d561fa312 100644
--- a/lib/portage/util/futures/meson.build
+++ b/lib/portage/util/futures/meson.build
@@ -1,6 +1,5 @@
py.install_sources(
[
- 'compat_coroutine.py',
'extendedfutures.py',
'futures.py',
'iter_completed.py',