1
0
Fork 0
mirror of https://github.com/yweber/lodel2.git synced 2025-11-21 21:26:54 +01:00

DatasourcePlugin class implementation

- DatasourcePlugin implmentation as child class of lodel.plugin.plugins.Plugin
- moved methods about datasource initialisation from LeObject to DatasourcePlugin ( _init_datasource(), plugin_name(), _get_ds_connection_conf() ...)
This commit is contained in:
Yann 2016-08-19 09:09:29 +02:00
commit 4627ae17e5
5 changed files with 132 additions and 97 deletions

View file

@ -4,13 +4,14 @@ import importlib
import warnings
import copy
from lodel.plugin import Plugin
from lodel import logger
from lodel.settings import Settings
from lodel.settings.utils import SettingsError
from .query import LeInsertQuery, LeUpdateQuery, LeDeleteQuery, LeGetQuery
from .exceptions import *
from lodel.plugin.exceptions import *
from lodel.plugin.hooks import LodelHook
from lodel.plugin import Plugin, DatasourcePlugin
from lodel.leapi.datahandlers.base_classes import DatasConstructor
##@brief Stores the name of the field present in each LeObject that indicates
@ -244,7 +245,7 @@ class LeObject(object):
else:
ro_ds, rw_ds = cls._datasource_name
#Read only datasource initialisation
cls._ro_datasource = cls._init_datasource(ro_ds, True)
cls._ro_datasource = DatasourcePlugin.init_datasource(ro_ds, True)
if cls._ro_datasource is None:
log_msg = "No read only datasource set for LeObject %s"
log_msg %= cls.__name__
@ -254,7 +255,7 @@ class LeObject(object):
log_msg %= (ro_ds, cls.__name__)
logger.debug(log_msg)
#Read write datasource initialisation
cls._rw_datasource = cls._init_datasource(rw_ds, False)
cls._rw_datasource = DatasourcePlugin.init_datasource(rw_ds, False)
if cls._ro_datasource is None:
log_msg = "No read/write datasource set for LeObject %s"
log_msg %= cls.__name__
@ -264,99 +265,6 @@ class LeObject(object):
log_msg %= (ro_ds, cls.__name__)
logger.debug(log_msg)
##@brief Replace the _datasource attribute value by a datasource instance
#
#This method is used once at dyncode load to replace the datasource string
#by a datasource instance to avoid doing this operation for each query
#@param ds_name str : The name of the datasource to instanciate
#@param ro bool : if true initialise the _ro_datasource attribute else
#initialise _rw_datasource attribute
#@throw SettingsError if an error occurs
@classmethod
def _init_datasource(cls, ds_name, ro):
expt_msg = "In LeAPI class '%s' " % cls.__name__
if ds_name not in Settings.datasources._fields:
#Checking that datasource exists
expt_msg += "Unknown or unconfigured datasource %s for class %s"
expt_msg %= (ds_name, cls.__name__)
raise SettingsError(expt_msg)
try:
#fetching plugin name
ds_plugin_name, ds_identifier = cls._get_ds_plugin_name(ds_name, ro)
except NameError:
expt_msg += "Datasource %s is missconfigured, missing identifier."
expt_msg %= ds_name
raise SettingsError(expt_msg)
except RuntimeError:
expt_msg += "Error in datasource %s configuration. Trying to use \
a read only as a read&write datasource"
expt_msg %= ds_name
raise SettingsError(expt_msg)
except ValueError as e:
expt_msg += str(e)
raise SettingsError(expt_msg)
try:
ds_conf = cls._get_ds_connection_conf(ds_identifier, ds_plugin_name)
except NameError as e:
expt_msg += str(e)
raise SettingsError(expt_msg)
#Checks that the datasource plugin exists
ds_plugin_module = Plugin.get(ds_plugin_name).loader_module()
try:
datasource_class = getattr(ds_plugin_module, "Datasource")
except AttributeError as e:
expt_msg += "The datasource plugin %s seems to be invalid. Error \
raised when trying to import Datasource"
expt_msg %= ds_identifier
raise SettingsError(expt_msg)
return datasource_class(**ds_conf)
##@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):
if ds_plugin_name not in Settings.datasource._fields:
msg = "Unknown or unconfigured datasource plugin %s"
msg %= ds_plugin
raise NameError(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 NameError(msg)
ds_conf = getattr(ds_conf, ds_identifier)
return {k: getattr(ds_conf,k) for k in ds_conf._fields }
##@brief fetch datasource plugin name
#@param ds_name str : datasource name
#@param ro bool : if true consider the datasource as read only
#@return a tuple(DATASOURCE_PLUGIN_NAME, DATASOURCE_CONNECTION_NAME)
#@throw NameError if datasource identifier not found
#@throw RuntimeError if datasource is read_only but ro flag was false
@staticmethod
def _get_ds_plugin_name(ds_name, ro):
datasource_orig_name = ds_name
# fetching connection identifier given datasource name
ds_identifier = getattr(Settings.datasources, ds_name)
read_only = getattr(ds_identifier, 'read_only')
try:
ds_identifier = getattr(ds_identifier, 'identifier')
except NameError as e:
raise e
if read_only and not ro:
raise RuntimeError()
res = ds_identifier.split('.')
if len(res) != 2:
raise ValueError("expected value for identifier is like \
DS_PLUGIN_NAME.DS_INSTANCE_NAME. But got %s" % ds_identifier)
return res
##@brief Return the uid of the current LeObject instance
#@return the uid value
#@warning Broke multiple uid capabilities

View file

@ -41,3 +41,4 @@
from .hooks import LodelHook
from .plugins import Plugin, CustomMethod
from .datasource_plugin import DatasourcePlugin

View file

@ -0,0 +1,119 @@
from .plugins import Plugin
from .exceptions import *
##@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):
def __init__(self, name):
super().__init__(name)
self.__datasource_cls = self.loader_module().Datasource
def datasource(self):
return self.__datasource
def migration_handler(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 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()
@classmethod
def get_migration_handler(cls, ds_plugin_name):
return cls.get(ds_plugin_name).migration_handler_class()

View file

@ -1,5 +1,11 @@
class PluginError(Exception):
pass
class PluginTypeErrror(PluginError):
pass
class LodelScriptError(Exception):
pass
class DatasourcePluginError(PluginError):
pass

View file

@ -8,8 +8,9 @@ import json
from importlib.machinery import SourceFileLoader, SourcelessFileLoader
import plugins
from .exceptions import *
from lodel import logger
from lodel.settings.utils import SettingsError
from .exceptions import *
## @package lodel.plugins Lodel2 plugins management
#