Funkcja glib.spawn_async umożliwia podpięcie trzech wywołań zwrotnych wywoływanych przy zdarzeniu na stdout
, stderr
oraz po zakończeniu procesu.Mimicing glib.spawn_async z Popen ...
Jak mogę naśladować tę samą funkcjonalność z subprocess z wątkami lub asynio?
Bardziej interesuje mnie funkcjonalność niż gwintowanie/asynio, ale odpowiedź, która zawiera obie, przyniesie nagrodę.
Oto program zabawka, która pokazuje, co chcę zrobić:
import glib
import logging
import os
import gtk
class MySpawn(object):
def __init__(self):
self._logger = logging.getLogger(self.__class__.__name__)
def execute(self, cmd, on_done, on_stdout, on_stderr):
self.pid, self.idin, self.idout, self.iderr = \
glib.spawn_async(cmd,
flags=glib.SPAWN_DO_NOT_REAP_CHILD,
standard_output=True,
standard_error=True)
fout = os.fdopen(self.idout, "r")
ferr = os.fdopen(self.iderr, "r")
glib.child_watch_add(self.pid, on_done)
glib.io_add_watch(fout, glib.IO_IN, on_stdout)
glib.io_add_watch(ferr, glib.IO_IN, on_stderr)
return self.pid
if __name__ == '__main__':
logging.basicConfig(format='%(thread)d %(levelname)s: %(message)s',
level=logging.DEBUG)
cmd = '/usr/bin/git ls-remote https://github.com/DiffSK/configobj'.split()
def on_done(pid, retval, *args):
logging.info("That's all folks!…")
def on_stdout(fobj, cond):
"""This blocks which is fine for this toy example…"""
for line in fobj.readlines():
logging.info(line.strip())
return True
def on_stderr(fobj, cond):
"""This blocks which is fine for this toy example…"""
for line in fobj.readlines():
logging.error(line.strip())
return True
runner = MySpawn()
runner.execute(cmd, on_done, on_stdout, on_stderr)
try:
gtk.main()
except KeyboardInterrupt:
print('')
Dodam, że od readlines()
blokuje, powyższe będzie buforować wszystkie wyjścia i wysłać go na raz. Jeśli nie tego chcesz, musisz użyć readline()
i upewnić się, że po zakończeniu polecenia skończyłeś czytać wszystkie linie, których wcześniej nie czytałeś.
Dziękuję bardzo za poświęcenie czasu na napisanie tej odpowiedzi. – Sardathrion
Należy zauważyć, że powyższe spowoduje buforowanie linii w 'stdout' i' stderr', ponieważ blokuje 'readlines()'. Jeśli chcesz zaktualizować, jak to się dzieje, użyj 'read()', ale pamiętaj, aby opróżnić bufor po zakończeniu wątków czytnika. – Sardathrion