Я работаю над проектом, в котором я хочу использовать утилиту командной строки 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
Я написал реализацию оболочки 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()
Если вы пишете программу GUI, которая читает из дескриптора файла, у вас есть два варианта использования диспетчера для интеграции событий дескриптора файла в цикл событий GUI. Общее описание циклов событий можно найти на Wikipedia. Конкретное описание для Gtk + можно найти в ссылке.
Решение для вашей проблемы: используйте функцию g_io_add_watch
для интеграции вашего действия в основной цикл событий. Здесь - пример в C. Python должен быть аналогичным.
Да, здесь есть 2 вопроса. Во-первых, вам нужно указать тайм-аут чтения, чтобы вы не блокируете до завершения суб-процесса. Во-вторых, вероятно, что происходит буферизация, что нежелательно.
Для решения первой проблемы и чтения из подпроцесса асинхронно вы можете попробовать мой модуль subProcess с таймаутом: http://www.pixelbeat.org/libs/subProcess.py Обратите внимание: это просто, но только старые и только Linux. Он был использован в качестве основы для нового модуля подпроцесса python, так что вам лучше пойти с этим, если вам нужна переносимость.
Чтобы понять/контролировать любую дополнительную буферизацию, которая может произойти, см. http://www.pixelbeat.org/programming/stdio_buffering/