|
@@ -119,7 +119,7 @@ class _LeObject(_LeCrud):
|
119
|
119
|
# @param field str : a relational field
|
120
|
120
|
# @return a nature
|
121
|
121
|
@staticmethod
|
122
|
|
- def _prepare_relational_field(field):
|
|
122
|
+ def _prepare_relational_fields(field):
|
123
|
123
|
spl = field.split('.')
|
124
|
124
|
if len(spl) != 2:
|
125
|
125
|
return ValueError("The relationalfield '%s' is not valid"%field)
|
|
@@ -134,212 +134,6 @@ class _LeObject(_LeCrud):
|
134
|
134
|
else:
|
135
|
135
|
return ValueError("Invalid preffix for relationnal field : '%s'"%spl[0])
|
136
|
136
|
|
137
|
|
- ## @brief Check if a LeType is a hierarchy root
|
138
|
|
- @staticmethod
|
139
|
|
- def ___is_root(leo):
|
140
|
|
- if isinstance(leo, leapi.letype.LeType):
|
141
|
|
- return False
|
142
|
|
- elif isinstance(leo, LeRoot):
|
143
|
|
- return True
|
144
|
|
- raise ValueError("Invalid value for a LeType : %s"%leo)
|
145
|
|
-
|
146
|
|
- ## @brief Return a LeRoot instance
|
147
|
|
- @staticmethod
|
148
|
|
- def ___get_root():
|
149
|
|
- return LeRoot()
|
150
|
|
-
|
151
|
|
- ## @brief Link two leobject together using a rel2type field
|
152
|
|
- # @param lesup LeType : LeType child class instance linked as superior
|
153
|
|
- # @param lesub LeType : LeType child class instance linked as subordinate
|
154
|
|
- # @param **rel_attr : Relation attributes
|
155
|
|
- # @return True if linked without problems
|
156
|
|
- # @throw LeObjectError if the link is not valid
|
157
|
|
- # @throw LeObkectError if the link already exists
|
158
|
|
- # @throw AttributeError if an non existing relation attribute is given as argument
|
159
|
|
- # @throw ValueError if the relation attrivute value check fails
|
160
|
|
- #
|
161
|
|
- # @todo Code factorisation on relation check
|
162
|
|
- # @todo unit tests
|
163
|
|
- @classmethod
|
164
|
|
- def ___link_together(cls, lesup, lesub, rank = 'last', **rel_attr):
|
165
|
|
- if lesub.__class__ not in lesup._linked_types.keys():
|
166
|
|
- raise LeObjectError("Relation error : %s cannot be linked with %s"%(lesup.__class__.__name__, lesub.__class__.__name__))
|
167
|
|
-
|
168
|
|
- for attr_name in rel_attr.keys():
|
169
|
|
- if attr_name not in [ f for f,g in lesup._linked_types[lesub.__class__] ]:
|
170
|
|
- raise AttributeError("A rel2type between a %s and a %s doesn't have an attribute %s"%(lesup.__class__.__name__, lesub.__class__.__name__))
|
171
|
|
- if not sup._linked_types[lesub.__class__][1].check(rel_attr[attr_name]):
|
172
|
|
- raise ValueError("Wrong value '%s' for attribute %s"%(rel_attr[attr_name], attr_name))
|
173
|
|
-
|
174
|
|
- #Checks that attributes are uniq for this relation
|
175
|
|
- rels_attr = [ attrs for lesup, lesub, attrs in cls.links_get(lesup) if lesup == lesup ]
|
176
|
|
- for e_attrs in rels_attrs:
|
177
|
|
- if rel_attr == e_attrs:
|
178
|
|
- raise LeObjectError("Relation error : a relation with the same attributes already exists")
|
179
|
|
-
|
180
|
|
- return cls._datasource.add_related(lesup, lesub, rank, **rel_attr)
|
181
|
|
-
|
182
|
|
- ## @brief Get related objects
|
183
|
|
- # @param leo LeType(instance) : LeType child class instance
|
184
|
|
- # @param letype LeType(class) : the wanted LeType child class (not instance)
|
185
|
|
- # @param leo_is_superior bool : if True leo is the superior in the relation
|
186
|
|
- # @return A dict with LeType child class instance as key and dict {rel_attr_name:rel_attr_value, ...}
|
187
|
|
- # @throw LeObjectError if the relation is not possible
|
188
|
|
- #
|
189
|
|
- # @todo Code factorisation on relation check
|
190
|
|
- # @todo unit tests
|
191
|
|
- @classmethod
|
192
|
|
- def ___linked_together(cls, leo, letype, leo_is_superior = True):
|
193
|
|
- valid_link = letype in leo._linked_types.keys() if leo_is_superior else leo.__class__ in letype._linked_types.keys()
|
194
|
|
-
|
195
|
|
- if not valid_link:
|
196
|
|
- raise LeObjectError("Relation error : %s have no links with %s"%(
|
197
|
|
- leo.__class__ if leo_is_superior else letype,
|
198
|
|
- letype if leo_is_superior else leo.__class__
|
199
|
|
- ))
|
200
|
|
-
|
201
|
|
- return cls._datasource.get_related(leo, letype, leo_is_superior)
|
202
|
|
-
|
203
|
|
- ## @brief Fetch a relation and its attributes
|
204
|
|
- # @param id_relation int : the relation identifier
|
205
|
|
- # @return a tuple(lesup, lesub, dict_attr) or False if no relation exists with this id
|
206
|
|
- # @throw Exception if the relation is not a rel2type relation
|
207
|
|
- @classmethod
|
208
|
|
- def ___link_get(cls, id_relation):
|
209
|
|
- return cls._datasource.get_relation(id_relation)
|
210
|
|
-
|
211
|
|
- ## @brief Fetch all relations for an objects
|
212
|
|
- # @param leo LeType : LeType child class instance
|
213
|
|
- # @return a list of tuple (lesup, lesub, dict_attr)
|
214
|
|
- def ___links_get(cls, leo):
|
215
|
|
- return cls._datasource.get_relations(leo)
|
216
|
|
-
|
217
|
|
- ## @brief Remove a link (and attributes) between two LeObject
|
218
|
|
- # @param id_relation int : Relation identifier
|
219
|
|
- # @return True if a link has been deleted
|
220
|
|
- # @throw LeObjectError if the relation is not a rel2type
|
221
|
|
- #
|
222
|
|
- # @todo Code factorisation on relation check
|
223
|
|
- # @todo unit tests
|
224
|
|
- @classmethod
|
225
|
|
- def ___link_remove(cls, id_relation):
|
226
|
|
- if lesub.__class__ not in lesup._linked_types.keys():
|
227
|
|
- raise LeObjectError("Relation errorr : %s cannot be linked with %s"%(lesup.__class__.__name__, lesub.__class__.__name__))
|
228
|
|
-
|
229
|
|
- return cls._datasource.del_related(lesup, lesub)
|
230
|
|
-
|
231
|
|
- ## @brief Add a hierarchy relation between two LeObject
|
232
|
|
- # @param lesup LeType|LeRoot : LeType child class instance
|
233
|
|
- # @param lesub LeType : LeType child class instance
|
234
|
|
- # @param nature str : The nature of the relation @ref EditorialModel.classtypes
|
235
|
|
- # @param rank str|int : The relation rank. Can be 'last', 'first' or an integer
|
236
|
|
- # @param replace_if_exists bool : if True delete the old superior and set the new one. If False and there is a superior raise an LeObjectQueryError
|
237
|
|
- # @return The relation ID or False if fails
|
238
|
|
- # @throw LeObjectQueryError replace_if_exists == False and there is a superior
|
239
|
|
- @classmethod
|
240
|
|
- def ___hierarchy_add(cls, lesup, lesub, nature, rank = 'last', replace_if_exists = False):
|
241
|
|
- #Arguments check
|
242
|
|
- if nature not in EditorialModel.classtypes.EmClassType.natures(lesub._classtype):
|
243
|
|
- raise ValueError("Invalid nature '%s' for %s"%(nature, lesup.__class__.__name__))
|
244
|
|
-
|
245
|
|
- if not cls.leo_is_root(lesup):
|
246
|
|
- if nature not in EditorialModel.classtypes.EmClassType.natures(lesup._classtype):
|
247
|
|
- raise ValueError("Invalid nature '%s' for %s"%(nature, lesup.__class__.__name__))
|
248
|
|
- if lesup.__class__ not in lesub._superiors[nature]:
|
249
|
|
- raise ValueError("%s is not a valid superior for %s"%(lesup.__class__, lesub.__class__))
|
250
|
|
- #else:
|
251
|
|
- # lesup is not a LeType but a hierarchy root
|
252
|
|
-
|
253
|
|
- if rank not in ['first', 'last'] and not isinstance(rank, int):
|
254
|
|
- raise ValueError("Allowed values for rank are integers and 'first' or 'last' but '%s' found"%rank)
|
255
|
|
-
|
256
|
|
- superiors = cls.hierarchy_get(lesub, nature, leo_is_sup = False)
|
257
|
|
- if lesup in len(superiors) > 0:
|
258
|
|
- if not replace_if_exists:
|
259
|
|
- raise LeObjectQueryError("The subordinate allready has a superior")
|
260
|
|
- #remove existig superior
|
261
|
|
- if not cls.hierarchy_del(superiors[0], lesub, nature):
|
262
|
|
- raise RuntimeError("Unable to delete the previous superior")
|
263
|
|
-
|
264
|
|
- return self._datasource.add_superior(lesup, lesub, nature, rank)
|
265
|
|
-
|
266
|
|
- ## @brief Delete a hierarchy link between two LeObject
|
267
|
|
- # @param lesup LeType | LeRoot : LeType child class or hierarchy root
|
268
|
|
- # @param lesub LeType : LeType child class
|
269
|
|
- # @param nature str : The nature of the relation @ref EditorialModel.classtypes
|
270
|
|
- # @return True if deletion done successfully
|
271
|
|
- # @throw ValueError when bad arguments given
|
272
|
|
- @classmethod
|
273
|
|
- def ___hierarchy_del(cls, lesup, lesub, nature):
|
274
|
|
- if nature not in EditorialModel.classtypes.EmClassType.natures(lesub._classtype):
|
275
|
|
- raise ValueError("Invalid nature '%s' for %s"%(nature, lesup.__class__.__name__))
|
276
|
|
-
|
277
|
|
- if not cls.leo_is_root(lesup):
|
278
|
|
- if nature not in EditorialModel.classtypes.EmClassType.natures(lesup._classtype):
|
279
|
|
- raise ValueError("Invalid nature '%s' for %s"%(nature, lesup.__class__.__name__))
|
280
|
|
- if lesup.__class__ not in lesub._superiors[nature]:
|
281
|
|
- raise ValueError("%s is not a valid superior for %s"%(lesup.__class__, lesub.__class__))
|
282
|
|
- superiors = cls.hierarchy_get(lesub, nature, leo_is_sup = False)
|
283
|
|
- res = True
|
284
|
|
- for _lesup in superiors:
|
285
|
|
- if not cls._datasource.del_superior(_lesup, lesub, nature):
|
286
|
|
- #How to handler this ?
|
287
|
|
- res = False
|
288
|
|
- return res
|
289
|
|
-
|
290
|
|
- ## @brief Fetch neighbour in hierarchy relation
|
291
|
|
- # @param leo LeType | LeRoot : We want the neighbour of this LeObject (can be the root)
|
292
|
|
- # @param nature str : @ref EditorialModel.classtypes
|
293
|
|
- # @param leo_is_sup bool : if True leo is the superior and we want to fetch the subordinates else its the oposite
|
294
|
|
- # @return A list of LeObject ordered by depth if leo_is_sup, else a list of subordinates
|
295
|
|
- @classmethod
|
296
|
|
- def ___hierarchy_get(cls, leo, nature, leo_is_sup = True):
|
297
|
|
- #Checking arguments
|
298
|
|
- if not (nature is None) and not cls.is_root(leo):
|
299
|
|
- if nature not in EditorialModel.classtypes.EmClassType.natures(leo._classtype):
|
300
|
|
- raise ValueError("Invalid nature '%s' for %s"%(nature, lesup.__class__.__name__))
|
301
|
|
-
|
302
|
|
- if leo_is_sup:
|
303
|
|
- return cls._datasource.get_subordinates(leo, nature)
|
304
|
|
- else:
|
305
|
|
- return cls._datasource.get_superiors(leo, nature)
|
306
|
|
-
|
307
|
|
- ## @brief Preparing letype and leclass arguments
|
308
|
|
- #
|
309
|
|
- # This function will do multiple things :
|
310
|
|
- # - Convert string to LeType or LeClass child instances
|
311
|
|
- # - If both letype and leclass given, check that letype inherit from leclass
|
312
|
|
- # - If only a letype is given, fetch the parent leclass
|
313
|
|
- # @note If we give only a leclass as argument returned letype will be None
|
314
|
|
- # @note Its possible to give letype=None and leclass=None. In this case the method will return tuple(None,None)
|
315
|
|
- # @param letype LeType|str|None : LeType child instant or its name
|
316
|
|
- # @param leclass LeClass|str|None : LeClass child instant or its name
|
317
|
|
- # @return a tuple with 2 python classes (LeTypeChild, LeClassChild)
|
318
|
|
- @classmethod
|
319
|
|
- def ___prepare_targets(cls, letype = None , leclass = None):
|
320
|
|
- warnings.warn("_LeObject._prepare_targets is deprecated", DeprecationWarning)
|
321
|
|
- raise ValueError()
|
322
|
|
- if not(leclass is None):
|
323
|
|
- if isinstance(leclass, str):
|
324
|
|
- leclass = LeFactory.leobj_from_name(leclass)
|
325
|
|
-
|
326
|
|
- if not isinstance(leclass, type) or not (leapi.leclass.LeClass in leclass.__bases__) or leclass.__class__ == leapi.leclass.LeClass:
|
327
|
|
- raise ValueError("None | str | LeType child class excpected, but got : '%s' %s"%(leclass,type(leclass)))
|
328
|
|
-
|
329
|
|
- if not(letype is None):
|
330
|
|
- if isinstance(letype, str):
|
331
|
|
- letype = LeFactory.leobj_from_name(letype)
|
332
|
|
-
|
333
|
|
- if not isinstance(letype, type) or not leapi.letype.LeType in letype.__bases__ or letype.__class__ == leapi.letype.LeType:
|
334
|
|
- raise ValueError("None | str | LeType child class excpected, but got : %s"%type(letype))
|
335
|
|
-
|
336
|
|
- if leclass is None:
|
337
|
|
- leclass = letype._leclass
|
338
|
|
- elif leclass != letype._leclass:
|
339
|
|
- raise ValueError("LeType child class %s does'nt inherite from LeClass %s"%(letype.__name__, leclass.__name__))
|
340
|
|
-
|
341
|
|
- return (letype, leclass)
|
342
|
|
-
|
343
|
137
|
## @brief Class designed to represent the hierarchy roots
|
344
|
138
|
# @see _LeObject.get_root() _LeObject.is_root()
|
345
|
139
|
class LeRoot(object):
|