Tyler Sorensen
Tyler Sorensen

Reputation: 23

How to compile .exe with Pyinstaller using --onefile and --add-data options

I am trying to compile a program to an .exe to be distributed among several computers at work. I need it to be one file, so I've used the --onefile option in Pyinstaller. Well, the program has several files that it is dependent on, so I've used the --add-data option for each of those files, and it seems to work. If i compile it with the --onedir option everything works perfectly, but if i change to --onefile, thats when it breaks. I get an error saying (the additional files) could not be found.

I've done plenty of research on the forums and the Pyinstaller manual and looked into the MEI**** folder. It looks like my additional files are being correctly loaded into the folder at runtime, but I don't really understand how that is useful, because The .exe would only be looking in its working directory for the files. I tried using the --runtime-tmpdir option to point at a folder i can run the .exe from, but it still creates the MEI***** folder, which is randomly named, so that doesn't help. Here is the command i am running in the terminal. I also tried changing the .spec file and running Pyinstaller with that, and I had the exact same problem.

pyinstaller.exe ^
--onefile ^
--runtime-tmpdir 
"C:\\Users\\MyUser\\PycharmProjects\\helloworld\\TempRuntime" ^
--add-data="DI1.npy;." ^
--add-data="DI2.npy;." ^
--add-data="DI3.npy;." ^
--add-data="DI4.npy;." ^
--add-data="DI5.npy;." ^
--add-data="DI6.npy;." ^
--add-data="OwnerPredict2.joblib;." ^
connectToOracle.py

(EDIT) And here is the portion of the code that actually needs those files. using numpy load and converting to a pandas dataframe.

TestFrame.fillna(0, inplace=True)

print('Copying Dataframe')
TestFrameFinal = TestFrame.copy(deep=True)

DI1 = load('DI1.npy', allow_pickle = True).item()
DI2 = load('DI2.npy', allow_pickle = True).item()
DI3 = load('DI3.npy', allow_pickle = True).item()
DI4 = load('DI4.npy', allow_pickle = True).item()
DI5 = load('DI5.npy', allow_pickle = True).item()
DI6 = load('DI6.npy', allow_pickle = True).item()

model = jl('OwnerPredict2.joblib')

I would like to be able to compile all of this into one .exe, no matter how large or slow, that can be executed on any pc at my work by anybody. I need to get these extra files to be unpacked into a location that the .exe can find so everything will run properly.

Upvotes: 2

Views: 2979

Answers (1)

john-hen
john-hen

Reputation: 4866

The solution is to modify your code so that it uses run-time information to know if it is running from the bundled .exe or as the original Python source, and have it use a different file-system path to the data files accordingly.

You are currently trying to load your data files from the current working directory, which is usually the directory that the .exe resides in. However, the data files are in the MEI**** folder that you mention.

For reference, this is the relevant passage from the PyInstaller documentation:

When your program is not frozen, the standard Python variable __file__ is the full path to the script now executing. When a bundled app starts up, the bootloader sets the sys.frozen attribute and stores the absolute path to the bundle folder in sys._MEIPASS. For a one-folder bundle, this is the path to that folder, wherever the user may have put it. For a one-file bundle, this is the path to the _MEIxxxxxx temporary folder created by the bootloader.

As a simple example, say you have a Python script app.py that simply prints out the content of a data file named data.txt, stored alongside the script. You would bundle it by running pyinstaller --onefile --add-data="data.txt;." app.py on the command line. To make sure the Python script app.py and the bundled executable app.exe both find the data, the source code could be this:

import sys
from pathlib import Path

if getattr(sys, 'frozen', False):
    folder = Path(sys._MEIPASS)
else:
    folder = Path(__file__).parent

file = folder/'data.txt'
data = file.read_text()
print(data)

Upvotes: 1

Related Questions