* [gentoo-commits] proj/portage:master commit in: lib/portage/tests/util/futures/, lib/portage/util/futures/
@ 2018-09-03 20:23 Zac Medico
0 siblings, 0 replies; 2+ messages in thread
From: Zac Medico @ 2018-09-03 20:23 UTC (permalink / raw
To: gentoo-commits
commit: b37256a524a0fbf88ffad20c9f01aaf37409ec66
Author: Zac Medico <zmedico <AT> gentoo <DOT> org>
AuthorDate: Mon Sep 3 20:16:37 2018 +0000
Commit: Zac Medico <zmedico <AT> gentoo <DOT> org>
CommitDate: Mon Sep 3 20:20:40 2018 +0000
URL: https://gitweb.gentoo.org/proj/portage.git/commit/?id=b37256a5
compat_coroutine: CancelledError cancels coroutine's future
lib/portage/tests/util/futures/test_compat_coroutine.py | 8 ++++++--
lib/portage/util/futures/compat_coroutine.py | 2 ++
2 files changed, 8 insertions(+), 2 deletions(-)
diff --git a/lib/portage/tests/util/futures/test_compat_coroutine.py b/lib/portage/tests/util/futures/test_compat_coroutine.py
index cbc070869..b6f75b1a2 100644
--- a/lib/portage/tests/util/futures/test_compat_coroutine.py
+++ b/lib/portage/tests/util/futures/test_compat_coroutine.py
@@ -71,6 +71,10 @@ class CompatCoroutineTestCase(TestCase):
loop.run_until_complete, future)
def test_cancelled_future(self):
+ """
+ When a coroutine raises CancelledError, the coroutine's
+ future is cancelled.
+ """
@coroutine
def cancelled_future_coroutine(loop=None):
@@ -81,8 +85,8 @@ class CompatCoroutineTestCase(TestCase):
yield future
loop = asyncio.get_event_loop()
- self.assertRaises(asyncio.CancelledError,
- loop.run_until_complete, cancelled_future_coroutine(loop=loop))
+ future = loop.run_until_complete(asyncio.wait([cancelled_future_coroutine()]))[0].pop()
+ self.assertTrue(future.cancelled())
def test_yield_expression_result(self):
@coroutine
diff --git a/lib/portage/util/futures/compat_coroutine.py b/lib/portage/util/futures/compat_coroutine.py
index 59fdc31b6..3edfa6bee 100644
--- a/lib/portage/util/futures/compat_coroutine.py
+++ b/lib/portage/util/futures/compat_coroutine.py
@@ -102,6 +102,8 @@ class _GeneratorTask(object):
self._generator.throw(previous.exception())
future = next(self._generator)
+ except asyncio.CancelledError:
+ self._result.cancel()
except _CoroutineReturnValue as e:
if not self._result.cancelled():
self._result.set_result(e.result)
^ permalink raw reply related [flat|nested] 2+ messages in thread
* [gentoo-commits] proj/portage:master commit in: lib/portage/tests/util/futures/, lib/portage/util/futures/
@ 2018-09-24 6:12 Zac Medico
0 siblings, 0 replies; 2+ messages in thread
From: Zac Medico @ 2018-09-24 6:12 UTC (permalink / raw
To: gentoo-commits
commit: de0b60ff277311e780102131dce3111b4db1c196
Author: Zac Medico <zmedico <AT> gentoo <DOT> org>
AuthorDate: Sat Jul 28 13:53:11 2018 +0000
Commit: Zac Medico <zmedico <AT> gentoo <DOT> org>
CommitDate: Mon Sep 24 03:41:32 2018 +0000
URL: https://gitweb.gentoo.org/proj/portage.git/commit/?id=de0b60ff
Add _sync_decorator module
Add functions that decorate coroutine methods and functions for
synchronous usage, allowing coroutines to smoothly blend with
synchronous code. This eliminates clutter that might otherwise
discourage the proliferation of coroutine usage for I/O bound tasks.
In the next commit, _sync_decorator will be used for smooth
integration of new classes that have coroutine methods.
Bug: https://bugs.gentoo.org/662070
Reviewed-by: Brian Dolbec <dolsen <AT> gentoo.org>
Signed-off-by: Zac Medico <zmedico <AT> gentoo.org>
.../tests/util/futures/test_compat_coroutine.py | 14 ++++++
lib/portage/util/futures/_sync_decorator.py | 54 ++++++++++++++++++++++
2 files changed, 68 insertions(+)
diff --git a/lib/portage/tests/util/futures/test_compat_coroutine.py b/lib/portage/tests/util/futures/test_compat_coroutine.py
index b6f75b1a2..f96aa9be5 100644
--- a/lib/portage/tests/util/futures/test_compat_coroutine.py
+++ b/lib/portage/tests/util/futures/test_compat_coroutine.py
@@ -6,6 +6,7 @@ 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
@@ -161,3 +162,16 @@ class CompatCoroutineTestCase(TestCase):
loop.run_until_complete(asyncio.wait([writer, reader]))
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)
+ 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/_sync_decorator.py b/lib/portage/util/futures/_sync_decorator.py
new file mode 100644
index 000000000..02a0963a7
--- /dev/null
+++ b/lib/portage/util/futures/_sync_decorator.py
@@ -0,0 +1,54 @@
+# Copyright 2018 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',
+)
+
+
+def _sync_decorator(func, loop=None):
+ """
+ Decorate an asynchronous function (either a corouting function or a
+ function that returns a Future) with a wrapper that runs the function
+ synchronously.
+ """
+ loop = asyncio._wrap_loop(loop)
+ @functools.wraps(func)
+ def wrapper(*args, **kwargs):
+ return loop.run_until_complete(func(*args, **kwargs))
+ return wrapper
+
+
+def _sync_methods(obj, loop=None):
+ """
+ For use with synchronous code that needs to interact with an object
+ that has coroutine methods, this function generates a proxy which
+ conveniently converts coroutine methods into synchronous methods.
+ This allows coroutines to smoothly blend with synchronous
+ code, eliminating clutter that might otherwise discourage the
+ proliferation of coroutine usage for I/O bound tasks.
+ """
+ loop = asyncio._wrap_loop(loop)
+ return _ObjectAttrWrapper(obj,
+ lambda attr: _sync_decorator(attr, loop=loop)
+ if asyncio.iscoroutinefunction(attr) else attr)
+
+
+class _ObjectAttrWrapper(portage.proxy.objectproxy.ObjectProxy):
+
+ __slots__ = ('_obj', '_attr_wrapper')
+
+ def __init__(self, obj, attr_wrapper):
+ object.__setattr__(self, '_obj', obj)
+ object.__setattr__(self, '_attr_wrapper', attr_wrapper)
+
+ def __getattribute__(self, attr):
+ obj = object.__getattribute__(self, '_obj')
+ attr_wrapper = object.__getattribute__(self, '_attr_wrapper')
+ return attr_wrapper(getattr(obj, attr))
+
+ def _get_target(self):
+ return object.__getattribute__(self, '_obj')
^ permalink raw reply related [flat|nested] 2+ messages in thread
end of thread, other threads:[~2018-09-24 6:12 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2018-09-03 20:23 [gentoo-commits] proj/portage:master commit in: lib/portage/tests/util/futures/, lib/portage/util/futures/ Zac Medico
-- strict thread matches above, loose matches on Subject: below --
2018-09-24 6:12 Zac Medico
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox