Commits

Nicolas Perriault committed e4beca1

fixed inconsistencies with hash generation

Comments (0)

Files changed (3)

cache_utils/group_backend.py

 import time
 from django.core.cache.backends.memcached import CacheClass as MemcachedCacheClass
 from django.conf import settings
-from cache_utils.utils import sanitize_memcached_key
 
 # This prefix is appended to the group name to prevent cache key clashes.
 _VERSION_PREFIX = getattr(settings, 'VERSION', "")
             if not hashkey:
                 hashkey = self._get_hashkey(group)
             key = "%s:%s-%s" % (group, key, hashkey)
-        return sanitize_memcached_key(key)
+        return key
 
     def _get_hashkey(self, group):
         """ This can be useful sometimes if you're doing a very large number

cache_utils/tests.py

 
 from django.core.cache import cache
 from cache_utils.decorators import cached
-from cache_utils.utils import sanitize_memcached_key, _func_type, _func_info
+from cache_utils.utils import _func_type, _func_info
 
 def foo(a,b):
     pass
                             'cache_utils.tests.Foo.bar', [1])
 
 
-class SanitizeTest(TestCase):
-    def test_sanitize_keys(self):
-        key = u"12345678901234567890123456789012345678901234567890"
-        self.assertTrue(len(key) >= 40)
-        key = sanitize_memcached_key(key, 40)
-        self.assertTrue(len(key) <= 40)
-
-
 class ClearMemcachedTest(TestCase):
     def tearDown(self):
         cache._cache.flush_all()

cache_utils/utils.py

 from hashlib import md5
 from django.utils.encoding  import smart_unicode
 
-CONTROL_CHARACTERS = set([chr(i) for i in range(0,33)])
-CONTROL_CHARACTERS.add(chr(127))
-
-def sanitize_memcached_key(key, max_length=250):
-    """ Removes control characters and ensures that key will
-        not hit the memcached key length limit by replacing
-        the key tail with md5 hash if key is too long.
-    """
-    key = ''.join([c for c in key if c not in CONTROL_CHARACTERS])
-    if len(key) > max_length:
-        hash = md5(key).hexdigest()
-        key = key[:max_length-33]+'-'+hash
-    return key
 
 def _args_to_unicode(args, kwargs):
-    key = ""
+    """Transforms passed args and kwargs to unicode string."""
+    key = u""
     if args:
         key += smart_unicode(args)
     if kwargs:
     return key
 
 
+def _encode_key(key):
+    """Encodes a key using hash() to prevent problems with Unicode
+       @see http://bugs.python.org/issue2948
+    """
+    return md5(str(hash(key))).hexdigest()
+
+
 def _func_type(func):
     """ returns if callable is a function, method or a classmethod """
     argnames = func.func_code.co_varnames[:func.func_code.co_argcount]
 
 
 def _func_info(func, args):
-    ''' introspect function's or method's full name.
+    """ introspect function's or method's full name.
     Returns a tuple (name, normalized_args,) with
-    'cls' and 'self' removed from normalized_args '''
-
+    'cls' and 'self' removed from normalized_args 
+    """
     func_type = _func_type(func)
-
     if func_type == 'function':
         return ".".join([func.__module__, func.__name__]), args
-
     class_name = args[0].__class__.__name__
     if func_type == 'classmethod':
         class_name = args[0].__name__
 
 
 def _cache_key(func_name, func_type, args, kwargs):
-    """ Construct readable cache key """
+    """ Construct readable cache key 
+    """
     if func_type == 'function':
         args_string = _args_to_unicode(args, kwargs)
     else:
         args_string = _args_to_unicode(args[1:], kwargs)
-    return '[cached]%s(%s)' % (func_name, args_string,)
+    return '[cached]%s(%s)' % (func_name, _encode_key(args_string),)