Documents are used to describe functions and usage of a plugin to an end-user.

Their output is independent, so that plugins can collect them and create documentations in different formats, like console output, html pages or whatever is needed.

groundwork documents support Jinja and rst. Based on this, they are not static and can be easily used to document dynamic behaviors of an application. For instance to provide a list of available commands.

Live example

groundwork provides an easy console viewer for its basic_app. It is part of the GwDocumentsInfo plugin.

After installation of groundwork, simply type the following in a console window:

groundwork doc

Use N and P to navigate. X to quit.


To register a document, a plugin must inherit from GwDocumentsPattern and call the register() function:

from groundwork.patterns import GwDocumentsPattern

class My_Plugin(GwDocumentsPattern):
    def __init__(self, app, **kwargs): = "My Plugin"
        super().__init__(app, **kwargs)

    def activate(self):
        my_content = """
        My Plugin
        Application name: {{}}
        Plugin name: {{}}
                                description="Provides information about 'My Plugin'")

Unregister document

To unregister a document, you must use unregister():

def deactivate(self):

Using Jinja and RST

Jinja and rst are powerful, wide used and well documented libraries for creating intelligent and beautiful documents.


Jinja is template engine and allows a developer to use variables and loops inside a text document (besides a lot of more awesome stuff).

groundwork provides the application object as app and the plugin object, which has registered the document, as plugin to each template:

# JINJA template

Application name: {{ }}

{% if app.plugins.get()|count > 5 %}
    Wohooow, we have a lot of plugins!
{% else %}
    Ok, we have some plugins.
{% endif %}

{# get() provides a dict, so we use items() to iterate over it #}
{% for key, plugin in app.plugins.get().items() %}
{% endfor %}

The template engine must be executed by the plugin, which provides a viewer to these documents. And the execution should be done directly before the document gets presented to the user.


Restructured Text is used to give your document some sort of a layout. For instance add titles and chapters, make some words strong and add some links.

rst is so generic, that it can be used to build pdf documents, html webpages, epub (an ebook format) and much more.

A famous rst based documentation framework is Sphinx

For a quick introduction, please read Quick reStructuredText.

Developing a document viewer

A viewer for the groundwork documents must care about the following functions:

  1. Render the Jinja template string.
  2. Transform rst-content to the needed output.

Step 1: Render Jinja

Step 1 can be done using the Jinja template and its from_string() command:

from jinja2 import Environment

...  # App initialisation, plugin activation, ...

document = my_app.documents.get("my example document")
rendered_doc = Environment().from_string(document.content).render(app=my_app, plugin=document.plugin))

It is important to provide 2 parameters to the jinja template:

  • app: the current application object
  • plugin: the plugin, which has registered the current document

Step 2: Transform rst

The second step depends on the needed output format. You will find a wide range of rst supports for different programming languages. A good starting point is a list of rst supporting libraries and tools in this stackoverflow answer.

However, the following example will make html from an already rendered, rst structured document content:

from docutils.core import publish_parts

...  # App initialisation, plugin activation, jinja rendering, ...

output = publish_parts(rendered_doc, writer_name="html")['html_body']

publish_parts() renders the rst string and provides several groups of html areas. Based on this it is very easy to get the complete html tree or the body content only. Which would be really helpful, if a document should be integrated into an already existing html frame.

Supported areas are: body_prefix, fragment, html_subtitle, header, version, meta, stylesheet, subtitle, html_head, body_pre_docinfo, head, html_body, body, html_prolog, title, docinfo, html_title, whole, body_suffix, head_prefix, footer, encoding.

For details of publish_parts() and its supported part names, please take a look into the official documentation.

Sphinx support

Sphinx is a documentation builder, which takes static, rst based files and generates websites, PDFs and more out of it. For instance, this documentation is using sphinx.

As sphinx supports physical files on a hard disk only, it can not integrate with groundwork documents directly.

Luckily the groundwork plugin GwDocumentsInfo provides the command doc_write to store the content of all registered documents of an application in a directory.

Before it writes the files, the command will give you an overview about what will happen and asks for a final confirmation.


# On a command line

groundwork doc_write ../temp            # Writes rst documents to given, relative path.

groundwork doc_write /home/user/temp    # Writes rst documents to the given, absolute path.

groundwork doc_write ./temp -h          # Writes HTML documents.

groundwork doc_write ./temp -o          # Does not exit, if given directory is not empty.

groundwork doc_write ./temp -q          # Does not ask for final confirmation. Most needed by automation scripts.

groundwork doc_write ./temp -o -q -h    # All options together...

After export, you can use the generated rst files as normal input files for sphinx. For instance you can add them to a .. toctree:: of your index.rst.


The output filename of a document is the document name in lowercase. Also all whitespaces are removed. For instance: “My Great Document” becomes “mygreatdocument.rst”