Browse Source

Implements SessionHandlerPlugin ExtensionsPlugin + settings preload

Implements both Plugin child classes handling extensions and session handling.
Modified the settings plugin preload piece of code. It is now adapted to the new plugins organisation.
Each Plugin child classes provides a confspec indicating where the plugin list is stored in configuration.
Yann Weber 8 years ago
parent
commit
76e386e321

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

@@ -42,3 +42,5 @@
42 42
 from .hooks import LodelHook
43 43
 from .plugins import Plugin, CustomMethod
44 44
 from .datasource_plugin import DatasourcePlugin
45
+from .sessionhandler import SessionHandlerPlugin
46
+from .extensions import Extension

+ 2
- 6
lodel/plugin/datasource_plugin.py View File

@@ -14,9 +14,9 @@ class DatasourcePlugin(Plugin):
14 14
     ##@brief Stores confspecs indicating where DatasourcePlugin list is stored
15 15
     _plist_confspecs = {
16 16
         'section': 'lodel2',
17
-        'key': 'datasources',
17
+        'key': 'datasource_connectors',
18 18
         'default': None,
19
-        'validator': SettingValidator('list', none_is_valid = False) }
19
+        'validator': SettingValidator('strip', none_is_valid = False) }
20 20
     
21 21
     def __init__(self, name):
22 22
         super().__init__(name)
@@ -30,10 +30,6 @@ class DatasourcePlugin(Plugin):
30 30
     def migration_handler(self):
31 31
         return self.loader_module().migration_handler_class()
32 32
 
33
-    @classmethod
34
-    def plist_confspec(cls):
35
-        return copy.copy(cls._plist_confspecs)
36
-
37 33
     ##@brief Return an initialized Datasource instance
38 34
     #@param ds_name str : The name of the datasource to instanciate
39 35
     #@param ro bool

+ 12
- 0
lodel/plugin/extensions.py View File

@@ -0,0 +1,12 @@
1
+from .plugins import Plugin
2
+from .exceptions import *
3
+from lodel.settings.validator import SettingValidator
4
+
5
+class Extension(Plugin):
6
+    
7
+    _plist_confspecs = {
8
+        'section': 'lodel2',
9
+        'key': 'extensions',
10
+        'default': [],
11
+        'validator': SettingValidator('list', none_is_valid = False)}
12
+

+ 22
- 52
lodel/plugin/plugins.py View File

@@ -11,6 +11,7 @@ import plugins
11 11
 from lodel import logger
12 12
 from lodel.settings.utils import SettingsError
13 13
 from .exceptions import *
14
+from lodel.exceptions import *
14 15
 
15 16
 ## @package lodel.plugins Lodel2 plugins management
16 17
 #
@@ -161,7 +162,6 @@ class MetaPlugType(type):
161 162
         #Here we can store all child classes of Plugin
162 163
         super().__init__(name, bases, attrs)
163 164
         if len(bases) == 1 and bases[0] == object:
164
-            print("Dropped : ", name, bases)
165 165
             return
166 166
         self.__register_types()
167 167
         #list_name= [cls.__name__ for cls in __all_ptypes] 
@@ -177,6 +177,9 @@ def plug_type_register(cls):
177 177
     __all_ptypes.append(cls)
178 178
     logger.info("New child class registered : %s" % cls.__name__)
179 179
 
180
+def all_types():
181
+    return copy.copy(__all_ptypes)
182
+
180 183
 
181 184
 ##@brief Handle plugins
182 185
 #
@@ -204,6 +207,10 @@ class Plugin(object, metaclass=MetaPlugType):
204 207
     
205 208
     ##@brief Store dict representation of discover cache content
206 209
     _discover_cache = None
210
+    
211
+    #@brief Designed to store, in child classes, the confspec indicating \
212
+    #where plugin list is stored
213
+    _plist_confspecs = None
207 214
 
208 215
     ##@brief Plugin class constructor
209 216
     #
@@ -213,7 +220,7 @@ class Plugin(object, metaclass=MetaPlugType):
213 220
     # @param plugin_name str : plugin name
214 221
     # @throw PluginError
215 222
     def __init__(self, plugin_name):
216
-        self.started()
223
+        
217 224
         self.name = plugin_name
218 225
         self.path = self.plugin_path(plugin_name)
219 226
         
@@ -272,9 +279,9 @@ class Plugin(object, metaclass=MetaPlugType):
272 279
             #PLUGIN_VERSION_VARNAME in init file is mandatory
273 280
             self.__version = getattr(self.module, PLUGIN_VERSION_VARNAME)
274 281
         except AttributeError:
275
-            msg = "Error that should not append : no %s found in plugin \
276
-init file. Malformed plugin"
277
-            msg %= PLUGIN_VERSION_VARNAME
282
+            msg = "Error that should not append while loading plugin '%s': no \
283
+%s found in plugin init file. Malformed plugin"
284
+            msg %= (plugin_name, PLUGIN_VERSION_VARNAME)
278 285
             raise LodelFatalError(msg)
279 286
 
280 287
         # Load plugin type
@@ -459,6 +466,13 @@ name differ from the one found in plugin's init file"
459 466
     def confspecs(self):
460 467
         return copy.copy(self.__confspecs)
461 468
 
469
+    @classmethod
470
+    def plist_confspecs(cls):
471
+        if cls._plist_confspecs is None:
472
+            raise LodelFatalError('Unitialized _plist_confspecs attribute for \
473
+%s' % cls.__name__)
474
+        return copy.copy(cls._plist_confspecs)
475
+
462 476
     ##@brief Retrieves plugin list confspecs
463 477
     #
464 478
     #This method ask for each Plugin child class the confspecs specifying where
@@ -525,7 +539,6 @@ file : '%s'. Running discover again..." % DISCOVER_CACHE_FILENAME)
525 539
             pcls = DatasourcePlugin
526 540
         else:
527 541
             pcls = cls
528
-        print(plugin_name, ptype, pcls)
529 542
         plugin = pcls(plugin_name)
530 543
         cls._plugin_instances[plugin_name] = plugin
531 544
         logger.debug("Plugin %s available." % plugin)
@@ -550,7 +563,7 @@ file : '%s'. Running discover again..." % DISCOVER_CACHE_FILENAME)
550 563
     # @return the plugin directory path
551 564
     @classmethod
552 565
     def plugin_path(cls, plugin_name):
553
-        cls.started()
566
+        
554 567
         plist = cls.plugin_list()
555 568
         if plugin_name not in plist:
556 569
             raise PluginError("No plugin named '%s' found" % plugin_name)
@@ -572,25 +585,10 @@ file : '%s'. Running discover again..." % DISCOVER_CACHE_FILENAME)
572 585
     #
573 586
     # This method load path and preload plugins
574 587
     @classmethod
575
-    def start(cls, plugins_directories, plugins):
576
-        if cls._plugin_directories is not None:
577
-            return
578
-        import inspect
579
-        self_path = inspect.getsourcefile(Plugin)
580
-        default_plugin_path = os.path.abspath(self_path + '../../../../plugins')
581
-        if plugins_directories is None:
582
-            plugins_directories = list()
583
-        plugins_directories += [ default_plugin_path ]
584
-        cls._plugin_directories = list(set(plugins_directories))
588
+    def start(cls, plugins):
585 589
         for plugin_name in plugins:
586 590
             cls.register(plugin_name)
587 591
         
588
-    @classmethod
589
-    def started(cls, raise_if_not = True):
590
-        res = cls._plugin_directories is not None
591
-        if raise_if_not and not res:
592
-            raise RuntimeError("Class Plugins is not initialized")
593
-            
594 592
     @classmethod
595 593
     def clear(cls):
596 594
         if cls._plugin_directories is not None:
@@ -657,7 +655,7 @@ file : '%s'. Running discover again..." % DISCOVER_CACHE_FILENAME)
657 655
     ##@brief Return a list of child Class Plugin
658 656
     @classmethod
659 657
     def plugin_types(cls):
660
-        return cls.__all_ptypes
658
+        return all_types()
661 659
 
662 660
     ##@brief Attempt to open and load plugin discover cache
663 661
     #@return discover cache
@@ -880,31 +878,3 @@ with %s" % (custom_method._method_name, custom_method))
880 878
                         custom_method.__get_method())
881 879
                     logger.debug(
882 880
                         "Custom method %s added to target" % custom_method)
883
-            
884
-
885
-##@page lodel2_plugins Lodel2 plugins system
886
-#
887
-# @par Plugin structure
888
-#A plugin is  a package (a folder containing, at least, an __init__.py file.
889
-#This file should expose multiple things :
890
-# - a CONFSPEC variable containing configuration specifications
891
-# - an _activate() method that returns True if the plugin can be activated (
892
-# optionnal)
893
-#
894
-
895
-
896
-class SessionHandler(Plugin):
897
-    __instance = None
898
-        
899
-    def __init__(self, plugin_name):
900
-        if self.__instance is None:
901
-            super(Plugin, self).__init__(plugin_name)
902
-            self.__instance = True
903
-        else:
904
-            raise RuntimeError("A SessionHandler Plugin is already plug")
905
-
906
-class InterfacePlugin(Plugin):
907
-    def __init__(self, plugin_name):
908
-        super(Plugin, self).__init__(plugin_name)
909
-
910
-        

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

@@ -17,7 +17,6 @@ class MetaLodelScript(type):
17 17
         #Here we can store all child classes of LodelScript
18 18
         super().__init__(name, bases, attrs)
19 19
         if len(bases) == 1 and bases[0] == object:
20
-            print("Dropped : ", name, bases)
21 20
             return
22 21
 
23 22
         self.__register_script(name)

+ 28
- 0
lodel/plugin/sessionhandler.py View File

@@ -0,0 +1,28 @@
1
+from .plugins import Plugin
2
+from .exceptions import *
3
+from lodel.settings.validator import SettingValidator
4
+
5
+##@page lodel2_plugins Lodel2 plugins system
6
+#
7
+# @par Plugin structure
8
+#A plugin is  a package (a folder containing, at least, an __init__.py file.
9
+#This file should expose multiple things :
10
+# - a CONFSPEC variable containing configuration specifications
11
+# - an _activate() method that returns True if the plugin can be activated (
12
+# optionnal)
13
+#
14
+class SessionHandlerPlugin(Plugin):
15
+    __instance = None
16
+    _plist_confspecs = {
17
+        'section': 'lodel2',
18
+        'key': 'session_handler',
19
+        'default': None,
20
+        'validator': SettingValidator('string', none_is_valid=False)}
21
+        
22
+    def __init__(self, plugin_name):
23
+        if self.__instance is None:
24
+            super(Plugin, self).__init__(plugin_name)
25
+            self.__instance = True
26
+        else:
27
+            raise RuntimeError("A SessionHandler Plugin is already plug")
28
+

+ 23
- 20
lodel/settings/settings.py View File

@@ -11,7 +11,8 @@ from collections import namedtuple
11 11
 from lodel import logger
12 12
 from lodel.plugin.plugins import Plugin, PluginError
13 13
 from lodel.settings.utils import SettingsError, SettingsErrors
14
-from lodel.settings.validator import SettingValidator, LODEL2_CONF_SPECS
14
+from lodel.settings.validator import SettingValidator, LODEL2_CONF_SPECS, \
15
+    confspec_append
15 16
 from lodel.settings.settings_loader import SettingsLoader
16 17
 
17 18
 ## @package lodel.settings.settings Lodel2 settings module
@@ -132,37 +133,39 @@ class Settings(object, metaclass=MetaSettings):
132 133
     def __bootstrap(self):
133 134
         logger.debug("Settings bootstraping")
134 135
         lodel2_specs = LODEL2_CONF_SPECS
136
+        loader = SettingsLoader(self.__conf_dir) 
137
+        plugin_list = []
138
+        for ptype in Plugin.plugin_types():
139
+            pls = ptype.plist_confspecs()
140
+            lodel2_specs = confspec_append(lodel2_specs, **pls)
141
+            cur_list = loader.getoption(
142
+                pls['section'],
143
+                pls['key'],
144
+                pls['validator'],
145
+                pls['default'])
146
+            if cur_list is None:
147
+                continue
148
+            try:
149
+                if isinstance(cur_list, str):
150
+                    cur_list = [cur_list]
151
+                plugin_list += cur_list
152
+            except TypeError:
153
+                plugin_list += [cur_list]
154
+        #Checking confspecs
135 155
         for section in lodel2_specs:
136 156
             if section.lower() != section:
137 157
                 raise SettingsError("Only lower case are allowed in section name (thank's ConfigParser...)")
138 158
             for kname in lodel2_specs[section]:
139 159
                 if kname.lower() != kname:
140 160
                     raise SettingsError("Only lower case are allowed in section name (thank's ConfigParser...)")
141
-         
142
-        # Load specs for the plugins list and plugins_path list conf keys
143
-        plugins_opt_specs = lodel2_specs['lodel2']['plugins']
144
-        plugins_path_opt_specs = lodel2_specs['lodel2']['plugins_path']
145
-        # Init the settings loader
146
-        loader = SettingsLoader(self.__conf_dir)
147
-        # fetching list of plugins to load
148 161
 
149
-        plugins_list = loader.getoption(    'lodel2',
150
-                                            'plugins',
151
-                                            plugins_opt_specs[1],
152
-                                            plugins_opt_specs[0],
153
-                                            False)
154
-        plugins_path = loader.getoption(    'lodel2',
155
-                                            'plugins_path',
156
-                                            plugins_path_opt_specs[1],
157
-                                            plugins_path_opt_specs[0],
158
-                                            False)
159 162
         # Starting the Plugins class
160 163
         logger.debug("Starting lodel.plugin.Plugin class")
161
-        Plugin.start(plugins_path, plugins_list)
164
+        Plugin.start(plugin_list)
162 165
         # Fetching conf specs from plugins
163 166
         specs = [lodel2_specs]
164 167
         errors = list()
165
-        for plugin_name in plugins_list:
168
+        for plugin_name in plugin_list:
166 169
             try:
167 170
                 specs.append(Plugin.get(plugin_name).confspecs)
168 171
             except PluginError as e:

+ 0
- 1
lodel/settings/settings_loader.py View File

@@ -66,7 +66,6 @@ class SettingsLoader(object):
66 66
     # @return the option
67 67
     def getoption(self,section,keyname,validator,default_value=None,mandatory=False):
68 68
         conf=self.__conf
69
-
70 69
         if section not in conf:
71 70
             conf[section] = dict()
72 71
 

+ 5
- 10
lodel/settings/validator.py View File

@@ -357,17 +357,12 @@ SettingValidator.create_re_validator(
357 357
 #@param orig dict : the confspec to update
358 358
 #@param upd dict : the confspec to add
359 359
 #@return new confspec
360
-def confspec_append(orig, upd):
361
-    for section in orig:
362
-        if section in upd:
363
-            orig[section].update(upd[section])
364
-        else:
365
-            orig[section] = upd[section]
366
-    return orig
367
-
368
-def confspec_add(orig, section, key, default, validator):
360
+def confspec_append(orig, section, key, validator, default):
369 361
     if section not in orig:
370
-        section[orig] = dict()
362
+        orig[section] = dict()
363
+    if key not in orig[section]:
364
+        orig[section][key] = (default, validator)
365
+    return orig
371 366
 
372 367
 ##@brief Global specifications for lodel2 settings
373 368
 LODEL2_CONF_SPECS = {

+ 1
- 1
plugins/filesystem_session/__init__.py View File

@@ -1,7 +1,7 @@
1 1
 from lodel.settings.validator import SettingValidator
2 2
 
3 3
 __plugin_name__ = 'filesystem_session'
4
-__version = [0,0,1]
4
+__version__ = [0,0,1]
5 5
 __type__ = 'session_handler'
6 6
 __loader__ = 'main.py'
7 7
 __confspec__ = "confspec.py"

+ 2
- 2
plugins/filesystem_session/confspec.py View File

@@ -4,8 +4,8 @@ from lodel.settings.validator import SettingValidator
4 4
 
5 5
 CONFSPEC = {
6 6
     'lodel2.sessions':{
7
-        'directory': ('/tmp/lodel2_session', SettingValidator('path')),
7
+        'directory': ('/tmp/', SettingValidator('path')),
8 8
         'expiration': (900, SettingValidator('int')),
9 9
         'file_template': ('lodel2_%s.sess', SettingValidator('dummy'))
10 10
     }
11
-}
11
+}

+ 2
- 0
plugins/filesystem_session/main.py View File

@@ -1,5 +1,6 @@
1 1
 # -*- coding: utf-8 -*-
2 2
 
3
+"""
3 4
 from lodel.auth.exceptions import AuthenticationError
4 5
 from lodel.plugin import LodelHook
5 6
 
@@ -38,3 +39,4 @@ def read_session(caller, sid):
38 39
 def clean_sessions(caller):
39 40
     FileSystemSession.clean()
40 41
 '''
42
+"""

+ 2
- 1
tests/settings/test_settings_loader.py View File

@@ -4,6 +4,7 @@ import unittest
4 4
 import os.path
5 5
 
6 6
 from lodel.settings.utils import *
7
+from lodel.plugin.exceptions import *
7 8
 from lodel.settings.settings_loader import SettingsLoader
8 9
 
9 10
 
@@ -255,5 +256,5 @@ class SettingsLoaderTestCase(unittest.TestCase):
255 256
     def test_invalid_conf(self):
256 257
         from lodel.settings.settings import Settings
257 258
         Settings.stop()
258
-        with self.assertRaises(SettingsErrors):
259
+        with self.assertRaises((SettingsErrors, PluginError)):
259 260
             Settings('tests/settings/settings_examples/bad_conf.d')

+ 3
- 0
tests/tests_conf.d/lodel2.ini View File

@@ -4,6 +4,9 @@ sitename = noname
4 4
 plugins_path = /foo/plugins
5 5
 plugins = dummy, dummy_datasource
6 6
 runtest=True
7
+extensions = dummy
8
+datasource_connectors = dummy_datasource
9
+session_handler = filesystem_session
7 10
 
8 11
 [lodel2.logging.stderr]
9 12
 level = Error

Loading…
Cancel
Save