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 7 years ago
parent
commit
76e386e321

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

42
 from .hooks import LodelHook
42
 from .hooks import LodelHook
43
 from .plugins import Plugin, CustomMethod
43
 from .plugins import Plugin, CustomMethod
44
 from .datasource_plugin import DatasourcePlugin
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
     ##@brief Stores confspecs indicating where DatasourcePlugin list is stored
14
     ##@brief Stores confspecs indicating where DatasourcePlugin list is stored
15
     _plist_confspecs = {
15
     _plist_confspecs = {
16
         'section': 'lodel2',
16
         'section': 'lodel2',
17
-        'key': 'datasources',
17
+        'key': 'datasource_connectors',
18
         'default': None,
18
         'default': None,
19
-        'validator': SettingValidator('list', none_is_valid = False) }
19
+        'validator': SettingValidator('strip', none_is_valid = False) }
20
     
20
     
21
     def __init__(self, name):
21
     def __init__(self, name):
22
         super().__init__(name)
22
         super().__init__(name)
30
     def migration_handler(self):
30
     def migration_handler(self):
31
         return self.loader_module().migration_handler_class()
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
     ##@brief Return an initialized Datasource instance
33
     ##@brief Return an initialized Datasource instance
38
     #@param ds_name str : The name of the datasource to instanciate
34
     #@param ds_name str : The name of the datasource to instanciate
39
     #@param ro bool
35
     #@param ro bool

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

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
 from lodel import logger
11
 from lodel import logger
12
 from lodel.settings.utils import SettingsError
12
 from lodel.settings.utils import SettingsError
13
 from .exceptions import *
13
 from .exceptions import *
14
+from lodel.exceptions import *
14
 
15
 
15
 ## @package lodel.plugins Lodel2 plugins management
16
 ## @package lodel.plugins Lodel2 plugins management
16
 #
17
 #
161
         #Here we can store all child classes of Plugin
162
         #Here we can store all child classes of Plugin
162
         super().__init__(name, bases, attrs)
163
         super().__init__(name, bases, attrs)
163
         if len(bases) == 1 and bases[0] == object:
164
         if len(bases) == 1 and bases[0] == object:
164
-            print("Dropped : ", name, bases)
165
             return
165
             return
166
         self.__register_types()
166
         self.__register_types()
167
         #list_name= [cls.__name__ for cls in __all_ptypes] 
167
         #list_name= [cls.__name__ for cls in __all_ptypes] 
177
     __all_ptypes.append(cls)
177
     __all_ptypes.append(cls)
178
     logger.info("New child class registered : %s" % cls.__name__)
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
 ##@brief Handle plugins
184
 ##@brief Handle plugins
182
 #
185
 #
204
     
207
     
205
     ##@brief Store dict representation of discover cache content
208
     ##@brief Store dict representation of discover cache content
206
     _discover_cache = None
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
     ##@brief Plugin class constructor
215
     ##@brief Plugin class constructor
209
     #
216
     #
213
     # @param plugin_name str : plugin name
220
     # @param plugin_name str : plugin name
214
     # @throw PluginError
221
     # @throw PluginError
215
     def __init__(self, plugin_name):
222
     def __init__(self, plugin_name):
216
-        self.started()
223
+        
217
         self.name = plugin_name
224
         self.name = plugin_name
218
         self.path = self.plugin_path(plugin_name)
225
         self.path = self.plugin_path(plugin_name)
219
         
226
         
272
             #PLUGIN_VERSION_VARNAME in init file is mandatory
279
             #PLUGIN_VERSION_VARNAME in init file is mandatory
273
             self.__version = getattr(self.module, PLUGIN_VERSION_VARNAME)
280
             self.__version = getattr(self.module, PLUGIN_VERSION_VARNAME)
274
         except AttributeError:
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
             raise LodelFatalError(msg)
285
             raise LodelFatalError(msg)
279
 
286
 
280
         # Load plugin type
287
         # Load plugin type
459
     def confspecs(self):
466
     def confspecs(self):
460
         return copy.copy(self.__confspecs)
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
     ##@brief Retrieves plugin list confspecs
476
     ##@brief Retrieves plugin list confspecs
463
     #
477
     #
464
     #This method ask for each Plugin child class the confspecs specifying where
478
     #This method ask for each Plugin child class the confspecs specifying where
525
             pcls = DatasourcePlugin
539
             pcls = DatasourcePlugin
526
         else:
540
         else:
527
             pcls = cls
541
             pcls = cls
528
-        print(plugin_name, ptype, pcls)
529
         plugin = pcls(plugin_name)
542
         plugin = pcls(plugin_name)
530
         cls._plugin_instances[plugin_name] = plugin
543
         cls._plugin_instances[plugin_name] = plugin
531
         logger.debug("Plugin %s available." % plugin)
544
         logger.debug("Plugin %s available." % plugin)
550
     # @return the plugin directory path
563
     # @return the plugin directory path
551
     @classmethod
564
     @classmethod
552
     def plugin_path(cls, plugin_name):
565
     def plugin_path(cls, plugin_name):
553
-        cls.started()
566
+        
554
         plist = cls.plugin_list()
567
         plist = cls.plugin_list()
555
         if plugin_name not in plist:
568
         if plugin_name not in plist:
556
             raise PluginError("No plugin named '%s' found" % plugin_name)
569
             raise PluginError("No plugin named '%s' found" % plugin_name)
572
     #
585
     #
573
     # This method load path and preload plugins
586
     # This method load path and preload plugins
574
     @classmethod
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
         for plugin_name in plugins:
589
         for plugin_name in plugins:
586
             cls.register(plugin_name)
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
     @classmethod
592
     @classmethod
595
     def clear(cls):
593
     def clear(cls):
596
         if cls._plugin_directories is not None:
594
         if cls._plugin_directories is not None:
657
     ##@brief Return a list of child Class Plugin
655
     ##@brief Return a list of child Class Plugin
658
     @classmethod
656
     @classmethod
659
     def plugin_types(cls):
657
     def plugin_types(cls):
660
-        return cls.__all_ptypes
658
+        return all_types()
661
 
659
 
662
     ##@brief Attempt to open and load plugin discover cache
660
     ##@brief Attempt to open and load plugin discover cache
663
     #@return discover cache
661
     #@return discover cache
880
                         custom_method.__get_method())
878
                         custom_method.__get_method())
881
                     logger.debug(
879
                     logger.debug(
882
                         "Custom method %s added to target" % custom_method)
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
         #Here we can store all child classes of LodelScript
17
         #Here we can store all child classes of LodelScript
18
         super().__init__(name, bases, attrs)
18
         super().__init__(name, bases, attrs)
19
         if len(bases) == 1 and bases[0] == object:
19
         if len(bases) == 1 and bases[0] == object:
20
-            print("Dropped : ", name, bases)
21
             return
20
             return
22
 
21
 
23
         self.__register_script(name)
22
         self.__register_script(name)

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

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
 from lodel import logger
11
 from lodel import logger
12
 from lodel.plugin.plugins import Plugin, PluginError
12
 from lodel.plugin.plugins import Plugin, PluginError
13
 from lodel.settings.utils import SettingsError, SettingsErrors
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
 from lodel.settings.settings_loader import SettingsLoader
16
 from lodel.settings.settings_loader import SettingsLoader
16
 
17
 
17
 ## @package lodel.settings.settings Lodel2 settings module
18
 ## @package lodel.settings.settings Lodel2 settings module
132
     def __bootstrap(self):
133
     def __bootstrap(self):
133
         logger.debug("Settings bootstraping")
134
         logger.debug("Settings bootstraping")
134
         lodel2_specs = LODEL2_CONF_SPECS
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
         for section in lodel2_specs:
155
         for section in lodel2_specs:
136
             if section.lower() != section:
156
             if section.lower() != section:
137
                 raise SettingsError("Only lower case are allowed in section name (thank's ConfigParser...)")
157
                 raise SettingsError("Only lower case are allowed in section name (thank's ConfigParser...)")
138
             for kname in lodel2_specs[section]:
158
             for kname in lodel2_specs[section]:
139
                 if kname.lower() != kname:
159
                 if kname.lower() != kname:
140
                     raise SettingsError("Only lower case are allowed in section name (thank's ConfigParser...)")
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
         # Starting the Plugins class
162
         # Starting the Plugins class
160
         logger.debug("Starting lodel.plugin.Plugin class")
163
         logger.debug("Starting lodel.plugin.Plugin class")
161
-        Plugin.start(plugins_path, plugins_list)
164
+        Plugin.start(plugin_list)
162
         # Fetching conf specs from plugins
165
         # Fetching conf specs from plugins
163
         specs = [lodel2_specs]
166
         specs = [lodel2_specs]
164
         errors = list()
167
         errors = list()
165
-        for plugin_name in plugins_list:
168
+        for plugin_name in plugin_list:
166
             try:
169
             try:
167
                 specs.append(Plugin.get(plugin_name).confspecs)
170
                 specs.append(Plugin.get(plugin_name).confspecs)
168
             except PluginError as e:
171
             except PluginError as e:

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

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

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

357
 #@param orig dict : the confspec to update
357
 #@param orig dict : the confspec to update
358
 #@param upd dict : the confspec to add
358
 #@param upd dict : the confspec to add
359
 #@return new confspec
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
     if section not in orig:
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
 ##@brief Global specifications for lodel2 settings
367
 ##@brief Global specifications for lodel2 settings
373
 LODEL2_CONF_SPECS = {
368
 LODEL2_CONF_SPECS = {

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

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

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

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

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

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

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

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

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

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

Loading…
Cancel
Save