pythonw und subprocess.popen

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.
2d23d
User
Beiträge: 14
Registriert: Mittwoch 12. September 2007, 11:15

Hi zusammen,
ich bin hier auf ein Problem gestoßen, und zwar habe ich eine Anwendung mit GUI (GTK & pygtk) unter Windows, die eigentlich wunderbar funktioniert. Jetzt habe ich meine Fehlermeldungen alle aus der Console in die GUI umgeleitet und würde gerne das Consolenfenster loswerden. Ich habe dies mit "pythonw" probiert, alles sieht soweit ganz gut aus. Bis zu dem Zeitpunkt, als ich mit subprocess.popen die ausgabe eines anderen Programmes in die GUI pipe. Wie gesagt, mit python.exe läuft alles wunderbar, mit pythonw.exe ist die PIPE einfach nur leer. Keine Fehlermeldung, kein GUI-freeze, einfach nur Leere...

Woran könnte das liegen?
Für Hinweise wäre ich sehr dankbar...


Code: Alles auswählen

        try:
            #find . \! -name '*.*' -type d -maxdepth 1
            cmd = [" find //usr//discreet//clip//stonefs \\! -name '*.*' -type d -maxdepth 1"]               
            test = subprocess.Popen(' '.join(cmd), shell=True, stdin=subprocess.STDOUT, stderr=subprocess.STDOUT, stdout=subprocess.PIPE)
        
            for line in test.stdout:
                self.oImcopyOutput.get_buffer().insert_at_cursor("2FLAME: " + line +" \n")


        except:
            self.oImcopyOutput.get_buffer().insert_at_cursor("2FLAME: Could not get existing projects on Flame \n")
2d23d
User
Beiträge: 14
Registriert: Mittwoch 12. September 2007, 11:15

Nach weiterem googlen habe ich folgende Aussage gefunden:
I thought pythonw didn't provide a console and so it could be that
stdin and stdout aren't connected to anything. Popen therefore doesn't
make sense.
Stimmt es also: mit pythonw kein popen??? Gibt es vielleicht einen anderen Ausweg? Workaround?

Gruß Philipp
Benutzeravatar
mkesper
User
Beiträge: 919
Registriert: Montag 20. November 2006, 15:48
Wohnort: formerly known as mkallas
Kontaktdaten:

Probier mal, sys.stdout in eine Datei umzuleiten.
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

2d23d hat geschrieben:Stimmt es also: mit pythonw kein popen?
Hallo Philipp!

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: iso-8859-15 -*-

import subprocess
import wx

app = wx.PySimpleApp(redirect = True)

proc = subprocess.Popen(["dir"], stdout = subprocess.PIPE)
print proc.stdout.read()

app.MainLoop()

# Das funktioniert as "hallo.py" genau so gut wie als "hallo.pyw".
Dein Problem liegt eher darin, dass du STDIN nach STDOUT umleitest. ???

Weiters verstehe ich nicht, dass du von Windows sprichst aber im Code "//usr//discreet//clip//stonefs" steht. Wird dein Skript unter Cygwin gestartet? Also pythonw.exe wird unter Cygwin nicht funktionieren.

Irgendetwas kapiere ich da nicht.

mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
2d23d
User
Beiträge: 14
Registriert: Mittwoch 12. September 2007, 11:15

Hi, und danke für die Hinweise.

Probier mal, sys.stdout in eine Datei umzuleiten.
Wenn ich stdout in eine Datei umleite, habe ich ungefähr den gleichen Effekt (mit python.exe schreibt er was in die Datei, mit pythonw bleibt sie leer...)

Code: Alles auswählen

test = subprocess.Popen(' '.join(cmd), stdout=open('output.tmp', 'w'))
Dein Problem liegt eher darin, dass du STDIN nach STDOUT umleitest.
Ich habs auch mal probiert, nur den stdout zu pipen (keine Änderung)

Code: Alles auswählen

test = subprocess.Popen(' '.join(cmd), stdout=subprocess.PIPE)
...Windows sprichst aber im Code "//usr//discreet//clip//stonefs" steht
Muss mich entschuldigen, habe den Befehl gekürzt, da ich den Rest für unerheblich hielt (eigentlich starte ich von Windows aus via plink einen Befehl auf einem Linux-Rechner...)

Code: Alles auswählen

cmd = ["\\\\"+iIP+"\\backbone\\Programs_MUC\\bin\\plink.exe -i \\\\"+iIP+"\\devel\\Scripts\\liSendToFlame\\SSH_key\\" + sSSHKey + ".PPK testuser@" + sIPFlame + " find //usr//discreet//clip//stonefs \\! -name '*.*' -type d -maxdepth 1"]


Hm, hoffe das bringt uns irgendwie weiter. Bin weiterhin für Hinweise tierisch dankbar! [@gerold:wx hab ich nicht ausprobiert... wohin wird in Deinem Beispiel ohne ConsolenFenster eigentlich der print-Befehl abgesetzt?]

Gruß
Philipp
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

2d23d hat geschrieben:@gerold:wx hab ich nicht ausprobiert... wohin wird in Deinem Beispiel ohne ConsolenFenster eigentlich der print-Befehl abgesetzt?
Hallo Philipp!

Das dürfte es erklären: http://www.python-forum.de/topic-5721.html

mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
2d23d
User
Beiträge: 14
Registriert: Mittwoch 12. September 2007, 11:15

@Gerold: Aha.
Meinst Du, dass es in meinem Fall vielleicht an GTK / pyGTK liegen kann, oder hab ich noch nen Fehler gemacht? Ne Idee?

Gruß
Philipp
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Hallo Philipp!

Mit einem normalen Kommandozeilenbefehl funktioniert es. Mit Plink.exe nicht. Das ist wahrscheinlich ein Angriffspunkt für das SSH-Protokoll, der damit umgangen wird. Ich weiß es aber nicht.

Vielleicht kannst du damit dieses Verhalten umgehen: http://pypi.python.org/pypi/paramiko

mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

gerold hat geschrieben:Mit einem normalen Kommandozeilenbefehl funktioniert es. Mit Plink.exe nicht. Das ist wahrscheinlich ein Angriffspunkt für das SSH-Protokoll, der damit umgangen wird. Ich weiß es aber nicht.
Und warum sollte dass mit ``python.exe`` dann doch gehen und mit ``pythonw.exe`` nicht?
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
2d23d
User
Beiträge: 14
Registriert: Mittwoch 12. September 2007, 11:15

Hi,
bei mir funktioniert es auch mit einem "normalen Kommandozeilenbefehl" nicht.

Code: Alles auswählen

cmd = ["D:\\usr\\local\\Blender\\blender.exe -h"]
test = subprocess.Popen(' '.join(cmd), stdout=subprocess.PIPE)
gibt mit python.exe was aus, mit pythonw.exe nicht...
2d23d
User
Beiträge: 14
Registriert: Mittwoch 12. September 2007, 11:15

Tschuldigung, wenn ich das Thema nochmal wieder aufwärme...
Ich habe noch immer keine Lösung gefunden und wollte mal fragen, ob das eventuell einen Bugreport wert ist (or is it a feature?). Wenn ja, welche mailinglist/welcher tracker wäre da die richtige?

Gruß
Philipp
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

2d23d hat geschrieben:Ich habe noch immer keine Lösung gefunden
Hallo Philipp!

Du musst schon auch ein wenig daran mitarbeiten.

1. Funktioniert dieses Beispiel? http://www.python-forum.de/viewtopic.php?p=78978#78978
Und schreib jetzt nicht, dass du wxPython nicht zum Testen installieren willst.

2. Ist paramiko keine Alternative? Funktioniert es mit paramiko nicht?

mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
2d23d
User
Beiträge: 14
Registriert: Mittwoch 12. September 2007, 11:15

Du musst schon auch ein wenig daran mitarbeiten.
Gerne, wusste nur nicht, was ich noch machen soll... :)

2. Ist paramiko keine Alternative? Funktioniert es mit paramiko nicht?
Wenn mich jetzt nicht alles täuscht, hatte ich schon ausgeschlossen, dass es _NUR_ was mit ssh zu tun hat, denn 2 posts drüber hab ich mal ein Beispiel probiert (lokal, ohne ssh) und das ging auch schon nicht...aber notfalls probier ich auch das nochmal aus...
1. Funktioniert dieses Beispiel? http://www.python-forum.de/viewtopic.php?p=78978#78978
Und schreib jetzt nicht, dass du wxPython nicht zum Testen installieren willst.
ich probiers jetzt mal...

Danke auf jeden Fall und bis gleich...
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Hallo

Ich verstehe das jetzt nicht ganz.

Meine Tests mit ``Popen`` funktionieren nur mehr sporadisch. Teilweise bekomme ich eine Meldung "Ungültiges Handle". Aber genaues kann ich nicht sagen, da ich es nicht schaffe, die Meldung irgendwohin auszugeben, so dass man diese länger als eine Zehntelsekunde sieht.

Andererseits funktioniert ein Testaufruf innerhalb der wxPython-Demo (suche nach "process") mit dieser Kommandozeile: ``J:\Programme\PuTTY\plink.exe -batch -load gps.gp "ls -al"`` immer.

Ich habe das jetzt in einem Testprogramm umgesetzt:

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: iso-8859-15 -*-

import wx
import sys


app = wx.PySimpleApp(redirect = True)
#cmd = "echo Hallo Welt"
cmd = 'J:\Programme\PuTTY\plink.exe -batch -load gps.gp "ls -al"'
proc = wx.Process()
proc.Redirect()
wx.Execute(cmd, wx.EXEC_SYNC, proc)
print proc.GetInputStream().read()
proc.Destroy()

app.MainLoop()
Wenn du die Kommandozeile (cmd) an deine Umstände anpasst -- funktioniert dieses Beispiel dann bei dir?

mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
2d23d
User
Beiträge: 14
Registriert: Mittwoch 12. September 2007, 11:15

Hi Gerold,
danke für Dein Nachforschen. Also meine Tests haben ergeben, dass mit man mit wx und Popen auch nur dann glücklich wird, wenn man nicht pythonw.exe benutzt...(Ausgabe mit python.exe OK, mit pythonw.exe bekomme ich einen Fehler, den ich auch nicht debuggen kann, da er nur kurz aufblinkt...)

mit wx.Process() sieht die Sache schon stabiler aus...das wäre also ne Alternative...würde aber auch bedeuten, die gesamte GUI mit allen events etc. nochmal umzuschreiben, wx in der gesamten Firma nachzuinstallieren (mein Admin guckt mich schon ganz sauer an :) ), hm...denk ich nochmal drüber nach...vielleicht kann ich doch mit dem zweiten, nutzlosen Fenster leben?

aber nochmal ganz zurück zum Anfang: kein Popen mit pythonw.exe? > So langsam könnte man vielleicht sagen, dass es so ist, oder? Vielleicht sollte man trotzdem mal irgendwo Bescheid sagen, damit es in Zukunft vielleicht funktioniert? auch mit GTK... gibts da ne mailingliste / bugtracker?

Gruß
Philipp
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Neuer Versuch -- neuer Ansatz:

hallo.py:

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: iso-8859-15 -*-

import subprocess
import wx

app = wx.PySimpleApp(redirect = True)

cmd = 'J:\Programme\PuTTY\plink.exe -batch -load gps.gp "ls -al"'
proc = subprocess.Popen(cmd, stdout = subprocess.PIPE)
print proc.stdout.read()

app.MainLoop() 
hallo.pyw:

Code: Alles auswählen

import win32process
import win32con
import sys
import os

PYTHON = os.path.join(sys.exec_prefix, "python.exe")


stui = win32process.GetStartupInfo()
win32process.CreateProcess(
    None, '%s "%s"' % (PYTHON, r"J:\Dokumente und Einstellungen\Gerold\Desktop\hallo.py"), 
    None, None, 0, win32con.CREATE_NO_WINDOW, None, None, stui
)
#win32con.CREATE_NEW_CONSOLE
#win32con.CREATE_NO_WINDOW
Damit wird von hallo.pyw (pythonw.exe) aus der **normale** Python-Interpreter, aber ohne Konsolenfenster, gestartet. Als Argument wird der Pfad zum Modul "hallo.py" angegeben. Damit wird also ein Python-Interpreter gestartet, dessen STDOUT und STDIN nicht irgendwohin umgeleitet wurde. Sondern es wurde einfach nur das Fenster unsichtbar gemacht.

Bitte testen und berichten!

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:

Hier noch eine kleine Modifikation:

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: iso-8859-15 -*-

import subprocess
import wx
import sys
import os


def redirect_pyw():
    """
    Wenn dieses Hauptmodul von pythonw.exe gestartet wird, dann wird zu
    python.exe umgeleitet.
    """
    
    if not sys.platform.startswith("win"):
        return
    
    PYTHON_DIR = os.path.abspath(sys.exec_prefix)
    PYTHON = os.path.join(PYTHON_DIR, "python.exe")
    PYTHONW = os.path.join(PYTHON_DIR, "pythonw.exe")
    
    if os.path.abspath(sys.executable) == PYTHONW:
        # Umleiten
        import win32process
        import win32con
        
        module_path = os.path.abspath(sys.argv[0])
        
        stui = win32process.GetStartupInfo()
        win32process.CreateProcess(
            None, '%s "%s"' % (PYTHON, module_path),
            None, None, 0, win32con.CREATE_NO_WINDOW, None, None, stui
        )
        sys.exit(0)


def main():
    
    redirect_pyw()
    
    app = wx.PySimpleApp(redirect = True)
    
    args = ["J:\Programme\PuTTY\plink.exe", "-batch", "-load", "gps.gp", "ls -al"]
    proc = subprocess.Popen(args, stdout = subprocess.PIPE)
    print proc.stdout.read()
    
    app.MainLoop()


if __name__ == "__main__":
    main()
Bitte testen und berichten!

mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
2d23d
User
Beiträge: 14
Registriert: Mittwoch 12. September 2007, 11:15

Hi Gerold und nochmal danke für die Mühe,

das schaint ja grundsätzlich zu funktionieren, ich kämpfe nun aber mit der Dokumentation von ActiveState (bzw. dem, was ich sonst so ergooglen kann), denn mir ist nicht ganz klar, wie ich jetzt an die Ausgabe des Prozesses komme...aber ich bleibe dran...
2d23d
User
Beiträge: 14
Registriert: Mittwoch 12. September 2007, 11:15

Hm, ich habe immer noch Probleme, die Ausgabe des Prozesses irgendwie einzufangen. Habe ein Beispiel gefunden und Deinen Code dann so umgeschrieben:

Code: Alles auswählen

if os.path.abspath(sys.executable) == PYTHONW:
        # Umleiten
        
        import win32process
        import win32con
        import win32security
        import win32file
        import win32api
        
        module_path = os.path.abspath(sys.argv[0])
        stui = win32process.GetStartupInfo()
        sa = win32security.SECURITY_ATTRIBUTES()
        sa.bInheritHandle = 1
        stui.dwFlags = win32process.STARTF_USESTDHANDLES

        fh = win32file.CreateFile("D:/mylog.log", win32file.GENERIC_WRITE,win32file.FILE_SHARE_READ|win32file.FILE_SHARE_WRITE, sa,win32file.OPEN_ALWAYS, win32file.FILE_FLAG_SEQUENTIAL_SCAN , 0)
        stui.hStdOutput = fh
        stui.hStdError = fh
        stui.hStdInput = fh
        
        (hProcess, hThread, dwProcessId, dwThreadId) = win32process.CreateProcess(None, '%s "%s"' % (PYTHON, module_path),None, None, 0, win32con.CREATE_NO_WINDOW, None, None, stui)
        
        sys.exit(0)
Aber das Logfile ist leer... sitze mal wieder n bisschen fest, da ich mir das aus der MS oder ActiveState-Doku irgendwie nicht extrahieren kann.:oops:
Ich bekomme also mit "CreateProcess" FileHandles, aber wie lese ich die aus? Bzw. warum ist im obigen Beispiel das Logfile leer?

Entschuldigt die Anfängerverzweiflung...:)

Gruß
Philipp
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

2d23d hat geschrieben:ich habe immer noch Probleme, die Ausgabe des Prozesses irgendwie einzufangen.
Hallo Philipp!

Kannst du dich noch erinnern? Das war deine Aufgabenstellung:
2d23d hat geschrieben:und zwar habe ich eine Anwendung mit GUI (GTK & pygtk) unter Windows, die eigentlich wunderbar funktioniert. Jetzt habe ich meine Fehlermeldungen alle aus der Console in die GUI umgeleitet und würde gerne das Consolenfenster loswerden.
Es gibt jetzt eine Lösung, die sofort nach dem Start deiner Anwendung prüft, ob sie von pythonw.exe oder von python.exe aufgerufen wurde. Wenn sie von pythonw.exe aufgerufen wurde, dann wird ein **komplett neuer** Prozess erstellt, der mit dem laufenden Prozess *nichts* zu tun hat. Danach wird der eigene, laufende Prozess beendet.

Der neue, soeben gestartete Prozess, prüft natürlich wieder, ob er von python.exe oder von pythonw.exe aufgerufen wurde. Da dieser aber von python.exe aufgerufen wurde, wird mit dem Programm ganz normal weiter gefahren.

Du musst dich also nicht in der Funktion ``redirect_pyw()`` mit der Ausgabe beschäftigen. Da wirst du nichts finden.

Im Beispiel wird in der Funktion ``main()`` mit ``subprocess.Popen`` das Programm plink.exe aufgerufen. Und dort -- nur dort -- wirst du mit der Rückgabe von plink.exe etwas anfangen können.

Du hast nicht geschrieben, dass du dein Programm aufrufen möchtest und von diesem Programm eine Rückgabe brauchst. Du hast geschrieben, dass du Fehlermeldungen nicht mehr in der Konsole anzeigen möchtest. Du brauchst keine Konsole mehr, da alles in die GUI geloggt wird. Wozu brauchst du dann noch eine Rückgabe? Und ich gehe davon aus, dass du den hier gezeigten Trick in dein GUI-Programm einbaust und nicht irgendwo anders.

Was anderes macht ja keinen Sinn, denn von deinem GUI-Programm aus kannst du ja jedes andere Programm mit ``subprocess.Popen`` starten, ohne dass eine neue Konsole auf geht.

Wenn du vom GUI-Programm etwas loggen möchtest, dann schreibe in eine Datei. Aber bitte nicht so umständlich wie in deinem Beispiel. Lies lieber das hier vorher einmal durch: http://www.python-forum.de/topic-6157.html

mfg
Gerold
:-)

PS: Lange Codezeilen solltest du evt. bei 80 Zeichen umbrechen. Das macht die Sache für alle einfacher.
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Antworten