[gentoo-commits] proj/portage:master commit in: lib/portage/util/futures/_asyncio/, lib/portage/util/futures/

2018-09-24 Thread Zac Medico
commit: 48c06e489e695321e8059da2dac1c03f6624d2e8
Author: Zac Medico  gentoo  org>
AuthorDate: Mon Aug  6 06:43:41 2018 +
Commit: Zac Medico  gentoo  org>
CommitDate: Mon Sep 24 03:41:17 2018 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=48c06e48

Implement asyncio.iscoroutinefunction for compat_coroutine

Sometimes it's useful to test if a function is a coroutine function,
so implement a version of asyncio.iscoroutinefunction that works
with asyncio.coroutine as well as compat_coroutine.coroutine (since
both kinds of coroutine functions behave identically for our
purposes).

Reviewed-by: Brian Dolbec  gentoo.org>
Signed-off-by: Zac Medico  gentoo.org>

 lib/portage/util/futures/_asyncio/__init__.py | 14 ++
 lib/portage/util/futures/compat_coroutine.py  | 12 
 2 files changed, 26 insertions(+)

diff --git a/lib/portage/util/futures/_asyncio/__init__.py 
b/lib/portage/util/futures/_asyncio/__init__.py
index faab98e47..2a637624d 100644
--- a/lib/portage/util/futures/_asyncio/__init__.py
+++ b/lib/portage/util/futures/_asyncio/__init__.py
@@ -36,6 +36,7 @@ except ImportError:
 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
 from portage.util._eventloop.global_event_loop import (
@@ -152,6 +153,19 @@ def create_subprocess_exec(*args, **kwargs):
return result
 
 
+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
+   elif _real_asyncio is not None and 
_real_asyncio.iscoroutinefunction(func):
+   return True
+   return False
+
+
 class Task(Future):
"""
Schedule the execution of a coroutine: wrap it in a future. A task

diff --git a/lib/portage/util/futures/compat_coroutine.py 
b/lib/portage/util/futures/compat_coroutine.py
index 3edfa6bee..b5ff92faf 100644
--- a/lib/portage/util/futures/compat_coroutine.py
+++ b/lib/portage/util/futures/compat_coroutine.py
@@ -8,6 +8,17 @@ 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):
"""
@@ -34,6 +45,7 @@ def coroutine(generator_func):
@functools.wraps(generator_func)
def wrapped(*args, **kwargs):
return _generator_future(generator_func, *args, **kwargs)
+   wrapped._is_coroutine = _is_coroutine
return wrapped
 
 



[gentoo-commits] proj/portage:master commit in: lib/portage/util/futures/_asyncio/, lib/portage/util/futures/, ...

2018-08-05 Thread Zac Medico
commit: 6b4252d3a0f12808a5bcce888b7f68e1f84b5301
Author: Zac Medico  gentoo  org>
AuthorDate: Sat Jul 28 21:22:42 2018 +
Commit: Zac Medico  gentoo  org>
CommitDate: Mon Aug  6 04:38:41 2018 +
URL:https://gitweb.gentoo.org/proj/portage.git/commit/?id=6b4252d3

Add asyncio.create_subprocess_exec support for python2 (bug 662388)

The asyncio.create_subprocess_exec function is essential for
using subprocesses in coroutines, so add support to do this
for python2. This paves the way for extensive use of coroutines
in portage, since coroutines are well-suited for many portage
tasks that involve subprocesses.

Bug: https://bugs.gentoo.org/662388

 .../util/futures/asyncio/test_subprocess_exec.py   | 184 ++---
 lib/portage/util/futures/_asyncio/__init__.py  |  53 ++
 lib/portage/util/futures/_asyncio/process.py   | 107 
 lib/portage/util/futures/_asyncio/streams.py   |  96 +++
 lib/portage/util/futures/compat_coroutine.py   |   6 +-
 5 files changed, 315 insertions(+), 131 deletions(-)

diff --git a/lib/portage/tests/util/futures/asyncio/test_subprocess_exec.py 
b/lib/portage/tests/util/futures/asyncio/test_subprocess_exec.py
index 5a812ba6a..61646cb92 100644
--- a/lib/portage/tests/util/futures/asyncio/test_subprocess_exec.py
+++ b/lib/portage/tests/util/futures/asyncio/test_subprocess_exec.py
@@ -3,61 +3,16 @@
 
 import os
 import subprocess
-
-try:
-   from asyncio import create_subprocess_exec
-except ImportError:
-   create_subprocess_exec = None
+import sys
 
 from portage.process import find_binary
 from portage.tests import TestCase
 from portage.util._eventloop.global_event_loop import global_event_loop
 from portage.util.futures import asyncio
-from portage.util.futures.executor.fork import ForkExecutor
+from portage.util.futures._asyncio import create_subprocess_exec
+from portage.util.futures._asyncio.streams import _reader as reader
+from portage.util.futures.compat_coroutine import coroutine, coroutine_return
 from portage.util.futures.unix_events import DefaultEventLoopPolicy
-from _emerge.PipeReader import PipeReader
-
-
-def reader(input_file, loop=None):
-   """
-   Asynchronously read a binary input file.
-
-   @param input_file: binary input file
-   @type input_file: file
-   @param loop: event loop
-   @type loop: EventLoop
-   @return: bytes
-   @rtype: asyncio.Future (or compatible)
-   """
-   loop = asyncio._wrap_loop(loop)
-   future = loop.create_future()
-   _Reader(future, input_file, loop)
-   return future
-
-
-class _Reader(object):
-   def __init__(self, future, input_file, loop):
-   self._future = future
-   self._pipe_reader = PipeReader(
-   input_files={'input_file':input_file}, scheduler=loop)
-
-   self._future.add_done_callback(self._cancel_callback)
-   self._pipe_reader.addExitListener(self._eof)
-   self._pipe_reader.start()
-
-   def _cancel_callback(self, future):
-   if future.cancelled():
-   self._cancel()
-
-   def _eof(self, pipe_reader):
-   self._pipe_reader = None
-   self._future.set_result(pipe_reader.getvalue())
-
-   def _cancel(self):
-   if self._pipe_reader is not None and self._pipe_reader.poll() 
is None:
-   self._pipe_reader.removeExitListener(self._eof)
-   self._pipe_reader.cancel()
-   self._pipe_reader = None
 
 
 class SubprocessExecTestCase(TestCase):
@@ -76,99 +31,66 @@ class SubprocessExecTestCase(TestCase):

self.assertFalse(global_event_loop().is_closed())
 
def testEcho(self):
-   if create_subprocess_exec is None:
-   self.skipTest('create_subprocess_exec not implemented 
for python2')
-
args_tuple = (b'hello', b'world')
echo_binary = find_binary("echo")
self.assertNotEqual(echo_binary, None)
echo_binary = echo_binary.encode()
 
-   # Use os.pipe(), since this loop does not implement the
-   # ReadTransport necessary for subprocess.PIPE support.
-   stdout_pr, stdout_pw = os.pipe()
-   stdout_pr = os.fdopen(stdout_pr, 'rb', 0)
-   stdout_pw = os.fdopen(stdout_pw, 'wb', 0)
-   files = [stdout_pr, stdout_pw]
-
def test(loop):
-   output = None
-   try:
-   with open(os.devnull, 'rb', 0) as devnull:
-   proc = loop.run_until_complete(
-   create_subprocess_exec(
-   echo_binary, *args_tuple,
-   stdin=devnull,