Source code for langchain_experimental.llm_bash.bash

"""封装了对子进程的操作,用于运行命令。"""
from __future__ import annotations

import platform
import re
import subprocess
from typing import TYPE_CHECKING, List, Union
from uuid import uuid4

if TYPE_CHECKING:
    import pexpect


[docs]class BashProcess: """包装器,用于启动子进程。 使用Python内置的subprocess.run() 在Windows系统上**不**支持持久进程,因为pexpect使用Unix伪终端(ptys)。MacOS和Linux可以。 示例: .. code-block:: python from langchain_community.utilities.bash import BashProcess bash = BashProcess( strip_newlines = False, return_err_output = False, persistent = False ) bash.run('echo 'hello world'') """ strip_newlines: bool = False """是否在输出上运行.strip()函数""" return_err_output: bool = False """是否返回失败命令的输出,或者只返回错误消息和堆栈跟踪""" persistent: bool = False """是否生成持久会话 注意:不适用于Windows环境"""
[docs] def __init__( self, strip_newlines: bool = False, return_err_output: bool = False, persistent: bool = False, ): """ 使用默认设置进行初始化 """ self.strip_newlines = strip_newlines self.return_err_output = return_err_output self.prompt = "" self.process = None if persistent: self.prompt = str(uuid4()) self.process = self._initialize_persistent_process(self, self.prompt)
@staticmethod def _lazy_import_pexpect() -> pexpect: """仅在需要时导入pexpect。""" if platform.system() == "Windows": raise ValueError( "Persistent bash processes are not yet supported on Windows." ) try: import pexpect except ImportError: raise ImportError( "pexpect required for persistent bash processes." " To install, run `pip install pexpect`." ) return pexpect @staticmethod def _initialize_persistent_process(self: BashProcess, prompt: str) -> pexpect.spawn: # Start bash in a clean environment # Doesn't work on windows """初始化一个在干净环境中持久的bash设置。 注意:在Windows上不可用 参数: Prompt(str): 要执行的bash命令 """ # noqa: E501 pexpect = self._lazy_import_pexpect() process = pexpect.spawn( "env", ["-i", "bash", "--norc", "--noprofile"], encoding="utf-8" ) # Set the custom prompt process.sendline("PS1=" + prompt) process.expect_exact(prompt, timeout=10) return process
[docs] def run(self, commands: Union[str, List[str]]) -> str: """在现有的持久子进程中运行命令,或者在新的子进程环境中运行命令。 参数: commands(List[str]): 要在会话中执行的命令列表 """ # noqa: E501 if isinstance(commands, str): commands = [commands] commands = ";".join(commands) if self.process is not None: return self._run_persistent( commands, ) else: return self._run(commands)
def _run(self, command: str) -> str: """在子进程中运行命令并返回输出。 参数: command: 要运行的命令 """ # noqa: E501 try: output = subprocess.run( command, shell=True, check=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, ).stdout.decode() except subprocess.CalledProcessError as error: if self.return_err_output: return error.stdout.decode() return str(error) if self.strip_newlines: output = output.strip() return output
[docs] def process_output(self, output: str, command: str) -> str: """使用正则表达式从输出中删除命令 参数: output: 进程的输出字符串 command: 执行的命令 """ # noqa: E501 pattern = re.escape(command) + r"\s*\n" output = re.sub(pattern, "", output, count=1) return output.strip()
def _run_persistent(self, command: str) -> str: """在持久环境中运行命令并返回输出。 参数: command: 要执行的命令 """ # noqa: E501 pexpect = self._lazy_import_pexpect() if self.process is None: raise ValueError("Process not initialized") self.process.sendline(command) # Clear the output with an empty string self.process.expect(self.prompt, timeout=10) self.process.sendline("") try: self.process.expect([self.prompt, pexpect.EOF], timeout=10) except pexpect.TIMEOUT: return f"Timeout error while executing command {command}" if self.process.after == pexpect.EOF: return f"Exited with error status: {self.process.exitstatus}" output = self.process.before output = self.process_output(output, command) if self.strip_newlines: return output.strip() return output