Mantissa Plugin Notes

Overview

This page is a collection of notes based on my adventures with the following tickets:

As such, you can imagine the following about these notes:

  • they are based on one specific aspect of Mantissa/Axiom plugins;
  • they are written from a relative Noob perspective; and
  • are most certainly not complete.

The plugin under scrutiny here (well, under rewrite, actually) is axiomatic project which has been (until some time in the near future) called in the following manner:

axiomatic project -n MyApp

This creates a Divmod™-approved directory structure populated by minimally functional code stubs, ready for the project dev to start making "MyApp" a software reality.

Quick Glance

The code that is responsible for this axiomatic subcommand is distributed over a few files. Here's the breakdown:

  • axiomatic itself lives in a bin dir somwhere, or if you are using Combinator, a bincache dir;
  • the contents of that script are the same as in most of the other Mantissa scripts: a remain() call;
  • combinator.chameleon.remain is a function which
    • determines the original script name, in this case axiomatic,
    • searches the paths in sys.path and locates the "real" script (not the wrapper in bincache),
    • passes the appropriate arguments, and calls the actual script.
  • Axiom/bin/axiomatic is called, which runs axiom.scripts.axiomatic.main() and thus does the following:
    • parses the command line with Options.parseOptions (t.p.usage.Options.parseOptions) which
    • iterates through the items yielded by subCommands (used as a property, but the property is a callable);
    • the yielded data structures have as their third element the plugin class that is used to parse the remaining plugin-specific command line options (subCommands calls getPlugins -- see the Plugins In-depth section below); also, parseOptions
    • instantiates the plugin class (parser), sets the .subOptions attribute with its value, and call postOptions.
    • Generate.postOptions() opens template.txt and epsilon.asplode.splode writes out the contents of template.txt to boilerplate project code.

Subcommands In-depth

TBD

Plugins In-depth

The big mover and shaker behind the plugin scene is twisted.plugin.getPlugins(). This guy first gets all "dropins" (twisted plugin modules or pickled data about plugin modules that are represented as objects and stored in a dict). Dropins can have potentially-many plugins, so they are iterated in the getPlugins function. Each plugin (note that plugins are classes) is then adapted to the passed interface, which results in getPlugins() returning (yielding, actually) an iterable whose elements are plugins (the classes that have been adapted).

When reading the two subsections below, it would be best to follow along in the source code of axiom/plugins/mantissacmd.py and twisted.plugin.getPlugins.

Interfaces

For our example, we have the axiom/plugins/mantissacmd.py dropin. The plugin of interest is the class mantissacmd.Generate, which is a subclass of axiom.scripts.axiomatic.AxiomaticCommand. This in turn has a metaclass which, for our case, sets Generate as providing both the twisted.plugin.IPlugin and axiom.iaxiom.IAxiomaticCommand interfaces.

Adaptation

Due to Generate implementing IAxiomaticCommand, when getPlugins (called from Options.subCommands) finds our mantissacmd dropin, it adapts the CachedPlugin to the IAxiomaticCommand which gives us the actual plugin object that's in the dropin cache.

For more on Twisted plugins, see http://twistedmatrix.com/projects/core/documentation/howto/plugin.html.

Template In-depth

Hrm, actually, I'm gonna put the template stuff in another wiki page.

jethro@divmod.org