Pyinstaller onefile doesn't find data files
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 :
Pass the option
--add-files
and the files as parameters when runningpyinstaller <yourscript.py>
from your script directoryFirst generate a spec file by navigating to your script directory and running
pyi-makespec <yourscript.py>
, then add your files to the list of tuplesdata=[]
. The tuples contains the actual path to the file and the path within your bundle. If you followed the first point, this should look likedatas = [('/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:
-
In your app root directory and
. venv/bin/activate
d:➜ ~ pip install pyinstaller ➜ ~ pyi-makespec --windowed --onedir --i ./resources/img/icn.icns \ --osx-bundle-identifier "com.myname.macOS.myappname" app.py
-
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 setdatas = added_files
. In my application I used images located at./resources/img
relative to my main.py file. -
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.
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, 2022Comments
-
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 )