Регистрация вывода внешней программы с помощью (wx)python

Я пишу графический интерфейс для использования команд oracle exp/imp и запуска sql-скриптов через sqlplus. Класс подпроцесса упрощает запуск команд, но мне нужна дополнительная функциональность. Я хочу избавиться от командной строки при использовании моего графического интерфейса wxPython, но мне все еще нужен способ показать вывод команд exp/imp.

Я уже пробовал эти два метода:

command = "exp userid=user/pwd@nsn file=dump.dmp"

process = subprocess.Popen(command, stdout=subprocess.PIPE)
output = process.communicate()[0]

process = subprocess.Popen(command, stdout=subprocess.PIPE)
process.wait()
output = process.stdout.read()

С помощью одного из этих методов (забыл каким) я действительно получил вывод exp/imp, но только после завершения команды, что совершенно бесполезно для меня, так как мне нужно частое обновление во время этих потенциально длительных операций. И sqlplus создал еще больше проблем, так как sqlplus в основном требует некоторого ввода при возникновении ошибки. Когда это происходит, python ждет завершения процесса, но пользователь не может видеть подсказку, поэтому вы не знаете, как долго ждать или что делать...

Я хотел бы иметь оболочку, которая выводит все, что я вижу в стандартной командной строке. Я хочу записать это в файл и показать его внутри элемента управления wxPython.

Я также попробовал код с этой страницы: http://code.activestate.com/recipes/440554/ но это также не может прочитать вывод. OutputWrapper из этого ответа также не работает: могу ли я перехватить все исключения из приложения wxPython?

Любая помощь будет оценена по достоинству!

EDIT:
Кажется, что подпроцессы не очищают свой вывод. Я уже пробовал это с .readline().
Мой инструмент должен работать в Windows и Unix, поэтому pexpect не является решением, если нет версии для Windows. И использование cx_oracle было бы излишним, так как мне пришлось бы перестраивать всю функциональность exp, imp и sqlplus.


person Fabian    schedule 10.02.2009    source источник
comment
почему что? не знаю, о чем вы говорите...   -  person Fabian    schedule 12.02.2009


Ответы (4)


Решение состоит в том, чтобы использовать список для вашей команды

command = ["exp", "userid=user/pwd@nsn", "file=dump.dmp"]
process = subprocess.Popen(command, stdout=subprocess.PIPE)

затем вы читаете process.stdout построчно:

line = process.stdout.readline()

таким образом вы можете обновить графический интерфейс без ожидания. ЕСЛИ запущенный вами подпроцесс (exp) сбрасывает выходные данные. Возможно, вывод буферизован, тогда вы ничего не увидите, пока буфер вывода не заполнится. Если это так, то вам, вероятно, не повезло.

person nosklo    schedule 10.02.2009

Если вы используете Linux, проверьте pexpect. Он делает именно то, что вы хотите.

Если вам нужно работать в Windows, возможно, вам следует стиснуть зубы и использовать привязки Python к Oracle, такие как cx_Oracle вместо запуска CL через subprocess.

person Ryan Ginstrom    schedule 10.02.2009

Могут ли эти решения также захватывать stderr? Я вижу, у вас есть опция stdout= выше. Как убедиться, что вы также получаете stderr? Другой вопрос: есть ли способ использовать import logging/import logging.handlers для захвата команды stdout/stderr. Было бы интересно иметь возможность использовать регистратор с его сборкой в ​​форматтерах/ротаторах и т.д.

person Community    schedule 20.02.2009
comment
документация для модуля python Subprocess показывает, что в дополнение к аргументу stdout есть также аргумент stderr.docs.python.org/library/subprocess.html - person Jon W; 29.07.2009

Попробуй это:

import subprocess

command = "ping google.com"

process = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE)
output = process.stdout
while 1:
    print output.readline(),
person Seb    schedule 10.02.2009
comment
не используйте shell=True. Он выполнит оболочку, и оболочка будет использоваться для выполнения команды, это еще один подпроцесс, без какой-либо выгоды. Это мешает и не имеет никакого отношения к проблеме. - person nosklo; 10.02.2009