Browse Source

New settings handler

Yann Weber 8 years ago
parent
commit
d5b866512c
5 changed files with 141 additions and 46 deletions
  1. 130
    33
      Lodel/settings.py
  2. 0
    0
      install/instance_settings.py
  3. 6
    6
      install/loader.py
  4. 4
    6
      install/utils.py
  5. 1
    1
      lodel_init.sh

+ 130
- 33
Lodel/settings.py View File

@@ -1,39 +1,136 @@
1 1
 #-*- coding: utf-8 -*-
2
-try:
3
-    import settings_local
4
-except ImportError:
5
-    settings_local = None
6
-
7
-class Settings:
8
-    # List of accepted settings
9
-    datasource = None
10
-
11
-    @staticmethod
12
-    # @throw AttributeError if the setting is not defined in this class
13
-    def get(attribute):
14
-        value = None
15
-        # find the value in settings itself, if not set search in settings_local
16
-        value = getattr(Settings, attribute)
17
-        if value is None:
18
-            try:
19
-                value = getattr(settings_local, attribute)
20
-            except AttributeError:
21
-                pass
22 2
 
23
-        if value is not None:
3
+import types
4
+import warnings
5
+from . import settings_format
6
+
7
+## @package Lodel.settings
8
+#
9
+# @brief Defines stuff to handles Lodel2 configuration
10
+#
11
+# To access the confs use the Lodel.settings.Settings SettingsHandler instance
12
+
13
+## @brief A class designed to handles Lodel2 settings
14
+#
15
+# When instanciating a SettingsHandler, the new instance is filled with the content of settings.py (in the root directory of lodel2
16
+#
17
+# @important You don't have to instanciate this class, you can access to the global instance with the Settings variable in this module
18
+# @todo Forbid module assignement in settings ! and disable tests about this
19
+# @todo Implements a type checking of config value
20
+# @todo Implements default values for config keys
21
+class SettingsHandler(object):
22
+    
23
+    ## @brief Shortcut
24
+    _allowed = settings_format.ALLOWED + settings_format.MANDATORY
25
+    ## @brief Shortcut
26
+    _mandatory = settings_format.MANDATORY
27
+
28
+    def __init__(self):
29
+        try:
30
+            import settings as default_settings
31
+            self._load_module(default_settings)
32
+        except ImportError:
33
+            warnings.warn("Unable to find global default settings")
34
+
35
+        ## @brief A flag set to True when the instance is fully loaded
36
+        self._set_loaded(False if len(self._missings()) > 0 else True)
37
+    
38
+    ## @brief Compat wrapper for getattr
39
+    def get(self, name):
40
+        return getattr(self, name)
41
+    
42
+    ## @brief Compat wrapper for setattr
43
+    def set(self, name, value):
44
+        return setattr(self, name, value)
45
+
46
+    ## @brief Load every module properties in the settings instance
47
+    #
48
+    # Load a module content into a SettingsHandler instance and checks that no mandatory settings are missing
49
+    # @note Example : <pre> import my_cool_settings;
50
+    # Settings._load_module(my_cool_settings);</pre>
51
+    # @param module module|None: a loaded module (if None just check for missing settings)
52
+    # @throw LookupError if invalid settings found or if mandatory settings are missing
53
+    def load_module(self, module = None):
54
+        if not(module is None):
55
+            self._load_module(module)
56
+        missings = self._missings()
57
+        if len(missings) > 0:
58
+            self._loaded = False
59
+            raise LookupError("Mandatory settings are missing : %s"%missings)
60
+        self._set_loaded(True)
61
+    
62
+    ## @brief supersede of default __setattr__ method
63
+    def __setattr__(self, name, value):
64
+        if not hasattr(self, name):
65
+            if name not in self._allowed:
66
+                raise LookupError("Invalid setting : %s"%name)
67
+        super().__setattr__(name, value)
68
+
69
+    ## @brief This method do the job for SettingsHandler.load_module()
70
+    #
71
+    # @note The difference with SettingsHandler.load_module() is that it didn't check if some settings are missing
72
+    # @throw LokkupError if an invalid settings is given
73
+    # @param module : a loaded module
74
+    def _load_module(self, module):
75
+        errors = []
76
+        fatal_errors = []
77
+        conf_dict = {
78
+            name: getattr(module, name)
79
+            for name in dir(module) 
80
+            if not name.startswith('__') and not isinstance(getattr(module, name), types.ModuleType)
81
+        }
82
+        for name, value in conf_dict.items():
24 83
             try:
25
-                func = getattr(Settings, attribute + '_args')
26
-                value = func(value)
27
-            except AttributeError:
28
-                pass
84
+                setattr(self, name, value)
85
+            except LookupError:
86
+                errors.append(name)
87
+        if len(errors) > 0:
88
+            err_msg = "Found invalid settings in %s : %s"%(module.__name__, errors)
89
+            raise LookupError(err_msg)
90
+
91
+    ## @brief If some settings are missings return their names
92
+    # @return an array of string
93
+    def _missings(self):
94
+        return [ confname for confname in self._mandatory if not hasattr(self, confname) ]
29 95
 
30
-        return value
96
+    def _set_loaded(self, value):
97
+        super().__setattr__('_loaded', bool(value))
31 98
 
32
-    @staticmethod
33
-    # @throw AttributeError if the setting is not defined in this class
34
-    def set(attribute, value):
35
-        setattr(Settings, attribute, value)
99
+Settings = SettingsHandler()
36 100
 
37
-    @staticmethod
38
-    def datasource_args(value):
39
-        return value
101
+## @page lodel_settings Lodel SettingsHandler
102
+#
103
+# This page describe the way settings are handled in Lodel2.
104
+#
105
+# @section lodel_settings_files Lodel settings files
106
+#
107
+# - Lodel/settings.py defines the Lodel.settings package, the SettingsHandler class and the Lodel.settings.Settings instance
108
+# - Lodel/settings_format.py defines the mandatory and allowed configurations keys lists
109
+# - install/instance_settings.py is a model of the file that will be deployed in Lodel2 instances directories
110
+#
111
+# @section Using Lodel.settings.Settings SettingsHandler instance
112
+#
113
+# @subsection lodel_settings_without_loader Without loader
114
+#
115
+# Without any loader you can import Lodel.settings.Settings and acces its property with getattr (or . ) or with SettingsHandler.get() method.
116
+# In the same way you can set a settings by standart affectation of a propery or with SettingsHandler.set() method.
117
+#
118
+# @subsection lodel_settings_loader With a loader in a lodel2 instance
119
+#
120
+# The loader will import Lodel.settings.Settings and then calls the SettingsHandler.load_module() method to load the content of the instance_settings.py file into the SettingsHandler instance
121
+#
122
+# @subsection lodel_settings_example Examples
123
+#
124
+# <pre>
125
+# #!/usr/bin/python
126
+# from Lodel.settings import Settings
127
+# if Settings.debug:
128
+#   print("DEBUG")
129
+# #or
130
+# if Settings.get('debug'):
131
+#   print("DEBUG")
132
+# Settings.debug = False
133
+# #or
134
+# Settings.set('debug', False)
135
+# </pre>
136
+# 

install/settings.py → install/instance_settings.py View File


+ 6
- 6
install/loader.py View File

@@ -1,4 +1,4 @@
1
-import settings as instance_settings
1
+import instance_settings
2 2
 import importlib
3 3
 import sys
4 4
 import os
@@ -7,12 +7,12 @@ sys.path.append(instance_settings.lodel2_lib_path)
7 7
 
8 8
 from Lodel.settings import Settings
9 9
 
10
-# Update the settings
11
-for name in [ name for name in dir(instance_settings) if not name.startswith('__') ]:
12
-    Settings.set(name, getattr(instance_settings, name))
10
+# Settings initialisation
11
+Settings.load_module(instance_settings)
12
+globals()['Settings'] = Settings
13 13
 
14 14
 # Import dynamic code
15
-if os.path.isfile(Settings.get('dynamic_code')):
15
+if os.path.isfile(Settings.dynamic_code_file):
16 16
     from dynleapi import *
17 17
 
18 18
 # Import wanted datasource objects
@@ -30,5 +30,5 @@ if __name__ == '__main__':
30 30
     print("""
31 31
      Running interactive python in Lodel2 %s instance environment
32 32
 
33
-"""%settings.name)
33
+"""%Settings.sitename)
34 34
     code.interact(local=locals())

+ 4
- 6
install/utils.py View File

@@ -1,7 +1,5 @@
1 1
 # -*- coding: utf-8 -*-
2 2
 
3
-import settings
4
-from settings import *
5 3
 from loader import *
6 4
 
7 5
 def refreshdyn():
@@ -10,8 +8,8 @@ def refreshdyn():
10 8
     from leapi.lefactory import LeFactory
11 9
     from EditorialModel.backend.json_backend import EmBackendJson
12 10
     from DataSource.MySQL.leapidatasource import LeDataSourceSQL
13
-    OUTPUT = dynamic_code
14
-    EMJSON = emfile
11
+    OUTPUT = Settings.dynamic_code_file
12
+    EMJSON = Settings.em_file
15 13
     # Load editorial model
16 14
     em = Model(EmBackendJson(EMJSON))
17 15
     # Generate dynamic code
@@ -22,8 +20,8 @@ def refreshdyn():
22 20
 def db_init():
23 21
     from EditorialModel.backend.json_backend import EmBackendJson
24 22
     from EditorialModel.model import Model
25
-    mh = getattr(migrationhandler,settings.mh_classname)()
26
-    em = Model(EmBackendJson(settings.emfile))
23
+    mh = getattr(migrationhandler,Settings.mh_classname)()
24
+    em = Model(EmBackendJson(Settings.em_file))
27 25
     em.migrate_handler(mh)
28 26
 
29 27
 

+ 1
- 1
lodel_init.sh View File

@@ -18,7 +18,7 @@ libdir="$3"
18 18
 libdir="${libdir:=$(realpath $(dirname $0))}"
19 19
 
20 20
 emfilename="em.json"
21
-settings="$instdir/settings.py"
21
+settings="$instdir/instance_settings.py"
22 22
 em="$instdir/em.json"
23 23
 dyncode="$instdir/${name}.py"
24 24
 

Loading…
Cancel
Save