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 .spec
file
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.
sumber
a.datas += ...
) sangat membantu saya sekarang. dokumentasi pyinstaller berbicara tentang penggunaanCOLLECT
tetapi gagal untuk memasukkan file ke dalam biner saat menggunakan--onefile
Jawaban:
Versi PyInstaller yang lebih baru tidak mengatur
env
variabel lagi, jadi jawaban Shish yang sangat baik tidak akan berfungsi. Sekarang jalur disetel sebagaisys._MEIPASS
:sumber
_MEIPASS2
di envs, tapisys._MEIPASS
bekerja dengan baik, jadi +1. Saya menyarankan:path = getattr(sys, '_MEIPASS', os.getcwd())
AttributeError
daripada yang lebih umumException
. Saya mengalami masalah di mana saya melewatkan impor sys dan jalur diam-diam defaultos.path.abspath
.pyinstaller membongkar data Anda ke dalam folder sementara, dan menyimpan jalur direktori ini di
_MEIPASS2
variabel lingkungan. Untuk mendapatkan_MEIPASS2
dir dalam mode-dikemas dan menggunakan direktori lokal dalam mode unpacked (pengembangan), saya menggunakan ini:Keluaran:
sumber
resource_path("file_to_be_accessed.mp3")
. Berhati-hatilah karena Anda harus menggunakan jawaban maks untuk versi PyInstaller saat ini.--one-file
opsi?Semua jawaban lain menggunakan direktori kerja saat ini dalam kasus di mana aplikasi tidak PyInstalled (yaitu
sys._MEIPASS
tidak disetel). Itu salah, karena mencegah Anda menjalankan aplikasi dari direktori selain dari tempat skrip Anda berada.Solusi yang lebih baik:
sumber
os.env['_MEIPASS2']
(menggunakan lingkungan OS) adalah metode lama untuk mendapatkan direktori. AFAIKsys._MEIPASS
adalah satu-satunya metode yang benar sekarang.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.__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.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.
langkah: Tulis salah satu metode di atas ke dalam file py Anda dengan mengimpor modul sys dan os. Saya mencoba keduanya. Yang terakhir adalah:
langkah: Tulis, pyi-makespec file.py , ke konsol, untuk membuat file file.spec.
langkah: Buka, file.spec dengan Notepad ++ untuk menambahkan file data seperti di bawah ini:
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.
langkah: Tambahkan kode di bawah ini ke file python Anda dengan mengimpor sys dan os.
langkah: Panggil fungsi di atas dengan menambahkan jalur file Anda:
langkah: Tulis variabel di atas yang memanggil fungsi ke tempat kode Anda membutuhkan jalur. Dalam kasus saya ini:
langkah: Buka konsol di direktori yang sama dengan file python Anda, tulis kode seperti di bawah ini:
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:
Setelah langkah 6. satu file Anda siap digunakan.
sumber
a.datas
array dari langkah 5 mengambil tupel string, lihat pythonhosted.org/PyInstaller/spec-files.html#adding-data-files untuk referensi.Alih-alih menulis ulang semua kode jalur saya seperti yang disarankan, saya mengubah direktori kerja:
Cukup tambahkan dua baris tersebut di awal kode Anda, Anda dapat membiarkan sisanya apa adanya.
sumber
Sedikit modifikasi pada jawaban yang diterima.
sumber
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's
resource_path()
sumber
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
(jikafoo.py
adalah file utama). Untuk memecahkan masalah ini, jangan jalankan PyInstaller dengan--noconsole
(atau editmain.spec
untuk mengubahconsole=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 folderx
tersebut 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 (misalnyaC:\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 sepertimain.exe.manifest
(Windows) ataupython35.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)
sumber
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.
sumber
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:
Pertama-tama, katakanlah Anda telah menentukan jalur ke folder
sound/
danimg/
ke dalam variabelsound_dir
danimg_dir
sebagai berikut:Anda harus mengubahnya, sebagai berikut:
Di mana,
resource_path()
didefinisikan di bagian atas skrip Anda sebagai:Aktifkan virtual env jika menggunakan venv,
Install PyInstaller jika Anda tidak belum, oleh:
pip3 install pyinstaller
.Run:
pyi-makespec --onefile main.py
untuk membuat file spesifikasi untuk proses kompilasi dan build.Ini akan mengubah hierarki file menjadi:
Terbuka (dengan edior)
main.spec
:Di atasnya, masukkan:
Kemudian, ubah baris
datas=[],
menjadidatas=added_files,
Untuk detail operasi yang dilakukan di
main.spec
lihat di sini.Lari
pyinstaller --onefile main.spec
Dan itu semua, Anda dapat menjalankan
main
diproject_folder/dist
dari mana saja, tanpa harus apa pun di folder nya. Anda hanya dapat mendistribusikanmain
file itu. Sekarang, mandiri sejati .sumber
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
--onefile
or-F
dengan 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.
Kami akan menggunakan fungsi di atas seperti ini sehingga ikon aplikasi muncul ketika aplikasi berjalan baik sebagai Script ATAU Frozen EXE.
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
pyinstaller
argumen 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 imporBagian 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 bawah
a = 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'
.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.
sumber
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.py
opsi pyinstaller. Jadi, jika data Anda adalah folder gambar , Anda harus menjalankan perintah:Cp_images_hook.py bisa jadi seperti ini:
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:
sumber