Browse Source

Implements order in fieldtype construct

Yann Weber 9 years ago
parent
commit
1daf9677c6

+ 7
- 8
EditorialModel/fieldtypes/emuid.py View File

@@ -10,6 +10,8 @@ class EmFieldType(integer.EmFieldType):
10 10
     
11 11
     help = 'Fieldtypes designed to handle editorial model UID for LeObjects'
12 12
 
13
+    _construct_datas_deps = []
14
+
13 15
     def __init__(self, is_id_class, **kwargs):
14 16
         self._is_id_class = is_id_class
15 17
         kwargs['internal'] = 'automatic'
@@ -18,18 +20,15 @@ class EmFieldType(integer.EmFieldType):
18 20
     def _check_data_value(self, value):
19 21
         return (value, None)
20 22
 
21
-    def construct_data(self, lec, fname, datas):
23
+    def _construct_data(self, lec, fname, datas, cur_value):
24
+        ret = None
22 25
         if self.is_id_class:
23 26
             if lec.implements_leclass():
24
-                datas[fname] = lec._class_id
25
-            else:
26
-                datas[fname] = None
27
+                ret = lec._class_id
27 28
         else:
28 29
             if lec.implements_letype():
29
-                datas[fname] = lec._type_id
30
-            else:
31
-                datas[fname] = None
32
-        return datas[fname]
30
+                ret = lec._type_id
31
+        return ret
33 32
     
34 33
     def check_data_consistency(self, lec, fname, datas):
35 34
         if datas[fname] != (lec._class_id if self.is_id_class else lec._type_id):

+ 49
- 3
EditorialModel/fieldtypes/generic.py View File

@@ -1,11 +1,15 @@
1 1
 #-*- coding: utf-8 -*-
2 2
 
3
+import copy
3 4
 import types
4 5
 import importlib
5 6
 
6 7
 class GenericFieldType(object):
7 8
     
8 9
     help_text = 'Generic field type : abstract class for every fieldtype'
10
+    
11
+    ## @brief List fields that will be exposed to the construct_data_method
12
+    _construct_datas_deps = []
9 13
 
10 14
     ## @param internal False | str : define wheter or not a field is internal
11 15
     # @throw NotImplementedError if called from bad class
@@ -35,15 +39,22 @@ class GenericFieldType(object):
35 39
     def _check_data_value(self, value):
36 40
         return (value, None)
37 41
     
42
+    ## @brief Wrapper for _construct_data() method
43
+    # 
44
+    # Now useless
45
+    def construct_data(self, lec, fname, datas, cur_value):
46
+        return self._construct_data(lec, fname, datas, cur_value)
47
+
38 48
     ## @brief Build field value
39 49
     # @param lec LeCrud : A LeCrud child class
40 50
     # @param fname str : The field name
41 51
     # @param datas dict : dict storing fields values (from the lec)
52
+    # @param cur_value : the value for the current field (identified by fieldname)
42 53
     # @return constructed datas (for the fname field)
43 54
     # @throw RuntimeError if unable to construct data
44
-    def construct_data(self, lec, fname, datas):
45
-        if fname in datas:
46
-            return datas[fname]
55
+    def _construct_data(self, lec, fname, datas, cur_value):
56
+        if fname in datas.keys():
57
+            return cur_value
47 58
         elif hasattr(lec.fieldtypes()[fname], 'default'):
48 59
             return lec.fieldtypes()[fname].default
49 60
         elif lec.fieldtypes()[fname].nullable:
@@ -152,6 +163,41 @@ class MultiValueFieldType(GenericFieldType):
152 163
         ## stores the fieldtype that handles the values
153 164
         self.value_fieldtype = value_fieldtype
154 165
 
166
+## @brief Class designed to handle datas access will fieldtypes are constructing datas
167
+class DatasConstructor(object):
168
+    
169
+    ## @brief Init a DatasConstructor
170
+    # @param lec LeCrud : LeCrud child class 
171
+    # @param datas dict : dict with field name as key and field values as value
172
+    # @param fieldtypes dict : dict with field name as key and fieldtype as value
173
+    def __init__(self, lec, datas, fieldtypes):
174
+        ## Stores concerned class
175
+        self._lec = lec
176
+        ## Stores datas and constructed datas
177
+        self._datas = copy.copy(datas)
178
+        ## Stores fieldtypes
179
+        self._fieldtypes = fieldtypes
180
+        ## Stores list of fieldname for constructed datas
181
+        self._constructed = []
182
+        ## Stores construct calls list
183
+        self._construct_calls = []
184
+        
185
+    def keys(self):
186
+        return self._datas.keys()
187
+
188
+    def __getitem__(self, fname):
189
+        if fname not in self._constructed:
190
+            if fname in self._construct_calls:
191
+                raise RuntimeError('Probably circular dependencies in fieldtypes')
192
+            cur_value = self._datas[fname] if fname in self._datas else None
193
+            self._datas[fname] = self._fieldtypes[fname].construct_data(self._lec, fname, self, cur_value)
194
+            self._constructed.append(fname)
195
+        return self._datas[fname]
196
+
197
+    def __setitem__(self, fname, value):
198
+        self._datas[fname] = value
199
+        
200
+
155 201
 #
156 202
 #
157 203
 #   Exceptions

+ 9
- 9
EditorialModel/fieldtypes/leo.py View File

@@ -9,7 +9,7 @@ class EmFieldType(ReferenceFieldType):
9 9
     
10 10
     help = 'Fieldtypes designed to handle pk of LeObject in LeRelations'
11 11
 
12
-    ftype = 'leobject'
12
+    _construct_data_deps = []
13 13
     
14 14
     ## @todo Replace hardcoded string for reference initialisation
15 15
     def __init__(self, superior=True, **kwargs):
@@ -25,23 +25,23 @@ class EmFieldType(ReferenceFieldType):
25 25
     
26 26
     ## @brief If field value is an integer, returns a partially instanciated LeObject (only with an ID)
27 27
     # @todo what should we do if the get fails ? Raise ?
28
-    def construct_data(self, lec, fname, datas):
29
-        if isinstance(datas[fname], str):
28
+    def _construct_data(self, lec, fname, datas, cur_value):
29
+        if isinstance(cur_value, str):
30 30
             # Cast to int
31 31
             try:
32
-                datas[fname] = int(datas[fname])
32
+                cur_value = int(cur_value)
33 33
             except (ValueError, TypeError) as e:
34 34
                 raise e # Raise Here !?
35
-        if datas[fname].is_leobject():
35
+        if cur_value.is_leobject():
36 36
             # Its an object not populated (we dont now its type)
37
-            datas[fname] = datas[fname].lodel_id #Optimize here giving only class_id and type_id to populate ?
38
-        if isinstance(datas[fname], int):
37
+            cur_value = cur_value.lodel_id #Optimize here giving only class_id and type_id to populate ?
38
+        if isinstance(cur_value, int):
39 39
             # Get instance with id
40
-            resget = lec.name2class('LeObject').get(['lodel_id = %d' % datas[fname]])
40
+            resget = lec.name2class('LeObject').get(['lodel_id = %d' % cur_value])
41 41
             if resget is None or len(resget) != 1:
42 42
                 # Bad filter or bad id... raise ?
43 43
                 raise Exception("BAAAAAD")
44
-        return datas[fname]
44
+        return cur_value
45 45
     
46 46
     ## @brief checks datas consistency
47 47
     # @param lec LeCrud : A LeCrud child instance

+ 8
- 5
EditorialModel/fieldtypes/rank.py View File

@@ -1,5 +1,6 @@
1 1
 #-*- coding utf-8 -*-
2 2
 
3
+import EditorialModel.classtypes
3 4
 import leapi.lerelation as lerelation
4 5
 
5 6
 from .generic import FieldTypeError
@@ -9,17 +10,19 @@ class EmFieldType(integer.EmFieldType):
9 10
     
10 11
     help = 'Fieldtype designed to handle relations rank'
11 12
 
13
+    _construct_datas_deps = [EditorialModel.classtypes.relation_superior]
14
+
12 15
     def __init__(self, **kwargs):
13 16
         super().__init__(**kwargs)
14 17
 
15
-    def construct_data(self, lec, fname, datas):
16
-        superior_id = datas[lec._superior_field_name]
18
+    def _construct_data(self, lec, fname, datas, cur_value):
19
+        superior_id = datas[EditorialModel.classtypes.relation_superior]
17 20
         if lec.is_lerel2type():
18 21
             subordinate = lec._subordinate_cls
19 22
             sub_em_type_id = subordinate._type_id
20
-            datas[fname] = lec.get_max_rank(superior_id, sub_em_type_id)
23
+            cur_value = lec.get_max_rank(superior_id, sub_em_type_id)
21 24
         elif lec.is_lehierarch():
22
-            datas[fname] = lec.get_max_rank(superior_id, datas['nature'])
25
+            cur_value = lec.get_max_rank(superior_id, datas['nature'])
23 26
         else:
24 27
             raise ValueError("Called with bad class : ", lec.__name__)
25
-        return datas[fname]
28
+        return cur_value

+ 10
- 5
leapi/lecrud.py View File

@@ -9,6 +9,8 @@ import warnings
9 9
 import importlib
10 10
 import re
11 11
 
12
+from EditorialModel.fieldtypes.generic import DatasConstructor
13
+
12 14
 REL_SUP = 0
13 15
 REL_SUB = 1
14 16
 
@@ -460,11 +462,14 @@ class _LeCrud(object):
460 462
     # @todo Decide wether or not the datas are modifed inplace or returned in a new dict (second solution for the moment)
461 463
     @classmethod
462 464
     def _construct_datas(cls, datas):
463
-        res_datas = copy.copy(datas)
464
-        for fname, ftype in cls.fieldtypes().items():
465
-            if not ftype.is_internal() or ftype.internal != 'autosql':
466
-                res_datas[fname] = ftype.construct_data(cls, fname, res_datas)
467
-        return res_datas
465
+        constructor = DatasConstructor(cls, datas, cls.fieldtypes())
466
+        ret = {
467
+                fname:constructor[fname]
468
+                for fname, ftype in cls.fieldtypes().items()
469
+                if not ftype.is_internal() or ftype.internal != 'autosql'
470
+        }
471
+        return ret
472
+
468 473
     ## @brief Check datas consistency
469 474
470 475
     # @warning assert that datas is complete

Loading…
Cancel
Save