Python distutils modules allows to release your python package very easily. What is less obvious is how to release it as a runnable application ?
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.
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.
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 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.
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]
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]
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.