Skip to content

Commit 8e1a182

Browse files
author
George Alexiou
committed
dill serializer support added
1 parent 9c8b07f commit 8e1a182

8 files changed

Lines changed: 100 additions & 2 deletions

File tree

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ format:
99
black -l 100 tests/ aiocache/
1010

1111
install-dev:
12-
pip install -e .[redis,memcached,msgpack,dev]
12+
pip install -e .[redis,memcached,msgpack,dill,dev]
1313

1414
pylint:
1515
pylint --disable=C0111 aiocache

README.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ Installing
5151
- ``pip install aiocache[memcached]``
5252
- ``pip install aiocache[redis,memcached]``
5353
- ``pip install aiocache[msgpack]``
54+
- ``pip install aiocache[dill]``
5455

5556

5657
Usage
@@ -168,7 +169,7 @@ How does it work
168169
Aiocache provides 3 main entities:
169170

170171
- **backends**: Allow you specify which backend you want to use for your cache. Currently supporting: SimpleMemoryCache, RedisCache using aioredis_ and MemCache using aiomcache_.
171-
- **serializers**: Serialize and deserialize the data between your code and the backends. This allows you to save any Python object into your cache. Currently supporting: StringSerializer, PickleSerializer, JsonSerializer, and MsgPackSerializer. But you can also build custom ones.
172+
- **serializers**: Serialize and deserialize the data between your code and the backends. This allows you to save any Python object into your cache. Currently supporting: StringSerializer, PickleSerializer, JsonSerializer, MsgPackSerializer and DillSerializer. But you can also build custom ones.
172173
- **plugins**: Implement a hooks system that allows to execute extra behavior before and after of each command.
173174

174175
If you are missing an implementation of backend, serializer or plugin you think it could be interesting for the package, do not hesitate to open a new issue.

aiocache/serializers/__init__.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,14 @@
2020

2121
del msgpack
2222

23+
try:
24+
import dill
25+
except ImportError:
26+
logger.debug("dill not installed, DillSerializer unavailable")
27+
else:
28+
from .serializers import DillSerializer
29+
30+
del dill
2331

2432
__all__ = [
2533
"BaseSerializer",
@@ -28,4 +36,5 @@
2836
"PickleSerializer",
2937
"JsonSerializer",
3038
"MsgPackSerializer",
39+
"DillSerializer",
3140
]

aiocache/serializers/serializers.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,12 @@
1515
msgpack = None
1616
logger.debug("msgpack not installed, MsgPackSerializer unavailable")
1717

18+
try:
19+
import dill
20+
except ImportError:
21+
dill = None
22+
logger.debug("dill not installed, DillSerializer unavailable")
23+
1824

1925
_NOT_SET = object()
2026

@@ -193,3 +199,35 @@ def loads(self, value):
193199
if value is None:
194200
return None
195201
return msgpack.loads(value, raw=raw, use_list=self.use_list)
202+
203+
204+
class DillSerializer(BaseSerializer):
205+
"""
206+
Transform data to bytes using dill.dumps and dill.loads to retrieve it back.
207+
"""
208+
209+
DEFAULT_ENCODING = None
210+
211+
def __init__(self, *args, protocol=dill.DEFAULT_PROTOCOL, **kwargs):
212+
super().__init__(*args, **kwargs)
213+
self.protocol = protocol
214+
215+
def dumps(self, value):
216+
"""
217+
Serialize the received value using ``dill.dumps``.
218+
219+
:param value: obj
220+
:returns: bytes
221+
"""
222+
return dill.dumps(value, protocol=self.protocol)
223+
224+
def loads(self, value):
225+
"""
226+
Deserialize value using ``dill.loads``.
227+
228+
:param value: bytes
229+
:returns: obj
230+
"""
231+
if value is None:
232+
return None
233+
return dill.loads(value)

docs/readthedocs.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,4 @@ python:
1111
- redis
1212
- memcached
1313
- msgpack
14+
- dill

docs/serializers.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,14 @@ MsgPackSerializer
5454
.. autoclass:: aiocache.serializers.MsgPackSerializer
5555
:members:
5656

57+
.. _dillserializer:
58+
59+
DillSerializer
60+
----------------
61+
62+
.. autoclass:: aiocache.serializers.DillSerializer
63+
:members:
64+
5765
In case the current serializers are not covering your needs, you can always define your custom serializer as shown in ``examples/serializer_class.py``:
5866

5967
.. literalinclude:: ../examples/serializer_class.py

setup.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
'redis:python_version>="3.7" and python_version<"3.8"': ['aioredis>=1.0.0'],
4343
'memcached': ['aiomcache>=0.5.2'],
4444
'msgpack': ['msgpack>=0.5.5'],
45+
'dill': ['dill>=0.3.3'],
4546
'dev': [
4647
'asynctest>=0.11.0',
4748
'black;python_version>="3.6"',

tests/ut/test_serializers.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import pytest
22
import pickle
3+
import dill
34

45
from collections import namedtuple
56
from unittest import mock
@@ -11,6 +12,7 @@
1112
PickleSerializer,
1213
JsonSerializer,
1314
MsgPackSerializer,
15+
DillSerializer,
1416
)
1517

1618

@@ -189,3 +191,41 @@ def test_dumps_and_loads_dict(self):
189191
"a": [1, 2, ["1", 2]],
190192
"b": {"b": 1, "c": [1, 2]},
191193
}
194+
195+
196+
class TestDillSerializer:
197+
@pytest.fixture
198+
def serializer(self):
199+
yield DillSerializer(protocol=4)
200+
201+
def test_init(self, serializer):
202+
assert isinstance(serializer, BaseSerializer)
203+
assert serializer.DEFAULT_ENCODING is None
204+
assert serializer.encoding is None
205+
assert serializer.protocol == 4
206+
207+
def test_init_sets_default_protocol(self):
208+
serializer = DillSerializer()
209+
assert serializer.protocol == dill.DEFAULT_PROTOCOL
210+
211+
@pytest.mark.parametrize("obj", TYPES)
212+
def test_set_types(self, obj, serializer):
213+
assert serializer.loads(serializer.dumps(obj)) == obj
214+
215+
def test_dumps(self, serializer):
216+
assert (
217+
serializer.dumps("hi") == b"\x80\x04\x95\x06\x00\x00\x00\x00\x00\x00\x00\x8c\x02hi\x94."
218+
)
219+
220+
def test_dumps_with_none(self, serializer):
221+
assert isinstance(serializer.dumps(None), bytes)
222+
223+
def test_loads(self, serializer):
224+
assert serializer.loads(b"\x80\x03X\x02\x00\x00\x00hiq\x00.") == "hi"
225+
226+
def test_loads_with_none(self, serializer):
227+
assert serializer.loads(None) is None
228+
229+
def test_dumps_and_loads(self, serializer):
230+
obj = Dummy(1, 2)
231+
assert serializer.loads(serializer.dumps(obj)) == obj

0 commit comments

Comments
 (0)