squirrelgod17
squirrelgod17

Reputation: 73

File path for pyinstaller bundled images?

I am trying to build a one file exe with pyinstaller but I am not sure what the file paths for the images should be in the main python file.

At the top of my main python file I used the MEIPASS code:

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)

From this page

This is the current code I have for each image file:

root.iconbitmap('C:\\Users\\username\\Downloads\\TripApp\\BennySM.ico')
filename = PhotoImage(file = 'C:\\Users\\username\\Downloads\\TripApp\\BgSM.gif')

I know these are not the best file paths but I am not sure what I need to add so the python file knows where to look. The images bundle with the exe and if I add the exe to the data file it finds the images and runs.

Thank you! I tried adding resource_path before but I was missing the file path in the define section at the top.

Thanks again!

Upvotes: 4

Views: 5317

Answers (1)

Stephen Rauch
Stephen Rauch

Reputation: 49784

Question: How do I use a data file in a pyinstaller built program?

Let's first assume that the python script is currently working when run as a script, and that the following line is in the script:

filename = PhotoImage(file='C:\\Users\\username\\Downloads\\TripApp\\BgSM.gif')

This line indicates that the script is retrieving a file from a fixed directory (probably not best practice, but fine for an example), and turning that .gif file into a PhotoImage() object instance. This will be our baseline.

There will need to be three things done to successfully use this file when our script is run as a pyinstaller built program.

1. During the pyinstaller build, move the file to a known location

This step is accomplished by adding a datas directive to the `.spec' file. See this post for more info on how to do that. But in short, this will be needed:

datas=[
    ('C:\\Users\\test\\Downloads\\TripApp\\BgSM.gif', 'data'),
    ...
],

Please note that there are two elements in the tuple. The first element is the path of our .gif file as it exists in the working python script before we packaged it into a pyinstaller executable. The second element of the tuple is the directory that the file will be in when the executable is run.

2. At runtime, find our .gif file

Here is the function from the example in the question, recast to use:

  1. The absolute path from the example, when the script is run as a script or,
  2. The path specified in the datas tuple when the script is run as a pyinstaller built program.

Code:

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,
        # and places our data files in a folder relative to that temp
        # folder named as specified in the datas tuple in the spec file
        base_path = os.path.join(sys._MEIPASS, 'data')
    except Exception:
        # sys._MEIPASS is not defined, so use the original path
        base_path = 'C:\\Users\\test\\Downloads\\TripApp'

    return os.path.join(base_path, relative_path)

3. Recast the baseline to work in our pyinstaller built program

So now that we can construct a path to our .gif file when run as a script, or as a pyinstaller built program, our baseline becomes:

filename = PhotoImage(file=resource_path('BgSM.gif'))

Upvotes: 4

Related Questions