4545 'RunResult' , ['returncode' , 'out' , 'err' ]
4646)
4747
48- def _handle_process_output (process , selector ):
49- """Handle process output events with registered selectors."""
48+ def _handle_process_output (process , live_output , buf_out , buf_err ):
49+ """Handle process output until it is terminated."""
50+
51+ # Process output lines handlers
52+ def handle_stdout_line (line ):
53+ buf_out .write (line )
54+ if live_output :
55+ sys .stdout .write (line )
56+ def handle_stderr_line (line ):
57+ buf_err .write (line )
58+ if live_output :
59+ sys .stderr .write (line )
60+
61+ # Process output event handlers
62+ def handle_stdout_event (stream ):
63+ handle_stdout_line (stream .readline ())
64+ def handle_stderr_event (stream ):
65+ handle_stderr_line (stream .readline ())
66+
67+ # Register callback for read events from subprocess stdout/stderr streams
68+ selector = selectors .DefaultSelector ()
69+ selector .register (process .stdout , selectors .EVENT_READ , handle_stdout_event )
70+ selector .register (process .stderr , selectors .EVENT_READ , handle_stderr_event )
71+
5072 # Loop until subprocess is terminated
5173 while process .poll () is None :
5274 # Wait for events and handle them with their registered callbacks
@@ -55,6 +77,19 @@ def _handle_process_output(process, selector):
5577 callback = key .data
5678 callback (key .fileobj )
5779
80+ # Close selector
81+ selector .close ()
82+
83+ # The loop above stops processing output as soon as the process is
84+ # terminated. However, there may still be buffered output to flush.
85+ for line in process .stdout :
86+ handle_stdout_line (line )
87+ for line in process .stderr :
88+ handle_stderr_line (line )
89+
90+ # Ensure process is terminated
91+ process .wait ()
92+
5893def run_command (
5994 cmd ,
6095 live_output = True ,
@@ -105,43 +140,10 @@ def run_command(
105140 else :
106141 buf_err = io .StringIO ()
107142
108- # Process output lines handlers
109- def handle_stdout (stream ):
110- line = stream .readline ()
111- buf_out .write (line )
112- if live_output :
113- sys .stdout .write (line )
114- def handle_stderr (stream ):
115- line = stream .readline ()
116- buf_err .write (line )
117- if live_output :
118- sys .stderr .write (line )
119-
120- # Register callback for read events from subprocess stdout/stderr streams
121- selector = selectors .DefaultSelector ()
122- selector .register (process .stdout , selectors .EVENT_READ , handle_stdout )
123- selector .register (process .stderr , selectors .EVENT_READ , handle_stderr )
124-
125- # Handle process output with registered selectors
126- _handle_process_output (process , selector )
127-
128- # _handle_process_output stops processing output as soon as the process
129- # is terminated. However, there may still be buffered output to flush.
130- for line in process .stdout :
131- buf_out .write (line )
132- if live_output :
133- sys .stdout .write (line )
134- for line in process .stderr :
135- buf_err .write (line )
136- if live_output :
137- sys .stdout .write (line )
138-
139- # Ensure process is terminated
140- process .wait ()
141-
142- # Store buffered output
143- selector .close ()
143+ # Handle process output
144+ _handle_process_output (process , live_output , buf_out , buf_err )
144145
146+ # Get values for out/err buffers and close them
145147 out = buf_out .getvalue ()
146148 buf_out .close ()
147149 if merge_out_err :
0 commit comments