Browse Source

New plugins organisation + utility methods + manage_lodel.py script

Yann Weber 8 years ago
parent
commit
dab52a3941
11 changed files with 202 additions and 6 deletions
  1. 13
    0
      Lodel/hooks.py
  2. 87
    0
      Lodel/plugins.py
  3. 8
    0
      Lodel/settings.py
  4. 12
    0
      Lodel/user.py
  5. 1
    0
      lodel_init.sh
  6. 0
    0
      lodel_web.py
  7. 64
    0
      manage_lodel.py
  8. 2
    2
      plugins/__init__.py
  9. 2
    0
      plugins/acl/__init__.py
  10. 4
    4
      plugins/acl/acl.py
  11. 9
    0
      plugins/acl/conf.py

+ 13
- 0
Lodel/hooks.py View File

@@ -1,6 +1,7 @@
1 1
 #-*- coding: utf-8 -*-
2 2
 
3 3
 import os
4
+import copy
4 5
 from importlib.machinery import SourceFileLoader
5 6
 
6 7
 from Lodel.settings import Settings
@@ -65,4 +66,16 @@ class LodelHook(object):
65 66
             for hook in cls._hooks[hook_name]:
66 67
                 payload = hook(hook_name, caller, payload)
67 68
         return payload
69
+    
70
+    ## @brief Fetch registered hooks
71
+    # @param names list | None : optionnal filter on name
72
+    # @return a list of functions
73
+    @classmethod
74
+    def hook_list(cls, names = None):
75
+        res = None
76
+        if names is not None:
77
+            res = { name: copy.copy(cls._hooks[name]) for name in cls._hooks if name in names}
78
+        else:
79
+            res = copy.copy(cls._hooks)
80
+        return { name: [(hook._hook, hook._priority) for hook in hooks] for name, hooks in res.items() }
68 81
 

+ 87
- 0
Lodel/plugins.py View File

@@ -0,0 +1,87 @@
1
+#-*- coding: utf-8 -*-
2
+
3
+import inspect
4
+import os, os.path
5
+import warnings
6
+
7
+from Lodel.settings import Settings
8
+from Lodel.hooks import LodelHook
9
+from Lodel.user import authentication_method, identification_method
10
+
11
+
12
+## @brief Returns a list of human readable registered hooks
13
+# @param names list | None : optionnal filter on name
14
+# @param plugins list | None : optionnal filter on plugin name
15
+# @return A str representing registered hooks
16
+def list_hooks(names = None, plugins = None):
17
+    res = ""
18
+    # Hooks registered and handled by Lodel.usera
19
+    for decorator in [authentication_method, identification_method]:
20
+        if names is None or decorator.__name__ in names:
21
+            res += "%s :\n" % decorator.__name__
22
+            for hook in decorator.list_methods():
23
+                module = inspect.getmodule(hook).__name__
24
+                if plugins is not None: # Filter by plugin
25
+                    spl = module.split('.')
26
+                    if spl[-1] not in plugins:
27
+                        continue
28
+                res += "\t- %s.%s\n" % (module, hook.__name__)
29
+    # Hooks registered and handled by Lodel.hooks
30
+    registered_hooks = LodelHook.hook_list(names)
31
+    for hook_name, hooks in registered_hooks.items():
32
+        if names is None or hook_name in names:
33
+            res += "%s :\n" % hook_name
34
+            for hook, priority in hooks:
35
+                module = inspect.getmodule(hook).__name__
36
+                if plugins is not None: # Filter by plugin
37
+                    spl = module.split('.')
38
+                    if spl[-1] not in plugins:
39
+                        continue
40
+                res += "\t- %s.%s ( priority %d )\n" % (module, hook.__name__, priority)
41
+    return res
42
+
43
+## @brief Return a human readable list of plugins
44
+# @param activated bool | None : Optionnal filter on activated or not plugin
45
+# @return a str
46
+def list_plugins(activated = None):
47
+    res = ""
48
+    # Activated plugins
49
+    if activated is None or activated:
50
+        res += "Activated plugins :\n"
51
+        for plugin_name in Settings.plugins:
52
+            res += "\t- %s\n" % plugin_name
53
+    # Deactivated plugins
54
+    if activated is None or not activated:
55
+        plugin_dir = os.path.join(Settings.lodel2_lib_path, 'plugins')
56
+        res += "Not activated plugins :\n"
57
+        all_plugins = [fname for fname in os.listdir(plugin_dir) if fname != '.' and fname != '..' and fname != '__init__.py']
58
+        for plugin_name in all_plugins:
59
+            if os.path.isfile(os.path.join(plugin_dir, plugin_name)) and plugin_name.endswith('.py'):
60
+                plugin_name = ''.join(plugin_name.split('.')[:-1])
61
+            elif not os.path.isdir(os.path.join(plugin_dir, plugin_name)):
62
+                warnings.warn("Dropped file in plugins directory : '%s'" % (os.path.join(plugin_dir, plugin_name)))
63
+                continue
64
+            elif plugin_name == '__pycache__':
65
+                continue
66
+
67
+            if plugin_name not in Settings.plugins:
68
+                res += "\t- %s\n" % plugin_name
69
+    return res
70
+
71
+## @brief Utility function that generate the __all__ list of the plugins/__init__.py file
72
+# @return A list of module name to import
73
+def _all_plugins():
74
+    plugin_dir = os.path.join(Settings.lodel2_lib_path, 'plugins')
75
+    res = list()
76
+    for plugin_name in Settings.plugins:
77
+        if os.path.isdir(os.path.join(plugin_dir, plugin_name)):
78
+            # plugin is a module
79
+            res.append('%s' % plugin_name)
80
+            #res.append('%s.loader' % plugin_name)
81
+        elif os.path.isfile(os.path.join(plugin_dir, '%s.py' % plugin_name)):
82
+            # plugin is a simple python sourcefile
83
+            res.append('%s' % plugin_name)
84
+    return res
85
+            
86
+            
87
+    

+ 8
- 0
Lodel/settings.py View File

@@ -88,6 +88,14 @@ class SettingsHandler(object):
88 88
             err_msg = "Found invalid settings in %s : %s"%(module.__name__, errors)
89 89
             raise LookupError(err_msg)
90 90
 
91
+    ## @brief Refresh the allowed and mandatory settings list
92
+    @classmethod
93
+    def _refresh_format(cls):
94
+        ## @brief Shortcut
95
+        cls._allowed = settings_format.ALLOWED + settings_format.MANDATORY
96
+        ## @brief Shortcut
97
+        cls._mandatory = settings_format.MANDATORY
98
+
91 99
     ## @brief If some settings are missings return their names
92 100
     # @return an array of string
93 101
     def _missings(self):

+ 12
- 0
Lodel/user.py View File

@@ -6,6 +6,7 @@
6 6
 # Classes defined in this package are "helpers" for Lodel2 UI
7 7
 
8 8
 import warnings
9
+import copy
9 10
 from Lodel.settings import Settings
10 11
 
11 12
 ## @brief Represent a Lodel user identity
@@ -121,6 +122,12 @@ class authentication_method(object):
121 122
                 res = ret
122 123
         return res
123 124
 
125
+    ## @return registered identification methods
126
+    @classmethod
127
+    def list_methods(cls):
128
+        return list(copy.copy(cls.__methods))
129
+
130
+
124 131
 
125 132
 ## @brief Decorator class designed to register identification methods
126 133
 #
@@ -161,6 +168,11 @@ class identification_method(object):
161 168
                         return ret
162 169
                     res = ret
163 170
         return res
171
+    
172
+    ## @return registered identification methods
173
+    @classmethod
174
+    def list_methods(cls):
175
+        return list(copy.copy(cls.__methods))
164 176
 
165 177
 
166 178
 ## @brief Static class designed to handle user context

+ 1
- 0
lodel_init.sh View File

@@ -33,6 +33,7 @@ mkdir -pv "$instdir"
33 33
 
34 34
 cp -v $libdir/install/* $instdir
35 35
 rm -fv $instdir/__init__.py
36
+cp -v $libdir/manage_lodel.py $instdir
36 37
 
37 38
 sed -i -e "s#LODEL2_LIB_ABS_PATH#$libdir#" "$settings"
38 39
 sed -i -e "s#LODEL2_INSTANCE_NAME#$name#" "$settings"

lodel.py → lodel_web.py View File


+ 64
- 0
manage_lodel.py View File

@@ -0,0 +1,64 @@
1
+#-*- coding: utf-8 -*-
2
+
3
+import sys
4
+import argparse
5
+
6
+try:
7
+    from loader import *
8
+except ImportError: pass
9
+
10
+from plugins import *
11
+
12
+if __name__ == '__main__':
13
+    parser = argparse.ArgumentParser()
14
+    parser.add_argument(
15
+                        '--list-hooks',
16
+                        action='store_const',
17
+                        const=True,
18
+                        default=False,
19
+                        help='Display the list of registered hooks'
20
+    )
21
+    parser.add_argument(
22
+                        '--list-plugins',
23
+                        action='store_const',
24
+                        const=True,
25
+                        default=False,
26
+                        help='Display the list of plugins'
27
+    )
28
+    parser.add_argument(
29
+                        '--plugin',
30
+                        action='store',
31
+                        type=str,
32
+                        metavar='PLUGIN_NAME',
33
+                        nargs='+',
34
+                        help='Filter on plugins name'
35
+    )
36
+    parser.add_argument(
37
+                        '--hookname',
38
+                        action='store',
39
+                        type=str,
40
+                        metavar='HOOK_NAME',
41
+                        nargs='+',
42
+                        help='Filter on hook name'
43
+    )
44
+    kwargs = parser.parse_args()
45
+
46
+    # Listing registered hooks
47
+    if kwargs.list_hooks:
48
+        import Lodel.plugins
49
+        list_args = {}
50
+        if kwargs.plugin is not None and len(kwargs.plugin) > 0:
51
+            list_args['plugins'] = kwargs.plugin
52
+        if kwargs.hookname is not None and len(kwargs.hookname) > 0:
53
+            list_args['names'] = kwargs.hookname
54
+            
55
+        print(Lodel.plugins.list_hooks(**list_args))
56
+        exit(0)
57
+    # Listing plugins
58
+    elif kwargs.list_plugins:
59
+        import Lodel.plugins
60
+        print(Lodel.plugins.list_plugins())
61
+        exit(0)
62
+
63
+    parser.print_help()
64
+    exit(1)

+ 2
- 2
plugins/__init__.py View File

@@ -1,2 +1,2 @@
1
-import Lodel.settings
2
-__all__ = Lodel.settings.Settings.plugins
1
+import Lodel.plugins
2
+__all__ = Lodel.plugins._all_plugins()

+ 2
- 0
plugins/acl/__init__.py View File

@@ -0,0 +1,2 @@
1
+__all__ = ['acl', 'conf']
2
+from . import *

plugins/acl.py → plugins/acl/acl.py View File

@@ -5,15 +5,15 @@ from Lodel.user import UserContext
5 5
 
6 6
 class PermissionDenied(Exception): pass
7 7
 
8
-@LodelHook('leapi_get_pre')
8
+@LodelHook('leapi_get_pre', 1)
9 9
 def check_anon(hook_name, caller, payload):
10 10
     if not UserContext.identity().is_identified:
11 11
         raise PermissionDenied("Anonymous user's are not allowed to get content")
12 12
     return payload
13 13
 
14
-@LodelHook('leapi_update_pre')
15
-@LodelHook('leapi_delete_pre')
16
-@LodelHook('leapi_insert_pre')
14
+@LodelHook('leapi_update_pre', 1)
15
+@LodelHook('leapi_delete_pre', 1)
16
+@LodelHook('leapi_insert_pre', 1)
17 17
 def check_auth(hook_name, caller, payload):
18 18
     if not UserContext.identity().is_authenticated:
19 19
         raise PermissionDenied("Only authenticated user's are allowed to do that !")

+ 9
- 0
plugins/acl/conf.py View File

@@ -0,0 +1,9 @@
1
+#-*- coding: utf-8 -*-
2
+
3
+import Lodel.settings_format
4
+from Lodel.settings import Settings
5
+
6
+Lodel.settings_format.ALLOWED.append('acl_settings')
7
+Settings._refresh_format()
8
+Settings.acl_settings = { 'super': 42, 'foo': None }
9
+

Loading…
Cancel
Save