Package Biskit :: Module DictList
[hide private]
[frames] | no frames]

Source Code for Module Biskit.DictList

  1  ## 
  2  ## Biskit, a toolkit for the manipulation of macromolecular structures 
  3  ## Copyright (C) 2004-2006 Raik Gruenberg & Johan Leckner 
  4  ## 
  5  ## This program is free software; you can redistribute it and/or 
  6  ## modify it under the terms of the GNU General Public License as 
  7  ## published by the Free Software Foundation; either version 2 of the 
  8  ## License, or any later version. 
  9  ## 
 10  ## This program is distributed in the hope that it will be useful, 
 11  ## but WITHOUT ANY WARRANTY; without even the implied warranty of 
 12  ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 
 13  ## General Public License for more details. 
 14  ## 
 15  ## You find a copy of the GNU General Public License in the file 
 16  ## license.txt along with this program; if not, write to the Free 
 17  ## Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
 18  ## 
 19  ## 
 20   
 21  ## last $Author: graik $ 
 22  ## last $Date: 2007/03/26 18:40:40 $ 
 23  ## $Revision: 2.16 $ 
 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   
34 -class DictList( BisList, list ):
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
71 - def version( self ):
72 """ 73 Version of class. 74 75 @return: version of class 76 @rtype: str 77 """ 78 return 'DictList $Revision: 2.16 $'
79 80
81 - def getItemValue( self, item, key, default=None ):
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
99 - def getItemKeys( self, item ):
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
130 - def checkType( self, v ):
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
142 - def _processNewItem( self, v, i=None ):
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
158 - def _processNewItems( self, lst, indices=None ):
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
186 - def __setitem__(self, i, v ):
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
200 - def __getslice__( self, i, j ):
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
216 - def extend( self, lst ):
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
230 - def append( self, v ):
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
257 - def keys( self ):
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
272 - def argsortRandom( self ):
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 ## TESTING 286 ############# 287 288 import Biskit.test as BT 289 import string 290
291 -class Test(BT.BiskitTest):
292 """Test DictList """ 293
294 - def test_append( self ):
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
306 - def test_plotArray( self ):
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 ## run Test and push self.* fields into global namespace 328 BT.localTest( ) 329