Source code for psyrun.store.pickle
"""Store using pickle files."""
import errno
from six import string_types
from six.moves import cPickle as pickle
from psyrun.store.base import Store
from psyrun.utils.doc import inherit_docs
[docs]@inherit_docs
class PickleStore(Store):
"""Store using Python pickle *.pkl* files.
It supports all pickle-able data types and has no additional dependencies,
but is not the most efficient store. Also, it has to load the complete
file to append to it.
"""
ext = '.pkl'
def __init__(self, protocol=pickle.HIGHEST_PROTOCOL):
self.protocol = protocol
[docs] def save(self, filename, data):
with open(filename, 'wb') as f:
pickle.dump(data, f, self.protocol)
[docs] def load(self, filename, row=None):
with open(filename, 'rb') as f:
data = pickle.load(f)
if row is None:
return data
else:
return {k: [v[row]] for k, v in data.items()}
def _get_data_len(self, data):
if len(data) > 0:
return max(
len(v) if not isinstance(v, string_types + (bytes,)) else 1
for v in data.values())
else:
return 0
[docs] def append(self, filename, data):
try:
loaded = self.load(filename)
except IOError as err:
if err.errno != errno.ENOENT:
raise
self.save(filename, data)
else:
keys = set(loaded.keys())
keys = keys.union(data.keys())
old_n = self._get_data_len(loaded)
new_n = self._get_data_len(data)
for k in keys:
if k not in loaded:
loaded[k] = [None] * old_n
if not isinstance(loaded[k], list):
loaded[k] = list(loaded[k])
v = data.get(k, [None])
if len(v) != new_n:
if len(v) == 1:
v = v * new_n
else:
raise ValueError("Incompatible data length.")
loaded[k].extend(v)
self.save(filename, loaded)