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
sape hat geschrieben:

Code: Alles auswählen

            ('python -u', 'testScript.py'),
Eher

Code: Alles auswählen

            ('python', '-u', 'testScript.py'),
Yeah, nitpicking is fun, sometimes. :wink:

Verfasst: Sonntag 28. Januar 2007, 18:45
von sape
Geht auch so

Code: Alles auswählen

('python -u', 'testScript.py')
zumindest macht er bei mir auch so das gleiche ;)
Yeah, nitpicking is fun, sometimes. :wink:
Schön! Typisch...*hust*... :D

Verfasst: Sonntag 28. Januar 2007, 18:47
von gerold
sape hat geschrieben:Was ist "nitpicking"?
... http://www.woerterbuch.info/?query=nitpicking&s=dict

:-)

Verfasst: Sonntag 28. Januar 2007, 18:48
von sape
gerold hat geschrieben:
sape hat geschrieben:Was ist "nitpicking"?
... http://www.woerterbuch.info/?query=nitpicking&s=dict
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