Browse Source

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() ...)
Yann Weber 7 years ago
parent
commit
4627ae17e5

+ 4
- 96
lodel/leapi/leobject.py View File

@@ -4,13 +4,14 @@ import importlib
4 4
 import warnings
5 5
 import copy
6 6
 
7
-from lodel.plugin import Plugin
8 7
 from lodel import logger
9 8
 from lodel.settings import Settings
10 9
 from lodel.settings.utils import SettingsError
11 10
 from .query import LeInsertQuery, LeUpdateQuery, LeDeleteQuery, LeGetQuery
12 11
 from .exceptions import *
12
+from lodel.plugin.exceptions import *
13 13
 from lodel.plugin.hooks import LodelHook
14
+from lodel.plugin import Plugin, DatasourcePlugin
14 15
 from lodel.leapi.datahandlers.base_classes import DatasConstructor
15 16
 
16 17
 ##@brief Stores the name of the field present in each LeObject that indicates
@@ -244,7 +245,7 @@ class LeObject(object):
244 245
         else:
245 246
             ro_ds, rw_ds = cls._datasource_name
246 247
         #Read only datasource initialisation
247
-        cls._ro_datasource = cls._init_datasource(ro_ds, True)
248
+        cls._ro_datasource = DatasourcePlugin.init_datasource(ro_ds, True)
248 249
         if cls._ro_datasource is None:
249 250
             log_msg = "No read only datasource set for LeObject %s"
250 251
             log_msg %= cls.__name__
@@ -254,7 +255,7 @@ class LeObject(object):
254 255
             log_msg %= (ro_ds, cls.__name__)
255 256
             logger.debug(log_msg)
256 257
         #Read write datasource initialisation
257
-        cls._rw_datasource = cls._init_datasource(rw_ds, False)
258
+        cls._rw_datasource = DatasourcePlugin.init_datasource(rw_ds, False)
258 259
         if cls._ro_datasource is None:
259 260
             log_msg = "No read/write datasource set for LeObject %s"
260 261
             log_msg %= cls.__name__
@@ -264,99 +265,6 @@ class LeObject(object):
264 265
             log_msg %= (ro_ds, cls.__name__)
265 266
             logger.debug(log_msg)
266 267
         
267
-
268
-    ##@brief Replace the _datasource attribute value by a datasource instance
269
-    #
270
-    #This method is used once at dyncode load to replace the datasource string
271
-    #by a datasource instance to avoid doing this operation for each query
272
-    #@param ds_name str : The name of the datasource to instanciate
273
-    #@param ro bool : if true initialise the _ro_datasource attribute else
274
-    #initialise _rw_datasource attribute
275
-    #@throw SettingsError if an error occurs
276
-    @classmethod
277
-    def _init_datasource(cls, ds_name, ro):
278
-        expt_msg = "In LeAPI class '%s' " % cls.__name__
279
-        if ds_name not in Settings.datasources._fields:
280
-            #Checking that datasource exists
281
-            expt_msg += "Unknown or unconfigured datasource %s for class %s"
282
-            expt_msg %= (ds_name, cls.__name__)
283
-            raise SettingsError(expt_msg)
284
-        try:
285
-            #fetching plugin name
286
-            ds_plugin_name, ds_identifier = cls._get_ds_plugin_name(ds_name, ro)
287
-        except NameError:
288
-            expt_msg += "Datasource %s is missconfigured, missing identifier."
289
-            expt_msg %= ds_name
290
-            raise SettingsError(expt_msg)
291
-        except RuntimeError:
292
-            expt_msg += "Error in datasource %s configuration. Trying to use \
293
-a read only as a read&write datasource"
294
-            expt_msg %= ds_name
295
-            raise SettingsError(expt_msg)
296
-        except ValueError as e:
297
-            expt_msg += str(e)
298
-            raise SettingsError(expt_msg)
299
-        
300
-        try:
301
-            ds_conf = cls._get_ds_connection_conf(ds_identifier, ds_plugin_name)
302
-        except NameError as e:
303
-            expt_msg += str(e)
304
-            raise SettingsError(expt_msg)
305
-        #Checks that the datasource plugin exists
306
-        ds_plugin_module = Plugin.get(ds_plugin_name).loader_module()
307
-        try:
308
-            datasource_class = getattr(ds_plugin_module, "Datasource")
309
-        except AttributeError as e:
310
-            expt_msg += "The datasource plugin %s seems to be invalid. Error \
311
-raised when trying to import Datasource"
312
-            expt_msg %= ds_identifier
313
-            raise SettingsError(expt_msg)
314
-
315
-        return datasource_class(**ds_conf)
316
-
317
-    ##@brief Try to fetch a datasource configuration
318
-    #@param ds_identifier str : datasource name
319
-    #@param ds_plugin_name : datasource plugin name
320
-    #@return a dict containing datasource initialisation options
321
-    #@throw NameError if a datasource plugin or instance cannot be found
322
-    @staticmethod
323
-    def _get_ds_connection_conf(ds_identifier,ds_plugin_name):
324
-        if ds_plugin_name not in Settings.datasource._fields:
325
-            msg = "Unknown or unconfigured datasource plugin %s"
326
-            msg %= ds_plugin
327
-            raise NameError(msg)
328
-        ds_conf = getattr(Settings.datasource, ds_plugin_name)
329
-        if ds_identifier not in ds_conf._fields:
330
-            msg = "Unknown or unconfigured datasource instance %s"
331
-            msg %= ds_identifier
332
-            raise NameError(msg)
333
-        ds_conf = getattr(ds_conf, ds_identifier)
334
-        return {k: getattr(ds_conf,k) for k in ds_conf._fields }
335
-
336
-    ##@brief fetch datasource plugin name
337
-    #@param ds_name str : datasource name
338
-    #@param ro bool : if true consider the datasource as read only
339
-    #@return a tuple(DATASOURCE_PLUGIN_NAME, DATASOURCE_CONNECTION_NAME)
340
-    #@throw NameError if datasource identifier not found
341
-    #@throw RuntimeError if datasource is read_only but ro flag was false
342
-    @staticmethod
343
-    def _get_ds_plugin_name(ds_name, ro):
344
-        datasource_orig_name = ds_name
345
-        # fetching connection identifier given datasource name
346
-        ds_identifier = getattr(Settings.datasources, ds_name)
347
-        read_only = getattr(ds_identifier, 'read_only')
348
-        try:
349
-            ds_identifier = getattr(ds_identifier, 'identifier')
350
-        except NameError as e:
351
-            raise e
352
-        if read_only and not ro:
353
-            raise RuntimeError()
354
-        res = ds_identifier.split('.')
355
-        if len(res) != 2:
356
-            raise ValueError("expected value for identifier is like \
357
-DS_PLUGIN_NAME.DS_INSTANCE_NAME. But got %s" % ds_identifier)
358
-        return res
359
-    
360 268
     ##@brief Return the uid of the current LeObject instance
361 269
     #@return the uid value
362 270
     #@warning Broke multiple uid capabilities

+ 1
- 0
lodel/plugin/__init__.py View File

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

+ 119
- 0
lodel/plugin/datasource_plugin.py View File

@@ -0,0 +1,119 @@
1
+from .plugins import Plugin
2
+from .exceptions import *
3
+
4
+##@brief Designed to handles datasources plugins
5
+#
6
+#A datasource provide data access to LeAPI typically a connector on a DB
7
+#or an API
8
+#@note For the moment implementation is done with a retro-compatibilities
9
+#priority and not with a convenience priority.
10
+#@todo Refactor and rewrite lodel2 datasource handling
11
+class DatasourcePlugin(Plugin):
12
+    
13
+    def __init__(self, name):
14
+        super().__init__(name)
15
+        self.__datasource_cls = self.loader_module().Datasource
16
+
17
+    def datasource(self):
18
+        return self.__datasource
19
+
20
+    def migration_handler(self):
21
+        return self.loader_module().migration_handler_class()
22
+
23
+    ##@brief Return an initialized Datasource instance
24
+    #@param ds_name str : The name of the datasource to instanciate
25
+    #@param ro bool
26
+    #@return A properly initialized Datasource instance
27
+    #@throw SettingsError if an error occurs in settings
28
+    #@throw DatasourcePluginError for various errors
29
+    @classmethod
30
+    def init_datasource(cls, ds_name, ro):
31
+        plugin_name, ds_identifier = cls.plugin_name(ds_name, ro)
32
+        ds_conf = cls._get_ds_connection_conf(ds_identifier, plugin_name)
33
+        ds_cls = cls.get_datasource(plugin_name)
34
+        return ds_cls(**ds_conf)
35
+
36
+    ##@brief Given a datasource name returns a DatasourcePlugin name
37
+    #@param ds_name str : datasource name
38
+    #@param ro bool : if true consider the datasource as readonly
39
+    #@return a DatasourcePlugin name
40
+    #@throw PluginError if datasource name not found
41
+    #@throw DatasourcePermError if datasource is read_only but ro flag arg is
42
+    #false
43
+    @staticmethod
44
+    def plugin_name(ds_name, ro):
45
+        from lodel.settings import Settings
46
+        # fetching connection identifier given datasource name
47
+        try:
48
+            ds_identifier = getattr(Settings.datasources, ds_name)
49
+        except (NameError, AttributeError):
50
+            raise DatasourcePluginError("Unknown or unconfigured datasource \
51
+'%s'" % ds_name)
52
+        # fetching read_only flag
53
+        try:
54
+            read_only = getattr(ds_identifier, 'read_only')
55
+        except (NameError, AttributeError):
56
+            raise SettingsError("Malformed datasource configuration for '%s' \
57
+: missing read_only key" % ds_name)
58
+        # fetching datasource identifier
59
+        try:
60
+            ds_identifier = getattr(ds_identifier, 'identifier')
61
+        except (NameError,AttributeError) as e:
62
+            raise SettingsError("Malformed datasource configuration for '%s' \
63
+: missing identifier key" % ds_name)
64
+        # settings and ro arg consistency check
65
+        if read_only and not ro:
66
+            raise DatasourcePluginError("ro argument was set to False but \
67
+True found in settings for datasource '%s'" % ds_name)
68
+        res = ds_identifier.split('.')
69
+        if len(res) != 2:
70
+            raise SettingsError("expected value for identifier is like \
71
+DS_PLUGIN_NAME.DS_INSTANCE_NAME. But got %s" % ds_identifier)
72
+        return res
73
+
74
+    ##@brief Try to fetch a datasource configuration
75
+    #@param ds_identifier str : datasource name
76
+    #@param ds_plugin_name : datasource plugin name
77
+    #@return a dict containing datasource initialisation options
78
+    #@throw NameError if a datasource plugin or instance cannot be found
79
+    @staticmethod
80
+    def _get_ds_connection_conf(ds_identifier,ds_plugin_name):
81
+        from lodel.settings import Settings
82
+        if ds_plugin_name not in Settings.datasource._fields:
83
+            msg = "Unknown or unconfigured datasource plugin %s"
84
+            msg %= ds_plugin
85
+            raise DatasourcePluginError(msg)
86
+        ds_conf = getattr(Settings.datasource, ds_plugin_name)
87
+        if ds_identifier not in ds_conf._fields:
88
+            msg = "Unknown or unconfigured datasource instance %s"
89
+            msg %= ds_identifier
90
+            raise DatasourcePluginError(msg)
91
+        ds_conf = getattr(ds_conf, ds_identifier)
92
+        return {k: getattr(ds_conf,k) for k in ds_conf._fields }
93
+
94
+    ##@brief DatasourcePlugin instance accessor
95
+    #@param ds_name str : plugin name
96
+    #@return a DatasourcePlugin instance
97
+    #@throw PluginError if no plugin named ds_name found
98
+    #@throw PluginTypeError if ds_name ref to a plugin that is not a 
99
+    #DatasourcePlugin
100
+    @classmethod
101
+    def get(cls, ds_name):
102
+        pinstance = super().get(ds_name) #Will raise PluginError if bad name
103
+        if not isinstance(pinstance, DatasourcePlugin):
104
+           raise PluginTypeErrror("A name of a DatasourcePlugin was excepted \
105
+but %s is a %s" % (ds_name, pinstance.__class__.__name__))
106
+        return pinstance
107
+
108
+    ##@brief Return a datasource class given a datasource name
109
+    #@param ds_name str : datasource plugin name
110
+    #@throw PluginError if ds_name is not an existing plugin name
111
+    #@throw PluginTypeError if ds_name is not the name of a DatasourcePlugin
112
+    @classmethod
113
+    def get_datasource(cls, ds_plugin_name):
114
+        return cls.get(ds_plugin_name).datasource()
115
+
116
+    @classmethod
117
+    def get_migration_handler(cls, ds_plugin_name):
118
+        return cls.get(ds_plugin_name).migration_handler_class()
119
+ 

+ 6
- 0
lodel/plugin/exceptions.py View File

@@ -1,5 +1,11 @@
1 1
 class PluginError(Exception):
2 2
     pass
3 3
 
4
+class PluginTypeErrror(PluginError):
5
+    pass
6
+
4 7
 class LodelScriptError(Exception):
5 8
     pass
9
+
10
+class DatasourcePluginError(PluginError):
11
+    pass

+ 2
- 1
lodel/plugin/plugins.py View File

@@ -8,8 +8,9 @@ import json
8 8
 from importlib.machinery import SourceFileLoader, SourcelessFileLoader
9 9
 
10 10
 import plugins
11
-from .exceptions import *
12 11
 from lodel import logger
12
+from lodel.settings.utils import SettingsError
13
+from .exceptions import *
13 14
 
14 15
 ## @package lodel.plugins Lodel2 plugins management
15 16
 #

Loading…
Cancel
Save