Skip to content
Snippets Groups Projects

New cool stuff!

Merged Simon Sebastian Humpohl requested to merge simon into master
5 files
+ 129
14
Compare changes
  • Side-by-side
  • Inline
Files
5
qutil/caching.py 0 → 100644
+ 84
0
"""Programming tools"""
import shelve
from typing import Callable, Generator, Any
import inspect
import tempfile
import os.path
import itertools
import functools
import numpy as np
from qutil.itertools import separate_iterator
__all__ = ["file_cache", "lru_cache"]
def to_key(obj: Any) -> Generator[str]:
"""Convert to a string representation that is unique except for
- lists and ndarrays are treated the same
:param obj:
:return:
"""
if isinstance(obj, tuple):
element_key_generator = itertools.chain.from_iterable(map(to_key, obj))
yield '('
yield from separate_iterator(element_key_generator, ',')
yield ',)'
elif isinstance(obj, (list, np.ndarray)):
element_key_generator = itertools.chain.from_iterable(map(to_key, obj))
yield '['
yield from separate_iterator(element_key_generator, ',')
yield ']'
elif isinstance(obj, dict):
# we need to sort the representations in the case the objects are not sortable
sorted_items = sorted(''.join(itertools.chain(to_key(key), (':',), to_key(value)))
for key, value in obj.items())
yield '{'
yield from separate_iterator(sorted_items, ',')
yield '}'
elif isinstance(obj, (set, frozenset)):
sorted_elements = sorted(map(''.join, map(to_key, obj)))
yield '{'
yield from separate_iterator(sorted_elements, ',')
yield '}'
elif isinstance(obj, (int, float, complex, str, bytes)) or obj is None:
yield repr(obj)
else:
raise TypeError('not handled: ', type(obj))
class CachingWrapper:
"""This object wraps a callable and caches the results in a dbm database on the file system (by default in the temp
folder). The key is generated via to_key which means that large arguments need a large time to process."""
def __init__(self, func, storage_path=None):
self._func = func
if storage_path is None:
storage_path = os.path.join(tempfile.gettempdir(), inspect.getmodule(func).__name__ + func.__name__)
self.storage_path = storage_path
def __call__(self, *args, **kwargs):
key = ''.join(to_key((args, kwargs)))
with shelve.open(self.storage_path) as db:
if key in db:
result = db[key]
else:
result = self._func(*args, **kwargs)
db[key] = result
return result
def clear(self):
with shelve.open(self.storage_path) as db:
db.clear()
def file_cache(func: Callable) -> Callable:
return CachingWrapper(func)
lru_cache = functools.lru_cache
Loading