To create a simple plugin framework in python we will be using the following features in Python
- Abstract Base Class : abc
- Dynamic module import : __import__
Use case: Create a plugin framework for loading dynamic model classes that will be deployed in a directory while the server is running. Here in the example we have created a standalone module instead of a server for invoking the dynamic models loaded. This kind of dynamic loading is required where the classes are required to be dynamically loaded with out changing your core implementation.
Abstract Class: ModelAbstract.py
This is the Abstract class used for define the structure of your derived model classes. The plugin framework should state the interfaces that needs to be defined by the derived classes which needs to be loaded dynamically. Every derived class should inherit & implement all the abstract methods in Abstract class
import abc class ModelAbstract(object): __metaclass__ = abc.ABCMeta def __init__( self ): print "Model abstract" @abc.abstractmethod def get_range(self,no_of_elements=1) : @abc.abstractmethod def get_resource(self, no_of_elements=1):
Derived Class : modela.py
This is the class which extends & implements all the abstract methods of ModelAbstract class
from . import ModelAbstract class modela(ModelAbstract.ModelAbstract): RESOURCE_CONSTANT = 10 def get_range(self,no_of_elements=1): return range(no_of_elements) def get_resource(self, resource_id=1) : return self.RESOURCE_CONSTANT * resource_id
Derived Class : modelb.py
from . import ModelAbstract class modelb(ModelAbstract.ModelAbstract): RESOURCE_CONSTANT = 100 def get_range(self,no_of_elements=1): return range(no_of_elements*2) def get_resource(self, resource_id=1) : return self.RESOURCE_CONSTANT * resource_id
Dynamic Model Loader : loader.py
This is the dynamic loader module which is used for dynamically loading the modules from the models directory.
import os def fetch_model_files() : lst = os.listdir("models") models = list() for fil in lst : if fil.find("__") == -1 and fil.find(".pyc") == -1 : print fil pos = fil.find(".py") models.append(fil[:pos]) return models def load_model(type): try: modname = type #TODO check if already loaded module = __import__(modname, globals(), locals(), [type], -1) class_ = getattr(module, type) print "Dynamically loaded model :"+type classObj = class_() return classObj except Exception as e : print("No Model : "+type+", Error : "+e.message) raise e
Dynamic Model Class Invoker: invoker.py
This is the piece of code which is used for executing the dynamic loader & invoking the methods in the models.
import loader def invoke_models(model_name) model_module_obj = loader.load_model(model_name.lower()) range_val = model_module_obj.get_range(2) print range_val invoke_model("modela") invoke_model("modelb")
$ python invoker.py $ [0,1] $ [0, 1, 2, 3]