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.
Related Pages
VersionSelection may be an important part of wxPRE
py2exe and other related systems will be helpful
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:
- A standalone wxPRE installer.
- An application installer that includes a bundled wxPRE
- A "light" application installer that relies on an already-installed wxPRE
Implementation questions
- How should applications be bundled? Possible in a zip file. In which directory?
- How will wxPRE installations be found? On Windows, could be through the registry.
- How will wxPRE handle multiple versions being installed?
- py2exe is Windows-only at the moment. How can wxPRE be made for other platforms? Is it neccessary?
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)