I am searching for an object storage in python that allows me to store a dictionary having tuple
s as keys. I already tried shelve and shove, which both exit with an error as soon as I pass my dictionary. Are there any solutions out that provide this?
For shove,
from shove import Shove
data = Shove('file://tmp')
("a",) in data
it gives me AttributeError: 'tuple' object has no attribute 'rstrip'
. But only, if the tuple is not in data.
from shove import Shove
data = Shove('file://tmp')
data[("a",)] = 2
("a",) in data
would not throw an error.
For shelve,
import shelve
d = shelve.open('tmp/test.db')
d[('a',)] = 2
gives me TypeError: dbm mappings have string indices only
shelve
is a module from Python Standard Library. The doc is clear about that : the values (not the keys!) in a shelf can be essentially arbitrary Python objects — anything that the pickle module can handle ... The keys are ordinary strings
By construction shelve will only accept strings as keys.
Shove is still in Beta according to the documentation from pypi, and I could not see any evidence that it supports anything other that a string for the key (the error object has no attribute 'rstrip'
let think it does not).
If I were you, I would stick to the well known shelve
, and just wrap it with a key serialisation layer. As suggested by Padraic Cunningham, pickle
should do the job.
Here is a (not extensively tested) possible implementation :
class tuple_dict(collections.MutableMapping):
class iterator(collections.Iterator):
def __init__(self, d):
self.it = d.udict.__iter__()
def __iter__(self):
return self
def next(self):
return pickle.loads(next(self.it))
def __init__(self, udict):
self.udict = udict
def __getitem__(self, key):
ukey = pickle.dumps(key)
return self.udict[ukey]
def __setitem__(self, key, value):
ukey = pickle.dumps(key)
self.udict[ukey] = value
def __delitem__(self, key):
ukey = pickle.dumps(key)
del self.udict[ukey]
def keys(self):
return [ pickle.loads(key) for key in self.udict.keys() ]
def __iter__(self):
return self.iterator(self)
def __len__(self):
return len(self.udict)
def __contains__(self, key):
return pickle.dumps(key) in self.udict
def sync(self):
self.udict.sync()
def close(self):
self.udict.close()
You would use it that way :
import shelve
underlying_d = shelve.open('tmp/test.db')
d = tuple_dict(underlying_d)
d will then accept tuple as keys and stores that all in the underlying shelf.
NB : if you later want to use a different persistence implementation, provided the implementation is a mapping (dict like class), you could reuse the tuple_dict
by simply changing the close and sync methods (shelve specifice) but what would be needed by the other implentation. In fact apart from these 2 methods tuple_dict just wraps an ordinary dict - and as such any mapping class ...