Viewing file: sequence.py (5.86 KB) -rw-r--r-- Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
# -*- test-case-name: axiom.test.test_sequence -*-
from axiom.item import Item from axiom.attributes import reference, integer, AND
class _ListItem(Item): typeName = 'list_item' schemaVersion = 1
_index = integer() _value = reference() _container = reference()
class List(Item): typeName = 'list' schemaVersion = 1
length = integer(default=0)
def __init__(self, *args, **kw): super(List, self).__init__(**kw) if args: self.extend(args[0])
def _queryListItems(self): return self.store.query(_ListItem, _ListItem._container == self)
def _getListItem(self, index): return list(self.store.query(_ListItem, AND(_ListItem._container == self, _ListItem._index == index)))[0]
def _delListItem(self, index, resetIndexes=True): for li in self.store.query(_ListItem, AND(_ListItem._container == self, _ListItem._index == index)): li.deleteFromStore(deleteObject=True) break
def _fixIndex(self, index, truncate=False): """ @param truncate: If true, negative indices which go past the beginning of the list will be evaluated as zero. For example::
>>> L = List([1,2,3,4,5]) >>> len(L) 5 >>> L._fixIndex(-9, truncate=True) 0 """ assert not isinstance(index, slice), 'slices are not supported (yet)' if index < 0: index += self.length if index < 0: if not truncate: raise IndexError('stored List index out of range') else: index = 0 return index
def __getitem__(self, index): index = self._fixIndex(index) return self._getListItem(index)._value
def __setitem__(self, index, value): index = self._fixIndex(index) self._getListItem(index)._value = value
def __add__(self, other): return list(self) + list(other) def __radd__(self, other): return list(other) + list(self)
def __mul__(self, other): return list(self) * other def __rmul__(self, other): return other * list(self)
def index(self, other, start=0, maximum=None): if maximum is None: maximum = len(self) for pos in range(start, maximum): if pos >= len(self): break if self[pos] == other: return pos raise ValueError, 'List.index(x): %r not in List' % other
def __len__(self): return self.length
def __delitem__(self, index): assert not isinstance(index, slice), 'slices are not supported (yet)' self._getListItem(index).deleteFromStore() if index < self.length - 1: for item in self.store.query(_ListItem, AND( _ListItem._container == self, _ListItem._index > index)): item._index -= 1 self.length -= 1
def __contains__(self, value): return bool(self.count(value))
def append(self, value): """ @type value: L{axiom.item.Item} @param value: Must be stored in the same L{Store<axiom.store.Store>} as this L{List} instance. """ # XXX: Should List.append(unstoredItem) automatically store the item? self.insert(self.length, value)
def extend(self, other): for item in iter(other): self.append(item)
def insert(self, index, value): index = self._fixIndex(index, truncate=True) # If we do List(length=5).insert(50, x), we don't want # x's _ListItem._index to actually be 50. index = min(index, self.length) # This uses list() in case our contents change halfway through. # But does that _really_ work? for li in list(self.store.query(_ListItem, AND(_ListItem._container == self, _ListItem._index >= index))): # XXX: The performance of this operation probably sucks # compared to what it would be with an UPDATE. li._index += 1 _ListItem(store=self.store, _value=value, _container=self, _index=index) self.length += 1
def pop(self, index=None): if index is None: index = self.length - 1 index = self._fixIndex(index) x = self[index] del self[index] return x
def remove(self, value): del self[self.index(value)]
def reverse(self): # XXX: Also needs to be an atomic action. length = 0 for li in list(self.store.query(_ListItem, _ListItem._container == self, sort=_ListItem._index.desc)): li._index = length length += 1 self.length = length
def sort(self, *args): # We want to sort by value, not sort by _ListItem. We could # accomplish this by having _ListItem.__cmp__ do something # with self._value, but that seemed wrong. This was easier. values = [li._value for li in self._queryListItems()] values.sort(*args) index = 0 for li in self._queryListItems(): # XXX: Well, can it? assert index < len(values), \ '_ListItems were added during a sort (can this happen?)' li._index = index li._value = values[index] index += 1
def count(self, value): return self.store.count(_ListItem, AND( _ListItem._container == self, _ListItem._value == value))
|