Building Mac OS X applications with py2app

How to make standalone Mac applications from Python and PyQt4 scripts using py2app.

Py2app is a tool, that can be used to make standalone Mac OS X application from Python scripts. To install Py2app you just need to execute from terminal (and you have XCode installed):
sudo easy_install py2app

Building standalone apps

To build a standalone application from a Python script you have to create a config file, usually setup.py. Here is an example config:
from setuptools import setup

APP = ['YOUR_SCRIPT.py']
OPTIONS = {'argv_emulation': True, 'includes': ['EXTERNAL LIBRARY'],}

setup(
    app=APP,
    options={'py2app': OPTIONS},
    setup_requires=['py2app'],
)
Where YOUR_SCRIPT is the script you run. includes should contain a list of all used external Python modules. Now to build your app run in terminal:
python setup.py py2app
After which in dist folder you will have ready to used app. You can (should) edit it's name editing App content ("Show package contents") in Contents/Info.plist, and using custom icon (Contents/Resources/PythonApplet.icns). Check also if the app doesn't contain unnecessary Python modules. If it does use excludes list in OPTIONS to exclude them.
Using system Python installation py2app will create semi-standalone apps, that will probably not work on other OS X releases (app build on Leopart may not run on Tiger for example). To build fully standalone apps use external Python installation from MacPorts or Fink. To build app against such Python install be sure to use full path to that Python executable file (for example: /sw/bin/python setup.py py2app)

Building PyQt4 application with py2app

You can use for example MacPorts to install all libraries, and build the app without bigger problems, or you can use the system Python (but some hacking will be needed). In case of system Python - you need to install Qt from QtSoftware (DMG can be used), and then compile and install SIP and PyQt4 from riverbankcomputing.co.uk:
Qt Software offers two DMGs - SDK and Libraries. If you want Intel only app download the SDK DMG. If you use "Libraries"-only DMG you will get double sized app, but universal.
python configure.py
make # if the compilation doesn't start
sudo make install
Here is a simple config for a PyQt4 app that uses QtCore, QtGui and simplejson:
from setuptools import setup
 
APP = ['run.py']
OPTIONS = {'argv_emulation': True, 'includes': ['sip', 'PyQt4', 'PyQt4.QtCore', 'PyQt4.QtGui', 'simplejson'],
			'excludes': ['PyQt4.QtDesigner', 'PyQt4.QtNetwork', 'PyQt4.QtOpenGL', 'PyQt4.QtScript', 'PyQt4.QtSql', 'PyQt4.QtTest', 'PyQt4.QtWebKit', 'PyQt4.QtXml', 'PyQt4.phonon']}
 
setup(
    app=APP,
    options={'py2app': OPTIONS},
    setup_requires=['py2app'],
)
We have to exclude all other components or they will be included in the app (which will make it big as hell). The app won't work out of the box in this case. You will get:
ImportError: '/System/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/lib-dynload/PyQt4/QtCore.so' not found
You have to edit Contents/Resources/__boot__.py and add in function def _run(*scripts): (near end of file) and add after imports this line:
sys.path = [os.path.join(os.environ['RESOURCEPATH'], 'lib', 'python2.5', 'lib-dynload')] + sys.path
And it should work now. You can also remove from Contents/Frameworks/* all *_debug versions of QtCore and QtGui as they aren't used, and they are bigger files. Those libs are placed in "Versions" subfolders, for example /Contents/Frameworks/QtGui.framework/Versions/4. After zipping my app had 12MB (9MB on Windows when built with Py2exe).

In case of MacPorts it's easier, but compiling everything will take some time (you need at least PyQt4, py2app, macholib, modulegraph, altgraph). Py2app config is nearly the same, you only add PyQt4._qt (but it may be bigger than build against system Python):
from setuptools import setup
 
APP = ['run.py']
OPTIONS = {'argv_emulation': True, 'includes': ['sip', 'PyQt4._qt', 'simplejson', 'PyQt4.QtCore', 'PyQt4.QtGui'],
			'excludes': ['PyQt4.QtDesigner', 'PyQt4.QtNetwork', 'PyQt4.QtOpenGL', 'PyQt4.QtScript', 'PyQt4.QtSql', 'PyQt4.QtTest', 'PyQt4.QtWebKit', 'PyQt4.QtXml', 'PyQt4.phonon']}
 
setup(
    app=APP,
    options={'py2app': OPTIONS},
    setup_requires=['py2app'],
)
You can find more on Aral Balkan blog.
blog comments powered by Disqus

Categories