9

I have a trouble with pyinstaller when adding some data files like images and txts to python program. For example, I have created a toolbar with icons, and I store them in a seperate folder named images. Also I have some some txt and xml files to store some configurations. These txt ant xml files are stored in another folder named data_files. All the py files are stored in another folder named source.

When I am trying to build this python program with pyinstaller, pyinstaller can successfully build all of the source folder, but the images and data_files folders can not be built. I checked the documentation of pyinstaller but I could not find any solution. I have made a lot of google searches and found only this resourse as helpful, but this is a very inadequate resource.

My main question is: How can I build an exe file with a separately built folder such as images and confs by using pyinstaller?

Edit: I found the solution. When you create the spec file you have to a.datas parameter.

# -*- mode: python -*-
a = Analysis([os.path.join(HOMEPATH,'support/_mountzlib.py'), os.path.join(HOMEPATH,'support/useUnicode.py'), '/home/vmode/Desktop/derlem2/sources/TextSTAT.py'],
             pathex=['/home/pyinstaller'])
a.datas += [("Images/New.gif","/home/vmode/Desktop/derlem2/Images/New.gif","DATA")]
a.datas += [("Images/Open.gif","/home/vmode/Desktop/derlem2/Images/Open.gif","DATA")]
a.datas += [("Images/Column.gif","/home/vmode/Desktop/derlem2/Images/Column.gif","DATA")]
pyz = PYZ(a.pure)
exe = EXE( pyz,
          a.scripts,
          a.binaries,
          a.zipfiles,
          a.datas,
          name=os.path.join('dist', 'TextSTAT'),
          debug=False,
          strip=False,
          upx=True,
          console=1 )

The above spec code is designed for my project. As seen in this spec code I have included 3 icons to build with the python program. When the programme is generated there is a standalone executable file with embedded these icons.

But what if we have so many files? Suppose that we have 1000 icons to use in our program. It is very inadequate to write down to spec file by hand. There must be a loop system to read the file directory and add these files dynamically. But I could not find how to add these files dynamically. There is no any chance to add these so many files by hand I think. If anyone knows please share.

Community
  • 1
  • 1
user1150508
  • 216
  • 2
  • 7
  • Try `cx_freeze`. I tried `py2exe`, `pyinstaller`, some other random program, and only `cx_freeze` worked for me (I used PyQt4). If you want to see my code for making a binary, it's on GitHub: https://github.com/Blender3D/Bindery/blob/master/tools/binary.py – Blender Jan 15 '12 at 15:37
  • Thank you for your interest. But cx_freeze only builds .exe file. I wanna build the programme fol all platforms. So I have to use pyinstaller. But have some big toubles. – user1150508 Jan 15 '12 at 15:55
  • No, `cx_freeze` creates binaries for Linux as well. Mac requires Py2app. – Blender Jan 15 '12 at 23:31
  • Also, do you mind posting your solution for others? – Blender Jan 15 '12 at 23:31

2 Answers2

5

In creating my executable, I came across this problem as well. Because the .spec file is using python, glob module was my solution.

imagesList = []
imagesList.append( ('icon.ico', '..\\pathfinder\\icon.ico',  'DATA') )
import glob
allImages = glob.glob('..\\pathfinder\\*.png')
for eachImage in allImages:
    imageParts = eachImage.split('\\')
    imagesList.append( (imageParts[-1], eachImage,  'DATA') )
print imagesList
a.datas += imagesList

Line 2 regarding icon.ico was separate because it had a different file extension, and can thus be excluded. '..\pathfinder' is the path for all of my program's files (relative from pyinstaller directory). glob searches the directory for all .png files (I have 65 and refused to write them all by hand) and returns a list of them as strings, full relative directory intact. To separate it into a list of filenames, I used string.split() on backslash. Then for each, append to a user-made list a tuple of the final part of the string split (which would end up being just the filename of the image) and the full pathname. Finally, with a list of all the files, add it to a.datas.

I've confirmed through the command line that this does indeed work correctly, and you can re-copy the loop for any additional file extensions.

Unfortunately, even though it seems to pull and attach the filenames correctly, my executable still does not seem to be created with the files (or the executable cannot find the files within its own data) and I still have to have the raw images in the same directory for it to work; perhaps I have the elements of the tuple ordered incorrectly (and thus, if so, you should adjust my code accordingly). Hopefully, this dynamic load will still work for you, though. imageParts[-1] represents each .png's filename, and eachImage represents its full path (or relative path if that's what was used in glob).

Mark
  • 51
  • 1
  • 2
1

If all images are listed under same directory you can use Tree

dict_tree = Tree('/home/vmode/Desktop/derlem2/Images', prefix = 'Images')
a.datas += dict_tree
hithwen
  • 2,154
  • 28
  • 46