Source code for zict.sieve
from __future__ import absolute_import, division, print_function
from collections import defaultdict
from itertools import chain
import sys
from .common import ZictBase, close
[docs]class Sieve(ZictBase):
""" Store values in different mappings based on a selector's
output.
This creates a MutableMapping combining several underlying
MutableMappings for storage. Items are dispatched based on
a selector function provided by the user.
Parameters
----------
mappings: dict of {mapping key: MutableMapping}
selector: callable (key, value) -> mapping key
Examples
--------
>>> small = {}
>>> large = DataBase() # doctest: +SKIP
>>> mappings = {True: small, False: large} # doctest: +SKIP
>>> def is_small(key, value): # doctest: +SKIP
return sys.getsizeof(value) < 10000
>>> d = Sieve(mappings, is_small) # doctest: +SKIP
See Also
--------
Buffer
"""
def __init__(self, mappings, selector):
self.mappings = mappings
self.selector = selector
self.key_to_mapping = {}
def __getitem__(self, key):
return self.key_to_mapping[key][key]
def __setitem__(self, key, value):
old_mapping = self.key_to_mapping.get(key)
mapping = self.mappings[self.selector(key, value)]
if old_mapping is not None and old_mapping is not mapping:
del old_mapping[key]
mapping[key] = value
self.key_to_mapping[key] = mapping
def __delitem__(self, key):
del self.key_to_mapping.pop(key)[key]
def _do_update(self, items):
# Optimized update() implementation issuing a single update()
# call per underlying mapping.
to_delete = []
updates = defaultdict(list)
mapping_ids = dict((id(m), m) for m in self.mappings.values())
for key, value in items:
old_mapping = self.key_to_mapping.get(key)
mapping = self.mappings[self.selector(key, value)]
if old_mapping is not None and old_mapping is not mapping:
del old_mapping[key]
# Can't hash a mutable mapping, so use its id() instead
updates[id(mapping)].append((key, value))
for mid, mitems in updates.items():
mapping = mapping_ids[mid]
mapping.update(mitems)
for key, _ in mitems:
self.key_to_mapping[key] = mapping
[docs] def keys(self):
return chain.from_iterable(self.mappings.values())
[docs] def values(self):
return chain.from_iterable(m.values() for m in self.mappings.values())
[docs] def items(self):
return chain.from_iterable(m.items() for m in self.mappings.values())
def __len__(self):
return sum(map(len, self.mappings.values()))
__iter__ = keys
def __contains__(self, key):
return key in self.key_to_mapping
def __str__(self):
return 'Sieve<%s>' % (str(self.mappings),)
__repr__ = __str__
def flush(self):
for m in self.mappings.values():
m.flush()
[docs] def close(self):
for m in self.mappings.values():
close(m)