Handle cache keys that are python3 bytes
twidi opened this issue · comments
Actually in CacheOp.__init__
, bytes are managed via the isinstance(key_or_keys, (Mapping, Sequence))
code branch, which will not work.
I actually made it work by patching your code adding
if isinstance(key_or_keys, bytes):
key_or_keys = key_or_keys.decode('utf-8')
at the top, but there may be a better way.
bytes
aren't documented as officially supported by Django's cache framework, and searching cache\.get.*b['"]
in its test suite shows me no usage.
I think you should really be using str
s and you're just lucky that whichever cache backend you're using is lenient, probably because of the Python 2 + 3 compatibility being maintained. On Python 3 bytes
iterate in a different way and have other quirks that don't make them the same as 'ascii strings'.
Ok I understand, I'll use patchy (as you do, thanks for letting me discover this awfully beautiful library) to patch your code :)
PS: btw, I don't create this kind of keys myself, there are created by django-waffle ;) cf https://github.com/jsocol/django-waffle/blob/master/waffle/utils.py#L19-L25
I think you should take this up with django-waffle
then 😄
If I have to choose, I prefer to keep a heavily used library in the django world that works very fine and patch your code manually (no offense, I totally understand your point of view!!) ;)
Keep the great job !
Waiting for the upgrade of django-waffle
(thanks for the issue), and in case someone else encounter the same "issue", here is my code (works for me, but provided without any guarantee):
from django_perf_rec.cache import CacheOp
import patchy
patchy.patch(CacheOp.__init__, '''
@@ -1,6 +1,8 @@
def __init__(self, alias, operation, key_or_keys):
self.alias = alias
self.operation = operation
+ if isinstance(key_or_keys, bytes):
+ key_or_keys = key_or_keys.decode('utf-8')
if isinstance(key_or_keys, six.string_types):
self.key_or_keys = self.clean_key(key_or_keys)
elif isinstance(key_or_keys, (Mapping, Sequence)):
''')
patchy.patch(CacheOp.clean_key, '''
@@ -3,6 +3,8 @@
"""
Replace things that look like variables with a '#' so tests aren't affected by random variables
"""
+ if isinstance(key, bytes):
+ key = key.decode('utf-8')
for var_re in cls.VARIABLE_RES:
key = var_re.sub('#', key)
return key
''')