Run command using subprocess.Popen. Run command and wait for command to complete. If the return code was zero then return, otherwise raise CalledProcessError. By default, this will also add stdout= and stderr=subproces.PIPE to the call to Popen to suppress printing to the terminal.
(command, return_code=False, verbose=None, *args, **kwargs)
| 100 | |
| 101 | @verbose |
| 102 | def run_subprocess(command, return_code=False, verbose=None, *args, **kwargs): |
| 103 | """Run command using subprocess.Popen. |
| 104 | |
| 105 | Run command and wait for command to complete. If the return code was zero |
| 106 | then return, otherwise raise CalledProcessError. |
| 107 | By default, this will also add stdout= and stderr=subproces.PIPE |
| 108 | to the call to Popen to suppress printing to the terminal. |
| 109 | |
| 110 | Parameters |
| 111 | ---------- |
| 112 | command : list of str | str |
| 113 | Command to run as subprocess (see subprocess.Popen documentation). |
| 114 | return_code : bool |
| 115 | If True, return the return code instead of raising an error if it's |
| 116 | non-zero. |
| 117 | |
| 118 | .. versionadded:: 0.20 |
| 119 | %(verbose)s |
| 120 | *args, **kwargs : arguments |
| 121 | Additional arguments to pass to subprocess.Popen. |
| 122 | |
| 123 | Returns |
| 124 | ------- |
| 125 | stdout : str |
| 126 | Stdout returned by the process. |
| 127 | stderr : str |
| 128 | Stderr returned by the process. |
| 129 | code : int |
| 130 | The return code, only returned if ``return_code == True``. |
| 131 | """ |
| 132 | all_out = "" |
| 133 | all_err = "" |
| 134 | # non-blocking adapted from https://stackoverflow.com/questions/375427/non-blocking-read-on-a-subprocess-pipe-in-python#4896288 # noqa: E501 |
| 135 | out_q = Queue() |
| 136 | err_q = Queue() |
| 137 | control_stdout = "stdout" not in kwargs |
| 138 | control_stderr = "stderr" not in kwargs |
| 139 | with running_subprocess(command, *args, **kwargs) as p: |
| 140 | if control_stdout: |
| 141 | out_t = Thread(target=_enqueue_output, args=(p.stdout, out_q)) |
| 142 | out_t.daemon = True |
| 143 | out_t.start() |
| 144 | if control_stderr: |
| 145 | err_t = Thread(target=_enqueue_output, args=(p.stderr, err_q)) |
| 146 | err_t.daemon = True |
| 147 | err_t.start() |
| 148 | while True: |
| 149 | do_break = p.poll() is not None |
| 150 | # read all current lines without blocking |
| 151 | while True: # process stdout |
| 152 | try: |
| 153 | out = out_q.get(timeout=0.01) |
| 154 | except Empty: |
| 155 | break |
| 156 | else: |
| 157 | out = out.decode("utf-8") |
| 158 | log_out = out.removesuffix("\n") |
| 159 | logger.info(log_out) |