Pārlūkot izejas kodu

Tests + bugfix on LeObject.get method

- Changed the way of instanciating results object in get (using __new__ )
Yann Weber 8 gadus atpakaļ
vecāks
revīzija
33b9ad84c6
3 mainītis faili ar 99 papildinājumiem un 68 dzēšanām
  1. 41
    64
      lodel/leapi/leobject.py
  2. 4
    4
      lodel/leapi/query.py
  3. 54
    0
      tests/leapi/test_leobject.py

+ 41
- 64
lodel/leapi/leobject.py Parādīt failu

@@ -26,21 +26,23 @@ class LeObjectValues(object):
26 26
     # @param set_callback method : The LeObject.set_datas() method of corresponding LeObject class
27 27
     # @param get_callback method : The LeObject.get_datas() method of corresponding LeObject class
28 28
     def __init__(self, fieldnames_callback, set_callback, get_callback):
29
-        self.__setter = set_callback
30
-        self.__getter = get_callback
29
+        self._setter = set_callback
30
+        self._getter = get_callback
31 31
     
32 32
     ##@brief Provide read access to datas values
33 33
     # @note Read access should be provided for all fields
34 34
     # @param fname str : Field name
35 35
     def __getattribute__(self, fname):
36
-        return self.__getter(fname)
36
+        getter = super().__getattribute__('_getter')
37
+        return getter(fname)
37 38
     
38 39
     ##@brief Provide write access to datas values
39 40
     # @note Write acces shouldn't be provided for internal or immutable fields
40 41
     # @param fname str : Field name
41 42
     # @param fval * : the field value
42 43
     def __setattribute__(self, fname, fval):
43
-        return self.__setter(fname, fval)
44
+        setter = super().__getattribute__('_setter')
45
+        return setter(fname, fval)
44 46
         
45 47
 
46 48
 class LeObject(object):
@@ -56,17 +58,26 @@ class LeObject(object):
56 58
     ##@breif Read & write datasource ( see @ref lodel2_datasources )
57 59
     _rw_datasource = None
58 60
 
59
-    ##@brief Construct an object representing an Editorial component
60
-    # @note Can be considered as EmClass instance
61
-    def __init__(self, **kwargs):
62
-        if self._abstract:
63
-            raise NotImplementedError("%s is abstract, you cannot instanciate it." % self.__class__.__name__ )
61
+    def __new__(cls, **kwargs):
62
+        
63
+        self = object.__new__(cls)
64 64
         ##@brief A dict that stores fieldvalues indexed by fieldname
65 65
         self.__datas = { fname:None for fname in self._fields }
66 66
         ##@brief Store a list of initianilized fields when instanciation not complete else store True
67 67
         self.__initialized = list()
68 68
         ##@brief Datas accessor. Instance of @ref LeObjectValues
69 69
         self.d = LeObjectValues(self.fieldnames, self.set_data, self.data)
70
+        for fieldname, fieldval in kwargs.items():
71
+            self.__datas[fieldname] = fieldval
72
+            self.__initialized.append(fieldname)
73
+        self.__set_initialized()
74
+        return self
75
+
76
+    ##@brief Construct an object representing an Editorial component
77
+    # @note Can be considered as EmClass instance
78
+    def __init__(self, **kwargs):
79
+        if self._abstract:
80
+            raise NotImplementedError("%s is abstract, you cannot instanciate it." % self.__class__.__name__ )
70 81
 
71 82
         # Checks that uid is given
72 83
         for uid_name in self._uid:
@@ -75,25 +86,24 @@ class LeObject(object):
75 86
             self.__datas[uid_name] = kwargs[uid_name]
76 87
             del(kwargs[uid_name])
77 88
             self.__initialized.append(uid_name)
78
-        
89
+
79 90
         # Processing given fields
80 91
         allowed_fieldnames = self.fieldnames(include_ro = False)
81
-        err_list = list()
92
+        err_list = dict()
82 93
         for fieldname, fieldval in kwargs.items():
83 94
             if fieldname not in allowed_fieldnames:
84 95
                 if fieldname in self._fields:
85
-                    err_list.append(
86
-                        LeApiError("Value given for internal field : '%s'" % fieldname)
87
-                    )
96
+                    err_list[fieldname] = LeApiError(
97
+                        "Value given but the field is internal")
88 98
                 else:
89
-                    err_list.append(
90
-                        LeApiError("Unknown fieldname : '%s'" % fieldname)
91
-                    )
99
+                    err_list[fieldname] = LeApiError(
100
+                        "Unknown fieldname : '%s'" % fieldname)
92 101
             else:
93 102
                 self.__datas[fieldname] = fieldval
94 103
                 self.__initialized.append(fieldname)
95 104
         if len(err_list) > 0:
96
-            raise LeApiErrors(err_list)
105
+            raise LeApiErrors(msg = "Unable to __init__ %s" % self.__class__,
106
+                exceptions = err_list)
97 107
         self.__set_initialized()
98 108
     
99 109
     #-----------------------------------#
@@ -537,43 +547,6 @@ raised when trying to import Datasource"
537 547
         deleted += result
538 548
         return deleted
539 549
             
540
-    
541
-    ## @brief Load an instance of LeObject
542
-    #@param uid a list of tuple (uid_field_nane, value) ou a single value
543
-    #@return an instance of a subclass of LeObject
544
-    @classmethod
545
-    def load(cls, uid_tuples):
546
-        query_filter = list()
547
-        uids = cls._uid
548
-        if uids.isinstance(tuple):
549
-            if not uid_tuples.isinstance(list):
550
-                raise AttributeError ("In %s:load : uid must be a list of tuple" % cls.__name__)
551
-            elif len(uid_tuples) != len(uids):
552
-                raise AttributeError ("In %s:load : must have %d uid fields" % len(uids))
553
-            for fieldname, fieldvalue in uid_tuples:
554
-                if fieldname in uids:
555
-                    dhdl = cls.data_handler(fieldname)
556
-                    if dhdl.check_data_value(fieldvalue)[1] is None:
557
-                        query_filter.append((fieldname, '=', fieldvalue))
558
-                    else:
559
-                        raise AttributeError("n %s:load :%s not a valid value for %s" % (fieldvalue, fieldname))
560
-                else:
561
-                    raise AttributeError ("In %s:load :%s not a uid field for class %s" % (fieldname, cls.__name__))
562
-        else:
563
-            dhdl = cls.data_handler(uids)
564
-            if dhdl.check_data_value(uid_tuples)[1] is None:
565
-                query_filter.append((uids, '=', uid_tuples))
566
-            else:
567
-                raise AttributeError("n %s:load :%s not a valid value for %s" % (uid_tuples, uids))
568
-        query = LeGetQuery(cls, query_filter, limit = 1)
569
-        try:
570
-            result=query.execute()
571
-        except LeQueryError as err:
572
-            print("Unable to load object of type %s" % cls.__name__)
573
-            raise err
574
-        
575
-        return cls.name2class(res[CLASS_IDENTIFIER])(result[0])
576
-        
577 550
     ## @brief Get instances of LeObject
578 551
     #
579 552
     #@param target_class LeObject : class of object the query is about
@@ -589,16 +562,19 @@ raised when trying to import Datasource"
589 562
     #@return a list of items (lists of (fieldname, fieldvalue))
590 563
     @classmethod
591 564
     def get(cls, query_filters, field_list=None, order=None, group=None, limit=None, offset=0):
592
-        if isinstance(cls._uids, tuple):
593
-            for uid in cls._uids:
594
-                if uid not in field_list:
595
-                    raise AttributeError("In %s:get : Cannot instanciate a LeObject without it's identifier" % cls.__name__)
565
+        if field_list is None:
566
+            field_list = self.fieldnames(True)
596 567
         else:
597
-            if uid not in field_list:
598
-                raise AttributeError("In %s:get : Cannot instanciate a LeObject without it's identifier" % cls.__name__)
599
-
568
+            for uid in [ uidname
569
+                for uidname in cls.uid_fieldname()
570
+                if uidname not in field_list ]:
571
+                field_list.append(uid)
572
+            if CLASS_ID_FIELDNAME not in field_list:
573
+                field_list.append(CLASS_ID_FIELDNAME)
600 574
         try:
601
-            query = LeGetQuery(cls, query_filter, field_list = field_list, order = order, group = group, limit = limit, offset = offset)
575
+            query = LeGetQuery(
576
+                cls, query_filters = query_filters, field_list = field_list,
577
+                order = order, group = group, limit = limit, offset = offset)
602 578
         except ValueError as err:
603 579
             raise err
604 580
             
@@ -609,7 +585,8 @@ raised when trying to import Datasource"
609 585
         
610 586
         objects = list()
611 587
         for res in result:
612
-            inst = cls.name2class(res[CLASS_ID_FIELDNAME])(res)
588
+            res_cls = cls.name2class(res[CLASS_ID_FIELDNAME])
589
+            inst = res_cls.__new__(res_cls,**res)
613 590
             objects.append(inst)
614 591
         
615 592
         return objects

+ 4
- 4
lodel/leapi/query.py Parādīt failu

@@ -199,7 +199,7 @@ class LeFilteredQuery(LeQuery):
199 199
                 for tclass, tfield in ref_dict.items():
200 200
                     query = LeGetQuery(
201 201
                         target_class = tclass,
202
-                        query_filter = [(tfield, op, value)],
202
+                        query_filters = [(tfield, op, value)],
203 203
                         field_list = [tfield])
204 204
                     subq.append((rfield, query))
205 205
         self.subqueries = subq
@@ -598,8 +598,8 @@ class LeGetQuery(LeFilteredQuery):
598 598
     #@param group list : A list of field names or tuple (FIELDNAME,[ASC | DESC])
599 599
     #@param limit int : The maximum number of returned results
600 600
     #@param offset int : offset
601
-    def __init__(self, target_class, query_filter, **kwargs):
602
-        super().__init__(target_class, query_filter)
601
+    def __init__(self, target_class, query_filters, **kwargs):
602
+        super().__init__(target_class, query_filters)
603 603
         
604 604
         ##@brief The fields to get
605 605
         self.__field_list = None
@@ -631,7 +631,7 @@ class LeGetQuery(LeFilteredQuery):
631 631
             self.__group = kwargs['group']
632 632
         if 'limit' in kwargs:
633 633
             try:
634
-                self.__limit = int(kwargs[limit])
634
+                self.__limit = int(kwargs['limit'])
635 635
                 if self.__limit <= 0:
636 636
                     raise ValueError()
637 637
             except ValueError:

+ 54
- 0
tests/leapi/test_leobject.py Parādīt failu

@@ -189,3 +189,57 @@ class LeObjectQueryMockTestCase(unittest.TestCase):
189 189
                     pass
190 190
                 mock_init.assert_called_once_with(
191 191
                     dyncode.Person, [('lodel_id', '=', 1)])
192
+        
193
+        with patch.object(
194
+            LeUpdateQuery, 'execute', return_value = None) as mock_update:
195
+            with patch.object(
196
+                LeObject, 'datas', return_value = {
197
+                    'lodel_id': 1, 'firstname': 'foo', 'lastname': 'bar',
198
+                    'fullname': 'Foo Bar', 'alias': None }) as mock_datas:
199
+            
200
+                inst = dyncode.Person(
201
+                    lodel_id = 1, firstname = "foo", lastname = "bar")
202
+                inst.update()
203
+                mock_update.assert_called_once_with({
204
+                    'lodel_id': 1, 'firstname': 'foo', 'lastname': 'bar',
205
+                    'fullname': 'Foo Bar', 'alias': None })
206
+                    
207
+    
208
+    def test_get(self):
209
+        """ Checking that LeObject.get method calls LeGetQuery
210
+            correctly """
211
+        get_args = {
212
+            'query_filters': ['lodel_id = 1'],
213
+            'field_list': ['firstname'],
214
+            'order': ['firstname'],
215
+            'group': ['alias'],
216
+            'limit': 42,
217
+            'offset': 24}
218
+
219
+        with patch.object(
220
+            LeGetQuery, '__init__', return_value = None) as mock_init:
221
+            
222
+            try:
223
+                dyncode.Person.get(**get_args)
224
+            except AttributeError:
225
+                pass
226
+
227
+            mock_init.assert_called_once_with(
228
+                dyncode.Person,
229
+                **get_args)
230
+
231
+        ret_val = [{
232
+            'lodel_id': 1,
233
+            'firstname': 'foo',
234
+            'lastname': 'bar',
235
+            'fullname': 'foo bar',
236
+            'alias': None,
237
+            'classname': 'Person'}]
238
+        with patch.object(
239
+            LeGetQuery, 'execute', return_value = ret_val) as mock_execute:
240
+            results = dyncode.Person.get(**get_args)
241
+            mock_execute.assert_called_once_with()
242
+            res = results[0]
243
+            self.assertEqual(res.d.lodel_id, 1)
244
+            self.assertEqual(res.d.firstname, 'foo')
245
+            self.assertEqual(res.d.lastname, 'bar')

Notiek ielāde…
Atcelt
Saglabāt