What is wxPRE?

wxPRE is the wxPython Runtime Environment.

wxPRE is being planned at the moment, and there has been some progress but there is plenty more to do.

Aim

The aim is to create a Runtime Environment containing wxPython and Python. Inspired by the JRE

These wiki pages are used for the planning and will hopefully become the basis for the wxPRE.

wxPRE requirements

wxPRE itself should contain everything needed to run wxPython apps, either as a standalone python source file, or as an application bundle of some sort.

It should be possible to create the following kinds of installers:

Implementation questions

Progress so far

So far a simple wxPRE script has been created that works successfully with py2exe.

A setup script has also been created that produces the py2exe-d wxPRE executable. It also uses InnoSetup to create a wxPRE installer. However there isn't yet a mechanism to produce application installers (with bundled wxPRE or lightweight).

Source code

wxPRE.py

"""wxPython Runtime Environment"""

import sys
import os

__version__ = "0.2.1"

def getversion():
    """returns wxPRE version, including the wx version if available"""
    try:
        import wx
        return "%s-wx%s-mingw" % (__version__, wx.VERSION_STRING)
    except ImportError:
        return __version__

def addpathsfromdir(dirname):
    """looks in the directory for .pth files and adds them to sys.path"""
    for direntry in os.listdir(dirname):
        if os.path.splitext(direntry)[1] == '.pth':
            pthfile = open(os.path.join(dirname, direntry), 'r')
            pthdirs = [pthdir.strip() for pthdir in pthfile]
            pthfile.close()
            for pthdir in pthdirs:
                if os.path.isdir(pthdir):
                    sys.path.append(pthdir)

if __name__ == "__main__":
    import sys
    if len(sys.argv) > 1:
        arg = sys.argv[1]
        if arg == "--version":
            print sys.argv[0], getversion()
        elif arg == "--test":
            print repr(sys.path)
            print repr(sys.prefix)
            print repr(sys.executable)
            print repr(getattr(sys, "frozen", None))
            print repr(getattr(locals, "__file__", None))
            print repr(sys.argv)
        else:
            filename = os.path.abspath(arg)
            addpathsfromdir(os.path.dirname(filename))
            addpathsfromdir(os.getcwd())
            sys.argv = sys.argv[1:]
            #make sure the current path is the required one
            #and that imports can be made
            path = os.path.dirname(filename)
            if path is not os.getcwd():
                os.chdir(path)
            if path not in sys.path:
                sys.path.append(path)
            try:
                execfile(filename)
            except ImportError,detail:
                print >>sys.stderr, "wxPRE ImportError: ",detail
                print >>sys.stderr, "Try adding a .pth file here or in the scripts dir."
                raise
    else:
        print >>sys.stderr, "Need to supply script filename for %s (version %s)" % (sys.argv[0], getversion())

setup.py

from distutils.core import setup, gen_usage, Command, grok_environment_error
from distutils.dist import Distribution
from distutils.errors import *
import os
import sys
try:
  import py2exe
  build_exe = py2exe.build_exe.py2exe
  Distribution = py2exe.Distribution
except ImportError:
  py2exe = None
  build_exe = Command
import wxPRE

class InnoScript:
    """class that builds an InnoSetup script"""
    def __init__(self, name, lib_dir, dist_dir, windows_exe_files = [], lib_files = [], version = "1.0"):
        self.lib_dir = lib_dir
        self.dist_dir = dist_dir
        if not self.dist_dir.endswith(os.sep):
            self.dist_dir += os.sep
        self.name = name
        self.version = version
        self.windows_exe_files = [self.chop(p) for p in windows_exe_files]
        self.lib_files = [self.chop(p) for p in lib_files]

    def chop(self, pathname):
        """returns the path relative to self.dist_dir"""
        assert pathname.startswith(self.dist_dir)
        return pathname[len(self.dist_dir):]

    def create(self, pathname=None):
        """creates the InnoSetup script"""
        if pathname is None:
          self.pathname = os.path.join(self.dist_dir, self.name + os.extsep + "iss")
        else:
          self.pathname = pathname
        ofi = self.file = open(self.pathname, "w")
        print >> ofi, "; WARNING: This script has been created by py2exe. Changes to this script"
        print >> ofi, "; will be overwritten the next time py2exe is run!"
        print >> ofi, r"[Setup]"
        print >> ofi, r"AppName=%s" % self.name
        print >> ofi, r"AppVerName=%s %s" % (self.name, self.version)
        print >> ofi, r"DefaultDirName={pf}\%s" % self.name
        print >> ofi, r"DefaultGroupName=%s" % self.name
        print >> ofi, r"OutputBaseFilename=%s-%s-setup" % (self.name, self.version)
        print >> ofi
        print >> ofi, r"[Files]"
        for path in self.windows_exe_files + self.lib_files:
            print >> ofi, r'Source: "%s"; DestDir: "{app}\%s"; Flags: ignoreversion' % (path, os.path.dirname(path))
        print >> ofi
        print >> ofi, r"[Icons]"
        for path in self.windows_exe_files:
            print >> ofi, r'Name: "{group}\%s"; Filename: "{app}\%s"' % \
                  (self.name, path)
        print >> ofi, 'Name: "{group}\Uninstall %s"; Filename: "{uninstallexe}"' % self.name

    def compile(self, compilercmd="compile"):
        """compiles the script using InnoSetup"""
        try:
            import ctypes
        except ImportError:
            try:
                import win32api
            except ImportError:
                os.startfile(self.pathname)
            else:
                print "Ok, using win32api."
                win32api.ShellExecute(0, compilercmd, self.pathname, None, None, 0)
        else:
            print "Cool, you have ctypes installed."
            res = ctypes.windll.shell32.ShellExecuteA(0, compilercmd, self.pathname, None, None, 0)
            if res < 32:
                raise RuntimeError, "ShellExecute failed, error %d" % res

###############################################################

class build_installer(build_exe):
    """distutils class that first builds the exe file(s), then creates a Windows installer using InnoSetup"""
    def run(self):
        # First, let py2exe do it's work.
        build_exe.run(self)
        lib_dir = self.lib_dir
        dist_dir = self.dist_dir
        # create the Installer, using the files py2exe has created.
        script = InnoScript(self.distribution.metadata.name, lib_dir, dist_dir, self.windows_exe_files, self.lib_files, version=wxPRE.getversion())
        print "*** creating the inno setup script***"
        script.create()
        print "*** compiling the inno setup script***"
        script.compile("compil32")
        # Note: By default the final setup.exe will be in an Output subdirectory.

class wxPREDistribution(Distribution):
    """A distribution class for wxPRE"""
    def __init__(self, attrs):
      baseattrs = {}
      baseattrs['script_name'] = os.path.basename(sys.argv[0])
      baseattrs['script_args'] = sys.argv[1:]
      # package information
      baseattrs['name'] = "wxPRE"
      baseattrs['version'] = wxPRE.__version__
      baseattrs['url'] = "http://wiki.wxpython.org/index.cgi/wxPRE"
      baseattrs['author'] = "David Fraser and Stephen Emslie"
      baseattrs['author_email'] = 'info@sjsoft.com'
      baseattrs['description'] = 'wxPython Runtime Environment'
      baseattrs['long_description'] = wxPRE.__doc__
      baseattrs['license'] = "wxWidgets license"
      py2exeoptions = {}
      py2exeoptions["packages"] = ["wx"]
      py2exeoptions["compressed"] = True
      py2exeoptions["dist_dir"] = "wxPRE-%s" % wxPRE.getversion()
      baseattrs['options'] = {"py2exe": py2exeoptions}
      if py2exe:
          baseattrs['console'] = ["wxPRE.py"]
          baseattrs['zipfile'] = "wxPRElibs.zip"
      baseattrs['cmdclass'] = {"py2exe": build_installer}
      baseattrs.update(attrs)
      Distribution.__init__(self, baseattrs)

if __name__ == "__main__":
    dist = wxPREDistribution({})
    try:
        ok = dist.parse_command_line()
    except DistutilsArgError, msg:
        raise SystemExit, gen_usage(dist.script_name) + "\nerror: %s" % msg
    if ok:
        try:
            dist.run_commands()
        except KeyboardInterrupt:
            raise SystemExit, "interrupted"
        except (IOError, os.error), exc:
            error = grok_environment_error(exc)
            raise SystemExit, error
        except (DistutilsError, CCompilerError), msg:
            raise SystemExit, "error: " + str(msg)

wxPRE (last edited 2009-12-04 20:25:14 by s235-176)

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