Как использовать Pexpect для получения спонтанного вывода подпроцесса в Python - PullRequest
3 голосов
/ 17 ноября 2010

Это связано с моей другой публикацией проблема многопоточности с wx.TextCtrl (или лежащим в основе GTK +) , которая после исправления с вызовом взаимодействий GUI из основного потока, я считаю, что она снова приходит к проблеме буферизации конвейерного блока , Так как получить спонтанный вывод из subprocess.stdout?

Короче говоря, в настоящее время я использую subprocess.popen для запуска внешней длительно работающей программы.

    launchcmd=["EXTERNAL_PROGRAM_EXE"]
    p = subprocess.Popen(launchcmd, stdin=subprocess.PIPE, 
            stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    self.outputThread = BashProcessThread(p.stdout.readline)
    self.outputThread.start()
    # wx.TextCtrl is used to make input/output
    self.textctrl = wx.TextCtrl(self, style=wx.TE_PROCESS_ENTER|wx.TE_MULTILINE)

И я использую отдельный поток, чтобы прочитать стандартный вывод фоновой программы, с "wx.CallAfter" для обратного вызова.

class BashProcessThread(threading.Thread):
    def __init__(self, readlineFunc, textctrl):
        threading.Thread.__init__(self)
        self.readlineFunc = readlineFunc

    def run(self):
        while True:
           line = self.readlineFunc()
           wx.CallAfter(textctrl.AppendText(line))

Приведенный выше код распечатывает блок-зависание блока сообщений журнала подпроцесса (вместо того, чтобы самопроизвольно построчно), и худшим является то, что оставшиеся 5-6 строк сообщений журнала не могут быть своевременно напечатаны, пока пользователь не отправит следующий вход.

Из моего старого поста я узнал, что есть pty и pexpect, которые могут заставить подпроцесс думать, что он взаимодействует с псевдо-tty. Но как использовать pexpect, особенно учитывая, что фоновый процесс - это долгосрочное, независимое выполнение задачи?

например, если я использовал

child=pexpect.spawn(launchcmd)

Как я могу получить выходные данные и входные данные подпроцесса, чтобы я мог использовать wx.TextCtrl для печати выходных данных, а также использовать wx.TextCtrl для пересылки пользовательского ввода в подпроцесс?

Ответы [ 2 ]

11 голосов
/ 18 ноября 2010

Вы пробовали что-то вроде:

child = pexpect.spawn(launchcmd)
while True:
    try:
        child.expect('\n')
        print(child.before)
    except pexpect.EOF:
        break
1 голос
/ 11 июня 2014

Я обнаружил, что эти два метода хорошо работают для получения живого вывода.

Если вам не нужен параметр для взаимодействия с пользователем, как в фоновом процессе:

child = pexpect.spawn(launchcmd)
child.logfile = sys.stdout
child.expect(pexpect.EOF)
child.close()

ЕслиВы не использовали фоновый процесс и хотите иметь возможность взаимодействовать с программой (если она вас запрашивает).Здесь происходит то, что вы переходите в интерактивный режим, и pexpect пишет прямо на экран.Когда программа достигает своего конца / EOF, она выдает OSError.

child = pexpect.spawn(launchcmd)
try:
    child.interact()
except OSError:
    pass
child.close()    
...