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

Ok, jetzt klappts...
Muss mich entschuldigen, hab in meinem letzten Post höchstwahrscheinlich den Überblick verloren...(und weiss auch nicht, ob ich ihn vollständig wiedererlangt habe :) )

Also, für mich nochmal zum Wiederholen:

- ich habe ein GUI-Programm
- zweierlei Art von Meldungen möchte ich in diesem Programm ausgeben:
(a) "eigene" Fehlermeldungen
(b) Meldungen, die ein anderes Programm via "subprocess.popen()" zurückgibt
- beide Arten von Meldungen sollen in der GUI ausgegeben werden
- da nur noch die GUI verwendet wird, brauche ich kein Konsolenfenster mehr
- wenn man aber einfach das GUI-Programm mit "pythonw" statt "python" aufruft, startet zwar das GUI-Programm ohne Konsolenfenster, die Rückgabe-Pipes von "subprocess.popen()" sind aber leer...
- dank Gerolds "redirect_pyw()"-Strategie kann man nun aber das *gesamte* GUI-Programm quasi mit "python" (statt "pythonw") **ohne** Konsohlenfenster starten (man startet es zwar mit pythonw, es wird aber umgeleitet und ein anderer Prozess - diesmal python - mit unterdrücktem Fenster gestartet)


Ich hoffe, ich habs jetzt ganz grob gepeilt.
Tausend Dank nochmal, Gerold!!

Nichts desto trotz würde ich gern nochmal wissen, ob die ursprüngliche Geschichte (pipes von subprocess.popen sind leer) eigentlich als Bug zu betrachten ist? Oder ist das "normales" Verhalten?

Also
Gruß nochmal und Dank

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:Nichts desto trotz würde ich gern nochmal wissen, ob die ursprüngliche Geschichte (pipes von subprocess.popen sind leer) eigentlich als Bug zu betrachten ist? Oder ist das "normales" Verhalten?
Hallo Philipp!

Ich halte es inzwischen für einen schweren Bug! Aber ich kann nichts dagegen tun, da ich kaum Englisch kann. Ein Bugreport würde bei mir einen ganzen Tag verschlingen.

Dass bei pythonw.exe STDOUT, STDIN und STDERR einfach ins Leere geht, das wäre ja normal, aber dass auch subprocess.Popen beim Aufruf von Programmen nichts oder nur ab und zu mal (je nach Art des aufgerufenen Programmes) etwas zurück liefert --> das ist sicher ein Bug.

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

Habe mich eben beim Bugtracker registriert (bugs.python.org), kann mich auch einloggen, aber bekomme immer eine quasi leere Seite beim Verfassen eines neuen "Issues"... scheint nicht ganz mein Tag zu sein, ich guck da vielleicht später nochmal vorbei...

troztdem froh, dass es jetzt erstmal so funktioniert...

Gruß
Philipp
Antworten