Codebase list python-lml / 9255412
New upstream release. Kali Janitor 1 year, 5 months ago
69 changed file(s) with 1173 addition(s) and 675 deletion(s). Raw diff Collapse all Expand all
0 on: [push]
1
2 jobs:
3 run_moban:
4 runs-on: ubuntu-latest
5 name: synchronize templates via moban
6 steps:
7 - uses: actions/checkout@v2
8 with:
9 ref: ${{ github.head_ref }}
10 - name: Set up Python
11 uses: actions/setup-python@v1
12 with:
13 python-version: '3.7'
14 - name: check changes
15 run: |
16 pip install moban gitfs2 pypifs moban-jinja2-github moban-ansible
17 moban
18 git status
19 git diff --exit-code
20 - name: Auto-commit
21 if: failure()
22 uses: docker://cdssnc/auto-commit-github-action
23 env:
24 GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
25 with:
26 args: >-
27 This is an auto-commit, updating project meta data,
28 such as changelog.rst, contributors.rst
0 name: Upload Python Package
1
2 on:
3 release:
4 types: [created]
5
6 jobs:
7 deploy:
8 runs-on: ubuntu-latest
9 steps:
10 - uses: actions/checkout@v1
11 - name: Set up Python
12 uses: actions/setup-python@v1
13 with:
14 python-version: '3.x'
15 - name: Install dependencies
16 run: |
17 python -m pip install --upgrade pip
18 pip install setuptools wheel twine
19 - name: Build and publish
20 env:
21 TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }}
22 TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }}
23 run: |
24 python setup.py sdist bdist_wheel
25 twine upload dist/*
0 # April 2016
1 # reference: https://github.com/github/gitignore/blob/master/Python.gitignore
2 # Byte-compiled / optimized / DLL files
3 __pycache__/
4 *.py[cod]
5 *$py.class
6
7 # C extensions
8 *.so
9
10 # Distribution / packaging
11 .Python
12 env/
13 build/
14 develop-eggs/
15 dist/
16 downloads/
17 eggs/
18 .eggs/
19 lib/
20 lib64/
21 parts/
22 sdist/
23 var/
24 *.egg-info/
25 .installed.cfg
26 *.egg
27
28 # PyInstaller
29 # Usually these files are written by a python script from a template
30 # before PyInstaller builds the exe, so as to inject date/other infos into it.
31 *.manifest
32 *.spec
33
34 # Installer logs
35 pip-log.txt
36 pip-delete-this-directory.txt
37
38 # Unit test / coverage reports
39 htmlcov/
40 .tox/
41 .coverage
42 .coverage.*
43 .cache
44 nosetests.xml
45 coverage.xml
46 *,cover
47 .hypothesis/
48
49 # Translations
50 *.mo
51 *.pot
52
53 # Django stuff:
54 *.log
55 local_settings.py
56
57 # Flask stuff:
58 instance/
59 .webassets-cache
60
61 # Scrapy stuff:
62 .scrapy
63
64 # Sphinx documentation
65 docs/_build/
66
67 # PyBuilder
68 target/
69
70 # IPython Notebook
71 .ipynb_checkpoints
72
73 # pyenv
74 .python-version
75
76 # celery beat schedule file
77 celerybeat-schedule
78
79 # dotenv
80 .env
81
82 # virtualenv
83 venv/
84 ENV/
85
86 # Spyder project settings
87 .spyderproject
88
89 # Rope project settings
90 .ropeproject
91 *~
92 commons/
93 commons
94 .moban.hashes
0 [submodule "examples/robotchef_allinone"]
1 path = examples/robotchef_allinone
2 url = https://github.com/python-lml/robotchef_allinone.git
3 [submodule "examples/robotchef_allinone_lml"]
4 path = examples/robotchef_allinone_lml
5 url = https://github.com/python-lml/robotchef_allinone_lml.git
6 [submodule "examples/robotchef"]
7 path = examples/robotchef
8 url = https://github.com/python-lml/robotchef.git
9 [submodule "examples/robotchef_cook"]
10 path = examples/robotchef_cook
11 url = https://github.com/python-lml/robotchef_cook.git
12 [submodule "examples/robotchef_britishcuisine"]
13 path = examples/robotchef_britishcuisine
14 url = https://github.com/python-lml/robotchef_britishcuisine.git
15 [submodule "examples/robotchef_chinesecuisine"]
16 path = examples/robotchef_chinesecuisine
17 url = https://github.com/python-lml/robotchef_chinesecuisine.git
18 [submodule "examples/v2/robotchef_v2"]
19 path = examples/v2/robotchef_v2
20 url = https://github.com/python-lml/robotchef_v2.git
21 [submodule "examples/v2/robotchef_britishcuisine"]
22 path = examples/v2/robotchef_britishcuisine
23 url = https://github.com/python-lml/robotchef_britishcuisine_v2
24 [submodule "examples/v2/robotchef_api"]
25 path = examples/v2/robotchef_api
26 url = https://github.com/python-lml/robotchef_api
0 [settings]
1 line_length=79
2 known_first_party=
3 known_third_party=mock,nose
4 indent=' '
5 multi_line_output=3
6 length_sort=1
7 default_section=FIRSTPARTY
8 no_lines_before=LOCALFOLDER
9 sections=FUTURE,STDLIB,FIRSTPARTY,THIRDPARTY,LOCALFOLDER
0 {% extends "README.rst.jj2" %}
1
2 {%block features%}
3 {%include "description.rst.jj2" %}
4 {%endblock%}
5
6 {%block bottom_block%}
7 lml enabled project
8 ================================================================================
9
10 {%include "lml-enabled-projects.rst.jj2" %}
11
12 License
13 ================================================================================
14
15 New BSD
16
17 {%endblock%}
0 {%extends "setup.py.jj2"%}
1
2
3 {%block platform_block%}
4 {%endblock %}
0 **{{name}}** seamlessly finds the lml based plugins from your current python
1 environment but loads your plugins on demand. It is designed to support
2 plugins that have external dependencies, especially bulky and/or
3 memory hungry ones. {{name}} provides the plugin management system only and the
4 plugin interface is on your shoulder.
5
6 **{{name}}** enabled applications helps your customers [#f1]_ in two ways:
7
8 #. Your customers could cherry-pick the plugins from pypi per python environment.
9 They could remove a plugin using `pip uninstall` command.
10 #. Only the plugins used at runtime gets loaded into computer memory.
11
12 When you would use **lml** to refactor your existing code, it aims to flatten the
13 complexity and to shrink the size of your bulky python library by
14 distributing the similar functionalities across its plugins. However, you as
15 the developer need to do the code refactoring by yourself and lml would lend you a hand.
16
17 .. [#f1] the end developers who uses your library and packages achieve their
18 objectives.
19
20
21 Quick start
22 ================================================================================
23
24 The following code tries to get you started quickly with **non-lazy** loading.
25
26 .. code-block:: python
27
28 from lml.plugin import PluginInfo, PluginManager
29
30
31 @PluginInfo("cuisine", tags=["Portable Battery"])
32 class Boost(object):
33 def make(self, food=None, **keywords):
34 print("I can cook %s for robots" % food)
35
36
37 class CuisineManager(PluginManager):
38 def __init__(self):
39 PluginManager.__init__(self, "cuisine")
40
41 def get_a_plugin(self, food_name=None, **keywords):
42 return PluginManager.get_a_plugin(self, key=food_name, **keywords)
43
44
45 if __name__ == '__main__':
46 manager = CuisineManager()
47 chef = manager.get_a_plugin("Portable Battery")
48 chef.make()
49
50
51 At a glance, above code simply replaces the Factory pattern should you write
52 them without lml. What's not obvious is, that once you got hands-on with it,
53 you can start work on how to do **lazy** loading.
54
0 {% include "docs/source/myconf.py.jj2" %}
1
2 master_doc = "index"
0 `{{name}}` - {{description}}
1 ================================================================================
2
3
4 :Author: C.W.
5 :Source code: http://github.com/{{name}}/{{name}}.git
6 :Issues: http://github.com/{{name}}/{{name}}/issues
7 :License: New BSD License
8 :Released: |version|
9 :Generated: |today|
10
11
12 Introduction
13 -------------
14
15 {% include "description.rst.jj2" %}
16
17
18 Documentation
19 ----------------
20
21 .. toctree::
22 :maxdepth: 2
23
24 design
25 tutorial
26 lml_log
27 api
28
29 {%include "lml-enabled-projects.rst.jj2" %}
0 {%extends "docs/source/conf.py.jj2"%}
1
2 {%block SPHINX_EXTENSIONS%}
3 'sphinx.ext.napoleon',
4 'sphinxcontrib.spelling'
5 {%endblock%}
6
7 {%block additional_config%}
8 spelling_lang = 'en_GB'
9 spelling_word_list_filename = 'spelling_wordlist.txt'
10 {%endblock%}
0 Beyond the documentation above, here is a list of projects using lml:
1
2 #. `pyexcel <https://github.com/pyexcel/pyexcel>`_
3 #. `pyecharts <https://github.com/pyecharts/pyecharts>`_
4 #. `moban <https://github.com/moremoban/moban>`_
5
6 lml is available on these distributions:
7
8 #. `ARCH linux <https://aur.archlinux.org/packages/python-lml/>`_
9 #. `Conda forge <https://anaconda.org/conda-forge/lml>`_
10 #. `OpenSuse <https://build.opensuse.org/package/show/devel:languages:python/python-lml>`_
11
0 {% for dependency in dependencies: %}
1 {{dependency}}
2 {% endfor %}
0 {%block pretest%}
1 {%endblock%}
2 {%if external_module_library%}
3 {%set package=external_module_library%}
4 {%else%}
5 {%if command_line_interface%}
6 {%set package=command_line_interface + '_cli' %}
7 {%else%}
8 {%set package=name%}
9 {%endif%}
10 {%endif%}
11 pip freeze
12 cd tests/test_plugin
13 python setup.py install
14 cd -
15 pytest tests --verbosity=3 --cov=lml --doctest-glob=*.rst && flake8 . --exclude=.moban.d,docs,setup.py {%block flake8_options%}--builtins=unicode,xrange,long{%endblock%}
16
17 {%block posttest%}
18 {%endblock%}
0 configuration:
1 template_dir:
2 - "git://github.com/moremoban/pypi-mobans.git?submodule=true&brach=dev!/statics"
3 - "git://github.com/moremoban/pypi-mobans.git?submodule=true&branch=dev!/templates"
4 - ".moban.d"
5 configuration: lml.yml
6 targets:
7 - README.rst: CUSTOM_README.rst.jj2
8 - setup.py: custom_setup.py.jj2
9 - requirements.txt: requirements.txt.jj2
10 - "docs/source/conf.py": "docs/source/custom_conf.py.jj2"
11 - "docs/source/index.rst": "docs/source/custom_index.rst.jj2"
12 - test.sh: test.sh.jj2
13 - "lml/_version.py": _version.py.jj2
14 - output: CHANGELOG.rst
15 configuration: changelog.yml
16 template: CHANGELOG.rst.jj2
17 - ".github/workflows/pythonpublish.yml": "pythonpublish.yml"
18 - ".github/workflows/moban-update.yml": "moban-update.yml"
19 - CONTRIBUTORS.rst: CONTRIBUTORS.rst.jj2
20 - MANIFEST.in: MANIFEST.in.jj2
0 sudo: false
1 language: python
2 notifications:
3 email: false
4 python:
5 - 3.9-dev
6 - 3.8
7 - 3.7
8 - 3.6
9 before_install:
10 - pip install -r tests/requirements.txt
11 script:
12 - make test
13 after_success:
14 codecov
00 Change log
11 ================================================================================
2
3 0.1.0 - 21/10/2020
4 --------------------------------------------------------------------------------
5
6 **Updated**
7
8 #. non class object can be a plugin too
9 #. `#20 <https://github.com/python-lml/lml/issues/20>`_: When a plugin was not
10 installed, it now calls raise_exception method
211
312 0.0.9 - 7/1/2019
413 --------------------------------------------------------------------------------
514
6 Updated
7 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
15 **Updated**
816
9 #. `#11 <https://github.com/chfw/lml/issues/11>`_: more test contents for
17 #. `#11 <https://github.com/python-lml/lml/issues/11>`_: more test contents for
1018 OpenSuse package validation
1119
1220 0.0.8 - 4/1/2019
1321 --------------------------------------------------------------------------------
1422
15 Updated
16 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
23 **Updated**
1724
18 #. `#9 <https://github.com/chfw/lml/issues/9>`_: include tests, docs for
25 #. `#9 <https://github.com/python-lml/lml/issues/9>`_: include tests, docs for
1926 OpenSuse package validation
2027
2128 0.0.7 - 17/11/2018
2229 --------------------------------------------------------------------------------
2330
24 Fixed
25 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
31 **Fixed**
2632
27 #. `#8 <https://github.com/chfw/lml/issues/8>`_: get_primary_key will fail when
28 a module is loaded later
33 #. `#8 <https://github.com/python-lml/lml/issues/8>`_: get_primary_key will fail
34 when a module is loaded later
2935 #. deprecated old style plugin scanner: scan_plugins
3036
3137 0.0.6 - 07/11/2018
3238 --------------------------------------------------------------------------------
3339
34 Fixed
35 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
40 **Fixed**
3641
3742 #. Revert the version 0.0.5 changes. Raise Import error and log the exception
3843
3944 0.0.5 - 06/11/2018
4045 --------------------------------------------------------------------------------
4146
42 Fixed
43 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
47 **Fixed**
4448
45 #. `#6 <https://github.com/chfw/lml/issues/6>`_: Catch and Ignore
49 #. `#6 <https://github.com/python-lml/lml/issues/6>`_: Catch and Ignore
4650 ModuleNotFoundError
4751
4852 0.0.4 - 07.08.2018
4953 --------------------------------------------------------------------------------
5054
51 Added
52 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
55 **Added**
5356
54 #. `#4 <https://github.com/chfw/lml/issues/4>`_: to find plugin names with
57 #. `#4 <https://github.com/python-lml/lml/issues/4>`_: to find plugin names with
5558 different naming patterns
5659
5760 0.0.3 - 12/06/2018
5861 --------------------------------------------------------------------------------
5962
60 Added
61 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
63 **Added**
6264
6365 #. `dict` can be a pluggable type in addition to `function`, `class`
6466 #. get primary tag of your tag, helping you find out which category of plugins
6769 0.0.2 - 23/10/2017
6870 --------------------------------------------------------------------------------
6971
70 Updated
71 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
72 **Updated**
7273
7374 #. `pyexcel#103 <https://github.com/pyexcel/pyexcel/issues/103>`_: include
7475 LICENSE in tar ball
7677 0.0.1 - 30/05/2017
7778 --------------------------------------------------------------------------------
7879
79 Added
80 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
80 **Added**
8181
8282 #. First release
0
1
2 2 contributors
3 ================================================================================
4
5 In alphabetical order:
6
7 * `Ayan Banerjee <https://github.com/ayan-b>`_
8 * `Matěj Cepl <https://github.com/mcepl>`_
00 include README.rst
11 include LICENSE
22 include CHANGELOG.rst
3 include CONTRIBUTORS.rst
34 recursive-include tests *
4 include docs/source/*
5 recursive-include docs *
0 all: test
1
2 test:
3 bash test.sh
4
5 document:
6 python setup.py install
7 sphinx-build -b html docs/source/ docs/build
8
9 spelling:
10 sphinx-build -b spelling docs/source/ docs/build/spelling
11
12 uml:
13 plantuml -tsvg -o ../_static/images/ docs/source/uml/*.uml
14
15 format:
16 isort -y $(find lml -name "*.py"|xargs echo) $(find tests -name "*.py"|xargs echo)
17 black -l 79 lml
18 black -l 79 tests
19 black -l 79 examples
+0
-163
PKG-INFO less more
0 Metadata-Version: 1.1
1 Name: lml
2 Version: 0.0.9
3 Summary: Load me later. A lazy plugin management system.
4 Home-page: https://github.com/chfw/lml
5 Author: C.W.
6 Author-email: [email protected]
7 License: New BSD
8 Download-URL: https://github.com/chfw/lml/archive/0.0.9.tar.gz
9 Description: ================================================================================
10 lml - Load me later. A lazy plugin management system.
11 ================================================================================
12
13 .. image:: https://api.travis-ci.org/chfw/lml.svg
14 :target: http://travis-ci.org/chfw/lml
15
16 .. image:: https://codecov.io/github/chfw/lml/coverage.png
17 :target: https://codecov.io/github/chfw/lml
18
19
20 .. image:: https://readthedocs.org/projects/lml/badge/?version=latest
21 :target: http://lml.readthedocs.org/en/latest/
22
23 **lml** seamlessly finds the lml based plugins from your current python
24 environment but loads your plugins on demand. It is designed to support
25 plugins that have external dependencies, especially bulky and/or
26 memory hungry ones. lml provides the plugin management system only and the
27 plugin interface is on your shoulder.
28
29 **lml** enabled applications helps your customers [#f1]_ in two ways:
30
31 #. Your customers could cherry-pick the plugins from pypi per python environment.
32 They could remove a plugin using `pip uninstall` command.
33 #. Only the plugins used at runtime gets loaded into computer memory.
34
35 When you would use **lml** to refactor your existing code, it aims to flatten the
36 complexity and to shrink the size of your bulky python library by
37 distributing the similar functionalities across its plugins. However, you as
38 the developer need to do the code refactoring by yourself and lml would lend you a hand.
39
40 .. [#f1] the end developers who uses your library and packages achieve their
41 objectives.
42
43 Installation
44 ================================================================================
45
46
47 You can install lml via pip:
48
49 .. code-block:: bash
50
51 $ pip install lml
52
53
54 or clone it and install it:
55
56 .. code-block:: bash
57
58 $ git clone https://github.com/chfw/lml.git
59 $ cd lml
60 $ python setup.py install
61
62 License
63 ================================================================================
64
65 New BSD
66
67 Change log
68 ================================================================================
69
70 0.0.9 - 7/1/2019
71 --------------------------------------------------------------------------------
72
73 Updated
74 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
75
76 #. `#11 <https://github.com/chfw/lml/issues/11>`_: more test contents for
77 OpenSuse package validation
78
79 0.0.8 - 4/1/2019
80 --------------------------------------------------------------------------------
81
82 Updated
83 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
84
85 #. `#9 <https://github.com/chfw/lml/issues/9>`_: include tests, docs for
86 OpenSuse package validation
87
88 0.0.7 - 17/11/2018
89 --------------------------------------------------------------------------------
90
91 Fixed
92 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
93
94 #. `#8 <https://github.com/chfw/lml/issues/8>`_: get_primary_key will fail when
95 a module is loaded later
96 #. deprecated old style plugin scanner: scan_plugins
97
98 0.0.6 - 07/11/2018
99 --------------------------------------------------------------------------------
100
101 Fixed
102 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
103
104 #. Revert the version 0.0.5 changes. Raise Import error and log the exception
105
106 0.0.5 - 06/11/2018
107 --------------------------------------------------------------------------------
108
109 Fixed
110 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
111
112 #. `#6 <https://github.com/chfw/lml/issues/6>`_: Catch and Ignore
113 ModuleNotFoundError
114
115 0.0.4 - 07.08.2018
116 --------------------------------------------------------------------------------
117
118 Added
119 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
120
121 #. `#4 <https://github.com/chfw/lml/issues/4>`_: to find plugin names with
122 different naming patterns
123
124 0.0.3 - 12/06/2018
125 --------------------------------------------------------------------------------
126
127 Added
128 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
129
130 #. `dict` can be a pluggable type in addition to `function`, `class`
131 #. get primary tag of your tag, helping you find out which category of plugins
132 your tag points to
133
134 0.0.2 - 23/10/2017
135 --------------------------------------------------------------------------------
136
137 Updated
138 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
139
140 #. `pyexcel#103 <https://github.com/pyexcel/pyexcel/issues/103>`_: include
141 LICENSE in tar ball
142
143 0.0.1 - 30/05/2017
144 --------------------------------------------------------------------------------
145
146 Added
147 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
148
149 #. First release
150
151
152 Keywords: python
153 Platform: UNKNOWN
154 Classifier: Topic :: Software Development :: Libraries
155 Classifier: Programming Language :: Python
156 Classifier: Intended Audience :: Developers
157 Classifier: Programming Language :: Python :: 2.6
158 Classifier: Programming Language :: Python :: 2.7
159 Classifier: Programming Language :: Python :: 3.3
160 Classifier: Programming Language :: Python :: 3.4
161 Classifier: Programming Language :: Python :: 3.5
162 Classifier: Programming Language :: Python :: 3.6
11 lml - Load me later. A lazy plugin management system.
22 ================================================================================
33
4 .. image:: https://api.travis-ci.org/chfw/lml.svg
5 :target: http://travis-ci.org/chfw/lml
4 .. image:: https://api.travis-ci.org/python-lml/lml.svg
5 :target: http://travis-ci.org/python-lml/lml
66
7 .. image:: https://codecov.io/github/chfw/lml/coverage.png
8 :target: https://codecov.io/github/chfw/lml
7 .. image:: https://codecov.io/github/python-lml/lml/coverage.png
8 :target: https://codecov.io/github/python-lml/lml
9 .. image:: https://badge.fury.io/py/lml.svg
10 :target: https://pypi.org/project/lml
911
12 .. image:: https://pepy.tech/badge/lml/month
13 :target: https://pepy.tech/project/lml/month
14
15 .. image:: https://img.shields.io/github/stars/python-lml/lml.svg?style=social&maxAge=3600&label=Star
16 :target: https://github.com/python-lml/lml/stargazers
17
18 .. 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
19 :target: https://moban.readthedocs.io/en/latest/#at-scale-continous-templating-for-open-source-projects
20
21 .. image:: https://img.shields.io/static/v1?label=coding%20style&message=black&color=black&style=flat-square
22 :target: https://github.com/psf/black
1023
1124 .. image:: https://readthedocs.org/projects/lml/badge/?version=latest
1225 :target: http://lml.readthedocs.org/en/latest/
3144 .. [#f1] the end developers who uses your library and packages achieve their
3245 objectives.
3346
47
48 Quick start
49 ================================================================================
50
51 The following code tries to get you started quickly with **non-lazy** loading.
52
53 .. code-block:: python
54
55 from lml.plugin import PluginInfo, PluginManager
56
57
58 @PluginInfo("cuisine", tags=["Portable Battery"])
59 class Boost(object):
60 def make(self, food=None, **keywords):
61 print("I can cook %s for robots" % food)
62
63
64 class CuisineManager(PluginManager):
65 def __init__(self):
66 PluginManager.__init__(self, "cuisine")
67
68 def get_a_plugin(self, food_name=None, **keywords):
69 return PluginManager.get_a_plugin(self, key=food_name, **keywords)
70
71
72 if __name__ == '__main__':
73 manager = CuisineManager()
74 chef = manager.get_a_plugin("Portable Battery")
75 chef.make()
76
77
78 At a glance, above code simply replaces the Factory pattern should you write
79 them without lml. What's not obvious is, that once you got hands-on with it,
80 you can start work on how to do **lazy** loading.
81
82
3483 Installation
3584 ================================================================================
3685
4695
4796 .. code-block:: bash
4897
49 $ git clone https://github.com/chfw/lml.git
98 $ git clone https://github.com/python-lml/lml.git
5099 $ cd lml
51100 $ python setup.py install
101
102 lml enabled project
103 ================================================================================
104
105 Beyond the documentation above, here is a list of projects using lml:
106
107 #. `pyexcel <https://github.com/pyexcel/pyexcel>`_
108 #. `pyecharts <https://github.com/pyecharts/pyecharts>`_
109 #. `moban <https://github.com/moremoban/moban>`_
110
111 lml is available on these distributions:
112
113 #. `ARCH linux <https://aur.archlinux.org/packages/python-lml/>`_
114 #. `Conda forge <https://anaconda.org/conda-forge/lml>`_
115 #. `OpenSuse <https://build.opensuse.org/package/show/devel:languages:python/python-lml>`_
116
52117
53118 License
54119 ================================================================================
0 name: lml
1 organisation: python-lml
2 releases:
3 - changes:
4 - action: Updated
5 details:
6 - "non class object can be a plugin too"
7 - "`#20`: When a plugin was not installed, it now calls raise_exception method"
8 date: 21/10/2020
9 version: 0.1.0
10 - changes:
11 - action: Updated
12 details:
13 - "`#11`: more test contents for OpenSuse package validation"
14 date: 7/1/2019
15 version: 0.0.9
16 - changes:
17 - action: Updated
18 details:
19 - "`#9`: include tests, docs for OpenSuse package validation"
20 date: 4/1/2019
21 version: 0.0.8
22 - changes:
23 - action: Fixed
24 details:
25 - "`#8`: get_primary_key will fail when a module is loaded later"
26 - "deprecated old style plugin scanner: scan_plugins"
27 date: 17/11/2018
28 version: 0.0.7
29 - changes:
30 - action: Fixed
31 details:
32 - "Revert the version 0.0.5 changes. Raise Import error and log the exception"
33 date: 07/11/2018
34 version: 0.0.6
35 - changes:
36 - action: Fixed
37 details:
38 - "`#6`: Catch and Ignore ModuleNotFoundError"
39 date: 06/11/2018
40 version: 0.0.5
41 - changes:
42 - action: Added
43 details:
44 - "`#4`: to find plugin names with different naming patterns"
45 date: 07.08.2018
46 version: 0.0.4
47 - changes:
48 - action: Added
49 details:
50 - "`dict` can be a pluggable type in addition to `function`, `class`"
51 - get primary tag of your tag, helping you find out which category of plugins your tag points to
52 date: 12/06/2018
53 version: 0.0.3
54 - changes:
55 - action: Updated
56 details:
57 - "`pyexcel#103 <https://github.com/pyexcel/pyexcel/issues/103>`_: include LICENSE in tar ball"
58 date: 23/10/2017
59 version: 0.0.2
60 - changes:
61 - action: Added
62 details:
63 - First release
64 date: 30/05/2017
65 version: 0.0.1
0 python-lml (0.1.0-0kali1) UNRELEASED; urgency=low
1
2 * New upstream release.
3
4 -- Kali Janitor <[email protected]> Thu, 08 Dec 2022 01:01:37 -0000
5
06 python-lml (0.0.9-0kali2) kali-dev; urgency=medium
17
28 [ Raphaël Hertzog ]
0 sphinxcontrib-plantuml
1
0 <?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><!--
1 @startuml
2
3 actor bob
4 participant robotchef
5 participant lml
6 participant robotchef_britishcuisine
7
8 bob -> robotchef : > robotchef "Jacket Potato"
9 robotchef -> lml : scan for plugins.
10 lml -> robotchef_britishcuisine : read plugin chain in the module
11 robotchef_britishcuisine -> lml: I can help with "Jacket Potato" and others.
12 lml -> robotchef : read the built-in robot_cuisine
13 robotchef -> lml : built-in chef knows "Portable Battery"
14 lml - -> robotchef : scanning done
15 robotchef -> lml : get me a plugin that knows "Jacket Potato"
16 lml -> robotchef : robotchef_britishcuisine.bake.Bake can do
17 robotchef -> robotchef: make the food
18 robotchef -> bob : "I can bake Jacket Potato"
19 @enduml
20
21 PlantUML version 1.2017.13(Wed May 10 17:52:33 BST 2017)
22 (GPL source distribution)
23 Java Runtime: Java(TM) SE Runtime Environment
24 JVM: Java HotSpot(TM) 64-Bit Server VM
25 Java Version: 1.8.0_131-b11
26 Operating System: Mac OS X
27 OS Version: 10.11.6
28 Default Encoding: UTF-8
29 Language: en
30 Country: US
31 --></g></svg>
0 <?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;"/><!--
1 @startuml
2
3 Interface Chef
4
5 Chef <|- - Boost
6 Chef <|- - Fry
7 Chef <|- - Bake
8
9 @enduml
10
11 PlantUML version 1.2017.13(Wed May 10 17:52:33 BST 2017)
12 (GPL source distribution)
13 Java Runtime: Java(TM) SE Runtime Environment
14 JVM: Java HotSpot(TM) 64-Bit Server VM
15 Java Version: 1.8.0_131-b11
16 Operating System: Mac OS X
17 OS Version: 10.11.6
18 Default Encoding: UTF-8
19 Language: en
20 Country: US
21 --></g></svg>
0 <?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;"/><!--
1 @startuml
2
3 package lml {
4 PluginManager o- - PluginInfo
5 }
6
7 package robotchef_allinone_lml {
8 class CuisineManager {
9 + get_a_plugin()
10 + raise_exception()
11 }
12 interface Chef {
13 + make()
14 }
15 PluginManager <|- - CuisineManager : cuisine
16 Chef <|- - Boost
17 Chef <|- - Fry
18 Chef <|- - Bake
19 PluginInfo .. Fry
20 PluginInfo .. Bake
21 PluginInfo .. Boost
22 }
23
24
25 @enduml
26
27 PlantUML version 1.2017.13(Wed May 10 17:52:33 BST 2017)
28 (GPL source distribution)
29 Java Runtime: Java(TM) SE Runtime Environment
30 JVM: Java HotSpot(TM) 64-Bit Server VM
31 Java Version: 1.8.0_131-b11
32 Operating System: Mac OS X
33 OS Version: 10.11.6
34 Default Encoding: UTF-8
35 Language: en
36 Country: US
37 --></g></svg>
0 <?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"/><!--
1 @startuml
2
3
4 package lml {
5 PluginManager .. PluginInfoChain : registers plugin info
6 PluginManager o- - PluginInfo
7 PluginInfoChain -right- PluginInfo
8 }
9
10 package robotchef_api {
11 class CuisineManager {
12 + get_a_plugin()
13 + raise_exception()
14 }
15 interface Chef {
16 + make()
17 }
18 PluginManager <|- - CuisineManager : cuisine
19 package robotchef.robot_cuisine {
20 Chef <|- - Boost
21 PluginInfoChain .. Boost
22 }
23 }
24
25 package robotchef_britishcuisine {
26 Chef <|- - Fry
27 Chef <|- - Bake
28 PluginInfoChain .. Fry
29 PluginInfoChain .. Bake
30 }
31
32 package robotchef_v2 {
33 }
34
35 robotchef_v2 +- - robotchef_api
36
37 @enduml
38
39 PlantUML version 1.2017.13(Wed May 10 17:52:33 BST 2017)
40 (GPL source distribution)
41 Java Runtime: Java(TM) SE Runtime Environment
42 JVM: Java HotSpot(TM) 64-Bit Server VM
43 Java Version: 1.8.0_131-b11
44 Operating System: Mac OS X
45 OS Version: 10.11.6
46 Default Encoding: UTF-8
47 Language: en
48 Country: US
49 --></g></svg>
0 <?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;"/><!--
1 @startuml
2
3 package lml {
4 PluginManager .. PluginInfoChain : registers plugin info
5 PluginManager o- - PluginInfo
6 PluginInfoChain -right- PluginInfo
7 }
8
9 package robotchef {
10 class CuisineManager {
11 + get_a_plugin()
12 + raise_exception()
13 }
14 interface Chef {
15 + make()
16 }
17 PluginManager <|- - CuisineManager : cuisine
18 package robotchef.robot_cuisine {
19 Chef <|- - Boost
20 PluginInfoChain .. Boost
21 }
22 }
23
24 package robotchef_britishcuisine {
25 Chef <|- - Fry
26 Chef <|- - Bake
27 PluginInfoChain .. Fry
28 PluginInfoChain .. Bake
29 }
30
31
32 @enduml
33
34 PlantUML version 1.2017.13(Wed May 10 17:52:33 BST 2017)
35 (GPL source distribution)
36 Java Runtime: Java(TM) SE Runtime Environment
37 JVM: Java HotSpot(TM) 64-Bit Server VM
38 Java Version: 1.8.0_131-b11
39 Operating System: Mac OS X
40 OS Version: 10.11.6
41 Default Encoding: UTF-8
42 Language: en
43 Country: US
44 --></g></svg>
1111 Demo
1212 --------------------------------------------------------------------------------
1313
14 Please navigate to
15 `lml/examples <https://github.com/chfw/lml/tree/master/examples>`_,
16 you would find robotchef_allinone_lml and its packages. Do the following::
14 Please navigate to robotchef_allinone_lml and its packages. Do the following::
1715
16 $ git clone https://github.com/python-lml/robotchef_allinone_lml
1817 $ cd robotchef_allinone_lml
1918 $ python setup.py install
2019
66 Demo
77 --------------------------------------------------------------------------------
88
9 Please checkout lml::
9 Please checkout the robot chef example::
1010
11 $ git clone https://github.com/chfw/lml.git
12
13 And navigate to `lml/examples <https://github.com/chfw/lml/tree/master/examples>`_,
14 you would find robotchef_allinone and its packages. Do the following::
15
11 $ git clone https://github.com/python-lml/robotchef_allinone
1612 $ cd robotchef_allinone
1713 $ python setup.py install
1814
3935
4036 .. literalinclude:: ../../examples/robotchef_allinone/robotchef_allinone/plugin.py
4137 :language: python
42 :lines: 5-26
38 :lines: 5-30
4339
4440 Line 13, class `Chef` defines the plugin class interface. For robotchef, `make` is
4541 defined to illustrate the functionality. Naturally you will be deciding the
6056
6157 .. literalinclude:: ../../examples/robotchef_allinone/robotchef_allinone/plugin.py
6258 :language: python
63 :lines: 29-
59 :lines: 33-
6460
6561 main.py
6662 +++++++++++
22
33 .. automodule:: lml.loader
44
5 .. autofunction:: scan_plugins
6
5 .. autofunction:: scan_plugins_regex
6
77 .. automodule:: lml.plugin
88
99 .. autoclass:: PluginInfo
1212
1313 .. autoclass:: PluginManager
1414 :members:
15
1010 Demo
1111 --------------------------------------------------------------------------------
1212
13 Navigate to `lml/examples/v2 <https://github.com/chfw/lml/tree/master/examples/v2>`_,
14 you would find robotchef and its packages. Do the following::
13 Please checkout the following examples::
1514
1615 $ virtualenv --no-site-packages robotchefv2
1716 $ source robotchefv2/bin/activate
17 $ git clone https://github.com/python-lml/robotchef_v2
1818 $ cd robotchef_v2
1919 $ python setup.py install
20 $ cd ..
21 $ git clone https://github.com/python-lml/robotchef_api
2022 $ cd robotchef_api
2123 $ python setup.py install
2224
3032 In order to add "Jacket Potato" in the know-how, you would need to install
3133 robotchef_britishcuisine in this folder::
3234
33 $ cd robotchef_britishcuisine
35 $ git clone https://github.com/python-lml/robotchef_britishcuisine_v2
36 $ cd robotchef_britishcuisine_v2
3437 $ python setup.py install
3538 $ robotchef_v2 "Jacket Potato"
3639 I can bake Jacket Potato
6467 .. literalinclude:: ../../examples/v2/robotchef_api/robotchef_api/__init__.py
6568 :language: python
6669
67 scan_plugins here loads all modules that start with "robotchef_" and as well as
70 scan_plugins_regex here loads all modules that start with "robotchef_" and as well as
6871 the module `robotchef_api.robot_cuisine` in the white_list.
6972
7073 This is how you will write the main component as a library.
22 'Load me later. A lazy plugin management system.' +
33 ''
44 )
5 # -*- coding: utf-8 -*-
6 #
75 # Configuration file for the Sphinx documentation builder.
86 #
9 # This file does only contain a selection of the most common options. For a
10 # full list see the documentation:
11 # http://www.sphinx-doc.org/en/master/config
7 # This file only contains a selection of the most common options. For a full
8 # list see the documentation:
9 # https://www.sphinx-doc.org/en/master/usage/configuration.html
1210
1311 # -- Path setup --------------------------------------------------------------
1412
2220
2321 # -- Project information -----------------------------------------------------
2422
25 project = u'lml'
26 copyright = u'2017-2019 Onni Software Ltd.'
27 author = u'C.W.'
28
23 project = 'lml'
24 copyright = '2017-2020 Onni Software Ltd.'
25 author = 'C.W.'
2926 # The short X.Y version
30 version = u'0.0.9'
27 version = '0.1.0'
3128 # The full version, including alpha/beta/rc tags
32 release = u'0.0.9'
33
29 release = '0.1.0'
3430
3531 # -- General configuration ---------------------------------------------------
36
37 # If your documentation needs a minimal Sphinx version, state it here.
38 #
39 # needs_sphinx = '1.0'
4032
4133 # Add any Sphinx extension module names here, as strings. They can be
4234 # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
4537
4638 # Add any paths that contain templates here, relative to this directory.
4739 templates_path = ['_templates']
48
49 # The suffix(es) of source filenames.
50 # You can specify multiple suffix as a list of string:
51 #
52 # source_suffix = ['.rst', '.md']
53 source_suffix = '.rst'
54
55 # The master toctree document.
56 master_doc = 'index'
5740
5841 # The language for content autogenerated by Sphinx. Refer to documentation
5942 # for a list of supported languages.
6750 # This pattern also affects html_static_path and html_extra_path.
6851 exclude_patterns = []
6952
70 # The name of the Pygments (syntax highlighting) style to use.
71 pygments_style = None
72
7353
7454 # -- Options for HTML output -------------------------------------------------
7555
7858 #
7959 html_theme = 'alabaster'
8060
81 # Theme options are theme-specific and customize the look and feel of a theme
82 # further. For a list of options available for each theme, see the
83 # documentation.
84 #
85 # html_theme_options = {}
86
8761 # Add any paths that contain custom static files (such as style sheets) here,
8862 # relative to this directory. They are copied after the builtin static files,
8963 # so a file named "default.css" will overwrite the builtin "default.css".
9064 html_static_path = ['_static']
9165
92 # Custom sidebar templates, must be a dictionary that maps document names
93 # to template names.
94 #
95 # The default sidebars (for documents that don't match any pattern) are
96 # defined by theme itself. Builtin themes are using these templates by
97 # default: ``['localtoc.html', 'relations.html', 'sourcelink.html',
98 # 'searchbox.html']``.
99 #
100 # html_sidebars = {}
101
102
103 # -- Options for HTMLHelp output ---------------------------------------------
104
105 # Output file base name for HTML help builder.
106 htmlhelp_basename = 'lmldoc'
107
108
109 # -- Options for LaTeX output ------------------------------------------------
110
111 latex_elements = {
112 # The paper size ('letterpaper' or 'a4paper').
113 #
114 # 'papersize': 'letterpaper',
115
116 # The font size ('10pt', '11pt' or '12pt').
117 #
118 # 'pointsize': '10pt',
119
120 # Additional stuff for the LaTeX preamble.
121 #
122 # 'preamble': '',
123
124 # Latex figure (float) alignment
125 #
126 # 'figure_align': 'htbp',
127 }
128
129 # Grouping the document tree into LaTeX files. List of tuples
130 # (source start file, target name, title,
131 # author, documentclass [howto, manual, or own class]).
132 latex_documents = [
133 (master_doc, 'lml.tex', u'lml Documentation',
134 u'Onni Software Ltd.', 'manual'),
135 ]
136
137
138 # -- Options for manual page output ------------------------------------------
139
140 # One entry per manual page. List of tuples
141 # (source start file, name, description, authors, manual section).
142 man_pages = [
143 (master_doc, 'lml', u'lml Documentation',
144 [author], 1)
145 ]
146
147
148 # -- Options for Texinfo output ----------------------------------------------
149
150 # Grouping the document tree into Texinfo files. List of tuples
151 # (source start file, target name, title, author,
152 # dir menu entry, description, category)
153 texinfo_documents = [
154 (master_doc, 'lml', u'lml Documentation',
155 author, 'lml', 'One line description of project.',
156 'Miscellaneous'),
157 ]
158
159
160 # -- Options for Epub output -------------------------------------------------
161
162 # Bibliographic Dublin Core info.
163 epub_title = project
164
165 # The unique identifier of the text. This can be a ISBN number
166 # or the project homepage.
167 #
168 # epub_identifier = ''
169
170 # A unique identification for the text.
171 #
172 # epub_uid = ''
173
174 # A list of files that should not be packed into the epub file.
175 epub_exclude_files = ['search.html']
176
17766 # -- Extension configuration -------------------------------------------------
17867 # -- Options for intersphinx extension ---------------------------------------
17968
18069 # Example configuration for intersphinx: refer to the Python standard library.
181 intersphinx_mapping = {'https://docs.python.org/': None}
70 intersphinx_mapping = {'https://docs.python.org/3/': None}
18271 # TODO: html_theme not configurable upstream
18372 html_theme = 'default'
18473
19281 ]
19382 intersphinx_mapping.update({
19483 })
84 master_doc = "index"
85
86 master_doc = "index"
55 its code growth, the code in pyexcel packages to manage the external and internal
66 plugins becomes a independent library, lml.
77
8 lml is similar to **Factories** in
9 Zope Component Architecture [#f2]_. Lml provides functionalities to
8 Lml is similar to **Factories** in
9 Zope Component Architecture [#f2]_. It provides functionalities to
1010 discover, register and load lml based plugins. It cares how the meta data were
11 written but it does care how the plugin interface is written.
11 written but it does NOT care how the plugin interface is written.
12
13 Simply, lml promises to load your external dependency when they are used, but
14 only when you follow lazy-loading design principle below. Otherwise, lml does
15 immediate import and takes away the developer's responsibility to manage plugin
16 registry and discovery.
17
18 In terms of extensibility of your proud package, lml keeps the door open even
19 if you use lml for immediate import. As a developer, you give the choice to other
20 contributor to write up a plugin for your package. As long as the user would have
21 installed community created extensions, lml will discover them and use them.
1222
1323
1424 Plugin discovery
1929 It allows the developer to split a bigger packages into a smaller ones and
2030 publish them separately. sphinxcontrib [#f4]_ uses a typical namespace package based
2131 method. However, namespace package places a strict requirement
22 on the module's __init__.py: nothing other than name space declaration should
32 on the module's `__init__.py`: nothing other than name space declaration should
2333 be present. It means no module level functions can be place there. This restriction
2434 forces the plugin to be driven by the main package but the plugin cannot use
2535 the main package as its own library to do specific things. So namespace package
3949 development since 2016.
4050
4151 In order to overcome those shortcomings, implicit imports were coded into module's
42 __init__.py. By iterating through currently installed modules in your python
52 `__init__.py`. By iterating through currently installed modules in your python
4353 environment, the relevant plugins are imported automatically.
4454
4555 lml uses implicit import. In order to manage the plugins, pip can be used to
4858 python path, you can nominate one plugin to be picked.
4959
5060 Plugin registration
51 ---------------------
61 --------------------------------------------------------------------------------
5262
5363 In terms of plugin registrations, three different approaches have been tried.
5464 Monkey-patching was easy to implement. When a plugin is imported, it loads
55 the plugin dictionary from the main package and add itself.
56 But it is generally perceived as a "bad" idea.
57 Another way of doing it is to place
58 the plugin code in the main component and the plugin just need to declare a
59 dictionary as the plugin's meta data. The main package register the meta data
60 when it is imported. tablib [#f5]_ uses such a approach.
61 The third way is to use meta-classes. M. Alchin (2008) [#f6]_ explained how meta class can
62 be used to register plugin classes in a simpler way.
65 the plugin dictionary from the main package and add itself. But it is generally
66 perceived as a "bad" idea. Another way of doing it is to place the plugin code
67 in the main component and the plugin just need to declare a dictionary as the
68 plugin's meta data. The main package register the meta data when it is imported.
69 tablib [#f5]_ uses such a approach. The third way is to use meta-classes.
70 M. Alchin (2008) [#f6]_ explained how meta class can be used to register plugin
71 classes in a simpler way.
6372
6473 lml uses meta data for plugin registration. Since lml load your plugin later,
65 the meta data is stored in the module's __init__.py. For example, to load plugins later
66 in tablib, the 'exports' variable should be taken out from the actual class file and
67 replace the hard reference to the classes with class path string.
74 the meta data is stored in the module's __init__.py. For example, to load plugins
75 later in tablib, the 'exports' variable should be taken out from the actual
76 class file and replace the hard reference to the classes with class path string.
6877
6978 Plugin distribution
7079 ---------------------
7180
72 In terms of plugin distribution, yapsy [#f7]_ and GEdit plugin management
73 system [#f8]_ load plugins from file system.
81 yapsy [#f7]_ and GEdit plugin management system [#f8]_ load plugins from file system.
7482 To install a plugin in those systems, is to copy and paste the plugin code to a
7583 designated directory. zope components, namespace packages and flask extensions
7684 can be installed via pypi. lml support the latter approach. lml plugins can be
8088 ------------------
8189
8290 To use lml, it asks you to avoid importing your "heavy" dependencies
83 in __init__.py. lml also respects the independence of individual packages. You can
91 in `__init__.py`. lml respects the independence of individual packages. You can
8492 put modular level functions in your __init__.py as long as it does not trigger
8593 immediate import of your dependency. This is to allow the individual plugin to
8694 become useful as it is, rather to be integrated with your main package. For example,
8997 With lml, as long as your third party developer respect the plugin name prefix,
9098 they could publish their plugins as they do to any normal pypi packages. And the end
9199 developer of yours would only need to do pip install.
92
93100
94101 References
95102 -------------
3333 objectives.
3434
3535
36 Quick start
37 ================================================================================
38
39 The following code tries to get you started quickly with **non-lazy** loading.
40
41 .. code-block:: python
42
43 from lml.plugin import PluginInfo, PluginManager
44
45
46 @PluginInfo("cuisine", tags=["Portable Battery"])
47 class Boost(object):
48 def make(self, food=None, **keywords):
49 print("I can cook %s for robots" % food)
50
51
52 class CuisineManager(PluginManager):
53 def __init__(self):
54 PluginManager.__init__(self, "cuisine")
55
56 def get_a_plugin(self, food_name=None, **keywords):
57 return PluginManager.get_a_plugin(self, key=food_name, **keywords)
58
59
60 if __name__ == '__main__':
61 manager = CuisineManager()
62 chef = manager.get_a_plugin("Portable Battery")
63 chef.make()
64
65
66 At a glance, above code simply replaces the Factory pattern should you write
67 them without lml. What's not obvious is, that once you got hands-on with it,
68 you can start work on how to do **lazy** loading.
69
70
71
3672 Documentation
3773 ----------------
3874
4682
4783 Beyond the documentation above, here is a list of projects using lml:
4884
49 #. `pyexcel <https://github.com/pyexcel.pyexcel>`_
50 #. `pyexcel-io <https://github.com/pyexcel.pyexcel-io>`_
51 #. `pyexcel-chart <https://github.com/pyexcel.pyexcel-chart>`_
85 #. `pyexcel <https://github.com/pyexcel/pyexcel>`_
86 #. `pyecharts <https://github.com/pyecharts/pyecharts>`_
87 #. `moban <https://github.com/moremoban/moban>`_
88
89 lml is available on these distributions:
90
91 #. `ARCH linux <https://aur.archlinux.org/packages/python-lml/>`_
92 #. `Conda forge <https://anaconda.org/conda-forge/lml>`_
93 #. `OpenSuse <https://build.opensuse.org/package/show/devel:languages:python/python-lml>`_
77 Enable the logging
88 -------------------
99
10 Let us open robotchef's `main.py <https://github.com/chfw/lml/blob/master/examples/robotchef/robotchef/main.py>`_. Insert the highlighted codes.
10 Let us open robotchef's `main.py <https://github.com/python-lml/robotchef/blob/master/robotchef/main.py>`_. Insert the highlighted codes.
1111
1212 .. code-block:: python
1313 :emphasize-lines: 5-10
88 Demo
99 --------------------------------------------------------------------------------
1010
11 Please navigate to
12 `lml/examples <https://github.com/chfw/lml/tree/master/examples>`_,
13 you would find robotchef and its packages. Do the following::
11 Do the following::
1412
13 $ git clone https://github.com/python-lml/robotchef
1514 $ cd robotchef
1615 $ python setup.py install
1716
2928 it starts to understand it once you install Chinese cuisine package to complement
3029 its knowledge::
3130
31 $ git clone https://github.com/python-lml/robotchef_britishcuisine
3232 $ cd robotchef_britishcuisine
3333 $ python setup.py install
3434
0 @startuml
1
2 actor bob
3 participant robotchef
4 participant lml
5 participant robotchef_britishcuisine
6
7 bob -> robotchef : > robotchef "Jacket Potato"
8 robotchef -> lml : scan for plugins.
9 lml -> robotchef_britishcuisine : read plugin chain in the module
10 robotchef_britishcuisine -> lml: I can help with "Jacket Potato" and others.
11 lml -> robotchef : read the built-in robot_cuisine
12 robotchef -> lml : built-in chef knows "Portable Battery"
13 lml --> robotchef : scanning done
14 robotchef -> lml : get me a plugin that knows "Jacket Potato"
15 lml -> robotchef : robotchef_britishcuisine.bake.Bake can do
16 robotchef -> robotchef: make the food
17 robotchef -> bob : "I can bake Jacket Potato"
18 @enduml
0 @startuml
1
2 Interface Chef
3
4 Chef <|-- Boost
5 Chef <|-- Fry
6 Chef <|-- Bake
7
8 @enduml
0 @startuml
1
2 package lml {
3 PluginManager o-- PluginInfo
4 }
5
6 package robotchef_allinone_lml {
7 class CuisineManager {
8 + get_a_plugin()
9 + raise_exception()
10 }
11 interface Chef {
12 + make()
13 }
14 PluginManager <|-- CuisineManager : cuisine
15 Chef <|-- Boost
16 Chef <|-- Fry
17 Chef <|-- Bake
18 PluginInfo .. Fry
19 PluginInfo .. Bake
20 PluginInfo .. Boost
21 }
22
23
24 @enduml
0 @startuml
1
2
3 package lml {
4 PluginManager .. PluginInfoChain : registers plugin info
5 PluginManager o-- PluginInfo
6 PluginInfoChain -right- PluginInfo
7 }
8
9 package robotchef_api {
10 class CuisineManager {
11 + get_a_plugin()
12 + raise_exception()
13 }
14 interface Chef {
15 + make()
16 }
17 PluginManager <|-- CuisineManager : cuisine
18 package robotchef.robot_cuisine {
19 Chef <|-- Boost
20 PluginInfoChain .. Boost
21 }
22 }
23
24 package robotchef_britishcuisine {
25 Chef <|-- Fry
26 Chef <|-- Bake
27 PluginInfoChain .. Fry
28 PluginInfoChain .. Bake
29 }
30
31 package robotchef_v2 {
32 }
33
34 robotchef_v2 +-- robotchef_api
35
36 @enduml
0 @startuml
1
2 package lml {
3 PluginManager .. PluginInfoChain : registers plugin info
4 PluginManager o-- PluginInfo
5 PluginInfoChain -right- PluginInfo
6 }
7
8 package robotchef {
9 class CuisineManager {
10 + get_a_plugin()
11 + raise_exception()
12 }
13 interface Chef {
14 + make()
15 }
16 PluginManager <|-- CuisineManager : cuisine
17 package robotchef.robot_cuisine {
18 Chef <|-- Boost
19 PluginInfoChain .. Boost
20 }
21 }
22
23 package robotchef_britishcuisine {
24 Chef <|-- Fry
25 Chef <|-- Bake
26 PluginInfoChain .. Fry
27 PluginInfoChain .. Bake
28 }
29
30
31 @enduml
0 READ ME
1 =========
2
3 A robot chef was created to master the cuisines around the world. It learns faster
4 than a human because it just needs a plugin to be installed. It consumes less
5 memory as it load the cuisine knowlege on demand.
6
7 Please note that there are two implementations of the robot chef. One is pure
8 command line interface(CLI) using lml directly; the other one is CLI using
9 robotchef_api package which uses lml. The former demonstrates how lml could
10 be used in a CLI package. The latter illustrates how to construct a pure
11 python library using lml.
77 :license: New BSD License, see LICENSE for more details
88 """
99 import logging
10
11 from lml._version import __author__ # noqa: F401
1012 from lml._version import __version__ # noqa: F401
11 from lml._version import __author__ # noqa: F401
1213
1314 try:
1415 from logging import NullHandler
0 __version__ = "0.0.9"
0 __version__ = "0.1.0"
11 __author__ = "C.W."
55 and pyinstaller. :func:`~lml.loader.scan_plugins` is expected to be
66 called in the main package of yours at an earliest time of convenience.
77
8 :copyright: (c) 2017-2018 by Onni Software Ltd.
8 :copyright: (c) 2017-2020 by Onni Software Ltd.
99 :license: New BSD License, see LICENSE for more details
1010 """
1111 import re
2121 can be overridden to help its matching :class:`~lml.plugin.PluginManager`
2222 to look itself up.
2323
24 :copyright: (c) 2017-2018 by Onni Software Ltd.
24 :copyright: (c) 2017-2020 by Onni Software Ltd.
2525 :license: New BSD License, see LICENSE for more details
2626 """
2727 import logging
272272 if keywords:
273273 self._logger.debug(keywords)
274274 __key = key.lower()
275
275276 if __key in self.registry:
276277 for plugin_info in self.registry[__key]:
277278 cls = self.dynamic_load_library(plugin_info)
281282 else:
282283 break
283284 else:
284 # only library condition coud raise an exception
285 raise Exception("%s is not installed" % library)
285 # only library condition could raise an exception
286 self._logger.debug("%s is not installed" % library)
287 self.raise_exception(key)
286288 self._logger.debug("load %s now for '%s'", cls, key)
287289 return cls
288290 else:
362364 manager.register_a_plugin(plugin_cls, plugin_info)
363365 else:
364366 # let's cache it and wait the manager to be registered
365 log.debug("caching %s", _show_me_your_name(plugin_cls.__name__))
367 try:
368 log.debug("caching %s", _show_me_your_name(plugin_cls.__name__))
369 except AttributeError:
370 log.debug("caching %s", _show_me_your_name(plugin_cls))
366371 CACHED_PLUGIN_INFO[plugin_info.plugin_type].append(plugin_info)
367372
368373
33
44 json utils for dump plugin info class
55
6 :copyright: (c) 2017-2018 by Onni Software Ltd.
6 :copyright: (c) 2017-2020 by Onni Software Ltd.
77 :license: New BSD License, see LICENSE for more details
88 """
99 import sys
4040 try:
4141 return _do_import(plugin_module_name)
4242 except ImportError:
43 log.exception(
44 "%s is abscent or cannot be imported", plugin_module_name
45 )
43 log.exception("%s is absent or cannot be imported", plugin_module_name)
4644 raise
4745
4846
+0
-163
lml.egg-info/PKG-INFO less more
0 Metadata-Version: 1.1
1 Name: lml
2 Version: 0.0.9
3 Summary: Load me later. A lazy plugin management system.
4 Home-page: https://github.com/chfw/lml
5 Author: C.W.
6 Author-email: [email protected]
7 License: New BSD
8 Download-URL: https://github.com/chfw/lml/archive/0.0.9.tar.gz
9 Description: ================================================================================
10 lml - Load me later. A lazy plugin management system.
11 ================================================================================
12
13 .. image:: https://api.travis-ci.org/chfw/lml.svg
14 :target: http://travis-ci.org/chfw/lml
15
16 .. image:: https://codecov.io/github/chfw/lml/coverage.png
17 :target: https://codecov.io/github/chfw/lml
18
19
20 .. image:: https://readthedocs.org/projects/lml/badge/?version=latest
21 :target: http://lml.readthedocs.org/en/latest/
22
23 **lml** seamlessly finds the lml based plugins from your current python
24 environment but loads your plugins on demand. It is designed to support
25 plugins that have external dependencies, especially bulky and/or
26 memory hungry ones. lml provides the plugin management system only and the
27 plugin interface is on your shoulder.
28
29 **lml** enabled applications helps your customers [#f1]_ in two ways:
30
31 #. Your customers could cherry-pick the plugins from pypi per python environment.
32 They could remove a plugin using `pip uninstall` command.
33 #. Only the plugins used at runtime gets loaded into computer memory.
34
35 When you would use **lml** to refactor your existing code, it aims to flatten the
36 complexity and to shrink the size of your bulky python library by
37 distributing the similar functionalities across its plugins. However, you as
38 the developer need to do the code refactoring by yourself and lml would lend you a hand.
39
40 .. [#f1] the end developers who uses your library and packages achieve their
41 objectives.
42
43 Installation
44 ================================================================================
45
46
47 You can install lml via pip:
48
49 .. code-block:: bash
50
51 $ pip install lml
52
53
54 or clone it and install it:
55
56 .. code-block:: bash
57
58 $ git clone https://github.com/chfw/lml.git
59 $ cd lml
60 $ python setup.py install
61
62 License
63 ================================================================================
64
65 New BSD
66
67 Change log
68 ================================================================================
69
70 0.0.9 - 7/1/2019
71 --------------------------------------------------------------------------------
72
73 Updated
74 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
75
76 #. `#11 <https://github.com/chfw/lml/issues/11>`_: more test contents for
77 OpenSuse package validation
78
79 0.0.8 - 4/1/2019
80 --------------------------------------------------------------------------------
81
82 Updated
83 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
84
85 #. `#9 <https://github.com/chfw/lml/issues/9>`_: include tests, docs for
86 OpenSuse package validation
87
88 0.0.7 - 17/11/2018
89 --------------------------------------------------------------------------------
90
91 Fixed
92 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
93
94 #. `#8 <https://github.com/chfw/lml/issues/8>`_: get_primary_key will fail when
95 a module is loaded later
96 #. deprecated old style plugin scanner: scan_plugins
97
98 0.0.6 - 07/11/2018
99 --------------------------------------------------------------------------------
100
101 Fixed
102 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
103
104 #. Revert the version 0.0.5 changes. Raise Import error and log the exception
105
106 0.0.5 - 06/11/2018
107 --------------------------------------------------------------------------------
108
109 Fixed
110 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
111
112 #. `#6 <https://github.com/chfw/lml/issues/6>`_: Catch and Ignore
113 ModuleNotFoundError
114
115 0.0.4 - 07.08.2018
116 --------------------------------------------------------------------------------
117
118 Added
119 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
120
121 #. `#4 <https://github.com/chfw/lml/issues/4>`_: to find plugin names with
122 different naming patterns
123
124 0.0.3 - 12/06/2018
125 --------------------------------------------------------------------------------
126
127 Added
128 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
129
130 #. `dict` can be a pluggable type in addition to `function`, `class`
131 #. get primary tag of your tag, helping you find out which category of plugins
132 your tag points to
133
134 0.0.2 - 23/10/2017
135 --------------------------------------------------------------------------------
136
137 Updated
138 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
139
140 #. `pyexcel#103 <https://github.com/pyexcel/pyexcel/issues/103>`_: include
141 LICENSE in tar ball
142
143 0.0.1 - 30/05/2017
144 --------------------------------------------------------------------------------
145
146 Added
147 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
148
149 #. First release
150
151
152 Keywords: python
153 Platform: UNKNOWN
154 Classifier: Topic :: Software Development :: Libraries
155 Classifier: Programming Language :: Python
156 Classifier: Intended Audience :: Developers
157 Classifier: Programming Language :: Python :: 2.6
158 Classifier: Programming Language :: Python :: 2.7
159 Classifier: Programming Language :: Python :: 3.3
160 Classifier: Programming Language :: Python :: 3.4
161 Classifier: Programming Language :: Python :: 3.5
162 Classifier: Programming Language :: Python :: 3.6
+0
-39
lml.egg-info/SOURCES.txt less more
0 CHANGELOG.rst
1 LICENSE
2 MANIFEST.in
3 README.rst
4 setup.cfg
5 setup.py
6 docs/source/allinone_lml_tutorial.rst
7 docs/source/allinone_tutorial.rst
8 docs/source/api.rst
9 docs/source/api_tutorial.rst
10 docs/source/appendix.rst
11 docs/source/conf.py
12 docs/source/design.rst
13 docs/source/index.rst
14 docs/source/lml_log.rst
15 docs/source/lml_tutorial.rst
16 docs/source/spelling_wordlist.txt
17 docs/source/tutorial.rst
18 lml/__init__.py
19 lml/_version.py
20 lml/loader.py
21 lml/plugin.py
22 lml/utils.py
23 lml.egg-info/PKG-INFO
24 lml.egg-info/SOURCES.txt
25 lml.egg-info/dependency_links.txt
26 lml.egg-info/not-zip-safe
27 lml.egg-info/top_level.txt
28 tests/requirements.txt
29 tests/test_plugin_info.py
30 tests/test_plugin_loader.py
31 tests/test_plugin_manager.py
32 tests/test_utils.py
33 tests/sample_plugin/setup.py
34 tests/sample_plugin/sample_plugin/__init__.py
35 tests/sample_plugin/sample_plugin/manager.py
36 tests/sample_plugin/sample_plugin/reader.py
37 tests/test_plugin/setup.py
38 tests/test_plugin/pyexcel_test/__init__.py
+0
-1
lml.egg-info/dependency_links.txt less more
0
+0
-1
lml.egg-info/not-zip-safe less more
0
+0
-1
lml.egg-info/top_level.txt less more
0 lml
0 name: "lml"
1 full_name: "Load me later. A lazy plugin management system."
2 organisation: "python-lml"
3 author: "C.W."
4 contact: "[email protected]"
5 company: "Onni Software Ltd."
6 version: "0.1.0"
7 current_version: "0.1.0"
8 release: "0.1.0"
9 copyright_year: 2017-2020
10 license: New BSD
11 dependencies: []
12 test_dependencies:
13 - lml
14 - pytest
15 - pytest-cov
16 description: "Load me later. A lazy plugin management system."
17 excluded_github_users:
18 - chfw
19 - gitter-badger
(New empty file)
0 https://github.com/pyexcel/pyexcel-xls/archive/v0.4.x.zip
00 [metadata]
11 description-file = README.rst
2
32 [bdist_wheel]
43 universal = 1
5
6 [egg_info]
7 tag_build =
8 tag_date = 0
9
00 #!/usr/bin/env python3
11
2 # Template by pypi-mobans
2 """
3 Template by pypi-mobans
4 """
5
36 import os
47 import sys
58 import codecs
9 import locale
10 import platform
611 from shutil import rmtree
712
813 from setuptools import Command, setup, find_packages
914
1015 PY2 = sys.version_info[0] == 2
1116 PY26 = PY2 and sys.version_info[1] < 7
12
13 NAME = 'lml'
14 AUTHOR = 'C.W.'
15 VERSION = '0.0.9'
16 EMAIL = '[email protected]'
17 LICENSE = 'New BSD'
17 PY33 = sys.version_info < (3, 4)
18
19 # Work around mbcs bug in distutils.
20 # http://bugs.python.org/issue10945
21 # This work around is only if a project supports Python < 3.4
22
23 # Work around for locale not being set
24 try:
25 lc = locale.getlocale()
26 pf = platform.system()
27 if pf != "Windows" and lc == (None, None):
28 locale.setlocale(locale.LC_ALL, "C.UTF-8")
29 except (ValueError, UnicodeError, locale.Error):
30 locale.setlocale(locale.LC_ALL, "en_US.UTF-8")
31
32 NAME = "lml"
33 AUTHOR = "C.W."
34 VERSION = "0.1.0"
35 EMAIL = "[email protected]"
36 LICENSE = "New BSD"
1837 DESCRIPTION = (
19 'Load me later. A lazy plugin management system.'
38 "Load me later. A lazy plugin management system."
2039 )
21 URL = 'https://github.com/chfw/lml'
22 DOWNLOAD_URL = '%s/archive/0.0.9.tar.gz' % URL
23 FILES = ['README.rst', 'CHANGELOG.rst']
40 URL = "https://github.com/python-lml/lml"
41 DOWNLOAD_URL = "%s/archive/0.1.0.tar.gz" % URL
42 FILES = ["README.rst", "CHANGELOG.rst"]
2443 KEYWORDS = [
25 'python',
44 "python",
2645 ]
2746
2847 CLASSIFIERS = [
29 'Topic :: Software Development :: Libraries',
30 'Programming Language :: Python',
31 'Intended Audience :: Developers',
32 'Programming Language :: Python :: 2.6',
33 'Programming Language :: Python :: 2.7',
34 'Programming Language :: Python :: 3.3',
35 'Programming Language :: Python :: 3.4',
36 'Programming Language :: Python :: 3.5',
37 'Programming Language :: Python :: 3.6',
48 "Topic :: Software Development :: Libraries",
49 "Programming Language :: Python",
50 "Intended Audience :: Developers",
51 "Programming Language :: Python :: 2.6",
52 "Programming Language :: Python :: 2.7",
53 "Programming Language :: Python :: 3.3",
54 "Programming Language :: Python :: 3.4",
55 "Programming Language :: Python :: 3.5",
56 "Programming Language :: Python :: 3.6",
57 "Programming Language :: Python :: 3.7",
58 "Programming Language :: Python :: 3.8",
59
3860 ]
61
3962
4063 INSTALL_REQUIRES = [
4164 ]
4265 SETUP_COMMANDS = {}
4366
44
45 PACKAGES = find_packages(exclude=['ez_setup', 'examples', 'tests'])
67 PACKAGES = find_packages(exclude=["ez_setup", "examples", "tests", "tests.*"])
4668 EXTRAS_REQUIRE = {}
4769 # You do not need to read beyond this line
48 PUBLISH_COMMAND = '{0} setup.py sdist bdist_wheel upload -r pypi'.format(
49 sys.executable)
50 GS_COMMAND = ('gs lml v0.0.9 ' +
51 "Find 0.0.9 in changelog for more details")
52 NO_GS_MESSAGE = ('Automatic github release is disabled. ' +
53 'Please install gease to enable it.')
70 PUBLISH_COMMAND = "{0} setup.py sdist bdist_wheel upload -r pypi".format(sys.executable)
71 HERE = os.path.abspath(os.path.dirname(__file__))
72
73 GS_COMMAND = ("gease lml v0.1.0 " +
74 "Find 0.1.0 in changelog for more details")
75 NO_GS_MESSAGE = ("Automatic github release is disabled. " +
76 "Please install gease to enable it.")
5477 UPLOAD_FAILED_MSG = (
5578 'Upload failed. please run "%s" yourself.' % PUBLISH_COMMAND)
56 HERE = os.path.abspath(os.path.dirname(__file__))
5779
5880
5981 class PublishCommand(Command):
6082 """Support setup.py upload."""
6183
62 description = 'Build and publish the package on github and pypi'
84 description = "Build and publish the package on github and pypi"
6385 user_options = []
6486
6587 @staticmethod
6688 def status(s):
6789 """Prints things in bold."""
68 print('\033[1m{0}\033[0m'.format(s))
90 print("\033[1m{0}\033[0m".format(s))
6991
7092 def initialize_options(self):
7193 pass
7597
7698 def run(self):
7799 try:
78 self.status('Removing previous builds...')
79 rmtree(os.path.join(HERE, 'dist'))
80 rmtree(os.path.join(HERE, 'build'))
81 rmtree(os.path.join(HERE, 'lml.egg-info'))
100 self.status("Removing previous builds...")
101 rmtree(os.path.join(HERE, "dist"))
102 rmtree(os.path.join(HERE, "build"))
103 rmtree(os.path.join(HERE, "lml.egg-info"))
82104 except OSError:
83105 pass
84106
85 self.status('Building Source and Wheel (universal) distribution...')
107 self.status("Building Source and Wheel (universal) distribution...")
86108 run_status = True
87109 if has_gease():
88110 run_status = os.system(GS_COMMAND) == 0
90112 self.status(NO_GS_MESSAGE)
91113 if run_status:
92114 if os.system(PUBLISH_COMMAND) != 0:
93 self.status(UPLOAD_FAILED_MSG % PUBLISH_COMMAND)
115 self.status(UPLOAD_FAILED_MSG)
94116
95117 sys.exit()
96118
97119
98120 SETUP_COMMANDS.update({
99 'publish': PublishCommand
121 "publish": PublishCommand
100122 })
101
102123
103124 def has_gease():
104125 """
125146 def read(afile):
126147 """Read a file into setup"""
127148 the_relative_file = os.path.join(HERE, afile)
128 with codecs.open(the_relative_file, 'r', 'utf-8') as opened_file:
149 with codecs.open(the_relative_file, "r", "utf-8") as opened_file:
129150 content = filter_out_test_code(opened_file)
130151 content = "".join(list(content))
131152 return content
134155 def filter_out_test_code(file_handle):
135156 found_test_code = False
136157 for line in file_handle.readlines():
137 if line.startswith('.. testcode:'):
158 if line.startswith(".. testcode:"):
138159 found_test_code = True
139160 continue
140161 if found_test_code is True:
141 if line.startswith(' '):
162 if line.startswith(" "):
142163 continue
143164 else:
144165 empty_line = line.strip()
148169 found_test_code = False
149170 yield line
150171 else:
151 for keyword in ['|version|', '|today|']:
172 for keyword in ["|version|", "|today|"]:
152173 if keyword in line:
153174 break
154175 else:
155176 yield line
156177
157178
158 if __name__ == '__main__':
179 if __name__ == "__main__":
159180 setup(
181 test_suite="tests",
160182 name=NAME,
161183 author=AUTHOR,
162184 version=VERSION,
168190 license=LICENSE,
169191 keywords=KEYWORDS,
170192 extras_require=EXTRAS_REQUIRE,
171 tests_require=['nose'],
193 tests_require=["nose"],
172194 install_requires=INSTALL_REQUIRES,
173195 packages=PACKAGES,
174196 include_package_data=True,
0 pip freeze
1 cd tests/test_plugin
2 python setup.py install
3 cd -
4 pytest tests --verbosity=3 --cov=lml --doctest-glob=*.rst && flake8 . --exclude=.moban.d,docs,setup.py --builtins=unicode,xrange,long
(New empty file)
00 mock
1 nose
1 pytest
2 pytest-cov
23 codecov
34 coverage
45 flake8
00 from lml.registry import PluginInfoChain
11
2
32 __test_plugins__ = PluginInfoChain(__name__).add_a_plugin("test_io2", "reader")
00 from lml.plugin import PluginInfoChain
11
2
32 __test_plugins__ = PluginInfoChain(__name__).add_a_plugin("test_io", "x")
00 import json
11
22 from lml.plugin import PluginInfo
3 from nose.tools import eq_
43
54
65 def test_plugin_info():
1716 "plugin_type": "renderer",
1817 "custom": "property",
1918 }
20 eq_(json.loads(info.__repr__()), expected)
19 assert json.loads(info.__repr__()) == expected
2120
2221
2322 def test_module_name_scenario_2():
2625
2726 info = PluginInfo("renderer", custom="property")
2827 info.cls = TestClass2
29 eq_(info.module_name, "test_plugin_info")
28 assert info.module_name == "tests.test_plugin_info"
00 from mock import patch
1 from nose.tools import eq_
21
32
43 @patch("pkgutil.get_importer")
98
109 module_names = scan_from_pyinstaller("pyexcel_", "path")
1110 expected = ["pyexcel_io", "pyexcel_xls"]
12 eq_(sorted(list(module_names)), sorted(expected))
11 assert sorted(list(module_names)) == sorted(expected)
1312
1413
1514 @patch("pkgutil.get_importer")
2019
2120 module_names = scan_from_pyinstaller("^.+cel_.+$", "path")
2221 expected = ["pyexcel_io", "pyexcel_xls"]
23 eq_(sorted(list(module_names)), sorted(expected))
22 assert sorted(list(module_names)) == sorted(expected)
2423
2524
2625 @patch("pkgutil.get_importer")
3635 from lml.plugin import CACHED_PLUGIN_INFO
3736
3837 info = CACHED_PLUGIN_INFO["test_io"][0]
39 eq_(info.plugin_type, "test_io")
40 eq_(info.absolute_import_path, "pyexcel_test.x")
38 assert info.plugin_type == "test_io"
39 assert info.absolute_import_path == "pyexcel_test.x"
4140
4241
4342 @patch("pkgutil.get_importer")
5655 from lml.plugin import CACHED_PLUGIN_INFO
5756
5857 info = CACHED_PLUGIN_INFO["test_io"][0]
59 eq_(info.plugin_type, "test_io")
60 eq_(info.absolute_import_path, "pyexcel_test.x")
58 assert info.plugin_type == "test_io"
59 assert info.absolute_import_path == "pyexcel_test.x"
6160
6261
6362 @patch("pkgutil.get_importer")
7271 from lml.loader import scan_plugins
7372
7473 scan_plugins("pyexcel_", ".", ["pyexcel_io"])
75 assert mocked_load_me_later.called is False
74 assert not mocked_load_me_later.called
7675
7776
7877 @patch("pkgutil.get_importer")
8786 from lml.loader import scan_plugins
8887
8988 scan_plugins("pyexcel_", ".")
90 assert mocked_load_me_later.called is False
89 assert not mocked_load_me_later.called
9190
9291
9392 @patch("pkgutil.get_importer")
102101 from lml.loader import scan_plugins
103102
104103 scan_plugins("test_", ".", ["pyexcel_io"])
105 assert mocked_load_me_later.called is False
104 assert not mocked_load_me_later.called
0 from mock import patch
10 from lml.plugin import (
21 PLUG_IN_MANAGERS,
32 CACHED_PLUGIN_INFO,
54 PluginManager,
65 _show_me_your_name,
76 )
8 from nose.tools import eq_, raises
7
8 from mock import patch
9 from pytest import raises
910
1011
1112 def test_plugin_manager():
3132 plugin_info = make_me_a_plugin_info(test_plugin)
3233 manager.load_me_later(plugin_info)
3334 actual = manager.load_me_now(test_plugin)
34 eq_(actual, custom_class)
35 eq_(manager.tag_groups, {"my plugin": "my plugin"})
36 eq_(plugin_info, manager.registry["my plugin"][0])
35 assert actual == custom_class
36 assert manager.tag_groups == {"my plugin": "my plugin"}
37 assert plugin_info == manager.registry["my plugin"][0]
3738
3839
39 @raises(Exception)
40 @patch("lml.plugin.do_import_class")
41 def test_load_me_now_with_known_missing_library(mock_import):
42 custom_class = PluginInfo
43 mock_import.return_value = custom_class
44 test_plugin = "my plugin"
45 manager = PluginManager(test_plugin)
46 plugin_info = make_me_a_plugin_info(test_plugin)
47 manager.load_me_later(plugin_info)
48 with raises(Exception):
49 manager.load_me_now(test_plugin, library='alien')
50
51
4052 @patch("lml.plugin.do_import_class")
4153 def test_load_me_now_exception(mock_import):
4254 custom_class = PluginInfo
4355 mock_import.return_value = custom_class
4456 test_plugin = "my plugin"
45 manager = PluginManager(test_plugin)
46 plugin_info = make_me_a_plugin_info("my")
47 manager.load_me_later(plugin_info)
48 manager.load_me_now("my", "my special library")
57 with raises(Exception):
58 manager = PluginManager(test_plugin)
59 plugin_info = make_me_a_plugin_info("my")
60 manager.load_me_later(plugin_info)
61 manager.load_me_now("my", "my special library")
4962
5063
51 @raises(Exception)
5264 def test_load_me_now_no_key_found():
5365 test_plugin = "my plugin"
54 manager = PluginManager(test_plugin)
55 manager.load_me_now("my", custom_property="here")
66 with raises(Exception):
67 manager = PluginManager(test_plugin)
68 manager.load_me_now("my", custom_property="here")
5669
5770
5871 @patch("lml.plugin.do_import_class")
6376 manager = PluginManager(test_plugin)
6477 plugin_info = make_me_a_plugin_info(test_plugin)
6578 manager.dynamic_load_library(plugin_info)
66 eq_(custom_obj, plugin_info.cls)
79 assert custom_obj == plugin_info.cls
6780
6881
6982 @patch("lml.plugin.do_import_class")
8699 manager = PluginManager(test_plugin)
87100 plugin_info = make_me_a_plugin_info("my")
88101 manager.register_a_plugin(TestClass, plugin_info)
89 eq_(plugin_info.cls, TestClass)
90 eq_(manager.registry["my"][0], plugin_info)
91 eq_(manager.tag_groups, {"my": "my"})
102 assert plugin_info.cls == TestClass
103 assert manager.registry["my"][0] == plugin_info
104 assert manager.tag_groups == {"my": "my"}
92105
93106
94107 def test_get_a_plugin():
120133 assert list(manager.registry.keys()) == [test_plugin]
121134
122135
123 @raises(ImportError)
124136 def test_do_import_cls_error():
125137 from lml.plugin import do_import_class
126138
127 do_import_class("non.exist.class")
139 with raises(ImportError):
140 do_import_class("non.exist.class")
128141
129142
130143 def test_register_a_plugin_function_1():
156169 pass
157170
158171 pk = manager.get_primary_key("key 1")
159 eq_(pk, "primary key")
172 assert pk == "primary key"
160173
161174
162175 def test_dict_as_plugin_payload():
166179 plugin(dict(B=1))
167180
168181 instance = manager.load_me_now("key 1")
169 eq_(instance, dict(B=1))
182 assert instance == dict(B=1)
170183
171184
172185 def test_show_me_your_name():
174187 pass
175188
176189 name = _show_me_your_name(Test)
177 eq_(name, "Test")
190 assert name == "Test"
178191
179192 name2 = _show_me_your_name(dict(A=1))
180193 assert "dict" in name2
0 from mock import patch
10 from lml.utils import do_import, json_dumps
21 from lml.plugin import PluginManager
3 from nose.tools import eq_, raises
2
3 from mock import patch
4 from pytest import raises
45
56
67 def test_json_dumps():
1314
1415
1516 def test_do_import():
16 import pyexcel_test
17 import isort
1718
18 pyexcel_test_package = do_import("pyexcel_test")
19 eq_(pyexcel_test_package, pyexcel_test)
19 test_package = do_import("isort")
20 assert test_package == isort
2021
2122
2223 def test_do_import_2():
2324 import lml.plugin as plugin
2425
2526 themodule = do_import("lml.plugin")
26 eq_(plugin, themodule)
27 assert plugin == themodule
2728
2829
29 @raises(ImportError)
3030 @patch("lml.utils.log.exception")
3131 def test_do_import_error(mock_exception):
32 do_import("non.exist")
33 mock_exception.assert_called_with("No module named 'non'")
32 with raises(ImportError):
33 do_import("non.exist")
34 mock_exception.assert_called_with(
35 "%s is absent or cannot be imported", "non.exist"
36 )
3437
3538
3639 def test_do_import_cls():
3740 from lml.utils import do_import_class
3841
3942 manager = do_import_class("lml.plugin.PluginManager")
40 eq_(manager, PluginManager)
43 assert manager == PluginManager