[Ungelöst] Output vom ``subprocess`` ungepuffert lesen

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
sape
User
Beiträge: 1157
Registriert: Sonntag 3. September 2006, 12:52

Samstag 27. Januar 2007, 17:43

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.
Zuletzt geändert von sape am Sonntag 28. Januar 2007, 18:53, insgesamt 1-mal geändert.
BlackJack

Samstag 27. Januar 2007, 18:55

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`)
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Samstag 27. Januar 2007, 19:04

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
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
sape
User
Beiträge: 1157
Registriert: Sonntag 3. September 2006, 12:52

Samstag 27. Januar 2007, 19:27

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
sape
User
Beiträge: 1157
Registriert: Sonntag 3. September 2006, 12:52

Samstag 27. Januar 2007, 19:35

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.
sape
User
Beiträge: 1157
Registriert: Sonntag 3. September 2006, 12:52

Samstag 27. Januar 2007, 19:42

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.
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Samstag 27. Januar 2007, 20:04

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
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
sape
User
Beiträge: 1157
Registriert: Sonntag 3. September 2006, 12:52

Samstag 27. Januar 2007, 21:16

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
sape
User
Beiträge: 1157
Registriert: Sonntag 3. September 2006, 12:52

Sonntag 28. Januar 2007, 11:32

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
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Sonntag 28. Januar 2007, 11:49

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
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Sonntag 28. Januar 2007, 11:55

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
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
sape
User
Beiträge: 1157
Registriert: Sonntag 3. September 2006, 12:52

Sonntag 28. Januar 2007, 12:04

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
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Sonntag 28. Januar 2007, 13:42

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
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Sonntag 28. Januar 2007, 13:48

Hi sape!

Vielleicht kannst du etwas mit dem Modul ``win32console`` anfangen. Das ist in pywin32 inkludiert.

mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
sape
User
Beiträge: 1157
Registriert: Sonntag 3. September 2006, 12:52

Sonntag 28. Januar 2007, 13:49

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
Antworten