Gentoo Archives: gentoo-portage-dev

From: Matt Turner <mattst88@g.o>
To: gentoo-portage-dev@l.g.o
Cc: Matt Turner <mattst88@g.o>
Subject: [gentoo-portage-dev] [PATCH] Use asyncio.subprocess.Process directly
Date: Thu, 04 Mar 2021 19:25:02
Message-Id: 20210304192458.899911-1-mattst88@gentoo.org
1 With no need to support Python 2, we can remove our private
2 implementation.
3
4 Signed-off-by: Matt Turner <mattst88@g.o>
5 ---
6 I don't know how to test this. I intentionally broke the return value of
7 create_subprocess_exec and didn't see any bad results.
8
9 lib/portage/util/futures/_asyncio/__init__.py | 8 +-
10 lib/portage/util/futures/_asyncio/process.py | 116 ------------------
11 2 files changed, 4 insertions(+), 120 deletions(-)
12 delete mode 100644 lib/portage/util/futures/_asyncio/process.py
13
14 diff --git a/lib/portage/util/futures/_asyncio/__init__.py b/lib/portage/util/futures/_asyncio/__init__.py
15 index 5590963f1..207e7205d 100644
16 --- a/lib/portage/util/futures/_asyncio/__init__.py
17 +++ b/lib/portage/util/futures/_asyncio/__init__.py
18 @@ -25,6 +25,7 @@ import types
19 import weakref
20
21 import asyncio as _real_asyncio
22 +from asyncio.subprocess import Process
23
24 try:
25 import threading
26 @@ -45,7 +46,6 @@ from portage.util.futures.futures import (
27 TimeoutError,
28 )
29 # pylint: enable=redefined-builtin
30 -from portage.util.futures._asyncio.process import _Process
31 from portage.util.futures._asyncio.tasks import (
32 ALL_COMPLETED,
33 FIRST_COMPLETED,
34 @@ -124,8 +124,8 @@ def create_subprocess_exec(*args, **kwargs):
35 @type loop: event loop
36 @type kwargs: varies
37 @param kwargs: subprocess.Popen parameters
38 - @rtype: asyncio.Future (or compatible)
39 - @return: subset of asyncio.subprocess.Process interface
40 + @rtype: asyncio.subprocess.Process (or compatible)
41 + @return: asyncio.subprocess.Process interface
42 """
43 loop = _wrap_loop(kwargs.pop('loop', None))
44 # Python 3.4 and later implement PEP 446, which makes newly
45 @@ -138,7 +138,7 @@ def create_subprocess_exec(*args, **kwargs):
46
47 result = loop.create_future()
48
49 - result.set_result(_Process(subprocess.Popen(
50 + result.set_result(Process(subprocess.Popen(
51 args,
52 stdin=kwargs.pop('stdin', None),
53 stdout=kwargs.pop('stdout', None),
54 diff --git a/lib/portage/util/futures/_asyncio/process.py b/lib/portage/util/futures/_asyncio/process.py
55 deleted file mode 100644
56 index 275c9031a..000000000
57 --- a/lib/portage/util/futures/_asyncio/process.py
58 +++ /dev/null
59 @@ -1,116 +0,0 @@
60 -# Copyright 2018-2020 Gentoo Authors
61 -# Distributed under the terms of the GNU General Public License v2
62 -
63 -import os
64 -
65 -import portage
66 -portage.proxy.lazyimport.lazyimport(globals(),
67 - 'portage.util.futures:asyncio',
68 - 'portage.util.futures.unix_events:_set_nonblocking',
69 -)
70 -from portage.util.futures._asyncio.streams import _reader, _writer
71 -from portage.util.futures.compat_coroutine import coroutine, coroutine_return
72 -
73 -
74 -class _Process:
75 - """
76 - Emulate a subset of the asyncio.subprocess.Process interface,
77 - for python2.
78 - """
79 - def __init__(self, proc, loop):
80 - """
81 - @param proc: process instance
82 - @type proc: subprocess.Popen
83 - @param loop: asyncio.AbstractEventLoop (or compatible)
84 - @type loop: event loop
85 - """
86 - self._proc = proc
87 - self._loop = loop
88 - self.terminate = proc.terminate
89 - self.kill = proc.kill
90 - self.send_signal = proc.send_signal
91 - self.pid = proc.pid
92 - self._waiters = []
93 - loop._asyncio_child_watcher.\
94 - add_child_handler(self.pid, self._proc_exit)
95 -
96 - @property
97 - def returncode(self):
98 - return self._proc.returncode
99 -
100 - @coroutine
101 - def communicate(self, input=None, loop=None): # pylint: disable=redefined-builtin
102 - """
103 - Read data from stdout and stderr, until end-of-file is reached.
104 - Wait for process to terminate.
105 -
106 - @param input: stdin content to write
107 - @type input: bytes
108 - @return: tuple (stdout_data, stderr_data)
109 - @rtype: asyncio.Future (or compatible)
110 - """
111 - loop = asyncio._wrap_loop(loop or self._loop)
112 - futures = []
113 - for input_file in (self._proc.stdout, self._proc.stderr):
114 - if input_file is None:
115 - future = loop.create_future()
116 - future.set_result(None)
117 - else:
118 - future = _reader(input_file, loop=loop)
119 - futures.append(future)
120 -
121 - writer = None
122 - if input is not None:
123 - if self._proc.stdin is None:
124 - raise TypeError('communicate: expected file or int, got {}'.format(type(self._proc.stdin)))
125 - stdin = self._proc.stdin
126 - stdin = os.fdopen(stdin, 'wb', 0) if isinstance(stdin, int) else stdin
127 - _set_nonblocking(stdin.fileno())
128 - writer = asyncio.ensure_future(_writer(stdin, input, loop=loop), loop=loop)
129 - writer.add_done_callback(lambda writer: stdin.close())
130 -
131 - try:
132 - yield asyncio.wait(futures + [self.wait(loop=loop)], loop=loop)
133 - finally:
134 - if writer is not None:
135 - if writer.done():
136 - # Consume expected exceptions.
137 - try:
138 - writer.result()
139 - except EnvironmentError:
140 - # This is normal if the other end of the pipe was closed.
141 - pass
142 - else:
143 - writer.cancel()
144 -
145 - coroutine_return(tuple(future.result() for future in futures))
146 -
147 - def wait(self, loop=None):
148 - """
149 - Wait for child process to terminate. Set and return returncode attribute.
150 -
151 - @return: returncode
152 - @rtype: asyncio.Future (or compatible)
153 - """
154 - loop = asyncio._wrap_loop(loop or self._loop)
155 - waiter = loop.create_future()
156 - if self.returncode is None:
157 - self._waiters.append(waiter)
158 - waiter.add_done_callback(self._waiter_cancel)
159 - else:
160 - waiter.set_result(self.returncode)
161 - return waiter
162 -
163 - def _waiter_cancel(self, waiter):
164 - if waiter.cancelled():
165 - try:
166 - self._waiters.remove(waiter)
167 - except ValueError:
168 - pass
169 -
170 - def _proc_exit(self, pid, returncode):
171 - self._proc.returncode = returncode
172 - waiters = self._waiters
173 - self._waiters = []
174 - for waiter in waiters:
175 - waiter.set_result(returncode)
176 --
177 2.26.2

Replies