diff --git a/.github/workflows/moban-update.yml b/.github/workflows/moban-update.yml
new file mode 100644
index 0000000..706fd82
--- /dev/null
+++ b/.github/workflows/moban-update.yml
@@ -0,0 +1,29 @@
+on: [push]
+
+jobs:
+  run_moban:
+    runs-on: ubuntu-latest
+    name: synchronize templates via moban
+    steps:
+      - uses: actions/checkout@v2
+        with:
+          ref: ${{ github.head_ref }}
+      - name: Set up Python
+        uses: actions/setup-python@v1
+        with:
+          python-version: '3.7'
+      - name: check changes
+        run: |
+          pip install moban gitfs2 pypifs moban-jinja2-github moban-ansible
+          moban
+          git status
+          git diff --exit-code
+      - name: Auto-commit
+        if: failure()
+        uses: docker://cdssnc/auto-commit-github-action
+        env:
+          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+        with:
+          args: >-
+            This is an auto-commit, updating project meta data,
+            such as changelog.rst, contributors.rst
diff --git a/.github/workflows/pythonpublish.yml b/.github/workflows/pythonpublish.yml
new file mode 100644
index 0000000..9e7ec42
--- /dev/null
+++ b/.github/workflows/pythonpublish.yml
@@ -0,0 +1,26 @@
+name: Upload Python Package
+
+on:
+  release:
+    types: [created]
+
+jobs:
+  deploy:
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v1
+      - name: Set up Python
+        uses: actions/setup-python@v1
+        with:
+          python-version: '3.x'
+      - name: Install dependencies
+        run: |
+          python -m pip install --upgrade pip
+          pip install setuptools wheel twine
+      - name: Build and publish
+        env:
+          TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }}
+          TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }}
+        run: |
+          python setup.py sdist bdist_wheel
+          twine upload dist/*
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..4727a58
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,95 @@
+# April 2016
+# reference: https://github.com/github/gitignore/blob/master/Python.gitignore
+# Byte-compiled / optimized / DLL files
+__pycache__/
+*.py[cod]
+*$py.class
+
+# C extensions
+*.so
+
+# Distribution / packaging
+.Python
+env/
+build/
+develop-eggs/
+dist/
+downloads/
+eggs/
+.eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+*.egg-info/
+.installed.cfg
+*.egg
+
+# PyInstaller
+#  Usually these files are written by a python script from a template
+#  before PyInstaller builds the exe, so as to inject date/other infos into it.
+*.manifest
+*.spec
+
+# Installer logs
+pip-log.txt
+pip-delete-this-directory.txt
+
+# Unit test / coverage reports
+htmlcov/
+.tox/
+.coverage
+.coverage.*
+.cache
+nosetests.xml
+coverage.xml
+*,cover
+.hypothesis/
+
+# Translations
+*.mo
+*.pot
+
+# Django stuff:
+*.log
+local_settings.py
+
+# Flask stuff:
+instance/
+.webassets-cache
+
+# Scrapy stuff:
+.scrapy
+
+# Sphinx documentation
+docs/_build/
+
+# PyBuilder
+target/
+
+# IPython Notebook
+.ipynb_checkpoints
+
+# pyenv
+.python-version
+
+# celery beat schedule file
+celerybeat-schedule
+
+# dotenv
+.env
+
+# virtualenv
+venv/
+ENV/
+
+# Spyder project settings
+.spyderproject
+
+# Rope project settings
+.ropeproject
+*~
+commons/
+commons
+.moban.hashes
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..80100f8
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,27 @@
+[submodule "examples/robotchef_allinone"]
+	path = examples/robotchef_allinone
+	url = https://github.com/python-lml/robotchef_allinone.git
+[submodule "examples/robotchef_allinone_lml"]
+	path = examples/robotchef_allinone_lml
+	url = https://github.com/python-lml/robotchef_allinone_lml.git
+[submodule "examples/robotchef"]
+	path = examples/robotchef
+	url = https://github.com/python-lml/robotchef.git
+[submodule "examples/robotchef_cook"]
+	path = examples/robotchef_cook
+	url = https://github.com/python-lml/robotchef_cook.git
+[submodule "examples/robotchef_britishcuisine"]
+	path = examples/robotchef_britishcuisine
+	url = https://github.com/python-lml/robotchef_britishcuisine.git
+[submodule "examples/robotchef_chinesecuisine"]
+	path = examples/robotchef_chinesecuisine
+	url = https://github.com/python-lml/robotchef_chinesecuisine.git
+[submodule "examples/v2/robotchef_v2"]
+	path = examples/v2/robotchef_v2
+	url = https://github.com/python-lml/robotchef_v2.git
+[submodule "examples/v2/robotchef_britishcuisine"]
+	path = examples/v2/robotchef_britishcuisine
+	url = https://github.com/python-lml/robotchef_britishcuisine_v2
+[submodule "examples/v2/robotchef_api"]
+	path = examples/v2/robotchef_api
+	url = https://github.com/python-lml/robotchef_api
diff --git a/.isort.cfg b/.isort.cfg
new file mode 100644
index 0000000..646d29a
--- /dev/null
+++ b/.isort.cfg
@@ -0,0 +1,10 @@
+[settings]
+line_length=79
+known_first_party=
+known_third_party=mock,nose
+indent='    '
+multi_line_output=3
+length_sort=1
+default_section=FIRSTPARTY
+no_lines_before=LOCALFOLDER
+sections=FUTURE,STDLIB,FIRSTPARTY,THIRDPARTY,LOCALFOLDER
diff --git a/.moban.d/CUSTOM_README.rst.jj2 b/.moban.d/CUSTOM_README.rst.jj2
new file mode 100644
index 0000000..12b7c34
--- /dev/null
+++ b/.moban.d/CUSTOM_README.rst.jj2
@@ -0,0 +1,18 @@
+{% extends "README.rst.jj2" %}
+
+{%block features%}
+{%include "description.rst.jj2" %}
+{%endblock%}
+
+{%block bottom_block%}
+lml enabled project
+================================================================================
+
+{%include "lml-enabled-projects.rst.jj2" %}
+
+License
+================================================================================
+
+New BSD
+
+{%endblock%}
\ No newline at end of file
diff --git a/.moban.d/custom_setup.py.jj2 b/.moban.d/custom_setup.py.jj2
new file mode 100644
index 0000000..ac3890c
--- /dev/null
+++ b/.moban.d/custom_setup.py.jj2
@@ -0,0 +1,5 @@
+{%extends "setup.py.jj2"%}
+
+
+{%block platform_block%}
+{%endblock %}
\ No newline at end of file
diff --git a/.moban.d/description.rst.jj2 b/.moban.d/description.rst.jj2
new file mode 100644
index 0000000..046fe56
--- /dev/null
+++ b/.moban.d/description.rst.jj2
@@ -0,0 +1,55 @@
+**{{name}}** seamlessly finds the lml based plugins from your current python
+environment but loads your plugins on demand. It is designed to support
+plugins that have external dependencies, especially bulky and/or
+memory hungry ones. {{name}} provides the plugin management system only and the
+plugin interface is on your shoulder.
+
+**{{name}}** enabled applications helps your customers [#f1]_ in two ways:
+
+#. Your customers could cherry-pick the plugins from pypi per python environment.
+   They could remove a plugin using `pip uninstall` command.
+#. Only the plugins used at runtime gets loaded into computer memory.
+
+When you would use **lml** to refactor your existing code, it aims to flatten the
+complexity and to shrink the size of your bulky python library by
+distributing the similar functionalities across its plugins. However, you as
+the developer need to do the code refactoring by yourself and lml would lend you a hand.
+
+.. [#f1] the end developers who uses your library and packages achieve their
+         objectives.
+
+
+Quick start
+================================================================================
+
+The following code tries to get you started quickly with **non-lazy** loading.
+
+.. code-block:: python
+
+    from lml.plugin import PluginInfo, PluginManager
+
+
+    @PluginInfo("cuisine", tags=["Portable Battery"])
+    class Boost(object):
+        def make(self, food=None, **keywords):
+            print("I can cook %s for robots" % food)
+
+
+    class CuisineManager(PluginManager):
+        def __init__(self):
+            PluginManager.__init__(self, "cuisine")
+
+        def get_a_plugin(self, food_name=None, **keywords):
+            return PluginManager.get_a_plugin(self, key=food_name, **keywords)
+
+
+    if __name__ == '__main__':
+        manager = CuisineManager()
+        chef = manager.get_a_plugin("Portable Battery")
+        chef.make()
+
+
+At a glance, above code simply replaces the Factory pattern should you write
+them without lml. What's not obvious is, that once you got hands-on with it,
+you can start work on how to do **lazy** loading.
+
diff --git a/.moban.d/docs/source/custom_conf.py.jj2 b/.moban.d/docs/source/custom_conf.py.jj2
new file mode 100644
index 0000000..e2378f1
--- /dev/null
+++ b/.moban.d/docs/source/custom_conf.py.jj2
@@ -0,0 +1,3 @@
+{% include "docs/source/myconf.py.jj2" %}
+
+master_doc = "index"
\ No newline at end of file
diff --git a/.moban.d/docs/source/custom_index.rst.jj2 b/.moban.d/docs/source/custom_index.rst.jj2
new file mode 100644
index 0000000..5094d13
--- /dev/null
+++ b/.moban.d/docs/source/custom_index.rst.jj2
@@ -0,0 +1,30 @@
+`{{name}}` - {{description}}
+================================================================================
+
+
+:Author: C.W.
+:Source code: http://github.com/{{name}}/{{name}}.git
+:Issues: http://github.com/{{name}}/{{name}}/issues
+:License: New BSD License
+:Released: |version|
+:Generated: |today|
+
+
+Introduction
+-------------
+
+{% include "description.rst.jj2" %}
+
+
+Documentation
+----------------
+
+.. toctree::
+   :maxdepth: 2
+
+   design
+   tutorial
+   lml_log
+   api
+
+{%include "lml-enabled-projects.rst.jj2" %}
diff --git a/.moban.d/docs/source/myconf.py.jj2 b/.moban.d/docs/source/myconf.py.jj2
new file mode 100644
index 0000000..348424d
--- /dev/null
+++ b/.moban.d/docs/source/myconf.py.jj2
@@ -0,0 +1,11 @@
+{%extends "docs/source/conf.py.jj2"%}
+
+{%block SPHINX_EXTENSIONS%}
+    'sphinx.ext.napoleon',
+    'sphinxcontrib.spelling'
+{%endblock%}
+
+{%block additional_config%}
+spelling_lang = 'en_GB'
+spelling_word_list_filename = 'spelling_wordlist.txt'
+{%endblock%}
\ No newline at end of file
diff --git a/.moban.d/lml-enabled-projects.rst.jj2 b/.moban.d/lml-enabled-projects.rst.jj2
new file mode 100644
index 0000000..84ffc86
--- /dev/null
+++ b/.moban.d/lml-enabled-projects.rst.jj2
@@ -0,0 +1,12 @@
+Beyond the documentation above, here is a list of projects using lml:
+
+#. `pyexcel <https://github.com/pyexcel/pyexcel>`_
+#. `pyecharts <https://github.com/pyecharts/pyecharts>`_
+#. `moban <https://github.com/moremoban/moban>`_
+
+lml is available on these distributions:
+
+#. `ARCH linux <https://aur.archlinux.org/packages/python-lml/>`_
+#. `Conda forge <https://anaconda.org/conda-forge/lml>`_
+#. `OpenSuse <https://build.opensuse.org/package/show/devel:languages:python/python-lml>`_
+
diff --git a/.moban.d/requirements.txt.jj2 b/.moban.d/requirements.txt.jj2
new file mode 100644
index 0000000..8337402
--- /dev/null
+++ b/.moban.d/requirements.txt.jj2
@@ -0,0 +1,3 @@
+{% for dependency in dependencies: %}
+{{dependency}}
+{% endfor %}
diff --git a/.moban.d/test.sh.jj2 b/.moban.d/test.sh.jj2
new file mode 100644
index 0000000..b47acda
--- /dev/null
+++ b/.moban.d/test.sh.jj2
@@ -0,0 +1,19 @@
+{%block pretest%}
+{%endblock%}
+{%if external_module_library%}
+  {%set package=external_module_library%}
+{%else%}
+  {%if command_line_interface%}
+    {%set package=command_line_interface + '_cli' %}
+  {%else%}
+    {%set package=name%}
+  {%endif%}
+{%endif%}
+pip freeze
+cd tests/test_plugin
+python setup.py install
+cd -
+pytest tests --verbosity=3 --cov=lml --doctest-glob=*.rst && flake8 . --exclude=.moban.d,docs,setup.py {%block flake8_options%}--builtins=unicode,xrange,long{%endblock%}
+
+{%block posttest%}
+{%endblock%}
diff --git a/.moban.yml b/.moban.yml
new file mode 100644
index 0000000..6c48a69
--- /dev/null
+++ b/.moban.yml
@@ -0,0 +1,21 @@
+configuration:
+  template_dir:
+  - "git://github.com/moremoban/pypi-mobans.git?submodule=true&brach=dev!/statics"
+  - "git://github.com/moremoban/pypi-mobans.git?submodule=true&branch=dev!/templates"
+  - ".moban.d"
+  configuration: lml.yml
+targets:
+  - README.rst: CUSTOM_README.rst.jj2
+  - setup.py: custom_setup.py.jj2
+  - requirements.txt: requirements.txt.jj2
+  - "docs/source/conf.py": "docs/source/custom_conf.py.jj2"
+  - "docs/source/index.rst": "docs/source/custom_index.rst.jj2"
+  - test.sh: test.sh.jj2
+  - "lml/_version.py": _version.py.jj2
+  - output: CHANGELOG.rst
+    configuration: changelog.yml
+    template: CHANGELOG.rst.jj2
+  - ".github/workflows/pythonpublish.yml": "pythonpublish.yml"
+  - ".github/workflows/moban-update.yml": "moban-update.yml"
+  - CONTRIBUTORS.rst: CONTRIBUTORS.rst.jj2
+  - MANIFEST.in: MANIFEST.in.jj2
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..21426f2
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,15 @@
+sudo: false
+language: python
+notifications:
+  email: false
+python:
+  - 3.9-dev
+  - 3.8
+  - 3.7
+  - 3.6
+before_install:
+  - pip install -r tests/requirements.txt
+script:
+  - make test
+after_success:
+  codecov
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 5f0bf77..f6f22a6 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -1,65 +1,67 @@
 Change log
 ================================================================================
 
+0.1.0 - 21/10/2020
+--------------------------------------------------------------------------------
+
+**Updated**
+
+#. non class object can be a plugin too
+#. `#20 <https://github.com/python-lml/lml/issues/20>`_: When a plugin was not
+   installed, it now calls raise_exception method
+
 0.0.9 - 7/1/2019
 --------------------------------------------------------------------------------
 
-Updated
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+**Updated**
 
-#. `#11 <https://github.com/chfw/lml/issues/11>`_: more test contents for
+#. `#11 <https://github.com/python-lml/lml/issues/11>`_: more test contents for
    OpenSuse package validation
 
 0.0.8 - 4/1/2019
 --------------------------------------------------------------------------------
 
-Updated
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+**Updated**
 
-#. `#9 <https://github.com/chfw/lml/issues/9>`_: include tests, docs for
+#. `#9 <https://github.com/python-lml/lml/issues/9>`_: include tests, docs for
    OpenSuse package validation
 
 0.0.7 - 17/11/2018
 --------------------------------------------------------------------------------
 
-Fixed
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+**Fixed**
 
-#. `#8 <https://github.com/chfw/lml/issues/8>`_: get_primary_key will fail when
-   a module is loaded later
+#. `#8 <https://github.com/python-lml/lml/issues/8>`_: get_primary_key will fail
+   when a module is loaded later
 #. deprecated old style plugin scanner: scan_plugins
 
 0.0.6 - 07/11/2018
 --------------------------------------------------------------------------------
 
-Fixed
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+**Fixed**
 
 #. Revert the version 0.0.5 changes. Raise Import error and log the exception
 
 0.0.5 - 06/11/2018
 --------------------------------------------------------------------------------
 
-Fixed
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+**Fixed**
 
-#. `#6 <https://github.com/chfw/lml/issues/6>`_: Catch and Ignore
+#. `#6 <https://github.com/python-lml/lml/issues/6>`_: Catch and Ignore
    ModuleNotFoundError
 
 0.0.4 - 07.08.2018
 --------------------------------------------------------------------------------
 
-Added
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+**Added**
 
-#. `#4 <https://github.com/chfw/lml/issues/4>`_: to find plugin names with
+#. `#4 <https://github.com/python-lml/lml/issues/4>`_: to find plugin names with
    different naming patterns
 
 0.0.3 - 12/06/2018
 --------------------------------------------------------------------------------
 
-Added
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+**Added**
 
 #. `dict` can be a pluggable type in addition to `function`, `class`
 #. get primary tag of your tag, helping you find out which category of plugins
@@ -68,8 +70,7 @@ Added
 0.0.2 - 23/10/2017
 --------------------------------------------------------------------------------
 
-Updated
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+**Updated**
 
 #. `pyexcel#103 <https://github.com/pyexcel/pyexcel/issues/103>`_: include
    LICENSE in tar ball
@@ -77,7 +78,6 @@ Updated
 0.0.1 - 30/05/2017
 --------------------------------------------------------------------------------
 
-Added
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+**Added**
 
 #. First release
diff --git a/CONTRIBUTORS.rst b/CONTRIBUTORS.rst
new file mode 100644
index 0000000..4165d31
--- /dev/null
+++ b/CONTRIBUTORS.rst
@@ -0,0 +1,9 @@
+
+
+2 contributors
+================================================================================
+
+In alphabetical order:
+
+* `Ayan Banerjee <https://github.com/ayan-b>`_
+* `Matěj Cepl <https://github.com/mcepl>`_
diff --git a/MANIFEST.in b/MANIFEST.in
index c5f22c6..e86ae54 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -1,5 +1,6 @@
 include README.rst
 include LICENSE
 include CHANGELOG.rst
+include CONTRIBUTORS.rst
 recursive-include tests *
-include docs/source/*
+recursive-include docs *
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..f993b37
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,20 @@
+all: test
+
+test:
+	bash test.sh
+
+document:
+	python setup.py install
+	sphinx-build -b html docs/source/ docs/build
+
+spelling:
+	sphinx-build -b spelling docs/source/ docs/build/spelling
+
+uml:
+	plantuml -tsvg -o ../_static/images/ docs/source/uml/*.uml
+
+format:
+	isort -y $(find lml -name "*.py"|xargs echo) $(find tests -name "*.py"|xargs echo)
+	black -l 79 lml
+	black -l 79 tests
+	black -l 79 examples
diff --git a/PKG-INFO b/PKG-INFO
deleted file mode 100644
index 1d394bb..0000000
--- a/PKG-INFO
+++ /dev/null
@@ -1,163 +0,0 @@
-Metadata-Version: 1.1
-Name: lml
-Version: 0.0.9
-Summary: Load me later. A lazy plugin management system.
-Home-page: https://github.com/chfw/lml
-Author: C.W.
-Author-email: wangc_2011@hotmail.com
-License: New BSD
-Download-URL: https://github.com/chfw/lml/archive/0.0.9.tar.gz
-Description: ================================================================================
-        lml - Load me later. A lazy plugin management system.
-        ================================================================================
-        
-        .. image:: https://api.travis-ci.org/chfw/lml.svg
-           :target: http://travis-ci.org/chfw/lml
-        
-        .. image:: https://codecov.io/github/chfw/lml/coverage.png
-           :target: https://codecov.io/github/chfw/lml
-        
-        
-        .. image:: https://readthedocs.org/projects/lml/badge/?version=latest
-           :target: http://lml.readthedocs.org/en/latest/
-        
-        **lml** seamlessly finds the lml based plugins from your current python
-        environment but loads your plugins on demand. It is designed to support
-        plugins that have external dependencies, especially bulky and/or
-        memory hungry ones. lml provides the plugin management system only and the
-        plugin interface is on your shoulder.
-        
-        **lml** enabled applications helps your customers [#f1]_ in two ways:
-        
-        #. Your customers could cherry-pick the plugins from pypi per python environment.
-           They could remove a plugin using `pip uninstall` command.
-        #. Only the plugins used at runtime gets loaded into computer memory.
-        
-        When you would use **lml** to refactor your existing code, it aims to flatten the
-        complexity and to shrink the size of your bulky python library by
-        distributing the similar functionalities across its plugins. However, you as
-        the developer need to do the code refactoring by yourself and lml would lend you a hand.
-        
-        .. [#f1] the end developers who uses your library and packages achieve their
-                 objectives.
-        
-        Installation
-        ================================================================================
-        
-        
-        You can install lml via pip:
-        
-        .. code-block:: bash
-        
-            $ pip install lml
-        
-        
-        or clone it and install it:
-        
-        .. code-block:: bash
-        
-            $ git clone https://github.com/chfw/lml.git
-            $ cd lml
-            $ python setup.py install
-        
-        License
-        ================================================================================
-        
-        New BSD
-        
-        Change log
-        ================================================================================
-        
-        0.0.9 - 7/1/2019
-        --------------------------------------------------------------------------------
-        
-        Updated
-        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-        
-        #. `#11 <https://github.com/chfw/lml/issues/11>`_: more test contents for
-           OpenSuse package validation
-        
-        0.0.8 - 4/1/2019
-        --------------------------------------------------------------------------------
-        
-        Updated
-        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-        
-        #. `#9 <https://github.com/chfw/lml/issues/9>`_: include tests, docs for
-           OpenSuse package validation
-        
-        0.0.7 - 17/11/2018
-        --------------------------------------------------------------------------------
-        
-        Fixed
-        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-        
-        #. `#8 <https://github.com/chfw/lml/issues/8>`_: get_primary_key will fail when
-           a module is loaded later
-        #. deprecated old style plugin scanner: scan_plugins
-        
-        0.0.6 - 07/11/2018
-        --------------------------------------------------------------------------------
-        
-        Fixed
-        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-        
-        #. Revert the version 0.0.5 changes. Raise Import error and log the exception
-        
-        0.0.5 - 06/11/2018
-        --------------------------------------------------------------------------------
-        
-        Fixed
-        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-        
-        #. `#6 <https://github.com/chfw/lml/issues/6>`_: Catch and Ignore
-           ModuleNotFoundError
-        
-        0.0.4 - 07.08.2018
-        --------------------------------------------------------------------------------
-        
-        Added
-        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-        
-        #. `#4 <https://github.com/chfw/lml/issues/4>`_: to find plugin names with
-           different naming patterns
-        
-        0.0.3 - 12/06/2018
-        --------------------------------------------------------------------------------
-        
-        Added
-        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-        
-        #. `dict` can be a pluggable type in addition to `function`, `class`
-        #. get primary tag of your tag, helping you find out which category of plugins
-           your tag points to
-        
-        0.0.2 - 23/10/2017
-        --------------------------------------------------------------------------------
-        
-        Updated
-        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-        
-        #. `pyexcel#103 <https://github.com/pyexcel/pyexcel/issues/103>`_: include
-           LICENSE in tar ball
-        
-        0.0.1 - 30/05/2017
-        --------------------------------------------------------------------------------
-        
-        Added
-        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-        
-        #. First release
-        
-        
-Keywords: python
-Platform: UNKNOWN
-Classifier: Topic :: Software Development :: Libraries
-Classifier: Programming Language :: Python
-Classifier: Intended Audience :: Developers
-Classifier: Programming Language :: Python :: 2.6
-Classifier: Programming Language :: Python :: 2.7
-Classifier: Programming Language :: Python :: 3.3
-Classifier: Programming Language :: Python :: 3.4
-Classifier: Programming Language :: Python :: 3.5
-Classifier: Programming Language :: Python :: 3.6
diff --git a/README.rst b/README.rst
index 665349a..ecc9100 100644
--- a/README.rst
+++ b/README.rst
@@ -2,12 +2,25 @@
 lml - Load me later. A lazy plugin management system.
 ================================================================================
 
-.. image:: https://api.travis-ci.org/chfw/lml.svg
-   :target: http://travis-ci.org/chfw/lml
+.. image:: https://api.travis-ci.org/python-lml/lml.svg
+   :target: http://travis-ci.org/python-lml/lml
 
-.. image:: https://codecov.io/github/chfw/lml/coverage.png
-   :target: https://codecov.io/github/chfw/lml
+.. image:: https://codecov.io/github/python-lml/lml/coverage.png
+   :target: https://codecov.io/github/python-lml/lml
+.. image:: https://badge.fury.io/py/lml.svg
+   :target: https://pypi.org/project/lml
 
+.. image:: https://pepy.tech/badge/lml/month
+   :target: https://pepy.tech/project/lml/month
+
+.. image:: https://img.shields.io/github/stars/python-lml/lml.svg?style=social&maxAge=3600&label=Star
+    :target: https://github.com/python-lml/lml/stargazers
+
+.. image:: https://img.shields.io/static/v1?label=continuous%20templating&message=%E6%A8%A1%E7%89%88%E6%9B%B4%E6%96%B0&color=blue&style=flat-square
+    :target: https://moban.readthedocs.io/en/latest/#at-scale-continous-templating-for-open-source-projects
+
+.. image:: https://img.shields.io/static/v1?label=coding%20style&message=black&color=black&style=flat-square
+    :target: https://github.com/psf/black
 
 .. image:: https://readthedocs.org/projects/lml/badge/?version=latest
    :target: http://lml.readthedocs.org/en/latest/
@@ -32,6 +45,42 @@ the developer need to do the code refactoring by yourself and lml would lend you
 .. [#f1] the end developers who uses your library and packages achieve their
          objectives.
 
+
+Quick start
+================================================================================
+
+The following code tries to get you started quickly with **non-lazy** loading.
+
+.. code-block:: python
+
+    from lml.plugin import PluginInfo, PluginManager
+
+
+    @PluginInfo("cuisine", tags=["Portable Battery"])
+    class Boost(object):
+        def make(self, food=None, **keywords):
+            print("I can cook %s for robots" % food)
+
+
+    class CuisineManager(PluginManager):
+        def __init__(self):
+            PluginManager.__init__(self, "cuisine")
+
+        def get_a_plugin(self, food_name=None, **keywords):
+            return PluginManager.get_a_plugin(self, key=food_name, **keywords)
+
+
+    if __name__ == '__main__':
+        manager = CuisineManager()
+        chef = manager.get_a_plugin("Portable Battery")
+        chef.make()
+
+
+At a glance, above code simply replaces the Factory pattern should you write
+them without lml. What's not obvious is, that once you got hands-on with it,
+you can start work on how to do **lazy** loading.
+
+
 Installation
 ================================================================================
 
@@ -47,10 +96,26 @@ or clone it and install it:
 
 .. code-block:: bash
 
-    $ git clone https://github.com/chfw/lml.git
+    $ git clone https://github.com/python-lml/lml.git
     $ cd lml
     $ python setup.py install
 
+lml enabled project
+================================================================================
+
+Beyond the documentation above, here is a list of projects using lml:
+
+#. `pyexcel <https://github.com/pyexcel/pyexcel>`_
+#. `pyecharts <https://github.com/pyecharts/pyecharts>`_
+#. `moban <https://github.com/moremoban/moban>`_
+
+lml is available on these distributions:
+
+#. `ARCH linux <https://aur.archlinux.org/packages/python-lml/>`_
+#. `Conda forge <https://anaconda.org/conda-forge/lml>`_
+#. `OpenSuse <https://build.opensuse.org/package/show/devel:languages:python/python-lml>`_
+
+
 License
 ================================================================================
 
diff --git a/changelog.yml b/changelog.yml
new file mode 100644
index 0000000..f578917
--- /dev/null
+++ b/changelog.yml
@@ -0,0 +1,66 @@
+name: lml
+organisation: python-lml
+releases:
+- changes:
+  - action: Updated
+    details:
+    - "non class object can be a plugin too"
+    - "`#20`: When a plugin was not installed, it now calls raise_exception method"
+  date: 21/10/2020
+  version: 0.1.0
+- changes:
+  - action: Updated
+    details:
+    - "`#11`: more test contents for OpenSuse package validation"
+  date: 7/1/2019
+  version: 0.0.9
+- changes:
+  - action: Updated
+    details:
+    - "`#9`: include tests, docs for OpenSuse package validation"
+  date: 4/1/2019
+  version: 0.0.8
+- changes:
+  - action: Fixed
+    details:
+    - "`#8`: get_primary_key will fail when a module is loaded later"
+    - "deprecated old style plugin scanner: scan_plugins"
+  date: 17/11/2018
+  version: 0.0.7
+- changes:
+  - action: Fixed
+    details:
+    - "Revert the version 0.0.5 changes. Raise Import error and log the exception"
+  date: 07/11/2018
+  version: 0.0.6
+- changes:
+  - action: Fixed
+    details:
+    - "`#6`: Catch and Ignore ModuleNotFoundError"
+  date: 06/11/2018
+  version: 0.0.5
+- changes:
+  - action: Added
+    details:
+    - "`#4`: to find plugin names with different naming patterns"
+  date: 07.08.2018
+  version: 0.0.4
+- changes:
+  - action: Added
+    details:
+    - "`dict` can be a pluggable type in addition to `function`, `class`"
+    - get primary tag of your tag, helping you find out which category of plugins your tag points to
+  date: 12/06/2018
+  version: 0.0.3
+- changes:
+  - action: Updated
+    details:
+    - "`pyexcel#103 <https://github.com/pyexcel/pyexcel/issues/103>`_: include LICENSE in tar ball"
+  date: 23/10/2017
+  version: 0.0.2
+- changes:
+  - action: Added
+    details:
+    - First release
+  date: 30/05/2017
+  version: 0.0.1
diff --git a/docs/requirements.txt b/docs/requirements.txt
new file mode 100644
index 0000000..418c66f
--- /dev/null
+++ b/docs/requirements.txt
@@ -0,0 +1,2 @@
+sphinxcontrib-plantuml
+
diff --git a/docs/source/_static/images/loading_sequence.svg b/docs/source/_static/images/loading_sequence.svg
new file mode 100644
index 0000000..732fad4
--- /dev/null
+++ b/docs/source/_static/images/loading_sequence.svg
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" contentScriptType="application/ecmascript" contentStyleType="text/css" height="526px" preserveAspectRatio="none" style="width:895px;height:526px;" version="1.1" viewBox="0 0 895 526" width="895px" zoomAndPan="magnify"><defs><filter height="300%" id="f1fnvkqvarjehh" width="300%" x="-1" y="-1"><feGaussianBlur result="blurOut" stdDeviation="2.0"/><feColorMatrix in="blurOut" result="blurOut2" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .4 0"/><feOffset dx="4.0" dy="4.0" in="blurOut2" result="blurOut3"/><feBlend in="SourceGraphic" in2="blurOut3" mode="normal"/></filter></defs><g><line style="stroke: #A80036; stroke-width: 1.0; stroke-dasharray: 5.0,5.0;" x1="24" x2="24" y1="86.4883" y2="441.9043"/><line style="stroke: #A80036; stroke-width: 1.0; stroke-dasharray: 5.0,5.0;" x1="219" x2="219" y1="86.4883" y2="441.9043"/><line style="stroke: #A80036; stroke-width: 1.0; stroke-dasharray: 5.0,5.0;" x1="511" x2="511" y1="86.4883" y2="441.9043"/><line style="stroke: #A80036; stroke-width: 1.0; stroke-dasharray: 5.0,5.0;" x1="798.5" x2="798.5" y1="86.4883" y2="441.9043"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacingAndGlyphs" textLength="27" x="8" y="83.5352">bob</text><ellipse cx="24.5" cy="13" fill="#FEFECE" filter="url(#f1fnvkqvarjehh)" rx="8" ry="8" style="stroke: #A80036; stroke-width: 2.0;"/><path d="M24.5,21 L24.5,48 M11.5,29 L37.5,29 M24.5,48 L11.5,63 M24.5,48 L37.5,63 " fill="#FEFECE" filter="url(#f1fnvkqvarjehh)" style="stroke: #A80036; stroke-width: 2.0;"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacingAndGlyphs" textLength="27" x="8" y="454.4395">bob</text><ellipse cx="24.5" cy="467.3926" fill="#FEFECE" filter="url(#f1fnvkqvarjehh)" rx="8" ry="8" style="stroke: #A80036; stroke-width: 2.0;"/><path d="M24.5,475.3926 L24.5,502.3926 M11.5,483.3926 L37.5,483.3926 M24.5,502.3926 L11.5,517.3926 M24.5,502.3926 L37.5,517.3926 " fill="#FEFECE" filter="url(#f1fnvkqvarjehh)" style="stroke: #A80036; stroke-width: 2.0;"/><rect fill="#FEFECE" filter="url(#f1fnvkqvarjehh)" height="30.4883" style="stroke: #A80036; stroke-width: 1.5;" width="81" x="177" y="51"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacingAndGlyphs" textLength="67" x="184" y="71.5352">robotchef</text><rect fill="#FEFECE" filter="url(#f1fnvkqvarjehh)" height="30.4883" style="stroke: #A80036; stroke-width: 1.5;" width="81" x="177" y="440.9043"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacingAndGlyphs" textLength="67" x="184" y="461.4395">robotchef</text><rect fill="#FEFECE" filter="url(#f1fnvkqvarjehh)" height="30.4883" style="stroke: #A80036; stroke-width: 1.5;" width="35" x="492" y="51"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacingAndGlyphs" textLength="21" x="499" y="71.5352">lml</text><rect fill="#FEFECE" filter="url(#f1fnvkqvarjehh)" height="30.4883" style="stroke: #A80036; stroke-width: 1.5;" width="35" x="492" y="440.9043"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacingAndGlyphs" textLength="21" x="499" y="461.4395">lml</text><rect fill="#FEFECE" filter="url(#f1fnvkqvarjehh)" height="30.4883" style="stroke: #A80036; stroke-width: 1.5;" width="180" x="706.5" y="51"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacingAndGlyphs" textLength="166" x="713.5" y="71.5352">robotchef_britishcuisine</text><rect fill="#FEFECE" filter="url(#f1fnvkqvarjehh)" height="30.4883" style="stroke: #A80036; stroke-width: 1.5;" width="180" x="706.5" y="440.9043"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacingAndGlyphs" textLength="166" x="713.5" y="461.4395">robotchef_britishcuisine</text><polygon fill="#A80036" points="207.5,113.4883,217.5,117.4883,207.5,121.4883,211.5,117.4883" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="24.5" x2="213.5" y1="117.4883" y2="117.4883"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="171" x="31.5" y="113.0566">&gt; robotchef "Jacket Potato"</text><polygon fill="#A80036" points="499.5,142.7988,509.5,146.7988,499.5,150.7988,503.5,146.7988" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="219.5" x2="505.5" y1="146.7988" y2="146.7988"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="106" x="226.5" y="142.3672">scan for plugins.</text><polygon fill="#A80036" points="786.5,172.1094,796.5,176.1094,786.5,180.1094,790.5,176.1094" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="511.5" x2="792.5" y1="176.1094" y2="176.1094"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="200" x="518.5" y="171.6777">read plugin chain in the module</text><polygon fill="#A80036" points="522.5,201.4199,512.5,205.4199,522.5,209.4199,518.5,205.4199" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="516.5" x2="797.5" y1="205.4199" y2="205.4199"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="263" x="528.5" y="200.9883">I can help with "Jacket Potato" and others.</text><polygon fill="#A80036" points="230.5,230.7305,220.5,234.7305,230.5,238.7305,226.5,234.7305" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="224.5" x2="510.5" y1="234.7305" y2="234.7305"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="194" x="236.5" y="230.2988">read the built-in robot_cuisine</text><polygon fill="#A80036" points="499.5,260.041,509.5,264.041,499.5,268.041,503.5,264.041" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="219.5" x2="505.5" y1="264.041" y2="264.041"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="237" x="226.5" y="259.6094">built-in chef knows "Portable Battery"</text><polygon fill="#A80036" points="230.5,289.3516,220.5,293.3516,230.5,297.3516,226.5,293.3516" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.0; stroke-dasharray: 2.0,2.0;" x1="224.5" x2="510.5" y1="293.3516" y2="293.3516"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="92" x="236.5" y="288.9199">scanning done</text><polygon fill="#A80036" points="499.5,318.6621,509.5,322.6621,499.5,326.6621,503.5,322.6621" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="219.5" x2="505.5" y1="322.6621" y2="322.6621"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="268" x="226.5" y="318.2305">get me a plugin that knows "Jacket Potato"</text><polygon fill="#A80036" points="230.5,347.9727,220.5,351.9727,230.5,355.9727,226.5,351.9727" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="224.5" x2="510.5" y1="351.9727" y2="351.9727"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="267" x="236.5" y="347.541">robotchef_britishcuisine.bake.Bake can do</text><line style="stroke: #A80036; stroke-width: 1.0;" x1="219.5" x2="261.5" y1="381.5938" y2="381.5938"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="261.5" x2="261.5" y1="381.5938" y2="394.5938"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="220.5" x2="261.5" y1="394.5938" y2="394.5938"/><polygon fill="#A80036" points="230.5,390.5938,220.5,394.5938,230.5,398.5938,226.5,394.5938" style="stroke: #A80036; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="91" x="226.5" y="376.8516">make the food</text><polygon fill="#A80036" points="35.5,419.5938,25.5,423.5938,35.5,427.5938,31.5,423.5938" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="29.5" x2="218.5" y1="423.5938" y2="423.5938"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="160" x="41.5" y="419.1621">"I can bake Jacket Potato"</text><!--
+@startuml
+
+actor bob
+participant robotchef
+participant lml
+participant robotchef_britishcuisine
+
+bob -> robotchef : > robotchef "Jacket Potato"
+robotchef -> lml : scan for plugins.
+lml -> robotchef_britishcuisine : read plugin chain in the module
+robotchef_britishcuisine -> lml: I can help with "Jacket Potato" and others.
+lml -> robotchef : read the built-in robot_cuisine
+robotchef -> lml : built-in chef knows "Portable Battery"
+lml - -> robotchef : scanning done
+robotchef -> lml : get me a plugin that knows "Jacket Potato"
+lml -> robotchef : robotchef_britishcuisine.bake.Bake can do
+robotchef -> robotchef: make the food
+robotchef -> bob : "I can bake Jacket Potato"
+@enduml
+
+PlantUML version 1.2017.13(Wed May 10 17:52:33 BST 2017)
+(GPL source distribution)
+Java Runtime: Java(TM) SE Runtime Environment
+JVM: Java HotSpot(TM) 64-Bit Server VM
+Java Version: 1.8.0_131-b11
+Operating System: Mac OS X
+OS Version: 10.11.6
+Default Encoding: UTF-8
+Language: en
+Country: US
+--></g></svg>
\ No newline at end of file
diff --git a/docs/source/_static/images/robot_chef.svg b/docs/source/_static/images/robot_chef.svg
new file mode 100644
index 0000000..516e767
--- /dev/null
+++ b/docs/source/_static/images/robot_chef.svg
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" contentScriptType="application/ecmascript" contentStyleType="text/css" height="173px" preserveAspectRatio="none" style="width:257px;height:173px;" version="1.1" viewBox="0 0 257 173" width="257px" zoomAndPan="magnify"><defs><filter height="300%" id="f6jrfqvs2pt7p" width="300%" x="-1" y="-1"><feGaussianBlur result="blurOut" stdDeviation="2.0"/><feColorMatrix in="blurOut" result="blurOut2" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .4 0"/><feOffset dx="4.0" dy="4.0" in="blurOut2" result="blurOut3"/><feBlend in="SourceGraphic" in2="blurOut3" mode="normal"/></filter></defs><g><!--class Chef--><rect fill="#FEFECE" filter="url(#f6jrfqvs2pt7p)" height="48" id="Chef" style="stroke: #A80036; stroke-width: 1.5;" width="58" x="99.5" y="8"/><ellipse cx="114.5" cy="24" fill="#B4A7E5" rx="11" ry="11" style="stroke: #A80036; stroke-width: 1.0;"/><path d="M110.4277,19.7651 L110.4277,17.6069 L117.8071,17.6069 L117.8071,19.7651 L115.3418,19.7651 L115.3418,27.8418 L117.8071,27.8418 L117.8071,30 L110.4277,30 L110.4277,27.8418 L112.8931,27.8418 L112.8931,19.7651 Z "/><text fill="#000000" font-family="sans-serif" font-size="12" font-style="italic" lengthAdjust="spacingAndGlyphs" textLength="26" x="128.5" y="28.5352">Chef</text><line style="stroke: #A80036; stroke-width: 1.5;" x1="100.5" x2="156.5" y1="40" y2="40"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="100.5" x2="156.5" y1="48" y2="48"/><!--class Boost--><rect fill="#FEFECE" filter="url(#f6jrfqvs2pt7p)" height="48" id="Boost" style="stroke: #A80036; stroke-width: 1.5;" width="63" x="6" y="116"/><ellipse cx="21" cy="132" fill="#ADD1B2" rx="11" ry="11" style="stroke: #A80036; stroke-width: 1.0;"/><path d="M23.9731,137.6431 Q23.3921,137.9419 22.7529,138.0913 Q22.1138,138.2407 21.4082,138.2407 Q18.9014,138.2407 17.5815,136.5889 Q16.2617,134.937 16.2617,131.8159 Q16.2617,128.6865 17.5815,127.0347 Q18.9014,125.3828 21.4082,125.3828 Q22.1138,125.3828 22.7612,125.5322 Q23.4087,125.6816 23.9731,125.9805 L23.9731,128.7031 Q23.3423,128.1221 22.7488,127.8523 Q22.1553,127.5825 21.5244,127.5825 Q20.1797,127.5825 19.4949,128.6492 Q18.8101,129.7158 18.8101,131.8159 Q18.8101,133.9077 19.4949,134.9744 Q20.1797,136.041 21.5244,136.041 Q22.1553,136.041 22.7488,135.7712 Q23.3423,135.5015 23.9731,134.9204 Z "/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="31" x="35" y="136.5352">Boost</text><line style="stroke: #A80036; stroke-width: 1.5;" x1="7" x2="68" y1="148" y2="148"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="7" x2="68" y1="156" y2="156"/><!--class Fry--><rect fill="#FEFECE" filter="url(#f6jrfqvs2pt7p)" height="48" id="Fry" style="stroke: #A80036; stroke-width: 1.5;" width="49" x="104" y="116"/><ellipse cx="119" cy="132" fill="#ADD1B2" rx="11" ry="11" style="stroke: #A80036; stroke-width: 1.0;"/><path d="M121.9731,137.6431 Q121.3921,137.9419 120.7529,138.0913 Q120.1138,138.2407 119.4082,138.2407 Q116.9014,138.2407 115.5815,136.5889 Q114.2617,134.937 114.2617,131.8159 Q114.2617,128.6865 115.5815,127.0347 Q116.9014,125.3828 119.4082,125.3828 Q120.1138,125.3828 120.7612,125.5322 Q121.4087,125.6816 121.9731,125.9805 L121.9731,128.7031 Q121.3423,128.1221 120.7488,127.8523 Q120.1553,127.5825 119.5244,127.5825 Q118.1797,127.5825 117.4949,128.6492 Q116.8101,129.7158 116.8101,131.8159 Q116.8101,133.9077 117.4949,134.9744 Q118.1797,136.041 119.5244,136.041 Q120.1553,136.041 120.7488,135.7712 Q121.3423,135.5015 121.9731,134.9204 Z "/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="17" x="133" y="136.5352">Fry</text><line style="stroke: #A80036; stroke-width: 1.5;" x1="105" x2="152" y1="148" y2="148"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="105" x2="152" y1="156" y2="156"/><!--class Bake--><rect fill="#FEFECE" filter="url(#f6jrfqvs2pt7p)" height="48" id="Bake" style="stroke: #A80036; stroke-width: 1.5;" width="60" x="188.5" y="116"/><ellipse cx="203.5" cy="132" fill="#ADD1B2" rx="11" ry="11" style="stroke: #A80036; stroke-width: 1.0;"/><path d="M206.4731,137.6431 Q205.8921,137.9419 205.2529,138.0913 Q204.6138,138.2407 203.9082,138.2407 Q201.4014,138.2407 200.0815,136.5889 Q198.7617,134.937 198.7617,131.8159 Q198.7617,128.6865 200.0815,127.0347 Q201.4014,125.3828 203.9082,125.3828 Q204.6138,125.3828 205.2612,125.5322 Q205.9087,125.6816 206.4731,125.9805 L206.4731,128.7031 Q205.8423,128.1221 205.2488,127.8523 Q204.6553,127.5825 204.0244,127.5825 Q202.6797,127.5825 201.9949,128.6492 Q201.3101,129.7158 201.3101,131.8159 Q201.3101,133.9077 201.9949,134.9744 Q202.6797,136.041 204.0244,136.041 Q204.6553,136.041 205.2488,135.7712 Q205.8423,135.5015 206.4731,134.9204 Z "/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="28" x="217.5" y="136.5352">Bake</text><line style="stroke: #A80036; stroke-width: 1.5;" x1="189.5" x2="247.5" y1="148" y2="148"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="189.5" x2="247.5" y1="156" y2="156"/><!--link Chef to Boost--><path d="M94.8159,71.9767 C82.4038,86.7075 68.7313,102.9342 57.854,115.8436 " fill="none" id="Chef-Boost" style="stroke: #A80036; stroke-width: 1.0;"/><polygon fill="none" points="89.8376,67.0214,108.0778,56.2373,100.5438,76.0424,89.8376,67.0214" style="stroke: #A80036; stroke-width: 1.0;"/><!--link Chef to Fry--><path d="M128.5,76.2911 C128.5,89.8171 128.5,104.1835 128.5,115.8436 " fill="none" id="Chef-Fry" style="stroke: #A80036; stroke-width: 1.0;"/><polygon fill="none" points="121.5001,76.2373,128.5,56.2373,135.5001,76.2373,121.5001,76.2373" style="stroke: #A80036; stroke-width: 1.0;"/><!--link Chef to Bake--><path d="M161.8139,71.9767 C174.0896,86.7075 187.6119,102.9342 198.3697,115.8436 " fill="none" id="Chef-Bake" style="stroke: #A80036; stroke-width: 1.0;"/><polygon fill="none" points="156.1239,76.0831,148.6978,56.2373,166.879,67.1205,156.1239,76.0831" style="stroke: #A80036; stroke-width: 1.0;"/><!--
+@startuml
+
+Interface Chef
+
+Chef <|- - Boost
+Chef <|- - Fry
+Chef <|- - Bake
+
+@enduml
+
+PlantUML version 1.2017.13(Wed May 10 17:52:33 BST 2017)
+(GPL source distribution)
+Java Runtime: Java(TM) SE Runtime Environment
+JVM: Java HotSpot(TM) 64-Bit Server VM
+Java Version: 1.8.0_131-b11
+Operating System: Mac OS X
+OS Version: 10.11.6
+Default Encoding: UTF-8
+Language: en
+Country: US
+--></g></svg>
\ No newline at end of file
diff --git a/docs/source/_static/images/robotchef_allinone_lml.svg b/docs/source/_static/images/robotchef_allinone_lml.svg
new file mode 100644
index 0000000..61cebb2
--- /dev/null
+++ b/docs/source/_static/images/robotchef_allinone_lml.svg
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" contentScriptType="application/ecmascript" contentStyleType="text/css" height="480px" preserveAspectRatio="none" style="width:420px;height:480px;" version="1.1" viewBox="0 0 420 480" width="420px" zoomAndPan="magnify"><defs><filter height="300%" id="fgf4x7z0zsey5" width="300%" x="-1" y="-1"><feGaussianBlur result="blurOut" stdDeviation="2.0"/><feColorMatrix in="blurOut" result="blurOut2" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .4 0"/><feOffset dx="4.0" dy="4.0" in="blurOut2" result="blurOut3"/><feBlend in="SourceGraphic" in2="blurOut3" mode="normal"/></filter></defs><g><!--cluster lml--><polygon fill="#FFFFFF" filter="url(#fgf4x7z0zsey5)" points="14,16,44,16,51,38.4883,146,38.4883,146,364,14,364,14,16" style="stroke: #000000; stroke-width: 2.0;"/><line style="stroke: #000000; stroke-width: 2.0;" x1="14" x2="51" y1="38.4883" y2="38.4883"/><text fill="#000000" font-family="sans-serif" font-size="14" font-weight="bold" lengthAdjust="spacingAndGlyphs" textLength="24" x="18" y="31.5352">lml</text><!--cluster robotchef_allinone_lml--><polygon fill="#FFFFFF" filter="url(#fgf4x7z0zsey5)" points="154,146,325,146,332,168.4883,413,168.4883,413,473,154,473,154,146" style="stroke: #000000; stroke-width: 2.0;"/><line style="stroke: #000000; stroke-width: 2.0;" x1="154" x2="332" y1="168.4883" y2="168.4883"/><text fill="#000000" font-family="sans-serif" font-size="14" font-weight="bold" lengthAdjust="spacingAndGlyphs" textLength="165" x="158" y="161.5352">robotchef_allinone_lml</text><!--class PluginManager--><rect fill="#FEFECE" filter="url(#fgf4x7z0zsey5)" height="48" id="PluginManager" style="stroke: #A80036; stroke-width: 1.5;" width="116" x="22" y="43"/><ellipse cx="37" cy="59" fill="#ADD1B2" rx="11" ry="11" style="stroke: #A80036; stroke-width: 1.0;"/><path d="M39.9731,64.6431 Q39.3921,64.9419 38.7529,65.0913 Q38.1138,65.2407 37.4082,65.2407 Q34.9014,65.2407 33.5815,63.5889 Q32.2617,61.937 32.2617,58.8159 Q32.2617,55.6865 33.5815,54.0347 Q34.9014,52.3828 37.4082,52.3828 Q38.1138,52.3828 38.7612,52.5322 Q39.4087,52.6816 39.9731,52.9805 L39.9731,55.7031 Q39.3423,55.1221 38.7488,54.8523 Q38.1553,54.5825 37.5244,54.5825 Q36.1797,54.5825 35.4949,55.6492 Q34.8101,56.7158 34.8101,58.8159 Q34.8101,60.9077 35.4949,61.9744 Q36.1797,63.041 37.5244,63.041 Q38.1553,63.041 38.7488,62.7712 Q39.3423,62.5015 39.9731,61.9204 Z "/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="84" x="51" y="63.5352">PluginManager</text><line style="stroke: #A80036; stroke-width: 1.5;" x1="23" x2="137" y1="75" y2="75"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="23" x2="137" y1="83" y2="83"/><!--class PluginInfo--><rect fill="#FEFECE" filter="url(#fgf4x7z0zsey5)" height="48" id="PluginInfo" style="stroke: #A80036; stroke-width: 1.5;" width="87" x="50.5" y="308"/><ellipse cx="65.5" cy="324" fill="#ADD1B2" rx="11" ry="11" style="stroke: #A80036; stroke-width: 1.0;"/><path d="M68.4731,329.6431 Q67.8921,329.9419 67.2529,330.0913 Q66.6138,330.2407 65.9082,330.2407 Q63.4014,330.2407 62.0815,328.5889 Q60.7617,326.937 60.7617,323.8159 Q60.7617,320.6865 62.0815,319.0347 Q63.4014,317.3828 65.9082,317.3828 Q66.6138,317.3828 67.2612,317.5322 Q67.9087,317.6816 68.4731,317.9805 L68.4731,320.7031 Q67.8423,320.1221 67.2488,319.8523 Q66.6553,319.5825 66.0244,319.5825 Q64.6797,319.5825 63.9949,320.6492 Q63.3101,321.7158 63.3101,323.8159 Q63.3101,325.9077 63.9949,326.9744 Q64.6797,328.041 66.0244,328.041 Q66.6553,328.041 67.2488,327.7712 Q67.8423,327.5015 68.4731,326.9204 Z "/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="55" x="79.5" y="328.5352">PluginInfo</text><line style="stroke: #A80036; stroke-width: 1.5;" x1="51.5" x2="136.5" y1="340" y2="340"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="51.5" x2="136.5" y1="348" y2="348"/><!--class CuisineManager--><rect fill="#FEFECE" filter="url(#fgf4x7z0zsey5)" height="73.9102" id="CuisineManager" style="stroke: #A80036; stroke-width: 1.5;" width="123" x="274.5" y="173"/><ellipse cx="289.5" cy="189" fill="#ADD1B2" rx="11" ry="11" style="stroke: #A80036; stroke-width: 1.0;"/><path d="M292.4731,194.6431 Q291.8921,194.9419 291.2529,195.0913 Q290.6138,195.2407 289.9082,195.2407 Q287.4014,195.2407 286.0815,193.5889 Q284.7617,191.937 284.7617,188.8159 Q284.7617,185.6865 286.0815,184.0347 Q287.4014,182.3828 289.9082,182.3828 Q290.6138,182.3828 291.2612,182.5322 Q291.9087,182.6816 292.4731,182.9805 L292.4731,185.7031 Q291.8423,185.1221 291.2488,184.8523 Q290.6553,184.5825 290.0244,184.5825 Q288.6797,184.5825 287.9949,185.6492 Q287.3101,186.7158 287.3101,188.8159 Q287.3101,190.9077 287.9949,191.9744 Q288.6797,193.041 290.0244,193.041 Q290.6553,193.041 291.2488,192.7712 Q291.8423,192.5015 292.4731,191.9204 Z "/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="91" x="303.5" y="193.5352">CuisineManager</text><line style="stroke: #A80036; stroke-width: 1.5;" x1="275.5" x2="396.5" y1="205" y2="205"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="275.5" x2="396.5" y1="213" y2="213"/><ellipse cx="285.5" cy="224.9775" fill="#84BE84" rx="3" ry="3" style="stroke: #038048; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="77" x="294.5" y="227.6348">get_a_plugin()</text><ellipse cx="285.5" cy="237.9326" fill="#84BE84" rx="3" ry="3" style="stroke: #038048; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="93" x="294.5" y="240.5898">raise_exception()</text><!--class Chef--><rect fill="#FEFECE" filter="url(#fgf4x7z0zsey5)" height="60.9551" id="Chef" style="stroke: #A80036; stroke-width: 1.5;" width="62" x="177" y="179.5"/><ellipse cx="193.8" cy="195.5" fill="#B4A7E5" rx="11" ry="11" style="stroke: #A80036; stroke-width: 1.0;"/><path d="M189.7277,191.2651 L189.7277,189.1069 L197.1071,189.1069 L197.1071,191.2651 L194.6418,191.2651 L194.6418,199.3418 L197.1071,199.3418 L197.1071,201.5 L189.7277,201.5 L189.7277,199.3418 L192.1931,199.3418 L192.1931,191.2651 Z "/><text fill="#000000" font-family="sans-serif" font-size="12" font-style="italic" lengthAdjust="spacingAndGlyphs" textLength="26" x="208.2" y="200.0352">Chef</text><line style="stroke: #A80036; stroke-width: 1.5;" x1="178" x2="238" y1="211.5" y2="211.5"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="178" x2="238" y1="219.5" y2="219.5"/><ellipse cx="188" cy="231.4775" fill="#84BE84" rx="3" ry="3" style="stroke: #038048; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="36" x="197" y="234.1348">make()</text><!--class Boost--><rect fill="#FEFECE" filter="url(#fgf4x7z0zsey5)" height="48" id="Boost" style="stroke: #A80036; stroke-width: 1.5;" width="63" x="162.5" y="417"/><ellipse cx="177.5" cy="433" fill="#ADD1B2" rx="11" ry="11" style="stroke: #A80036; stroke-width: 1.0;"/><path d="M180.4731,438.6431 Q179.8921,438.9419 179.2529,439.0913 Q178.6138,439.2407 177.9082,439.2407 Q175.4014,439.2407 174.0815,437.5889 Q172.7617,435.937 172.7617,432.8159 Q172.7617,429.6865 174.0815,428.0347 Q175.4014,426.3828 177.9082,426.3828 Q178.6138,426.3828 179.2612,426.5322 Q179.9087,426.6816 180.4731,426.9805 L180.4731,429.7031 Q179.8423,429.1221 179.2488,428.8523 Q178.6553,428.5825 178.0244,428.5825 Q176.6797,428.5825 175.9949,429.6492 Q175.3101,430.7158 175.3101,432.8159 Q175.3101,434.9077 175.9949,435.9744 Q176.6797,437.041 178.0244,437.041 Q178.6553,437.041 179.2488,436.7712 Q179.8423,436.5015 180.4731,435.9204 Z "/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="31" x="191.5" y="437.5352">Boost</text><line style="stroke: #A80036; stroke-width: 1.5;" x1="163.5" x2="224.5" y1="449" y2="449"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="163.5" x2="224.5" y1="457" y2="457"/><!--class Fry--><rect fill="#FEFECE" filter="url(#fgf4x7z0zsey5)" height="48" id="Fry" style="stroke: #A80036; stroke-width: 1.5;" width="49" x="260.5" y="417"/><ellipse cx="275.5" cy="433" fill="#ADD1B2" rx="11" ry="11" style="stroke: #A80036; stroke-width: 1.0;"/><path d="M278.4731,438.6431 Q277.8921,438.9419 277.2529,439.0913 Q276.6138,439.2407 275.9082,439.2407 Q273.4014,439.2407 272.0815,437.5889 Q270.7617,435.937 270.7617,432.8159 Q270.7617,429.6865 272.0815,428.0347 Q273.4014,426.3828 275.9082,426.3828 Q276.6138,426.3828 277.2612,426.5322 Q277.9087,426.6816 278.4731,426.9805 L278.4731,429.7031 Q277.8423,429.1221 277.2488,428.8523 Q276.6553,428.5825 276.0244,428.5825 Q274.6797,428.5825 273.9949,429.6492 Q273.3101,430.7158 273.3101,432.8159 Q273.3101,434.9077 273.9949,435.9744 Q274.6797,437.041 276.0244,437.041 Q276.6553,437.041 277.2488,436.7712 Q277.8423,436.5015 278.4731,435.9204 Z "/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="17" x="289.5" y="437.5352">Fry</text><line style="stroke: #A80036; stroke-width: 1.5;" x1="261.5" x2="308.5" y1="449" y2="449"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="261.5" x2="308.5" y1="457" y2="457"/><!--class Bake--><rect fill="#FEFECE" filter="url(#fgf4x7z0zsey5)" height="48" id="Bake" style="stroke: #A80036; stroke-width: 1.5;" width="60" x="345" y="417"/><ellipse cx="360" cy="433" fill="#ADD1B2" rx="11" ry="11" style="stroke: #A80036; stroke-width: 1.0;"/><path d="M362.9731,438.6431 Q362.3921,438.9419 361.7529,439.0913 Q361.1138,439.2407 360.4082,439.2407 Q357.9014,439.2407 356.5815,437.5889 Q355.2617,435.937 355.2617,432.8159 Q355.2617,429.6865 356.5815,428.0347 Q357.9014,426.3828 360.4082,426.3828 Q361.1138,426.3828 361.7612,426.5322 Q362.4087,426.6816 362.9731,426.9805 L362.9731,429.7031 Q362.3423,429.1221 361.7488,428.8523 Q361.1553,428.5825 360.5244,428.5825 Q359.1797,428.5825 358.4949,429.6492 Q357.8101,430.7158 357.8101,432.8159 Q357.8101,434.9077 358.4949,435.9744 Q359.1797,437.041 360.5244,437.041 Q361.1553,437.041 361.7488,436.7712 Q362.3423,436.5015 362.9731,435.9204 Z "/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="28" x="374" y="437.5352">Bake</text><line style="stroke: #A80036; stroke-width: 1.5;" x1="346" x2="404" y1="449" y2="449"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="346" x2="404" y1="457" y2="457"/><!--link PluginManager to PluginInfo--><path d="M81.9783,104.447 C84.8997,159.7441 90.285,261.6801 92.7314,307.9863 " fill="none" id="PluginManager-PluginInfo" style="stroke: #A80036; stroke-width: 1.0;"/><polygon fill="#FFFFFF" points="81.292,91.4556,77.6141,97.6583,81.9251,103.4389,85.603,97.2362,81.292,91.4556" style="stroke: #A80036; stroke-width: 1.0;"/><!--link PluginManager to CuisineManager--><path d="M156.7735,96.1035 C188.7295,109.5183 225.6181,126.7449 257,146 C269.7882,153.8465 282.7936,163.5381 294.4621,172.9845 " fill="none" id="PluginManager-CuisineManager" style="stroke: #A80036; stroke-width: 1.0;"/><polygon fill="none" points="153.9641,102.5173,138.1089,88.4598,159.2699,89.5616,153.9641,102.5173" style="stroke: #A80036; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="45" x="239" y="134.5684">cuisine</text><!--link Chef to Boost--><path d="M204.9186,260.8439 C201.9821,309.295 197.6885,380.1403 195.4614,416.8861 " fill="none" id="Chef-Boost" style="stroke: #A80036; stroke-width: 1.0;"/><polygon fill="none" points="197.9437,260.2149,206.1409,240.675,211.9181,261.0619,197.9437,260.2149" style="stroke: #A80036; stroke-width: 1.0;"/><!--link Chef to Fry--><path d="M224.6224,259.8671 C240.7794,308.3382 264.6309,379.8926 276.962,416.8861 " fill="none" id="Chef-Fry" style="stroke: #A80036; stroke-width: 1.0;"/><polygon fill="none" points="217.9088,261.8623,218.225,240.675,231.1904,257.4351,217.9088,261.8623" style="stroke: #A80036; stroke-width: 1.0;"/><!--link Chef to Bake--><path d="M241.9597,256.9742 C277.0045,305.4493 330.2855,379.1494 357.567,416.8861 " fill="none" id="Chef-Bake" style="stroke: #A80036; stroke-width: 1.0;"/><polygon fill="none" points="236.221,260.9842,230.1763,240.675,247.5667,252.7819,236.221,260.9842" style="stroke: #A80036; stroke-width: 1.0;"/><!--link PluginInfo to Fry--><path d="M120.1156,356.042 C132.4644,366.5363 147.8088,378.3852 163,387 C196.0316,405.732 208.6267,400.8614 243,417 C248.7775,419.7126 254.8263,422.9298 260.4761,426.113 " fill="none" id="PluginInfo-Fry" style="stroke: #A80036; stroke-width: 1.0; stroke-dasharray: 7.0,7.0;"/><!--link PluginInfo to Bake--><path d="M130.5519,356.1486 C135.6292,359.0095 140.8662,361.7181 146,364 C222.5967,398.0458 248.9798,386.3566 327,417 C332.897,419.3161 339.0479,422.0952 344.9018,424.9278 " fill="none" id="PluginInfo-Bake" style="stroke: #A80036; stroke-width: 1.0; stroke-dasharray: 7.0,7.0;"/><!--link PluginInfo to Boost--><path d="M102.3837,356.2512 C106.6481,366.4256 112.5285,377.9657 120,387 C131.7575,401.2169 148.0536,413.6371 162.3611,422.9699 " fill="none" id="PluginInfo-Boost" style="stroke: #A80036; stroke-width: 1.0; stroke-dasharray: 7.0,7.0;"/><!--
+@startuml
+
+package lml {
+  PluginManager o- - PluginInfo
+}
+
+package robotchef_allinone_lml {
+  class CuisineManager {
+  + get_a_plugin()
+  + raise_exception()
+  }
+  interface Chef {
+  + make()
+  }
+  PluginManager <|- -  CuisineManager : cuisine
+  Chef <|- - Boost
+  Chef <|- - Fry
+  Chef <|- - Bake
+  PluginInfo .. Fry
+  PluginInfo .. Bake
+  PluginInfo .. Boost
+}
+
+
+@enduml
+
+PlantUML version 1.2017.13(Wed May 10 17:52:33 BST 2017)
+(GPL source distribution)
+Java Runtime: Java(TM) SE Runtime Environment
+JVM: Java HotSpot(TM) 64-Bit Server VM
+Java Version: 1.8.0_131-b11
+Operating System: Mac OS X
+OS Version: 10.11.6
+Default Encoding: UTF-8
+Language: en
+Country: US
+--></g></svg>
\ No newline at end of file
diff --git a/docs/source/_static/images/robotchef_api_crd.svg b/docs/source/_static/images/robotchef_api_crd.svg
new file mode 100644
index 0000000..ca86aa5
--- /dev/null
+++ b/docs/source/_static/images/robotchef_api_crd.svg
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" contentScriptType="application/ecmascript" contentStyleType="text/css" height="496px" preserveAspectRatio="none" style="width:664px;height:496px;" version="1.1" viewBox="0 0 664 496" width="664px" zoomAndPan="magnify"><defs><filter height="300%" id="f6ad7nhn1c42l" width="300%" x="-1" y="-1"><feGaussianBlur result="blurOut" stdDeviation="2.0"/><feColorMatrix in="blurOut" result="blurOut2" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .4 0"/><feOffset dx="4.0" dy="4.0" in="blurOut2" result="blurOut3"/><feBlend in="SourceGraphic" in2="blurOut3" mode="normal"/></filter></defs><g><!--cluster lml--><polygon fill="#FFFFFF" filter="url(#f6ad7nhn1c42l)" points="294,16.5,324,16.5,331,38.9883,657,38.9883,657,367,294,367,294,16.5" style="stroke: #000000; stroke-width: 2.0;"/><line style="stroke: #000000; stroke-width: 2.0;" x1="294" x2="331" y1="38.9883" y2="38.9883"/><text fill="#000000" font-family="sans-serif" font-size="14" font-weight="bold" lengthAdjust="spacingAndGlyphs" textLength="24" x="298" y="32.0352">lml</text><!--cluster robotchef_api--><polygon fill="#FFFFFF" filter="url(#f6ad7nhn1c42l)" points="14,149,118,149,125,171.4883,286,171.4883,286,489,14,489,14,149" style="stroke: #000000; stroke-width: 2.0;"/><line style="stroke: #000000; stroke-width: 2.0;" x1="14" x2="125" y1="171.4883" y2="171.4883"/><text fill="#000000" font-family="sans-serif" font-size="14" font-weight="bold" lengthAdjust="spacingAndGlyphs" textLength="98" x="18" y="164.5352">robotchef_api</text><!--cluster robotchef.robot_cuisine--><polygon fill="#FFFFFF" filter="url(#f6ad7nhn1c42l)" points="57,398,232,398,239,420.4883,242,420.4883,242,481,57,481,57,398" style="stroke: #000000; stroke-width: 2.0;"/><line style="stroke: #000000; stroke-width: 2.0;" x1="57" x2="239" y1="420.4883" y2="420.4883"/><text fill="#000000" font-family="sans-serif" font-size="14" font-weight="bold" lengthAdjust="spacingAndGlyphs" textLength="169" x="61" y="413.5352">robotchef.robot_cuisine</text><!--cluster robotchef_britishcuisine--><polygon fill="#FFFFFF" filter="url(#f6ad7nhn1c42l)" points="294,398,475,398,482,420.4883,485,420.4883,485,481,294,481,294,398" style="stroke: #000000; stroke-width: 2.0;"/><line style="stroke: #000000; stroke-width: 2.0;" x1="294" x2="482" y1="420.4883" y2="420.4883"/><text fill="#000000" font-family="sans-serif" font-size="14" font-weight="bold" lengthAdjust="spacingAndGlyphs" textLength="175" x="298" y="413.5352">robotchef_britishcuisine</text><!--class PluginManager--><rect fill="#FEFECE" filter="url(#f6ad7nhn1c42l)" height="48" id="PluginManager" style="stroke: #A80036; stroke-width: 1.5;" width="116" x="304" y="43.5"/><ellipse cx="319" cy="59.5" fill="#ADD1B2" rx="11" ry="11" style="stroke: #A80036; stroke-width: 1.0;"/><path d="M321.9731,65.1431 Q321.3921,65.4419 320.7529,65.5913 Q320.1138,65.7407 319.4082,65.7407 Q316.9014,65.7407 315.5815,64.0889 Q314.2617,62.437 314.2617,59.3159 Q314.2617,56.1865 315.5815,54.5347 Q316.9014,52.8828 319.4082,52.8828 Q320.1138,52.8828 320.7612,53.0322 Q321.4087,53.1816 321.9731,53.4805 L321.9731,56.2031 Q321.3423,55.6221 320.7488,55.3523 Q320.1553,55.0825 319.5244,55.0825 Q318.1797,55.0825 317.4949,56.1492 Q316.8101,57.2158 316.8101,59.3159 Q316.8101,61.4077 317.4949,62.4744 Q318.1797,63.541 319.5244,63.541 Q320.1553,63.541 320.7488,63.2712 Q321.3423,63.0015 321.9731,62.4204 Z "/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="84" x="333" y="64.0352">PluginManager</text><line style="stroke: #A80036; stroke-width: 1.5;" x1="305" x2="419" y1="75.5" y2="75.5"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="305" x2="419" y1="83.5" y2="83.5"/><!--class PluginInfoChain--><rect fill="#FEFECE" filter="url(#f6ad7nhn1c42l)" height="48" id="PluginInfoChain" style="stroke: #A80036; stroke-width: 1.5;" width="119" x="302.5" y="311"/><ellipse cx="317.5" cy="327" fill="#ADD1B2" rx="11" ry="11" style="stroke: #A80036; stroke-width: 1.0;"/><path d="M320.4731,332.6431 Q319.8921,332.9419 319.2529,333.0913 Q318.6138,333.2407 317.9082,333.2407 Q315.4014,333.2407 314.0815,331.5889 Q312.7617,329.937 312.7617,326.8159 Q312.7617,323.6865 314.0815,322.0347 Q315.4014,320.3828 317.9082,320.3828 Q318.6138,320.3828 319.2612,320.5322 Q319.9087,320.6816 320.4731,320.9805 L320.4731,323.7031 Q319.8423,323.1221 319.2488,322.8523 Q318.6553,322.5825 318.0244,322.5825 Q316.6797,322.5825 315.9949,323.6492 Q315.3101,324.7158 315.3101,326.8159 Q315.3101,328.9077 315.9949,329.9744 Q316.6797,331.041 318.0244,331.041 Q318.6553,331.041 319.2488,330.7712 Q319.8423,330.5015 320.4731,329.9204 Z "/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="87" x="331.5" y="331.5352">PluginInfoChain</text><line style="stroke: #A80036; stroke-width: 1.5;" x1="303.5" x2="420.5" y1="343" y2="343"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="303.5" x2="420.5" y1="351" y2="351"/><!--class PluginInfo--><rect fill="#FEFECE" filter="url(#f6ad7nhn1c42l)" height="48" id="PluginInfo" style="stroke: #A80036; stroke-width: 1.5;" width="87" x="561.5" y="311"/><ellipse cx="576.5" cy="327" fill="#ADD1B2" rx="11" ry="11" style="stroke: #A80036; stroke-width: 1.0;"/><path d="M579.4731,332.6431 Q578.8921,332.9419 578.2529,333.0913 Q577.6138,333.2407 576.9082,333.2407 Q574.4014,333.2407 573.0815,331.5889 Q571.7617,329.937 571.7617,326.8159 Q571.7617,323.6865 573.0815,322.0347 Q574.4014,320.3828 576.9082,320.3828 Q577.6138,320.3828 578.2612,320.5322 Q578.9087,320.6816 579.4731,320.9805 L579.4731,323.7031 Q578.8423,323.1221 578.2488,322.8523 Q577.6553,322.5825 577.0244,322.5825 Q575.6797,322.5825 574.9949,323.6492 Q574.3101,324.7158 574.3101,326.8159 Q574.3101,328.9077 574.9949,329.9744 Q575.6797,331.041 577.0244,331.041 Q577.6553,331.041 578.2488,330.7712 Q578.8423,330.5015 579.4731,329.9204 Z "/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="55" x="590.5" y="331.5352">PluginInfo</text><line style="stroke: #A80036; stroke-width: 1.5;" x1="562.5" x2="647.5" y1="343" y2="343"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="562.5" x2="647.5" y1="351" y2="351"/><!--class CuisineManager--><rect fill="#FEFECE" filter="url(#f6ad7nhn1c42l)" height="73.9102" id="CuisineManager" style="stroke: #A80036; stroke-width: 1.5;" width="123" x="154.5" y="176"/><ellipse cx="169.5" cy="192" fill="#ADD1B2" rx="11" ry="11" style="stroke: #A80036; stroke-width: 1.0;"/><path d="M172.4731,197.6431 Q171.8921,197.9419 171.2529,198.0913 Q170.6138,198.2407 169.9082,198.2407 Q167.4014,198.2407 166.0815,196.5889 Q164.7617,194.937 164.7617,191.8159 Q164.7617,188.6865 166.0815,187.0347 Q167.4014,185.3828 169.9082,185.3828 Q170.6138,185.3828 171.2612,185.5322 Q171.9087,185.6816 172.4731,185.9805 L172.4731,188.7031 Q171.8423,188.1221 171.2488,187.8523 Q170.6553,187.5825 170.0244,187.5825 Q168.6797,187.5825 167.9949,188.6492 Q167.3101,189.7158 167.3101,191.8159 Q167.3101,193.9077 167.9949,194.9744 Q168.6797,196.041 170.0244,196.041 Q170.6553,196.041 171.2488,195.7712 Q171.8423,195.5015 172.4731,194.9204 Z "/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="91" x="183.5" y="196.5352">CuisineManager</text><line style="stroke: #A80036; stroke-width: 1.5;" x1="155.5" x2="276.5" y1="208" y2="208"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="155.5" x2="276.5" y1="216" y2="216"/><ellipse cx="165.5" cy="227.9775" fill="#84BE84" rx="3" ry="3" style="stroke: #038048; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="77" x="174.5" y="230.6348">get_a_plugin()</text><ellipse cx="165.5" cy="240.9326" fill="#84BE84" rx="3" ry="3" style="stroke: #038048; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="93" x="174.5" y="243.5898">raise_exception()</text><!--class Chef--><rect fill="#FEFECE" filter="url(#f6ad7nhn1c42l)" height="60.9551" id="Chef" style="stroke: #A80036; stroke-width: 1.5;" width="62" x="22" y="182.5"/><ellipse cx="38.8" cy="198.5" fill="#B4A7E5" rx="11" ry="11" style="stroke: #A80036; stroke-width: 1.0;"/><path d="M34.7277,194.2651 L34.7277,192.1069 L42.1071,192.1069 L42.1071,194.2651 L39.6418,194.2651 L39.6418,202.3418 L42.1071,202.3418 L42.1071,204.5 L34.7277,204.5 L34.7277,202.3418 L37.1931,202.3418 L37.1931,194.2651 Z "/><text fill="#000000" font-family="sans-serif" font-size="12" font-style="italic" lengthAdjust="spacingAndGlyphs" textLength="26" x="53.2" y="203.0352">Chef</text><line style="stroke: #A80036; stroke-width: 1.5;" x1="23" x2="83" y1="214.5" y2="214.5"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="23" x2="83" y1="222.5" y2="222.5"/><ellipse cx="33" cy="234.4775" fill="#84BE84" rx="3" ry="3" style="stroke: #038048; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="36" x="42" y="237.1348">make()</text><!--class Boost--><rect fill="#FEFECE" filter="url(#f6ad7nhn1c42l)" height="48" id="Boost" style="stroke: #A80036; stroke-width: 1.5;" width="63" x="113.5" y="425"/><ellipse cx="128.5" cy="441" fill="#ADD1B2" rx="11" ry="11" style="stroke: #A80036; stroke-width: 1.0;"/><path d="M131.4731,446.6431 Q130.8921,446.9419 130.2529,447.0913 Q129.6138,447.2407 128.9082,447.2407 Q126.4014,447.2407 125.0815,445.5889 Q123.7617,443.937 123.7617,440.8159 Q123.7617,437.6865 125.0815,436.0347 Q126.4014,434.3828 128.9082,434.3828 Q129.6138,434.3828 130.2612,434.5322 Q130.9087,434.6816 131.4731,434.9805 L131.4731,437.7031 Q130.8423,437.1221 130.2488,436.8523 Q129.6553,436.5825 129.0244,436.5825 Q127.6797,436.5825 126.9949,437.6492 Q126.3101,438.7158 126.3101,440.8159 Q126.3101,442.9077 126.9949,443.9744 Q127.6797,445.041 129.0244,445.041 Q129.6553,445.041 130.2488,444.7712 Q130.8423,444.5015 131.4731,443.9204 Z "/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="31" x="142.5" y="445.5352">Boost</text><line style="stroke: #A80036; stroke-width: 1.5;" x1="114.5" x2="175.5" y1="457" y2="457"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="114.5" x2="175.5" y1="465" y2="465"/><!--class Fry--><rect fill="#FEFECE" filter="url(#f6ad7nhn1c42l)" height="48" id="Fry" style="stroke: #A80036; stroke-width: 1.5;" width="49" x="302.5" y="425"/><ellipse cx="317.5" cy="441" fill="#ADD1B2" rx="11" ry="11" style="stroke: #A80036; stroke-width: 1.0;"/><path d="M320.4731,446.6431 Q319.8921,446.9419 319.2529,447.0913 Q318.6138,447.2407 317.9082,447.2407 Q315.4014,447.2407 314.0815,445.5889 Q312.7617,443.937 312.7617,440.8159 Q312.7617,437.6865 314.0815,436.0347 Q315.4014,434.3828 317.9082,434.3828 Q318.6138,434.3828 319.2612,434.5322 Q319.9087,434.6816 320.4731,434.9805 L320.4731,437.7031 Q319.8423,437.1221 319.2488,436.8523 Q318.6553,436.5825 318.0244,436.5825 Q316.6797,436.5825 315.9949,437.6492 Q315.3101,438.7158 315.3101,440.8159 Q315.3101,442.9077 315.9949,443.9744 Q316.6797,445.041 318.0244,445.041 Q318.6553,445.041 319.2488,444.7712 Q319.8423,444.5015 320.4731,443.9204 Z "/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="17" x="331.5" y="445.5352">Fry</text><line style="stroke: #A80036; stroke-width: 1.5;" x1="303.5" x2="350.5" y1="457" y2="457"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="303.5" x2="350.5" y1="465" y2="465"/><!--class Bake--><rect fill="#FEFECE" filter="url(#f6ad7nhn1c42l)" height="48" id="Bake" style="stroke: #A80036; stroke-width: 1.5;" width="60" x="387" y="425"/><ellipse cx="402" cy="441" fill="#ADD1B2" rx="11" ry="11" style="stroke: #A80036; stroke-width: 1.0;"/><path d="M404.9731,446.6431 Q404.3921,446.9419 403.7529,447.0913 Q403.1138,447.2407 402.4082,447.2407 Q399.9014,447.2407 398.5815,445.5889 Q397.2617,443.937 397.2617,440.8159 Q397.2617,437.6865 398.5815,436.0347 Q399.9014,434.3828 402.4082,434.3828 Q403.1138,434.3828 403.7612,434.5322 Q404.4087,434.6816 404.9731,434.9805 L404.9731,437.7031 Q404.3423,437.1221 403.7488,436.8523 Q403.1553,436.5825 402.5244,436.5825 Q401.1797,436.5825 400.4949,437.6492 Q399.8101,438.7158 399.8101,440.8159 Q399.8101,442.9077 400.4949,443.9744 Q401.1797,445.041 402.5244,445.041 Q403.1553,445.041 403.7488,444.7712 Q404.3423,444.5015 404.9731,443.9204 Z "/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="28" x="416" y="445.5352">Bake</text><line style="stroke: #A80036; stroke-width: 1.5;" x1="388" x2="446" y1="457" y2="457"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="388" x2="446" y1="465" y2="465"/><polygon fill="#FFFFFF" filter="url(#f6ad7nhn1c42l)" points="62.5,41,161.5,41,168.5,63.4883,175.5,63.4883,175.5,93.9766,62.5,93.9766,62.5,41" style="stroke: #000000; stroke-width: 2.0;"/><line style="stroke: #000000; stroke-width: 2.0;" x1="62.5" x2="168.5" y1="63.4883" y2="63.4883"/><text fill="#000000" font-family="sans-serif" font-size="14" font-weight="bold" lengthAdjust="spacingAndGlyphs" textLength="93" x="66.5" y="56.5352">robotchef_v2</text><!--link PluginManager to PluginInfoChain--><path d="M362,91.7106 C362,142.511 362,259.7309 362,310.6513 " fill="none" id="PluginManager-PluginInfoChain" style="stroke: #A80036; stroke-width: 1.0; stroke-dasharray: 7.0,7.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="128" x="363" y="218.0684">registers plugin info</text><!--link PluginManager to PluginInfo--><path d="M428.7615,97.7313 C453.1727,111.0197 479.7421,128.3422 500,149 C547.7724,197.7153 581.1151,272.4903 596.0916,310.6977 " fill="none" id="PluginManager-PluginInfo" style="stroke: #A80036; stroke-width: 1.0;"/><polygon fill="#FFFFFF" points="416.9883,91.535,420.4349,97.8691,427.6074,97.1238,424.1608,90.7897,416.9883,91.535" style="stroke: #A80036; stroke-width: 1.0;"/><!--link PluginInfoChain to PluginInfo--><path d="M421.8008,335 C468.3162,335 514.8316,335 561.3471,335 " fill="none" id="PluginInfoChain-PluginInfo" style="stroke: #A80036; stroke-width: 1.0;"/><!--link PluginManager to CuisineManager--><path d="M323.5085,105.8596 C301.8029,127.4909 274.8106,154.3908 253.3025,175.8252 " fill="none" id="PluginManager-CuisineManager" style="stroke: #A80036; stroke-width: 1.0;"/><polygon fill="none" points="318.7834,100.686,337.8911,91.5264,328.6659,110.6025,318.7834,100.686" style="stroke: #A80036; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="45" x="303" y="137.5684">cuisine</text><!--link Chef to Boost--><path d="M68.4346,262.6835 C80.0468,298.5379 96.9972,347.8507 115,390 C120.0101,401.73 126.3157,414.3801 131.8513,424.9471 " fill="none" id="Chef-Boost" style="stroke: #A80036; stroke-width: 1.0;"/><polygon fill="none" points="61.7352,264.715,62.3252,243.5336,75.0729,260.4599,61.7352,264.715" style="stroke: #A80036; stroke-width: 1.0;"/><!--link PluginInfoChain to Boost--><path d="M316.245,359.0372 C274.3403,381.0516 213.4105,413.0608 176.6548,432.3703 " fill="none" id="PluginInfoChain-Boost" style="stroke: #A80036; stroke-width: 1.0; stroke-dasharray: 7.0,7.0;"/><!--link Chef to Fry--><path d="M85.1916,260.114 C115.2232,300.4931 163.6283,357.1833 219,390 C231.2409,397.2547 237.0004,392.2138 250,398 C268.604,406.2807 287.6997,418.897 302.2207,429.5092 " fill="none" id="Chef-Fry" style="stroke: #A80036; stroke-width: 1.0;"/><polygon fill="none" points="79.3384,263.9656,73.2911,243.6572,90.683,255.762,79.3384,263.9656" style="stroke: #A80036; stroke-width: 1.0;"/><!--link Chef to Bake--><path d="M100.482,249.6371 C100.6549,249.7584 100.8276,249.8794 101,250 C180.7225,305.7568 198.8567,323.7503 286,367 C321.2726,384.506 336.2044,376.204 369,398 C379.9366,405.2685 390.1885,415.4811 398.3868,424.8601 " fill="none" id="Chef-Bake" style="stroke: #A80036; stroke-width: 1.0;"/><polygon fill="none" points="96.189,255.1696,84.188,237.7061,104.4601,243.874,96.189,255.1696" style="stroke: #A80036; stroke-width: 1.0;"/><!--link PluginInfoChain to Fry--><path d="M354.5774,359.1765 C348.6378,378.5227 340.3487,405.5214 334.4119,424.8584 " fill="none" id="PluginInfoChain-Fry" style="stroke: #A80036; stroke-width: 1.0; stroke-dasharray: 7.0,7.0;"/><!--link PluginInfoChain to Bake--><path d="M373.6641,359.1765 C382.9978,378.5227 396.0235,405.5214 405.3527,424.8584 " fill="none" id="PluginInfoChain-Bake" style="stroke: #A80036; stroke-width: 1.0; stroke-dasharray: 7.0,7.0;"/><!--link robotchef_v2 to robotchef_api--><path d="M119,109.409 C119,119.5876 119,130.7546 119,141.8711 C119,143.2607 119,144.6494 119,146.0354 C119,146.7284 119,147.4207 119,148.112 C119,148.2848 119,148.4576 119,148.6303 " fill="none" id="robotchef_v2-robotchef_api" style="stroke: #A80036; stroke-width: 1.0;"/><ellipse cx="119.0001" cy="102.1869" fill="#FFFFFF" rx="8" ry="8" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="119.0002" x2="119" y1="110.1869" y2="94.1869"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="111.0001" x2="127.0001" y1="102.187" y2="102.1868"/><!--
+@startuml
+
+
+package lml {
+  PluginManager .. PluginInfoChain : registers plugin info
+  PluginManager o- - PluginInfo
+  PluginInfoChain -right- PluginInfo
+}
+
+package robotchef_api {
+  class CuisineManager {
+  + get_a_plugin()
+  + raise_exception()
+  }
+  interface Chef {
+  + make()
+  }
+  PluginManager <|- -  CuisineManager : cuisine
+  package robotchef.robot_cuisine {
+    Chef <|- - Boost
+    PluginInfoChain .. Boost
+  }
+}
+
+package robotchef_britishcuisine {
+  Chef <|- - Fry
+  Chef <|- - Bake
+  PluginInfoChain .. Fry
+  PluginInfoChain .. Bake
+}
+
+package robotchef_v2 {
+}
+
+robotchef_v2 +- - robotchef_api
+
+@enduml
+
+PlantUML version 1.2017.13(Wed May 10 17:52:33 BST 2017)
+(GPL source distribution)
+Java Runtime: Java(TM) SE Runtime Environment
+JVM: Java HotSpot(TM) 64-Bit Server VM
+Java Version: 1.8.0_131-b11
+Operating System: Mac OS X
+OS Version: 10.11.6
+Default Encoding: UTF-8
+Language: en
+Country: US
+--></g></svg>
\ No newline at end of file
diff --git a/docs/source/_static/images/robotchef_crd.svg b/docs/source/_static/images/robotchef_crd.svg
new file mode 100644
index 0000000..f6b1b3a
--- /dev/null
+++ b/docs/source/_static/images/robotchef_crd.svg
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" contentScriptType="application/ecmascript" contentStyleType="text/css" height="493px" preserveAspectRatio="none" style="width:629px;height:493px;" version="1.1" viewBox="0 0 629 493" width="629px" zoomAndPan="magnify"><defs><filter height="300%" id="ftjlkw6cxn2mj" width="300%" x="-1" y="-1"><feGaussianBlur result="blurOut" stdDeviation="2.0"/><feColorMatrix in="blurOut" result="blurOut2" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .4 0"/><feOffset dx="4.0" dy="4.0" in="blurOut2" result="blurOut3"/><feBlend in="SourceGraphic" in2="blurOut3" mode="normal"/></filter></defs><g><!--cluster lml--><polygon fill="#FFFFFF" filter="url(#ftjlkw6cxn2mj)" points="259,16,289,16,296,38.4883,622,38.4883,622,364,259,364,259,16" style="stroke: #000000; stroke-width: 2.0;"/><line style="stroke: #000000; stroke-width: 2.0;" x1="259" x2="296" y1="38.4883" y2="38.4883"/><text fill="#000000" font-family="sans-serif" font-size="14" font-weight="bold" lengthAdjust="spacingAndGlyphs" textLength="24" x="263" y="31.5352">lml</text><!--cluster robotchef--><polygon fill="#FFFFFF" filter="url(#ftjlkw6cxn2mj)" points="14,146,89,146,96,168.4883,251,168.4883,251,486,14,486,14,146" style="stroke: #000000; stroke-width: 2.0;"/><line style="stroke: #000000; stroke-width: 2.0;" x1="14" x2="96" y1="168.4883" y2="168.4883"/><text fill="#000000" font-family="sans-serif" font-size="14" font-weight="bold" lengthAdjust="spacingAndGlyphs" textLength="69" x="18" y="161.5352">robotchef</text><!--cluster robotchef.robot_cuisine--><polygon fill="#FFFFFF" filter="url(#ftjlkw6cxn2mj)" points="40,395,215,395,222,417.4883,225,417.4883,225,478,40,478,40,395" style="stroke: #000000; stroke-width: 2.0;"/><line style="stroke: #000000; stroke-width: 2.0;" x1="40" x2="222" y1="417.4883" y2="417.4883"/><text fill="#000000" font-family="sans-serif" font-size="14" font-weight="bold" lengthAdjust="spacingAndGlyphs" textLength="169" x="44" y="410.5352">robotchef.robot_cuisine</text><!--cluster robotchef_britishcuisine--><polygon fill="#FFFFFF" filter="url(#ftjlkw6cxn2mj)" points="259,395,440,395,447,417.4883,450,417.4883,450,478,259,478,259,395" style="stroke: #000000; stroke-width: 2.0;"/><line style="stroke: #000000; stroke-width: 2.0;" x1="259" x2="447" y1="417.4883" y2="417.4883"/><text fill="#000000" font-family="sans-serif" font-size="14" font-weight="bold" lengthAdjust="spacingAndGlyphs" textLength="175" x="263" y="410.5352">robotchef_britishcuisine</text><!--class PluginManager--><rect fill="#FEFECE" filter="url(#ftjlkw6cxn2mj)" height="48" id="PluginManager" style="stroke: #A80036; stroke-width: 1.5;" width="116" x="269" y="43"/><ellipse cx="284" cy="59" fill="#ADD1B2" rx="11" ry="11" style="stroke: #A80036; stroke-width: 1.0;"/><path d="M286.9731,64.6431 Q286.3921,64.9419 285.7529,65.0913 Q285.1138,65.2407 284.4082,65.2407 Q281.9014,65.2407 280.5815,63.5889 Q279.2617,61.937 279.2617,58.8159 Q279.2617,55.6865 280.5815,54.0347 Q281.9014,52.3828 284.4082,52.3828 Q285.1138,52.3828 285.7612,52.5322 Q286.4087,52.6816 286.9731,52.9805 L286.9731,55.7031 Q286.3423,55.1221 285.7488,54.8523 Q285.1553,54.5825 284.5244,54.5825 Q283.1797,54.5825 282.4949,55.6492 Q281.8101,56.7158 281.8101,58.8159 Q281.8101,60.9077 282.4949,61.9744 Q283.1797,63.041 284.5244,63.041 Q285.1553,63.041 285.7488,62.7712 Q286.3423,62.5015 286.9731,61.9204 Z "/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="84" x="298" y="63.5352">PluginManager</text><line style="stroke: #A80036; stroke-width: 1.5;" x1="270" x2="384" y1="75" y2="75"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="270" x2="384" y1="83" y2="83"/><!--class PluginInfoChain--><rect fill="#FEFECE" filter="url(#ftjlkw6cxn2mj)" height="48" id="PluginInfoChain" style="stroke: #A80036; stroke-width: 1.5;" width="119" x="267.5" y="308"/><ellipse cx="282.5" cy="324" fill="#ADD1B2" rx="11" ry="11" style="stroke: #A80036; stroke-width: 1.0;"/><path d="M285.4731,329.6431 Q284.8921,329.9419 284.2529,330.0913 Q283.6138,330.2407 282.9082,330.2407 Q280.4014,330.2407 279.0815,328.5889 Q277.7617,326.937 277.7617,323.8159 Q277.7617,320.6865 279.0815,319.0347 Q280.4014,317.3828 282.9082,317.3828 Q283.6138,317.3828 284.2612,317.5322 Q284.9087,317.6816 285.4731,317.9805 L285.4731,320.7031 Q284.8423,320.1221 284.2488,319.8523 Q283.6553,319.5825 283.0244,319.5825 Q281.6797,319.5825 280.9949,320.6492 Q280.3101,321.7158 280.3101,323.8159 Q280.3101,325.9077 280.9949,326.9744 Q281.6797,328.041 283.0244,328.041 Q283.6553,328.041 284.2488,327.7712 Q284.8423,327.5015 285.4731,326.9204 Z "/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="87" x="296.5" y="328.5352">PluginInfoChain</text><line style="stroke: #A80036; stroke-width: 1.5;" x1="268.5" x2="385.5" y1="340" y2="340"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="268.5" x2="385.5" y1="348" y2="348"/><!--class PluginInfo--><rect fill="#FEFECE" filter="url(#ftjlkw6cxn2mj)" height="48" id="PluginInfo" style="stroke: #A80036; stroke-width: 1.5;" width="87" x="526.5" y="308"/><ellipse cx="541.5" cy="324" fill="#ADD1B2" rx="11" ry="11" style="stroke: #A80036; stroke-width: 1.0;"/><path d="M544.4731,329.6431 Q543.8921,329.9419 543.2529,330.0913 Q542.6138,330.2407 541.9082,330.2407 Q539.4014,330.2407 538.0815,328.5889 Q536.7617,326.937 536.7617,323.8159 Q536.7617,320.6865 538.0815,319.0347 Q539.4014,317.3828 541.9082,317.3828 Q542.6138,317.3828 543.2612,317.5322 Q543.9087,317.6816 544.4731,317.9805 L544.4731,320.7031 Q543.8423,320.1221 543.2488,319.8523 Q542.6553,319.5825 542.0244,319.5825 Q540.6797,319.5825 539.9949,320.6492 Q539.3101,321.7158 539.3101,323.8159 Q539.3101,325.9077 539.9949,326.9744 Q540.6797,328.041 542.0244,328.041 Q542.6553,328.041 543.2488,327.7712 Q543.8423,327.5015 544.4731,326.9204 Z "/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="55" x="555.5" y="328.5352">PluginInfo</text><line style="stroke: #A80036; stroke-width: 1.5;" x1="527.5" x2="612.5" y1="340" y2="340"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="527.5" x2="612.5" y1="348" y2="348"/><!--class CuisineManager--><rect fill="#FEFECE" filter="url(#ftjlkw6cxn2mj)" height="73.9102" id="CuisineManager" style="stroke: #A80036; stroke-width: 1.5;" width="123" x="119.5" y="173"/><ellipse cx="134.5" cy="189" fill="#ADD1B2" rx="11" ry="11" style="stroke: #A80036; stroke-width: 1.0;"/><path d="M137.4731,194.6431 Q136.8921,194.9419 136.2529,195.0913 Q135.6138,195.2407 134.9082,195.2407 Q132.4014,195.2407 131.0815,193.5889 Q129.7617,191.937 129.7617,188.8159 Q129.7617,185.6865 131.0815,184.0347 Q132.4014,182.3828 134.9082,182.3828 Q135.6138,182.3828 136.2612,182.5322 Q136.9087,182.6816 137.4731,182.9805 L137.4731,185.7031 Q136.8423,185.1221 136.2488,184.8523 Q135.6553,184.5825 135.0244,184.5825 Q133.6797,184.5825 132.9949,185.6492 Q132.3101,186.7158 132.3101,188.8159 Q132.3101,190.9077 132.9949,191.9744 Q133.6797,193.041 135.0244,193.041 Q135.6553,193.041 136.2488,192.7712 Q136.8423,192.5015 137.4731,191.9204 Z "/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="91" x="148.5" y="193.5352">CuisineManager</text><line style="stroke: #A80036; stroke-width: 1.5;" x1="120.5" x2="241.5" y1="205" y2="205"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="120.5" x2="241.5" y1="213" y2="213"/><ellipse cx="130.5" cy="224.9775" fill="#84BE84" rx="3" ry="3" style="stroke: #038048; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="77" x="139.5" y="227.6348">get_a_plugin()</text><ellipse cx="130.5" cy="237.9326" fill="#84BE84" rx="3" ry="3" style="stroke: #038048; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="93" x="139.5" y="240.5898">raise_exception()</text><!--class Chef--><rect fill="#FEFECE" filter="url(#ftjlkw6cxn2mj)" height="60.9551" id="Chef" style="stroke: #A80036; stroke-width: 1.5;" width="62" x="22" y="179.5"/><ellipse cx="38.8" cy="195.5" fill="#B4A7E5" rx="11" ry="11" style="stroke: #A80036; stroke-width: 1.0;"/><path d="M34.7277,191.2651 L34.7277,189.1069 L42.1071,189.1069 L42.1071,191.2651 L39.6418,191.2651 L39.6418,199.3418 L42.1071,199.3418 L42.1071,201.5 L34.7277,201.5 L34.7277,199.3418 L37.1931,199.3418 L37.1931,191.2651 Z "/><text fill="#000000" font-family="sans-serif" font-size="12" font-style="italic" lengthAdjust="spacingAndGlyphs" textLength="26" x="53.2" y="200.0352">Chef</text><line style="stroke: #A80036; stroke-width: 1.5;" x1="23" x2="83" y1="211.5" y2="211.5"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="23" x2="83" y1="219.5" y2="219.5"/><ellipse cx="33" cy="231.4775" fill="#84BE84" rx="3" ry="3" style="stroke: #038048; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="36" x="42" y="234.1348">make()</text><!--class Boost--><rect fill="#FEFECE" filter="url(#ftjlkw6cxn2mj)" height="48" id="Boost" style="stroke: #A80036; stroke-width: 1.5;" width="63" x="91.5" y="422"/><ellipse cx="106.5" cy="438" fill="#ADD1B2" rx="11" ry="11" style="stroke: #A80036; stroke-width: 1.0;"/><path d="M109.4731,443.6431 Q108.8921,443.9419 108.2529,444.0913 Q107.6138,444.2407 106.9082,444.2407 Q104.4014,444.2407 103.0815,442.5889 Q101.7617,440.937 101.7617,437.8159 Q101.7617,434.6865 103.0815,433.0347 Q104.4014,431.3828 106.9082,431.3828 Q107.6138,431.3828 108.2612,431.5322 Q108.9087,431.6816 109.4731,431.9805 L109.4731,434.7031 Q108.8423,434.1221 108.2488,433.8523 Q107.6553,433.5825 107.0244,433.5825 Q105.6797,433.5825 104.9949,434.6492 Q104.3101,435.7158 104.3101,437.8159 Q104.3101,439.9077 104.9949,440.9744 Q105.6797,442.041 107.0244,442.041 Q107.6553,442.041 108.2488,441.7712 Q108.8423,441.5015 109.4731,440.9204 Z "/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="31" x="120.5" y="442.5352">Boost</text><line style="stroke: #A80036; stroke-width: 1.5;" x1="92.5" x2="153.5" y1="454" y2="454"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="92.5" x2="153.5" y1="462" y2="462"/><!--class Fry--><rect fill="#FEFECE" filter="url(#ftjlkw6cxn2mj)" height="48" id="Fry" style="stroke: #A80036; stroke-width: 1.5;" width="49" x="267.5" y="422"/><ellipse cx="282.5" cy="438" fill="#ADD1B2" rx="11" ry="11" style="stroke: #A80036; stroke-width: 1.0;"/><path d="M285.4731,443.6431 Q284.8921,443.9419 284.2529,444.0913 Q283.6138,444.2407 282.9082,444.2407 Q280.4014,444.2407 279.0815,442.5889 Q277.7617,440.937 277.7617,437.8159 Q277.7617,434.6865 279.0815,433.0347 Q280.4014,431.3828 282.9082,431.3828 Q283.6138,431.3828 284.2612,431.5322 Q284.9087,431.6816 285.4731,431.9805 L285.4731,434.7031 Q284.8423,434.1221 284.2488,433.8523 Q283.6553,433.5825 283.0244,433.5825 Q281.6797,433.5825 280.9949,434.6492 Q280.3101,435.7158 280.3101,437.8159 Q280.3101,439.9077 280.9949,440.9744 Q281.6797,442.041 283.0244,442.041 Q283.6553,442.041 284.2488,441.7712 Q284.8423,441.5015 285.4731,440.9204 Z "/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="17" x="296.5" y="442.5352">Fry</text><line style="stroke: #A80036; stroke-width: 1.5;" x1="268.5" x2="315.5" y1="454" y2="454"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="268.5" x2="315.5" y1="462" y2="462"/><!--class Bake--><rect fill="#FEFECE" filter="url(#ftjlkw6cxn2mj)" height="48" id="Bake" style="stroke: #A80036; stroke-width: 1.5;" width="60" x="352" y="422"/><ellipse cx="367" cy="438" fill="#ADD1B2" rx="11" ry="11" style="stroke: #A80036; stroke-width: 1.0;"/><path d="M369.9731,443.6431 Q369.3921,443.9419 368.7529,444.0913 Q368.1138,444.2407 367.4082,444.2407 Q364.9014,444.2407 363.5815,442.5889 Q362.2617,440.937 362.2617,437.8159 Q362.2617,434.6865 363.5815,433.0347 Q364.9014,431.3828 367.4082,431.3828 Q368.1138,431.3828 368.7612,431.5322 Q369.4087,431.6816 369.9731,431.9805 L369.9731,434.7031 Q369.3423,434.1221 368.7488,433.8523 Q368.1553,433.5825 367.5244,433.5825 Q366.1797,433.5825 365.4949,434.6492 Q364.8101,435.7158 364.8101,437.8159 Q364.8101,439.9077 365.4949,440.9744 Q366.1797,442.041 367.5244,442.041 Q368.1553,442.041 368.7488,441.7712 Q369.3423,441.5015 369.9731,440.9204 Z "/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="28" x="381" y="442.5352">Bake</text><line style="stroke: #A80036; stroke-width: 1.5;" x1="353" x2="411" y1="454" y2="454"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="353" x2="411" y1="462" y2="462"/><!--link PluginManager to PluginInfoChain--><path d="M327,91.4556 C327,142.0673 327,257.7559 327,307.9863 " fill="none" id="PluginManager-PluginInfoChain" style="stroke: #A80036; stroke-width: 1.0; stroke-dasharray: 7.0,7.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="128" x="328" y="215.0684">registers plugin info</text><!--link PluginManager to PluginInfo--><path d="M396.2319,97.2468 C419.9614,109.9144 445.4373,126.3195 465,146 C513.2318,194.5223 546.4803,269.7151 561.2904,307.9322 " fill="none" id="PluginManager-PluginInfo" style="stroke: #A80036; stroke-width: 1.0;"/><polygon fill="#FFFFFF" points="384.3912,91.1484,387.8939,97.4517,395.0594,96.6428,391.5568,90.3395,384.3912,91.1484" style="stroke: #A80036; stroke-width: 1.0;"/><!--link PluginInfoChain to PluginInfo--><path d="M386.8008,332 C433.3162,332 479.8316,332 526.3471,332 " fill="none" id="PluginInfoChain-PluginInfo" style="stroke: #A80036; stroke-width: 1.0;"/><!--link PluginManager to CuisineManager--><path d="M287.057,105.3977 C281.6499,110.6303 276.1818,115.9399 271,121 C253.7058,137.888 234.657,156.695 218.5545,172.6539 " fill="none" id="PluginManager-CuisineManager" style="stroke: #A80036; stroke-width: 1.0;"/><polygon fill="none" points="282.5934,99.9772,301.8458,91.1259,292.3153,110.0513,282.5934,99.9772" style="stroke: #A80036; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="45" x="272" y="134.5684">cuisine</text><!--link Chef to Boost--><path d="M62.0066,260.3132 C69.1326,296.1851 80.325,345.2543 95,387 C99.1361,398.766 104.8875,411.3138 110.1023,421.7993 " fill="none" id="Chef-Boost" style="stroke: #A80036; stroke-width: 1.0;"/><polygon fill="none" points="55.1222,261.5808,58.2389,240.6217,68.8728,258.9499,55.1222,261.5808" style="stroke: #A80036; stroke-width: 1.0;"/><!--link PluginInfoChain to Boost--><path d="M283.7368,356.1765 C245.0238,377.8102 189.1869,409.0132 154.5465,428.3711 " fill="none" id="PluginInfoChain-Boost" style="stroke: #A80036; stroke-width: 1.0; stroke-dasharray: 7.0,7.0;"/><!--link Chef to Fry--><path d="M76.1936,258.6153 C98.4418,299.68 136.0226,356.5306 186,387 C204.0921,398.0301 213.8352,385.9613 233,395 C246.7153,401.4686 259.7227,412.0389 270.0164,421.8838 " fill="none" id="Chef-Fry" style="stroke: #A80036; stroke-width: 1.0;"/><polygon fill="none" points="69.9148,261.7129,66.9248,240.7353,82.344,255.2697,69.9148,261.7129" style="stroke: #A80036; stroke-width: 1.0;"/><!--link Chef to Bake--><path d="M99.1211,252.4825 C137.523,286.1638 194.8153,332.6282 251,364 C285.3813,383.1975 301.2044,373.204 334,395 C344.9366,402.2685 355.1885,412.4811 363.3868,421.8601 " fill="none" id="Chef-Bake" style="stroke: #A80036; stroke-width: 1.0;"/><polygon fill="none" points="94.4127,257.6629,84.1274,239.1368,103.7208,247.2053,94.4127,257.6629" style="stroke: #A80036; stroke-width: 1.0;"/><!--link PluginInfoChain to Fry--><path d="M319.5774,356.1765 C313.6378,375.5227 305.3487,402.5214 299.4119,421.8584 " fill="none" id="PluginInfoChain-Fry" style="stroke: #A80036; stroke-width: 1.0; stroke-dasharray: 7.0,7.0;"/><!--link PluginInfoChain to Bake--><path d="M338.6641,356.1765 C347.9978,375.5227 361.0235,402.5214 370.3527,421.8584 " fill="none" id="PluginInfoChain-Bake" style="stroke: #A80036; stroke-width: 1.0; stroke-dasharray: 7.0,7.0;"/><!--
+@startuml
+
+package lml {
+  PluginManager .. PluginInfoChain : registers plugin info
+  PluginManager o- - PluginInfo
+  PluginInfoChain -right- PluginInfo
+}
+
+package robotchef {
+  class CuisineManager {
+  + get_a_plugin()
+  + raise_exception()
+  }
+  interface Chef {
+  + make()
+  }
+  PluginManager <|- -  CuisineManager : cuisine
+  package robotchef.robot_cuisine {
+    Chef <|- - Boost
+    PluginInfoChain .. Boost
+  }
+}
+
+package robotchef_britishcuisine {
+  Chef <|- - Fry
+  Chef <|- - Bake
+  PluginInfoChain .. Fry
+  PluginInfoChain .. Bake
+}
+
+
+@enduml
+
+PlantUML version 1.2017.13(Wed May 10 17:52:33 BST 2017)
+(GPL source distribution)
+Java Runtime: Java(TM) SE Runtime Environment
+JVM: Java HotSpot(TM) 64-Bit Server VM
+Java Version: 1.8.0_131-b11
+Operating System: Mac OS X
+OS Version: 10.11.6
+Default Encoding: UTF-8
+Language: en
+Country: US
+--></g></svg>
\ No newline at end of file
diff --git a/docs/source/allinone_lml_tutorial.rst b/docs/source/allinone_lml_tutorial.rst
index 6165854..ddbb3ed 100644
--- a/docs/source/allinone_lml_tutorial.rst
+++ b/docs/source/allinone_lml_tutorial.rst
@@ -12,10 +12,9 @@ the next section where we will make the plugins to be loaded later.
 Demo
 --------------------------------------------------------------------------------
 
-Please navigate to
-`lml/examples <https://github.com/chfw/lml/tree/master/examples>`_,
-you would find robotchef_allinone_lml and its packages. Do the following::
+Please navigate to robotchef_allinone_lml and its packages. Do the following::
 
+    $ git clone https://github.com/python-lml/robotchef_allinone_lml
     $ cd robotchef_allinone_lml
     $ python setup.py install
 
diff --git a/docs/source/allinone_tutorial.rst b/docs/source/allinone_tutorial.rst
index 0606d7d..0db77a9 100644
--- a/docs/source/allinone_tutorial.rst
+++ b/docs/source/allinone_tutorial.rst
@@ -7,13 +7,9 @@ without lml. In later on chapters, we will bring in **lml** step by step.
 Demo
 --------------------------------------------------------------------------------
 
-Please checkout lml::
-
-    $ git clone https://github.com/chfw/lml.git
-
-And navigate to `lml/examples <https://github.com/chfw/lml/tree/master/examples>`_,
-you would find robotchef_allinone and its packages. Do the following::
+Please checkout the robot chef example::
 
+    $ git clone https://github.com/python-lml/robotchef_allinone
     $ cd robotchef_allinone
     $ python setup.py install
 
@@ -40,7 +36,7 @@ actual implementations. Boost are for "robots". Bake and Fry are for human.
 
 .. literalinclude:: ../../examples/robotchef_allinone/robotchef_allinone/plugin.py
   :language: python
-  :lines: 5-26
+  :lines: 5-30
 
 Line 13, class `Chef` defines the plugin class interface. For robotchef, `make` is
 defined to illustrate the functionality. Naturally you will be deciding the
@@ -61,7 +57,7 @@ raises NoChefException.
 
 .. literalinclude:: ../../examples/robotchef_allinone/robotchef_allinone/plugin.py
   :language: python
-  :lines: 29-
+  :lines: 33-
 
 main.py
 +++++++++++
diff --git a/docs/source/api.rst b/docs/source/api.rst
index 98ad4ac..7159447 100644
--- a/docs/source/api.rst
+++ b/docs/source/api.rst
@@ -3,8 +3,8 @@ API documentation
 
 .. automodule:: lml.loader
 
-.. autofunction:: scan_plugins
-				  
+.. autofunction:: scan_plugins_regex
+
 .. automodule:: lml.plugin
 
 .. autoclass:: PluginInfo
@@ -13,4 +13,3 @@ API documentation
 
 .. autoclass:: PluginManager
    :members:
-		
diff --git a/docs/source/api_tutorial.rst b/docs/source/api_tutorial.rst
index e33b341..bb49c2d 100644
--- a/docs/source/api_tutorial.rst
+++ b/docs/source/api_tutorial.rst
@@ -11,13 +11,15 @@ two so as to showcase how to use lml to write a shared api library.
 Demo
 --------------------------------------------------------------------------------
 
-Navigate to `lml/examples/v2 <https://github.com/chfw/lml/tree/master/examples/v2>`_,
-you would find robotchef and its packages. Do the following::
+Please checkout the following examples::
 
     $ virtualenv --no-site-packages robotchefv2
     $ source robotchefv2/bin/activate
+    $ git clone https://github.com/python-lml/robotchef_v2
     $ cd robotchef_v2
     $ python setup.py install
+    $ cd ..
+    $ git clone https://github.com/python-lml/robotchef_api
     $ cd robotchef_api
     $ python setup.py install
 
@@ -31,7 +33,8 @@ And then you can type in and test the second version of Robot Chef::
 In order to add "Jacket Potato" in the know-how, you would need to install
 robotchef_britishcuisine in this folder::
 
-    $ cd robotchef_britishcuisine
+    $ git clone https://github.com/python-lml/robotchef_britishcuisine_v2
+    $ cd robotchef_britishcuisine_v2
     $ python setup.py install
     $ robotchef_v2 "Jacket Potato"
     I can bake Jacket Potato
@@ -65,7 +68,7 @@ Notably, the plugin loader is put in the __init__.py:
 .. literalinclude:: ../../examples/v2/robotchef_api/robotchef_api/__init__.py
   :language: python
 
-scan_plugins here loads all modules that start with "robotchef_" and as well as
+scan_plugins_regex here loads all modules that start with "robotchef_" and as well as
 the module `robotchef_api.robot_cuisine` in the white_list.
 
 This is how you will write the main component as a library.
diff --git a/docs/source/conf.py b/docs/source/conf.py
index a6c609c..ed08dc1 100644
--- a/docs/source/conf.py
+++ b/docs/source/conf.py
@@ -3,13 +3,11 @@ DESCRIPTION = (
     'Load me later. A lazy plugin management system.' +
     ''
 )
-# -*- coding: utf-8 -*-
-#
 # Configuration file for the Sphinx documentation builder.
 #
-# This file does only contain a selection of the most common options. For a
-# full list see the documentation:
-# http://www.sphinx-doc.org/en/master/config
+# This file only contains a selection of the most common options. For a full
+# list see the documentation:
+# https://www.sphinx-doc.org/en/master/usage/configuration.html
 
 # -- Path setup --------------------------------------------------------------
 
@@ -23,22 +21,16 @@ DESCRIPTION = (
 
 # -- Project information -----------------------------------------------------
 
-project = u'lml'
-copyright = u'2017-2019 Onni Software Ltd.'
-author = u'C.W.'
-
+project = 'lml'
+copyright = '2017-2020 Onni Software Ltd.'
+author = 'C.W.'
 # The short X.Y version
-version = u'0.0.9'
+version = '0.1.0'
 # The full version, including alpha/beta/rc tags
-release = u'0.0.9'
-
+release = '0.1.0'
 
 # -- General configuration ---------------------------------------------------
 
-# If your documentation needs a minimal Sphinx version, state it here.
-#
-# needs_sphinx = '1.0'
-
 # Add any Sphinx extension module names here, as strings. They can be
 # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
 # ones.
@@ -47,15 +39,6 @@ extensions = [    'sphinx.ext.autodoc',    'sphinx.ext.doctest',    'sphinx.ext.
 # Add any paths that contain templates here, relative to this directory.
 templates_path = ['_templates']
 
-# The suffix(es) of source filenames.
-# You can specify multiple suffix as a list of string:
-#
-# source_suffix = ['.rst', '.md']
-source_suffix = '.rst'
-
-# The master toctree document.
-master_doc = 'index'
-
 # The language for content autogenerated by Sphinx. Refer to documentation
 # for a list of supported languages.
 #
@@ -68,9 +51,6 @@ language = 'en'
 # This pattern also affects html_static_path and html_extra_path.
 exclude_patterns = []
 
-# The name of the Pygments (syntax highlighting) style to use.
-pygments_style = None
-
 
 # -- Options for HTML output -------------------------------------------------
 
@@ -79,107 +59,16 @@ pygments_style = None
 #
 html_theme = 'alabaster'
 
-# Theme options are theme-specific and customize the look and feel of a theme
-# further.  For a list of options available for each theme, see the
-# documentation.
-#
-# html_theme_options = {}
-
 # Add any paths that contain custom static files (such as style sheets) here,
 # relative to this directory. They are copied after the builtin static files,
 # so a file named "default.css" will overwrite the builtin "default.css".
 html_static_path = ['_static']
 
-# Custom sidebar templates, must be a dictionary that maps document names
-# to template names.
-#
-# The default sidebars (for documents that don't match any pattern) are
-# defined by theme itself.  Builtin themes are using these templates by
-# default: ``['localtoc.html', 'relations.html', 'sourcelink.html',
-# 'searchbox.html']``.
-#
-# html_sidebars = {}
-
-
-# -- Options for HTMLHelp output ---------------------------------------------
-
-# Output file base name for HTML help builder.
-htmlhelp_basename = 'lmldoc'
-
-
-# -- Options for LaTeX output ------------------------------------------------
-
-latex_elements = {
-    # The paper size ('letterpaper' or 'a4paper').
-    #
-    # 'papersize': 'letterpaper',
-
-    # The font size ('10pt', '11pt' or '12pt').
-    #
-    # 'pointsize': '10pt',
-
-    # Additional stuff for the LaTeX preamble.
-    #
-    # 'preamble': '',
-
-    # Latex figure (float) alignment
-    #
-    # 'figure_align': 'htbp',
-}
-
-# Grouping the document tree into LaTeX files. List of tuples
-# (source start file, target name, title,
-#  author, documentclass [howto, manual, or own class]).
-latex_documents = [
-    (master_doc, 'lml.tex', u'lml Documentation',
-     u'Onni Software Ltd.', 'manual'),
-]
-
-
-# -- Options for manual page output ------------------------------------------
-
-# One entry per manual page. List of tuples
-# (source start file, name, description, authors, manual section).
-man_pages = [
-    (master_doc, 'lml', u'lml Documentation',
-     [author], 1)
-]
-
-
-# -- Options for Texinfo output ----------------------------------------------
-
-# Grouping the document tree into Texinfo files. List of tuples
-# (source start file, target name, title, author,
-#  dir menu entry, description, category)
-texinfo_documents = [
-    (master_doc, 'lml', u'lml Documentation',
-     author, 'lml', 'One line description of project.',
-     'Miscellaneous'),
-]
-
-
-# -- Options for Epub output -------------------------------------------------
-
-# Bibliographic Dublin Core info.
-epub_title = project
-
-# The unique identifier of the text. This can be a ISBN number
-# or the project homepage.
-#
-# epub_identifier = ''
-
-# A unique identification for the text.
-#
-# epub_uid = ''
-
-# A list of files that should not be packed into the epub file.
-epub_exclude_files = ['search.html']
-
 # -- Extension configuration -------------------------------------------------
 # -- Options for intersphinx extension ---------------------------------------
 
 # Example configuration for intersphinx: refer to the Python standard library.
-intersphinx_mapping = {'https://docs.python.org/': None}
+intersphinx_mapping = {'https://docs.python.org/3/': None}
 # TODO: html_theme not configurable upstream
 html_theme = 'default'
 
@@ -193,3 +82,6 @@ texinfo_documents = [
 ]
 intersphinx_mapping.update({
 })
+master_doc = "index"
+
+master_doc = "index"
\ No newline at end of file
diff --git a/docs/source/design.rst b/docs/source/design.rst
index b3710b2..766575e 100644
--- a/docs/source/design.rst
+++ b/docs/source/design.rst
@@ -6,10 +6,20 @@ loosely coupled plugins to extend the main package to read more file formats. Du
 its code growth, the code in pyexcel packages to manage the external and internal
 plugins becomes a independent library, lml.
 
-lml is similar to **Factories** in
-Zope Component Architecture [#f2]_. Lml provides functionalities to
+Lml is similar to **Factories** in
+Zope Component Architecture [#f2]_. It provides functionalities to
 discover, register and load lml based plugins. It cares how the meta data were
-written but it does care how the plugin interface is written.
+written but it does NOT care how the plugin interface is written.
+
+Simply, lml promises to load your external dependency when they are used, but
+only when you follow lazy-loading design principle below. Otherwise, lml does
+immediate import and takes away the developer's responsibility to manage plugin
+registry and discovery.
+
+In terms of extensibility of your proud package, lml keeps the door open even
+if you use lml for immediate import. As a developer, you give the choice to other
+contributor to write up a plugin for your package. As long as the user would have
+installed community created extensions, lml will discover them and use them.
 
 
 Plugin discovery
@@ -20,7 +30,7 @@ namespace package [#f3]_ comes from Python 3 or pkgutil style in Python 2 and 3.
 It allows the developer to split a bigger packages into a smaller ones and
 publish them separately. sphinxcontrib [#f4]_ uses a typical namespace package based
 method. However, namespace package places a strict requirement
-on the module's __init__.py: nothing other than name space declaration should
+on the module's `__init__.py`: nothing other than name space declaration should
 be present. It means no module level functions can be place there. This restriction
 forces the plugin to be driven by the main package but the plugin cannot use
 the main package as its own library to do specific things. So namespace package
@@ -40,7 +50,7 @@ import it, you can use "import pyexcel.ext.xls". The shortcomings are:
    development since 2016.
 
 In order to overcome those shortcomings, implicit imports were coded into module's
-__init__.py. By iterating through currently installed modules in your python
+`__init__.py`. By iterating through currently installed modules in your python
 environment, the relevant plugins are imported automatically.
 
 lml uses implicit import. In order to manage the plugins, pip can be used to
@@ -49,29 +59,27 @@ where two plugins perform the same thing but have to co-exist in your current
 python path, you can nominate one plugin to be picked.
 
 Plugin registration
----------------------
+--------------------------------------------------------------------------------
 
 In terms of plugin registrations, three different approaches have been tried.
 Monkey-patching was easy to implement. When a plugin is imported, it loads
-the plugin dictionary from the main package and add itself.
-But it is generally perceived as a "bad" idea.
-Another way of doing it is to place
-the plugin code in the main component and the plugin just need to declare a
-dictionary as the plugin's meta data. The main package register the meta data
-when it is imported. tablib [#f5]_ uses such a approach.
-The third way is to use meta-classes. M. Alchin (2008) [#f6]_ explained how meta class can
-be used to register plugin classes in a simpler way.
+the plugin dictionary from the main package and add itself. But it is generally
+perceived as a "bad" idea. Another way of doing it is to place the plugin code
+in the main component and the plugin just need to declare a dictionary as the
+plugin's meta data. The main package register the meta data when it is imported.
+tablib [#f5]_ uses such a approach. The third way is to use meta-classes.
+M. Alchin (2008) [#f6]_ explained how meta class can be used to register plugin
+classes in a simpler way.
 
 lml uses meta data for plugin registration. Since lml load your plugin later,
-the meta data is stored in the module's __init__.py. For example, to load plugins later
-in tablib, the 'exports' variable should be taken out from the actual class file and
-replace the hard reference to the classes with class path string.
+the meta data is stored in the module's __init__.py. For example, to load plugins
+later in tablib, the 'exports' variable should be taken out from the actual
+class file and replace the hard reference to the classes with class path string.
 
 Plugin distribution
 ---------------------
 
-In terms of plugin distribution, yapsy [#f7]_ and GEdit plugin management
-system [#f8]_ load plugins from file system.
+yapsy [#f7]_ and GEdit plugin management system [#f8]_ load plugins from file system.
 To install a plugin in those systems, is to copy and paste the plugin code to a
 designated directory. zope components, namespace packages and flask extensions
 can be installed via pypi. lml support the latter approach. lml plugins can be
@@ -81,7 +89,7 @@ Design principle
 ------------------
 
 To use lml, it asks you to avoid importing your "heavy" dependencies
-in __init__.py. lml also respects the independence of individual packages. You can
+in `__init__.py`. lml respects the independence of individual packages. You can
 put modular level functions in your __init__.py as long as it does not trigger
 immediate import of your dependency. This is to allow the individual plugin to
 become useful as it is, rather to be integrated with your main package. For example,
@@ -91,7 +99,6 @@ With lml, as long as your third party developer respect the plugin name prefix,
 they could publish their plugins as they do to any normal pypi packages. And the end
 developer of yours would only need to do pip install.
 
-
 References
 -------------
 
diff --git a/docs/source/index.rst b/docs/source/index.rst
index 5c577f5..5254787 100644
--- a/docs/source/index.rst
+++ b/docs/source/index.rst
@@ -34,6 +34,42 @@ the developer need to do the code refactoring by yourself and lml would lend you
          objectives.
 
 
+Quick start
+================================================================================
+
+The following code tries to get you started quickly with **non-lazy** loading.
+
+.. code-block:: python
+
+    from lml.plugin import PluginInfo, PluginManager
+
+
+    @PluginInfo("cuisine", tags=["Portable Battery"])
+    class Boost(object):
+        def make(self, food=None, **keywords):
+            print("I can cook %s for robots" % food)
+
+
+    class CuisineManager(PluginManager):
+        def __init__(self):
+            PluginManager.__init__(self, "cuisine")
+
+        def get_a_plugin(self, food_name=None, **keywords):
+            return PluginManager.get_a_plugin(self, key=food_name, **keywords)
+
+
+    if __name__ == '__main__':
+        manager = CuisineManager()
+        chef = manager.get_a_plugin("Portable Battery")
+        chef.make()
+
+
+At a glance, above code simply replaces the Factory pattern should you write
+them without lml. What's not obvious is, that once you got hands-on with it,
+you can start work on how to do **lazy** loading.
+
+
+
 Documentation
 ----------------
 
@@ -47,6 +83,12 @@ Documentation
 
 Beyond the documentation above, here is a list of projects using lml:
 
-#. `pyexcel <https://github.com/pyexcel.pyexcel>`_
-#. `pyexcel-io <https://github.com/pyexcel.pyexcel-io>`_
-#. `pyexcel-chart <https://github.com/pyexcel.pyexcel-chart>`_
+#. `pyexcel <https://github.com/pyexcel/pyexcel>`_
+#. `pyecharts <https://github.com/pyecharts/pyecharts>`_
+#. `moban <https://github.com/moremoban/moban>`_
+
+lml is available on these distributions:
+
+#. `ARCH linux <https://aur.archlinux.org/packages/python-lml/>`_
+#. `Conda forge <https://anaconda.org/conda-forge/lml>`_
+#. `OpenSuse <https://build.opensuse.org/package/show/devel:languages:python/python-lml>`_
diff --git a/docs/source/lml_log.rst b/docs/source/lml_log.rst
index 996a7e5..c22e54f 100644
--- a/docs/source/lml_log.rst
+++ b/docs/source/lml_log.rst
@@ -8,7 +8,7 @@ me show you how to enable the logs of lml.
 Enable the logging
 -------------------
 
-Let us open robotchef's `main.py <https://github.com/chfw/lml/blob/master/examples/robotchef/robotchef/main.py>`_. Insert the highlighted codes.
+Let us open robotchef's `main.py <https://github.com/python-lml/robotchef/blob/master/robotchef/main.py>`_. Insert the highlighted codes.
 
 .. code-block:: python
     :emphasize-lines: 5-10
diff --git a/docs/source/lml_tutorial.rst b/docs/source/lml_tutorial.rst
index ad858a5..a6d8d7f 100644
--- a/docs/source/lml_tutorial.rst
+++ b/docs/source/lml_tutorial.rst
@@ -9,10 +9,9 @@ demonstrates the changes needed to plugin them back with the main package.
 Demo
 --------------------------------------------------------------------------------
 
-Please navigate to
-`lml/examples <https://github.com/chfw/lml/tree/master/examples>`_,
-you would find robotchef and its packages. Do the following::
+Do the following::
 
+    $ git clone https://github.com/python-lml/robotchef
     $ cd robotchef
     $ python setup.py install
 
@@ -30,6 +29,7 @@ as below::
 it starts to understand it once you install Chinese cuisine package to complement
 its knowledge::
 
+    $ git clone https://github.com/python-lml/robotchef_britishcuisine
     $ cd robotchef_britishcuisine
     $ python setup.py install
 
diff --git a/docs/source/uml/loading_sequence.uml b/docs/source/uml/loading_sequence.uml
new file mode 100644
index 0000000..59cc905
--- /dev/null
+++ b/docs/source/uml/loading_sequence.uml
@@ -0,0 +1,19 @@
+@startuml
+
+actor bob
+participant robotchef
+participant lml
+participant robotchef_britishcuisine
+
+bob -> robotchef : > robotchef "Jacket Potato"
+robotchef -> lml : scan for plugins.
+lml -> robotchef_britishcuisine : read plugin chain in the module
+robotchef_britishcuisine -> lml: I can help with "Jacket Potato" and others.
+lml -> robotchef : read the built-in robot_cuisine
+robotchef -> lml : built-in chef knows "Portable Battery"
+lml --> robotchef : scanning done
+robotchef -> lml : get me a plugin that knows "Jacket Potato"
+lml -> robotchef : robotchef_britishcuisine.bake.Bake can do
+robotchef -> robotchef: make the food
+robotchef -> bob : "I can bake Jacket Potato"
+@enduml
\ No newline at end of file
diff --git a/docs/source/uml/robot_chef.uml b/docs/source/uml/robot_chef.uml
new file mode 100644
index 0000000..c5601ec
--- /dev/null
+++ b/docs/source/uml/robot_chef.uml
@@ -0,0 +1,9 @@
+@startuml
+
+Interface Chef
+
+Chef <|-- Boost
+Chef <|-- Fry
+Chef <|-- Bake
+
+@enduml
\ No newline at end of file
diff --git a/docs/source/uml/robotchef_allinone_lml.uml b/docs/source/uml/robotchef_allinone_lml.uml
new file mode 100644
index 0000000..a27a39b
--- /dev/null
+++ b/docs/source/uml/robotchef_allinone_lml.uml
@@ -0,0 +1,25 @@
+@startuml
+
+package lml {
+  PluginManager o-- PluginInfo
+}
+
+package robotchef_allinone_lml {
+  class CuisineManager {
+  + get_a_plugin()
+  + raise_exception()
+  }
+  interface Chef {
+  + make()
+  }
+  PluginManager <|--  CuisineManager : cuisine
+  Chef <|-- Boost
+  Chef <|-- Fry
+  Chef <|-- Bake
+  PluginInfo .. Fry
+  PluginInfo .. Bake
+  PluginInfo .. Boost
+}
+
+
+@enduml
\ No newline at end of file
diff --git a/docs/source/uml/robotchef_api_crd.uml b/docs/source/uml/robotchef_api_crd.uml
new file mode 100644
index 0000000..d2bd3d7
--- /dev/null
+++ b/docs/source/uml/robotchef_api_crd.uml
@@ -0,0 +1,37 @@
+@startuml
+
+
+package lml {
+  PluginManager .. PluginInfoChain : registers plugin info
+  PluginManager o-- PluginInfo
+  PluginInfoChain -right- PluginInfo
+}
+
+package robotchef_api {
+  class CuisineManager {
+  + get_a_plugin()
+  + raise_exception()
+  }
+  interface Chef {
+  + make()
+  }
+  PluginManager <|--  CuisineManager : cuisine
+  package robotchef.robot_cuisine {
+    Chef <|-- Boost
+    PluginInfoChain .. Boost
+  }
+}
+
+package robotchef_britishcuisine {
+  Chef <|-- Fry
+  Chef <|-- Bake
+  PluginInfoChain .. Fry
+  PluginInfoChain .. Bake
+}
+
+package robotchef_v2 {
+}
+
+robotchef_v2 +-- robotchef_api
+
+@enduml
\ No newline at end of file
diff --git a/docs/source/uml/robotchef_crd.uml b/docs/source/uml/robotchef_crd.uml
new file mode 100644
index 0000000..4ee8e2a
--- /dev/null
+++ b/docs/source/uml/robotchef_crd.uml
@@ -0,0 +1,32 @@
+@startuml
+
+package lml {
+  PluginManager .. PluginInfoChain : registers plugin info
+  PluginManager o-- PluginInfo
+  PluginInfoChain -right- PluginInfo
+}
+
+package robotchef {
+  class CuisineManager {
+  + get_a_plugin()
+  + raise_exception()
+  }
+  interface Chef {
+  + make()
+  }
+  PluginManager <|--  CuisineManager : cuisine
+  package robotchef.robot_cuisine {
+    Chef <|-- Boost
+    PluginInfoChain .. Boost
+  }
+}
+
+package robotchef_britishcuisine {
+  Chef <|-- Fry
+  Chef <|-- Bake
+  PluginInfoChain .. Fry
+  PluginInfoChain .. Bake
+}
+
+
+@enduml
\ No newline at end of file
diff --git a/examples/README.rst b/examples/README.rst
new file mode 100644
index 0000000..8fcd41a
--- /dev/null
+++ b/examples/README.rst
@@ -0,0 +1,12 @@
+READ ME
+=========
+
+A robot chef was created to master the cuisines around the world. It learns faster
+than a human because it just needs a plugin to be installed. It consumes less
+memory as it load the cuisine knowlege on demand.
+
+Please note that there are two implementations of the robot chef. One is pure
+command line interface(CLI) using lml directly; the other one is CLI using
+robotchef_api package which uses lml. The former demonstrates how lml could
+be used in a CLI package. The latter illustrates how to construct a pure
+python library using lml.
diff --git a/lml.egg-info/PKG-INFO b/lml.egg-info/PKG-INFO
deleted file mode 100644
index 1d394bb..0000000
--- a/lml.egg-info/PKG-INFO
+++ /dev/null
@@ -1,163 +0,0 @@
-Metadata-Version: 1.1
-Name: lml
-Version: 0.0.9
-Summary: Load me later. A lazy plugin management system.
-Home-page: https://github.com/chfw/lml
-Author: C.W.
-Author-email: wangc_2011@hotmail.com
-License: New BSD
-Download-URL: https://github.com/chfw/lml/archive/0.0.9.tar.gz
-Description: ================================================================================
-        lml - Load me later. A lazy plugin management system.
-        ================================================================================
-        
-        .. image:: https://api.travis-ci.org/chfw/lml.svg
-           :target: http://travis-ci.org/chfw/lml
-        
-        .. image:: https://codecov.io/github/chfw/lml/coverage.png
-           :target: https://codecov.io/github/chfw/lml
-        
-        
-        .. image:: https://readthedocs.org/projects/lml/badge/?version=latest
-           :target: http://lml.readthedocs.org/en/latest/
-        
-        **lml** seamlessly finds the lml based plugins from your current python
-        environment but loads your plugins on demand. It is designed to support
-        plugins that have external dependencies, especially bulky and/or
-        memory hungry ones. lml provides the plugin management system only and the
-        plugin interface is on your shoulder.
-        
-        **lml** enabled applications helps your customers [#f1]_ in two ways:
-        
-        #. Your customers could cherry-pick the plugins from pypi per python environment.
-           They could remove a plugin using `pip uninstall` command.
-        #. Only the plugins used at runtime gets loaded into computer memory.
-        
-        When you would use **lml** to refactor your existing code, it aims to flatten the
-        complexity and to shrink the size of your bulky python library by
-        distributing the similar functionalities across its plugins. However, you as
-        the developer need to do the code refactoring by yourself and lml would lend you a hand.
-        
-        .. [#f1] the end developers who uses your library and packages achieve their
-                 objectives.
-        
-        Installation
-        ================================================================================
-        
-        
-        You can install lml via pip:
-        
-        .. code-block:: bash
-        
-            $ pip install lml
-        
-        
-        or clone it and install it:
-        
-        .. code-block:: bash
-        
-            $ git clone https://github.com/chfw/lml.git
-            $ cd lml
-            $ python setup.py install
-        
-        License
-        ================================================================================
-        
-        New BSD
-        
-        Change log
-        ================================================================================
-        
-        0.0.9 - 7/1/2019
-        --------------------------------------------------------------------------------
-        
-        Updated
-        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-        
-        #. `#11 <https://github.com/chfw/lml/issues/11>`_: more test contents for
-           OpenSuse package validation
-        
-        0.0.8 - 4/1/2019
-        --------------------------------------------------------------------------------
-        
-        Updated
-        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-        
-        #. `#9 <https://github.com/chfw/lml/issues/9>`_: include tests, docs for
-           OpenSuse package validation
-        
-        0.0.7 - 17/11/2018
-        --------------------------------------------------------------------------------
-        
-        Fixed
-        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-        
-        #. `#8 <https://github.com/chfw/lml/issues/8>`_: get_primary_key will fail when
-           a module is loaded later
-        #. deprecated old style plugin scanner: scan_plugins
-        
-        0.0.6 - 07/11/2018
-        --------------------------------------------------------------------------------
-        
-        Fixed
-        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-        
-        #. Revert the version 0.0.5 changes. Raise Import error and log the exception
-        
-        0.0.5 - 06/11/2018
-        --------------------------------------------------------------------------------
-        
-        Fixed
-        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-        
-        #. `#6 <https://github.com/chfw/lml/issues/6>`_: Catch and Ignore
-           ModuleNotFoundError
-        
-        0.0.4 - 07.08.2018
-        --------------------------------------------------------------------------------
-        
-        Added
-        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-        
-        #. `#4 <https://github.com/chfw/lml/issues/4>`_: to find plugin names with
-           different naming patterns
-        
-        0.0.3 - 12/06/2018
-        --------------------------------------------------------------------------------
-        
-        Added
-        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-        
-        #. `dict` can be a pluggable type in addition to `function`, `class`
-        #. get primary tag of your tag, helping you find out which category of plugins
-           your tag points to
-        
-        0.0.2 - 23/10/2017
-        --------------------------------------------------------------------------------
-        
-        Updated
-        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-        
-        #. `pyexcel#103 <https://github.com/pyexcel/pyexcel/issues/103>`_: include
-           LICENSE in tar ball
-        
-        0.0.1 - 30/05/2017
-        --------------------------------------------------------------------------------
-        
-        Added
-        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-        
-        #. First release
-        
-        
-Keywords: python
-Platform: UNKNOWN
-Classifier: Topic :: Software Development :: Libraries
-Classifier: Programming Language :: Python
-Classifier: Intended Audience :: Developers
-Classifier: Programming Language :: Python :: 2.6
-Classifier: Programming Language :: Python :: 2.7
-Classifier: Programming Language :: Python :: 3.3
-Classifier: Programming Language :: Python :: 3.4
-Classifier: Programming Language :: Python :: 3.5
-Classifier: Programming Language :: Python :: 3.6
diff --git a/lml.egg-info/SOURCES.txt b/lml.egg-info/SOURCES.txt
deleted file mode 100644
index d69f64f..0000000
--- a/lml.egg-info/SOURCES.txt
+++ /dev/null
@@ -1,39 +0,0 @@
-CHANGELOG.rst
-LICENSE
-MANIFEST.in
-README.rst
-setup.cfg
-setup.py
-docs/source/allinone_lml_tutorial.rst
-docs/source/allinone_tutorial.rst
-docs/source/api.rst
-docs/source/api_tutorial.rst
-docs/source/appendix.rst
-docs/source/conf.py
-docs/source/design.rst
-docs/source/index.rst
-docs/source/lml_log.rst
-docs/source/lml_tutorial.rst
-docs/source/spelling_wordlist.txt
-docs/source/tutorial.rst
-lml/__init__.py
-lml/_version.py
-lml/loader.py
-lml/plugin.py
-lml/utils.py
-lml.egg-info/PKG-INFO
-lml.egg-info/SOURCES.txt
-lml.egg-info/dependency_links.txt
-lml.egg-info/not-zip-safe
-lml.egg-info/top_level.txt
-tests/requirements.txt
-tests/test_plugin_info.py
-tests/test_plugin_loader.py
-tests/test_plugin_manager.py
-tests/test_utils.py
-tests/sample_plugin/setup.py
-tests/sample_plugin/sample_plugin/__init__.py
-tests/sample_plugin/sample_plugin/manager.py
-tests/sample_plugin/sample_plugin/reader.py
-tests/test_plugin/setup.py
-tests/test_plugin/pyexcel_test/__init__.py
\ No newline at end of file
diff --git a/lml.egg-info/dependency_links.txt b/lml.egg-info/dependency_links.txt
deleted file mode 100644
index 8b13789..0000000
--- a/lml.egg-info/dependency_links.txt
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/lml.egg-info/not-zip-safe b/lml.egg-info/not-zip-safe
deleted file mode 100644
index 8b13789..0000000
--- a/lml.egg-info/not-zip-safe
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/lml.egg-info/top_level.txt b/lml.egg-info/top_level.txt
deleted file mode 100644
index 87bedb6..0000000
--- a/lml.egg-info/top_level.txt
+++ /dev/null
@@ -1 +0,0 @@
-lml
diff --git a/lml.yml b/lml.yml
new file mode 100644
index 0000000..6acdc76
--- /dev/null
+++ b/lml.yml
@@ -0,0 +1,20 @@
+name: "lml"
+full_name: "Load me later. A lazy plugin management system."
+organisation: "python-lml"
+author: "C.W."
+contact: "wangc_2011@hotmail.com"
+company: "Onni Software Ltd."
+version: "0.1.0"
+current_version: "0.1.0"
+release: "0.1.0"
+copyright_year: 2017-2020
+license: New BSD
+dependencies: []
+test_dependencies:
+  - lml
+  - pytest
+  - pytest-cov
+description: "Load me later. A lazy plugin management system."
+excluded_github_users:
+  - chfw
+  - gitter-badger
diff --git a/lml/__init__.py b/lml/__init__.py
index bcdac60..bf0db19 100644
--- a/lml/__init__.py
+++ b/lml/__init__.py
@@ -8,8 +8,9 @@
     :license: New BSD License, see LICENSE for more details
 """
 import logging
-from lml._version import __version__  # noqa: F401
+
 from lml._version import __author__  # noqa: F401
+from lml._version import __version__  # noqa: F401
 
 try:
     from logging import NullHandler
diff --git a/lml/_version.py b/lml/_version.py
index 4380c4e..c606527 100644
--- a/lml/_version.py
+++ b/lml/_version.py
@@ -1,2 +1,2 @@
-__version__ = "0.0.9"
+__version__ = "0.1.0"
 __author__ = "C.W."
diff --git a/lml/loader.py b/lml/loader.py
index a4cb1ca..0d5482d 100644
--- a/lml/loader.py
+++ b/lml/loader.py
@@ -6,7 +6,7 @@
     and pyinstaller. :func:`~lml.loader.scan_plugins` is expected to be
     called in the main package of yours at an earliest time of convenience.
 
-    :copyright: (c) 2017-2018 by Onni Software Ltd.
+    :copyright: (c) 2017-2020 by Onni Software Ltd.
     :license: New BSD License, see LICENSE for more details
 """
 import re
diff --git a/lml/plugin.py b/lml/plugin.py
index 70629fc..1a49d54 100644
--- a/lml/plugin.py
+++ b/lml/plugin.py
@@ -22,7 +22,7 @@
     can be overridden to help its matching :class:`~lml.plugin.PluginManager`
     to look itself up.
 
-    :copyright: (c) 2017-2018 by Onni Software Ltd.
+    :copyright: (c) 2017-2020 by Onni Software Ltd.
     :license: New BSD License, see LICENSE for more details
 """
 import logging
@@ -273,6 +273,7 @@ class PluginManager(object):
         if keywords:
             self._logger.debug(keywords)
         __key = key.lower()
+
         if __key in self.registry:
             for plugin_info in self.registry[__key]:
                 cls = self.dynamic_load_library(plugin_info)
@@ -282,8 +283,9 @@ class PluginManager(object):
                 else:
                     break
             else:
-                # only library condition coud raise an exception
-                raise Exception("%s is not installed" % library)
+                # only library condition could raise an exception
+                self._logger.debug("%s is not installed" % library)
+                self.raise_exception(key)
             self._logger.debug("load %s now for '%s'", cls, key)
             return cls
         else:
@@ -363,7 +365,10 @@ def _register_a_plugin(plugin_info, plugin_cls):
         manager.register_a_plugin(plugin_cls, plugin_info)
     else:
         # let's cache it and wait the manager to be registered
-        log.debug("caching %s", _show_me_your_name(plugin_cls.__name__))
+        try:
+            log.debug("caching %s", _show_me_your_name(plugin_cls.__name__))
+        except AttributeError:
+            log.debug("caching %s", _show_me_your_name(plugin_cls))
         CACHED_PLUGIN_INFO[plugin_info.plugin_type].append(plugin_info)
 
 
diff --git a/lml/utils.py b/lml/utils.py
index 45c474d..a9e385c 100644
--- a/lml/utils.py
+++ b/lml/utils.py
@@ -4,7 +4,7 @@
 
     json utils for dump plugin info class
 
-    :copyright: (c) 2017-2018 by Onni Software Ltd.
+    :copyright: (c) 2017-2020 by Onni Software Ltd.
     :license: New BSD License, see LICENSE for more details
 """
 import sys
@@ -41,9 +41,7 @@ def do_import(plugin_module_name):
     try:
         return _do_import(plugin_module_name)
     except ImportError:
-        log.exception(
-            "%s is abscent or cannot be imported", plugin_module_name
-        )
+        log.exception("%s is absent or cannot be imported", plugin_module_name)
         raise
 
 
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 0000000..e69de29
diff --git a/rnd_requirements.txt b/rnd_requirements.txt
new file mode 100644
index 0000000..84372e8
--- /dev/null
+++ b/rnd_requirements.txt
@@ -0,0 +1 @@
+https://github.com/pyexcel/pyexcel-xls/archive/v0.4.x.zip
diff --git a/setup.cfg b/setup.cfg
index 45563e7..8c8abfd 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,10 +1,4 @@
 [metadata]
 description-file = README.rst
-
 [bdist_wheel]
 universal = 1
-
-[egg_info]
-tag_build = 
-tag_date = 0
-
diff --git a/setup.py b/setup.py
index c62cafe..fd839e9 100644
--- a/setup.py
+++ b/setup.py
@@ -1,72 +1,94 @@
 #!/usr/bin/env python3
 
-# Template by pypi-mobans
+"""
+Template by pypi-mobans
+"""
+
 import os
 import sys
 import codecs
+import locale
+import platform
 from shutil import rmtree
 
 from setuptools import Command, setup, find_packages
 
 PY2 = sys.version_info[0] == 2
 PY26 = PY2 and sys.version_info[1] < 7
-
-NAME = 'lml'
-AUTHOR = 'C.W.'
-VERSION = '0.0.9'
-EMAIL = 'wangc_2011@hotmail.com'
-LICENSE = 'New BSD'
+PY33 = sys.version_info < (3, 4)
+
+# Work around mbcs bug in distutils.
+# http://bugs.python.org/issue10945
+# This work around is only if a project supports Python < 3.4
+
+# Work around for locale not being set
+try:
+    lc = locale.getlocale()
+    pf = platform.system()
+    if pf != "Windows" and lc == (None, None):
+        locale.setlocale(locale.LC_ALL, "C.UTF-8")
+except (ValueError, UnicodeError, locale.Error):
+    locale.setlocale(locale.LC_ALL, "en_US.UTF-8")
+
+NAME = "lml"
+AUTHOR = "C.W."
+VERSION = "0.1.0"
+EMAIL = "wangc_2011@hotmail.com"
+LICENSE = "New BSD"
 DESCRIPTION = (
-    'Load me later. A lazy plugin management system.'
+    "Load me later. A lazy plugin management system."
 )
-URL = 'https://github.com/chfw/lml'
-DOWNLOAD_URL = '%s/archive/0.0.9.tar.gz' % URL
-FILES = ['README.rst', 'CHANGELOG.rst']
+URL = "https://github.com/python-lml/lml"
+DOWNLOAD_URL = "%s/archive/0.1.0.tar.gz" % URL
+FILES = ["README.rst", "CHANGELOG.rst"]
 KEYWORDS = [
-    'python',
+    "python",
 ]
 
 CLASSIFIERS = [
-    'Topic :: Software Development :: Libraries',
-    'Programming Language :: Python',
-    'Intended Audience :: Developers',
-    'Programming Language :: Python :: 2.6',
-    'Programming Language :: Python :: 2.7',
-    'Programming Language :: Python :: 3.3',
-    'Programming Language :: Python :: 3.4',
-    'Programming Language :: Python :: 3.5',
-    'Programming Language :: Python :: 3.6',
+    "Topic :: Software Development :: Libraries",
+    "Programming Language :: Python",
+    "Intended Audience :: Developers",
+    "Programming Language :: Python :: 2.6",
+    "Programming Language :: Python :: 2.7",
+    "Programming Language :: Python :: 3.3",
+    "Programming Language :: Python :: 3.4",
+    "Programming Language :: Python :: 3.5",
+    "Programming Language :: Python :: 3.6",
+    "Programming Language :: Python :: 3.7",
+    "Programming Language :: Python :: 3.8",
+
 ]
 
+
 INSTALL_REQUIRES = [
 ]
 SETUP_COMMANDS = {}
 
-
-PACKAGES = find_packages(exclude=['ez_setup', 'examples', 'tests'])
+PACKAGES = find_packages(exclude=["ez_setup", "examples", "tests", "tests.*"])
 EXTRAS_REQUIRE = {}
 # You do not need to read beyond this line
-PUBLISH_COMMAND = '{0} setup.py sdist bdist_wheel upload -r pypi'.format(
-    sys.executable)
-GS_COMMAND = ('gs lml v0.0.9 ' +
-              "Find 0.0.9 in changelog for more details")
-NO_GS_MESSAGE = ('Automatic github release is disabled. ' +
-                 'Please install gease to enable it.')
+PUBLISH_COMMAND = "{0} setup.py sdist bdist_wheel upload -r pypi".format(sys.executable)
+HERE = os.path.abspath(os.path.dirname(__file__))
+
+GS_COMMAND = ("gease lml v0.1.0 " +
+              "Find 0.1.0 in changelog for more details")
+NO_GS_MESSAGE = ("Automatic github release is disabled. " +
+                 "Please install gease to enable it.")
 UPLOAD_FAILED_MSG = (
     'Upload failed. please run "%s" yourself.' % PUBLISH_COMMAND)
-HERE = os.path.abspath(os.path.dirname(__file__))
 
 
 class PublishCommand(Command):
     """Support setup.py upload."""
 
-    description = 'Build and publish the package on github and pypi'
+    description = "Build and publish the package on github and pypi"
     user_options = []
 
     @staticmethod
     def status(s):
         """Prints things in bold."""
-        print('\033[1m{0}\033[0m'.format(s))
+        print("\033[1m{0}\033[0m".format(s))
 
     def initialize_options(self):
         pass
@@ -76,14 +98,14 @@ class PublishCommand(Command):
 
     def run(self):
         try:
-            self.status('Removing previous builds...')
-            rmtree(os.path.join(HERE, 'dist'))
-            rmtree(os.path.join(HERE, 'build'))
-            rmtree(os.path.join(HERE, 'lml.egg-info'))
+            self.status("Removing previous builds...")
+            rmtree(os.path.join(HERE, "dist"))
+            rmtree(os.path.join(HERE, "build"))
+            rmtree(os.path.join(HERE, "lml.egg-info"))
         except OSError:
             pass
 
-        self.status('Building Source and Wheel (universal) distribution...')
+        self.status("Building Source and Wheel (universal) distribution...")
         run_status = True
         if has_gease():
             run_status = os.system(GS_COMMAND) == 0
@@ -91,16 +113,15 @@ class PublishCommand(Command):
             self.status(NO_GS_MESSAGE)
         if run_status:
             if os.system(PUBLISH_COMMAND) != 0:
-                self.status(UPLOAD_FAILED_MSG % PUBLISH_COMMAND)
+                self.status(UPLOAD_FAILED_MSG)
 
         sys.exit()
 
 
 SETUP_COMMANDS.update({
-    'publish': PublishCommand
+    "publish": PublishCommand
 })
 
-
 def has_gease():
     """
     test if github release command is installed
@@ -126,7 +147,7 @@ def read_files(*files):
 def read(afile):
     """Read a file into setup"""
     the_relative_file = os.path.join(HERE, afile)
-    with codecs.open(the_relative_file, 'r', 'utf-8') as opened_file:
+    with codecs.open(the_relative_file, "r", "utf-8") as opened_file:
         content = filter_out_test_code(opened_file)
         content = "".join(list(content))
         return content
@@ -135,11 +156,11 @@ def read(afile):
 def filter_out_test_code(file_handle):
     found_test_code = False
     for line in file_handle.readlines():
-        if line.startswith('.. testcode:'):
+        if line.startswith(".. testcode:"):
             found_test_code = True
             continue
         if found_test_code is True:
-            if line.startswith('  '):
+            if line.startswith("  "):
                 continue
             else:
                 empty_line = line.strip()
@@ -149,15 +170,16 @@ def filter_out_test_code(file_handle):
                     found_test_code = False
                     yield line
         else:
-            for keyword in ['|version|', '|today|']:
+            for keyword in ["|version|", "|today|"]:
                 if keyword in line:
                     break
             else:
                 yield line
 
 
-if __name__ == '__main__':
+if __name__ == "__main__":
     setup(
+        test_suite="tests",
         name=NAME,
         author=AUTHOR,
         version=VERSION,
@@ -169,7 +191,7 @@ if __name__ == '__main__':
         license=LICENSE,
         keywords=KEYWORDS,
         extras_require=EXTRAS_REQUIRE,
-        tests_require=['nose'],
+        tests_require=["nose"],
         install_requires=INSTALL_REQUIRES,
         packages=PACKAGES,
         include_package_data=True,
diff --git a/test.sh b/test.sh
new file mode 100644
index 0000000..8527177
--- /dev/null
+++ b/test.sh
@@ -0,0 +1,5 @@
+pip freeze
+cd tests/test_plugin
+python setup.py install
+cd -
+pytest tests --verbosity=3 --cov=lml --doctest-glob=*.rst && flake8 . --exclude=.moban.d,docs,setup.py --builtins=unicode,xrange,long
diff --git a/tests/__init__.py b/tests/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/tests/requirements.txt b/tests/requirements.txt
index 8c52119..05bb89b 100644
--- a/tests/requirements.txt
+++ b/tests/requirements.txt
@@ -1,5 +1,6 @@
 mock
-nose
+pytest
+pytest-cov
 codecov
 coverage
 flake8
diff --git a/tests/sample_plugin/sample_plugin/__init__.py b/tests/sample_plugin/sample_plugin/__init__.py
index e062d6b..c3eac13 100644
--- a/tests/sample_plugin/sample_plugin/__init__.py
+++ b/tests/sample_plugin/sample_plugin/__init__.py
@@ -1,4 +1,3 @@
 from lml.registry import PluginInfoChain
 
-
 __test_plugins__ = PluginInfoChain(__name__).add_a_plugin("test_io2", "reader")
diff --git a/tests/test_plugin/pyexcel_test/__init__.py b/tests/test_plugin/pyexcel_test/__init__.py
index e5c2055..d11cfe6 100644
--- a/tests/test_plugin/pyexcel_test/__init__.py
+++ b/tests/test_plugin/pyexcel_test/__init__.py
@@ -1,4 +1,3 @@
 from lml.plugin import PluginInfoChain
 
-
 __test_plugins__ = PluginInfoChain(__name__).add_a_plugin("test_io", "x")
diff --git a/tests/test_plugin_info.py b/tests/test_plugin_info.py
index c81f4c7..d9ecffa 100644
--- a/tests/test_plugin_info.py
+++ b/tests/test_plugin_info.py
@@ -1,7 +1,6 @@
 import json
 
 from lml.plugin import PluginInfo
-from nose.tools import eq_
 
 
 def test_plugin_info():
@@ -18,7 +17,7 @@ def test_plugin_info():
         "plugin_type": "renderer",
         "custom": "property",
     }
-    eq_(json.loads(info.__repr__()), expected)
+    assert json.loads(info.__repr__()) == expected
 
 
 def test_module_name_scenario_2():
@@ -27,4 +26,4 @@ def test_module_name_scenario_2():
 
     info = PluginInfo("renderer", custom="property")
     info.cls = TestClass2
-    eq_(info.module_name, "test_plugin_info")
+    assert info.module_name == "tests.test_plugin_info"
diff --git a/tests/test_plugin_loader.py b/tests/test_plugin_loader.py
index 356644b..968b9cb 100644
--- a/tests/test_plugin_loader.py
+++ b/tests/test_plugin_loader.py
@@ -1,5 +1,4 @@
 from mock import patch
-from nose.tools import eq_
 
 
 @patch("pkgutil.get_importer")
@@ -10,7 +9,7 @@ def test_load_from_pyinstaller(pkgutil_get_importer):
 
     module_names = scan_from_pyinstaller("pyexcel_", "path")
     expected = ["pyexcel_io", "pyexcel_xls"]
-    eq_(sorted(list(module_names)), sorted(expected))
+    assert sorted(list(module_names)) == sorted(expected)
 
 
 @patch("pkgutil.get_importer")
@@ -21,7 +20,7 @@ def test_load_from_pyinstaller_with_regex(pkgutil_get_importer):
 
     module_names = scan_from_pyinstaller("^.+cel_.+$", "path")
     expected = ["pyexcel_io", "pyexcel_xls"]
-    eq_(sorted(list(module_names)), sorted(expected))
+    assert sorted(list(module_names)) == sorted(expected)
 
 
 @patch("pkgutil.get_importer")
@@ -37,8 +36,8 @@ def test_load_plugins(pkgutil_iter_modules, pkgutil_get_importer):
     from lml.plugin import CACHED_PLUGIN_INFO
 
     info = CACHED_PLUGIN_INFO["test_io"][0]
-    eq_(info.plugin_type, "test_io")
-    eq_(info.absolute_import_path, "pyexcel_test.x")
+    assert info.plugin_type == "test_io"
+    assert info.absolute_import_path == "pyexcel_test.x"
 
 
 @patch("pkgutil.get_importer")
@@ -57,8 +56,8 @@ def test_load_plugins_without_pyinstaller(
     from lml.plugin import CACHED_PLUGIN_INFO
 
     info = CACHED_PLUGIN_INFO["test_io"][0]
-    eq_(info.plugin_type, "test_io")
-    eq_(info.absolute_import_path, "pyexcel_test.x")
+    assert info.plugin_type == "test_io"
+    assert info.absolute_import_path == "pyexcel_test.x"
 
 
 @patch("pkgutil.get_importer")
@@ -73,7 +72,7 @@ def test_load_plugins_without_any_plugins(
     from lml.loader import scan_plugins
 
     scan_plugins("pyexcel_", ".", ["pyexcel_io"])
-    assert mocked_load_me_later.called is False
+    assert not mocked_load_me_later.called
 
 
 @patch("pkgutil.get_importer")
@@ -88,7 +87,7 @@ def test_load_plugins_without_black_list(
     from lml.loader import scan_plugins
 
     scan_plugins("pyexcel_", ".")
-    assert mocked_load_me_later.called is False
+    assert not mocked_load_me_later.called
 
 
 @patch("pkgutil.get_importer")
@@ -103,4 +102,4 @@ def test_load_plugins_import_error(
     from lml.loader import scan_plugins
 
     scan_plugins("test_", ".", ["pyexcel_io"])
-    assert mocked_load_me_later.called is False
+    assert not mocked_load_me_later.called
diff --git a/tests/test_plugin_manager.py b/tests/test_plugin_manager.py
index 49ea972..b82b436 100644
--- a/tests/test_plugin_manager.py
+++ b/tests/test_plugin_manager.py
@@ -1,4 +1,3 @@
-from mock import patch
 from lml.plugin import (
     PLUG_IN_MANAGERS,
     CACHED_PLUGIN_INFO,
@@ -6,7 +5,9 @@ from lml.plugin import (
     PluginManager,
     _show_me_your_name,
 )
-from nose.tools import eq_, raises
+
+from mock import patch
+from pytest import raises
 
 
 def test_plugin_manager():
@@ -32,28 +33,40 @@ def test_load_me_now(mock_import):
     plugin_info = make_me_a_plugin_info(test_plugin)
     manager.load_me_later(plugin_info)
     actual = manager.load_me_now(test_plugin)
-    eq_(actual, custom_class)
-    eq_(manager.tag_groups, {"my plugin": "my plugin"})
-    eq_(plugin_info, manager.registry["my plugin"][0])
+    assert actual == custom_class
+    assert manager.tag_groups == {"my plugin": "my plugin"}
+    assert plugin_info == manager.registry["my plugin"][0]
 
 
-@raises(Exception)
 @patch("lml.plugin.do_import_class")
-def test_load_me_now_exception(mock_import):
+def test_load_me_now_with_known_missing_library(mock_import):
     custom_class = PluginInfo
     mock_import.return_value = custom_class
     test_plugin = "my plugin"
     manager = PluginManager(test_plugin)
-    plugin_info = make_me_a_plugin_info("my")
+    plugin_info = make_me_a_plugin_info(test_plugin)
     manager.load_me_later(plugin_info)
-    manager.load_me_now("my", "my special library")
+    with raises(Exception):
+        manager.load_me_now(test_plugin, library='alien')
+
+
+@patch("lml.plugin.do_import_class")
+def test_load_me_now_exception(mock_import):
+    custom_class = PluginInfo
+    mock_import.return_value = custom_class
+    test_plugin = "my plugin"
+    with raises(Exception):
+        manager = PluginManager(test_plugin)
+        plugin_info = make_me_a_plugin_info("my")
+        manager.load_me_later(plugin_info)
+        manager.load_me_now("my", "my special library")
 
 
-@raises(Exception)
 def test_load_me_now_no_key_found():
     test_plugin = "my plugin"
-    manager = PluginManager(test_plugin)
-    manager.load_me_now("my", custom_property="here")
+    with raises(Exception):
+        manager = PluginManager(test_plugin)
+        manager.load_me_now("my", custom_property="here")
 
 
 @patch("lml.plugin.do_import_class")
@@ -64,7 +77,7 @@ def test_dynamic_load_library(mock_import):
     manager = PluginManager(test_plugin)
     plugin_info = make_me_a_plugin_info(test_plugin)
     manager.dynamic_load_library(plugin_info)
-    eq_(custom_obj, plugin_info.cls)
+    assert custom_obj == plugin_info.cls
 
 
 @patch("lml.plugin.do_import_class")
@@ -87,9 +100,9 @@ def test_register_a_plugin():
     manager = PluginManager(test_plugin)
     plugin_info = make_me_a_plugin_info("my")
     manager.register_a_plugin(TestClass, plugin_info)
-    eq_(plugin_info.cls, TestClass)
-    eq_(manager.registry["my"][0], plugin_info)
-    eq_(manager.tag_groups, {"my": "my"})
+    assert plugin_info.cls == TestClass
+    assert manager.registry["my"][0] == plugin_info
+    assert manager.tag_groups == {"my": "my"}
 
 
 def test_get_a_plugin():
@@ -121,11 +134,11 @@ def test_load_me_later_function():
     assert list(manager.registry.keys()) == [test_plugin]
 
 
-@raises(ImportError)
 def test_do_import_cls_error():
     from lml.plugin import do_import_class
 
-    do_import_class("non.exist.class")
+    with raises(ImportError):
+        do_import_class("non.exist.class")
 
 
 def test_register_a_plugin_function_1():
@@ -157,7 +170,7 @@ def test_primary_key():
         pass
 
     pk = manager.get_primary_key("key 1")
-    eq_(pk, "primary key")
+    assert pk == "primary key"
 
 
 def test_dict_as_plugin_payload():
@@ -167,7 +180,7 @@ def test_dict_as_plugin_payload():
     plugin(dict(B=1))
 
     instance = manager.load_me_now("key 1")
-    eq_(instance, dict(B=1))
+    assert instance == dict(B=1)
 
 
 def test_show_me_your_name():
@@ -175,7 +188,7 @@ def test_show_me_your_name():
         pass
 
     name = _show_me_your_name(Test)
-    eq_(name, "Test")
+    assert name == "Test"
 
     name2 = _show_me_your_name(dict(A=1))
     assert "dict" in name2
diff --git a/tests/test_utils.py b/tests/test_utils.py
index 0f4a605..e6820c9 100644
--- a/tests/test_utils.py
+++ b/tests/test_utils.py
@@ -1,7 +1,8 @@
-from mock import patch
 from lml.utils import do_import, json_dumps
 from lml.plugin import PluginManager
-from nose.tools import eq_, raises
+
+from mock import patch
+from pytest import raises
 
 
 def test_json_dumps():
@@ -14,28 +15,30 @@ def test_json_dumps():
 
 
 def test_do_import():
-    import pyexcel_test
+    import isort
 
-    pyexcel_test_package = do_import("pyexcel_test")
-    eq_(pyexcel_test_package, pyexcel_test)
+    test_package = do_import("isort")
+    assert test_package == isort
 
 
 def test_do_import_2():
     import lml.plugin as plugin
 
     themodule = do_import("lml.plugin")
-    eq_(plugin, themodule)
+    assert plugin == themodule
 
 
-@raises(ImportError)
 @patch("lml.utils.log.exception")
 def test_do_import_error(mock_exception):
-    do_import("non.exist")
-    mock_exception.assert_called_with("No module named 'non'")
+    with raises(ImportError):
+        do_import("non.exist")
+    mock_exception.assert_called_with(
+        "%s is absent or cannot be imported", "non.exist"
+    )
 
 
 def test_do_import_cls():
     from lml.utils import do_import_class
 
     manager = do_import_class("lml.plugin.PluginManager")
-    eq_(manager, PluginManager)
+    assert manager == PluginManager