mardi 14 mai 2019

Better implementation of Pluggable Database in Python through Singleton+Factory pattern and inheritance

I am implementing a pluggable storage system for a middleware in Python with Flask.

What I would like to do is start my program and have it create a database. This database can be a CouchDB, a local file system, etc. It is called a "configuration_store" The rest of the program should have access to this database.

At the moment it looks like this:

I have an /api folder with init.py and in the start of this file I have

...
configuration_store = ConfigurationStoreFactory.create("CouchDB")
config = Config()
...

For instance, the Config class should be able to access the sole instance of the configuration_store. For instance, it should be able to do something like store.getstoreurl().

In a /configuration_store folder, I have 4 files: __init__py, configurtion_store_factory.py, couchDB_store.py, and local_file_system_store.py.

In init.py I have:

from simplekv import KeyValueStore
from abc import ABCMeta, abstractmethod, abstractproperty

class ConfigurationStore(type, KeyValueStore):
    __metaclass__ = ABCMeta

    _instances = {}
    def __call__(cls, *args, **kwargs):
        if cls not in cls._instances:
            cls._instances[cls] = super(ConfigurationStore, cls).__call__(*args, **kwargs)
        return cls._instances[cls]

    @abstractmethod    
    def getConfigurationStoreTenantUrl(self, database):
        pass

    @abstractproperty
    def configuration_store_url(self):
        pass

In my factory I have

class ConfigurationStoreFactory():

    def __init__(self, logger_name):
        self.logger = Logger(logger_name)

    @staticmethod
    def create(type):
        if type == "CouchDB":
            from couchDB_store import CouchDBStore
            store = CouchDBStore()
        elif type == "LFS" or type == "LocalFileSystemStore":
            from local_file_system_store import LocalFileSystemStore
            store = LocalFileSystemStore('./data')
        else: #assume LFS
            from simplekv.fs import FilesystemStore
            store = FilesystemStore('./data')
        return store

In the CouchDB_store.py I have

    from configuration_store import ConfigurationStore

class CouchDBStore(ConfigurationStore):
    configuration_store_url = None

    #Instantiate this later since we need access to the config to get it correct
    def __init__(self):
        super(CouchDBStore,self).__init__('CouchDBStore')

        self.configuration_store_url = "https://"+ self.manager.config.getConfigKey("couchDbAdmin")+":" +self.config.getConfigKey("couchDbPassword")+"@" \
            +  self.config.getConfigKey("couchDbHostHttp") + ":"+ self.config.getConfigKey("couchDbPort")+"/"

This does not work: I get complaints about "Abstract class 'CouchDBStore' with abstract methods instantiated" in the factory. I also have the feeling I am confusing things and this is not a good approach.

The difficulty lies in that I want to inherit from the Python package simplekv but also want to subclass into my own database types and have this entire package available as a singleton so that only one database is created and it is accessible by the rest of the program.

What would be a good way to approach this? I was thinking of dropping the Factory and just having the initialisation happen once in init.py and determine the type of the database there. But I am not sure.

Aucun commentaire:

Enregistrer un commentaire