Notice: While Javascript is not essential for this website, your interaction with the content will be limited. Please turn Javascript on for the full experience.

Python Distutils-SIG: Proposed User Interface

Python Distutils-SIG

Proposed User Interface

In addition to identifying the common tasks and division of labour involved in developing, distributing, and installing Python modules, the "Extension Building Considered Painful" Developer's Day Session also came up with a proposed user interface. The core idea of the interface is that the module developer would provide a small Python script, called setup.py for purposes of illustration (although it is hoped that this convention catches on!). This script would have two components: meta-data about the module distribution (name, version number, description, etc.), written as Python code of some sort; and optional code to inspect the target system and carry out any needed pre-build configuration operations. Only the meta-data will be required, and indeed it is anticipated that most module distributions (especially those written purely in Python) will have only the meta-data component. Some ideas for how to represent the meta-data will be presented below.

This document describes an interface based on what we agreed upon at the Developer's Day session, but with a lot more detail. (Some of that detail could be construed as implementation rather than interface, but it's important to specify it somewhere.)

Once the setup.py script is written, developers, packagers, and installers alike will use it to carry out all of their tasks that can be automated (i.e. everything except actually writing the modules, documentation, and test suite). This will be done by running setup.py with a mandatory "command" argument corresponding to the task to be accomplished. (By sheer coincidence, many of these commands will look a lot like traditional makefile targets.)

For example, the command to initiate a build is build. The developer, packager, and installer (at least an installer working from a source distribution) will all have to build the module(s), using the following command:

    ./setup.py build
After building, everyone should run the test suite, using the test command:
    ./setup.py test
When he's happy with the state of the code, the developer will want to put on his first packager hat and create a source distribution:
    ./setup.py dist
or he might want to put on his other packager hat and make a built distribution (or this could be done by a packager for some other platform):
    ./setup.py bdist
If the packager is making build distributions for a system that supports a "smart installer" (which the distutils also support!), he could make a "smart" built distribution, e.g. an RPM for the Linux distributions that use it:
    ./setup.py bdist -rpm
(Note the use of a command-specific option here; for instance, the bdist command should also have options to enable generating "smart" distributions for Windows and Macintosh, assuming suitable smart install tools can be found for those platforms.)

By now, you're probably wondering what's really happening behind each of those commands. It could be argued that that is an implementation detail that doesn't belong in an interface proposal, but I think that most developers, many packagers, and a few curious users will be inclined to look "under the hood" and see what's really going on as they build and install module distributions. (And the unlucky ones will have to understand the process if things go wrong!) So, here is a list of commands to be supported by setup.py (through cooperation with the distutils modules) and the actions corresponding to each command:

make_blib
If it doesn't already exist, create a mockup installation tree, blib/, under the current directory. blib/ would contain directories for pure Python code (non-architecture-specific, or shared) and compiled code (architecture-specific), modelled after the directories in the system Python library on the current machine (which are determined when Python itself is built). For instance, make_blib might create blib/share/ (shared files) and blib/plat-i86-linux/ (architecture-specific files). There might also be directories for documentation, e.g. blib/man/ for Unix-style man pages, blib/info/ for GNU info documentation, and/or blib/html/ for (you guessed it) HTML documenation.
build_py
Do make_blib; copy .py files into the "shared" blib directory (or subdirectories of it, if they belong to packages), and compile them to .pyc and .pyo form.
build_extensions
Do make_blib; compile ancillary C files (those that don't provide extension modules themselves, but are needed for the extension(s) being built to work); compile extension C files; link ancillary and extension C files (along with any external libraries needed) to create dynamic libraries (e.g. .so files for Unix, DLLs for Windows, etc.) in the architecture-specific blib directory
build_doc
process documentation to an installable form somewhere under ./blib e.g. *roff-formatted man pages, GNU Info, HTML, Windows help, etc. Perhaps the desired documentation format(s) could be determined when Python itself is built (and, naturally, the Python documentation would be available in that format, in the same place that module documentation accumulates)?
build
Do build_py, build_extensions, and build_doc. (Of course, any one of these operations does nothing if the appropriate inputs are not there.)
dist
Create a source distribution ...
bdist
Create a built distribution ...
test
Look for the test suite and run it. One possible way to define a test suite: put a bunch of scripts in a predefined subdirectory of the source distribution; they will then be executed with the shared and architecture-specific blib directories added to Python's library search path. For instance, the test command might search for test/*.t, executing each script in turn and interpreting its output to determine whether that series of tests succeeded or failed.
install
Copy .py, .pyc, and .pyo files into the shared installation directory (which would default to the site-specific area of the Python system library tree); copy dynamic libraries (shared objects or DLLs) to the architecture-specific installation directory; copy processed documentation (man pages, Info files, whatever) to the documentation installation directory. (Perhaps this should be split up into install_py, install_extensions, and install_doc?)