1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 """
25 organise, sort, and filter list of dictionaries or similar objects
26 """
27
28 import random
29
30 import Biskit.tools as t
31 from Biskit import EHandler, BisList, ConditionError, AmbiguousMatch,\
32 ItemNotFound, BisListError
33
35 """
36 List of dictionaries (or similar objects). Special support is
37 given to access and use entries in the dictionaries for filtering
38 and sorting. Some care is taken to avoid the adding of
39 non-allowed objects (but somehow it is, certainly, still
40 possible).
41
42 The list can be sorted and filtered by any dictionary key,
43 values within the dictionaries are easily accessible and can be
44 plotted against each other.
45
46 I{Overriding / Extending:}
47 The class is designed to be easily adapted for holding more complex
48 objects. In order to do so, the attribute item_type should be
49 set to the allowed class. All objects with a get( key, default )
50 and a keys() method should then work out of the box. If the two
51 methods are missing, getItemValue and getItemKeys must be overriden.
52 """
53
54 - def __init__(self, lst=[], item_type=dict ):
55 """
56 @param lst: list of dictionaries
57 @type lst: [ dict ]
58 @param item_type: class of allowed items [ dict ]
59 @type item_type: type
60
61 @raise BisListError: if list contains non-item_type item.
62 """
63 BisList.__init__( self )
64
65 self.item_type = item_type
66
67 if lst != []:
68 self.extend( lst )
69
70
72 """
73 Version of class.
74
75 @return: version of class
76 @rtype: str
77 """
78 return 'DictList $Revision: 2.16 $'
79
80
82 """
83 Get a value from a given item (dictionary). Override this
84 method to use the DictList for entries without get() function.
85
86 @param item: possible entry of this list
87 @type item: any
88 @param key: dictionary key
89 @type key: any
90 @param default: return value if key is not found (default: None)
91 @type default: any
92
93 @return: any
94 @rtype: any
95 """
96 return item.get( key, default )
97
98
100 """
101 Get the attribute keys used by a certain item. Override this
102 method to use the DictList for entries without keys() function.
103
104 @param item: possible entry of this list
105 @type item: any
106
107 @return: list of keys
108 @rtype: [ any ],
109 """
110 return item.keys()
111
112
113 - def getValue( self, i, key, default=None ):
114 """
115 Get the value of a dictionary entry of a list item.
116
117 @param i: position in list
118 @type i: int
119 @param key: dictionary key
120 @type key: any
121 @param default: return value if key is not found (default: None)
122 @type default: any
123
124 @return: any
125 @rtype: any
126 """
127 return self.getItemValue( self[i], key, default )
128
129
131 """
132 Make sure v is a dictionary
133
134 @raise BisListError: if not a dictionary
135 """
136 if not isinstance(v, self.item_type):
137 raise BisListError(
138 str( v ) + " not allowed. DictList requires "+\
139 str(self.item_type))
140
141
143 """
144 Called before an item is added to the list. Override but call.
145
146 @param v: value
147 @type v: dict or similar
148 @param i: anticipated index (ignored in this implementation)
149 @type i: int
150
151 @return: value
152 @rtype: dict
153 """
154 self.checkType( v )
155 return v
156
157
159 """
160 Called before list of items is added to the list.
161 For efficiency, the single new items are only processed if lst is
162 not already an instance of this class (DictList by default).
163 Override but call.
164
165 @param lst: list of new items
166 @type lst: [ any ]
167 @param indices: anticipated positions of the new items (default: None)
168 defaults to indices following the current end of list
169 @type indices: [ int ]
170
171 @return: list
172 @rtype: list
173 """
174 if not isinstance( lst, list ):
175 raise BisListError("Wrong argument type: "+str(type(lst)))
176
177 if not isinstance( lst, self.__class__ ):
178
179 if indices is None: indices = range( len(self), len(self)+len(lst) )
180
181 lst = [self._processNewItem(v, i) for v,i in zip( lst, indices )]
182
183 return lst
184
185
187 """
188 Set value v of position i.
189 >>> lst[i] = v
190
191 @param i: list index
192 @type i: int
193 @param v: value
194 @type v: any
195 """
196 v = self._processNewItem( v, i )
197 list.__setitem__( self, i, v)
198
199
201 """
202 Return new instance with only the given range of items.
203
204 @param i: start list index
205 @type i: int
206 @param j: end list index
207 @type j: int
208
209 @return: new instance with only the given range of items
210 @rtype: instance
211 """
212 r = self.__class__(super(DictList, self).__getslice__(i,j))
213 return r
214
215
217 """
218 Add all items to (the end of) this instance.
219
220 Use::
221 extend( list ).
222
223 @param lst: list of new items
224 @type lst: [ any ]
225 """
226 lst = self._processNewItems( lst )
227 list.extend( self, lst )
228
229
231 """
232 Append item to the end of this list.
233
234 Use::
235 append( dict ).
236
237 @param v: value
238 @type v: any
239 """
240 v = self._processItem( v, len( self ) )
241 list.append( self, v )
242
243
244 - def take( self, indices ):
245 """
246 @param indices: list positions
247 @type indices: array/list of int
248
249 @return: DictList (or sub-class) with specified items
250 @rtype: DictList
251 """
252 r = self.__class__( [ self[i] for i in indices ] )
253
254 return r
255
256
258 """
259 @return: attribute keys used by the current items.
260 @rtype: [ any ],
261 """
262 r = []
263
264 for x in self:
265 for k in self.getItemKeys( x ):
266 if not k in r:
267 r.append( k )
268
269 return r
270
271
273 """
274 Random sort.
275
276 @return: indices in random order.
277 @rtype: [ int ]
278 """
279 r = range( len( self ) )
280 random.shuffle( r )
281 return r
282
283
284
285
286
287
288 import Biskit.test as BT
289 import string
290
291 -class Test(BT.BiskitTest):
292 """Test DictList """
293
295 """DictList.__append__ test """
296
297 self.l1 = DictList()
298
299 for i in range( 10 ):
300 d = {'random':random.random(), 'name':'A'}
301 self.l1 += [ d ]
302
303 self.assertEqual( len(self.l1), 10, '%r != 10' % len(self.l1) )
304
305
307 """BisList.plotArray test"""
308
309 self.l2 = DictList()
310
311 for i in range( 50 ):
312 d = {'random':random.random(),
313 'name':string.letters[random.randint(0,50)] }
314 self.l2 += [ d ]
315
316 self.p = None
317 self.p = self.l2.plotArray( 'index', 'random', 'random' )
318
319 if self.local:
320 self.p.show()
321
322 self.assertNotEqual( self.p, None )
323
324
325 if __name__ == '__main__':
326
327
328 BT.localTest( )
329