Browse Source

Validator documentation

Quentin Bonaventure 7 years ago
parent
commit
ab03bbf7c8
1 changed files with 111 additions and 93 deletions
  1. 111
    93
      lodel/validator/validator.py

+ 111
- 93
lodel/validator/validator.py View File

@@ -6,42 +6,50 @@ import re
6 6
 import socket
7 7
 import inspect
8 8
 import copy
9
-
10 9
 from lodel.context import LodelContext
10
+
11
+
11 12
 LodelContext.expose_modules(globals(), {
12 13
     'lodel.mlnamedobject.mlnamedobject': ['MlNamedObject'],
13 14
     'lodel.exceptions': ['LodelException', 'LodelExceptions',
14 15
                          'LodelFatalError', 'FieldValidationError']})
15 16
 
16
-# @package lodel.settings.validator Lodel2 settings validators/cast module
17
+
18
+##
19
+# @package lodel.settings.validator Lodel2 settings validators/cast module.
17 20
 #
18 21
 # Validator are registered in the Validator class.
19 22
 # @note to get a list of registered default validators just run
20 23
 # <pre>$ python scripts/settings_validator.py</pre>
21
-
22
-# @brief Exception class that should be raised when a validation fails
24
+#
25
+# @remarks Should we reconsider specifying conf right in this module?
23 26
 
24 27
 
28
+##
29
+# @brief Exception class that should be raised when a validation fails
25 30
 class ValidationError(Exception):
26 31
     pass
27 32
 
33
+
34
+##
28 35
 # @brief Handles settings validators
29 36
 #
30
-# Class instance are callable objects that takes a value argument (the value to validate). It raises
31
-# a ValidationError if validation fails, else it returns a properly
32
-# casted value.
33
-#@todo implement an IP validator and use it in multisite confspec
34
-
35
-
37
+# Class instance are callable objects that takes a value argument (the value
38
+# to validate). It raises a ValidationError if validation fails, else it returns
39
+# a properly cast value.
40
+#
41
+#@todo Implement an IP validator for use in the multisite confspec
36 42
 class Validator(MlNamedObject):
37 43
 
38 44
     _validators = dict()
39 45
     _description = dict()
40 46
 
41
-    # @brief Instanciate a validator
42
-    #@param name str : validator name
43
-    #@param none_is_valid bool : if True None will be validated
44
-    #@param **kwargs : more arguement for the validator
47
+    ##
48
+    # @brief Instantiate a validator
49
+    #
50
+    #@param name str: validator name
51
+    #@param none_is_valid bool: if True None will be validated
52
+    #@param **kwargs: more arguments for the validator
45 53
     def __init__(self, name, none_is_valid=False, display_name=None, help_text=None, **kwargs):
46 54
         if name is not None and name not in self._validators:
47 55
             raise LodelFatalError("No validator named '%s'" % name)
@@ -52,9 +60,11 @@ class Validator(MlNamedObject):
52 60
             display_name = name
53 61
         super().__init__(display_name, help_text)
54 62
 
55
-    # @brief Call the validator
56
-    # @param value *
57
-    # @return properly casted value
63
+    ##
64
+    # @brief Calls the validator.
65
+    #
66
+    # @param value mixed:
67
+    # @return mixed: The properly casted value
58 68
     # @throw ValidationError
59 69
     def __call__(self, value):
60 70
         if value is None:
@@ -70,31 +80,38 @@ class Validator(MlNamedObject):
70 80
         except Exception as exp:
71 81
             raise ValidationError(exp)
72 82
 
83
+    ##
73 84
     # @brief Register a new validator
74
-    # @param name str : validator name
75
-    # @param callback callable : the function that will validate a value
76
-    # @param description str
85
+    #
86
+    # @param name string: validator name
87
+    # @param callback callable: the function that will validate a value
88
+    # @param description string:
77 89
     @classmethod
78 90
     def register_validator(cls, name, callback, description=None):
79 91
         if name in cls._validators:
80 92
             raise NameError("A validator named '%s' allready exists" % name)
81
-        # Broken test for callable
93
+        ##
94
+        # @todo Broken test for callable.
82 95
         if not inspect.isfunction(callback) and not inspect.ismethod(callback) and not hasattr(callback, '__call__'):
83 96
             raise TypeError("Callable expected but got %s" % type(callback))
84 97
         cls._validators[name] = callback
85 98
         cls._description[name] = description
86 99
 
100
+    ##
87 101
     # @brief Get the validator list associated with description
88 102
     @classmethod
89 103
     def validators_list(cls):
90 104
         return copy.copy(cls._description)
91 105
 
92
-    # @brief Create and register a list validator
93
-    # @param elt_validator callable : The validator that will be used for validate each elt value
94
-    # @param validator_name str
95
-    # @param description None | str
96
-    # @param separator str : The element separator
97
-    # @return A Validator instance
106
+    ##
107
+    # @brief Creates and registers an iterative list validator
108
+    #
109
+    # @param elt_validator callable: The validator that will be used to validate
110
+    #         each of the list values.
111
+    # @param validator_name string:
112
+    # @param description None | string:
113
+    # @param separator string: The element separator.
114
+    # @return A Validator instance.
98 115
     @classmethod
99 116
     def create_list_validator(cls, validator_name, elt_validator, description=None, separator=','):
100 117
         def list_validator(value):
@@ -111,11 +128,14 @@ class Validator(MlNamedObject):
111 128
         cls.register_validator(validator_name, list_validator, description)
112 129
         return cls(validator_name)
113 130
 
114
-    # @brief Create and register a list validator which reads an array and returns a string
115
-    # @param elt_validator callable : The validator that will be used for validate each elt value
116
-    # @param validator_name str
117
-    # @param description None | str
118
-    # @param separator str : The element separator
131
+    ##
132
+    # @brief Creates and registers a list validator that reads an array
133
+    #        and returns a string
134
+    # @param elt_validator callable: The validator that will be used to validate
135
+    #        each elt value
136
+    # @param validator_name string:
137
+    # @param description None | string:
138
+    # @param separator string: The element separator
119 139
     # @return A Validator instance
120 140
     @classmethod
121 141
     def create_write_list_validator(cls, validator_name, elt_validator, description=None, separator=','):
@@ -128,10 +148,12 @@ class Validator(MlNamedObject):
128 148
         cls.register_validator(validator_name, write_list_validator, description)
129 149
         return cls(validator_name)
130 150
 
151
+    ##
131 152
     # @brief Create and register a regular expression validator
132
-    # @param pattern str : regex pattern
133
-    # @param validator_name str : The validator name
134
-    # @param description str : Validator description
153
+    #
154
+    # @param pattern str: regex pattern
155
+    # @param validator_name str: The validator name
156
+    # @param description str: Validator description
135 157
     # @return a Validator instance
136 158
     @classmethod
137 159
     def create_re_validator(cls, pattern, validator_name, description=None):
@@ -147,7 +169,8 @@ class Validator(MlNamedObject):
147 169
                                if description is None else description)
148 170
         return cls(validator_name)
149 171
 
150
-    #  @return a list of registered validators
172
+    ##
173
+    #  @return The list of registered validators.
151 174
     @classmethod
152 175
     def validators_list_str(cls):
153 176
         result = ''
@@ -158,16 +181,20 @@ class Validator(MlNamedObject):
158 181
             result += "\n"
159 182
         return result
160 183
 
161
-# @brief Integer value validator callback
162
-
163 184
 
185
+##
186
+# @brief Integer value validator callback
187
+#
188
+# @remarks Is it intended that this function simply tries casting to an integer?
189
+#            Is it also intended that it does not use any try/catch block?
164 190
 def int_val(value):
165 191
     return int(value)
166 192
 
193
+
194
+##
167 195
 # @brief Output file validator callback
196
+#
168 197
 # @return A file object (if filename is '-' return sys.stderr)
169
-
170
-
171 198
 def file_err_output(value):
172 199
     if not isinstance(value, str):
173 200
         raise ValidationError("A string was expected but got '%s' " % value)
@@ -175,9 +202,9 @@ def file_err_output(value):
175 202
         return None
176 203
     return value
177 204
 
178
-# @brief Boolean value validator callback
179
-
180 205
 
206
+##
207
+# @brief Boolean validator callback
181 208
 def boolean_val(value):
182 209
     if isinstance(value, bool):
183 210
         return value
@@ -189,18 +216,18 @@ def boolean_val(value):
189 216
         raise ValidationError("A boolean was expected but got '%s' " % value)
190 217
     return bool(value)
191 218
 
192
-# @brief Validate a directory path
193
-
194 219
 
220
+##
221
+# @brief Validate a directory path
195 222
 def directory_val(value):
196 223
     res = Validator('strip')(value)
197 224
     if not os.path.isdir(res):
198 225
         raise ValidationError("Following path don't exists or is not a directory : '%s'" % res)
199 226
     return res
200 227
 
201
-# @brief Validate a loglevel value
202
-
203 228
 
229
+##
230
+# @brief Validates a loglevel value
204 231
 def loglevel_val(value):
205 232
     valids = ['DEBUG', 'INFO', 'WARNING', 'SECURITY', 'ERROR', 'CRITICAL']
206 233
     if value.upper() not in valids:
@@ -208,44 +235,49 @@ def loglevel_val(value):
208 235
             "The value '%s' is not a valid loglevel" % value)
209 236
     return value.upper()
210 237
 
211
-# @brief Validate a path
212
-
213 238
 
239
+##
240
+# @brief Validates a path
241
+#
242
+# @remarks is it intended to have both @ref directory_val and this function
243
+#            right here?
214 244
 def path_val(value):
215 245
     if value is None or not os.path.exists(value):
216 246
         raise ValidationError(
217 247
             "path '%s' doesn't exists" % value)
218 248
     return value
219 249
 
220
-# @brief Validate None
221
-
222 250
 
251
+##
252
+# @brief Validates None
253
+#
254
+# @remarks Purpose?
223 255
 def none_val(value):
224 256
     if value is None:
225 257
         return None
226 258
     raise ValidationError("This settings cannot be set in configuration file")
227 259
 
228
-# @brief Validate a string
229
-
230 260
 
261
+##
262
+# @brief Validates a string
231 263
 def str_val(value):
232 264
     try:
233 265
         return str(value)
234 266
     except Exception as exp:
235 267
         raise ValidationError("Can't to convert value to string: " + str(exp))
236 268
 
237
-# @brief Validate using a regex
238
-
239 269
 
270
+##
271
+# @brief Validate using a regex
240 272
 def regex_val(value, pattern):
241 273
     if re.match(pattern, value) is None:
242 274
         raise ValidationError("The value '%s' is not validated by : \
243 275
 r\"%s\"" % (value, pattern))
244 276
     return value
245 277
 
246
-# @brief Validate a hostname (ipv4 or ipv6)
247
-
248 278
 
279
+##
280
+# @brief Validate a hostname (ipv4 or ipv6)
249 281
 def host_val(value):
250 282
     if value == 'localhost':
251 283
         return value
@@ -275,67 +307,52 @@ def custom_list_validator(value, validator_name, validator_kwargs=None):
275 307
         validator(item)
276 308
     return value.split()
277 309
 
310
+
278 311
 #
279 312
 #   Default validators registration
280 313
 #
281
-
282 314
 Validator.register_validator('custom_list', custom_list_validator,
283 315
                              'A list validator that takes a "validator_name" as argument')
284
-
285 316
 Validator.register_validator('dummy', lambda value: value, 'Validate anything')
286
-
287 317
 Validator.register_validator('none', none_val, 'Validate None')
288
-
289 318
 Validator.register_validator('string', str_val, 'Validate string values')
290
-
291 319
 Validator.register_validator('strip', str.strip, 'String trim')
292
-
293 320
 Validator.register_validator('int', int_val, 'Integer value validator')
294
-
295 321
 Validator.register_validator('bool', boolean_val, 'Boolean value validator')
296
-
297 322
 Validator.register_validator('errfile', file_err_output,
298 323
                              'Error output file validator (return stderr if filename is "-")')
299
-
300 324
 Validator.register_validator('directory', directory_val,
301 325
                              'Directory path validator')
302
-
303 326
 Validator.register_validator('loglevel', loglevel_val, 'Loglevel validator')
304
-
305 327
 Validator.register_validator('path', path_val, 'path validator')
306
-
307 328
 Validator.register_validator('host', host_val, 'host validator')
308
-
309 329
 Validator.register_validator('regex', regex_val,
310 330
                              'RegEx name validator (take re as argument)')
311
-
312 331
 Validator.create_list_validator('list', Validator('strip'), description="Simple list validator. Validate a list of values separated by ','",
313 332
                                 separator=',')
314
-
315 333
 Validator.create_list_validator(
316 334
     'directory_list',
317 335
     Validator('directory'),
318 336
     description="Validator for a list of directory path separated with ','",
319 337
     separator=',')
320
-
321 338
 Validator.create_write_list_validator(
322 339
     'write_list',
323 340
     Validator('directory'),
324 341
     description="Validator for an array of values \
325 342
         which will be set in a string, separated by ','",
326 343
     separator=',')
327
-
328 344
 Validator.create_re_validator(
329 345
     r'^https?://[^\./]+.[^\./]+/?.*$',
330 346
     'http_url',
331 347
     'Url validator')
332 348
 
333
-# @brief Validator for Editorial model component
334
-#
335
-# Designed to validate a conf that indicate a class.field in an EM
336
-#@todo modified the hardcoded dyncode import (it's a warning)
337
-
338 349
 
350
+##
351
+# @brief Validator for Editorial Model components.
352
+#
353
+# Designed to validate a conf that indicates a class.field in an EM
354
+#
355
+# @todo modify the hardcoded dyncode import (it's a warning)
339 356
 def emfield_val(value):
340 357
     LodelContext.expose_modules(globals(),
341 358
                                 {'lodel.plugin.hooks': ['LodelHook']})
@@ -359,11 +376,11 @@ def emfield_val(value):
359 376
             raise ValidationError(msg % value)
360 377
     return value
361 378
 
362
-# @brief Validator for plugin name & optionnaly type
379
+
380
+##
381
+# @brief Validator for plugin name & its type optionally
363 382
 #
364 383
 # Able to check that the value is a plugin and if it is of a specific type
365
-
366
-
367 384
 def plugin_validator(value, ptype=None):
368 385
     if value:
369 386
         LodelContext.expose_modules(globals(), {
@@ -396,26 +413,25 @@ Validator.register_validator(
396 413
     'plugin',
397 414
     plugin_validator,
398 415
     'plugin name & type validator')
399
-
400 416
 Validator.register_validator(
401 417
     'emfield',
402 418
     emfield_val,
403 419
     'EmField name validator')
404 420
 
405
-#
421
+
422
+##
406 423
 #   Lodel 2 configuration specification
407 424
 #
408
-
409 425
 # @brief Append a piece of confspec
410
-#@note orig is modified during the process
411
-#@param orig dict : the confspec to update
412
-#@param section str : section name
413
-#@param key str
414
-#@param validator Validator : the validator to use to check this configuration key's value
415
-#@param default
416
-#@return new confspec
417
-
418
-
426
+#
427
+# @param orig dict : the confspec to update
428
+# @param section str : section name
429
+# @param key str
430
+# @param validator Validator : the validator to use to check this configuration key's value
431
+# @param default
432
+# @return new confspec
433
+#
434
+# @note orig is modified during the process
419 435
 def confspec_append(orig, section, key, validator, default):
420 436
     if section not in orig:
421 437
         orig[section] = dict()
@@ -423,6 +439,8 @@ def confspec_append(orig, section, key, validator, default):
423 439
         orig[section][key] = (default, validator)
424 440
     return orig
425 441
 
442
+
443
+##
426 444
 # @brief Global specifications for lodel2 settings
427 445
 LODEL2_CONF_SPECS = {
428 446
     'lodel2': {

Loading…
Cancel
Save