pythonpathpyinstallerauto-py-to-exe

Pyinstaller images data put in the root file but error not found


I created a one dir exe with pyinstaller from my Python source code. In my code, I use images with the images relative image path put next to the .py files.

As I read the pyinstaller doc I tried 2 things: the official way with the -add data and another method where I copy the images directly next to the main.exe.

With the 2 methods, I try to launch the main.exe and I get a not found error:

couldn't open "bdd_trans.png": no such file or directory

So I tried to see where was the current work directory while launching the exe with:

from os import getcwd
path = getcwd()
print(path)

I then paste all the images in the printed directory and then the exe app worked. The problem is the directory I have to put the images on is on the windows users data which is not inside the build folder. So I can't send my app to someone and make it instantly work which is a huge deal.

Do someone knows why the official methods didn't work for me?

Here's the pyinstaller command I'm running:

pyinstaller --noconfirm --onedir --windowed --icon "C:/app_final_v8/base-de-donnees.ico" --add-data "C:/app_final_v8/actualiser_trans.png;." --add-data "C:/app_final_v8/ajouter_trans.png;." --add-data "C:/app_final_v8/bdd_trans.png;." --add-data "C:/app_final_v8/client_trans.png;." --add-data "C:/app_final_v8/composant_trans.png;." --add-data "C:/app_final_v8/cyxplus_red.png;." --add-data "C:/app_final_v8/employees_trans.png;." --add-data "C:/app_final_v8/equipement_trans.png;." --add-data "C:/app_final_v8/exporter_trans.png;." --add-data "C:/app_final_v8/modifier_trans.png;." --add-data "C:/app_final_v8/quitter_trans.png;." --add-data "C:/app_final_v8/rechercher_trans.png;." --add-data "C:/app_final_v8/retour_trans.png;." --add-data "C:/app_final_v8/site_trans.png;." --add-data "C:/app_final_v8/supprimer_trans.png;." --add-data "C:/app_final_v8/ticket_trans.png;." --add-data "C:/app_final_v8/trait.png;."  "C:/app_final_v8/main.py"

Here's the output trying to run the exe:

Traceback (most recent call last):
  File "main.py", line 7, in <module>
  File "app.py", line 98, in __init__
  File "page_accueil.py", line 26, in __init__
  File "tkinter\__init__.py", line 4061, in __init__
  File "tkinter\__init__.py", line 4006, in __init__
_tkinter.TclError: couldn't open "bdd_trans.png": no such file or directory
[11300] Failed to execute script 'main' due to unhandled exception!

Here's how I use the data images:

correspondance_table_icone = {
    "activite_client": "trait.png",
    "type_anomalie": "trait.png",
    "client": "client_trans.png",
    "composant": "composant_trans.png",
    "contrat_maintenance": "trait.png",
    "employe":"employees_trans.png",
    "equipement": "equipement_trans.png",
    "extension_chrono": "trait.png",
    "fabricant_composant": "trait.png",
    "fonction_composant": "trait.png",
    "pays": "trait.png",
    "sous_client": "trait.png",
    "ticket": "ticket_trans.png",
    "trigramme": "trait.png",
    "type_equipement": "trait.png",
    "type_ticket": "trait.png",
    "site": "site_trans.png",
    "ville": "trait.png"
}
for ligne in range(len(controller.base.nom_tables)):
            table = controller.base.nom_tables[ligne]
            icon_image = PhotoImage(file = correspondance_table_icone[table])
            self.dict_bouton_tab[table] = tb.Button(canvas_tab.interior, text = correspondance_table_tab[table][0], image=icon_image, compound="left", style = 'Custom_tab.Outline.TButton', command = lambda _table = table: self.afficher_table(controller.base, _table), bootstyle = INFO)
            self.dict_bouton_tab[table].image = icon_image
            self.dict_bouton_tab[table].grid(row = correspondance_table_tab[table][1], column = 0, sticky = "nsew")

Solution

  • Tkinter doesn't know the location of your bdd_trans.png. You need to modify your program to be able to detect the files. I suggest doing the following:


    1. Create a spec file for all your files! Adding all images one by one is bad practice and creates redundancies. For more information about creating spec file, refer to: Pyinstaller Spec Files

    1. Create a Python script (e.g. ‘add_lib.py’) with the following content:
    import sys,os
    sys.path.append(os.path.join(os.getcwd(), 'lib'))
    

    sys.path contains directories in which Python looks for imported modules and similar files. By appending the path of your subfolder, you enable the Python interpreter to find your moved files. In the code above, sys.path contains the current working directory (getcwd) and the subfolder name ‘lib’, which can be adjusted to whatever name you like.


    1. Add your python script (‘add_lib.py’) to the list of run-time hooks and build your program with PyInstaller:

    Any run-time hook you provide will be excecuted before the main script. You may simply modify your *.spec-file or use the corresponding console command:

    pyinstaller main.py --runtime-hook add_lib.py
    

    1. Move most files (not folders) to your subdirectory

    For a detailed explanation see the following medium article.