root / home / tseaver / obzervationz / 2008 / bulidout_vs_plain_setuptools zc.buildout vs. "plain" setuptoolsA brief proposal on how and when one might prefer to use "standard" setuptools features, rather than relying on zc.bulidout.
Created by tseaver. Last modified 2008-04-24 00:32:58. |
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.
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.
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:
buildout.cfg
file is redundant to the equivalent information
expressed in the distutils
/ setuptools
driver file, setup.py
.buildout.cfg
are noticeable as "clutter" in the checkout /
tarball, which provide no interesting benefit to developers who mean
only to "consume" the package.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
`distuilts' (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.
Rather than advocating that the Zope community abandon zc.buildout
,
for the "simple package" case, I would like to propose some practices
which mitigate some of the downsides.
setup.py
script. Resist the temptation to exploit the additional expressiveness of
the configuration language provided by zc.buildout
when packaging
reusable librarires.
setup.py
as declarative as possible. Avoid "tricky" things inside the script: use the "standard"
mechanisms as much as possible. For instance, use
pkg_resources.find_packages
, rather than roll your own
file-finding logic.
In particular, move the various kinds dependency information out
into globals, if the zc.buildout
framework cannot introspect it
directly.
For instance, because zc.buildout
does not support the
tests_require
keyword directly, we should perhaps adopt a
conventional name (e.g., TESTS_REQUIRE
) at "module scope" in the
setup.py
script, which contains the testing dependencies to be
passed to setup()
. zc.buildout
could then use such a name to
configure its test runner scripts.
zc.buildout
. Before releasing the package to the wider Python world, ensure that
the "standard" distutils
/ setuptools
commands (build
,
develop
, install
, 'test'[1]) work with the package in an
environment which does not have zc.buildout
installed.
The virtualenv
package
provides an easy means of creating such environments.
sdist
tarball. Unless your package has C extensions, you should plan to
distribute only the source distribution (the one created
by setup.py sdist
). This tarball will contain all the files
in your package, including tests and documentation, as opposed to
the various binary formats. The binary formats often have subtle
portability issues, as well some of which can't be resolved (e.g.,
32-bit vs. 64-bit, Python version, UCS2 vs. UCS4, etc.).
Windows developers should be able to install pure Python sdist
distributions, as well, even without the compiler required to
build C extensions.
If your package does include C extensions, then you should plan,
if possible, to build and distribute the bdist_win
package, for
the benefit of Windows users who can't compile the extension.
You might also distribute a bdist_egg
built for Windows (some
users prefer the installer version, and others the egg). Generally,
it would be best to avoid building other binary distributions at all:
on any platform where Python or Zope is likely to run, the extension
should be trivial to build from the sdist
version.
[1] One issue with the setup.py test
command is that any
dependencies which are not already in the current
environment will be installed as eggs into the unpacked
tarball's top-level directory. These eggs will interfere
with later setup.py
commands, if not removed.