Browse Source

List of DataHandlers

prieto 7 years ago
parent
commit
a8577a7f2f
2 changed files with 75 additions and 63 deletions
  1. 7
    0
      lodel/editorial_model/model.py
  2. 68
    63
      lodel/leapi/datahandlers/base_classes.py

+ 7
- 0
lodel/editorial_model/model.py View File

@@ -11,6 +11,7 @@ LodelContext.expose_modules(globals(), {
11 11
     'lodel.logger': 'logger',
12 12
     'lodel.settings': ['Settings'],
13 13
     'lodel.settings.utils': ['SettingsError'],
14
+    'lodel.leapi.datahandlers.base_classes': ['DataHandler'],
14 15
     'lodel.editorial_model.exceptions': ['EditorialModelError', 'assert_edit'],
15 16
     'lodel.editorial_model.components': ['EmClass', 'EmField', 'EmGroup']})
16 17
 
@@ -275,3 +276,9 @@ class EditorialModel(MlNamedObject):
275 276
             hashlib.md5(bytes(payload, 'utf-8')).digest(),
276 277
             byteorder='big'
277 278
         )
279
+
280
+    # @brief Returns a list of all datahandlers
281
+    # @return a list of all datahandlers
282
+    @staticmethod
283
+    def list_datahandlers():
284
+        return DataHandler.list_data_handlers()

+ 68
- 63
lodel/leapi/datahandlers/base_classes.py View File

@@ -1,6 +1,6 @@
1 1
 #-*- coding: utf-8 -*-
2 2
 
3
-## @package lodel.leapi.datahandlers.base_classes Define all base/abstract class for data handlers
3
+#  @package lodel.leapi.datahandlers.base_classes Define all base/abstract class for data handlers
4 4
 #
5 5
 # Contains custom exceptions too
6 6
 
@@ -31,14 +31,14 @@ LodelContext.expose_modules(globals(), {
31 31
     'lodel.utils.mlstring': ['MlString']})
32 32
 
33 33
 
34
-## @brief Base class for all data handlers
34
+# @brief Base class for all data handlers
35 35
 # @ingroup lodel2_datahandlers
36 36
 class DataHandler(MlNamedObject):
37 37
     base_type = "type"
38 38
     _HANDLERS_MODULES = ('datas_base', 'datas', 'references')
39
-    ## @brief Stores the DataHandler childs classes indexed by name
39
+    # @brief Stores the DataHandler childs classes indexed by name
40 40
     _base_handlers = None
41
-    ## @brief Stores custom datahandlers classes indexed by name
41
+    # @brief Stores custom datahandlers classes indexed by name
42 42
     # @todo do it ! (like plugins, register handlers... blablabla)
43 43
     __custom_handlers = dict()
44 44
 
@@ -47,12 +47,12 @@ class DataHandler(MlNamedObject):
47 47
     options_spec = dict()
48 48
     options_values = dict()
49 49
 
50
-    ## @brief List fields that will be exposed to the construct_data_method
50
+    # @brief List fields that will be exposed to the construct_data_method
51 51
     _construct_datas_deps = []
52 52
 
53 53
     directly_editable = True
54 54
 
55
-    ## @brief constructor
55
+    # @brief constructor
56 56
     #
57 57
     # @param internal False | str : define whether or not a field is internal
58 58
     # @param immutable bool : indicates if the fieldtype has to be defined in child classes of
@@ -76,11 +76,11 @@ class DataHandler(MlNamedObject):
76 76
             setattr(self, argname, argval)
77 77
         self.check_options()
78 78
 
79
-        display_name = kwargs.get('display_name',MlString(self.display_name))
79
+        display_name = kwargs.get('display_name', MlString(self.display_name))
80 80
         help_text = kwargs.get('help_text', MlString(self.help_text))
81 81
         super().__init__(display_name, help_text)
82 82
 
83
-    ## @brief Sets properly casted and checked options for the datahandler
83
+    # @brief Sets properly casted and checked options for the datahandler
84 84
     # @raises LodelDataHandlerNotAllowedOptionException when a passed option is not in the option
85 85
     # specifications of the datahandler
86 86
     def check_options(self):
@@ -96,7 +96,7 @@ class DataHandler(MlNamedObject):
96 96
                 # This option was not configured, we get the default value from the specs
97 97
                 self.options_values[option_name] = option_datas[0]
98 98
 
99
-    ## Fieldtype name
99
+    # Fieldtype name
100 100
     @classmethod
101 101
     def name(cls):
102 102
         return cls.__module__.split('.')[-1]
@@ -112,12 +112,12 @@ class DataHandler(MlNamedObject):
112 112
     def is_primary_key(self):
113 113
         return self.primary_key
114 114
 
115
-    ## @brief checks if a fieldtype is internal
115
+    # @brief checks if a fieldtype is internal
116 116
     # @return bool
117 117
     def is_internal(self):
118 118
         return self.internal is not False
119 119
 
120
-    ## @brief check if a value can be nullable
120
+    # @brief check if a value can be nullable
121 121
     # @param value *
122 122
     # @throw DataNoneValid if value is None and nullable. LodelExceptions if not nullable
123 123
     # @return value (if not None)
@@ -129,7 +129,7 @@ class DataHandler(MlNamedObject):
129 129
             raise DataNoneValid("None with a nullable. This exeption is allowed")
130 130
         return value
131 131
 
132
-    ## @brief calls the data_field (defined in derived class) _check_data_value() method
132
+    # @brief calls the data_field (defined in derived class) _check_data_value() method
133 133
     # @param value *
134 134
     # @return tuple (value|None, None|error) value can be cast if NoneError
135 135
     def check_data_value(self, value):
@@ -141,7 +141,7 @@ class DataHandler(MlNamedObject):
141 141
             return None, expt
142 142
         return value, None
143 143
 
144
-    ## @brief checks if this class can override the given data handler
144
+    # @brief checks if this class can override the given data handler
145 145
     # @param data_handler DataHandler
146 146
     # @return bool
147 147
     def can_override(self, data_handler):
@@ -149,7 +149,7 @@ class DataHandler(MlNamedObject):
149 149
             return False
150 150
         return True
151 151
 
152
-    ## @brief Build field value
152
+    # @brief Build field value
153 153
     # @ingroup lodel2_dh_checks
154 154
     # @warning DO NOT REIMPLEMENT THIS METHOD IN A CUSTOM DATAHANDLER (see
155 155
     # @ref _construct_data() and @ref lodel2_dh_check_impl )
@@ -174,7 +174,7 @@ class DataHandler(MlNamedObject):
174 174
             new_val = None
175 175
         return self._construct_data(emcomponent, fname, datas, new_val)
176 176
 
177
-    ## @brief Designed to be reimplemented by child classes
177
+    # @brief Designed to be reimplemented by child classes
178 178
     # @param emcomponent EmComponent : An EmComponent child class instance
179 179
     # @param fname str : The field name
180 180
     # @param datas dict : dict storing fields values (from the component)
@@ -184,7 +184,7 @@ class DataHandler(MlNamedObject):
184 184
     def _construct_data(self, empcomponent, fname, datas, cur_value):
185 185
         return cur_value
186 186
 
187
-    ## @brief Check datas consistency
187
+    # @brief Check datas consistency
188 188
     # @ingroup lodel2_dh_checks
189 189
     # @warning DO NOT REIMPLEMENT THIS METHOD IN A CUSTOM DATAHANDLER (see
190 190
     # @ref _construct_data() and @ref lodel2_dh_check_impl )
@@ -199,7 +199,7 @@ class DataHandler(MlNamedObject):
199 199
     def check_data_consistency(self, emcomponent, fname, datas):
200 200
         return self._check_data_consistency(emcomponent, fname, datas)
201 201
 
202
-    ## @brief Designed to be reimplemented by child classes
202
+    # @brief Designed to be reimplemented by child classes
203 203
     # @param emcomponent EmComponent : An EmComponent child class instance
204 204
     # @param fname : the field name
205 205
     # @param datas dict : dict storing fields values
@@ -208,7 +208,7 @@ class DataHandler(MlNamedObject):
208 208
     def _check_data_consistency(self, emcomponent, fname, datas):
209 209
         return True
210 210
 
211
-    ## @brief make consistency after a query
211
+    # @brief make consistency after a query
212 212
     # @param emcomponent EmComponent : An EmComponent child class instance
213 213
     # @param fname : the field name
214 214
     # @param datas dict : dict storing fields values
@@ -217,7 +217,7 @@ class DataHandler(MlNamedObject):
217 217
     def make_consistency(self, emcomponent, fname, datas):
218 218
         pass
219 219
 
220
-    ## @brief This method is use by plugins to register new data handlers
220
+    # @brief This method is use by plugins to register new data handlers
221 221
     @classmethod
222 222
     def register_new_handler(cls, name, data_handler):
223 223
         if not inspect.isclass(data_handler):
@@ -226,7 +226,7 @@ class DataHandler(MlNamedObject):
226 226
             raise ValueError("A data handler HAS TO be a child class of DataHandler")
227 227
         cls.__custom_handlers[name] = data_handler
228 228
 
229
-    ## @brief Load all datahandlers
229
+    # @brief Load all datahandlers
230 230
     @classmethod
231 231
     def load_base_handlers(cls):
232 232
         if cls._base_handlers is None:
@@ -239,7 +239,7 @@ class DataHandler(MlNamedObject):
239 239
                         cls._base_handlers[name.lower()] = obj
240 240
         return copy.copy(cls._base_handlers)
241 241
 
242
-    ## @brief given a field type name, returns the associated python class
242
+    # @brief given a field type name, returns the associated python class
243 243
     # @param fieldtype_name str : A field type name (not case sensitive)
244 244
     # @return DataField child class
245 245
     # @note To access custom data handlers it can be cool to prefix the handler name by plugin
@@ -254,23 +254,22 @@ class DataHandler(MlNamedObject):
254 254
         return all_handlers[name]
255 255
 
256 256
     # @brief List all datahandlers
257
-    # @return a dict with, display_name for keys, and a dict for value 
257
+    # @return a dict with, display_name for keys, and a dict for value
258 258
     @classmethod
259 259
     def list_data_handlers(cls):
260 260
         cls.load_base_handlers()
261 261
         all_handlers = dict(cls._base_handlers, **cls.__custom_handlers)
262 262
         list_dh = dict()
263 263
         for hdl in all_handlers:
264
-            list_dh[hdl.display_name] = {'help_text' : hdl.help_text,
265
-                            'nullable' : hdl.nullable, \
266
-                            'internal' : hdl.internal,
267
-                            'immutable' : hdl.immutable, \
268
-                            'primary_key' : hdl.primary_key, \
269
-                            'options' : self.options_spec}
264
+            options = dict({'nullable': hdl.nullable,
265
+                            'internal': hdl.internal,
266
+                            'immutable': hdl.immutable,
267
+                            'primary_key': hdl.primary_key}, hdl.options_spec)
268
+            list_dh[hdl.display_name] = {'help_text': hdl.help_text, 'options': options}
270 269
 
271 270
         return list_dh
272 271
 
273
-    ## @brief Return the module name to import in order to use the datahandler
272
+    # @brief Return the module name to import in order to use the datahandler
274 273
     # @param data_handler_name str : Data handler name
275 274
     # @return a str
276 275
     @classmethod
@@ -282,20 +281,22 @@ class DataHandler(MlNamedObject):
282 281
             class_name=handler_class.__name__
283 282
         )
284 283
 
285
-    ## @brief __hash__ implementation for fieldtypes
284
+    # @brief __hash__ implementation for fieldtypes
286 285
     def __hash__(self):
287 286
         hash_dats = [self.__class__.__module__]
288 287
         for kdic in sorted([k for k in self.__dict__.keys() if not k.startswith('_')]):
289 288
             hash_dats.append((kdic, getattr(self, kdic)))
290 289
         return hash(tuple(hash_dats))
291 290
 
292
-## @brief Base class for datas data handler (by opposition with references)
291
+# @brief Base class for datas data handler (by opposition with references)
293 292
 # @ingroup lodel2_datahandlers
293
+
294
+
294 295
 class DataField(DataHandler):
295 296
     pass
296 297
 
297 298
 
298
-## @brief Abstract class for all references
299
+# @brief Abstract class for all references
299 300
 # @ingroup lodel2_datahandlers
300 301
 #
301 302
 # References are fields that stores a reference to another
@@ -304,7 +305,7 @@ class DataField(DataHandler):
304 305
 class Reference(DataHandler):
305 306
     base_type = "ref"
306 307
 
307
-    ## @brief Instanciation
308
+    # @brief Instanciation
308 309
     # @param allowed_classes list | None : list of allowed em classes if None no restriction
309 310
     # @param back_reference tuple | None : tuple containing (LeObject child class, fieldname)
310 311
     # @param internal bool : if False, the field is not internal
@@ -315,7 +316,8 @@ class Reference(DataHandler):
315 316
         self.allowed_classes = list() if allowed_classes is None else allowed_classes
316 317
         if back_reference is not None:
317 318
             if len(back_reference) != 2:
318
-                raise ValueError("A tuple (classname, fieldname) expected but got '%s'" % back_reference)
319
+                raise ValueError(
320
+                    "A tuple (classname, fieldname) expected but got '%s'" % back_reference)
319 321
             # if not issubclass(lodel.leapi.leobject.LeObject, back_reference[0])
320 322
             # or not isinstance(back_reference[1], str):
321 323
             # raise TypeError("Back reference was expected to be a tuple(<class LeObject>, str)
@@ -323,18 +325,18 @@ class Reference(DataHandler):
323 325
         self.__back_reference = back_reference
324 326
         super().__init__(internal=internal, **kwargs)
325 327
 
326
-    ## @brief Method designed to return an empty value for this kind of
328
+    # @brief Method designed to return an empty value for this kind of
327 329
     # multipleref
328 330
     @classmethod
329 331
     def empty(cls):
330 332
         return None
331 333
 
332
-    ## @brief Property that takes value of a copy of the back_reference tuple
334
+    # @brief Property that takes value of a copy of the back_reference tuple
333 335
     @property
334 336
     def back_reference(self):
335 337
         return copy.copy(self.__back_reference)
336 338
 
337
-    ## @brief Property that takes value of datahandler of the backreference or
339
+    # @brief Property that takes value of datahandler of the backreference or
338 340
     # None
339 341
     @property
340 342
     def back_ref_datahandler(self):
@@ -346,11 +348,11 @@ class Reference(DataHandler):
346 348
     def linked_classes(self):
347 349
         return copy.copy(self.__allowed_classes)
348 350
 
349
-    ## @brief Set the back reference for this field.
351
+    # @brief Set the back reference for this field.
350 352
     def _set_back_reference(self, back_reference):
351 353
         self.__back_reference = back_reference
352 354
 
353
-    ## @brief Check and cast value in appropriate type
355
+    # @brief Check and cast value in appropriate type
354 356
     # @param value *
355 357
     # @throw FieldValidationError if value is an appropriate type
356 358
     # @return value
@@ -362,14 +364,15 @@ class Reference(DataHandler):
362 364
                 issubclass(value.__class__, LeObject)):
363 365
             if self.__allowed_classes:
364 366
                 rcls = list(self.__allowed_classes)[0]
365
-                uidname = rcls.uid_fieldname()[0]# TODO multiple uid is broken
367
+                uidname = rcls.uid_fieldname()[0]  # TODO multiple uid is broken
366 368
                 uiddh = rcls.data_handler(uidname)
367 369
                 value = uiddh._check_data_value(value)
368 370
             else:
369
-                raise FieldValidationError("Reference datahandler can not check this value %s if any allowed_class is allowed." % value)
371
+                raise FieldValidationError(
372
+                    "Reference datahandler can not check this value %s if any allowed_class is allowed." % value)
370 373
         return value
371 374
 
372
-    ## @brief Check datas consistency
375
+    # @brief Check datas consistency
373 376
     # @param emcomponent EmComponent : An EmComponent child class instance
374 377
     # @param fname : the field name
375 378
     # @param datas dict : dict storing fields values
@@ -398,14 +401,14 @@ class Reference(DataHandler):
398 401
         #    return False
399 402
         return True
400 403
 
401
-    ## @brief Utility method designed to fetch referenced objects
404
+    # @brief Utility method designed to fetch referenced objects
402 405
     # @param value mixed : the field value
403 406
     # @throw NotImplementedError
404 407
     def get_referenced(self, value):
405 408
         raise NotImplementedError
406 409
 
407 410
 
408
-## @brief This class represent a data_handler for single reference to another object
411
+# @brief This class represent a data_handler for single reference to another object
409 412
 #
410 413
 # The fields using this data handlers are like "foreign key" on another object
411 414
 class SingleRef(Reference):
@@ -413,8 +416,7 @@ class SingleRef(Reference):
413 416
     def __init__(self, allowed_classes=None, **kwargs):
414 417
         super().__init__(allowed_classes=allowed_classes, **kwargs)
415 418
 
416
-
417
-    ## @brief Check and cast value in appropriate type
419
+    # @brief Check and cast value in appropriate type
418 420
     # @param value: *
419 421
     # @throw FieldValidationError if value is unappropriate or can not be cast
420 422
     # @return value
@@ -422,7 +424,7 @@ class SingleRef(Reference):
422 424
         value = super()._check_data_value(value)
423 425
         return value
424 426
 
425
-    ## @brief Utility method designed to fetch referenced objects
427
+    # @brief Utility method designed to fetch referenced objects
426 428
     # @param value mixed : the field value
427 429
     # @return A LeObject child class instance
428 430
     # @throw LodelDataHandlerConsistencyException if no referenced object found
@@ -435,26 +437,26 @@ class SingleRef(Reference):
435 437
 referenced object with uid %s" % value)
436 438
 
437 439
 
438
-## @brief This class represent a data_handler for multiple references to another object
440
+# @brief This class represent a data_handler for multiple references to another object
439 441
 # @ingroup lodel2_datahandlers
440 442
 #
441 443
 # The fields using this data handlers are like SingleRef but can store multiple references in one field
442 444
 # @note for the moment split on ',' chars
443 445
 class MultipleRef(Reference):
444 446
 
445
-    ## @brief Constructor
447
+    # @brief Constructor
446 448
     # @param max_item int | None : indicate the maximum number of item referenced by this field, None mean no limit
447 449
     def __init__(self, max_item=None, **kwargs):
448 450
         self.max_item = max_item
449 451
         super().__init__(**kwargs)
450 452
 
451
-    ## @brief Method designed to return an empty value for this kind of
453
+    # @brief Method designed to return an empty value for this kind of
452 454
     # multipleref
453 455
     @classmethod
454 456
     def empty(cls):
455 457
         return []
456 458
 
457
-    ## @brief Check and cast value in appropriate type
459
+    # @brief Check and cast value in appropriate type
458 460
     # @param value *
459 461
     # @throw FieldValidationError if value is unappropriate or can not be cast
460 462
     # @return value
@@ -462,7 +464,8 @@ class MultipleRef(Reference):
462 464
     def _check_data_value(self, value):
463 465
         value = DataHandler._check_data_value(self, value)
464 466
         if not hasattr(value, '__iter__'):
465
-            raise FieldValidationError("MultipleRef has to be an iterable or a string, '%s' found" % value)
467
+            raise FieldValidationError(
468
+                "MultipleRef has to be an iterable or a string, '%s' found" % value)
466 469
         if self.max_item is not None:
467 470
             if self.max_item < len(value):
468 471
                 raise FieldValidationError("Too many items")
@@ -475,10 +478,11 @@ class MultipleRef(Reference):
475 478
             except (FieldValidationError):
476 479
                 error_list.append(repr(v))
477 480
         if len(error_list) > 0:
478
-            raise FieldValidationError("MultipleRef have for invalid values [%s]  :" % (",".join(error_list)))
481
+            raise FieldValidationError(
482
+                "MultipleRef have for invalid values [%s]  :" % (",".join(error_list)))
479 483
         return new_val
480 484
 
481
-    ## @brief Utility method designed to fetch referenced objects
485
+    # @brief Utility method designed to fetch referenced objects
482 486
     # @param values mixed : the field values
483 487
     # @return A list of LeObject child class instance
484 488
     # @throw LodelDataHandlerConsistencyException if some referenced objects
@@ -501,7 +505,7 @@ class MultipleRef(Reference):
501 505
 some referenced objects. Following uids were not found : %s" % ','.join(left))
502 506
 
503 507
 
504
-## @brief Class designed to handle datas access will fieldtypes are constructing datas
508
+#  @brief Class designed to handle datas access will fieldtypes are constructing datas
505 509
 # @ingroup lodel2_datahandlers
506 510
 #
507 511
 # This class is designed to allow automatic scheduling of construct_data calls.
@@ -511,7 +515,7 @@ some referenced objects. Following uids were not found : %s" % ','.join(left))
511 515
 # @todo test circular deps false positive
512 516
 class DatasConstructor(object):
513 517
 
514
-    ## @brief Init a DatasConstructor
518
+    # @brief Init a DatasConstructor
515 519
     # @param leobject LeCrud : @ref LeObject child class
516 520
     # @param datas dict : dict with field name as key and field values as value
517 521
     # @param fields_handler dict : dict with field name as key and data handler instance as value
@@ -527,31 +531,32 @@ class DatasConstructor(object):
527 531
         # Stores construct calls list
528 532
         self._construct_calls = []
529 533
 
530
-    ## @brief Implements the dict.keys() method on instance
534
+    # @brief Implements the dict.keys() method on instance
531 535
     def keys(self):
532 536
         return self._datas.keys()
533 537
 
534
-    ## @brief Allows to access the instance like a dict
538
+    #  @brief Allows to access the instance like a dict
535 539
     def __getitem__(self, fname):
536 540
         if fname not in self._constructed:
537 541
             if fname in self._construct_calls:
538 542
                 raise RuntimeError('Probably circular dependencies in fieldtypes')
539 543
             cur_value = self._datas[fname] if fname in self._datas else None
540
-            self._datas[fname] = self._fields_handler[fname].construct_data(self._leobject, fname, self, cur_value)
544
+            self._datas[fname] = self._fields_handler[fname].construct_data(
545
+                self._leobject, fname, self, cur_value)
541 546
             self._constructed.append(fname)
542 547
         return self._datas[fname]
543 548
 
544
-    ## @brief Allows to set instance values like a dict
549
+    # @brief Allows to set instance values like a dict
545 550
     # @warning Should not append in theory
546 551
     def __setitem__(self, fname, value):
547 552
         self._datas[fname] = value
548 553
         warnings.warn("Setting value of an DatasConstructor instance")
549 554
 
550 555
 
551
-## @brief Class designed to handle an option of a DataHandler
556
+# @brief Class designed to handle an option of a DataHandler
552 557
 class DatahandlerOption(MlNamedObject):
553 558
 
554
-    ## @brief instanciates a new Datahandler option object
559
+    # @brief instanciates a new Datahandler option object
555 560
     #
556 561
     # @param id str
557 562
     # @param display_name MlString
@@ -566,7 +571,7 @@ class DatahandlerOption(MlNamedObject):
566 571
     def id(self):
567 572
         return self.__id
568 573
 
569
-    ## @brief checks a value corresponding to this option is valid
574
+    # @brief checks a value corresponding to this option is valid
570 575
     # @param value
571 576
     # @return casted value
572 577
     def check_value(self, value):

Loading…
Cancel
Save