Deploy your python application

Python distutils modules allows to release your python package very easily. What is less obvious is how to release it as a runnable application ?

If your target is only Windows, use py2exe that do a wonderful job with the bundle_files option ! Because py2exe in only a distutils extension, this is compatible with what comes next.

For posix platforms like Linux, there are multiple possibilities depending of the installed version of python !Since version 2.6, python can run ZIP file. When possible you can bundle all your .py files in one ZIP file and run it that way. For older versions of python the best way is to release a source package and install it on the target host.

The purpose of this article is not to details distutils usage, for a tutorial see here, but to help you to make your python application easy to deploy and easy to use.

You can find all the tips described here used in my TcpProxyReflector package and MKSBackup. Download the sources and take a look on how things works together in a real package.

Of course if the use of a script as described in Python 2.4 and above below is the most natural way to release your application, others can have some advantages.

EGG files, easy_install and setuptools

Since EGG file and setuptools are not the future of python and most pythonic projects slowly switch to standard distutils and new pip install tool, I will not recommend it. Be aware that easy_install is able to install from source too, no need to build .egg ! Anyway setuptools is until now the only way I found to release runnable ZIP file for Python 2.6 and above.

The Python Package Index

The PyPI is a repository of software for the Python programming language. If your application, belongs to the public domain, upload it to PyPI. This will make it even more easy to install and upgrade using easy_install or pip. And it is also very easy to register and use distutils to upload your application when building new release.

Python 2.6 and above

Since version 2.6, python can execute a ZIP file, and EGG is precisely one ! Python search for a __main__.py file in the top root directory of the archive and run it. Until now, I cannot build such an archive without using setuptools, distutils looks to be useless here !

Create one __main__.py file and write the appropriate code.

# __main__.py
# if your application already exists inside a python module, just import it
import your_package.your_runnable_module
# if not, you have to import your main() function and run it here

Import setuptools instead of distutils and include the file in your setup.py

try: 
  from setuptools import setup 
except ImportError: 
  from distutils.core import setup
...
    setup(...
    ....
    data_files=[ ('', ['__main__.py', ]), ....
...

Finally, build your egg file this way :

python setup.py bdist_egg

Now you don't need to install your package, you can run your EGG file this way:

python your_package.egg [options] [args]

Python 2.5 and above

Option -m that requires a module-name has been extended in python 2.5 to support zipimport. This allows to run a package when it is installed like single .egg file. This is not universal because it depend on how the package is installed, and in a way, how the package is released ! I thing this is too unpredictable to be used as an universal solution. Anyway you can easily modify your sources to work that way ! Modify your __init__.py file to allow it to be run as an application:

if __name__=='__main__':
    # if your application already exists inside a python module, just import it
    import your_package.your_runnable_module
    # if not, you have to import your main() function and run it here
else:
    # If used as a module, do it as usual
    from any_module import any_symbol

When the package is installed as a single .egg file, you can run it this way:

python -m your_package [options] [args]

Python 2.4 and above

If your target is python 2.4, the best way is to use scripts and add the appropriate declaration in your setup.py. Your script will be copied near your python binary. If the first line of your script contains the string python, distutils will replace the line by the path of the python binary used to install the package ! If your application already exists somewhere in your package, just import the module. If not start the main function from inside your script. The main advantage of using a script is to give it the name you want.

#!/usr/bin/env python
if __name__ == "__main__":
    # if your application already exists inside a python module, just import it
    import your_package.your_runnable_module
    # if not, you have to import your main() function and run it here

Update your setup.py to include your script

...
setup(
    ...
    scripts=[ '/scripts/your_script' ],
    ....)
...

Hope this help.

Add new comment