123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146 |
- from .plugins import Plugin
- from .exceptions import *
- from lodel.settings.validator import SettingValidator
-
- ##@brief Designed to handles datasources plugins
- #
- #A datasource provide data access to LeAPI typically a connector on a DB
- #or an API
- #@note For the moment implementation is done with a retro-compatibilities
- #priority and not with a convenience priority.
- #@todo Refactor and rewrite lodel2 datasource handling
- class DatasourcePlugin(Plugin):
-
- ##@brief Stores confspecs indicating where DatasourcePlugin list is stored
- _plist_confspecs = {
- 'section': 'lodel2',
- 'key': 'datasource_connectors',
- 'default': None,
- 'validator': SettingValidator('strip', none_is_valid = False) }
- _type_conf_name = 'datasource'
-
- def __init__(self, name):
- super().__init__(name)
- self.__datasource_cls = None
-
- def datasource_cls(self):
- if self.__datasource_cls is None:
- self.__datasource_cls = self.loader_module().Datasource
- return self.__datasource_cls
-
- def migration_handler_cls(self):
- return self.loader_module().migration_handler_class()
-
- ##@brief Return an initialized Datasource instance
- #@param ds_name str : The name of the datasource to instanciate
- #@param ro bool
- #@return A properly initialized Datasource instance
- #@throw SettingsError if an error occurs in settings
- #@throw DatasourcePluginError for various errors
- @classmethod
- def init_datasource(cls, ds_name, ro):
- plugin_name, ds_identifier = cls.plugin_name(ds_name, ro)
- ds_conf = cls._get_ds_connection_conf(ds_identifier, plugin_name)
- ds_cls = cls.get_datasource(plugin_name)
- return ds_cls(**ds_conf)
-
- ##@brief Return an initialized MigrationHandler instance
- #@param ds_name str : The datasource name
- #@return A properly initialized MigrationHandler instance
- @classmethod
- def init_migration_handler(cls, ds_name):
- plugin_name, ds_identifier = cls.plugin_name(ds_name, False)
- ds_conf = cls._get_ds_connection_conf(ds_identifier, plugin_name)
- mh_cls = cls.get_migration_handler(plugin_name)
- if 'read_only' in ds_conf:
- if ds_conf['read_only']:
- raise PluginError("A read only datasource was given to \
- migration handler !!!")
- del(ds_conf['read_only'])
- return mh_cls(**ds_conf)
-
-
- ##@brief Given a datasource name returns a DatasourcePlugin name
- #@param ds_name str : datasource name
- #@param ro bool : if true consider the datasource as readonly
- #@return a DatasourcePlugin name
- #@throw PluginError if datasource name not found
- #@throw DatasourcePermError if datasource is read_only but ro flag arg is
- #false
- @staticmethod
- def plugin_name(ds_name, ro):
- from lodel.settings import Settings
- # fetching connection identifier given datasource name
- try:
- ds_identifier = getattr(Settings.datasources, ds_name)
- except (NameError, AttributeError):
- raise DatasourcePluginError("Unknown or unconfigured datasource \
- '%s'" % ds_name)
- # fetching read_only flag
- try:
- read_only = getattr(ds_identifier, 'read_only')
- except (NameError, AttributeError):
- raise SettingsError("Malformed datasource configuration for '%s' \
- : missing read_only key" % ds_name)
- # fetching datasource identifier
- try:
- ds_identifier = getattr(ds_identifier, 'identifier')
- except (NameError,AttributeError) as e:
- raise SettingsError("Malformed datasource configuration for '%s' \
- : missing identifier key" % ds_name)
- # settings and ro arg consistency check
- if read_only and not ro:
- raise DatasourcePluginError("ro argument was set to False but \
- True found in settings for datasource '%s'" % ds_name)
- res = ds_identifier.split('.')
- if len(res) != 2:
- raise SettingsError("expected value for identifier is like \
- DS_PLUGIN_NAME.DS_INSTANCE_NAME. But got %s" % ds_identifier)
- return res
-
- ##@brief Try to fetch a datasource configuration
- #@param ds_identifier str : datasource name
- #@param ds_plugin_name : datasource plugin name
- #@return a dict containing datasource initialisation options
- #@throw NameError if a datasource plugin or instance cannot be found
- @staticmethod
- def _get_ds_connection_conf(ds_identifier,ds_plugin_name):
- from lodel.settings import Settings
- if ds_plugin_name not in Settings.datasource._fields:
- msg = "Unknown or unconfigured datasource plugin %s"
- msg %= ds_plugin
- raise DatasourcePluginError(msg)
- ds_conf = getattr(Settings.datasource, ds_plugin_name)
- if ds_identifier not in ds_conf._fields:
- msg = "Unknown or unconfigured datasource instance %s"
- msg %= ds_identifier
- raise DatasourcePluginError(msg)
- ds_conf = getattr(ds_conf, ds_identifier)
- return {k: getattr(ds_conf,k) for k in ds_conf._fields }
-
- ##@brief DatasourcePlugin instance accessor
- #@param ds_name str : plugin name
- #@return a DatasourcePlugin instance
- #@throw PluginError if no plugin named ds_name found
- #@throw PluginTypeError if ds_name ref to a plugin that is not a
- #DatasourcePlugin
- @classmethod
- def get(cls, ds_name):
- pinstance = super().get(ds_name) #Will raise PluginError if bad name
- if not isinstance(pinstance, DatasourcePlugin):
- raise PluginTypeErrror("A name of a DatasourcePlugin was excepted \
- but %s is a %s" % (ds_name, pinstance.__class__.__name__))
- return pinstance
-
- ##@brief Return a datasource class given a datasource name
- #@param ds_name str : datasource plugin name
- #@throw PluginError if ds_name is not an existing plugin name
- #@throw PluginTypeError if ds_name is not the name of a DatasourcePlugin
- @classmethod
- def get_datasource(cls, ds_plugin_name):
- return cls.get(ds_plugin_name).datasource_cls()
-
- @classmethod
- def get_migration_handler(cls, ds_plugin_name):
- return cls.get(ds_plugin_name).migration_handler_cls()
-
|