|
@@ -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
|
+#
|