Commit ff014f34 authored by Sean Bleier's avatar Sean Bleier

Merge pull request #86 from sebleier/unstable

Unstable
parents f02a00e8 729f7df8
......@@ -13,7 +13,7 @@ development_settings.py
.pydevproject
.settings
dist/*
dump.rdb
*.rdb
dist/*
MANIFEST
.venv
......
......@@ -19,6 +19,12 @@ A Redis cache backend for Django
Changelog
=========
1.3.0
-----
* Adds support for pluggable serializers including pickle(default), json,
msgpack, and yaml.
1.2.0
-----
......@@ -232,6 +238,7 @@ Example::
Running Tests
=============
``./install_redis.sh``
``make test``
.. _redis-py: http://github.com/andymccurdy/redis-py/
......
......@@ -5,11 +5,6 @@ from django.utils.importlib import import_module
from redis_cache.compat import smart_bytes, DEFAULT_TIMEOUT
try:
import cPickle as pickle
except ImportError:
import pickle
try:
import redis
except ImportError:
......@@ -64,6 +59,11 @@ class BaseRedisCache(BaseCache):
self.connection_pool_class_kwargs = (
self.get_connection_pool_class_kwargs()
)
self.serializer_class = self.get_serializer_class()
self.serializer_class_kwargs = self.get_serializer_class_kwargs()
self.serializer = self.serializer_class(
**self.serializer_class_kwargs
)
def __getstate__(self):
return {'params': self.params, 'server': self.server}
......@@ -117,6 +117,21 @@ class BaseRedisCache(BaseCache):
def get_connection_pool_class_kwargs(self):
return self.options.get('CONNECTION_POOL_CLASS_KWARGS', {})
def get_serializer_class(self):
serializer_class = self.options.get(
'SERIALIZER_CLASS',
'redis_cache.serializers.PickleSerializer'
)
module_name, class_name = serializer_class.rsplit('.', 1)
module = import_module(module_name)
try:
return getattr(module, class_name)
except AttributeError:
raise ImportError('cannot import name %s' % class_name)
def get_serializer_class_kwargs(self):
return self.options.get('SERIALIZER_CLASS_KWARGS', {})
def get_master_client(self):
"""
Get the write server:port of the master cache
......@@ -150,14 +165,10 @@ class BaseRedisCache(BaseCache):
return client
def serialize(self, value):
return pickle.dumps(value, self.pickle_version)
return self.serializer.serialize(value)
def deserialize(self, value):
"""
Unpickles the given value.
"""
value = smart_bytes(value)
return pickle.loads(value)
return self.serializer.deserialize(value)
def get_value(self, original):
try:
......
......@@ -13,7 +13,6 @@ except ImportError:
smart_text = smart_unicode
smart_bytes = smart_str
if PY3:
bytes_type = bytes
from urllib.parse import parse_qs, urlparse
......
try:
import cPickle as pickle
except ImportError:
import pickle
import json
try:
import msgpack
except ImportError:
pass
try:
import yaml
except ImportError:
pass
from redis_cache.compat import smart_bytes, smart_text
class BaseSerializer(object):
def __init__(self, **kwargs):
super(BaseSerializer, self).__init__(**kwargs)
def serialize(self, value):
raise NotImplementedError
def deserialize(self, value):
raise NotImplementedError
class PickleSerializer(object):
def __init__(self, pickle_version=-1):
self.pickle_version = pickle_version
def serialize(self, value):
return pickle.dumps(value, self.pickle_version)
def deserialize(self, value):
return pickle.loads(smart_bytes(value))
class JSONSerializer(BaseSerializer):
def __init__(self, **kwargs):
super(JSONSerializer, self).__init__(**kwargs)
def serialize(self, value):
return smart_bytes(json.dumps(value))
def deserialize(self, value):
return json.loads(smart_text(value))
class MSGPackSerializer(BaseSerializer):
def serialize(self, value):
return msgpack.dumps(value)
def deserialize(self, value):
return msgpack.loads(value, encoding='utf-8')
class YAMLSerializer(BaseSerializer):
def serialize(self, value):
return yaml.dump(value, encoding='utf-8')
def deserialize(self, value):
return yaml.load(value)
......@@ -2,3 +2,5 @@ hiredis==0.2.0
django-nose==1.4
nose==1.3.6
unittest2==1.0.1
msgpack-python==0.4.6
pyyaml==3.11
......@@ -5,7 +5,7 @@ setup(
url="http://github.com/sebleier/django-redis-cache/",
author="Sean Bleier",
author_email="sebleier@gmail.com",
version="1.2.1",
version="1.3.0",
packages=["redis_cache", "redis_cache.backends"],
description="Redis Cache Backend for Django",
install_requires=['redis>=2.10.3'],
......
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.test import TestCase
try:
from django.test import override_settings
except ImportError:
from django.test.utils import override_settings
from redis_cache.connection import pool
from tests.testapp.tests.base_tests import SetupMixin
LOCATION = "127.0.0.1:6381"
# functions/classes for complex data type tests
def f():
return 42
class C:
def m(n):
return 24
class BaseSerializerTestCase(SetupMixin, TestCase):
converts_tuple_to_list = False
serializes_objects = True
def test_string(self):
self.cache.set('a', 'a')
self.assertEqual(self.cache.get('a'), 'a')
def test_unicode(self):
self.cache.set('Iñtërnâtiônàlizætiøn', 'Iñtërnâtiônàlizætiøn2')
self.assertEqual(
self.cache.get('Iñtërnâtiônàlizætiøn'),
'Iñtërnâtiônàlizætiøn2'
)
def test_number(self):
self.cache.set('a', 10)
self.assertEqual(self.cache.get('a'), 10)
def test_dictionary(self):
stuff = {
'string': 'this is a string',
'int': 42,
'list': [1, 2, 3, 4],
'tuple': (1, 2, 3, 4),
'dict': {'A': 1, 'B': 2},
}
if self.serializes_objects:
stuff.update({
'function': f,
'class': C,
})
self.cache.set('a', stuff)
stuff = self.cache.get('a')
_tuple = [1, 2, 3, 4] if self.converts_tuple_to_list else (1, 2, 3, 4)
data = {
'string': 'this is a string',
'int': 42,
'list': [1, 2, 3, 4],
'tuple': _tuple,
'dict': {'A': 1, 'B': 2},
}
if self.serializes_objects:
data.update({
'function': f,
'class': C,
})
self.assertEqual(stuff, data)
@override_settings(CACHES={
'default': {
'BACKEND': 'redis_cache.RedisCache',
'LOCATION': LOCATION,
'OPTIONS': {
'DB': 1,
'PASSWORD': 'yadayada',
'PARSER_CLASS': 'redis.connection.HiredisParser',
'PICKLE_VERSION': -1,
'SERIALIZER_CLASS': 'redis_cache.serializers.JSONSerializer'
},
},
})
class JsonSerializerTestCase(BaseSerializerTestCase):
converts_tuple_to_list = True
serializes_objects = False
@override_settings(CACHES={
'default': {
'BACKEND': 'redis_cache.RedisCache',
'LOCATION': LOCATION,
'OPTIONS': {
'DB': 1,
'PASSWORD': 'yadayada',
'PARSER_CLASS': 'redis.connection.HiredisParser',
'PICKLE_VERSION': -1,
'SERIALIZER_CLASS': 'redis_cache.serializers.MSGPackSerializer'
},
},
})
class MSGPackSerializerTestCase(BaseSerializerTestCase):
converts_tuple_to_list = True
serializes_objects = False
@override_settings(CACHES={
'default': {
'BACKEND': 'redis_cache.RedisCache',
'LOCATION': LOCATION,
'OPTIONS': {
'DB': 1,
'PASSWORD': 'yadayada',
'PARSER_CLASS': 'redis.connection.HiredisParser',
'PICKLE_VERSION': -1,
'SERIALIZER_CLASS': 'redis_cache.serializers.YAMLSerializer'
},
},
})
class YAMLSerializerTestCase(BaseSerializerTestCase):
converts_tuple_to_list = False
serializes_objects = True
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment