A Proposal for User Plugins for Docutils Readers/Writers

Author: Dave Kuhlman
Address:
dkuhlman@rexx.com
http://www.rexx.com/~dkuhlman
Date: March 21, 2007

Contents

Abstract

This proposal describes a standard for support of user directives for Docutils readers/writers. It is intended that Docutils writers (for example, rst2html.py, rst2latex.py, rst2odt.py, etc.) would attempt to load and register directives as described by this proposal.

Rationale

Directives are a Docutils extension mechanism. In particular, directives enable us to implement a class that adds nodes to the document node tree as that tree is being constructed and before the tree is processed by a writer.

This proposal describes a way to make directive implementations automatically loadable. It is intended that this mechanism would enable users to add their own directives and even to provide different directive implementations for different documents.

The Proposal

The following items describe this proposal:

Notes:

Alternatives

Lea Wiemann also has a proposal for extensions. That proposal seems more oriented toward adding extensions to an installation of Docutils rather than, as in this proposal, enabling users to load and register directives automatically, on the fly. So, for example, under Lea's plugins proposal, in order to change the implementation of a directive, the user must perform some sort of install operation. Am I right about that?

Lea's proposal also appears to be much more general and powerful than this one. It covers the ability to add other types of extensions besides directives. A quote from Lea's proposal:

"Specifically, this document covers the addition of Docutils components (readers, parsers, and writers), and the addition of reStructuredText roles and directives."

See:

A Sample Implementation

The following code could be added near the top of a Docutils writer in order to implement this proposal. This code is provided for discussion. Note that it does not support a command line flag that can pass in the directive module name.

import inspect

#
# Register directives defined in a module named "odtwriter_plugins".
#
def load_plugins():
    plugin_mod = None
    count = 0
    try:
        import odtwriter_plugins
        plugin_mod = odtwriter_plugins
    except ImportError, e:
        pass
    if plugin_mod is None:
        return count
    klasses = inspect.getmembers(plugin_mod, inspect.isclass)
    for klass in klasses:
        if register_plugin(*klass):
            count += 1
    return count

def register_plugin(name, klass):
    plugin_name = getattr(klass, 'plugin_name', None)
    if plugin_name is not None:
        rst.directives.register_directive(plugin_name, klass)

load_plugins()