Context manager to do something with a command running via Popen. Parameters ---------- command : list of str | str Command to run as subprocess (see :class:`python:subprocess.Popen`). after : str Can be: - "wait" to use :meth:`~python:subprocess.Popen.wait`
(command, after="wait", verbose=None, *args, **kwargs)
| 195 | |
| 196 | @contextmanager |
| 197 | def running_subprocess(command, after="wait", verbose=None, *args, **kwargs): |
| 198 | """Context manager to do something with a command running via Popen. |
| 199 | |
| 200 | Parameters |
| 201 | ---------- |
| 202 | command : list of str | str |
| 203 | Command to run as subprocess (see :class:`python:subprocess.Popen`). |
| 204 | after : str |
| 205 | Can be: |
| 206 | |
| 207 | - "wait" to use :meth:`~python:subprocess.Popen.wait` |
| 208 | - "communicate" to use :meth:`~python.subprocess.Popen.communicate` |
| 209 | - "terminate" to use :meth:`~python:subprocess.Popen.terminate` |
| 210 | - "kill" to use :meth:`~python:subprocess.Popen.kill` |
| 211 | |
| 212 | %(verbose)s |
| 213 | *args, **kwargs : arguments |
| 214 | Additional arguments to pass to subprocess.Popen. |
| 215 | |
| 216 | Returns |
| 217 | ------- |
| 218 | p : instance of Popen |
| 219 | The process. |
| 220 | """ |
| 221 | _validate_type(after, str, "after") |
| 222 | _check_option("after", after, ["wait", "terminate", "kill", "communicate"]) |
| 223 | contexts = list() |
| 224 | for stdxxx in ("stderr", "stdout"): |
| 225 | if stdxxx not in kwargs: |
| 226 | kwargs[stdxxx] = subprocess.PIPE |
| 227 | contexts.append(stdxxx) |
| 228 | |
| 229 | # Check the PATH environment variable. If run_subprocess() is to be called |
| 230 | # frequently this should be refactored so as to only check the path once. |
| 231 | env = kwargs.get("env", os.environ) |
| 232 | if any(p.startswith("~") for p in env["PATH"].split(os.pathsep)): |
| 233 | warn( |
| 234 | "Your PATH environment variable contains at least one path " |
| 235 | 'starting with a tilde ("~") character. Such paths are not ' |
| 236 | "interpreted correctly from within Python. It is recommended " |
| 237 | 'that you use "$HOME" instead of "~".' |
| 238 | ) |
| 239 | if isinstance(command, str): |
| 240 | command_str = command |
| 241 | else: |
| 242 | command = [str(s) for s in command] |
| 243 | command_str = " ".join(s for s in command) |
| 244 | logger.info(f"Running subprocess: {command_str}") |
| 245 | try: |
| 246 | p = subprocess.Popen(command, *args, **kwargs) |
| 247 | except Exception: |
| 248 | if isinstance(command, str): |
| 249 | command_name = command.split()[0] |
| 250 | else: |
| 251 | command_name = command[0] |
| 252 | logger.error(f"Command not found: {command_name}") |
| 253 | raise |
| 254 | try: |
no test coverage detected