9

I have been combing Stack Overflow and the rest of the web on how to add data files into my python application:

import Tkinter

class simpleapp_tk(Tkinter.Tk):
    def __init__(self,parent):
        Tkinter.Tk.__init__(self,parent)
        self.parent = parent
        self.initialize()

    def initialize(self):
        self.grid()

--- Everything Fine Here ---

        self.B = Tkinter.Button(self, text = 'Create Document', command = self.OnButtonClick)
        self.B.grid(column = 0, row = 6)


    def OnButtonClick(self):
        createDoc()

if __name__ == "__main__":
    app = simpleapp_tk(None)
    app.title('Receipt Form')
    app.iconbitmap(os.getcwd() + '/M.ico')
    app.mainloop()

I have tried using the .spec file with no luck

Onedir works fine, however when I try to compile into a single executable, it gives an error that the file 'M.ico' isn't defined.

If anyone was able to bundle data files with pyinstaller into a single file. Please help. Thanks.

I am on a Windows 10 computer running Python 2.7 with PyInstaller 3.2

Michael Zheng
  • 136
  • 1
  • 9
  • I think your issue is that `pyinstaller` [uses a temporary folder to extract the files](https://pythonhosted.org/PyInstaller/advanced-topics.html#bootloader). You have specify that in your code for the frozen application as done [here](http://stackoverflow.com/questions/7674790/bundling-data-files-with-pyinstaller-onefile). – Repiklis Aug 15 '16 at 15:05
  • @Repiklis Ok, how exactly do I use this though? Do I do `app.iconbitmap(resource_path('/M.ico'))` – Michael Zheng Aug 15 '16 at 16:41
  • It's very similar to [this](http://stackoverflow.com/questions/38874563/pypandoc-in-combination-with-pyinstaller/38957523#38957523). You have to include your icon in the `resources` in the spec file and add the two lines at the bottom of the answer in your code (before setting the icon). If you still have issues let me know. – Repiklis Aug 15 '16 at 16:47
  • @Repiklis I did exactly what you said: I added `resources=['M.ico'])` to the end of my spec and added `if hasattr(sys, '_MEIPASS'): os.chdir(sys._MEIPASS)` to my actual python file, but I still get the error: `_tkinter.TclError: bitmap "C:\Users\micha\AppData\Local\Temp\_MEI69~1/M.ico" not defined` – Michael Zheng Aug 15 '16 at 20:44
  • The slash you are using before `M.ico` is wrong. Should be `\\M.ico` in this case. Even better, use [`os.sep`](https://docs.python.org/2/library/os.html#os.sep) to get the system path separator. – Repiklis Aug 16 '16 at 09:04

1 Answers1

7

You must specify every data file you want added in your pyinstaller .spec file, or via the command line options (.spec is much easier.) Below is my .spec file,with a "datas" section:

# -*- mode: python -*-

block_cipher = None


a = Analysis(['pubdata.py'],
             pathex=['.', '/interface','/recommender'],
             binaries=None,
             datas=[('WordNet/*.txt','WordNet'),
             ('WordNet/*.json','WordNet'),
             ('WordNet/pdf_parsing/*.json','pdf_parsing'),
             ('WordNet/pdf_parsing/*.xml','pdf_parsing'),
             ('images/*.png','images'),
             ('database/all_meta/Flybase/*.txt','all_meta'),
             ('database/all_meta/Uniprot/*.txt','all_meta'),
             ('database/json_files/*.json','json_files'),
             ('Data.db','.')],

             hiddenimports=['interface','recommender'],
             hookspath=[],
             runtime_hooks=[],
             excludes=[],
             win_no_prefer_redirects=False,
             win_private_assemblies=False,
             cipher=block_cipher)
pyz = PYZ(a.pure, a.zipped_data,
             cipher=block_cipher)
exe = EXE(pyz,
          a.scripts,
          exclude_binaries=True,
          name='GUI',
          debug=False,
          strip=False,
          upx=True,
          console=True )
coll = COLLECT(exe,
               a.binaries,
               a.zipfiles,
               a.datas,
               strip=False,
               upx=True,
               name='GUI')
app = BUNDLE(coll,
             name='App.app',
             icon=None)

After this, if you are trying to access any data file you specified in the .spec file, in your code, you must use Pyinstaller's _MEIPASS folder to reference your file. Here is how i did so with the file named Data.db:

import sys
import os.path

        if hasattr(sys, "_MEIPASS"):
            datadir = os.path.join(sys._MEIPASS, 'Data.db')
        else:
            datadir = 'Data.db'

        conn = lite.connect(datadir)

This method above replaced this statement that was on its own:

conn = lite.connect("Data.db")

This link helped me a lot when i was going through the same thing: https://irwinkwan.com/2013/04/29/python-executables-pyinstaller-and-a-48-hour-game-design-compo/

Hope this helps!

cyborg95
  • 185
  • 11