import collectionsimport subprocessimport warningsfrom . import protocolsfrom . import transportsfrom .log import loggerclass BaseSubprocessTransport(transports.SubprocessTransport):def __init__(self, loop, protocol, args, shell,stdin, stdout, stderr, bufsize,waiter=None, extra=None, **kwargs):super().__init__(extra)self._closed = Falseself._protocol = protocolself._loop = loopself._proc = Noneself._pid = Noneself._returncode = Noneself._exit_waiters = []self._pending_calls = collections.deque()self._pipes = {}self._finished = Falseif stdin == subprocess.PIPE:self._pipes[0] = Noneif stdout == subprocess.PIPE:self._pipes[1] = Noneif stderr == subprocess.PIPE:self._pipes[2] = None# Create the child process: set the _proc attributetry:self._start(args=args, shell=shell, stdin=stdin, stdout=stdout,stderr=stderr, bufsize=bufsize, **kwargs)except:self.close()raiseself._pid = self._proc.pidself._extra['subprocess'] = self._procif self._loop.get_debug():if isinstance(args, (bytes, str)):program = argselse:program = args[0]logger.debug('process %r created: pid %s',program, self._pid)self._loop.create_task(self._connect_pipes(waiter))def __repr__(self):info = [self.__class__.__name__]if self._closed:info.append('closed')if self._pid is not None:info.append(f'pid={self._pid}')if self._returncode is not None:info.append(f'returncode={self._returncode}')elif self._pid is not None:info.append('running')else:info.append('not started')stdin = self._pipes.get(0)if stdin is not None:info.append(f'stdin={stdin.pipe}')stdout = self._pipes.get(1)stderr = self._pipes.get(2)if stdout is not None and stderr is stdout:info.append(f'stdout=stderr={stdout.pipe}')else:if stdout is not None:info.append(f'stdout={stdout.pipe}')if stderr is not None:info.append(f'stderr={stderr.pipe}')return '<{}>'.format(' '.join(info))def _start(self, args, shell, stdin, stdout, stderr, bufsize, **kwargs):raise NotImplementedErrordef set_protocol(self, protocol):self._protocol = protocoldef get_protocol(self):return self._protocoldef is_closing(self):return self._closeddef close(self):if self._closed:returnself._closed = Truefor proto in self._pipes.values():if proto is None:continueproto.pipe.close()if (self._proc is not None and# has the child process finished?self._returncode is None and# the child process has finished, but the# transport hasn't been notified yet?self._proc.poll() is None):if self._loop.get_debug():logger.warning('Close running child process: kill %r', self)try:self._proc.kill()except ProcessLookupError:pass# Don't clear the _proc reference yet: _post_init() may still rundef __del__(self, _warn=warnings.warn):if not self._closed:_warn(f"unclosed transport {self!r}", ResourceWarning, source=self)self.close()def get_pid(self):return self._piddef get_returncode(self):return self._returncodedef get_pipe_transport(self, fd):if fd in self._pipes:return self._pipes[fd].pipeelse:return Nonedef _check_proc(self):if self._proc is None:raise ProcessLookupError()def send_signal(self, signal):self._check_proc()self._proc.send_signal(signal)def terminate(self):self._check_proc()self._proc.terminate()def kill(self):self._check_proc()self._proc.kill()async def _connect_pipes(self, waiter):try:proc = self._procloop = self._loopif proc.stdin is not None:_, pipe = await loop.connect_write_pipe(lambda: WriteSubprocessPipeProto(self, 0),proc.stdin)self._pipes[0] = pipeif proc.stdout is not None:_, pipe = await loop.connect_read_pipe(lambda: ReadSubprocessPipeProto(self, 1),proc.stdout)self._pipes[1] = pipeif proc.stderr is not None:_, pipe = await loop.connect_read_pipe(lambda: ReadSubprocessPipeProto(self, 2),proc.stderr)self._pipes[2] = pipeassert self._pending_calls is not Noneloop.call_soon(self._protocol.connection_made, self)for callback, data in self._pending_calls:loop.call_soon(callback, *data)self._pending_calls = Noneexcept (SystemExit, KeyboardInterrupt):raiseexcept BaseException as exc:if waiter is not None and not waiter.cancelled():waiter.set_exception(exc)else:if waiter is not None and not waiter.cancelled():waiter.set_result(None)def _call(self, cb, *data):if self._pending_calls is not None:self._pending_calls.append((cb, data))else:self._loop.call_soon(cb, *data)def _pipe_connection_lost(self, fd, exc):self._call(self._protocol.pipe_connection_lost, fd, exc)self._try_finish()def _pipe_data_received(self, fd, data):self._call(self._protocol.pipe_data_received, fd, data)def _process_exited(self, returncode):assert returncode is not None, returncodeassert self._returncode is None, self._returncodeif self._loop.get_debug():logger.info('%r exited with return code %r', self, returncode)self._returncode = returncodeif self._proc.returncode is None:# asyncio uses a child watcher: copy the status into the Popen# object. On Python 3.6, it is required to avoid a ResourceWarning.self._proc.returncode = returncodeself._call(self._protocol.process_exited)self._try_finish()# wake up futures waiting for wait()for waiter in self._exit_waiters:if not waiter.cancelled():waiter.set_result(returncode)self._exit_waiters = Noneasync def _wait(self):"""Wait until the process exit and return the process return code.This method is a coroutine."""if self._returncode is not None:return self._returncodewaiter = self._loop.create_future()self._exit_waiters.append(waiter)return await waiterdef _try_finish(self):assert not self._finishedif self._returncode is None:returnif all(p is not None and p.disconnectedfor p in self._pipes.values()):self._finished = Trueself._call(self._call_connection_lost, None)def _call_connection_lost(self, exc):try:self._protocol.connection_lost(exc)finally:self._loop = Noneself._proc = Noneself._protocol = Noneclass WriteSubprocessPipeProto(protocols.BaseProtocol):def __init__(self, proc, fd):self.proc = procself.fd = fdself.pipe = Noneself.disconnected = Falsedef connection_made(self, transport):self.pipe = transportdef __repr__(self):return f'<{self.__class__.__name__} fd={self.fd} pipe={self.pipe!r}>'def connection_lost(self, exc):self.disconnected = Trueself.proc._pipe_connection_lost(self.fd, exc)self.proc = Nonedef pause_writing(self):self.proc._protocol.pause_writing()def resume_writing(self):self.proc._protocol.resume_writing()class ReadSubprocessPipeProto(WriteSubprocessPipeProto,protocols.Protocol):def data_received(self, data):self.proc._pipe_data_received(self.fd, data)
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。