Pack an Enthought Traits app inside a .exe using py2exe !

[DEPRECATED if you use ETS 4.0 — see the new version]

So, guys, today is a great day, BIG news : I succeeded packaging an Enthought Traits UI script inside a standalone package.

Keys to remember:

  1. To get things to work, I had to manually import all packages used, surely the Wx backend.
  2. It’s not possible, currently, to bundle and to compress.
  3. I add the /images folders manually using the data_files variable.

My configuration:

  • Windows XP Pro 32bits
  • Python 2.5.4
  • Numpy 1.5.0
  • Py2exe 0.6.9
  • Distutils 2.5.1
  • Enthought Tool Suite ETS 3.5.0 from SVN

So, here is a typical example :

from enthought.traits.api import *

class Person(HasTraits):
    name = Str
    age = CInt
    weight = CFloat

if __name__ == "__main__":
    joe = Person()
    joe.configure_traits()
    print joe.name, joe.age, joe.weight

You’ll see below, the ETS from SVN in downloaded in “c:\python_install\ETS”

The setup.py script looks like :

from distutils.core import setup
import py2exe
import os
import enthought

includes = []
includes.append('numpy')
includes.append('scipy')
includes.append('numpy.core')
includes.append('wx')
includes.append('wx.*')
includes.append('enthought')
includes.append('enthought.kiva')
includes.append('enthought.traits')
includes.append('enthought.traits.ui')
includes.append('enthought.traits.ui.wx')
includes.append('enthought.traits.ui.wx.*')
includes.append('enthought.pyface.*')
includes.append('enthought.pyface.ui.*')
includes.append('enthought.pyface.ui.wx.*')
includes.append('enthought.pyface.ui.wx.action.*')
includes.append('enthought.pyface.ui.wx.timer.*')
includes.append('enthought.pyface.ui.wx.wizard.*')
includes.append('enthought.pyface.ui.wx.workbench.*')
includes.append('enthought.enable')
includes.append('enthought.enable.*')
includes.append('enthought.enable.drawing')
includes.append('enthought.enable.image')
includes.append('enthought.enable.image_title')
includes.append('enthought.enable.traits')
includes.append('enthought.enable.wx_backend')

packages = []

ETS_folder = r'C:\python_install\ETS'

data_folders = []

data_folders.append( ( os.path.join(ETS_folder,r'TraitsGUI\enthought\pyface\images') , 'enthought/pyface/images') )
data_folders.append( ( os.path.join(ETS_folder,r'Enable\enthought\enable\images') , 'enthought/enable/images') )
data_folders.append( ( os.path.join(ETS_folder,r'TraitsBackendWX\enthought\pyface\ui\wx\images') , 'enthought/pyface/ui/wx/images') )
data_folders.append( ( os.path.join(ETS_folder,r'TraitsBackendWX\enthought\traits\ui\wx\images') , 'enthought/traits/ui/wx/images') )
data_folders.append( ( os.path.join(ETS_folder,r'TraitsGUI\enthought\traits\ui\image\library') , 'enthought/traits/ui/image/library') )

data_files = []

for folder, relative_path in data_folders:
    for file in os.listdir(folder):
        f1 = os.path.join(folder,file)
        if os.path.isfile(f1): # skip directories
            f2 = relative_path, [f1]
            data_files.append(f2)

setup(console=['helloworld.py'],

    options = {"py2exe": {    "optimize": 0,
                              "packages": packages,
                              "includes": includes,
                              "dist_dir": 'dist',
                              "bundle_files":2,
                              "xref": False,
                              "skip_archive": True,
                              "ascii": False,
                              "custom_boot_script": '',
                              "compressed":False,
                             },},
    data_files=data_files)

then, to launch the packing, just do:
$ python setup.py py2exe

The build and packing process takes some time, but it works. The /dist directory contains a lot of libraries (~100 MB), there must be a way to cut down the imports, but I have to admit, now that I have a successful build, I really don’t care if it’s 110 MB or 80 MB !

to launch the script, just hit “helloworld.exe” in the /dist folder. Note, I set the “console” value to “helloworld.py”, because I wanted to have a python console running behind my GUI. If you replace “console” by “windows”, double-clicking “helloworld.exe” will just load your GUI.

Nota Bene : if you need matplotlib, here is the way:
Replace:

data_files = []

Load the related files instead:

import matplotlib as mpl
data_files = mpl.get_py2exe_datafiles()

Cheers & Have Fun !

Thomas

2 thoughts on “Pack an Enthought Traits app inside a .exe using py2exe !”

  1. Hi Thomas

    Did you ever find a way around the archive problem, and the way includes are handled. I am stuck trying to created a bundled exe file with py2exe and traits ui.

    Thanks,
    Morten

  2. Morten,

    No, actually not. I’ve bundled the whole /dist folder in a single setup.exe using NSI. For the end user, it unpacks the data in %programfiles%/MyProgram/ and creates a link in the start menu. For most users, that’s simple enough and they don’t go checking the complexity of the /MyProgram folder !

    I’m pretty sure that it will never be easy to properly include all the enthought packages, simply because they do a lot of very clever relative imports, etc.

    Cheers,

    Thom

Leave a Reply

Your email address will not be published. Required fields are marked *

*