Bündeln von Datendateien mit PyInstaller (--onefile)


107

Ich versuche mit PyInstaller eine EXE-Datei mit einer Datei zu erstellen, die ein Bild und ein Symbol enthält. Ich kann es nicht für mein Leben zum Arbeiten bringen --onefile.

Wenn ich es tue --onedir, funktioniert alles sehr gut. Wenn ich verwende --onefile, kann es die referenzierten zusätzlichen Dateien nicht finden (wenn die kompilierte EXE ausgeführt wird). Es findet die DLLs und alles andere in Ordnung, nur nicht die beiden Bilder.

Ich habe in das temporäre Verzeichnis geschaut, das beim Ausführen der EXE- \Temp\_MEI95642\Datei generiert wurde ( zum Beispiel), und die Dateien sind tatsächlich dort. Wenn ich die EXE in dieses temporäre Verzeichnis lege, findet sie sie. Sehr verwirrend.

Dies ist, was ich der .specDatei hinzugefügt habe

a.datas += [('images/icon.ico', 'D:\\[workspace]\\App\\src\\images\\icon.ico',  'DATA'),
('images/loaderani.gif','D:\\[workspace]\\App\\src\\images\\loaderani.gif','DATA')]     

Ich sollte hinzufügen, dass ich versucht habe, sie nicht auch in Unterordnern abzulegen, was keinen Unterschied machte.

Bearbeiten: Neuere Antwort aufgrund des PyInstaller-Updates als korrekt markiert.


11
ich danke dir sehr! Die Zeile hier ( a.datas += ...) hat mir gerade wirklich geholfen. In der Pyinstaller-Dokumentation wird über die Verwendung gesprochen, COLLECTaber bei der Verwendung werden keine Dateien in die Binärdatei --onefile
Igor Serebryany

@IgorSerebryany: Abgeordnet! Ich hatte genau das gleiche Problem.
Hubro

Meine .exe stürzt ab, wenn ich auf die Menüleiste
klicke,

1
Berücksichtigen Sie, dass die temporäre Ordner verschwinden , wenn die Ausführung beendet ist , so zu überprüfen , was drin ist es ein listdir von sys._MEIPASS in Ihrem Programm setzte Haupt
hithwen

Gibt es auch eine Möglichkeit, die Tree () - Syntax zu verwenden, die ich anscheinend überall gesehen habe?
Fatuhoku

Antworten:


152

Neuere Versionen von PyInstaller setzen die envVariable nicht mehr, sodass Shishs hervorragende Antwort nicht funktioniert. Jetzt wird der Pfad wie folgt festgelegt sys._MEIPASS:

def resource_path(relative_path):
    """ Get absolute path to resource, works for dev and for PyInstaller """
    try:
        # PyInstaller creates a temp folder and stores path in _MEIPASS
        base_path = sys._MEIPASS
    except Exception:
        base_path = os.path.abspath(".")

    return os.path.join(base_path, relative_path)

10
Ich verwende Pyinstaller 2 mit Python 2.7 und habe keine _MEIPASS2Envs, aber es sys._MEIPASSfunktioniert gut, also +1. Ich schlage vor:path = getattr(sys, '_MEIPASS', os.getcwd())
kbec

2
+1. Dank dafür. Beim Versuch, die Umgebungsvariable _MEIPASS2 zu verwenden, habe ich offenbar meinen Code geschrieben, als es noch die Umgebungsvariable war, weil ich mich daran erinnere, dass sie funktioniert hat. Plötzlich hörte es auf, als ich mich kürzlich neu kompilierte.
Favil Orbedios

8
Ich würde empfehlen, die AttributeErrorstatt der allgemeineren zu fangen Exception. Ich bin auf Probleme gestoßen, bei denen mir der Systemimport gefehlt hat und der Pfad standardmäßig verwendet wurde os.path.abspath.
Aaron

Möglicherweise können Sie bei der Lösung meines Problems helfen .
Phillip

1
Die Verwendung des aktuellen Arbeitsverzeichnisses in dem Fall, in dem _MEIPASS nicht festgelegt ist, ist falsch. Siehe meine Antwort .
Jonathon Reinhart

51

pyinstaller entpackt Ihre Daten in einen temporären Ordner und speichert diesen Verzeichnispfad in der _MEIPASS2Umgebungsvariablen. Um das _MEIPASS2Verzeichnis in den gepackten Modus zu bringen und das lokale Verzeichnis im entpackten (Entwicklungs-) Modus zu verwenden, verwende ich Folgendes:

def resource_path(relative):
    return os.path.join(
        os.environ.get(
            "_MEIPASS2",
            os.path.abspath(".")
        ),
        relative
    )

Ausgabe:

# in development
>>> resource_path("app_icon.ico")
"/home/shish/src/my_app/app_icon.ico"

# in production
>>> resource_path("app_icon.ico")
"/tmp/_MEI34121/app_icon.ico"

10
Wie, wann und wo würde man das verwenden?
Gseattle

4
Sie sollten dieses Skript in der .py-Datei verwenden, die Sie mit PyInstaller kompilieren möchten. Fügen Sie dieses Code-Snippet nicht in die .spec-Datei ein, da dies nicht funktioniert. Greifen Sie auf Ihre Dateien zu, indem Sie den Pfad ersetzen, den Sie normalerweise eingeben resource_path("file_to_be_accessed.mp3"). Seien Sie vorsichtig, dass Sie max 'answer für die aktuelle Version von PyInstaller verwenden sollten.
Exeleration-G

1
Ist diese Antwort spezifisch für die Verwendung der --one-fileOption?
Fatuhoku

Möglicherweise können Sie bei der Lösung meines Problems helfen .
Phillip

Die Verwendung des aktuellen Arbeitsverzeichnisses in dem Fall, in dem _MEIPASS nicht festgelegt ist, ist falsch. Siehe meine Antwort .
Jonathon Reinhart

30

Alle anderen Antworten verwenden das aktuelle Arbeitsverzeichnis, wenn die Anwendung nicht PyInstalled ist (dh sys._MEIPASSnicht festgelegt ist). Dies ist falsch, da Sie dadurch nicht in der Lage sind, Ihre Anwendung in einem anderen Verzeichnis als dem auszuführen, in dem sich Ihr Skript befindet.

Eine bessere Lösung:

import sys
import os

def resource_path(relative_path):
    """ Get absolute path to resource, works for dev and for PyInstaller """
    base_path = getattr(sys, '_MEIPASS', os.path.dirname(os.path.abspath(__file__)))
    return os.path.join(base_path, relative_path)

Danke Jon, deine Funktion hat mir heute geholfen, ein Problem zu lösen. Ich habe nur eine Frage. Warum schreiben manche _MEIPASS2 anstelle von _MEIPASS? Als ich zuvor versucht habe, die 2 hinzuzufügen, hat es nicht funktioniert.
Ahmed AbdelKhalek

Ich denke os.env['_MEIPASS2'](unter Verwendung der Betriebssystemumgebung) war eine alte Methode, um das Verzeichnis zu erhalten. AFAIK sys._MEIPASSist jetzt die einzig richtige Methode.
Jonathon Reinhart

Hallo, Ihre Lösung funktioniert einwandfrei, wenn sie resource_path()sich im Hauptskript befindet. Gibt es eine Möglichkeit, es zum Laufen zu bringen, wenn es stattdessen in einem Modul geschrieben ist? Ab sofort wird versucht, Ressourcen in dem Ordner abzurufen, in dem sich das Modul befindet, nicht in dem Hauptmodul.
Guimoute

1
@Guimoute klingt so, als ob der Code in dieser Antwort wie geplant funktioniert: Er lokalisiert die Ressourcen in dem Modul, das sie bereitstellt, weil sie verwendet werden __file__. Wenn Sie möchten, dass ein Modul auf Ressourcen außerhalb seines eigenen Bereichs zugreifen kann, müssen Sie implementieren, dass der Importcode einen Pfad zu diesen bereitstellt, den Ihr Modul verwenden kann, z. B. indem das Modul einen Aufruf "set_resource_location ()" bereitstellt, den die Importer-Aufrufe - denken Sie nicht, dass dies anders ist, als wenn Sie Pyinstaller nicht verwenden.
Scheune

@barny Danke für den Hinweis! Ich werde etwas in diese Richtung versuchen.
Guimoute

14

Vielleicht habe ich einen Schritt verpasst oder etwas falsch gemacht, aber die oben genannten Methoden haben Datendateien mit PyInstaller nicht in einer Exe-Datei gebündelt. Lassen Sie mich die Schritte teilen, die ich getan habe.

  1. Schritt: Schreiben Sie eine der oben genannten Methoden in Ihre py-Datei, indem Sie sys- und os-Module importieren. Ich habe beide ausprobiert. Der letzte ist:

    def resource_path(relative_path):
    """ Get absolute path to resource, works for dev and for PyInstaller """
        base_path = getattr(sys, '_MEIPASS', os.path.dirname(os.path.abspath(__file__)))
        return os.path.join(base_path, relative_path)
    
  2. Schritt: Schreiben Sie pyi-makepec file.py in die Konsole, um eine file.spec-Datei zu erstellen.

  3. Schritt: Öffnen Sie file.spec mit Notepad ++, um die folgenden Datendateien hinzuzufügen:

    a = Analysis(['C:\\Users\\TCK\\Desktop\\Projeler\\Converter-GUI.py'],
                 pathex=['C:\\Users\\TCK\\Desktop\\Projeler'],
                 binaries=[],
                 datas=[],
                 hiddenimports=[],
                 hookspath=[],
                 runtime_hooks=[],
                 excludes=[],
                 win_no_prefer_redirects=False,
                 win_private_assemblies=False,
                 cipher=block_cipher)
    #Add the file like the below example
    a.datas += [('Converter-GUI.ico', 'C:\\Users\\TCK\\Desktop\\Projeler\\Converter-GUI.ico', 'DATA')]
    pyz = PYZ(a.pure, a.zipped_data,
         cipher=block_cipher)
    exe = EXE(pyz,
              a.scripts,
              exclude_binaries=True,
              name='Converter-GUI',
              debug=False,
              strip=False,
              upx=True,
              #Turn the console option False if you don't want to see the console while executing the program.
              console=False,
              #Add an icon to the program.
              icon='C:\\Users\\TCK\\Desktop\\Projeler\\Converter-GUI.ico')
    
    coll = COLLECT(exe,
                   a.binaries,
                   a.zipfiles,
                   a.datas,
                   strip=False,
                   upx=True,
                   name='Converter-GUI')
    
  4. Schritt: Ich habe die obigen Schritte ausgeführt und dann die Spezifikationsdatei gespeichert. Zuletzt öffnete sich die Konsole und schrieb pyinstaller file.spec (in meinem Fall file = Converter-GUI).

Fazit: Der dist-Ordner enthält noch mehr als eine Datei.

Hinweis: Ich verwende Python 3.5.

EDIT: Schließlich funktioniert es mit Jonathan Reinharts Methode.

  1. Schritt: Fügen Sie die folgenden Codes zu Ihrer Python-Datei hinzu, indem Sie sys und os importieren.

    def resource_path(relative_path):
    """ Get absolute path to resource, works for dev and for PyInstaller """
        base_path = getattr(sys, '_MEIPASS', os.path.dirname(os.path.abspath(__file__)))
        return os.path.join(base_path, relative_path)
    
  2. Schritt: Rufen Sie die obige Funktion auf, indem Sie den Pfad Ihrer Datei hinzufügen:

    image_path = resource_path("Converter-GUI.ico")
  3. Schritt: Schreiben Sie die obige Variable, die die Funktion dort aufruft, wo Ihre Codes den Pfad benötigen. In meinem Fall ist es:

        self.window.iconbitmap(image_path)
  4. Schritt: Öffnen Sie die Konsole im selben Verzeichnis wie Ihre Python-Datei und schreiben Sie die folgenden Codes:

        pyinstaller --onefile your_file.py
  5. Schritt: Öffnen Sie die .spec-Datei der Python-Datei, hängen Sie das a.datas-Array an und fügen Sie das Symbol zur exe-Klasse hinzu, die oben vor der Bearbeitung im 3. Schritt angegeben wurde.
  6. Schritt: Speichern und beenden Sie die Pfaddatei. Gehen Sie zu Ihrem Ordner, der die Spezifikations- und Py-Datei enthält. Öffnen Sie das Konsolenfenster erneut und geben Sie den folgenden Befehl ein:

        pyinstaller your_file.spec

Nach dem 6. Schritt ist Ihre eine Datei einsatzbereit.


Danke @dilde! Nicht dass das a.datasArray aus Schritt 5 Tupel von Zeichenfolgen akzeptiert , siehe pythonhosted.org/PyInstaller/spec-files.html#adding-data-files als Referenz.
Ian Campbell

Entschuldigung, ich kann einen Teil Ihrer Nachricht aufgrund meines schwachen Englisch nicht verstehen. Dieser Teil ist "Nicht dass die a.datas ...." , Wollten Sie schreiben 'Beachten Sie, dass die a.datas ... " Stimmt etwas nicht mit dem, was ich über das Hinzufügen von Strings zum a.datas-Array geschrieben habe?
Dildeolupbiten

Hoppla! Es sollte beachtet werden, dass ... ya, Entschuldigung für den Tippfehler. Ihre Schritte haben bei mir hervorragend funktioniert :) Ich konnte diese Informationen weder in der Dokumentation noch anderswo finden.
Ian Campbell

8

Anstatt meinen gesamten Pfadcode wie vorgeschlagen neu zu schreiben, habe ich das Arbeitsverzeichnis geändert:

if getattr(sys, 'frozen', False):
    os.chdir(sys._MEIPASS)

Fügen Sie einfach diese beiden Zeilen am Anfang Ihres Codes hinzu, Sie können den Rest unverändert lassen.


2
Nein. Gute Anwendungen sollten das Arbeitsverzeichnis selten ändern. Es gibt bessere Wege.
Jonathon Reinhart

3

Leichte Änderung an der akzeptierten Antwort.

def resource_path(relative_path):
    """ Get absolute path to resource, works for dev and for PyInstaller """
    if hasattr(sys, '_MEIPASS'):
        return os.path.join(sys._MEIPASS, relative_path)

    return os.path.join(os.path.abspath("."), relative_path)

Die Verwendung des aktuellen Arbeitsverzeichnisses in dem Fall, in dem _MEIPASS nicht festgelegt ist, ist falsch. Siehe meine Antwort .
Jonathon Reinhart

1

Die häufigste Beschwerde / Frage, die ich bei PyInstaller gesehen habe, ist "Mein Code kann keine Datendatei finden, die ich definitiv in das Bundle aufgenommen habe, wo ist sie?", Und es ist nicht einfach zu sehen, was / wo Ihr Code ist sucht, weil sich der extrahierte Code an einem temporären Ort befindet und beim Beenden entfernt wird. Fügen Sie diesen Code hinzu , um mithilfe von @Jonathon Reinharts zu sehen, was in Ihrer OneFile enthalten ist und wo er sich befindetresource_path()

for root, dirs, files in os.walk(resource_path("")):
    print(root)
    for file in files:
        print( "  ",file)

0

Ich fand die vorhandenen Antworten verwirrend und brauchte lange, um herauszufinden, wo das Problem liegt. Hier ist eine Zusammenstellung von allem, was ich gefunden habe.

Wenn ich meine App starte, wird eine Fehlermeldung angezeigt Failed to execute script foo(wenn foo.pyes sich um die Hauptdatei handelt). Um dies zu beheben, führen Sie PyInstaller nicht mit aus --noconsole(oder bearbeiten Sie es main.spec, um es zu ändern console=False=> console=True). Führen Sie damit die ausführbare Datei über eine Befehlszeile aus, und Sie werden den Fehler sehen.

Als erstes müssen Sie überprüfen, ob Ihre zusätzlichen Dateien korrekt verpackt sind. Sie sollten Tupel hinzufügen, z. B. ('x', 'x')wenn der Ordner xenthalten sein soll.

Klicken Sie nach dem Absturz nicht auf OK. Wenn Sie unter Windows arbeiten, können Sie Search Everything verwenden . Suchen Sie nach einer Ihrer Dateien (z. B. sword.png). Sie sollten den temporären Pfad finden, in dem die Dateien entpackt wurden (z. B. C:\Users\ashes999\AppData\Local\Temp\_MEI157682\images\sword.png). Sie können dieses Verzeichnis durchsuchen und sicherstellen, dass es alles enthält. Wenn Sie es auf diese Weise nicht finden können, suchen Sie nach etwas wie main.exe.manifest(Windows) oder python35.dll(wenn Sie Python 3.5 verwenden).

Wenn das Installationsprogramm alles enthält, ist das nächste wahrscheinliche Problem die Datei-E / A: Ihr Python-Code sucht im Verzeichnis der ausführbaren Datei anstelle des temporären Verzeichnisses nach Dateien.

Um dies zu beheben, funktionieren alle Antworten auf diese Frage. Persönlich habe ich eine Mischung von allen gefunden, die funktioniert: Wechseln Sie das Verzeichnis als erstes in Ihrer Haupteinstiegspunktdatei, und alles andere funktioniert wie es ist:

if hasattr(sys, '_MEIPASS'): os.chdir(sys._MEIPASS)


1
Es tut uns leid. Ein Verzeichniswechsel ist jedoch nie die richtige Antwort. Wenn ein Benutzer einen Pfad zur Anwendung bereitstellt, erwartet er, dass dieser relativ zum aktuellen Verzeichnis ist. Wenn Sie das ändern, wird es falsch sein.
Jonathon Reinhart

0

Wenn Sie immer noch versuchen, Dateien relativ zu Ihrer ausführbaren Datei anstatt im temporären Verzeichnis abzulegen, müssen Sie sie selbst kopieren. So habe ich es geschafft.

https://stackoverflow.com/a/59415662/999943

Sie fügen der Spezifikationsdatei einen Schritt hinzu, der eine Dateisystemkopie in die Variable DISTPATH ​​ausführt.

Hoffentlich hilft das.


0

Ich habe mich lange (na ja, sehr lange) mit diesem Thema beschäftigt. Ich habe fast jede Quelle durchsucht, aber die Dinge haben sich in meinem Kopf nicht verändert.

Schließlich denke ich, ich habe die genauen Schritte herausgefunden, die ich befolgen möchte.

Beachten Sie, dass meine Antwort Informationen zu den Antworten anderer auf diese Frage verwendet.

So erstellen Sie eine eigenständige ausführbare Datei eines Python-Projekts.

Angenommen, wir haben einen Projektordner und der Dateibaum lautet wie folgt:

project_folder/
    main.py
    xxx.py # modules
    xxx.py # modules
    sound/ # directory containing the sound files
    img/ # directory containing the image files
    venv/ # if using a venv

Zunächst einmal, sagen wir , Sie haben Ihre Pfade definiert sound/und img/Ordner in Variablen sound_dirund img_dirwie folgt dar :

img_dir = os.path.join(os.path.dirname(__file__), "img")
sound_dir = os.path.join(os.path.dirname(__file__), "sound")

Sie müssen sie wie folgt ändern:

img_dir = resource_path("img")
sound_dir = resource_path("sound")

Wobei resource_path()oben in Ihrem Skript Folgendes definiert ist:

def resource_path(relative_path):
    """ Get absolute path to resource, works for dev and for PyInstaller """
    base_path = getattr(sys, '_MEIPASS', os.path.dirname(os.path.abspath(__file__)))
    return os.path.join(base_path, relative_path)

Aktivieren Sie die virtuelle Umgebung, wenn Sie ein Venv verwenden.

Installieren Sie pyinstaller, falls Sie dies noch nicht getan haben pip3 install pyinstaller.

Ausführen: pyi-makespec --onefile main.pyZum Erstellen der Spezifikationsdatei für den Kompilierungs- und Erstellungsprozess.

Dadurch wird die Dateihierarchie wie folgt geändert:

project_folder/
    main.py
    xxx.py # modules
    xxx.py # modules
    sound/ # directory containing the sound files
    img/ # directory containing the image files
    venv/ # if using a venv
    main.spec

Offen (mit einem Edior) main.spec:

Fügen Sie oben Folgendes ein:

added_files = [

("sound", "sound"),
("img", "img")

]

Ändern Sie dann die Zeile von datas=[],bisdatas=added_files,

Einzelheiten zu den durchgeführten Operationen finden main.specSie hier.

Lauf pyinstaller --onefile main.spec

Und das alles ist, können Sie laufen mainin project_folder/distvon überall, ohne irgendetwas anderes in ihrem Ordner mit. Sie können nur diese mainDatei verteilen . Es ist jetzt ein wahrer Standalone .


@ JonathonReinhart Wenn Sie noch da sind, wollte ich Sie darüber informieren, dass ich Ihre Funktion in meiner Antwort verwendet habe.
Muyustan

0

Mit der hervorragenden Antwort von Max und diesem Beitrag über das Hinzufügen zusätzlicher Datendateien wie Bilder oder Ton und meine eigenen Recherchen / Tests habe ich herausgefunden, was meiner Meinung nach der einfachste Weg ist, solche Dateien hinzuzufügen.

Wenn Sie ein Live-Beispiel sehen möchten, ist mein Repository hier auf GitHub.

Hinweis: Dies dient zum Kompilieren mit dem Befehl --onefileoder -Fmit pyinstaller.

Meine Umgebung ist wie folgt.


Lösen des Problems in 2 Schritten

Um das Problem zu lösen, müssen wir Pyinstaller ausdrücklich mitteilen, dass wir zusätzliche Dateien haben, die mit der Anwendung "gebündelt" werden müssen.

Wir müssen auch einen "relativen" Pfad verwenden , damit die Anwendung ordnungsgemäß ausgeführt werden kann, wenn sie als Python-Skript oder als Frozen EXE ausgeführt wird.

Wenn dies gesagt ist, brauchen wir eine Funktion, die es uns ermöglicht, relative Pfade zu haben. Mit der Funktion Max Posted können wir die relative Pfadbildung leicht lösen.

def img_resource_path(relative_path):
    """ Get absolute path to resource, works for dev and for PyInstaller """
    try:
        # PyInstaller creates a temp folder and stores path in _MEIPASS
        base_path = sys._MEIPASS
    except Exception:
        base_path = os.path.abspath(".")

    return os.path.join(base_path, relative_path)

Wir würden die obige Funktion wie folgt verwenden, damit das Anwendungssymbol angezeigt wird, wenn die App entweder als Skript oder als eingefrorene EXE ausgeführt wird.

icon_path = img_resource_path("app/img/app_icon.ico")
root.wm_iconbitmap(icon_path)

Der nächste Schritt besteht darin, Pyinstaller anzuweisen, wo die zusätzlichen Dateien beim Kompilieren zu finden sind, damit sie beim Ausführen der Anwendung im temporären Verzeichnis erstellt werden.

Wir können dieses Problem auf zwei Arten lösen, wie in der Dokumentation gezeigt , aber ich persönlich bevorzuge es, meine eigene .spec-Datei zu verwalten, damit wir es so machen.

Zunächst müssen Sie bereits eine .spec-Datei haben. In meinem Fall konnte ich das erstellen, was ich brauchte, indem ich pyinstallermit zusätzlichen Argumenten lief. Weitere Argumente finden Sie hier . Aus diesem Grund sieht meine Spezifikationsdatei möglicherweise etwas anders aus als Ihre, aber ich poste sie alle als Referenz, nachdem ich die wichtigen Teile erklärt habe.

added_files ist im Wesentlichen eine Liste mit Tupeln. In meinem Fall möchte ich nur ein EINZELNES Bild hinzufügen, aber Sie können mehrere Icos, PNGs oder JPGs hinzufügen.('app/img/*.ico', 'app/img')Sie können auch ein anderes Tupel erstellenadded_files = [ (), (), ()], um mehrere Importedurchzuführen

Der erste Teil des Tupels definiert, welche Datei oder welchen Dateityp Sie hinzufügen möchten und wo Sie sie finden. Stellen Sie sich dies als STRG + C vor

Der zweite Teil des Tupels weist Pyinstaller an, den Pfad 'app / img /' zu erstellen und die Dateien in diesem Verzeichnis RELATIV zu dem temporären Verzeichnis abzulegen, das beim Ausführen der EXE-Datei erstellt wird. Stellen Sie sich dies als STRG + V vor

Untera = Analysis([main... mir festgelegt habedatas=added_files,ursprünglich verwendetes zu seindatas=[]aber wir wollenum die Liste der Importe aus, na ja, importiertso dass wir in unseren eigenen Importen passieren.

Sie müssen dies nur tun, wenn Sie ein bestimmtes Symbol für die EXE-Datei möchten. Am Ende der Spezifikationsdatei fordere ich Pyinstaller auf, mein Anwendungssymbol für die Exe mit der Option festzulegen icon='app\\img\\app_icon.ico'.

added_files = [
    ('app/img/app_icon.ico','app/img/')
]
a = Analysis(['main.py'],
             pathex=['D:\\Github Repos\\Processes-Killer\\Process Killer'],
             binaries=[],
             datas=added_files,
             hiddenimports=[],
             hookspath=[],
             runtime_hooks=[],
             excludes=[],
             win_no_prefer_redirects=False,
             win_private_assemblies=False,
             cipher=block_cipher,
             noarchive=False)
pyz = PYZ(a.pure, a.zipped_data,
             cipher=block_cipher)
exe = EXE(pyz,
          a.scripts,
          a.binaries,
          a.zipfiles,
          a.datas,
          [],
          name='Process Killer',
          debug=False,
          bootloader_ignore_signals=False,
          strip=False,
          upx=True,
          upx_exclude=[],
          runtime_tmpdir=None,
          console=True , uac_admin=True, icon='app\\img\\app_icon.ico')

Kompilieren zu EXE

Ich bin sehr faul; Ich mag es nicht mehr Dinge zu tippen als ich muss. Ich habe eine .bat-Datei erstellt, auf die ich einfach klicken kann. Sie müssen dies nicht tun, dieser Code wird ohne ihn in einer Eingabeaufforderungs-Shell ausgeführt.

Da die .spec-Datei alle unsere Kompilierungseinstellungen und -argumente (auch als Optionen bezeichnet) enthält, müssen wir diese .spec-Datei nur Pyinstaller übergeben.

pyinstaller.exe "Process Killer.spec"

0

Eine andere Lösung besteht darin, einen Laufzeit-Hook zu erstellen, der Ihre Daten (Dateien / Ordner) in das Verzeichnis kopiert (oder verschiebt), in dem die ausführbare Datei gespeichert ist. Der Hook ist eine einfache Python-Datei, die kurz vor der Ausführung Ihrer App fast alles kann. Um es einzustellen, sollten Sie die --runtime-hook=my_hook.pyOption pyinstaller verwenden. Also, falls Sie Ihre Daten ein ist Bilder - Ordner, sollten Sie den Befehl ausführen:

pyinstaller.py --onefile -F --add-data=images;images --runtime-hook=cp_images_hook.py main.py

Die Datei cp_images_hook.py könnte ungefähr so ​​aussehen:

import sys
import os
import shutil

path = getattr(sys, '_MEIPASS', os.getcwd())

full_path = path+"\\images"
try:
    shutil.move(full_path, ".\\images")
except:
    print("Cannot create 'images' folder. Already exists.")

Vor jeder Ausführung die Bilder - Ordner in dem aktuellen Verzeichnis (aus dem _MEIPASS Ordner) bewegt wird, so wird die ausführbare Datei immer Zugriff darauf haben. Auf diese Weise müssen Sie den Code Ihres Projekts nicht ändern.

Zweite Lösung

Sie können den Runtime-Hook-Mechanismus nutzen und das aktuelle Verzeichnis ändern. Dies ist nach Ansicht einiger Entwickler keine gute Vorgehensweise, funktioniert aber einwandfrei.

Den Hook-Code finden Sie unten:

import sys
import os

path = getattr(sys, '_MEIPASS', os.getcwd())   
os.chdir(path)
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.