Package obitools :: Package table
[hide private]
[frames] | no frames]

Source Code for Package obitools.table

  1  ''' 
  2   
  3  ''' 
  4   
  5  from itertools import imap,count,chain 
  6   
  7  from itertools import imap,count,chain 
  8   
9 -class Table(list):
10 """ 11 Tables are list of rows of the same model 12 """
13 - def __init__(self, headers=None, 14 types=None, 15 colcount=None, 16 rowFactory=None, 17 subrowFactory=None):
18 ''' 19 20 @param headers: the list of column header. 21 22 if this parametter is C{None}, C{colcount} 23 parametter must be set. 24 25 @type headers: C{list}, C{tuple} or and iterable object 26 27 @param types: the list of data type associated to each column. 28 29 If this parametter is specified its length must be 30 equal to the C{headers} length or to C{colcount}. 31 32 @type types: C{list}, C{tuple} or and iterable object 33 34 @param colcount: number of column in the created table. 35 36 If C{headers} parametter is not C{None} this 37 parametter is ignored 38 39 @type colcount: int 40 ''' 41 42 assert headers is not None or colcount is not None,\ 43 'headers or colcount parametter must be not None value' 44 45 if headers is None: 46 headers = tuple('Col_%d' % x for x in xrange(colcount)) 47 48 self.headers = headers 49 self.types = types 50 self.colcount= len(self.headers) 51 52 if rowFactory is None: 53 self.rowFactory=TableRow 54 else: 55 self.rowFactory=rowFactory 56 57 if subrowFactory is None: 58 self.subrowFactory=TableRow 59 else: 60 self.subrowFactory=rowFactory 61 62 63 self.likedTo=set()
64 65 66
67 - def isCompatible(self,data):
68 assert isinstance(data,(Table,TableRow)) 69 return (self.colcount == data.colcount and 70 (id(self.types)==id(data.types) or 71 self.types==data.types 72 ) 73 )
74
75 - def __setitem__ (self,key,value):
76 ''' 77 78 @param key: 79 @type key: C{int}, C{slice} or C{str} 80 @param value: 81 @type value: 82 ''' 83 84 if isintance(key,int): 85 if not isinstance(value, TableRow): 86 value = self.rowFactory(self,value) 87 else: 88 assert self.isCompatible(value) 89 list.__setitem__(self,key,value.row) 90 91 elif isinstance(key,slice): 92 indices = xrange(key.indices(len(self))) 93 for i,d in imap(None,indices,value): 94 self[i]=d 95 96 else: 97 raise TypeError, "Key must be an int or slice value"
98
99 - def __getitem__(self,key):
100 ''' 101 this function has different comportements depending 102 of the data type of C{key} and the table used. 103 104 @param key: description of the table part to return 105 @type key: C{int} or C{slice} 106 107 @return: return a TableRow (if key is C{int}) 108 or a subpart of the table (if key is C{slice}). 109 ''' 110 if isinstance(key,int): 111 return self.rowFactory(self, 112 list.__getitem__(self,key)) 113 114 if isinstance(key,slice): 115 newtable=Table(self.headers,self.types) 116 indices = xrange(key.indices(len(self))) 117 for i in indices: 118 list.append(newtable,list.__getitem__(self,i)) 119 self.likedTo.add(newtable) 120 return newtable 121 122 raise TypeError
123 124
125 - def __getslice__(self,x,y):
126 return self.__getitem__(slice(x,y))
127
128 - def __iter__(self):
129 return TableIterator(self)
130
131 - def __hash__(self):
132 return id(self)
133
134 - def __add__(self,itable):
135 return concatTables(self,itable)
136
137 - def _setTypes(self,types):
138 if types is not None and not isinstance(type,tuple): 139 types = tuple(x for x in types) 140 141 assert types is None or len(types)==len(self._headers) 142 143 self._types = types 144 145 if types is not None: 146 for row in self: 147 row.castRow()
148
149 - def _getTypes(self):
150 return self._types
151 152 types = property(_getTypes,_setTypes) 153
154 - def _getHeaders(self):
155 return self._headers
156
157 - def _setHeaders(self,headers):
158 if not isinstance(headers, tuple): 159 headers = tuple(x for x in headers) 160 161 self._hindex = dict((k,i) for i,k in imap(None,count(),headers)) 162 self._headers=headers 163 self.colcount=len(headers)
164 165 headers=property(_getHeaders,_setHeaders) 166
167 - def append(self,value):
168 if not isinstance(value, TableRow): 169 value = self.rowFactory(self,value) 170 else: 171 assert self.isCompatible(value) 172 list.append(self,value.row)
173 174 175
176 -class _Row(list):
177 - def __init__(self,data,size):
178 if data is None: 179 list.__init__(self,(None for x in xrange(size))) 180 else: 181 list.__init__(self,data) 182 assert len(self)==size, \ 183 "Size of data is not correct (%d instead of %d)" % (len(self),size)
184
185 - def append(self,value):
186 raise NotImplementedError, \ 187 "Rows cannot change of size"
188
189 - def pop(self,key=None):
190 raise NotImplementedError, \ 191 "Rows cannot change of size"
192
193 - def extend(self,values):
194 raise NotImplementedError, \ 195 "Rows cannot change of size"
196 197 198 199
200 -class TableRow(object):
201 ''' 202 203 '''
204 - def __init__(self, table, 205 data=None, 206 ):
207 208 self.table = table 209 210 if isinstance(data,_Row): 211 self.row=row 212 else: 213 data = self._castRow(data) 214 self.row=_Row(data,self._colcount)
215
216 - def getType(self):
217 return self.table.types
218
219 - def getHeaders(self):
220 return self.table.headers
221
222 - def getHIndex(self):
223 return self.table._hindex
224
225 - def getColCount(self):
226 return self.table.colcount
227 228 types = property(getType,None,None, 229 "List of types associated to this row") 230 headers= property(getHeaders,None,None, 231 "List of headers associated to this row") 232 233 _hindex= property(getHIndex,None,None) 234 _colcount = property(getColCount,None,None) 235
236 - def _castValue(t,x):
237 ''' 238 Cast a value to a specified type, with exception of 239 C{None} values that are returned without cast. 240 241 @param t: the destination type 242 @type t: C{type} 243 @param x: the value to cast 244 245 @return: the casted value or C{None} 246 247 ''' 248 if x is None or t is None: 249 return x 250 else: 251 return t(x)
252 253 _castValue=staticmethod(_castValue) 254
255 - def _castRow(self,data):
256 257 if not isinstance(data, (list,dict)): 258 data=[x for x in data] 259 260 if isinstance(data,list): 261 assert len(data)==self._colcount, \ 262 'values has not good length' 263 if self.types is not None: 264 data=[TableRow._castValue(t, x) 265 for t,x in imap(None,self.types,data)] 266 267 elif isinstance(data,dict): 268 lvalue = [None] * len(self.header) 269 270 for k,v in data.items(): 271 try: 272 hindex = self._hindex[k] 273 if self.types is not None: 274 lvalue[hindex]=TableRow._castValue(self.types[hindex], v) 275 else: 276 lvalue[hindex]=v 277 except KeyError: 278 info('%s is not a table column' % k) 279 280 data=lvalue 281 else: 282 raise TypeError 283 284 return data
285
286 - def __getitem__(self,key):
287 ''' 288 289 @param key: 290 @type key: 291 ''' 292 293 if isinstance(key,(int,slice)): 294 return self.row[key] 295 296 if isinstance(key,str): 297 i = self._hindex[key] 298 return self.row[i] 299 300 raise TypeError, "Key must be an int, slice or str value"
301
302 - def __setitem__(self,key,value):
303 ''' 304 305 @param key: 306 @type key: 307 @param value: 308 @type value: 309 ''' 310 311 if isinstance(key,str): 312 key = self._hindex[key] 313 314 elif isinstance(key,int): 315 if self.types is not None: 316 value = TableRow._castValue(self.types[key], value) 317 self.row[key]=value 318 319 elif isinstance(key,slice): 320 indices = xrange(key.indices(len(self.row))) 321 for i,v in imap(None,indices,value): 322 self[i]=v 323 else: 324 raise TypeError, "Key must be an int, slice or str value"
325 326 327
328 - def __iter__(self):
329 ''' 330 331 ''' 332 return iter(self.row)
333
334 - def append(self,value):
335 raise NotImplementedError, \ 336 "Rows cannot change of size"
337
338 - def pop(self,key=None):
339 raise NotImplementedError, \ 340 "Rows cannot change of size"
341
342 - def extend(self,values):
343 raise NotImplementedError, \ 344 "Rows cannot change of size"
345
346 - def __len__(self):
347 return self._colcount
348
349 - def __repr__(self):
350 return repr(self.row)
351
352 - def __str__(self):
353 return str(self.row)
354
355 - def castRow(self):
356 self.row = _Row(self._castRow(self.row),len(self.row))
357 358
359 -class iTableIterator(object):
360
361 - def _getHeaders(self):
362 raise NotImplemented
363
364 - def _getTypes(self):
365 raise NotImplemented
366
367 - def _getRowFactory(self):
368 raise NotImplemented
369
370 - def _getSubrowFactory(self):
371 raise NotImplemented
372
373 - def _getColcount(self):
374 return len(self._getTypes())
375
376 - def __iter__(self):
377 return self
378 379 headers = property(_getHeaders,None,None) 380 types = property(_getTypes,None,None) 381 rowFactory = property(_getRowFactory,None,None) 382 subrowFactory = property(_getSubrowFactory,None,None) 383 colcount = property(_getColcount,None,None) 384
385 - def columnIndex(self,name):
386 if isinstance(name,str): 387 return self._reference.headers.index(name) 388 elif isinstance(name,int): 389 lh = len(self._reference.headers) 390 if name < lh and name >=0: 391 return name 392 elif name < 0 and name >= -lh: 393 return lh - name 394 raise IndexError 395 raise TypeError
396
397 - def next(self):
398 raise NotImplemented
399 400
401 -class TableIterator(iTableIterator):
402
403 - def __init__(self,table):
404 if not isinstance(table,Table): 405 raise TypeError 406 407 self._reftable=table 408 self._i=0
409
410 - def _getHeaders(self):
411 return self._reftable.headers
412
413 - def _getTypes(self):
414 return self._reftable.types
415
416 - def _getRowFactory(self):
417 return self._reftable.rowFactory
418
419 - def _getSubrowFactory(self):
420 return self._reftable.subrowFactory
421
422 - def columnIndex(self,name):
423 if isinstance(name,str): 424 return self._reftable._hindex[name] 425 elif isinstance(name,int): 426 lh = len(self._reftable._headers) 427 if name < lh and name >=0: 428 return name 429 elif name < 0 and name >= -lh: 430 return lh - name 431 raise IndexError 432 raise TypeError
433 434
435 - def rewind(self):
436 i=0
437
438 - def next(self):
439 if self._i < len(self._reftable): 440 rep=self._reftable[self._i] 441 self._i+=1 442 return rep 443 else: 444 raise StopIteration
445 446 headers = property(_getHeaders,None,None) 447 types = property(_getTypes,None,None) 448 rowFactory = property(_getRowFactory,None,None) 449 subrowFactory = property(_getSubrowFactory,None,None)
450 451
452 -class ProjectionIterator(iTableIterator):
453
454 - def __init__(self,tableiterator,*cols):
455 self._reference = iter(tableiterator) 456 457 assert isinstance(self._reference, iTableIterator) 458 459 self._selected = tuple(self._reference.columnIndex(x) 460 for x in cols) 461 self._headers = tuple(self._reference.headers[x] 462 for x in self._selected) 463 464 if self._reference.types is not None: 465 self._types= tuple(self._reference.types[x] 466 for x in self._selected) 467 else: 468 self._types=None
469
470 - def _getRowFactory(self):
471 return self._reference.subrowFactory
472
473 - def _getSubrowFactory(self):
474 return self._reference.subrowFactory
475
476 - def _getHeaders(self):
477 return self._headers
478
479 - def _getTypes(self):
480 return self._types
481 482 headers = property(_getHeaders,None,None) 483 types = property(_getTypes,None,None) 484 rowFactory = property(_getRowFactory,None,None) 485 subrowFactory = property(_getSubrowFactory,None,None) 486
487 - def next(self):
488 value = self._reference.next() 489 value = (value[x] for x in self._selected) 490 return self.rowFactory(self,value)
491
492 -class SelectionIterator(iTableIterator):
493 - def __init__(self,tableiterator,**conditions):
494 self._reference = iter(tableiterator) 495 496 assert isinstance(self._reference, iTableIterator) 497 498 self._conditions=dict((self._reference.columnIndex(i),c) 499 for i,c in conditions.iteritems())
500
501 - def _checkCondition(self,row):
502 return reduce(lambda x,y : x and y, 503 (bool(self._conditions[i](row[i])) 504 for i in self._conditions), 505 True)
506
507 - def _getRowFactory(self):
508 return self._reference.rowFactory
509
510 - def _getSubrowFactory(self):
511 return self._reference.subrowFactory
512
513 - def _getHeaders(self):
514 return self._reference.headers
515
516 - def _getTypes(self):
517 return self._reference.types
518
519 - def next(self):
520 row = self._reference.next() 521 while not self._checkCondition(row): 522 row = self._reference.next() 523 return row
524 525 526 headers = property(_getHeaders,None,None) 527 types = property(_getTypes,None,None) 528 rowFactory = property(_getRowFactory,None,None) 529 subrowFactory = property(_getSubrowFactory,None,None)
530 531
532 -class UnionIterator(iTableIterator):
533 - def __init__(self,*itables):
534 self._itables=[iter(x) for x in itables] 535 self._types = self._itables[0].types 536 self._headers = self._itables[0].headers 537 538 assert reduce(lambda x,y: x and y, 539 ( isinstance(z,iTableIterator) 540 and len(z.headers)==len(self._headers) 541 for z in self._itables), 542 True) 543 544 self._iterator = chain(*self._itables)
545
546 - def _getRowFactory(self):
547 return self._itables[0].rowFactory
548
549 - def _getSubrowFactory(self):
550 return self._itables[0].subrowFactory
551
552 - def _getHeaders(self):
553 return self._headers
554
555 - def _getTypes(self):
556 return self._types
557
558 - def next(self):
559 value = self._iterator.next() 560 return self.rowFactory(self,value.row)
561 562 headers = property(_getHeaders,None,None) 563 types = property(_getTypes,None,None) 564 rowFactory = property(_getRowFactory,None,None) 565 subrowFactory = property(_getSubrowFactory,None,None)
566 567 568
569 -def tableFactory(tableiterator):
570 tableiterator = iter(tableiterator) 571 assert isinstance(tableiterator, iTableIterator) 572 573 newtable = Table(tableiterator.headers, 574 tableiterator.types, 575 tableiterator.rowFactory, 576 tableiterator.subrowFactory) 577 578 for r in tableiterator: 579 newtable.append(r) 580 581 return newtable
582
583 -def projectTable(tableiterator,*cols):
584 return tableFactory(ProjectionIterator(tableiterator,*cols))
585
586 -def subTable(tableiterator,**conditions):
587 return tableFactory(SelectionIterator(tableiterator,**conditions))
588
589 -def concatTables(*itables):
590 ''' 591 Concatene severals tables. 592 593 concatenation is done using the L{UnionIterator<UnionIterator>} 594 595 @type itables: iTableIterator or Table 596 597 @return: a new Table 598 @rtype: c{Table} 599 600 @see: L{UnionIterator<UnionIterator>} 601 ''' 602 return tableFactory(UnionIterator(*itables))
603
604 -class TableIteratorAsDict(object):
605
606 - def __init__(self,tableiterator):
607 self._reference = iter(tableiterator) 608 609 assert isinstance(self._reference, iTableIterator) 610 611 self._headers = self._reference.headers 612 self._types = self._reference.types 613 if self._types is not None: 614 self._types = dict((n,t) 615 for n,t in imap(None,self._headers,self._types))
616
617 - def __iter__(self):
618 return self
619
620 - def next(self):
621 value = self._reference.next() 622 return dict((n,t) 623 for n,t in imap(None,self._headers,value))
624
625 - def _getHeaders(self):
626 return self._headers
627
628 - def _getTypes(self):
629 return self._types
630 631 headers = property(_getHeaders,None,None) 632 types = property(_getTypes,None,None)
633