Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add MessagePackSerializer #370

Merged
merged 10 commits into from
Jan 16, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ lint:
flake8

install-dev:
pipenv install --dev
pipenv install '-e .' --dev

pylint:
pylint --disable=C0111 aiocache
Expand Down
5 changes: 4 additions & 1 deletion Pipfile
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,11 @@ name = "pypi"


[packages]
"-e .[redis,memcached]" = "*"

"-e .[redis,memcached,msgpack]" = "*"


[dev-packages]

"-e .[dev]" = "*"
"e1839a8" = {path = ".", editable = true}
103 changes: 56 additions & 47 deletions Pipfile.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ Installing
- ``pip install aiocache[redis]``
- ``pip install aiocache[memcached]``
- ``pip install aiocache[redis,memcached]``
- ``pip install aiocache[msgpack]``


Usage
Expand Down Expand Up @@ -163,7 +164,7 @@ How does it work
Aiocache provides 3 main entities:

- **backends**: Allow you specify which backend you want to use for your cache. Currently supporting: SimpleMemoryCache, RedisCache using aioredis_ and MemCache using aiomcache_.
- **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. But you can also build custom ones.
- **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.
- **plugins**: Implement a hooks system that allows to execute extra behavior before and after of each command.

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.
Expand Down
30 changes: 30 additions & 0 deletions aiocache/serializers.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import logging
import pickle
import msgpack

logger = logging.getLogger(__file__)

Expand Down Expand Up @@ -137,3 +138,32 @@ def loads(cls, value):
if value is None:
return None
return json.loads(value)


class MsgPackSerializer(StringSerializer):
"""
Transform data to bytes using msgpack.dumps and msgpack.loads to retrieve it back. You need
to have ``msgpack`` installed in order to be able to use this serializer.
"""

@classmethod
def dumps(cls, value):
"""
Serialize the received value using ``msgpack.dumps``.

:param value: obj
:returns: bytes
"""
return msgpack.dumps(value)

@classmethod
def loads(cls, value):
"""
Deserialize value using ``msgpack.loads``.

:param value: bytes
:returns: obj
"""
if value is None:
return None
return msgpack.loads(value, encoding=cls.encoding)
7 changes: 7 additions & 0 deletions docs/serializers.rst
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,13 @@ JsonSerializer
.. autoclass:: aiocache.serializers.JsonSerializer
:members:

.. _msgpackserializer:

MessagePackSerializer
--------------

.. autoclass:: aiocache.serializers.MessagePackSerializer
:members:

In case the current serializers are not covering your needs, you can always define your custom serializer as shown in ``examples/serializer_class.py``:

Expand Down
1 change: 1 addition & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
extras_require={
'redis': ['aioredis>=0.3.3'],
'memcached': ['aiomcache>=0.5.2'],
'msgpack': ['msgpack'],
'dev': [
'flake8',
'pytest',
Expand Down
51 changes: 44 additions & 7 deletions tests/ut/test_serializers.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
import pytest
try:
import ujson as json
except ImportError:
import json

from collections import namedtuple

from aiocache.serializers import NullSerializer, StringSerializer, PickleSerializer, JsonSerializer
from aiocache.serializers import (
NullSerializer, StringSerializer, PickleSerializer, JsonSerializer, MsgPackSerializer)


Dummy = namedtuple("Dummy", "a, b")

TYPES = [1, 2.0, "hi", True, ["1", 1], {"key": "value"}, Dummy(1, 2)]
JSON_TYPES = [1, 2.0, "hi", True, ["1", 1], {"key": "value"}]


class TestNullSerializer:
Expand Down Expand Up @@ -60,9 +58,10 @@ def test_dumps_and_loads(self):

class TestJsonSerializer:

@pytest.mark.parametrize("obj", TYPES)
@pytest.mark.parametrize("obj", JSON_TYPES)
def test_set_types(self, obj):
assert JsonSerializer().dumps(obj) == json.dumps(obj)
serializer = JsonSerializer()
assert serializer.loads(serializer.dumps(obj)) == obj

def test_dumps(self):
assert (
Expand All @@ -82,3 +81,41 @@ def test_dumps_and_loads(self):
obj = {"hi": 1}
serializer = JsonSerializer()
assert serializer.loads(serializer.dumps(obj)) == obj


class TestMsgPackSerializer:

@pytest.mark.parametrize("obj", JSON_TYPES)
def test_set_types(self, obj):
serializer = MsgPackSerializer()
assert serializer.loads(serializer.dumps(obj)) == obj

def test_dumps(self):
assert MsgPackSerializer().dumps('hi') == b'\xa2hi'

def test_dumps_with_none(self):
assert isinstance(MsgPackSerializer().dumps(None), bytes)

def test_loads(self):
assert MsgPackSerializer().loads(b'\xa2hi') == 'hi'

def test_loads_no_encoding(self):
MsgPackSerializer.encoding = None
assert MsgPackSerializer().loads(b'\xa2hi') == b'hi'
MsgPackSerializer.encoding = 'utf-8'

def test_loads_with_none(self):
assert MsgPackSerializer().loads(None) is None

def test_dumps_and_loads_tuple(self):
assert MsgPackSerializer.loads(MsgPackSerializer.dumps(Dummy(1, 2))) == [1, 2]

def test_dumps_and_loads_dict(self):
d = {
'a': [1, 2, ('1', 2)],
'b': {'b': 1, 'c': [1, 2]}
}
assert MsgPackSerializer.loads(MsgPackSerializer.dumps(d)) == {
'a': [1, 2, ['1', 2]],
'b': {'b': 1, 'c': [1, 2]}
}
1 change: 1 addition & 0 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ deps =

.[redis]
.[memcached]
.[msgpack]
.[dev]

commands =
Expand Down