Browse Source

Only indentation and stuff like that

prieto 7 years ago
parent
commit
3b4494cb7a

+ 133
- 121
lodel/editorial_model/components.py View File

1
 #-*- coding: utf-8 -*-
1
 #-*- coding: utf-8 -*-
2
 
2
 
3
-##@package lodel.editorial_model.components
3
+# @package lodel.editorial_model.components
4
 #@brief Defines all @ref lodel2_em "EM" components
4
 #@brief Defines all @ref lodel2_em "EM" components
5
 #@ingroup lodel2_em
5
 #@ingroup lodel2_em
6
 
6
 
17
     'lodel.editorial_model.exceptions': ['EditorialModelError', 'assert_edit'],
17
     'lodel.editorial_model.exceptions': ['EditorialModelError', 'assert_edit'],
18
     'lodel.leapi.leobject': ['CLASS_ID_FIELDNAME']})
18
     'lodel.leapi.leobject': ['CLASS_ID_FIELDNAME']})
19
 
19
 
20
-##@brief Abstract class to represent editorial model components
20
+# @brief Abstract class to represent editorial model components
21
 # @see EmClass EmField
21
 # @see EmClass EmField
22
 # @todo forbid '.' in uid
22
 # @todo forbid '.' in uid
23
 #@ingroup lodel2_em
23
 #@ingroup lodel2_em
24
+
25
+
24
 class EmComponent(MlNamedObject):
26
 class EmComponent(MlNamedObject):
25
-    
26
-    ##@brief Instanciate an EmComponent
27
+
28
+    # @brief Instanciate an EmComponent
27
     # @param uid str : uniq identifier
29
     # @param uid str : uniq identifier
28
     # @param display_name MlString|str|dict : component display_name
30
     # @param display_name MlString|str|dict : component display_name
29
     # @param help_text MlString|str|dict : help_text
31
     # @param help_text MlString|str|dict : help_text
30
-    def __init__(self, uid, display_name = None, help_text = None, group = None):
32
+    def __init__(self, uid, display_name=None, help_text=None, group=None):
31
         if self.__class__ == EmComponent:
33
         if self.__class__ == EmComponent:
32
             raise NotImplementedError('EmComponent is an abstract class')
34
             raise NotImplementedError('EmComponent is an abstract class')
33
         self.uid = uid
35
         self.uid = uid
34
         self.group = group
36
         self.group = group
35
         super().__init__(display_name, help_text)
37
         super().__init__(display_name, help_text)
36
-    
38
+
37
     def __str__(self):
39
     def __str__(self):
38
         if self.display_name is None:
40
         if self.display_name is None:
39
             return str(self.uid)
41
             return str(self.uid)
42
     def d_hash(self):
44
     def d_hash(self):
43
         m = hashlib.md5()
45
         m = hashlib.md5()
44
         for data in (
46
         for data in (
45
-                        self.uid,
46
-                        'NODISPNAME' if self.display_name is None else str(self.display_name.d_hash()),
47
-                        'NOHELP' if self.help_text is None else str(self.help_text.d_hash()),
48
-                        'NOGROUP' if self.group is None else str(self.group.d_hash()),
47
+            self.uid,
48
+            'NODISPNAME' if self.display_name is None else str(self.display_name.d_hash()),
49
+            'NOHELP' if self.help_text is None else str(self.help_text.d_hash()),
50
+            'NOGROUP' if self.group is None else str(self.group.d_hash()),
49
         ):
51
         ):
50
             m.update(bytes(data, 'utf-8'))
52
             m.update(bytes(data, 'utf-8'))
51
         return int.from_bytes(m.digest(), byteorder='big')
53
         return int.from_bytes(m.digest(), byteorder='big')
52
 
54
 
53
 
55
 
54
-##@brief Handles editorial model objects classes
56
+# @brief Handles editorial model objects classes
55
 #@ingroup lodel2_em
57
 #@ingroup lodel2_em
56
 class EmClass(EmComponent):
58
 class EmClass(EmComponent):
57
-    
58
-    ##@brief Instanciate a new EmClass
59
+
60
+    # @brief Instanciate a new EmClass
59
     #@param uid str : uniq identifier
61
     #@param uid str : uniq identifier
60
     #@param display_name MlString|str|dict : component display_name
62
     #@param display_name MlString|str|dict : component display_name
61
     #@param abstract bool : set the class as asbtract if True
63
     #@param abstract bool : set the class as asbtract if True
62
     #@param pure_abstract bool : if True the EmClass will not be represented in
64
     #@param pure_abstract bool : if True the EmClass will not be represented in
63
-    #leapi dyncode
65
+    # leapi dyncode
64
     #@param parents list: parent EmClass list or uid list
66
     #@param parents list: parent EmClass list or uid list
65
     #@param help_text MlString|str|dict : help_text
67
     #@param help_text MlString|str|dict : help_text
66
-    #@param datasources str|tuple|list : The datasource name ( see 
68
+    #@param datasources str|tuple|list : The datasource name ( see
67
     #@ref lodel2_datasources ) or two names (first is read_only datasource the
69
     #@ref lodel2_datasources ) or two names (first is read_only datasource the
68
-    #second is read write)
70
+    # second is read write)
69
     def __init__(
71
     def __init__(
70
-        self, uid, display_name = None, help_text = None, abstract = False,
71
-        parents = None, group = None, pure_abstract = False,
72
-        datasources = 'default'):
72
+            self, uid, display_name=None, help_text=None, abstract=False,
73
+            parents=None, group=None, pure_abstract=False,
74
+            datasources='default'):
73
 
75
 
74
         super().__init__(uid, display_name, help_text, group)
76
         super().__init__(uid, display_name, help_text, group)
75
         self.abstract = bool(abstract)
77
         self.abstract = bool(abstract)
85
                 parents = [parents]
87
                 parents = [parents]
86
             for parent in parents:
88
             for parent in parents:
87
                 if not isinstance(parent, EmClass):
89
                 if not isinstance(parent, EmClass):
88
-                    raise ValueError("<class EmClass> expected in parents list, but %s found" % type(parent))
90
+                    raise ValueError(
91
+                        "<class EmClass> expected in parents list, but %s found" % type(parent))
89
         else:
92
         else:
90
             parents = list()
93
             parents = list()
91
         self.parents = parents
94
         self.parents = parents
92
-        ##@brief Stores EmFields instances indexed by field uid
93
-        self.__fields = dict() 
94
-        
95
+        # @brief Stores EmFields instances indexed by field uid
96
+        self.__fields = dict()
97
+
95
         self.group = group
98
         self.group = group
96
         if group is None:
99
         if group is None:
97
             warnings.warn("NO GROUP FOR EMCLASS %s" % uid)
100
             warnings.warn("NO GROUP FOR EMCLASS %s" % uid)
98
         else:
101
         else:
99
             group.add_components([self])
102
             group.add_components([self])
100
-    
101
-        #Adding common field
103
+
104
+        # Adding common field
102
         if not self.abstract:
105
         if not self.abstract:
103
             self.new_field(
106
             self.new_field(
104
                 CLASS_ID_FIELDNAME,
107
                 CLASS_ID_FIELDNAME,
105
-                display_name = {
108
+                display_name={
106
                     'eng': "LeObject subclass identifier",
109
                     'eng': "LeObject subclass identifier",
107
                     'fre': "Identifiant de la class fille de LeObject"},
110
                     'fre': "Identifiant de la class fille de LeObject"},
108
-                help_text = {
111
+                help_text={
109
                     'eng': "Allow to create instance of the good class when\
112
                     'eng': "Allow to create instance of the good class when\
110
  fetching arbitrary datas from DB"},
113
  fetching arbitrary datas from DB"},
111
-                data_handler = 'LeobjectSubclassIdentifier',
112
-                internal = True,
113
-                group = group)
114
+                data_handler='LeobjectSubclassIdentifier',
115
+                internal=True,
116
+                group=group)
114
 
117
 
115
-    ##@brief Property that represent a dict of all fields (the EmField defined in this class and all its parents)
118
+    # @brief Property that represent a dict of all fields (the EmField defined in this class and all its parents)
116
     # @todo use Settings.editorialmodel.groups to determine wich fields should be returned
119
     # @todo use Settings.editorialmodel.groups to determine wich fields should be returned
117
     @property
120
     @property
118
     def __all_fields(self):
121
     def __all_fields(self):
119
         res = dict()
122
         res = dict()
120
-        for pfields in [ p.__all_fields for p in self.parents]:
123
+        for pfields in [p.__all_fields for p in self.parents]:
121
             res.update(pfields)
124
             res.update(pfields)
122
         res.update(self.__fields)
125
         res.update(self.__fields)
123
         return res
126
         return res
124
-    
125
-    ##@brief RO access to datasource attribute
127
+
128
+    # @brief RO access to datasource attribute
126
     @property
129
     @property
127
     def datasource(self):
130
     def datasource(self):
128
         return self.__datasource
131
         return self.__datasource
129
 
132
 
130
-    ##@brief Return the list of all dependencies
133
+    # @brief Return the list of all dependencies
131
     #
134
     #
132
     # Reccursive parents listing
135
     # Reccursive parents listing
133
     @property
136
     @property
140
             res |= parent.parents_recc
143
             res |= parent.parents_recc
141
         return res
144
         return res
142
 
145
 
143
-    ##@brief EmField getter
146
+    # @brief EmField getter
144
     # @param uid None | str : If None returns an iterator on EmField instances else return an EmField instance
147
     # @param uid None | str : If None returns an iterator on EmField instances else return an EmField instance
145
     # @param no_parents bool : If True returns only fields defined is this class and not the one defined in parents classes
148
     # @param no_parents bool : If True returns only fields defined is this class and not the one defined in parents classes
146
     # @return A list on EmFields instances (if uid is None) else return an EmField instance
149
     # @return A list on EmFields instances (if uid is None) else return an EmField instance
147
     # @todo use Settings.editorialmodel.groups to determine wich fields should be returned
150
     # @todo use Settings.editorialmodel.groups to determine wich fields should be returned
148
-    def fields(self, uid = None, no_parents = False):
151
+    def fields(self, uid=None, no_parents=False):
149
         fields = self.__fields if no_parents else self.__all_fields
152
         fields = self.__fields if no_parents else self.__all_fields
150
         try:
153
         try:
151
             return list(fields.values()) if uid is None else fields[uid]
154
             return list(fields.values()) if uid is None else fields[uid]
152
         except KeyError:
155
         except KeyError:
153
             raise EditorialModelError("No such EmField '%s'" % uid)
156
             raise EditorialModelError("No such EmField '%s'" % uid)
154
-    
155
-    ##@brief Keep in __fields only fields contained in active groups
157
+
158
+    # @brief Keep in __fields only fields contained in active groups
156
     def _set_active_fields(self, active_groups):
159
     def _set_active_fields(self, active_groups):
157
         if not Settings.editorialmodel.editormode:
160
         if not Settings.editorialmodel.editormode:
158
             active_fields = []
161
             active_fields = []
159
             for grp_name, agrp in active_groups.items():
162
             for grp_name, agrp in active_groups.items():
160
-                active_fields += [ emc for emc in agrp.components()
161
-                    if isinstance(emc, EmField)]
162
-            self.__fields = { fname:fdh for fname, fdh in self.__fields.items()
163
-                if fdh in active_fields }
163
+                active_fields += [emc for emc in agrp.components()
164
+                                  if isinstance(emc, EmField)]
165
+            self.__fields = {fname: fdh for fname, fdh in self.__fields.items()
166
+                             if fdh in active_fields}
164
 
167
 
165
-    ##@brief Add a field to the EmClass
168
+    # @brief Add a field to the EmClass
166
     # @param emfield EmField : an EmField instance
169
     # @param emfield EmField : an EmField instance
167
     # @warning do not add an EmField allready in another class !
170
     # @warning do not add an EmField allready in another class !
168
     # @throw EditorialModelException if an EmField with same uid allready in this EmClass (overwritting allowed from parents)
171
     # @throw EditorialModelException if an EmField with same uid allready in this EmClass (overwritting allowed from parents)
170
     def add_field(self, emfield):
173
     def add_field(self, emfield):
171
         assert_edit()
174
         assert_edit()
172
         if emfield.uid in self.__fields:
175
         if emfield.uid in self.__fields:
173
-            raise EditorialModelError("Duplicated uid '%s' for EmField in this class ( %s )" % (emfield.uid, self))
176
+            raise EditorialModelError(
177
+                "Duplicated uid '%s' for EmField in this class ( %s )" % (emfield.uid, self))
174
         # Incomplete field override check
178
         # Incomplete field override check
175
         if emfield.uid in self.__all_fields:
179
         if emfield.uid in self.__all_fields:
176
             parent_field = self.__all_fields[emfield.uid]
180
             parent_field = self.__all_fields[emfield.uid]
177
             if not emfield.data_handler_instance.can_override(parent_field.data_handler_instance):
181
             if not emfield.data_handler_instance.can_override(parent_field.data_handler_instance):
178
-                raise AttributeError("'%s' field override a parent field, but data_handles are not compatible" % emfield.uid)
182
+                raise AttributeError(
183
+                    "'%s' field override a parent field, but data_handles are not compatible" % emfield.uid)
179
         self.__fields[emfield.uid] = emfield
184
         self.__fields[emfield.uid] = emfield
180
         return emfield
185
         return emfield
181
-    
182
-    ##@brief Create a new EmField and add it to the EmClass
186
+
187
+    # @brief Create a new EmField and add it to the EmClass
183
     # @param data_handler str : A DataHandler name
188
     # @param data_handler str : A DataHandler name
184
     # @param uid str : the EmField uniq id
189
     # @param uid str : the EmField uniq id
185
-    # @param **field_kwargs :  EmField constructor parameters ( see @ref EmField.__init__() ) 
190
+    # @param **field_kwargs :  EmField constructor parameters ( see @ref EmField.__init__() )
186
     def new_field(self, uid, data_handler, **field_kwargs):
191
     def new_field(self, uid, data_handler, **field_kwargs):
187
         assert_edit()
192
         assert_edit()
188
         return self.add_field(EmField(uid, data_handler, self, **field_kwargs))
193
         return self.add_field(EmField(uid, data_handler, self, **field_kwargs))
189
 
194
 
190
     def d_hash(self):
195
     def d_hash(self):
191
         m = hashlib.md5()
196
         m = hashlib.md5()
192
-        payload = str(super().d_hash())  + ("1" if self.abstract else "0") 
197
+        payload = str(super().d_hash()) + ("1" if self.abstract else "0")
193
 
198
 
194
         for p in sorted(self.parents):
199
         for p in sorted(self.parents):
195
             payload += str(p.d_hash())
200
             payload += str(p.d_hash())
196
         for fuid in sorted(self.__fields.keys()):
201
         for fuid in sorted(self.__fields.keys()):
197
             payload += str(self.__fields[fuid].d_hash())
202
             payload += str(self.__fields[fuid].d_hash())
198
-            
203
+
199
         m.update(bytes(payload, 'utf-8'))
204
         m.update(bytes(payload, 'utf-8'))
200
         return int.from_bytes(m.digest(), byteorder='big')
205
         return int.from_bytes(m.digest(), byteorder='big')
201
 
206
 
202
     def __str__(self):
207
     def __str__(self):
203
         return "<class EmClass %s>" % self.uid
208
         return "<class EmClass %s>" % self.uid
204
-    
209
+
205
     def __repr__(self):
210
     def __repr__(self):
206
         if not self.abstract:
211
         if not self.abstract:
207
             abstract = ''
212
             abstract = ''
209
             abstract = 'PureAbstract'
214
             abstract = 'PureAbstract'
210
         else:
215
         else:
211
             abstract = 'Abstract'
216
             abstract = 'Abstract'
212
-        return "<class %s EmClass uid=%s>" % (abstract, repr(self.uid) )
217
+        return "<class %s EmClass uid=%s>" % (abstract, repr(self.uid))
213
 
218
 
214
 
219
 
215
-##@brief Handles editorial model classes fields
220
+# @brief Handles editorial model classes fields
216
 #@ingroup lodel2_em
221
 #@ingroup lodel2_em
217
 class EmField(EmComponent):
222
 class EmField(EmComponent):
218
 
223
 
219
-    ##@brief Instanciate a new EmField
224
+    # @brief Instanciate a new EmField
220
     # @param uid str : uniq identifier
225
     # @param uid str : uniq identifier
221
     # @param display_name MlString|str|dict : field display_name
226
     # @param display_name MlString|str|dict : field display_name
222
     # @param data_handler str : A DataHandler name
227
     # @param data_handler str : A DataHandler name
223
     # @param help_text MlString|str|dict : help text
228
     # @param help_text MlString|str|dict : help text
224
     # @param group EmGroup :
229
     # @param group EmGroup :
225
     # @param **handler_kwargs : data handler arguments
230
     # @param **handler_kwargs : data handler arguments
226
-    def __init__(self, uid, data_handler, em_class = None, display_name = None, help_text = None, group = None, **handler_kwargs):
231
+    def __init__(self, uid, data_handler, em_class=None, display_name=None, help_text=None, group=None, **handler_kwargs):
227
         from lodel.leapi.datahandlers.base_classes import DataHandler
232
         from lodel.leapi.datahandlers.base_classes import DataHandler
228
         super().__init__(uid, display_name, help_text, group)
233
         super().__init__(uid, display_name, help_text, group)
229
-        ##@brief The data handler name
234
+        # @brief The data handler name
230
         self.data_handler_name = data_handler
235
         self.data_handler_name = data_handler
231
-        ##@brief The data handler class
236
+        # @brief The data handler class
232
         self.data_handler_cls = DataHandler.from_name(data_handler)
237
         self.data_handler_cls = DataHandler.from_name(data_handler)
233
-        ##@brief The data handler instance associated with this EmField
238
+        # @brief The data handler instance associated with this EmField
234
         self.data_handler_instance = self.data_handler_cls(**handler_kwargs)
239
         self.data_handler_instance = self.data_handler_cls(**handler_kwargs)
235
-        ##@brief Stores data handler instanciation options
240
+        # @brief Stores data handler instanciation options
236
         self.data_handler_options = handler_kwargs
241
         self.data_handler_options = handler_kwargs
237
-        ##@brief Stores the emclass that contains this field (set by EmClass.add_field() method)
242
+        # @brief Stores the emclass that contains this field (set by EmClass.add_field() method)
238
         self._emclass = em_class
243
         self._emclass = em_class
239
         if self._emclass is None:
244
         if self._emclass is None:
240
-            warnings.warn("No EmClass for field %s" %uid)
245
+            warnings.warn("No EmClass for field %s" % uid)
241
         if group is None:
246
         if group is None:
242
             warnings.warn("No EmGroup for field  %s" % uid)
247
             warnings.warn("No EmGroup for field  %s" % uid)
243
         else:
248
         else:
244
             group.add_components([self])
249
             group.add_components([self])
245
 
250
 
246
-    ##@brief Returns data_handler_name attribute
251
+    # @brief Returns data_handler_name attribute
247
     def get_data_handler_name(self):
252
     def get_data_handler_name(self):
248
         return copy.copy(self.data_handler_name)
253
         return copy.copy(self.data_handler_name)
249
-        
250
-    ##@brief Returns data_handler_cls attribute
254
+
255
+    # @brief Returns data_handler_cls attribute
251
     def get_data_handler_cls(self):
256
     def get_data_handler_cls(self):
252
         return copy.copy(self.data_handler_cls)
257
         return copy.copy(self.data_handler_cls)
253
-    
258
+
254
     ##@brief Returne the uid of the emclass which contains this field
259
     ##@brief Returne the uid of the emclass which contains this field
255
     def get_emclass_uid(self):
260
     def get_emclass_uid(self):
256
         return self._emclass.uid
261
         return self._emclass.uid
257
-    
262
+
258
     # @warning Not complete !
263
     # @warning Not complete !
259
     # @todo Complete the hash when data handlers becomes available
264
     # @todo Complete the hash when data handlers becomes available
260
     def d_hash(self):
265
     def d_hash(self):
261
         return int.from_bytes(hashlib.md5(
266
         return int.from_bytes(hashlib.md5(
262
-                        bytes(
263
-                                "%s%s%s" % (  super().d_hash(),
264
-                                            self.data_handler_name,
265
-                                            self.data_handler_options), 
266
-                                'utf-8')
267
+            bytes(
268
+                "%s%s%s" % (super().d_hash(),
269
+                            self.data_handler_name,
270
+                            self.data_handler_options),
271
+                'utf-8')
267
         ).digest(), byteorder='big')
272
         ).digest(), byteorder='big')
268
 
273
 
269
-##@brief Handles functionnal group of EmComponents
274
+# @brief Handles functionnal group of EmComponents
270
 #@ingroup lodel2_em
275
 #@ingroup lodel2_em
276
+
277
+
271
 class EmGroup(MlNamedObject):
278
 class EmGroup(MlNamedObject):
272
-        
273
-    ##@brief Create a new EmGroup
279
+
280
+    # @brief Create a new EmGroup
274
     # @note you should NEVER call the constructor yourself. Use Model.add_group instead
281
     # @note you should NEVER call the constructor yourself. Use Model.add_group instead
275
     # @param uid str : Uniq identifier
282
     # @param uid str : Uniq identifier
276
     # @param depends list : A list of EmGroup dependencies
283
     # @param depends list : A list of EmGroup dependencies
277
-    # @param display_name MlString|str : 
278
-    # @param help_text MlString|str : 
279
-    def __init__(self, uid, depends = None, display_name = None, help_text = None):
284
+    # @param display_name MlString|str :
285
+    # @param help_text MlString|str :
286
+    def __init__(self, uid, depends=None, display_name=None, help_text=None):
280
         self.uid = uid
287
         self.uid = uid
281
-        ##@brief Stores the list of groups that depends on this EmGroup indexed by uid
288
+        # @brief Stores the list of groups that depends on this EmGroup indexed by uid
282
         self.required_by = dict()
289
         self.required_by = dict()
283
-        ##@brief Stores the list of dependencies (EmGroup) indexed by uid
290
+        # @brief Stores the list of dependencies (EmGroup) indexed by uid
284
         self.require = dict()
291
         self.require = dict()
285
-        ##@brief Stores the list of EmComponent instances contained in this group
292
+        # @brief Stores the list of EmComponent instances contained in this group
286
         self.__components = set()
293
         self.__components = set()
287
         super().__init__(display_name, help_text)
294
         super().__init__(display_name, help_text)
288
 
295
 
291
                 if not isinstance(grp, EmGroup):
298
                 if not isinstance(grp, EmGroup):
292
                     raise ValueError("EmGroup expected in depends argument but %s found" % grp)
299
                     raise ValueError("EmGroup expected in depends argument but %s found" % grp)
293
                 self.add_dependencie(grp)
300
                 self.add_dependencie(grp)
294
-    
295
-    ##@brief Returns EmGroup dependencie
301
+
302
+    # @brief Returns EmGroup dependencie
296
     # @param recursive bool : if True return all dependencies and their dependencies
303
     # @param recursive bool : if True return all dependencies and their dependencies
297
     # @return a dict of EmGroup identified by uid
304
     # @return a dict of EmGroup identified by uid
298
-    def dependencies(self, recursive = False):
305
+    def dependencies(self, recursive=False):
299
         res = copy.copy(self.require)
306
         res = copy.copy(self.require)
300
         if not recursive:
307
         if not recursive:
301
             return res
308
             return res
307
                     to_scan.append(new_dep)
314
                     to_scan.append(new_dep)
308
                     res[new_dep.uid] = new_dep
315
                     res[new_dep.uid] = new_dep
309
         return res
316
         return res
310
-    
311
-    ##@brief Returns EmGroup applicants
317
+
318
+    # @brief Returns EmGroup applicants
312
     # @param recursive bool : if True return all dependencies and their dependencies
319
     # @param recursive bool : if True return all dependencies and their dependencies
313
     # @returns a dict of EmGroup identified by uid
320
     # @returns a dict of EmGroup identified by uid
314
-    def applicants(self, recursive = False):
321
+    def applicants(self, recursive=False):
315
         res = copy.copy(self.required_by)
322
         res = copy.copy(self.required_by)
316
         if not recursive:
323
         if not recursive:
317
             return res
324
             return res
323
                     to_scan.append(new_app)
330
                     to_scan.append(new_app)
324
                     res[new_app.uid] = new_app
331
                     res[new_app.uid] = new_app
325
         return res
332
         return res
326
-    
327
-    ##@brief Returns EmGroup components
333
+
334
+    # @brief Returns EmGroup components
328
     # @returns a copy of the set of components
335
     # @returns a copy of the set of components
329
     def components(self):
336
     def components(self):
330
         return (self.__components).copy()
337
         return (self.__components).copy()
331
 
338
 
332
-    ##@brief Returns EmGroup display_name
339
+    # @brief Returns EmGroup display_name
333
     #  @param lang str | None : If None return default lang translation
340
     #  @param lang str | None : If None return default lang translation
334
     #  @returns None if display_name is None, a str for display_name else
341
     #  @returns None if display_name is None, a str for display_name else
335
     def get_display_name(self, lang=None):
342
     def get_display_name(self, lang=None):
336
-        name=self.display_name
337
-        if name is None : return None
338
-        return name.get(lang);
343
+        name = self.display_name
344
+        if name is None:
345
+            return None
346
+        return name.get(lang)
339
 
347
 
340
-    ##@brief Returns EmGroup help_text
348
+    # @brief Returns EmGroup help_text
341
     #  @param lang str | None : If None return default lang translation
349
     #  @param lang str | None : If None return default lang translation
342
     #  @returns None if display_name is None, a str for display_name else
350
     #  @returns None if display_name is None, a str for display_name else
343
     def get_help_text(self, lang=None):
351
     def get_help_text(self, lang=None):
344
-        help=self.help_text
345
-        if help is None : return None
346
-        return help.get(lang);
347
-    
348
-    ##@brief Add components in a group
352
+        help = self.help_text
353
+        if help is None:
354
+            return None
355
+        return help.get(lang)
356
+
357
+    # @brief Add components in a group
349
     # @param components list : EmComponent instances list
358
     # @param components list : EmComponent instances list
350
     def add_components(self, components):
359
     def add_components(self, components):
351
         assert_edit()
360
         assert_edit()
356
                     msg %= (component, self)
365
                     msg %= (component, self)
357
                     warnings.warn(msg)
366
                     warnings.warn(msg)
358
             elif not isinstance(component, EmClass):
367
             elif not isinstance(component, EmClass):
359
-                raise EditorialModelError("Expecting components to be a list of EmComponent, but %s found in the list" % type(component))
368
+                raise EditorialModelError(
369
+                    "Expecting components to be a list of EmComponent, but %s found in the list" % type(component))
360
         self.__components |= set(components)
370
         self.__components |= set(components)
361
 
371
 
362
-    ##@brief Add a dependencie
372
+    # @brief Add a dependencie
363
     # @param em_group EmGroup|iterable : an EmGroup instance or list of instance
373
     # @param em_group EmGroup|iterable : an EmGroup instance or list of instance
364
     def add_dependencie(self, grp):
374
     def add_dependencie(self, grp):
365
         assert_edit()
375
         assert_edit()
367
             for group in grp:
377
             for group in grp:
368
                 self.add_dependencie(group)
378
                 self.add_dependencie(group)
369
             return
379
             return
370
-        except TypeError: pass
371
-                
380
+        except TypeError:
381
+            pass
382
+
372
         if grp.uid in self.require:
383
         if grp.uid in self.require:
373
             return
384
             return
374
         if self.__circular_dependencie(grp):
385
         if self.__circular_dependencie(grp):
375
             raise EditorialModelError("Circular dependencie detected, cannot add dependencie")
386
             raise EditorialModelError("Circular dependencie detected, cannot add dependencie")
376
         self.require[grp.uid] = grp
387
         self.require[grp.uid] = grp
377
         grp.required_by[self.uid] = self
388
         grp.required_by[self.uid] = self
378
-        
379
-    ##@brief Add a applicant
389
+
390
+    # @brief Add a applicant
380
     # @param em_group EmGroup|iterable : an EmGroup instance or list of instance
391
     # @param em_group EmGroup|iterable : an EmGroup instance or list of instance
381
     # Useless ???
392
     # Useless ???
382
     def add_applicant(self, grp):
393
     def add_applicant(self, grp):
385
             for group in grp:
396
             for group in grp:
386
                 self.add_applicant(group)
397
                 self.add_applicant(group)
387
             return
398
             return
388
-        except TypeError: pass
389
-                
399
+        except TypeError:
400
+            pass
401
+
390
         if grp.uid in self.required_by:
402
         if grp.uid in self.required_by:
391
             return
403
             return
392
         if self.__circular_applicant(grp):
404
         if self.__circular_applicant(grp):
393
             raise EditorialModelError("Circular applicant detected, cannot add applicant")
405
             raise EditorialModelError("Circular applicant detected, cannot add applicant")
394
         self.required_by[grp.uid] = grp
406
         self.required_by[grp.uid] = grp
395
         grp.require[self.uid] = self
407
         grp.require[self.uid] = self
396
-    
397
-    ##@brief Search for circular dependencie
408
+
409
+    # @brief Search for circular dependencie
398
     # @return True if circular dep found else False
410
     # @return True if circular dep found else False
399
     def __circular_dependencie(self, new_dep):
411
     def __circular_dependencie(self, new_dep):
400
         return self.uid in new_dep.dependencies(True)
412
         return self.uid in new_dep.dependencies(True)
401
-    
402
-    ##@brief Search for circular applicant
413
+
414
+    # @brief Search for circular applicant
403
     # @return True if circular app found else False
415
     # @return True if circular app found else False
404
     def __circular_applicant(self, new_app):
416
     def __circular_applicant(self, new_app):
405
         return self.uid in new_app.applicants(True)
417
         return self.uid in new_app.applicants(True)
406
 
418
 
407
-    ##@brief Fancy string representation of an EmGroup
419
+    # @brief Fancy string representation of an EmGroup
408
     # @return a string
420
     # @return a string
409
     def __str__(self):
421
     def __str__(self):
410
         if self.display_name is None:
422
         if self.display_name is None:
413
             return self.display_name.get()
425
             return self.display_name.get()
414
 
426
 
415
     def d_hash(self):
427
     def d_hash(self):
416
-        
428
+
417
         payload = "%s%s%s" % (
429
         payload = "%s%s%s" % (
418
-                                self.uid,
419
-                                'NODNAME' if self.display_name is None else self.display_name.d_hash(),
420
-                                'NOHELP' if self.help_text is None else self.help_text.d_hash()
430
+            self.uid,
431
+            'NODNAME' if self.display_name is None else self.display_name.d_hash(),
432
+            'NOHELP' if self.help_text is None else self.help_text.d_hash()
421
         )
433
         )
422
         for recurs in (False, True):
434
         for recurs in (False, True):
423
             deps = self.dependencies(recurs)
435
             deps = self.dependencies(recurs)
426
         for req_by_uid in self.required_by:
438
         for req_by_uid in self.required_by:
427
             payload += req_by_uid
439
             payload += req_by_uid
428
         return int.from_bytes(
440
         return int.from_bytes(
429
-                                bytes(payload, 'utf-8'),
430
-                                byteorder = 'big'
441
+            bytes(payload, 'utf-8'),
442
+            byteorder='big'
431
         )
443
         )
432
-    
433
-    ##@brief Complete string representation of an EmGroup
444
+
445
+    # @brief Complete string representation of an EmGroup
434
     # @return a string
446
     # @return a string
435
     def __repr__(self):
447
     def __repr__(self):
436
-        return "<class EmGroup '%s' depends : [%s]>" % (self.uid, ', '.join([duid for duid in self.dependencies(False)]) )
448
+        return "<class EmGroup '%s' depends : [%s]>" % (self.uid, ', '.join([duid for duid in self.dependencies(False)]))

+ 63
- 65
lodel/editorial_model/model.py View File

15
     'lodel.editorial_model.components': ['EmClass', 'EmField', 'EmGroup']})
15
     'lodel.editorial_model.components': ['EmClass', 'EmField', 'EmGroup']})
16
 
16
 
17
 
17
 
18
-##@brief Describe an editorial model
18
+# @brief Describe an editorial model
19
 #@ingroup lodel2_em
19
 #@ingroup lodel2_em
20
 class EditorialModel(MlNamedObject):
20
 class EditorialModel(MlNamedObject):
21
-    
22
-    ##@brief Create a new editorial model
21
+
22
+    # @brief Create a new editorial model
23
     # @param name MlString|str|dict : the editorial model name
23
     # @param name MlString|str|dict : the editorial model name
24
     # @param description MlString|str|dict : the editorial model description
24
     # @param description MlString|str|dict : the editorial model description
25
-    def __init__(self, name, description = None, display_name = None, help_text = None):
25
+    def __init__(self, name, description=None, display_name=None, help_text=None):
26
         self.name = MlString(name)
26
         self.name = MlString(name)
27
         self.description = MlString(description)
27
         self.description = MlString(description)
28
-        ##@brief Stores all groups indexed by id
28
+        # @brief Stores all groups indexed by id
29
         self.__groups = dict()
29
         self.__groups = dict()
30
-        ##@brief Stores all classes indexed by id
30
+        # @brief Stores all classes indexed by id
31
         self.__classes = dict()
31
         self.__classes = dict()
32
-        ## @brief Stores all activated groups indexed by id
32
+        #  @brief Stores all activated groups indexed by id
33
         self.__active_groups = dict()
33
         self.__active_groups = dict()
34
-        ## @brief Stores all activated classes indexed by id
34
+        #  @brief Stores all activated classes indexed by id
35
         self.__active_classes = dict()
35
         self.__active_classes = dict()
36
         self.__set_actives()
36
         self.__set_actives()
37
         if display_name is None:
37
         if display_name is None:
39
         if help_text is None:
39
         if help_text is None:
40
             help_text = description
40
             help_text = description
41
         super().__init__(display_name, help_text)
41
         super().__init__(display_name, help_text)
42
-    
43
-    ##@brief EmClass uids accessor
42
+
43
+    # @brief EmClass uids accessor
44
     #@return a dict of emclasses
44
     #@return a dict of emclasses
45
-    def all_classes(self, uid = None):
45
+    def all_classes(self, uid=None):
46
         if uid is None:
46
         if uid is None:
47
             return copy.copy(self.__classes)
47
             return copy.copy(self.__classes)
48
         else:
48
         else:
50
                 return copy.copy(self.__classes[uid])
50
                 return copy.copy(self.__classes[uid])
51
             except KeyError:
51
             except KeyError:
52
                 raise EditorialModelException("EmClass not found : '%s'" % uid)
52
                 raise EditorialModelException("EmClass not found : '%s'" % uid)
53
-                
54
-    def all_classes_ref(self, uid = None):
53
+
54
+    def all_classes_ref(self, uid=None):
55
         if uid is None:
55
         if uid is None:
56
             return self.__classes
56
             return self.__classes
57
         else:
57
         else:
59
                 return self.__classes[uid]
59
                 return self.__classes[uid]
60
             except KeyError:
60
             except KeyError:
61
                 raise EditorialModelException("EmGroup not found : '%s'" % uid)
61
                 raise EditorialModelException("EmGroup not found : '%s'" % uid)
62
-                                
63
-    ##@brief active EmClass uids accessor
62
+
63
+    # @brief active EmClass uids accessor
64
     #@return a list of class uids
64
     #@return a list of class uids
65
     def active_classes_uids(self):
65
     def active_classes_uids(self):
66
-            return list(self.__active_classes.keys())
67
-        
68
-    
69
-    ##@brief EmGroups accessor
66
+        return list(self.__active_classes.keys())
67
+
68
+    # @brief EmGroups accessor
70
     #@return a dict of groups
69
     #@return a dict of groups
71
-    def all_groups(self, uid = None):
70
+    def all_groups(self, uid=None):
72
         if uid is None:
71
         if uid is None:
73
             return copy.copy(self.__groups)
72
             return copy.copy(self.__groups)
74
         else:
73
         else:
76
                 return copy.copy(self.__groups[uid])
75
                 return copy.copy(self.__groups[uid])
77
             except KeyError:
76
             except KeyError:
78
                 raise EditorialModelException("EmGroup not found : '%s'" % uid)
77
                 raise EditorialModelException("EmGroup not found : '%s'" % uid)
79
-    
80
-    ##@brief EmGroups accessor
78
+
79
+    # @brief EmGroups accessor
81
     #@return a dict of groups
80
     #@return a dict of groups
82
-    def all_groups_ref(self, uid = None):
81
+    def all_groups_ref(self, uid=None):
83
         if uid is None:
82
         if uid is None:
84
             return self.__groups
83
             return self.__groups
85
         else:
84
         else:
87
                 return self.__groups[uid]
86
                 return self.__groups[uid]
88
             except KeyError:
87
             except KeyError:
89
                 raise EditorialModelException("EmGroup not found : '%s'" % uid)
88
                 raise EditorialModelException("EmGroup not found : '%s'" % uid)
90
-                
91
-    ##@brief active EmClass uids accessor
89
+
90
+    # @brief active EmClass uids accessor
92
     #@return a list of class uids
91
     #@return a list of class uids
93
     def active_groups_uids(self):
92
     def active_groups_uids(self):
94
-            return list(self.__active_groups.keys())
93
+        return list(self.__active_groups.keys())
95
 
94
 
96
-    ##@brief EmClass accessor
95
+    # @brief EmClass accessor
97
     #@param uid None | str : give this argument to get a specific EmClass
96
     #@param uid None | str : give this argument to get a specific EmClass
98
     #@return if uid is given returns an EmClass else returns an EmClass
97
     #@return if uid is given returns an EmClass else returns an EmClass
99
     # iterator
98
     # iterator
100
     #@todo use Settings.editorialmodel.groups to determine wich classes should
99
     #@todo use Settings.editorialmodel.groups to determine wich classes should
101
     # be returned
100
     # be returned
102
-    def classes(self, uid = None):
101
+    def classes(self, uid=None):
103
         try:
102
         try:
104
-            return self.__elt_getter(   self.__active_classes,
105
-                                        uid)
103
+            return self.__elt_getter(self.__active_classes,
104
+                                     uid)
106
         except KeyError:
105
         except KeyError:
107
             raise EditorialModelException("EmClass not found : '%s'" % uid)
106
             raise EditorialModelException("EmClass not found : '%s'" % uid)
108
-    
109
-    ##@brief EmClass child list accessor
107
+
108
+    # @brief EmClass child list accessor
110
     #@param uid str : the EmClass uid
109
     #@param uid str : the EmClass uid
111
     #@return a set of EmClass
110
     #@return a set of EmClass
112
     def get_class_childs(self, uid):
111
     def get_class_childs(self, uid):
117
                 res.append(cls)
116
                 res.append(cls)
118
         return set(res)
117
         return set(res)
119
 
118
 
120
-
121
-    ##@brief EmGroup getter
119
+    # @brief EmGroup getter
122
     # @param uid None | str : give this argument to get a specific EmGroup
120
     # @param uid None | str : give this argument to get a specific EmGroup
123
     # @return if uid is given returns an EmGroup else returns an EmGroup iterator
121
     # @return if uid is given returns an EmGroup else returns an EmGroup iterator
124
-    def groups(self, uid = None):
122
+    def groups(self, uid=None):
125
         try:
123
         try:
126
-            return self.__elt_getter(   self.__active_groups,
127
-                                        uid)
124
+            return self.__elt_getter(self.__active_groups,
125
+                                     uid)
128
         except KeyError:
126
         except KeyError:
129
             raise EditorialModelException("EmGroup not found : '%s'" % uid)
127
             raise EditorialModelException("EmGroup not found : '%s'" % uid)
130
-    
131
-    ##@brief Private getter for __groups or __classes
128
+
129
+    # @brief Private getter for __groups or __classes
132
     # @see classes() groups()
130
     # @see classes() groups()
133
     def __elt_getter(self, elts, uid):
131
     def __elt_getter(self, elts, uid):
134
         return list(elts.values()) if uid is None else elts[uid]
132
         return list(elts.values()) if uid is None else elts[uid]
135
-    
136
-    ##@brief Update the EditorialModel.__active_groups and
137
-    #EditorialModel.__active_classes attibutes
133
+
134
+    # @brief Update the EditorialModel.__active_groups and
135
+    # EditorialModel.__active_classes attibutes
138
     def __set_actives(self):
136
     def __set_actives(self):
139
         if Settings.editorialmodel.editormode:
137
         if Settings.editorialmodel.editormode:
140
             logger.warning("All EM groups active because editormode in ON")
138
             logger.warning("All EM groups active because editormode in ON")
142
             self.__active_groups = self.__groups
140
             self.__active_groups = self.__groups
143
             self.__active_classes = self.__classes
141
             self.__active_classes = self.__classes
144
         else:
142
         else:
145
-            #determine groups first
143
+            # determine groups first
146
             self.__active_groups = dict()
144
             self.__active_groups = dict()
147
             self.__active_classes = dict()
145
             self.__active_classes = dict()
148
             for agrp in Settings.editorialmodel.groups:
146
             for agrp in Settings.editorialmodel.groups:
159
                 raise RuntimeError("No active class found. Abording")
157
                 raise RuntimeError("No active class found. Abording")
160
             for clsname, acls in self.__active_classes.items():
158
             for clsname, acls in self.__active_classes.items():
161
                 acls._set_active_fields(self.__active_groups)
159
                 acls._set_active_fields(self.__active_groups)
162
-    
163
-    ##@brief EmField getter
160
+
161
+    # @brief EmField getter
164
     # @param uid str : An EmField uid represented by "CLASSUID.FIELDUID"
162
     # @param uid str : An EmField uid represented by "CLASSUID.FIELDUID"
165
     # @return Fals or an EmField instance
163
     # @return Fals or an EmField instance
166
     #
164
     #
167
     # @todo delete it, useless...
165
     # @todo delete it, useless...
168
-    def field(self, uid = None):
166
+    def field(self, uid=None):
169
         spl = uid.split('.')
167
         spl = uid.split('.')
170
         if len(spl) != 2:
168
         if len(spl) != 2:
171
             raise ValueError("Malformed EmField identifier : '%s'" % uid)
169
             raise ValueError("Malformed EmField identifier : '%s'" % uid)
181
             pass
179
             pass
182
         return False
180
         return False
183
 
181
 
184
-    ##@brief Add a class to the editorial model
182
+    # @brief Add a class to the editorial model
185
     # @param emclass EmClass : the EmClass instance to add
183
     # @param emclass EmClass : the EmClass instance to add
186
     # @return emclass
184
     # @return emclass
187
     def add_class(self, emclass):
185
     def add_class(self, emclass):
193
         self.__classes[emclass.uid] = emclass
191
         self.__classes[emclass.uid] = emclass
194
         return emclass
192
         return emclass
195
 
193
 
196
-    ##@brief Add a group to the editorial model
194
+    # @brief Add a group to the editorial model
197
     # @param emgroup EmGroup : the EmGroup instance to add
195
     # @param emgroup EmGroup : the EmGroup instance to add
198
     # @return emgroup
196
     # @return emgroup
199
     def add_group(self, emgroup):
197
     def add_group(self, emgroup):
205
         self.__groups[emgroup.uid] = emgroup
203
         self.__groups[emgroup.uid] = emgroup
206
         return emgroup
204
         return emgroup
207
 
205
 
208
-    ##@brief Add a new EmClass to the editorial model
206
+    # @brief Add a new EmClass to the editorial model
209
     #@param uid str : EmClass uid
207
     #@param uid str : EmClass uid
210
-    #@param **kwargs : EmClass constructor options ( 
208
+    #@param **kwargs : EmClass constructor options (
211
     # see @ref lodel.editorial_model.component.EmClass.__init__() )
209
     # see @ref lodel.editorial_model.component.EmClass.__init__() )
212
     def new_class(self, uid, **kwargs):
210
     def new_class(self, uid, **kwargs):
213
         assert_edit()
211
         assert_edit()
214
         return self.add_class(EmClass(uid, **kwargs))
212
         return self.add_class(EmClass(uid, **kwargs))
215
-    
216
-    ##@brief Add a new EmGroup to the editorial model
213
+
214
+    # @brief Add a new EmGroup to the editorial model
217
     #@param uid str : EmGroup uid
215
     #@param uid str : EmGroup uid
218
     #@param *kwargs : EmGroup constructor keywords arguments (
216
     #@param *kwargs : EmGroup constructor keywords arguments (
219
     # see @ref lodel.editorial_model.component.EmGroup.__init__() )
217
     # see @ref lodel.editorial_model.component.EmGroup.__init__() )
221
         assert_edit()
219
         assert_edit()
222
         return self.add_group(EmGroup(uid, **kwargs))
220
         return self.add_group(EmGroup(uid, **kwargs))
223
 
221
 
224
-    ##@brief Save a model
222
+    # @brief Save a model
225
     # @param translator module : The translator module to use
223
     # @param translator module : The translator module to use
226
     # @param **translator_args
224
     # @param **translator_args
227
     def save(self, translator, **translator_kwargs):
225
     def save(self, translator, **translator_kwargs):
229
         if isinstance(translator, str):
227
         if isinstance(translator, str):
230
             translator = self.translator_from_name(translator)
228
             translator = self.translator_from_name(translator)
231
         return translator.save(self, **translator_kwargs)
229
         return translator.save(self, **translator_kwargs)
232
-    
233
-    ##@brief Raise an error if lodel is not in EM edition mode
230
+
231
+    # @brief Raise an error if lodel is not in EM edition mode
234
     @staticmethod
232
     @staticmethod
235
     def raise_if_ro():
233
     def raise_if_ro():
236
         if not Settings.editorialmodel.editormode:
234
         if not Settings.editorialmodel.editormode:
237
-            raise EditorialModelError("Lodel in not in EM editor mode. The EM is in read only state")
235
+            raise EditorialModelError(
236
+                "Lodel in not in EM editor mode. The EM is in read only state")
238
 
237
 
239
-    ##@brief Load a model
238
+    # @brief Load a model
240
     # @param translator module : The translator module to use
239
     # @param translator module : The translator module to use
241
     # @param **translator_args
240
     # @param **translator_args
242
     @classmethod
241
     @classmethod
247
         res.__set_actives()
246
         res.__set_actives()
248
         return res
247
         return res
249
 
248
 
250
-    ##@brief Return a translator module given a translator name
249
+    # @brief Return a translator module given a translator name
251
     # @param translator_name str : The translator name
250
     # @param translator_name str : The translator name
252
     # @return the translator python module
251
     # @return the translator python module
253
     # @throw NameError if the translator does not exists
252
     # @throw NameError if the translator does not exists
259
         except ImportError:
258
         except ImportError:
260
             raise NameError("No translator named %s")
259
             raise NameError("No translator named %s")
261
         return mod
260
         return mod
262
-        
263
-    ##@brief Lodel hash
261
+
262
+    # @brief Lodel hash
264
     def d_hash(self):
263
     def d_hash(self):
265
         payload = "%s%s" % (
264
         payload = "%s%s" % (
266
-                            self.name,
267
-                            'NODESC' if self.description is None else self.description.d_hash()
265
+            self.name,
266
+            'NODESC' if self.description is None else self.description.d_hash()
268
         )
267
         )
269
         for guid in sorted(self.__groups):
268
         for guid in sorted(self.__groups):
270
             payload += str(self.__groups[guid].d_hash())
269
             payload += str(self.__groups[guid].d_hash())
273
             payload += str(self.__classes[cuid].d_hash())
272
             payload += str(self.__classes[cuid].d_hash())
274
 
273
 
275
         return int.from_bytes(
274
         return int.from_bytes(
276
-                                hashlib.md5(bytes(payload, 'utf-8')).digest(),
277
-                                byteorder='big'
275
+            hashlib.md5(bytes(payload, 'utf-8')).digest(),
276
+            byteorder='big'
278
         )
277
         )
279
-

+ 4
- 2
lodel/mlnamedobject/mlnamedobject.py View File

4
 LodelContext.expose_modules(globals(), {
4
 LodelContext.expose_modules(globals(), {
5
     'lodel.utils.mlstring': ['MlString']})
5
     'lodel.utils.mlstring': ['MlString']})
6
 
6
 
7
-## @package lodel.mlnamedobject Lodel2 description of objects module
7
+# @package lodel.mlnamedobject Lodel2 description of objects module
8
 #
8
 #
9
 # Display name and Description of a lodel2 object
9
 # Display name and Description of a lodel2 object
10
 
10
 
11
-##@brief Class allows dislpay name and help text for lodel2 objects and fields
11
+# @brief Class allows display name and help text for lodel2 objects and fields
12
+
13
+
12
 class MlNamedObject(object):
14
 class MlNamedObject(object):
13
 
15
 
14
     def __init__(self, display_name=None, help_text=None):
16
     def __init__(self, display_name=None, help_text=None):

+ 79
- 67
lodel/settings/settings.py View File

5
 import configparser
5
 import configparser
6
 import copy
6
 import copy
7
 import warnings
7
 import warnings
8
-import types # for dynamic bindings
8
+import types  # for dynamic bindings
9
 from collections import namedtuple
9
 from collections import namedtuple
10
 
10
 
11
 from lodel.context import LodelContext
11
 from lodel.context import LodelContext
12
 
12
 
13
-LodelContext.expose_modules(globals(),{
13
+LodelContext.expose_modules(globals(), {
14
     'lodel.logger': 'logger',
14
     'lodel.logger': 'logger',
15
     'lodel.settings.utils': ['SettingsError', 'SettingsErrors'],
15
     'lodel.settings.utils': ['SettingsError', 'SettingsErrors'],
16
     'lodel.validator.validator': ['Validator', 'LODEL2_CONF_SPECS',
16
     'lodel.validator.validator': ['Validator', 'LODEL2_CONF_SPECS',
17
-        'confspec_append'],
18
-    'lodel.settings.settings_loader':['SettingsLoader']})
19
-    
17
+                                  'confspec_append'],
18
+    'lodel.settings.settings_loader': ['SettingsLoader']})
20
 
19
 
21
-## @package lodel.settings.settings Lodel2 settings module
20
+
21
+#  @package lodel.settings.settings Lodel2 settings module
22
 #
22
 #
23
 # Contains the class that handles the namedtuple tree of settings
23
 # Contains the class that handles the namedtuple tree of settings
24
 
24
 
25
-##@brief A default python system lib path
25
+# @brief A default python system lib path
26
 PYTHON_SYS_LIB_PATH = '/usr/local/lib/python{major}.{minor}/'.format(
26
 PYTHON_SYS_LIB_PATH = '/usr/local/lib/python{major}.{minor}/'.format(
27
 
27
 
28
-                                                major = sys.version_info.major,
29
-                                                minor = sys.version_info.minor)
28
+    major=sys.version_info.major,
29
+    minor=sys.version_info.minor)
30
+
30
 
31
 
31
 class MetaSettings(type):
32
 class MetaSettings(type):
33
+
32
     @property
34
     @property
33
     def s(self):
35
     def s(self):
34
         self.singleton_assert(True)
36
         self.singleton_assert(True)
35
         return self.instance.settings
37
         return self.instance.settings
36
 
38
 
37
-##@brief Handles configuration load etc.
39
+# @brief Handles configuration load etc.
38
 #
40
 #
39
-# To see howto bootstrap Settings and use it in lodel instance see 
41
+# To see howto bootstrap Settings and use it in lodel instance see
40
 # @ref lodel.settings
42
 # @ref lodel.settings
41
-# 
43
+#
42
 # @par Basic instance usage
44
 # @par Basic instance usage
43
 # For example if a file defines confs like :
45
 # For example if a file defines confs like :
44
 # <pre>
46
 # <pre>
50
 #
52
 #
51
 # @par Init sequence
53
 # @par Init sequence
52
 # The initialization sequence is a bit tricky. In fact, plugins adds allowed
54
 # The initialization sequence is a bit tricky. In fact, plugins adds allowed
53
-# configuration sections/values, but the list of plugins to load are in... the 
55
+# configuration sections/values, but the list of plugins to load are in... the
54
 # settings.
56
 # settings.
55
 # Here is the conceptual presentation of Settings class initialization stages :
57
 # Here is the conceptual presentation of Settings class initialization stages :
56
 #   -# Preloading (sets values like lodel2 library path or the plugins path)
58
 #   -# Preloading (sets values like lodel2 library path or the plugins path)
57
-#   -# Ask a @ref lodel.settings.setting_loader.SettingsLoader to load all 
58
-#configurations files
59
+#   -# Ask a @ref lodel.settings.setting_loader.SettingsLoader to load all
60
+# configurations files
59
 #   -# Fetch the list of plugins in the loaded settings
61
 #   -# Fetch the list of plugins in the loaded settings
60
-#   -# Merge plugins settings specification with the global lodel settings 
61
-#specs ( see @ref lodel.plugin )
62
+#   -# Merge plugins settings specification with the global lodel settings
63
+# specs ( see @ref lodel.plugin )
62
 #   -# Fetch all settings from the merged settings specs
64
 #   -# Fetch all settings from the merged settings specs
63
 #
65
 #
64
 # @par Init sequence in practical
66
 # @par Init sequence in practical
68
 #   -# @ref Settings.__populate_from_specs() (step 5)
70
 #   -# @ref Settings.__populate_from_specs() (step 5)
69
 #   -# And finally @ref Settings.__confs_to_namedtuple()
71
 #   -# And finally @ref Settings.__confs_to_namedtuple()
70
 #
72
 #
71
-# @todo handles default sections for variable sections (sections ending with 
73
+# @todo handles default sections for variable sections (sections ending with
72
 # '.*')
74
 # '.*')
73
 # @todo delete the first stage, the lib path HAVE TO BE HARDCODED. In fact
75
 # @todo delete the first stage, the lib path HAVE TO BE HARDCODED. In fact
74
-#when we will run lodel in production the lodel2 lib will be in the python path
76
+# when we will run lodel in production the lodel2 lib will be in the python path
75
 #@todo add log messages (now we can)
77
 #@todo add log messages (now we can)
78
+
79
+
76
 class Settings(object, metaclass=MetaSettings):
80
 class Settings(object, metaclass=MetaSettings):
77
 
81
 
78
-    ## @brief Stores the singleton instance
82
+    #  @brief Stores the singleton instance
79
     instance = None
83
     instance = None
80
-    
81
-    ## @brief Instanciate the Settings singleton
84
+
85
+    #  @brief Instanciate the Settings singleton
82
     # @param conf_dir str : The configuration directory
86
     # @param conf_dir str : The configuration directory
83
     #@param custom_confspecs None | dict : if given overwrite default lodel2
87
     #@param custom_confspecs None | dict : if given overwrite default lodel2
84
-    #confspecs
85
-    def __init__(self, conf_dir, custom_confspecs = None):
86
-        self.singleton_assert() # check that it is the only instance
88
+    # confspecs
89
+    def __init__(self, conf_dir, custom_confspecs=None):
90
+        self.singleton_assert()  # check that it is the only instance
87
         Settings.instance = self
91
         Settings.instance = self
88
-        ## @brief Configuration specification
92
+        #  @brief Configuration specification
89
         #
93
         #
90
         # Initialized by Settings.__bootstrap() method
94
         # Initialized by Settings.__bootstrap() method
91
         self.__conf_specs = custom_confspecs
95
         self.__conf_specs = custom_confspecs
92
-        ## @brief Stores the configurations in namedtuple tree
96
+        #  @brief Stores the configurations in namedtuple tree
93
         self.__confs = None
97
         self.__confs = None
94
         self.__conf_dir = conf_dir
98
         self.__conf_dir = conf_dir
95
         self.__started = False
99
         self.__started = False
96
         self.__bootstrap()
100
         self.__bootstrap()
97
-    
98
-    ## @brief Get the named tuple representing configuration
101
+
102
+    #  @brief Get the named tuple representing configuration
99
     @property
103
     @property
100
     def settings(self):
104
     def settings(self):
101
         return self.__confs.lodel2
105
         return self.__confs.lodel2
102
-    
103
-    ## @brief Delete the singleton instance
106
+
107
+    #  @brief Delete the singleton instance
104
     @classmethod
108
     @classmethod
105
     def stop(cls):
109
     def stop(cls):
106
         del(cls.instance)
110
         del(cls.instance)
110
     def started(cls):
114
     def started(cls):
111
         return cls.instance is not None and cls.instance.__started
115
         return cls.instance is not None and cls.instance.__started
112
 
116
 
113
-    ##@brief An utility method that raises if the singleton is not in a good
117
+    # @brief An utility method that raises if the singleton is not in a good
114
     # state
118
     # state
115
     #@param expect_instanciated bool : if True we expect that the class is
119
     #@param expect_instanciated bool : if True we expect that the class is
116
     # allready instanciated, else not
120
     # allready instanciated, else not
124
             if cls.started():
128
             if cls.started():
125
                 raise RuntimeError("The Settings class is already started")
129
                 raise RuntimeError("The Settings class is already started")
126
 
130
 
127
-    ##@brief Saves a new configuration for section confname
131
+    # @brief Saves a new configuration for section confname
128
     #@param confname is the name of the modified section
132
     #@param confname is the name of the modified section
129
     #@param confvalue is a dict with variables to save
133
     #@param confvalue is a dict with variables to save
130
     #@param validator is a dict with adapted validator
134
     #@param validator is a dict with adapted validator
131
     @classmethod
135
     @classmethod
132
-    def set(cls, confname, confvalue,validator):
136
+    def set(cls, confname, confvalue, validator):
133
         loader = SettingsLoader(cls.instance.__conf_dir)
137
         loader = SettingsLoader(cls.instance.__conf_dir)
134
-        confkey=confname.rpartition('.')
138
+        confkey = confname.rpartition('.')
135
         loader.setoption(confkey[0], confkey[2], confvalue, validator)
139
         loader.setoption(confkey[0], confkey[2], confvalue, validator)
136
 
140
 
137
-    ##@brief This method handles Settings instance bootstraping
141
+    # @brief This method handles Settings instance bootstraping
138
     def __bootstrap(self):
142
     def __bootstrap(self):
139
         LodelContext.expose_modules(globals(), {
143
         LodelContext.expose_modules(globals(), {
140
             'lodel.plugin.plugins': ['Plugin', 'PluginError']})
144
             'lodel.plugin.plugins': ['Plugin', 'PluginError']})
144
         else:
148
         else:
145
             lodel2_specs = self.__conf_specs
149
             lodel2_specs = self.__conf_specs
146
             self.__conf_specs = None
150
             self.__conf_specs = None
147
-        loader = SettingsLoader(self.__conf_dir) 
151
+        loader = SettingsLoader(self.__conf_dir)
148
         plugin_list = []
152
         plugin_list = []
149
-        for ptype_name,ptype in Plugin.plugin_types().items():
153
+        for ptype_name, ptype in Plugin.plugin_types().items():
150
             pls = ptype.plist_confspecs()
154
             pls = ptype.plist_confspecs()
151
             lodel2_specs = confspec_append(lodel2_specs, **pls)
155
             lodel2_specs = confspec_append(lodel2_specs, **pls)
152
             cur_list = loader.getoption(
156
             cur_list = loader.getoption(
162
                 plugin_list += cur_list
166
                 plugin_list += cur_list
163
             except TypeError:
167
             except TypeError:
164
                 plugin_list += [cur_list]
168
                 plugin_list += [cur_list]
165
-        #Checking confspecs
169
+        # Checking confspecs
166
         for section in lodel2_specs:
170
         for section in lodel2_specs:
167
             if section.lower() != section:
171
             if section.lower() != section:
168
-                raise SettingsError("Only lower case are allowed in section name (thank's ConfigParser...)")
172
+                raise SettingsError(
173
+                    "Only lower case are allowed in section name (thank's ConfigParser...)")
169
             for kname in lodel2_specs[section]:
174
             for kname in lodel2_specs[section]:
170
                 if kname.lower() != kname:
175
                 if kname.lower() != kname:
171
-                    raise SettingsError("Only lower case are allowed in section name (thank's ConfigParser...)")
176
+                    raise SettingsError(
177
+                        "Only lower case are allowed in section name (thank's ConfigParser...)")
172
 
178
 
173
         # Starting the Plugins class
179
         # Starting the Plugins class
174
         logger.debug("Starting lodel.plugin.Plugin class")
180
         logger.debug("Starting lodel.plugin.Plugin class")
181
                 specs.append(Plugin.get(plugin_name).confspecs)
187
                 specs.append(Plugin.get(plugin_name).confspecs)
182
             except PluginError as e:
188
             except PluginError as e:
183
                 errors.append(SettingsError(msg=str(e)))
189
                 errors.append(SettingsError(msg=str(e)))
184
-        if len(errors) > 0: #Raise all plugins import errors
190
+        if len(errors) > 0:  # Raise all plugins import errors
185
             raise SettingsErrors(errors)
191
             raise SettingsErrors(errors)
186
         self.__conf_specs = self.__merge_specs(specs)
192
         self.__conf_specs = self.__merge_specs(specs)
187
         self.__populate_from_specs(self.__conf_specs, loader)
193
         self.__populate_from_specs(self.__conf_specs, loader)
188
         self.__started = True
194
         self.__started = True
189
-    
190
-    ##@brief Produce a configuration specification dict by merging all specifications
195
+
196
+    # @brief Produce a configuration specification dict by merging all specifications
191
     #
197
     #
192
     # Merges global lodel2 conf spec from @ref lodel.settings.validator.LODEL2_CONF_SPECS
198
     # Merges global lodel2 conf spec from @ref lodel.settings.validator.LODEL2_CONF_SPECS
193
     # and configuration specifications from loaded plugins
199
     # and configuration specifications from loaded plugins
198
         for spec in specs:
204
         for spec in specs:
199
             for section in spec:
205
             for section in spec:
200
                 if section.lower() != section:
206
                 if section.lower() != section:
201
-                    raise SettingsError("Only lower case are allowed in section name (thank's ConfigParser...)")
207
+                    raise SettingsError(
208
+                        "Only lower case are allowed in section name (thank's ConfigParser...)")
202
                 if section not in res:
209
                 if section not in res:
203
                     res[section] = dict()
210
                     res[section] = dict()
204
                 for kname in spec[section]:
211
                 for kname in spec[section]:
205
                     if kname.lower() != kname:
212
                     if kname.lower() != kname:
206
-                        raise SettingsError("Only lower case are allowed in section name (thank's ConfigParser...)")
213
+                        raise SettingsError(
214
+                            "Only lower case are allowed in section name (thank's ConfigParser...)")
207
                     if kname in res[section]:
215
                     if kname in res[section]:
208
-                        raise SettingsError("Duplicated key '%s' in section '%s'" % (kname, section))
216
+                        raise SettingsError("Duplicated key '%s' in section '%s'" %
217
+                                            (kname, section))
209
                     res[section.lower()][kname] = copy.copy(spec[section][kname])
218
                     res[section.lower()][kname] = copy.copy(spec[section][kname])
210
         return res
219
         return res
211
-    
212
-    ##@brief Populate the Settings instance with options values fetched with the loader from merged specs
220
+
221
+    # @brief Populate the Settings instance with options values fetched with the loader from merged specs
213
     #
222
     #
214
     # Populate the __confs attribute
223
     # Populate the __confs attribute
215
     # @param specs dict : Settings specification dictionnary as returned by __merge_specs
224
     # @param specs dict : Settings specification dictionnary as returned by __merge_specs
216
     # @param loader SettingsLoader : A SettingsLoader instance
225
     # @param loader SettingsLoader : A SettingsLoader instance
217
     def __populate_from_specs(self, specs, loader):
226
     def __populate_from_specs(self, specs, loader):
218
         self.__confs = dict()
227
         self.__confs = dict()
219
-        specs = copy.copy(specs) #Avoid destroying original specs dict (may be useless)
228
+        specs = copy.copy(specs)  # Avoid destroying original specs dict (may be useless)
220
         # Construct final specs dict replacing variable sections
229
         # Construct final specs dict replacing variable sections
221
         # by the actual existing sections
230
         # by the actual existing sections
222
-        variable_sections = [ section for section in specs if section.endswith('.*') ]
231
+        variable_sections = [section for section in specs if section.endswith('.*')]
223
         for vsec in variable_sections:
232
         for vsec in variable_sections:
224
             preffix = vsec[:-2]
233
             preffix = vsec[:-2]
225
-            for section in loader.getsection(preffix, 'default'): #WARNING : hardcoded default section
234
+            # WARNING : hardcoded default section
235
+            for section in loader.getsection(preffix, 'default'):
226
                 specs[section] = copy.copy(specs[vsec])
236
                 specs[section] = copy.copy(specs[vsec])
227
             del(specs[vsec])
237
             del(specs[vsec])
228
         # Fetching values for sections
238
         # Fetching values for sections
238
 
248
 
239
         self.__confs_to_namedtuple()
249
         self.__confs_to_namedtuple()
240
         pass
250
         pass
241
-    
242
-    ##@brief Transform the __confs attribute into imbricated namedtuple
251
+
252
+    # @brief Transform the __confs attribute into imbricated namedtuple
243
     #
253
     #
244
     # For example an option named "foo" in a section named "hello.world" will
254
     # For example an option named "foo" in a section named "hello.world" will
245
     # be acessible with self.__confs.hello.world.foo
255
     # be acessible with self.__confs.hello.world.foo
257
             section_name = ""
267
             section_name = ""
258
             cur = section_tree
268
             cur = section_tree
259
             for sec_part in spl:
269
             for sec_part in spl:
260
-                section_name += sec_part+'.'
270
+                section_name += sec_part + '.'
261
                 if sec_part not in cur:
271
                 if sec_part not in cur:
262
                     cur[sec_part] = dict()
272
                     cur[sec_part] = dict()
263
                 cur = cur[sec_part]
273
                 cur = cur[sec_part]
267
                     raise SettingsError("Duplicated key for '%s.%s'" % (section_name, kname))
277
                     raise SettingsError("Duplicated key for '%s.%s'" % (section_name, kname))
268
                 cur[kname] = kval
278
                 cur[kname] = kval
269
 
279
 
270
-        path = [ ('root', section_tree) ]
280
+        path = [('root', section_tree)]
271
         visited = set()
281
         visited = set()
272
-        
282
+
273
         curname = 'root'
283
         curname = 'root'
274
         nodename = 'Lodel2Settings'
284
         nodename = 'Lodel2Settings'
275
         cur = section_tree
285
         cur = section_tree
276
         while True:
286
         while True:
277
             visited.add(nodename)
287
             visited.add(nodename)
278
-            left = [    (kname, cur[kname])
279
-                        for kname in cur
280
-                        if nodename+'.'+kname.title() not in visited and isinstance(cur[kname], dict)
288
+            left = [(kname, cur[kname])
289
+                    for kname in cur
290
+                    if nodename + '.' + kname.title() not in visited and isinstance(cur[kname], dict)
281
                     ]
291
                     ]
282
             if len(left) == 0:
292
             if len(left) == 0:
283
                 name, leaf = path.pop()
293
                 name, leaf = path.pop()
284
                 typename = nodename.replace('.', '')
294
                 typename = nodename.replace('.', '')
285
                 if len(path) == 0:
295
                 if len(path) == 0:
286
                     # END
296
                     # END
287
-                    self.__confs = self.__tree2namedtuple(leaf,typename)
297
+                    self.__confs = self.__tree2namedtuple(leaf, typename)
288
                     break
298
                     break
289
                 else:
299
                 else:
290
-                    path[-1][1][name] = self.__tree2namedtuple(leaf,typename)
300
+                    path[-1][1][name] = self.__tree2namedtuple(leaf, typename)
291
                 nodename = '.'.join(nodename.split('.')[:-1])
301
                 nodename = '.'.join(nodename.split('.')[:-1])
292
                 cur = path[-1][1]
302
                 cur = path[-1][1]
293
             else:
303
             else:
294
                 curname, cur = left[0]
304
                 curname, cur = left[0]
295
-                path.append( (curname, cur) )
305
+                path.append((curname, cur))
296
                 nodename += '.' + curname.title()
306
                 nodename += '.' + curname.title()
297
-    
298
-    ##@brief Forge a named tuple given a conftree node
307
+
308
+    # @brief Forge a named tuple given a conftree node
299
     # @param conftree dict : A conftree node
309
     # @param conftree dict : A conftree node
300
     # @param name str
310
     # @param name str
301
     # @return a named tuple with fieldnames corresponding to conftree keys
311
     # @return a named tuple with fieldnames corresponding to conftree keys
303
         ResNamedTuple = namedtuple(name, conftree.keys())
313
         ResNamedTuple = namedtuple(name, conftree.keys())
304
         return ResNamedTuple(**conftree)
314
         return ResNamedTuple(**conftree)
305
 
315
 
316
+
306
 class MetaSettingsRO(type):
317
 class MetaSettingsRO(type):
318
+
307
     def __getattr__(self, name):
319
     def __getattr__(self, name):
308
         return getattr(Settings.s, name)
320
         return getattr(Settings.s, name)
309
-        
310
 
321
 
311
-## @brief A class that provide . notation read only access to configurations
322
+
323
+#  @brief A class that provide . notation read only access to configurations
312
 class SettingsRO(object, metaclass=MetaSettingsRO):
324
 class SettingsRO(object, metaclass=MetaSettingsRO):
313
     pass
325
     pass

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

181
         for key_id, filename in remains.items():
181
         for key_id, filename in remains.items():
182
             err_l.append(SettingsError(msg="Invalid configuration key", \
182
             err_l.append(SettingsError(msg="Invalid configuration key", \
183
                                     key_id=key_id, \
183
                                     key_id=key_id, \
184
-                                    filename=filename))
184
+                                    filename =filename))
185
         if len(err_l) > 0:
185
         if len(err_l) > 0:
186
             raise SettingsErrors(err_l)
186
             raise SettingsErrors(err_l)
187
         else:
187
         else:

+ 1
- 1
lodel/utils/datetime.py View File

6
     d = datetime.datetime.utcnow()
6
     d = datetime.datetime.utcnow()
7
     epoch = datetime.datetime(1970, 1, 1)
7
     epoch = datetime.datetime(1970, 1, 1)
8
     t = (d - epoch).total_seconds()
8
     t = (d - epoch).total_seconds()
9
-    return t
9
+    return t

+ 17
- 16
lodel/utils/mlstring.py View File

5
 import json
5
 import json
6
 
6
 
7
 
7
 
8
-##@brief Stores multilangage string
8
+# @brief Stores multilangage string
9
 class MlString(object):
9
 class MlString(object):
10
-    
10
+
11
     __default_lang = 'eng'
11
     __default_lang = 'eng'
12
 
12
 
13
     langs = [
13
     langs = [
17
         'esp',
17
         'esp',
18
     ]
18
     ]
19
 
19
 
20
-    ##@brief Create a new MlString instance
20
+    # @brief Create a new MlString instance
21
     # @param arg str | dict : Can be a json string, a string or a dict. It could be also a MlString object
21
     # @param arg str | dict : Can be a json string, a string or a dict. It could be also a MlString object
22
     def __init__(self, arg):
22
     def __init__(self, arg):
23
         self.values = dict()
23
         self.values = dict()
31
         elif isinstance(arg, MlString):
31
         elif isinstance(arg, MlString):
32
             self.values = copy.copy(arg.values)
32
             self.values = copy.copy(arg.values)
33
         else:
33
         else:
34
-            raise ValueError('<class str>, <class dict> or <class MlString> expected, but %s found' % type(arg))
35
-    
36
-    ##@brief Return a translation given a lang
34
+            raise ValueError(
35
+                '<class str>, <class dict> or <class MlString> expected, but %s found' % type(arg))
36
+
37
+    # @brief Return a translation given a lang
37
     # @param lang str | None : If None return default lang translation
38
     # @param lang str | None : If None return default lang translation
38
-    def get(self, lang = None):
39
+    def get(self, lang=None):
39
         lang = self.__default_lang if lang is None else lang
40
         lang = self.__default_lang if lang is None else lang
40
         if not self.lang_is_valid(lang):
41
         if not self.lang_is_valid(lang):
41
             raise ValueError("Invalid lang : '%s'" % lang)
42
             raise ValueError("Invalid lang : '%s'" % lang)
44
         else:
45
         else:
45
             return str(self)
46
             return str(self)
46
 
47
 
47
-    ##@brief Set a translation
48
+    # @brief Set a translation
48
     # @param lang str : the lang
49
     # @param lang str : the lang
49
     # @param val str | None:  the translation if None delete the translation
50
     # @param val str | None:  the translation if None delete the translation
50
     def set(self, lang, val):
51
     def set(self, lang, val):
57
         else:
58
         else:
58
             self.values[lang] = val
59
             self.values[lang] = val
59
 
60
 
60
-    ##@brief Checks that given lang is valid
61
+    # @brief Checks that given lang is valid
61
     # @param lang str : the lang
62
     # @param lang str : the lang
62
     @classmethod
63
     @classmethod
63
     def lang_is_valid(cls, lang):
64
     def lang_is_valid(cls, lang):
65
             raise ValueError('Invalid value for lang. Str expected but %s found' % type(lang))
66
             raise ValueError('Invalid value for lang. Str expected but %s found' % type(lang))
66
         return lang in cls.langs
67
         return lang in cls.langs
67
 
68
 
68
-    ##@brief Get or set the default lang
69
+    # @brief Get or set the default lang
69
     @classmethod
70
     @classmethod
70
-    def default_lang(cls, lang = None):
71
+    def default_lang(cls, lang=None):
71
         if lang is None:
72
         if lang is None:
72
             return cls.__default_lang
73
             return cls.__default_lang
73
         if not cls.lang_is_valid(lang):
74
         if not cls.lang_is_valid(lang):
74
             raise ValueError('lang "%s" is not valid"' % lang)
75
             raise ValueError('lang "%s" is not valid"' % lang)
75
         cls.__default_lang = lang
76
         cls.__default_lang = lang
76
-    
77
-    ##@brief Return a mlstring loaded from a json string
77
+
78
+    # @brief Return a mlstring loaded from a json string
78
     # @param json_str str : Json string
79
     # @param json_str str : Json string
79
     @classmethod
80
     @classmethod
80
     def from_json(cls, json_str):
81
     def from_json(cls, json_str):
89
     def d_hash(self):
90
     def d_hash(self):
90
         m = hashlib.md5()
91
         m = hashlib.md5()
91
         for lang in sorted(list(self.values.keys())):
92
         for lang in sorted(list(self.values.keys())):
92
-            m.update(bytes(lang+";"+self.values[lang], 'utf-8'))
93
+            m.update(bytes(lang + ";" + self.values[lang], 'utf-8'))
93
         return int.from_bytes(m.digest(), byteorder='big')
94
         return int.from_bytes(m.digest(), byteorder='big')
94
 
95
 
95
     def __eq__(self, a):
96
     def __eq__(self, a):
96
         return hash(self) == hash(a)
97
         return hash(self) == hash(a)
97
-    
98
-    ## @return The default langage translation or any available translation
98
+
99
+    # @return The default langage translation or any available translation
99
     def __str__(self):
100
     def __str__(self):
100
         if self.__default_lang in self.values:
101
         if self.__default_lang in self.values:
101
             return self.values[self.__default_lang]
102
             return self.values[self.__default_lang]

+ 107
- 75
lodel/validator/validator.py View File

11
 LodelContext.expose_modules(globals(), {
11
 LodelContext.expose_modules(globals(), {
12
     'lodel.mlnamedobject.mlnamedobject': ['MlNamedObject'],
12
     'lodel.mlnamedobject.mlnamedobject': ['MlNamedObject'],
13
     'lodel.exceptions': ['LodelException', 'LodelExceptions',
13
     'lodel.exceptions': ['LodelException', 'LodelExceptions',
14
-    'LodelFatalError', 'FieldValidationError']})
14
+                         'LodelFatalError', 'FieldValidationError']})
15
 
15
 
16
-## @package lodel.settings.validator Lodel2 settings validators/cast module
16
+# @package lodel.settings.validator Lodel2 settings validators/cast module
17
 #
17
 #
18
 # Validator are registered in the Validator class.
18
 # Validator are registered in the Validator class.
19
 # @note to get a list of registered default validators just run
19
 # @note to get a list of registered default validators just run
20
 # <pre>$ python scripts/settings_validator.py</pre>
20
 # <pre>$ python scripts/settings_validator.py</pre>
21
 
21
 
22
-##@brief Exception class that should be raised when a validation fails
22
+# @brief Exception class that should be raised when a validation fails
23
+
24
+
23
 class ValidationError(Exception):
25
 class ValidationError(Exception):
24
     pass
26
     pass
25
 
27
 
26
-##@brief Handles settings validators
28
+# @brief Handles settings validators
27
 #
29
 #
28
 # Class instance are callable objects that takes a value argument (the value to validate). It raises
30
 # Class instance are callable objects that takes a value argument (the value to validate). It raises
29
 # a ValidationError if validation fails, else it returns a properly
31
 # a ValidationError if validation fails, else it returns a properly
30
 # casted value.
32
 # casted value.
31
 #@todo implement an IP validator and use it in multisite confspec
33
 #@todo implement an IP validator and use it in multisite confspec
34
+
35
+
32
 class Validator(MlNamedObject):
36
 class Validator(MlNamedObject):
33
 
37
 
34
     _validators = dict()
38
     _validators = dict()
35
     _description = dict()
39
     _description = dict()
36
 
40
 
37
-    ##@brief Instanciate a validator
41
+    # @brief Instanciate a validator
38
     #@param name str : validator name
42
     #@param name str : validator name
39
     #@param none_is_valid bool : if True None will be validated
43
     #@param none_is_valid bool : if True None will be validated
40
     #@param **kwargs : more arguement for the validator
44
     #@param **kwargs : more arguement for the validator
48
             display_name = name
52
             display_name = name
49
         super().__init__(display_name, help_text)
53
         super().__init__(display_name, help_text)
50
 
54
 
51
-    ##@brief Call the validator
55
+    # @brief Call the validator
52
     # @param value *
56
     # @param value *
53
     # @return properly casted value
57
     # @return properly casted value
54
     # @throw ValidationError
58
     # @throw ValidationError
61
         except Exception as exp:
65
         except Exception as exp:
62
             raise ValidationError(exp)
66
             raise ValidationError(exp)
63
 
67
 
64
-    ##@brief Register a new validator
68
+    # @brief Register a new validator
65
     # @param name str : validator name
69
     # @param name str : validator name
66
     # @param callback callable : the function that will validate a value
70
     # @param callback callable : the function that will validate a value
67
     # @param description str
71
     # @param description str
75
         cls._validators[name] = callback
79
         cls._validators[name] = callback
76
         cls._description[name] = description
80
         cls._description[name] = description
77
 
81
 
78
-    ##@brief Get the validator list associated with description
82
+    # @brief Get the validator list associated with description
79
     @classmethod
83
     @classmethod
80
     def validators_list(cls):
84
     def validators_list(cls):
81
         return copy.copy(cls._description)
85
         return copy.copy(cls._description)
82
 
86
 
83
-    ##@brief Create and register a list validator
87
+    # @brief Create and register a list validator
84
     # @param elt_validator callable : The validator that will be used for validate each elt value
88
     # @param elt_validator callable : The validator that will be used for validate each elt value
85
     # @param validator_name str
89
     # @param validator_name str
86
     # @param description None | str
90
     # @param description None | str
99
         cls.register_validator(validator_name, list_validator, description)
103
         cls.register_validator(validator_name, list_validator, description)
100
         return cls(validator_name)
104
         return cls(validator_name)
101
 
105
 
102
-    ##@brief Create and register a list validator which reads an array and returns a string
106
+    # @brief Create and register a list validator which reads an array and returns a string
103
     # @param elt_validator callable : The validator that will be used for validate each elt value
107
     # @param elt_validator callable : The validator that will be used for validate each elt value
104
     # @param validator_name str
108
     # @param validator_name str
105
     # @param description None | str
109
     # @param description None | str
111
             res = ''
115
             res = ''
112
             for elt in value:
116
             for elt in value:
113
                 res += elt_validator(elt) + ','
117
                 res += elt_validator(elt) + ','
114
-            return res[:len(res)-1]
118
+            return res[:len(res) - 1]
115
         description = "Convert value to a string" if description is None else description
119
         description = "Convert value to a string" if description is None else description
116
         cls.register_validator(validator_name, write_list_validator, description)
120
         cls.register_validator(validator_name, write_list_validator, description)
117
         return cls(validator_name)
121
         return cls(validator_name)
118
 
122
 
119
-    ##@brief Create and register a regular expression validator
123
+    # @brief Create and register a regular expression validator
120
     # @param pattern str : regex pattern
124
     # @param pattern str : regex pattern
121
     # @param validator_name str : The validator name
125
     # @param validator_name str : The validator name
122
     # @param description str : Validator description
126
     # @param description str : Validator description
125
     def create_re_validator(cls, pattern, validator_name, description=None):
129
     def create_re_validator(cls, pattern, validator_name, description=None):
126
         def re_validator(value):
130
         def re_validator(value):
127
             if not re.match(pattern, value):
131
             if not re.match(pattern, value):
128
-                raise ValidationError(\
129
-                    "The value '%s' doesn't match the following pattern '%s'" \
132
+                raise ValidationError(
133
+                    "The value '%s' doesn't match the following pattern '%s'"
130
                     % pattern)
134
                     % pattern)
131
             return value
135
             return value
132
-        #registering the validator
133
-        cls.register_validator(validator_name, re_validator, \
134
-            ("Match value to '%s'" % pattern) \
135
-            if description is None else description)
136
+        # registering the validator
137
+        cls.register_validator(validator_name, re_validator,
138
+                               ("Match value to '%s'" % pattern)
139
+                               if description is None else description)
136
         return cls(validator_name)
140
         return cls(validator_name)
137
 
141
 
138
-    ## @return a list of registered validators
142
+    #  @return a list of registered validators
139
     @classmethod
143
     @classmethod
140
     def validators_list_str(cls):
144
     def validators_list_str(cls):
141
         result = ''
145
         result = ''
146
             result += "\n"
150
             result += "\n"
147
         return result
151
         return result
148
 
152
 
149
-##@brief Integer value validator callback
153
+# @brief Integer value validator callback
154
+
155
+
150
 def int_val(value):
156
 def int_val(value):
151
     return int(value)
157
     return int(value)
152
 
158
 
153
-##@brief Output file validator callback
159
+# @brief Output file validator callback
154
 # @return A file object (if filename is '-' return sys.stderr)
160
 # @return A file object (if filename is '-' return sys.stderr)
161
+
162
+
155
 def file_err_output(value):
163
 def file_err_output(value):
156
     if not isinstance(value, str):
164
     if not isinstance(value, str):
157
         raise ValidationError("A string was expected but got '%s' " % value)
165
         raise ValidationError("A string was expected but got '%s' " % value)
159
         return None
167
         return None
160
     return value
168
     return value
161
 
169
 
162
-##@brief Boolean value validator callback
170
+# @brief Boolean value validator callback
171
+
172
+
163
 def boolean_val(value):
173
 def boolean_val(value):
164
     if isinstance(value, bool):
174
     if isinstance(value, bool):
165
         return value
175
         return value
171
         raise ValidationError("A boolean was expected but got '%s' " % value)
181
         raise ValidationError("A boolean was expected but got '%s' " % value)
172
     return bool(value)
182
     return bool(value)
173
 
183
 
174
-##@brief Validate a directory path
184
+# @brief Validate a directory path
185
+
186
+
175
 def directory_val(value):
187
 def directory_val(value):
176
     res = Validator('strip')(value)
188
     res = Validator('strip')(value)
177
     if not os.path.isdir(res):
189
     if not os.path.isdir(res):
178
-        raise ValidationError("Following path don't exists or is not a directory : '%s'"%res)
190
+        raise ValidationError("Following path don't exists or is not a directory : '%s'" % res)
179
     return res
191
     return res
180
 
192
 
181
-##@brief Validate a loglevel value
193
+# @brief Validate a loglevel value
194
+
195
+
182
 def loglevel_val(value):
196
 def loglevel_val(value):
183
     valids = ['DEBUG', 'INFO', 'WARNING', 'SECURITY', 'ERROR', 'CRITICAL']
197
     valids = ['DEBUG', 'INFO', 'WARNING', 'SECURITY', 'ERROR', 'CRITICAL']
184
     if value.upper() not in valids:
198
     if value.upper() not in valids:
185
-        raise ValidationError( \
199
+        raise ValidationError(
186
             "The value '%s' is not a valid loglevel" % value)
200
             "The value '%s' is not a valid loglevel" % value)
187
     return value.upper()
201
     return value.upper()
188
 
202
 
189
-##@brief Validate a path
203
+# @brief Validate a path
204
+
205
+
190
 def path_val(value):
206
 def path_val(value):
191
     if value is None or not os.path.exists(value):
207
     if value is None or not os.path.exists(value):
192
-        raise ValidationError( \
208
+        raise ValidationError(
193
             "path '%s' doesn't exists" % value)
209
             "path '%s' doesn't exists" % value)
194
     return value
210
     return value
195
 
211
 
196
-##@brief Validate None
212
+# @brief Validate None
213
+
214
+
197
 def none_val(value):
215
 def none_val(value):
198
     if value is None:
216
     if value is None:
199
         return None
217
         return None
200
     raise ValidationError("This settings cannot be set in configuration file")
218
     raise ValidationError("This settings cannot be set in configuration file")
201
 
219
 
202
-##@brief Validate a string
220
+# @brief Validate a string
221
+
222
+
203
 def str_val(value):
223
 def str_val(value):
204
     try:
224
     try:
205
         return str(value)
225
         return str(value)
206
     except Exception as exp:
226
     except Exception as exp:
207
         raise ValidationError("Can't to convert value to string: " + str(exp))
227
         raise ValidationError("Can't to convert value to string: " + str(exp))
208
 
228
 
209
-##@brief Validate using a regex
229
+# @brief Validate using a regex
230
+
231
+
210
 def regex_val(value, pattern):
232
 def regex_val(value, pattern):
211
     if re.match(pattern, value) is None:
233
     if re.match(pattern, value) is None:
212
         raise ValidationError("The value '%s' is not validated by : \
234
         raise ValidationError("The value '%s' is not validated by : \
213
-r\"%s\"" %(value, pattern))
235
+r\"%s\"" % (value, pattern))
214
     return value
236
     return value
215
 
237
 
216
-##@brief Validate a hostname (ipv4 or ipv6)
238
+# @brief Validate a hostname (ipv4 or ipv6)
239
+
240
+
217
 def host_val(value):
241
 def host_val(value):
218
     if value == 'localhost':
242
     if value == 'localhost':
219
         return value
243
         return value
235
         msg = "The value '%s' is not a valid host"
259
         msg = "The value '%s' is not a valid host"
236
         raise ValidationError(msg % value)
260
         raise ValidationError(msg % value)
237
 
261
 
262
+
238
 def custom_list_validator(value, validator_name, validator_kwargs=None):
263
 def custom_list_validator(value, validator_name, validator_kwargs=None):
239
     validator_kwargs = dict() if validator_kwargs is None else validator_kwargs
264
     validator_kwargs = dict() if validator_kwargs is None else validator_kwargs
240
     validator = Validator(validator_name, **validator_kwargs)
265
     validator = Validator(validator_name, **validator_kwargs)
246
 #   Default validators registration
271
 #   Default validators registration
247
 #
272
 #
248
 
273
 
249
-Validator.register_validator('custom_list', custom_list_validator, \
250
-    'A list validator that takes a "validator_name" as argument')
274
+Validator.register_validator('custom_list', custom_list_validator,
275
+                             'A list validator that takes a "validator_name" as argument')
251
 
276
 
252
 Validator.register_validator('dummy', lambda value: value, 'Validate anything')
277
 Validator.register_validator('dummy', lambda value: value, 'Validate anything')
253
 
278
 
261
 
286
 
262
 Validator.register_validator('bool', boolean_val, 'Boolean value validator')
287
 Validator.register_validator('bool', boolean_val, 'Boolean value validator')
263
 
288
 
264
-Validator.register_validator('errfile', file_err_output,\
265
-    'Error output file validator (return stderr if filename is "-")')
289
+Validator.register_validator('errfile', file_err_output,
290
+                             'Error output file validator (return stderr if filename is "-")')
266
 
291
 
267
-Validator.register_validator('directory', directory_val, \
268
-    'Directory path validator')
292
+Validator.register_validator('directory', directory_val,
293
+                             'Directory path validator')
269
 
294
 
270
 Validator.register_validator('loglevel', loglevel_val, 'Loglevel validator')
295
 Validator.register_validator('loglevel', loglevel_val, 'Loglevel validator')
271
 
296
 
273
 
298
 
274
 Validator.register_validator('host', host_val, 'host validator')
299
 Validator.register_validator('host', host_val, 'host validator')
275
 
300
 
276
-Validator.register_validator('regex', regex_val, \
277
-    'RegEx name validator (take re as argument)')
301
+Validator.register_validator('regex', regex_val,
302
+                             'RegEx name validator (take re as argument)')
278
 
303
 
279
-Validator.create_list_validator('list', Validator('strip'), description=\
280
-    "Simple list validator. Validate a list of values separated by ','", \
281
-    separator=',')
304
+Validator.create_list_validator('list', Validator('strip'), description="Simple list validator. Validate a list of values separated by ','",
305
+                                separator=',')
282
 
306
 
283
-Validator.create_list_validator( \
284
-    'directory_list', \
285
-    Validator('directory'), \
286
-    description="Validator for a list of directory path separated with ','", \
307
+Validator.create_list_validator(
308
+    'directory_list',
309
+    Validator('directory'),
310
+    description="Validator for a list of directory path separated with ','",
287
     separator=',')
311
     separator=',')
288
 
312
 
289
-Validator.create_write_list_validator( \
290
-    'write_list', \
291
-    Validator('directory'), \
313
+Validator.create_write_list_validator(
314
+    'write_list',
315
+    Validator('directory'),
292
     description="Validator for an array of values \
316
     description="Validator for an array of values \
293
         which will be set in a string, separated by ','",
317
         which will be set in a string, separated by ','",
294
     separator=',')
318
     separator=',')
295
 
319
 
296
-Validator.create_re_validator( \
297
-    r'^https?://[^\./]+.[^\./]+/?.*$', \
298
-    'http_url', \
320
+Validator.create_re_validator(
321
+    r'^https?://[^\./]+.[^\./]+/?.*$',
322
+    'http_url',
299
     'Url validator')
323
     'Url validator')
300
 
324
 
301
-##@brief Validator for Editorial model component
325
+# @brief Validator for Editorial model component
302
 #
326
 #
303
 # Designed to validate a conf that indicate a class.field in an EM
327
 # Designed to validate a conf that indicate a class.field in an EM
304
 #@todo modified the hardcoded dyncode import (it's a warning)
328
 #@todo modified the hardcoded dyncode import (it's a warning)
329
+
330
+
305
 def emfield_val(value):
331
 def emfield_val(value):
306
-    LodelContext.expose_modules(globals(), \
307
-        {'lodel.plugin.hooks': ['LodelHook']})
332
+    LodelContext.expose_modules(globals(),
333
+                                {'lodel.plugin.hooks': ['LodelHook']})
308
     spl = value.split('.')
334
     spl = value.split('.')
309
     if len(spl) != 2:
335
     if len(spl) != 2:
310
         msg = "Expected a value in the form CLASSNAME.FIELDNAME but got : %s"
336
         msg = "Expected a value in the form CLASSNAME.FIELDNAME but got : %s"
311
         raise SettingsValidationError(msg % value)
337
         raise SettingsValidationError(msg % value)
312
     value = tuple(spl)
338
     value = tuple(spl)
313
-    #Late validation hook
339
+    # Late validation hook
340
+
314
     @LodelHook('lodel2_dyncode_bootstraped')
341
     @LodelHook('lodel2_dyncode_bootstraped')
315
     def emfield_conf_check(hookname, caller, payload):
342
     def emfield_conf_check(hookname, caller, payload):
316
-        import leapi_dyncode as dyncode # <-- dirty & quick
317
-        classnames = { cls.__name__.lower(): cls for cls in dyncode.dynclasses}
343
+        import leapi_dyncode as dyncode  # <-- dirty & quick
344
+        classnames = {cls.__name__.lower(): cls for cls in dyncode.dynclasses}
318
         if value[0].lower() not in classnames:
345
         if value[0].lower() not in classnames:
319
             msg = "Following dynamic class do not exists in current EM : %s"
346
             msg = "Following dynamic class do not exists in current EM : %s"
320
             raise SettingsValidationError(msg % value[0])
347
             raise SettingsValidationError(msg % value[0])
324
             raise SettingsValidationError(msg % value)
351
             raise SettingsValidationError(msg % value)
325
     return value
352
     return value
326
 
353
 
327
-##@brief Validator for plugin name & optionnaly type
354
+# @brief Validator for plugin name & optionnaly type
328
 #
355
 #
329
-#Able to check that the value is a plugin and if it is of a specific type
356
+# Able to check that the value is a plugin and if it is of a specific type
357
+
358
+
330
 def plugin_validator(value, ptype=None):
359
 def plugin_validator(value, ptype=None):
331
-    LodelContext.expose_modules(globals(), { \
360
+    LodelContext.expose_modules(globals(), {
332
         'lodel.plugin.hooks': ['LodelHook']})
361
         'lodel.plugin.hooks': ['LodelHook']})
333
     value = copy.copy(value)
362
     value = copy.copy(value)
363
+
334
     @LodelHook('lodel2_dyncode_bootstraped')
364
     @LodelHook('lodel2_dyncode_bootstraped')
335
     def plugin_type_checker(hookname, caller, payload):
365
     def plugin_type_checker(hookname, caller, payload):
336
-        LodelContext.expose_modules(globals(), { \
337
-            'lodel.plugin.plugins': ['Plugin'], \
366
+        LodelContext.expose_modules(globals(), {
367
+            'lodel.plugin.plugins': ['Plugin'],
338
             'lodel.plugin.exceptions': ['PluginError']})
368
             'lodel.plugin.exceptions': ['PluginError']})
339
         if value is None:
369
         if value is None:
340
             return
370
             return
352
     return value
382
     return value
353
 
383
 
354
 
384
 
355
-Validator.register_validator( \
356
-    'plugin', \
357
-    plugin_validator, \
385
+Validator.register_validator(
386
+    'plugin',
387
+    plugin_validator,
358
     'plugin name & type validator')
388
     'plugin name & type validator')
359
 
389
 
360
-Validator.register_validator( \
361
-    'emfield', \
362
-    emfield_val, \
390
+Validator.register_validator(
391
+    'emfield',
392
+    emfield_val,
363
     'EmField name validator')
393
     'EmField name validator')
364
 
394
 
365
 #
395
 #
366
 #   Lodel 2 configuration specification
396
 #   Lodel 2 configuration specification
367
 #
397
 #
368
 
398
 
369
-##@brief Append a piece of confspec
399
+# @brief Append a piece of confspec
370
 #@note orig is modified during the process
400
 #@note orig is modified during the process
371
 #@param orig dict : the confspec to update
401
 #@param orig dict : the confspec to update
372
 #@param section str : section name
402
 #@param section str : section name
374
 #@param validator Validator : the validator to use to check this configuration key's value
404
 #@param validator Validator : the validator to use to check this configuration key's value
375
 #@param default
405
 #@param default
376
 #@return new confspec
406
 #@return new confspec
407
+
408
+
377
 def confspec_append(orig, section, key, validator, default):
409
 def confspec_append(orig, section, key, validator, default):
378
     if section not in orig:
410
     if section not in orig:
379
         orig[section] = dict()
411
         orig[section] = dict()
381
         orig[section][key] = (default, validator)
413
         orig[section][key] = (default, validator)
382
     return orig
414
     return orig
383
 
415
 
384
-##@brief Global specifications for lodel2 settings
416
+# @brief Global specifications for lodel2 settings
385
 LODEL2_CONF_SPECS = {
417
 LODEL2_CONF_SPECS = {
386
     'lodel2': {
418
     'lodel2': {
387
         'debug': (True, Validator('bool')),
419
         'debug': (True, Validator('bool')),
388
         'sitename': ('noname', Validator('strip')),
420
         'sitename': ('noname', Validator('strip')),
389
         'runtest': (False, Validator('bool')),
421
         'runtest': (False, Validator('bool')),
390
     },
422
     },
391
-    'lodel2.logging.*' : {
423
+    'lodel2.logging.*': {
392
         'level': ('ERROR', Validator('loglevel')),
424
         'level': ('ERROR', Validator('loglevel')),
393
         'context': (False, Validator('bool')),
425
         'context': (False, Validator('bool')),
394
         'filename': ("-", Validator('errfile', none_is_valid=False)),
426
         'filename': ("-", Validator('errfile', none_is_valid=False)),
395
         'backupcount': (5, Validator('int', none_is_valid=False)),
427
         'backupcount': (5, Validator('int', none_is_valid=False)),
396
-        'maxbytes': (1024*10, Validator('int', none_is_valid=False)),
428
+        'maxbytes': (1024 * 10, Validator('int', none_is_valid=False)),
397
     },
429
     },
398
     'lodel2.editorialmodel': {
430
     'lodel2.editorialmodel': {
399
         'emfile': ('em.pickle', Validator('strip')),
431
         'emfile': ('em.pickle', Validator('strip')),

Loading…
Cancel
Save