This repository was archived by the owner on Nov 23, 2017. It is now read-only.
-
-
Notifications
You must be signed in to change notification settings - Fork 178
/
Copy pathchild_process.py
132 lines (110 loc) · 3.69 KB
/
child_process.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
"""
Example of asynchronous interaction with a child python process.
This example shows how to attach an existing Popen object and use the low level
transport-protocol API. See shell.py and subprocess_shell.py for higher level
examples.
"""
import os
import sys
try:
import asyncio
except ImportError:
# asyncio is not installed
sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
import asyncio
if sys.platform == 'win32':
from asyncio.windows_utils import Popen, PIPE
from asyncio.windows_events import ProactorEventLoop
else:
from subprocess import Popen, PIPE
#
# Return a write-only transport wrapping a writable pipe
#
@asyncio.coroutine
def connect_write_pipe(file):
loop = asyncio.get_event_loop()
transport, _ = yield from loop.connect_write_pipe(asyncio.Protocol, file)
return transport
#
# Wrap a readable pipe in a stream
#
@asyncio.coroutine
def connect_read_pipe(file):
loop = asyncio.get_event_loop()
stream_reader = asyncio.StreamReader(loop=loop)
def factory():
return asyncio.StreamReaderProtocol(stream_reader)
transport, _ = yield from loop.connect_read_pipe(factory, file)
return stream_reader, transport
#
# Example
#
@asyncio.coroutine
def main(loop):
# program which prints evaluation of each expression from stdin
code = r'''if 1:
import os
def writeall(fd, buf):
while buf:
n = os.write(fd, buf)
buf = buf[n:]
while True:
s = os.read(0, 1024)
if not s:
break
s = s.decode('ascii')
s = repr(eval(s)) + '\n'
s = s.encode('ascii')
writeall(1, s)
'''
# commands to send to input
commands = iter([b"1+1\n",
b"2**16\n",
b"1/3\n",
b"'x'*50",
b"1/0\n"])
# start subprocess and wrap stdin, stdout, stderr
p = Popen([sys.executable, '-c', code],
stdin=PIPE, stdout=PIPE, stderr=PIPE)
stdin = yield from connect_write_pipe(p.stdin)
stdout, stdout_transport = yield from connect_read_pipe(p.stdout)
stderr, stderr_transport = yield from connect_read_pipe(p.stderr)
# interact with subprocess
name = {stdout: 'OUT', stderr: 'ERR'}
registered = {asyncio.Task(stderr.readline()): stderr,
asyncio.Task(stdout.readline()): stdout}
while registered:
# write command
cmd = next(commands, None)
if cmd is None:
stdin.close()
else:
print('>>>', cmd.decode('ascii').rstrip())
stdin.write(cmd)
# get and print lines from stdout, stderr
timeout = None
while registered:
done, pending = yield from asyncio.wait(
registered, timeout=timeout,
return_when=asyncio.FIRST_COMPLETED)
if not done:
break
for f in done:
stream = registered.pop(f)
res = f.result()
print(name[stream], res.decode('ascii').rstrip())
if res != b'':
registered[asyncio.Task(stream.readline())] = stream
timeout = 0.0
stdout_transport.close()
stderr_transport.close()
if __name__ == '__main__':
if sys.platform == 'win32':
loop = ProactorEventLoop()
asyncio.set_event_loop(loop)
else:
loop = asyncio.get_event_loop()
try:
loop.run_until_complete(main(loop))
finally:
loop.close()