|
@@ -8,9 +8,11 @@ import copy
|
8
|
8
|
import importlib
|
9
|
9
|
import inspect
|
10
|
10
|
import warnings
|
11
|
|
-
|
|
11
|
+from lodel.exceptions import *
|
12
|
12
|
from lodel import logger
|
13
|
13
|
|
|
14
|
+class DataNoneValid(Exception):
|
|
15
|
+ pass
|
14
|
16
|
|
15
|
17
|
class FieldValidationError(Exception):
|
16
|
18
|
pass
|
|
@@ -31,6 +33,7 @@ class DataHandler(object):
|
31
|
33
|
##@brief List fields that will be exposed to the construct_data_method
|
32
|
34
|
_construct_datas_deps = []
|
33
|
35
|
|
|
36
|
+ directly_editable = True
|
34
|
37
|
##@brief constructor
|
35
|
38
|
# @param internal False | str : define whether or not a field is internal
|
36
|
39
|
# @param immutable bool : indicates if the fieldtype has to be defined in child classes of LeObject or if it is
|
|
@@ -53,7 +56,6 @@ class DataHandler(object):
|
53
|
56
|
if error:
|
54
|
57
|
raise error
|
55
|
58
|
del(kwargs['default'])
|
56
|
|
-
|
57
|
59
|
for argname, argval in kwargs.items():
|
58
|
60
|
setattr(self, argname, argval)
|
59
|
61
|
|
|
@@ -74,23 +76,32 @@ class DataHandler(object):
|
74
|
76
|
def is_internal(self):
|
75
|
77
|
return self.internal is not False
|
76
|
78
|
|
77
|
|
- ##@brief calls the data_field defined _check_data_value() method
|
78
|
|
- #@ingroup lodel2_dh_checks
|
79
|
|
- #@warning DO NOT REIMPLEMENT THIS METHOD IN A CUSTOM DATAHANDLER (see
|
80
|
|
- #@ref _construct_data() and @ref lodel2_dh_check_impl )
|
81
|
|
- #@return tuple (value, error|None)
|
82
|
|
- def check_data_value(self, value):
|
|
79
|
+
|
|
80
|
+ def _check_data_value(self, value):
|
83
|
81
|
if value is None:
|
84
|
82
|
if not self.nullable:
|
85
|
|
- return None, TypeError("'None' value but field is not nullable")
|
86
|
|
- return None, None
|
87
|
|
- return self._check_data_value(value)
|
88
|
|
-
|
89
|
|
- ##@brief Designed to be implemented in child classes
|
90
|
|
- def _check_data_value(self, value):
|
91
|
|
-
|
|
83
|
+ print(LodelExeption)
|
|
84
|
+ raise LodelExceptions("None value is forbidden")
|
|
85
|
+ print(self.nullable, value)
|
|
86
|
+ raise DataNoneValid("None with a nullable. GOTO CHECK")
|
|
87
|
+ return value, None
|
|
88
|
+
|
|
89
|
+#
|
|
90
|
+# ##@brief calls the data_field defined _check_data_value() method
|
|
91
|
+# #@ingroup lodel2_dh_checks
|
|
92
|
+# #@warning DO NOT REIMPLEMENT THIS METHOD IN A CUSTOM DATAHANDLER (see
|
|
93
|
+# #@ref _construct_data() and @ref lodel2_dh_check_impl )
|
|
94
|
+# #@return tuple (value, error|None)
|
|
95
|
+ def check_data_value(self, value):
|
|
96
|
+ try:
|
|
97
|
+ self._check_data_value(value)
|
|
98
|
+ except DataNoneValid as expt:
|
|
99
|
+ return value, None
|
|
100
|
+ except LodelExceptions as expt:
|
|
101
|
+ return None, expt
|
92
|
102
|
return value, None
|
93
|
103
|
|
|
104
|
+#
|
94
|
105
|
##@brief checks if this class can override the given data handler
|
95
|
106
|
# @param data_handler DataHandler
|
96
|
107
|
# @return bool
|
|
@@ -250,11 +261,15 @@ class Reference(DataHandler):
|
250
|
261
|
# @param internal bool : if False, the field is not internal
|
251
|
262
|
# @param **kwargs : other arguments
|
252
|
263
|
def __init__(self, allowed_classes = None, back_reference = None, internal=False, **kwargs):
|
253
|
|
- ##@brief set of allowed LeObject child classes
|
254
|
264
|
self.__allowed_classes = set() if allowed_classes is None else set(allowed_classes)
|
255
|
|
- ##@brief Stores back references informations
|
256
|
|
- self.__back_reference = None
|
257
|
|
- self.__set_back_reference(back_reference)
|
|
265
|
+ self.allowed_classes = list() if allowed_classes is None else allowed_classes
|
|
266
|
+
|
|
267
|
+ if back_reference is not None:
|
|
268
|
+ if len(back_reference) != 2:
|
|
269
|
+ raise ValueError("A tuple (classname, fieldname) expected but got '%s'" % back_reference)
|
|
270
|
+ #if not issubclass(lodel.leapi.leobject.LeObject, back_reference[0]) or not isinstance(back_reference[1], str):
|
|
271
|
+ # raise TypeError("Back reference was expected to be a tuple(<class LeObject>, str) but got : (%s, %s)" % (back_reference[0], back_reference[1]))
|
|
272
|
+ self.__back_reference = back_reference
|
258
|
273
|
super().__init__(internal=internal, **kwargs)
|
259
|
274
|
|
260
|
275
|
##@brief Property that takes value of a copy of the back_reference tuple
|
|
@@ -275,30 +290,22 @@ class Reference(DataHandler):
|
275
|
290
|
return copy.copy(self.__allowed_classes)
|
276
|
291
|
|
277
|
292
|
##@brief Set the back reference for this field.
|
278
|
|
- def __set_back_reference(self, back_reference):
|
279
|
|
- if back_reference is None:
|
280
|
|
- return
|
281
|
|
- if len(back_reference) != 2:
|
282
|
|
- raise LodelDataHandlerException("A tuple(LeObjectChild, fieldname) \
|
283
|
|
-expected but got '%s'" % back_reference)
|
284
|
|
-
|
|
293
|
+ def _set_back_reference(self, back_reference):
|
285
|
294
|
self.__back_reference = back_reference
|
286
|
295
|
|
287
|
296
|
##@brief Check value
|
288
|
297
|
#@param value *
|
289
|
298
|
#@return tuple(value, exception)
|
290
|
299
|
#@todo implement the check when we have LeObject to check value
|
291
|
|
- def check_data_value(self, value):
|
292
|
|
- for elt in self.__allowed_classes:
|
293
|
|
- for k, v in elt.fields().items():
|
294
|
|
- # k is a fieldname and v is a datahandler instance
|
295
|
|
- if v.check_data_value(value)[0] is not None:
|
296
|
|
- return value, None
|
297
|
|
-
|
298
|
|
- def construct_data(self, emcomponent, fname, datas, cur_value)
|
299
|
|
- super().construct_data(self, emcomponent, fname, datas, cur_value)
|
300
|
|
-
|
|
300
|
+ def _check_data_value(self, value):
|
|
301
|
+ super()._check_data_value(value)
|
|
302
|
+ elt = self.__allowed_classes[0]
|
|
303
|
+ uid = elt.uid_fieldname()[0]# TODO multiple uid is broken
|
|
304
|
+ if (expt is None and not (isinstance(value, LeObject)) or (value is uid)):
|
|
305
|
+ raise FieldValidationError("LeObject instance or id exxpected for a reference field")
|
301
|
306
|
|
|
307
|
+ def construct_data(self, emcomponent, fname, datas, cur_value):
|
|
308
|
+ super().construct_data(emcomponent, fname, datas, cur_value)
|
302
|
309
|
|
303
|
310
|
##@brief Check datas consistency
|
304
|
311
|
#@param emcomponent EmComponent : An EmComponent child class instance
|
|
@@ -315,8 +322,7 @@ expected but got '%s'" % back_reference)
|
315
|
322
|
return rep
|
316
|
323
|
if self.back_reference is None:
|
317
|
324
|
return True
|
318
|
|
- #Checking back reference consistency
|
319
|
|
-
|
|
325
|
+
|
320
|
326
|
# !! Reimplement instance fetching in construct data !!
|
321
|
327
|
dh = emcomponent.field(fname)
|
322
|
328
|
uid = datas[emcomponent.uid_fieldname()[0]] #multi uid broken here
|
|
@@ -341,12 +347,11 @@ class SingleRef(Reference):
|
341
|
347
|
def __init__(self, allowed_classes = None, **kwargs):
|
342
|
348
|
super().__init__(allowed_classes = allowed_classes)
|
343
|
349
|
|
344
|
|
- def _check_data_value(self, value):
|
345
|
|
- val, expt = super()._check_data_value(value)
|
346
|
|
- if not isinstance(expt, Exception):
|
347
|
|
- if len(val) > 1:
|
348
|
|
- return None, FieldValidationError("Only single values are allowed for SingleRef fields")
|
349
|
|
- return val, expt
|
|
350
|
+ def check_data_value(self, value):
|
|
351
|
+ super()._check_data_value(value)
|
|
352
|
+ if (expt is None and (len(val)>1)):
|
|
353
|
+ raise FieldValidationError("List or string expected for a set field")
|
|
354
|
+
|
350
|
355
|
|
351
|
356
|
|
352
|
357
|
##@brief This class represent a data_handler for multiple references to another object
|
|
@@ -363,25 +368,16 @@ class MultipleRef(Reference):
|
363
|
368
|
super().__init__(**kwargs)
|
364
|
369
|
|
365
|
370
|
|
366
|
|
- def check_data_value(self, value):
|
367
|
|
- value, expt = super().check_data_value(value)
|
368
|
|
- if expt is not None:
|
369
|
|
- #error in parent
|
370
|
|
- return value, expt
|
371
|
|
- elif value is None:
|
372
|
|
- #none value
|
373
|
|
- return value, expt
|
374
|
|
-
|
375
|
|
- expt = None
|
376
|
|
-
|
377
|
|
- if isinstance(value, str):
|
378
|
|
- value, expt = super()._check_data_value(value)
|
379
|
|
- elif not hasattr(value, '__iter__'):
|
380
|
|
- return None, FieldValidationError("MultipleRef has to be an iterable or a string, '%s' found" % value)
|
|
371
|
+ def _check_data_value(self, value):
|
|
372
|
+ super()._check_data_value(value)
|
|
373
|
+ if not hasattr(value, '__iter__'):
|
|
374
|
+ raise FieldValidationError("MultipleRef has to be an iterable or a string, '%s' found" % value)
|
381
|
375
|
if self.max_item is not None:
|
382
|
376
|
if self.max_item < len(value):
|
383
|
|
- return None, FieldValidationError("Too many items")
|
384
|
|
- return value, expt
|
|
377
|
+ raise FieldValidationError("Too many items")
|
|
378
|
+ ref_list = []
|
|
379
|
+ for v in value.items():
|
|
380
|
+ ref_list.append(super()._check_data_value(v))
|
385
|
381
|
|
386
|
382
|
def construct_data(self, emcomponent, fname, datas, cur_value):
|
387
|
383
|
cur_value = super().construct_data(emcomponent, fname, datas, cur_value)
|