Adding a Data File in Pyinstaller Using the Onefile Option

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

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)

Include multiple data files with pyinstaller

The answer was in https://media.readthedocs.org/pdf/pyinstaller/cross-compiling/pyinstaller.pdf which indicates I can simply use the --add-data option multiple times!

Adding textfile with --onefile option

When you add your text file with one-dir, Pyinstaller would put your file next to your executable and you will be fine when accessing your file by the script (e.g open("myfile.txt"). But when you create your executable with --onefile it would extract your file in a temp directory which is a separate directory, so calling open("myfile.txt") would result in a NotFound error because the file doesn't exist besides your executable. So you need to change the path to point to the temp directory. The sys._MEIPASS would return the temp directory so you need to locate your files inside it. You can find more info in here.

A function like this would solve the problem:

import sys
import os


def resource_path(relative_path):
if hasattr(sys, '_MEIPASS'):
return os.path.join(sys._MEIPASS, relative_path)
return os.path.join(os.path.abspath("."), relative_path)

Then you can access your file with source = resource_path("myfile.txt").



Related Topics



Leave a reply



Submit