Wraps ``subprocess.Popen`` with IOStream support. The constructor is the same as ``subprocess.Popen`` with the following additions: * ``stdin``, ``stdout``, and ``stderr`` may have the value ``tornado.process.Subprocess.STREAM``, which will make the corresponding attribute
| 186 | |
| 187 | |
| 188 | class Subprocess: |
| 189 | """Wraps ``subprocess.Popen`` with IOStream support. |
| 190 | |
| 191 | The constructor is the same as ``subprocess.Popen`` with the following |
| 192 | additions: |
| 193 | |
| 194 | * ``stdin``, ``stdout``, and ``stderr`` may have the value |
| 195 | ``tornado.process.Subprocess.STREAM``, which will make the corresponding |
| 196 | attribute of the resulting Subprocess a `.PipeIOStream`. If this option |
| 197 | is used, the caller is responsible for closing the streams when done |
| 198 | with them. |
| 199 | |
| 200 | The ``Subprocess.STREAM`` option and the ``set_exit_callback`` and |
| 201 | ``wait_for_exit`` methods do not work on Windows. There is |
| 202 | therefore no reason to use this class instead of |
| 203 | ``subprocess.Popen`` on that platform. |
| 204 | |
| 205 | .. versionchanged:: 5.0 |
| 206 | The ``io_loop`` argument (deprecated since version 4.1) has been removed. |
| 207 | |
| 208 | """ |
| 209 | |
| 210 | STREAM = object() |
| 211 | |
| 212 | _initialized = False |
| 213 | _waiting = {} # type: ignore |
| 214 | |
| 215 | def __init__(self, *args: Any, **kwargs: Any) -> None: |
| 216 | self.io_loop = ioloop.IOLoop.current() |
| 217 | # All FDs we create should be closed on error; those in to_close |
| 218 | # should be closed in the parent process on success. |
| 219 | pipe_fds = [] # type: List[int] |
| 220 | to_close = [] # type: List[int] |
| 221 | if kwargs.get("stdin") is Subprocess.STREAM: |
| 222 | in_r, in_w = os.pipe() |
| 223 | kwargs["stdin"] = in_r |
| 224 | pipe_fds.extend((in_r, in_w)) |
| 225 | to_close.append(in_r) |
| 226 | self.stdin = PipeIOStream(in_w) |
| 227 | if kwargs.get("stdout") is Subprocess.STREAM: |
| 228 | out_r, out_w = os.pipe() |
| 229 | kwargs["stdout"] = out_w |
| 230 | pipe_fds.extend((out_r, out_w)) |
| 231 | to_close.append(out_w) |
| 232 | self.stdout = PipeIOStream(out_r) |
| 233 | if kwargs.get("stderr") is Subprocess.STREAM: |
| 234 | err_r, err_w = os.pipe() |
| 235 | kwargs["stderr"] = err_w |
| 236 | pipe_fds.extend((err_r, err_w)) |
| 237 | to_close.append(err_w) |
| 238 | self.stderr = PipeIOStream(err_r) |
| 239 | try: |
| 240 | self.proc = subprocess.Popen(*args, **kwargs) |
| 241 | except: |
| 242 | for fd in pipe_fds: |
| 243 | os.close(fd) |
| 244 | raise |
| 245 | for fd in to_close: |
no outgoing calls