Contributing guidelines

In general

  • PEP 8, when sensible.
  • Test ruthlessly. Write docs for new features.
  • Even more important than Test-Driven Development–Human-Driven Development.
  • If you add an extension to, add it to
  • Please update AUTHORS.rst when you contribute.

In particular

Setting up for development

Clone the repo:

$ git clone
$ cd modular-file-renderer

Configure development environment and install the development dependencies.


It is recommended that you use a virtualenv with virtualenvwrapper during development. Python 3.5 or greater, R, and pspp are required.

# For Mac OS X: Install the latest version of python3.5
$ brew install python3
$ brew install r pspp

# Linux users, probably the same thing but with apt-get
# If someone wants to update this guide, please do.

$ pip install virtualenv
$ pip install virtualenvwrapper
$ mkvirtualenv --python=`which python3` mfr
$ pip install setuptools==30.4.0
$ pip install invoke==0.13.0

Lastly, install mfr in development mode.

$ invoke install -d
$ invoke server

Running tests

To run all tests (requires pytest)

$ invoke test

You can also use pytest directly.

$ py.test

Writing tests

Unit tests should be written for all rendering code.

Tests should be encapsulated within a class and written as functions, like so:

# in

from mfr_something import render

def test_render_html():
    with open('testfile.mp4') as fp:
        assert render.render_html(fp) == '<p>rendered testfile.mp4</p>'

There are a few pytest fixtures to help you mock files. You can use them by simply including them as parameters to your test functions. For example, the fakefile fixture is a fake file-like object whose name and content you can set to any value.

The above test can be rewritten like so:

# in

from mfr_something import render

def test_render_html(fakefile):
    assert render.render_html(fakefile) == '<p>rendered testfile.mp4</p>'

Manual Local Testing

To make sure a new renderer is functioning properly, it’s recommended that you try to render a file of that type locally.

First, change the default provider to HTTP (in /mfr/server/, then update the provider domain in the ALLOWED_PROVIDER_DOMAINS whitelist (a space-separated string):

PROVIDER_NAME = config.get('PROVIDER_NAME', 'http')
ALLOWED_PROVIDER_DOMAINS = config.get('ALLOWED_PROVIDER_DOMAINS', 'http://localhost:8000/')

Because the MFR is passed a url to render, you also need to be running an http server.

From a directory with a file you want to render:

python -m SimpleHTTPServer 8000

Or for python 3

python3 -m http.server 8000

With both the SimpleHTTPServer and the MFR server running, go to


Writing A File Format Package

There are two main pieces of a file format package are

  • Your custom rendering and/or exporting code
  • Your FileHandler

Rendering Code

Renderers are simply callables (functions or methods) that take a file as their first argument and return

Here is a very simple example of function that takes a filepointer and outputs a render result with an HTML image tag.

def render_img_tag(filepointer):
    filename =
    content = '<img src="{filename}" />'.format(filename=filename)
    return RenderResult(content)

You can also write renderers as methods.

# in mfr_video/

class VideoRenderer(object):

    def render_html5_tag(self, fp):
        content = '<video src="{filename}"></video>'.format(
        return RenderResult(content)

    def render_flash(self, fp):
        # ...

The FileHandler

A file handler is responsible for using your custom rendering and exporting code to actually render and export a file. When you call mfr.detect, you receive a list of FileHandler classes.

Your FileHandler must define a detect method which, given a file object, returns whether or not it can handle the file.

Your FileHandler class should be named Handler and should be defined in your `mfr_format/` file.

# in mfr_image/

from mfr import FileHandler, get_file_extension

# Your custom code
from mfr_image.render import render_img_tag
from mfr_image.export import ImageExporter

class Handler(FileHandler):
    renderers = {
        'html': render_img_tag,

    exporters = {
        'png': ImageExporter().export_png,
        'jpg': ImageExporter().export_jpg,
        # ...

    def detect(self, fp):
        return get_file_extension( in ['.jpg', '.png', ]  # and so on


Each package has its own directory. At a minimum, your package should include:

  • Where your FileHandler <mfr.core.FileHandler>` subclass will live.
  • render-requirements.txt: External dependencies for rendering functionality.
  • export-requirements.txt: External dependencies for export functionality.

Apart from those files, you are free to organize your rendering and export code however you want.

A typical extension plugin directory structure might look like this:

├── mfr
│       ├──
│       └── extensions
│               ├──
│               └── custom-plugin
│                       ├──
│                       ├──
│                       ├──
│                       ├──
│                       ├── static
│                       │       ├── css
│                       │       └── js
│                       ├── templates
│                       │       └── viewer.mako
│                       └── libs
│                               ├──
│                               └──
├── tests
│       ├──
│       └── extensions
│               ├──
│               └── custom-plugin
│                       ├──
│                       └──
└── requirements.txt


Contributions to the documentation are welcome. Documentation is written in reStructured Text (rST). A quick rST reference can be found here. Builds are powered by Sphinx.

To build docs:

$ pip install -r doc-requirements.txt
$ cd docs
$ make html
$ open _build/html/index.html

The -b (for “browse”) automatically opens up the docs in your browser after building.