How to stream stdout/stderr from a child process using asyncio, and obtain its exit code after?

前端 未结 3 1473
一向
一向 2020-12-19 15:51

Under Python 3.4 on Windows, I need to stream data written to stdout/stderr by a child process, i.e. receive its output as it occurs, using the asyncio framework introduced

3条回答
  •  夕颜
    夕颜 (楼主)
    2020-12-19 16:48

    The solution I've come up with so far uses SubprocessProtocol to receive output from the child process, and the associated transport to get the process' exit code. I don't know if this is optimal though. I've based my approach on an answer to a similar question by J.F. Sebastian.

    import asyncio
    import contextlib
    import os
    import locale
    
    
    class SubprocessProtocol(asyncio.SubprocessProtocol):
        def pipe_data_received(self, fd, data):
            if fd == 1:
                name = 'stdout'
            elif fd == 2:
                name = 'stderr'
            text = data.decode(locale.getpreferredencoding(False))
            print('Received from {}: {}'.format(name, text.strip()))
    
        def process_exited(self):
            loop.stop()
    
    
    if os.name == 'nt':
        # On Windows, the ProactorEventLoop is necessary to listen on pipes
        loop = asyncio.ProactorEventLoop()
        asyncio.set_event_loop(loop)
    else:
        loop = asyncio.get_event_loop()
    with contextlib.closing(loop):
        # This will only connect to the process
        transport = loop.run_until_complete(loop.subprocess_exec(
            SubprocessProtocol, 'python', '-c', 'print(\'Hello async world!\')'))[0]
        # Wait until process has finished
        loop.run_forever()
        print('Program exited with: {}'.format(transport.get_returncode()))
    

提交回复
热议问题