11
votes

I have been trying to make a single executable file and I am getting close. Please do not recommend that I use PyInstaller -- I have tried that route, asked on SO here, and have put in tickets. It is close but not quite working. I am now trying py2exe and am also very close. In pyinstaller, I am able to create resource files (which builds the executable with the files included -- I can then access these in the temporary folder).

I want to do the same for py2exe. I have a single executable, but five extra folders (maps, mpl-data, data, pics and tcl). I have seen this question but can't seem to understand it, nor get it to work. In my main py file, I am using PersistentDict(filepath) which is where I need the path to the file.

My question is two parts: 1. How do I get the files (data files below) packaged into the executable. 2. How do I access these files in my code and return their path (as a string) such as /temp/file1.jpg.

Here is my code for my py2exe setup file -- note that I have matplotlib and must include the mpl-data correctly in my executable. Thanks!

from distutils.core import setup 
import py2exe 
import shutil
import glob 
import matplotlib,six

opts = {'py2exe': { "includes" : ["matplotlib.backends",
                                  "matplotlib.backends.backend_qt4agg",
                                  "matplotlib.figure","numpy",
                                  "six",
                                  "mpl_toolkits.basemap", 
                                  "matplotlib.backends.backend_tkagg"], 
                     'excludes': ['_gtkagg', '_tkagg','_agg2','_cairo',
                                  '_cocoaagg', '_fltkagg', '_gtk', '_gtkcairo', 'tcl' ], 
                 'dll_excludes': ['libgdk-win32-2.0-0.dll','w9xpopen.exe', 
                                 'libgobject-2.0-0.dll'],
                    'bundle_files': 1,
                    'dist_dir': "Dist Folder",
                    'compressed': True,
              } 
       }

data_files = [(r'mpl-data', glob.glob(r'C:\Python27\Lib\site-packages\matplotlib\mpl-data\*.*')),
              (r'mpl-data', [r'C:\Python27\Lib\site-packages\matplotlib\mpl-data\matplotlibrc']), 
              (r'mpl-data\images',glob.glob(r'C:\Python27\Lib\site-packages\matplotlib\mpl-data\images\*.*')), 
              (r'mpl-data\fonts',glob.glob(r'C:\Python27\Lib\site-packages\matplotlib\mpl-data\fonts\*.*')),
              (r'mpl-data\data', glob.glob(r'C:\Python27\Lib\site-packages\matplotlib\mpl-data\data\*.*')),
              ('data', ['C:\\Users\\Me\\Documents\\Example_Json_File.json']),
              ('pics', ['C:\\Users\\Me\\Documents\\Example_Icon.ico',
                        'C:\\Users\\Me\\Documents\\Example_Jpg.jpg',
                        ])]


setup(windows=[{"script" : "MyMainScript.py",
                "data_files" : data_files,
                "icon_resources": [(1, 'C:\\Users\\Me\\Documents\\Example_Icon.ico')]}, ],

                version = "1.0", 
                options=opts,
                data_files=data_files,
                zipfile = None,
      ) 
2
Have you tried IExpress? It was originally designed for installing device drivers and IE 6 (shudder), but I've abused it before for exactly your use case. - Lambda Fairy
I dont think this is what I want. I am using Inno Setup which seems similar to this. When I give the executable (or installer) to another user, I want them to only have an executable -- no files associated with it that they could see/change (thus the files are built into the executable). - mcfly
So what exactly do you want the executable to do? Do you want it to 1) extract itself into a temporary folder, 2) run your program, 3) when the program finishes, delete the temporary files? That's what IExpress does. - Lambda Fairy
Okay -- let me take a deeper look into this. Will the user have any way to see the extracted files (this is mainly what I am trying to avoid). - mcfly

2 Answers

4
votes

Guy here explains how to package to one file with py2exe. He's setup doesn't package resources inside the executable either.

When I package my apps, I don't use one executable option

options = {"py2exe": {'bundle_files': 1, 'compressed': True}},

not even bothered to put them in library.zip via

options = {"py2exe": {"skip_archive":0}}

Just have a number of pyc's, data files, dlls etc in one dir. Then create an installer using NSIS or Inno setup. As some of my apps have to run as services, Inno was taking care of that. The biggest plus of that approach, you don't have to deal with "frozen" paths to your files, that are different from your original paths.

Otherwise you might need to alter your code to detect frozen paths, e.g. http://www.py2exe.org/index.cgi/WhereAmI

0
votes

I've seen a batch to EXE converter (Advanced Batch to EXE Converter) do this, but in an odd way: It would let you put your files in a "bake" directory, and they could be manipulated via the "%MYFILES%\[path]" directory/variable. If you have some wiggle room, check this out. The only problem is it'll add an "intro" (read: glorified Flash animation) to the file, and it'll show FIRST. (I'm against piracy, but I'd be OK with it here... the "intro" is 45 seconds long and obnoxious.)

If that does not bug you, try giving that a shot.