@@ -686,6 +686,88 @@ async def execute():
686
686
687
687
self .assertIsNone (self .loop .run_until_complete (execute ()))
688
688
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
+
689
771
def test_subprocess_communicate_stdout (self ):
690
772
# See https://github.com/python/cpython/issues/100133
691
773
async def get_command_stdout (cmd , * args ):
0 commit comments