Seite 1 von 2
[Ungelöst] Output vom ``subprocess`` ungepuffert lesen
Verfasst: Samstag 27. Januar 2007, 17:43
von sape
Vorheriger Thread:
http://www.python-forum.de/topic-9027.h ... hlight=24h
Um das geht es eigentlich:
http://www.python-forum.de/post-56625.html#56625
@Gerold:
Danke für deine Beispiele, aber die machen immer ncoh nicht das was ich eigentlich meinte. In der Konsole, gibt der Server alle 3 Sekunden
Code: Alles auswählen
print
print "Ausgabe des Servers:"
print "********************"
for key, value in ini.items("values"):
print key, value
print "********************"
aus.
Aber nur in der Konsole.
Wenn es außerhalb einer Konsole gestartet wird (z.B. Eclipse, oder einfach nur von einem wxPython Programm), wird die Meldung vom Server erst ausgegeben, wenn der Client durch ist. Ich will es aber gerne wirklich Synchron haben. Ist da überhaupt möglich?
Hier mal ein Beispiel was ich meine (Hab beide Scripte in einen Paste kopiert!):
http://paste.pocoo.org/show/823/
...
Es geht mir darum ein Script-Starte zu schreiben. Die Ausgabe vom gestarteten Script, soll dann z.B. in einer Instanz von ``wx.TextCtrl`` ausgegeben werden, aber zur Laufzeit. Wenn man im zum Startenden Script ein ``time.sleep`` einbaut, kann man gut sehen, das ``stdout`` vom gestarteten Prozess erst ausgegeben wird, wenn der Prozess terminiert wurde.
lg
EDIT:
wx.lib.shell.PyShell ist keine Option. Damit würde es gehen, da ich damit ein Python-Script ausführen kann. Aber Ich will ja nicht nur Pyhon-Scripte, sondern auch andere (z.B. Ruby, etc) Ausführenen können. Daher muss ich mir so ein Sarter fertig machen.
Verfasst: Samstag 27. Januar 2007, 18:55
von BlackJack
Du darfst halt nicht mit `read()` arbeiten weil das erst zurückkehrt wenn alles gelesen wurde, dass heisst die Gegenseite die Datei schliesst, also bei den `std*`-Dateien bei Programmende.
Wenn `stderr` und `stdout` der Gegenseite gleich behandelt werden sollen, dann einfach `stderr` nach `stdout` umleiten statt eine eigene Pipe dafür zu verwenden, ansonsten muss man mit `select.select()` oder Threads arbeiten, um beide Kanäle gleichzeitig bearbeiten zu können.
(Den paste-Code konnte ich mir nicht anschauen, da gab's gerade einen `500 - internal server error`)
Re: Output eines ``subprocess`` während der Laufzeit lesen..
Verfasst: Samstag 27. Januar 2007, 19:04
von gerold
sape hat geschrieben:Ich will es aber gerne wirklich Synchron haben. Ist da überhaupt möglich?
[...]
Die Ausgabe vom gestarteten Script, soll dann z.B. in einer Instanz von ``wx.TextCtrl`` ausgegeben werden, aber zur Laufzeit.
Hi sape!
Das zu startende Skript oder Programm muss mitspielen. Python hat dafür den Befehl ``sys.stdout.flush()``. Damit kann man den soeben geschriebenen Text vom Buffer rausschieben.
client.py:
Code: Alles auswählen
#!/usr/bin/env python
# -*- coding: iso-8859-1 -*-
import os
import sys
import subprocess
proc = subprocess.Popen(
(sys.executable, "server.py"),
stdout = subprocess.PIPE,
cwd = os.curdir,
)
while True:
line = proc.stdout.readline()
if not line:
break
print "Vom Client ausgegeben:", line,
server.py:
Code: Alles auswählen
#!/usr/bin/env python
# -*- coding: iso-8859-1 -*-
import os
import sys
import time
def main():
for i in range(3):
print "Hallo %i" % i
sys.stdout.flush()
time.sleep(1)
if __name__ == "__main__":
main()
Ich sehe also keine Probleme bei eigenen Python- oder Ruby-Skripten. Du musst dich nur darum kümmern, dass die Skripte öfter mal ein Flush eingebaut bekommen. Bei Exe-Dateien wird es schwierig. Da kannst du nicht eingreifen.
Unter Linux kannst du mit dem Modul `pty` oder besser mit `pexpect` arbeiten, aber unter Windows weiß ich keine Möglichkeit, das EXE-Programm dazu zu bewegen, keinen Buffer zu verwenden.
mfg
Gerold

Re: Output eines ``subprocess`` während der Laufzeit lesen..
Verfasst: Samstag 27. Januar 2007, 19:27
von sape
Jack, sorry aber so ganz verstehe ich das nicht
Gerold, das ist ja gerade das Problem. ``sys.stdout.flush`` bringt das nicht das gewünschte Ergebnis.
gerold hat geschrieben:
Ich sehe also keine Probleme bei eigenen Python- oder Ruby-Skripten. Du musst dich nur darum kümmern, dass die Skripte öfter mal ein Flush eingebaut bekommen. Bei Exe-Dateien wird es schwierig. Da kannst du nicht eingreifen.
Ne, das ist nicht das was ich wollte. Ich will einen IDE wie jEdit + Eclipse in Python mit wxPython schrieben (Ja es gibt schon viele, aber keiner der Editoren erfüllt ganz meine Vorstellungen und es ist IMHO ein schönes Projekt und man kann da viel lernen

) -- wxAui wird mir dafür dienlich sein. Nun will ich ein Python oder Ruby Script da sich dann in der IDE geschriebene habe ausführen und ``stdout`` und ``stderr`` soll dann "Synchron" ausgegeben werden und nicht erst wenn das Script fertig ist.
gerold hat geschrieben:
Unter Linux kannst du mit dem Modul `pty` oder besser mit `pexpect` arbeiten, aber unter Windows weiß ich keine Möglichkeit, das EXE-Programm dazu zu bewegen, keinen Buffer zu verwenden.
Schade :-[
Aber Eclipse macht das doch auch irgendwie? Wenn ich über Eclipse ein Script starte, dann wird ``stdout`` auch nicht erst ausgegeben, wenn das Script beendet ist, sondern Synchron.
Z.B:
Code: Alles auswählen
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from time import sleep
import sys
for i in xrange(2):
print i
sleep(1)
Wenn ich das Script über Eclispe starte, erscheint erstmal eine 1 in der Eclispe-Konsole und eine Sekunden später eine 2. Irgenwie muss es doch möglich sein sowas selber zu machen? Ich frage mich echt was da Eclips für Mechanismen verwendet.
lg
Verfasst: Samstag 27. Januar 2007, 19:35
von sape
Hi Gerold. Ich habe jetzt gerade in meinen Paste flush verwendet und read durch readlines verwendet. Das Funktioniert auch. Aber das Problem ist dadurch cniht gelöst, da ich im zu strandende Script ein flush einbauen muss.
Hmm, vielleicht ncoh eine davorliegendes Script Programmieren das erstmal alles von zu startenden Script sammelt und dann per flush, etc an den Starte zurückgibt? Also 2 Scripte?
Werde ich gleich mal testen.
lg
EDIT: Ach ne geht auch nicht. Damit ist das Problem auch nicht wirklich gelöst.
Verfasst: Samstag 27. Januar 2007, 19:42
von sape
Mal ein anderer Ansatz: Wäre es möglich eine eigene PIPE zu schreiben die ich dann an ``stdin`` von ``subprocess.Popen`` übergebe, so das mir der output direkt an die PIPE geschickt wird? Als PIPE würde eich dann z.B. ``wx.TextCtrl`` verwenden.
Verfasst: Samstag 27. Januar 2007, 20:04
von gerold
Hi!
Wenn das Client-Skript ein Python-Skript ist, dann ist es einfach. Du musst nur ``python -u skriptname.py`` aufrufen. Damit wird alles ungepuffert übernommen. So etwas gibt es sicher auch für Ruby. Da EXE-Dateien ja bei deinem Verwendungszweck ausgeschlossen sind, dürfte das dein Problem wahrscheinlich beheben.
mfg
Gerold

Verfasst: Samstag 27. Januar 2007, 21:16
von sape
Hi.
Ja, das löst das Problem "provisorisch" (=Ich muss mich darauf verlassen, das dass Programm in einem ungepufferten Modus geschalten werden kann.), aber ist für Python Ideal. Schade das es keine flexiblere Möglichkeit gibt.
Ich versuche mal Informationen zu finden um so eine PIPE selber zu machen, damit ich den ``std*`` von `subprocess.Popen` darauf umleiten kann. Vielleicht geht das.
lg
Verfasst: Sonntag 28. Januar 2007, 11:32
von sape
Warum hat der Parameter ``buff`` eigentlich keine Wirkung? Ob 0, 1 oder was anderes angegeben, es passiert nichts.
Code: Alles auswählen
process = subprocess.Popen(
('python', 'testScript.py'),
shell = True,
stdout = subprocess.PIPE,
#stderr = subprocess.PIPE,
bufsize=1 #0, -1, etc. Keine Wirkung.
)
Laut der Beschreibung in der
LibRef soll bei 0 (Default) alles ungepuffert werden

Merken tue ich davon nichts.
lg
Verfasst: Sonntag 28. Januar 2007, 11:49
von gerold
Hi sape!
Du hast mich falsch verstanden. Du sollst nicht dein Programm mit ``-u`` aufrufen, sondern das Skript, von dem du den ungepufferten Output brauchst.
Code: Alles auswählen
process = subprocess.Popen(
('python', '-u', 'testScript.py'),
stdout = subprocess.PIPE,
#stderr = subprocess.PIPE,
)
Der Output des Skripts geht sowiso schon ungepuffert durch ``Popen`` durch. Es ist nicht die Pipe die puffert, sondern das aufgerufene Programm. Einem Python-Programm kannst du dieses Verhalten austreiben, indem du Python mit dem Parameter ``-u`` aufrufst. Bei fertig kompilierten Programmen wirst du dich aber schwer tun. Da wurde dieses Verhalten vom Kompiler in das Programm eingeimpft und lässt sich nicht einfach ausschalten. Zumindest weiß ich nicht, wie man so etwas unter Windows machen könnte.
mfg
Gerold

Verfasst: Sonntag 28. Januar 2007, 11:55
von gerold
Hi sape!
Ich habe beim Verwenden des Programms PyShell ``wx.py.pseudo.PseudoFileOut`` entdeckt. Habe aber keine Zeit, mir anzuschauen, was man damit machen kann. Vielleicht bringt es dir irgendetwas.
mfg
Gerold

Verfasst: Sonntag 28. Januar 2007, 12:04
von sape
Hi Gerold.
Ja, mit -u habe ich ja schon getestet und Funktioniert sehr gut
Code: Alles auswählen
def OnRunScript(self, event=None):
process = subprocess.Popen(
('python -u', 'testScript.py'),
shell = True,
stdout = subprocess.PIPE,
stderr = subprocess.PIPE,
)
while process.poll() == None:
print >> self.txt_ctrl, process.stdout.readline()[:-1]
Ich wollte halt das -u vermieden damit auch andere Exe-Programme ihre ausgaben ungepuffert ausgeben. Daher dachte ich das es mit dem ``buff`` Parameter und der PIPE zusammenhängt.
Das es aber daran leigt bei andere Exe Programmen...
Da wurde dieses Verhalten vom Kompiler in das Programm eingeimpft und lässt sich nicht einfach ausschalten.
...wusste ich nicht. Danke für die Information

Wenn du mir das jetzt nicht gesagt hättest, hätte ich tagelang an der Falschen stelle versucht was auszuprobieren.
Ich habe beim Verwenden des Programms PyShell ``wx.py.pseudo.PseudoFileOut`` entdeckt. Habe aber keine Zeit, mir anzuschauen, was man damit machen kann. Vielleicht bringt es dir irgendetwas.
Danke für die Info

Werde ich gleich testen.
Hab gestern noch ein wenig mit
wxProcess gespielt, was mich auch nicht sonderlich weitergebracht hat (Es wird auch alles gepuffert :/).
lg
sape
Verfasst: Sonntag 28. Januar 2007, 13:42
von gerold
sape hat geschrieben:Daher dachte ich das es mit dem ``buff`` Parameter und der PIPE zusammenhängt.
Hi sape!
Ja, es hängt schon irgendwie auch mit der Pipe zusammen. Wird das Programm über die Konsole aufgerufen, dann wird ja auch nicht gepuffert. Man müsste dem Programm eine Konsole vorgaukeln. Unter Linux geht das ja mit ``tty`` und ``termios``. Und unter Windows wird es auch irgendwie zu machen sein.
Versuche mal im Google die Stichworte "unbuffered STDOUT windows". Vielleicht findest du da einen Anhaltspunkt.
mfg
Gerold

Verfasst: Sonntag 28. Januar 2007, 13:48
von gerold
Hi sape!
Vielleicht kannst du etwas mit dem Modul ``win32console`` anfangen. Das ist in pywin32 inkludiert.
mfg
Gerold

Verfasst: Sonntag 28. Januar 2007, 13:49
von sape
EDIT:
gerold hat geschrieben:
Versuche mal im Google die Stichworte "unbuffered STDOUT windows". Vielleicht findest du da einen Anhaltspunkt.
gerold hat geschrieben:
Vielleicht kannst du etwas mit dem Modul ``win32console`` anfangen. Das ist in pywin32 inkludiert.
Danke, werde ich gleich mal machen.
lg
sape
Verfasst: Sonntag 28. Januar 2007, 18:33
von Leonidas
Eher
Yeah, nitpicking is fun, sometimes.

Verfasst: Sonntag 28. Januar 2007, 18:45
von sape
Geht auch so
zumindest macht er bei mir auch so das gleiche
Yeah, nitpicking is fun, sometimes.

Schön! Typisch...*hust*...

Verfasst: Sonntag 28. Januar 2007, 18:47
von gerold
Verfasst: Sonntag 28. Januar 2007, 18:48
von sape
Habs schon entdeckt :-[ ;oops;(
Verfasst: Sonntag 28. Januar 2007, 18:51
von sape
gerold hat geschrieben:
Vielleicht kannst du etwas mit dem Modul ``win32console`` anfangen. Das ist in pywin32 inkludiert.
Hi Gerold. Hab das vorhin geteste. komme damit auch nicht weiter. Ich steig da auch nicht wirklich durch, wie man das nutzt.
Die Doku ist auch nicht wirklich gut.
lg