""" $URL: svn+ssh://svn.mems-exchange.org/repos/trunk/qp/lib/keep.py $ $Id: keep.py 29531 2007-03-05 15:11:28Z dbinger $ """ from durus.btree import BTree from durus.persistent import PersistentObject from durus.persistent_dict import PersistentDict from qp.lib.spec import either, datetime_with_tz, mapping, spec from qp.lib.spec import require, get_spec_problems, anything from qp.lib.tz import UTC class Keyed (object): """ An item with an int key used as a key in an Keep. Note that the key attribute is set when the item is put in the Keep, so there is no set_key() method. This is a mixin for PersistentObject classes. """ key_is = int __slots__ = [] def __init__(self): assert isinstance(self, PersistentObject) self.key = None def get_key(self): return self.key class Counter (PersistentObject): """ Keep a key counter. This may change often, so we keep this isolated here instead of on the Keep itself. """ next_available_is = int __slots__ = ['next_available'] def __init__(self): self.next_available = 1 def next(self): result = self.next_available self.next_available = self.next_available + 1 return result class Keep (object): """ A simple database that stores a mapping of objects by key. This is a mixin for PersistentObject classes. """ value_spec_is = spec( anything, "Specifies the type of values allowed in mapping") mapping_is = mapping({int:Keyed}, either(PersistentDict, BTree)) key_counter_is = Counter __slots__ = [] def __init__(self, value_spec=Keyed): assert isinstance(self, PersistentObject) self.mapping = BTree() self.key_counter = Counter() self.value_spec = value_spec def get_mapping(self): return self.mapping def get(self, key, default=None): return self.mapping.get(key, default) def itervalues(self): for value in self.mapping.itervalues(): yield value def iterkeys(self): for key in self.mapping.iterkeys(): yield key def iteritems(self): for item in self.mapping.iteritems(): yield item def add(self, value): require(value, self.value_spec) assert value.key is None value.key = self.key_counter.next() if get_spec_problems(value): raise TypeError(''.join(get_spec_problems(value))) self.mapping[value.key] = value class Stamped (object): """ Provides a timestamp. This is a mixin for PersistentObject classes. """ stamp_is = datetime_with_tz __slots__ = [] def __init__(self): assert isinstance(self, PersistentObject) self.set_stamp() def get_stamp(self): return self.stamp def set_stamp(self): self.stamp = UTC.now() def stamp_sorted(stamped_sequence): items = [(x.stamp, x) for x in stamped_sequence] items.sort() return [x for (stamp, x) in items] def reverse_stamp_sorted(stamped_sequence): result = stamp_sorted(stamped_sequence) result.reverse() return result