Plugins are a very important aspect of MoinMoin, allowing for great flexibility in terms of input format, processing capabilities, dynamic content, and output of pages. (german version)

See also: ErrorHandlingInPlugins.

Overview

These are the main types of plugins:

Basically, for each of these plugin types, you can write your own plugin module, which is executed by MoinMoin (if appropriate) when it processes a client request.

Plugins are written in Python code. They are located in specific directories and must provide the required interface to MoinMoin in order for the system to load and run them.

Main Event Sequence

The main sequence of events in MoinMoin for handling a page is (roughly):

Builtin plugins and wiki plugins

Each wiki data directory has a plugin directory, which is a Python package. Inside there are packages for each type of plugin - action, macro, etc. Wiki plugins are installed in one of these packages, for example data/plugin/macro/RecentChanges.py would provide a macro named RecentChanges. MoinMoin plugins are installed in the MoinMoin package under MoinMoin/plugin kind/plugin name.

Wiki plugins always override builtin plugins. For example, if you want to have a different RecentChanges macro, you don't have to touch MoinMoin code, simply write your own RecentChanges macro and install in the wiki data/plugin/macro/. Your macro will be used instead of the built-in one.

How plugins are imported

To import a plugin, call wikiutil.importPlugin. It will return either a wiki plugin or a builtin plugin, or raise wikiutil.PluginError or more specific subclass. If you want to get specific plugin, call either importWikiPlugin or importBuiltinPlugin.

When you call one of the importXXXPlugin, the the plugin name is checked in the list of available plugins, created once per run by the plugin package (see __init__.py). If a plugin is missing, the request to import it will raise PluginMissingError without trying again to load the plugin.

Wiki plugins are imported once and then cached in Python sys.modules, like any other module. Wiki plugins are imported as siteid.plugins.kind.name. Each wiki has a siteid which is the name of the wiki configuration module. In a default single wiki install, all wiki plugins will be imported as wikiconfig.plugin.kind.name. Builtin plugins are imported as MoinMoin.kind.name.

Installing or modifying plugins

If you install a new plugin or change existing plugin code, it will be activated only after moin code is restarted. For CGI, it will be active on the next request. For the standalone or twisted servers, after restarting the MoinMoin server. For FastCGI and mod_python, you will have to restart Apache.

Types of plugins

Available add-on plugins can be found on several market pages. See CategoryMarket or try the links below.

Action

The action is what the MoinMoin code does with the client request (and the requested page). The default action is to parse the page as wiki text and output HTML. However other actions can be defined to allow arbitrary processing. Actions are the moral equivalent of CGI scripts, but inside a MoinMoin context.

Essentially, by writing an action you can extend MoinMoin to perform any processing you wish. This is most often done to perform processing on a page (a page is given as the argument to the action), but any processing is allowed.

The builtin page actions are things like:

There are also some add-on actions provided with standard MoinMoin, like SpellCheck, to check the spelling of words on a page.

See also: HelpOnActions, ActionMarket.

API:

def execute(pagename, request):

Parser

A parser reads the page contents, and calls the formatter to output the page.

Parsers allow MoinMoin to have flexibility of input format. The default input format is the wiki format, which is the text format that pages are normally saved in. However, other input formats are possible, such as python code fragments, plain text, or others.

By writing your own parser, you can extend MoinMoin to support additional document formats.

See also: ParserMarket.

   1 class Parser:
   2 
   3     extensions = ['.txt']
   4 
   5     def __init__(self, raw, request, **kw):
   6 
   7     def format(self, formatter):

See MoinMoin/parser/text.py for a simple example.

Question: The example includes Dependencies variables at both the class and module level; are either of these part of the API? There are no comments in the example to explain their status or purpose.

Question: Does MoinMoin require that Parser be a class, or just a callable factory? Is extensions an attribute of the factory or the instance?

Formatter

A formatter is used to output the page in a particular format. The default output format is HTML, but the page results may also be delivered in XML or some other format.

A formatter provides to MoinMoin an interface for outputting standard document elements. Parsers, macros and processors should use this interface, rather than directly outputting HTML, so that the document can be delivered to the client in any supported output format. Read ApplyingFormatters to learn how to use it or have a look at the sources: MoinMoin/formatter/, MoinMoin/formatter/text_html.py

See also: FormatterMarket.

Macro

A macro is a mechanism for incorporating dynamic content in the middle of page output. A macro definition usually includes a small number of parameters, and is used to output information which is processed and/or formatted when the page is accessed.

These are used to cause extra data or controls to appear as part of the page.

See also: HelpOnMacros, MacroMarket.

Macros reside in MoinMoin/macro and data/plugin/macro.

API:

def execute(macro, args):

The macro object can access the following objects:

Macros should use macro.formatter to create the output and return it.

Theme

A theme determines the visual appearance of the output. You can have different screen layout, icons and CSS per theme.

The default theme is 'modern'. A user can set a different theme in the user preferences.

Themes are available starting with MoinMoin 1.2.

See also: HelpOnThemes, ThemeMarket.

Dependencies

Plugins such as parsers and macros may declare a Dependencies attribute, indicating the elements of the request or site from which the plugin requires "live" (or "static"), not cached (or "dynamic"), information. The following values can be supplied in the Dependencies list (or are supplied by various standard plugins distributed with MoinMoin):

As of MoinMoin 1.9, there isn't much code really supporting all this. In the MoinMoin.formatter.text_python.Formatter class, the only real use of the declared dependencies of a plugin involves comparing them to a list of known "static" dependencies, and this appears to be limited to page (defined in the MoinMoin.Page.Page.makeCache method); all other dependencies will cause the plugin to demand "live" content.

Thus, an empty dependency list (or one containing the page dependency, but not pages) means that a plugin's output is "static" (and that the content rendered by the plugin gets cached) whereas a non-empty list makes it "dynamic" (the cached code contains a dynamic call that invokes the plugin, regardless of whether other parts of a page are cached) precisely because the plugin needs live access to the specified facilities to correctly produce its output.

It is arguably a good practice to specify correct dependencies in case a more sophisticated dependency system is introduced in MoinMoin at some point in the future, not least because with more sophisticated content caching, any plugin not accurately specifying the dependencies will unnecessarily generate dynamic content and potentially cause wiki performance problems, requiring someone to determine and enforce the dependencies that the plugin really needs so that it may function correctly and efficiently.

See also: Understanding the Caching Framework

Comments

Well, what I'd like to see is a cross between the CategoryMarket or HelpPages and SystemInfo. The SystemInfo (or the MacroManager) page should not only list the available modules, but also present a brief description of what the macro does along with a usage() of some sort. All this should be dynamically generated, not maintained through the wiki pages. So I guess the macro definition should also have "meta-data" associated to it. Let's call this MacroMetaData. That's what PluginManager does (when it works ;). Note: this is a FeatureRequests (see item #13: Self-Documenting Extensions) -- TheAnarcat 2004-07-16 19:17:35

Is there any infrastructure that allows more complicated "extension" type development? I just finished (soon to be released, once the semester is over and I get a chance to clean up the code and comment a lot) a contextual annotation system for MoinMoin 1.3.5, which ended up consisiting of an action, a parser and a slight bit of hackery to Page.py... this was necessary because the functionality was a little more complicated than any of the single notions of plugin could encapsulate (it needed to diddle the user interface, and provide some back-end support for creating, saving, and reading annotations). I imagine there should be a way to create a package-style module which can be placed in a particular wiki instance's local space (data/plugin/extensions/ maybe?) which then has access to both the MoinMoin plugin namespace, as well as its own (if you have data/plugin/extensions/foo/, then you can from foo import Bar, etc). I don't know how hard that would be to actually implement, I may look into doing it sanely and safely if I get some more spare time. -- DanCrosta

MoinMoin: MoinDev/PluginConcept (last edited 2014-01-24 22:17:42 by PaulBoddie)