Question

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 .

Was it helpful?

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.

OTHER TIPS

It looks like right now you have to change a couple of lines of code each time you change pdf renderer. The code is simple and easy to understand.

Sure, you can abstract it all out, and use configuration files, and add a plugin architecture. But what will you gain? Instead of changing a couple of lines of code, you'll instead change a plugin or a configuration file, and that machinery will need to be maintained: for example, if you decide you need to pass in some flags to one of the renderers, then you have to add that functionality to your configuration file or whatever abstraction you've chosen.

How many times do you think you'll change pdf renderer? My guess would be at most once a year. Keep your code simple, and don't build complex solutions until you really need them.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top