>> Noel O'Boyle

Distutils

Distutils is the recommended method for distributing python modules and packages (a selection of modules). However, it is quite difficult to figure out how to use it. Here I present some examples. You should look at these examples before starting your project, as you are encouraged to lay your project out using standard directories as described below.

Please tell me if there are any errors on this page, or if one of the examples doesn't work for you.

Example 1

Several .py files (modules) that are all part of one package

Lay your project out as follows:

setup.py
README
license.txt
src/
    mypkg/
        __init__.py
        module_a.py
        module_b.py

Use the following setup.py:

from distutils.core import setup

setup(name="mypkg",
      version="1.0",
      author="Noel O'Boyle",
      author_email="baoilleach@users.sf.net",
      url="http://www.redbrick.dcu.ie/~noel/",
      packages=['mypkg'],
      package_dir = {'mypkg':'src/mypkg'}
      )

To create a source distribution, type:

python setup.py sdist

A file, mypkg-1.0.tar.gz, is created in the dist directory, which you can distribute. To test whether it works, try to install from it:

cd dist
tar zxvf mypkg-1.0.tar.gz
cd mypkg-1.0
python setup.py install
python
>>> import mypkg

Example 2

Some modules are in a subdirectory

What about if some of the .py modules are in a subdirectory of the main package? For example:

setup.py
README
license.txt
src/
    mypkg/
        __init__.py
        module_a.py
        plugins/
	    __init__.py
            module_b.py

Use the following setup.py:

from distutils.core import setup

setup(name="mypkg",
      version="1.0",
      author="Noel O'Boyle",
      author_email="baoilleach@users.sf.net",
      url="http://www.redbrick.dcu.ie/~noel/",
      packages=['mypkg','mypkg.plugins'],
      package_dir = {'mypkg':'src/mypkg'}
      )

Example 3

The project includes data files

What if you have help files, images, or some other type of non .py file? It took me a while to figure out, but here are two solutions.

Method 1

Method 1 uses the package_data option. Unfortunately, the distutils that comes with Python 2.3 doesn't understand the package_data command. You either need to use Python 2.4, or install the latest version of distutils for Python 2.3. To do this, get the latest version of distutils from CVS. Once you have checked it out of CVS, use the standard "python setup.py install" to install it. To use the new version, rather than the one in the standard library, you will need to set your PYTHONPATH to include the site-packages directory (this is because PYTHONPATH is checked before the standard library is checked).

In the following directory layout, note the new file "MANIFEST.in", and the new data directory, "src/mypkg/images":

setup.py
README
MANIFEST.in
license.txt
src/
    mypkg/
        __init__.py
        module_a.py
        index.html
        images/
            shamrock.png

Use the following setup.py:

from distutils.core import setup

setup(name="mypkg",
      version="1.0",
      author="Noel O'Boyle",
      author_email="baoilleach@users.sf.net",
      url="http://www.redbrick.dcu.ie/~noel/",
      packages=['mypkg'],
      package_dir = {'mypkg':'src/mypkg'},
      package_data = {'mypkg':['images/*.png','*.html']}
      )

You also need to use the following MANIFEST.in or source distributions are not built properly (don't ask me why):

include src/mypkg/images/*.png
include src/mypkg/*.html

Method 2

Method 2 should work for both Python 2.3 and 2.4. It involves finding out where the data files should be copied to, and then copying them there explicity. In this case, you need to use the same MANIFEST.in as for Method 1, and use setup.py the following setup.py:

from distutils.core import setup
from distutils import dir_util,file_util
import sys

mydist = setup(
               name="mypkg",
               version="1.0",
               author="Noel O'Boyle",
               author_email="baoilleach@users.sf.net",
               url="http://www.redbrick.dcu.ie/~noel/",
               packages=['mypkg'],
               package_dir = {'mypkg':'src/mypkg'},
              )

if "install" in sys.argv:
    wheretoinstall = mydist.command_obj['install'].install_purelib
    for dirname in ['images']:
        dir_util.copy_tree(os.path.join("src","mypkg",dirname),os.path.join(wheretoinstall,"mypkg",dirname))
    for filename in ['index.html']:
        file_util.copy_file(os.path.join("src","mypkg",filename),os.path.join(wheretoinstall,"mypkg"))

Example 4...coming soon...

A Python GUI application for Windows (and Linux)