You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

134 lines
3.2 KiB

import six
import pickle
from six.moves import map, UserDict
ROOT_SENTINEL = u'\u200B'
SEP_SENTINEL = u'\u200D'
OBJ_SENTINEL = u'\u200C'
CAST_SENTINEL = u'\u24EA'
def join_key(*args):
nargs = []
for arg in args:
if not isinstance(arg, six.string_types):
arg = CAST_SENTINEL + pickle.dumps(arg)
nargs.append(arg)
return SEP_SENTINEL.join(nargs)
def true_key(key):
key = key.rsplit(SEP_SENTINEL, 1)[-1]
if key.startswith(CAST_SENTINEL):
return pickle.loads(key)
return key
class BaseProvider(object):
def __init__(self, config):
self.config = config
self.data = {}
def exists(self, key):
return key in self.data
def keys(self, other):
count = other.count(SEP_SENTINEL) + 1
for key in self.data.keys():
if key.startswith(other) and key.count(SEP_SENTINEL) == count:
yield key
def get_many(self, keys):
for key in keys:
yield key, self.get(key)
def get(self, key):
return self.data[key]
def set(self, key, value):
self.data[key] = value
def delete(self, key):
del self.data[key]
def load(self):
pass
def save(self):
pass
def root(self):
return StorageDict(self)
class StorageDict(UserDict):
def __init__(self, parent_or_provider, key=None):
if isinstance(parent_or_provider, BaseProvider):
self.provider = parent_or_provider
self.parent = None
else:
self.parent = parent_or_provider
self.provider = self.parent.provider
self._key = key or ROOT_SENTINEL
def keys(self):
return map(true_key, self.provider.keys(self.key))
def values(self):
for key in self.keys():
yield self.provider.get(key)
def items(self):
for key in self.keys():
yield (true_key(key), self.provider.get(key))
def ensure(self, key, typ=dict):
if key not in self:
self[key] = typ()
return self[key]
def update(self, obj):
for k, v in six.iteritems(obj):
self[k] = v
@property
def data(self):
obj = {}
for raw, value in self.provider.get_many(self.provider.keys(self.key)):
key = true_key(raw)
if value == OBJ_SENTINEL:
value = self.__class__(self, key=key).data
obj[key] = value
return obj
@property
def key(self):
if self.parent is not None:
return join_key(self.parent.key, self._key)
return self._key
def __setitem__(self, key, value):
if isinstance(value, dict):
obj = self.__class__(self, key)
obj.update(value)
value = OBJ_SENTINEL
self.provider.set(join_key(self.key, key), value)
def __getitem__(self, key):
res = self.provider.get(join_key(self.key, key))
if res == OBJ_SENTINEL:
return self.__class__(self, key)
return res
def __delitem__(self, key):
return self.provider.delete(join_key(self.key, key))
def __contains__(self, key):
return self.provider.exists(join_key(self.key, key))