Differences between revisions 2 and 18 (spanning 16 versions)
Revision 2 as of 2009-05-16 13:44:44
Size: 11371
Editor: ABordeaux-156-1-121-103
Comment:
Revision 18 as of 2010-08-21 18:54:09
Size: 4815
Editor: c-75-72-71-98
Comment: fix bullet list markup
Deletions are marked like this. Additions are marked like this.
Line 1: Line 1:
== Introduction == == Using py2exe to freeze your application ==
Line 9: Line 9:
* Python

* wxPython

* [[http://www.py2exe.org/|py2exe]]

* [[http://code.google.com/p/gui2exe/|Gui2Exe - by Andrea Gavana]]
  * [[http://www.python.org/|Python]]
  * [[http://www.wxpython.org/|wxPython]]
  * [[http://www.py2exe.org/|py2exe]]
  * [[http://code.google.com/p/gui2exe/|Gui2Exe - by Andrea Gavana]]
Line 19: Line 16:
A tiny sample wxPython "Hello world" application will be used to demonstrate the process. I created the tiny application using [[https://sourceforge.net/projects/boa-constructor/|Boa Constructor]] but you could use any other IDE you use for your wxPython development. The creation of the setup.py file I did using [[http://code.google.com/p/gui2exe/|Gui2Exe]], but again one could create this by hand. A small sample wxPython "Hello world" application will be used to demonstrate the process. I created the tiny application using [[https://sourceforge.net/projects/boa-constructor/|Boa Constructor]] but you could use any other IDE you use for your wxPython development. I did the initial creation of the setup.py file with [[http://code.google.com/p/gui2exe/|Gui2Exe]] and then keep maintaining it and running it from the IDE (Boa in my case).
Line 21: Line 18:
== Special Concerns == == Python 2.5 ==
Line 23: Line 20:
Python 2.5x
  * you will need the MS C run time dll 'msvcr71.dll', included with Python
  * the dll 'gdiplus.dll' might also be needed depending on what wxPython widgets you use
The setup.py needed for Python 2.5 or lower is shown on [[py2exe-python25|the py2exe for Python 2.5 page]].
Line 27: Line 22:
== Python 2.6 ==
Line 28: Line 24:
Python 2.6x
  * you will need the MS C run time dll's (msvcr90.dll, msvcp90.dll, msvcm90.dll), included with Python (see the SxS folder under Windows)
  * you will need a copy of the Microsoft.VC90.CRT.manifest file
  * the dll 'gdiplus.dll' might also be needed depending on what wxPython widgets you use
The setup.py needed for Python 2.6 is shown on [[py2exe-python26|the py2exe for Python 2.6 page]].
Line 33: Line 26:

== The setup.py ==

Save the following code in your working folder as a file called 'setup.py'.

{{{
#!python
# ======================================================#
# File automagically generated by GUI2Exe version 0.3
# Andrea Gavana, 01 April 2007
# ======================================================#

# Let's start with some default (for me) imports...

from distutils.core import setup
import py2exe
import glob
import os
import zlib
import shutil

# Remove the build folder
shutil.rmtree("build", ignore_errors=True)

print 'is this shown'

class Target(object):
    """ A simple class that holds information on our executable file. """
    def __init__(self, **kw):
        """ Default class constructor. Update as you need. """
        self.__dict__.update(kw)
        

# Ok, let's explain why I am doing that.
# Often, data_files, excludes and dll_excludes (but also resources)
# can be very long list of things, and this will clutter too much
# the setup call at the end of this file. So, I put all the big lists
# here and I wrap them using the textwrap module.

data_files = []

includes = []
excludes = ['_gtkagg', '_tkagg', 'bsddb', 'curses', 'email', 'pywin.debugger',
            'pywin.debugger.dbgcon', 'pywin.dialogs', 'tcl',
            'Tkconstants', 'Tkinter']
packages = []
dll_excludes = ['libgdk-win32-2.0-0.dll', 'libgobject-2.0-0.dll', 'tcl84.dll',
                'tk84.dll']
icon_resources = []
bitmap_resources = []
other_resources = []


# This is a place where the user custom code may go. You can do almost
# whatever you want, even modify the data_files, includes and friends
# here as long as they have the same variable name that the setup call
# below is expecting.

baseFolder, progFolder = os.path.split(os.getcwd())

#
# The following will copy the MSVC run time dll's
# (msvcm90.dll, msvcp90.dll and msvcr90.dll) and
# the Microsoft.VC90.CRT.manifest which I keep in the
# "Py26MSdlls" folder to the dist folder
#
# depending on wx widgets you use, you might need to add
# gdiplus.dll to the above collection

py26MSdll = glob.glob(r"c:\dev\Py26MSdlls\*.*")

data_files += [("", py26MSdll),
     ]


# Ok, now we are going to build our target class.
# I chose this building strategy as it works perfectly for me :-D


GUI2Exe_Target_1 = Target(
    # what to build
    script = "simplewx.py",
    icon_resources = icon_resources,
    bitmap_resources = bitmap_resources,
    other_resources = other_resources,
    dest_base = "simplewx",
    version = "0.1",
    company_name = "No Company",
    copyright = "No Copyrights",
    name = "Py2Exe Sample File"
    )



# That's serious now: we have all (or almost all) the options py2exe
# supports. I put them all even if some of them are usually defaulted
# and not used. Some of them I didn't even know about.

setup(

    data_files = data_files,

    options = {"py2exe": {"compressed": 2,
                          "optimize": 2,
                          "includes": includes,
                          "excludes": excludes,
                          "packages": packages,
                          "dll_excludes": dll_excludes,
                          "bundle_files": 3,
                          "dist_dir": "dist",
                          "xref": False,
                          "skip_archive": False,
                          "ascii": False,
                          "custom_boot_script": '',
                         }
              },

    zipfile = r'lib/library.zip',
    console = [],
    windows = [GUI2Exe_Target_1]
    )


# And we are done. That's a setup script :-D

# Run setup standalone...
if __name__ == "__main__":
    print 'just running setup'
    setup()
    print 'setup done'

print 'clean up'

# This is a place where any post-compile code may go.
# You can add as much code as you want, which can be used, for example,
# to clean up your folders or to do some particular post-compilation
# actions.

# for some reason some files remain sometimes in dist, but they
# are already present in dist/lib, so lets remove them
#

cwdFolder = os.getcwd()
libFile = os.path.join(cwdFolder, 'dist\\library.zip')
if os.path.exists(libFile):
 print 'deleting duplicate files'
 os.remove(libFile)
 os.remove(os.path.join(cwdFolder, 'dist\\bz2.pyd'))
 os.remove(os.path.join(cwdFolder, 'dist\\select.pyd'))
 os.remove(os.path.join(cwdFolder, 'dist\\unicodedata.pyd'))

}}}

== The MS manifest ==

Following is the content of the Microsoft manifest file, note that the content of "version" and "publicKeyToken" are specific to the version of the dll files. Installing Python 2.6 on Windows 7rc1 with the option "for this user only" this manifest file is created in the Python26 folder. Note the Py26 installer does not offer the "for this user only" option on Vista.

{{{
#!xml
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!-- Copyright (c) Microsoft Corporation. All rights reserved. -->
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
    <noInheritable/>
    <assemblyIdentity
        type="win32"
        name="Microsoft.VC90.CRT"
        version="9.0.21022.8"
        processorArchitecture="x86"
        publicKeyToken="1fc8b3b9a1e18e3b"
    />
    <file name="msvcr90.dll" /> <file name="msvcp90.dll" /> <file name="msvcm90.dll" />
</assembly>
}}}
Line 220: Line 40:
[wxID_FRAME1, wxID_FRAME1PANEL1, wxID_FRAME1STATICTEXT1,
] = [wx.NewId() for _init_ctrls in range(3)]
[wxID_FRAME1, wxID_FRAME1BUTTON1, wxID_FRAME1BUTTON2, wxID_FRAME1PANEL1,   wxID_FRAME1STATICTEXT1,
] = [wx.NewId() for _init_ctrls in range(5)]
Line 229: Line 50:
        parent.AddSizer(self.fgsButtons, 1, border=2, flag=wx.ALL | wx.EXPAND)

    def _init_coll_fgsButtons_Items(self, parent):
        # generated method, don't edit

        parent.AddWindow(self.button1, 1, border=2, flag=wx.ALL | wx.EXPAND)
        parent.AddWindow(self.button2, 1, border=2, flag=wx.ALL | wx.EXPAND)
Line 236: Line 64:
    def _init_coll_fgsButtons_Growables(self, parent):
        # generated method, don't edit

        parent.AddGrowableCol(0)
        parent.AddGrowableCol(1)
Line 242: Line 76:
        self.fgsButtons = wx.FlexGridSizer(cols=2, hgap=0, rows=0, vgap=0)
Line 244: Line 80:
        self._init_coll_fgsButtons_Items(self.fgsButtons)
        self._init_coll_fgsButtons_Growables(self.fgsButtons)
Line 245: Line 83:
        self.SetSizer(self.bsFrame)
Line 246: Line 85:
        self.SetSizer(self.bsFrame)
Line 251: Line 89:
              pos=wx.Point(642, 279), size=wx.Size(124, 86),               pos=wx.Point(642, 279), size=wx.Size(236, 106),
Line 253: Line 91:
        self.SetClientSize(wx.Size(108, 50))         self.SetClientSize(wx.Size(220, 70))
Line 256: Line 94:
              pos=wx.Point(2, 2), size=wx.Size(104, 46),               pos=wx.Point(2, 2), size=wx.Size(216, 66),
Line 261: Line 99:
              pos=wx.Point(10, 10), size=wx.Size(84, 13),               pos=wx.Point(10, 10), size=wx.Size(196, 13),
Line 263: Line 101:

        self.button1 = wx.Button(id=wxID_FRAME1BUTTON1, label='button1',
              name='button1', parent=self.panel1, pos=wx.Point(4, 37),
              size=wx.Size(100, 23), style=0)

        self.button2 = wx.Button(id=wxID_FRAME1BUTTON2, label='button2',
              name='button2', parent=self.panel1, pos=wx.Point(116, 37),
              size=wx.Size(100, 23), style=0)
Line 278: Line 124:
== Sample wxPython application == === Other wiki pages to check ===
Line 280: Line 126:
Save the following code in your working folder as a file called 'simplewx.py'.

{{{
#!python
#Boa:Frame:Frame1

import wx

def create(parent):
    return Frame1(parent)

[wxID_FRAME1, wxID_FRAME1PANEL1, wxID_FRAME1STATICTEXT1,
] = [wx.NewId() for _init_ctrls in range(3)]

class Frame1(wx.Frame):
    def _init_coll_bsPanel_Items(self, parent):
        # generated method, don't edit

        parent.AddWindow(self.staticText1, 0, border=10,
              flag=wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_CENTER_HORIZONTAL | wx.ALL | wx.EXPAND)

    def _init_coll_bsFrame_Items(self, parent):
        # generated method, don't edit

        parent.AddWindow(self.panel1, 1, border=2,
              flag=wx.EXPAND | wx.ALL | wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_CENTER_HORIZONTAL)

    def _init_sizers(self):
        # generated method, don't edit
        self.bsPanel = wx.BoxSizer(orient=wx.VERTICAL)

        self.bsFrame = wx.BoxSizer(orient=wx.VERTICAL)

        self._init_coll_bsPanel_Items(self.bsPanel)
        self._init_coll_bsFrame_Items(self.bsFrame)

        self.panel1.SetSizer(self.bsPanel)
        self.SetSizer(self.bsFrame)

    def _init_ctrls(self, prnt):
        # generated method, don't edit
        wx.Frame.__init__(self, id=wxID_FRAME1, name='', parent=prnt,
              pos=wx.Point(642, 279), size=wx.Size(124, 86),
              style=wx.DEFAULT_FRAME_STYLE, title='Frame1')
        self.SetClientSize(wx.Size(108, 50))

        self.panel1 = wx.Panel(id=wxID_FRAME1PANEL1, name='panel1', parent=self,
              pos=wx.Point(2, 2), size=wx.Size(104, 46),
              style=wx.TAB_TRAVERSAL)

        self.staticText1 = wx.StaticText(id=wxID_FRAME1STATICTEXT1,
              label=u'Hello world!', name='staticText1', parent=self.panel1,
              pos=wx.Point(10, 10), size=wx.Size(84, 13),
              style=wx.ALIGN_CENTRE)

        self._init_sizers()

    def __init__(self, parent):
        self._init_ctrls(parent)
        

if __name__ == '__main__':
    app = wx.PySimpleApp()
    frame = create(None)
    frame.Show()

    app.MainLoop()
}}}
 * CreatingStandaloneExecutables
 * DistributingYourApplication
 * [[py2exeAndGettext]]
 * SmallApp

Using py2exe to freeze your application

The following will explain how to freeze a Python/wxPython application using the py2exe tool.

What Objects are Involved

You will need a working development environment including

Process Overview

A small sample wxPython "Hello world" application will be used to demonstrate the process. I created the tiny application using Boa Constructor but you could use any other IDE you use for your wxPython development. I did the initial creation of the setup.py file with Gui2Exe and then keep maintaining it and running it from the IDE (Boa in my case).

Python 2.5

The setup.py needed for Python 2.5 or lower is shown on the py2exe for Python 2.5 page.

Python 2.6

The setup.py needed for Python 2.6 is shown on the py2exe for Python 2.6 page.

Sample wxPython application

Save the following code in your working folder as a file called 'simplewx.py'.

Toggle line numbers
   1 #Boa:Frame:Frame1
   2 
   3 import wx
   4 
   5 def create(parent):
   6     return Frame1(parent)
   7 
   8 [wxID_FRAME1, wxID_FRAME1BUTTON1, wxID_FRAME1BUTTON2, wxID_FRAME1PANEL1, 
   9  wxID_FRAME1STATICTEXT1, 
  10 ] = [wx.NewId() for _init_ctrls in range(5)]
  11 
  12 class Frame1(wx.Frame):
  13     def _init_coll_bsPanel_Items(self, parent):
  14         # generated method, don't edit
  15 
  16         parent.AddWindow(self.staticText1, 0, border=10,
  17               flag=wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_CENTER_HORIZONTAL | wx.ALL | wx.EXPAND)
  18         parent.AddSizer(self.fgsButtons, 1, border=2, flag=wx.ALL | wx.EXPAND)
  19 
  20     def _init_coll_fgsButtons_Items(self, parent):
  21         # generated method, don't edit
  22 
  23         parent.AddWindow(self.button1, 1, border=2, flag=wx.ALL | wx.EXPAND)
  24         parent.AddWindow(self.button2, 1, border=2, flag=wx.ALL | wx.EXPAND)
  25 
  26     def _init_coll_bsFrame_Items(self, parent):
  27         # generated method, don't edit
  28 
  29         parent.AddWindow(self.panel1, 1, border=2,
  30               flag=wx.EXPAND | wx.ALL | wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_CENTER_HORIZONTAL)
  31 
  32     def _init_coll_fgsButtons_Growables(self, parent):
  33         # generated method, don't edit
  34 
  35         parent.AddGrowableCol(0)
  36         parent.AddGrowableCol(1)
  37 
  38     def _init_sizers(self):
  39         # generated method, don't edit
  40         self.bsPanel = wx.BoxSizer(orient=wx.VERTICAL)
  41 
  42         self.bsFrame = wx.BoxSizer(orient=wx.VERTICAL)
  43 
  44         self.fgsButtons = wx.FlexGridSizer(cols=2, hgap=0, rows=0, vgap=0)
  45 
  46         self._init_coll_bsPanel_Items(self.bsPanel)
  47         self._init_coll_bsFrame_Items(self.bsFrame)
  48         self._init_coll_fgsButtons_Items(self.fgsButtons)
  49         self._init_coll_fgsButtons_Growables(self.fgsButtons)
  50 
  51         self.SetSizer(self.bsFrame)
  52         self.panel1.SetSizer(self.bsPanel)
  53 
  54     def _init_ctrls(self, prnt):
  55         # generated method, don't edit
  56         wx.Frame.__init__(self, id=wxID_FRAME1, name='', parent=prnt,
  57               pos=wx.Point(642, 279), size=wx.Size(236, 106),
  58               style=wx.DEFAULT_FRAME_STYLE, title='Frame1')
  59         self.SetClientSize(wx.Size(220, 70))
  60 
  61         self.panel1 = wx.Panel(id=wxID_FRAME1PANEL1, name='panel1', parent=self,
  62               pos=wx.Point(2, 2), size=wx.Size(216, 66),
  63               style=wx.TAB_TRAVERSAL)
  64 
  65         self.staticText1 = wx.StaticText(id=wxID_FRAME1STATICTEXT1,
  66               label=u'Hello world!', name='staticText1', parent=self.panel1,
  67               pos=wx.Point(10, 10), size=wx.Size(196, 13),
  68               style=wx.ALIGN_CENTRE)
  69 
  70         self.button1 = wx.Button(id=wxID_FRAME1BUTTON1, label='button1',
  71               name='button1', parent=self.panel1, pos=wx.Point(4, 37),
  72               size=wx.Size(100, 23), style=0)
  73 
  74         self.button2 = wx.Button(id=wxID_FRAME1BUTTON2, label='button2',
  75               name='button2', parent=self.panel1, pos=wx.Point(116, 37),
  76               size=wx.Size(100, 23), style=0)
  77 
  78         self._init_sizers()
  79 
  80     def __init__(self, parent):
  81         self._init_ctrls(parent)
  82         
  83 
  84 if __name__ == '__main__':
  85     app = wx.PySimpleApp()
  86     frame = create(None)
  87     frame.Show()
  88 
  89     app.MainLoop()

Other wiki pages to check

Comments

Please feel free to provide any feedback on this page either here, on the wxPython-user list or to werner.bruhin at free.fr.

py2exe (last edited 2010-08-21 18:54:09 by c-75-72-71-98)

NOTE: To edit pages in this wiki you must be a member of the TrustedEditorsGroup.