Search code examples
pythonparadigms

How to abstract 3rd party implementation details from the core functionality?


Here is an example of the problem and requirement .

Scenario : We have a Web App , The Controller has a function that does HTML to PDF conversion . We have to switch to various engines depending on the requirement and advancement in Technology . This means we need to keep changing the core file . It can even be a web service that does my job and not implemented locally .

Overall the current architecture in pseudo Python is :

Controller

def requestEntry():
    """Entry point"""
    html = REQUEST['html'] , css = REQUEST['css']
    createPDF(html,css)

def createPDF(html,css):
    """Sigh"""
    #Hardcoding Begines
    configured_engine  = getXMLOption('configured_engine')
    if configured_engine == "SuperPDFGen":
       #Returns SuperGen's PDF Blob
       supergen = SuperGen(html,css)
       return supergen.pdfout() 
    if configured_engine = "PISA":
       pisa = PISA(html,css)
       return pisa.pdf_out()

The problem here is every new engine requirement is a code change in the controller .And suppose we find a new technology we have to upgrade the core software version .

Solving it :

One way I can think of is to define a simple class like this :

def createPdf(data,engine):
    pdf_render = PDFRender(html,css,engine)
    return pdf_render.pdf_out() 

So now we keep out PDFRender astracted - core version need not be changed any more for a implemetation change , but we need to code the engines with a If ladder in the PDFRender Class .

To extend this idea , i could have a convention engine would be the module name too . But this own't adapt to a URL if its given as Engine .

def createPdf(data,engine):
    #Convert the string called engine to a Module ! Sigh 
    import engine Engine!!
    pdf_render = engine.Engine(data)
    return pdf_render()

Are there any suggested paradigm's or a plugin adapter mechanism for this? It should take a URL or a Python Module as input and get the job done . New implementations should be standalone and pluggable to the existing code with no version changes in core feature . How can I do that ? I think the core should talk in terms of service (either a python module , sub process or a url ) this is what I trying to achieve .


Solution

  • Add a package where you stick your renderers, one Python module for each, the module being named after the "engine" and the renderer class being named "PDFRenderer". Then in the package's __init__ scan the modules in the directory, import the PDFRenderer class from each module, and build a enginename:PDFRenderer mapping, and use it to get the PDFRenderer class for the engine.