Filedict v0.2 Code

FileDict.py

Depends on

  • sqlite3

Code

"""filedict.py
a Persistent Dictionary in Python
 
Author: Erez Shinan
Date  : 31-May-2009
"""
 
import UserDict
import cPickle as pickle
 
import sqlite3
 
class DefaultArg:
    pass
 
class Solutions:
    Sqlite3 = 0
 
class FileDict(UserDict.DictMixin):
    "A dictionary that stores its data persistantly in a file"
 
    def __init__(self, solution=Solutions.Sqlite3, **options):
        assert solution == Solutions.Sqlite3
        try:
            self.__conn = options.pop('connection')
        except KeyError:
            filename = options.pop('filename')
            self.__conn = sqlite3.connect(filename)
 
        self.__tablename = options.pop('table', 'dict')
 
        self._nocommit = False
 
        assert not options, "Unrecognized options: %s" % options
 
        self.__conn.execute('create table if not exists %s (id integer primary key, hash integer, key blob, value blob);'%self.__tablename)
        self.__conn.execute('create index if not exists %s_index ON %s(hash);' % (self.__tablename, self.__tablename))
        self.__conn.commit()
 
    def _commit(self):
        if self._nocommit:
            return
 
        self.__conn.commit()
 
    def __pack(self, value):
        return sqlite3.Binary(pickle.dumps(value, -1))
    def __unpack(self, value):
        return pickle.loads(str(value))
 
    def __get_id(self, key):
        cursor = self.__conn.execute('select key,id from %s where hash=?;'%self.__tablename, (hash(key),))
        for k,id in cursor:
            if self.__unpack(k) == key:
                return id
 
        raise KeyError(key)
 
    def __getitem__(self, key):
        cursor = self.__conn.execute('select key,value from %s where hash=?;'%self.__tablename, (hash(key),))
        for k,v in cursor:
            if self.__unpack(k) == key:
                return self.__unpack(v)
 
        raise KeyError(key)
 
    def __setitem(self, key, value):
        value_pickle = self.__pack(value)
 
        try:
            id = self.__get_id(key)
            cursor = self.__conn.execute('update %s set value=? where id=?;'%self.__tablename, (value_pickle, id) )
        except KeyError:
            key_pickle = self.__pack(key)
            cursor = self.__conn.execute('insert into %s (hash, key, value) values (?, ?, ?);'
                    %self.__tablename, (hash(key), key_pickle, value_pickle) )
 
        assert cursor.rowcount == 1
 
    def __setitem__(self, key, value):
        self.__setitem(key, value)
        self._commit()
 
    def __delitem__(self, key):
        id = self.__get_id(key)
        cursor = self.__conn.execute('delete from %s where id=?;'%self.__tablename, (id,))
        if cursor.rowcount <= 0:
            raise KeyError(key)
 
        self._commit()
 
    def update(self, d):
        for k,v in d.iteritems():
            self.__setitem(k, v)
        self._commit()
 
    def __iter__(self):
        return (self.__unpack(x[0]) for x in self.__conn.execute('select key from %s;'%self.__tablename) )
    def keys(self):
        return iter(self)
    def values(self):
        return (self.__unpack(x[0]) for x in self.__conn.execute('select value from %s;'%self.__tablename) )
    def items(self):
        return (map(self.__unpack, x) for x in self.__conn.execute('select key,value from %s;'%self.__tablename) )
    def iterkeys(self):
        return self.keys()
    def itervalues(self):
        return self.values()
    def iteritems(self):
        return self.items()
 
    def __contains__(self, key):
        try:
            self.__get_id(key)
            return True
        except KeyError:
            return False
 
    def __len__(self):
        return self.__conn.execute('select count(*) from %s;' % self.__tablename).fetchone()[0]
 
    def __del__(self):
        try:
            self.__conn
        except AttributeError:
            pass
        else:
            self.__conn.commit()
 
    @property
    def batch(self):
        return self._Batch(self)
 
    class _Batch:
        def __init__(self, d):
            self.__d = d
 
        def __enter__(self):
            self.__old_nocommit = self.__d._nocommit
            self.__d._nocommit = True
            return self.__d
 
        def __exit__(self, type, value, traceback):
            self.__d._nocommit = self.__old_nocommit
            self.__d._commit()
            return True
Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License