Robot Chef all in one package with lml¶
Now let us bring in lml and see see how the lml package can be used
to rewrite Robot Chef but in a single package. This chapter introduces
two classes: lml.plugin.PluginManager
and lml.plugin.PluginInfo
.
And show how those classes can be used to make factory pattern.
Meanwhile, it demonstrates that the lml based plugins can be made to load
immediately and in a single package. And this sections helps you to understand
the next section where we will make the plugins to be loaded later.
Demo¶
Please navigate to robotchef_allinone_lml and its packages. Do the following:
$ git clone https://github.com/python-lml/robotchef_allinone_lml
$ cd robotchef_allinone_lml
$ python setup.py install
And then you could try:
$ robotchef_allinone_lml "Fish and Chips"
I can fry Fish and Chips
Lml plugins and plugin manager¶
plugin.py¶
CuisineManager inherits from PluginManager
class and
replaces the static registry PLUGINS and the modular function get_a_plugin.
Please note that CuisineManager declares that it is a manager for plugin_type named
cuisine.
class CuisineManager(PluginManager):
def __init__(self):
PluginManager.__init__(self, "cuisine")
def get_a_plugin(self, food_name=None, **keywords):
return PluginManager.get_a_plugin(self, key=food_name, **keywords)
def raise_exception(self, key):
raise NoChefException("Cannot find a chef")
Next, the PluginInfo
decorates all Chef’s subclasses as
cuisine plugins and register the decorated classes with the manager class
for cuisine, CuisineManager. The food names become the tags which will
be used to look up the classes.
from lml.plugin import PluginInfo, PluginManager
class Chef(object):
def make(self, **params):
print("I am a chef")
@PluginInfo("cuisine", tags=["Portable Battery"])
class Boost(Chef):
def make(self, food=None, **keywords):
print("I can cook %s for robots" % food)
@PluginInfo("cuisine", tags=["Fish and Chips"])
class Fry(Chef):
def make(self, food=None):
print("I can fry " + food)
@PluginInfo("cuisine", tags=["Cornish Scone", "Jacket Potato"])
class Bake(Chef):
def make(self, food=None):
print("I can bake " + food)
Here is the code difference with Robot Chef All In One solution: plugin.py.
main.py¶
The main code has been updated to reflect the changes in plugin.py. CuisineManager has to be instantiated to be the a factory manager.
--- /home/docs/checkouts/readthedocs.org/user_builds/lml/checkouts/latest/examples/robotchef_allinone/robotchef_allinone/main.py
+++ /home/docs/checkouts/readthedocs.org/user_builds/lml/checkouts/latest/examples/robotchef_allinone_lml/robotchef_allinone_lml/main.py
@@ -1,15 +1,17 @@
import sys
-import robotchef_allinone.plugin as cuisine_manager
+from robotchef_allinone_lml.plugin import CuisineManager, NoChefException
def main():
if len(sys.argv) < 2:
sys.exit(-1)
+ cuisine_manager = CuisineManager()
+
food_name = sys.argv[1]
try:
knowledged_chef = cuisine_manager.get_a_plugin(food_name)
knowledged_chef.make(food=food_name)
- except cuisine_manager.NoChefException:
+ except NoChefException:
print("I do not know how to cook " + food_name)
Remember this interaction:
$ robotchef "Portable Battery"
I can cook Portable Battery for robots
The response comes from class Boost. It is obtained via CuisineManager when user types ‘Portable Battery’. And the food parameter was passed to the instance of Boost. make method was called and it prints ‘I can cook Portable Battery for robots’.
See also¶
- pyexcel-chart: use lml to refactor existing plugins