rowset.py (18743B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\common\script\sys\rowset.py 2 import _weakref 3 import __builtin__ 4 import types 5 import string 6 import weakref 7 import sys 8 import uthread 9 import copy 10 import blue 11 from carbon.common.script.sys.row import Row as utilRow 12 import log 13 14 def Select(selection, headers, iterator, options): 15 if len(selection) == 1: 16 i = headers.index(selection[0]) 17 if options.get('line', False): 18 return [ (line, line[i]) for line in iterator ] 19 else: 20 return [ line[i] for line in iterator ] 21 else: 22 indices = [] 23 for header in selection: 24 indices.append(headers.index(header)) 25 26 if options.get('line', False): 27 return [ (line, [ line[i] for i in indices ]) for line in iterator ] 28 return [ [ line[i] for i in indices ] for line in iterator ] 29 30 31 class Rowset: 32 __passbyvalue__ = 1 33 __immutable__ = weakref.WeakKeyDictionary() 34 RowClass = utilRow 35 36 def __init__(self, hd = None, li = None, RowClass = utilRow): 37 if hd is None: 38 hd = [] 39 if li is None: 40 li = [] 41 self.header = hd 42 self.lines = li 43 self.RowClass = RowClass 44 45 def Clone(self): 46 return Rowset(copy.copy(self.header), copy.copy(self.lines), self.RowClass) 47 48 def IsImmutable(self): 49 return self in self.__immutable__ 50 51 def MakeImmutable(self): 52 if self not in self.__immutable__: 53 self.__immutable__[self] = [{}, {}] 54 55 def __str__(self): 56 try: 57 stuff = [] 58 for eachRow in self: 59 stuff.append(strx(eachRow)) 60 61 return '<Rowset: header=%s, data=["' % strx(self.header) + string.join(stuff, '","') + '"]>' 62 except: 63 sys.exc_clear() 64 return 'Rowset, hd=' + strx(self.header) 65 66 def __len__(self): 67 return len(self.lines) 68 69 def RenameField(self, oldName, newName): 70 if self in self.__immutable__: 71 raise RuntimeError('Immutable Rowsets may not be modified') 72 for i in range(len(self.header)): 73 if self.header[i] == oldName: 74 self.header[i] = newName 75 return 76 77 log.LogTraceback() 78 raise RuntimeError('No Such Field') 79 80 def AddField(self, fieldName, value): 81 if self in self.__immutable__: 82 raise RuntimeError('Immutable Rowsets may not be modified') 83 if len(self.lines) and type(self.lines[0]) == type(()): 84 raise RuntimeError('CannotAddFieldsToATupleRowset', self) 85 self.header.append(fieldName) 86 for l in self.lines: 87 l.append(value) 88 89 def RemoveField(self, fieldName): 90 if self in self.__immutable__: 91 raise RuntimeError('Immutable Rowsets may not be modified') 92 if len(self.lines) and type(self.lines[0]) == type(()): 93 raise RuntimeError('CannotRemoveFieldsFromATupleRowset', self) 94 idx = self.header.index(fieldName) 95 del self.header[idx] 96 for l in self.lines: 97 del l[idx] 98 99 def find(self, column, value): 100 h = self.header.index(column) 101 for i in xrange(len(self.lines)): 102 if self.lines[i][h] == value: 103 return i 104 105 return -1 106 107 def Select(self, *selection, **options): 108 return Select(selection, self.header, self.lines, options) 109 110 def __getitem__(self, index): 111 return self.RowClass(self.header, self.lines[index]) 112 113 def __setitem__(self, i, v): 114 if self in self.__immutable__: 115 raise RuntimeError('Immutable Rowsets may not be modified') 116 if type(v) == types.InstanceType: 117 self[i] = v.line 118 return 119 if len(v): 120 if len(v) > len(self.header): 121 raise RuntimeError('Too many columns, got %s, fields are %s' % (len(v), self.header)) 122 self.lines[i] = list(v) + [None] * (len(self.header) - len(v)) 123 else: 124 self.lines[i] = [None] * len(self.header) 125 126 def __getslice__(self, i, j): 127 return Rowset(self.header, self.lines[i:j], self.RowClass) 128 129 def __delitem__(self, index): 130 if self in self.__immutable__: 131 raise RuntimeError('Immutable Rowsets may not be modified') 132 del self.lines[index] 133 134 def sort(self, f = None): 135 if self in self.__immutable__: 136 raise RuntimeError('Immutable Rowsets may not be modified') 137 if f is not None: 138 self.lines.sort(f) 139 else: 140 self.lines.sort() 141 142 def extend(self, other): 143 if self in self.__immutable__: 144 raise RuntimeError('Immutable Rowsets may not be modified') 145 self.lines.extend(other.lines) 146 147 def remove(self, row): 148 if self in self.__immutable__: 149 raise RuntimeError('Immutable Rowsets may not be modified') 150 try: 151 self.lines.remove(row.line) 152 except ValueError: 153 sys.exc_clear() 154 except AttributeError: 155 sys.exc_clear() 156 self.lines.remove(row) 157 158 def pop(self, idx): 159 if self in self.__immutable__: 160 raise RuntimeError('Immutable Rowsets may not be modified') 161 return self.RowClass(self.header, self.lines.pop(idx)) 162 163 def InsertNew(self, *args): 164 if self in self.__immutable__: 165 raise RuntimeError('Immutable Rowsets may not be modified') 166 if len(args): 167 if len(args) > len(self.header): 168 raise RuntimeError('Too many arguments, got %s, fields are %s' % (len(args), self.header)) 169 self.lines.append(list(args) + [None] * (len(self.header) - len(args))) 170 else: 171 self.lines.append([None] * len(self.header)) 172 return self[-1] 173 174 def Sort(self, colname, asc = 1): 175 ret = self[:] 176 if asc: 177 ret.lines.sort(lambda a, b, colid = self.header.index(colname): -(a[colid] < b[colid])) 178 else: 179 ret.lines.sort(lambda b, a, colid = self.header.index(colname): -(a[colid] < b[colid])) 180 return ret 181 182 def Index(self, colname): 183 if self in self.__immutable__: 184 uthread.Lock(self, '__immutable__', colname) 185 try: 186 if colname not in self.__immutable__[self][0]: 187 ret = IndexRowset(self.header, self.lines, colname) 188 self.__immutable__[self][0][colname] = ret 189 ret.MakeImmutable() 190 return self.__immutable__[self][0][colname] 191 finally: 192 uthread.UnLock(self, '__immutable__', colname) 193 194 else: 195 return IndexRowset(self.header, self.lines, colname) 196 197 def Filter(self, colname, colname2 = None): 198 if self in self.__immutable__: 199 k = (colname, colname2) 200 uthread.Lock(self, '__immutable__', k) 201 try: 202 if k not in self.__immutable__[self][1]: 203 ret = FilterRowset(self.header, self.lines, colname, idName2=colname2) 204 ret.MakeImmutable() 205 self.__immutable__[self][1][k] = ret 206 return self.__immutable__[self][1][k] 207 finally: 208 uthread.UnLock(self, '__immutable__', k) 209 210 else: 211 return FilterRowset(self.header, self.lines, colname, idName2=colname2) 212 213 def append(self, row): 214 if self in self.__immutable__: 215 raise RuntimeError('Immutable Rowsets may not be modified') 216 if type(row) == type([]): 217 if len(row) != len(self.header): 218 raise RuntimeError('Invalid row length for appending', self, row) 219 self.lines.append(row) 220 else: 221 if len(self.header) != len(row.header): 222 raise RuntimeError('Invalid header for appending', self, row) 223 self.lines.append(row.line) 224 225 226 class IndexOrFilterRowsetIterator: 227 228 def __init__(self, rowset, iterator): 229 self.rowset = _weakref.proxy(rowset) 230 self.iterator = iterator 231 232 def next(self): 233 return self.rowset.RowClass(self.rowset.header, self.iterator.next()) 234 235 236 class IndexRowset: 237 __passbyvalue__ = 1 238 __immutable__ = weakref.WeakKeyDictionary() 239 RowClass = utilRow 240 stacktraceCnt = 0 241 242 def __init__(self, header = None, li = (), idName = None, RowClass = utilRow, dict = None): 243 if dict is not None: 244 self.items = dict 245 elif header is not None and li is not None: 246 idfield = header.index(idName) 247 self.items = __builtin__.dict([ (i[idfield], i) for i in li ]) 248 else: 249 self.items = {} 250 self.header = header 251 self.RowClass = RowClass 252 self.idName = idName 253 254 def GetKeyColumn(self): 255 return self.idName 256 257 def GetLine(self, key): 258 return self.items[key] 259 260 def Clone(self): 261 return IndexRowset(copy.copy(self.header), None, self.idName, self.RowClass, copy.copy(self.items)) 262 263 def IsImmutable(self): 264 return self in self.__immutable__ 265 266 def MakeImmutable(self): 267 if self not in self.__immutable__: 268 self.__immutable__[self] = 1 269 270 def Select(self, *selection, **options): 271 return Select(selection, self.header, self.items.itervalues(), options) 272 273 def __iter__(self): 274 return iter(self.items) 275 276 def __contains__(self, key): 277 return key in self.items 278 279 def __getitem__(self, i): 280 return self.RowClass(self.header, self.items[i]) 281 282 def __len__(self): 283 return len(self.items) 284 285 def values(self): 286 return Rowset(self.header, self.items.values(), self.RowClass) 287 288 def itervalues(self): 289 return self.values() 290 291 def keys(self): 292 return self.items.keys() 293 294 def iterkeys(self): 295 return self.items.iterkeys() 296 297 def iteritems(self): 298 return self.items.iteritems() 299 300 def has_key(self, key): 301 return key in self.items 302 303 def __setitem__(self, ind, row): 304 if self in self.__immutable__: 305 raise RuntimeError('Immutable IndexRowsets may not be modified') 306 if type(row) == type([]): 307 self.items[ind] = row 308 else: 309 if hasattr(row, '__columns__'): 310 rowHeader = row.__columns__ 311 rowLine = list(row) 312 else: 313 rowHeader = row.header 314 rowLine = row.line 315 if len(self.header) != len(rowHeader): 316 line = [None] * len(self.header) 317 for i in range(len(self.header)): 318 cname = self.header[i] 319 try: 320 idx = rowHeader.index(cname) 321 except ValueError: 322 raise RuntimeError('Mismatched row headers - game is broken', self.header, rowHeader) 323 324 line[i] = rowLine[idx] 325 326 if self.stacktraceCnt < 2: 327 log.LogTraceback('rowset') 328 self.stacktraceCnt += 1 329 self.items[ind] = line 330 else: 331 self.items[ind] = rowLine 332 333 def __delitem__(self, ind): 334 if self in self.__immutable__: 335 raise RuntimeError('Immutable IndexRowsets may not be modified') 336 del self.items[ind] 337 338 def Sort(self, colname): 339 ret = self.values() 340 return ret.Sort(colname) 341 342 def get(self, ind, defValue): 343 try: 344 return self[ind] 345 except: 346 sys.exc_clear() 347 return defValue 348 349 def UpdateLI(self, lines, indexName, overWrite = 0): 350 if self in self.__immutable__: 351 raise RuntimeError('Immutable IndexRowsets may not be modified') 352 ind = self.header.index(indexName) 353 for i in lines: 354 if not (not overWrite and i[ind] in self.items): 355 self.items[i[ind]] = i 356 357 def Map(self, indexes): 358 ret = Rowset(self.header, []) 359 for i in indexes: 360 if i in self: 361 ret.append(self[i]) 362 363 return ret 364 365 def __str__(self): 366 stuff = {} 367 for key in self.iterkeys(): 368 eachRow = self[key] 369 stuff[key] = eachRow 370 371 return '<IndexRowset: header=%s, data=' % strx(self.header) + strx(stuff).replace('"', '') + '>' 372 373 374 class FilterRowset: 375 __guid__ = 'util.FilterRowset' 376 __passbyvalue__ = 1 377 __immutable__ = weakref.WeakKeyDictionary() 378 RowClass = utilRow 379 380 def __init__(self, header = None, li = None, idName = None, RowClass = utilRow, idName2 = None, dict = None): 381 items = {} 382 self.RowClass = RowClass 383 if dict is not None: 384 items = dict 385 elif header is not None: 386 if not idName2: 387 idfield = header.index(idName) 388 for i in li: 389 id = i[idfield] 390 if id in items: 391 items[id].append(i) 392 else: 393 items[id] = [i] 394 395 else: 396 idfield = header.index(idName) 397 idfield2 = header.index(idName2) 398 for i in li: 399 id = i[idfield] 400 if id in items: 401 items[id][i[idfield2]] = i 402 else: 403 items[id] = {i[idfield2]: i} 404 405 self.items = items 406 self.header = header 407 self.idName = idName 408 self.idName2 = idName2 409 410 def Clone(self): 411 return FilterRowset(copy.copy(self.header), None, self.idName, self.RowClass, self.idName2, dict=copy.deepcopy(self.items)) 412 413 def IsImmutable(self): 414 return self in self.__immutable__ 415 416 def MakeImmutable(self): 417 if self not in self.__immutable__: 418 self.__immutable__[self] = 1 419 420 def __iter__(self): 421 return IndexOrFilterRowsetIterator(self, self.items.iterkeys()) 422 423 def __contains__(self, key): 424 return key in self.items 425 426 def has_key(self, key): 427 return key in self.items 428 429 def get(self, key, val): 430 try: 431 return self[key] 432 except: 433 sys.exc_clear() 434 return val 435 436 def keys(self): 437 return self.items.keys() 438 439 def iterkeys(self): 440 return self.items.iterkeys() 441 442 def __getitem__(self, i): 443 if self.idName2: 444 return IndexRowset(self.header, None, self.idName2, self.RowClass, self.items.get(i, {})) 445 return Rowset(self.header, self.items.get(i, []), self.RowClass) 446 447 def __len__(self): 448 return len(self.items) 449 450 def Sort(self, colname): 451 ret = Rowset(self.header, self.items.values(), self.RowClass) 452 return ret.Sort(colname) 453 454 def GetIndexKeys(self): 455 if self.idName2 is not None: 456 return (self.idName, self.idName2) 457 return (self.idName,) 458 459 def GetLines(self, idValue, idValue2 = None): 460 if self.idName2 is not None: 461 return self.items[idValue][idValue2] 462 return self.items[idValue] 463 464 465 def RowsInit(rows, columns): 466 header = None 467 if type(rows) is types.TupleType: 468 header = rows[0] 469 rows = rows[1] 470 if rows: 471 first = rows[0] 472 if type(first) != blue.DBRow: 473 raise AttributeError('Not DBRow. Initialization requires a non-empty list of DBRows') 474 header = first.__header__ 475 elif header: 476 if type(header) != blue.DBRowDescriptor: 477 raise AttributeError('expected (DBRowDesciptor, [])') 478 if header: 479 columns = header.Keys() 480 return (rows, columns, header) 481 482 483 class RowDict(dict): 484 __guid__ = 'dbutil.RowDict' 485 __passbyvalue__ = 1 486 slots = ['columns', 'header', 'key'] 487 488 def __init__(self, rowList, key, columns = None): 489 dict.__init__(self) 490 rows, self.columns, self.header = RowsInit(rowList, columns) 491 if key not in self.columns: 492 raise AttributeError('Indexing key not found in row') 493 self.key = key 494 for row in rows: 495 self[row[key]] = row 496 497 def ReIndex(self, key): 498 if key not in self.columns: 499 raise AttributeError('Indexing key not found in columns') 500 vals = self.values() 501 self.clear() 502 self.key = key 503 for row in vals: 504 self[row[self.key]] = row 505 506 def Add(self, row): 507 if type(row) != blue.DBRow: 508 raise AttributeError('Not DBRow') 509 if row.__columns__ != self.columns: 510 raise ValueError('Incompatible rows') 511 if self.header is None: 512 self.header = row.__header__ 513 self[row[self.key]] = row 514 515 516 class RowList(list): 517 __guid__ = 'dbutil.RowList' 518 __passbyvalue__ = 1 519 slots = ['header', 'columns'] 520 521 def __init__(self, rowList, columns = None): 522 list.__init__(self) 523 rows, self.columns, self.header = RowsInit(rowList, columns) 524 self[:] = rows 525 526 def append(self, row): 527 if type(row) != blue.DBRow: 528 raise ValueError('Not DBRow') 529 if row.__columns__ != self.columns: 530 raise ValueError('Incompatible headers') 531 if self.header is None: 532 self.header = row.__header__ 533 list.append(self, row) 534 535 536 class IndexedRows(dict): 537 __guid__ = 'util.IndexedRows' 538 __passbyvalue__ = 1 539 540 def __init__(self, rows = [], keys = None): 541 self.InsertMany(keys, rows) 542 543 def InsertMany(self, keys, rows): 544 for r in rows: 545 self.Insert(keys, r) 546 547 def Insert(self, keys, e): 548 key, rkeys = keys[0], keys[1:] 549 if rkeys: 550 if e[key] not in self: 551 self[e[key]] = IndexedRows() 552 self[e[key]].Insert(rkeys, e) 553 else: 554 self[e[key]] = e 555 556 557 class IndexedRowLists(dict): 558 __guid__ = 'util.IndexedRowLists' 559 __passbyvalue__ = 1 560 561 def __init__(self, rows = [], keys = None): 562 self.header = [] 563 self.InsertMany(keys, rows) 564 565 def InsertMany(self, keys, rows): 566 for r in rows: 567 self.Insert(keys, r) 568 569 def Insert(self, keys, e): 570 key, rkeys = keys[0], keys[1:] 571 self.header = [key] 572 if rkeys: 573 if e[key] not in self: 574 self[e[key]] = IndexedRowLists() 575 self[e[key]].Insert(rkeys, e) 576 else: 577 if e[key] not in self: 578 self[e[key]] = [] 579 self[e[key]].append(e) 580 581 def GetIndexKeys(self): 582 l = self.header[:] 583 for v in self.itervalues(): 584 if isinstance(v, self.__class__): 585 l.extend(v.GetIndexKeys()) 586 break 587 588 return l 589 590 def GetLines(self, firstKey, *nextKeys): 591 ret = self[firstKey] 592 if len(nextKeys): 593 return ret.GetLines(*nextKeys) 594 return ret