Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Adding a data file in Pyinstaller using the onefile option

I'm trying to add an image to the one file produced by Pyinstaller. I've read many questions/forums like this one and that one and still it's not working.

I know that for one file operation, Pyinstller produce a temp folder that could be reached by sys.MEIPASS. However I don't know where exactly in my script I should add this sys.MEIPASS.

Kindly show the following:

1- Where and how sys.MEIPASS should be added? In the python script, or in the spec file?

2- What is the exact command to use? I've tried

pyinstaller --onefile --windowed --add-data="myImag.png;imag" myScript.py

or

pyinstaller --onefile --windowed myScript.py

and then add ('myImag.png','imag') to the spec file and then run

pyinstller myScript.spec

None has worked.

Note: I have python 3.6 under windows 7

like image 993
AhmedWas Avatar asked Jun 27 '18 10:06

AhmedWas


People also ask

What is Onefile in PyInstaller?

When we specify the onefile option, to the PyInstaller, it unpacks all the files to a TEMP directory, executes the file, and later discard the TEMP folder. When you specify the add-data option along with onefile, then you need to read the data referred to in the TEMP folder.

What is Pathex in PyInstaller?

Explanation. pathex is an optional list of paths to be searched before sys.path. Source: https://github.com/pyinstaller/pyinstaller/blob/develop/PyInstaller/building/build_main.py#L123. The spec file is actually executable Python code. PyInstaller builds the app by executing the contents of the spec file.

How do I use PyInstaller hidden import?

The simpler solution is to use --hidden-import=modulename along with the PyInstaller script. It will add modulename as import statement silently. Hooks are better if you want to specify which import needs what additional modules. --hidden-import is simpler as a one-shot or for debugging.


1 Answers

When packaged to a single file with PyInstaller, running the .exe will unpack everything to a folder in your TEMP directory, run the script, then discard the temporary files. The path of the temporary folder changes with each running, but a reference to its location is added to sys as sys._MEIPASS.

To make use of this, when your Python codes reads any file that will also be packaged into your .exe, you need to change the files location to be located under sys._MEIPASS. In other words, you need to add it to your python code.

Here is an example that using the code from the link you referenced to adjust the file path to correct location when packaged to a single file.

Example

# data_files/data.txt
hello
world

# myScript.py
import sys
import os

def resource_path(relative_path):
    """ Get absolute path to resource, works for dev and for PyInstaller """
    try:
        # PyInstaller creates a temp folder and stores path in _MEIPASS
        base_path = sys._MEIPASS
    except Exception:
        base_path = os.path.abspath(".")

    return os.path.join(base_path, relative_path)

def print_file(file_path):
    file_path = resource_path(file_path)
    with open(file_path) as fp:
        for line in fp:
            print(line)

if __name__ == '__main__':
    print_file('data_files/data.txt')

Running PyInstaller with the following options packages the file:

pyinstaller --onefile --add-data="data_files/data.txt;data_files" myScript.py

builds myScript.exe which runs correctly and can open and read the packaged data file.

like image 94
James Avatar answered Oct 09 '22 18:10

James