Nearly each Python application depends on third-party Python modules. When the application is distributed, maintaining all dependencies may become a real headache. Some systems have built-in tools facilitaing this task (ports collection on *BSD systems, RPM and Debian package system on Linuxes etc.), but on Windows there seems to be no other way than include all required modules into the application distribution package.
Python application packaging may be done with several tools (like McMillian Installer or py2exe), but none of them works with PEAK out-of-the-box, because of module import tweaks used in PEAK core.
This page describes the steps taken in our company to make a distribution for PEAK-based application.
All sources listed on this page may be used under the same terms as Python or PEAK.
Currently, the application has single executable script (module) run as Windows NT service. This module uses PEAK ZConfigInterpreter to load and run all components. There are no direct references to included components in the main script.
The distribution package contains a binary wrapper for the executable script, and single subdirectory lib containing all required Python modules (both source and binary) as well as the Python dll and executable. Python modules are distributed in source form. This helps to avoid problems with PEAK lazy modules and is unlike py2exe or Installer packages including all modules as binaries.
We use McMillian Installer to build the list of module dependencies and to perform initial collecting of the module files.
The installer may be downloaded from http://mcmillan-inc.com/dnld/installer_6a1.zip or http://mcmillan-inc.com/dnld/installer_6a1.tar.gz Installer versions prior to 6a1 have some problems and cannot be used.
We use a simple c program to wrap executable python modules. This program is compiled to Windows executable stub pyrun.exe. When run, it takes Python command line options attached to the stub by utility script build_exe.py and runs Py_Main() with these options. Additional options may be specified on the executable command line; these are added to the end of "command line" passed to Py_Main.
In addition to options processing, this executable wrapper sets PYTHONPATH to the lib subdirectory, so that all modules are first looked up in the package, and not in the installed Python library (if any). site processing is disabled, and Python optimization level is set to 2 (enable basic optimizations and discard docstrings). Current directory is set to the directory of the exe file.
pyrun.c source:
build_exe.py source:
As i said above, there are no direct references to included components in the main script. We have to explicitely list all components for Installer to include and analyse them. Also some modules from PEAK and standard lib are not found automatically, and need to be named explicitely.
I did this by making a modulefinder hook for the package in which the main executable module resides. This hook has hiddenimports attribute which is a list of additional module import names. The list is composed by collecting all modules in the main components package (ank.BBS.Protocol) and adding some well-known names.
hooks/hook-ank.BBS.py source:
Below is the spec file for McMillian Installer:
------------------------------------------------------------------------------
-- alexander smishlajev - 07-dec-2003