Browse Source

DataHandlers documentation

Quentin Bonaventure 7 years ago
parent
commit
7c94b9f7a4
1 changed files with 279 additions and 85 deletions
  1. 279
    85
      lodel/leapi/datahandlers/base_classes.py

+ 279
- 85
lodel/leapi/datahandlers/base_classes.py View File

@@ -1,6 +1,7 @@
1 1
 #-*- coding: utf-8 -*-
2
-
3
-#  @package lodel.leapi.datahandlers.base_classes Define all base/abstract class for data handlers
2
+##
3
+#  @package lodel.leapi.datahandlers.base_classes Defines all base/abstract
4
+#            classes for DataHandlers
4 5
 #
5 6
 # Contains custom exceptions too
6 7
 
@@ -30,15 +31,33 @@ LodelContext.expose_modules(globals(), {
30 31
     'lodel.logger': 'logger',
31 32
     'lodel.utils.mlstring': ['MlString']})
32 33
 
33
-
34
-# @brief Base class for all data handlers
34
+##
35
+# @brief Base class for all DataHandlers
35 36
 # @ingroup lodel2_datahandlers
37
+#
38
+# @remarks Some of the methods and properties in this "abstract" class are 
39
+#            bounded to its children. This implies that the parent
40
+#            is aware of its children, which is an absolute anti-pattern
41
+#            (Liskov / OC violation), a source of confusion and a decrased
42
+#            maintainability. Aggregation =/= Inheritance
43
+#            Concerned methods are: is_reference; is_singlereference.
44
+#            Concerned properties are __custom_datahandlers; base_handlers.
45
+# @remarks What is the purpose of an internal property being set to a 
46
+#            string (namely 'automatic')
47
+# @remarks Two sets of methods appears a little strange in regards to their
48
+#            visibility.
49
+#            - @ref _construct_data / @ref construct_data
50
+#            - @ref _check_data_consistency / @ref check_data_consistency
36 51
 class DataHandler(MlNamedObject):
37 52
     base_type = "type"
38 53
     _HANDLERS_MODULES = ('datas_base', 'datas', 'references')
39
-    # @brief Stores the DataHandler childs classes indexed by name
54
+    
55
+    ##
56
+    # @brief Stores the DataHandler child classes indexed by name
40 57
     _base_handlers = None
41
-    # @brief Stores custom datahandlers classes indexed by name
58
+    
59
+    ##
60
+    # @brief Stores custom DataHandlers classes indexed by name
42 61
     # @todo do it ! (like plugins, register handlers... blablabla)
43 62
     __custom_handlers = dict()
44 63
 
@@ -47,17 +66,22 @@ class DataHandler(MlNamedObject):
47 66
     options_spec = dict()
48 67
     options_values = dict()
49 68
 
50
-    # @brief List fields that will be exposed to the construct_data_method
69
+    ##
70
+    # @brief Lists fields that will be exposed to the construct_data method
51 71
     _construct_datas_deps = []
52 72
 
53 73
     directly_editable = True
54 74
 
75
+
76
+    ##
55 77
     # @brief constructor
56 78
     #
57 79
     # @param internal False | str : define whether or not a field is internal
58
-    # @param immutable bool : indicates if the fieldtype has to be defined in child classes of
80
+    # @param immutable bool : Indicates if the fieldtype has to be defined in child classes of
59 81
     #                         LeObject or if it is designed globally and immutable
60
-    # @throw NotImplementedError if it is instanciated directly
82
+    # @throw NotImplementedError If it is instantiated directly
83
+    # @remarks Shouldn't the class be declared abstract? No need to check if it
84
+    #            is instantiated directly, no exception to throw, cleaner code.
61 85
     def __init__(self, **kwargs):
62 86
         if self.__class__ == DataHandler:
63 87
             raise NotImplementedError("Abstract class")
@@ -80,9 +104,12 @@ class DataHandler(MlNamedObject):
80 104
         help_text = kwargs.get('help_text', MlString(self.help_text))
81 105
         super().__init__(display_name, help_text)
82 106
 
83
-    # @brief Sets properly casted and checked options for the datahandler
84
-    # @raises LodelDataHandlerNotAllowedOptionException when a passed option is not in the option
85
-    # specifications of the datahandler
107
+
108
+    ##
109
+    # @brief Sets properly cast and checked options for the DataHandler
110
+    #
111
+    # @throw LodelDataHandlerNotAllowedOptionException when a passed option 
112
+    #            is not in the option specifications of the DataHandler
86 113
     def check_options(self):
87 114
         for option_name, option_datas in self.options_spec.items():
88 115
             if option_name in self.options_values:
@@ -96,42 +123,70 @@ class DataHandler(MlNamedObject):
96 123
                 # This option was not configured, we get the default value from the specs
97 124
                 self.options_values[option_name] = option_datas[0]
98 125
 
99
-    # Fieldtype name
126
+
127
+    ##
128
+    # @return string: Field type name
100 129
     @classmethod
101 130
     def name(cls):
102 131
         return cls.__module__.split('.')[-1]
103 132
 
133
+
134
+    ##
135
+    # @return bool: True if subclass is of Reference type, False otherwise.
104 136
     @classmethod
105 137
     def is_reference(cls):
106 138
         return issubclass(cls, Reference)
107 139
 
140
+
141
+    ##
142
+    # @return bool: True if subclass is of SingleRef type, False otherwise.
108 143
     @classmethod
109 144
     def is_singlereference(cls):
110 145
         return issubclass(cls, SingleRef)
111 146
 
147
+
148
+    ##
149
+    # @return bool: True if the field is a primary_key, False otherwise.
112 150
     def is_primary_key(self):
113 151
         return self.primary_key
114 152
 
115
-    # @brief checks if a fieldtype is internal
116
-    # @return bool
153
+
154
+    ##
155
+    # @brief checks if a field type is internal
156
+    # @return bool: True if the field is internal, False otherwise.
117 157
     def is_internal(self):
118 158
         return self.internal is not False
119 159
 
160
+
161
+    ##
120 162
     # @brief check if a value can be nullable
163
+    # 
121 164
     # @param value *
122
-    # @throw DataNoneValid if value is None and nullable. LodelExceptions if not nullable
165
+    # @throw DataNoneValid if value is None and nullable.
166
+    # @throw LodelExceptions if not nullable
123 167
     # @return value (if not None)
124 168
     # @return value
169
+    #
170
+    # @remarks why are there an thrown exception if it is allowed?
171
+    #            Exceptions are no message brokers
125 172
     def _check_data_value(self, value):
126 173
         if value is None:
127 174
             if not self.nullable:
128 175
                 raise LodelExceptions("None value is forbidden for this data field")
129
-            raise DataNoneValid("None with a nullable. This exeption is allowed")
176
+            raise DataNoneValid("None with a nullable. This exception is allowed")
130 177
         return value
131 178
 
179
+
180
+    ##
132 181
     # @brief calls the data_field (defined in derived class) _check_data_value() method
133 182
     # @param value *
134 183
     # @return tuple (value|None, None|error) value can be cast if NoneError
184
+    # @remarks Consider renaming this method, such as '_is_data_nullable'.
185
+    # @remarks Exceptions ARE NOT message brokers! Moreover, those two methods
186
+    #            are more complicated than required. In case 'value' is None,
187
+    #            the returned value is the same as the input value. This is the
188
+    #            same behavior as when the value is not None!
189
+    # @return What's a "NoneError"? Value can be cast to what?
135 190
     def check_data_value(self, value):
136 191
         try:
137 192
             value = self._check_data_value(value)
@@ -141,25 +196,36 @@ class DataHandler(MlNamedObject):
141 196
             return None, expt
142 197
         return value, None
143 198
 
144
-    # @brief checks if this class can override the given data handler
199
+    ##
200
+    # @brief Checks if this class can override the given data handler.
201
+    #        i.e. both class having the same base_type.  
145 202
     # @param data_handler DataHandler
146 203
     # @return bool
204
+    # @remarks Simplify by "return data_handler.__class__.base_type == self.__class__.base_type"?
147 205
     def can_override(self, data_handler):
148 206
         if data_handler.__class__.base_type != self.__class__.base_type:
149 207
             return False
150 208
         return True
151 209
 
210
+
211
+    ##
152 212
     # @brief Build field value
213
+    #
153 214
     # @ingroup lodel2_dh_checks
154
-    # @warning DO NOT REIMPLEMENT THIS METHOD IN A CUSTOM DATAHANDLER (see
155 215
     # @ref _construct_data() and @ref lodel2_dh_check_impl )
216
+    #
156 217
     # @param emcomponent EmComponent : An EmComponent child class instance
157 218
     # @param fname str : The field name
158 219
     # @param datas dict : dict storing fields values (from the component)
159 220
     # @param cur_value : the value from the current field (identified by fieldname)
160 221
     # @return the value
161 222
     # @throw RunTimeError if data construction fails
223
+    #
224
+    # @warning DO NOT REIMPLEMENT THIS METHOD IN A CUSTOM DATAHANDLER (see
162 225
     # @todo raise something else
226
+    #
227
+    # @remarks What the todo up right here means? Raise what? When?
228
+    # @remarks Nothing is being raised in this method, should it?
163 229
     def construct_data(self, emcomponent, fname, datas, cur_value):
164 230
         emcomponent_fields = emcomponent.fields()
165 231
         data_handler = None
@@ -174,50 +240,71 @@ class DataHandler(MlNamedObject):
174 240
             new_val = None
175 241
         return self._construct_data(emcomponent, fname, datas, new_val)
176 242
 
243
+
244
+    ##
177 245
     # @brief Designed to be reimplemented by child classes
246
+    #
178 247
     # @param emcomponent EmComponent : An EmComponent child class instance
179 248
     # @param fname str : The field name
180 249
     # @param datas dict : dict storing fields values (from the component)
181 250
     # @param cur_value : the value from the current field (identified by fieldname)
182 251
     # @return the value
183 252
     # @see construct_data() lodel2_dh_check_impl
184
-    def _construct_data(self, empcomponent, fname, datas, cur_value):
253
+    def _construct_data(self, emcomponent, fname, datas, cur_value):
185 254
         return cur_value
186 255
 
187
-    # @brief Check datas consistency
256
+
257
+    ##
258
+    # @brief Check data consistency
188 259
     # @ingroup lodel2_dh_checks
189
-    # @warning DO NOT REIMPLEMENT THIS METHOD IN A CUSTOM DATAHANDLER (see
190
-    # @ref _construct_data() and @ref lodel2_dh_check_impl )
191
-    # @warning the datas argument looks like a dict but is not a dict
192
-    # see @ref base_classes.DatasConstructor "DatasConstructor" and
193
-    # @ref lodel2_dh_datas_construction "Datas construction section"
260
+    #
261
+    # @ref lodel2_dh_datas_construction "Data construction section"
194 262
     # @param emcomponent EmComponent : An EmComponent child class instance
195 263
     # @param fname : the field name
196 264
     # @param datas dict : dict storing fields values
197 265
     # @return an Exception instance if fails else True
266
+    #
267
+    # @warning DO NOT REIMPLEMENT THIS METHOD IN A CUSTOM DATAHANDLER (see
268
+    #             @ref _construct_data() and @ref lodel2_dh_check_impl )
269
+    # @warning the data argument looks like a dict but is not a dict
270
+    #             see @ref base_classes.DatasConstructor "DatasConstructor" and
198 271
     # @todo A implémenter
199 272
     def check_data_consistency(self, emcomponent, fname, datas):
200 273
         return self._check_data_consistency(emcomponent, fname, datas)
201 274
 
275
+
276
+    ##
202 277
     # @brief Designed to be reimplemented by child classes
278
+    #
203 279
     # @param emcomponent EmComponent : An EmComponent child class instance
204 280
     # @param fname : the field name
205 281
     # @param datas dict : dict storing fields values
206 282
     # @return an Exception instance if fails else True
283
+    #
207 284
     # @see check_data_consistency() lodel2_dh_check_impl
208 285
     def _check_data_consistency(self, emcomponent, fname, datas):
209 286
         return True
210 287
 
211
-    # @brief make consistency after a query
288
+
289
+    ##
290
+    # @brief Makes consistency after a query
291
+    #
212 292
     # @param emcomponent EmComponent : An EmComponent child class instance
213 293
     # @param fname : the field name
214 294
     # @param datas dict : dict storing fields values
215 295
     # @return an Exception instance if fails else True
216
-    # @todo A implémenter
296
+    #
297
+    # @todo To be implemented
298
+    # @remarks It not clear what is the intent of this method... 
217 299
     def make_consistency(self, emcomponent, fname, datas):
218 300
         pass
219 301
 
220
-    # @brief This method is use by plugins to register new data handlers
302
+
303
+    ##
304
+    # @brief Registers a new data handlers
305
+    #
306
+    # @note Used by plugins.
307
+    # @remarks This method is actually never used anywhere. May consider removing it.
221 308
     @classmethod
222 309
     def register_new_handler(cls, name, data_handler):
223 310
         if not inspect.isclass(data_handler):
@@ -226,7 +313,9 @@ class DataHandler(MlNamedObject):
226 313
             raise ValueError("A data handler HAS TO be a child class of DataHandler")
227 314
         cls.__custom_handlers[name] = data_handler
228 315
 
229
-    # @brief Load all datahandlers
316
+
317
+    ##
318
+    # @brief Loads all DataHandlers
230 319
     @classmethod
231 320
     def load_base_handlers(cls):
232 321
         if cls._base_handlers is None:
@@ -239,22 +328,38 @@ class DataHandler(MlNamedObject):
239 328
                         cls._base_handlers[name.lower()] = obj
240 329
         return copy.copy(cls._base_handlers)
241 330
 
331
+
332
+    ##
242 333
     # @brief given a field type name, returns the associated python class
243
-    # @param fieldtype_name str : A field type name (not case sensitive)
334
+    #
335
+    # @param name str : A field type name (not case sensitive)
244 336
     # @return DataField child class
245
-    # @note To access custom data handlers it can be cool to prefix the handler name by plugin
246
-    # name for example ? (to ensure name unicity)
337
+    # @throw NameError
338
+    #
339
+    # @note Would not it be better to prefix the DataHandler name with the
340
+    #        plugin's one so that it is ensured names are unique? 
341
+    # @remarks "do/get what from name?" Consider renaming this method (e.g. 
342
+    #            'get_datafield_from_name')
247 343
     @classmethod
248 344
     def from_name(cls, name):
249 345
         cls.load_base_handlers()
250 346
         all_handlers = dict(cls._base_handlers, **cls.__custom_handlers)
251 347
         name = name.lower()
348
+        
252 349
         if name not in all_handlers:
253 350
             raise NameError("No data handlers named '%s'" % (name,))
254 351
         return all_handlers[name]
255 352
 
256
-    # @brief List all datahandlers
353
+
354
+    ##
355
+    # @brief List all DataHandlers
257 356
     # @return a dict with, display_name for keys, and a dict for value
357
+    # @remarks ATM, solely used by the EditorialModel.
358
+    # @remarks EditorialModel own class does nothing but calls this class.
359
+    #            Moreover, nothing calls it anyway.
360
+    # @remarks It also seems like it is an EM related concern, and has
361
+    #            nothing to do with this class. That list appears to be doing
362
+    #            a purely presentational job. Isn't that a serialization instead?
258 363
     @classmethod
259 364
     def list_data_handlers(cls):
260 365
         cls.load_base_handlers()
@@ -269,33 +374,39 @@ class DataHandler(MlNamedObject):
269 374
 
270 375
         return list_dh
271 376
 
272
-    # @brief Return the module name to import in order to use the datahandler
273
-    # @param data_handler_name str : Data handler name
274
-    # @return a str
377
+
378
+    ##
379
+    # @brief Return the module name to import in order to use the DataHandler
380
+    # @param datahandler_name str : Data handler name
381
+    # @return str
382
+    # @remarks consider renaming this (e.g. "datahandler_module_name")
275 383
     @classmethod
276
-    def module_name(cls, name):
277
-        name = name.lower()
278
-        handler_class = cls.from_name(name)
384
+    def module_name(cls, datahandler_name):
385
+        datahandler_name = datahandler_name.lower()
386
+        handler_class = cls.from_name(datahandler_name)
279 387
         return '{module_name}.{class_name}'.format(
280 388
             module_name=handler_class.__module__,
281 389
             class_name=handler_class.__name__
282 390
         )
283 391
 
284
-    # @brief __hash__ implementation for fieldtypes
392
+
393
+    ##
394
+    # @brief __hash__ implementation for field types
285 395
     def __hash__(self):
286 396
         hash_dats = [self.__class__.__module__]
287 397
         for kdic in sorted([k for k in self.__dict__.keys() if not k.startswith('_')]):
288 398
             hash_dats.append((kdic, getattr(self, kdic)))
289 399
         return hash(tuple(hash_dats))
290 400
 
291
-# @brief Base class for datas data handler (by opposition with references)
292
-# @ingroup lodel2_datahandlers
293
-
294 401
 
402
+##
403
+# @brief Base class for data data handler (by opposition with references)
404
+# @ingroup lodel2_datahandlers
295 405
 class DataField(DataHandler):
296 406
     pass
297 407
 
298 408
 
409
+##
299 410
 # @brief Abstract class for all references
300 411
 # @ingroup lodel2_datahandlers
301 412
 #
@@ -303,21 +414,31 @@ class DataField(DataHandler):
303 414
 # editorial object
304 415
 # @todo Construct data implementation : transform the data into a LeObject instance
305 416
 class Reference(DataHandler):
417
+    
306 418
     base_type = "ref"
307
-
308
-    # @brief Instanciation
419
+    
420
+    ##
421
+    # @brief Instantiation
309 422
     # @param allowed_classes list | None : list of allowed em classes if None no restriction
310
-    # @param back_reference tuple | None : tuple containing (LeObject child class, fieldname)
311
-    # @param internal bool : if False, the field is not internal
423
+    # @param back_reference tuple | None : tuple containing (LeObject child class, field name)
424
+    # @param internal bool | string: if False, the field is not internal
312 425
     # @param **kwargs : other arguments
426
+    # @throw ValueError
427
+    # @remarks internal may hold the string value 'automatic'. So far, nothing
428
+    #                mentions what that means, and nothing seems to be aware
429
+    #                of an 'automatic' value (at least not in leapi package)
313 430
     def __init__(self, allowed_classes=None, back_reference=None, internal=False, **kwargs):
314 431
         self.__allowed_classes = set() if allowed_classes is None else set(allowed_classes)
315
-        # For now usefull to jinja 2
432
+        ##
433
+        # @note what is "useful to Jinja 2"?
434
+        # For now useful to jinja 2
316 435
         self.allowed_classes = list() if allowed_classes is None else allowed_classes
317 436
         if back_reference is not None:
318 437
             if len(back_reference) != 2:
319 438
                 raise ValueError(
320 439
                     "A tuple (classname, fieldname) expected but got '%s'" % back_reference)
440
+            ##
441
+            # @note Why is there commented out code? Should it be deleted? Ractivated?
321 442
             # if not issubclass(lodel.leapi.leobject.LeObject, back_reference[0])
322 443
             # or not isinstance(back_reference[1], str):
323 444
             # raise TypeError("Back reference was expected to be a tuple(<class LeObject>, str)
@@ -325,17 +446,24 @@ class Reference(DataHandler):
325 446
         self.__back_reference = back_reference
326 447
         super().__init__(internal=internal, **kwargs)
327 448
 
449
+
450
+    ##
328 451
     # @brief Method designed to return an empty value for this kind of
329 452
     # multipleref
453
+    # @remarks purpose!?
330 454
     @classmethod
331 455
     def empty(cls):
332 456
         return None
333 457
 
458
+
459
+    ##
334 460
     # @brief Property that takes value of a copy of the back_reference tuple
335 461
     @property
336 462
     def back_reference(self):
337 463
         return copy.copy(self.__back_reference)
338 464
 
465
+
466
+    ##
339 467
     # @brief Property that takes value of datahandler of the backreference or
340 468
     # None
341 469
     @property
@@ -348,12 +476,17 @@ class Reference(DataHandler):
348 476
     def linked_classes(self):
349 477
         return copy.copy(self.__allowed_classes)
350 478
 
351
-    # @brief Set the back reference for this field.
479
+
480
+    ##
481
+    # @brief Sets a back reference.
352 482
     def _set_back_reference(self, back_reference):
353 483
         self.__back_reference = back_reference
354 484
 
355
-    # @brief Check and cast value in appropriate type
356
-    # @param value *
485
+
486
+    ##
487
+    # @brief Check and cast value in the appropriate type
488
+    #
489
+    # @param value 
357 490
     # @throw FieldValidationError if value is an appropriate type
358 491
     # @return value
359 492
     # @todo implement the check when we have LeObject uid check value
@@ -369,62 +502,85 @@ class Reference(DataHandler):
369 502
                 value = uiddh._check_data_value(value)
370 503
             else:
371 504
                 raise FieldValidationError(
372
-                    "Reference datahandler can not check this value %s if any allowed_class is allowed." % value)
505
+                    "Reference datahandler can not check this value %s if any allowed_class is allowed. " % value)
373 506
         return value
374 507
 
375
-    # @brief Check datas consistency
376
-    # @param emcomponent EmComponent : An EmComponent child class instance
377
-    # @param fname : the field name
508
+
509
+    ##
510
+    # @brief Check data consistency
511
+    #
512
+    # @param emcomponent EmComponent :
513
+    # @param fname string : the field name
378 514
     # @param datas dict : dict storing fields values
379
-    # @return an Exception instance if fails else True
380
-    # @todo check for performance issue and check logics
381
-    # @warning composed uid capabilities broken here
515
+    # @return bool | Exception :
516
+    #
517
+    # @todo check for performance issues and checks logic
518
+    # @warning composed uid capabilities are broken
519
+    # @remarks Is that really a legitimate case of retuning an Exception object? 
382 520
     def check_data_consistency(self, emcomponent, fname, datas):
383 521
         rep = super().check_data_consistency(emcomponent, fname, datas)
384 522
         if isinstance(rep, Exception):
385 523
             return rep
386 524
         if self.back_reference is None:
387 525
             return True
388
-        # !! Reimplement instance fetching in construct data !!
526
+        ##
527
+        # @todo Reimplement instance fetching in construct data
528
+        # @remarks Set the previous todo as one, looked like it was intended to be.
389 529
         target_class = self.back_reference[0]
390 530
         if target_class not in self.__allowed_classes:
391 531
             logger.warning('Class of the back_reference given is not an allowed class')
392 532
             return False
393 533
         value = datas[fname]
394
-        target_uidfield = target_class.uid_fieldname()[0]  # multi uid broken here
534
+        ##
535
+        # @warning multi uid broken here
536
+        # @remarks Why is that broken? Any clue? Set as a warning.
537
+        target_uidfield = target_class.uid_fieldname()[0]  
395 538
         obj = target_class.get([(target_uidfield, '=', value)])
396 539
         if len(obj) == 0:
397 540
             logger.warning('Object referenced does not exist')
398 541
             return False
399 542
         return True
400 543
 
544
+
545
+    ##
401 546
     # @brief Utility method designed to fetch referenced objects
547
+    #
402 548
     # @param value mixed : the field value
403 549
     # @throw NotImplementedError
550
+    # @remarks Not implemented? Consider renaming?
404 551
     def get_referenced(self, value):
405 552
         raise NotImplementedError
406 553
 
407 554
 
408
-# @brief This class represent a data_handler for single reference to another object
555
+##
556
+# @brief DataHandler for single reference to another object
409 557
 #
410
-# The fields using this data handlers are like "foreign key" on another object
558
+# An instance of this class acts like a "foreign key" to another object
411 559
 class SingleRef(Reference):
412 560
 
561
+
413 562
     def __init__(self, allowed_classes=None, **kwargs):
414 563
         super().__init__(allowed_classes=allowed_classes, **kwargs)
415 564
 
416
-    # @brief Check and cast value in appropriate type
417
-    # @param value: *
418
-    # @throw FieldValidationError if value is unappropriate or can not be cast
419
-    # @return value
565
+
566
+    ##
567
+    # @brief Checks and casts value to the appropriate type
568
+    #
569
+    # @param value: mixed
570
+    # @throw FieldValidationError if value is inappropriate or can not be cast
571
+    # @return mixed
420 572
     def _check_data_value(self, value):
421 573
         value = super()._check_data_value(value)
422 574
         return value
423 575
 
424
-    # @brief Utility method designed to fetch referenced objects
576
+
577
+    ##
578
+    # @brief Utility method to fetch referenced objects
579
+    #
425 580
     # @param value mixed : the field value
426 581
     # @return A LeObject child class instance
427 582
     # @throw LodelDataHandlerConsistencyException if no referenced object found
583
+    # @remarks Consider renaming (e.g. get_referenced_object)?
428 584
     def get_referenced(self, value):
429 585
         for leo_cls in self.linked_classes:
430 586
             res = leo_cls.get_from_uid(value)
@@ -434,30 +590,39 @@ class SingleRef(Reference):
434 590
 referenced object with uid %s" % value)
435 591
 
436 592
 
437
-# @brief This class represent a data_handler for multiple references to another object
593
+##
594
+# @brief DataHandler for multiple references to another object
438 595
 # @ingroup lodel2_datahandlers
439 596
 #
440
-# The fields using this data handlers are like SingleRef but can store multiple references in one field
597
+# The fields using this data handlers are like SingleRef but can store multiple
598
+# references in one field.
441 599
 # @note for the moment split on ',' chars
442 600
 class MultipleRef(Reference):
443 601
 
602
+    ##
444 603
     # @brief Constructor
445
-    # @param max_item int | None : indicate the maximum number of item referenced by this field, None mean no limit
604
+    #
605
+    # @param max_item int | None : indicate the maximum number of item referenced
606
+    #         by this field, None mean no limit
446 607
     def __init__(self, max_item=None, **kwargs):
447 608
         self.max_item = max_item
448 609
         super().__init__(**kwargs)
449 610
 
611
+    ##
450 612
     # @brief Method designed to return an empty value for this kind of
451
-    # multipleref
613
+    #         multipleref
614
+    # @remarks Purpose!?
452 615
     @classmethod
453 616
     def empty(cls):
454 617
         return []
455 618
 
619
+
620
+    ##
456 621
     # @brief Check and cast value in appropriate type
457
-    # @param value *
622
+    # @param value mixed
458 623
     # @throw FieldValidationError if value is unappropriate or can not be cast
459 624
     # @return value
460
-    # @TODO  Writing test error for errors when stored multiple references in one field
625
+    # @todo  Writing test error for errors when stored multiple references in one field
461 626
     def _check_data_value(self, value):
462 627
         value = DataHandler._check_data_value(self, value)
463 628
         if not hasattr(value, '__iter__'):
@@ -479,7 +644,9 @@ class MultipleRef(Reference):
479 644
                 "MultipleRef have for invalid values [%s]  :" % (",".join(error_list)))
480 645
         return new_val
481 646
 
647
+    ##
482 648
     # @brief Utility method designed to fetch referenced objects
649
+    #
483 650
     # @param values mixed : the field values
484 651
     # @return A list of LeObject child class instance
485 652
     # @throw LodelDataHandlerConsistencyException if some referenced objects
@@ -502,37 +669,51 @@ class MultipleRef(Reference):
502 669
 some referenced objects. Following uids were not found : %s" % ','.join(left))
503 670
 
504 671
 
505
-#  @brief Class designed to handle datas access will fieldtypes are constructing datas
672
+##
673
+# @brief Class designed to handle data access while field types are constructing data
506 674
 # @ingroup lodel2_datahandlers
507 675
 #
508 676
 # This class is designed to allow automatic scheduling of construct_data calls.
509 677
 #
510
-# In theory it's able to detect circular dependencies
678
+# In theory it has the ability to detect circular dependencies
511 679
 # @todo test circular deps detection
512 680
 # @todo test circular deps false positive
681
+# @remarks Would not it be better to make sure what the code actually is doing? 
513 682
 class DatasConstructor(object):
514 683
 
684
+    ##
515 685
     # @brief Init a DatasConstructor
516
-    # @param leobject LeCrud : @ref LeObject child class
686
+    #
687
+    # @param leobject LeObject
517 688
     # @param datas dict : dict with field name as key and field values as value
518 689
     # @param fields_handler dict : dict with field name as key and data handler instance as value
519 690
     def __init__(self, leobject, datas, fields_handler):
520
-        # Stores concerned class
521 691
         self._leobject = leobject
522
-        # Stores datas and constructed datas
523 692
         self._datas = copy.copy(datas)
524 693
         # Stores fieldtypes
525 694
         self._fields_handler = fields_handler
526
-        # Stores list of fieldname for constructed datas
695
+        # Stores list of fieldname for constructed 
527 696
         self._constructed = []
528 697
         # Stores construct calls list
529 698
         self._construct_calls = []
530 699
 
700
+
701
+    ##
531 702
     # @brief Implements the dict.keys() method on instance
703
+    #
704
+    # @return list
532 705
     def keys(self):
533 706
         return self._datas.keys()
534 707
 
535
-    #  @brief Allows to access the instance like a dict
708
+
709
+    ##
710
+    # @brief Allows to access the instance like a dict
711
+    #
712
+    # @param fname string: The field name
713
+    # @return field values
714
+    # @throw RuntimeError
715
+    #
716
+    # @note Determine return type 
536 717
     def __getitem__(self, fname):
537 718
         if fname not in self._constructed:
538 719
             if fname in self._construct_calls:
@@ -543,17 +724,25 @@ class DatasConstructor(object):
543 724
             self._constructed.append(fname)
544 725
         return self._datas[fname]
545 726
 
727
+
728
+    ##
546 729
     # @brief Allows to set instance values like a dict
730
+    #
547 731
     # @warning Should not append in theory
732
+    #
733
+    # @remarks Why is a warning issued any time we call this method?  
548 734
     def __setitem__(self, fname, value):
549 735
         self._datas[fname] = value
550 736
         warnings.warn("Setting value of an DatasConstructor instance")
551 737
 
552 738
 
553
-# @brief Class designed to handle an option of a DataHandler
739
+##
740
+# @brief Class designed to handle a DataHandler option
554 741
 class DatahandlerOption(MlNamedObject):
555 742
 
556
-    # @brief instanciates a new Datahandler option object
743
+
744
+    ##
745
+    # @brief instantiates a new DataHandlerOption object
557 746
     #
558 747
     # @param id str
559 748
     # @param display_name MlString
@@ -564,13 +753,18 @@ class DatahandlerOption(MlNamedObject):
564 753
         self.__validator = validator
565 754
         super().__init__(display_name, help_text)
566 755
 
756
+    ##
757
+    # @brief Accessor to the id property.
567 758
     @property
568 759
     def id(self):
569 760
         return self.__id
570 761
 
762
+    ##
571 763
     # @brief checks a value corresponding to this option is valid
572
-    # @param value
573
-    # @return casted value
764
+    #
765
+    # @param value mixed
766
+    # @return cast value
767
+    # @throw ValueError
574 768
     def check_value(self, value):
575 769
         try:
576 770
             return self.__validator(value)

Loading…
Cancel
Save