zc.buildout vs. "plain" setuptools

tl;dr

A brief proposal on how and when one might prefer to use "standard" setuptools features, rather than relying on zc.buildout.

Overview

The Zope development community has largely adopted zc.buildout as a de facto standard for how it builds and maintains Zope-related software. This post attempts to outline some reasons why zc.buildout may not be a "sufficient" tool for all cases, and proposes some additional practices which may help alleviate the issues described.

Strengths of zc.buildout

The zc.buildout framework allows for creating a repeatable environment using one or more "recipes" (which serve as plug-ins for the fraemwork) and a configuration file, which defines policies for a given environment. There are recipes available for a wide variety of tasks, ranging from building and testing a single Python package, to building a Python application using any number of such packages, to building arbitrary applications from source (e.g., using "configure && make && make install").

After bootstrapping, a developer can ensure that her environment is in a known state by running (or re-running) the bin/buildout command created by the bootstrap script. This command parses the buildout.cfg file, and uses it to build a number of "parts", each configured via a section in the configuration file, and driven by a recipe.

As the environment grows more complex, the find-grained control provided by zc.buildout becomes much more helpful.

Weaknesses of zc.buildout

At the simpler end of the spectrum, however (building and testing a single, pure-Python package), the advantages are not so clear. In particular:

  • At the level of a single package, the policy maintained in the buildout.cfg file is redundant to the equivalent information expressed in the distutils / setuptools driver file, setup.py.

  • The bolerplate bootstrap and the (largely) boilerplate buildout.cfg are noticeable as "clutter" in the checkout / tarball, which provide no interesting benefit to developers who mean only to "consume" the package.

  • Python developers unfamiliar with zc.buildout may be put off by its "foreign" paradigm, which violates their expectation that a package should be manageable using the standard commands of distutils (a de jure standard) or setuptools (a de facto standard).

    For instance, runing the tests for a package in the setuptools world involves merely unpacking the tarball and running setup.py test; for zc.buildout, the equivalent steps are unpacking, running the bootstrap script, then runnning an arbitrarily-named test runner script. Documenting this paradigm in each package is extra effort for the maintainer, as well.