[Chandler-dev] Integrating Egg-based parcels in 0.7alpha2

Phillip J. Eby pje at telecommunity.com
Wed Mar 22 10:35:24 PST 2006


Egg-based Parcels in Chandler
=============================

This document summarizes how egg-based parcels are to be implemented in 
Chandler 0.7alpha2.  Some portions of this have already been implemented, 
while others are still in progress.  (See the `Implementation Plan`_ 
section below for details.)

For 0.7alpha2, we are only supporting the installation of plugins (and any 
supporting libraries) as eggs.  The Chandler core is not being put into 
eggs yet, nor any of the external libraries we depend on, except for 
setuptools itself (which is needed for creating and using other eggs).

During the development of 0.7alpha2, we'll be porting existing plugins like 
the Amazon, Flickr, and Feeds parcels to egg format.  Mostly, this just 
means a slight reorganization of the directory structure, and the addition 
of "setup.py" files describing each plugin.

The proposed directory layout would look like this::

     chandler/
         projects/
             Chandler-AmazonPlugin/
                 setup.py
                 amazon/
                     ...
             Chandler-FlickrPlugin/
                 setup.py
                 flickr/
                     ...
             ... etc.

The new 'projects' directory would be the home for any egg-based project 
that is bundled with the Chandler distribution.

Each subdirectory under 'projects' is a modular, independently 
distributable component that can be packaged in a standard .egg file for 
distribution.  The only things added to the existing code of these 
projects, is the parent directory and the setup.py.

The naming of the project directories is based on an emerging convention in 
the Python community for naming plugin projects registered with the Cheese 
Shop (Python's CPAN).  All Python eggs projects must have unique names 
(case-insensitively), so using a "Chandler-" prefix and "Plugin" suffix 
avoids confusion with any other "Amazon" or "Flickr" packages distributed 
in the Cheese Shop.

This means that we will be able to register plugins with the Python Cheese 
Shop, and users will be able to install them by typing simple commands like::

     release/easy_install Chandler-AmazonPlugin

which will automatically find and download the latest egg from the Cheese 
Shop and install it for use by Chandler.  At startup, Chandler will notice 
the presence of the egg and load any parcels that were registered in that 
project's setup.py.


Creating Plugin Eggs
--------------------

To create a plugin egg, one simply creates a directory with a 'setup.py' 
script, looking something like this::

     from setuptools import setup

     setup(
         name = "MyPlugin",
         version = "0.1",
         description = "This is just an example of a plugin project",
         test_suite = "mypackage.test_module",
         packages = ["mypackage"],
         include_package_data = True,
         entry_points = {
             "chandler.parcels": ["My Plugin Name = mypackage.plugin"]
         }
     )

(There are other fields you can fill out besides these, like license, 
author name, etc., but they are all optional.)

In the directory with this script, you place any Python modules or packages 
that are part of the plugin.  You must make sure that all packages and 
modules are listed in the setup() arguments, and that any modules which are 
Chandler parcels are named in the entry_points argument.

In all other respects, the modules and packages are normal Chandler parcels 
or Python code.  However, you do not need to put the directory on the 
PARCELPATH or PYTHONPATH.  Instead, you run the setup script with either 
"install" or "develop" as a command.  For example, running this::

     RunPython setup.py develop

will add a (temporary) link to your package from site-packages, so that 
your code is automatically importable when Chandler runs.  And, the 
"entry_points" information in setup.py is also registered, so that Chandler 
will autodetect and load the parcels you listed there.

If you want to distribute your plugin, you can do:

     RunPython setup.py bdist_egg

which will create a file like "MyPlugin-0.1-py2.4.egg" in a "dist/" 
subdirectory of your project.  This file, if placed in a directory on the 
PARCELPATH of a working Chandler installation, will automatically be 
scanned for parcels to load when Chandler starts.

Finally, if you want to run your plugin's tests, you can use:

     RunPython setup.py test

assuming you've defined an appropriate test_suite in the setup() 
arguments.  Currently, a test suite must be the name of a module containing 
unittest.TestCase subclasses, or the name of a zero-argument function that 
returns a unittest.TestSuite.

There are many other things you can do with your setup script, but rather 
than detail them all here, I'll refer you to the setuptools developer's guide:

     http://peak.telecommunity.com/DevCenter/setuptools

It covers everything from how to define project version numbers, to 
autotagging SVN revisions, to registering your project with PyPI (aka the 
Cheese Shop), and defining dependencies that get automatically installed 
along with your project.


Build System Integration
------------------------

Initially, the chandler/Makefile will include a BUNDLED_PLUGINS variable, 
listing the .egg file for each plugin.  As part of the normal "make 
install" process, it will download the .egg files and install them.

Initially, this process will be done via curl, but as soon as is practical 
we will switch to using easy_install to do this directly, because managing 
an explicit .egg list will quickly become annoying.  For example, running 
"make install" with a .egg list will wipe out any "setup.py develop" steps 
that a developer has done to work on a plugin.  There are also a few other 
creature comforts that easy_install will give us for plugin development 
that the curl-based downloads cannot.

So, pretty much as soon as we have the basic integration set up and 
working, we'll move to using easy_install instead of curl to download and 
install anything that's packaged as an .egg file.

For full builds, the externals/Makefile will implement the "builds" and 
"binaries" targets for plugins by running their "setup.py build" and 
"setup.py bdist_egg" commands, thus creating the .egg files needed by the 
chandler/Makefile's "make install" step.


Modifying Plugins
-----------------

Because the normal "make install" installs a .egg file with the contents of 
a plugin, there will be an extra step needed to do development on a plugin.

No, you will not need to run "make install" after every change.  Instead, 
you will run "RunPython setup.py develop" in your project *once*.  This 
will switch the plugin to "development mode", where any changes you make 
will take immediate effect.  The plugin will remain in development mode 
until/unless you install an .egg for it (e.g. via running "make install", 
or by using "setup.py install" to explicitly install it as a .egg file).

This step is needed because in the new model of parcel development, there 
is no requirement that a parcel be in any particular directory.  A user can 
develop parcels *anywhere* on their system, not just on PARCELPATH.  So, 
the parcel has to be activated by installing it, either as a .egg file or 
as a "development" link.  The "develop" command installs a special link 
file that tells Python (and Chandler) where the plugin's source code is.

(All of this means, by the way, that it won't actually be necessary to 
check out the projects/ subtree onto a machine unless you're going to be 
changing those plugins, just like you don't have to check out internals/ or 
externals/ unless you're editing that code.)


Test Integration
----------------

The do_tests.sh script will be updated to also run the "setup.py test" of 
each project in the projects/ directory.  If you want to run just one 
project's tests, or a specific test in that project, you can use "RunPython 
setup.py test" in that directory.  The "test" command accepts options to 
tell it what test or suite to run; you can use "RunPython setup.py test 
--help" to get more info, or consult the setuptools documentation.


Implementation Plan
-------------------

Currently, the Chandler startup code has been modified to detect eggs in 
PARCELPATH directories and automatically load any parcels registered in 
them.  (Including "development mode" eggs.)

The next step is to create a "Chandler-HelloWorldPlugin" project, which 
will have no real functionality but serve simply as an example of a plugin 
project.  Its purpose will be to support Bear in adding the new 
build-and-test pieces, before we begin porting any of the current plugins.

Once the hello-world plugin is integrated with the build, we can begin 
porting the existing plugins, which will mainly consist of moving them to 
subdirectories and adding setup.py files.  It would be best if this were 
done by volunteers so that as many people as possible get a chance to 
experience tinkering with a setup.py.  However, it's a simple enough 
process that we could probably do a "porting party" as an IRC office hour, 
with me there to answer questions and take people through a test drive of 
the basic setup.py commands and installing their parcels.



More information about the chandler-dev mailing list