diff options
author | Zac Medico <zmedico@gentoo.org> | 2024-02-28 20:26:02 -0800 |
---|---|---|
committer | Zac Medico <zmedico@gentoo.org> | 2024-02-28 20:37:21 -0800 |
commit | b2d8226af4589d95f44d20d441056f645a523039 (patch) | |
tree | f2176bdb45dedacd57b1d51523c7a2c1bd9e9cd7 /lib | |
parent | gpkg: placate black (diff) | |
download | portage-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.build | 1 | ||||
-rw-r--r-- | lib/portage/tests/util/futures/test_compat_coroutine.py | 210 | ||||
-rw-r--r-- | lib/portage/util/futures/_asyncio/__init__.py | 15 | ||||
-rw-r--r-- | lib/portage/util/futures/compat_coroutine.py | 142 | ||||
-rw-r--r-- | lib/portage/util/futures/meson.build | 1 |
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', |