1 """
2 I define the class of lists.
3 """
4 from weakref import ref
5
6 from advene.model.consts import _RAISE
7 from advene.model.core.element \
8 import PackageElement, LIST
9 from advene.model.core.content import WithContentMixin
10 from advene.model.core.group import GroupMixin
11
12 -class List(PackageElement, WithContentMixin, GroupMixin):
13 """
14 I expose the protocol of a basic collection, to give access to the items
15 of a list.
16
17 I also try to efficiently cache the results I know.
18 """
19
20
21
22
23
24
25
26
27
28 ADVENE_TYPE = LIST
29
30
31 _cache = None
32 _ids = None
33
34 @classmethod
41
42 @classmethod
49
65
68
70 """Iter over the items of this list.
71
72 If the list contains unreachable items, None is yielded instead.
73
74 See also `iter_item_ids`.
75 """
76 for i,y in enumerate(self._cache):
77 y = y()
78 if y is None:
79 y = self.get_item(i, None)
80 yield y
81
83 """Return item with index i, or raise an exception if the item is
84 unreachable.
85
86 See also `get_item` and `get_item_id`.
87 """
88 if isinstance(i, slice): return self._get_slice(i)
89 else: return self.get_item(i, _RAISE)
90
92 if isinstance(i, slice): return self._set_slice(i, a)
93 assert hasattr(a, "ADVENE_TYPE"), "List %s does not specify an ADVENE_TYPE" % str(self)
94 o = self._owner
95 assert o._can_reference(a), "The list owner %s cannot reference %s" % (str(o), str(a))
96 aid = a.make_id_in(o)
97 s = slice(i, i+1)
98 L = [a,]
99 self.emit("pre-modified-items", s, L)
100 self._ids[i] = aid
101 self._cache[i] = ref(a)
102 o._backend.update_item(o._id, self._id, aid, i)
103 self.emit("modified-items", s, L)
104
106 if isinstance(i, slice): return self._del_slice(i)
107 s = slice(i, i+1)
108 self.emit("pre-modified-items", s, [])
109 del self._ids[i]
110 del self._cache[i]
111 o = self._owner
112 o._backend.remove_item(o._id, self._id, i)
113 self.emit("modified-items", s, [])
114
118
120 c = len(self._cache)
121 indices = range(c)[s]
122 same_length = (len(elements) == len(indices))
123 if s.step is None and not same_length:
124 self._del_slice(s)
125 insertpoint = s.start or 0
126 for e in elements:
127 self.insert(insertpoint, e)
128 insertpoint += 1
129 else:
130 if not same_length:
131 raise ValueError("attempt to assign sequence of size %s to "
132 "extended slice of size %s"
133 % (len(elements), len(indices)))
134 for i,j in enumerate(indices):
135 self.__setitem__(j, elements[i])
136
138 c = len(self._cache)
139 indices = range(c)[s]
140 indices.sort()
141 for offset, i in enumerate(indices):
142 del self[i-offset]
143
145
146 o = self._owner
147 assert o._can_reference(a), "The list owner %s cannot reference %s" % (str(o), str(a))
148
149 if hasattr(a, "ADVENE_TYPE"):
150 aid = a.make_id_in(o)
151 else:
152 aid = unicode(a)
153 assert aid.find(":") > 0, "Expected *strict* id-ref"
154 a = None
155 c = len(self._cache)
156 if i > c : i = c
157 if i < -c: i = 0
158 if i < 0 : i += c
159 self._ids.insert(i,aid)
160 if a is not None:
161 a = ref(a)
162 else:
163 a = lambda: None
164 self._cache.insert(i,a)
165 o._backend.insert_item(o._id, self._id, aid, i, c)
166
167
168
170
171 o = self._owner
172 assert o._can_reference(a), "The list owner %s cannot reference %s" % (str(o), str(a))
173 if hasattr(a, "ADVENE_TYPE"):
174 aid = a.make_id_in(o)
175 else:
176 aid = unicode(a)
177 assert aid.find(":") > 0, "Expected *strict* id-ref"
178 a = None
179 c = len(self._cache)
180 s = slice(c,c)
181 L = [a,]
182 self.emit("pre-modified-items", s, L)
183 self._ids.append(aid)
184 if a is not None:
185 a = ref(a)
186 else:
187 a = lambda: None
188 self._cache.append(a)
189 o._backend.insert_item(o._id, self._id, aid, -1, c)
190 self.emit("modified-items", s, L)
191
192
193
195 for e in elements:
196 self.append(e)
197
199 """Iter over the id-refs of the items of this list.
200
201 See also `__iter__`.
202 """
203 for i,y in enumerate(self._ids):
204 if y is not None:
205 yield y
206 else:
207 yield self.get_item_id(i)
208
210 """Return item with index i, or default if it can not be retrieved.
211
212 Note that if ``i`` is an invalid index, an IndexError will still be
213 raised.
214
215 See also `__getitem__` and `get_item_id`.
216 """
217
218 assert isinstance(i, (int, long)), "The index must be an integer"
219 r = self._cache[i]()
220 if r is None:
221 o = self._owner
222 rid = self._ids[i]
223 if rid is None:
224 c = len(self._cache)
225 i = xrange(c)[i]
226 rid = self._ids[i] = \
227 o._backend.get_item(o._id, self._id, i)
228 r = o.get_element(rid, default)
229 if r is not default:
230 self._cache[i] = ref(r)
231 return r
232
234 """Return id-ref of the item with index i.
235
236 See also `__getitem__` and `get_item`.
237 """
238 assert isinstance(i, (int, long)), "The index must be an integer"
239 r = self._ids[i]
240 if r is None:
241 o = self._owner
242 c = len(self._ids)
243 i = xrange(c)[i]
244 r = self._ids[i] = o._backend.get_item(o._id, self._id, i)
245 return r
246