Skip to content

Writing pluglets

Note

New, as of version 0.4.20.

Introduction

Definition

A pluglet is a preinstalled module for mkdocs-macros, which is installed thanks to Pythons standard packaging process.

The only thing needed (as a bare minimum), is to implement a single function, define_env():

def define_env(env):
    ....

What makes a pluglet different from a plain module?

The only difference between a pluglet and an ordinary mkdocs-macros module (typically main.py or main directory), is that the pluglet is preinstalled. In this way, you can benefit from pluglets written by others, and you could share the pluglets that you wrote.

A pluglet can do two things that any mkdocs-macro module can do:

  1. Define macros.
  2. Perform changes on the architecture of the website.

What makes a pluglet different from a plugin?

A pluglet is distinct from an MkDocs plugin. A pluglet is a more lightweight tool that sits over the mkdocs-macros plugin and uses the framework provided by it.

There is no need to implement a subclass of the BasePlugin class, only to declare a define_env(env) function.

Could a pluglet do everything a plugin can do?

The answer is, quite a lot, but not everything. MkDocs plugins are able to rely on a wide range of events, which are hooks for acting on the website at various stages of the config/build process.

A mkdocs-macros pluglet operates mostly on the on_config event of MkDocs thanks to define_env(env)hook; but its use can be extended thanks to other hooks.

Using existing pluglets

Declaring a pluglet for an MkDocs project

For your specific documentation project, you may call already installed pluglets (which would appear with pip list):

pip list | grep mkdocs-macros

Use the modules argument.
It is a list, so that you can declare one or more:

e.g. :

plugins:
  ...
  - macros:
      modules: [mkdocs_macros_test]

or:

plugins:
  ...
  - macros:
      modules: [mkdocs_macros_foo, mkdocs_macros_bar]

Finding pluglets

Every pluglet specified in the moduleslist should be already installed.

As of 1.4.0

No more auto-install of pluglets

However, if a pluglet cannot be found, mkdocs will no longer attempt to install it (with pip3 install) from the standard repositories (Pypi and others defined locally).

If a plugin is available on Pypi and it was not installed, mkdocs serve and mkdocs build will fail with a ModuleNotFound exception and a meaningful message, making debugging easier on a new install:

Could not import pluglet 'mkdocs_macros_foo'. Please install it from Pypi:

    pip install mkdocs_macros_foo

If the plugin name is different from the Python import name, you should specify it in the modules parameter so that MkDocs-Macros can check for its existence on Pypi, in case it is not installed.

plugins:
  ...
  - macros:
      modules: [mkdocs-macros-test:mkdocs_macros_test]

In the example above mkdocs-macros-test is the package source, and mkdocs_macros_test is the package name for the import statement.

If those names are correct, the mkdocs serve or mkdocs build will give the correct error message.

Implementing a new pluglet

General Principles

You can develop pluglets for mkdocs-macros-plugin and publish them on github and pypi.

How to name a pluglet

The names for pluglets are not constrained. As a naming convention, we strongly recommend:

  • a package name starting with mkdocs-macros-
  • an import name starting mkdocs_macros_, i.e. replacing the hyphen (-) symbol by underscore (_).

Typical structure of a pluglet

Note

You will find a simple example with the mkdocs-test pluglet, available on gihub.

The setup.py file will typically have this form:

from setuptools import setup

setup(
    name='mkdocs-macros-foo',
    version='0.0.1',
    description="Foo library for macros plugin",
    packages=['mkdocs_macros_foo'],
    license='<YOUR CHOICE>',
    author='Joe Bloe'
)

The structure will be typically like so:

├── LICENSE.md
├── README.md
├── mkdocs_macros_test.py
└── setup.py

or like so (if it is more complex):

├── LICENSE.md
├── README.md
├── mkdocs_macros_test
│   └── __init__.py
|   └── util.py
└── setup.py

Note

The subdirectory containing the code will have to be called mkdocs_macros_foo (underscores).

How to write the code

For the code itself, proceed as for a usual module:

"""
Code of the pluglet
"""

def test_fn(x:float):
    "Test function"
    return x * 4 / 3

def say_hello(s:str):
    "Test procedure"
    return "<i>Hello %s</i>" % s

def define_env(env):
    "Declare environment for jinja2 templates for markdown"

    for fn in [test_fn, say_hello]:
        env.macro(fn)


    # you could, of course, also define a macro here:
    @env.macro
    def test_fn2(s:str):
        return "I am displaying this: %s" % s