Packaging with py2exe and cxFreeze¶
In this section we will see how to package applications that use pubsub, with py2exe and cx_Freeze packaging tools.
Introduction¶
Packaging tools such as py2exe and cx_Freeze determine the dependencies
that have to be included in a package by recursively finding the modules
from the import statements used. Recursive finding of modules from the
import statements uses straight forward approach i.e., if the python
code dynamically imports certain modules by modifying the sys.path
at
runtime or if the code uses __import__
statements, those modules
are likely to be left out by the packaging tool. This can be a problem
for some packaged applications.
Packaging modules that uses pubsub¶
Pubsub supports two different messaging protocols namely args1
and
kwargs
; choosing and switching between these protocols is done by
modifying the module path dynamically. This can result in import error
like this at runtime:
from listenerimpl import Listener, ListenerValidator
ImportError: No module named listenerimpl
In the following sections we show an example script that uses pubsub and discuss the setup script to package it using py2exe or cx_Freeze packaging tools.
Example¶
Consider a sample application which has a single file named say
testpubsub.py
from pubsub import pub
def listener1(msg):
print "The listener received the message : %s" % (msg, )
pub.subscribe(listener1, 'test.pubsub')
def sender():
pub.sendMessage('test.pubsub', msg="Hola! this is a test message")
if __name__ == "__main__":
sender()
To package this with py2exe and cx_Freeze you
write a conventional setup.py
module, but with extra options that
the packaging tool uses to create the final distribution.
Setup file using py2exe¶
The setup.py
for this would look something like this
"""
File based on a contribution from Josh Immanuel. Use via
python setup-py2exe.py py2exe
which will create a dist folder containing the .exe, the python DLL, and a
few other DLL deemed by py2exe to be critical to the application execution.
The contents of the dist folder should then be packaged using a tool such
as NSIS or Inno Setup. The py2exe page has an example for NSIS.
"""
from distutils.core import setup
import py2exe
setup (
name='TestPubSub',
description="Script to test pubsub for packaging",
version="0.1",
console=[{'script': 'testpubsub.py'}],
options={ 'py2exe': {
'packages': 'encodings, pubsub',
'includes': None}
},
)
The line 'packages': 'encodings, pubsub'
explicitly
tells py2exe to include pubsub
as a package so that the entire pubsub
folder (from the installation location) including its sub packages are
included for packaging. As the package has the entire list of python
modules under pubsub, runtime protocol selection is now possible in
the generated exe
file.
To build, run:
python setup.py py2exe
which will produce a dist folder containing testpubsub.exe
and other
DLLs and files required to run the application. Interestingly, py2exe
command complains about modules that appear to be missing:
The following modules appear to be missing [‘callables’, ‘core’, ‘core.notificationmgr’, … , ‘topicu’, ‘validatedefnargs’]
however, the application runs fine.
Setup file using cx_Freeze¶
The setup.py
for this would look something like this
from cx_Freeze import setup, Executable as cxExecutable
import platform
if platform.system() == 'Windows':
# base must be set on Windows to either console or gui app
# testpubsub is currently a console application
# base = 'Win32GUI'
base = 'Console'
else:
base = None
opts = { 'compressed' : True,
'create_shared_zip' : False,
'packages' : ['pubsub.core.kwargs', 'pubsub.core.arg1'],
}
WIN_Target = cxExecutable(
script='testpubsub.py',
base=base,
targetName='testpubsub.exe',
compress=True,
appendScriptToLibrary=False,
appendScriptToExe=True
)
setup(
name='TestPubSub',
description="Script to test pubsub for packaging with cxfreeze",
version='0.1',
options={'build_exe' : opts},
executables=[WIN_Target]
)
The packages option slightly differs for cx_Freeze: we have to
explicitly include the sub packages pubsub.core.kwargs
and
pubsub.core.arg1
so that all the modules under them get included
for packaging.
To build, run:
python setup.py build
We can safely ignore the missing modules warning in the build log:
Missing modules:
? core.publisher imported from pubsub.pub
? listenerimpl imported from pubsub.core.listener
? publishermixin imported from pubsub.core.topicobj
? topicargspecimpl imported from pubsub.core.topicargspec
? topicmgrimpl imported from pubsub.core.topicmgr
All these modules are under pubsub.core.kwargs
and
pubsub.core.arg1
. In cx_Freeze dependent modules are gathered from
the import statements recursively, during this it reports that it
can’t find the above modules. But as we have included them directly in
the packages option these modules are included for packaging.