pyInstaller und subprocess

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.
Antworten
s0pply
User
Beiträge: 8
Registriert: Montag 23. März 2026, 19:53

Hallo zusammen,

mal wieder ich und zu einem Problem, wo google aktuell nicht weiterhelfen kann.
Mein Script, soll laut Befehl in sich selbst per subprocess im Hintergrund Starten.
normal per "python3 ./test.py" läuft es auch aber wenn ich dies in pyinstaller Onefile
umwandle, geht hier auf einmal nichts mehr.
Python Version: 3.10.12 (soll so sein)
pyinstaller Version: 6.19.0

hier mein Beispiel, was ich dafür Vorbereitet habe:

Code: Alles auswählen

#!/usr/bin/env python3

import time, os, sys
import subprocess as sp

if getattr(sys, "frozen", False):
    APPLICATION_PATH = os.path.dirname(sys.executable)
elif __file__:
    APPLICATION_PATH = os.path.dirname(__file__)

APPLICATION_PATH = os.path.normpath(APPLICATION_PATH)
SCRIPT_NAME = os.path.basename(__file__)

EXE = APPLICATION_PATH + "/" + SCRIPT_NAME

def zahler():
    I = 0
    for a in range(10):
        I += 1
        time.sleep(0.25)

def start():
    sp.Popen(
        [sys.executable, EXE, "nur_ein_test"],
        stdout=sp.DEVNULL,
        stderr=sp.DEVNULL
    )

if len(sys.argv) > 1:
    if sys.argv[1] == "--start":
        start()

    if sys.argv[1] == "nur_ein_test":
        zahler()

sys.exit(0)
Dachte zuerst es liegt an den Path oder am Script Name oder liegt es daran, das die Datei im tmp Ordner ausgeführt wird
und sich selbst nicht doppelt ausführen kann.
Oder muss da eine weiter Datei mit rein die das Script aufrufen könnte aber es muss mit Impot dann laufen...

Gruß
Benutzeravatar
__blackjack__
User
Beiträge: 14391
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@s0pply: Was heisst „geht nichts mehr“ konkret?

Ein paar strategische `print()`-Ausgaben und/oder das entfernen der Umleitung von Ausgaben nach DEVNULL könnten Erkenntnisse bringen.
Who is General Failure and why is he reading my hard disk?
imonbln
User
Beiträge: 204
Registriert: Freitag 3. Dezember 2021, 17:07

Es besteht die Möglichkeit, dass /tmp mit noexec gemountet ist; dann kann der Subprocess es unter Umständen nicht starten. Wie schon @__blackjack__ sagte: Ein paar Debug-Prints oder Breakpoints an den richtigen Stellen können helfen.

Abgesehen davon ist es sicherheitstechnisch eine bescheidene Idee, etwas mit subprocess zu starten, das im Temp-Ordner liegt. Normalerweise kann dort jeder schreiben, und wenn das System nicht entsprechend gehärtet ist, könnte ein Angreifer dein Programm gegen eine evil.bin austauschen, welche dann im Kontext deines Skripts ausgeführt wird.

Was willst du eigentlich erreichen? Warum müssen bei dir Skripte andere Skripte aufrufen und Werte übergeben? Vielleicht beschreibst du uns, was deine Idee ist, eventuell findet die Community eine bessere Lösung als Skripte, die sich gegenseitig via subprocess starten müssen
Benutzeravatar
__blackjack__
User
Beiträge: 14391
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@imonbln: Dann könnte das eigentliche Programm doch schon nicht starten. PyInstaller entpackt doch alles nach `/tmp/`.

Es reicht übrigens schon die Umleitung(en) nach DEVNULL zu entfernen um eine Fehlermeldung zu sehen, der man dann weiter nachgehen kann.

Ich finde die Konstruktion auch komisch. Es kann Gründe geben mehr als einen Prozess mit dem ”gleichen” Code laufen zu lassen. Das würde ich dann aber nicht selber basteln, sondern `multiprocessing` oder `concurrent.futures` dafür verwenden.
Who is General Failure and why is he reading my hard disk?
s0pply
User
Beiträge: 8
Registriert: Montag 23. März 2026, 19:53

Das Script soll per "--start" einen webserver sowie websocked starten, da diese beiden Modul aber die Shell brauchen, möchte ich dies,
in den Hintergrund ohne Ausgabe schieben. Mein Gedankenansatz ist:

Code: Alles auswählen

def start_wso():
    global server
    server = WebsocketServer()
    server.set_fn_new_client(new_client)
    server.set_fn_client_left(client_left)
    server.set_fn_message_received(message_received)
    server.run_forever()


def start_web():
    global client
    app.start(controller)


def start_http():
    sys.stdout = open(os.devnull, "w")
    p1 = multiprocessing.Process(target=start_wso, name="websocked")
    p1.daemon = True
    p2 = multiprocessing.Process(target=start_web, name="webserver")
    p2.daemon = True
    p1.start()
    p2.start()
    p1.join()
    p2.join()

def web_start():
    sp.Popen(
        [sys.executable, EXE,  "ALL_Server"],
        stdout=sp.DEVNULL,
        stderr=sp.DEVNULL,
        start_new_session=True,
    )

if sys.argv[1] == "--start":
        web_start()

if sys.argv[1] == "ALL_Server":
        start_http()
(teile des Codes) rufe ich dies normal auf per "./test.py --start" läuft es auch, nach pyinstalller zu Onefile geht es nicht mehr, mache ich aber "./test ALL_Server" als Onefile, läuft es, aber nicht im Hintergrund sondern in der Aktiven Shell
Benutzeravatar
sparrow
User
Beiträge: 4654
Registriert: Freitag 17. April 2009, 10:28

@s0pply: Mir ist noch immer nicht klar, was du tun willst. Das wirkt alles sehr unstrukturiert und wirr.
Wenn du einen Background-Service mit Pyinstaller starten willst, dann kannst du die Konsole verstecken. Dafür hat Pyinstaller beim erstellen der .exe einen Parameter.

global hat in einem Programm nichts verloren.
Verwende niemals globale Variablen.

Ist das der Versuch ein Webserver und einen Client in ein Programm zu quetschen?
Mach das einfach nicht. Entweder kann es nur gleichzeitig laufen (dann musst da gar nichts mit subprocess starten) oder es läuft unabhängig voneinander ,dann sind das zwei unterschiedliche Programme.
Sirius3
User
Beiträge: 18406
Registriert: Sonntag 21. Oktober 2012, 17:20

@s0pply: normalerweise läuft ja websocket und http über das selbe Framework. Dann benutzt man WSGI das selbständig dafür sorgt, dass entweder genug Threads oder Prozesse gestartet werden.

Bei Deinem multiprocessing-Fragment fehlt das `if __name__ == "__main__"` das man auf jeden Fall braucht, aber wie schon geschrieben, sollte man eh nicht so machen.

Das Terminal benutzt man für jegliche Log-Ausgaben, die Umzuleiten ist kontraproduktiv, weil das das Debugging unmöglich macht.

Also erfinde nichts eigenes, sondern benutze das, was Dein Framework vorsieht, und kombiere nur Dinge, die dafür auch vorgesehen sind.
Antworten