Требуется помощь Захват STDOUT в реальном времени из графического интерфейса pygtk в проекте python

1

Я работаю над проектом, в котором я хочу использовать утилиту командной строки cdparanoia из графического интерфейса pygtk python. Я использую Glade для разработки пользовательского интерфейса. Я попытался импортировать подпроцесс и использовать subprocess.Popen. Он работает, но он замораживает мой графический интерфейс (даже не допускает перерисовки окон) во время выполнения процесса. Не очень приятное взаимодействие для пользователя. Как я могу предотвратить это поведение? Я хотел бы поместить кнопку отмены в окне, но это будет работать, поскольку оно "зависает" от программы. В конечном счете, я хотел бы захватить stderr (как показано ниже, аудиоинформация передана в sox через stdout) и представить его как gtk.Expander с похожим взглядом на Synaptic, когда он устанавливает программу с возможностью видеть пользователя что происходит в реальном времени. Кроме того, я хотел бы использовать текст из индикатора прогресса (как показано ниже) для создания виджета индикатора реального прогресса. Как я могу заставить оболочку передавать информацию обратно на python в режиме реального времени, а не как только процесс завершается (когда он дает все это как один большой дамп информации)?

Информация в режиме реального времени, требуемая для захвата:

Working on me - me - DISK 01.flac
cdparanoia III release 10.2 (September 11, 2008)

Ripping from sector       0 (track  1 [0:00.00])
      to sector  325195 (track 15 [1:56.70])

outputting to stdout

 (== PROGRESS == [>                             | 004727 00 ] == :-) O ==)

Вот код, который я использовал до сих пор:

        quick = " -Z" if self.quick == True else ""
        command = "cdparanoia -w%s 1- -| sox -t wav - \"%s - %s - DISK %s%s.flac\"" %\
                    (
                        quick,
                        self.book_name.replace(" ", "_"),
                        self.author_name.replace(" ", "_"),
                        "0" if disc < 10 else "", 
                        disc
                    )
        print command
        shell = subprocess.Popen(command, shell=True, executable="/bin/bash",
                                    stdin=subprocess.PIPE,
                                    stdout=subprocess.PIPE,
                                    stderr=subprocess.PIPE
                                )
        data, err = shell.communicate(command)

С благодарностью, Narnie

Теги:
stdout
capture
pygtk

3 ответа

2
Лучший ответ

Я написал реализацию оболочки Python один раз, и она выполнила wget и фактическую консоль Python с полностью функциональным выходом.

Вам нужно использовать subprocess.Popen и писать непосредственно в sys.stdout:

process = subprocess.Popen(shlex.split(command), stdout = subprocess.PIPE, stderr = subprocess.STDOUT)
complete = False

while True:
  output = process.stdout.read(1)

  if output == '' and process.poll() != None:
    break

  if output != '':
    sys.stdout.write(output)
    sys.stdout.flush()
  • 0
    Это в соответствии с тем, что мне нужно. Я использовал shell = True и запускал его как таковой, я думаю, это то, что заморозило вещи. Все работает, читая stderr (куда программа отправляет свой текстовый вывод), но текст индикатора выполнения не захватывается). Есть идеи?
  • 0
    Кстати, мне тоже приятно узнать о синтаксическом анализаторе оболочки shlex. Не знал об этом раньше, и он прекрасно работает!
1

Если вы пишете программу GUI, которая читает из дескриптора файла, у вас есть два варианта использования диспетчера для интеграции событий дескриптора файла в цикл событий GUI. Общее описание циклов событий можно найти на Wikipedia. Конкретное описание для Gtk + можно найти в ссылке.

Решение для вашей проблемы: используйте функцию g_io_add_watch для интеграции вашего действия в основной цикл событий. Здесь - пример в C. Python должен быть аналогичным.

0

Да, здесь есть 2 вопроса. Во-первых, вам нужно указать тайм-аут чтения, чтобы вы не блокируете до завершения суб-процесса. Во-вторых, вероятно, что происходит буферизация, что нежелательно.

Для решения первой проблемы и чтения из подпроцесса асинхронно вы можете попробовать мой модуль subProcess с таймаутом: http://www.pixelbeat.org/libs/subProcess.py Обратите внимание: это просто, но только старые и только Linux. Он был использован в качестве основы для нового модуля подпроцесса python, так что вам лучше пойти с этим, если вам нужна переносимость.

Чтобы понять/контролировать любую дополнительную буферизацию, которая может произойти, см. http://www.pixelbeat.org/programming/stdio_buffering/

  • 0
    Спасибо за советы. Я буду стремиться прочитать ссылку. Для всех, кто следит, я также нашел этот полезный faq.pygtk.org/index.py?file=faq23.020.htp&req=show. Я использовал первый метод прямо сейчас, но, вероятно, реализую технику генератора в более окончательной версии.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню