|
@@ -11,7 +11,7 @@ from lodel.context import LodelContext
|
11
|
11
|
LodelContext.expose_modules(globals(), {
|
12
|
12
|
'lodel.mlnamedobject.mlnamedobject': ['MlNamedObject'],
|
13
|
13
|
'lodel.exceptions': ['LodelException', 'LodelExceptions',
|
14
|
|
- 'LodelFatalError', 'FieldValidationError']})
|
|
14
|
+ 'LodelFatalError', 'FieldValidationError']})
|
15
|
15
|
|
16
|
16
|
## @package lodel.settings.validator Lodel2 settings validators/cast module
|
17
|
17
|
#
|
|
@@ -30,15 +30,15 @@ class ValidationError(Exception):
|
30
|
30
|
# casted value.
|
31
|
31
|
#@todo implement an IP validator and use it in multisite confspec
|
32
|
32
|
class Validator(MlNamedObject):
|
33
|
|
-
|
|
33
|
+
|
34
|
34
|
_validators = dict()
|
35
|
35
|
_description = dict()
|
36
|
|
-
|
|
36
|
+
|
37
|
37
|
##@brief Instanciate a validator
|
38
|
38
|
#@param name str : validator name
|
39
|
39
|
#@param none_is_valid bool : if True None will be validated
|
40
|
40
|
#@param **kwargs : more arguement for the validator
|
41
|
|
- def __init__(self, name, none_is_valid = False, display_name = None, help_text = None, **kwargs):
|
|
41
|
+ def __init__(self, name, none_is_valid=False, display_name=None, help_text=None, **kwargs):
|
42
|
42
|
if name is not None and name not in self._validators:
|
43
|
43
|
raise LodelFatalError("No validator named '%s'" % name)
|
44
|
44
|
self.__none_is_valid = none_is_valid
|
|
@@ -58,9 +58,9 @@ class Validator(MlNamedObject):
|
58
|
58
|
try:
|
59
|
59
|
ret = self._validators[self.__name](value, **self._opt_args)
|
60
|
60
|
return ret
|
61
|
|
- except Exception as e:
|
62
|
|
- raise ValidationError(e)
|
63
|
|
-
|
|
61
|
+ except Exception as exp:
|
|
62
|
+ raise ValidationError(exp)
|
|
63
|
+
|
64
|
64
|
##@brief Register a new validator
|
65
|
65
|
# @param name str : validator name
|
66
|
66
|
# @param callback callable : the function that will validate a value
|
|
@@ -74,7 +74,7 @@ class Validator(MlNamedObject):
|
74
|
74
|
raise TypeError("Callable expected but got %s" % type(callback))
|
75
|
75
|
cls._validators[name] = callback
|
76
|
76
|
cls._description[name] = description
|
77
|
|
-
|
|
77
|
+
|
78
|
78
|
##@brief Get the validator list associated with description
|
79
|
79
|
@classmethod
|
80
|
80
|
def validators_list(cls):
|
|
@@ -87,22 +87,18 @@ class Validator(MlNamedObject):
|
87
|
87
|
# @param separator str : The element separator
|
88
|
88
|
# @return A Validator instance
|
89
|
89
|
@classmethod
|
90
|
|
- def create_list_validator(cls, validator_name, elt_validator, description = None, separator = ','):
|
|
90
|
+ def create_list_validator(cls, validator_name, elt_validator, description=None, separator=','):
|
91
|
91
|
def list_validator(value):
|
92
|
92
|
res = list()
|
93
|
|
- errors = list()
|
94
|
93
|
for elt in value.split(separator):
|
95
|
94
|
elt = elt_validator(elt)
|
96
|
95
|
if len(elt) > 0:
|
97
|
96
|
res.append(elt)
|
98
|
97
|
return res
|
99
|
98
|
description = "Convert value to an array" if description is None else description
|
100
|
|
- cls.register_validator(
|
101
|
|
- validator_name,
|
102
|
|
- list_validator,
|
103
|
|
- description)
|
|
99
|
+ cls.register_validator(validator_name, list_validator, description)
|
104
|
100
|
return cls(validator_name)
|
105
|
|
-
|
|
101
|
+
|
106
|
102
|
##@brief Create and register a list validator which reads an array and returns a string
|
107
|
103
|
# @param elt_validator callable : The validator that will be used for validate each elt value
|
108
|
104
|
# @param validator_name str
|
|
@@ -110,39 +106,35 @@ class Validator(MlNamedObject):
|
110
|
106
|
# @param separator str : The element separator
|
111
|
107
|
# @return A Validator instance
|
112
|
108
|
@classmethod
|
113
|
|
- def create_write_list_validator(cls, validator_name, elt_validator, description = None, separator = ','):
|
|
109
|
+ def create_write_list_validator(cls, validator_name, elt_validator, description=None, separator=','):
|
114
|
110
|
def write_list_validator(value):
|
115
|
111
|
res = ''
|
116
|
|
- errors = list()
|
117
|
112
|
for elt in value:
|
118
|
113
|
res += elt_validator(elt) + ','
|
119
|
114
|
return res[:len(res)-1]
|
120
|
115
|
description = "Convert value to a string" if description is None else description
|
121
|
|
- cls.register_validator(
|
122
|
|
- validator_name,
|
123
|
|
- write_list_validator,
|
124
|
|
- description)
|
|
116
|
+ cls.register_validator(validator_name, write_list_validator, description)
|
125
|
117
|
return cls(validator_name)
|
126
|
|
-
|
|
118
|
+
|
127
|
119
|
##@brief Create and register a regular expression validator
|
128
|
120
|
# @param pattern str : regex pattern
|
129
|
121
|
# @param validator_name str : The validator name
|
130
|
122
|
# @param description str : Validator description
|
131
|
123
|
# @return a Validator instance
|
132
|
124
|
@classmethod
|
133
|
|
- def create_re_validator(cls, pattern, validator_name, description = None):
|
|
125
|
+ def create_re_validator(cls, pattern, validator_name, description=None):
|
134
|
126
|
def re_validator(value):
|
135
|
127
|
if not re.match(pattern, value):
|
136
|
|
- raise ValidationError("The value '%s' doesn't match the following pattern '%s'" % pattern)
|
|
128
|
+ raise ValidationError(\
|
|
129
|
+ "The value '%s' doesn't match the following pattern '%s'" \
|
|
130
|
+ % pattern)
|
137
|
131
|
return value
|
138
|
132
|
#registering the validator
|
139
|
|
- cls.register_validator(
|
140
|
|
- validator_name,
|
141
|
|
- re_validator,
|
142
|
|
- ("Match value to '%s'" % pattern) if description is None else description)
|
|
133
|
+ cls.register_validator(validator_name, re_validator, \
|
|
134
|
+ ("Match value to '%s'" % pattern) \
|
|
135
|
+ if description is None else description)
|
143
|
136
|
return cls(validator_name)
|
144
|
137
|
|
145
|
|
-
|
146
|
138
|
## @return a list of registered validators
|
147
|
139
|
@classmethod
|
148
|
140
|
def validators_list_str(cls):
|
|
@@ -183,22 +175,22 @@ def boolean_val(value):
|
183
|
175
|
def directory_val(value):
|
184
|
176
|
res = Validator('strip')(value)
|
185
|
177
|
if not os.path.isdir(res):
|
186
|
|
- raise ValidationError("Folowing path don't exists or is not a directory : '%s'"%res)
|
|
178
|
+ raise ValidationError("Following path don't exists or is not a directory : '%s'"%res)
|
187
|
179
|
return res
|
188
|
180
|
|
189
|
181
|
##@brief Validate a loglevel value
|
190
|
182
|
def loglevel_val(value):
|
191
|
183
|
valids = ['DEBUG', 'INFO', 'WARNING', 'SECURITY', 'ERROR', 'CRITICAL']
|
192
|
184
|
if value.upper() not in valids:
|
193
|
|
- raise ValidationError(
|
194
|
|
- "The value '%s' is not a valid loglevel" % value)
|
|
185
|
+ raise ValidationError( \
|
|
186
|
+ "The value '%s' is not a valid loglevel" % value)
|
195
|
187
|
return value.upper()
|
196
|
188
|
|
197
|
189
|
##@brief Validate a path
|
198
|
190
|
def path_val(value):
|
199
|
191
|
if value is None or not os.path.exists(value):
|
200
|
|
- raise ValidationError(
|
201
|
|
- "path '%s' doesn't exists" % value)
|
|
192
|
+ raise ValidationError( \
|
|
193
|
+ "path '%s' doesn't exists" % value)
|
202
|
194
|
return value
|
203
|
195
|
|
204
|
196
|
##@brief Validate None
|
|
@@ -211,8 +203,8 @@ def none_val(value):
|
211
|
203
|
def str_val(value):
|
212
|
204
|
try:
|
213
|
205
|
return str(value)
|
214
|
|
- except Exception as e:
|
215
|
|
- raise ValidationError("Not able to convert value to string : " + str(e))
|
|
206
|
+ except Exception as exp:
|
|
207
|
+ raise ValidationError("Can't to convert value to string: " + str(exp))
|
216
|
208
|
|
217
|
209
|
##@brief Validate using a regex
|
218
|
210
|
def regex_val(value, pattern):
|
|
@@ -229,21 +221,21 @@ def host_val(value):
|
229
|
221
|
try:
|
230
|
222
|
socket.inet_aton(value)
|
231
|
223
|
return value
|
232
|
|
- except (TypeError,OSError):
|
|
224
|
+ except (TypeError, OSError):
|
233
|
225
|
pass
|
234
|
226
|
try:
|
235
|
227
|
socket.inet_pton(socket.AF_INET6, value)
|
236
|
228
|
return value
|
237
|
|
- except (TypeError,OSError):
|
|
229
|
+ except (TypeError, OSError):
|
238
|
230
|
pass
|
239
|
231
|
try:
|
240
|
232
|
socket.getaddrinfo(value, 80)
|
241
|
233
|
return value
|
242
|
|
- except (TypeError,socket.gaierror):
|
|
234
|
+ except (TypeError, socket.gaierror):
|
243
|
235
|
msg = "The value '%s' is not a valid host"
|
244
|
236
|
raise ValidationError(msg % value)
|
245
|
237
|
|
246
|
|
-def custom_list_validator(value, validator_name, validator_kwargs = None):
|
|
238
|
+def custom_list_validator(value, validator_name, validator_kwargs=None):
|
247
|
239
|
validator_kwargs = dict() if validator_kwargs is None else validator_kwargs
|
248
|
240
|
validator = Validator(validator_name, **validator_kwargs)
|
249
|
241
|
for item in value.split():
|
|
@@ -254,100 +246,65 @@ def custom_list_validator(value, validator_name, validator_kwargs = None):
|
254
|
246
|
# Default validators registration
|
255
|
247
|
#
|
256
|
248
|
|
257
|
|
-Validator.register_validator(
|
258
|
|
- 'custom_list',
|
259
|
|
- custom_list_validator,
|
|
249
|
+Validator.register_validator('custom_list', custom_list_validator, \
|
260
|
250
|
'A list validator that takes a "validator_name" as argument')
|
261
|
251
|
|
262
|
|
-Validator.register_validator(
|
263
|
|
- 'dummy',
|
264
|
|
- lambda value:value,
|
265
|
|
- 'Validate anything')
|
266
|
|
-
|
267
|
|
-Validator.register_validator(
|
268
|
|
- 'none',
|
269
|
|
- none_val,
|
270
|
|
- 'Validate None')
|
271
|
|
-
|
272
|
|
-Validator.register_validator(
|
273
|
|
- 'string',
|
274
|
|
- str_val,
|
275
|
|
- 'Validate string values')
|
276
|
|
-
|
277
|
|
-Validator.register_validator(
|
278
|
|
- 'strip',
|
279
|
|
- str.strip,
|
280
|
|
- 'String trim')
|
281
|
|
-
|
282
|
|
-Validator.register_validator(
|
283
|
|
- 'int',
|
284
|
|
- int_val,
|
285
|
|
- 'Integer value validator')
|
286
|
|
-
|
287
|
|
-Validator.register_validator(
|
288
|
|
- 'bool',
|
289
|
|
- boolean_val,
|
290
|
|
- 'Boolean value validator')
|
291
|
|
-
|
292
|
|
-Validator.register_validator(
|
293
|
|
- 'errfile',
|
294
|
|
- file_err_output,
|
|
252
|
+Validator.register_validator('dummy', lambda value: value, 'Validate anything')
|
|
253
|
+
|
|
254
|
+Validator.register_validator('none', none_val, 'Validate None')
|
|
255
|
+
|
|
256
|
+Validator.register_validator('string', str_val, 'Validate string values')
|
|
257
|
+
|
|
258
|
+Validator.register_validator('strip', str.strip, 'String trim')
|
|
259
|
+
|
|
260
|
+Validator.register_validator('int', int_val, 'Integer value validator')
|
|
261
|
+
|
|
262
|
+Validator.register_validator('bool', boolean_val, 'Boolean value validator')
|
|
263
|
+
|
|
264
|
+Validator.register_validator('errfile', file_err_output,\
|
295
|
265
|
'Error output file validator (return stderr if filename is "-")')
|
296
|
266
|
|
297
|
|
-Validator.register_validator(
|
298
|
|
- 'directory',
|
299
|
|
- directory_val,
|
|
267
|
+Validator.register_validator('directory', directory_val, \
|
300
|
268
|
'Directory path validator')
|
301
|
269
|
|
302
|
|
-Validator.register_validator(
|
303
|
|
- 'loglevel',
|
304
|
|
- loglevel_val,
|
305
|
|
- 'Loglevel validator')
|
|
270
|
+Validator.register_validator('loglevel', loglevel_val, 'Loglevel validator')
|
306
|
271
|
|
307
|
|
-Validator.register_validator(
|
308
|
|
- 'path',
|
309
|
|
- path_val,
|
310
|
|
- 'path validator')
|
|
272
|
+Validator.register_validator('path', path_val, 'path validator')
|
311
|
273
|
|
312
|
|
-Validator.register_validator(
|
313
|
|
- 'host',
|
314
|
|
- host_val,
|
315
|
|
- 'host validator')
|
|
274
|
+Validator.register_validator('host', host_val, 'host validator')
|
316
|
275
|
|
317
|
|
-Validator.register_validator(
|
318
|
|
- 'regex',
|
319
|
|
- regex_val,
|
|
276
|
+Validator.register_validator('regex', regex_val, \
|
320
|
277
|
'RegEx name validator (take re as argument)')
|
321
|
278
|
|
322
|
|
-Validator.create_list_validator(
|
323
|
|
- 'list',
|
324
|
|
- Validator('strip'),
|
325
|
|
- description = "Simple list validator. Validate a list of values separated by ','",
|
326
|
|
- separator = ',')
|
327
|
|
-
|
328
|
|
-Validator.create_list_validator(
|
329
|
|
- 'directory_list',
|
330
|
|
- Validator('directory'),
|
331
|
|
- description = "Validator for a list of directory path separated with ','",
|
332
|
|
- separator = ',')
|
333
|
|
-
|
334
|
|
-Validator.create_write_list_validator(
|
335
|
|
- 'write_list',
|
336
|
|
- Validator('directory'),
|
337
|
|
- description = "Validator for an array of values which will be set in a string, separated by ','",
|
338
|
|
- separator = ',')
|
339
|
|
-
|
340
|
|
-Validator.create_re_validator(
|
341
|
|
- r'^https?://[^\./]+.[^\./]+/?.*$',
|
342
|
|
- 'http_url',
|
|
279
|
+Validator.create_list_validator('list', Validator('strip'), description=\
|
|
280
|
+ "Simple list validator. Validate a list of values separated by ','", \
|
|
281
|
+ separator=',')
|
|
282
|
+
|
|
283
|
+Validator.create_list_validator( \
|
|
284
|
+ 'directory_list', \
|
|
285
|
+ Validator('directory'), \
|
|
286
|
+ description="Validator for a list of directory path separated with ','", \
|
|
287
|
+ separator=',')
|
|
288
|
+
|
|
289
|
+Validator.create_write_list_validator( \
|
|
290
|
+ 'write_list', \
|
|
291
|
+ Validator('directory'), \
|
|
292
|
+ description="Validator for an array of values \
|
|
293
|
+ which will be set in a string, separated by ','",
|
|
294
|
+ separator=',')
|
|
295
|
+
|
|
296
|
+Validator.create_re_validator( \
|
|
297
|
+ r'^https?://[^\./]+.[^\./]+/?.*$', \
|
|
298
|
+ 'http_url', \
|
343
|
299
|
'Url validator')
|
|
300
|
+
|
344
|
301
|
##@brief Validator for Editorial model component
|
345
|
302
|
#
|
346
|
303
|
# Designed to validate a conf that indicate a class.field in an EM
|
347
|
304
|
#@todo modified the hardcoded dyncode import (it's a warning)
|
348
|
305
|
def emfield_val(value):
|
349
|
|
- LodelContext.expose_modules(globals(), {
|
350
|
|
- 'lodel.plugin.hooks': ['LodelHook']})
|
|
306
|
+ LodelContext.expose_modules(globals(), \
|
|
307
|
+ {'lodel.plugin.hooks': ['LodelHook']})
|
351
|
308
|
spl = value.split('.')
|
352
|
309
|
if len(spl) != 2:
|
353
|
310
|
msg = "Expected a value in the form CLASSNAME.FIELDNAME but got : %s"
|
|
@@ -357,7 +314,7 @@ def emfield_val(value):
|
357
|
314
|
@LodelHook('lodel2_dyncode_bootstraped')
|
358
|
315
|
def emfield_conf_check(hookname, caller, payload):
|
359
|
316
|
import leapi_dyncode as dyncode # <-- dirty & quick
|
360
|
|
- classnames = { cls.__name__.lower():cls for cls in dyncode.dynclasses}
|
|
317
|
+ classnames = { cls.__name__.lower(): cls for cls in dyncode.dynclasses}
|
361
|
318
|
if value[0].lower() not in classnames:
|
362
|
319
|
msg = "Following dynamic class do not exists in current EM : %s"
|
363
|
320
|
raise SettingsValidationError(msg % value[0])
|
|
@@ -370,14 +327,14 @@ def emfield_val(value):
|
370
|
327
|
##@brief Validator for plugin name & optionnaly type
|
371
|
328
|
#
|
372
|
329
|
#Able to check that the value is a plugin and if it is of a specific type
|
373
|
|
-def plugin_validator(value, ptype = None):
|
374
|
|
- LodelContext.expose_modules(globals(), {
|
|
330
|
+def plugin_validator(value, ptype=None):
|
|
331
|
+ LodelContext.expose_modules(globals(), { \
|
375
|
332
|
'lodel.plugin.hooks': ['LodelHook']})
|
376
|
333
|
value = copy.copy(value)
|
377
|
334
|
@LodelHook('lodel2_dyncode_bootstraped')
|
378
|
335
|
def plugin_type_checker(hookname, caller, payload):
|
379
|
|
- LodelContext.expose_modules(globals(), {
|
380
|
|
- 'lodel.plugin.plugins': ['Plugin'],
|
|
336
|
+ LodelContext.expose_modules(globals(), { \
|
|
337
|
+ 'lodel.plugin.plugins': ['Plugin'], \
|
381
|
338
|
'lodel.plugin.exceptions': ['PluginError']})
|
382
|
339
|
if value is None:
|
383
|
340
|
return
|
|
@@ -395,14 +352,14 @@ named '%s' that is a '%s' plugin"
|
395
|
352
|
return value
|
396
|
353
|
|
397
|
354
|
|
398
|
|
-Validator.register_validator(
|
399
|
|
- 'plugin',
|
400
|
|
- plugin_validator,
|
|
355
|
+Validator.register_validator( \
|
|
356
|
+ 'plugin', \
|
|
357
|
+ plugin_validator, \
|
401
|
358
|
'plugin name & type validator')
|
402
|
359
|
|
403
|
|
-Validator.register_validator(
|
404
|
|
- 'emfield',
|
405
|
|
- emfield_val,
|
|
360
|
+Validator.register_validator( \
|
|
361
|
+ 'emfield', \
|
|
362
|
+ emfield_val, \
|
406
|
363
|
'EmField name validator')
|
407
|
364
|
|
408
|
365
|
#
|
|
@@ -427,38 +384,30 @@ def confspec_append(orig, section, key, validator, default):
|
427
|
384
|
##@brief Global specifications for lodel2 settings
|
428
|
385
|
LODEL2_CONF_SPECS = {
|
429
|
386
|
'lodel2': {
|
430
|
|
- 'debug': ( True,
|
431
|
|
- Validator('bool')),
|
432
|
|
- 'sitename': ( 'noname',
|
433
|
|
- Validator('strip')),
|
434
|
|
- 'runtest': ( False,
|
435
|
|
- Validator('bool')),
|
|
387
|
+ 'debug': (True, Validator('bool')),
|
|
388
|
+ 'sitename': ('noname', Validator('strip')),
|
|
389
|
+ 'runtest': (False, Validator('bool')),
|
436
|
390
|
},
|
437
|
391
|
'lodel2.logging.*' : {
|
438
|
|
- 'level': ( 'ERROR',
|
439
|
|
- Validator('loglevel')),
|
440
|
|
- 'context': ( False,
|
441
|
|
- Validator('bool')),
|
442
|
|
- 'filename': ( "-",
|
443
|
|
- Validator('errfile', none_is_valid = False)),
|
444
|
|
- 'backupcount': ( 5,
|
445
|
|
- Validator('int', none_is_valid = False)),
|
446
|
|
- 'maxbytes': ( 1024*10,
|
447
|
|
- Validator('int', none_is_valid = False)),
|
|
392
|
+ 'level': ('ERROR', Validator('loglevel')),
|
|
393
|
+ 'context': (False, Validator('bool')),
|
|
394
|
+ 'filename': ("-", Validator('errfile', none_is_valid=False)),
|
|
395
|
+ 'backupcount': (5, Validator('int', none_is_valid=False)),
|
|
396
|
+ 'maxbytes': (1024*10, Validator('int', none_is_valid=False)),
|
448
|
397
|
},
|
449
|
398
|
'lodel2.editorialmodel': {
|
450
|
|
- 'emfile': ( 'em.pickle', Validator('strip')),
|
451
|
|
- 'emtranslator': ( 'picklefile', Validator('strip')),
|
452
|
|
- 'dyncode': ( 'leapi_dyncode.py', Validator('strip')),
|
453
|
|
- 'groups': ( '', Validator('list')),
|
454
|
|
- 'editormode': ( False, Validator('bool')),
|
|
399
|
+ 'emfile': ('em.pickle', Validator('strip')),
|
|
400
|
+ 'emtranslator': ('picklefile', Validator('strip')),
|
|
401
|
+ 'dyncode': ('leapi_dyncode.py', Validator('strip')),
|
|
402
|
+ 'groups': ('', Validator('list')),
|
|
403
|
+ 'editormode': (False, Validator('bool')),
|
455
|
404
|
},
|
456
|
405
|
'lodel2.datasources.*': {
|
457
|
406
|
'read_only': (False, Validator('bool')),
|
458
|
|
- 'identifier': ( None, Validator('string')),
|
|
407
|
+ 'identifier': (None, Validator('string')),
|
459
|
408
|
},
|
460
|
409
|
'lodel2.auth': {
|
461
|
410
|
'login_classfield': ('user.login', Validator('emfield')),
|
462
|
411
|
'pass_classfield': ('user.password', Validator('emfield')),
|
463
|
412
|
},
|
464
|
|
-}
|
|
413
|
+}
|