Source code for sophia

#!/usr/bin/env python

__all__ = ['Database', 'Error', 'ObjectDatabase', 'SPCMP', 'SPGC', 'SPGCF', 'SPGROW', 'SPGT', 'SPGTE', 'SPLT', 'SPLTE', 'SPMERGE', 'SPMERGEWM', 'SPPAGE', 'ThreadedDatabase', 'ThreadedObjectDatabase']

from _sophia import *
import threading, pickle


[docs]class ObjectDatabase(Database): """Database model for storing arbitrary kinds of objects. `pack_key`, `unpack_key`, `pack_value`, and `unpack_value`, should be callables that, when passed an object as parameter, return a byte representation of it, suitable for storage. By default, all these functions use the :mod:`pickle` module. """ def __init__(self, pack_key=pickle.dumps, unpack_key=pickle.loads, pack_value=pickle.dumps, unpack_value=pickle.loads): self.pack_key = pack_key self.unpack_key = unpack_key self.pack_value = pack_value self.unpack_value = unpack_value super(ObjectDatabase, self).__init__() def get(self, key, default=None): value = super(ObjectDatabase, self).get(self.pack_key(key), default) return default if value is default else self.unpack_value(value) def set(self, key, value): return super(ObjectDatabase, self).set(self.pack_key(key), self.pack_value(value)) def delete(self, key): return super(ObjectDatabase, self).delete(self.pack_key(key)) def iterkeys(self, start_key=None, order=SPGTE): begin = start_key if start_key is None else self.pack_key(start_key) return (self.unpack_key(k) for k in super(ObjectDatabase, self).iterkeys(begin, order)) def itervalues(self, start_key=None, order=SPGTE): begin = start_key if start_key is None else self.pack_key(start_key) return (self.unpack_value(v) for v in super(ObjectDatabase, self).itervalues(begin, order)) def iteritems(self, start_key=None, order=SPGTE): begin = start_key if start_key is None else self.pack_key(start_key) return ((self.unpack_key(k), self.unpack_value(v)) \ for k, v in super(ObjectDatabase, self).iteritems(begin, order))
[docs]class ThreadedDatabase(Database): """Thread-safe database model. It should only be used if you want to use a database in a threaded environment AND need to iterate over it. Otherwise, the vanilla :class:`Database` class is suitable (and more efficient). """ def __init__(self): self._lock = threading.Lock() super(ThreadedDatabase, self).__init__() def _protect(self, method, *args, **kwargs): self._lock.acquire() try: method(*args, **kwargs) finally: self._lock.release() def _protect_iter(self, method, *args, **kwargs): self._lock.acquire() try: for something in method(*args, **kwargs): yield something finally: self._lock.release() def set(self, *args): return self._protect(super(ThreadedDatabase, self).set, *args) def delete(self, *args): return self._protect(super(ThreadedDatabase, self).delete, *args) def iterkeys(self, **kwargs): return self._protect_iter(super(ThreadedDatabase, self).iterkeys, **kwargs) def itervalues(self, **kwargs): return self._protect_iter(super(ThreadedDatabase, self).itervalues, **kwargs) def iteritems(self, **kwargs): return self._protect_iter(super(ThreadedDatabase, self).iteritems, **kwargs)
[docs]class ThreadedObjectDatabase(ObjectDatabase, ThreadedDatabase): """Mixing of a :class:`ThreadedDatabase` and an :class:`ObjectDatabase`.""" pass