MaxPi
MaxPi

Reputation: 867

Include data with spec file using pyinstaller

I am trying to bundle an application written in Python and include the relevant data files in the bundle. What is wrong with the way I am adding in data?

This is using a spec file to exclude certain libraries and include data files. I run the cmd pyinstaller --onefile main.spec

# -*- mode: python -*-

block_cipher = None

added_data = [('file_one.pickle', '.'),
              ('file_two.pickle', '.'),
              ('file_three.pickle', '.')]

excluded_libraries = [XXX]

a = Analysis(['main.py'],
             pathex=['C:\\Users\\XXX\\XXX\\XXX\\XXX\\Folder'],
             binaries=[],
             datas=added_data,
             hiddenimports=[],
             hookspath=[],
             runtime_hooks=[],
             excludes=excluded_libraries,
             win_no_prefer_redirects=False,
             win_private_assemblies=False,
             cipher=block_cipher,
             noarchive=False)
pyz = PYZ(a.pure, a.zipped_data,
             cipher=block_cipher)
exe = EXE(pyz,
          a.scripts,
          [],
          exclude_binaries=True,
          name='main',
          debug=False,
          bootloader_ignore_signals=False,
          strip=False,
          upx=True,
          console=True )
coll = COLLECT(exe,
               a.binaries,
               a.zipfiles,
               a.datas,
               strip=False,
               upx=True,
               name='main')

When I run the .exe, the program runs until the files I want to bundle are necessary. However, the program runs completely if I place the files in the same directory as the .exe

Upvotes: 1

Views: 1377

Answers (1)

Masoud Rahimi
Masoud Rahimi

Reputation: 6041

The way you are bundling the files are fine but I recommend you to use add-data flag with the build arguments. I think your problem is with the way you retrieve the files. According to docs:

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. For a one-file bundle, this is the path to the temporary folder created by the bootloader.

So you bundle the files PyInstaller would extract them in a temporary directory something like C:/Users/<Username>/AppData/Local/Temp/_MEIxxxxxx. You need to retrieve the files from there.

import os
import sys


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)


if __name__ == "__main__":
    file_one_path = resource_path("file_one.pickle")
    file_two_path = resource_path("file_two.pickle")
    file_three_path = resource_path("file_three.pickle")

Upvotes: 1

Related Questions