Browse Source

Delete is_exist

prieto 7 years ago
parent
commit
cdd13d9b4b

+ 109
- 101
lodel/auth/client.py View File

11
     'lodel.logger': 'logger',
11
     'lodel.logger': 'logger',
12
     'lodel.plugin': [('SessionHandlerPlugin', 'SessionHandler')],
12
     'lodel.plugin': [('SessionHandlerPlugin', 'SessionHandler')],
13
     'lodel.auth.exceptions': ['ClientError', 'ClientAuthenticationFailure',
13
     'lodel.auth.exceptions': ['ClientError', 'ClientAuthenticationFailure',
14
-        'ClientPermissionDenied', 'ClientAuthenticationError'],
15
-    'lodel.leapi.query': ['LeGetQuery'],})
14
+                              'ClientPermissionDenied', 'ClientAuthenticationError'],
15
+    'lodel.leapi.query': ['LeGetQuery'], })
16
 
16
 
17
-##@brief Client metaclass designed to implements container accessor on 
18
-#Client Class
17
+# @brief Client metaclass designed to implements container accessor on
18
+# Client Class
19
 #
19
 #
20
 #@todo Maybe we can delete this metaclass....
20
 #@todo Maybe we can delete this metaclass....
21
+
22
+
21
 class ClientMetaclass(type):
23
 class ClientMetaclass(type):
22
-    
24
+
23
     def __init__(self, name, bases, attrs):
25
     def __init__(self, name, bases, attrs):
24
         return super(ClientMetaclass, self).__init__(name, bases, attrs)
26
         return super(ClientMetaclass, self).__init__(name, bases, attrs)
25
 
27
 
26
     def __getitem__(self, key):
28
     def __getitem__(self, key):
27
-        return self.datas()[key]
29
+        return self.data()[key]
28
 
30
 
29
     def __delitem__(self, key):
31
     def __delitem__(self, key):
30
-        del(self.datas()[key])
32
+        del(self.data()[key])
31
 
33
 
32
     def __setitem__(self, key, value):
34
     def __setitem__(self, key, value):
33
         if self.get_session_token() is None:
35
         if self.get_session_token() is None:
34
             self.set_session_token(SessionHandler.start())
36
             self.set_session_token(SessionHandler.start())
35
-        datas = self.datas()
36
-        datas[key] = value
37
+        data = self.data()
38
+        data[key] = value
37
 
39
 
38
     def __str__(self):
40
     def __str__(self):
39
         return str(self._instance)
41
         return str(self._instance)
40
 
42
 
41
-##@brief Abstract singleton class designed to handle client informations
43
+# @brief Abstract singleton class designed to handle client informations
42
 #
44
 #
43
 # This class is designed to handle client authentication and sessions
45
 # This class is designed to handle client authentication and sessions
44
-class Client(object, metaclass = ClientMetaclass):
45
-    
46
-    ##@brief Singleton instance
46
+
47
+
48
+class Client(object, metaclass=ClientMetaclass):
49
+
50
+    # @brief Singleton instance
47
     _instance = None
51
     _instance = None
48
-    ##@brief List of dict that stores field ref for login and password
52
+    # @brief List of dict that stores field ref for login and password
49
     #
53
     #
50
-    # Storage specs : 
54
+    # Storage specs :
51
     #
55
     #
52
     # A list of dict, with keys 'login' and 'password', items are tuple.
56
     # A list of dict, with keys 'login' and 'password', items are tuple.
53
-    #- login tuple contains (LeObjectChild, FieldName, link_field) with:
57
+    # - login tuple contains (LeObjectChild, FieldName, link_field) with:
54
     # - LeObjectChild the dynclass containing the login
58
     # - LeObjectChild the dynclass containing the login
55
     # - Fieldname the fieldname of LeObjectChild containing the login
59
     # - Fieldname the fieldname of LeObjectChild containing the login
56
     # - link_field None if both login and password are in the same
60
     # - link_field None if both login and password are in the same
57
     # LeObjectChild. Else contains the field that make the link between
61
     # LeObjectChild. Else contains the field that make the link between
58
     # login LeObject and password LeObject
62
     # login LeObject and password LeObject
59
-    #- password typle contains (LeObjectChild, FieldName)
63
+    # - password typle contains (LeObjectChild, FieldName)
60
     _infos_fields = None
64
     _infos_fields = None
61
-    
62
-    ##@brief Constant that stores the session key that stores authentication
63
-    #informations
65
+
66
+    # @brief Constant that stores the session key that stores authentication
67
+    # informations
64
     _AUTH_DATANAME = '__auth_user_infos'
68
     _AUTH_DATANAME = '__auth_user_infos'
65
-    
66
 
69
 
67
-    ##@brief Constructor
70
+    # @brief Constructor
68
     #@param session_token mixed : Session token provided by client to interface
71
     #@param session_token mixed : Session token provided by client to interface
69
-    def __init__(self,session_token = None):
72
+    def __init__(self, session_token=None):
70
         logger.debug(session_token)
73
         logger.debug(session_token)
71
         if self.__class__ == Client:
74
         if self.__class__ == Client:
72
             raise NotImplementedError("Abstract class")
75
             raise NotImplementedError("Abstract class")
73
         logger.debug("New instance of Client child class %s" %
76
         logger.debug("New instance of Client child class %s" %
74
-            self.__class__.__name__)
77
+                     self.__class__.__name__)
75
         if Client._instance is not None:
78
         if Client._instance is not None:
76
             old = Client._instance
79
             old = Client._instance
77
             Client._instance = None
80
             Client._instance = None
78
             del(old)
81
             del(old)
79
             logger.debug("Replacing old Client instance by a new one")
82
             logger.debug("Replacing old Client instance by a new one")
80
         else:
83
         else:
81
-            #first instanciation, fetching settings
84
+            # first instanciation, fetching settings
82
             self.fetch_settings()
85
             self.fetch_settings()
83
-        ##@brief Stores infos for authenticated users (None == anonymous)
86
+        # @brief Stores infos for authenticated users (None == anonymous)
84
         self.__user = None
87
         self.__user = None
85
-        ##@brief Stores the session handler
88
+        # @brief Stores the session handler
86
         Client._instance = self
89
         Client._instance = self
87
-        ##@brief Stores LodelSession instance
88
-        
89
-        self.__datas = dict()
90
+        # @brief Stores LodelSession instance
91
+        self.__data = dict()
90
         if session_token is not None:
92
         if session_token is not None:
91
-            self.__datas = SessionHandler.restore(session_token)
93
+            self.__data = SessionHandler.restore(session_token)
92
         self.__session_token = session_token
94
         self.__session_token = session_token
93
-        
95
+
94
         logger.debug("New client : %s" % self)
96
         logger.debug("New client : %s" % self)
95
-    
97
+
96
     def __del__(self):
98
     def __del__(self):
97
         del(self.__session_token)
99
         del(self.__session_token)
98
-        del(self.__datas)
100
+        del(self.__data)
101
+    # @brief Returns session
102
+    #@ returns the dict which stores session
99
 
103
 
100
     @classmethod
104
     @classmethod
101
-    def datas(cls):
102
-        return cls._instance.__datas
103
-    
105
+    def data(cls):
106
+        return cls._instance.__data
107
+
108
+    # @brief Returns the user's information contained in the session's data
104
     @classmethod
109
     @classmethod
105
     def user(cls):
110
     def user(cls):
106
-        if '__auth_user_infos' in cls._instance.__datas:
107
-            return cls._instance.__datas['__auth_user_infos']
111
+        if '__auth_user_infos' in cls._instance.__data:
112
+            return cls._instance.__data['__auth_user_infos']
108
         else:
113
         else:
109
             return None
114
             return None
115
+
116
+    # @brief Returns the session's token
110
     @classmethod
117
     @classmethod
111
     def get_session_token(cls):
118
     def get_session_token(cls):
112
         return cls._instance.__session_token
119
         return cls._instance.__session_token
113
-    
120
+
121
+    # @brief Set the session's token
122
+    #@param the value of the token
114
     @classmethod
123
     @classmethod
115
     def set_session_token(cls, value):
124
     def set_session_token(cls, value):
116
         cls._instance.__session_token = value
125
         cls._instance.__session_token = value
117
-    
118
-    ##@brief Try to authenticate a user with a login and a password
126
+
127
+    # @brief Try to authenticate a user with a login and a password
119
     #@param login str : provided login
128
     #@param login str : provided login
120
     #@param password str : provided password (hash)
129
     #@param password str : provided password (hash)
121
     #@warning brokes composed UID
130
     #@warning brokes composed UID
122
-    #@note implemets multiple login/password sources (useless ?)
131
+    #@note implements multiple login/password sources (useless ?)
123
     #@todo composed UID broken method
132
     #@todo composed UID broken method
124
     #@todo allow to provide an authentication source
133
     #@todo allow to provide an authentication source
125
     @classmethod
134
     @classmethod
126
-    def authenticate(self, login = None, password = None):
127
-        #Authenticate
135
+    def authenticate(self, login=None, password=None):
136
+        # Authenticate
128
         for infos in self._infos_fields:
137
         for infos in self._infos_fields:
129
             logger.debug(self._infos_fields)
138
             logger.debug(self._infos_fields)
130
             login_cls = infos['login'][0]
139
             login_cls = infos['login'][0]
131
             pass_cls = infos['password'][0]
140
             pass_cls = infos['password'][0]
132
             qfilter = "{passfname} = {passhash}"
141
             qfilter = "{passfname} = {passhash}"
133
-            uid_fname = login_cls.uid_fieldname()[0] #COMPOSED UID BROKEN
142
+            uid_fname = login_cls.uid_fieldname()[0]  # COMPOSED UID BROKEN
134
             if login_cls == pass_cls:
143
             if login_cls == pass_cls:
135
-                #Same EmClass for login & pass
144
+                # Same EmClass for login & pass
136
                 qfilter = qfilter.format(
145
                 qfilter = qfilter.format(
137
-                    passfname = infos['password'][1],
138
-                    passhash = password)
146
+                    passfname=infos['password'][1],
147
+                    passhash=password)
139
             else:
148
             else:
140
-                #Different EmClass, building a relational filter
149
+                # Different EmClass, building a relational filter
141
                 passfname = "%s.%s" % (infos['login'][2], infos['password'][1])
150
                 passfname = "%s.%s" % (infos['login'][2], infos['password'][1])
142
                 qfilter = qfilter.format(
151
                 qfilter = qfilter.format(
143
-                    passfname = passfname,
144
-                    passhash = password)
152
+                    passfname=passfname,
153
+                    passhash=password)
145
             getq = LeGetQuery(infos['login'][0], qfilter,
154
             getq = LeGetQuery(infos['login'][0], qfilter,
146
-                field_list = [uid_fname], limit = 1)
155
+                              field_list=[uid_fname], limit=1)
147
             req = getq.execute()
156
             req = getq.execute()
148
             if len(req) == 1:
157
             if len(req) == 1:
149
-                self.__set_authenticated(infos['login'][0],req[0][uid_fname])
158
+                self.__set_authenticated(infos['login'][0], req[0][uid_fname])
150
                 break
159
                 break
151
         if self.is_anonymous():
160
         if self.is_anonymous():
152
-            self.authentication_failure() #Security logging
153
-    
154
-    ##@brief Attempt to restore a session given a session token
161
+            self.authentication_failure()  # Security logging
162
+
163
+    # @brief Attempt to restore a session given a session token
155
     #@param token mixed : a session token
164
     #@param token mixed : a session token
156
-    #@return Session datas (a dict)
165
+    #@return Session data (a dict)
157
     #@throw ClientAuthenticationFailure if token is not valid or not
166
     #@throw ClientAuthenticationFailure if token is not valid or not
158
-    #existing
167
+    # existing
159
     @classmethod
168
     @classmethod
160
     def restore_session(cls, token):
169
     def restore_session(cls, token):
161
         cls._assert_instance()
170
         cls._assert_instance()
162
         if cls._instance.__session_token is not None:
171
         if cls._instance.__session_token is not None:
163
             raise ClientAuthenticationError("Trying to restore a session, but \
172
             raise ClientAuthenticationError("Trying to restore a session, but \
164
-a session is allready started !!!")
173
+a session is already started !!!")
165
         try:
174
         try:
166
-            cls._instance.__datas = SessionHandler.restore(token)
175
+            cls._instance.__data = SessionHandler.restore(token)
167
             cls._instance.__session_token = token
176
             cls._instance.__session_token = token
168
         except ClientAuthenticationFailure:
177
         except ClientAuthenticationFailure:
169
-            logger.warning("Session restoring fails")
170
-        return copy.copy(cls._instance.datas)
171
-    
172
-    ##@brief Return the current session token or None
178
+            logger.warning("Session restoring failed")
179
+        return copy.copy(cls._instance.data)
180
+
181
+    # @brief Returns the current session token or None
173
     #@return A session token or None
182
     #@return A session token or None
174
     @classmethod
183
     @classmethod
175
     def session_token(cls):
184
     def session_token(cls):
176
         cls._assert_instance()
185
         cls._assert_instance()
177
         return cls._instance.__session_token
186
         return cls._instance.__session_token
178
 
187
 
179
-   
180
-    ##@brief Delete current session
188
+    # @brief Deletes current session
181
     @classmethod
189
     @classmethod
182
     def destroy(cls):
190
     def destroy(cls):
183
         cls._assert_instance()
191
         cls._assert_instance()
184
         SessionHandler.destroy(cls._instance.__session_token)
192
         SessionHandler.destroy(cls._instance.__session_token)
185
         cls._instance.__session_token = None
193
         cls._instance.__session_token = None
186
-        cls._instance.__datas = dict()
187
-    
188
-    ##@brief Delete current client and save its session
194
+        cls._instance.__data = dict()
195
+
196
+    # @brief Deletes current client and saves its session
189
     @classmethod
197
     @classmethod
190
     def clean(cls):
198
     def clean(cls):
191
         if cls._instance.__session_token is not None:
199
         if cls._instance.__session_token is not None:
192
-            SessionHandler.save(cls._instance.__session_token, cls._instance.__datas)
200
+            SessionHandler.save(cls._instance.__session_token, cls._instance.__data)
193
         if Client._instance is not None:
201
         if Client._instance is not None:
194
             del(Client._instance)
202
             del(Client._instance)
195
         Client._instance = None
203
         Client._instance = None
196
-    
197
-    ##@brief Test wether a client is anonymous or logged in
204
+
205
+    # @brief Tests if a client is anonymous or logged in
198
     #@return True if client is anonymous
206
     #@return True if client is anonymous
199
     @classmethod
207
     @classmethod
200
     def is_anonymous(cls):
208
     def is_anonymous(cls):
201
         return Client._instance.user() is None
209
         return Client._instance.user() is None
202
-        
203
-    ##@brief Method to call on authentication failure
210
+
211
+    # @brief Method to be called on authentication failure
204
     #@throw ClientAuthenticationFailure
212
     #@throw ClientAuthenticationFailure
205
-    #@throw LodelFatalError if no Client child instance found
213
+    #@throw LodelFatalError if no Client child instance is found
206
     @classmethod
214
     @classmethod
207
     def authentication_failure(cls):
215
     def authentication_failure(cls):
208
         cls._generic_error(ClientAuthenticationFailure)
216
         cls._generic_error(ClientAuthenticationFailure)
209
-    
210
-    ##@brief Method to call on authentication error
217
+
218
+    # @brief Method to be called on authentication error
211
     #@throw ClientAuthenticationError
219
     #@throw ClientAuthenticationError
212
-    #@throw LodelFatalError if no Client child instance found
220
+    #@throw LodelFatalError if no Client child instance is found
213
     @classmethod
221
     @classmethod
214
-    def authentication_error(cls, msg = "Unknow error"):
222
+    def authentication_error(cls, msg="Unknow error"):
215
         cls._generic_error(ClientAuthenticationError, msg)
223
         cls._generic_error(ClientAuthenticationError, msg)
216
 
224
 
217
-    ##@brief Method to call on permission denied error
225
+    # @brief Method to be called on permission denied error
218
     #@throw ClientPermissionDenied
226
     #@throw ClientPermissionDenied
219
-    #@throw LodelFatalError if no Client child instance found
227
+    #@throw LodelFatalError if no Client child instance is found
220
     @classmethod
228
     @classmethod
221
-    def permission_denied_error(cls, msg = ""):
229
+    def permission_denied_error(cls, msg=""):
222
         cls._generic_error(ClientPermissionDenied, msg)
230
         cls._generic_error(ClientPermissionDenied, msg)
223
-    
224
-    ##@brief Generic error method
231
+
232
+    # @brief Generic error method
225
     #@see Client::authentication_failure() Client::authentication_error()
233
     #@see Client::authentication_failure() Client::authentication_error()
226
-    #Client::permission_denied_error()
227
-    #@throw LodelFatalError if no Client child instance found
234
+    # Client::permission_denied_error()
235
+    #@throw LodelFatalError if no Client child instance is found
228
     @classmethod
236
     @classmethod
229
-    def _generic_error(cls, expt, msg = ""):
237
+    def _generic_error(cls, expt, msg=""):
230
         cls._assert_instance()
238
         cls._assert_instance()
231
         raise expt(Client._instance, msg)
239
         raise expt(Client._instance, msg)
232
-    
233
-    ##@brief Assert that an instance of Client child class exists
234
-    #@throw LodelFataError if no instance of Client child class found
240
+
241
+    # @brief Asserts that an instance of Client child class exists
242
+    #@throw LodelFataError if no instance of Client child class is found
235
     @classmethod
243
     @classmethod
236
     def _assert_instance(cls):
244
     def _assert_instance(cls):
237
         if Client._instance is None:
245
         if Client._instance is None:
238
             raise LodelFatalError("No client instance found. Abording.")
246
             raise LodelFatalError("No client instance found. Abording.")
239
 
247
 
240
-    ##@brief Class method that fetches conf
248
+    # @brief Class method that fetches conf
241
     #
249
     #
242
-    #This method populates Client._infos_fields . This attribute stores
243
-    #informations on login and password location (LeApi object & field)
250
+    # This method populates Client._infos_fields . This attribute stores
251
+    # informations on login and password location (LeApi object & field)
244
     @classmethod
252
     @classmethod
245
     def fetch_settings(cls):
253
     def fetch_settings(cls):
246
         LodelContext.expose_dyncode(globals(), 'dyncode')
254
         LodelContext.expose_dyncode(globals(), 'dyncode')
247
         if cls._infos_fields is None:
255
         if cls._infos_fields is None:
248
             cls._infos_fields = list()
256
             cls._infos_fields = list()
249
         else:
257
         else:
250
-            #Allready fetched
258
+            # Already fetched
251
             return
259
             return
252
         infos = (
260
         infos = (
253
             Settings.auth.login_classfield,
261
             Settings.auth.login_classfield,
266
                 if fdh.is_reference() and res_infos[1][0] in fdh.linked_classes():
274
                 if fdh.is_reference() and res_infos[1][0] in fdh.linked_classes():
267
                     link_field = fname
275
                     link_field = fname
268
             if link_field is None:
276
             if link_field is None:
269
-                #Unable to find link between login & password EmClasses
277
+                # Unable to find link between login & password EmClass
270
                 raise AuthenticationError("Unable to find a link between \
278
                 raise AuthenticationError("Unable to find a link between \
271
 login EmClass '%s' and password EmClass '%s'. Abording..." % (
279
 login EmClass '%s' and password EmClass '%s'. Abording..." % (
272
                     res_infos[0][0], res_infos[1][0]))
280
                     res_infos[0][0], res_infos[1][0]))
273
         res_infos[0] = (res_infos[0][0], res_infos[0][1], link_field)
281
         res_infos[0] = (res_infos[0][0], res_infos[0][1], link_field)
274
         cls._infos_fields.append(
282
         cls._infos_fields.append(
275
-            {'login':res_infos[0], 'password':res_infos[1]})
283
+            {'login': res_infos[0], 'password': res_infos[1]})
276
 
284
 
277
-    ##@brief Set a user as authenticated and start a new session
285
+    # @brief Sets a user as authenticated and starts a new session
278
     #@param leo LeObject child class : the LeObject the user is stored in
286
     #@param leo LeObject child class : the LeObject the user is stored in
279
     #@param uid str : uniq id (in leo)
287
     #@param uid str : uniq id (in leo)
280
     #@return None
288
     #@return None
281
     @classmethod
289
     @classmethod
282
     def __set_authenticated(cls, leo, uid):
290
     def __set_authenticated(cls, leo, uid):
283
         cls._instance.__user = {'classname': leo.__name__, 'uid': uid, 'leoclass': leo}
291
         cls._instance.__user = {'classname': leo.__name__, 'uid': uid, 'leoclass': leo}
284
-        #Store auth infos in session
285
-        cls._instance.__datas[cls._instance.__class__._AUTH_DATANAME] = copy.copy(cls._instance.__user)
286
-
292
+        # Store auth infos in session
293
+        cls._instance.__data[cls._instance.__class__._AUTH_DATANAME] = copy.copy(
294
+            cls._instance.__user)

+ 34
- 29
lodel/editorial_model/components.py View File

36
         self.group = group
36
         self.group = group
37
         super().__init__(display_name, help_text)
37
         super().__init__(display_name, help_text)
38
 
38
 
39
+    # @brief Returns the display_name of the component if it is not None, its uid else
39
     def __str__(self):
40
     def __str__(self):
40
         if self.display_name is None:
41
         if self.display_name is None:
41
             return str(self.uid)
42
             return str(self.uid)
42
         return str(self.display_name)
43
         return str(self.display_name)
43
 
44
 
45
+    # @brief Returns a hash code for the component
44
     def d_hash(self):
46
     def d_hash(self):
45
         m = hashlib.md5()
47
         m = hashlib.md5()
46
         for data in (
48
         for data in (
57
 #@ingroup lodel2_em
59
 #@ingroup lodel2_em
58
 class EmClass(EmComponent):
60
 class EmClass(EmComponent):
59
 
61
 
60
-    # @brief Instanciate a new EmClass
62
+    # @brief Instanciates a new EmClass
61
     #@param uid str : uniq identifier
63
     #@param uid str : uniq identifier
62
     #@param display_name MlString|str|dict : component display_name
64
     #@param display_name MlString|str|dict : component display_name
63
     #@param abstract bool : set the class as asbtract if True
65
     #@param abstract bool : set the class as asbtract if True
78
         self.pure_abstract = bool(pure_abstract)
80
         self.pure_abstract = bool(pure_abstract)
79
         self.__datasource = datasources
81
         self.__datasource = datasources
80
         if not isinstance(datasources, str) and len(datasources) != 2:
82
         if not isinstance(datasources, str) and len(datasources) != 2:
81
-            raise ValueError("datasources arguement can be a single datasource\
83
+            raise ValueError("datasources argument can be a single datasource\
82
  name or two names in a tuple or a list")
84
  name or two names in a tuple or a list")
83
         if self.pure_abstract:
85
         if self.pure_abstract:
84
             self.abtract = True
86
             self.abtract = True
115
                 internal=True,
117
                 internal=True,
116
                 group=group)
118
                 group=group)
117
 
119
 
118
-    # @brief Property that represent a dict of all fields (the EmField defined in this class and all its parents)
119
-    # @todo use Settings.editorialmodel.groups to determine wich fields should be returned
120
+    # @brief Property that represents a dict of all fields 
121
+    # (the EmField objects defined in this class and all their parents)
122
+    # @todo use Settings.editorialmodel.groups to determine which fields should be returned
120
     @property
123
     @property
121
     def __all_fields(self):
124
     def __all_fields(self):
122
         res = dict()
125
         res = dict()
130
     def datasource(self):
133
     def datasource(self):
131
         return self.__datasource
134
         return self.__datasource
132
 
135
 
133
-    # @brief Return the list of all dependencies
136
+    # @brief Returns the list of all dependencies
134
     #
137
     #
135
-    # Reccursive parents listing
138
+    # Recursive parents listing
136
     @property
139
     @property
137
     def parents_recc(self):
140
     def parents_recc(self):
138
         if len(self.parents) == 0:
141
         if len(self.parents) == 0:
155
         except KeyError:
158
         except KeyError:
156
             raise EditorialModelError("No such EmField '%s'" % uid)
159
             raise EditorialModelError("No such EmField '%s'" % uid)
157
 
160
 
158
-    # @brief Keep in __fields only fields contained in active groups
161
+    # @brief Keeps in __fields only fields contained in active groups
159
     def _set_active_fields(self, active_groups):
162
     def _set_active_fields(self, active_groups):
160
         if not Settings.editorialmodel.editormode:
163
         if not Settings.editorialmodel.editormode:
161
             active_fields = []
164
             active_fields = []
165
             self.__fields = {fname: fdh for fname, fdh in self.__fields.items()
168
             self.__fields = {fname: fdh for fname, fdh in self.__fields.items()
166
                              if fdh in active_fields}
169
                              if fdh in active_fields}
167
 
170
 
168
-    # @brief Add a field to the EmClass
171
+    # @brief Adds a field to the EmClass
169
     # @param emfield EmField : an EmField instance
172
     # @param emfield EmField : an EmField instance
170
-    # @warning do not add an EmField allready in another class !
171
-    # @throw EditorialModelException if an EmField with same uid allready in this EmClass (overwritting allowed from parents)
173
+    # @warning do not add an EmField already in another class !
174
+    # @throw EditorialModelException if an EmField with same uid already in this EmClass (overwriting allowed from parents)
172
     # @todo End the override checks (needs methods in data_handlers)
175
     # @todo End the override checks (needs methods in data_handlers)
173
     def add_field(self, emfield):
176
     def add_field(self, emfield):
174
         assert_edit()
177
         assert_edit()
180
             parent_field = self.__all_fields[emfield.uid]
183
             parent_field = self.__all_fields[emfield.uid]
181
             if not emfield.data_handler_instance.can_override(parent_field.data_handler_instance):
184
             if not emfield.data_handler_instance.can_override(parent_field.data_handler_instance):
182
                 raise AttributeError(
185
                 raise AttributeError(
183
-                    "'%s' field override a parent field, but data_handles are not compatible" % emfield.uid)
186
+                    "'%s' field overrides a parent field, but data_handlers are not compatible" % emfield.uid)
184
         self.__fields[emfield.uid] = emfield
187
         self.__fields[emfield.uid] = emfield
185
         return emfield
188
         return emfield
186
 
189
 
187
-    # @brief Create a new EmField and add it to the EmClass
190
+    # @brief Creates a new EmField and adds it to the EmClass
188
     # @param data_handler str : A DataHandler name
191
     # @param data_handler str : A DataHandler name
189
     # @param uid str : the EmField uniq id
192
     # @param uid str : the EmField uniq id
190
     # @param **field_kwargs :  EmField constructor parameters ( see @ref EmField.__init__() )
193
     # @param **field_kwargs :  EmField constructor parameters ( see @ref EmField.__init__() )
221
 #@ingroup lodel2_em
224
 #@ingroup lodel2_em
222
 class EmField(EmComponent):
225
 class EmField(EmComponent):
223
 
226
 
224
-    # @brief Instanciate a new EmField
227
+    # @brief Instanciates a new EmField
225
     # @param uid str : uniq identifier
228
     # @param uid str : uniq identifier
226
     # @param display_name MlString|str|dict : field display_name
229
     # @param display_name MlString|str|dict : field display_name
227
     # @param data_handler str : A DataHandler name
230
     # @param data_handler str : A DataHandler name
256
     def get_data_handler_cls(self):
259
     def get_data_handler_cls(self):
257
         return copy.copy(self.data_handler_cls)
260
         return copy.copy(self.data_handler_cls)
258
 
261
 
259
-    ##@brief Returne the uid of the emclass which contains this field
262
+    ##@brief Returns the uid of the emclass which contains this field
260
     def get_emclass_uid(self):
263
     def get_emclass_uid(self):
261
         return self._emclass.uid
264
         return self._emclass.uid
262
 
265
 
277
 
280
 
278
 class EmGroup(MlNamedObject):
281
 class EmGroup(MlNamedObject):
279
 
282
 
280
-    # @brief Create a new EmGroup
283
+    # @brief Creates a new EmGroup
281
     # @note you should NEVER call the constructor yourself. Use Model.add_group instead
284
     # @note you should NEVER call the constructor yourself. Use Model.add_group instead
282
     # @param uid str : Uniq identifier
285
     # @param uid str : Uniq identifier
283
     # @param depends list : A list of EmGroup dependencies
286
     # @param depends list : A list of EmGroup dependencies
297
             for grp in depends:
300
             for grp in depends:
298
                 if not isinstance(grp, EmGroup):
301
                 if not isinstance(grp, EmGroup):
299
                     raise ValueError("EmGroup expected in depends argument but %s found" % grp)
302
                     raise ValueError("EmGroup expected in depends argument but %s found" % grp)
300
-                self.add_dependencie(grp)
303
+                self.add_dependency(grp)
301
 
304
 
302
-    # @brief Returns EmGroup dependencie
303
-    # @param recursive bool : if True return all dependencies and their dependencies
305
+    # @brief Returns EmGroup dependencies
306
+    # @param recursive bool : if True returns all dependencies and their own dependencies
304
     # @return a dict of EmGroup identified by uid
307
     # @return a dict of EmGroup identified by uid
305
     def dependencies(self, recursive=False):
308
     def dependencies(self, recursive=False):
306
         res = copy.copy(self.require)
309
         res = copy.copy(self.require)
316
         return res
319
         return res
317
 
320
 
318
     # @brief Returns EmGroup applicants
321
     # @brief Returns EmGroup applicants
319
-    # @param recursive bool : if True return all dependencies and their dependencies
322
+    # @param recursive bool : if True returns all dependencies and their dependencies
320
     # @returns a dict of EmGroup identified by uid
323
     # @returns a dict of EmGroup identified by uid
321
     def applicants(self, recursive=False):
324
     def applicants(self, recursive=False):
322
         res = copy.copy(self.required_by)
325
         res = copy.copy(self.required_by)
337
         return (self.__components).copy()
340
         return (self.__components).copy()
338
 
341
 
339
     # @brief Returns EmGroup display_name
342
     # @brief Returns EmGroup display_name
340
-    #  @param lang str | None : If None return default lang translation
343
+    #  @param lang str | None : If None returns default lang translation
341
     #  @returns None if display_name is None, a str for display_name else
344
     #  @returns None if display_name is None, a str for display_name else
342
     def get_display_name(self, lang=None):
345
     def get_display_name(self, lang=None):
343
         name = self.display_name
346
         name = self.display_name
346
         return name.get(lang)
349
         return name.get(lang)
347
 
350
 
348
     # @brief Returns EmGroup help_text
351
     # @brief Returns EmGroup help_text
349
-    #  @param lang str | None : If None return default lang translation
352
+    #  @param lang str | None : If None returns default lang translation
350
     #  @returns None if display_name is None, a str for display_name else
353
     #  @returns None if display_name is None, a str for display_name else
351
     def get_help_text(self, lang=None):
354
     def get_help_text(self, lang=None):
352
         help = self.help_text
355
         help = self.help_text
354
             return None
357
             return None
355
         return help.get(lang)
358
         return help.get(lang)
356
 
359
 
357
-    # @brief Add components in a group
360
+    # @brief Adds components in a group
358
     # @param components list : EmComponent instances list
361
     # @param components list : EmComponent instances list
359
     def add_components(self, components):
362
     def add_components(self, components):
360
         assert_edit()
363
         assert_edit()
369
                     "Expecting components to be a list of EmComponent, but %s found in the list" % type(component))
372
                     "Expecting components to be a list of EmComponent, but %s found in the list" % type(component))
370
         self.__components |= set(components)
373
         self.__components |= set(components)
371
 
374
 
372
-    # @brief Add a dependencie
373
-    # @param em_group EmGroup|iterable : an EmGroup instance or list of instance
374
-    def add_dependencie(self, grp):
375
+    # @brief Add a dependency
376
+    # @param em_group EmGroup|iterable : an EmGroup instance or list of instances
377
+    def add_dependency(self, grp):
375
         assert_edit()
378
         assert_edit()
376
         try:
379
         try:
377
             for group in grp:
380
             for group in grp:
378
-                self.add_dependencie(group)
381
+                self.add_dependency(group)
379
             return
382
             return
380
         except TypeError:
383
         except TypeError:
381
             pass
384
             pass
382
 
385
 
383
         if grp.uid in self.require:
386
         if grp.uid in self.require:
384
             return
387
             return
385
-        if self.__circular_dependencie(grp):
388
+        if self.__circular_dependency(grp):
386
             raise EditorialModelError("Circular dependencie detected, cannot add dependencie")
389
             raise EditorialModelError("Circular dependencie detected, cannot add dependencie")
387
         self.require[grp.uid] = grp
390
         self.require[grp.uid] = grp
388
         grp.required_by[self.uid] = self
391
         grp.required_by[self.uid] = self
406
         self.required_by[grp.uid] = grp
409
         self.required_by[grp.uid] = grp
407
         grp.require[self.uid] = self
410
         grp.require[self.uid] = self
408
 
411
 
409
-    # @brief Search for circular dependencie
412
+    # @brief Search for circular dependency
410
     # @return True if circular dep found else False
413
     # @return True if circular dep found else False
411
-    def __circular_dependencie(self, new_dep):
414
+    def __circular_dependency(self, new_dep):
412
         return self.uid in new_dep.dependencies(True)
415
         return self.uid in new_dep.dependencies(True)
413
 
416
 
414
     # @brief Search for circular applicant
417
     # @brief Search for circular applicant
424
         else:
427
         else:
425
             return self.display_name.get()
428
             return self.display_name.get()
426
 
429
 
430
+    # @brief Computes a d-hash code for the EmGroup
431
+    # @return a string
427
     def d_hash(self):
432
     def d_hash(self):
428
 
433
 
429
         payload = "%s%s%s" % (
434
         payload = "%s%s%s" % (

+ 12
- 6
lodel/editorial_model/model.py View File

42
         super().__init__(display_name, help_text)
42
         super().__init__(display_name, help_text)
43
 
43
 
44
     # @brief EmClass uids accessor
44
     # @brief EmClass uids accessor
45
-    #@return a dict of emclasses
45
+    #@return a copy of the dict containing all emclasses of the model if uid is None
46
+    # else a copy the class with uid uid
46
     def all_classes(self, uid=None):
47
     def all_classes(self, uid=None):
47
         if uid is None:
48
         if uid is None:
48
             return copy.copy(self.__classes)
49
             return copy.copy(self.__classes)
52
             except KeyError:
53
             except KeyError:
53
                 raise EditorialModelException("EmClass not found : '%s'" % uid)
54
                 raise EditorialModelException("EmClass not found : '%s'" % uid)
54
 
55
 
56
+    # @brief EmClass uids accessor
57
+    #@return the dict containing all emclasses of the model if uid is None
58
+    # else the class with uid uid
55
     def all_classes_ref(self, uid=None):
59
     def all_classes_ref(self, uid=None):
56
         if uid is None:
60
         if uid is None:
57
             return self.__classes
61
             return self.__classes
62
                 raise EditorialModelException("EmGroup not found : '%s'" % uid)
66
                 raise EditorialModelException("EmGroup not found : '%s'" % uid)
63
 
67
 
64
     # @brief active EmClass uids accessor
68
     # @brief active EmClass uids accessor
65
-    #@return a list of class uids
69
+    #@return a list of active class uids
66
     def active_classes_uids(self):
70
     def active_classes_uids(self):
67
         return list(self.__active_classes.keys())
71
         return list(self.__active_classes.keys())
68
 
72
 
69
     # @brief EmGroups accessor
73
     # @brief EmGroups accessor
70
-    #@return a dict of groups
74
+    #@return a copy of the dict of the model's group if uid is None
75
+    # else a copy of the group with uniq id uid
71
     def all_groups(self, uid=None):
76
     def all_groups(self, uid=None):
72
         if uid is None:
77
         if uid is None:
73
             return copy.copy(self.__groups)
78
             return copy.copy(self.__groups)
78
                 raise EditorialModelException("EmGroup not found : '%s'" % uid)
83
                 raise EditorialModelException("EmGroup not found : '%s'" % uid)
79
 
84
 
80
     # @brief EmGroups accessor
85
     # @brief EmGroups accessor
81
-    #@return a dict of groups
86
+    #@return the dict of the model's group if uid is None
87
+    # else the group with uniq id uid
82
     def all_groups_ref(self, uid=None):
88
     def all_groups_ref(self, uid=None):
83
         if uid is None:
89
         if uid is None:
84
             return self.__groups
90
             return self.__groups
89
                 raise EditorialModelException("EmGroup not found : '%s'" % uid)
95
                 raise EditorialModelException("EmGroup not found : '%s'" % uid)
90
 
96
 
91
     # @brief active EmClass uids accessor
97
     # @brief active EmClass uids accessor
92
-    #@return a list of class uids
98
+    #@return a list of active group uids
93
     def active_groups_uids(self):
99
     def active_groups_uids(self):
94
         return list(self.__active_groups.keys())
100
         return list(self.__active_groups.keys())
95
 
101
 
97
     #@param uid None | str : give this argument to get a specific EmClass
103
     #@param uid None | str : give this argument to get a specific EmClass
98
     #@return if uid is given returns an EmClass else returns an EmClass
104
     #@return if uid is given returns an EmClass else returns an EmClass
99
     # iterator
105
     # iterator
100
-    #@todo use Settings.editorialmodel.groups to determine wich classes should
106
+    #@todo use Settings.editorialmodel.groups to determine which classes should
101
     # be returned
107
     # be returned
102
     def classes(self, uid=None):
108
     def classes(self, uid=None):
103
         try:
109
         try:

+ 1
- 1
lodel/editorial_model/translator/xmlfile.py View File

460
         group = model.all_groups_ref(uid.text)
460
         group = model.all_groups_ref(uid.text)
461
         group.display_name = name
461
         group.display_name = name
462
         group.help_text = help_text
462
         group.help_text = help_text
463
-        group.add_dependencie(requires)
463
+        group.add_dependency(requires)
464
     else:
464
     else:
465
         group = EmGroup(uid.text, requires, name, help_text)
465
         group = EmGroup(uid.text, requires, name, help_text)
466
 
466
 

+ 2
- 0
lodel/leapi/datahandlers/exceptions.py View File

1
+## @brief Exception classes for datahandlers
2
+
1
 class LodelDataHandlerException(Exception):
3
 class LodelDataHandlerException(Exception):
2
     pass
4
     pass
3
 
5
 

+ 6
- 2
lodel/leapi/datahandlers/references.py View File

9
                          'LodelFatalError', 'DataNoneValid',
9
                          'LodelFatalError', 'DataNoneValid',
10
                          'FieldValidationError']})
10
                          'FieldValidationError']})
11
 
11
 
12
-
12
+## @brief Child class of SingleRef. The object referenced must exist
13
 class Link(SingleRef):
13
 class Link(SingleRef):
14
     pass
14
     pass
15
 
15
 
16
 
16
 
17
 ## @brief Child class of MultipleRef where references are represented in the form of a python list
17
 ## @brief Child class of MultipleRef where references are represented in the form of a python list
18
+# All the objects referenced must exist
18
 class List(MultipleRef):
19
 class List(MultipleRef):
19
 
20
 
20
     ## @brief instanciates a list reference
21
     ## @brief instanciates a list reference
97
 
98
 
98
 ## @brief This Reference class is designed to handler hierarchy with some constraint
99
 ## @brief This Reference class is designed to handler hierarchy with some constraint
99
 class Hierarch(MultipleRef):
100
 class Hierarch(MultipleRef):
100
-    
101
+
101
     directly_editable = False
102
     directly_editable = False
102
 
103
 
103
     ## @brief Instanciate a data handler handling hierarchical relation with constraints
104
     ## @brief Instanciate a data handler handling hierarchical relation with constraints
104
     # @param back_reference tuple : Here it is mandatory to have a back ref (like a parent field)
105
     # @param back_reference tuple : Here it is mandatory to have a back ref (like a parent field)
105
     # @param max_depth int | None :  limit of depth
106
     # @param max_depth int | None :  limit of depth
106
     # @param max_childs int | Nine : maximum number of childs by nodes
107
     # @param max_childs int | Nine : maximum number of childs by nodes
108
+    # @param kwargs : 
109
+    #   - allowed_classes list | None : list of allowed em classes if None no restriction
110
+    #   - internal bool : if False, the field is not internal
107
     def __init__(self, back_reference, max_depth=None, max_childs=None, **kwargs):
111
     def __init__(self, back_reference, max_depth=None, max_childs=None, **kwargs):
108
         super().__init__(back_reference=back_reference,
112
         super().__init__(back_reference=back_reference,
109
                          max_depth=max_depth,
113
                          max_depth=max_depth,

+ 5
- 4
lodel/leapi/exceptions.py View File

4
 LodelContext.expose_modules(globals(), {
4
 LodelContext.expose_modules(globals(), {
5
     'lodel.exceptions': ['LodelExceptions', 'LodelException']})
5
     'lodel.exceptions': ['LodelExceptions', 'LodelException']})
6
 
6
 
7
+##@brief Handles LeApi error
7
 class LeApiError(LodelException):
8
 class LeApiError(LodelException):
8
     pass
9
     pass
9
 
10
 
13
     pass
14
     pass
14
 
15
 
15
 
16
 
16
-##@brief When an error concerns a datas
17
+##@brief When an error concerns a data
17
 class LeApiDataCheckError(LeApiError):
18
 class LeApiDataCheckError(LeApiError):
18
     pass
19
     pass
19
 
20
 
20
-
21
+##@brief Handles LeApi data errors
21
 class LeApiDataCheckErrors(LodelExceptions, LeApiError):
22
 class LeApiDataCheckErrors(LodelExceptions, LeApiError):
22
     pass
23
     pass
23
 
24
 
24
 
25
 
26
+##@brief Handles leapi query errors
25
 class LeApiQueryError(LeApiError):
27
 class LeApiQueryError(LeApiError):
26
     pass
28
     pass
27
 
29
 
28
 
30
 
29
-##@brief Handles mulitple query errors
31
+##@brief Handles multiple query errors
30
 class LeApiQueryErrors(LodelExceptions, LeApiQueryError):
32
 class LeApiQueryErrors(LodelExceptions, LeApiQueryError):
31
     pass
33
     pass
32
-

+ 83
- 64
lodel/leapi/lefactory.py View File

1
 #-*- coding: utf-8 -*-
1
 #-*- coding: utf-8 -*-
2
 
2
 
3
-import os, os.path
3
+import os
4
+import os.path
4
 import functools
5
 import functools
5
 
6
 
6
 from lodel.context import LodelContext
7
 from lodel.context import LodelContext
7
 LodelContext.expose_modules(globals(), {
8
 LodelContext.expose_modules(globals(), {
8
     'lodel.editorial_model.components': ['EmComponent', 'EmClass', 'EmField',
9
     'lodel.editorial_model.components': ['EmComponent', 'EmClass', 'EmField',
9
-        'EmGroup'],
10
+                                         'EmGroup'],
10
     'lodel.leapi.leobject': ['LeObject'],
11
     'lodel.leapi.leobject': ['LeObject'],
11
     'lodel.leapi.datahandlers.base_classes': ['DataHandler'],
12
     'lodel.leapi.datahandlers.base_classes': ['DataHandler'],
12
     'lodel.logger': 'logger'})
13
     'lodel.logger': 'logger'})
13
 
14
 
14
-##@brief Generate python module code from a given model
15
+# @brief Generates python module code from a given model
15
 # @param model lodel.editorial_model.model.EditorialModel
16
 # @param model lodel.editorial_model.model.EditorialModel
17
+
18
+
16
 def dyncode_from_em(model):
19
 def dyncode_from_em(model):
17
-    
20
+
18
     # Generation of LeObject child classes code
21
     # Generation of LeObject child classes code
19
-    cls_code, modules, bootstrap_instr = generate_classes(model)
22
+    cls_code, bootstrap_instr = generate_classes(model)
20
 
23
 
21
     # Header
24
     # Header
22
     imports = """from lodel.context import LodelContext
25
     imports = """from lodel.context import LodelContext
25
     'lodel.leapi.datahandlers.base_classes': ['DataField'],
28
     'lodel.leapi.datahandlers.base_classes': ['DataField'],
26
     'lodel.plugin.hooks': ['LodelHook']})
29
     'lodel.plugin.hooks': ['LodelHook']})
27
 """
30
 """
28
-    for module in modules:
29
-        imports += "import %s\n" % module
30
-    
31
-    class_list = [ LeObject.name2objname(cls.uid) for cls in get_classes(model) ]
31
+    # generates the list of all classes in the editorial model
32
+    class_list = [LeObject.name2objname(cls.uid) for cls in get_classes(model)]
32
 
33
 
33
     # formating all components of output
34
     # formating all components of output
34
     res_code = """#-*- coding: utf-8 -*-
35
     res_code = """#-*- coding: utf-8 -*-
41
 dynclasses_dict = {class_dict}
42
 dynclasses_dict = {class_dict}
42
 {common_code}
43
 {common_code}
43
 """.format(
44
 """.format(
44
-            imports = imports,
45
-            classes = cls_code,
46
-            bootstrap_instr = bootstrap_instr,
47
-            class_list = '[' + (', '.join([cls for cls in class_list]))+']',
48
-            class_dict = '{' + (', '.join([ "'%s': %s" % (cls, cls)
49
-                for cls in class_list]))+'}',
50
-            common_code = common_code(),
45
+        imports=imports,
46
+        classes=cls_code,
47
+        bootstrap_instr=bootstrap_instr,
48
+        class_list='[' + (', '.join([cls for cls in class_list])) + ']',
49
+        class_dict='{' + (', '.join(["'%s': %s" % (cls, cls)
50
+                                     for cls in class_list])) + '}',
51
+        common_code=common_code(),
51
     )
52
     )
52
     return res_code
53
     return res_code
53
 
54
 
54
-##@brief Return the content of lodel.leapi.lefactory_common
55
+# @brief Returns the content of lodel.leapi.lefactory_common
56
+#
57
+# @return a string
58
+
59
+
55
 def common_code():
60
 def common_code():
56
     res = ""
61
     res = ""
57
     fname = os.path.dirname(__file__)
62
     fname = os.path.dirname(__file__)
61
             if not line.startswith('#-'):
66
             if not line.startswith('#-'):
62
                 res += line
67
                 res += line
63
     return res
68
     return res
64
-    
65
 
69
 
66
-##@brief return A list of EmClass sorted by dependencies
70
+
71
+# @brief return A list of EmClass sorted by dependencies
67
 #
72
 #
68
-# The first elts in the list depends on nothing, etc.
73
+# The first elts in the list depend on nothing, etc.
74
+# @param a list of Emclass instances to be sorted
69
 # @return a list of EmClass instances
75
 # @return a list of EmClass instances
70
 def emclass_sorted_by_deps(emclass_list):
76
 def emclass_sorted_by_deps(emclass_list):
71
     def emclass_deps_cmp(cls_a, cls_b):
77
     def emclass_deps_cmp(cls_a, cls_b):
72
         return len(cls_a.parents_recc) - len(cls_b.parents_recc)
78
         return len(cls_a.parents_recc) - len(cls_b.parents_recc)
73
-    ret = sorted(emclass_list, key = functools.cmp_to_key(emclass_deps_cmp))
79
+    ret = sorted(emclass_list, key=functools.cmp_to_key(emclass_deps_cmp))
74
     return ret
80
     return ret
75
 
81
 
76
-##@brief Returns a list of EmClass that will be represented as LeObject child classes
82
+# @brief Returns a list of EmClass instances that will be represented as LeObject child classes
83
+# @param model : an EditorialModel instance
84
+# @return a list of EmClass instances
85
+
86
+
77
 def get_classes(model):
87
 def get_classes(model):
78
-    return [ cls for cls in emclass_sorted_by_deps(model.classes()) if not cls.pure_abstract ]
88
+    return [cls for cls in emclass_sorted_by_deps(model.classes()) if not cls.pure_abstract]
89
+
90
+# @brief Given an EmField returns the data_handler constructor suitable for dynamic code
91
+# @param a EmField instance
92
+# @return a string
93
+
79
 
94
 
80
-##@brief Given an EmField returns the data_handler constructor suitable for dynamic code
81
 def data_handler_constructor(emfield):
95
 def data_handler_constructor(emfield):
82
     #dh_module_name = DataHandler.module_name(emfield.data_handler_name)+'.DataHandler'
96
     #dh_module_name = DataHandler.module_name(emfield.data_handler_name)+'.DataHandler'
83
     get_handler_class_instr = 'DataField.from_name(%s)' % repr(emfield.data_handler_name)
97
     get_handler_class_instr = 'DataField.from_name(%s)' % repr(emfield.data_handler_name)
85
     for name, val in emfield.data_handler_options.items():
99
     for name, val in emfield.data_handler_options.items():
86
         if name == 'back_reference' and isinstance(val, tuple):
100
         if name == 'back_reference' and isinstance(val, tuple):
87
             options.append('{optname}: ({leo_name}, {fieldname})'.format(
101
             options.append('{optname}: ({leo_name}, {fieldname})'.format(
88
-                optname = repr(name),
89
-                leo_name = LeObject.name2objname(val[0]),
90
-                fieldname = repr(val[1]),))
102
+                optname=repr(name),
103
+                leo_name=LeObject.name2objname(val[0]),
104
+                fieldname=repr(val[1]),))
91
         else:
105
         else:
92
-            options.append(repr(name)+': '+forge_optval(val))
106
+            options.append(repr(name) + ': ' + forge_optval(val))
93
 
107
 
94
     return '{handler_instr}(**{{ {options} }})'.format(
108
     return '{handler_instr}(**{{ {options} }})'.format(
95
-                                                        handler_instr = get_handler_class_instr,
96
-                                                        options = ', '.join(options))
97
-            
98
-##@brief Return a python repr of option values
109
+        handler_instr=get_handler_class_instr,
110
+        options=', '.join(options))
111
+
112
+# @brief Return a python repr of option values
113
+# @param A value of any type which represents option
114
+# @return a string
115
+
116
+
99
 def forge_optval(optval):
117
 def forge_optval(optval):
100
     if isinstance(optval, dict):
118
     if isinstance(optval, dict):
101
-        return '{' + (', '.join( [ '%s: %s' % (repr(name), forge_optval(val)) for name, val in optval.items()])) + '}'
119
+        return '{' + (', '.join(['%s: %s' % (repr(name), forge_optval(val)) for name, val in optval.items()])) + '}'
102
 
120
 
103
     if isinstance(optval, (set, list, tuple)):
121
     if isinstance(optval, (set, list, tuple)):
104
         return '[' + (', '.join([forge_optval(val) for val in optval])) + ']'
122
         return '[' + (', '.join([forge_optval(val) for val in optval])) + ']'
105
-        
123
+
106
     if isinstance(optval, EmField):
124
     if isinstance(optval, EmField):
107
         return "{leobject}.data_handler({fieldname})".format(
125
         return "{leobject}.data_handler({fieldname})".format(
108
-                leobject = LeObject.name2objname(optval._emclass.uid),
109
-                fieldname = repr(optval.uid)
110
-            )
111
-    elif isinstance(optval, EmClass):
126
+            leobject=LeObject.name2objname(optval._emclass.uid),
127
+            fieldname=repr(optval.uid)
128
+        )
129
+    if isinstance(optval, EmClass):
112
         return LeObject.name2objname(optval.uid)
130
         return LeObject.name2objname(optval.uid)
113
-    else:
114
-        return repr(optval)
115
 
131
 
116
-##@brief Generate dyncode from an EmClass
117
-# @param model EditorialModel : 
118
-# @todo delete imports. It is never use, consequently changed return parameters.
132
+    return repr(optval)
133
+
134
+# @brief Generate dyncode from an EmClass
135
+# @param model EditorialModel :
119
 # @return a tuple with emclass python code, a set containing modules name to import, and a list of python instruction to bootstrap dynamic code, in this order
136
 # @return a tuple with emclass python code, a set containing modules name to import, and a list of python instruction to bootstrap dynamic code, in this order
137
+
138
+
120
 def generate_classes(model):
139
 def generate_classes(model):
121
     res = ""
140
     res = ""
122
-    imports = list()
141
+
123
     bootstrap = ""
142
     bootstrap = ""
124
     # Generating field list for LeObjects generated from EmClass
143
     # Generating field list for LeObjects generated from EmClass
125
     for em_class in get_classes(model):
144
     for em_class in get_classes(model):
126
         logger.info("Generating a dynamic class for %s" % em_class.uid)
145
         logger.info("Generating a dynamic class for %s" % em_class.uid)
127
-        uid = list()        # List of fieldnames that are part of the EmClass primary key
128
-        parents = list()    # List of parents EmClass
129
-        # Determine pk
146
+        uid = list()        # List for fieldnames that are part of the EmClass primary key
147
+        parents = list()    # List for em_class's parents
148
+        # Determines primary key
130
         for field in em_class.fields():
149
         for field in em_class.fields():
131
             if field.data_handler_instance.is_primary_key():
150
             if field.data_handler_instance.is_primary_key():
132
                 uid.append(field.uid)
151
                 uid.append(field.uid)
133
-        # Determine parent for inheritance
152
+        # Determines parentsfor inheritance
134
         if len(em_class.parents) > 0:
153
         if len(em_class.parents) > 0:
135
             for parent in em_class.parents:
154
             for parent in em_class.parents:
136
-               parents.append(LeObject.name2objname(parent.uid))
155
+                parents.append(LeObject.name2objname(parent.uid))
137
         else:
156
         else:
138
             parents.append('LeObject')
157
             parents.append('LeObject')
139
         datasource_name = em_class.datasource
158
         datasource_name = em_class.datasource
140
-        
141
-        # Dynamic code generation for LeObject childs classes
159
+
160
+        # Dynamic code generation for LeObject child classes
142
         em_cls_code = """
161
         em_cls_code = """
143
 class {clsname}({parents}):
162
 class {clsname}({parents}):
144
     _abstract = {abstract}
163
     _abstract = {abstract}
150
     _child_classes = None
169
     _child_classes = None
151
 
170
 
152
 """.format(
171
 """.format(
153
-    clsname = LeObject.name2objname(em_class.uid),
154
-    parents = ', '.join(parents),
155
-    abstract = 'True' if em_class.abstract else 'False',
156
-    uid_list = repr(uid),
157
-    datasource_name = repr(datasource_name),
158
-)
172
+            clsname=LeObject.name2objname(em_class.uid),
173
+            parents=', '.join(parents),
174
+            abstract='True' if em_class.abstract else 'False',
175
+            uid_list=repr(uid),
176
+            datasource_name=repr(datasource_name),
177
+        )
159
         res += em_cls_code
178
         res += em_cls_code
160
         # Dyncode fields bootstrap instructions
179
         # Dyncode fields bootstrap instructions
161
         child_classes = model.get_class_childs(em_class.uid)
180
         child_classes = model.get_class_childs(em_class.uid)
163
             child_classes = 'tuple()'
182
             child_classes = 'tuple()'
164
         else:
183
         else:
165
             child_classes = '(%s,)' % (', '.join(
184
             child_classes = '(%s,)' % (', '.join(
166
-                [ LeObject.name2objname(emcls.uid) for emcls in child_classes]))
185
+                [LeObject.name2objname(emcls.uid) for emcls in child_classes]))
167
         bootstrap += """{classname}._set__fields({fields})
186
         bootstrap += """{classname}._set__fields({fields})
168
 {classname}._child_classes = {child_classes}
187
 {classname}._child_classes = {child_classes}
169
 """.format(
188
 """.format(
170
-    classname = LeObject.name2objname(em_class.uid),
171
-    fields = '{' + (', '.join(['\n\t%s: %s' % (repr(emfield.uid),data_handler_constructor(emfield)) for emfield in em_class.fields()])) + '}',
172
-    child_classes = child_classes,
173
-)
189
+            classname=LeObject.name2objname(em_class.uid),
190
+            fields='{' + (', '.join(['\n\t%s: %s' % (repr(emfield.uid),
191
+                                                     data_handler_constructor(emfield)) for emfield in em_class.fields()])) + '}',
192
+            child_classes=child_classes,
193
+        )
174
     bootstrap += "\n"
194
     bootstrap += "\n"
175
-    return res, set(imports), bootstrap
176
-    
195
+    return res, bootstrap

+ 3
- 4
lodel/leapi/lefactory_common.py View File

5
 #- All lines that begins with #- will be deleted from dynamically generated
5
 #- All lines that begins with #- will be deleted from dynamically generated
6
 #- code...
6
 #- code...
7
 
7
 
8
-##@brief Return a dynamically generated class given it's name
8
+##@brief Returns a dynamically generated class given its name
9
 #@param name str : The dynamic class name
9
 #@param name str : The dynamic class name
10
 #@return False or a child class of LeObject
10
 #@return False or a child class of LeObject
11
 def name2class(name):
11
 def name2class(name):
14
     return dynclasses_dict[name]
14
     return dynclasses_dict[name]
15
 
15
 
16
 
16
 
17
-##@brief Return a dynamically generated class given it's name
17
+##@brief Returns a dynamically generated class given its name
18
 #@note Case insensitive version of name2class
18
 #@note Case insensitive version of name2class
19
 #@param name str
19
 #@param name str
20
 #@return False or a child class of LeObject
20
 #@return False or a child class of LeObject
26
     return new_dict[name]
26
     return new_dict[name]
27
 
27
 
28
 
28
 
29
-##@brief Trigger dynclasses datasources initialisation
29
+##@brief Triggers dynclasses datasources initialisation
30
 @LodelHook("lodel2_plugins_loaded")
30
 @LodelHook("lodel2_plugins_loaded")
31
 def lodel2_dyncode_datasources_init(self, caller, payload):
31
 def lodel2_dyncode_datasources_init(self, caller, payload):
32
     for cls in dynclasses:
32
     for cls in dynclasses:
33
         cls._init_datasources()
33
         cls._init_datasources()
34
     LodelContext.expose_modules(globals(), {'lodel.plugin.hooks': ['LodelHook']})
34
     LodelContext.expose_modules(globals(), {'lodel.plugin.hooks': ['LodelHook']})
35
     LodelHook.call_hook("lodel2_dyncode_loaded", __name__, dynclasses)
35
     LodelHook.call_hook("lodel2_dyncode_loaded", __name__, dynclasses)
36
-

+ 194
- 188
lodel/leapi/query.py View File

8
 from lodel.context import LodelContext
8
 from lodel.context import LodelContext
9
 LodelContext.expose_modules(globals(), {
9
 LodelContext.expose_modules(globals(), {
10
     'lodel.leapi.exceptions': ['LeApiError', 'LeApiErrors',
10
     'lodel.leapi.exceptions': ['LeApiError', 'LeApiErrors',
11
-        'LeApiDataCheckError', 'LeApiDataCheckErrors', 'LeApiQueryError',
12
-        'LeApiQueryErrors'],
11
+                               'LeApiDataCheckError', 'LeApiDataCheckErrors', 'LeApiQueryError',
12
+                               'LeApiQueryErrors'],
13
     'lodel.plugin.hooks': ['LodelHook'],
13
     'lodel.plugin.hooks': ['LodelHook'],
14
     'lodel.logger': ['logger']})
14
     'lodel.logger': ['logger']})
15
 
15
 
16
-##@todo check datas when running query
16
+# @todo check data when running query
17
+
18
+
17
 class LeQuery(object):
19
 class LeQuery(object):
18
 
20
 
19
-    ##@brief Hookname prefix
21
+    # @brief Hookname prefix
20
     _hook_prefix = None
22
     _hook_prefix = None
21
-    ##@brief arguments for the LeObject.check_data_value()
23
+    # @brief arguments for the LeObject.check_data_value()
22
     _data_check_args = {'complete': False, 'allow_internal': False}
24
     _data_check_args = {'complete': False, 'allow_internal': False}
23
 
25
 
24
-    ##@brief Abstract constructor
26
+    # @brief Abstract constructor
25
     # @param target_class LeObject : class of object the query is about
27
     # @param target_class LeObject : class of object the query is about
26
     def __init__(self, target_class):
28
     def __init__(self, target_class):
27
         from .leobject import LeObject
29
         from .leobject import LeObject
29
             raise NotImplementedError("Abstract class")
31
             raise NotImplementedError("Abstract class")
30
         if not inspect.isclass(target_class) or \
32
         if not inspect.isclass(target_class) or \
31
            not issubclass(target_class, LeObject):
33
            not issubclass(target_class, LeObject):
32
-            raise TypeError("target class has to be a child class of LeObject but %s given"% target_class)
34
+            raise TypeError(
35
+                "target class has to be a child class of LeObject but %s given" % target_class)
33
         self._target_class = target_class
36
         self._target_class = target_class
34
         self._ro_datasource = target_class._ro_datasource
37
         self._ro_datasource = target_class._ro_datasource
35
         self._rw_datasource = target_class._rw_datasource
38
         self._rw_datasource = target_class._rw_datasource
36
 
39
 
37
-    ##@brief Execute a query and return the result
38
-    #@param **datas
40
+    # @brief Executes a query and returns the result
41
+    #@param **data
39
     #@return the query result
42
     #@return the query result
40
     #@see LeQuery._query()
43
     #@see LeQuery._query()
41
     #@todo check that the check_datas_value is not duplicated/useless
44
     #@todo check that the check_datas_value is not duplicated/useless
42
-    def execute(self, datas):
43
-        if not datas is None:
45
+    def execute(self, data):
46
+        if data is not None:
44
             self._target_class.check_datas_value(
47
             self._target_class.check_datas_value(
45
-                                                    datas,
46
-                                                    **self._data_check_args)
47
-            self._target_class.prepare_datas(datas) #not yet implemented
48
+                data,
49
+                **self._data_check_args)
50
+            self._target_class.prepare_datas(data)  # not yet implemented
48
         if self._hook_prefix is None:
51
         if self._hook_prefix is None:
49
             raise NotImplementedError("Abstract method")
52
             raise NotImplementedError("Abstract method")
50
-        LodelHook.call_hook(self._hook_prefix+'pre',
51
-                                self._target_class,
52
-                                datas)
53
-        ret = self._query(datas=datas)
54
-        ret = LodelHook.call_hook(self._hook_prefix+'post',
55
-                                    self._target_class,
56
-                                    ret)
53
+        LodelHook.call_hook(self._hook_prefix + 'pre',
54
+                            self._target_class,
55
+                            data)
56
+        ret = self._query(data=data)
57
+        ret = LodelHook.call_hook(self._hook_prefix + 'post',
58
+                                  self._target_class,
59
+                                  ret)
57
         return ret
60
         return ret
58
 
61
 
59
-    ##@brief Childs classes implements this method to execute the query
60
-    #@param **datas
62
+    # @brief Child classes implement this method to execute the query
63
+    #@param **data
61
     #@return query result
64
     #@return query result
62
-    def _query(self, **datas):
65
+    def _query(self, **data):
63
         raise NotImplementedError("Asbtract method")
66
         raise NotImplementedError("Asbtract method")
64
 
67
 
65
-    ##@return a dict with query infos
68
+    # @return a dict with query infos
66
     def dump_infos(self):
69
     def dump_infos(self):
67
         return {'target_class': self._target_class}
70
         return {'target_class': self._target_class}
68
 
71
 
69
     def __repr__(self):
72
     def __repr__(self):
70
         ret = "<{classname} target={target_class}>"
73
         ret = "<{classname} target={target_class}>"
71
         return ret.format(
74
         return ret.format(
72
-                            classname=self.__class__.__name__,
73
-                            target_class = self._target_class)
75
+            classname=self.__class__.__name__,
76
+            target_class=self._target_class)
77
+
78
+# @brief Abstract class handling query with filters
79
+
74
 
80
 
75
-##@brief Abstract class handling query with filters
76
 class LeFilteredQuery(LeQuery):
81
 class LeFilteredQuery(LeQuery):
77
-    ##@brief The available operators used in query definitions
82
+    # @brief The available operators used in query definitions
78
     _query_operators = [
83
     _query_operators = [
79
-                        ' = ',
80
-                        ' <= ',
81
-                        ' >= ',
82
-                        ' != ',
83
-                        ' < ',
84
-                        ' > ',
85
-                        ' in ',
86
-                        ' not in ',
87
-                        ' like ',
88
-                        ' not like ']
89
-
90
-    ##@brief Regular expression to process filters
84
+        ' = ',
85
+        ' <= ',
86
+        ' >= ',
87
+        ' != ',
88
+        ' < ',
89
+        ' > ',
90
+        ' in ',
91
+        ' not in ',
92
+        ' like ',
93
+        ' not like ']
94
+
95
+    # @brief Regular expression to process filters
91
     _query_re = None
96
     _query_re = None
92
 
97
 
93
-    ##@brief Abtract constructor for queries with filter
98
+    # @brief Abtract constructor for queries with filter
94
     #@param target_class LeObject : class of object the query is about
99
     #@param target_class LeObject : class of object the query is about
95
     #@param query_filters list : with a tuple (only one filter) or a list of
100
     #@param query_filters list : with a tuple (only one filter) or a list of
96
     # tuple or a dict: {OP,list(filters)} with OP = 'OR' or 'AND for tuple
101
     # tuple or a dict: {OP,list(filters)} with OP = 'OR' or 'AND for tuple
97
     # (FIELD,OPERATOR,VALUE)
102
     # (FIELD,OPERATOR,VALUE)
98
     def __init__(self, target_class, query_filters=None):
103
     def __init__(self, target_class, query_filters=None):
99
         super().__init__(target_class)
104
         super().__init__(target_class)
100
-        ##@brief The query filter tuple(std_filter, relational_filters)
105
+        # @brief The query filter tuple(std_filter, relational_filters)
101
         self._query_filter = None
106
         self._query_filter = None
102
-        ##@brief Stores potential subqueries (used when a query implies
107
+        # @brief Stores potential subqueries (used when a query implies
103
         # more than one datasource.
108
         # more than one datasource.
104
         #
109
         #
105
         # Subqueries are tuple(target_class_ref_field, LeGetQuery)
110
         # Subqueries are tuple(target_class_ref_field, LeGetQuery)
107
         query_filters = [] if query_filters is None else query_filters
112
         query_filters = [] if query_filters is None else query_filters
108
         self.set_query_filter(query_filters)
113
         self.set_query_filter(query_filters)
109
 
114
 
110
-    ##@brief Abstract FilteredQuery execution method
115
+    # @brief Abstract FilteredQuery execution method
111
     #
116
     #
112
     # This method takes care to execute subqueries before calling super execute
117
     # This method takes care to execute subqueries before calling super execute
113
-    def execute(self, datas=None):
114
-        #copy originals filters
118
+    def execute(self, data=None):
119
+        # copy originals filters
115
         orig_filters = copy.copy(self._query_filter)
120
         orig_filters = copy.copy(self._query_filter)
116
         std_filters, rel_filters = self._query_filter
121
         std_filters, rel_filters = self._query_filter
117
 
122
 
123
         try:
128
         try:
124
 
129
 
125
             filters, rel_filters = self._query_filter
130
             filters, rel_filters = self._query_filter
126
-            res = super().execute(datas)
131
+            res = super().execute(data)
127
         except Exception as e:
132
         except Exception as e:
128
-            #restoring filters even if an exception is raised
133
+            # restoring filters even if an exception is raised
129
             self.__query_filter = orig_filters
134
             self.__query_filter = orig_filters
130
 
135
 
131
-            raise e #reraise
132
-        #restoring filters
136
+            raise e  # reraise
137
+        # restoring filters
133
         self._query_filter = orig_filters
138
         self._query_filter = orig_filters
134
         return res
139
         return res
135
 
140
 
136
-    ##@brief Add filter(s) to the query
141
+    # @brief Add filter(s) to the query
137
     #
142
     #
138
     # This method is also able to slice query if different datasources are
143
     # This method is also able to slice query if different datasources are
139
     # implied in the request
144
     # implied in the request
144
     def set_query_filter(self, query_filter):
149
     def set_query_filter(self, query_filter):
145
         if isinstance(query_filter, str):
150
         if isinstance(query_filter, str):
146
             query_filter = [query_filter]
151
             query_filter = [query_filter]
147
-        #Query filter prepration
152
+        # Query filter prepration
148
         filters_orig, rel_filters = self._prepare_filters(query_filter)
153
         filters_orig, rel_filters = self._prepare_filters(query_filter)
149
         # Here we now that each relational filter concern only one datasource
154
         # Here we now that each relational filter concern only one datasource
150
         # thank's to _prepare_relational_fields
155
         # thank's to _prepare_relational_fields
151
 
156
 
152
-        #Multiple datasources detection
157
+        # Multiple datasources detection
153
         self_ds_name = self._target_class._datasource_name
158
         self_ds_name = self._target_class._datasource_name
154
-        result_rel_filters = list() # The filters that will stay in the query
159
+        result_rel_filters = list()  # The filters that will stay in the query
155
         other_ds_filters = dict()
160
         other_ds_filters = dict()
156
         for rfilter in rel_filters:
161
         for rfilter in rel_filters:
157
             (rfield, ref_dict), op, value = rfilter
162
             (rfield, ref_dict), op, value = rfilter
158
-            #rfield : the field in self._target_class
159
-            tmp_rel_filter = dict() #designed to stores rel_field of same DS
163
+            # rfield : the field in self._target_class
164
+            tmp_rel_filter = dict()  # designed to stores rel_field of same DS
160
             # First step : simplification
165
             # First step : simplification
161
             # Trying to delete relational filters done on referenced class uid
166
             # Trying to delete relational filters done on referenced class uid
162
             for tclass, tfield in copy.copy(ref_dict).items():
167
             for tclass, tfield in copy.copy(ref_dict).items():
163
-                #tclass : reference target class
164
-                #tfield : referenced field from target class
168
+                # tclass : reference target class
169
+                # tfield : referenced field from target class
165
                 #
170
                 #
166
                 #   !!!WARNING!!!
171
                 #   !!!WARNING!!!
167
                 # The line below brake multi UID support
172
                 # The line below brake multi UID support
168
                 #
173
                 #
169
                 if tfield == tclass.uid_fieldname()[0]:
174
                 if tfield == tclass.uid_fieldname()[0]:
170
-                    #This relational filter can be simplified as
175
+                    # This relational filter can be simplified as
171
                     # ref_field, op, value
176
                     # ref_field, op, value
172
                     # Note : we will have to dedup filters_orig
177
                     # Note : we will have to dedup filters_orig
173
                     filters_orig.append((rfield, op, value))
178
                     filters_orig.append((rfield, op, value))
174
                     del(ref_dict[tclass])
179
                     del(ref_dict[tclass])
175
             if len(ref_dict) == 0:
180
             if len(ref_dict) == 0:
176
                 continue
181
                 continue
177
-            #Determine what to do with other relational filters given
182
+            # Determine what to do with other relational filters given
178
             # referenced class datasource
183
             # referenced class datasource
179
-            #Remember : each class in a relational filter has the same
184
+            # Remember : each class in a relational filter has the same
180
             # datasource
185
             # datasource
181
             tclass = list(ref_dict.keys())[0]
186
             tclass = list(ref_dict.keys())[0]
182
             cur_ds = tclass._datasource_name
187
             cur_ds = tclass._datasource_name
189
                     other_ds_filters[cur_ds] = list()
194
                     other_ds_filters[cur_ds] = list()
190
                 other_ds_filters[cur_ds].append(
195
                 other_ds_filters[cur_ds].append(
191
                     ((rfield, ref_dict), op, value))
196
                     ((rfield, ref_dict), op, value))
192
-        #deduplication of std filters
197
+        # deduplication of std filters
193
         filters_cp = set()
198
         filters_cp = set()
194
         if not isinstance(filters_orig, set):
199
         if not isinstance(filters_orig, set):
195
             for i, cfilt in enumerate(filters_orig):
200
             for i, cfilt in enumerate(filters_orig):
196
                 a, b, c = cfilt
201
                 a, b, c = cfilt
197
-                if isinstance(c, list): #list are not hashable
202
+                if isinstance(c, list):  # list are not hashable
198
                     newc = tuple(c)
203
                     newc = tuple(c)
199
                 else:
204
                 else:
200
                     newc = c
205
                     newc = c
201
                 old_len = len(filters_cp)
206
                 old_len = len(filters_cp)
202
-                filters_cp |= set((a,b,newc))
207
+                filters_cp |= set((a, b, newc))
203
                 if len(filters_cp) == old_len:
208
                 if len(filters_cp) == old_len:
204
                     del(filters_orig[i])
209
                     del(filters_orig[i])
205
         # Sets _query_filter attribute of self query
210
         # Sets _query_filter attribute of self query
206
         self._query_filter = (filters_orig, result_rel_filters)
211
         self._query_filter = (filters_orig, result_rel_filters)
207
 
212
 
208
-        #Sub queries creation
213
+        # Sub queries creation
209
         subq = list()
214
         subq = list()
210
         for ds, rfilters in other_ds_filters.items():
215
         for ds, rfilters in other_ds_filters.items():
211
             for rfilter in rfilters:
216
             for rfilter in rfilters:
218
                     subq.append((rfield, query))
223
                     subq.append((rfield, query))
219
         self.subqueries = subq
224
         self.subqueries = subq
220
 
225
 
221
-    ##@return informations
226
+    # @return informations
222
     def dump_infos(self):
227
     def dump_infos(self):
223
         ret = super().dump_infos()
228
         ret = super().dump_infos()
224
         ret['query_filter'] = self._query_filter
229
         ret['query_filter'] = self._query_filter
238
         res += '>'
243
         res += '>'
239
         return res
244
         return res
240
 
245
 
241
-    ## @brief Prepare filters for datasource
246
+    # @brief Prepare filters for datasource
242
     #
247
     #
243
-    #A filter can be a string or a tuple with len = 3.
248
+    # A filter can be a string or a tuple with len = 3.
244
     #
249
     #
245
-    #This method divide filters in two categories :
250
+    # This method divide filters in two categories :
246
     #
251
     #
247
     #@par Simple filters
252
     #@par Simple filters
248
     #
253
     #
249
-    #Those filters concerns fields that represent object values (a title,
250
-    #the content, etc.) They are composed of three elements : FIELDNAME OP
254
+    # Those filters concerns fields that represent object values (a title,
255
+    # the content, etc.) They are composed of three elements : FIELDNAME OP
251
     # VALUE . Where :
256
     # VALUE . Where :
252
     #- FIELDNAME is the name of the field
257
     #- FIELDNAME is the name of the field
253
     #- OP is one of the authorized comparison operands (see
258
     #- OP is one of the authorized comparison operands (see
256
     #
261
     #
257
     #@par Relational filters
262
     #@par Relational filters
258
     #
263
     #
259
-    #Those filters concerns on reference fields (see the corresponding
260
-    #abstract datahandler @ref lodel.leapi.datahandlers.base_classes.Reference)
261
-    #The filter as quite the same composition than simple filters :
264
+    # Those filters concerns on reference fields (see the corresponding
265
+    # abstract datahandler @ref lodel.leapi.datahandlers.base_classes.Reference)
266
+    # The filter as quite the same composition than simple filters :
262
     # FIELDNAME[.REF_FIELD] OP VALUE . Where :
267
     # FIELDNAME[.REF_FIELD] OP VALUE . Where :
263
     #- FIELDNAME is the name of the reference field
268
     #- FIELDNAME is the name of the reference field
264
     #- REF_FIELD is an optionnal addon to the base field. It indicate on wich
269
     #- REF_FIELD is an optionnal addon to the base field. It indicate on wich
265
-    #field of the referenced object the comparison as to be done. If no
266
-    #REF_FIELD is indicated the comparison will be done on identifier.
270
+    # field of the referenced object the comparison as to be done. If no
271
+    # REF_FIELD is indicated the comparison will be done on identifier.
267
     #
272
     #
268
     #@param cls
273
     #@param cls
269
     #@param filters_l list : This list of str or tuple (or both)
274
     #@param filters_l list : This list of str or tuple (or both)
271
     #@todo move this doc in another place (a dedicated page ?)
276
     #@todo move this doc in another place (a dedicated page ?)
272
     #@warning Does not supports multiple UID for an EmClass
277
     #@warning Does not supports multiple UID for an EmClass
273
     def _prepare_filters(self, filters_l):
278
     def _prepare_filters(self, filters_l):
274
-        filters=list()
279
+        filters = list()
275
         res_filters = list()
280
         res_filters = list()
276
         rel_filters = list()
281
         rel_filters = list()
277
         err_l = dict()
282
         err_l = dict()
278
-        #Splitting in tuple if necessary
283
+        # Splitting in tuple if necessary
279
         for i, fil in enumerate(filters_l):
284
         for i, fil in enumerate(filters_l):
280
             if len(fil) == 3 and not isinstance(fil, str):
285
             if len(fil) == 3 and not isinstance(fil, str):
281
                 filters.append(tuple(fil))
286
                 filters.append(tuple(fil))
286
                     err_l["filter %d" % i] = e
291
                     err_l["filter %d" % i] = e
287
 
292
 
288
         for field, operator, value in filters:
293
         for field, operator, value in filters:
289
-            err_key = "%s %s %s" % (field, operator, value) #to push in err_l
294
+            err_key = "%s %s %s" % (field, operator, value)  # to push in err_l
290
             # Spliting field name to be able to detect a relational field
295
             # Spliting field name to be able to detect a relational field
291
             field_spl = field.split('.')
296
             field_spl = field.split('.')
292
             if len(field_spl) == 2:
297
             if len(field_spl) == 2:
310
                 # inconsistency
315
                 # inconsistency
311
                 err_l[field] = NameError("The field '%s' in %s is not \
316
                 err_l[field] = NameError("The field '%s' in %s is not \
312
 a relational field, but %s.%s was present in the filter"
317
 a relational field, but %s.%s was present in the filter"
313
-                                            % (field,
314
-                                                self._target_class.__name__,
315
-                                                field,
316
-                                                ref_field))
318
+                                         % (field,
319
+                                            self._target_class.__name__,
320
+                                            field,
321
+                                            ref_field))
317
             if field_datahandler.is_reference():
322
             if field_datahandler.is_reference():
318
-                #Relationnal field
323
+                # Relationnal field
319
                 if ref_field is None:
324
                 if ref_field is None:
320
                     # ref_field default value
325
                     # ref_field default value
321
                     #
326
                     #
350
                 value, error = field_datahandler.check_data_value(value)
355
                 value, error = field_datahandler.check_data_value(value)
351
                 if isinstance(error, Exception):
356
                 if isinstance(error, Exception):
352
                     value = value_orig
357
                     value = value_orig
353
-                res_filters.append((field,operator, value))
358
+                res_filters.append((field, operator, value))
354
         if len(err_l) > 0:
359
         if len(err_l) > 0:
355
             raise LeApiDataCheckErrors(
360
             raise LeApiDataCheckErrors(
356
-                                        "Error while preparing filters : ",
357
-                                        err_l)
361
+                "Error while preparing filters : ",
362
+                err_l)
358
         return (res_filters, rel_filters)
363
         return (res_filters, rel_filters)
359
 
364
 
360
-    ## @brief Check and split a query filter
365
+    # @brief Check and split a query filter
361
     # @note The query_filter format is "FIELD OPERATOR VALUE"
366
     # @note The query_filter format is "FIELD OPERATOR VALUE"
362
     # @param query_filter str : A query_filter string
367
     # @param query_filter str : A query_filter string
363
     # @param cls
368
     # @param cls
382
                 raise ValueError(msg % query_filter)
387
                 raise ValueError(msg % query_filter)
383
         return result
388
         return result
384
 
389
 
385
-    ## @brief Compile the regex for query_filter processing
390
+    # @brief Compile the regex for query_filter processing
386
     # @note Set _LeObject._query_re
391
     # @note Set _LeObject._query_re
387
     @classmethod
392
     @classmethod
388
     def __compile_query_re(cls):
393
     def __compile_query_re(cls):
389
         op_re_piece = '(?P<operator>(%s)'
394
         op_re_piece = '(?P<operator>(%s)'
390
         op_re_piece %= cls._query_operators[0].replace(' ', '\s')
395
         op_re_piece %= cls._query_operators[0].replace(' ', '\s')
391
         for operator in cls._query_operators[1:]:
396
         for operator in cls._query_operators[1:]:
392
-            op_re_piece += '|(%s)'%operator.replace(' ', '\s')
397
+            op_re_piece += '|(%s)' % operator.replace(' ', '\s')
393
         op_re_piece += ')'
398
         op_re_piece += ')'
394
 
399
 
395
         re_full = '^\s*(?P<field>([a-z_][a-z0-9\-_]*\.)?[a-z_][a-z0-9\-_]*)\s*'
400
         re_full = '^\s*(?P<field>([a-z_][a-z0-9\-_]*\.)?[a-z_][a-z0-9\-_]*)\s*'
396
-        re_full += op_re_piece+'\s*(?P<value>.*)\s*$'
401
+        re_full += op_re_piece + '\s*(?P<value>.*)\s*$'
397
 
402
 
398
         cls._query_re = re.compile(re_full, flags=re.IGNORECASE)
403
         cls._query_re = re.compile(re_full, flags=re.IGNORECASE)
399
         pass
404
         pass
407
             msg %= (fieldname, target_class.__name__)
412
             msg %= (fieldname, target_class.__name__)
408
             return NameError(msg)
413
             return NameError(msg)
409
 
414
 
410
-    ##@brief Prepare a relational filter
415
+    # @brief Prepare a relational filter
411
     #
416
     #
412
-    #Relational filters are composed of a tuple like the simple filters
413
-    #but the first element of this tuple is a tuple to :
417
+    # Relational filters are composed of a tuple like the simple filters
418
+    # but the first element of this tuple is a tuple to :
414
     #
419
     #
415
     #<code>((FIELDNAME, {REF_CLASS: REF_FIELD}), OP, VALUE)</code>
420
     #<code>((FIELDNAME, {REF_CLASS: REF_FIELD}), OP, VALUE)</code>
416
     # Where :
421
     # Where :
419
     # - REF_CLASS as key. It's a LeObject child class
424
     # - REF_CLASS as key. It's a LeObject child class
420
     # - REF_FIELD as value. The name of the referenced field in the REF_CLASS
425
     # - REF_FIELD as value. The name of the referenced field in the REF_CLASS
421
     #
426
     #
422
-    #Visibly the REF_FIELD value of the dict will vary only when
423
-    #no REF_FIELD is explicitly given in the filter string notation
424
-    #and REF_CLASSES has differents uid
427
+    # Visibly the REF_FIELD value of the dict will vary only when
428
+    # no REF_FIELD is explicitly given in the filter string notation
429
+    # and REF_CLASSES has differents uid
425
     #
430
     #
426
     #@par String notation examples
431
     #@par String notation examples
427
     #<pre>contributeur IN (1,2,3,5)</pre> will be transformed into :
432
     #<pre>contributeur IN (1,2,3,5)</pre> will be transformed into :
439
     #
444
     #
440
     #@param fieldname str : The relational field name
445
     #@param fieldname str : The relational field name
441
     #@param ref_field str|None : The referenced field name (if None use
446
     #@param ref_field str|None : The referenced field name (if None use
442
-    #uniq identifiers as referenced field
447
+    # uniq identifiers as referenced field
443
     #@return a well formed relational filter tuple or an Exception instance
448
     #@return a well formed relational filter tuple or an Exception instance
444
     def _prepare_relational_fields(self, fieldname, ref_field=None):
449
     def _prepare_relational_fields(self, fieldname, ref_field=None):
445
         datahandler = self._target_class.field(fieldname)
450
         datahandler = self._target_class.field(fieldname)
467
                     logger.debug(msg)
472
                     logger.debug(msg)
468
         if len(ref_dict) == 0:
473
         if len(ref_dict) == 0:
469
             return NameError("No field named '%s' in referenced objects [%s]"
474
             return NameError("No field named '%s' in referenced objects [%s]"
470
-                                % (ref_field,
471
-                                    ','.join([rc.__name__ for rc in ref_classes])))
475
+                             % (ref_field,
476
+                                ','.join([rc.__name__ for rc in ref_classes])))
472
         return (fieldname, ref_dict)
477
         return (fieldname, ref_dict)
473
 
478
 
474
 
479
 
475
-##@brief A query to insert a new object
480
+# @brief A query to insert a new object
476
 class LeInsertQuery(LeQuery):
481
 class LeInsertQuery(LeQuery):
477
     _hook_prefix = 'leapi_insert_'
482
     _hook_prefix = 'leapi_insert_'
478
     _data_check_args = {'complete': True, 'allow_internal': False}
483
     _data_check_args = {'complete': True, 'allow_internal': False}
483
 abstract LeObject : %s" % target_class)
488
 abstract LeObject : %s" % target_class)
484
         super().__init__(target_class)
489
         super().__init__(target_class)
485
 
490
 
486
-    ## @brief Implements an insert query operation, with only one insertion
487
-    # @param datas : datas to be inserted
488
-    def _query(self, datas):
489
-        datas = self._target_class.prepare_datas(datas, True, False)
490
-        id_inserted = self._rw_datasource.insert(self._target_class, datas)
491
+    #  @brief Implements an insert query operation, with only one insertion
492
+    # @param data : data to be inserted
493
+    def _query(self, data):
494
+        data = self._target_class.prepare_datas(data, True, False)
495
+        id_inserted = self._rw_datasource.insert(self._target_class, data)
491
         return id_inserted
496
         return id_inserted
492
     """
497
     """
493
     ## @brief Implements an insert query operation, with multiple insertions
498
     ## @brief Implements an insert query operation, with multiple insertions
494
-    # @param datas : list of **datas to be inserted
495
-    def _query(self, datas):
499
+    # @param data : list of **data to be inserted
500
+    def _query(self, data):
496
         nb_inserted = self._datasource.insert_multi(
501
         nb_inserted = self._datasource.insert_multi(
497
-            self._target_class,datas_list)
502
+            self._target_class,data_list)
498
         if nb_inserted < 0:
503
         if nb_inserted < 0:
499
             raise LeApiQueryError("Multiple insertions error")
504
             raise LeApiQueryError("Multiple insertions error")
500
         return nb_inserted
505
         return nb_inserted
501
     """
506
     """
502
 
507
 
503
-    ## @brief Execute the insert query
504
-    def execute(self, datas):
505
-        return super().execute(datas=datas)
508
+    #  @brief Execute the insert query
509
+    def execute(self, data):
510
+        return super().execute(data=data)
506
 
511
 
507
 
512
 
508
-##@brief A query to update datas for a given object
513
+# @brief A query to update data for a given object
509
 #
514
 #
510
 #@todo Change behavior, Huge optimization problem when updating using filters
515
 #@todo Change behavior, Huge optimization problem when updating using filters
511
-#and not instance. We have to run a GET and then 1 update by fecthed object...
516
+# and not instance. We have to run a GET and then 1 update by fecthed object...
512
 class LeUpdateQuery(LeFilteredQuery):
517
 class LeUpdateQuery(LeFilteredQuery):
513
     _hook_prefix = 'leapi_update_'
518
     _hook_prefix = 'leapi_update_'
514
     _data_check_args = {'complete': False, 'allow_internal': False}
519
     _data_check_args = {'complete': False, 'allow_internal': False}
515
 
520
 
516
-    ##@brief Instanciate an update query
521
+    # @brief Instanciate an update query
517
     #
522
     #
518
-    #If a class and not an instance is given, no query_filters are expected
519
-    #and the update will be fast and simple. Else we have to run a get query
520
-    #before updating (to fetch datas, update them and then, construct them
521
-    #and check their consistency)
523
+    # If a class and not an instance is given, no query_filters are expected
524
+    # and the update will be fast and simple. Else we have to run a get query
525
+    # before updating (to fetch data, update them and then, construct them
526
+    # and check their consistency)
522
     #@param target LeObject clas or instance
527
     #@param target LeObject clas or instance
523
     #@param query_filters list|None
528
     #@param query_filters list|None
524
-    #@todo change strategy with instance update. We have to accept datas for
525
-    #the execute method
529
+    #@todo change strategy with instance update. We have to accept data for
530
+    # the execute method
526
     def __init__(self, target, query_filters=None):
531
     def __init__(self, target, query_filters=None):
527
-        ##@brief This attr is set only if the target argument is an
528
-        #instance of a LeObject subclass
532
+        # @brief This attr is set only if the target argument is an
533
+        # instance of a LeObject subclass
529
         self.__leobject_instance_datas = None
534
         self.__leobject_instance_datas = None
530
         target_class = target
535
         target_class = target
531
 
536
 
542
 
547
 
543
         super().__init__(target_class, query_filters)
548
         super().__init__(target_class, query_filters)
544
 
549
 
545
-    ##@brief Implements an update query
546
-    #@param datas dict : datas to update
550
+    # @brief Implements an update query
551
+    #@param data dict : data to be updated
547
     #@returns the number of updated items
552
     #@returns the number of updated items
548
-    #@todo change stategy for instance update. Datas should be allowed
549
-    #for execute method (and query)
550
-    def _query(self, datas):
553
+    #@todo change stategy for instance update. Data should be allowed
554
+    # for execute method (and query)
555
+    def _query(self, data):
551
         uid_name = self._target_class._uid[0]
556
         uid_name = self._target_class._uid[0]
552
         if self.__leobject_instance_datas is not None:
557
         if self.__leobject_instance_datas is not None:
553
-            #Instance update
554
-            #Building query_filter
558
+            # Instance update
559
+            # Building query_filter
555
             filters = [(
560
             filters = [(
556
                 uid_name,
561
                 uid_name,
557
                 '=',
562
                 '=',
560
                 self._target_class, filters, [],
565
                 self._target_class, filters, [],
561
                 self.__leobject_instance_datas)
566
                 self.__leobject_instance_datas)
562
         else:
567
         else:
563
-            #Update by filters, we have to fetch datas before updating
568
+            # Update by filters, we have to fetch data before updating
564
             res = self._ro_datasource.select(
569
             res = self._ro_datasource.select(
565
                 self._target_class, self._target_class.fieldnames(True),
570
                 self._target_class, self._target_class.fieldnames(True),
566
                 self._query_filter[0],
571
                 self._query_filter[0],
567
                 self._query_filter[1])
572
                 self._query_filter[1])
568
-            #Checking and constructing datas
569
-            upd_datas = dict()
573
+            # Checking and constructing data
574
+            upd_data = dict()
570
             for res_data in res:
575
             for res_data in res:
571
-                res_data.update(datas)
572
-                res_datas = self._target_class.prepare_datas(
576
+                res_data.update(data)
577
+                res_data = self._target_class.prepare_datas(
573
                     res_data, True, True)
578
                     res_data, True, True)
574
                 filters = [(uid_name, '=', res_data[uid_name])]
579
                 filters = [(uid_name, '=', res_data[uid_name])]
575
                 res = self._rw_datasource.update(
580
                 res = self._rw_datasource.update(
576
                     self._target_class, filters, [],
581
                     self._target_class, filters, [],
577
-                    res_datas)
582
+                    res_data)
578
         return res
583
         return res
579
 
584
 
580
-    ## @brief Execute the update query
581
-    def execute(self, datas=None):
582
-        if self.__leobject_instance_datas is not None and datas is not None:
583
-            raise LeApiQueryError("No datas expected when running an update \
585
+    #  @brief Execute the update query
586
+    def execute(self, data=None):
587
+        if self.__leobject_instance_datas is not None and data is not None:
588
+            raise LeApiQueryError("No data expected when running an update \
584
 query on an instance")
589
 query on an instance")
585
-        if self.__leobject_instance_datas is None and datas is None:
586
-            raise LeApiQueryError("Datas are mandatory when running an update \
590
+        if self.__leobject_instance_datas is None and data is None:
591
+            raise LeApiQueryError("Data are mandatory when running an update \
587
 query on a class with filters")
592
 query on a class with filters")
588
-        return super().execute(datas=datas)
593
+        return super().execute(data=data)
589
 
594
 
590
 
595
 
591
-##@brief A query to delete an object
596
+# @brief A query to delete an object
592
 class LeDeleteQuery(LeFilteredQuery):
597
 class LeDeleteQuery(LeFilteredQuery):
593
     _hook_prefix = 'leapi_delete_'
598
     _hook_prefix = 'leapi_delete_'
594
 
599
 
595
     def __init__(self, target_class, query_filter):
600
     def __init__(self, target_class, query_filter):
596
         super().__init__(target_class, query_filter)
601
         super().__init__(target_class, query_filter)
597
 
602
 
598
-    ## @brief Execute the delete query
599
-    # @param datas
600
-    def execute(self, datas=None):
603
+    #  @brief Execute the delete query
604
+    # @param data
605
+    def execute(self, data=None):
601
         return super().execute()
606
         return super().execute()
602
 
607
 
603
-    ##@brief Implements delete query operations
604
-    # @param datas
608
+    # @brief Implements delete query operations
609
+    # @param data
605
     #@returns the number of deleted items
610
     #@returns the number of deleted items
606
-    def _query(self, datas=None):
611
+    def _query(self, data=None):
607
         filters, rel_filters = self._query_filter
612
         filters, rel_filters = self._query_filter
608
         nb_deleted = self._rw_datasource.delete(
613
         nb_deleted = self._rw_datasource.delete(
609
             self._target_class, filters, rel_filters)
614
             self._target_class, filters, rel_filters)
610
         return nb_deleted
615
         return nb_deleted
611
 
616
 
617
+
612
 class LeGetQuery(LeFilteredQuery):
618
 class LeGetQuery(LeFilteredQuery):
613
     _hook_prefix = 'leapi_get_'
619
     _hook_prefix = 'leapi_get_'
614
 
620
 
615
-    ##@brief Instanciate a new get query
621
+    # @brief Instanciate a new get query
616
     #@param target_class LeObject : class of object the query is about
622
     #@param target_class LeObject : class of object the query is about
617
     #@param query_filters dict : {OP, list of query filters}
623
     #@param query_filters dict : {OP, list of query filters}
618
     # or tuple (FIELD, OPERATOR, VALUE) )
624
     # or tuple (FIELD, OPERATOR, VALUE) )
624
     #   - offset int : offset
630
     #   - offset int : offset
625
     def __init__(self, target_class, query_filters, **kwargs):
631
     def __init__(self, target_class, query_filters, **kwargs):
626
         super().__init__(target_class, query_filters)
632
         super().__init__(target_class, query_filters)
627
-        ##@brief The fields to get
633
+        # @brief The fields to get
628
         self._field_list = None
634
         self._field_list = None
629
-        ##@brief An equivalent to the SQL ORDER BY
635
+        # @brief An equivalent to the SQL ORDER BY
630
         self._order = None
636
         self._order = None
631
-        ##@brief An equivalent to the SQL GROUP BY
637
+        # @brief An equivalent to the SQL GROUP BY
632
         self._group = None
638
         self._group = None
633
-        ##@brief An equivalent to the SQL LIMIT x
639
+        # @brief An equivalent to the SQL LIMIT x
634
         self._limit = None
640
         self._limit = None
635
-        ##@brief An equivalent to the SQL LIMIT x, OFFSET
641
+        # @brief An equivalent to the SQL LIMIT x, OFFSET
636
         self._offset = 0
642
         self._offset = 0
637
 
643
 
638
         # Checking kwargs and assigning default values if there is some
644
         # Checking kwargs and assigning default values if there is some
639
         for argname in kwargs:
645
         for argname in kwargs:
640
             if argname not in (
646
             if argname not in (
641
-                'field_list', 'order', 'group', 'limit', 'offset'):
647
+                    'field_list', 'order', 'group', 'limit', 'offset'):
642
                 raise TypeError("Unexpected argument '%s'" % argname)
648
                 raise TypeError("Unexpected argument '%s'" % argname)
643
 
649
 
644
         if 'field_list' not in kwargs:
650
         if 'field_list' not in kwargs:
645
-            self.set_field_list(target_class.fieldnames(include_ro = True))
651
+            self.set_field_list(target_class.fieldnames(include_ro=True))
646
         else:
652
         else:
647
             self.set_field_list(kwargs['field_list'])
653
             self.set_field_list(kwargs['field_list'])
648
 
654
 
649
         if 'order' in kwargs:
655
         if 'order' in kwargs:
650
-            #check kwargs['order']
656
+            # check kwargs['order']
651
             self._order = kwargs['order']
657
             self._order = kwargs['order']
652
         if 'group' in kwargs:
658
         if 'group' in kwargs:
653
-            #check kwargs['group']
659
+            # check kwargs['group']
654
             self._group = kwargs['group']
660
             self._group = kwargs['group']
655
         if 'limit' in kwargs and kwargs['limit'] is not None:
661
         if 'limit' in kwargs and kwargs['limit'] is not None:
656
             try:
662
             try:
669
                 msg = "offset argument expected to be an integer >= 0"
675
                 msg = "offset argument expected to be an integer >= 0"
670
                 raise ValueError(msg)
676
                 raise ValueError(msg)
671
 
677
 
672
-    ##@brief Set the field list
678
+    # @brief Set the field list
673
     # @param field_list list | None : If None use all fields
679
     # @param field_list list | None : If None use all fields
674
     # @return None
680
     # @return None
675
     # @throw LeApiQueryError if unknown field given
681
     # @throw LeApiQueryError if unknown field given
682
                     msg = "No field named '%s' in %s"
688
                     msg = "No field named '%s' in %s"
683
                     msg %= (fieldname, self._target_class.__name__)
689
                     msg %= (fieldname, self._target_class.__name__)
684
                     expt = NameError(msg)
690
                     expt = NameError(msg)
685
-                    err_l[fieldname] =  expt
691
+                    err_l[fieldname] = expt
686
             if len(err_l) > 0:
692
             if len(err_l) > 0:
687
                 msg = "Error while setting field_list in a get query"
693
                 msg = "Error while setting field_list in a get query"
688
-                raise LeApiQueryErrors(msg = msg, exceptions = err_l)
694
+                raise LeApiQueryErrors(msg=msg, exceptions=err_l)
689
             self._field_list = list(set(field_list))
695
             self._field_list = list(set(field_list))
690
 
696
 
691
-    ##@brief Execute the get query
692
-    def execute(self, datas=None):
697
+    # @brief Execute the get query
698
+    def execute(self, data=None):
693
         return super().execute()
699
         return super().execute()
694
 
700
 
695
-    ##@brief Implements select query operations
701
+    # @brief Implements select query operations
696
     # @returns a list containing the item(s)
702
     # @returns a list containing the item(s)
697
-    def _query(self, datas=None):
698
-        # select datas corresponding to query_filter
703
+    def _query(self, data=None):
704
+        # select data corresponding to query_filter
699
         fl = list(self._field_list) if self._field_list is not None else None
705
         fl = list(self._field_list) if self._field_list is not None else None
700
-        l_datas=self._ro_datasource.select(
701
-            target = self._target_class,
702
-            field_list = fl,
703
-            filters = self._query_filter[0],
704
-            relational_filters = self._query_filter[1],
705
-            order = self._order,
706
-            group = self._group,
707
-            limit = self._limit,
708
-            offset = self._offset)
709
-        return l_datas
710
-
711
-    ##@return a dict with query infos
706
+        l_data = self._ro_datasource.select(
707
+            target=self._target_class,
708
+            field_list=fl,
709
+            filters=self._query_filter[0],
710
+            relational_filters=self._query_filter[1],
711
+            order=self._order,
712
+            group=self._group,
713
+            limit=self._limit,
714
+            offset=self._offset)
715
+        return l_data
716
+
717
+    # @return a dict with query infos
712
     def dump_infos(self):
718
     def dump_infos(self):
713
         ret = super().dump_infos()
719
         ret = super().dump_infos()
714
-        ret.update({  'field_list' : self._field_list,
715
-                        'order' : self._order,
716
-                        'group' : self._group,
717
-                        'limit' : self._limit,
718
-                        'offset': self._offset,
719
-       })
720
+        ret.update({'field_list': self._field_list,
721
+                    'order': self._order,
722
+                    'group': self._group,
723
+                    'limit': self._limit,
724
+                    'offset': self._offset,
725
+                    })
720
         return ret
726
         return ret
721
 
727
 
722
     def __repr__(self):
728
     def __repr__(self):
725
 offset={offset}"
731
 offset={offset}"
726
         res = res.format(**self.dump_infos())
732
         res = res.format(**self.dump_infos())
727
         if len(self.subqueries) > 0:
733
         if len(self.subqueries) > 0:
728
-            for n,subq in enumerate(self.subqueries):
734
+            for n, subq in enumerate(self.subqueries):
729
                 res += "\n\tSubquerie %d : %s"
735
                 res += "\n\tSubquerie %d : %s"
730
                 res %= (n, subq)
736
                 res %= (n, subq)
731
         res += ">"
737
         res += ">"

+ 27
- 37
lodel/plugins/mongodb_datasource/datasource.py View File

84
         target = emcomp.uid_source()
84
         target = emcomp.uid_source()
85
         tuid = target._uid[0] # Multiple UID broken here
85
         tuid = target._uid[0] # Multiple UID broken here
86
         results = self.select(
86
         results = self.select(
87
-            target, field_list = [tuid], filters = [], 
87
+            target, field_list = [tuid], filters = [],
88
             order=[(tuid, 'DESC')], limit = 1)
88
             order=[(tuid, 'DESC')], limit = 1)
89
-        if len(results) == 0: 
89
+        if len(results) == 0:
90
             return 1
90
             return 1
91
         return results[0][tuid]+1
91
         return results[0][tuid]+1
92
 
92
 
95
     #@param field_list list
95
     #@param field_list list
96
     #@param filters list : List of filters
96
     #@param filters list : List of filters
97
     #@param relational_filters list : List of relational filters
97
     #@param relational_filters list : List of relational filters
98
-    #@param order list : List of column to order. ex: order = 
98
+    #@param order list : List of column to order. ex: order =
99
     #[('title', 'ASC'),]
99
     #[('title', 'ASC'),]
100
-    #@param group list : List of tupple representing the column used as 
100
+    #@param group list : List of tupple representing the column used as
101
     #"group by" fields. ex: group = [('title', 'ASC'),]
101
     #"group by" fields. ex: group = [('title', 'ASC'),]
102
     #@param limit int : Number of records to be returned
102
     #@param limit int : Number of records to be returned
103
     #@param offset int: used with limit to choose the start record
103
     #@param offset int: used with limit to choose the start record
104
     #@return list
104
     #@return list
105
     #@todo Implement group for abstract LeObject childs
105
     #@todo Implement group for abstract LeObject childs
106
-    def select(self, target, field_list, filters = None, 
107
-            relational_filters=None, order=None, group=None, limit=None, 
106
+    def select(self, target, field_list, filters = None,
107
+            relational_filters=None, order=None, group=None, limit=None,
108
             offset=0):
108
             offset=0):
109
         if target.is_abstract():
109
         if target.is_abstract():
110
             #Reccursiv calls for abstract LeObject child
110
             #Reccursiv calls for abstract LeObject child
111
             results =  self.__act_on_abstract(target, filters,
111
             results =  self.__act_on_abstract(target, filters,
112
                 relational_filters, self.select, field_list = field_list,
112
                 relational_filters, self.select, field_list = field_list,
113
                 order = order, group = group, limit = limit)
113
                 order = order, group = group, limit = limit)
114
-            
114
+
115
             #Here we may implement the group
115
             #Here we may implement the group
116
             #If sorted query we have to sort again
116
             #If sorted query we have to sort again
117
             if order is not None:
117
             if order is not None:
138
 
138
 
139
         query_filters = self.__process_filters(
139
         query_filters = self.__process_filters(
140
             target, filters, relational_filters)
140
             target, filters, relational_filters)
141
-        
141
+
142
         query_result_ordering = None
142
         query_result_ordering = None
143
         if order is not None:
143
         if order is not None:
144
             query_result_ordering = utils.parse_query_order(order)
144
             query_result_ordering = utils.parse_query_order(order)
145
-        
145
+
146
         if group is None:
146
         if group is None:
147
             if field_list is None:
147
             if field_list is None:
148
                 field_list = dict()
148
                 field_list = dict()
189
         results = list()
189
         results = list()
190
         for document in cursor:
190
         for document in cursor:
191
             results.append(document)
191
             results.append(document)
192
-        
192
+
193
         return results
193
         return results
194
 
194
 
195
     ##@brief Deletes records according to given filters
195
     ##@brief Deletes records according to given filters
236
         self.__update_backref_filtered(target, filters, relational_filters,
236
         self.__update_backref_filtered(target, filters, relational_filters,
237
             upd_datas, old_datas_l)
237
             upd_datas, old_datas_l)
238
         return res
238
         return res
239
-    
239
+
240
     ##@brief Designed to be called by backref update in order to avoid
240
     ##@brief Designed to be called by backref update in order to avoid
241
     #infinite updates between back references
241
     #infinite updates between back references
242
     #@see update()
242
     #@see update()
269
             raise MongoDataSourceError("Missing UID data will inserting a new \
269
             raise MongoDataSourceError("Missing UID data will inserting a new \
270
 %s" % target.__class__)
270
 %s" % target.__class__)
271
         res = self.__collection(target).insert(new_datas)
271
         res = self.__collection(target).insert(new_datas)
272
-        self.__update_backref(target, new_datas[uidname], None, new_datas) 
272
+        self.__update_backref(target, new_datas[uidname], None, new_datas)
273
         return str(res)
273
         return str(res)
274
 
274
 
275
     ## @brief Inserts a list of records in a given collection
275
     ## @brief Inserts a list of records in a given collection
281
             self._data_cast(datas)
281
             self._data_cast(datas)
282
         res = self.__collection(target).insert_many(datas_list)
282
         res = self.__collection(target).insert_many(datas_list)
283
         for new_datas in datas_list:
283
         for new_datas in datas_list:
284
-            self.__update_backref(target, None, new_datas) 
284
+            self.__update_backref(target, None, new_datas)
285
             target.make_consistency(datas=new_datas)
285
             target.make_consistency(datas=new_datas)
286
         return list(res.inserted_ids)
286
         return list(res.inserted_ids)
287
-    
287
+
288
     ##@brief Update backref giving an action
288
     ##@brief Update backref giving an action
289
     #@param target leObject child class
289
     #@param target leObject child class
290
     #@param filters
290
     #@param filters
303
             old_datas_l = self.__collection(target).find(
303
             old_datas_l = self.__collection(target).find(
304
                 mongo_filters)
304
                 mongo_filters)
305
             old_datas_l = list(old_datas_l)
305
             old_datas_l = list(old_datas_l)
306
-        
306
+
307
         uidname = target.uid_fieldname()[0] #MULTIPLE UID BROKEN HERE
307
         uidname = target.uid_fieldname()[0] #MULTIPLE UID BROKEN HERE
308
         for old_datas in old_datas_l:
308
         for old_datas in old_datas_l:
309
             self.__update_backref(
309
             self.__update_backref(
312
     ##@brief Update back references of an object
312
     ##@brief Update back references of an object
313
     #@ingroup plugin_mongodb_bref_op
313
     #@ingroup plugin_mongodb_bref_op
314
     #
314
     #
315
-    #old_datas and new_datas arguments are set to None to indicate 
315
+    #old_datas and new_datas arguments are set to None to indicate
316
     #insertion or deletion. Calls examples :
316
     #insertion or deletion. Calls examples :
317
     #@par LeObject insert __update backref call
317
     #@par LeObject insert __update backref call
318
     #<pre>
318
     #<pre>
441
                 self.__update_no_backref(
441
                 self.__update_no_backref(
442
                     leo.__class__, [(leo.uid_fieldname()[0], '=', uidval)],
442
                     leo.__class__, [(leo.uid_fieldname()[0], '=', uidval)],
443
                     [], datas)
443
                     [], datas)
444
-    
445
-    ##@brief Utility function designed to handle the upd_dict of 
444
+
445
+    ##@brief Utility function designed to handle the upd_dict of
446
     #__update_backref()
446
     #__update_backref()
447
     #
447
     #
448
     #Basically checks if a key exists at some level, if not create it with
448
     #Basically checks if a key exists at some level, if not create it with
453
     #@param uid_val mixed : the UID of the referenced object
453
     #@param uid_val mixed : the UID of the referenced object
454
     #@return the updated version of upd_dict
454
     #@return the updated version of upd_dict
455
     @staticmethod
455
     @staticmethod
456
-    def __update_backref_upd_dict_prepare(upd_dict,bref_infos, bref_fname, 
456
+    def __update_backref_upd_dict_prepare(upd_dict,bref_infos, bref_fname,
457
             uid_val):
457
             uid_val):
458
         bref_cls, bref_leo, bref_dh, bref_value = bref_infos
458
         bref_cls, bref_leo, bref_dh, bref_value = bref_infos
459
         if bref_cls not in upd_dict:
459
         if bref_cls not in upd_dict:
463
         if bref_fname not in upd_dict[bref_cls][uid_val]:
463
         if bref_fname not in upd_dict[bref_cls][uid_val]:
464
             upd_dict[bref_cls][uid_val][1][bref_fname] = bref_value
464
             upd_dict[bref_cls][uid_val][1][bref_fname] = bref_value
465
         return upd_dict
465
         return upd_dict
466
-        
467
-        
466
+
467
+
468
     ##@brief Prepare a one value back reference update
468
     ##@brief Prepare a one value back reference update
469
     #@param fname str : the source Reference field name
469
     #@param fname str : the source Reference field name
470
     #@param fdh DataHandler : the source Reference DataHandler
470
     #@param fdh DataHandler : the source Reference DataHandler
520
                 return bref_val
520
                 return bref_val
521
             elif oldd and not newdd:
521
             elif oldd and not newdd:
522
                 #deletion
522
                 #deletion
523
-                if not hasattr(bref_dh, "default"): 
523
+                if not hasattr(bref_dh, "default"):
524
                     raise MongoDbConsistencyError("Unable to delete a \
524
                     raise MongoDbConsistencyError("Unable to delete a \
525
 value for a back reference update. The concerned field don't have a default \
525
 value for a back reference update. The concerned field don't have a default \
526
 value : in %s field %s" % (bref_leo,fname))
526
 value : in %s field %s" % (bref_leo,fname))
528
             elif not oldd and newdd:
528
             elif not oldd and newdd:
529
                 bref_val = tuid
529
                 bref_val = tuid
530
         return bref_val
530
         return bref_val
531
-    
531
+
532
     ##@brief Fetch back reference informations
532
     ##@brief Fetch back reference informations
533
     #@warning thank's to __update_backref_act() this method is useless
533
     #@warning thank's to __update_backref_act() this method is useless
534
     #@param bref_cls LeObject child class : __back_reference[0]
534
     #@param bref_cls LeObject child class : __back_reference[0]
608
             port = self.__db_infos['port'],
608
             port = self.__db_infos['port'],
609
             db_name = db_name,
609
             db_name = db_name,
610
             ro = ro)
610
             ro = ro)
611
-        
611
+
612
         self.__conn_hash = conn_h = hash(conn_string)
612
         self.__conn_hash = conn_h = hash(conn_string)
613
         if conn_h in self._connections:
613
         if conn_h in self._connections:
614
             self._connections[conn_h]['conn_count'] += 1
614
             self._connections[conn_h]['conn_count'] += 1
619
                 'conn_count': 1,
619
                 'conn_count': 1,
620
                 'db': utils.connect(conn_string)}
620
                 'db': utils.connect(conn_string)}
621
             return self._connections[conn_h]['db'][self.__db_infos['db_name']]
621
             return self._connections[conn_h]['db'][self.__db_infos['db_name']]
622
-                    
622
+
623
 
623
 
624
     ##@brief Return a pymongo collection given a LeObject child class
624
     ##@brief Return a pymongo collection given a LeObject child class
625
     #@param leobject LeObject child class (no instance)
625
     #@param leobject LeObject child class (no instance)
760
                     rfilters[fname][repr_leo][rfield] = list()
760
                     rfilters[fname][repr_leo][rfield] = list()
761
                 rfilters[fname][repr_leo][rfield].append((op, value))
761
                 rfilters[fname][repr_leo][rfield].append((op, value))
762
         return rfilters
762
         return rfilters
763
-    
763
+
764
     ##@brief Convert lodel2 filters to pymongo conditions
764
     ##@brief Convert lodel2 filters to pymongo conditions
765
     #@param filters list : list of lodel filters
765
     #@param filters list : list of lodel filters
766
     #@return dict representing pymongo conditions
766
     #@return dict representing pymongo conditions
859
             1 if (a[fname]>b[fname] if cmpdir == 'ASC' else a[fname]<b[fname])\
859
             1 if (a[fname]>b[fname] if cmpdir == 'ASC' else a[fname]<b[fname])\
860
             else -1)
860
             else -1)
861
 
861
 
862
-    
862
+
863
     ##@brief Correct some datas before giving them to pymongo
863
     ##@brief Correct some datas before giving them to pymongo
864
     #
864
     #
865
     #For example sets has to be casted to lise
865
     #For example sets has to be casted to lise
874
                 #with sets
874
                 #with sets
875
                 datas[dname] = list(datas[dname])
875
                 datas[dname] = list(datas[dname])
876
         return datas
876
         return datas
877
-
878
-    ##@brief Tool to check if a record with unique id uid is set in the target_class representation
879
-    #@param target_class : class to check in 
880
-    #@param uid : a unique id in target_class
881
-    #@returns true if a record with unique id uid exists in the target_class representation, false if not
882
-    def is_exist(self, target_class, uid):
883
-    # retrouver la table qui correspond à target_class
884
-    # vérifier qu'il existe, ou pas, un enregistrement contenant uid
885
-        result = self.select(self, target_class, [target_class.uid_fieldname], filters = [(target_class.uid_fieldname, '=', uid)])
886
-        return len(result) == 1

+ 13
- 13
tests/editorial_model/test_model.py View File

23
         grp1.add_components((cls1, c1f1))
23
         grp1.add_components((cls1, c1f1))
24
         grp2 = model.new_group('testgroup2')
24
         grp2 = model.new_group('testgroup2')
25
         grp2.add_components((cls2, c1f2, c2f1, c2f2))
25
         grp2.add_components((cls2, c1f2, c2f1, c2f2))
26
-        grp2.add_dependencie(grp1)
26
+        grp2.add_dependency(grp1)
27
         e_hash = 0x250eab75e782e51bbf212f47c6159571
27
         e_hash = 0x250eab75e782e51bbf212f47c6159571
28
         self.assertEqual(model.d_hash(), e_hash)
28
         self.assertEqual(model.d_hash(), e_hash)
29
 
29
 
181
         grp3 = EmGroup('grp3')
181
         grp3 = EmGroup('grp3')
182
         grp4 = EmGroup('grp4')
182
         grp4 = EmGroup('grp4')
183
 
183
 
184
-        grp2.add_dependencie(grp1)
185
-        grp3.add_dependencie(grp2)
186
-        grp4.add_dependencie(grp2)
187
-        grp4.add_dependencie(grp1)
184
+        grp2.add_dependency(grp1)
185
+        grp3.add_dependency(grp2)
186
+        grp4.add_dependency(grp2)
187
+        grp4.add_dependency(grp1)
188
 
188
 
189
         self.assertEqual(set(grp1.dependencies().values()), set())
189
         self.assertEqual(set(grp1.dependencies().values()), set())
190
         self.assertEqual(set(grp2.dependencies().values()), set([grp1]))
190
         self.assertEqual(set(grp2.dependencies().values()), set([grp1]))
261
     def test_deps_complex(self):
261
     def test_deps_complex(self):
262
         """ More complex dependencies handling test """
262
         """ More complex dependencies handling test """
263
         grps = [ EmGroup('group%d' % i) for i in range(6) ]
263
         grps = [ EmGroup('group%d' % i) for i in range(6) ]
264
-        grps[5].add_dependencie( (grps[1], grps[2], grps[4]) )
265
-        grps[4].add_dependencie( (grps[1], grps[3]) )
266
-        grps[3].add_dependencie( (grps[0],) )
267
-        grps[1].add_dependencie( (grps[2], grps[0]) )
264
+        grps[5].add_dependency( (grps[1], grps[2], grps[4]) )
265
+        grps[4].add_dependency( (grps[1], grps[3]) )
266
+        grps[3].add_dependency( (grps[0],) )
267
+        grps[1].add_dependency( (grps[2], grps[0]) )
268
         self.assertEqual(
268
         self.assertEqual(
269
                             set(grps[5].dependencies(True).values()),
269
                             set(grps[5].dependencies(True).values()),
270
                             set( grps[i] for i in range(5))
270
                             set( grps[i] for i in range(5))
273
                             set(grps[4].dependencies(True).values()),
273
                             set(grps[4].dependencies(True).values()),
274
                             set( grps[i] for i in range(4))
274
                             set( grps[i] for i in range(4))
275
         )
275
         )
276
-        grps[2].add_dependencie(grps[0])
276
+        grps[2].add_dependency(grps[0])
277
         self.assertEqual(
277
         self.assertEqual(
278
                             set(grps[5].dependencies(True).values()),
278
                             set(grps[5].dependencies(True).values()),
279
                             set( grps[i] for i in range(5))
279
                             set( grps[i] for i in range(5))
284
         )
284
         )
285
         # Inserting circular deps
285
         # Inserting circular deps
286
         with self.assertRaises(EditorialModelError):
286
         with self.assertRaises(EditorialModelError):
287
-            grps[0].add_dependencie(grps[5])
287
+            grps[0].add_dependency(grps[5])
288
 
288
 
289
     def test_circular_dep(self):
289
     def test_circular_dep(self):
290
         """ Test circular dependencies detection """
290
         """ Test circular dependencies detection """
291
         grps = [ EmGroup('group%d' % i) for i in range(10) ]
291
         grps = [ EmGroup('group%d' % i) for i in range(10) ]
292
         for i in range(1,10):
292
         for i in range(1,10):
293
-            grps[i].add_dependencie(grps[i-1])
293
+            grps[i].add_dependency(grps[i-1])
294
 
294
 
295
         for i in range(1,10):
295
         for i in range(1,10):
296
             for j in range(i+1,10):
296
             for j in range(i+1,10):
297
                 with self.assertRaises(EditorialModelError):
297
                 with self.assertRaises(EditorialModelError):
298
-                    grps[i].add_dependencie(grps[j])
298
+                    grps[i].add_dependency(grps[j])
299
 
299
 
300
     def test_d_hash(self):
300
     def test_d_hash(self):
301
         """ Test the deterministic hash method """
301
         """ Test the deterministic hash method """

+ 1
- 1
tests/editorial_model/test_translator_picklefile.py View File

26
         grp2 = model.new_group('testgroup2')
26
         grp2 = model.new_group('testgroup2')
27
         grp2.add_components((cls2, c1f2, c2f1, c2f2))
27
         grp2.add_components((cls2, c1f2, c2f1, c2f2))
28
 
28
 
29
-        grp2.add_dependencie(grp1)
29
+        grp2.add_dependency(grp1)
30
         
30
         
31
         tmpfd, temp_file = tempfile.mkstemp()
31
         tmpfd, temp_file = tempfile.mkstemp()
32
         os.close(tmpfd)
32
         os.close(tmpfd)

+ 1
- 1
tests/editorial_model/test_translator_xmlfile.py View File

44
         grp2 = emmodel.new_group('testgroup2')
44
         grp2 = emmodel.new_group('testgroup2')
45
         grp2.add_components((cls2, c1f2, c2f1, c2f2))
45
         grp2.add_components((cls2, c1f2, c2f1, c2f2))
46
 
46
 
47
-        grp2.add_dependencie(grp1)
47
+        grp2.add_dependency(grp1)
48
         
48
         
49
         f_tmp, file_name = tempfile.mkstemp()
49
         f_tmp, file_name = tempfile.mkstemp()
50
         os.close(f_tmp)
50
         os.close(f_tmp)

+ 3
- 3
tests/leapi/query/test_datasource.py View File

105
             [(('alias', {cls: 'firstname'}), '=', 'foo')])
105
             [(('alias', {cls: 'firstname'}), '=', 'foo')])
106
         self.check_nocall(read = False, exclude = ['delete'])
106
         self.check_nocall(read = False, exclude = ['delete'])
107
         self.check_nocall(read = True)
107
         self.check_nocall(read = True)
108
-    
108
+
109
     @unittest.skip("Waiting references checks stack implementation")
109
     @unittest.skip("Waiting references checks stack implementation")
110
     def test_insert(self):
110
     def test_insert(self):
111
         """ Testing LeInsertQuery mocking datasource """
111
         """ Testing LeInsertQuery mocking datasource """
145
         query = LeUpdateQuery(inst)
145
         query = LeUpdateQuery(inst)
146
 
146
 
147
         with self.assertRaises(LeApiQueryError):
147
         with self.assertRaises(LeApiQueryError):
148
-            # Bad call, giving datas while an instance was given to __init__
149
-            query.execute(datas = {'firstname': 'ooba'})
148
+            # Bad call, giving data while an instance was given to __init__
149
+            query.execute(data = {'firstname': 'ooba'})
150
 
150
 
151
         query.execute()
151
         query.execute()
152
         self.mockwrite.update.assert_called_once_with(
152
         self.mockwrite.update.assert_called_once_with(

Loading…
Cancel
Save