# MultiQC Plugins

MultiQC is written around a system designed for extensibility and plugins.
These features allow custom code to be written without polluting the central
code base.

Please note that we want MultiQC to grow as a community tool! So if you're
writing a module or theme that can be used by others, please keep it within
the main MultiQC framework and submit a pull request.

## Entry Points

The plugin system works using setuptools
[entry points](http://setuptools.readthedocs.io/en/latest/setuptools.html#dynamic-discovery-of-services-and-plugins).
In `setup.py` you will see a section of code that looks like this _(truncated)_:

```python
entry_points = {
    'multiqc.modules.v1': [
        'qualimap = multiqc.modules.qualimap:MultiqcModule',
    ],
    'multiqc.templates.v1': [
        'default = multiqc.templates.default',
    ],
    # 'multiqc.cli_options.v1': [
        # 'my-new-option = myplugin.cli:new_option'
    # ],
    # 'multiqc.hooks.v1': [
        # 'before_config = myplugin.hooks:before_config',
        # 'config_loaded = myplugin.hooks:config_loaded',
        # 'execution_start = myplugin.hooks:execution_start',
        # 'before_modules = myplugin.hooks:before_modules',
        # 'after_modules = myplugin.hooks:after_modules',
        # 'execution_finish = myplugin.hooks:execution_finish',
    # ]
},
```

These sets of entry points can each be extended to add functionality
to MultiQC:

- `multiqc.modules.v1`
  - Defines the module classes. Used to add new modules.
- `multiqc.templates.v1`
  - Defines the templates. Can be used for new templates.
- `multiqc.cli_options.v1`
  - Allows plugins to add new custom command line options
- `multiqc.hooks.v1`
  - Code hooks for plugins to add new functionality

Any python program can create entry points with the same name, once installed
MultiQC will find these and run them accordingly. For an example of this in
action, see the [MultiQC_NGI](https://github.com/ewels/MultiQC_NGI/blob/master/setup.py)
setup file:

```python
entry_points = {
        'multiqc.templates.v1': [
            'ngi = multiqc_ngi.templates.ngi',
            'genstat = multiqc_ngi.templates.genstat',
        ],
        'multiqc.cli_options.v1': [
            'project = multiqc_ngi.cli:pid_option'
        ],
        'multiqc.hooks.v1': [
            'after_modules = multiqc_ngi.hooks:ngi_metadata',
        ]
    },
```

Here, two new templates are added, a new command line option and a new code hook.

## Modules

List items added to `multiqc.modules.v1` specify new modules. They should
be described as follows:

```python
modname = python_mod.dirname.submodname:classname'
```

Once this is done, everything else should be the same as described in the
[writing modules](http://multiqc.info/docs/#writing-new-modules) documentation.

## Templates

As above, though no need to specify a class name at the end. See the
[writing templates](http://multiqc.info/docs/#writing-new-templates) documentation for further instructions.

## Command line options

MultiQC handles command line interaction using the [click](http://click.pocoo.org/)
framework. You can use the `multiqc.cli_options.v1` entry point to add new
click decorators for command line options. For example, the MultiQC_NGI
plugin uses the entry point above with the following code in `cli.py`:

```python
import click
pid_option = click.option('--project', type=str)
```

The values given from additional command line arguments are parsed by
MultiQC and put into `config.kwargs`. The above plugin later reads
the value given by the user with the `--project` flag in a hook:

```python
if config.kwargs['project'] is not None:
  # do some stuff
```

See the [click documentation](http://click.pocoo.org/) or the main
MultiQC script for more information and examples of adding command line
options.

## Hooks

Hooks are a little more complicated - these define points in the core
MultiQC code where you can run custom functions. This can be useful as
your code is able to access data generated by other parts of the program.
For example, you could tie into the `after_modules` hook to insert data
processed by MultiQC modules into a database automatically.

Here, the entry point names are the hook titles, described as commented out
lines in the core MultiQC `setup.py`: `execution_start`, `config_loaded`,
`before_modules`, `after_modules` and `execution_finish`.

These should point to a function in your code which will be executed when
that hook fires. Your custom code can import the core MultiQC modules to
access configuration and loggers. For example:

```python
#!/usr/bin/env python
""" MultiQC hook functions - we tie into the MultiQC
core here to add in extra functionality. """

import logging
from multiqc.utils import report, config

log = logging.getLogger('multiqc')

def after_modules():
  """ Plugin code to run when MultiQC modules have completed  """
  num_modules = len(report.modules_output)
  status_string = "MultiQC hook - {} modules reported!".format(num_modules)
  log.critical(status_string)
```
