Browse Source

Changed LeFactory generated code (again) + Bugfix on LeCrud + more tests and tests update

Yann Weber 9 years ago
parent
commit
52cbce9865

+ 16
- 0
EditorialModel/fieldtypes/generic.py View File

75
         if value is None and not self.nullable:
75
         if value is None and not self.nullable:
76
             return (None, TypeError("'None' value but field is not nullable"))
76
             return (None, TypeError("'None' value but field is not nullable"))
77
         return self._check_data_value(value)
77
         return self._check_data_value(value)
78
+    
79
+    ## @brief Build automatic fields values
80
+    # @param lec LeCrud : A LeCrud child class
81
+    # @param fname str : The field name
82
+    # @param datas dict : dict storing fields values
83
+    # @return constructed datas
84
+    def construct_data(self, lec, fname, datas):
85
+        return datas[fname]
86
+    
87
+    ## @brief Check datas consistency
88
+    # @param leo LeCrud : A LeCrud child class instance
89
+    # @param fname str : The field name
90
+    # @param datas dict : dict storing fields values
91
+    # @return an Exception instance if fails else True
92
+    def check_data_consistency(self, lec, fname, datas):
93
+        return True
78
 
94
 
79
     ## @brief Check if a value is correct
95
     ## @brief Check if a value is correct
80
     # @param value * : The value
96
     # @param value * : The value

+ 3
- 3
leapi/leclass.py View File

2
 
2
 
3
 import leapi
3
 import leapi
4
 
4
 
5
-
5
+from leapi.leobject import _LeObject
6
 
6
 
7
 ## @brief Represent an EmClass data instance
7
 ## @brief Represent an EmClass data instance
8
 # @note Is not a derivated class of LeObject because the concrete class will be a derivated class from LeObject
8
 # @note Is not a derivated class of LeObject because the concrete class will be a derivated class from LeObject
9
-class _LeClass(object):
9
+class _LeClass(_LeObject):
10
 
10
 
11
     ## @brief Stores fieldtypes by field name
11
     ## @brief Stores fieldtypes by field name
12
     _fieldtypes = dict()
12
     _fieldtypes = dict()
28
     @classmethod
28
     @classmethod
29
     def fieldtypes(cls):
29
     def fieldtypes(cls):
30
         ret = dict()
30
         ret = dict()
31
-        ret.update(super(LeClass,cls).fieldtypes())
31
+        ret.update(super(_LeClass,cls).fieldtypes())
32
         ret.update(cls._fieldtypes)
32
         ret.update(cls._fieldtypes)
33
         return ret
33
         return ret
34
 
34
 

+ 6
- 9
leapi/lecrud.py View File

8
 import importlib
8
 import importlib
9
 import re
9
 import re
10
 
10
 
11
-import leapi.leobject
12
-
13
 class LeApiErrors(Exception):
11
 class LeApiErrors(Exception):
14
     ## @brief Instanciate a new exceptions handling multiple exceptions
12
     ## @brief Instanciate a new exceptions handling multiple exceptions
15
     # @param expt_l list : A list of data check Exception
13
     # @param expt_l list : A list of data check Exception
134
         provided = set(datas.keys())
132
         provided = set(datas.keys())
135
 
133
 
136
         #searching unknow fields
134
         #searching unknow fields
137
-        print("provided", provided, "correct", correct)
138
         unknown = provided - correct
135
         unknown = provided - correct
139
         for u_f in unknown:
136
         for u_f in unknown:
140
             #here we can check if the field is unknown or rejected because it is internal
137
             #here we can check if the field is unknown or rejected because it is internal
193
     # @return A new id if success else False
190
     # @return A new id if success else False
194
     @classmethod
191
     @classmethod
195
     def insert(cls, datas):
192
     def insert(cls, datas):
196
-        insert_datas = self.prepare_datas(datas, complete = True, allow_internal = False)
193
+        insert_datas = cls.prepare_datas(datas, complete = True, allow_internal = False)
197
         return cls._datasource.insert(cls, insert_datas)
194
         return cls._datasource.insert(cls, insert_datas)
198
     
195
     
199
     ## @brief Check and prepare datas
196
     ## @brief Check and prepare datas
208
     def prepare_datas(cls, datas, complete = False, allow_internal = True):
205
     def prepare_datas(cls, datas, complete = False, allow_internal = True):
209
         if not complete:
206
         if not complete:
210
             warnings.warn("Actual implementation can make datas construction and consitency checks fails when datas are not complete")
207
             warnings.warn("Actual implementation can make datas construction and consitency checks fails when datas are not complete")
211
-        ret_dats = self.check_datas_value(cls, datas, complete, allow_internal)
212
-        ret_datas = self._construct_datas(cls, ret_datas)
213
-        ret_datas = self._check_data_consistency(cls, ret_datas)
208
+        ret_datas = cls.check_datas_value(datas, complete, allow_internal)
209
+        ret_datas = cls._construct_datas(ret_datas)
210
+        cls._check_datas_consistency(ret_datas)
214
         return ret_datas
211
         return ret_datas
215
 
212
 
216
     #-###################-#
213
     #-###################-#
236
         res_datas = dict()
233
         res_datas = dict()
237
         for fname, ftype in cls.fieldtypes().items():
234
         for fname, ftype in cls.fieldtypes().items():
238
             if fname in datas:
235
             if fname in datas:
239
-                res_datas[fname] = ftype.construct_data(datas)
236
+                res_datas[fname] = ftype.construct_data(cls, fname, datas)
240
         return res_datas
237
         return res_datas
241
     ## @brief Check datas consistency
238
     ## @brief Check datas consistency
242
239
248
     def _check_datas_consistency(cls, datas):
245
     def _check_datas_consistency(cls, datas):
249
         err_l = []
246
         err_l = []
250
         for fname, ftype in cls.fieldtypes().items():
247
         for fname, ftype in cls.fieldtypes().items():
251
-            ret = ftype.check_data_consistency(datas)
248
+            ret = ftype.check_data_consistency(cls, fname, datas)
252
             if isinstance(ret, Exception):
249
             if isinstance(ret, Exception):
253
                 err_l.append(ret)
250
                 err_l.append(ret)
254
 
251
 

+ 1
- 1
leapi/lefactory.py View File

225
             result += """
225
             result += """
226
 ## @brief EmType {name} LeType child class
226
 ## @brief EmType {name} LeType child class
227
 # @see leobject::letype::LeType
227
 # @see leobject::letype::LeType
228
-class {name}({leclass}, LeType):
228
+class {name}(LeType, {leclass}):
229
     _type_id = {uid}
229
     _type_id = {uid}
230
 
230
 
231
 """.format(
231
 """.format(

+ 3
- 22
leapi/leobject.py View File

14
 import warnings
14
 import warnings
15
 
15
 
16
 import leapi
16
 import leapi
17
-import EditorialModel
17
+from leapi.lecrud import _LeCrud
18
 from leapi.lefactory import LeFactory
18
 from leapi.lefactory import LeFactory
19
+import EditorialModel
19
 from EditorialModel.types import EmType
20
 from EditorialModel.types import EmType
20
 
21
 
21
 REL_SUP = 0
22
 REL_SUP = 0
22
 REL_SUB = 1
23
 REL_SUB = 1
23
 
24
 
24
 ## @brief Main class to handle objects defined by the types of an Editorial Model
25
 ## @brief Main class to handle objects defined by the types of an Editorial Model
25
-class _LeObject(object):
26
+class _LeObject(_LeCrud):
26
     
27
     
27
     ## @brief maps em uid with LeType or LeClass keys are uid values are LeObject childs classes
28
     ## @brief maps em uid with LeType or LeClass keys are uid values are LeObject childs classes
28
     # @todo check if this attribute shouldn't be in _LeCrud
29
     # @todo check if this attribute shouldn't be in _LeCrud
55
             cls._fieldtypes_all.update(cls._leo_fieldtypes)
56
             cls._fieldtypes_all.update(cls._leo_fieldtypes)
56
         return cls._fieldtypes_all
57
         return cls._fieldtypes_all
57
 
58
 
58
-    ## @brief Creates new entries in the datasource
59
-    # @param datas list : A list a dict with fieldname as key
60
-    # @param cls
61
-    # @return a list of inserted lodel_id
62
-    # @see leapi.datasources.dummy.DummyDatasource.insert(), leapi.letype.LeType.insert()
63
-    @classmethod
64
-    def insert(cls, letype, datas):
65
-        if isinstance(datas, dict):
66
-            datas = [datas]
67
-
68
-        if cls == _LeObject:
69
-            raise NotImplementedError("Abstract method")
70
-        letype,leclass = cls._prepare_targets(letype)
71
-        if letype is None:
72
-            raise ValueError("letype argument cannot be None")
73
-
74
-        for data in datas:
75
-            letype.prepare_data(data, complete = True)
76
-        return cls._datasource.insert(letype, leclass, datas)
77
-    
78
     ## @brief Check if a LeType is a hierarchy root
59
     ## @brief Check if a LeType is a hierarchy root
79
     @staticmethod
60
     @staticmethod
80
     def is_root(leo):
61
     def is_root(leo):

+ 2
- 1
leapi/letype.py View File

11
 # @note LeObject will be generated by leapi.lefactory.LeFactory
11
 # @note LeObject will be generated by leapi.lefactory.LeFactory
12
 
12
 
13
 import leapi
13
 import leapi
14
+from leapi.leclass import _LeClass
14
 from leapi.leobject import LeObjectError
15
 from leapi.leobject import LeObjectError
15
 
16
 
16
 ## @brief Represent an EmType data instance
17
 ## @brief Represent an EmType data instance
17
 # @note Is not a derivated class of LeClass because the concrete class will be a derivated class from LeClass
18
 # @note Is not a derivated class of LeClass because the concrete class will be a derivated class from LeClass
18
-class _LeType(object):
19
+class _LeType(_LeClass):
19
     
20
     
20
     ## @brief Stores selected fields with key = name
21
     ## @brief Stores selected fields with key = name
21
     _fields = list()
22
     _fields = list()

+ 41
- 0
leapi/test/test_lecrud.py View File

11
 import leapi.test.utils
11
 import leapi.test.utils
12
 from leapi.lecrud import _LeCrud
12
 from leapi.lecrud import _LeCrud
13
 
13
 
14
+## @brief Test LeCrud methods
15
+# @note those tests need the full dynamically generated code
14
 class LeCrudTestCase(TestCase):
16
 class LeCrudTestCase(TestCase):
15
     @classmethod
17
     @classmethod
16
     def setUpClass(cls):
18
     def setUpClass(cls):
139
         filters = ['hello world !']
141
         filters = ['hello world !']
140
         with self.assertRaises(ValueError):
142
         with self.assertRaises(ValueError):
141
             Personnes._prepare_filters(filters)
143
             Personnes._prepare_filters(filters)
144
+    
145
+
146
+    # 
147
+    #   Tests mocking the datasource
148
+    # 
149
+
150
+    @patch('leapi.datasources.dummy.DummyDatasource.insert')
151
+    def test_insert(self, dsmock):
152
+        from dyncode import Publication, Numero, LeObject, Personne, Article
153
+        ndatas = [
154
+            (Numero, {'titre' : 'FooBar'}),
155
+            (Numero, {'titre':'hello'}),
156
+            (Personne, {'nom':'world', 'prenom':'hello'}),
157
+            (Article, {'titre': 'Ar Boof', 'soustitre': 'Wow!'}),
158
+        ]
159
+        for lecclass, ndats in ndatas:
160
+            lecclass.insert(ndats)
161
+            dsmock.assert_called_once_with(lecclass, ndats)
162
+            dsmock.reset_mock()
163
+
164
+            lecclass.insert(ndats)
165
+            dsmock.assert_called_once_with(lecclass, ndats)
166
+            dsmock.reset_mock()
167
+    
168
+    ## @todo try failing on inserting from LeClass child or LeObject
169
+    @patch('leapi.datasources.dummy.DummyDatasource.insert')
170
+    def test_insert_fails(self, dsmock):
171
+        from dyncode import Publication, Numero, LeObject, Personne, Article
172
+        ndatas = [
173
+            (Numero, dict()),
174
+            (Numero, {'titre':'hello', 'lodel_id':42}),
175
+            (Numero, {'tititre': 'hehello'}),
176
+            (Personne, {'titre':'hello'}),
177
+            (Article, {'titre': 'hello'}),
178
+        ]
179
+        for lecclass, ndats in ndatas:
180
+            with self.assertRaises(leapi.lecrud.LeApiDataCheckError, msg="But trying to insert %s as %s"%(ndats, lecclass.__name__)):
181
+                lecclass.insert(ndats)
182
+        pass
142
 
183
 

+ 10
- 6
leapi/test/test_lefactory.py View File

35
     def test_leobject(self):
35
     def test_leobject(self):
36
         """ Testing the generated LeObject class """
36
         """ Testing the generated LeObject class """
37
         import dyncode
37
         import dyncode
38
+        from dyncode import LeType, LeClass
39
+
38
         self.assertTrue(hasattr(dyncode, 'LeObject'))
40
         self.assertTrue(hasattr(dyncode, 'LeObject'))
39
 
41
 
40
         for uid, cls in dyncode.LeObject._me_uid.items():
42
         for uid, cls in dyncode.LeObject._me_uid.items():
41
-            if leapi.letype.LeType in cls.__bases__:
42
-                self.assertNotEqual(cls, leapi.letype.LeType)
43
+            if LeType in cls.__bases__:
44
+                self.assertNotEqual(cls, LeType)
43
                 self.assertEqual(cls._type_id, uid)
45
                 self.assertEqual(cls._type_id, uid)
44
-            elif leapi.leclass.LeClass in cls.__bases__:
45
-                self.assertNotEqual(cls, leapi.leclass.LeClass)
46
+            elif LeClass in cls.__bases__:
47
+                self.assertNotEqual(cls, LeClass)
46
                 self.assertEqual(cls._class_id, uid)
48
                 self.assertEqual(cls._class_id, uid)
47
             else:
49
             else:
48
                 self.fail("Bad instance type for _me_uid values : %s"%type(cls))
50
                 self.fail("Bad instance type for _me_uid values : %s"%type(cls))
51
     def test_leclass(self):
53
     def test_leclass(self):
52
         """ Testing generated LeClass childs classes """
54
         """ Testing generated LeClass childs classes """
53
         import dyncode
55
         import dyncode
56
+        from dyncode import LeType, LeClass
54
 
57
 
55
         for emclass in self.model.components(EditorialModel.classes.EmClass):
58
         for emclass in self.model.components(EditorialModel.classes.EmClass):
56
             leclass_name = LeFactory.name2classname(emclass.name)
59
             leclass_name = LeFactory.name2classname(emclass.name)
60
             self.assertEqual(leclass._class_id, emclass.uid)
63
             self.assertEqual(leclass._class_id, emclass.uid)
61
             
64
             
62
             #Testing inheritance
65
             #Testing inheritance
63
-            self.assertEqual(set(leclass.__bases__), set([dyncode.LeObject, leapi.leclass.LeClass]))
66
+            self.assertEqual(set(leclass.__bases__), set([dyncode.LeObject, dyncode.LeClass]))
64
             
67
             
65
             #Testing _linked_types attr
68
             #Testing _linked_types attr
66
             self.assertEqual(
69
             self.assertEqual(
83
     def test_letype(self):
86
     def test_letype(self):
84
         """ Testing generated LeType childs classes """
87
         """ Testing generated LeType childs classes """
85
         import dyncode
88
         import dyncode
89
+        from dyncode import LeType, LeClass
86
 
90
 
87
         for emtype in self.model.components(EditorialModel.types.EmType):
91
         for emtype in self.model.components(EditorialModel.types.EmType):
88
             letype_name = LeFactory.name2classname(emtype.name)
92
             letype_name = LeFactory.name2classname(emtype.name)
95
             #Testing inheritance
99
             #Testing inheritance
96
             self.assertEqual(
100
             self.assertEqual(
97
                 set(letype.__bases__),
101
                 set(letype.__bases__),
98
-                set([leapi.letype.LeType, letype._leclass])
102
+                set([LeType, letype._leclass])
99
             )
103
             )
100
 
104
 
101
             #Testing _fields
105
             #Testing _fields

+ 3
- 2
leapi/test/test_leobject.py View File

26
     def test_uid2leobj(self):
26
     def test_uid2leobj(self):
27
         """ Testing _Leobject.uid2leobj() """
27
         """ Testing _Leobject.uid2leobj() """
28
         import dyncode
28
         import dyncode
29
+        from dyncode import LeType, LeClass
29
         for i in dyncode.LeObject._me_uid.keys():
30
         for i in dyncode.LeObject._me_uid.keys():
30
             cls = dyncode.LeObject.uid2leobj(i)
31
             cls = dyncode.LeObject.uid2leobj(i)
31
-            if leapi.letype.LeType in cls.__bases__:
32
+            if LeType in cls.__bases__:
32
                 self.assertEqual(i, cls._type_id)
33
                 self.assertEqual(i, cls._type_id)
33
-            elif leapi.leclass.LeClass in cls.__bases__:
34
+            elif LeClass in cls.__bases__:
34
                 self.assertEqual(i, cls._class_id)
35
                 self.assertEqual(i, cls._class_id)
35
             else:
36
             else:
36
                 self.fail("Bad value returned : '%s'"%cls)
37
                 self.fail("Bad value returned : '%s'"%cls)

+ 3
- 3
leapi/test/test_letype.py View File

24
     @unittest.skip("Waiting for EmFieldType full implementation")
24
     @unittest.skip("Waiting for EmFieldType full implementation")
25
     def test_init(self):
25
     def test_init(self):
26
         """ testing the constructor """
26
         """ testing the constructor """
27
-        from dyncode import Publication, Numero, LeObject
27
+        from dyncode import Publication, Numero, LeObject, LeType
28
         
28
         
29
         with self.assertRaises(NotImplementedError):
29
         with self.assertRaises(NotImplementedError):
30
-            leapi.letype.LeType(42)
30
+            LeType(42)
31
 
31
 
32
         badargs = [
32
         badargs = [
33
             {'class_id':Numero._class_id + 1},
33
             {'class_id':Numero._class_id + 1},
45
             with self.assertRaises(expect_e, msg="Invalid argument given %s"%badarg):
45
             with self.assertRaises(expect_e, msg="Invalid argument given %s"%badarg):
46
                 Numero(**badarg)
46
                 Numero(**badarg)
47
     
47
     
48
-    @patch('leapi.letype.LeType.populate')
48
+    @patch('leapi.letype._LeType.populate')
49
     def test_datas(self, dsmock):
49
     def test_datas(self, dsmock):
50
         """ Testing the datas @property method """
50
         """ Testing the datas @property method """
51
         from dyncode import Publication, Numero, LeObject
51
         from dyncode import Publication, Numero, LeObject

Loading…
Cancel
Save