-

Hi, I got an private message from Osirus requesting that I share my py2exe code. I figure if it’s useful to one person, it may be useful to others.

I am writing a whole set of utilities based off of panda so I wrote a generic py2exe setup script that lets me easily retarget the python code that gets packaged.

The code is split up into two files build.py and pandasetup.py. build.py collects commandline arguments and calls setup. pandasetup.py just manages all of the directories and paths required to build panda into the final distibutable.

You should be able to make an exe w/this code using the following example commandline:

ppython -OO build.py -f mytestfile.py -r src

NOTE: in this example, your code would be in a directory named “src” and there would be a file in that directory called “mytestfile.py” that you wanted to turn into an .exe

However, I never run the code this way myself. Instead I made a target for apache ant that lets me run py2exe w/through these scripts during my build process. I included this code as well.

#Listing for build.py
import os 
import glob
from pandasetup import *
#import distutils
from distutils.core import setup 
from optparse import OptionParser
import sys
from string import *
import py2exe 



parser = OptionParser()

parser.add_option("-p",
                  "--pandapath",
                  dest="pandapath",
                  default = "C:\\Panda3D-1.3.2",
                  help="Path to Panda")

parser.add_option("-r",
                  "--rootpath",
                  dest="rootpath",
                  default = "src",
                  help="Project Root")

parser.add_option("-f",
                  "--file",
                  dest="buildfile",
                  default = "test.py",
                  help="file to compile FILE", metavar="FILE")

parser.add_option("-d",
                  "--dist",
                  dest="distpath",
                  default = "dist",
                  help="Directory Output DIR",metavar="DIR")

parser.add_option("-l",
                  "--library",
                  dest="libfile",
                  default = "library.zip",
                  help="Zipfile libraryname")

parser.add_option("-w",
                  "--windowed",
                  dest="windowed",
                  default = False,
                 help="Run in windows mode")

parser.add_option("-i",
                  "--icon",
                  dest="icon_path",
                  default = "icon.ico",
                  help="Icon path")


(cmdopts, args) = parser.parse_args()
print "argv: "+str(sys.argv)
sys.argv=[sys.argv[0],'py2exe']
print "Current Working Dir: "+str(os.getcwd())
def createSetupCommandLine(pandapath,
                           rootpath,
                           buildfile,
                           distpath,
                           libfile,
				   iconpath,
                           isWindowed):
    args ={}
    if(isWindowed):
       args['windows']=[{"script":os.path.join(rootpath,buildfile),"icon_resources":[(1,iconpath)]}]
    else:
        args['console']=[{"script":os.path.join(rootpath,buildfile),"icon_resources":[(1,iconpath)]}]
    
    args['zipfile'] = libfile
    py2exeOpts= {}
    py2exeOpts['unbuffered']=True
    py2exeOpts['optimize']=2
    py2exeOpts['dist_dir']=distpath           
    
    args['options'] = {'py2exe':py2exeOpts}
    args['packages'] = getPackages()
    args['package_dir'] = getPackageDirs(pandapath,rootpath)
    args['data_files'] = getDataFiles(pandapath)
    return args


setupArgs =createSetupCommandLine(strip(cmdopts.pandapath),
                                  os.path.join(os.getcwd(),strip(cmdopts.rootpath)),
                                  strip(cmdopts.buildfile),
                                  os.path.join(os.getcwd(),strip(cmdopts.distpath)),
                                  strip(cmdopts.libfile),
					    cmdopts.icon_path,
                                  cmdopts.windowed)
setup(**setupArgs)
#Listing for pandasetup.py
import os 
import glob
def getPackages():
    return [ '',
            'direct', 
            'direct.directbase', 
            'direct.showbase', 
            'direct.interval', 
            'direct.actor', 
            'direct.gui', 
            'direct.task', 
            'direct.controls', 
            'direct.directnotify', 
            'direct.directtools', 
            'direct.directutil', 
            'direct.fsm', 
            'direct.cluster', 
            'direct.particles', 
            'direct.tkpanels', 
            'direct.tkwidgets', 
            'direct.directdevices', 
            'direct.distributed', 
            'pandac', 
            ]

def getPackageDirs(pandapath,srcdir):
    return {    '':srcdir,
                'direct' : os.path.join(pandapath, 'direct'), 
                'direct.directbase' : os.path.join(pandapath, 'direct/directbase'), 
                'direct.showbase' : os.path.join(pandapath, 'direct/showbase'), 
                'direct.interval' : os.path.join(pandapath, 'direct/interval'), 
                'direct.actor' : os.path.join(pandapath, 'direct/actor'), 
                'direct.gui' : os.path.join(pandapath, 'direct/gui'), 
                'direct.task' : os.path.join(pandapath, 'direct/task'), 
                'direct.controls' : os.path.join(pandapath, 'direct/controls'), 
                'direct.directnotify' : os.path.join(pandapath, 'direct/directnotify'), 
                'direct.directtools' : os.path.join(pandapath, 'direct/directtools'), 
                'direct.directutil' : os.path.join(pandapath, 'direct/directutil'), 
                'direct.fsm' : os.path.join(pandapath, 'direct/fsm'), 
                'direct.cluster' : os.path.join(pandapath, 'direct/cluster'), 
                'direct.particles' : os.path.join(pandapath, 'direct/particles'), 
                'direct.tkpanels' : os.path.join(pandapath, 'direct/tkpanels'), 
                'direct.tkwidgets' : os.path.join(pandapath, 'direct/tkwidgets'), 
                'direct.directdevices' : os.path.join(pandapath, 'direct/directdevices'), 
                'direct.distributed' : os.path.join(pandapath, 'direct/distributed'), 
                'pandac' : os.path.join(pandapath, 'pandac'), 
                }
def getDataFiles(pandapath):
    return [    ('etc', [os.path.join(pandapath, 'etc/Config.prc')]), 
                # make sure all dlls are copied from Panda3D 
                ('.', glob.glob(os.path.join(pandapath, 'bin/*.dll'))), 
            ] 
<!--ANT Py2exe code for panda-->
<project>
    <property name="panda.dir" value="C:\Panda3D-1.3.2"/>
    <property name="panda.bin.dir" value="${panda.dir}\bin"/>
    <property name="panda.python.dir" value="${panda.dir}\python"/>
    <property name="ppython.exe" value="${panda.python.dir}\ppython.exe"/>
    <property name="py2exe.tools.dir" location="tools\py2exe"/>
    <property name="py2exeHelper" value="${py2exe.tools.dir}\build.py"/>

    <target name="py2exe">
        <echo message="pyfile=${pyfile}"/>
        <echo message="Python : ${ppython.exe}"/>
        <echo message="Panda Dir: ${panda.dir}"/>
        <echo message="Src Dir : ${src.dir}"/>
        <echo message="Target File : ${pyfile}.py"/>
        <echo message="Target Dir : ${target.dir}\${pyfile}"/>
        <echo message="Library File : ${pyfile}.zip"/>
        
        <exec executable="${ppython.exe}" failonerror="yes">
                <arg value="-OO"/>
                <arg value="${py2exeHelper}"/>
                <arg value="-p ${panda.dir}"/>
                <arg value="-r ${src.dir}"/>
                <arg value="-f ${pyfile}.py"/>
                <arg value="-d ${target.dir}\${pyfile}"/>
                <arg value="-l ${pyfile}.zip"/>
                <redirector output="${log.dir}/${pyfile}/${pyfile}.out.txt"
                            error="${log.dir}/${pyfile}/${pyfile}.err.txt">
                </redirector>

        </exec>
    </target>
</project>