@@ -686,6 +686,88 @@ async def execute():
686686
687687 self .assertIsNone (self .loop .run_until_complete (execute ()))
688688
689+ async def check_stdout_output (self , coro , output ):
690+ proc = await coro
691+ stdout , _ = await proc .communicate ()
692+ self .assertEqual (stdout , output )
693+ self .assertEqual (proc .returncode , 0 )
694+ task = asyncio .create_task (proc .wait ())
695+ await asyncio .sleep (0 )
696+ self .assertEqual (task .result (), proc .returncode )
697+
698+ def test_create_subprocess_env_shell (self ) -> None :
699+ async def main () -> None :
700+ cmd = f'''{ sys .executable } -c "import os, sys; sys.stdout.write(os.getenv('FOO'))"'''
701+ env = {"FOO" : 'bar' }
702+ proc = await asyncio .create_subprocess_shell (
703+ cmd , env = env , stdout = subprocess .PIPE
704+ )
705+ return proc
706+
707+ self .loop .run_until_complete (self .check_stdout_output (main (), b'bar' ))
708+
709+ def test_create_subprocess_env_exec (self ) -> None :
710+ async def main () -> None :
711+ cmd = [sys .executable , "-c" ,
712+ "import os, sys; sys.stdout.write(os.getenv('FOO'))" ]
713+ env = {"FOO" : 'baz' }
714+ proc = await asyncio .create_subprocess_exec (
715+ * cmd , env = env , stdout = subprocess .PIPE
716+ )
717+ return proc
718+
719+ self .loop .run_until_complete (self .check_stdout_output (main (), b'baz' ))
720+
721+
722+ def test_subprocess_concurrent_wait (self ) -> None :
723+ async def main () -> None :
724+ proc = await asyncio .create_subprocess_exec (
725+ * PROGRAM_CAT ,
726+ stdin = subprocess .PIPE ,
727+ stdout = subprocess .PIPE ,
728+ )
729+ stdout , _ = await proc .communicate (b'some data' )
730+ self .assertEqual (stdout , b"some data" )
731+ self .assertEqual (proc .returncode , 0 )
732+ self .assertEqual (await asyncio .gather (* [proc .wait () for _ in range (10 )]),
733+ [proc .returncode ] * 10 )
734+
735+ self .loop .run_until_complete (main ())
736+
737+ def test_subprocess_consistent_callbacks (self ):
738+ events = []
739+ class MyProtocol (asyncio .SubprocessProtocol ):
740+ def __init__ (self , exit_future : asyncio .Future ) -> None :
741+ self .exit_future = exit_future
742+
743+ def pipe_data_received (self , fd , data ) -> None :
744+ events .append (('pipe_data_received' , fd , data ))
745+
746+ def pipe_connection_lost (self , fd , exc ) -> None :
747+ events .append ('pipe_connection_lost' )
748+
749+ def process_exited (self ) -> None :
750+ events .append ('process_exited' )
751+ self .exit_future .set_result (True )
752+
753+ async def main () -> None :
754+ loop = asyncio .get_running_loop ()
755+ exit_future = asyncio .Future ()
756+ code = 'import sys; sys.stdout.write("stdout"); sys.stderr.write("stderr")'
757+ transport , _ = await loop .subprocess_exec (lambda : MyProtocol (exit_future ),
758+ sys .executable , '-c' , code , stdin = None )
759+ await exit_future
760+ transport .close ()
761+ self .assertEqual (events , [
762+ ('pipe_data_received' , 1 , b'stdout' ),
763+ ('pipe_data_received' , 2 , b'stderr' ),
764+ 'pipe_connection_lost' ,
765+ 'pipe_connection_lost' ,
766+ 'process_exited' ,
767+ ])
768+
769+ self .loop .run_until_complete (main ())
770+
689771 def test_subprocess_communicate_stdout (self ):
690772 # See https://github.com/python/cpython/issues/100133
691773 async def get_command_stdout (cmd , * args ):
0 commit comments