BulliM
Anmeldungsdatum: 7. März 2010
Beiträge: 207
|
Ich möchte Customern eine einfache Anwendung zur Verfügung stellen. Die Anwendung selbst ist in Python programmiert, funktioniert auf der Kommandozeile gut, weil die anderen Dateien natürlich mit im Ordner liegen. Nun kompiliere ich die GUI.py mit nuitka zu einem --onefile *.bin, eben, weils ohne Konsole auskommt. Allerdings wird ein aufgerufenes Pythonscript (subprocess.POPEN) dann nicht mehr gefunden, obwohl es zusammen mit der *.bin kompiliert worden ist. Das Binary sucht die datei.py außerhalb des Binaries. Ich bekomme einen Fehler angezeigt: | OSError: Python file "/root/datei.py" could not be opened: No such file or directory
|
Klar, ich könnte das Binary zusammen mit den anderen Files in einen Ordner packen, aber das möchte ich wenn möglich vermeiden. Wie mache ich das?
|
seahawk1986
Anmeldungsdatum: 27. Oktober 2006
Beiträge: 11176
Wohnort: München
|
Grundsätzlich kannst du auf Dateien innerhalb der gepackten Datei wie in Nuitka/Nuitka gezeigt zugreifen. AFAIK klappt das Ausführen eines Python-Skripts so aber nicht, weil es keinen aus der Anwendung heraus aufrufbaren Python-Interpreter innerhalb der Umgebung gibt, die nuitka packt (zumindest kann man sys.executable nicht mit subprocess aufrufen) - mir ist auch nicht klar, warum man ein Python-Skript per subprocess ausführt, statt es zu importieren und dann ggf. Methoden daraus aufzurufen - diese Importe kann nuitka automatisch auflösen, wenn es alles in eine Datei packt - z.B.: test.py:
| #!/usr/bin/env python3
import datei
if __name__ == '__main__':
datei.greet("Foo")
|
datei.py:
| def greet(name=None):
print(f"Hallo, {'Welt' if name is None else name}!")
|
Dann das Ganze verpacken:
nuitka3 --standalone --python-flag=no_site --onefile test.py -o test.bin
|
BulliM
(Themenstarter)
Anmeldungsdatum: 7. März 2010
Beiträge: 207
|
Danke seahawk1986, das werde ich testen.
|
BulliM
(Themenstarter)
Anmeldungsdatum: 7. März 2010
Beiträge: 207
|
seahawk1986 schrieb: Grundsätzlich kannst du auf Dateien innerhalb der gepackten Datei wie in Nuitka/Nuitka gezeigt zugreifen.
Das funktioniert leider nicht, da bekomme ich einen FileNotFoundError, obwohl ich beide Versionen mit try und except probieren lasse.
|
seahawk1986
Anmeldungsdatum: 27. Oktober 2006
Beiträge: 11176
Wohnort: München
|
Dateien, die nicht über Python-Importe aufgelöst werden können, muss man explizit mit verpacken lassen (vgl. https://github.com/Nuitka/Nuitka#use-case-4---program-distribution) Also z.B. - user_provided_file_demo.py:
| #!/usr/bin/env python3
from pathlib import Path
import sys
if __name__ == '__main__':
print(Path(__file__).parent / "user-provided-file.txt").read_text(), end='')
|
Und eine user-provided-file.txt:
Hallo, Welt!
Das ganze verpacken:
$ nuitka3 --standalone --python-flag=no_site --onefile --include-data-file='user-provided-file.txt=./user-provided-file.txt' user_provided_file_demo.py
|
BulliM
(Themenstarter)
Anmeldungsdatum: 7. März 2010
Beiträge: 207
|
Ich werde das morgen ausprobieren, heute habe ich genug getan. Ich verwende die datei.py eben in dem subprocess. Eine externe Anwendung soll die aufrufen bzw. verarbeiten. Aber ich glaube, das ist dir bereits klar. Scheinst jedenfalls nuitka gut zu kennen. Ich bin sehr dankbar für deine Hilfe. ☺
|
seahawk1986
Anmeldungsdatum: 27. Oktober 2006
Beiträge: 11176
Wohnort: München
|
BulliM schrieb: Ich werde das morgen ausprobieren, heute habe ich genug getan. Ich verwende die datei.py eben in dem subprocess. Eine externe Anwendung soll die aufrufen bzw. verarbeiten. Aber ich glaube, das ist dir bereits klar.
Ich habe den Anwendungsfall immer noch nicht ganz verstanden - du willst also eine Python-Anwendung an die Kunden ausliefern, die den Python-Interpreter des Systems nutzt, um ein in dem Binary liegendes Skript auszuführen? Das geht, setzt dann aber voraus, dass die Umgebung alles nötige enthält, um das Skript erfolgreich ausführen zu können - subprocess_demo.py:
| #!/usr/bin/env python3
import subprocess
import sys
from pathlib import Path
if __name__ == '__main__':
try:
s = subprocess.run(['python3', Path(__file__).parent / "datei.py"], check=True)
except subprocess.CalledProcessError:
print("Error executing internal script 'datei.py' with the system interpreter", file=sys.stderr)
|
datei.py:
| import sys
def greet(name=None):
print(f"Hallo, {'Welt' if name is None else name}!")
if __name__ == '__main__':
greet(sys.executable)
|
Dann das Ganze verpacken:
nuitka3 --standalone --python-flag=no_site --onefile --include-data-file='datei.py=./datei.py' subprocess_demo.py -o subprocess_demo.bin Scheinst jedenfalls nuitka gut zu kennen.
Das war heute das erste Mal - aber die README bzw. Dokumentation war bezüglich der Fragestellung recht gut geschrieben, auch wenn ich da gerne etwas mehr zu den Interna gelesen hätte, wie die Umgebung in dem internen Image aussieht.
|
BulliM
(Themenstarter)
Anmeldungsdatum: 7. März 2010
Beiträge: 207
|
Ach je. Das du nuitka auch nicht kennst, ist kein Vorteil. Ich habe das getestet, und auch da gibt es Fehler. Ich drehe mich im Kreis. Besser, ich erkläre genauer, was ich mache. Also, ich habe ein funktinierendes Script, nennen wir es script.py. Darin wird ein subprocess ausgeführt. ~Code im script.py
| command = "anwendung --run-python datei.py"
process = subprocess-Popen(command, shell=True, stdout=subprocess.PIPE)
|
Der Subprocess wird also darin ausgeführt. Darin wird die datei.py genannt. Das interessiert nuitka aber nicht, was erstmal gut ist. Noch wird die datei.py gar nicht benötigt. Importieren mit kann ich nicht, weil die datei.py ein anderes Script relativ aus der Anwendung "anwendung" importiert. Das verursacht einen Fehler. Dieses relative Script kann natürlich nicht gefunden werden, wenn die *.bin ausgeführt wird, sondern erst, wenn das command darin ausgeführt wird. Die *.bin spricht ja die Anwendung an, welche den Import des relativen Scripts erst möglich macht. Wie gesagt, ist beim Öffnen der *.bin die Anwendung noch nicht gefragt. Das funktioniert auf der Kommandozeile, wo ich die Anwendung direkt anspreche perfekt. Nun will ich mir aber das Tippen in der Konsole ersparen. Das script.py erstellt dazu ein grafisches Interface, fügt Argumente in das command ein. Das will ich in einer einzigen C-Anwendung (idealerweise dann später auch für andere OS) realisieren. Das Interface steht, die Scripts funktionieren. Das Problem ist, ich bekomme das nicht zusammen zum Laufen, weil die datei.py (und deren Abhängigkeiten) nicht mit in die *.bin gepackt wird. Die wird nicht gefunden, weil sie stets außerhalb der *.bin gesucht wird. nuitka soll sie einpacken/mitkompilieren/vorrätig halten oder sonstwie anwesend machen und die *.bin bis auf die Anwendung nichts Externes verwenden.
|
seahawk1986
Anmeldungsdatum: 27. Oktober 2006
Beiträge: 11176
Wohnort: München
|
Kannst du mal ein Minimalbeispiel zeigen, das in der Shell wie gewünscht funktioniert, aber dann nach dem Verpacken mit nuitka scheitert? Der Zugriff mit externen Programmen auf Dateien des temporär eingebundenen Images aus dem von nuitka erstellen Binary ist definitiv möglich, die Pfade der im Image abgelegten Dateien sind relativ zum Ordner, in dem die im Skript über __file__ erreichbare Pseudodatei liegt. Und von der datei.py genutzte Module bzw. Dateien musst du mit ins Image packen und die unter dem korrekten Pfad ansprechen - für Python-Module könnte es - je nachdem wie deine anwendung die aufruft - ggf. nötig sein den PYTHONPATH passend zu erweitern.
|
BulliM
(Themenstarter)
Anmeldungsdatum: 7. März 2010
Beiträge: 207
|
seahawk1986 schrieb: Kannst du mal ein Minimalbeispiel zeigen, das in der Shell wie gewünscht funktioniert, aber dann nach dem Verpacken mit nuitka scheitert?
Hatte ich oben getan. Es ist derselbe Befehl, der als variable "command" eben im subprocess ausgeführt wird. Das Binary findet die datei.py nicht, weil die nicht neben dem Binary liegt. Dort erwartet es das *.bin. seahawk1986 schrieb: Der Zugriff mit externen Programmen auf Dateien des temporär eingebundenen Images aus dem von nuitka erstellen Binary ist definitiv möglich, die Pfade der im Image abgelegten Dateien sind relativ zum Ordner, in dem die im Skript über __file__ erreichbare Pseudodatei liegt. Und von der datei.py genutzte Module bzw. Dateien musst du mit ins Image packen und die unter dem korrekten Pfad ansprechen - für Python-Module könnte es - je nachdem wie deine anwendung die aufruft - ggf. nötig sein den PYTHONPATH passend zu erweitern.
Das Problem ist, dass dieses relative Modul erst zur Laufzeit erstellt wird. Das hängt eben von der Version der Anwendung ab. Ich kann dieses relative Modul, welches in der Shell aus der Anwendung importiert wird, daher nicht in die *.bin packen. Wie gesagt, wäre es einfach, die datei.py zu mit "import datei" in das Script zu importieren, wenn da das relative Modul nicht wäre. Das verursacht einen Fehler, unmittelbar beim Aufruf der *.bin. Der Weg ist also verbaut.
|
seahawk1986
Anmeldungsdatum: 27. Oktober 2006
Beiträge: 11176
Wohnort: München
|
BulliM schrieb: seahawk1986 schrieb: Kannst du mal ein Minimalbeispiel zeigen, das in der Shell wie gewünscht funktioniert, aber dann nach dem Verpacken mit nuitka scheitert?
Hatte ich oben getan.
Meine Vorstellung von einem Minimalbeispiel ist eher etwas, das die Kriterien aus https://stackoverflow.com/help/minimal-reproducible-example erfüllt, nicht irgendwelche Code-Schnipsel, die nur einen Teil des Problems zeigen.
Das Problem ist, dass dieses relative Modul erst zur Laufzeit erstellt wird. Das hängt eben von der Version der Anwendung ab. Ich kann dieses relative Modul, welches in der Shell aus der Anwendung importiert wird, daher nicht in die *.bin packen.
Das macht ja nichts, dafür gibt es temporäre Dateien und Ordner (https://docs.python.org/3/library/tempfile.html), die man in den PYTHONPATH bzw. sys.path aufnehmen kann - das Image aus der .bin-Datei wird sowieso read-only gemountet, also muss man die Datei eh woanders hin schreiben, wenn die erst zur Laufzeit erzeugt wird.
|
BulliM
(Themenstarter)
Anmeldungsdatum: 7. März 2010
Beiträge: 207
|
seahawk1986 schrieb: Meine Vorstellung von einem Minimalbeispiel ist eher etwas, das die Kriterien aus https://stackoverflow.com/help/minimal-reproducible-example erfüllt, nicht irgendwelche Code-Schnipsel, die nur einen Teil des Problems zeigen.
Würde keinen Sinn machen. Das script.py erstellt das Interface und führt den subprocess aus - mehr nicht. Es importiert PySimpleGUI und subprocess. Die GUI läuft ja, auch als Binary, solange ich die datei.py nicht als Modul lade. Und in der datei.py werden weitere Module importiert. Eines davon braucht das zur Laufzeit erstellte, nicht vor dem subprocess verfügbare Modul. seahawk1986 schrieb: Das macht ja nichts, dafür gibt es temporäre Dateien und Ordner (https://docs.python.org/3/library/tempfile.html), die man in den PYTHONPATH bzw. sys.path aufnehmen kann - das Image aus der .bin-Datei wird sowieso read-only gemountet, also muss man die Datei eh woanders hin schreiben, wenn die erst zur Laufzeit erzeugt wird.
Sehe ich bei den Errors. /tmp/undsoweiter wird da immer als Pfad angegeben. Es wird eine Lösung geben. Ich habe einfach nicht wirklich Erfahrungen mit Python und verstehe im Grunde nicht wirklich, was da beim Kompilieren abläuft. Bin kurz vor dem Aufgeben. Drei Tage hänge ich an dem Problem, irgendwann ist einfach gut.
|
seahawk1986
Anmeldungsdatum: 27. Oktober 2006
Beiträge: 11176
Wohnort: München
|
BulliM schrieb: seahawk1986 schrieb: Meine Vorstellung von einem Minimalbeispiel ist eher etwas, das die Kriterien aus https://stackoverflow.com/help/minimal-reproducible-example erfüllt, nicht irgendwelche Code-Schnipsel, die nur einen Teil des Problems zeigen.
Würde keinen Sinn machen. Das script.py erstellt das Interface und führt den subprocess aus - mehr nicht. Es importiert PySimpleGUI und subprocess. Die GUI läuft ja, auch als Binary, solange ich die datei.py nicht als Modul lade. Und in der datei.py werden weitere Module importiert. Eines davon braucht das zur Laufzeit erstellte, nicht vor dem subprocess verfügbare Modul.
Ich hab mir mal die Mühe gemacht - deckt sich das mit deinem Anwendungsfall? seahawk1986/dynamic_module_creation_nuitka
|
BulliM
(Themenstarter)
Anmeldungsdatum: 7. März 2010
Beiträge: 207
|
Die main.py sieht ähnlich wie meine "script.py" (eigentlich gui.py) aus, ja. Ich kann Python aber nicht so gut "lesen" wie z. B. PHP, dass ich gut "spreche". Ich werde mir das lange ansehen und ein bisschen probieren müssen. Das mache ich morgen Nachmittag. Also nicht wundern, wenn ich mich erst übermorgen melde. In jedem Fall gibt es von mir ein Lob für deine Initiative. Ich weiß da wirklich nicht weiter und würde sicherlich scheitern oder bald aufgeben. Also Danke dafür!
|
BulliM
(Themenstarter)
Anmeldungsdatum: 7. März 2010
Beiträge: 207
|
seahawk1986 schrieb: Ich hab mir mal die Mühe gemacht... seahawk1986/dynamic_module_creation_nuitka
Habe ich getestet. Dein Beispiel funktioniert nur, wenn ich die example.bin über die run.sh auf der Konsole starte. Das wollte ich vermeiden, könnte ich aber einfach durch Einbau in die GUI unterlaufen. Wie ich das jetzt allerdings auf das importierte Laufzeit-Modul anwenden soll, weiß ich nicht. Du hast das ja in Textform (Spanische Inquisition? 😀 ) eingefügt. Ich werde deshalb experimentieren müssen.
|