|
@@ -2,21 +2,14 @@
|
2
|
2
|
|
3
|
3
|
## @package EditorialModel.components
|
4
|
4
|
# @brief Base objects for all EditorialModel components
|
5
|
|
-#
|
|
5
|
+#
|
6
|
6
|
# Defines the EditorialModel::components::EmComponent class
|
7
|
7
|
|
8
|
8
|
import datetime
|
9
|
|
-import logging
|
10
|
|
-from collections import OrderedDict
|
11
|
9
|
import hashlib
|
12
|
|
-
|
13
|
10
|
import EditorialModel
|
14
|
|
-from EditorialModel.exceptions import *
|
15
|
11
|
from Lodel.utils.mlstring import MlString
|
16
|
12
|
|
17
|
|
-logger = logging.getLogger('Lodel2.EditorialModel')
|
18
|
|
-
|
19
|
|
-
|
20
|
13
|
## This class is the mother class of all editorial model objects
|
21
|
14
|
#
|
22
|
15
|
# It gather all the properties and mechanism that are common to every editorial model objects
|
|
@@ -27,9 +20,9 @@ class EmComponent(object):
|
27
|
20
|
## Used by EmComponent::modify_rank
|
28
|
21
|
ranked_in = None
|
29
|
22
|
|
30
|
|
- def __init__(self, model, uid, name, string = None, help_text = None, date_update = None, date_create = None, rank = None):
|
|
23
|
+ def __init__(self, model, uid, name, string=None, help_text=None, date_update=None, date_create=None, rank=None):
|
31
|
24
|
if type(self) == EmComponent:
|
32
|
|
- raise NotImplementedError('Abstract class')
|
|
25
|
+ raise NotImplementedError('Abstract class')
|
33
|
26
|
if model.__class__.__name__ != 'Model':
|
34
|
27
|
raise TypeError("Excepted type for 'model' arg is <class 'Model'> but got {} instead".format(type(model)))
|
35
|
28
|
|
|
@@ -43,14 +36,14 @@ class EmComponent(object):
|
43
|
36
|
self.check_type('string', MlString)
|
44
|
37
|
self.help_text = MlString() if help_text is None else help_text
|
45
|
38
|
self.check_type('help_text', MlString)
|
46
|
|
- self.date_update = datetime.datetime.now() if date_update is None else date_update #WARNING timezone !
|
|
39
|
+ self.date_update = datetime.datetime.now() if date_update is None else date_update # WARNING timezone !
|
47
|
40
|
self.check_type('date_update', datetime.datetime)
|
48
|
|
- self.date_create = datetime.datetime.now() if date_create is None else date_create #WARNING timezone !
|
|
41
|
+ self.date_create = datetime.datetime.now() if date_create is None else date_create # WARNING timezone !
|
49
|
42
|
self.check_type('date_create', datetime.datetime)
|
|
43
|
+ self._inited = False
|
50
|
44
|
|
51
|
45
|
#Handling specials ranks for component creation
|
52
|
46
|
self.rank = rank
|
53
|
|
- pass
|
54
|
47
|
|
55
|
48
|
## @brief Return a dict with attributes name as key and attributes value as value
|
56
|
49
|
# @note Used at creation and deletion to call the migration handler
|
|
@@ -75,11 +68,12 @@ class EmComponent(object):
|
75
|
68
|
# Identify a component with his type and name
|
76
|
69
|
def uniq_name(self):
|
77
|
70
|
uname = self.__class__.__name__
|
78
|
|
- if not isinstance(self, EditorialModel.fields.EmField):
|
|
71
|
+ if not isinstance(self, EditorialModel.fields.EmField): # WARNING this could crash with fieldtypes
|
79
|
72
|
try:
|
80
|
|
- uname += '_'+self.em_class.name
|
81
|
|
- except AttributeError: pass
|
82
|
|
- uname += '_'+self.name
|
|
73
|
+ uname += '_' + self.em_class.name
|
|
74
|
+ except AttributeError:
|
|
75
|
+ pass
|
|
76
|
+ uname += '_' + self.name
|
83
|
77
|
return uname
|
84
|
78
|
|
85
|
79
|
## @brief This function has to be called after the instanciation, checks, and init manipulations are done
|
|
@@ -89,24 +83,23 @@ class EmComponent(object):
|
89
|
83
|
|
90
|
84
|
## @brief Reimplementation for calling the migration handler to register the change
|
91
|
85
|
def __setattr__(self, attr_name, value):
|
92
|
|
- inited = '_inited' in self.__dict__
|
|
86
|
+ inited = '_inited' in self.__dict__ and self.__dict__['_inited']
|
93
|
87
|
if inited:
|
94
|
88
|
# if fails raise MigrationHandlerChangeError
|
95
|
|
- self.model.migration_handler.register_change(self.model, self.uid, {attr_name: getattr(self, attr_name) }, {attr_name: value} )
|
|
89
|
+ self.model.migration_handler.register_change(self.model, self.uid, {attr_name: getattr(self, attr_name)}, {attr_name: value})
|
96
|
90
|
super(EmComponent, self).__setattr__(attr_name, value)
|
97
|
91
|
if inited:
|
98
|
92
|
self.model.migration_handler.register_model_state(self.model, hash(self.model))
|
99
|
93
|
|
100
|
94
|
## Check the type of attribute named var_name
|
101
|
95
|
# @param var_name str : the attribute name
|
102
|
|
- # @param excepted_type tuple|type : Tuple of type or a type
|
|
96
|
+ # @param excepted_type tuple|type : Tuple of type or a type
|
103
|
97
|
# @throw AttributeError if wrong type detected
|
104
|
98
|
def check_type(self, var_name, excepted_type):
|
105
|
99
|
var = getattr(self, var_name)
|
106
|
|
-
|
|
100
|
+
|
107
|
101
|
if not isinstance(var, excepted_type):
|
108
|
|
- raise AttributeError("Excepted %s to be an %s but got %s instead" % (var_name, str(excepted_type), str(type(var))) )
|
109
|
|
- pass
|
|
102
|
+ raise AttributeError("Excepted %s to be an %s but got %s instead" % (var_name, str(excepted_type), str(type(var))))
|
110
|
103
|
|
111
|
104
|
## @brief Hash function that allows to compare two EmComponent
|
112
|
105
|
# @return EmComponent+ClassName+uid
|
|
@@ -157,7 +150,7 @@ class EmComponent(object):
|
157
|
150
|
def same_rank_group(self):
|
158
|
151
|
components = self.model.components(self.__class__)
|
159
|
152
|
ranked_in = self.__class__.ranked_in
|
160
|
|
- return [ c for c in components if getattr(c, ranked_in) == getattr(self, ranked_in) ]
|
|
153
|
+ return [c for c in components if getattr(c, ranked_in) == getattr(self, ranked_in)]
|
161
|
154
|
|
162
|
155
|
## Set a new rank for this component
|
163
|
156
|
# @note This function assume that ranks are properly set from 1 to x with no gap
|
|
@@ -171,38 +164,36 @@ class EmComponent(object):
|
171
|
164
|
# @throw ValueError if out of bound value
|
172
|
165
|
def set_rank(self, new_rank):
|
173
|
166
|
if not isinstance(new_rank, int):
|
174
|
|
- raise TypeError("Excepted <class int> but got "+str(type(new_rank)))
|
|
167
|
+ raise TypeError("Excepted <class int> but got " + str(type(new_rank)))
|
175
|
168
|
if new_rank <= 0 or new_rank > self.get_max_rank():
|
176
|
|
- raise ValueError("Invalid new rank : "+str(new_rank))
|
|
169
|
+ raise ValueError("Invalid new rank : " + str(new_rank))
|
177
|
170
|
|
178
|
|
- mod = new_rank - self.rank #Indicates the "direction" of the "move"
|
|
171
|
+ mod = new_rank - self.rank # Indicates the "direction" of the "move"
|
179
|
172
|
|
180
|
173
|
if mod == 0:
|
181
|
174
|
return True
|
182
|
175
|
|
183
|
|
- limits = [ self.rank + ( 1 if mod > 0 else -1), new_rank ] #The range of modified ranks
|
|
176
|
+ limits = [self.rank + (1 if mod > 0 else -1), new_rank] # The range of modified ranks
|
184
|
177
|
limits.sort()
|
185
|
178
|
|
186
|
|
- for component in [ c for c in self.same_rank_group() if c.rank >= limits[0] and c.rank <= limits[1] ] :
|
187
|
|
- component.rank = component.rank + ( -1 if mod > 0 else 1 )
|
|
179
|
+ for component in [c for c in self.same_rank_group() if c.rank >= limits[0] and c.rank <= limits[1]]:
|
|
180
|
+ component.rank = component.rank + (-1 if mod > 0 else 1)
|
188
|
181
|
|
189
|
182
|
self.rank = new_rank
|
190
|
183
|
|
191
|
184
|
self.model.sort_components(self.__class__)
|
192
|
185
|
|
193
|
|
- pass
|
194
|
|
-
|
195
|
186
|
## Modify a rank given an integer modifier
|
196
|
187
|
# @param rank_mod int : can be a negative positive or zero integer
|
197
|
188
|
# @throw TypeError if rank_mod is not an integer
|
198
|
189
|
# @throw ValueError if rank_mod is out of bound
|
199
|
190
|
def modify_rank(self, rank_mod):
|
200
|
191
|
if not isinstance(rank_mod, int):
|
201
|
|
- raise TypeError("Excepted <class int>, <class str>. But got "+str(type(rank_mod))+", "+str(type(sign)))
|
|
192
|
+ raise TypeError("Excepted <class int>. But got %s" % str(type(rank_mod)))
|
202
|
193
|
try:
|
203
|
194
|
self.set_rank(self.rank + rank_mod)
|
204
|
195
|
except ValueError:
|
205
|
|
- raise ValueError("The rank modifier '"+str(rank_mod)+"' is out of bounds")
|
|
196
|
+ raise ValueError("The rank modifier '%s' is out of bounds" % str(rank_mod))
|
206
|
197
|
|
207
|
198
|
## @brief Return a string representation of the component
|
208
|
199
|
# @return A string representation of the component
|
|
@@ -211,4 +202,3 @@ class EmComponent(object):
|
211
|
202
|
return "<%s #%s, 'non populated'>" % (type(self).__name__, self.uid)
|
212
|
203
|
else:
|
213
|
204
|
return "<%s #%s, '%s'>" % (type(self).__name__, self.uid, self.name)
|
214
|
|
-
|