import hashlib
import json
import os
import pickle
import logging


def _resolve_path(key, dir='', ext='', prefix='', hash_len=16):
    key_encoded = json.dumps(
        key, sort_keys=True, separators=(',', ':')).encode('utf-8')
    key_hash = hashlib.md5(key_encoded).hexdigest()
    path = os.path.join(dir, prefix + key_hash[:hash_len] + ext)
    return path


class Cache(object):
    LOG_LEVEL = logging.DEBUG

    def __init__(self, key, dir='', ext='.pkl', prefix='',
                 serializer=None, deserializer=None, logger=None):
        self._file = _resolve_path(key, dir, ext, prefix)
        self._serializer = serializer \
            if serializer is not None else pickle
        self._deserializer = deserializer \
            if deserializer is not None else self._serializer
        self._logger = logger \
            if logger is not None else logging.getLogger(__name__)

    def load(self):
        self._logger.log(
            self.LOG_LEVEL, "loading cache from `{}`".format(self._file))
        with open(self._file, 'rb') as f:
            return self._serializer.load(f)

    def load_or_create(self, factory):
        try:
            self.load()
        except FileNotFoundError:
            self._logger.log(
                self.LOG_LEVEL, "missing cache - creating a new object")
            obj = factory()
            self.dump(obj)
            return obj

    def dump(self, obj):
        self._logger.log(
            self.LOG_LEVEL, "dumping cache to `{}`".format(self._file))
        with open(self._file, 'wb') as f:
            self._serializer.dump(obj, f)


def load(key, dir='', ext='.pkl', prefix='',
         serializer=None, deserializer=None, logger=None):
    return Cache(key, dir, ext, prefix, serializer, deserializer, logger) \
        .load()


def load_or_create(key, factory, dir='', ext='.pkl', prefix='',
                   serializer=None, deserializer=None, logger=None):
    return Cache(key, dir, ext, prefix, serializer, deserializer, logger) \
        .load_or_create(factory)


def dump(obj, key, dir='', ext='.pkl', prefix='',
         serializer=None, deserializer=None, logger=None):
    Cache(key, dir, ext, prefix, serializer, deserializer, logger).dump(obj)

@@ -460,32 +460,45 @@
 pkl', prefix='',
+ mkdir=False,
 %0A               
@@ -545,24 +545,288 @@
 gger=None):%0A
+        dir = os.path.abspath(os.path.expanduser(dir))%0A        if os.path.isdir(dir):%0A            pass%0A        elif mkdir:%0A            os.makedirs(dir)%0A        else:%0A            raise FileNotFoundError(%0A                %22cache dir was not found: %60%7B%7D%60%22.format(dir))%0A
         self
@@ -1410,19 +1410,62 @@
  factory
-):%0A
+, refresh=False):%0A        if not refresh:%0A    
         
@@ -1477,24 +1477,35 @@
             
+    return 
 self.load()%0A
@@ -1504,16 +1504,20 @@
 .load()%0A
+    
         
@@ -1546,32 +1546,36 @@
 or:%0A            
+    
 self._logger.log
@@ -1584,32 +1584,36 @@
                 
+ 
+   
 self.LOG_LEVEL, 
@@ -1653,24 +1653,138 @@
 bject%22)%0A    
+    else:%0A            self._logger.log(%0A                self.LOG_LEVEL, %22updating cache - creating a new object%22)%0A
         obj 
@@ -1795,20 +1795,16 @@
 ctory()%0A
-    
         
@@ -1818,20 +1818,16 @@
 mp(obj)%0A
-    
         
@@ -2182,32 +2182,56 @@
 ir, ext, prefix,
+ False,%0A                
  serializer, des
@@ -2244,35 +2244,24 @@
 zer, logger)
- %5C%0A        
 .load()%0A%0A%0Ade
@@ -2290,16 +2290,50 @@
 factory,
+ refresh=False,%0A                  
  dir='',
@@ -2347,32 +2347,45 @@
 pkl', prefix='',
+ mkdir=False,
 %0A               
@@ -2469,32 +2469,56 @@
 ir, ext, prefix,
+ mkdir,%0A                
  serializer, des
@@ -2569,16 +2569,25 @@
 (factory
+, refresh
 )%0A%0A%0Adef 
@@ -2623,32 +2623,45 @@
 pkl', prefix='',
+ mkdir=False,
 %0A         serial
@@ -2736,16 +2736,23 @@
  prefix,
+ mkdir,
  seriali
@@ -2777,16 +2777,27 @@
  logger)
+ %5C%0A        
 .dump(ob

Add options for cache.