Membundel file data dengan PyInstaller (--onefile)

107

Saya mencoba membuat EXE satu file dengan PyInstaller yang menyertakan gambar dan ikon. Saya tidak bisa seumur hidup saya membuatnya bekerja dengannya --onefile.

Jika saya melakukannya --onedir, semuanya bekerja dengan sangat baik. Ketika saya menggunakan --onefile, itu tidak dapat menemukan file tambahan yang direferensikan (saat menjalankan EXE yang dikompilasi). Ia menemukan DLL dan segalanya baik-baik saja, hanya saja bukan dua gambar.

Saya telah melihat di temp-dir yang dihasilkan saat menjalankan EXE ( \Temp\_MEI95642\misalnya) dan file memang ada di sana. Ketika saya menjatuhkan EXE di direktori temp itu menemukan mereka. Sangat membingungkan.

Ini yang saya tambahkan ke .specfile

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

Saya harus menambahkan bahwa saya juga mencoba untuk tidak memasukkannya ke dalam subfolder, tidak ada bedanya.

Edit: Menandai jawaban baru sebagai benar karena pembaruan PyInstaller.

hiu arboreal
sumber
11
Terima kasih banyak! baris di sini ( a.datas += ...) sangat membantu saya sekarang. dokumentasi pyinstaller berbicara tentang penggunaan COLLECTtetapi gagal untuk memasukkan file ke dalam biner saat menggunakan--onefile
Igor Serebryany
@IgorSerebryany: Didukung! Saya baru saja mengalami masalah yang sama persis.
Hubro
.Exe saya lumpuh saat saya mengeklik bilah menu jika saya menggunakan
iacopo
1
Perhatikan bahwa folder temp hilang ketika eksekusi selesai, jadi untuk memeriksa apa yang ada di dalamnya, letakkan listdir sys._MEIPASS di program utama Anda
hithwen
Apakah ada juga cara menggunakan sintaks Tree () yang sepertinya pernah saya lihat di sekitar tempat itu?
fatuhoku

Jawaban:

152

Versi PyInstaller yang lebih baru tidak mengatur envvariabel lagi, jadi jawaban Shish yang sangat baik tidak akan berfungsi. Sekarang jalur disetel sebagai 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)
maks
sumber
10
Saya menggunakan pyinstaller 2 dengan python 2.7 dan saya tidak punya _MEIPASS2di envs, tapi sys._MEIPASSbekerja dengan baik, jadi +1. Saya menyarankan:path = getattr(sys, '_MEIPASS', os.getcwd())
kbec
2
+1. Terima kasih untuk itu. Mencoba menggunakan variabel lingkungan _MEIPASS2 untuk sementara waktu sekarang, ternyata saya menulis kode saya ketika masih variabel lingkungan, karena saya ingat itu berfungsi. Tiba-tiba, itu berhenti, ketika saya mengkompilasi ulang baru-baru ini.
Favil Orbedios
8
Saya akan merekomendasikan untuk menangkap ikan AttributeErrordaripada yang lebih umum Exception. Saya mengalami masalah di mana saya melewatkan impor sys dan jalur diam-diam default os.path.abspath.
Aaron
Anda mungkin dapat membantu memecahkan masalah saya .
Phillip
1
Menggunakan direktori kerja saat ini jika _MEIPASS tidak disetel salah. Lihat jawaban saya .
Jonathon Reinhart
51

pyinstaller membongkar data Anda ke dalam folder sementara, dan menyimpan jalur direktori ini di _MEIPASS2variabel lingkungan. Untuk mendapatkan _MEIPASS2dir dalam mode-dikemas dan menggunakan direktori lokal dalam mode unpacked (pengembangan), saya menggunakan ini:

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

Keluaran:

# 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"
Shish
sumber
10
Bagaimana, kapan, dan di mana orang akan menggunakannya?
gseattle
4
Anda harus menggunakan skrip ini dalam file .py yang Anda coba kompilasi dengan PyInstaller. Jangan letakkan cuplikan kode ini dalam file .spec, itu tidak akan berfungsi. Akses file Anda dengan mengganti jalur yang biasanya Anda gunakan untuk mengetik resource_path("file_to_be_accessed.mp3"). Berhati-hatilah karena Anda harus menggunakan jawaban maks untuk versi PyInstaller saat ini.
Exeleration-G
1
Apakah jawaban ini khusus untuk menggunakan --one-fileopsi?
fatuhoku
Anda mungkin dapat membantu memecahkan masalah saya .
Phillip
Menggunakan direktori kerja saat ini jika _MEIPASS tidak disetel salah. Lihat jawaban saya .
Jonathon Reinhart
30

Semua jawaban lain menggunakan direktori kerja saat ini dalam kasus di mana aplikasi tidak PyInstalled (yaitu sys._MEIPASStidak disetel). Itu salah, karena mencegah Anda menjalankan aplikasi dari direktori selain dari tempat skrip Anda berada.

Solusi yang lebih baik:

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)
Jonathon Reinhart
sumber
Terima kasih Jon, fungsi Anda membantu saya hari ini untuk memecahkan masalah. Saya hanya punya pertanyaan. Mengapa beberapa orang menulis _MEIPASS2, bukan _MEIPASS? Ketika saya mencoba menambahkan 2 sebelumnya, itu tidak berhasil.
Ahmed AbdelKhalek
Saya pikir os.env['_MEIPASS2'](menggunakan lingkungan OS) adalah metode lama untuk mendapatkan direktori. AFAIK sys._MEIPASSadalah satu-satunya metode yang benar sekarang.
Jonathon Reinhart
Halo, solusi Anda berfungsi dengan baik saat resource_path()berada di skrip utama. Apakah ada cara untuk membuatnya berfungsi saat ditulis dalam modul? Untuk saat ini, ia akan mencoba mendapatkan sumber daya di folder tempat modul tersebut berada, bukan utama.
Guimoute
1
@Guimoute terdengar seperti kode dalam jawaban ini berfungsi seperti yang dirancang: ia melokalkan sumber daya ke modul yang menyediakannya karena digunakan __file__. Jika Anda ingin modul dapat mengakses sumber daya di luar cakupannya sendiri, maka Anda harus mengimplementasikan bahwa kode pengimporan menyediakan jalur ke modul tersebut untuk digunakan modul Anda, misalnya oleh modul yang menyediakan panggilan "set_resource_location ()" yang panggilan importir - jangan berpikir ini berbeda dari bagaimana Anda seharusnya bekerja saat tidak menggunakan pyinstaller.
barny
@barny Terima kasih atas petunjuknya! Saya akan mencoba sesuatu seperti itu.
Guimoute
14

Mungkin saya melewatkan satu langkah atau melakukan kesalahan tetapi metode yang ada di atas, tidak menggabungkan file data dengan PyInstaller menjadi satu file exe. Izinkan saya membagikan langkah-langkah apa yang telah saya lakukan.

  1. langkah: Tulis salah satu metode di atas ke dalam file py Anda dengan mengimpor modul sys dan os. Saya mencoba keduanya. Yang terakhir adalah:

    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. langkah: Tulis, pyi-makespec file.py , ke konsol, untuk membuat file file.spec.

  3. langkah: Buka, file.spec dengan Notepad ++ untuk menambahkan file data seperti di bawah ini:

    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. langkah: Saya mengikuti langkah-langkah di atas, lalu menyimpan file spesifikasi. Akhirnya membuka konsol dan menulis, pyinstaller file.spec (dalam kasus saya, file = Converter-GUI).

Kesimpulan: Masih ada lebih dari satu file di folder dist.

Catatan: Saya menggunakan Python 3.5.

EDIT: Akhirnya berfungsi dengan metode Jonathan Reinhart.

  1. langkah: Tambahkan kode di bawah ini ke file python Anda dengan mengimpor sys dan 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)
  2. langkah: Panggil fungsi di atas dengan menambahkan jalur file Anda:

    image_path = resource_path("Converter-GUI.ico")
  3. langkah: Tulis variabel di atas yang memanggil fungsi ke tempat kode Anda membutuhkan jalur. Dalam kasus saya ini:

        self.window.iconbitmap(image_path)
  4. langkah: Buka konsol di direktori yang sama dengan file python Anda, tulis kode seperti di bawah ini:

        pyinstaller --onefile your_file.py
  5. langkah: Buka file .spec dari file python dan tambahkan array a.datas dan tambahkan ikon ke kelas exe, yang diberikan di atas sebelum edit pada langkah ke-3.
  6. langkah: Simpan dan keluar dari file path. Buka folder Anda yang menyertakan file spesifikasi dan py. Buka lagi jendela konsol dan ketik perintah di bawah ini:

        pyinstaller your_file.spec

Setelah langkah 6. satu file Anda siap digunakan.

dildeolupbiten
sumber
Terima kasih @dilde! Bukan karena a.datasarray dari langkah 5 mengambil tupel string, lihat pythonhosted.org/PyInstaller/spec-files.html#adding-data-files untuk referensi.
Ian Campbell
Maaf, saya tidak dapat memahami sebagian dari pesan Anda juga, saya berharap karena bahasa Inggris saya yang lemah. Bagian itu adalah "Bukan itu a.datas ...." , Apakah Anda ingin menulis 'Perhatikan bahwa a.datas ... " Apakah ada yang salah dengan apa yang saya tulis tentang menambahkan string ke larik a.datas?
dildeolupbiten
Ups! Perlu diperhatikan bahwa ... ya, maaf salah ketik. Langkah Anda berhasil dengan baik untuk saya :), saya tidak dapat menemukan informasi ini di dokumentasi mereka atau di mana pun.
Ian Campbell
8

Alih-alih menulis ulang semua kode jalur saya seperti yang disarankan, saya mengubah direktori kerja:

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

Cukup tambahkan dua baris tersebut di awal kode Anda, Anda dapat membiarkan sisanya apa adanya.

Bobsleigh
sumber
2
Tidak. Aplikasi yang bagus seharusnya jarang mengubah direktori kerja. Ada cara yang lebih baik.
Jonathon Reinhart
3

Sedikit modifikasi pada jawaban yang diterima.

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)
Krishna Balan
sumber
Menggunakan direktori kerja saat ini jika _MEIPASS tidak disetel salah. Lihat jawaban saya .
Jonathon Reinhart
1

Keluhan / pertanyaan paling umum yang pernah saya lihat wrt PyInstaller adalah "kode saya tidak dapat menemukan file data yang pasti saya sertakan dalam bundel, di mana itu?", Dan tidak mudah untuk melihat apa / di mana kode Anda sedang menelusuri karena kode yang diekstrak berada di lokasi sementara dan dihapus saat keluar. Tambahkan sedikit kode ini untuk melihat apa yang termasuk dalam onefile Anda dan di mana lokasinya, menggunakan @Jonathon Reinhart'sresource_path()

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

Saya menemukan jawaban yang ada membingungkan, dan butuh waktu lama untuk mencari tahu di mana masalahnya. Ini kompilasi dari semua yang saya temukan.

Ketika saya menjalankan aplikasi saya, saya mendapatkan kesalahan Failed to execute script foo(jika foo.pyadalah file utama). Untuk memecahkan masalah ini, jangan jalankan PyInstaller dengan --noconsole(atau edit main.specuntuk mengubah console=False=> console=True). Dengan ini, jalankan executable dari baris perintah, dan Anda akan melihat kegagalannya.

Hal pertama yang harus diperiksa adalah mengemas file ekstra Anda dengan benar. Anda harus menambahkan tupel seperti ('x', 'x')jika Anda ingin folder xtersebut disertakan.

Setelah macet, jangan klik OK. Jika Anda menggunakan Windows, Anda dapat menggunakan Search Everything . Cari salah satu file Anda (mis. sword.png). Anda harus menemukan jalur sementara di mana ia membongkar file (misalnya C:\Users\ashes999\AppData\Local\Temp\_MEI157682\images\sword.png). Anda dapat menelusuri direktori ini dan memastikan itu termasuk semuanya. Jika Anda tidak dapat menemukannya dengan cara ini, cari sesuatu seperti main.exe.manifest(Windows) atau python35.dll(jika Anda menggunakan Python 3.5).

Jika penginstal menyertakan semuanya, kemungkinan masalah berikutnya adalah file I / O: kode Python Anda mencari file di direktori yang dapat dieksekusi, bukan direktori temp, untuk file.

Untuk memperbaikinya, salah satu jawaban atas pertanyaan ini berfungsi. Secara pribadi, saya menemukan campuran dari semuanya untuk bekerja: ubah direktori secara kondisional hal pertama di file titik masuk utama Anda, dan yang lainnya berfungsi sebagaimana adanya:

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

abu 999
sumber
1
Maaf. Namun mengubah direktori bukanlah jawaban yang tepat. Jika pengguna menyediakan jalur ke aplikasi, mereka berharap itu relatif terhadap direktori saat ini. Jika Anda mengubahnya, itu salah.
Jonathon Reinhart
0

Jika Anda masih mencoba meletakkan file relatif terhadap file yang dapat dieksekusi alih-alih di direktori temp, Anda perlu menyalinnya sendiri. Beginilah akhirnya saya menyelesaikannya.

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

Anda menambahkan langkah dalam file spesifikasi yang menyalin sistem file ke variabel DISTPATH.

Semoga membantu.

phyatt.dll
sumber
0

Saya telah menangani masalah ini untuk waktu yang lama (yah, sangat lama). Saya telah mencari hampir setiap sumber tetapi hal-hal tidak sesuai pola di kepala saya.

Akhirnya, saya pikir saya telah menemukan langkah-langkah yang tepat untuk diikuti, saya ingin berbagi.

Perhatikan bahwa, jawaban saya menggunakan informasi dari jawaban orang lain atas pertanyaan ini.

Cara membuat eksekusi mandiri dari proyek python.

Asumsikan, kami memiliki project_folder dan pohon file adalah sebagai berikut:

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

Pertama-tama, katakanlah Anda telah menentukan jalur ke folder sound/dan img/ke dalam variabel sound_dirdan img_dirsebagai berikut:

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

Anda harus mengubahnya, sebagai berikut:

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

Di mana, resource_path()didefinisikan di bagian atas skrip Anda sebagai:

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)

Aktifkan virtual env jika menggunakan venv,

Install PyInstaller jika Anda tidak belum, oleh: pip3 install pyinstaller.

Run: pyi-makespec --onefile main.pyuntuk membuat file spesifikasi untuk proses kompilasi dan build.

Ini akan mengubah hierarki file menjadi:

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

Terbuka (dengan edior) main.spec:

Di atasnya, masukkan:

added_files = [

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

]

Kemudian, ubah baris datas=[],menjadidatas=added_files,

Untuk detail operasi yang dilakukan di main.speclihat di sini.

Lari pyinstaller --onefile main.spec

Dan itu semua, Anda dapat menjalankan maindi project_folder/distdari mana saja, tanpa harus apa pun di folder nya. Anda hanya dapat mendistribusikan mainfile itu. Sekarang, mandiri sejati .

muyustan
sumber
@JonathonReinhart jika Anda masih ada, saya ingin memberi tahu Anda bahwa saya telah menggunakan fungsi Anda dalam jawaban saya.
muyustan
0

Menggunakan jawaban luar biasa dari Max dan Posting ini tentang menambahkan file data tambahan seperti gambar atau suara & penelitian / pengujian saya sendiri, saya telah menemukan apa yang saya yakini sebagai cara termudah untuk menambahkan file semacam itu.

Jika Anda ingin melihat contoh langsung, repositori saya ada di sini di GitHub.

Catatan: ini untuk kompilasi menggunakan perintah --onefileor -Fdengan pyinstaller.

Lingkungan saya adalah sebagai berikut.


Memecahkan masalah dalam 2 langkah

Untuk mengatasi masalah ini, kami perlu memberi tahu Pyinstaller secara khusus bahwa kami memiliki file tambahan yang perlu "digabungkan" dengan aplikasi.

Kita juga perlu menggunakan path 'relative' , sehingga aplikasi dapat berjalan dengan baik ketika dijalankan sebagai Python Script atau Frozen EXE.

Dengan itu kita membutuhkan fungsi yang memungkinkan kita memiliki jalur relatif. Menggunakan fungsi yang Diposting Maks kita dapat dengan mudah menyelesaikan jalur relatif.

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)

Kami akan menggunakan fungsi di atas seperti ini sehingga ikon aplikasi muncul ketika aplikasi berjalan baik sebagai Script ATAU Frozen EXE.

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

Langkah selanjutnya adalah kita perlu menginstruksikan Pyinstaller di mana menemukan file tambahan saat dikompilasi sehingga ketika aplikasi dijalankan, mereka dibuat di direktori temp.

Kami dapat menyelesaikan masalah ini dengan dua cara seperti yang ditunjukkan dalam dokumentasi , tetapi saya pribadi lebih suka mengelola file .spec saya sendiri jadi begitulah cara kami melakukannya.

Pertama, Anda harus sudah memiliki file .spec. Dalam kasus saya, saya dapat membuat apa yang saya butuhkan dengan menjalankan pyinstallerargumen tambahan, Anda dapat menemukan argumen tambahan di sini . Karena itu, file spesifikasi saya mungkin terlihat sedikit berbeda dari milik Anda tetapi saya memposting semuanya untuk referensi setelah saya menjelaskan bagian-bagian penting.

added_files pada dasarnya adalah List yang berisi Tuple's, dalam kasus saya, saya hanya ingin menambahkan gambar TUNGGAL, tetapi Anda dapat menambahkan beberapa ico's, png's atau jpg's menggunakan('app/img/*.ico', 'app/img')Anda juga dapat membuat tuple lain seperti ituadded_files = [ (), (), ()]untuk memiliki banyak impor

Bagian pertama tupel mendefinisikan file apa atau jenis file apa yang ingin Anda tambahkan serta di mana menemukannya. Pikirkan ini sebagai CTRL + C

Bagian kedua dari tuple memberi tahu Pyinstaller, untuk membuat jalur 'app / img /' dan menempatkan file di direktori tersebut RELATIF ke direktori temp apa pun yang dibuat saat Anda menjalankan .exe. Pikirkan ini sebagai CTRL + V

Di bawaha = Analysis([main... , saya telah menetapkandatas=added_files, awalnya duludatas=[]tetapi kami ingin daftar impor menjadi, baik, diimpor jadi kami meneruskan impor kustom kami.

Anda tidak perlu melakukan ini kecuali Anda menginginkan ikon khusus untuk EXE, di bagian bawah file spesifikasi, saya memberi tahu Pyinstaller untuk mengatur ikon aplikasi saya untuk exe dengan opsi 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')

Mengompilasi ke EXE

Saya sangat malas; Saya tidak suka mengetik lebih dari yang harus saya lakukan. Saya telah membuat file .bat yang bisa saya klik. Anda tidak harus melakukan ini, kode ini akan berjalan di shell prompt perintah dengan baik tanpa itu.

Karena file .spec berisi semua pengaturan kompilasi & args (alias opsi), kami hanya perlu memberikan file .spec itu ke Pyinstaller.

pyinstaller.exe "Process Killer.spec"
Jtonna
sumber
0

Solusi lain adalah membuat pengait runtime, yang akan menyalin (atau memindahkan) data Anda (file / folder) ke direktori tempat penyimpanan yang dapat dieksekusi. Hook adalah file python sederhana yang hampir dapat melakukan apa saja, sebelum aplikasi Anda dijalankan. Untuk mengaturnya, Anda harus menggunakan --runtime-hook=my_hook.pyopsi pyinstaller. Jadi, jika data Anda adalah folder gambar , Anda harus menjalankan perintah:

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

Cp_images_hook.py bisa jadi seperti ini:

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.")

Sebelum setiap eksekusi, folder gambar dipindahkan ke direktori saat ini (dari folder _MEIPASS), sehingga file yang dapat dieksekusi akan selalu memiliki akses ke sana. Dengan cara itu, Anda tidak perlu mengubah kode proyek Anda.

Solusi Kedua

Anda dapat memanfaatkan mekanisme runtime-hook dan mengubah direktori saat ini, yang menurut beberapa pengembang bukan praktik yang baik, tetapi berfungsi dengan baik.

Kode hook dapat ditemukan di bawah ini:

import sys
import os

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