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:
parent
ccb643a4aa
commit
4627ae17e5
5 changed files with 132 additions and 97 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -41,3 +41,4 @@
|
|||
|
||||
from .hooks import LodelHook
|
||||
from .plugins import Plugin, CustomMethod
|
||||
from .datasource_plugin import DatasourcePlugin
|
||||
|
|
|
|||
119
lodel/plugin/datasource_plugin.py
Normal file
119
lodel/plugin/datasource_plugin.py
Normal 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()
|
||||
|
||||
|
|
@ -1,5 +1,11 @@
|
|||
class PluginError(Exception):
|
||||
pass
|
||||
|
||||
class PluginTypeErrror(PluginError):
|
||||
pass
|
||||
|
||||
class LodelScriptError(Exception):
|
||||
pass
|
||||
|
||||
class DatasourcePluginError(PluginError):
|
||||
pass
|
||||
|
|
|
|||
|
|
@ -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
|
||||
#
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue