In debug mode, BaseEventLoop._run_once() now sets the BaseEventLoop._current_handle attribute to the handle currently executed. In release mode or when no handle is executed, the attribute is None. BaseEventLoop.default_exception_handler() displays the traceback of the current handle if available.
129 lines
3.7 KiB
Python
129 lines
3.7 KiB
Python
"""
|
|
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()
|