Pyinstaller onefile doesn't find data files

10,754

Solution 1

(this question is old but a it is one of the only sources I found to solve the same problem, I will share my solution here in case it could help someone)

There is two main things to do to add data files to your script in --onefile mode.

1. Adapt the paths

In your script, adapt your paths to find the datafiles in the bundle. According to PyInstaller documentation here,the executable is launched from a temporary file, so your path must take care of this dynamic part :

For a file with the following relative path : ./your/file/is/here.ext

The code will be :

import sys
wd = sys._MEIPASS
file_path = os.path.join(wd,<your>,<file>,<is>,<here>)

Note : to make your code also work on other contexts, you can do the following :

import sys
import os
try:
   wd = sys._MEIPASS
except AttributeError:
   wd = os.getcwd()
file_path = os.path.join(wd,<your>,<file>,<is>,<here>)

2. Add the data files paths in the PyInstaller specs

According to PyInstaller documentation here, there is two ways to add data files to the bundle :

  1. Pass the option --add-files and the files as parameters when running pyinstaller <yourscript.py> from your script directory

  2. First generate a spec file by navigating to your script directory and running pyi-makespec <yourscript.py>, then add your files to the list of tuples data=[]. The tuples contains the actual path to the file and the path within your bundle. If you followed the first point, this should look like datas = [('/your/file/is/here.ext','/your/file/is/')]

Then run PyInstall <yourscript.spec> to build the bundle, based on your specs file.

Solution 2

After going back and forward between confusing stack overflow threads and the Pyinstaller documentation I was able to finally bundle my app.

Step by step:

  1. In your app root directory and . venv/bin/activated:

    ➜  ~ pip install pyinstaller
    ➜  ~ pyi-makespec --windowed --onedir --i ./resources/img/icn.icns \
          --osx-bundle-identifier "com.myname.macOS.myappname" app.py
    
  2. Now, modify your app.spec just a tiny bit:

    added_files = [
     ('resources/img', 'resources/img'),
     ( 'README.md', '.' )
     ]
    

    initialize a dictionary added_files with the relative path to your resources and set datas = added_files. In my application I used images located at ./resources/img relative to my main.py file.

  3. And to finilize, this is perhaps the easiest to forget step and not-so obvious:

    ➜  ~ pyinstaller --onefile app.spec
    

Notice this last step is taken from here.

Solution 3

Using an application like AutoPyToExe can solve most of the challenges you have with PyInstaller. The Interface allows you to address most of the challenges you have listed here. See attached file on how hidden files, data files, clean build and much more by simply selecting the location of the files instead of having to move them around.

enter image description here

Share:
10,754
userMP1960434
Author by

userMP1960434

Electrical engineer, informal programming experience generally limited to solving work-related problems over the last 25yrs. Some C, but mostly VB these days...new to Python, expecting to make it my first option.

Updated on June 09, 2022

Comments

  • userMP1960434
    userMP1960434 almost 2 years

    I too am trying for the first time to build a simple --onefile exe which includes data files, but Pyinstaller doesn't seem to find them when building the .exe. A --onedir build seems to work fine.

    I'm using the --debug switch at this point as well. I am able to run the onefile executable and can see that it appears to start working. The program finds the (sys._MEIPASS) temp directory ok (prints the needed directory name as directed) but reports a "no such file or directory" error when it looks for the first data file from the temp directory. I used archiveviewer.py on the .exe and DIDN'T find the needed data files there-- which seems to be the problem, but I can't figure out why. Data files for the build are in the directory the spec file describes. My complete spec file is

    # -*- mode: python -*-
    
    a = Analysis(['develop6.py'],
             pathex=['C:\\PYINST20'],
             hiddenimports=[],
             hookspath=None)
    
    a.datas += [ ('conlist.txt', 'C:\\pyinst20\\conlist.txt', 'DATA'), ('imageblank.gif', 'C:\\pyinst20\\imageblank.gif', 'DATA')]
    
    pyz = PYZ(a.pure)
    
    exe = EXE(pyz,
          a.scripts,
          a.binaries,
          a.zipfiles,
          a.datas,
          name=os.path.join('dist', 'develop6.exe'),
          debug=True,
          strip=None,
          upx=True,
          console=True )